Hi, Jones Could you let me know what's the benefit of putting these Fake FSRT and Fake Capsule lib to MdeModulePkg? Why not purely for Ovmf platform?
Thanks Feng -----Original Message----- From: Peter Jones [mailto:pjo...@redhat.com] Sent: Saturday, April 11, 2015 03:02 To: edk2-devel@lists.sourceforge.net Subject: [edk2] [PATCH 09/11] Add a fake ESRT driver to go with Fake Capsule driver. This patch adds a generator for ESRT data. To create the ESRT, a table is allocated during DXE and filled with the current set of updates which would be accepted by the FakeCapsuleLib driver. With this patch, we have a full (if minimal) framework for testing the /other/ side of this API; that is, you can deploy a full stack of production-level OS and pre-boot firmware update utilities with no special code /inside/ those utilities. To do so you have to augment them with some system for setting variables in the gFakeCapsuleHeaderGuid GUID-space, and something to drive your test harness (i.e. simulated user input at some level.) A sample (and somewhat simplified) workflow is something like this: [tester] - create {gFakeCapsuleHeaderGuid} variables - populate fs with updates - sets up OS code to be run when we boot up, so we can test it - boots the VM ,>[Ovmf] <-' (that's a curved little arrow, you see, from the previous | thing doing work to the current thing doing work) | - lots of stuff -----, | [Ovmf / FakeEsrtDxe] <-' | - GetVariable({gFakeCapsuleHeaderGuid} variables) | - InstallConfigurationTable(ESRT) | [Ovmf] <-' | - loads OS | [OS] <-' | - reads the status of updates available from ESRT | - looks for Capsule####/CapsuleLast/CapsuleMax for previous state | - reads update files it may have available | - makes some decisions from the above | - decides there's an update! | - sets some state and a BootNext variable to start a pre-boot | application to do firmware updates | - reboots | [Ovmf] <-' | - GetVariable({gFakeCapsuleHeaderGuid} variables) | - InstallConfigurationTable(ESRT) | - pre-boot application (fwupdate.efi) | [fwupdate.efi] <-' | - Looks for state left from OS utility | - reads the firmware files and coalesces them into a scatter gather | list with capsule headers as appropriate | - calls UpdateCapsule() ---, | [Ovmf / FakeCapsuleLib ] <--' | - SetVariable() on the appropriate {gFakeCapsuleHeaderGuid} variables * - updates ESRT maybe |\-- calls EfiResetSystem() maybe | - returns to caller maybe | [fwupdate.efi] <--' | - calls EfiResetSystem() +------------' And then at some point [tester] examines according to some criteria to decide if the thing being tested worked. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Peter Jones <pjo...@redhat.com> --- MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.c | 359 ++++++++++++++++++++ MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.inf | 59 ++++ 2 files changed, 418 insertions(+) diff --git a/MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.c b/MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.c new file mode 100644 index 0000000..662d839 --- /dev/null +++ b/MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.c @@ -0,0 +1,359 @@ +/** @file + Fake Dxe Capsule Library instance that just keeps ESRT data in UEFI + Variables. + + Copyright 2015 Red Hat, Inc. + + This program and the accompanying materials are licensed and made + available under the terms and conditions of the BSD License which + accompanies this distribution. The full text of the license may be + found at http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR + IMPLIED. + +**/ +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/CapsuleLib.h> +#include <Library/DebugLib.h> +#include <Library/Esrt.h> +#include <Library/FakeCapsuleBase.h> +#include <Library/MemoryAllocationLib.h> #include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Guid/FakeCapsuleBase.h> +#include <Guid/EventGroup.h> + +STATIC EFI_SYSTEM_RESOURCE_TABLE *GlobalEsrt; STATIC UINTN +GlobalEsrtSize; + +/** + Find an ESRT entry by the FwClass GUID + + @param FwEntryGuid GUID to use as lookup key + @param FwEntry Storage space to hole the entry in. + + @return EFI_NOT_FOUND No such entry could be located. +**/ +STATIC +EFI_STATUS +EFIAPI +FakeEsrtGetFwEntryByGuid ( + IN EFI_GUID FwEntryGuid, + OUT EFI_SYSTEM_RESOURCE_ENTRY *FwEntry + ) +{ + RETURN_STATUS Status; + CHAR16 *VariableName = NULL; + VOID *VariableData = NULL; + UINTN VariableDataSize = 0; + UINT32 VariableAttributes; + EFI_GUID VendorGuid = { 0, }; + + DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__)); + + Status = FindEsrtVariableByCapsuleGuid (&FwEntryGuid, + &VendorGuid, + &VariableName, + &VariableData, + &VariableDataSize, + &VariableAttributes); if + (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, + "%a: FindEsrtVariableByCapsuleGuid failed: %r\n", + __FUNCTION__, + Status + )); + return Status; + } + + FreePool (VariableName); + CopyMem (FwEntry, VariableData, VariableDataSize); + FreePool (VariableData); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +FakeEsrtUpdateConfigTableEntry ( + EFI_SYSTEM_RESOURCE_ENTRY *FwEntry + ) +{ + EFI_SYSTEM_RESOURCE_ENTRY *Entry; + UINTN i; + + if (GlobalEsrt == NULL || + GlobalEsrtSize <= sizeof (EFI_SYSTEM_RESOURCE_TABLE)) { + return EFI_NOT_FOUND; + } + + Entry = (EFI_SYSTEM_RESOURCE_ENTRY *)(GlobalEsrt + 1); for (i = 0; i + < GlobalEsrt->FwResourceCount; i++) { + if (CompareGuid (&FwEntry->FwClass, &Entry[i].FwClass)) { + CopyMem (Entry+i, FwEntry, sizeof (*FwEntry)); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +// +// set new values in an ESRT entry +// +STATIC +EFI_STATUS +EFIAPI +FakeEsrtUpdateTableEntryByGuid ( + IN EFI_GUID FwEntryGuid, + IN EFI_SYSTEM_RESOURCE_ENTRY *FwEntry + ) +{ + RETURN_STATUS Status; + EFI_GUID VendorGuid = { 0, }; + CHAR16 *VariableName = L"Esrt0000"; + VOID *VariableData = NULL; + UINTN VariableDataSize = sizeof (EFI_SYSTEM_RESOURCE_ENTRY); + UINT32 VariableAttributes; + UINTN NEntries = 0; + UINT16 VariableNumber = 0; + + DEBUG ((EFI_D_INFO, "%a\n", __FUNCTION__)); Status = + FakeCapsuleCountEntries(&NEntries); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d FakeCapsuleCountEntries(): %r\n", + __FUNCTION__, __LINE__, Status)); + return Status; + } + + VariableData = AllocateZeroPool (VariableDataSize); if + (!VariableData) { + DEBUG ((EFI_D_ERROR, "%a:%d AllocateZeroPool(): %r\n", + __FUNCTION__, __LINE__, EFI_OUT_OF_RESOURCES)); + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (VariableData, FwEntry, sizeof (EFI_SYSTEM_RESOURCE_ENTRY)); + Status = FindEsrtVariableByCapsuleGuid (&FwEntryGuid, + &VendorGuid, + &VariableName, + &VariableData, + &VariableDataSize, + &VariableAttributes + ); FreePool (VariableData); + VariableData = NULL; if (Status == EFI_NOT_FOUND) { + Status = FindFreeNumberName (L"Esrt", + &gFakeCapsuleHeaderGuid, + NEntries * 3, + &VariableNumber); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_FOUND) { + Status = EFI_OUT_OF_RESOURCES; + } + return Status; + } + } + + UnicodeSPrint (VariableName, StrSize(L"Esrt0000"), L"Esrt%04X", + VariableNumber); + Status = gRT->SetVariable(VariableName, + &gFakeCapsuleHeaderGuid, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_SYSTEM_RESOURCE_ENTRY), + FwEntry + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d SetVariable(%s): %r\n", + __FUNCTION__, __LINE__, VariableName, Status)); } + FreePool (VariableName); + + Status = FakeEsrtUpdateConfigTableEntry (FwEntry); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d FakeEsrtUpdateConfigTableEntry(): %r\n", + __FUNCTION__, __LINE__, Status)); + } + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +FakeEsrtPopulateTable ( + ) +{ + RETURN_STATUS Status; + CHAR16 *VariableName = NULL; + VOID *VariableData = NULL; + UINTN VariableDataSize; + UINT32 VariableAttributes = 0; + EFI_GUID VendorGuid = { 0, }; + UINTN NEntries = 0; + EFI_SYSTEM_RESOURCE_TABLE Esrt; + UINTN TableSize; + EFI_PHYSICAL_ADDRESS TableAddr = 0; + UINT8 *TableBuf; + UINTN i; + CHAR16 CapsuleMax[] = L"Capsule0000"; + UINTN NChars; + VOID *Esre; + + DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__)); Status = + FakeCapsuleCountEntries(&NEntries); + if (EFI_ERROR (Status)) { + return Status; + } + + VariableDataSize = sizeof (EFI_SYSTEM_RESOURCE_ENTRY); VariableData + = AllocateZeroPool (VariableDataSize); if (!VariableData) { + DEBUG ((EFI_D_ERROR, "%a:%d AllocateZeroPool(%d) failed\n", + __FUNCTION__, __LINE__, VariableDataSize)); + return EFI_OUT_OF_RESOURCES; + } + + TableSize = ALIGN_VALUE(sizeof (Esrt) + + NEntries * sizeof (EFI_SYSTEM_RESOURCE_ENTRY), + 4096 + ); + + Status = gBS->AllocatePages (AllocateAnyPages, + EfiRuntimeServicesData, + TableSize / 4096, + &TableAddr + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d AllocatePages(%d) failed: %r\n", + __FUNCTION__, __LINE__, TableSize, Status)); + return Status; + } + TableBuf = (UINT8 *)(UINTN)TableAddr; + + Esrt.FwResourceVersion = 1; + Esrt.FwResourceMax = (TableSize - sizeof (Esrt)) + / sizeof (EFI_SYSTEM_RESOURCE_ENTRY); + Esrt.FwResourceCount = 0; + + Esre = TableBuf + sizeof (Esrt); + + for (i = 0; i < NEntries; i++) { + Esre = TableBuf + sizeof (Esrt) + sizeof (EFI_SYSTEM_RESOURCE_ENTRY) * i; + VariableData = NULL; + VariableDataSize = 0; + Status = FindEsrtVariableByCapsuleGuid (NULL, + &VendorGuid, + &VariableName, + &VariableData, + &VariableDataSize, + &VariableAttributes + ); + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + break; + } + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d: FindEsrtVariableByCapsuleGuid failed: %r\n", + __FUNCTION__, __LINE__, Status)); + break; + } + if (VariableData && VariableDataSize) { + CopyMem (Esre, VariableData, VariableDataSize); + FreePool (VariableData); + VariableData = NULL; + } + } + if (VariableName) { + FreePool (VariableName); + VariableName = NULL; + } + + Esrt.FwResourceCount = i; + CopyMem (TableBuf, &Esrt, sizeof (Esrt)); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d: Couldn't get variable: %r\n", + __FUNCTION__, __LINE__, Status)); + gBS->FreePages (TableAddr, TableSize / 4096); + return Status; + } + + Status = gBS->InstallConfigurationTable (&gEfiEsrtTableGuid, + TableBuf); if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d InstallConfigurationTable failed: %r\n", + __FUNCTION__, __LINE__, Status)); + gBS->FreePages (TableAddr, TableSize / 4096); + return Status; + } + + GlobalEsrt = (EFI_SYSTEM_RESOURCE_TABLE *)TableBuf; GlobalEsrtSize = + TableSize; + + NChars = UnicodeSPrint (CapsuleMax, sizeof (CapsuleMax), L"Capsule%04X", + NEntries * 3); if (NChars != 11) { + DEBUG ((EFI_D_ERROR, "%a:%d UnicodeSPrint(Capsule####)=%d (should be 11)\n", + __FUNCTION__,__LINE__, NChars)); + gBS->FreePages (TableAddr, TableSize / 4096); + return EFI_ABORTED; + } + Status = gRT->SetVariable (L"CapsuleMax", + &gEfiCapsuleReportGuid, + EFI_VARIABLE_NON_VOLATILE + | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS, + NChars * sizeof (CHAR16), + CapsuleMax + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a:%d: SetVariable(CapsuleMax) failed: %r\n", + __FUNCTION__, __LINE__, Status)); } + + return Status; +} + +STATIC CONST ESRT_OPERATION_PROTOCOL mFakeEsrtOperationProtocol = { + FakeEsrtPopulateTable, + FakeEsrtUpdateTableEntryByGuid, + FakeEsrtGetFwEntryByGuid, +}; + +EFI_STATUS +EFIAPI +FakeEsrtDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + RETURN_STATUS Status; + + DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__)); + + /* Ideally this would be called by some /consumer/ of + * gEfiEsrtOperationProtocolGuid, but there's not much of that existing + * just yet in the actual tiano tree. */ FakeEsrtPopulateTable(); + + Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle, + &gEfiEsrtOperationProtocolGuid, + &mFakeEsrtOperationProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a: InstallMultipleProtocolInterfaces failed: %r\n", + __FUNCTION__, Status)); + } + return Status; +} diff --git a/MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.inf b/MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.inf new file mode 100644 index 0000000..bfcffcf --- /dev/null +++ b/MdeModulePkg/Universal/FakeEsrtDxe/FakeEsrtDxe.inf @@ -0,0 +1,59 @@ +## @file +# Build a fake ESRT based on capsules available through FakeCapsuleBase. +# +# Copyright 2015 Red Hat, Inc. +# +# This program and the accompanying materials are licensed and made # +available under the terms and conditions of the BSD License which # +accompanies this distribution. The full text of the license may be # +found at http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" +BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER +EXPRESS OR # IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FakeEsrtDxe + FILE_GUID = ef3f0157-4c04-493a-8904-cb6bef9a62aa + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FakeEsrtDxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + FakeEsrtDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + PrintLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + FakeCapsuleBase + +[Protocols] + gEfiEsrtOperationProtocolGuid + +[Guids] + gEfiCapsuleReportGuid + gEfiEventReadyToBootGuid + gEfiEsrtTableGuid + gFakeCapsuleHeaderGuid + +[Depex] + gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid -- 2.3.5 ------------------------------------------------------------------------------ BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT Develop your own process in accordance with the BPMN 2 standard Learn Process modeling best practices with Bonita BPM through live exercises http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_ source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel ------------------------------------------------------------------------------ BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT Develop your own process in accordance with the BPMN 2 standard Learn Process modeling best practices with Bonita BPM through live exercises http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_ source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel