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 EF2F72194D387 for ; Tue, 5 Feb 2019 08:26:19 -0800 (PST) Received: by mail-ed1-x543.google.com with SMTP id h15so3365490edb.4 for ; Tue, 05 Feb 2019 08:26:19 -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=1waY1JbmJdmFJyxzWGti96Kn2bY8RGQAZiPR+5+/fFQ=; b=IvqOIJdM/m/BZssu2OmeQK5uQ27ITfrIUkhT2f170bPKeOZgqyxnFeL4PbhYKgaSWe JTpeJhdp42o+ilpCGiutW5gGoWlRqsPqiiNVIicKzxryVQLlp1/VM0Bv/PdeqSiBL2tp lIs/LB9MKiu152ZEHVkdxl9qAjFikr+MfOp3M/X5Gky+Q6dgpqzWCfOWm7CePJOtmC7V SiMl0Fi/mmdVf0PofWllRML1ZPenW8dNgTmkSUWYkMJJ7KwZXkT7K5DUqdblCoGKtbpk 7IVs2NTb2yEwPCpwSj/Bydft2qbqphAbGellVbNq33TQylWomPaLvGWdBIlo0C1cNXnF mEcA== 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=1waY1JbmJdmFJyxzWGti96Kn2bY8RGQAZiPR+5+/fFQ=; b=NYtB7TAV9T5NbKhd8+5PB9+iOu/D7zMAPBDB8bXkr9UZpkoOTQHl/d5uYiXl6KBCuX Ypn/8SxzympmSokspXjEV/tuA0qk44WcilAMJtilggAl9Q276U1Ac8pLR1UiOzmR7aul OS4lo6QaD6Qu4p+0kWFvQ8JCrORdOevsuIZtYqODAddUoJws2c+JILIWGK6WztM+qQ+Z 6DGEBe4OBhNZIg5YiMubsXTCi7P3Dd+IE6ev76YxzOAoqfXaPHIUrKPsfeSDUIlqpvHI ojqMQH9zPpdqaIPQNgEOGNMWx/YtzZeAtg74McCGVLQSIAdeSwwEPExvuxsmTZ/Zd4qH 5tvQ== X-Gm-Message-State: AHQUAubIT7p1uMlMDKXvaDgQyCbBZRyC1+gBNmmp3/LmeNPLjNIucW5j zDD9DIKGwUnMDqBfhKyJrG82/11TFgQ= X-Google-Smtp-Source: AHgI3Ib+mE5MeuyTJc4wGAzrTwtzKGSa2EqXQ4wfhO9DIdKFIQj8lJCo5XJnWNMfVr8AhchRoHBuJw== X-Received: by 2002:a50:9226:: with SMTP id i35mr4771141eda.8.1549383977210; Tue, 05 Feb 2019 08:26:17 -0800 (PST) Received: from localhost.localdomain ([84.203.58.139]) by smtp.gmail.com with ESMTPSA id j16sm3191430ejq.59.2019.02.05.08.26.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 05 Feb 2019 08:26:16 -0800 (PST) From: Pete Batard To: edk2-devel@lists.01.org Date: Tue, 5 Feb 2019 16:25:26 +0000 Message-Id: <20190205162537.6472-12-pete@akeo.ie> X-Mailer: git-send-email 2.17.0.windows.1 In-Reply-To: <20190205162537.6472-1-pete@akeo.ie> References: <20190205162537.6472-1-pete@akeo.ie> Subject: [PATCH v5 edk2-platforms 11/22] Platform/RaspberryPi/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: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 X-List-Received-Date: Tue, 05 Feb 2019 16:26:20 -0000 Since the Raspberry Pi doesn't have a NVRAM, this driver is used to store non-volatile user configuration settings into the firmware volume itself. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Pete Batard --- Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FileIo.c | 196 ++++ Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FvbInfo.c | 115 +++ Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.c | 971 ++++++++++++++++++++ Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.h | 217 +++++ Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c | 331 +++++++ Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf | 93 ++ 6 files changed, 1923 insertions(+) diff --git a/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FileIo.c b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FileIo.c new file mode 100644 index 000000000000..0e8cd516f65e --- /dev/null +++ b/Platform/RaspberryPi/RPi3/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/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FvbInfo.c b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FvbInfo.c new file mode 100644 index 000000000000..14341def4ccd --- /dev/null +++ b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/FvbInfo.c @@ -0,0 +1,115 @@ +/** @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 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/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.c b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.c new file mode 100644 index 000000000000..7ff5bd7a74cc --- /dev/null +++ b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.c @@ -0,0 +1,971 @@ +/** @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/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.h b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockService.h new file mode 100644 index 000000000000..3596c4ac55b9 --- /dev/null +++ b/Platform/RaspberryPi/RPi3/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/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c new file mode 100644 index 000000000000..3c6ede74c21c --- /dev/null +++ b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.c @@ -0,0 +1,331 @@ +/** @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/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf b/Platform/RaspberryPi/RPi3/Drivers/VarBlockServiceDxe/VarBlockServiceDxe.inf new file mode 100644 index 000000000000..f440e4eee8f3 --- /dev/null +++ b/Platform/RaspberryPi/RPi3/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 = 0x0001001A + 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/RaspberryPi/RPi3/RPi3.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