From 9071550e8697ed9df3d24b369bd30e3f0e190d1f Mon Sep 17 00:00:00 2001 From: klu2 Date: Fri, 18 Apr 2008 03:09:54 +0000 Subject: [PATCH] Add missing module for duet package. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5088 6f19259b-4bc3-4df7-8a09-765794883524 --- DuetPkg/EfiLdr/Debug.c | 93 + DuetPkg/EfiLdr/Debug.h | 49 + DuetPkg/EfiLdr/EfiLdr.h | 115 ++ DuetPkg/EfiLdr/EfiLdr.inf | 58 + DuetPkg/EfiLdr/EfiLdrHandoff.h | 56 + DuetPkg/EfiLdr/EfiLoader.c | 266 +++ DuetPkg/EfiLdr/Ia32/EfiLdr.inf | 27 + DuetPkg/EfiLdr/Ia32/Makefile | 183 ++ DuetPkg/EfiLdr/PeLoader.c | 641 +++++++ DuetPkg/EfiLdr/PeLoader.h | 42 + DuetPkg/EfiLdr/Support.c | 237 +++ DuetPkg/EfiLdr/Support.h | 50 + DuetPkg/EfiLdr/X64/EfiLdr.inf | 27 + DuetPkg/EfiLdr/X64/Makefile | 186 ++ DuetPkg/EfiLdr/efildr.c | 28 + DuetPkg/FSVariable/FSVariable.c | 1356 +++++++++++++++ DuetPkg/FSVariable/FSVariable.dxs | 26 + DuetPkg/FSVariable/FSVariable.h | 162 ++ DuetPkg/FSVariable/FSVariable.inf | 69 + DuetPkg/FSVariable/FileStorage.c | 441 +++++ DuetPkg/FSVariable/MemStorage.c | 135 ++ DuetPkg/FSVariable/VariableStorage.h | 111 ++ DuetPkg/FvbRuntimeService/DUETFwh.dxs | 26 + DuetPkg/FvbRuntimeService/DUETFwh.inf | 62 + DuetPkg/FvbRuntimeService/FWBlockService.c | 1822 ++++++++++++++++++++ DuetPkg/FvbRuntimeService/FileIo.c | 210 +++ DuetPkg/FvbRuntimeService/FileIo.h | 58 + DuetPkg/FvbRuntimeService/FvbInfo.c | 121 ++ DuetPkg/FvbRuntimeService/FwBlockService.h | 348 ++++ 29 files changed, 7005 insertions(+) create mode 100644 DuetPkg/EfiLdr/Debug.c create mode 100644 DuetPkg/EfiLdr/Debug.h create mode 100644 DuetPkg/EfiLdr/EfiLdr.h create mode 100644 DuetPkg/EfiLdr/EfiLdr.inf create mode 100644 DuetPkg/EfiLdr/EfiLdrHandoff.h create mode 100644 DuetPkg/EfiLdr/EfiLoader.c create mode 100644 DuetPkg/EfiLdr/Ia32/EfiLdr.inf create mode 100644 DuetPkg/EfiLdr/Ia32/Makefile create mode 100644 DuetPkg/EfiLdr/PeLoader.c create mode 100644 DuetPkg/EfiLdr/PeLoader.h create mode 100644 DuetPkg/EfiLdr/Support.c create mode 100644 DuetPkg/EfiLdr/Support.h create mode 100644 DuetPkg/EfiLdr/X64/EfiLdr.inf create mode 100644 DuetPkg/EfiLdr/X64/Makefile create mode 100644 DuetPkg/EfiLdr/efildr.c create mode 100644 DuetPkg/FSVariable/FSVariable.c create mode 100644 DuetPkg/FSVariable/FSVariable.dxs create mode 100644 DuetPkg/FSVariable/FSVariable.h create mode 100644 DuetPkg/FSVariable/FSVariable.inf create mode 100644 DuetPkg/FSVariable/FileStorage.c create mode 100644 DuetPkg/FSVariable/MemStorage.c create mode 100644 DuetPkg/FSVariable/VariableStorage.h create mode 100644 DuetPkg/FvbRuntimeService/DUETFwh.dxs create mode 100644 DuetPkg/FvbRuntimeService/DUETFwh.inf create mode 100644 DuetPkg/FvbRuntimeService/FWBlockService.c create mode 100644 DuetPkg/FvbRuntimeService/FileIo.c create mode 100644 DuetPkg/FvbRuntimeService/FileIo.h create mode 100644 DuetPkg/FvbRuntimeService/FvbInfo.c create mode 100644 DuetPkg/FvbRuntimeService/FwBlockService.h diff --git a/DuetPkg/EfiLdr/Debug.c b/DuetPkg/EfiLdr/Debug.c new file mode 100644 index 0000000000..2cc8c73a1e --- /dev/null +++ b/DuetPkg/EfiLdr/Debug.c @@ -0,0 +1,93 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + Debug.c + +Abstract: + +Revision History: + +--*/ +#include "EfiLdr.h" +#include "Debug.h" + +UINT8 *mCursor; +UINT8 mHeaderIndex = 10; + +VOID +PrintHeader ( + CHAR8 Char + ) +{ + *(UINT8 *)(UINTN)(0x000b8000 + mHeaderIndex) = Char; + mHeaderIndex += 2; +} + +VOID +ClearScreen ( + VOID + ) +{ + UINT32 Index; + + mCursor = (UINT8 *)(UINTN)(0x000b8000 + 160); + for (Index = 0; Index < 80 * 49; Index++) { + *mCursor = ' '; + mCursor += 2; + } + mCursor = (UINT8 *)(UINTN)(0x000b8000 + 160); +} + +VOID +PrintValue64 ( + UINT64 Value + ) +{ + PrintValue ((UINT32) RShiftU64 (Value, 32)); + PrintValue ((UINT32) Value); +} + +VOID +PrintValue ( + UINT32 Value + ) +{ + UINT32 Index; + UINT8 Char; + + for (Index = 0; Index < 8; Index++) { + Char = (UINT8)((Value >> ((7 - Index) * 4)) & 0x0f) + '0'; + if (Char > '9') { + Char = Char - '0' - 10 + 'A'; + } + *mCursor = Char; + mCursor += 2; + } +} + +VOID +PrintString ( + UINT8 *String + ) +{ + UINT32 Index; + + for (Index = 0; String[Index] != 0; Index++) { + if (String[Index] == '\n') { + mCursor = (UINT8 *)(UINTN)(0xb8000 + (((((UINTN)mCursor - 0xb8000) + 160) / 160) * 160)); + } else { + *mCursor = String[Index]; + mCursor += 2; + } + } +} + diff --git a/DuetPkg/EfiLdr/Debug.h b/DuetPkg/EfiLdr/Debug.h new file mode 100644 index 0000000000..9939109e91 --- /dev/null +++ b/DuetPkg/EfiLdr/Debug.h @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + Debug.h + +Abstract: + +Revision History: + +--*/ + +#ifndef _EFILDR_DEBUG_H_ +#define _EFILDR_DEBUG_H_ + +VOID +PrintHeader ( + CHAR8 Char + ); + +VOID +PrintValue ( + UINT32 Value + ); + +VOID +PrintValue64 ( + UINT64 Value + ); + +VOID +PrintString ( + UINT8 *String + ); + +VOID +ClearScreen ( + VOID + ); + +#endif diff --git a/DuetPkg/EfiLdr/EfiLdr.h b/DuetPkg/EfiLdr/EfiLdr.h new file mode 100644 index 0000000000..b1d0e1c272 --- /dev/null +++ b/DuetPkg/EfiLdr/EfiLdr.h @@ -0,0 +1,115 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + EfiLdr.c + +Abstract: + +Revision History: + +--*/ + +#ifndef _DUET_EFI_LOADER_H_ +#define _DUET_EFI_LOADER_H_ + +#include "FrameworkDxe.h" +#include "Uefi.h" +#include "EfiLdrHandoff.h" + +#include +#include +#include +#include +#include + +#define INT15_E820_AddressRangeMemory 1 +#define INT15_E820_AddressRangeReserved 2 +#define INT15_E820_AddressRangeACPI 3 +#define INT15_E820_AddressRangeNVS 4 + +#define EFI_FIRMWARE_BASE_ADDRESS 0x00200000 + +#define EFI_DECOMPRESSED_BUFFER_ADDRESS 0x00600000 + +#define EFI_MAX_MEMORY_DESCRIPTORS 64 + +#define LOADED_IMAGE_SIGNATURE EFI_SIGNATURE_32('l','d','r','i') + +typedef struct { + UINTN Signature; + CHAR16 *Name; // Displayable name + UINTN Type; + + BOOLEAN Started; // If entrypoint has been called + VOID *StartImageContext; + + EFI_IMAGE_ENTRY_POINT EntryPoint; // The image's entry point + EFI_LOADED_IMAGE_PROTOCOL Info; // loaded image protocol + + // + EFI_PHYSICAL_ADDRESS ImageBasePage; // Location in memory + UINTN NoPages; // Number of pages + UINT8 *ImageBase; // As a char pointer + UINT8 *ImageEof; // End of memory image + + // relocate info + UINT8 *ImageAdjust; // Bias for reloc calculations + UINTN StackAddress; + UINT8 *FixupData; // Original fixup data +} EFILDR_LOADED_IMAGE; + +#pragma pack(4) +typedef struct { + UINT64 BaseAddress; + UINT64 Length; + UINT32 Type; +} BIOS_MEMORY_MAP_ENTRY; +#pragma pack() + +typedef struct { + UINT32 MemoryMapSize; + BIOS_MEMORY_MAP_ENTRY MemoryMapEntry[1]; +} BIOS_MEMORY_MAP; + +EFI_STATUS +EFIAPI +UefiDecompressGetInfo ( + IN EFI_TIANO_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +EFI_STATUS +EFIAPI +TianoDecompress ( + IN EFI_TIANO_DECOMPRESS_PROTOCOL *This, + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +EFILDR_LOADED_IMAGE DxeCoreImage; +EFILDR_LOADED_IMAGE DxeIplImage; + +typedef +VOID +(* EFI_MAIN_ENTRYPOINT) ( + IN EFILDRHANDOFF *Handoff + ) +; + +#endif //_DUET_EFI_LOADER_H_ \ No newline at end of file diff --git a/DuetPkg/EfiLdr/EfiLdr.inf b/DuetPkg/EfiLdr/EfiLdr.inf new file mode 100644 index 0000000000..d829ca2479 --- /dev/null +++ b/DuetPkg/EfiLdr/EfiLdr.inf @@ -0,0 +1,58 @@ +#/*++ +# +# Copyright (c) 2006, 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. +# +# Module Name: +# EfiLdr.inf +# +# Abstract: +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EfiLoader + FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + #MODULE_TYPE = USER_DEFINED + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + ENTRY_POINT = EfiLoader + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiApplicationEntryPoint + BaseUefiTianoDecompressLib + +[Sources.common] + Debug.h + PeLoader.h + Support.h + EfiLdrHandoff.h + EfiLdr.h + EfiLoader.c + Debug.c + PeLoader.c + Support.c + +[BuildOptions.common] + #MSFT:*_*_IA32_DLINK_FLAGS = /out:"$(BIN_DIR)\SecMain.exe" /base:0x10000000 /pdb:"$(BIN_DIR)\SecMain.pdb" /LIBPATH:"$(VCINSTALLDIR)\Lib" /LIBPATH:"$(VCINSTALLDIR)\PlatformSdk\Lib" /NOLOGO /SUBSYSTEM:CONSOLE /NODEFAULTLIB /IGNORE:4086 /MAP /OPT:REF /DEBUG /MACHINE:I386 /LTCG Kernel32.lib MSVCRTD.lib Gdi32.lib User32.lib Winmm.lib + MSFT:*_*_IA32_CC_FLAGS = /nologo /W4 /WX /Gy /c /D UNICODE /Od /FI$(DEST_DIR_DEBUG)/AutoGen.h /EHs-c- /GF /Gs8192 /Zi /Gm /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE + MSFT:*_*_IA32_PP_FLAGS = /nologo /E /TC /FI$(DEST_DIR_DEBUG)/AutoGen.h + MSFT:*_*_IA32_ASM_FLAGS = /nologo /W3 /WX /c /coff /Cx /Zd /W0 /Zi + MSFT:*_*_IA32_ASMLINK_FLAGS = /link /nologo /tiny diff --git a/DuetPkg/EfiLdr/EfiLdrHandoff.h b/DuetPkg/EfiLdr/EfiLdrHandoff.h new file mode 100644 index 0000000000..786b6cb828 --- /dev/null +++ b/DuetPkg/EfiLdr/EfiLdrHandoff.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + EfiLdrHandoff.h + +Abstract: + +Revision History: + +--*/ + +#ifndef _EFILDR_HANDOFF_H_ +#define _EFILDR_HANDOFF_H_ + +#define EFILDR_BASE_SEGMENT 0x2000 +#define EFILDR_LOAD_ADDRESS (EFILDR_BASE_SEGMENT << 4) +#define EFILDR_HEADER_ADDRESS (EFILDR_LOAD_ADDRESS+0x2000) + +#define EFILDR_CB_VA 0x00 + +typedef struct _EFILDRHANDOFF { + UINTN MemDescCount; + EFI_MEMORY_DESCRIPTOR *MemDesc; + VOID *BfvBase; + UINTN BfvSize; + VOID *DxeIplImageBase; + UINTN DxeIplImageSize; + VOID *DxeCoreImageBase; + UINTN DxeCoreImageSize; + VOID *DxeCoreEntryPoint; +} EFILDRHANDOFF; + +typedef struct { + UINT32 CheckSum; + UINT32 Offset; + UINT32 Length; + UINT8 FileName[52]; +} EFILDR_IMAGE; + +typedef struct { + UINT32 Signature; + UINT32 HeaderCheckSum; + UINT32 FileLength; + UINT32 NumberOfImages; +} EFILDR_HEADER; + +#endif diff --git a/DuetPkg/EfiLdr/EfiLoader.c b/DuetPkg/EfiLdr/EfiLoader.c new file mode 100644 index 0000000000..382b7802a1 --- /dev/null +++ b/DuetPkg/EfiLdr/EfiLoader.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + EfiLoader.c + +Abstract: + +Revision History: + +--*/ + +#include "EfiLdr.h" +#include "Support.h" +#include "Debug.h" +#include "PeLoader.h" + +VOID +EfiLoader ( + UINT32 BiosMemoryMapBaseAddress + ) +{ + BIOS_MEMORY_MAP *BiosMemoryMap; + EFILDR_HEADER *EFILDRHeader; + EFILDR_IMAGE *EFILDRImage; + EFI_MEMORY_DESCRIPTOR EfiMemoryDescriptor[EFI_MAX_MEMORY_DESCRIPTORS]; + EFI_STATUS Status; + UINTN NumberOfMemoryMapEntries; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINTN BfvPageNumber; + UINTN BfvBase; + EFI_MAIN_ENTRYPOINT EfiMainEntrypoint; + static EFILDRHANDOFF Handoff; + +PrintHeader ('A'); + + ClearScreen(); + PrintString("EFI Loader\n"); + +// PrintString("&BiosMemoryMapBaseAddress = "); +// PrintValue64 ((UINT64)(&BiosMemoryMapBaseAddress)); +// PrintString(" BiosMemoryMapBaseAddress = "); +// PrintValue(BiosMemoryMapBaseAddress); +// PrintString("\n"); + + // + // Add all EfiConventionalMemory descriptors to the table. If there are partial pages, then + // round the start address up to the next page, and round the length down to a page boundry. + // + BiosMemoryMap = (BIOS_MEMORY_MAP *)(UINTN)(BiosMemoryMapBaseAddress); + NumberOfMemoryMapEntries = 0; + GenMemoryMap (&NumberOfMemoryMapEntries, EfiMemoryDescriptor, BiosMemoryMap); + + // + // Get information on where the image is in memory + // + + EFILDRHeader = (EFILDR_HEADER *)(UINTN)(EFILDR_HEADER_ADDRESS); + EFILDRImage = (EFILDR_IMAGE *)(UINTN)(EFILDR_HEADER_ADDRESS + sizeof(EFILDR_HEADER)); + +PrintHeader ('D'); + + // + // Point to the 4th image (Bfv) + // + + EFILDRImage += 3; + + // + // Decompress the image + // + + Status = UefiDecompressGetInfo ( + NULL, + (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset), + EFILDRImage->Length, + &DestinationSize, + &ScratchSize + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + + Status = TianoDecompress ( + NULL, + (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset), + EFILDRImage->Length, + (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS, + DestinationSize, + (VOID *)(UINTN)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000), + ScratchSize + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + + BfvPageNumber = EFI_SIZE_TO_PAGES (DestinationSize); + BfvBase = (UINTN) FindSpace (BfvPageNumber, &NumberOfMemoryMapEntries, EfiMemoryDescriptor, EfiRuntimeServicesData, EFI_MEMORY_WB); + if (BfvBase == 0) { + CpuDeadLoop(); + } + ZeroMem ((VOID *)(UINTN)BfvBase, BfvPageNumber * EFI_PAGE_SIZE); + CopyMem ((VOID *)(UINTN)BfvBase, (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS, DestinationSize); + +PrintHeader ('B'); + + // + // Point to the 2nd image (DxeIpl) + // + + EFILDRImage -= 2; + + // + // Decompress the image + // + + Status = UefiDecompressGetInfo ( + NULL, + (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset), + EFILDRImage->Length, + &DestinationSize, + &ScratchSize + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + + Status = TianoDecompress ( + NULL, + (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset), + EFILDRImage->Length, + (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS, + DestinationSize, + (VOID *)(UINTN)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000), + ScratchSize + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + + // + // Load and relocate the EFI PE/COFF Firmware Image + // + Status = EfiLdrPeCoffLoadPeImage ( + (VOID *)(UINTN)(EFI_DECOMPRESSED_BUFFER_ADDRESS), + &DxeIplImage, + &NumberOfMemoryMapEntries, + EfiMemoryDescriptor + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + +// PrintString("Image.NoPages = "); +// PrintValue(Image.NoPages); +// PrintString("\n"); + +PrintHeader ('C'); + + // + // Point to the 3rd image (DxeMain) + // + + EFILDRImage++; + + // + // Decompress the image + // + + Status = UefiDecompressGetInfo ( + NULL, + (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset), + EFILDRImage->Length, + &DestinationSize, + &ScratchSize + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + + Status = TianoDecompress ( + NULL, + (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset), + EFILDRImage->Length, + (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS, + DestinationSize, + (VOID *)(UINTN)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000), + ScratchSize + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + + // + // Load and relocate the EFI PE/COFF Firmware Image + // + Status = EfiLdrPeCoffLoadPeImage ( + (VOID *)(UINTN)(EFI_DECOMPRESSED_BUFFER_ADDRESS), + &DxeCoreImage, + &NumberOfMemoryMapEntries, + EfiMemoryDescriptor + ); + if (EFI_ERROR (Status)) { + CpuDeadLoop(); + } + +PrintHeader ('E'); + + // + // Display the table of memory descriptors. + // + +// PrintString("\nEFI Memory Descriptors\n"); +/* + { + UINTN Index; + for (Index = 0; Index < NumberOfMemoryMapEntries; Index++) { + PrintString("Type = "); + PrintValue(EfiMemoryDescriptor[Index].Type); + PrintString(" Start = "); + PrintValue((UINT32)(EfiMemoryDescriptor[Index].PhysicalStart)); + PrintString(" NumberOfPages = "); + PrintValue((UINT32)(EfiMemoryDescriptor[Index].NumberOfPages)); + PrintString("\n"); + } + } +*/ + + // + // Jump to EFI Firmware + // + + if (DxeIplImage.EntryPoint != NULL) { + + Handoff.MemDescCount = NumberOfMemoryMapEntries; + Handoff.MemDesc = EfiMemoryDescriptor; + Handoff.BfvBase = (VOID *)(UINTN)BfvBase; + Handoff.BfvSize = BfvPageNumber * EFI_PAGE_SIZE; + Handoff.DxeIplImageBase = (VOID *)(UINTN)DxeIplImage.ImageBasePage; + Handoff.DxeIplImageSize = DxeIplImage.NoPages * EFI_PAGE_SIZE; + Handoff.DxeCoreImageBase = (VOID *)(UINTN)DxeCoreImage.ImageBasePage; + Handoff.DxeCoreImageSize = DxeCoreImage.NoPages * EFI_PAGE_SIZE; + Handoff.DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreImage.EntryPoint; + + EfiMainEntrypoint = (EFI_MAIN_ENTRYPOINT)(UINTN)DxeIplImage.EntryPoint; + EfiMainEntrypoint (&Handoff); + } + +PrintHeader ('F'); + + // + // There was a problem loading the image, so HALT the system. + // + + CpuDeadLoop(); +} + diff --git a/DuetPkg/EfiLdr/Ia32/EfiLdr.inf b/DuetPkg/EfiLdr/Ia32/EfiLdr.inf new file mode 100644 index 0000000000..ba87791958 --- /dev/null +++ b/DuetPkg/EfiLdr/Ia32/EfiLdr.inf @@ -0,0 +1,27 @@ +#/*++ +# +# Copyright (c) 2006, 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. +# +# Module Name: +# EfiLdr.inf +# +# Abstract: +# +#--*/ + +[defines] +BASE_NAME = EfiLoader +COMPONENT_TYPE = FILE +BUILD_TYPE = CUSTOM_MAKEFILE +FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + +[sources.common] + +[nmake.common] diff --git a/DuetPkg/EfiLdr/Ia32/Makefile b/DuetPkg/EfiLdr/Ia32/Makefile new file mode 100644 index 0000000000..61cadf7e8f --- /dev/null +++ b/DuetPkg/EfiLdr/Ia32/Makefile @@ -0,0 +1,183 @@ +#/*++ +# +# Copyright (c) 2006 - 2007, 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. +# +# Module Name: +# Makefile +# +# Abstract: +# +#--*/ + +# +# Globals +# +BIN_DIR = $(BUILD_DIR)\$(PROCESSOR) +TOOLCHAIN = TOOLCHAIN_$(PROCESSOR) + +TOOLBIN_DIR = $(BUILD_DIR)\Tools + +# +# Include CommonTools.env enviroment +# + +!INCLUDE $(BUILD_DIR)\PlatformTools.env + +# +# Include paths +# +INC = -I $(SOURCE_DIR)\. -I $(SOURCE_DIR)\.\$(PROCESSOR) $(INC) +INC = -I $(EDK_SOURCE)\Foundation\ \ + -I $(EDK_SOURCE)\Foundation\Include \ + -I $(EDK_SOURCE)\Foundation\Include\$(PROCESSOR) \ + -I $(EDK_SOURCE)\Foundation\Efi \ + -I $(EDK_SOURCE)\Foundation\Efi\Include \ + -I $(EDK_SOURCE)\Foundation\Framework \ + -I $(EDK_SOURCE)\Foundation\Framework\Include \ + -I $(EDK_SOURCE)\Foundation\Library\Dxe\Include \ + -I $(EDK_SOURCE)\Foundation\Library\Pei\Include \ + -I $(EDK_SOURCE)\Foundation\Include\Pei \ + $(INC) + +LDRDEP = $(BUILD_DIR)\..\Loader\EfiLdr\Efildr.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\EfiLdrHandoff.h \ + $(BUILD_DIR)\..\Loader\EfiLdr\EfiLoader.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\Debug.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\Debug.h \ + $(BUILD_DIR)\..\Loader\EfiLdr\PeLoader.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\PeLoader.h \ + $(BUILD_DIR)\..\Loader\EfiLdr\Support.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\Support.h + +all : \ + $(BIN_DIR)\BootSect.com \ + $(BIN_DIR)\Bs16.com \ + $(BIN_DIR)\Bs32.com \ + $(BIN_DIR)\Gpt.com \ + $(BIN_DIR)\Mbr.com \ + $(BIN_DIR)\Start.com \ + $(BIN_DIR)\Start16.com \ + $(BIN_DIR)\Start32.com \ + $(BIN_DIR)\Efi32.com2 \ + $(BIN_DIR)\Efildr.efi \ + + +loader : \ + Fv\Efildr \ + Fv\Efildr16 \ + Fv\Efildr20 \ + + +# +# Generate loader object +# +$(BIN_DIR)\BootSect.obj: $(BUILD_DIR)\..\Loader\BootSector\BootSect.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\BootSect.obj $(BUILD_DIR)\..\Loader\BootSector\BootSect.asm + +$(BIN_DIR)\BootSect.com: $(BIN_DIR)\BootSect.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny BootSect.obj,BootSect.com,BootSect.map,,, + +$(BIN_DIR)\Bs16.obj: $(BUILD_DIR)\..\Loader\BootSector\Bs16.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Bs16.obj $(BUILD_DIR)\..\Loader\BootSector\Bs16.asm + +$(BIN_DIR)\Bs16.com: $(BIN_DIR)\Bs16.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Bs16.obj,Bs16.com,Bs16.map,,, + +$(BIN_DIR)\Bs32.obj: $(BUILD_DIR)\..\Loader\BootSector\Bs32.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Bs32.obj $(BUILD_DIR)\..\Loader\BootSector\Bs32.asm + +$(BIN_DIR)\Bs32.com: $(BIN_DIR)\Bs32.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Bs32.obj,Bs32.com,Bs32.map,,, + +$(BIN_DIR)\Gpt.obj: $(BUILD_DIR)\..\Loader\BootSector\Gpt.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Gpt.obj $(BUILD_DIR)\..\Loader\BootSector\Gpt.asm + +$(BIN_DIR)\Gpt.com: $(BIN_DIR)\Gpt.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Gpt.obj,Gpt.com,Gpt.map,,, + +$(BIN_DIR)\Mbr.obj: $(BUILD_DIR)\..\Loader\BootSector\Mbr.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Mbr.obj $(BUILD_DIR)\..\Loader\BootSector\Mbr.asm + +$(BIN_DIR)\Mbr.com: $(BIN_DIR)\Mbr.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Mbr.obj,Mbr.com,Mbr.map,,, + +$(BIN_DIR)\Start.obj: $(BUILD_DIR)\..\Loader\BootSector\Start.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Start.obj $(BUILD_DIR)\..\Loader\BootSector\Start.asm + +$(BIN_DIR)\Start.com: $(BIN_DIR)\Start.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Start.obj,Start.com,Start.map,,, + +$(BIN_DIR)\Start16.obj: $(BUILD_DIR)\..\Loader\BootSector\Start16.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Start16.obj $(BUILD_DIR)\..\Loader\BootSector\Start16.asm + +$(BIN_DIR)\Start16.com: $(BIN_DIR)\Start16.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Start16.obj,Start16.com,Start16.map,,, + +$(BIN_DIR)\Start32.obj: $(BUILD_DIR)\..\Loader\BootSector\Start32.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Start32.obj $(BUILD_DIR)\..\Loader\BootSector\Start32.asm + +$(BIN_DIR)\Start32.com: $(BIN_DIR)\Start32.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Start32.obj,Start32.com,Start32.map,,, + +$(BIN_DIR)\Efi32.obj: $(BUILD_DIR)\..\Loader\BootSector\Efi32.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Efi32.obj $(BUILD_DIR)\..\Loader\BootSector\Efi32.asm + +$(BIN_DIR)\Efi32.com: $(BIN_DIR)\Efi32.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Efi32.obj,Efi32.com,Efi32.map,,, + +$(BIN_DIR)\Efi32.com2: $(BIN_DIR)\Efi32.com + $(TOOLBIN_DIR)\Splitfile $(BIN_DIR)\Efi32.com 135168 + +$(BIN_DIR)\Efildr.obj: $(LDRDEP) + $(CC) $(C_FLAGS) $(BUILD_DIR)\..\Loader\EfiLdr\Efildr.c + +$(BIN_DIR)\Efildr.dll: $(BIN_DIR)\Efildr.obj + $(LINK) /nologo /MACHINE:X86 /SUBSYSTEM:CONSOLE /NODEFAULTLIB /INCREMENTAL:NO \ + /MAP /FIXED /BASE:0x00010000 /OPT:REF /ALIGN:32 /MERGE:.data=.text \ + /MERGE:.rdata=.text /DRIVER /ENTRY:EfiLoader $(BIN_DIR)\Efildr.obj \ + $(BIN_DIR)\CompilerStub.lib $(BIN_DIR)\EfiCommonLib.lib $(BIN_DIR)\PeiLib.lib \ + /OUT:$(BIN_DIR)\Efildr.dll /IGNORE:4078,4096 + +$(BIN_DIR)\Efildr.efi: $(BIN_DIR)\Efildr.dll + $(TOOLBIN_DIR)\FwImage app $(BIN_DIR)\Efildr.dll $(BIN_DIR)\Efildr.efi + +# +# Generate loader binary +# +Fv\EfiMain.z : Fv\EfiMain.fv + $(TOOLBIN_DIR)\Eficompress -tTiano Fv\EfiMain.fv Fv\EfiMain.z + +Fv\DxeMain.z : $(BIN_DIR)\DxeMain.efi + $(TOOLBIN_DIR)\Eficompress -tTiano $(BIN_DIR)\DxeMain.efi Fv\DxeMain.z + +Fv\DxeIpl.z : $(BIN_DIR)\DxeIpl.efi + $(TOOLBIN_DIR)\Eficompress -tTiano $(BIN_DIR)\DxeIpl.efi Fv\DxeIpl.z + +Fv\Efildr32: $(BIN_DIR)\Efildr.efi Fv\DxeIpl.z Fv\DxeMain.z Fv\EfiMain.z + $(TOOLBIN_DIR)\Efildrimage Fv\Efildr32 $(BIN_DIR)\Efildr.efi Fv\DxeIpl.z Fv\DxeMain.z Fv\EfiMain.z + +Fv\Efildr: $(BIN_DIR)\Start.com $(BIN_DIR)\Efi32.com2 Fv\Efildr32 + copy /b $(BIN_DIR)\Start.com+$(BIN_DIR)\Efi32.com2+Fv\Efildr32 Fv\Efildr + +Fv\Efildr16: $(BIN_DIR)\Start16.com $(BIN_DIR)\Efi32.com2 Fv\Efildr32 + copy /b $(BIN_DIR)\Start16.com+$(BIN_DIR)\Efi32.com2+Fv\Efildr32 Fv\Efildr16 + +Fv\Efildr20: $(BIN_DIR)\Start32.com $(BIN_DIR)\Efi32.com2 Fv\Efildr32 + copy /b $(BIN_DIR)\Start32.com+$(BIN_DIR)\Efi32.com2+Fv\Efildr32 Fv\Efildr20 + diff --git a/DuetPkg/EfiLdr/PeLoader.c b/DuetPkg/EfiLdr/PeLoader.c new file mode 100644 index 0000000000..73608da161 --- /dev/null +++ b/DuetPkg/EfiLdr/PeLoader.c @@ -0,0 +1,641 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + PeLoader.c + +Abstract: + +Revision History: + +--*/ +#include "EfiLdr.h" +#include "Debug.h" +#include "Support.h" + +STATIC +EFI_STATUS +EfiLdrPeCoffLoadPeRelocate ( + IN EFILDR_LOADED_IMAGE *Image, + IN EFI_IMAGE_DATA_DIRECTORY *RelocDir, + IN UINTN Adjust, + IN UINTN *NumberOfMemoryMapEntries, + IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor + ); + +STATIC +EFI_STATUS +EfiLdrPeCoffImageRead ( + IN VOID *FHand, + IN UINTN Offset, + IN OUT UINTN ReadSize, + OUT VOID *Buffer + ); + +STATIC +VOID * +EfiLdrPeCoffImageAddress ( + IN EFILDR_LOADED_IMAGE *Image, + IN UINTN Address + ); + + +EFI_STATUS +EfiLdrPeCoffSetImageType ( + IN OUT EFILDR_LOADED_IMAGE *Image, + IN UINTN ImageType + ); + +EFI_STATUS +EfiLdrPeCoffCheckImageMachineType ( + IN UINT16 MachineType + ); + +EFI_STATUS +EfiLdrGetPeImageInfo ( + IN VOID *FHand, + OUT UINT64 *ImageBase, + OUT UINT32 *ImageSize + ) +{ + EFI_STATUS Status; + EFI_IMAGE_DOS_HEADER DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr; + + ZeroMem (&DosHdr, sizeof(DosHdr)); + ZeroMem (&PeHdr, sizeof(PeHdr)); + + // + // Read image headers + // + + EfiLdrPeCoffImageRead (FHand, 0, sizeof(DosHdr), &DosHdr); + if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + return EFI_UNSUPPORTED; + } + + EfiLdrPeCoffImageRead (FHand, DosHdr.e_lfanew, sizeof(PeHdr), &PeHdr); + + if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + return EFI_UNSUPPORTED; + } + + // + // Verify machine type + // + + Status = EfiLdrPeCoffCheckImageMachineType (PeHdr.Pe32.FileHeader.Machine); + if (EFI_ERROR(Status)) { + return Status; + } + + if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + *ImageBase = (UINT32)PeHdr.Pe32.OptionalHeader.ImageBase; + } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + *ImageBase = PeHdr.Pe32Plus.OptionalHeader.ImageBase; + } else { + return EFI_UNSUPPORTED; + } + + *ImageSize = PeHdr.Pe32.OptionalHeader.SizeOfImage; + + return EFI_SUCCESS; +} + +EFI_STATUS +EfiLdrPeCoffLoadPeImage ( + IN VOID *FHand, + IN EFILDR_LOADED_IMAGE *Image, + IN UINTN *NumberOfMemoryMapEntries, + IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor + ) +{ + EFI_IMAGE_DOS_HEADER DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr; + EFI_IMAGE_SECTION_HEADER *FirstSection; + EFI_IMAGE_SECTION_HEADER *Section; + UINTN Index; + EFI_STATUS Status; + UINT8 *Base; + UINT8 *End; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + UINTN DirCount; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY TempDebugEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN CodeViewSize; + UINTN CodeViewOffset; + UINTN CodeViewFileOffset; + UINTN OptionalHeaderSize; + UINTN PeHeaderSize; + UINT32 NumberOfRvaAndSizes; + EFI_IMAGE_DATA_DIRECTORY *DataDirectory; + UINT64 ImageBase; + + ZeroMem (&DosHdr, sizeof(DosHdr)); + ZeroMem (&PeHdr, sizeof(PeHdr)); + + // + // Read image headers + // + + EfiLdrPeCoffImageRead (FHand, 0, sizeof(DosHdr), &DosHdr); + if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) { +// DEBUG ((D_LOAD, "PeCoffLoadPeImage: Dos header signature not found\n")); +PrintHeader ('F'); + return EFI_UNSUPPORTED; + } + + EfiLdrPeCoffImageRead (FHand, DosHdr.e_lfanew, sizeof(PeHdr), &PeHdr); + + if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { +// DEBUG ((D_LOAD, "PeCoffLoadPeImage: PE image header signature not found\n")); +PrintHeader ('G'); + return EFI_UNSUPPORTED; + } + + // + // Set the image subsystem type + // + + Status = EfiLdrPeCoffSetImageType (Image, PeHdr.Pe32.OptionalHeader.Subsystem); + if (EFI_ERROR(Status)) { +// DEBUG ((D_LOAD, "PeCoffLoadPeImage: Subsystem type not known\n")); +PrintHeader ('H'); + return Status; + } + + // + // Verify machine type + // + + Status = EfiLdrPeCoffCheckImageMachineType (PeHdr.Pe32.FileHeader.Machine); + if (EFI_ERROR(Status)) { +// DEBUG ((D_LOAD, "PeCoffLoadPeImage: Incorrect machine type\n")); +PrintHeader ('I'); + return Status; + } + + // + // Compute the amount of memory needed to load the image and + // allocate it. This will include all sections plus the codeview debug info. + // Since the codeview info is actually outside of the image, we calculate + // its size seperately and add it to the total. + // + // Memory starts off as data + // + + CodeViewSize = 0; + CodeViewFileOffset = 0; + if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(PeHdr.Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(PeHdr.Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } else { + return EFI_UNSUPPORTED; + } + for (DirCount = 0; + (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && (CodeViewSize == 0); + DirCount++) { + Status = EfiLdrPeCoffImageRead ( + FHand, + DirectoryEntry->VirtualAddress + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), + sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), + &TempDebugEntry + ); + if (!EFI_ERROR (Status)) { + if (TempDebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + CodeViewSize = TempDebugEntry.SizeOfData; + CodeViewFileOffset = TempDebugEntry.FileOffset; + } + } + } + + CodeViewOffset = PeHdr.Pe32.OptionalHeader.SizeOfImage + PeHdr.Pe32.OptionalHeader.SectionAlignment; + Image->NoPages = EFI_SIZE_TO_PAGES (CodeViewOffset + CodeViewSize); + + // + // Compute the amount of memory needed to load the image and + // allocate it. Memory starts off as data + // + + Image->ImageBasePage = (EFI_PHYSICAL_ADDRESS)FindSpace (Image->NoPages, NumberOfMemoryMapEntries, EfiMemoryDescriptor, EfiRuntimeServicesCode, EFI_MEMORY_WB); + if (Image->ImageBasePage == 0) { + return EFI_OUT_OF_RESOURCES; + } + + if (EFI_ERROR(Status)) { +PrintHeader ('J'); + return Status; + } + +// DEBUG((D_LOAD, "LoadPe: new image base %lx\n", Image->ImageBasePage)); + Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageBasePage; + Image->Info.ImageSize = (Image->NoPages << EFI_PAGE_SHIFT) - 1; + Image->ImageBase = (UINT8 *)(UINTN)Image->ImageBasePage; + Image->ImageEof = Image->ImageBase + Image->Info.ImageSize; + Image->ImageAdjust = Image->ImageBase; + + // + // Copy the Image header to the base location + // + Status = EfiLdrPeCoffImageRead ( + FHand, + 0, + PeHdr.Pe32.OptionalHeader.SizeOfHeaders, + Image->ImageBase + ); + + if (EFI_ERROR(Status)) { +PrintHeader ('K'); + return Status; + } + + // + // Load each directory of the image into memory... + // Save the address of the Debug directory for later + // + if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + NumberOfRvaAndSizes = PeHdr.Pe32.OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = PeHdr.Pe32.OptionalHeader.DataDirectory; + } else { + NumberOfRvaAndSizes = PeHdr.Pe32Plus.OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = PeHdr.Pe32Plus.OptionalHeader.DataDirectory; + } + DebugEntry = NULL; + for (Index = 0; Index < NumberOfRvaAndSizes; Index++) { + if ((DataDirectory[Index].VirtualAddress != 0) && (DataDirectory[Index].Size != 0)) { + Status = EfiLdrPeCoffImageRead ( + FHand, + DataDirectory[Index].VirtualAddress, + DataDirectory[Index].Size, + Image->ImageBase + DataDirectory[Index].VirtualAddress + ); + if (EFI_ERROR(Status)) { + return Status; + } + if (Index == EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (Image->ImageBase + DataDirectory[Index].VirtualAddress); + } + } + } + + // + // Load each section of the image + // + + // BUGBUG: change this to use the in memory copy + if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + OptionalHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER32); + PeHeaderSize = sizeof(EFI_IMAGE_NT_HEADERS32); + } else { + OptionalHeaderSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER64); + PeHeaderSize = sizeof(EFI_IMAGE_NT_HEADERS64); + } + FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( + Image->ImageBase + + DosHdr.e_lfanew + + PeHeaderSize + + PeHdr.Pe32.FileHeader.SizeOfOptionalHeader - + OptionalHeaderSize + ); + + Section = FirstSection; + for (Index=0; Index < PeHdr.Pe32.FileHeader.NumberOfSections; Index += 1) { + + // + // Compute sections address + // + + Base = EfiLdrPeCoffImageAddress (Image, (UINTN)Section->VirtualAddress); + End = EfiLdrPeCoffImageAddress (Image, (UINTN)(Section->VirtualAddress + Section->Misc.VirtualSize)); + + if (EFI_ERROR(Status) || !Base || !End) { +// DEBUG((D_LOAD|D_ERROR, "LoadPe: Section %d was not loaded\n", Index)); +PrintHeader ('L'); + return EFI_LOAD_ERROR; + } + +// DEBUG((D_LOAD, "LoadPe: Section %d, loaded at %x\n", Index, Base)); + + // + // Read the section + // + + if (Section->SizeOfRawData) { + Status = EfiLdrPeCoffImageRead (FHand, Section->PointerToRawData, Section->SizeOfRawData, Base); + if (EFI_ERROR(Status)) { +PrintHeader ('M'); + return Status; + } + } + + // + // If raw size is less then virt size, zero fill the remaining + // + + if (Section->SizeOfRawData < Section->Misc.VirtualSize) { + ZeroMem ( + Base + Section->SizeOfRawData, + Section->Misc.VirtualSize - Section->SizeOfRawData + ); + } + + // + // Next Section + // + + Section += 1; + } + + // + // Copy in CodeView information if it exists + // + if (CodeViewSize != 0) { + Status = EfiLdrPeCoffImageRead (FHand, CodeViewFileOffset, CodeViewSize, Image->ImageBase + CodeViewOffset); + DebugEntry->RVA = (UINT32) (CodeViewOffset); + } + + // + // Apply relocations only if needed + // + if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImageBase = (UINT64)PeHdr.Pe32.OptionalHeader.ImageBase; + } else { + ImageBase = PeHdr.Pe32Plus.OptionalHeader.ImageBase; + } + if ((UINTN)(Image->ImageBase) != (UINTN) (ImageBase)) { + Status = EfiLdrPeCoffLoadPeRelocate ( + Image, + &DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC], + (UINTN) Image->ImageBase - (UINTN)ImageBase, + NumberOfMemoryMapEntries, + EfiMemoryDescriptor + ); + + if (EFI_ERROR(Status)) { +PrintHeader ('N'); + return Status; + } + } + + // + // Use exported EFI specific interface if present, else use the image's entry point + // + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN) + (EfiLdrPeCoffImageAddress( + Image, + PeHdr.Pe32.OptionalHeader.AddressOfEntryPoint + )); + + return Status; +} + +STATIC +EFI_STATUS +EfiLdrPeCoffLoadPeRelocate ( + IN EFILDR_LOADED_IMAGE *Image, + IN EFI_IMAGE_DATA_DIRECTORY *RelocDir, + IN UINTN Adjust, + IN UINTN *NumberOfMemoryMapEntries, + IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor + ) +{ + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + UINT8 *Fixup; + UINT8 *FixupBase; + UINT16 *F16; + UINT32 *F32; + UINT64 *F64; + UINT8 *FixupData; + UINTN NoFixupPages; + + // + // Find the relocation block + // + + RelocBase = EfiLdrPeCoffImageAddress (Image, RelocDir->VirtualAddress); + RelocBaseEnd = EfiLdrPeCoffImageAddress (Image, RelocDir->VirtualAddress + RelocDir->Size); + if (!RelocBase || !RelocBaseEnd) { +PrintHeader ('O'); + return EFI_LOAD_ERROR; + } + + NoFixupPages = EFI_SIZE_TO_PAGES(RelocDir->Size / sizeof(UINT16) * sizeof(UINTN)); + Image->FixupData = (UINT8*) FindSpace (NoFixupPages, NumberOfMemoryMapEntries, EfiMemoryDescriptor, EfiRuntimeServicesData, EFI_MEMORY_WB); + if (Image->FixupData == 0) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Run the whole relocation block + // + + FixupData = Image->FixupData; + while (RelocBase < RelocBaseEnd) { + + Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof(EFI_IMAGE_BASE_RELOCATION)); + RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock); + FixupBase = EfiLdrPeCoffImageAddress (Image, RelocBase->VirtualAddress); + if ((UINT8 *) RelocEnd < Image->ImageBase || (UINT8 *) RelocEnd > Image->ImageEof) { +PrintHeader ('P'); + return EFI_LOAD_ERROR; + } + + // + // Run this relocation record + // + + while (Reloc < RelocEnd) { + + Fixup = FixupBase + (*Reloc & 0xFFF); + switch ((*Reloc) >> 12) { + + case EFI_IMAGE_REL_BASED_ABSOLUTE: + break; + + case EFI_IMAGE_REL_BASED_HIGH: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16) (*F16 + (UINT16)(((UINT32)Adjust) >> 16)); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof(UINT16); + } + break; + + case EFI_IMAGE_REL_BASED_LOW: + F16 = (UINT16 *) Fixup; + *F16 = *F16 + (UINT16) Adjust; + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof(UINT16); + } + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + F32 = (UINT32 *) Fixup; + *F32 = *F32 + (UINT32) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER(FixupData, sizeof(UINT32)); + *(UINT32 *) FixupData = *F32; + FixupData = FixupData + sizeof(UINT32); + } + break; + + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *F64 = *F64 + (UINT64) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER(FixupData, sizeof(UINT64)); + *(UINT64 *) FixupData = *F64; + FixupData = FixupData + sizeof(UINT64); + } + break; + + case EFI_IMAGE_REL_BASED_HIGHADJ: + CpuDeadLoop(); // BUGBUG: not done + break; + + default: +// DEBUG((D_LOAD|D_ERROR, "PeRelocate: unknown fixed type\n")); +PrintHeader ('Q'); + CpuDeadLoop(); + return EFI_LOAD_ERROR; + } + + // Next reloc record + Reloc += 1; + } + + // next reloc block + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + } + + // + // Add Fixup data to whole Image (assume Fixup data just below the image), so that there is no hole in the descriptor. + // Because only NoPages or ImageBasePage will be used in EfiLoader(), we update these 2 fields. + // + Image->NoPages += NoFixupPages; + Image->ImageBasePage -= (NoFixupPages << EFI_PAGE_SHIFT); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EfiLdrPeCoffImageRead ( + IN VOID *FHand, + IN UINTN Offset, + IN OUT UINTN ReadSize, + OUT VOID *Buffer + ) +{ + CopyMem (Buffer, (VOID *)((UINTN)FHand + Offset), ReadSize); + + return EFI_SUCCESS; +} + +STATIC +VOID * +EfiLdrPeCoffImageAddress ( + IN EFILDR_LOADED_IMAGE *Image, + IN UINTN Address + ) +{ + UINT8 *FixedAddress; + + FixedAddress = Image->ImageAdjust + Address; + + if ((FixedAddress < Image->ImageBase) || (FixedAddress > Image->ImageEof)) { +// DEBUG((D_LOAD|D_ERROR, "PeCoffImageAddress: pointer is outside of image\n")); + FixedAddress = NULL; + } + +// DEBUG(( +// D_LOAD, +// "PeCoffImageAddress: ImageBase %x, ImageEof %x, Address %x, FixedAddress %x\n", +// Image->ImageBase, +// Image->ImageEof, +// Address, +// FixedAddress +// )); + return FixedAddress; +} + + +EFI_STATUS +EfiLdrPeCoffSetImageType ( + IN OUT EFILDR_LOADED_IMAGE *Image, + IN UINTN ImageType + ) +{ + EFI_MEMORY_TYPE CodeType; + EFI_MEMORY_TYPE DataType; + + switch (ImageType) { + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + CodeType = EfiLoaderCode; + DataType = EfiLoaderData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + CodeType = EfiBootServicesCode; + DataType = EfiBootServicesData; + break; + + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + CodeType = EfiRuntimeServicesCode; + DataType = EfiRuntimeServicesData; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + Image->Type = ImageType; + Image->Info.ImageCodeType = CodeType; + Image->Info.ImageDataType = DataType; + + return EFI_SUCCESS; +} + +EFI_STATUS +EfiLdrPeCoffCheckImageMachineType ( + IN UINT16 MachineType + ) +{ + EFI_STATUS Status; + + Status = EFI_UNSUPPORTED; + +#if EFI32 + if (MachineType == EFI_IMAGE_MACHINE_IA32) { + Status = EFI_SUCCESS; + } +#endif + +#if EFIX64 + if (MachineType == EFI_IMAGE_MACHINE_X64) { + Status = EFI_SUCCESS; + } +#endif + +#if EFI64 + if (MachineType == EFI_IMAGE_MACHINE_IA64) { + Status = EFI_SUCCESS; + } +#endif + + return Status; +} + diff --git a/DuetPkg/EfiLdr/PeLoader.h b/DuetPkg/EfiLdr/PeLoader.h new file mode 100644 index 0000000000..895c0b704e --- /dev/null +++ b/DuetPkg/EfiLdr/PeLoader.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + PeLoader.h + +Abstract: + +Revision History: + +--*/ + +#ifndef _EFILDR_PELOADER_H_ +#define _EFILDR_PELOADER_H_ + +#include "EfiLdr.h" + +EFI_STATUS +EfiLdrGetPeImageInfo ( + IN VOID *FHand, + OUT UINT64 *ImageBase, + OUT UINT32 *ImageSize + ); + +EFI_STATUS +EfiLdrPeCoffLoadPeImage ( + IN VOID *FHand, + IN EFILDR_LOADED_IMAGE *Image, + IN UINTN *NumberOfMemoryMapEntries, + IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor + ); + + +#endif diff --git a/DuetPkg/EfiLdr/Support.c b/DuetPkg/EfiLdr/Support.c new file mode 100644 index 0000000000..0335d20e5a --- /dev/null +++ b/DuetPkg/EfiLdr/Support.c @@ -0,0 +1,237 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + Support.c + +Abstract: + +Revision History: + +--*/ +#include "EfiLdr.h" + +EFI_STATUS +EfiAddMemoryDescriptor( + UINTN *NoDesc, + EFI_MEMORY_DESCRIPTOR *Desc, + EFI_MEMORY_TYPE Type, + EFI_PHYSICAL_ADDRESS BaseAddress, + UINT64 NoPages, + UINT64 Attribute + ) +{ + UINTN NumberOfDesc; + UINT64 Temp; + UINTN Index; + + if (NoPages == 0) { + return EFI_SUCCESS; + } + + // + // See if the new memory descriptor needs to be carved out of an existing memory descriptor + // + + NumberOfDesc = *NoDesc; + for (Index = 0; Index < NumberOfDesc; Index++) { + + if (Desc[Index].Type == EfiConventionalMemory) { + + Temp = DivU64x32 ((BaseAddress - Desc[Index].PhysicalStart), EFI_PAGE_SIZE) + NoPages; + + if ((Desc[Index].PhysicalStart < BaseAddress) && (Desc[Index].NumberOfPages >= Temp)) { + if (Desc[Index].NumberOfPages > Temp) { + Desc[*NoDesc].Type = EfiConventionalMemory; + Desc[*NoDesc].PhysicalStart = BaseAddress + MultU64x32 (NoPages, EFI_PAGE_SIZE); + Desc[*NoDesc].NumberOfPages = Desc[Index].NumberOfPages - Temp; + Desc[*NoDesc].VirtualStart = 0; + Desc[*NoDesc].Attribute = Desc[Index].Attribute; + *NoDesc = *NoDesc + 1; + } + Desc[Index].NumberOfPages = Temp - NoPages; + } + + if ((Desc[Index].PhysicalStart == BaseAddress) && (Desc[Index].NumberOfPages == NoPages)) { + Desc[Index].Type = Type; + Desc[Index].Attribute = Attribute; + return EFI_SUCCESS; + } + + if ((Desc[Index].PhysicalStart == BaseAddress) && (Desc[Index].NumberOfPages > NoPages)) { + Desc[Index].NumberOfPages -= NoPages; + Desc[Index].PhysicalStart += MultU64x32 (NoPages, EFI_PAGE_SIZE); + } + } + } + + // + // Add the new memory descriptor + // + + Desc[*NoDesc].Type = Type; + Desc[*NoDesc].PhysicalStart = BaseAddress; + Desc[*NoDesc].NumberOfPages = NoPages; + Desc[*NoDesc].VirtualStart = 0; + Desc[*NoDesc].Attribute = Attribute; + *NoDesc = *NoDesc + 1; + + return EFI_SUCCESS; +} + +UINTN +FindSpace ( + UINTN NoPages, + IN UINTN *NumberOfMemoryMapEntries, + IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor, + EFI_MEMORY_TYPE Type, + UINT64 Attribute + ) +{ + EFI_PHYSICAL_ADDRESS MaxPhysicalStart; + UINT64 MaxNoPages; + UINTN Index; + EFI_MEMORY_DESCRIPTOR *CurrentMemoryDescriptor; + + MaxPhysicalStart = 0; + MaxNoPages = 0; + CurrentMemoryDescriptor = NULL; + for (Index = 0; Index < *NumberOfMemoryMapEntries; Index++) { + if (EfiMemoryDescriptor[Index].PhysicalStart + LShiftU64(EfiMemoryDescriptor[Index].NumberOfPages, EFI_PAGE_SHIFT) <= 0x100000) { + continue; + } + if ((EfiMemoryDescriptor[Index].Type == EfiConventionalMemory) && + (EfiMemoryDescriptor[Index].NumberOfPages >= NoPages)) { + if (EfiMemoryDescriptor[Index].PhysicalStart > MaxPhysicalStart) { + if (EfiMemoryDescriptor[Index].PhysicalStart + LShiftU64(EfiMemoryDescriptor[Index].NumberOfPages, EFI_PAGE_SHIFT) <= 0x100000000) { + MaxPhysicalStart = EfiMemoryDescriptor[Index].PhysicalStart; + MaxNoPages = EfiMemoryDescriptor[Index].NumberOfPages; + CurrentMemoryDescriptor = &EfiMemoryDescriptor[Index]; + } + } + } + if ((EfiMemoryDescriptor[Index].Type == EfiReservedMemoryType) || + (EfiMemoryDescriptor[Index].Type >= EfiACPIReclaimMemory) ) { + continue; + } + if ((EfiMemoryDescriptor[Index].Type == EfiRuntimeServicesCode) || + (EfiMemoryDescriptor[Index].Type == EfiRuntimeServicesData)) { + break; + } + } + + if (MaxPhysicalStart == 0) { + return 0; + } + + if (MaxNoPages != NoPages) { + CurrentMemoryDescriptor->NumberOfPages = MaxNoPages - NoPages; + EfiMemoryDescriptor[*NumberOfMemoryMapEntries].Type = Type; + EfiMemoryDescriptor[*NumberOfMemoryMapEntries].PhysicalStart = MaxPhysicalStart + LShiftU64(MaxNoPages - NoPages, EFI_PAGE_SHIFT); + EfiMemoryDescriptor[*NumberOfMemoryMapEntries].NumberOfPages = NoPages; + EfiMemoryDescriptor[*NumberOfMemoryMapEntries].VirtualStart = 0; + EfiMemoryDescriptor[*NumberOfMemoryMapEntries].Attribute = Attribute; + *NumberOfMemoryMapEntries = *NumberOfMemoryMapEntries + 1; + } else { + CurrentMemoryDescriptor->Type = Type; + CurrentMemoryDescriptor->Attribute = Attribute; + } + + return (UINTN)(MaxPhysicalStart + LShiftU64(MaxNoPages - NoPages, EFI_PAGE_SHIFT)); +} + +VOID +GenMemoryMap ( + UINTN *NumberOfMemoryMapEntries, + EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor, + BIOS_MEMORY_MAP *BiosMemoryMap + ) +{ + UINT64 BaseAddress; + UINT64 Length; + EFI_MEMORY_TYPE Type; + UINTN Index; + UINTN Attr; + UINT64 Ceiling; + + Ceiling = 0xFFFFFFFF; + for (Index = 0; Index < BiosMemoryMap->MemoryMapSize / sizeof(BIOS_MEMORY_MAP_ENTRY); Index++) { + + switch (BiosMemoryMap->MemoryMapEntry[Index].Type) { + case (INT15_E820_AddressRangeMemory): + Type = EfiConventionalMemory; + Attr = EFI_MEMORY_WB; + break; + case (INT15_E820_AddressRangeReserved): + Type = EfiReservedMemoryType; + Attr = EFI_MEMORY_UC; + break; + case (INT15_E820_AddressRangeACPI): + Type = EfiACPIReclaimMemory; + Attr = EFI_MEMORY_WB; + break; + case (INT15_E820_AddressRangeNVS): + Type = EfiACPIMemoryNVS; + Attr = EFI_MEMORY_UC; + break; + default: + // We should not get here, according to ACPI 2.0 Spec. + // BIOS behaviour of the Int15h, E820h + Type = EfiReservedMemoryType; + Attr = EFI_MEMORY_UC; + break; + } + if (Type == EfiConventionalMemory) { + BaseAddress = BiosMemoryMap->MemoryMapEntry[Index].BaseAddress; + Length = BiosMemoryMap->MemoryMapEntry[Index].Length; + if (BaseAddress & EFI_PAGE_MASK) { + Length = Length + (BaseAddress & EFI_PAGE_MASK) - EFI_PAGE_SIZE; + BaseAddress = LShiftU64 (RShiftU64 (BaseAddress, EFI_PAGE_SHIFT) + 1, EFI_PAGE_SHIFT); + } + } else { + BaseAddress = BiosMemoryMap->MemoryMapEntry[Index].BaseAddress; + Length = BiosMemoryMap->MemoryMapEntry[Index].Length + (BaseAddress & EFI_PAGE_MASK); + BaseAddress = LShiftU64 (RShiftU64 (BaseAddress, EFI_PAGE_SHIFT), EFI_PAGE_SHIFT); + if (Length & EFI_PAGE_MASK) { + Length = LShiftU64 (RShiftU64 (Length, EFI_PAGE_SHIFT) + 1, EFI_PAGE_SHIFT); + } + // + // Update Memory Ceiling + // + if ((BaseAddress >= 0x100000) && (BaseAddress < 0x100000000)) { + if (Ceiling > BaseAddress) { + Ceiling = BaseAddress; + } + } + } + EfiAddMemoryDescriptor ( + NumberOfMemoryMapEntries, + EfiMemoryDescriptor, + Type, + (EFI_PHYSICAL_ADDRESS)BaseAddress, + RShiftU64 (Length, EFI_PAGE_SHIFT), + Attr + ); + } + + // + // Update MemoryMap according to Ceiling + // + for (Index = 0; Index < *NumberOfMemoryMapEntries; Index++) { + if ((EfiMemoryDescriptor[Index].Type == EfiConventionalMemory) && + (EfiMemoryDescriptor[Index].PhysicalStart > 0x100000) && + (EfiMemoryDescriptor[Index].PhysicalStart < 0x100000000)) { + if (EfiMemoryDescriptor[Index].PhysicalStart >= Ceiling) { + EfiMemoryDescriptor[Index].Type = EfiReservedMemoryType; + } + } + } +} diff --git a/DuetPkg/EfiLdr/Support.h b/DuetPkg/EfiLdr/Support.h new file mode 100644 index 0000000000..360f4250d0 --- /dev/null +++ b/DuetPkg/EfiLdr/Support.h @@ -0,0 +1,50 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + Support.h + +Abstract: + +Revision History: + +--*/ + +#ifndef _EFILDR_SUPPORT_H_ +#define _EFILDR_SUPPORT_H_ + +EFI_STATUS +EfiAddMemoryDescriptor( + UINTN *NoDesc, + EFI_MEMORY_DESCRIPTOR *Desc, + EFI_MEMORY_TYPE Type, + EFI_PHYSICAL_ADDRESS BaseAddress, + UINT64 NoPages, + UINT64 Attribute + ); + +UINTN +FindSpace( + UINTN NoPages, + IN UINTN *NumberOfMemoryMapEntries, + IN EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor, + EFI_MEMORY_TYPE Type, + UINT64 Attribute + ); + +VOID +GenMemoryMap ( + UINTN *NumberOfMemoryMapEntries, + EFI_MEMORY_DESCRIPTOR *EfiMemoryDescriptor, + BIOS_MEMORY_MAP *BiosMemoryMap + ); + +#endif diff --git a/DuetPkg/EfiLdr/X64/EfiLdr.inf b/DuetPkg/EfiLdr/X64/EfiLdr.inf new file mode 100644 index 0000000000..ba87791958 --- /dev/null +++ b/DuetPkg/EfiLdr/X64/EfiLdr.inf @@ -0,0 +1,27 @@ +#/*++ +# +# Copyright (c) 2006, 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. +# +# Module Name: +# EfiLdr.inf +# +# Abstract: +# +#--*/ + +[defines] +BASE_NAME = EfiLoader +COMPONENT_TYPE = FILE +BUILD_TYPE = CUSTOM_MAKEFILE +FILE_GUID = 7E374E25-8E01-4FEE-87F2-390C23C606CD + +[sources.common] + +[nmake.common] diff --git a/DuetPkg/EfiLdr/X64/Makefile b/DuetPkg/EfiLdr/X64/Makefile new file mode 100644 index 0000000000..dc31b137d7 --- /dev/null +++ b/DuetPkg/EfiLdr/X64/Makefile @@ -0,0 +1,186 @@ +#/*++ +# +# Copyright (c) 2006 - 2007, 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. +# +# Module Name: +# Makefile +# +# Abstract: +# +#--*/ + +# +# Globals +# +BIN_DIR = $(BUILD_DIR)\$(PROCESSOR) +TOOLCHAIN = TOOLCHAIN_$(PROCESSOR) + +TOOLBIN_DIR = $(BUILD_DIR)\Tools + +# +# Include CommonTools.env enviroment +# + +!INCLUDE $(BUILD_DIR)\PlatformTools.env + +# +# Include paths +# +INC = -I $(SOURCE_DIR)\. -I $(SOURCE_DIR)\.\$(PROCESSOR) $(INC) +INC = -I $(EDK_SOURCE)\Foundation\ \ + -I $(EDK_SOURCE)\Foundation\Include \ + -I $(EDK_SOURCE)\Foundation\Include\$(PROCESSOR) \ + -I $(EDK_SOURCE)\Foundation\Efi \ + -I $(EDK_SOURCE)\Foundation\Efi\Include \ + -I $(EDK_SOURCE)\Foundation\Framework \ + -I $(EDK_SOURCE)\Foundation\Framework\Include \ + -I $(EDK_SOURCE)\Foundation\Library\Dxe\Include \ + -I $(EDK_SOURCE)\Foundation\Library\Pei\Include \ + -I $(EDK_SOURCE)\Foundation\Include\Pei \ + $(INC) + +LDRDEP = $(BUILD_DIR)\..\Loader\EfiLdr\Efildr.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\EfiLdrHandoff.h \ + $(BUILD_DIR)\..\Loader\EfiLdr\EfiLoader.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\Debug.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\Debug.h \ + $(BUILD_DIR)\..\Loader\EfiLdr\PeLoader.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\PeLoader.h \ + $(BUILD_DIR)\..\Loader\EfiLdr\Support.c \ + $(BUILD_DIR)\..\Loader\EfiLdr\Support.h + +all : \ + $(BIN_DIR)\BootSect.com \ + $(BIN_DIR)\Bs16.com \ + $(BIN_DIR)\Bs32.com \ + $(BIN_DIR)\Gpt.com \ + $(BIN_DIR)\Mbr.com \ + $(BIN_DIR)\Start64.com \ + $(BIN_DIR)\St16_64.com \ + $(BIN_DIR)\St32_64.com \ + $(BIN_DIR)\Efi64.com2 \ + $(BIN_DIR)\Efildr.efi \ + + +loader : \ + Fv\Efildr \ + Fv\Efildr16 \ + Fv\Efildr20 \ + + +# +# Generate loader object +# +$(BIN_DIR)\BootSect.obj: $(BUILD_DIR)\..\Loader\BootSector\BootSect.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\BootSect.obj $(BUILD_DIR)\..\Loader\BootSector\BootSect.asm + +$(BIN_DIR)\BootSect.com: $(BIN_DIR)\BootSect.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny BootSect.obj,BootSect.com,BootSect.map,,, + +$(BIN_DIR)\Bs16.obj: $(BUILD_DIR)\..\Loader\BootSector\Bs16.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Bs16.obj $(BUILD_DIR)\..\Loader\BootSector\Bs16.asm + +$(BIN_DIR)\Bs16.com: $(BIN_DIR)\Bs16.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Bs16.obj,Bs16.com,Bs16.map,,, + +$(BIN_DIR)\Bs32.obj: $(BUILD_DIR)\..\Loader\BootSector\Bs32.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Bs32.obj $(BUILD_DIR)\..\Loader\BootSector\Bs32.asm + +$(BIN_DIR)\Bs32.com: $(BIN_DIR)\Bs32.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Bs32.obj,Bs32.com,Bs32.map,,, + +$(BIN_DIR)\Gpt.obj: $(BUILD_DIR)\..\Loader\BootSector\Gpt.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Gpt.obj $(BUILD_DIR)\..\Loader\BootSector\Gpt.asm + +$(BIN_DIR)\Gpt.com: $(BIN_DIR)\Gpt.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Gpt.obj,Gpt.com,Gpt.map,,, + +$(BIN_DIR)\Mbr.obj: $(BUILD_DIR)\..\Loader\BootSector\Mbr.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Mbr.obj $(BUILD_DIR)\..\Loader\BootSector\Mbr.asm + +$(BIN_DIR)\Mbr.com: $(BIN_DIR)\Mbr.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Mbr.obj,Mbr.com,Mbr.map,,, + +$(BIN_DIR)\Start64.obj: $(BUILD_DIR)\..\Loader\BootSector\Start64.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Start64.obj $(BUILD_DIR)\..\Loader\BootSector\Start64.asm + +$(BIN_DIR)\Start64.com: $(BIN_DIR)\Start64.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Start64.obj,Start64.com,Start64.map,,, + +$(BIN_DIR)\St16_64.obj: $(BUILD_DIR)\..\Loader\BootSector\St16_64.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\St16_64.obj $(BUILD_DIR)\..\Loader\BootSector\St16_64.asm + +$(BIN_DIR)\St16_64.com: $(BIN_DIR)\St16_64.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny St16_64.obj,St16_64.com,St16_64.map,,, + +$(BIN_DIR)\St32_64.obj: $(BUILD_DIR)\..\Loader\BootSector\St32_64.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\St32_64.obj $(BUILD_DIR)\..\Loader\BootSector\St32_64.asm + +$(BIN_DIR)\St32_64.com: $(BIN_DIR)\St32_64.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny St32_64.obj,St32_64.com,St32_64.map,,, + +$(BIN_DIR)\Efi64.obj: $(BUILD_DIR)\..\Loader\BootSector\Efi64.asm + $(ASM16) /c /omf /Fo$(BIN_DIR)\Efi64.obj $(BUILD_DIR)\..\Loader\BootSector\Efi64.asm + +$(BIN_DIR)\Efi64.com: $(BIN_DIR)\Efi64.obj + cd $(BIN_DIR) + $(ASMLINK16) /tiny Efi64.obj,Efi64.com,Efi64.map,,, + +$(BIN_DIR)\Efi64.com2: $(BIN_DIR)\Efi64.com + $(TOOLBIN_DIR)\Splitfile $(BIN_DIR)\Efi64.com 135168 + +$(BIN_DIR)\Efildr.obj: $(LDRDEP) + $(CC) $(C_FLAGS) $(BUILD_DIR)\..\Loader\EfiLdr\Efildr.c + +$(BIN_DIR)\Efildr.dll: $(BIN_DIR)\Efildr.obj + $(LINK) /nologo /MACHINE:AMD64 /SUBSYSTEM:CONSOLE /NODEFAULTLIB /INCREMENTAL:NO \ + /MAP /FIXED /BASE:0x00010000 /OPT:REF /ALIGN:32 /MERGE:.data=.text \ + /MERGE:.rdata=.text /DRIVER /ENTRY:EfiLoader $(BIN_DIR)\Efildr.obj \ + $(BIN_DIR)\CompilerStub.lib $(BIN_DIR)\EfiCommonLib.lib $(BIN_DIR)\PeiLib.lib \ + /OUT:$(BIN_DIR)\Efildr.dll /IGNORE:4078,4096 + +$(BIN_DIR)\Efildr.efi: $(BIN_DIR)\Efildr.dll + $(TOOLBIN_DIR)\FwImage app $(BIN_DIR)\Efildr.dll $(BIN_DIR)\Efildr.efi + +# +# Generate loader binary +# +Fv\EfiMain.z : Fv\EfiMain.fv + $(TOOLBIN_DIR)\Eficompress -tTiano Fv\EfiMain.fv Fv\EfiMain.z + +Fv\DxeMain.z : $(BIN_DIR)\DxeMain.efi + $(TOOLBIN_DIR)\Eficompress -tTiano $(BIN_DIR)\DxeMain.efi Fv\DxeMain.z + +Fv\DxeIpl.z : $(BIN_DIR)\DxeIpl.efi + $(TOOLBIN_DIR)\Eficompress -tTiano $(BIN_DIR)\DxeIpl.efi Fv\DxeIpl.z + +Fv\Efildr64: $(BIN_DIR)\Efildr.efi Fv\DxeIpl.z Fv\DxeMain.z Fv\EfiMain.z + $(TOOLBIN_DIR)\Efildrimage Fv\Efildr64 $(BIN_DIR)\Efildr.efi Fv\DxeIpl.z Fv\DxeMain.z Fv\EfiMain.z + +Fv\Efildr: $(BIN_DIR)\Start64.com $(BIN_DIR)\Efi64.com2 Fv\Efildr64 + copy /b $(BIN_DIR)\Start64.com+$(BIN_DIR)\Efi64.com2+Fv\Efildr64 Fv\EfildrPure + $(TOOLBIN_DIR)\GenPage Fv\EfildrPure Fv\Efildr + +Fv\Efildr16: $(BIN_DIR)\St16_64.com $(BIN_DIR)\Efi64.com2 Fv\Efildr64 + copy /b $(BIN_DIR)\St16_64.com+$(BIN_DIR)\Efi64.com2+Fv\Efildr64 Fv\Efildr16Pure + $(TOOLBIN_DIR)\GenPage Fv\Efildr16Pure Fv\Efildr16 + +Fv\Efildr20: $(BIN_DIR)\St32_64.com $(BIN_DIR)\Efi64.com2 Fv\Efildr64 + copy /b $(BIN_DIR)\St32_64.com+$(BIN_DIR)\Efi64.com2+Fv\Efildr64 Fv\Efildr20Pure + $(TOOLBIN_DIR)\GenPage Fv\Efildr20Pure Fv\Efildr20 + diff --git a/DuetPkg/EfiLdr/efildr.c b/DuetPkg/EfiLdr/efildr.c new file mode 100644 index 0000000000..5cf7db6eb6 --- /dev/null +++ b/DuetPkg/EfiLdr/efildr.c @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + EfiLdr.c + +Abstract: + +Revision History: + +--*/ + +// +// BUGBUG, include all C files +// +#include "EfiLoader.c" +#include "PeLoader.c" +#include "Support.c" +#include "Debug.c" + diff --git a/DuetPkg/FSVariable/FSVariable.c b/DuetPkg/FSVariable/FSVariable.c new file mode 100644 index 0000000000..0413691067 --- /dev/null +++ b/DuetPkg/FSVariable/FSVariable.c @@ -0,0 +1,1356 @@ +/*++ + +Copyright (c) 2006 - 2007, 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. + +Module Name: + + FSVariable.c + +Abstract: + + Provide support functions for variable services. + +--*/ + +#include "FSVariable.h" + +VARIABLE_STORE_HEADER mStoreHeaderTemplate = { + VARIABLE_STORE_SIGNATURE, + VOLATILE_VARIABLE_STORE_SIZE, + VARIABLE_STORE_FORMATTED, + VARIABLE_STORE_HEALTHY, + 0, + 0 +}; + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +VARIABLE_GLOBAL *mGlobal; + +STATIC +VOID +EFIAPI +OnVirtualAddressChange ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +VOID +EFIAPI +OnSimpleFileSystemInstall ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code checks if variable header is valid or not. + +Arguments: + Variable Pointer to the Variable Header. + +Returns: + TRUE Variable header is valid. + FALSE Variable header is not valid. + +--*/ +{ + if (Variable == NULL || + Variable->StartId != VARIABLE_DATA || + (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE + ) { + return FALSE; + } + + return TRUE; +} + +STATIC +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the current status of Variable Store. + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + EfiRaw Variable store status is raw + EfiValid Variable store status is valid + EfiInvalid Variable store status is invalid + +--*/ +{ + if ((VarStoreHeader->Signature == mStoreHeaderTemplate.Signature) && + (VarStoreHeader->Format == mStoreHeaderTemplate.Format) && + (VarStoreHeader->State == mStoreHeaderTemplate.State) + ) { + return EfiValid; + } else if (VarStoreHeader->Signature == VAR_DEFAULT_VALUE_32 && + VarStoreHeader->Size == VAR_DEFAULT_VALUE_32 && + VarStoreHeader->Format == VAR_DEFAULT_VALUE && + VarStoreHeader->State == VAR_DEFAULT_VALUE + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +STATIC +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the variable data. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + UINT8* Pointer to Variable Data + +--*/ +{ + // + // Be careful about pad size for alignment + // + return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize)); +} + +STATIC +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + This code gets the pointer to the next variable header. + +Arguments: + + Variable Pointer to the Variable Header. + +Returns: + + VARIABLE_HEADER* Pointer to next variable header. + +--*/ +{ + if (!IsValidVariableHeader (Variable)) { + return NULL; + } + // + // Be careful about pad size for alignment + // + return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize)); +} + +STATIC +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +/*++ + +Routine Description: + + This code gets the pointer to the last variable memory pointer byte + +Arguments: + + VarStoreHeader Pointer to the Variable Store Header. + +Returns: + + VARIABLE_HEADER* Pointer to last unavailable Variable Header + +--*/ +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size); +} + +BOOLEAN +ExistNewerVariable ( + IN VARIABLE_HEADER *Variable + ) +/*++ + +Routine Description: + + Check if exist newer variable when doing reclaim + +Arguments: + + Variable Pointer to start position + +Returns: + + TRUE - Exists another variable, which is newer than the current one + FALSE - Doesn't exist another vairable which is newer than the current one + +--*/ +{ + VARIABLE_HEADER *NextVariable; + CHAR16 *VariableName; + EFI_GUID *VendorGuid; + + VendorGuid = &Variable->VendorGuid; + VariableName = GET_VARIABLE_NAME_PTR(Variable); + + NextVariable = GetNextVariablePtr (Variable); + while (IsValidVariableHeader (NextVariable)) { + if ((NextVariable->State == VAR_ADDED) || (NextVariable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + // + // If match Guid and Name + // + if (CompareGuid (VendorGuid, &NextVariable->VendorGuid)) { + if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (NextVariable), StrSize (VariableName)) == 0) { + return TRUE; + } + } + } + NextVariable = GetNextVariablePtr (NextVariable); + } + return FALSE; +} + +STATIC +EFI_STATUS +Reclaim ( + IN VARIABLE_STORAGE_TYPE StorageType, + IN VARIABLE_HEADER *CurrentVariable OPTIONAL + ) +/*++ + +Routine Description: + + Variable store garbage collection and reclaim operation + +Arguments: + + IsVolatile The variable store is volatile or not, + if it is non-volatile, need FTW + CurrentVairable If it is not NULL, it means not to process + current variable for Reclaim. + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *NextVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINT8 *ValidBuffer; + UINTN ValidBufferSize; + UINTN VariableSize; + UINT8 *CurrPtr; + EFI_STATUS Status; + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType]; + + // + // Start Pointers for the variable. + // + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + + + // + // To make the reclaim, here we just allocate a memory that equal to the original memory + // + ValidBufferSize = sizeof (VARIABLE_STORE_HEADER) + VariableStoreHeader->Size; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + ValidBufferSize, + &ValidBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CurrPtr = ValidBuffer; + + // + // Copy variable store header + // + CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER)); + CurrPtr += sizeof (VARIABLE_STORE_HEADER); + + // + // Start Pointers for the variable. + // + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + + + ValidBufferSize = sizeof (VARIABLE_STORE_HEADER); + while (IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + // + // State VAR_ADDED or VAR_IN_DELETED_TRANSITION are to kept, + // The CurrentVariable, is also saved, as SetVariable may fail due to lack of space + // + if (Variable->State == VAR_ADDED) { + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + ValidBufferSize += VariableSize; + CurrPtr += VariableSize; + } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) { + // + // As variables that with the same guid and name may exist in NV due to power failure during SetVariable, + // we will only save the latest valid one + // + if (!ExistNewerVariable(Variable)) { + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + // + // If CurrentVariable == Variable, mark as VAR_IN_DELETED_TRANSITION + // + if (Variable != CurrentVariable){ + ((VARIABLE_HEADER *)CurrPtr)->State = VAR_ADDED; + } + CurrPtr += VariableSize; + ValidBufferSize += VariableSize; + } + } + Variable = NextVariable; + } + + // + // TODO: cannot restore to original state, basic FTW needed + // + Status = mGlobal->VariableStore[StorageType]->Erase ( + mGlobal->VariableStore[StorageType] + ); + Status = mGlobal->VariableStore[StorageType]->Write ( + mGlobal->VariableStore[StorageType], + 0, + ValidBufferSize, + ValidBuffer + ); + + // ASSERT_EFI_ERROR (Status); + + mGlobal->LastVariableOffset[StorageType] = ValidBufferSize; + gBS->FreePool (ValidBuffer); + + return Status; +} + +STATIC +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of the variable to be found + VendorGuid Vendor GUID to be found. + PtrTrack Variable Track Pointer structure that contains + Variable Information. + Contains the pointer of Variable header. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + EFI_SUCCESS - Find the specified variable + EFI_NOT_FOUND - Not found + +--*/ +{ + VARIABLE_HEADER *Variable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINTN Index; + VARIABLE_HEADER *InDeleteVariable; + UINTN InDeleteIndex; + VARIABLE_HEADER *InDeleteStartPtr; + VARIABLE_HEADER *InDeleteEndPtr; + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + InDeleteVariable = NULL; + InDeleteIndex = (UINTN)-1; + InDeleteStartPtr = NULL; + InDeleteEndPtr = NULL; + + for (Index = 0; Index < MaxType; Index ++) { + // + // 0: Non-Volatile, 1: Volatile + // + VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Index]; + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + + // + // Find the variable by walk through non-volatile and volatile variable store + // + PtrTrack->StartPtr = Variable; + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader); + + while (IsValidVariableHeader (Variable) && (Variable < PtrTrack->EndPtr)) { + if (Variable->State == VAR_ADDED) { + if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable; + PtrTrack->Type = (VARIABLE_STORAGE_TYPE) Index; + return EFI_SUCCESS; + } else { + if (CompareGuid (VendorGuid, &Variable->VendorGuid)) { + if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), StrSize (VariableName))) { + PtrTrack->CurrPtr = Variable; + PtrTrack->Type = (VARIABLE_STORAGE_TYPE) Index; + return EFI_SUCCESS; + } + } + } + } + } else if (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) { + // + // VAR_IN_DELETED_TRANSITION should also be checked. + // + if (!EfiAtRuntime () || (Variable->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + if (VariableName[0] == 0) { + InDeleteVariable = Variable; + InDeleteIndex = Index; + InDeleteStartPtr = PtrTrack->StartPtr; + InDeleteEndPtr = PtrTrack->EndPtr; + } else { + if (CompareGuid (VendorGuid, &Variable->VendorGuid)) { + if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), StrSize (VariableName))) { + InDeleteVariable = Variable; + InDeleteIndex = Index; + InDeleteStartPtr = PtrTrack->StartPtr; + InDeleteEndPtr = PtrTrack->EndPtr; + } + } + } + } + } + + Variable = GetNextVariablePtr (Variable); + } + // + // While (...) + // + } + // + // for (...) + // + + // + // if VAR_IN_DELETED_TRANSITION found, and VAR_ADDED not found, + // we return it. + // + if (InDeleteVariable != NULL) { + PtrTrack->CurrPtr = InDeleteVariable; + PtrTrack->Type = (VARIABLE_STORAGE_TYPE) InDeleteIndex; + PtrTrack->StartPtr = InDeleteStartPtr; + PtrTrack->EndPtr = InDeleteEndPtr; + return EFI_SUCCESS; + } + + PtrTrack->CurrPtr = NULL; + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +/*++ + +Routine Description: + + This code finds variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes OPTIONAL Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Find existing variable + // + Status = FindVariable (VariableName, VendorGuid, &Variable); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + // + // Get data size + // + VarDataSize = Variable.CurrPtr->DataSize; + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +/*++ + +Routine Description: + + This code Finds the Next available variable + +Arguments: + + VariableNameSize Size of the variable + VariableName Pointer to variable name + VendorGuid Variable Vendor Guid + +Returns: + + EFI STATUS + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (VariableName, VendorGuid, &Variable); + + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + return Status; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (TRUE) { + // + // The order we find variable is: 1). NonVolatile; 2). Volatile + // If both volatile and non-volatile variable store are parsed, + // return not found + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + if (Variable.Type == Volatile) { + // + // Since we met the end of Volatile storage, we have parsed all the stores. + // + return EFI_NOT_FOUND; + } + + // + // End of NonVolatile, continue to parse Volatile + // + Variable.Type = Volatile; + Variable.StartPtr = (VARIABLE_HEADER *) ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile] + 1); + Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[Volatile]); + + Variable.CurrPtr = Variable.StartPtr; + if (!IsValidVariableHeader (Variable.CurrPtr)) { + continue; + } + } + // + // Variable is found + // + if (IsValidVariableHeader (Variable.CurrPtr) && + ((Variable.CurrPtr->State == VAR_ADDED) || + (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)))) { + if (!EfiAtRuntime () || (Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + VarNameSize = Variable.CurrPtr->NameSize; + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GET_VARIABLE_NAME_PTR (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + } + } + + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +/*++ + +Routine Description: + + This code sets variable in storage blocks (Volatile or Non-Volatile) + +Arguments: + + VariableName Name of Variable to be found + VendorGuid Variable vendor GUID + Attributes Attribute value of the variable found + DataSize Size of Data found. If size is less than the + data, this value contains the required size. + Data Data pointer + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter + EFI_SUCCESS - Set successfully + EFI_OUT_OF_RESOURCES - Resource not enough to set variable + EFI_NOT_FOUND - Not found + EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure + EFI_WRITE_PROTECTED - Variable is read-only + +--*/ +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN VarNameSize; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarSize; + UINT8 State; + BOOLEAN Reclaimed; + VARIABLE_STORAGE_TYPE StorageType; + + Reclaimed = FALSE; + + // + // Check input parameters + // + + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Make sure if runtime bit is set, boot service bit is set also + // + if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + return EFI_INVALID_PARAMETER; + } + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K) + // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others. + // + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) { + return EFI_INVALID_PARAMETER; + } + } else { + if ((DataSize > MAX_VARIABLE_SIZE) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) { + return EFI_INVALID_PARAMETER; + } + } +#else + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes. + // + if ((DataSize > MAX_VARIABLE_SIZE) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) { + return EFI_INVALID_PARAMETER; + } +#endif + // + // Check whether the input variable is already existed + // + + Status = FindVariable (VariableName, VendorGuid, &Variable); + + if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) { + // + // Update/Delete existing variable + // + + if (EfiAtRuntime ()) { + // + // If EfiAtRuntime and the variable is Volatile and Runtime Access, + // the volatile is ReadOnly, and SetVariable should be aborted and + // return EFI_WRITE_PROTECTED. + // + if (Variable.Type == Volatile) { + return EFI_WRITE_PROTECTED; + } + // + // Only variable have NV attribute can be updated/deleted in Runtime + // + if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Setting a data variable with no access, or zero DataSize attributes + // specified causes it to be deleted. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + // + // Found this variable in storage + // + State = Variable.CurrPtr->State; + State &= VAR_DELETED; + + Status = mGlobal->VariableStore[Variable.Type]->Write ( + mGlobal->VariableStore[Variable.Type], + VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr), + sizeof (Variable.CurrPtr->State), + &State + ); + // + // NOTE: Write operation at least can write data to memory cache + // Discard file writing failure here. + // + return EFI_SUCCESS; + } + + // + // Found this variable in storage + // If the variable is marked valid and the same data has been passed in + // then return to the caller immediately. + // + if ((Variable.CurrPtr->DataSize == DataSize) && + (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0) + ) { + return EFI_SUCCESS; + } else if ((Variable.CurrPtr->State == VAR_ADDED) || + (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + // + // Mark the old variable as in delete transition + // + State = Variable.CurrPtr->State; + State &= VAR_IN_DELETED_TRANSITION; + + Status = mGlobal->VariableStore[Variable.Type]->Write ( + mGlobal->VariableStore[Variable.Type], + VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr), + sizeof (Variable.CurrPtr->State), + &State + ); + // + // NOTE: Write operation at least can write data to memory cache + // Discard file writing failure here. + // + } + } else if (Status == EFI_NOT_FOUND) { + // + // Create a new variable + // + + // + // Make sure we are trying to create a new variable. + // Setting a data variable with no access, or zero DataSize attributes means to delete it. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + return EFI_NOT_FOUND; + } + // + // Only variable have NV|RT attribute can be created in Runtime + // + if (EfiAtRuntime () && + (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) { + return EFI_INVALID_PARAMETER; + } + + } else { + // + // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable(). + // + return Status; + } + + // + // Function part - create a new variable and copy the data. + // Both update a variable and create a variable will come here. + // We can firstly write all the data in memory, then write them to file + // This can reduce the times of write operation + // + + NextVariable = (VARIABLE_HEADER *) mGlobal->Scratch; + + NextVariable->StartId = VARIABLE_DATA; + NextVariable->Attributes = Attributes; + NextVariable->State = VAR_ADDED; + NextVariable->Reserved = 0; + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = StrSize (VariableName); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarDataOffset), + Data, + DataSize + ); + CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + // + // There will be pad bytes after Data, the NextVariable->NameSize and + // NextVariable->DataSize should not include pad size so that variable + // service can get actual size in GetVariable + // + NextVariable->NameSize = (UINT32)VarNameSize; + NextVariable->DataSize = (UINT32)DataSize; + + // + // The actual size of the variable that stores in storage should + // include pad size. + // VarDataOffset: offset from begin of current variable header + // + VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize); + + StorageType = (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile; + + if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) > + ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size + ) { + if ((StorageType == NonVolatile) && EfiAtRuntime ()) { + return EFI_OUT_OF_RESOURCES; + } + // + // Perform garbage collection & reclaim operation + // + Status = Reclaim (StorageType, Variable.CurrPtr); + if (EFI_ERROR (Status)) { + // + // Reclaim error + // we cannot restore to original state, fetal error, report to user + // + DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status)); + return Status; + } + // + // If still no enough space, return out of resources + // + if ((UINT32) (VarSize + mGlobal->LastVariableOffset[StorageType]) > + ((VARIABLE_STORE_HEADER *) mGlobal->VariableBase[StorageType])->Size + ) { + return EFI_OUT_OF_RESOURCES; + } + + Reclaimed = TRUE; + } + Status = mGlobal->VariableStore[StorageType]->Write ( + mGlobal->VariableStore[StorageType], + mGlobal->LastVariableOffset[StorageType], + VarSize, + NextVariable + ); + // + // NOTE: Write operation at least can write data to memory cache + // Discard file writing failure here. + // + mGlobal->LastVariableOffset[StorageType] += VarSize; + + // + // Mark the old variable as deleted + // + if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) { + State = Variable.CurrPtr->State; + State &= VAR_DELETED; + + Status = mGlobal->VariableStore[StorageType]->Write ( + mGlobal->VariableStore[StorageType], + VARIABLE_MEMBER_OFFSET (State, (UINTN) Variable.CurrPtr - (UINTN) Variable.StartPtr), + sizeof (Variable.CurrPtr->State), + &State + ); + // + // NOTE: Write operation at least can write data to memory cache + // Discard file writing failure here. + // + } + + return EFI_SUCCESS; +} + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +EFI_STATUS +EFIAPI +QueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +/*++ + +Routine Description: + + This code returns information about the EFI variables. + +Arguments: + + Attributes Attributes bitmask to specify the type of variables + on which to return information. + MaximumVariableStorageSize Pointer to the maximum size of the storage space available + for the EFI variables associated with the attributes specified. + RemainingVariableStorageSize Pointer to the remaining size of the storage space available + for the EFI variables associated with the attributes specified. + MaximumVariableSize Pointer to the maximum size of the individual EFI variables + associated with the attributes specified. + +Returns: + + EFI STATUS + EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied. + EFI_SUCCESS - Query successfully. + EFI_UNSUPPORTED - The attribute is not supported on this platform. + +--*/ +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *NextVariable; + UINT64 VariableSize; + VARIABLE_STORE_HEADER *VariableStoreHeader; + + if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) { + return EFI_INVALID_PARAMETER; + } + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) { + // + // Make sure the Attributes combination is supported by the platform. + // + return EFI_UNSUPPORTED; + } +#else + if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) { + // + // Make sure the Attributes combination is supported by the platform. + // + return EFI_UNSUPPORTED; + } +#endif + else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + // + // Make sure if runtime bit is set, boot service bit is set also. + // + return EFI_INVALID_PARAMETER; + } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { + // + // Make sure RT Attribute is set if we are in Runtime phase. + // + return EFI_INVALID_PARAMETER; + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) mGlobal->VariableBase[ + (Attributes & EFI_VARIABLE_NON_VOLATILE) ? NonVolatile : Volatile + ]; + // + // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize + // with the storage size (excluding the storage header size). + // + *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); + *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); + + // + // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size. + // + *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER); + +#if (EFI_SPECIFICATION_VERSION >= 0x0002000A) + // + // Harware error record variable needs larger size. + // + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER); + } +#endif + + // + // Point to the starting address of the variables. + // + Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + + // + // Now walk through the related variable store. + // + while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) { + NextVariable = GetNextVariablePtr (Variable); + VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable; + + if (EfiAtRuntime ()) { + // + // we don't take the state of the variables in mind + // when calculating RemainingVariableStorageSize, + // since the space occupied by variables not marked with + // VAR_ADDED is not allowed to be reclaimed in Runtime. + // + *RemainingVariableStorageSize -= VariableSize; + } else { + // + // Only care about Variables with State VAR_ADDED,because + // the space not marked as VAR_ADDED is reclaimable now. + // + if ((Variable->State == VAR_ADDED) || + (Variable->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + *RemainingVariableStorageSize -= VariableSize; + } + } + + // + // Go to the next one + // + Variable = NextVariable; + } + + if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) { + *MaximumVariableSize = 0; + } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) { + *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER); + } + + return EFI_SUCCESS; +} +#endif + +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + This function does initialization for variable services + +Arguments: + + ImageHandle - The firmware allocated handle for the EFI image. + SystemTable - A pointer to the EFI System Table. + +Returns: + + Status code. + + EFI_NOT_FOUND - Variable store area not found. + EFI_SUCCESS - Variable services successfully initialized. + +--*/ +{ + EFI_STATUS Status; + EFI_HANDLE NewHandle; + VS_DEV *Dev; + VOID *HobList; + VARIABLE_HEADER *NextVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntryData; + EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry; + VOID *Buffer; + UINT64 BaseAddress; + UINT64 Length; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + (UINTN) sizeof (VARIABLE_GLOBAL), + &mGlobal + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + + if (EFI_ERROR (Status)) { + return Status; + } + + + for (FlashMapEntryData = NULL; ;) { + Buffer = GetNextGuidHob (&gEfiFlashMapHobGuid, &HobList); + + FlashMapEntryData = (EFI_FLASH_MAP_FS_ENTRY_DATA *) Buffer; + + // + // Get the variable store area + // + if (FlashMapEntryData->AreaType == EFI_FLASH_AREA_EFI_VARIABLES) { + break; + } + } + + if (EFI_ERROR (Status) || FlashMapEntryData == NULL) { + Status = EFI_NOT_FOUND; + return Status; + } + + VariableStoreEntry = FlashMapEntryData->Entries[0]; + + // + // Mark the variable storage region of the FLASH as RUNTIME + // + BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK); + Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress); + Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK); + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor); + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + return Status; + } + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + return Status; + } + + Status = FileStorageConstructor ( + &mGlobal->VariableStore[NonVolatile], + &mGlobal->GoVirtualChildEvent[NonVolatile], + VariableStoreEntry.Base, + (UINT32) VariableStoreEntry.Length, + FlashMapEntryData->VolumeId, + FlashMapEntryData->FilePath + ); + ASSERT_EFI_ERROR (Status); + + // + // Volatile Storage + // + Status = MemStorageConstructor ( + &mGlobal->VariableStore[Volatile], + &mGlobal->GoVirtualChildEvent[Volatile], + VOLATILE_VARIABLE_STORE_SIZE + ); + ASSERT_EFI_ERROR (Status); + + // + // Scratch + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + VARIABLE_SCRATCH_SIZE, + &mGlobal->Scratch + ); + ASSERT_EFI_ERROR (Status); + + // + // 1. NV Storage + // + Dev = DEV_FROM_THIS (mGlobal->VariableStore[NonVolatile]); + VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev); + if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { + if (~VariableStoreHeader->Size == 0) { + VariableStoreHeader->Size = (UINT32) VariableStoreEntry.Length; + } + } + // + // Calculate LastVariableOffset + // + NextVariable = (VARIABLE_HEADER *) (VariableStoreHeader + 1); + while (IsValidVariableHeader (NextVariable)) { + NextVariable = GetNextVariablePtr (NextVariable); + } + mGlobal->LastVariableOffset[NonVolatile] = (UINTN) NextVariable - (UINTN) VariableStoreHeader; + mGlobal->VariableBase[NonVolatile] = VariableStoreHeader; + + // + // Reclaim if remaining space is too small + // + if ((VariableStoreHeader->Size - mGlobal->LastVariableOffset[NonVolatile]) < VARIABLE_RECLAIM_THRESHOLD) { + Status = Reclaim (NonVolatile, NULL); + if (EFI_ERROR (Status)) { + // + // Reclaim error + // we cannot restore to original state + // + DEBUG ((EFI_D_ERROR, "FSVariable: Recalim error (fetal error) - %r\n", Status)); + ASSERT_EFI_ERROR (Status); + } + } + + // + // 2. Volatile Storage + // + Dev = DEV_FROM_THIS (mGlobal->VariableStore[Volatile]); + VariableStoreHeader = (VARIABLE_STORE_HEADER *) VAR_DATA_PTR (Dev); + mGlobal->VariableBase[Volatile] = VAR_DATA_PTR (Dev); + mGlobal->LastVariableOffset[Volatile] = sizeof (VARIABLE_STORE_HEADER); + // + // init store_header & body in memory. + // + mGlobal->VariableStore[Volatile]->Erase (mGlobal->VariableStore[Volatile]); + mGlobal->VariableStore[Volatile]->Write ( + mGlobal->VariableStore[Volatile], + 0, + sizeof (VARIABLE_STORE_HEADER), + &mStoreHeaderTemplate + ); + + + SystemTable->RuntimeServices->GetVariable = GetVariable; + SystemTable->RuntimeServices->GetNextVariableName = GetNextVariableName; + SystemTable->RuntimeServices->SetVariable = SetVariable; + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + SystemTable->RuntimeServices->QueryVariableInfo = QueryVariableInfo; +#endif + + // + // Now install the Variable Runtime Architectural Protocol on a new handle + // + NewHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &NewHandle, + &gEfiVariableArchProtocolGuid, + NULL, + &gEfiVariableWriteArchProtocolGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; + +//Shutdown: +// EfiShutdownRuntimeDriverLib (); +// return Status; +} + + + +STATIC +VOID +EFIAPI +OnVirtualAddressChange ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + + for (Index = 0; Index < MaxType; Index++) { + mGlobal->GoVirtualChildEvent[Index] (Event, mGlobal->VariableStore[Index]); + EfiConvertPointer (0, &mGlobal->VariableStore[Index]); + EfiConvertPointer (0, &mGlobal->VariableBase[Index]); + } + EfiConvertPointer (0, &mGlobal->Scratch); + EfiConvertPointer (0, &mGlobal); +} diff --git a/DuetPkg/FSVariable/FSVariable.dxs b/DuetPkg/FSVariable/FSVariable.dxs new file mode 100644 index 0000000000..e3707dab24 --- /dev/null +++ b/DuetPkg/FSVariable/FSVariable.dxs @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) 2006, 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. + +Module Name: + + FSVariable.dxs + +Abstract: + + Dependency expression source file. + +--*/ +#include "EfiDepex.h" +#include EFI_ARCH_PROTOCOL_DEFINITION (StatusCode) + +DEPENDENCY_START + EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID +DEPENDENCY_END diff --git a/DuetPkg/FSVariable/FSVariable.h b/DuetPkg/FSVariable/FSVariable.h new file mode 100644 index 0000000000..434c302783 --- /dev/null +++ b/DuetPkg/FSVariable/FSVariable.h @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) 2006 - 2007, 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. + +Module Name: + + FSVariable.h + +Abstract: + +--*/ + +#ifndef _FS_VARIABLE_H +#define _FS_VARIABLE_H + +// +// Statements that include other header files +// +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#include "EfiFlashMap.h" +#include "VariableFormat.h" +#include "VariableStorage.h" + +#define VOLATILE_VARIABLE_STORE_SIZE (64 * 1024) +#define VARIABLE_SCRATCH_SIZE (4 * 1024) +#define VARIABLE_RECLAIM_THRESHOLD (1024) + +// +// Define GET_PAD_SIZE to optimize compiler +// +#if ((ALIGNMENT == 0) || (ALIGNMENT == 1)) +#define GET_PAD_SIZE(a) (0) +#else +#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) +#endif + +#define GET_VARIABLE_NAME_PTR(a) (CHAR16 *) ((UINTN) (a) + sizeof (VARIABLE_HEADER)) + +typedef enum { + Physical, + Virtual +} VARIABLE_POINTER_TYPE; + +typedef enum { + NonVolatile, + Volatile, + MaxType +} VARIABLE_STORAGE_TYPE; + +typedef struct { + VARIABLE_HEADER *CurrPtr; + VARIABLE_HEADER *EndPtr; + VARIABLE_HEADER *StartPtr; + VARIABLE_STORAGE_TYPE Type; +} VARIABLE_POINTER_TRACK; + +#define VARIABLE_MEMBER_OFFSET(Member, StartOffset) \ + ( sizeof (VARIABLE_STORE_HEADER) + (StartOffset) + \ + (UINTN) ((UINT8 *) &((VARIABLE_HEADER*) 0)->Member - (UINT8 *) &((VARIABLE_HEADER*) 0)->StartId) \ + ) + + +typedef struct { + EFI_EVENT_NOTIFY GoVirtualChildEvent[MaxType]; + VARIABLE_STORAGE *VariableStore[MaxType]; // Instance of VariableStorage + VOID *VariableBase[MaxType]; // Start address of variable storage + UINTN LastVariableOffset[MaxType]; // The position to write new variable to (index from VariableBase) + VOID *Scratch; // Buffer used during reclaim +} VARIABLE_GLOBAL; + +// +// Functions +// + +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +; + +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +; + +EFI_STATUS +EFIAPI +GetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +; + +EFI_STATUS +EFIAPI +GetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +; + +EFI_STATUS +EFIAPI +SetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +; + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +EFI_STATUS +EFIAPI +QueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +; +#endif // EFI_SPECIFICATION_VERSION >= 0x00020000 + +#endif diff --git a/DuetPkg/FSVariable/FSVariable.inf b/DuetPkg/FSVariable/FSVariable.inf new file mode 100644 index 0000000000..9a9ff7feff --- /dev/null +++ b/DuetPkg/FSVariable/FSVariable.inf @@ -0,0 +1,69 @@ +#/*++ +# +# Copyright (c) 2006 - 2007, 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. +# +# Module Name: +# +# FSVariable.inf +# +# Abstract: +# +# Component description file for variable module +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FSVariable + FILE_GUID = A36495C1-C205-414e-B71F-4BE3476D699C + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + ENTRY_POINT = VariableServiceInitialize + +[Packages] + MdePkg/MdePkg.dec + DuetPkg/DuetPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Sources.common] + FSVariable.h + VariableStorage.h + FSVariable.c + FileStorage.c + MemStorage.c + +[LibraryClasses.common] + PcdLib + BaseMemoryLib + BaseLib + UefiBootServicesTableLib + UefiRuntimeLib + DebugLib + UefiLib + HobLib + DxeServicesTableLib + DevicePathLib + UefiDriverEntryPoint + +[Guids] + gEfiHobListGuid + gEfiFlashMapHobGuid + +[Protocols] + gEfiVariableArchProtocolGuid + gEfiVariableWriteArchProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiBlockIoProtocolGuid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize + diff --git a/DuetPkg/FSVariable/FileStorage.c b/DuetPkg/FSVariable/FileStorage.c new file mode 100644 index 0000000000..4e366de0a4 --- /dev/null +++ b/DuetPkg/FSVariable/FileStorage.c @@ -0,0 +1,441 @@ +/*++ + +Copyright (c) 2006 - 2007, 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. + +Module Name: + + FileStorage.c + +Abstract: + + handles variable store/reads on file + +Revision History + +--*/ +#include "FSVariable.h" + +VOID *mSFSRegistration; + +// +// Prototypes +// + +STATIC +VOID +EFIAPI +OnVirtualAddressChange ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +EFI_STATUS +EFIAPI +FileEraseStore( + IN VARIABLE_STORAGE *This + ); + +STATIC +EFI_STATUS +EFIAPI +FileWriteStore ( + IN VARIABLE_STORAGE *This, + IN UINTN Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +STATIC +EFI_STATUS +OpenStore ( + IN EFI_DEVICE_PATH_PROTOCOL *Device, + IN CHAR16 *FilePathName, + IN UINT64 OpenMode, + OUT EFI_FILE **File + ); + +// +// Implementation below: +// +STATIC +VOID +FileClose ( + IN EFI_FILE *File + ) +{ + EFI_STATUS Status; + + Status = File->Flush (File); + ASSERT_EFI_ERROR (Status); + + Status = File->Close (File); + ASSERT_EFI_ERROR (Status); +} + +EFI_STATUS +CheckStore ( + IN EFI_HANDLE SimpleFileSystemHandle, + IN UINT32 VolumeId, + OUT EFI_DEVICE_PATH_PROTOCOL **Device + ) +{ +#define BLOCK_SIZE 0x200 +#define FAT16_VOLUME_ID_OFFSET 39 +#define FAT32_VOLUME_ID_OFFSET 67 + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINT8 BootSector[BLOCK_SIZE]; + + *Device = NULL; + Status = gBS->HandleProtocol ( + SimpleFileSystemHandle, + &gEfiBlockIoProtocolGuid, // BlockIo should be supported if it supports SimpleFileSystem + (VOID*)&BlkIo + ); + + if (EFI_ERROR (Status)) { + goto ErrHandle; + } + if (!BlkIo->Media->MediaPresent) { + DEBUG ((EFI_D_ERROR, "FileStorage: Media not present!\n")); + Status = EFI_NO_MEDIA; + goto ErrHandle; + } + if (BlkIo->Media->ReadOnly) { + DEBUG ((EFI_D_ERROR, "FileStorage: Media is read-only!\n")); + Status = EFI_ACCESS_DENIED; + goto ErrHandle; + } + + Status = BlkIo->ReadBlocks( + BlkIo, + BlkIo->Media->MediaId, + 0, + BLOCK_SIZE, + BootSector + ); + ASSERT_EFI_ERROR (Status); + if ((*(UINT32 *) &BootSector[FAT16_VOLUME_ID_OFFSET] != VolumeId) && + (*(UINT32 *) &BootSector[FAT32_VOLUME_ID_OFFSET] != VolumeId) + ) { + Status = EFI_NOT_FOUND; + goto ErrHandle; + } + + *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, + &Volume + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +// this routine is still running in BS period, no limitation +// call FileInitStorage(), which load variable content file to memory +// read the store_header, init store_header if it has not been inited (read sth. about format/heathy) +// reclaim space using scratch memory + +STATIC +VOID +EFIAPI +OnSimpleFileSystemInstall ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN HandleSize; + EFI_HANDLE Handle; + EFI_DEVICE_PATH_PROTOCOL *Device; + VS_DEV *Dev; + EFI_FILE *File; + UINTN NumBytes; + + Dev = (VS_DEV *) Context; + + if (VAR_FILE_DEVICEPATH (Dev) != NULL && + !EFI_ERROR (CheckStoreExists (VAR_FILE_DEVICEPATH (Dev))) + ) { + DEBUG ((EFI_D_ERROR, "FileStorage: Already mapped!\n")); + return ; + } + + while (TRUE) { + HandleSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle ( + ByRegisterNotify, + NULL, + mSFSRegistration, + &HandleSize, + &Handle + ); + if (EFI_ERROR (Status)) { + return ; + } + + Status = CheckStore (Handle, VAR_FILE_VOLUMEID (Dev), &Device); + if (!EFI_ERROR (Status)) { + break; + } + } + + VAR_FILE_DEVICEPATH (Dev) = Device; + Status = OpenStore ( + VAR_FILE_DEVICEPATH (Dev), + VAR_FILE_FILEPATH (Dev), + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE, + &File + ); + ASSERT_EFI_ERROR (Status); + + NumBytes = Dev->Size; + Status = File->Write (File, &NumBytes, VAR_DATA_PTR (Dev)); + ASSERT_EFI_ERROR (Status); + FileClose (File); + DEBUG ((EFI_D_ERROR, "FileStorage: Mapped to file!\n")); +} + +EFI_STATUS +FileStorageConstructor ( + OUT VARIABLE_STORAGE **VarStore, + OUT EFI_EVENT_NOTIFY *GoVirtualEvent, + IN EFI_PHYSICAL_ADDRESS NvStorageBase, + IN UINTN Size, + IN UINT32 VolumeId, + IN CHAR16 *FilePath + ) +{ + VS_DEV *Dev; + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof(VS_DEV), &Dev); + ASSERT_EFI_ERROR (Status); + ZeroMem (Dev, sizeof(VS_DEV)); + + Dev->Signature = VARIABLE_STORE_SIGNATURE; + Dev->Size = Size; + VAR_DATA_PTR (Dev) = (UINT8 *) (UINTN) NvStorageBase; + VAR_FILE_VOLUMEID (Dev) = VolumeId; + StrCpy (VAR_FILE_FILEPATH (Dev), FilePath); + Dev->VarStore.Erase = FileEraseStore; + Dev->VarStore.Write = FileWriteStore; + + DEBUG ((EFI_D_ERROR, "FileStorageConstructor(0x%0x:0x%0x): added!\n", NvStorageBase, Size)); + + // add notify on SFS's installation. + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnSimpleFileSystemInstall, + Dev, + &Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify ( + &gEfiSimpleFileSystemProtocolGuid, + Event, + &mSFSRegistration + ); + ASSERT_EFI_ERROR (Status); + + *VarStore = &Dev->VarStore; + *GoVirtualEvent = OnVirtualAddressChange; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +FileEraseStore( + IN VARIABLE_STORAGE *This + ) +{ + EFI_STATUS Status; + VS_DEV *Dev; + EFI_FILE *File; + UINTN NumBytes; + + Status = EFI_SUCCESS; + Dev = DEV_FROM_THIS(This); + + SetMem (VAR_DATA_PTR (Dev), Dev->Size, VAR_DEFAULT_VALUE); + + if (!EfiAtRuntime () && VAR_FILE_DEVICEPATH (Dev) != NULL) { + Status = OpenStore ( + VAR_FILE_DEVICEPATH (Dev), + VAR_FILE_FILEPATH (Dev), + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, + &File + ); + ASSERT_EFI_ERROR (Status); + NumBytes = Dev->Size; + Status = File->Write (File, &NumBytes, VAR_DATA_PTR (Dev)); + ASSERT_EFI_ERROR (Status); + FileClose (File); + } + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +FileWriteStore ( + IN VARIABLE_STORAGE *This, + IN UINTN Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + VS_DEV *Dev; + EFI_FILE *File; + + Status = EFI_SUCCESS; + Dev = DEV_FROM_THIS(This); + + ASSERT (Buffer != NULL); + ASSERT (Offset + BufferSize <= Dev->Size); + + CopyMem (VAR_DATA_PTR (Dev) + Offset, Buffer, BufferSize); + + if (!EfiAtRuntime () && VAR_FILE_DEVICEPATH (Dev) != NULL) { + Status = OpenStore ( + VAR_FILE_DEVICEPATH (Dev), + VAR_FILE_FILEPATH (Dev), + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, + &File + ); + Status = File->SetPosition (File, Offset); + ASSERT_EFI_ERROR (Status); + Status = File->Write (File, &BufferSize, Buffer); + ASSERT_EFI_ERROR (Status); + FileClose (File); + } + return Status; +} + +STATIC +VOID +EFIAPI +OnVirtualAddressChange ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + VS_DEV *Dev; + + Dev = DEV_FROM_THIS (Context); + + EfiConvertPointer (0, &VAR_DATA_PTR (Dev)); + EfiConvertPointer (0, (VOID **) &Dev->VarStore.Erase); + EfiConvertPointer (0, (VOID **) &Dev->VarStore.Write); +} + +STATIC +EFI_STATUS +OpenStore ( + IN EFI_DEVICE_PATH_PROTOCOL *Device, + IN CHAR16 *FilePathName, + IN UINT64 OpenMode, + OUT EFI_FILE **File + ) +{ + 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, + &Volume + ); + 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, + FilePathName, + OpenMode, + 0 + ); + if (EFI_ERROR (Status)) { + *File = NULL; + } + + // + // Close the Root directory + // + Root->Close (Root); + return Status; +} diff --git a/DuetPkg/FSVariable/MemStorage.c b/DuetPkg/FSVariable/MemStorage.c new file mode 100644 index 0000000000..ed72b898f0 --- /dev/null +++ b/DuetPkg/FSVariable/MemStorage.c @@ -0,0 +1,135 @@ +/*++ + +Copyright (c) 2006 - 2007, 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. + +Module Name: + + MemStorage.c + +Abstract: + + handles variable store/reads with emulated memory + +Revision History + +--*/ +#include "FSVariable.h" + +STATIC +VOID +EFIAPI +OnVirtualAddressChange ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +STATIC +EFI_STATUS +EFIAPI +MemEraseStore( + IN VARIABLE_STORAGE *This + ); + +STATIC +EFI_STATUS +EFIAPI +MemWriteStore ( + IN VARIABLE_STORAGE *This, + IN UINTN Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +EFI_STATUS +MemStorageConstructor ( + OUT VARIABLE_STORAGE **VarStore, + OUT EFI_EVENT_NOTIFY *GoVirtualEvent, + IN UINTN Size + ) +{ + EFI_STATUS Status; + VS_DEV *Dev; + + Status = gBS->AllocatePool (EfiRuntimeServicesData, sizeof(VS_DEV), &Dev); + ASSERT_EFI_ERROR (Status); + + ZeroMem (Dev, sizeof(VS_DEV)); + + Dev->Signature = VARIABLE_STORE_SIGNATURE; + Dev->Size = Size; + + Dev->VarStore.Erase = MemEraseStore; + Dev->VarStore.Write = MemWriteStore; + + Status = gBS->AllocatePool (EfiRuntimeServicesData, Size, &VAR_DATA_PTR (Dev)); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_ERROR, "VStorage: Size = 0x%x\n", Size)); + + *VarStore = &Dev->VarStore; + *GoVirtualEvent = OnVirtualAddressChange; + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +OnVirtualAddressChange ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + VS_DEV *Dev; + + Dev = DEV_FROM_THIS (Context); + + EfiConvertPointer (0, &VAR_DATA_PTR (Dev)); + EfiConvertPointer (0, (VOID**)&Dev->VarStore.Erase); + EfiConvertPointer (0, (VOID**)&Dev->VarStore.Write); +} + +STATIC +EFI_STATUS +EFIAPI +MemEraseStore( + IN VARIABLE_STORAGE *This + ) +{ + VS_DEV *Dev; + + Dev = DEV_FROM_THIS(This); + SetMem (VAR_DATA_PTR (Dev), Dev->Size, VAR_DEFAULT_VALUE); + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +EFIAPI +MemWriteStore ( + IN VARIABLE_STORAGE *This, + IN UINTN Offset, + IN UINTN BufferSize, + IN VOID *UserBuffer + ) +{ + VS_DEV *Dev; + + Dev = DEV_FROM_THIS(This); + + ASSERT (Offset + BufferSize < Dev->Size); + + // For better performance + if (VAR_DATA_PTR (Dev) + Offset != UserBuffer) { + CopyMem (VAR_DATA_PTR (Dev) + Offset, UserBuffer, BufferSize); + } + return EFI_SUCCESS; +} diff --git a/DuetPkg/FSVariable/VariableStorage.h b/DuetPkg/FSVariable/VariableStorage.h new file mode 100644 index 0000000000..3ebfaeb5db --- /dev/null +++ b/DuetPkg/FSVariable/VariableStorage.h @@ -0,0 +1,111 @@ +/*++ + +Copyright (c) 2006 - 2007, 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. + +Module Name: + + VariableStorage.h + +Abstract: + + handles variable store/reads with memory and file + +Revision History + +--*/ +#ifndef _VARIABLE_STORAGE_H_ +#define _VARIABLE_STORAGE_H_ + +#define VAR_DEFAULT_VALUE (0xff) +#define VAR_DEFAULT_VALUE_16 EFI_SIGNATURE_16 (VAR_DEFAULT_VALUE, VAR_DEFAULT_VALUE) +#define VAR_DEFAULT_VALUE_32 EFI_SIGNATURE_32 (VAR_DEFAULT_VALUE, VAR_DEFAULT_VALUE, \ + VAR_DEFAULT_VALUE, VAR_DEFAULT_VALUE) + +typedef struct _VARIABLE_STORAGE VARIABLE_STORAGE; + +EFI_STATUS +FileStorageConstructor ( + OUT VARIABLE_STORAGE **VarStore, + OUT EFI_EVENT_NOTIFY *GoVirtualEvent, + IN EFI_PHYSICAL_ADDRESS NvStorageBase, + IN UINTN Size, + IN UINT32 VolumeId, + IN CHAR16 *FilePath + ); + +EFI_STATUS +MemStorageConstructor ( + OUT VARIABLE_STORAGE **VarStore, + OUT EFI_EVENT_NOTIFY *GoVirtualEvent, + IN UINTN Size + ); + +typedef +EFI_STATUS +(EFIAPI *ERASE_STORE) ( + IN VARIABLE_STORAGE *This + ); + +typedef +EFI_STATUS +(EFIAPI *WRITE_STORE) ( + IN VARIABLE_STORAGE *This, + IN UINTN Offset, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +struct _VARIABLE_STORAGE { + + // + // Functions to access the storage + // + ERASE_STORE Erase; + WRITE_STORE Write; +}; + +typedef struct _VS_FILE_INFO { + UINT8 *FileData; // local buffer for reading acceleration + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; // device having storage file + UINT32 VolumeId; + CHAR16 FilePath[256]; +} VS_FILE_INFO; + +typedef struct _VS_MEM_INFO { + UINT8 *MemData; +} VS_MEM_INFO; + +typedef struct _VS_DEV { + UINT32 Signature; + VARIABLE_STORAGE VarStore; + UINTN Size; + + union { + // + // finally visit FileInfo.FileData or MemInfo.MemData + // + UINT8 *Data; + + VS_FILE_INFO FileInfo; + VS_MEM_INFO MemInfo; + } Info; + +} VS_DEV; + +#define DEV_FROM_THIS(a) CR (a, VS_DEV, VarStore, VARIABLE_STORE_SIGNATURE) + +#define VAR_DATA_PTR(a) ((a)->Info.Data) +#define VAR_FILE_DEVICEPATH(a) ((a)->Info.FileInfo.DevicePath) +#define VAR_FILE_VOLUMEID(a) ((a)->Info.FileInfo.VolumeId) +#define VAR_FILE_FILEPATH(a) ((a)->Info.FileInfo.FilePath) + + +#endif diff --git a/DuetPkg/FvbRuntimeService/DUETFwh.dxs b/DuetPkg/FvbRuntimeService/DUETFwh.dxs new file mode 100644 index 0000000000..8895c36a0b --- /dev/null +++ b/DuetPkg/FvbRuntimeService/DUETFwh.dxs @@ -0,0 +1,26 @@ +#/*++ +# +# Copyright (c) 2007, 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. +# +# Module Name: +# +# Nt32Fwh.inf +# +# Abstract: +# +# Component description file for Nt32 Module +# +#--*/ +#include "EfiDepex.h" + + +DEPENDENCY_START + TRUE +DEPENDENCY_END diff --git a/DuetPkg/FvbRuntimeService/DUETFwh.inf b/DuetPkg/FvbRuntimeService/DUETFwh.inf new file mode 100644 index 0000000000..90d73ec433 --- /dev/null +++ b/DuetPkg/FvbRuntimeService/DUETFwh.inf @@ -0,0 +1,62 @@ +#/*++ +# +# Copyright (c) 2007, 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. +# +# Module Name: +# +# DUETFwh.inf +# +# Abstract: +# +# Component description file for DUET Module +# +#--*/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DuetFwh + FILE_GUID = BDFE5FAA-2A35-44bb-B17A-8084D4E2B9E9 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + ENTRY_POINT = FvbInitialize + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + DuetPkg/DuetPkg.dec + #TianoModulePkg/TianoModulePkg.dec + +[Sources.common] + FwBlockService.c + FwBlockService.h + FvbInfo.c + FileIo.c + FileIo.h + +[LibraryClasses] + DevicePathLib + UefiLib + UefiDriverEntryPoint + UefiRuntimeLib + HobLib + +[Guids] + gEfiFlashMapHobGuid + gEfiHobListGuid + gEfiAlternateFvBlockGuid + +[Protocols] + gEfiFvbExtensionProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid + gEfiBlockIoProtocolGuid + diff --git a/DuetPkg/FvbRuntimeService/FWBlockService.c b/DuetPkg/FvbRuntimeService/FWBlockService.c new file mode 100644 index 0000000000..ab1ef25f57 --- /dev/null +++ b/DuetPkg/FvbRuntimeService/FWBlockService.c @@ -0,0 +1,1822 @@ +/**@file +Copyright (c) 2007, 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. + +Module Name: + + FWBlockService.c + +Abstract: + +Revision History + +**/ +#include "FWBlockService.h" +#include "EfiFlashMap.h" +#include "FileIo.h" +#include "FlashLayout.h" + +ESAL_FWB_GLOBAL *mFvbModuleGlobal; +VOID *mSFSRegistration; +#define TRY_ASSIGN(var, value) if(var != NULL) {*var = value;} + +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { + FVB_DEVICE_SIGNATURE, + { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + sizeof (MEMMAP_DEVICE_PATH), + 0 + } + }, + EfiMemoryMappedIO, + 0, + 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } + }, + 0, + { + FvbProtocolGetAttributes, + FvbProtocolSetAttributes, + FvbProtocolGetPhysicalAddress, + FvbProtocolGetBlockSize, + FvbProtocolRead, + FvbProtocolWrite, + FvbProtocolEraseBlocks, + NULL + }, + { + FvbExtendProtocolEraseCustomBlockRange + } +}; + + +EFI_STATUS +FlashFdWrite ( + IN UINTN Address, + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the address + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_FILE *File; + UINTN FileOffset; + UINTN BufferForFile; + UINTN Length; + + Status = EFI_SUCCESS; + CopyMem ((VOID *) Address, Buffer, *NumBytes); + + if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) { + Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) { + FileOffset = 0; + BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset; + Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL])); + } else { + FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset; + BufferForFile = Address; + Length = *NumBytes; + } + + Status = FileWrite (File, FileOffset, BufferForFile, Length); + ASSERT_EFI_ERROR (Status); + FileClose (File); + } + } + return Status; +} + +EFI_STATUS +FlashFdErase ( + IN UINTN Address, + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN UINTN LbaLength + ) +/*++ + +Routine Description: + Erase a certain block from address LbaWriteAddress + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_FILE *File; + UINTN FileOffset; + UINTN BufferForFile; + UINTN Length; + + Status = EFI_SUCCESS; + + SetMem ((VOID *)Address, LbaLength, 0xff); + + if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) { + Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) { + FileOffset = 0; + BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset; + Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL])); + } else { + FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset; + BufferForFile = Address; + Length = LbaLength; + } + + Status = FileWrite (File, FileOffset, BufferForFile, Length); + ASSERT_EFI_ERROR (Status); + FileClose (File); + } + } + return Status; +} + +VOID +EFIAPI +FvbVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Fixup internal data so that EFI and SAL can be call in virtual mode. + Call the passed in Child Notify event and convert the mFvbModuleGlobal + date items to there virtual address. + + mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data + mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common + instance data. + +Arguments: + + (Standard EFI notify event - EFI_EVENT_NOTIFY) + +Returns: + + None + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN Index; + + EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]); + + // + // Convert the base address of all the instances + // + Index = 0; + FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; + while (Index < mFvbModuleGlobal->NumFv) { + EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]); + FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); + Index++; + } + + EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]); + EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal); +} + +EFI_STATUS +GetFvbInstance ( + IN UINTN Instance, + IN ESAL_FWB_GLOBAL *Global, + OUT EFI_FW_VOL_INSTANCE **FwhInstance, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhRecord; + + if (Instance >= Global->NumFv) { + return EFI_INVALID_PARAMETER; + } + // + // Find the right instance of the FVB private data + // + FwhRecord = Global->FvInstance[Virtual]; + while (Instance > 0) { + FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); + Instance--; + } + + *FwhInstance = FwhRecord; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *Address, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the physical address of a memory mapped FV + +Arguments: + Instance - The FV instance whose base address is going to be + returned + Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS + that on successful return, contains the base address + of the firmware volume. + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + *Address = FwhInstance->FvBase[Virtual]; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves attributes, insures positive polarity of attribute bits, returns + resulting attributes in output parameter + +Arguments: + Instance - The FV instance whose attributes is going to be + returned + Attributes - Output buffer which contains attributes + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + *Attributes = FwhInstance->VolumeHeader.Attributes; + + return EFI_SUCCESS; +} + +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress OPTIONAL, + OUT UINTN *LbaLength OPTIONAL, + OUT UINTN *NumOfBlocks OPTIONAL, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Retrieves the starting address of an LBA in an FV + +Arguments: + Instance - The FV instance which the Lba belongs to + Lba - The logical block address + LbaAddress - On output, contains the physical starting address + of the Lba for writing + 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 + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_INVALID_PARAMETER - Instance not found + +--*/ +{ + UINT32 NumBlocks; + UINT32 BlockLength; + UINTN Offset; + EFI_LBA StartLba; + EFI_LBA NextLba; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + StartLba = 0; + Offset = 0; + BlockMap = &(FwhInstance->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) { + *LbaAddress = FwhInstance->FvBase[Virtual] + Offset; + } + + if (LbaLength) { + *LbaLength = BlockLength; + } + + if (NumOfBlocks) { + *NumOfBlocks = (UINTN) (NextLba - Lba); + } + + return EFI_SUCCESS; + } + + StartLba = NextLba; + Offset = Offset + NumBlocks * BlockLength; + BlockMap++; + } +} + +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Reads specified number of bytes into a buffer from the specified block + +Arguments: + Instance - The FV instance to be read from + Lba - The logical block address to be read from + BlockOffset - Offset into the block at which to begin reading + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + Buffer - Pointer to a caller allocated buffer that will be + used to hold the data read + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +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 - Instance not found, or NumBytes, Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES 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 (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if the FV is read enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB2_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes); + + return Status; +} +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Writes specified number of bytes from the input buffer to the block + +Arguments: + Instance - The FV instance to be written to + Lba - The starting logical block index to write to + BlockOffset - Offset into the block at which to begin writing + NumBytes - Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + Buffer - Pointer to a caller allocated buffer that contains + the source for the write + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +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 - Instance not found, or NumBytes, Buffer are NULL + +--*/ +{ + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + // + // Writes are enabled in the init routine itself + // + if (!FwhInstance->WriteEnabled) { + return EFI_ACCESS_DENIED; + } + // + // Check for invalid conditions + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (*NumBytes == 0) { + return EFI_INVALID_PARAMETER; + } + + Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + // + // Perform boundary checks and adjust NumBytes + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + ReturnStatus = FlashFdWrite ( + LbaAddress + BlockOffset, + FwhInstance, + NumBytes, + Buffer + ); + if (EFI_ERROR (ReturnStatus)) { + return ReturnStatus; + } + + return Status; +} + +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Erases and initializes a firmware volume block + +Arguments: + Instance - The FV instance to be erased + Lba - The logical block index to be erased + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +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 - Instance not found + +--*/ +{ + + EFI_FVB_ATTRIBUTES Attributes; + UINTN LbaAddress; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN LbaLength; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + // + // Writes are enabled in the init routine itself + // + if (!FwhInstance->WriteEnabled) { + return EFI_ACCESS_DENIED; + } + // + // Check if the FV is write enabled + // + FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual); + + 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 (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual); + if (EFI_ERROR (Status)) { + return Status; + } + + return FlashFdErase ( + LbaAddress, + FwhInstance, + LbaLength + ); +} + +EFI_STATUS +FvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + Instance - The FV instance to be erased + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetStartLba - Offset into the last block at which to end erasing + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - The firmware volume was erased successfully + 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 - Instance not found + +--*/ +{ + EFI_LBA Index; + UINTN LbaSize; + UINTN ScratchLbaSizeData; + + // + // First LBA. + // + FvbGetLbaAddress (Instance, StartLba, NULL, &LbaSize, NULL, Global, Virtual); + + // + // Use the scratch space as the intermediate buffer to transfer data + // Back up the first LBA in scratch space. + // + FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual); + + // + // erase now + // + FvbEraseBlock (Instance, StartLba, Global, Virtual); + ScratchLbaSizeData = OffsetStartLba; + + // + // write the data back to the first block + // + if (ScratchLbaSizeData > 0) { + FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual); + } + // + // Middle LBAs + // + if (LastLba > (StartLba + 1)) { + for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) { + FvbEraseBlock (Instance, Index, Global, Virtual); + } + } + // + // Last LBAs, the same as first LBAs + // + if (LastLba > StartLba) { + FvbGetLbaAddress (Instance, LastLba, NULL, &LbaSize, NULL, Global, Virtual); + FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual); + FvbEraseBlock (Instance, LastLba, Global, Virtual); + } + + ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1); + + return FvbWriteBlock ( + Instance, + LastLba, + (OffsetLastLba + 1), + &ScratchLbaSizeData, + Global->FvbScratchSpace[Virtual], + Global, + Virtual + ); +} + +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +/*++ + +Routine Description: + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + +Arguments: + Instance - The FV instance whose attributes is going to be + modified + Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + Global - Pointer to ESAL_FWB_GLOBAL that contains all + instance data + Virtual - Whether CPU is in virtual or physical mode + +Returns: + EFI_SUCCESS - Successfully returns + EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified + EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are + in conflict with the capabilities as declared in the + firmware volume header + +--*/ +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FVB_ATTRIBUTES OldAttributes; + EFI_FVB_ATTRIBUTES *AttribPtr; + UINT32 Capabilities; + UINT32 OldStatus; + UINT32 NewStatus; + EFI_STATUS Status; + + // + // Find the right instance of the FVB private data + // + Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual); + ASSERT_EFI_ERROR (Status); + + AttribPtr = (EFI_FVB_ATTRIBUTES *) &(FwhInstance->VolumeHeader.Attributes); + OldAttributes = *AttribPtr; + Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES; + OldStatus = OldAttributes & EFI_FVB2_STATUS; + NewStatus = *Attributes & EFI_FVB2_STATUS; + + // + // 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; +} +// +// FVB protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +/*++ + +Routine Description: + + Retrieves the physical address of the device. + +Arguments: + + This - Calling context + Address - Output buffer containing the address. + +Returns: + +Returns: + EFI_SUCCESS - Successfully returns + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN 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 + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetLbaAddress ( + FvbDevice->Instance, + Lba, + NULL, + BlockSize, + NumOfBlocks, + mFvbModuleGlobal, + EfiGoneVirtual () + ); +} + +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *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 + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES *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 + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +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 + +--*/ +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN NumOfBlocks; + VA_LIST args; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_STATUS Status; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ()); + ASSERT_EFI_ERROR (Status); + + NumOfBlocks = FwhInstance->NumOfBlocks; + + VA_START (args, This); + + do { + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (args, UINT32); + + // + // Check input parameters + // + 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, UINT32); + + while (NumOfLba > 0) { + Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ()); + 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_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); +} + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN 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_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + + return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ()); +} +// +// FVB Extension Protocols +// +EFI_STATUS +EFIAPI +FvbExtendProtocolEraseCustomBlockRange ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +/*++ + +Routine Description: + Erases and initializes a specified range of a firmware volume + +Arguments: + This - Calling context + StartLba - The starting logical block index to be erased + OffsetStartLba - Offset into the starting block at which to + begin erasing + LastLba - The last logical block index to be erased + OffsetStartLba - Offset into the last block at which to end erasing + +Returns: + EFI_SUCCESS - The firmware volume was erased successfully + 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_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This); + + return FvbEraseCustomBlockRange ( + FvbDevice->Instance, + StartLba, + OffsetStartLba, + LastLba, + OffsetLastLba, + mFvbModuleGlobal, + EfiGoneVirtual () + ); +} + +STATIC +EFI_STATUS +ValidateFvHeader ( + 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 *Ptr; + UINT16 HeaderLength; + 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 + // + HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2); + Ptr = (UINT16 *) FwVolHeader; + Checksum = 0; + while (HeaderLength > 0) { + Checksum = Checksum + (*Ptr); + HeaderLength--; + Ptr++; + } + + if (Checksum != 0) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +GetFvbHeader ( + IN OUT VOID **HobList, + OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader, + OUT EFI_PHYSICAL_ADDRESS *BaseAddress OPTIONAL, + OUT UINT32 *VolumeId OPTIONAL, + OUT CHAR16 **MappedFile OPTIONAL, + OUT UINT32 *ActuralSize OPTIONAL, + OUT UINT32 *Offset OPTIONAL, + OUT BOOLEAN *WriteBack OPTIONAL + ) +{ + EFI_STATUS Status; + VOID *Buffer; + EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry; + EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry; + + Status = EFI_SUCCESS; + *FwVolHeader = NULL; + TRY_ASSIGN (WriteBack, FALSE); + + Buffer = GetNextGuidHob (&gEfiFlashMapHobGuid, HobList); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + FlashMapEntry = (EFI_FLASH_MAP_FS_ENTRY_DATA *) Buffer; + FlashMapSubEntry = &FlashMapEntry->Entries[0]; + // + // Check if it is a "FVB" area + // + if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) { + return Status; + } + // + // Check if it is a "real" flash + // + if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) { + return Status; + } + + TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base); + + // + // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver + // + TRY_ASSIGN (VolumeId, FlashMapEntry->VolumeId); + TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize); + TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath)); + TRY_ASSIGN (Offset, FlashMapEntry->Offset); + + DEBUG (( + EFI_D_ERROR, + "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n", + (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length, + (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset + )); + DEBUG (( + EFI_D_ERROR, + "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n", + (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath + )); + *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base); + Status = ValidateFvHeader (*FwVolHeader); + if (EFI_ERROR (Status)) { + // + // Get FvbInfo + // + TRY_ASSIGN (WriteBack, TRUE); + Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader); + DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status)); + ASSERT_EFI_ERROR (Status); + } + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +OnSimpleFileSystemInstall ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN HandleSize; + EFI_HANDLE Handle; + UINTN Instance; + EFI_DEVICE_PATH_PROTOCOL *Device; + EFI_FILE *File; + EFI_FW_VOL_INSTANCE *FwhInstance; + while (TRUE) { + HandleSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle ( + ByRegisterNotify, + NULL, + mSFSRegistration, + &HandleSize, + &Handle + ); + if (Status == EFI_NOT_FOUND) { + break; + } + DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n")); + ASSERT_EFI_ERROR (Status); + // + // Check if this is the storage we care about, and store it in FwhInstance + // + for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) { + Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE); + ASSERT_EFI_ERROR (Status); + + if (FwhInstance->MappedFile[0] == L'\0') { + // + // The instance of FVB isn't mapped to file. + // + continue; + } + + if ((FwhInstance->Device != NULL) && + !EFI_ERROR (CheckStoreExists (FwhInstance->Device)) + ) { + // + // The instance of FVB has already associated to a device + // and the device is not removed from system. + // + DEBUG (( + EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n", + (UINTN) FwhInstance->FvBase[FVB_PHYSICAL], + (UINTN) FwhInstance->Offset + )); + continue; + } + + Status = CheckStore (Handle, FwhInstance->VolumeId, &Device); + if (!EFI_ERROR (Status)) { + // + // Write back memory content to file + // + Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n", + (UINTN) FwhInstance->FvBase[FVB_PHYSICAL], + (UINTN) FwhInstance->Offset + )); + Status = FileWrite ( + File, + 0, + FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset, + FwhInstance->ActuralSize - FwhInstance->Offset + ); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + if (FwhInstance->Device != NULL) { + gBS->FreePool (FwhInstance->Device); + } + FwhInstance->Device = Device; + DEBUG (( + EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n", + (UINTN) FwhInstance->FvBase[FVB_PHYSICAL], + (UINTN) FwhInstance->Offset + )); + } + FileClose (File); + } + } + } + } +} + +STATIC +VOID +FvbInstallSfsNotify ( + VOID +) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OnSimpleFileSystemInstall, + NULL, + &Event + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->RegisterProtocolNotify ( + &gEfiSimpleFileSystemProtocolGuid, + Event, + &mSFSRegistration + ); + ASSERT_EFI_ERROR (Status); +} + + +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; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VOID *HobList; + VOID *FirmwareVolumeHobList; + UINT32 BufferSize; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + UINTN LbaAddress; + EFI_HANDLE FwbHandle; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; + EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath; + FV_DEVICE_PATH TempFvbDevicePathData; + UINT32 MaxLbaSize; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT32 VolumeId; + CHAR16 *MappedFile; + UINT32 ActuralSize; + UINT32 Offset; + BOOLEAN WriteBack; + UINTN NumOfBlocks; + UINTN HeaderLength; + BOOLEAN InstallSfsNotify; + + Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList); + // + // No FV HOBs found + // + ASSERT_EFI_ERROR (Status); + + HeaderLength = 0; + InstallSfsNotify = FALSE; + + // + // Allocate runtime services data for global variable, which contains + // the private data of all firmware volume block instances + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (ESAL_FWB_GLOBAL), + &mFvbModuleGlobal + ); + ASSERT_EFI_ERROR (Status); + // + // Calculate the total size for all firmware volume block instances + // + BufferSize = 0; + FirmwareVolumeHobList = HobList; + do { + Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL); + if (EFI_ERROR (Status)) { + break; + } + + if (FwVolHeader) { + BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + } + } while (TRUE); + + // + // Only need to allocate once. There is only one copy of physical memory for + // the private data of each FV instance. But in virtual mode or in physical + // mode, the address of the the physical memory may be different. + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + BufferSize, + &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] + ); + ASSERT_EFI_ERROR (Status); + + // + // Make a virtual copy of the FvInstance pointer. + // + FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]; + mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance; + + mFvbModuleGlobal->NumFv = 0; + FirmwareVolumeHobList = HobList; + MaxLbaSize = 0; + + // + // Fill in the private data of each firmware volume block instance + // + do { + Status = GetFvbHeader ( + &FirmwareVolumeHobList, &FwVolHeader, + &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset, + &WriteBack + ); + if (EFI_ERROR (Status)) { + break; + } + + if (!FwVolHeader) { + continue; + } + + CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength); + FwVolHeader = &(FwhInstance->VolumeHeader); + + FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress; + FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress; + FwhInstance->Device = NULL; + FwhInstance->Offset = Offset; + + if (*MappedFile != '\0') { + FwhInstance->VolumeId = VolumeId; + FwhInstance->ActuralSize = ActuralSize; + StrCpy (FwhInstance->MappedFile, MappedFile); + + InstallSfsNotify = TRUE; + } else { + FwhInstance->VolumeId = (UINT32) -1; + FwhInstance->ActuralSize = (UINT32) -1; + FwhInstance->MappedFile[0] = L'\0'; + } + + + // + // We may expose readonly FVB in future. + // + FwhInstance->WriteEnabled = TRUE; + EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL); + + LbaAddress = (UINTN) FwhInstance->FvBase[0]; + NumOfBlocks = 0; + + if (FwhInstance->WriteEnabled) { + for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + + LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length; + // + // Get the maximum size of a block. The size will be used to allocate + // buffer for Scratch space, the intermediate buffer for FVB extension + // protocol + // + if (MaxLbaSize < PtrBlockMapEntry->Length) { + MaxLbaSize = PtrBlockMapEntry->Length; + } + + NumOfBlocks += PtrBlockMapEntry->NumBlocks; + } + // + // Write back a healthy FV header + // + if (WriteBack) { + Status = FlashFdErase ( + (UINTN) FwhInstance->FvBase[0], + FwhInstance, + FwVolHeader->BlockMap->Length + ); + + HeaderLength = (UINTN) FwVolHeader->HeaderLength; + + Status = FlashFdWrite ( + (UINTN) FwhInstance->FvBase[0], + FwhInstance, + (UINTN *) &HeaderLength, + (UINT8 *) FwVolHeader + ); + + FwVolHeader->HeaderLength = (UINT16) HeaderLength; + + DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status)); + } + } + // + // The total number of blocks in the FV. + // + FwhInstance->NumOfBlocks = NumOfBlocks; + + // + // Add a FVB Protocol Instance + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + sizeof (EFI_FW_VOL_BLOCK_DEVICE), + &FvbDevice + ); + ASSERT_EFI_ERROR (Status); + + CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE)); + + FvbDevice->Instance = mFvbModuleGlobal->NumFv; + mFvbModuleGlobal->NumFv++; + + // + // Set up the devicepath + // + FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress; + FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1); + + // + // Find a handle with a matching device path that has supports FW Block protocol + // + TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData; + CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH)); + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &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 (EfiIsDevicePathEnd (TempFwbDevicePath)) { + // + // Device allready exists, so reinstall the FVB protocol + // + Status = gBS->HandleProtocol ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &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); + } + // + // Install FVB Extension Protocol on the same handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFvbExtensionProtocolGuid, + &FvbDevice->FvbExtension, + &gEfiAlternateFvBlockGuid, + NULL, + NULL + ); + + ASSERT_EFI_ERROR (Status); + + FwhInstance = (EFI_FW_VOL_INSTANCE *) + ( + (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)) + ); + } while (TRUE); + + // + // Allocate for scratch space, an intermediate buffer for FVB extention + // + Status = gBS->AllocatePool ( + EfiRuntimeServicesData, + MaxLbaSize, + &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] + ); + ASSERT_EFI_ERROR (Status); + + mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]; + + if (InstallSfsNotify) { + FvbInstallSfsNotify (); + } + return EFI_SUCCESS; +} diff --git a/DuetPkg/FvbRuntimeService/FileIo.c b/DuetPkg/FvbRuntimeService/FileIo.c new file mode 100644 index 0000000000..0162b15b19 --- /dev/null +++ b/DuetPkg/FvbRuntimeService/FileIo.c @@ -0,0 +1,210 @@ +/**@file +Copyright (c) 2007, 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. + +Module Name: + + FileIo.c + +Abstract: + + File operation for Firmware volume block driver + +**/ +#include "FileIo.h" + +// +// Variable storage hot plug is supported but there are still some restrictions: +// After plugging the storage back, +// 1. Still use memory as NV if newly plugged storage is not same as the original one +// 2. Still use memory as NV if there are some update operation during storage is unplugged. +// + + +EFI_STATUS +FileWrite ( + IN EFI_FILE *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; +} + +EFI_STATUS +CheckStore ( + IN EFI_HANDLE SimpleFileSystemHandle, + IN UINT32 VolumeId, + OUT EFI_DEVICE_PATH_PROTOCOL **Device + ) +{ +#define BLOCK_SIZE 0x200 +#define FAT16_VOLUME_ID_OFFSET 39 +#define FAT32_VOLUME_ID_OFFSET 67 + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + UINT8 BootSector[BLOCK_SIZE]; + + *Device = NULL; + Status = gBS->HandleProtocol ( + SimpleFileSystemHandle, + &gEfiBlockIoProtocolGuid, // BlockIo should be supported if it supports SimpleFileSystem + (VOID*)&BlkIo + ); + + if (EFI_ERROR (Status)) { + goto ErrHandle; + } + if (!BlkIo->Media->MediaPresent) { + DEBUG ((EFI_D_ERROR, "FwhMappedFile: Media not present!\n")); + Status = EFI_NO_MEDIA; + goto ErrHandle; + } + if (BlkIo->Media->ReadOnly) { + DEBUG ((EFI_D_ERROR, "FwhMappedFile: Media is read-only!\n")); + Status = EFI_ACCESS_DENIED; + goto ErrHandle; + } + + Status = BlkIo->ReadBlocks( + BlkIo, + BlkIo->Media->MediaId, + 0, + BLOCK_SIZE, + BootSector + ); + ASSERT_EFI_ERROR (Status); + if ((*(UINT32 *) &BootSector[FAT16_VOLUME_ID_OFFSET] != VolumeId) && + (*(UINT32 *) &BootSector[FAT32_VOLUME_ID_OFFSET] != VolumeId) + ) { + Status = EFI_NOT_FOUND; + goto ErrHandle; + } + + *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, + &Volume + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +VOID +FileClose ( + IN EFI_FILE *File + ) +{ + File->Flush (File); + File->Close (File); +} +EFI_STATUS +FileOpen ( + IN EFI_DEVICE_PATH_PROTOCOL *Device, + IN CHAR16 *MappedFile, + OUT EFI_FILE **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, + &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; +} diff --git a/DuetPkg/FvbRuntimeService/FileIo.h b/DuetPkg/FvbRuntimeService/FileIo.h new file mode 100644 index 0000000000..67068bfee2 --- /dev/null +++ b/DuetPkg/FvbRuntimeService/FileIo.h @@ -0,0 +1,58 @@ +/**@file +Copyright (c) 2007, 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. + +Module Name: + + FileIo.h + +Abstract: + + File operation for Firmware volume block driver + +**/ +#ifndef _FW_BLOCK_SERVICE_FILE_IO_H +#define _FW_BLOCK_SERVICE_FILE_IO_H + +#include "FwBlockService.h" + +EFI_STATUS +FileWrite ( + IN EFI_FILE *File, + IN UINTN Offset, + IN UINTN Buffer, + IN UINTN Size + ); + +EFI_STATUS +CheckStore ( + IN EFI_HANDLE SimpleFileSystemHandle, + IN UINT32 VolumeId, + 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 **File, + IN UINT64 OpenMode + ); + +VOID +FileClose ( + IN EFI_FILE *File + ); + +#endif // _FW_BLOCK_SERVICE_FILE_IO_H diff --git a/DuetPkg/FvbRuntimeService/FvbInfo.c b/DuetPkg/FvbRuntimeService/FvbInfo.c new file mode 100644 index 0000000000..2642e5941f --- /dev/null +++ b/DuetPkg/FvbRuntimeService/FvbInfo.c @@ -0,0 +1,121 @@ +/**@file +Copyright (c) 2007, 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. + +Module Name: + + FvbInfo.c + +Abstract: + + Defines data structure that is the volume header found.These data is intent + to decouple FVB driver with FV header. + +**/ +#include "FileIo.h" +#include "FlashLayout.h" + +typedef struct { + UINT64 FvLength; + EFI_FIRMWARE_VOLUME_HEADER FvbInfo; + EFI_FV_BLOCK_MAP_ENTRY End; +} EFI_FVB_MEDIA_INFO; + +#define FVB_MEDIA_BLOCK_SIZE FIRMWARE_BLOCK_SIZE +#define RECOVERY_BOIS_BLOCK_NUM FIRMWARE_BLOCK_NUMBER +#define SYSTEM_NV_BLOCK_NUM 2 + +EFI_FVB_MEDIA_INFO mPlatformFvbMediaInfo[] = { + // + // Systen NvStorage FVB + // + { + NV_STORAGE_FVB_SIZE, + { + { + 0, + }, // ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + NV_STORAGE_FVB_SIZE, + EFI_FVH_SIGNATURE, + EFI_FVB2_READ_ENABLED_CAP | + EFI_FVB2_READ_STATUS | + EFI_FVB2_WRITE_ENABLED_CAP | + EFI_FVB2_WRITE_STATUS | + EFI_FVB2_ERASE_POLARITY, + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, // CheckSum + 0, // ExtHeaderOffset + { + 0, + }, // Reserved[1] + 1, // Revision + { + NV_STORAGE_FVB_BLOCK_NUM, + FV_BLOCK_SIZE, + } + }, + { + 0, + 0 + } + }, + // + // System FTW FVB + // + { + NV_FTW_FVB_SIZE, + { + { + 0, + }, // ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + NV_FTW_FVB_SIZE, + EFI_FVH_SIGNATURE, + EFI_FVB2_READ_ENABLED_CAP | + EFI_FVB2_READ_STATUS | + EFI_FVB2_WRITE_ENABLED_CAP | + EFI_FVB2_WRITE_STATUS | + EFI_FVB2_ERASE_POLARITY, + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, // CheckSum + 0, // ExtHeaderOffset + { + 0, + }, // Reserved[1] + 1, // Revision + { + NV_FTW_FVB_BLOCK_NUM, + FV_BLOCK_SIZE, + } + }, + { + 0, + 0 + } + } +}; + +EFI_STATUS +GetFvbInfo ( + IN UINT64 FvLength, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +{ + UINTN Index; + + 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/DuetPkg/FvbRuntimeService/FwBlockService.h b/DuetPkg/FvbRuntimeService/FwBlockService.h new file mode 100644 index 0000000000..c3fe7d52b3 --- /dev/null +++ b/DuetPkg/FvbRuntimeService/FwBlockService.h @@ -0,0 +1,348 @@ +/**@file +Copyright (c) 2007, 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. + +Module Name: + + FwBlockService.h + +Abstract: + + Firmware volume block driver for Intel Firmware Hub (FWH) device + +**/ +#ifndef _FW_BLOCK_SERVICE_H +#define _FW_BLOCK_SERVICE_H + +// +// The package level header files this module uses +// +#include + +// +// The protocols, PPI and GUID defintions for this module +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// The Library classes this module consumes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define FWH_READ_LOCK (1 << 2) +#define FWH_LOCK_DOWN (1 << 1) +#define FWH_WRITE_LOCK 1 +#define FWH_WRITE_STATE_STATUS (1 << 7) +#define FWH_ERASE_STATUS (1 << 5) +#define FWH_PROGRAM_STATUS (1 << 4) +#define FWH_VPP_STATUS (1 << 3) +#define STALL_TIME 5 +#define FWH_ERASE_STATUS_BITS (FWH_ERASE_STATUS || FWH_VPP_STATUS) +#define FWH_WRITE_STATUS_BITS (FWH_WRITE_STATUS || FWH_VPP_STATUS) + +// +// BugBug: Add documentation here for data structure!!!! +// +#define FVB_PHYSICAL 0 +#define FVB_VIRTUAL 1 + +#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP \ + ) +#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS) + +typedef struct { + EFI_LOCK FvbDevLock; + UINTN FvBase[2]; + // + // We can treat VolumeSignature combined with MappedFile + // as a unique key to locate the mapped file. +#define MAX_PATH 256 + UINT32 VolumeId; + CHAR16 MappedFile[MAX_PATH]; + UINT32 ActuralSize; + UINT32 Offset; + + EFI_DEVICE_PATH_PROTOCOL *Device; // only used in BS period, won't use after memory map changed + UINTN NumOfBlocks; + BOOLEAN WriteEnabled; + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; +} EFI_FW_VOL_INSTANCE; + +typedef struct { + UINT32 NumFv; + EFI_FW_VOL_INSTANCE *FvInstance[2]; + UINT8 *FvbScratchSpace[2]; +} ESAL_FWB_GLOBAL; + +// +// Fvb Protocol instance data +// +#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE) +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR (a, EFI_FW_VOL_BLOCK_DEVICE, FvbExtension, FVB_DEVICE_SIGNATURE) +#define FVB_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('F', 'V', 'B', 'C') + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_DEVICE_PATH; + +typedef struct { + UINTN Signature; + FV_DEVICE_PATH DevicePath; + UINTN Instance; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; + EFI_FVB_EXTENSION_PROTOCOL FvbExtension; +} EFI_FW_VOL_BLOCK_DEVICE; + +EFI_STATUS +GetFvbInfo ( + IN EFI_PHYSICAL_ADDRESS FvBaseAddress, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +; + +EFI_STATUS +EnableFvbWrites ( + IN BOOLEAN EnableWrites + ) +; + +EFI_STATUS +PlatformGetFvbWriteBase ( + IN UINTN CurrentBaseAddress, + IN UINTN *NewBaseAddress, + IN BOOLEAN *WriteEnabled + ) +; + +EFI_STATUS +EnablePlatformFvb ( + VOID + ) +; + +BOOLEAN +SetPlatformFvbLock ( + IN UINTN LbaAddress + ) +; + +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbGetVolumeAttributes ( + IN UINTN Instance, + OUT EFI_FVB_ATTRIBUTES *Attributes, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbGetPhysicalAddress ( + IN UINTN Instance, + OUT EFI_PHYSICAL_ADDRESS *Address, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +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 +FvbSpecificInitialize ( + IN ESAL_FWB_GLOBAL *mFvbModuleGlobal + ) +; + +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +EFI_STATUS +FvbEraseCustomBlockRange ( + IN UINTN Instance, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba, + IN ESAL_FWB_GLOBAL *Global, + IN BOOLEAN Virtual + ) +; + +// +// Protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES *Attributes + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES *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 EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +; + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + 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 +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, + ... + ) +; + +EFI_STATUS +EFIAPI +FvbExtendProtocolEraseCustomBlockRange ( + IN EFI_FVB_EXTENSION_PROTOCOL *This, + IN EFI_LBA StartLba, + IN UINTN OffsetStartLba, + IN EFI_LBA LastLba, + IN UINTN OffsetLastLba + ) +; + +#endif -- 2.39.2