Add "MdeModulePkg: " prefix to subject. Cc package maintainers.
But, like I mentioned in the other email, I'd prefer to attempt to
support capsules more realistically with OVMF.
-Jordan
On 2015-04-10 12:01:50, Peter Jones wrote:
> 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 <[email protected]>
> ---
> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel