From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: None (no SPF record) identity=mailfrom; client-ip=2a00:1450:4864:20::543; helo=mail-ed1-x543.google.com; envelope-from=pete@akeo.ie; receiver=edk2-devel@lists.01.org Received: from mail-ed1-x543.google.com (mail-ed1-x543.google.com [IPv6:2a00:1450:4864:20::543]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 5F5062194D3B9 for ; Mon, 10 Dec 2018 04:39:42 -0800 (PST) Received: by mail-ed1-x543.google.com with SMTP id j6so9315064edp.9 for ; Mon, 10 Dec 2018 04:39:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=akeo-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=QJzIDg0bzUV21jV1K+KOzqxEkfNWmq+OI4TUw4OqEks=; b=IRE3MGFy4A01oaHCuwAw9fUrB6hVSAjIfQGxoV5W7QnNC/TKD8hESXVBlxkPgvuBpd F6Ify3k2OimPV5DQ4WGG4RQ9Aang4zDv69uuMaB3ZDjdY8qZigdKFT3H/i4O7QKt/yiT dgmcx8sjcO+cywK1L/Fv+uGllDuJYv3/vcC0R5O/Zlyx6OjuA7SbLLpXPBt6zQ2AW/1D tFARf2FfAvpgzMi1iuv4WTp4JygCWe6dudpsxYS+S0hRzt5khHTKyF4y9OOTMPMiAzNY +is+/vX0SoBajtsHjHwZ+wNnNFR04588jlJSL2wXCUeKCH+B3rm/HkCZ34mOShhFeYgQ KgVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=QJzIDg0bzUV21jV1K+KOzqxEkfNWmq+OI4TUw4OqEks=; b=ggkI/KAhfWBYGuxBoaobGfeuPktA+LVN6g1u3qp04Lpooezha24sdFK1ZBFfqZ75G7 xsafkPEl+CLa9kkO42H6DJXJ33Xbq2oxclcvh4bIZ8FCsOE+utQYxLyudsGzOCsA7Dfg fnroK9ZA4E4WL/VuSgzbaMfs58OCvZCI+1utbj66rRJ+U48yyYG3zoz34IAXLQ5VABTp LoAJmpHsvA+8VWv0xXDXs0nS7nCfgh3xaoPDXyizJCcjxj4hbOlbERNXQ5bMZ5pJtBHI UkIL5GH+W+EF6taUABz5qtRuuQlH4sIc2WfjkGJSSArX9B34FI7kFfpFKvvI5f7AAJ2I 7adA== X-Gm-Message-State: AA+aEWaRHDcohYv4tIKZtxX7nnpZcbY7GwBmN2aUsG9DKdVbNgUqm3Kg WKtH11AQEQhuQitl6dEB9xOYcioDrtc= X-Google-Smtp-Source: AFSGD/U8gzbQNZ5SjIhBvbq05f+CZ9OEQG2QU+PI49VGoUv+He8WGS/sUxUg6laSuyj04lHudtJnOQ== X-Received: by 2002:a17:906:7a4e:: with SMTP id i14-v6mr9586089ejo.16.1544445579804; Mon, 10 Dec 2018 04:39:39 -0800 (PST) Received: from localhost.localdomain ([84.203.68.105]) by smtp.gmail.com with ESMTPSA id e14sm3296949edb.79.2018.12.10.04.39.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 10 Dec 2018 04:39:39 -0800 (PST) From: Pete Batard To: edk2-devel@lists.01.org Date: Mon, 10 Dec 2018 12:38:47 +0000 Message-Id: <20181210123853.4864-15-pete@akeo.ie> X-Mailer: git-send-email 2.17.0.windows.1 In-Reply-To: <20181210123853.4864-1-pete@akeo.ie> References: <20181210123853.4864-1-pete@akeo.ie> Subject: [PATCH v2 edk2-platforms 14/20] Platform/Broadcom/RPi3: Add NV Storage driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 X-List-Received-Date: Mon, 10 Dec 2018 12:39:43 -0000 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Pete Batard --- Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c | 196 ++++ Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c | 118 +++ Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c | 984 ++++++++++++++++++++ Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h | 217 +++++ Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c | 334 +++++++ Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf | 93 ++ 6 files changed, 1942 insertions(+) diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c new file mode 100644 index 000000000000..961de586c78b --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FileIo.c @@ -0,0 +1,196 @@ +/** @file + * + * Copyright (c) 2018, Andrei Warkentin + * Copyright (c) 2007-2009, Intel Corporation. All rights reserved. + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + **/ + +#include "VarBlockService.h" + + +EFI_STATUS +FileWrite ( + IN EFI_FILE_PROTOCOL *File, + IN UINTN Offset, + IN UINTN Buffer, + IN UINTN Size + ) +{ + EFI_STATUS Status; + + Status = File->SetPosition (File, Offset); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + Status = File->Write (File, &Size, (VOID *) Buffer); + ASSERT_EFI_ERROR (Status); + } + return Status; +} + + +VOID +FileClose ( + IN EFI_FILE_PROTOCOL *File + ) +{ + File->Flush (File); + File->Close (File); +} + + +EFI_STATUS +FileOpen ( + IN EFI_DEVICE_PATH_PROTOCOL *Device, + IN CHAR16 *MappedFile, + OUT EFI_FILE_PROTOCOL **File, + IN UINT64 OpenMode + ) +{ + EFI_HANDLE Handle; + EFI_FILE_HANDLE Root; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_STATUS Status; + + *File = NULL; + + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + &Device, + &Handle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + Handle, + &gEfiSimpleFileSystemProtocolGuid, + (void **) &Volume + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the root directory of the volume + // + Root = NULL; + Status = Volume->OpenVolume ( + Volume, + &Root + ); + ASSERT_EFI_ERROR (Status); + ASSERT (Root != NULL); + + // + // Open file + // + Status = Root->Open ( + Root, + File, + MappedFile, + OpenMode, + 0 + ); + if (EFI_ERROR (Status)) { + *File = NULL; + } + + // + // Close the Root directory + // + Root->Close (Root); + return Status; +} + + +EFI_STATUS +CheckStore ( + IN EFI_HANDLE SimpleFileSystemHandle, + OUT EFI_DEVICE_PATH_PROTOCOL **Device + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_FILE_PROTOCOL *File; + + *Device = NULL; + Status = gBS->HandleProtocol ( + SimpleFileSystemHandle, + &gEfiBlockIoProtocolGuid, + (VOID*)&BlkIo + ); + + if (EFI_ERROR (Status)) { + goto ErrHandle; + } + if (!BlkIo->Media->MediaPresent) { + DEBUG ((DEBUG_ERROR, "FwhMappedFile: Media not present!\n")); + Status = EFI_NO_MEDIA; + goto ErrHandle; + } + if (BlkIo->Media->ReadOnly) { + DEBUG ((DEBUG_ERROR, "FwhMappedFile: Media is read-only!\n")); + Status = EFI_ACCESS_DENIED; + goto ErrHandle; + } + + Status = FileOpen (DevicePathFromHandle (SimpleFileSystemHandle), + mFvInstance->MappedFile, &File, + EFI_FILE_MODE_READ); + if (EFI_ERROR (Status)) { + goto ErrHandle; + } + + /* We found it! Maybe do more checks...? */ + + FileClose (File); + *Device = DuplicateDevicePath (DevicePathFromHandle (SimpleFileSystemHandle)); + + ASSERT (*Device != NULL); + +ErrHandle: + return Status; +} + + +EFI_STATUS +CheckStoreExists ( + IN EFI_DEVICE_PATH_PROTOCOL *Device + ) +{ + EFI_HANDLE Handle; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_STATUS Status; + + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + &Device, + &Handle + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + Handle, + &gEfiSimpleFileSystemProtocolGuid, + (void **) &Volume + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c new file mode 100644 index 000000000000..ddfd746b0eca --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/FvbInfo.c @@ -0,0 +1,118 @@ +/** @file + * + * Copyright (c) 2018, Andrei Warkentin + * Copyright (c) 2006-2014, Intel Corporation. All rights reserved. + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + **/ + +#include +#include +#include +#include + +typedef struct { + UINT64 FvLength; + EFI_FIRMWARE_VOLUME_HEADER FvbInfo; + // + // EFI_FV_BLOCK_MAP_ENTRY ExtraBlockMap[n];//n=0 + // + EFI_FV_BLOCK_MAP_ENTRY End[1]; +} EFI_FVB_MEDIA_INFO; + +EFI_FVB_MEDIA_INFO mPlatformFvbMediaInfo[] = { + // + // System NvStorage FVB + // + { + FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) + + FixedPcdGet32 (PcdNvStorageEventLogSize), + { + { + 0, + }, // ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) + + FixedPcdGet32 (PcdNvStorageEventLogSize), + EFI_FVH_SIGNATURE, + EFI_FVB2_MEMORY_MAPPED | + EFI_FVB2_READ_ENABLED_CAP | + EFI_FVB2_READ_STATUS | + EFI_FVB2_WRITE_ENABLED_CAP | + EFI_FVB2_WRITE_STATUS | + EFI_FVB2_ERASE_POLARITY | + EFI_FVB2_ALIGNMENT_16, + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, // CheckSum + 0, // ExtHeaderOffset + { + 0, + }, // Reserved[1] + 2, // Revision + { + { + (FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) + + FixedPcdGet32 (PcdNvStorageEventLogSize)) / + FixedPcdGet32 (PcdFirmwareBlockSize), + FixedPcdGet32 (PcdFirmwareBlockSize), + } + } // BlockMap[1] + }, + { + { + 0, + 0 + } + } // End[1] + } +}; + + +EFI_STATUS +GetFvbInfo ( + IN UINT64 FvLength, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +{ + STATIC BOOLEAN Checksummed = FALSE; + UINTN Index; + + if (!Checksummed) { + for (Index = 0; + Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO); + Index += 1) { + UINT16 Checksum; + mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = 0; + Checksum = CalculateCheckSum16 ( + (UINT16*) &mPlatformFvbMediaInfo[Index].FvbInfo, + mPlatformFvbMediaInfo[Index].FvbInfo.HeaderLength + ); + mPlatformFvbMediaInfo[Index].FvbInfo.Checksum = Checksum; + } + Checksummed = TRUE; + } + + for (Index = 0; + Index < sizeof (mPlatformFvbMediaInfo) / sizeof (EFI_FVB_MEDIA_INFO); + Index += 1) { + if (mPlatformFvbMediaInfo[Index].FvLength == FvLength) { + *FvbInfo = &mPlatformFvbMediaInfo[Index].FvbInfo; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c new file mode 100644 index 000000000000..7ff9e90c0207 --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.c @@ -0,0 +1,984 @@ +/** @file + * + * Copyright (c) 2018, Andrei Warkentin + * Copyright (c) 2006-2014, Intel Corporation. All rights reserved. + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + **/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "VarBlockService.h" + +#define EFI_FVB2_STATUS \ + (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS) + +EFI_FW_VOL_INSTANCE *mFvInstance; + +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) + } + }, + EfiMemoryMappedIO, + (EFI_PHYSICAL_ADDRESS) 0, + (EFI_PHYSICAL_ADDRESS) 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = { + { + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + { + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) + } + }, + { 0 } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { + NULL, + { + FvbProtocolGetAttributes, + FvbProtocolSetAttributes, + FvbProtocolGetPhysicalAddress, + FvbProtocolGetBlockSize, + FvbProtocolRead, + FvbProtocolWrite, + FvbProtocolEraseBlocks, + NULL + } +}; + + +EFI_STATUS +VarStoreWrite ( + IN UINTN Address, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + CopyMem ((VOID *) Address, Buffer, *NumBytes); + mFvInstance->Dirty = TRUE; + + return EFI_SUCCESS; +} + + +EFI_STATUS +VarStoreErase ( + IN UINTN Address, + IN UINTN LbaLength + ) +{ + SetMem ((VOID *)Address, LbaLength, 0xff); + mFvInstance->Dirty = TRUE; + + return EFI_SUCCESS; +} + + +EFI_STATUS +FvbGetVolumeAttributes ( + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + *Attributes = mFvInstance->VolumeHeader->Attributes; + return EFI_SUCCESS; +} + + +EFI_STATUS +FvbGetLbaAddress ( + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks + ) +/*++ + + Routine Description: + Retrieves the starting address of an LBA in an FV + + Arguments: + Lba - The logical block address + LbaAddress - On output, contains the physical starting address + of the Lba + LbaLength - On output, contains the length of the block + NumOfBlocks - A pointer to a caller allocated UINTN in which the + number of consecutive blocks starting with Lba is + returned. All blocks in this range have a size of + BlockSize + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + +--*/ +{ + UINT32 NumBlocks; + UINT32 BlockLength; + UINTN Offset; + EFI_LBA StartLba; + EFI_LBA NextLba; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + + StartLba = 0; + Offset = 0; + BlockMap = &(mFvInstance->VolumeHeader->BlockMap[0]); + + // + // Parse the blockmap of the FV to find which map entry the Lba belongs to. + // + while (TRUE) { + NumBlocks = BlockMap->NumBlocks; + BlockLength = BlockMap->Length; + + if (NumBlocks == 0 || BlockLength == 0) { + return EFI_INVALID_PARAMETER; + } + + NextLba = StartLba + NumBlocks; + + // + // The map entry found. + // + if (Lba >= StartLba && Lba < NextLba) { + Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength); + if (LbaAddress != NULL) { + *LbaAddress = mFvInstance->FvBase + Offset; + } + + if (LbaLength != NULL) { + *LbaLength = BlockLength; + } + + if (NumOfBlocks != NULL) { + *NumOfBlocks = (UINTN) (NextLba - Lba); + } + + return EFI_SUCCESS; + } + + StartLba = NextLba; + Offset = Offset + NumBlocks * BlockLength; + BlockMap++; + } +} + + +EFI_STATUS +FvbEraseBlock ( + IN EFI_LBA Lba + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Lba - The logical block index to be erased + +Returns: + EFI_SUCCESS - The erase request was successfully completed + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (&Attributes); + + if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Get the starting address of the block for erase. For debug reasons, + // LbaWriteAddress may not be the same as LbaAddress. + // + Status = FvbGetLbaAddress (Lba, &LbaAddress, &LbaLength, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + return VarStoreErase ( + LbaAddress, + LbaLength + ); +} + + +EFI_STATUS +FvbSetVolumeAttributes ( + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +/*++ + + Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + + Arguments: + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 + containing the desired firmware volume settings. + On successful return, it contains the new setting. + + Returns: + EFI_SUCCESS - Successfully returns + EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_FVB_ATTRIBUTES_2 OldAttributes; + EFI_FVB_ATTRIBUTES_2 *AttribPtr; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; + + AttribPtr = + (EFI_FVB_ATTRIBUTES_2 *) &(mFvInstance->VolumeHeader->Attributes); + OldAttributes = *AttribPtr; + Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP \ + ); + OldStatus = OldAttributes & EFI_FVB2_STATUS; + NewStatus = *Attributes & EFI_FVB2_STATUS; + + UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP | \ + EFI_FVB2_STICKY_WRITE | \ + EFI_FVB2_MEMORY_MAPPED | \ + EFI_FVB2_ERASE_POLARITY | \ + EFI_FVB2_READ_LOCK_CAP | \ + EFI_FVB2_WRITE_LOCK_CAP | \ + EFI_FVB2_ALIGNMENT; + + // + // Some attributes of FV is read only can *not* be set. + // + if ((OldAttributes & UnchangedAttributes) ^ + (*Attributes & UnchangedAttributes)) { + return EFI_INVALID_PARAMETER; + } + + // + // If firmware volume is locked, no status bit can be updated. + // + if (OldAttributes & EFI_FVB2_LOCK_STATUS) { + if (OldStatus ^ NewStatus) { + return EFI_ACCESS_DENIED; + } + } + + // + // Test read disable. + // + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test read enable. + // + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB2_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test write disable. + // + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test write enable. + // + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB2_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test lock. + // + if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { + if (NewStatus & EFI_FVB2_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); + *AttribPtr = (*AttribPtr) | NewStatus; + *Attributes = *AttribPtr; + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + *Address = mFvInstance->FvBase; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN CONST EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +/*++ + + Routine Description: + Retrieve the size of a logical block + + Arguments: + This - Calling context + Lba - Indicates which block to return the size for. + BlockSize - A pointer to a caller allocated UINTN in which + the size of the block is returned + NumOfBlocks - a pointer to a caller allocated UINTN in which the + number of consecutive blocks starting with Lba is + returned. All blocks in this range have a size of + BlockSize + + Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + +--*/ +{ + return FvbGetLbaAddress ( + Lba, + NULL, + BlockSize, + NumOfBlocks + ); +} + + +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +/*++ + + Routine Description: + Retrieves Volume attributes. No polarity translations are done. + + Arguments: + This - Calling context + Attributes - output buffer which contains attributes + + Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + return FvbGetVolumeAttributes (Attributes); +} + + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +/*++ + + Routine Description: + Sets Volume attributes. No polarity translations are done. + + Arguments: + This - Calling context + Attributes - output buffer which contains attributes + + Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + return FvbSetVolumeAttributes (Attributes); +} + + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL*This, + ... + ) +/*++ + + Routine Description: + + The EraseBlock() function erases one or more blocks as denoted by the + variable argument list. The entire parameter list of blocks must be + verified prior to erasing any blocks. If a block is requested that does + not exist within the associated firmware volume (it has a larger index than + the last block of the firmware volume), the EraseBlock() function must + return EFI_INVALID_PARAMETER without modifying the contents of the firmware + volume. + + Arguments: + This - Calling context + ... - Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + + Returns: + EFI_SUCCESS - The erase request was successfully completed + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written. Firmware device may have been + partially erased + +--*/ +{ + UINTN NumOfBlocks; + VA_LIST args; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_STATUS Status; + + NumOfBlocks = mFvInstance->NumOfBlocks; + VA_START (args, This); + + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINTN); + + if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) { + VA_END (args); + return EFI_INVALID_PARAMETER; + } + } while (1); + + VA_END (args); + + VA_START (args, This); + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINTN); + + while (NumOfLba > 0) { + Status = FvbEraseBlock (StartingLba); + if (EFI_ERROR (Status)) { + VA_END (args); + return Status; + } + + StartingLba++; + NumOfLba--; + } + + } while (1); + + VA_END (args); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + + Routine Description: + + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + Arguments: + This - Calling context + Lba - Block in which to begin write + Offset - Offset in the block at which to begin write + NumBytes - On input, indicates the requested write size. On + output, indicates the actual number of bytes + written + Buffer - Buffer containing source data for the write. + + Returns: + EFI_SUCCESS - The firmware volume was written successfully + EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes + actually written + EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be written + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + + // + // Check for invalid conditions. + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Lba, &LbaAddress, &LbaLength, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check if the FV is write enabled. + // + FvbGetVolumeAttributes (&Attributes); + + if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + // + // Perform boundary checks and adjust NumBytes. + // + if (Offset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + Offset)) { + *NumBytes = (UINT32) (LbaLength - Offset); + Status = EFI_BAD_BUFFER_SIZE; + } + + ReturnStatus = VarStoreWrite ( + LbaAddress + Offset, + NumBytes, + Buffer + ); + if (EFI_ERROR (ReturnStatus)) { + return ReturnStatus; + } + + return Status; +} + + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN CONST EFI_LBA Lba, + IN CONST UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + + Routine Description: + + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + Arguments: + This - Calling context + Lba - Block in which to begin Read + Offset - Offset in the block at which to begin Read + NumBytes - On input, indicates the requested write size. On + output, indicates the actual number of bytes Read + Buffer - Buffer containing source data for the Read. + + Returns: + EFI_SUCCESS - The firmware volume was read successfully and + contents are in Buffer + EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output, + NumBytes contains the total number of bytes + returned in Buffer + EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state + EFI_DEVICE_ERROR - The block device is not functioning correctly and + could not be read + EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Check for invalid conditions. + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Lba, &LbaAddress, &LbaLength, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check if the FV is read enabled. + // + FvbGetVolumeAttributes (&Attributes); + + if ((Attributes & EFI_FVB2_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + // + // Perform boundary checks and adjust NumBytes. + // + if (Offset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + Offset)) { + *NumBytes = (UINT32) (LbaLength - Offset); + Status = EFI_BAD_BUFFER_SIZE; + } + + CopyMem (Buffer, (VOID *) (LbaAddress + Offset), (UINTN) *NumBytes); + + return Status; +} + + +EFI_STATUS +ValidateFvHeader ( + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader + ) +/*++ + + Routine Description: + Check the integrity of firmware volume header + + Arguments: + FwVolHeader - A pointer to a firmware volume header + + Returns: + EFI_SUCCESS - The firmware volume is consistent + EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an + FV + +--*/ +{ + UINT16 Checksum; + + // + // Verify the header revision, header signature, length + // Length of FvBlock cannot be 2**64-1 + // HeaderLength cannot be an odd number. + // + if ((FwVolHeader->Revision != EFI_FVH_REVISION) || + (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength == ((UINTN) -1)) || + ((FwVolHeader->HeaderLength & 0x01) != 0) + ) { + return EFI_NOT_FOUND; + } + + // + // Verify the header checksum. + // + + Checksum = CalculateSum16 ((UINT16 *) FwVolHeader, + FwVolHeader->HeaderLength); + if (Checksum != 0) { + UINT16 Expected; + + Expected = + (UINT16) (((UINTN) FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff); + + DEBUG ((DEBUG_INFO, "FV@%p Checksum is 0x%x, expected 0x%x\n", + FwVolHeader, FwVolHeader->Checksum, Expected)); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +FvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + + Routine Description: + This function does common initialization for FVB services + + Arguments: + + Returns: + +--*/ +{ + EFI_STATUS Status; + UINT32 BufferSize; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + UINT32 MaxLbaSize; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINTN Length; + UINTN NumOfBlocks; + RETURN_STATUS PcdStatus; + UINTN StartOffset; + + BaseAddress = PcdGet32 (PcdNvStorageVariableBase); + Length = (FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) + + FixedPcdGet32 (PcdNvStorageEventLogSize)); + StartOffset = BaseAddress - FixedPcdGet64 (PcdFdBaseAddress); + + BufferSize = sizeof (EFI_FW_VOL_INSTANCE); + + mFvInstance = AllocateRuntimeZeroPool (BufferSize); + if (mFvInstance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mFvInstance->FvBase = (UINTN) BaseAddress; + mFvInstance->FvLength = (UINTN) Length; + mFvInstance->Offset = StartOffset; + /* + * Should I parse config.txt instead and find the real name? + */ + mFvInstance->MappedFile = L"RPI_EFI.FD"; + + Status = ValidateFvHeader (mFvInstance->VolumeHeader); + if (!EFI_ERROR (Status)) { + if (mFvInstance->VolumeHeader->FvLength != Length || + mFvInstance->VolumeHeader->BlockMap[0].Length != + PcdGet32 (PcdFirmwareBlockSize)) { + Status = EFI_VOLUME_CORRUPTED; + } + } + if (EFI_ERROR (Status)) { + EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader; + UINTN WriteLength; + + DEBUG ((DEBUG_INFO, + "Variable FV header is not valid. It will be reinitialized.\n")); + + // + // Get FvbInfo + // + Status = GetFvbInfo (Length, &GoodFwVolHeader); + ASSERT_EFI_ERROR (Status); + + // + // Erase all the blocks + // + Status = VarStoreErase ((UINTN) mFvInstance->FvBase, + mFvInstance->FvLength); + ASSERT_EFI_ERROR (Status); + // + // Write good FV header + // + WriteLength = GoodFwVolHeader->HeaderLength; + Status = VarStoreWrite((UINTN) mFvInstance->FvBase, + &WriteLength, + (UINT8*) GoodFwVolHeader); + ASSERT_EFI_ERROR (Status); + ASSERT (WriteLength == GoodFwVolHeader->HeaderLength); + + Status = ValidateFvHeader (mFvInstance->VolumeHeader); + ASSERT_EFI_ERROR (Status); + } + + MaxLbaSize = 0; + NumOfBlocks = 0; + for (PtrBlockMapEntry = mFvInstance->VolumeHeader->BlockMap; + PtrBlockMapEntry->NumBlocks != 0; + PtrBlockMapEntry++) { + // + // Get the maximum size of a block. + // + if (MaxLbaSize < PtrBlockMapEntry->Length) { + MaxLbaSize = PtrBlockMapEntry->Length; + } + + NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks; + } + + // + // The total number of blocks in the FV. + // + mFvInstance->NumOfBlocks = NumOfBlocks; + + // + // Add a FVB Protocol Instance + // + FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE)); + ASSERT (FvbDevice != NULL); + CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); + + // + // Set up the devicepath + // + if (mFvInstance->VolumeHeader->ExtHeaderOffset == 0) { + FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath; + + // + // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH + // + FvMemmapDevicePath = AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), + &mFvMemmapDevicePathTemplate); + FvMemmapDevicePath->MemMapDevPath.StartingAddress = mFvInstance->FvBase; + FvMemmapDevicePath->MemMapDevPath.EndingAddress = mFvInstance->FvBase + + mFvInstance->FvLength - 1; + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePath; + } else { + FV_PIWG_DEVICE_PATH *FvPiwgDevicePath; + + FvPiwgDevicePath = AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), + &mFvPIWGDevicePathTemplate); + CopyGuid ( + &FvPiwgDevicePath->FvDevPath.FvName, + (GUID *)(UINTN)(mFvInstance->FvBase + + mFvInstance->VolumeHeader->ExtHeaderOffset) + ); + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath; + } + + // + // Module type specific hook. + // + InstallProtocolInterfaces (FvbDevice); + + // + // Set several PCD values to point to flash. + // + PcdStatus = PcdSet64S ( + PcdFlashNvStorageVariableBase64, + (UINTN) PcdGet32 (PcdNvStorageVariableBase) + ); + ASSERT_RETURN_ERROR (PcdStatus); + PcdStatus = PcdSet32S ( + PcdFlashNvStorageFtwWorkingBase, + PcdGet32 (PcdNvStorageFtwWorkingBase) + ); + ASSERT_RETURN_ERROR (PcdStatus); + PcdStatus = PcdSet32S ( + PcdFlashNvStorageFtwSpareBase, + PcdGet32 (PcdNvStorageFtwSpareBase) + ); + ASSERT_RETURN_ERROR (PcdStatus); + + InstallFSNotifyHandler (); + InstallDumpVarEventHandlers (); + InstallVirtualAddressChangeHandler (); + + return EFI_SUCCESS; +} diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h new file mode 100644 index 000000000000..3596c4ac55b9 --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockService.h @@ -0,0 +1,217 @@ +/** @file + * + * Copyright (c) 2018, Andrei Warkentin + * Copyright (c) 2007-2009, Intel Corporation. All rights reserved. + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + **/ + +#ifndef _FW_BLOCK_SERVICE_H +#define _FW_BLOCK_SERVICE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + union { + UINTN FvBase; + EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader; + }; + UINTN FvLength; + UINTN Offset; + UINTN NumOfBlocks; + EFI_DEVICE_PATH_PROTOCOL *Device; + CHAR16 *MappedFile; + BOOLEAN Dirty; +} EFI_FW_VOL_INSTANCE; + +extern EFI_FW_VOL_INSTANCE *mFvInstance; + +typedef struct { + MEDIA_FW_VOL_DEVICE_PATH FvDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_PIWG_DEVICE_PATH; + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_MEMMAP_DEVICE_PATH; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; +} EFI_FW_VOL_BLOCK_DEVICE; + +EFI_STATUS +GetFvbInfo ( + IN UINT64 FvLength, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ); + +EFI_STATUS +FvbSetVolumeAttributes ( + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +FvbGetVolumeAttributes ( + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +FvbGetPhysicalAddress ( + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +VOID +EFIAPI +FvbClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +FvbGetLbaAddress ( + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks + ); + +// +// Protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN CONST EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ); + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN CONST EFI_LBA Lba, + IN CONST UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ); + +VOID +InstallProtocolInterfaces ( + IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice + ); + +VOID +InstallVirtualAddressChangeHandler ( + VOID + ); + +VOID +InstallFSNotifyHandler ( + VOID + ); + +VOID +InstallDumpVarEventHandlers ( + VOID +); + +EFI_STATUS +FileWrite ( + IN EFI_FILE_PROTOCOL *File, + IN UINTN Offset, + IN UINTN Buffer, + IN UINTN Size + ); + +EFI_STATUS +CheckStore ( + IN EFI_HANDLE SimpleFileSystemHandle, + OUT EFI_DEVICE_PATH_PROTOCOL **Device + ); + +EFI_STATUS +CheckStoreExists ( + IN EFI_DEVICE_PATH_PROTOCOL *Device + ); + +EFI_STATUS +FileOpen ( + IN EFI_DEVICE_PATH_PROTOCOL *Device, + IN CHAR16 *MappedFile, + OUT EFI_FILE_PROTOCOL **File, + IN UINT64 OpenMode + ); + +VOID +FileClose ( + IN EFI_FILE_PROTOCOL *File + ); + +#endif diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c new file mode 100644 index 000000000000..8c4db3dcfd59 --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c @@ -0,0 +1,334 @@ +/** @file + * + * Copyright (c) 2018, Andrei Warkentin + * Copyright (C) 2015, Red Hat, Inc. + * Copyright (c) 2006-2014, Intel Corporation. All rights reserved. + * + * This program and the accompanying materials + * are licensed and made available under the terms and conditions of the BSD License + * which accompanies this distribution. The full text of the license may be found at + * http://opensource.org/licenses/bsd-license.php + * + * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + * + **/ + +#include "VarBlockService.h" + +VOID *mSFSRegistration; + + +VOID +InstallProtocolInterfaces ( + IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice + ) +{ + EFI_STATUS Status; + EFI_HANDLE FwbHandle; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; + + // + // Find a handle with a matching device path that has supports FW Block + // protocol. + // + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, + &FvbDevice->DevicePath, &FwbHandle); + if (EFI_ERROR (Status)) { + // + // LocateDevicePath fails so install a new interface and device path. + // + FwbHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &FvbDevice->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, + FvbDevice->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + } else if (IsDevicePathEnd (FvbDevice->DevicePath)) { + // + // Device already exists, so reinstall the FVB protocol + // + Status = gBS->HandleProtocol ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID**)&OldFwbInterface + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->ReinstallProtocolInterface ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + OldFwbInterface, + &FvbDevice->FwVolBlockInstance + ); + ASSERT_EFI_ERROR (Status); + } else { + // + // There was a FVB protocol on an End Device Path node + // + ASSERT (FALSE); + } +} + + +STATIC +VOID +EFIAPI +FvbVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + + Fixup internal data so that EFI can be called in virtual mode. + + Arguments: + + (Standard EFI notify event - EFI_EVENT_NOTIFY) + + Returns: + + None + +--*/ +{ + EfiConvertPointer (0x0, (VOID **) &mFvInstance->FvBase); + EfiConvertPointer (0x0, (VOID **) &mFvInstance->VolumeHeader); + EfiConvertPointer (0x0, (VOID **) &mFvInstance); +} + + +VOID +InstallVirtualAddressChangeHandler ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT VirtualAddressChangeEvent; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + FvbVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &VirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); +} + + +STATIC +EFI_STATUS +DoDump( + IN EFI_DEVICE_PATH_PROTOCOL *Device + ) +{ + EFI_STATUS Status; + EFI_FILE_PROTOCOL *File; + + Status = FileOpen (Device, + mFvInstance->MappedFile, + &File, + EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_READ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FileWrite (File, + mFvInstance->Offset, + mFvInstance->FvBase, + mFvInstance->FvLength); + FileClose (File); + return Status; +} + + +STATIC +VOID +EFIAPI +DumpVars( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + if (mFvInstance->Device == NULL) { + DEBUG((DEBUG_INFO, "Variable store not found?\n")); + return; + } + + if (!mFvInstance->Dirty) { + DEBUG((DEBUG_INFO, "Variables not dirty, not dumping!\n")); + return; + } + + Status = DoDump (mFvInstance->Device); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "Couldn't dump '%s'\n", + mFvInstance->MappedFile)); + ASSERT_EFI_ERROR(Status); + return; + } + + DEBUG((DEBUG_INFO, "Variables dumped!\n")); + mFvInstance->Dirty = FALSE; +} + + +VOID +ReadyToBootHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_EVENT ImageInstallEvent; + VOID *ImageRegistration; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DumpVars, + NULL, + &ImageInstallEvent + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify ( + &gEfiLoadedImageProtocolGuid, + ImageInstallEvent, + &ImageRegistration + ); + ASSERT_EFI_ERROR (Status); + + DumpVars(NULL, NULL); + Status = gBS->CloseEvent(Event); + ASSERT_EFI_ERROR (Status); +} + + +VOID +InstallDumpVarEventHandlers ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT ResetEvent; + EFI_EVENT ReadyToBootEvent; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + DumpVars, + NULL, + &gRaspberryPiEventResetGuid, + &ResetEvent + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + ReadyToBootHandler, + NULL, + &gEfiEventReadyToBootGuid, + &ReadyToBootEvent + ); + ASSERT_EFI_ERROR (Status); +} + + +VOID +EFIAPI +OnSimpleFileSystemInstall ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN HandleSize; + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *Device; + + if ((mFvInstance->Device != NULL) && + !EFI_ERROR (CheckStoreExists (mFvInstance->Device)) + ) { + // + // We've already found the variable store before, + // and that device is not removed from the ssystem. + // + return; + } + + while (TRUE) { + HandleSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle ( + ByRegisterNotify, + NULL, + mSFSRegistration, + &HandleSize, + &Handle + ); + if (Status == EFI_NOT_FOUND) { + break; + } + + ASSERT_EFI_ERROR (Status); + + Status = CheckStore (Handle, &Device); + if (EFI_ERROR (Status)) { + continue; + } + + Status = DoDump (Device); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "Couldn't update '%s'\n", + mFvInstance->MappedFile)); + ASSERT_EFI_ERROR(Status); + continue; + } + + if (mFvInstance->Device != NULL) { + gBS->FreePool (mFvInstance->Device); + } + + DEBUG((DEBUG_INFO, "Found variable store!\n")); + mFvInstance->Device = Device; + break; + } +} + + +VOID +InstallFSNotifyHandler ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnSimpleFileSystemInstall, + NULL, + &Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify ( + &gEfiSimpleFileSystemProtocolGuid, + Event, + &mSFSRegistration + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf new file mode 100644 index 000000000000..95ec0f8a64e9 --- /dev/null +++ b/Platform/Broadcom/Bcm283x/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf @@ -0,0 +1,93 @@ +#/** @file +# +# Support for the FS-backed "flash" device. +# The trick is to keep it inside the RPI firmware file itself... +# +# Copyright (c) 2018, Andrei Warkentin +# Copyright (c) 2006-2013, Intel Corporation. All rights reserved. +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR +# IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VarBlockServiceDxe + FILE_GUID = 733cbac2-b23f-4b92-bc8e-fb01ce5907b7 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FvbInitialize + +# +# The following information is for reference only and not required by the build +# tools. +# +# VALID_ARCHITECTURES = AARCH64 +# + +[Sources] + FvbInfo.c + VarBlockService.c + VarBlockServiceDxe.c + FileIo.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/Broadcom/Bcm283x/RaspberryPiPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + DxeServicesTableLib + MemoryAllocationLib + PcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeLib + +[Guids] + gEfiEventVirtualAddressChangeGuid + gRaspberryPiEventResetGuid + gEfiEventReadyToBootGuid + +[Protocols] + gEfiSimpleFileSystemProtocolGuid + gEfiLoadedImageProtocolGuid + gEfiBlockIoProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_PRODUCED + gEfiDevicePathProtocolGuid # PROTOCOL SOMETIMES_PRODUCED + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + gRaspberryPiTokenSpaceGuid.PcdNvStorageVariableBase + gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwWorkingBase + gRaspberryPiTokenSpaceGuid.PcdNvStorageFtwSpareBase + gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogSize + gRaspberryPiTokenSpaceGuid.PcdFirmwareBlockSize + gArmTokenSpaceGuid.PcdFdBaseAddress + gArmTokenSpaceGuid.PcdFdSize + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gRaspberryPiTokenSpaceGuid.PcdNvStorageEventLogBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + +[FeaturePcd] + +[Depex] + TRUE -- 2.17.0.windows.1