summaryrefslogtreecommitdiff
path: root/DuetPkg
diff options
context:
space:
mode:
authorklu2 <klu2@6f19259b-4bc3-4df7-8a09-765794883524>2008-04-18 03:09:54 +0000
committerklu2 <klu2@6f19259b-4bc3-4df7-8a09-765794883524>2008-04-18 03:09:54 +0000
commit9071550e8697ed9df3d24b369bd30e3f0e190d1f (patch)
treeae93a60e5311a6864330e72daee092255a2e64fb /DuetPkg
parent25ab7ab110193a0b5fc468fd3839acb8ae4d93df (diff)
downloadedk2-platforms-9071550e8697ed9df3d24b369bd30e3f0e190d1f.tar.xz
Add missing module for duet package.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5088 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'DuetPkg')
-rw-r--r--DuetPkg/EfiLdr/Debug.c93
-rw-r--r--DuetPkg/EfiLdr/Debug.h49
-rw-r--r--DuetPkg/EfiLdr/EfiLdr.h115
-rw-r--r--DuetPkg/EfiLdr/EfiLdr.inf58
-rw-r--r--DuetPkg/EfiLdr/EfiLdrHandoff.h56
-rw-r--r--DuetPkg/EfiLdr/EfiLoader.c266
-rw-r--r--DuetPkg/EfiLdr/Ia32/EfiLdr.inf27
-rw-r--r--DuetPkg/EfiLdr/Ia32/Makefile183
-rw-r--r--DuetPkg/EfiLdr/PeLoader.c641
-rw-r--r--DuetPkg/EfiLdr/PeLoader.h42
-rw-r--r--DuetPkg/EfiLdr/Support.c237
-rw-r--r--DuetPkg/EfiLdr/Support.h50
-rw-r--r--DuetPkg/EfiLdr/X64/EfiLdr.inf27
-rw-r--r--DuetPkg/EfiLdr/X64/Makefile186
-rw-r--r--DuetPkg/EfiLdr/efildr.c28
-rw-r--r--DuetPkg/FSVariable/FSVariable.c1356
-rw-r--r--DuetPkg/FSVariable/FSVariable.dxs26
-rw-r--r--DuetPkg/FSVariable/FSVariable.h162
-rw-r--r--DuetPkg/FSVariable/FSVariable.inf69
-rw-r--r--DuetPkg/FSVariable/FileStorage.c441
-rw-r--r--DuetPkg/FSVariable/MemStorage.c135
-rw-r--r--DuetPkg/FSVariable/VariableStorage.h111
-rw-r--r--DuetPkg/FvbRuntimeService/DUETFwh.dxs26
-rw-r--r--DuetPkg/FvbRuntimeService/DUETFwh.inf62
-rw-r--r--DuetPkg/FvbRuntimeService/FWBlockService.c1822
-rw-r--r--DuetPkg/FvbRuntimeService/FileIo.c210
-rw-r--r--DuetPkg/FvbRuntimeService/FileIo.h58
-rw-r--r--DuetPkg/FvbRuntimeService/FvbInfo.c121
-rw-r--r--DuetPkg/FvbRuntimeService/FwBlockService.h348
29 files changed, 7005 insertions, 0 deletions
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 <Protocol/LoadedImage.h>
+#include <Protocol/EdkDecompress.h>
+#include <IndustryStandard/PeImage.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#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 <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HobLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/HobList.h>
+#include <Guid/FlashMapHob.h>
+
+#include <Protocol/Variable.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/BlockIo.h>
+
+
+#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 <PiDxe.h>
+
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Guid/EventGroup.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Protocol/FvbExtension.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Guid/AlternateFvBlock.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/BlockIo.h>
+#include <Library/DevicePathLib.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/FlashMapHob.h>
+#include <Guid/HobList.h>
+#include <Guid/AlternateFvBlock.h>
+#include <Protocol/FvbExtension.h>
+
+//
+// The Library classes this module consumes
+//
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+
+#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