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

Reply via email to