public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 00/11] Kvmtool guest firmware support for Arm
@ 2020-05-14  8:40 Sami Mujawar
  2020-05-14  8:40 ` [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver Sami Mujawar
                   ` (10 more replies)
  0 siblings, 11 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, ray.ni, michael.d.kinney,
	liming.gao, lersek, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

Kvmtool is a virtual machine manager that can be used to launch
guest partitions. Kvmtool additionally supports emulation of
hardware like the RTC, CFI etc. essentially providing an
emulated platform for a Guest OS to run.

To boot a standards-based OS one would need UEFI. In this case
it is UEFI at EL1 or guest/virtual firmware.

Kvmtool has been enhanced to enable launching of KVM guests with
UEFI support e.g. CFI emulation has been added to store UEFI
variables, etc. These changes have been merged in the kvmtool
repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.git

This patch series:
  - adds UEFI guest firmware support for the Kvmtool emulated
    Arm platform.
  - addresses the review feedback for the v1 series discussed
    on the mailing list at:
    https://edk2.groups.io/g/devel/topic/30915280#30694

The changes for the v2 series can be seen at:
https://github.com/samimujawar/edk2/tree/299_kvmtool_plat_support_v2

Sami Mujawar (11):
  PcAtChipsetPkg: Add MMIO Support to RTC driver
  MdePkg: Add NULL implementation for PCILib
  MdePkg: Base Memory Lib instance using MMIO
  ArmPlatformPkg: Use MMIO to read device memory
  ArmPlatformPkg: Dynamic flash variable base
  ArmVirtPkg: Add kvmtool platform driver
  ArmVirtPkg: kvmtool platform memory map
  ArmVirtPkg: Add Kvmtool NOR flash lib
  ArmVirtPkg: Support for kvmtool emulated platform
  ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio
  Maintainer.txt: Add Kvmtool emulated plat maintainer

 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c                           |   65 +-
 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c                        |    4 +-
 ArmVirtPkg/{ArmVirtQemuKernel.dsc => ArmVirtKvmTool.dsc}                   |  309 +++--
 ArmVirtPkg/ArmVirtKvmTool.fdf                                              |  276 +++++
 ArmVirtPkg/ArmVirtQemu.dsc                                                 |    8 +-
 ArmVirtPkg/ArmVirtQemuKernel.dsc                                           |    8 +-
 ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c                         |   93 ++
 ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf                       |   47 +
 ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c           |  114 ++
 ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf         |   42 +
 ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c                    |  265 +++++
 ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf               |   50 +
 Maintainers.txt                                                            |    7 +
 MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf                     |   50 +
 MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni                     |   15 +
 MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c                       |   62 +
 MdePkg/Library/BaseMemoryLibMmio/CopyMem.c                                 |  149 +++
 MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c                          |   59 +
 MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c                     |   50 +
 MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c                           |  304 +++++
 MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c                              |  143 +++
 MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h                         |  248 ++++
 MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c                        |   63 +
 MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c                        |   62 +
 MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c                        |   63 +
 MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c                         |   95 ++
 MdePkg/Library/BaseMemoryLibMmio/SetMem.c                                  |   83 ++
 MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c                         |   60 +
 MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c                         |   60 +
 MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c                         |   60 +
 MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c                           |   87 ++
 MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c                          |   52 +
 MdePkg/Library/PciLibNull/PciLibNull.c                                     | 1213 ++++++++++++++++++++
 MdePkg/Library/PciLibNull/PciLibNull.inf                                   |   25 +
 PcAtChipsetPkg/PcAtChipsetPkg.dec                                          |    8 +
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c                         |  117 +-
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h                         |   31 +
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c                    |  130 ++-
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf |    8 +
 39 files changed, 4326 insertions(+), 259 deletions(-)
 copy ArmVirtPkg/{ArmVirtQemuKernel.dsc => ArmVirtKvmTool.dsc} (59%)
 create mode 100644 ArmVirtPkg/ArmVirtKvmTool.fdf
 create mode 100644 ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
 create mode 100644 ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
 create mode 100644 ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
 create mode 100644 ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
 create mode 100644 ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
 create mode 100644 ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/SetMem.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
 create mode 100644 MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
 create mode 100644 MdePkg/Library/PciLibNull/PciLibNull.c
 create mode 100644 MdePkg/Library/PciLibNull/PciLibNull.inf

-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:24   ` Ard Biesheuvel
  2020-05-15 10:50   ` André Przywara
  2020-05-14  8:40 ` [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib Sami Mujawar
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, ray.ni, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Some virtual machine managers like kvmtool emulate the MC146818
RTC controller in the MMIO space so that architectures that do
not support I/O Mapped I/O can use the RTC. This patch adds MMIO
support to the RTC controller driver.

The PCD PcdRtcUseMmio has been added to select I/O or MMIO support.
  If PcdRtcUseMmio is:
    TRUE  - Indicates the RTC port registers are in MMIO space.
    FALSE - Indicates the RTC port registers are in I/O space.
            Default is I/O space.

When MMIO support is selected (PcdRtcUseMmio == TRUE) the driver
maps the MMIO region used by the RTC as runtime memory so that the
RTC registers are accessible post ExitBootServices.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---

Notes:
    v2:
      - Code review comments incorporated.                              [Sami]
    
    v1:
      - Add support to read/write from RTC registers using MMIO access  [Sami]
      - Use wrapper functions for RtcRead/Write accessors               [Leif]
        Ref: https://edk2.groups.io/g/devel/topic/30915281#30695

 PcAtChipsetPkg/PcAtChipsetPkg.dec                                          |   8 ++
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c                         | 117 ++++++++++++++++--
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h                         |  31 +++++
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c                    | 130 +++++++++++++++++++-
 PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf |   8 ++
 5 files changed, 280 insertions(+), 14 deletions(-)

diff --git a/PcAtChipsetPkg/PcAtChipsetPkg.dec b/PcAtChipsetPkg/PcAtChipsetPkg.dec
index 88de5cceea593176c3a2425a5963b66b789f2b9e..76d0c7eda69bb505914ba904e09c89de170f69ae 100644
--- a/PcAtChipsetPkg/PcAtChipsetPkg.dec
+++ b/PcAtChipsetPkg/PcAtChipsetPkg.dec
@@ -6,6 +6,7 @@
 #
 # Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -142,5 +143,12 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
   # @Prompt RTC Update Timeout Value.
   gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000|UINT32|0x00000020
 
+  ## Indicates the RTC port registers are in MMIO space, or in I/O space.
+  #  Default is I/O space.<BR><BR>
+  #   TRUE  - RTC port registers are in MMIO space.<BR>
+  #   FALSE - RTC port registers are in I/O space.<BR>
+  # @Prompt RTC port registers use MMIO.
+  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|FALSE|BOOLEAN|0x00000021
+
 [UserExtensions.TianoCore."ExtraFiles"]
   PcAtChipsetPkgExtra.uni
diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
index 52af17941786ef81c3911512ee64551724e67209..df8dea83ab27bbba12351096d1bfd9ea31accb60 100644
--- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
+++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
@@ -3,6 +3,7 @@
 
 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -10,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #include "PcRtc.h"
 
+extern EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
+
 //
 // Days of month.
 //
@@ -21,6 +24,28 @@ UINTN mDayOfMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 CHAR16 mTimeZoneVariableName[] = L"RTC";
 
 /**
+  A function pointer that evaluates to a function that reads the RTC content
+  through its registers either using IO or MMIO access.
+
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+
+  @return The data of UINT8 type read from RTC.
+**/
+RTC_READ  RtcRead;
+
+/**
+  A function pointer that evaluates to a function that reads the RTC content
+  through its registers either using IO or MMIO access.
+
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+
+  @return The data of UINT8 type read from RTC.
+**/
+RTC_WRITE RtcWrite;
+
+/**
   Compare the Hour, Minute and Second of the From time and the To time.
 
   Only compare H/M/S in EFI_TIME and ignore other fields here.
@@ -54,41 +79,99 @@ IsWithinOneDay (
   );
 
 /**
-  Read RTC content through its registers.
+  Read RTC content through its registers using IO access.
 
-  @param  Address  Address offset of RTC. It is recommended to use macros such as
-                   RTC_ADDRESS_SECONDS.
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
 
   @return The data of UINT8 type read from RTC.
 **/
+STATIC
 UINT8
-RtcRead (
+IoRtcRead (
   IN  UINT8 Address
   )
 {
-  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
+  IoWrite8 (
+    PcdGet8 (PcdRtcIndexRegister),
+    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
+    );
   return IoRead8 (PcdGet8 (PcdRtcTargetRegister));
 }
 
 /**
-  Write RTC through its registers.
+  Write RTC through its registers  using IO access.
 
-  @param  Address  Address offset of RTC. It is recommended to use macros such as
-                   RTC_ADDRESS_SECONDS.
-  @param  Data     The content you want to write into RTC.
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+  @param  Data      The content you want to write into RTC.
 
 **/
+STATIC
 VOID
-RtcWrite (
+IoRtcWrite (
   IN  UINT8   Address,
   IN  UINT8   Data
   )
 {
-  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
+  IoWrite8 (
+    PcdGet8 (PcdRtcIndexRegister),
+    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
+    );
   IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);
 }
 
 /**
+  Read RTC content through its registers using MMIO access.
+
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+
+  @return The data of UINT8 type read from RTC.
+**/
+STATIC
+UINT8
+MmioRtcRead (
+  IN  UINT8 Address
+  )
+{
+  MmioWrite8 (
+    mRtcRegisterBase,
+    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
+    );
+  return MmioRead8 (
+           mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
+             PcdGet8 (PcdRtcIndexRegister))
+           );
+}
+
+/**
+  Write RTC through its registers using MMIO access.
+
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+  @param  Data      The content you want to write into RTC.
+
+**/
+STATIC
+VOID
+MmioRtcWrite (
+  IN  UINT8   Address,
+  IN  UINT8   Data
+  )
+{
+  MmioWrite8 (
+    mRtcRegisterBase,
+    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
+    );
+  MmioWrite8 (
+    mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
+      PcdGet8 (PcdRtcIndexRegister)),
+    Data
+    );
+}
+
+/**
   Initialize RTC.
 
   @param  Global            For global use inside this module.
@@ -113,6 +196,18 @@ PcRtcInit (
   BOOLEAN         Pending;
 
   //
+  // Initialize the RtcRead and RtcWrite functions
+  // based on the chosen IO/MMIO access.
+  //
+  if (FixedPcdGetBool (PcdRtcUseMmio)) {
+    RtcRead = MmioRtcRead;
+    RtcWrite = MmioRtcWrite;
+  } else {
+    RtcRead = IoRtcRead;
+    RtcWrite = IoRtcWrite;
+  }
+
+  //
   // Acquire RTC Lock to make access to RTC atomic
   //
   if (!EfiAtRuntime ()) {
diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
index 47293ce44c5a1f4792892892f7da40d7f0a5a001..e64dbbea48f7f0d2f317c65c2e4b93e7b1888efc 100644
--- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
+++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
@@ -3,6 +3,7 @@
 
 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.<BR>
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -371,4 +372,34 @@ PcRtcAcpiTableChangeCallback (
   IN EFI_EVENT        Event,
   IN VOID             *Context
   );
+
+/**
+  Function pointer to Read RTC content through its registers.
+
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+
+  @return The data of UINT8 type read from RTC.
+**/
+typedef
+UINT8
+(EFIAPI *RTC_READ) (
+  IN  UINT8 Address
+  );
+
+/**
+  Function pointer to Write RTC through its registers.
+
+  @param  Address   Address offset of RTC. It is recommended to use
+                    macros such as RTC_ADDRESS_SECONDS.
+  @param  Data      The content you want to write into RTC.
+
+**/
+typedef
+VOID
+(EFIAPI *RTC_WRITE) (
+  IN  UINT8   Address,
+  IN  UINT8   Data
+  );
+
 #endif
diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
index ccda6331373bfe4069b0a59495b5e5cc731c8fc8..5d5dbeaf970ca8eb291c1e094fd764d201f9071e 100644
--- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
+++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
@@ -2,16 +2,32 @@
   Provides Set/Get time operations.
 
 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
+#include <Library/DxeServicesTableLib.h>
 #include "PcRtc.h"
 
 PC_RTC_MODULE_GLOBALS  mModuleGlobal;
 
 EFI_HANDLE             mHandle = NULL;
 
+STATIC EFI_EVENT       mVirtualAddrChangeEvent;
+
+EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
+
+//
+// Function pointer for the Rtc Read interface function
+//
+extern RTC_READ   RtcRead;
+
+//
+// Function pointer for the Rtc Write interface function
+//
+extern RTC_WRITE  RtcWrite;
+
 /**
   Returns the current time and date information, and the time-keeping capabilities
   of the hardware platform.
@@ -106,6 +122,33 @@ PcRtcEfiSetWakeupTime (
 }
 
 /**
+  Fixup internal data so that EFI can be called in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  // Only needed if you are going to support the OS calling RTC functions in
+  // virtual mode. You will need to call EfiConvertPointer (). To convert any
+  // stored physical addresses to virtual address. After the OS transitions to
+  // calling in virtual mode, all future runtime calls will be made in virtual
+  // mode.
+  EfiConvertPointer (0x0, (VOID**)&mRtcRegisterBase);
+
+  // Convert the RtcRead and RtcWrite pointers for runtime use.
+  EfiConvertPointer (0x0, (VOID**)&RtcRead);
+  EfiConvertPointer (0x0, (VOID**)&RtcWrite);
+}
+
+/**
   The user Entry Point for PcRTC module.
 
   This is the entry point for PcRTC module. It installs the UEFI runtime service
@@ -125,12 +168,77 @@ InitializePcRtc (
   IN EFI_SYSTEM_TABLE                      *SystemTable
   )
 {
-  EFI_STATUS  Status;
-  EFI_EVENT   Event;
+  EFI_STATUS             Status;
+  EFI_EVENT              Event;
+  EFI_PHYSICAL_ADDRESS   RtcPageBase;
 
   EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK);
   mModuleGlobal.CenturyRtcAddress = GetCenturyRtcAddress ();
 
+  if (FixedPcdGetBool (PcdRtcUseMmio)) {
+    mRtcRegisterBase = PcdGet8 (PcdRtcIndexRegister);
+    RtcPageBase = mRtcRegisterBase & ~(EFI_PAGE_SIZE - 1);
+
+    // Declare the controller as EFI_MEMORY_RUNTIME
+    Status = gDS->AddMemorySpace (
+                    EfiGcdMemoryTypeMemoryMappedIo,
+                    RtcPageBase,
+                    EFI_PAGE_SIZE,
+                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
+        Status
+        ));
+      return Status;
+    }
+
+    Status = gDS->AllocateMemorySpace (
+                    EfiGcdAllocateAddress,
+                    EfiGcdMemoryTypeMemoryMappedIo,
+                    0,
+                    EFI_PAGE_SIZE,
+                    &RtcPageBase,
+                    ImageHandle,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "Failed to allocate memory space. Status = %r\n",
+        Status
+        ));
+      gDS->RemoveMemorySpace (
+             RtcPageBase,
+             EFI_PAGE_SIZE
+             );
+      return Status;
+    }
+
+    Status = gDS->SetMemorySpaceAttributes (
+                    RtcPageBase,
+                    EFI_PAGE_SIZE,
+                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "Failed to set memory attributes. Status = %r\n",
+        Status
+        ));
+      gDS->FreeMemorySpace (
+               RtcPageBase,
+               EFI_PAGE_SIZE
+               );
+      gDS->RemoveMemorySpace (
+             RtcPageBase,
+             EFI_PAGE_SIZE
+             );
+      return Status;
+    }
+  }
+
   Status = PcRtcInit (&mModuleGlobal);
   ASSERT_EFI_ERROR (Status);
 
@@ -165,7 +273,23 @@ InitializePcRtc (
                   NULL,
                   NULL
                   );
-  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  if (FixedPcdGetBool (PcdRtcUseMmio)) {
+    // Register for the virtual address change event
+    Status = gBS->CreateEventEx (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_NOTIFY,
+                    LibRtcVirtualNotifyEvent,
+                    NULL,
+                    &gEfiEventVirtualAddressChangeGuid,
+                    &mVirtualAddrChangeEvent
+                    );
+    ASSERT_EFI_ERROR (Status);
+  }
 
   return Status;
 }
diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
index c73ee98105e510f9e4e23c1a6c1e5c505325d2c9..3a373d11f8bfc7df0e4d00be8b43e90bfa06b192 100644
--- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
+++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
@@ -6,6 +6,7 @@
 #
 # Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
+# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -48,6 +49,7 @@ [LibraryClasses]
   BaseLib
   PcdLib
   ReportStatusCodeLib
+  DxeServicesTableLib
 
 [Protocols]
   gEfiRealTimeClockArchProtocolGuid             ## PRODUCES
@@ -61,10 +63,13 @@ [Guids]
   ## SOMETIMES_CONSUMES ## SystemTable
   gEfiAcpiTableGuid
 
+  gEfiEventVirtualAddressChangeGuid
+
 [FixedPcd]
   gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA     ## CONSUMES
   gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB     ## CONSUMES
   gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterD     ## CONSUMES
+  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio                   ## CONSUMES
 
 [Pcd]
   gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout   ## CONSUMES
@@ -76,5 +81,8 @@ [Pcd]
 [Depex]
   gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
 
+[Depex.common.DXE_RUNTIME_DRIVER]
+  gEfiCpuArchProtocolGuid
+
 [UserExtensions.TianoCore."ExtraFiles"]
   PcRtcExtra.uni
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
  2020-05-14  8:40 ` [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:23   ` Ard Biesheuvel
  2020-05-14 16:21   ` Michael D Kinney
  2020-05-14  8:40 ` [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO Sami Mujawar
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, michael.d.kinney, liming.gao,
	Alexandru.Elisei, Andre.Przywara, Matteo.Carlini, Laura.Moretta,
	nd

On some platforms the Serial 16550 UART is interfaced
over PCI. To support such platforms the Serial 16550
driver links with PciLib.

For platforms that do not interface the Serial 16550
UART over PCI, the driver still needs to link with a
PciLib library. Linking to the full implementation of
the PCI library may not be possible during the early
firmware boot stage.

To facilitate early firmware logs over the serial port
this patch introduces a NULL PCI library implementation.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 MdePkg/Library/PciLibNull/PciLibNull.c   | 1213 ++++++++++++++++++++
 MdePkg/Library/PciLibNull/PciLibNull.inf |   25 +
 2 files changed, 1238 insertions(+)

diff --git a/MdePkg/Library/PciLibNull/PciLibNull.c b/MdePkg/Library/PciLibNull/PciLibNull.c
new file mode 100644
index 0000000000000000000000000000000000000000..c186ca9f86e5a0c860472b80209aae9b958a95d7
--- /dev/null
+++ b/MdePkg/Library/PciLibNull/PciLibNull.c
@@ -0,0 +1,1213 @@
+/** @file
+  Provides a NULL implementation of PCI services used to access
+  PCI Configuration Space.
+
+  Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+
+/**
+  Registers a PCI device so PCI configuration registers may be accessed after
+  SetVirtualAddressMap().
+
+  Registers the PCI device specified by Address so all the PCI configuration
+  registers associated with that PCI device may be accessed after
+  SetVirtualAddressMap() is called.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @retval RETURN_SUCCESS           The PCI device was registered for runtime
+                                   access.
+  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
+                                   after ExitBootServices().
+  @retval RETURN_UNSUPPORTED       The resources required to access the PCI
+                                   device at runtime could not be mapped.
+  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
+                                   complete the registration.
+
+**/
+RETURN_STATUS
+EFIAPI
+PciRegisterForRuntimeAccess (
+  IN UINTN  Address
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return RETURN_UNSUPPORTED;
+}
+
+/**
+  Reads an 8-bit PCI configuration register.
+
+  Reads and returns the 8-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are
+  serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @return The read value from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciRead8 (
+  IN      UINTN                     Address
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes an 8-bit PCI configuration register.
+
+  Writes the 8-bit PCI configuration register specified by Address with the
+  value specified by Value. Value is returned. This function must guarantee
+  that all PCI read and write operations are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  Value   The value to write.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciWrite8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     Value
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise OR of an 8-bit PCI configuration register with
+  an 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 8-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  OrData  The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciOr8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
+  value.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 8-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  AndData The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciAnd8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     AndData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
+  value, followed by a bitwise OR with another 8-bit value.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and
+  the value specified by OrData, and writes the result to the 8-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  AndData The value to AND with the PCI configuration register.
+  @param  OrData  The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciAndThenOr8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     AndData,
+  IN      UINT8                     OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in an 8-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciBitFieldRead8 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  8-bit register is returned.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciBitFieldWrite8 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     Value
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 8-bit port.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 8-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciBitFieldOr8 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 8-bit register.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 8-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized. Extra left bits in AndData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciBitFieldAnd8 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     AndData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  8-bit port.
+
+  Reads the 8-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 8-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT8
+EFIAPI
+PciBitFieldAndThenOr8 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     AndData,
+  IN      UINT8                     OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 16-bit PCI configuration register.
+
+  Reads and returns the 16-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are
+  serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @return The read value from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciRead16 (
+  IN      UINTN                     Address
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 16-bit PCI configuration register.
+
+  Writes the 16-bit PCI configuration register specified by Address with the
+  value specified by Value. Value is returned. This function must guarantee
+  that all PCI read and write operations are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  Value   The value to write.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciWrite16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    Value
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise OR of a 16-bit PCI configuration register with
+  a 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 16-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  OrData  The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciOr16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
+  value.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 16-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  AndData The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciAnd16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    AndData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
+  value, followed a  bitwise OR with another 16-bit value.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and
+  the value specified by OrData, and writes the result to the 16-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  AndData The value to AND with the PCI configuration register.
+  @param  OrData  The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciAndThenOr16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    AndData,
+  IN      UINT16                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in a 16-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciBitFieldRead16 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  16-bit register is returned.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciBitFieldWrite16 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    Value
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 16-bit port.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 16-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciBitFieldOr16 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 16-bit register.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 16-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized. Extra left bits in AndData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciBitFieldAnd16 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    AndData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  16-bit port.
+
+  Reads the 16-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 16-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 16-bit boundary, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT16
+EFIAPI
+PciBitFieldAndThenOr16 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    AndData,
+  IN      UINT16                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 32-bit PCI configuration register.
+
+  Reads and returns the 32-bit PCI configuration register specified by Address.
+  This function must guarantee that all PCI read and write operations are
+  serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+
+  @return The read value from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciRead32 (
+  IN      UINTN                     Address
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 32-bit PCI configuration register.
+
+  Writes the 32-bit PCI configuration register specified by Address with the
+  value specified by Value. Value is returned. This function must guarantee
+  that all PCI read and write operations are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  Value   The value to write.
+
+  @return The value written to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciWrite32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    Value
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise OR of a 32-bit PCI configuration register with
+  a 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 32-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  OrData  The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciOr32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
+  value.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 32-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  AndData The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciAnd32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    AndData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
+  value, followed a  bitwise OR with another 32-bit value.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData,
+  performs a bitwise OR between the result of the AND operation and
+  the value specified by OrData, and writes the result to the 32-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Address Address that encodes the PCI Bus, Device, Function and
+                  Register.
+  @param  AndData The value to AND with the PCI configuration register.
+  @param  OrData  The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciAndThenOr32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    AndData,
+  IN      UINT32                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field of a PCI configuration register.
+
+  Reads the bit field in a 32-bit PCI configuration register. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Address   PCI configuration register to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+
+  @return The value of the bit field read from the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciBitFieldRead32 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a bit field to a PCI configuration register.
+
+  Writes Value to the bit field of the PCI configuration register. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination PCI configuration register are preserved. The new value of the
+  32-bit register is returned.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciBitFieldWrite32 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    Value
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
+  writes the result back to the bit field in the 32-bit port.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise OR between the read result and the value specified by
+  OrData, and writes the result to the 32-bit PCI configuration register
+  specified by Address. The value written to the PCI configuration register is
+  returned. This function must guarantee that all PCI read and write operations
+  are serialized. Extra left bits in OrData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  OrData    The value to OR with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciBitFieldOr32 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
+  AND, and writes the result back to the bit field in the 32-bit register.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise AND between the read result and the value specified by AndData, and
+  writes the result to the 32-bit PCI configuration register specified by
+  Address. The value written to the PCI configuration register is returned.
+  This function must guarantee that all PCI read and write operations are
+  serialized. Extra left bits in AndData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the PCI configuration register.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciBitFieldAnd32 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    AndData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  32-bit port.
+
+  Reads the 32-bit PCI configuration register specified by Address, performs a
+  bitwise AND followed by a bitwise OR between the read result and
+  the value specified by AndData, and writes the result to the 32-bit PCI
+  configuration register specified by Address. The value written to the PCI
+  configuration register is returned. This function must guarantee that all PCI
+  read and write operations are serialized. Extra left bits in both AndData and
+  OrData are stripped.
+
+  If Address > 0x0FFFFFFF, then ASSERT().
+  If Address is not aligned on a 32-bit boundary, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by
+    StartBit and EndBit, then ASSERT().
+
+  @param  Address   PCI configuration register to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the PCI configuration register.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the PCI configuration register.
+
+**/
+UINT32
+EFIAPI
+PciBitFieldAndThenOr32 (
+  IN      UINTN                     Address,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    AndData,
+  IN      UINT32                    OrData
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a range of PCI configuration registers into a caller supplied buffer.
+
+  Reads the range of PCI configuration registers specified by StartAddress and
+  Size into the buffer specified by Buffer. This function only allows the PCI
+  configuration registers from a single PCI function to be read. Size is
+  returned. When possible 32-bit PCI configuration read cycles are used to read
+  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
+  and 16-bit PCI configuration read cycles may be used at the beginning and the
+  end of the range.
+
+  If StartAddress > 0x0FFFFFFF, then ASSERT().
+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+  If Size > 0 and Buffer is NULL, then ASSERT().
+
+  @param  StartAddress  Starting address that encodes the PCI Bus, Device,
+                        Function and Register.
+  @param  Size          Size in bytes of the transfer.
+  @param  Buffer        Pointer to a buffer receiving the data read.
+
+  @return Size
+
+**/
+UINTN
+EFIAPI
+PciReadBuffer (
+  IN      UINTN                     StartAddress,
+  IN      UINTN                     Size,
+  OUT     VOID                      *Buffer
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Copies the data in a caller supplied buffer to a specified range of PCI
+  configuration space.
+
+  Writes the range of PCI configuration registers specified by StartAddress and
+  Size from the buffer specified by Buffer. This function only allows the PCI
+  configuration registers from a single PCI function to be written. Size is
+  returned. When possible 32-bit PCI configuration write cycles are used to
+  write from StartAdress to StartAddress + Size. Due to alignment restrictions,
+  8-bit and 16-bit PCI configuration write cycles may be used at the beginning
+  and the end of the range.
+
+  If StartAddress > 0x0FFFFFFF, then ASSERT().
+  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
+  If Size > 0 and Buffer is NULL, then ASSERT().
+
+  @param  StartAddress  Starting address that encodes the PCI Bus, Device,
+                        Function and Register.
+  @param  Size          Size in bytes of the transfer.
+  @param  Buffer        Pointer to a buffer containing the data to write.
+
+  @return Size written to StartAddress.
+
+**/
+UINTN
+EFIAPI
+PciWriteBuffer (
+  IN      UINTN                     StartAddress,
+  IN      UINTN                     Size,
+  IN      VOID                      *Buffer
+  )
+{
+  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
+  ASSERT (FALSE);
+  return 0;
+}
diff --git a/MdePkg/Library/PciLibNull/PciLibNull.inf b/MdePkg/Library/PciLibNull/PciLibNull.inf
new file mode 100644
index 0000000000000000000000000000000000000000..1778b4025e550939a6d13c5cc466567ce99ebaa5
--- /dev/null
+++ b/MdePkg/Library/PciLibNull/PciLibNull.inf
@@ -0,0 +1,25 @@
+#/** @file
+#
+#  Null implementation of Pcilib
+#
+#  Copyright (c) 2019, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = PciLibNull
+  FILE_GUID                      = C2E95ECC-9A39-4293-9F52-4C82BA370952
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PciLib
+
+
+[Sources]
+  PciLibNull.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
  2020-05-14  8:40 ` [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver Sami Mujawar
  2020-05-14  8:40 ` [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:22   ` Ard Biesheuvel
  2020-05-14 16:33   ` [edk2-devel] " Michael D Kinney
  2020-05-14  8:40 ` [PATCH v1 04/11] ArmPlatformPkg: Use MMIO to read device memory Sami Mujawar
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, michael.d.kinney, liming.gao,
	Alexandru.Elisei, Andre.Przywara, Matteo.Carlini, Laura.Moretta,
	nd

Some device drivers perform copy operations on
device memory, e.g. device drivers for a Flash
device. On some architectures unaligned access
to device memory regions is not permitted. To
add to this if the device is virtualised then
there are further restrictions on the type of
load/store operations that can be performed
on the device memory regions, e.g. on AARCH64,
Pre/Post index or LDP operations cannot be
used, as a trap to EL2 does not provide the
syndrome information to the hypervisor.

To address these issues this patch introduces
BaseMemoryLibMmio library which provides an
implementation of Base memory library that
uses aligned MMIO accesses.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf |  50 ++++
 MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni |  15 +
 MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c   |  62 ++++
 MdePkg/Library/BaseMemoryLibMmio/CopyMem.c             | 149 ++++++++++
 MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c      |  59 ++++
 MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c |  50 ++++
 MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c       | 304 ++++++++++++++++++++
 MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c          | 143 +++++++++
 MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h     | 248 ++++++++++++++++
 MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c    |  63 ++++
 MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c    |  62 ++++
 MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c    |  63 ++++
 MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c     |  95 ++++++
 MdePkg/Library/BaseMemoryLibMmio/SetMem.c              |  83 ++++++
 MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c     |  60 ++++
 MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c     |  60 ++++
 MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c     |  60 ++++
 MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c       |  87 ++++++
 MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c      |  52 ++++
 19 files changed, 1765 insertions(+)

diff --git a/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
new file mode 100644
index 0000000000000000000000000000000000000000..3a61cb985a242a4ce7a2446c4efb9b78fb1d7b5d
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
@@ -0,0 +1,50 @@
+## @file
+#  Instance of Base Memory Library using Mmio operations.
+#
+#
+#  Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = BaseMemoryLibMmio
+  MODULE_UNI_FILE                = BaseMemoryLibMmio.uni
+  FILE_GUID                      = 5724063D-9855-4B3A-8DEE-1F80ED07E096
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = BaseMemoryLib
+
+#
+#  VALID_ARCHITECTURES           = ARM AARCH64
+#
+
+[Sources]
+  SetMem.c
+  ScanMem64Wrapper.c
+  ScanMem32Wrapper.c
+  ScanMem16Wrapper.c
+  ScanMem8Wrapper.c
+  ZeroMemWrapper.c
+  CompareMemWrapper.c
+  SetMem64Wrapper.c
+  SetMem32Wrapper.c
+  SetMem16Wrapper.c
+  SetMemWrapper.c
+  CopyMemWrapper.c
+  IsZeroBufferWrapper.c
+  MemLibGeneric.c
+  MemLibGuid.c
+  CopyMem.c
+  MemLibInternals.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  DebugLib
+  BaseLib
+  IoLib
+
diff --git a/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni
new file mode 100644
index 0000000000000000000000000000000000000000..3dc99103e9a673902abcefe824d5cf5c19b258b8
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni
@@ -0,0 +1,15 @@
+// /** @file
+// Instance of Base Memory Library using Mmio operations.
+//
+//
+// Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Instance of Base Memory Library using Mmio operations"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Base Memory Library using Mmio operations"
+
diff --git a/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..63e0e3ea583cb242a9242f483e8c952e48122e77
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
@@ -0,0 +1,62 @@
+/** @file
+  CompareMem() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Compares the contents of two buffers.
+
+  This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
+  If all Length bytes of the two buffers are identical, then 0 is returned.  Otherwise, the
+  value returned is the first mismatched byte in SourceBuffer subtracted from the first
+  mismatched byte in DestinationBuffer.
+
+  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
+  If Length > 0 and SourceBuffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
+  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
+
+  @param  DestinationBuffer A pointer to the destination buffer to compare.
+  @param  SourceBuffer      A pointer to the source buffer to compare.
+  @param  Length            The number of bytes to compare.
+
+  @return 0                 All Length bytes of the two buffers are identical.
+  @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
+                            mismatched byte in DestinationBuffer.
+
+**/
+INTN
+EFIAPI
+CompareMem (
+  IN CONST VOID  *DestinationBuffer,
+  IN CONST VOID  *SourceBuffer,
+  IN UINTN       Length
+  )
+{
+  if (Length == 0 || DestinationBuffer == SourceBuffer) {
+    return 0;
+  }
+  ASSERT (DestinationBuffer != NULL);
+  ASSERT (SourceBuffer != NULL);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)DestinationBuffer));
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)SourceBuffer));
+
+  return InternalMemCompareMem (DestinationBuffer, SourceBuffer, Length);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c b/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
new file mode 100644
index 0000000000000000000000000000000000000000..84a207bf0f8a537b0832b5c4c9f6735122ee7851
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
@@ -0,0 +1,149 @@
+/** @file
+  Implementation of the InternalMemCopyMem routine. This function is broken
+  out into its own source file so that it can be excluded from a build for a
+  particular platform easily if an optimized version is desired.
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2012 - 2020, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Copy Length bytes from Source to Destination.
+
+  @param  DestinationBuffer The target of the copy request.
+  @param  SourceBuffer      The place to copy from.
+  @param  Length            The number of bytes to copy.
+
+  @return Destination
+
+**/
+VOID *
+EFIAPI
+InternalMemCopyMem (
+  OUT     VOID                      *DestinationBuffer,
+  IN      CONST VOID                *SourceBuffer,
+  IN      UINTN                     Length
+  )
+{
+  //
+  // Declare the local variables that actually move the data elements as
+  // volatile to prevent the optimizer from replacing this function with
+  // the intrinsic memcpy()
+  //
+  volatile UINT8                    *Destination8;
+  CONST UINT8                       *Source8;
+  volatile UINT32                   *Destination32;
+  CONST UINT32                      *Source32;
+  volatile UINT64                   *Destination64;
+  CONST UINT64                      *Source64;
+  UINTN                             Alignment;
+
+  if ((((UINTN)DestinationBuffer & 0x7) == 0) &&
+      (((UINTN)SourceBuffer & 0x7) == 0)      &&
+      (Length >= 8)) {
+    if (SourceBuffer > DestinationBuffer) {
+      Destination64 = (UINT64*)DestinationBuffer;
+      Source64 = (CONST UINT64*)SourceBuffer;
+      while (Length >= 8) {
+        MmioWrite64 ((UINTN)Destination64++, MmioRead64 ((UINTN)Source64++));
+        Length -= 8;
+      }
+
+      // Finish if there are still some bytes to copy
+      Destination8 = (UINT8*)Destination64;
+      Source8 = (CONST UINT8*)Source64;
+      while (Length-- != 0) {
+        MmioWrite8 ((UINTN)Destination8++, MmioRead8 ((UINTN)Source8++));
+      }
+    } else if (SourceBuffer < DestinationBuffer) {
+      Destination64 = (UINT64*)((UINTN)DestinationBuffer + Length);
+      Source64 = (CONST UINT64*)((UINTN)SourceBuffer + Length);
+
+      // Destination64 and Source64 were aligned on a 64-bit boundary
+      // but if length is not a multiple of 8 bytes then they won't be
+      // anymore.
+
+      Alignment = Length & 0x7;
+      if (Alignment != 0) {
+        Destination8 = (UINT8*)Destination64;
+        Source8 = (CONST UINT8*)Source64;
+
+        while (Alignment-- != 0) {
+          MmioWrite8 ((UINTN)--Destination8, MmioRead8 ((UINTN)--Source8));
+          --Length;
+        }
+        Destination64 = (UINT64*)Destination8;
+        Source64 = (CONST UINT64*)Source8;
+      }
+
+      while (Length > 0) {
+        MmioWrite64 ((UINTN)--Destination64, MmioRead64 ((UINTN)--Source64));
+        Length -= 8;
+      }
+    }
+  } else if ((((UINTN)DestinationBuffer & 0x3) == 0)  &&
+             (((UINTN)SourceBuffer & 0x3) == 0)       &&
+             (Length >= 4)) {
+    if (SourceBuffer > DestinationBuffer) {
+      Destination32 = (UINT32*)DestinationBuffer;
+      Source32 = (CONST UINT32*)SourceBuffer;
+      while (Length >= 4) {
+        MmioWrite32 ((UINTN)Destination32++, MmioRead32 ((UINTN)Source32++));
+        Length -= 4;
+      }
+
+      // Finish if there are still some bytes to copy
+      Destination8 = (UINT8*)Destination32;
+      Source8 = (CONST UINT8*)Source32;
+      while (Length-- != 0) {
+        MmioWrite8 ((UINTN)Destination8++, MmioRead8 ((UINTN)Source8++));
+      }
+    } else if (SourceBuffer < DestinationBuffer) {
+      Destination32 = (UINT32*)((UINTN)DestinationBuffer + Length);
+      Source32 = (CONST UINT32*)((UINTN)SourceBuffer + Length);
+
+      // Destination32 and Source32 were aligned on a 32-bit boundary
+      // but if length is not a multiple of 4 bytes then they won't be
+      // anymore.
+
+      Alignment = Length & 0x3;
+      if (Alignment != 0) {
+        Destination8 = (UINT8*)Destination32;
+        Source8 = (CONST UINT8*)Source32;
+
+        while (Alignment-- != 0) {
+          MmioWrite8 ((UINTN)--Destination8, MmioRead8 ((UINTN)--Source8));
+          --Length;
+        }
+        Destination32 = (UINT32*)Destination8;
+        Source32 = (CONST UINT32*)Source8;
+      }
+
+      while (Length > 0) {
+        MmioWrite32 ((UINTN)--Destination32, MmioRead32 ((UINTN)--Source32));
+        Length -= 4;
+      }
+    }
+  } else {
+    if (SourceBuffer > DestinationBuffer) {
+      Destination8 = (UINT8*)DestinationBuffer;
+      Source8 = (CONST UINT8*)SourceBuffer;
+      while (Length-- != 0) {
+        MmioWrite8 ((UINTN)Destination8++, MmioRead8 ((UINTN)Source8++));
+      }
+    } else if (SourceBuffer < DestinationBuffer) {
+      Destination8 = (UINT8*)DestinationBuffer + (Length - 1);
+      Source8 = (CONST UINT8*)SourceBuffer + (Length - 1);
+      while (Length-- != 0) {
+        MmioWrite8 ((UINTN)Destination8--, MmioRead8 ((UINTN)Source8--));
+      }
+    }
+  }
+  return DestinationBuffer;
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..d557bbb8904c2b07c644261290a62be6fc831c08
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
@@ -0,0 +1,59 @@
+/** @file
+  CopyMem() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Copies a source buffer to a destination buffer, and returns the destination buffer.
+
+  This function copies Length bytes from SourceBuffer to DestinationBuffer, and returns
+  DestinationBuffer.  The implementation must be reentrant, and it must handle the case
+  where SourceBuffer overlaps DestinationBuffer.
+
+  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
+  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
+
+  @param  DestinationBuffer   A pointer to the destination buffer of the memory copy.
+  @param  SourceBuffer        A pointer to the source buffer of the memory copy.
+  @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
+
+  @return DestinationBuffer.
+
+**/
+VOID *
+EFIAPI
+CopyMem (
+  OUT VOID       *DestinationBuffer,
+  IN CONST VOID  *SourceBuffer,
+  IN UINTN       Length
+  )
+{
+  if (Length == 0) {
+    return DestinationBuffer;
+  }
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)DestinationBuffer));
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)SourceBuffer));
+
+  if (DestinationBuffer == SourceBuffer) {
+    return DestinationBuffer;
+  }
+  return InternalMemCopyMem (DestinationBuffer, SourceBuffer, Length);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c3133c668c434839b0d9bf105bc7265eeb76a5b
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c
@@ -0,0 +1,50 @@
+/** @file
+  Implementation of IsZeroBuffer function.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Checks if the contents of a buffer are all zeros.
+
+  This function checks whether the contents of a buffer are all zeros. If the
+  contents are all zeros, return TRUE. Otherwise, return FALSE.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to be checked.
+  @param  Length      The size of the buffer (in bytes) to be checked.
+
+  @retval TRUE        Contents of the buffer are all zeros.
+  @retval FALSE       Contents of the buffer are not all zeros.
+
+**/
+BOOLEAN
+EFIAPI
+IsZeroBuffer (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length
+  )
+{
+  ASSERT (!(Buffer == NULL && Length > 0));
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  return InternalMemIsZeroBuffer (Buffer, Length);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c b/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c65b674230795e956c9d22f2b9c151c41839706
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
@@ -0,0 +1,304 @@
+/** @file
+  Architecture Independent Base Memory Library Implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Fills a target buffer with a 16-bit value, and returns the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The count of 16-bit value to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem16 (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT16                    Value
+  )
+{
+  volatile UINT16  *Destination16;
+
+  Destination16 = (UINT16*)Buffer;
+  while (Length > 0) {
+    MmioWrite16 ((UINTN)--Destination16, Value);
+    Length -= 2;
+  }
+
+  return Buffer;
+}
+
+/**
+  Fills a target buffer with a 32-bit value, and returns the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The count of 32-bit value to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem32 (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT32                    Value
+  )
+{
+  volatile UINT32  *Destination32;
+
+  Destination32 = (UINT32*)Buffer;
+  while (Length > 0) {
+    MmioWrite32 ((UINTN)--Destination32, Value);
+    Length -= 4;
+  }
+  return Buffer;
+}
+
+/**
+  Fills a target buffer with a 64-bit value, and returns the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The count of 64-bit value to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem64 (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT64                    Value
+  )
+{
+  volatile UINT64  *Destination64;
+
+  Destination64 = (UINT64*)Buffer;
+  while (Length > 0) {
+    MmioWrite64 ((UINTN)--Destination64, Value);
+    Length -= 8;
+  }
+  return Buffer;
+}
+
+/**
+  Set Buffer to 0 for Size bytes.
+
+  @param  Buffer Memory to set.
+  @param  Length The number of bytes to set.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemZeroMem (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length
+  )
+{
+  return InternalMemSetMem (Buffer, Length, 0);
+}
+
+/**
+  Compares two memory buffers of a given length.
+
+  @param  DestinationBuffer The first memory buffer.
+  @param  SourceBuffer      The second memory buffer.
+  @param  Length            Length of DestinationBuffer and SourceBuffer memory
+                            regions to compare. Must be non-zero.
+
+  @return 0                 All Length bytes of the two buffers are identical.
+  @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
+                            mismatched byte in DestinationBuffer.
+
+**/
+INTN
+EFIAPI
+InternalMemCompareMem (
+  IN      CONST VOID                *DestinationBuffer,
+  IN      CONST VOID                *SourceBuffer,
+  IN      UINTN                     Length
+  )
+{
+  while ((--Length != 0) &&
+         (MmioRead8 ((UINTN)DestinationBuffer) ==
+          MmioRead8 ((UINTN)SourceBuffer))) {
+    DestinationBuffer = (INT8*)DestinationBuffer + 1;
+    SourceBuffer = (INT8*)SourceBuffer + 1;
+  }
+  return (INTN)MmioRead8 ((UINTN)DestinationBuffer) -
+         (INTN)MmioRead8 ((UINTN)SourceBuffer);
+}
+
+/**
+  Scans a target buffer for an 8-bit value, and returns a pointer to the
+  matching 8-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 8-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem8 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT8                     Value
+  )
+{
+  CONST UINT8                       *Pointer;
+
+  Pointer = (CONST UINT8*)Buffer;
+  do {
+    if (MmioRead8 ((UINTN)Pointer) == Value) {
+      return Pointer;
+    }
+    ++Pointer;
+  } while (--Length != 0);
+  return NULL;
+}
+
+/**
+  Scans a target buffer for a 16-bit value, and returns a pointer to the
+  matching 16-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 16-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem16 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT16                    Value
+  )
+{
+  CONST UINT16                      *Pointer;
+
+  Pointer = (CONST UINT16*)Buffer;
+  do {
+    if (MmioRead16 ((UINTN)Pointer) == Value) {
+      return Pointer;
+    }
+    ++Pointer;
+  } while (--Length != 0);
+  return NULL;
+}
+
+/**
+  Scans a target buffer for a 32-bit value, and returns a pointer to the
+  matching 32-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 32-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem32 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT32                    Value
+  )
+{
+  CONST UINT32                      *Pointer;
+
+  Pointer = (CONST UINT32*)Buffer;
+  do {
+    if (MmioRead32 ((UINTN)Pointer) == Value) {
+      return Pointer;
+    }
+    ++Pointer;
+  } while (--Length != 0);
+  return NULL;
+}
+
+/**
+  Scans a target buffer for a 64-bit value, and returns a pointer to the
+  matching 64-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 64-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem64 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT64                    Value
+  )
+{
+  CONST UINT64                      *Pointer;
+
+  Pointer = (CONST UINT64*)Buffer;
+  do {
+    if (MmioRead64 ((UINTN)Pointer) == Value) {
+      return Pointer;
+    }
+    ++Pointer;
+  } while (--Length != 0);
+  return NULL;
+}
+
+/**
+  Checks whether the contents of a buffer are all zeros.
+
+  @param  Buffer  The pointer to the buffer to be checked.
+  @param  Length  The size of the buffer (in bytes) to be checked.
+
+  @retval TRUE    Contents of the buffer are all zeros.
+  @retval FALSE   Contents of the buffer are not all zeros.
+
+**/
+BOOLEAN
+EFIAPI
+InternalMemIsZeroBuffer (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length
+  )
+{
+  CONST UINT8 *BufferData;
+  UINTN       Index;
+
+  BufferData = Buffer;
+  for (Index = 0; Index < Length; Index++) {
+    if (MmioRead8 ((UINTN)(BufferData + Index)) != 0) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c b/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
new file mode 100644
index 0000000000000000000000000000000000000000..ce69e431309f4447a4e99251a86b5182123e5b97
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
@@ -0,0 +1,143 @@
+/** @file
+  Implementation of GUID functions.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Copies a source GUID to a destination GUID.
+
+  This function copies the contents of the 128-bit GUID specified by SourceGuid
+  to DestinationGuid, and returns DestinationGuid.
+
+  If DestinationGuid is NULL, then ASSERT().
+  If SourceGuid is NULL, then ASSERT().
+
+  @param  DestinationGuid   A pointer to the destination GUID.
+  @param  SourceGuid        A pointer to the source GUID.
+
+  @return DestinationGuid.
+
+**/
+GUID *
+EFIAPI
+CopyGuid (
+  OUT GUID       *DestinationGuid,
+  IN CONST GUID  *SourceGuid
+  )
+{
+  return InternalMemCopyMem (DestinationGuid, SourceGuid, sizeof (GUID));
+}
+
+/**
+  Compares two GUIDs.
+
+  This function compares Guid1 to Guid2.  If the GUIDs are identical then TRUE is returned.
+  If there are any bit differences in the two GUIDs, then FALSE is returned.
+
+  If Guid1 is NULL, then ASSERT().
+  If Guid2 is NULL, then ASSERT().
+
+  @param  Guid1       A pointer to a 128 bit GUID.
+  @param  Guid2       A pointer to a 128 bit GUID.
+
+  @retval TRUE        Guid1 and Guid2 are identical.
+  @retval FALSE       Guid1 and Guid2 are not identical.
+
+**/
+BOOLEAN
+EFIAPI
+CompareGuid (
+  IN CONST GUID  *Guid1,
+  IN CONST GUID  *Guid2
+  )
+{
+  return (0 == InternalMemCompareMem (Guid1, Guid2, sizeof (GUID)));
+}
+
+/**
+  Scans a target buffer for a GUID, and returns a pointer to the matching GUID
+  in the target buffer.
+
+  This function searches the target buffer specified by Buffer and Length from
+  the lowest address to the highest address at 128-bit increments for the 128-bit
+  GUID value that matches Guid.  If a match is found, then a pointer to the matching
+  GUID in the target buffer is returned.  If no match is found, then NULL is returned.
+  If Length is 0, then NULL is returned.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is not aligned on a 128-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The number of bytes in Buffer to scan.
+  @param  Guid    The value to search for in the target buffer.
+
+  @return A pointer to the matching Guid in the target buffer or NULL otherwise.
+
+**/
+VOID *
+EFIAPI
+ScanGuid (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length,
+  IN CONST GUID  *Guid
+  )
+{
+  CONST GUID                        *GuidPtr;
+
+  ASSERT (((UINTN)Buffer & (sizeof (Guid->Data1) - 1)) == 0);
+  ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer + 1));
+  ASSERT ((Length & (sizeof (*GuidPtr) - 1)) == 0);
+
+  GuidPtr = (GUID*)Buffer;
+  Buffer  = GuidPtr + Length / sizeof (*GuidPtr);
+  while (GuidPtr < (CONST GUID*)Buffer) {
+    if (CompareGuid (GuidPtr, Guid)) {
+      return (VOID*)GuidPtr;
+    }
+    GuidPtr++;
+  }
+  return NULL;
+}
+
+/**
+  Checks if the given GUID is a zero GUID.
+
+  This function checks whether the given GUID is a zero GUID. If the GUID is
+  identical to a zero GUID then TRUE is returned. Otherwise, FALSE is returned.
+
+  If Guid is NULL, then ASSERT().
+
+  @param  Guid        The pointer to a 128 bit GUID.
+
+  @retval TRUE        Guid is a zero GUID.
+  @retval FALSE       Guid is not a zero GUID.
+
+**/
+BOOLEAN
+EFIAPI
+IsZeroGuid (
+  IN CONST GUID  *Guid
+  )
+{
+  return InternalMemIsZeroBuffer (Guid, sizeof (GUID));
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h b/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
new file mode 100644
index 0000000000000000000000000000000000000000..dc28a9078a8a707af8a83517d3756c6126093079
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
@@ -0,0 +1,248 @@
+/** @file
+  Declaration of internal functions for Base Memory Library.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+
+  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __MEM_LIB_INTERNALS__
+#define __MEM_LIB_INTERNALS__
+
+#include <Base.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+
+/**
+  Copy Length bytes from Source to Destination.
+
+  @param  DestinationBuffer Target of copy
+  @param  SourceBuffer      Place to copy from
+  @param  Length            The number of bytes to copy
+
+  @return Destination
+
+**/
+VOID *
+EFIAPI
+InternalMemCopyMem (
+  OUT     VOID                      *DestinationBuffer,
+  IN      CONST VOID                *SourceBuffer,
+  IN      UINTN                     Length
+  );
+
+/**
+  Set Buffer to Value for Size bytes.
+
+  @param  Buffer   The memory to set.
+  @param  Length   The number of bytes to set
+  @param  Value    The value of the set operation.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT8                     Value
+  );
+
+/**
+  Fills a target buffer with a 16-bit value, and returns the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The count of 16-bit value to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem16 (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT16                    Value
+  );
+
+/**
+  Fills a target buffer with a 32-bit value, and returns the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The count of 32-bit value to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem32 (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT32                    Value
+  );
+
+/**
+  Fills a target buffer with a 64-bit value, and returns the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The count of 64-bit value to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem64 (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT64                    Value
+  );
+
+/**
+  Set Buffer to 0 for Size bytes.
+
+  @param  Buffer The memory to set.
+  @param  Length The number of bytes to set.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemZeroMem (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length
+  );
+
+/**
+  Compares two memory buffers of a given length.
+
+  @param  DestinationBuffer The first memory buffer.
+  @param  SourceBuffer      The second memory buffer.
+  @param  Length            The length of DestinationBuffer and SourceBuffer memory
+                            regions to compare. Must be non-zero.
+
+  @return 0                 All Length bytes of the two buffers are identical.
+  @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
+                            mismatched byte in DestinationBuffer.
+
+**/
+INTN
+EFIAPI
+InternalMemCompareMem (
+  IN      CONST VOID                *DestinationBuffer,
+  IN      CONST VOID                *SourceBuffer,
+  IN      UINTN                     Length
+  );
+
+/**
+  Scans a target buffer for an 8-bit value, and returns a pointer to the
+  matching 8-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 8-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem8 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT8                     Value
+  );
+
+/**
+  Scans a target buffer for a 16-bit value, and returns a pointer to the
+  matching 16-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 16-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem16 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT16                    Value
+  );
+
+/**
+  Scans a target buffer for a 32-bit value, and returns a pointer to the
+  matching 32-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 32-bit value to scan. Must be non-zero.
+  @param  Value   The value to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem32 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT32                    Value
+  );
+
+/**
+  Scans a target buffer for a 64-bit value, and returns a pointer to the
+  matching 64-bit value in the target buffer.
+
+  @param  Buffer  The pointer to the target buffer to scan.
+  @param  Length  The count of 64-bit value to scan. Must be non-zero.
+  @param  Value   The calue to search for in the target buffer.
+
+  @return The pointer to the first occurrence, or NULL if not found.
+
+**/
+CONST VOID *
+EFIAPI
+InternalMemScanMem64 (
+  IN      CONST VOID                *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT64                    Value
+  );
+
+/**
+  Checks whether the contents of a buffer are all zeros.
+
+  @param  Buffer  The pointer to the buffer to be checked.
+  @param  Length  The size of the buffer (in bytes) to be checked.
+
+  @retval TRUE    Contents of the buffer are all zeros.
+  @retval FALSE   Contents of the buffer are not all zeros.
+
+**/
+BOOLEAN
+EFIAPI
+InternalMemIsZeroBuffer (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length
+  );
+
+#endif
diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..ad9330b9938df9995a597dbabc1aa2744aa0d8c1
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
@@ -0,0 +1,63 @@
+/** @file
+  ScanMem16() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Scans a target buffer for a 16-bit value, and returns a pointer to the matching 16-bit value
+  in the target buffer.
+
+  This function searches the target buffer specified by Buffer and Length from the lowest
+  address to the highest address for a 16-bit value that matches Value.  If a match is found,
+  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
+  then NULL is returned.  If Length is 0, then NULL is returned.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the target buffer to scan.
+  @param  Length      The number of bytes in Buffer to scan.
+  @param  Value       The value to search for in the target buffer.
+
+  @return A pointer to the matching byte in the target buffer or NULL otherwise.
+
+**/
+VOID *
+EFIAPI
+ScanMem16 (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length,
+  IN UINT16      Value
+  )
+{
+  if (Length == 0) {
+    return NULL;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) == 0);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
+
+  return (VOID*)InternalMemScanMem16 (Buffer, Length / sizeof (Value), Value);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..84675697d12016f92c46c08c65aca647288a8b99
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
@@ -0,0 +1,62 @@
+/** @file
+  ScanMem32() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Scans a target buffer for a 32-bit value, and returns a pointer to the matching 32-bit value
+  in the target buffer.
+
+  This function searches the target buffer specified by Buffer and Length from the lowest
+  address to the highest address for a 32-bit value that matches Value.  If a match is found,
+  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
+  then NULL is returned.  If Length is 0, then NULL is returned.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the target buffer to scan.
+  @param  Length      The number of bytes in Buffer to scan.
+  @param  Value       The value to search for in the target buffer.
+
+  @return A pointer to the matching byte in the target buffer or NULL otherwise.
+
+**/
+VOID *
+EFIAPI
+ScanMem32 (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length,
+  IN UINT32      Value
+  )
+{
+  if (Length == 0) {
+    return NULL;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) == 0);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
+
+  return (VOID*)InternalMemScanMem32 (Buffer, Length / sizeof (Value), Value);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..df749dce457827fe070bad8b7c6071aae29ebb02
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
@@ -0,0 +1,63 @@
+/** @file
+  ScanMem64() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Scans a target buffer for a 64-bit value, and returns a pointer to the matching 64-bit value
+  in the target buffer.
+
+  This function searches the target buffer specified by Buffer and Length from the lowest
+  address to the highest address for a 64-bit value that matches Value.  If a match is found,
+  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
+  then NULL is returned.  If Length is 0, then NULL is returned.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the target buffer to scan.
+  @param  Length      The number of bytes in Buffer to scan.
+  @param  Value       The value to search for in the target buffer.
+
+  @return A pointer to the matching byte in the target buffer or NULL otherwise.
+
+**/
+VOID *
+EFIAPI
+ScanMem64 (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length,
+  IN UINT64      Value
+  )
+{
+  if (Length == 0) {
+    return NULL;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) == 0);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
+
+  return (VOID*)InternalMemScanMem64 (Buffer, Length / sizeof (Value), Value);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..170981017dbe31cf5e0c3dabf26a4fea33f7a7d7
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
@@ -0,0 +1,95 @@
+/** @file
+  ScanMem8() and ScanMemN() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Scans a target buffer for an 8-bit value, and returns a pointer to the matching 8-bit value
+  in the target buffer.
+
+  This function searches the target buffer specified by Buffer and Length from the lowest
+  address to the highest address for an 8-bit value that matches Value.  If a match is found,
+  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
+  then NULL is returned.  If Length is 0, then NULL is returned.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the target buffer to scan.
+  @param  Length      The number of bytes in Buffer to scan.
+  @param  Value       The value to search for in the target buffer.
+
+  @return A pointer to the matching byte in the target buffer, or NULL otherwise.
+
+**/
+VOID *
+EFIAPI
+ScanMem8 (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length,
+  IN UINT8       Value
+  )
+{
+  if (Length == 0) {
+    return NULL;
+  }
+  ASSERT (Buffer != NULL);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+
+  return (VOID*)InternalMemScanMem8 (Buffer, Length, Value);
+}
+
+/**
+  Scans a target buffer for a UINTN sized value, and returns a pointer to the matching
+  UINTN sized value in the target buffer.
+
+  This function searches the target buffer specified by Buffer and Length from the lowest
+  address to the highest address for a UINTN sized value that matches Value.  If a match is found,
+  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
+  then NULL is returned.  If Length is 0, then NULL is returned.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a UINTN boundary, then ASSERT().
+  If Length is not aligned on a UINTN boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the target buffer to scan.
+  @param  Length      The number of bytes in Buffer to scan.
+  @param  Value       The value to search for in the target buffer.
+
+  @return A pointer to the matching byte in the target buffer, or NULL otherwise.
+
+**/
+VOID *
+EFIAPI
+ScanMemN (
+  IN CONST VOID  *Buffer,
+  IN UINTN       Length,
+  IN UINTN       Value
+  )
+{
+  if (sizeof (UINTN) == sizeof (UINT64)) {
+    return ScanMem64 (Buffer, Length, (UINT64)Value);
+  } else {
+    return ScanMem32 (Buffer, Length, (UINT32)Value);
+  }
+}
+
diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
new file mode 100644
index 0000000000000000000000000000000000000000..40255670c6f26eb72a82568f035720fc6fe75546
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
@@ -0,0 +1,83 @@
+/** @file
+  Implementation of the EfiSetMem routine. This function is broken
+  out into its own source file so that it can be excluded from a
+  build for a particular platform easily if an optimized version
+  is desired.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2012 - 2020, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Set Buffer to Value for Size bytes.
+
+  @param  Buffer   The memory to set.
+  @param  Length   The number of bytes to set.
+  @param  Value    The value of the set operation.
+
+  @return Buffer
+
+**/
+VOID *
+EFIAPI
+InternalMemSetMem (
+  OUT     VOID                      *Buffer,
+  IN      UINTN                     Length,
+  IN      UINT8                     Value
+  )
+{
+  //
+  // Declare the local variables that actually move the data elements as
+  // volatile to prevent the optimizer from replacing this function with
+  // the intrinsic memset()
+  //
+  volatile UINT8                    *Pointer8;
+  volatile UINT32                   *Pointer32;
+  volatile UINT64                   *Pointer64;
+  UINT32                            Value32;
+  UINT64                            Value64;
+
+  if ((((UINTN)Buffer & 0x7) == 0) && (Length >= 8)) {
+    // Generate the 64bit value
+    Value32 = (Value << 24) | (Value << 16) | (Value << 8) | Value;
+    Value64 = LShiftU64 (Value32, 32) | Value32;
+
+    Pointer64 = (UINT64*)Buffer;
+    while (Length >= 8) {
+      MmioWrite64 ((UINTN)Pointer64++, Value64);
+      Length -= 8;
+    }
+
+    // Finish with bytes if needed
+    Pointer8 = (UINT8*)Pointer64;
+  } else if ((((UINTN)Buffer & 0x3) == 0) && (Length >= 4)) {
+    // Generate the 32bit value
+    Value32 = (Value << 24) | (Value << 16) | (Value << 8) | Value;
+
+    Pointer32 = (UINT32*)Buffer;
+    while (Length >= 4) {
+      MmioWrite32 ((UINTN)Pointer32++, Value32);
+      Length -= 4;
+    }
+
+    // Finish with bytes if needed
+    Pointer8 = (UINT8*)Pointer32;
+  } else {
+    Pointer8 = (UINT8*)Buffer;
+  }
+  while (Length-- > 0) {
+    MmioWrite8 ((UINTN)Pointer8++, Value);
+  }
+  return Buffer;
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..be785c5eb696ef6b913bf7bc0081a5f414c6f141
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
@@ -0,0 +1,60 @@
+/** @file
+  SetMem16() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Fills a target buffer with a 16-bit value, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with the 16-bit value specified by
+  Value, and returns Buffer. Value is repeated every 16-bits in for Length
+  bytes of Buffer.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+  If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is not aligned on a 16-bit boundary, then ASSERT().
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The number of bytes in Buffer to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer.
+
+**/
+VOID *
+EFIAPI
+SetMem16 (
+  OUT VOID   *Buffer,
+  IN UINTN   Length,
+  IN UINT16  Value
+  )
+{
+  if (Length == 0) {
+    return Buffer;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) == 0);
+  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
+
+  return InternalMemSetMem16 (Buffer, Length / sizeof (Value), Value);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..622c6eddccc88e846921782efc29e40f816ae499
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
@@ -0,0 +1,60 @@
+/** @file
+  SetMem32() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Fills a target buffer with a 32-bit value, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with the 32-bit value specified by
+  Value, and returns Buffer. Value is repeated every 32-bits in for Length
+  bytes of Buffer.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is not aligned on a 32-bit boundary, then ASSERT().
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The number of bytes in Buffer to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer.
+
+**/
+VOID *
+EFIAPI
+SetMem32 (
+  OUT VOID   *Buffer,
+  IN UINTN   Length,
+  IN UINT32  Value
+  )
+{
+  if (Length == 0) {
+    return Buffer;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) == 0);
+  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
+
+  return InternalMemSetMem32 (Buffer, Length / sizeof (Value), Value);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..7653eed85cd633be5aea439cf4ab62958dd62c47
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
@@ -0,0 +1,60 @@
+/** @file
+  SetMem64() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Fills a target buffer with a 64-bit value, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with the 64-bit value specified by
+  Value, and returns Buffer. Value is repeated every 64-bits in for Length
+  bytes of Buffer.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+  If Buffer is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is not aligned on a 64-bit boundary, then ASSERT().
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The number of bytes in Buffer to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer.
+
+**/
+VOID *
+EFIAPI
+SetMem64 (
+  OUT VOID   *Buffer,
+  IN UINTN   Length,
+  IN UINT64  Value
+  )
+{
+  if (Length == 0) {
+    return Buffer;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) == 0);
+  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
+
+  return InternalMemSetMem64 (Buffer, Length / sizeof (Value), Value);
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..96dd956686d15b4b4cb25157d764849043d1b57b
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
@@ -0,0 +1,87 @@
+/** @file
+  SetMem() and SetMemN() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Fills a target buffer with a byte value, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with Value, and returns Buffer.
+
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer    The memory to set.
+  @param  Length    The number of bytes to set.
+  @param  Value     The value with which to fill Length bytes of Buffer.
+
+  @return Buffer.
+
+**/
+VOID *
+EFIAPI
+SetMem (
+  OUT VOID  *Buffer,
+  IN UINTN  Length,
+  IN UINT8  Value
+  )
+{
+  if (Length == 0) {
+    return Buffer;
+  }
+
+  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
+
+  return InternalMemSetMem (Buffer, Length, Value);
+}
+
+/**
+  Fills a target buffer with a value that is size UINTN, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with the UINTN sized value specified by
+  Value, and returns Buffer. Value is repeated every sizeof(UINTN) bytes for Length
+  bytes of Buffer.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+  If Buffer is not aligned on a UINTN boundary, then ASSERT().
+  If Length is not aligned on a UINTN boundary, then ASSERT().
+
+  @param  Buffer  The pointer to the target buffer to fill.
+  @param  Length  The number of bytes in Buffer to fill.
+  @param  Value   The value with which to fill Length bytes of Buffer.
+
+  @return Buffer.
+
+**/
+VOID *
+EFIAPI
+SetMemN (
+  OUT VOID  *Buffer,
+  IN UINTN  Length,
+  IN UINTN  Value
+  )
+{
+  if (sizeof (UINTN) == sizeof (UINT64)) {
+    return SetMem64 (Buffer, Length, (UINT64)Value);
+  } else {
+    return SetMem32 (Buffer, Length, (UINT32)Value);
+  }
+}
diff --git a/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
new file mode 100644
index 0000000000000000000000000000000000000000..55246d121c6820d371af463792614c1d73676e6f
--- /dev/null
+++ b/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
@@ -0,0 +1,52 @@
+/** @file
+  ZeroMem() implementation.
+
+  The following BaseMemoryLib instances contain the same copy of this file:
+
+    BaseMemoryLib
+    BaseMemoryLibMmio
+    BaseMemoryLibMmx
+    BaseMemoryLibSse2
+    BaseMemoryLibRepStr
+    BaseMemoryLibOptDxe
+    BaseMemoryLibOptPei
+    PeiMemoryLib
+    UefiMemoryLib
+
+  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MemLibInternals.h"
+
+/**
+  Fills a target buffer with zeros, and returns the target buffer.
+
+  This function fills Length bytes of Buffer with zeros, and returns Buffer.
+
+  If Length > 0 and Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the target buffer to fill with zeros.
+  @param  Length      The number of bytes in Buffer to fill with zeros.
+
+  @return Buffer.
+
+**/
+VOID *
+EFIAPI
+ZeroMem (
+  OUT VOID  *Buffer,
+  IN UINTN  Length
+  )
+{
+  if (Length == 0) {
+    return Buffer;
+  }
+
+  ASSERT (Buffer != NULL);
+  ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer + 1));
+  return InternalMemZeroMem (Buffer, Length);
+}
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 04/11] ArmPlatformPkg: Use MMIO to read device memory
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (2 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  8:40 ` [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base Sami Mujawar
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

NorFlashDxe must use aligned MMIO accesses to
read data from flash as this is device memory.

The AlignedCopyMem() was used to copy the flash
data which prevented unaligned access to device
memory. However, the compiler could optimize the
code to generate pre/post indexed or LDP
operations. This is a problem for guest/virtual
firmware as the hypervisor code cannot get the
syndrome information for the trapped accesses.

Similarly, the GUIDS FwVolHeader->FileSystemGuid
and VariableStoreHeader->Signature in
ValidateFvHeader() are compared using
CompareGuid(). These GUIDs point to flash data
(which is device memory) and therefore need
aligned MMIO accesses.

To address the above issues, BaseMemoryLibMmio
library has been introduced to perform aligned
MMIO accesses.

This patch removes the usage of AlignedCopyMem()
and replaces it with CopyMem() with an expectation
that the BaseMemoryLibMmio will be linked
with NorFlashDxe.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c | 65 +-------------------
 1 file changed, 3 insertions(+), 62 deletions(-)

diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
index d9e196cbf18c32fe5306cc3c0674a7b5798a9191..f9890de8244d37e0e860fd183bb216ff7d1e7035 100644
--- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
+++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
@@ -1,6 +1,6 @@
 /** @file  NorFlashDxe.c
 
-  Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2011 - 2020, ARM Ltd. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -735,65 +735,6 @@ NorFlashWriteBlocks (
   return Status;
 }
 
-#define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
-
-/**
-  Copy Length bytes from Source to Destination, using aligned accesses only.
-  Note that this implementation uses memcpy() semantics rather then memmove()
-  semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
-
-  @param  DestinationBuffer The target of the copy request.
-  @param  SourceBuffer      The place to copy from.
-  @param  Length            The number of bytes to copy.
-
-  @return Destination
-
-**/
-STATIC
-VOID *
-AlignedCopyMem (
-  OUT     VOID                      *DestinationBuffer,
-  IN      CONST VOID                *SourceBuffer,
-  IN      UINTN                     Length
-  )
-{
-  UINT8             *Destination8;
-  CONST UINT8       *Source8;
-  UINT32            *Destination32;
-  CONST UINT32      *Source32;
-  UINT64            *Destination64;
-  CONST UINT64      *Source64;
-
-  if (BOTH_ALIGNED(DestinationBuffer, SourceBuffer, 8) && Length >= 8) {
-    Destination64 = DestinationBuffer;
-    Source64 = SourceBuffer;
-    while (Length >= 8) {
-      *Destination64++ = *Source64++;
-      Length -= 8;
-    }
-
-    Destination8 = (UINT8 *)Destination64;
-    Source8 = (CONST UINT8 *)Source64;
-  } else if (BOTH_ALIGNED(DestinationBuffer, SourceBuffer, 4) && Length >= 4) {
-    Destination32 = DestinationBuffer;
-    Source32 = SourceBuffer;
-    while (Length >= 4) {
-      *Destination32++ = *Source32++;
-      Length -= 4;
-    }
-
-    Destination8 = (UINT8 *)Destination32;
-    Source8 = (CONST UINT8 *)Source32;
-  } else {
-    Destination8 = DestinationBuffer;
-    Source8 = SourceBuffer;
-  }
-  while (Length-- != 0) {
-    *Destination8++ = *Source8++;
-  }
-  return DestinationBuffer;
-}
-
 EFI_STATUS
 NorFlashReadBlocks (
   IN NOR_FLASH_INSTANCE   *Instance,
@@ -841,7 +782,7 @@ NorFlashReadBlocks (
   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
 
   // Readout the data
-  AlignedCopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
+  CopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
 
   return EFI_SUCCESS;
 }
@@ -882,7 +823,7 @@ NorFlashRead (
   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
 
   // Readout the data
-  AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
+  CopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
 
   return EFI_SUCCESS;
 }
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (3 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v1 04/11] ArmPlatformPkg: Use MMIO to read device memory Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:24   ` Ard Biesheuvel
  2020-05-27 11:48   ` [edk2-devel] " Philippe Mathieu-Daudé
  2020-05-14  8:40 ` [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver Sami Mujawar
                   ` (5 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Some virtual machine managers like kvmtool can relocate
the devices in the system memory map. The information
about the devices location in memory is described in the
device tree. Therefore, the CFI memory region and the
associated Non volatile storage variables need to be
adjusted accordingly.

To support such use cases the non-volatile storage
variable base PCD PcdFlashNvStorageVariableBase has
been defined as a dynamic PCD.

The NOR flash driver was using the Flash non-volatile
storage variable base PCD as a fixed PCD, thereby
preventing runtime resolution of the variable base
address.

Therefore update the NOR flash driver to load the
PCD using PcdGet32 instead of FixedPcdGet32.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
index e248fdf6db94191648b5d33bf1a9263f446ee141..9cdd85096a463f69b3b864cecdeaf247e65f4f73 100644
--- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
+++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
@@ -1,6 +1,6 @@
 /*++ @file  NorFlashFvbDxe.c
 
- Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2011 - 2020, ARM Ltd. All rights reserved.<BR>
 
  SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -736,7 +736,7 @@ NorFlashFvbInitialize (
       EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
   ASSERT_EFI_ERROR (Status);
 
-  mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
+  mFlashNvStorageVariableBase = PcdGet32 (PcdFlashNvStorageVariableBase);
 
   // Set the index of the first LBA for the FVB
   Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize;
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (4 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:29   ` Ard Biesheuvel
  2020-05-14  8:40 ` [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map Sami Mujawar
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, lersek, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Kvmtool is a virtual machine manager that enables
hosting KVM guests. It essentially provides an
emulated platform for guest operating systems.

Kvmtool hands of a device tree containing the
current hardware configuration to the firmware.

A standards-based operating system would use
ACPI to consume the platform hardware
information, while some operating systems may
prefer to use Device Tree.

The KvmtoolPlatformDxe performs the platform
actions like determining if the firmware should
expose ACPI or the Device Tree based hardware
description to the operating system.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---

Notes:
    v2:
      - Updated according to review comments.                     [Sami]
    
    v1:
      - Add kvmtool platform driver to support loading platform   [Sami]
        specific information.
      - Keep code to initialise the variable storage PCDs in the  [Laszlo]
        platform-specific FVB driver.
      - Document code derived from                                [Laszlo]
        "ArmVirtPkg/PlatformHasAcpiDtDxe"
        Ref: https://edk2.groups.io/g/devel/topic/30915278#30757

 ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93 ++++++++++++++++++++
 ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
 2 files changed, 140 insertions(+)

diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
new file mode 100644
index 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
--- /dev/null
+++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
@@ -0,0 +1,93 @@
+/** @file
+
+  The KvmtoolPlatformDxe performs the platform specific initialization like:
+  - It decides if the firmware should expose ACPI or Device Tree-based
+    hardware description to the operating system.
+
+  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/VariableFormat.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Protocol/FdtClient.h>
+
+/** Decide if the firmware should expose ACPI tables or Device Tree and
+    install the appropriate protocol interface.
+
+  Note: This function is derived from "ArmVirtPkg/PlatformHasAcpiDtDxe",
+        by dropping the word size check, and the fw_cfg check.
+
+  @param [in]  ImageHandle  Handle for this image.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to install the
+                                  protocols.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+
+**/
+STATIC
+EFI_STATUS
+PlatformHasAcpiDt (
+  IN EFI_HANDLE           ImageHandle
+  )
+{
+  if (!PcdGetBool (PcdForceNoAcpi)) {
+    // Expose ACPI tables
+    return gBS->InstallProtocolInterface (
+                  &ImageHandle,
+                  &gEdkiiPlatformHasAcpiGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  }
+
+  // Expose the Device Tree.
+  return gBS->InstallProtocolInterface (
+                &ImageHandle,
+                &gEdkiiPlatformHasDeviceTreeGuid,
+                EFI_NATIVE_INTERFACE,
+                NULL
+                );
+}
+
+/** Entry point for Kvmtool Platform Dxe
+
+  @param [in]  ImageHandle  Handle for this image.
+  @param [in]  SystemTable  Pointer to the EFI system table.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to install the
+                                  protocols.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+KvmtoolPlatformDxeEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  EFI_STATUS                     Status;
+
+  Status = PlatformHasAcpiDt (ImageHandle);
+  if (EFI_ERROR (Status)) {
+    goto Failed;
+  }
+
+  return Status;
+
+Failed:
+  ASSERT_EFI_ERROR (Status);
+  CpuDeadLoop ();
+
+  return Status;
+}
diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
new file mode 100644
index 0000000000000000000000000000000000000000..08a0fe5ce14469133479046385bdd48c22698639
--- /dev/null
+++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
@@ -0,0 +1,47 @@
+#/** @file
+#
+#  The KvmtoolPlatformDxe performs the platform specific initialization like:
+#  - It decides if the firmware should expose ACPI or Device Tree-based
+#    hardware description to the operating system.
+#
+#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = KvmtoolPlatformDxe
+  FILE_GUID                      = 7479CCCD-D721-442A-8C73-A72DBB886669
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = KvmtoolPlatformDxeEntryPoint
+
+[Sources]
+  KvmtoolPlatformDxe.c
+
+[Packages]
+  ArmVirtPkg/ArmVirtPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+
+[Guids]
+  gEdkiiPlatformHasAcpiGuid       ## SOMETIMES_PRODUCES ## PROTOCOL
+  gEdkiiPlatformHasDeviceTreeGuid ## SOMETIMES_PRODUCES ## PROTOCOL
+
+[Pcd]
+  gArmVirtTokenSpaceGuid.PcdForceNoAcpi
+
+[Depex]
+  TRUE
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (5 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:30   ` Ard Biesheuvel
  2020-05-14 12:15   ` [edk2-devel] " Laszlo Ersek
  2020-05-14  8:40 ` [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib Sami Mujawar
                   ` (3 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, lersek, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Kvmtool is a virtual machine manager that enables
hosting KVM guests. Kvmtool allows to vary the
hardware configuration of the emulated platform
it provides to the guest partition. It provides
the current hardware configuration to the firmware
by handing off a device tree containing the hardware
information.

This library parses the kvmtool provided device
tree and populates the system memory map for the
kvmtool emulated platform.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c   | 114 ++++++++++++++++++++
 ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf |  42 ++++++++
 2 files changed, 156 insertions(+)

diff --git a/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d353733478b2d097d160246007022990a9cbacb
--- /dev/null
+++ b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
@@ -0,0 +1,114 @@
+/** @file
+
+  Copyright (c) 2018, ARM Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+// Number of Virtual Memory Map Descriptors
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS          5
+
+#define LOG_VM_MAP(txt)                       \
+  DEBUG ((                                    \
+    DEBUG_ERROR,                              \
+    "%a: " #txt "\n"                          \
+    "\tPhysicalBase: 0x%lX\n"                 \
+    "\tVirtualBase: 0x%lX\n"                  \
+    "\tLength: 0x%lX\n",                      \
+    __FUNCTION__,                             \
+    VirtualMemoryTable[Idx].PhysicalBase,     \
+    VirtualMemoryTable[Idx].VirtualBase,      \
+    VirtualMemoryTable[Idx].Length            \
+    ));
+
+/**
+  Return the Virtual Memory Map of your platform
+
+  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+  on your platform.
+
+  @param[out]   VirtualMemoryMap    Array of ARM_MEMORY_REGION_DESCRIPTOR
+                                    describing a Physical-to-Virtual Memory
+                                    mapping. This array must be ended by a
+                                    zero-filled entry. The allocated memory
+                                    will not be freed.
+
+**/
+VOID
+ArmVirtGetMemoryMap (
+  OUT ARM_MEMORY_REGION_DESCRIPTOR   **VirtualMemoryMap
+  )
+{
+  ARM_MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
+  UINTN                          Idx = 0;
+  EFI_PHYSICAL_ADDRESS           TopOfAddressSpace;
+
+  ASSERT (VirtualMemoryMap != NULL);
+
+  TopOfAddressSpace = LShiftU64 (1ULL, ArmGetPhysicalAddressBits ());
+
+  VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)
+                        AllocatePages (
+                          EFI_SIZE_TO_PAGES (
+                            sizeof (ARM_MEMORY_REGION_DESCRIPTOR) *
+                            MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
+                            )
+                          );
+
+  if (VirtualMemoryTable == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Error: Failed to Allocate Pages\n",
+      __FUNCTION__
+      ));
+    return;
+  }
+
+  // System DRAM
+  VirtualMemoryTable[Idx].PhysicalBase = PcdGet64 (PcdSystemMemoryBase);
+  VirtualMemoryTable[Idx].VirtualBase  = VirtualMemoryTable[Idx].PhysicalBase;
+  VirtualMemoryTable[Idx].Length       = PcdGet64 (PcdSystemMemorySize);
+  VirtualMemoryTable[Idx].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
+  LOG_VM_MAP ("System DRAM Memory Map");
+
+  // Peripheral space before DRAM
+  VirtualMemoryTable[++Idx].PhysicalBase = 0x0;
+  VirtualMemoryTable[Idx].VirtualBase    = 0x0;
+  VirtualMemoryTable[Idx].Length         = PcdGet64 (PcdSystemMemoryBase);
+  VirtualMemoryTable[Idx].Attributes     = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
+  LOG_VM_MAP ("Peripheral space before DRAM");
+
+  // Peripheral space after DRAM
+  VirtualMemoryTable[++Idx].PhysicalBase = PcdGet64 (PcdSystemMemoryBase) +
+                                           PcdGet64 (PcdSystemMemorySize);
+  VirtualMemoryTable[Idx].VirtualBase    = VirtualMemoryTable[Idx].PhysicalBase;
+  VirtualMemoryTable[Idx].Length         = TopOfAddressSpace -
+                                           VirtualMemoryTable[Idx].PhysicalBase;
+  VirtualMemoryTable[Idx].Attributes     = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
+  LOG_VM_MAP ("Peripheral space after DRAM");
+
+  // Map the FV region as normal executable memory
+  VirtualMemoryTable[++Idx].PhysicalBase = PcdGet64 (PcdFvBaseAddress);
+  VirtualMemoryTable[Idx].VirtualBase  = VirtualMemoryTable[Idx].PhysicalBase;
+  VirtualMemoryTable[Idx].Length       = FixedPcdGet32 (PcdFvSize);
+  VirtualMemoryTable[Idx].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
+  LOG_VM_MAP ("FV region");
+
+  // End of Table
+  VirtualMemoryTable[++Idx].PhysicalBase  = 0;
+  VirtualMemoryTable[Idx].VirtualBase     = 0;
+  VirtualMemoryTable[Idx].Length          = 0;
+  VirtualMemoryTable[Idx].Attributes      = (ARM_MEMORY_REGION_ATTRIBUTES)0;
+
+  ASSERT((Idx + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS);
+
+  *VirtualMemoryMap = VirtualMemoryTable;
+}
diff --git a/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
new file mode 100644
index 0000000000000000000000000000000000000000..dbf4ceabe3ae0db5e743e1d9a575542dca32ed0a
--- /dev/null
+++ b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
@@ -0,0 +1,42 @@
+#/* @file
+#
+#  Copyright (c) 2018, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#*/
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = KvmtoolVirtMemInfoLib
+  FILE_GUID                      = B752E953-394F-462C-811C-F8BE35C8C071
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = ArmVirtMemInfoLib
+
+[Sources]
+  KvmtoolVirtMemInfoLib.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmVirtPkg/ArmVirtPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  PcdLib
+
+[Pcd]
+  gArmTokenSpaceGuid.PcdFvBaseAddress
+  gArmTokenSpaceGuid.PcdSystemMemoryBase
+  gArmTokenSpaceGuid.PcdSystemMemorySize
+
+[FixedPcd]
+  gArmTokenSpaceGuid.PcdFvSize
+
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (6 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:32   ` Ard Biesheuvel
  2020-05-27 11:59   ` Philippe Mathieu-Daudé
  2020-05-14  8:40 ` [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform Sami Mujawar
                   ` (2 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, lersek, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Kvmtool places the base address of the CFI flash in
the device tree it passes to UEFI. This library
parses the kvmtool device tree to read the CFI base
address and initialise the PCDs use by the NOR flash
driver and the variable storage.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c      | 265 ++++++++++++++++++++
 ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf |  50 ++++
 2 files changed, 315 insertions(+)

diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
new file mode 100644
index 0000000000000000000000000000000000000000..2e43c2e21bc9ef7dd1dd198eebbd70c3b0b96d1c
--- /dev/null
+++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
@@ -0,0 +1,265 @@
+/** @file
+   An instance of the NorFlashPlatformLib for Kvmtool platform.
+
+ Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/NorFlashPlatformLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/FdtClient.h>
+
+/** Macro defining the maximum number of Flash Banks.
+ */
+#define MAX_FLASH_BANKS       4
+
+STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];
+STATIC UINTN                  mNorFlashDeviceCount = 0;
+
+/** This function performs platform specific actions to initialise
+    the NOR flash, if required.
+
+  @retval EFI_SUCCESS           Success.
+**/
+EFI_STATUS
+NorFlashPlatformInitialization (
+  VOID
+  )
+{
+  DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
+  // Nothing to do here
+  return EFI_SUCCESS;
+}
+
+/** Initialise Non volatile Flash storage variables.
+
+  @param [in]  FlashDevice Pointer to the NOR Flash device.
+
+  @retval EFI_SUCCESS           Success.
+  @retval EFI_INVALID_PARAMETER A parameter is invalid.
+  @retval EFI_OUT_OF_RESOURCES  Insufficient flash storage space.
+**/
+EFI_STATUS
+SetupVariableStore (
+  IN NOR_FLASH_DESCRIPTION * FlashDevice
+  )
+{
+  UINTN   FlashRegion;
+  UINTN   FlashNvStorageVariableBase;
+  UINTN   FlashNvStorageFtwWorkingBase;
+  UINTN   FlashNvStorageFtwSpareBase;
+  UINTN   FlashNvStorageVariableSize;
+  UINTN   FlashNvStorageFtwWorkingSize;
+  UINTN   FlashNvStorageFtwSpareSize;
+
+  FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
+  FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+  FlashNvStorageFtwSpareSize =  PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+  if ((FlashNvStorageVariableSize == 0)   ||
+      (FlashNvStorageFtwWorkingSize == 0) ||
+      (FlashNvStorageFtwSpareSize == 0)) {
+    DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Setup the variable store
+  FlashRegion = FlashDevice->DeviceBaseAddress;
+
+  FlashNvStorageVariableBase = FlashRegion;
+  FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
+
+  FlashNvStorageFtwWorkingBase = FlashRegion;
+  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
+
+  FlashNvStorageFtwSpareBase = FlashRegion;
+  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+  if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
+    DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PcdSet32S (
+    PcdFlashNvStorageVariableBase,
+    FlashNvStorageVariableBase
+    );
+
+  PcdSet32S (
+    PcdFlashNvStorageFtwWorkingBase,
+    FlashNvStorageFtwWorkingBase
+    );
+
+  PcdSet32S (
+    PcdFlashNvStorageFtwSpareBase,
+    FlashNvStorageFtwSpareBase
+    );
+
+  DEBUG ((
+    DEBUG_INFO,
+    "PcdFlashNvStorageVariableBase = 0x%x\n",
+    FlashNvStorageVariableBase
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "PcdFlashNvStorageVariableSize = 0x%x\n",
+    FlashNvStorageVariableSize
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
+    FlashNvStorageFtwWorkingBase
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
+    FlashNvStorageFtwWorkingSize
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
+    FlashNvStorageFtwSpareBase
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
+    FlashNvStorageFtwSpareSize
+    ));
+
+  return EFI_SUCCESS;
+}
+
+/** Return the Flash devices on the platform.
+
+  @param [out]  NorFlashDescriptions    Pointer to the Flash device description.
+  @param [out]  Count                   Number of Flash devices.
+
+  @retval EFI_SUCCESS           Success.
+  @retval EFI_NOT_FOUND         Flash device not found.
+**/
+EFI_STATUS
+NorFlashPlatformGetDevices (
+  OUT NOR_FLASH_DESCRIPTION   **NorFlashDescriptions,
+  OUT UINT32                  *Count
+  )
+{
+  if (mNorFlashDeviceCount > 0) {
+    *NorFlashDescriptions = mNorFlashDevices;
+    *Count = mNorFlashDeviceCount;
+    return EFI_SUCCESS;
+  }
+  return EFI_NOT_FOUND;
+}
+
+/** Entrypoint for NorFlashPlatformLib.
+
+  @param [in]  ImageHandle  The handle to the image.
+  @param [in]  SystemTable  Pointer to the System Table.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_NOT_FOUND           Flash device not found.
+**/
+EFI_STATUS
+EFIAPI
+NorFlashPlatformLibConstructor (
+  IN  EFI_HANDLE          ImageHandle,
+  IN  EFI_SYSTEM_TABLE  * SystemTable
+  )
+{
+  FDT_CLIENT_PROTOCOL         *FdtClient;
+  INT32                       Node;
+  EFI_STATUS                  Status;
+  EFI_STATUS                  FindNodeStatus;
+  CONST UINT32                *Reg;
+  UINT32                      PropSize;
+  UINT64                      Base;
+  UINT64                      Size;
+
+  if (mNorFlashDeviceCount != 0) {
+    return EFI_SUCCESS;
+  }
+
+  Status = gBS->LocateProtocol (
+                  &gFdtClientProtocolGuid,
+                  NULL,
+                  (VOID **)&FdtClient
+                  );
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  for (FindNodeStatus = FdtClient->FindCompatibleNode (
+                                     FdtClient,
+                                     "cfi-flash",
+                                     &Node
+                                     );
+       !EFI_ERROR (FindNodeStatus) && (mNorFlashDeviceCount < MAX_FLASH_BANKS);
+       FindNodeStatus = FdtClient->FindNextCompatibleNode (
+                                     FdtClient,
+                                     "cfi-flash",
+                                     Node,
+                                     &Node
+    )) {
+    Status = FdtClient->GetNodeProperty (
+                          FdtClient,
+                          Node,
+                          "reg",
+                          (CONST VOID **)&Reg,
+                          &PropSize
+                          );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
+        __FUNCTION__, Status));
+      continue;
+    }
+
+    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
+
+    while ((PropSize >= (4 * sizeof (UINT32))) &&
+           (mNorFlashDeviceCount < MAX_FLASH_BANKS)) {
+      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
+      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
+      Reg += 4;
+
+      PropSize -= 4 * sizeof (UINT32);
+
+      //
+      // Disregard any flash devices that overlap with the primary FV.
+      // The firmware is not updatable from inside the guest anyway.
+      //
+      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
+          (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {
+        continue;
+      }
+
+      DEBUG ((
+        DEBUG_INFO,
+        "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
+        mNorFlashDeviceCount,
+        Base,
+        Size
+        ));
+
+      mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
+      mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
+      mNorFlashDevices[mNorFlashDeviceCount].Size              = (UINTN)Size;
+      mNorFlashDevices[mNorFlashDeviceCount].BlockSize         = SIZE_256KB;
+      mNorFlashDeviceCount++;
+    }
+  }
+
+  // Setup the variable store in the last bank
+  if ((mNorFlashDeviceCount > 0) &&
+      (mNorFlashDevices[mNorFlashDeviceCount - 1].DeviceBaseAddress != 0)) {
+    return SetupVariableStore (&mNorFlashDevices[mNorFlashDeviceCount - 1]);
+  }
+
+  return EFI_NOT_FOUND;
+}
+
diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
new file mode 100644
index 0000000000000000000000000000000000000000..8bd6f730dcb52e597b418e59766c1566a9519789
--- /dev/null
+++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
@@ -0,0 +1,50 @@
+#/** @file
+#
+#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = NorFlashKvmtoolLib
+  FILE_GUID                      = E75F07A1-B160-4893-BDD4-09E32FF847DC
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NorFlashPlatformLib
+  CONSTRUCTOR                    = NorFlashPlatformLibConstructor
+
+[Sources.common]
+  NorFlashKvmtool.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  ArmVirtPkg/ArmVirtPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  PcdLib
+  UefiBootServicesTableLib
+
+[Protocols]
+  gFdtClientProtocolGuid          ## CONSUMES
+
+[Pcd]
+  gArmTokenSpaceGuid.PcdFvBaseAddress
+  gArmTokenSpaceGuid.PcdFvSize
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+
+[Depex]
+  gFdtClientProtocolGuid
+
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (7 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14  9:56   ` Ard Biesheuvel
  2020-05-14 12:24   ` [edk2-devel] " Laszlo Ersek
  2020-05-14  8:40 ` [PATCH v1 10/11] ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio Sami Mujawar
  2020-05-14  8:40 ` [PATCH v1 11/11] Maintainer.txt: Add Kvmtool emulated plat maintainer Sami Mujawar
  10 siblings, 2 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, lersek, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Kvmtool is a virtual machine manager that enables hosting
KVM guests. Kvmtool emulates certain devices like serial
port, RTC, etc. essentially providing an emulated platform.

This patch adds support for kvmtool emulated platform.

Following is a brief description of the firmware
implementation choices:

- Serial Port: 16550 UART
  On some platforms the 16550 UART is interfaced using
  PCI. Therefore, the 16550 Serial port library is
  dependent on the PCI library. The 16550 UART driver
  checks the Device ID represented using the PCD
  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo
  to determine if the UART is behind PCI.
  If the Device ID is 0xFF then the serial 16550 UART
  is not behind PCI. For such platforms a NULL
  implementation of the PCI library has been provided
  so that the serial output is available during the
  early boot stages.

  On Kvmtool the Serial 16550 UART is not behind PCI,
  and therefore makes use of PciLibNull library during
  early boot stages. The DXE modules that make use of
  PCI functionality explicitly include the library
  BasePciLibPciExpress, so that the required PCI
  functionality is available.

  The PcdSerialPciDeviceInfo is also set to 0xFF to
  indicate that the Serial 16550 UART is not behind
  PCI. The PCD PcdSerialUseMmio is also set to TRUE
  to indicate MMIO accesses are required for the
  UART registers.

- Dependency order for Flash
  FaultTolerantWriteDxe makes use of PCDs (e.g.
  PcdFlashNvStorageFtwSpareBase64 etc.), which in
  case of kvmtool will be evaluated based on the CFI
  flash base address read from the DT. These variables
  are populated in the NorFlashPlatformLib loaded by
  ArmVeNorFlashDxe.

  This results in a dependency issue with
  FaultTolerantWriteDxe. To resolve this make the
  NorFlashPlatformLib as a library dependency for
  FaultTolerantWriteDxe.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---

Notes:
    v2:
      - Updates to reflect review comments and support             [Sami]
        for latest features emulated by kvmtool e.g. CFI.
    
    v1:
      - Add support for Kvmtool emulated platform                  [Sami]
      - Add more justification for platform and                    [Laszlo]
        document platform maintainer.
        Ref: https://edk2.groups.io/g/devel/topic/30915279#30693

 ArmVirtPkg/ArmVirtKvmTool.dsc | 408 ++++++++++++++++++++
 ArmVirtPkg/ArmVirtKvmTool.fdf | 276 +++++++++++++
 2 files changed, 684 insertions(+)

diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
new file mode 100644
index 0000000000000000000000000000000000000000..b2dc5eb2a09521c57a30babbee40749abdb7f7ff
--- /dev/null
+++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
@@ -0,0 +1,408 @@
+#  @file
+#  Workspace file for KVMTool virtual platform.
+#
+#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+  PLATFORM_NAME                  = ArmVirtKvmTool
+  PLATFORM_GUID                  = 4CB2C61E-FA32-4130-8E37-54ABC71A1A43
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x0001001B
+!ifdef $(EDK2_OUT_DIR)
+  OUTPUT_DIRECTORY               = $(EDK2_OUT_DIR)
+!else
+  OUTPUT_DIRECTORY               = Build/ArmVirtKvmTool-$(ARCH)
+!endif
+  SUPPORTED_ARCHITECTURES        = AARCH64|ARM
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
+  FLASH_DEFINITION               = ArmVirtPkg/ArmVirtKvmTool.fdf
+
+  #
+  # Defines for default states.  These can be changed on the command line.
+  # -D FLAG=VALUE
+  #
+  DEFINE SECURE_BOOT_ENABLE      = FALSE
+  DEFINE HTTP_BOOT_ENABLE        = FALSE
+  DEFINE TTY_TERMINAL            = TRUE
+  DEFINE ENABLE_NETWORK          = TRUE
+  DEFINE TPM2_ENABLE             = FALSE
+
+!include ArmVirtPkg/ArmVirt.dsc.inc
+
+[LibraryClasses.common]
+  ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
+  ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
+
+  # Virtio Support
+  VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
+  VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
+
+  ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf
+  ArmVirtMemInfoLib|ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
+
+  TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
+  NorFlashPlatformLib|ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
+
+  CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+
+  # BDS Libraries
+  UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+  PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+  BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
+
+  CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
+  FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+
+  FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+  PciPcdProducerLib|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+  PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+  PciHostBridgeLib|ArmVirtPkg/Library/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
+
+!if $(HTTP_BOOT_ENABLE) == TRUE
+  HttpLib|NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf
+!endif
+
+!if $(TPM2_ENABLE) == FALSE
+  TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+  AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+!endif
+
+[LibraryClasses.common, LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE, LibraryClasses.common.PEIM]
+  # The 16550 Serial port library is dependent on PCI library.
+  # A null implementation of the PCI Library has been provided so that
+  # the serial output is available during the early boot stages.
+  # The DXE modules that make use of PCI override the PciLibNull library
+  # and are individually linked with the real PCI library.
+  PciLib|MdePkg/Library/PciLibNull/PciLibNull.inf
+  PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
+  SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
+
+[LibraryClasses.common.UEFI_DRIVER]
+  UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+
+[BuildOptions.ARM.EDKII.SEC, BuildOptions.ARM.EDKII.BASE]
+  # Avoid MOVT/MOVW instruction pairs in code that may end up in the PIE
+  # executable we build for the relocatable PrePi. They are not runtime
+  # relocatable in ELF.
+  *_CLANG35_*_CC_FLAGS = -mno-movt
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFeatureFlag.common]
+  ## If TRUE, Graphics Output Protocol will be installed on virtual handle created by ConsplitterDxe.
+  #  It could be set FALSE to save size.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
+
+  gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|$(TPM2_ENABLE)
+
+[PcdsFixedAtBuild.common]
+  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
+
+  gArmPlatformTokenSpaceGuid.PcdCoreCount|1
+
+!if $(ARCH) == AARCH64
+  gArmTokenSpaceGuid.PcdVFPEnabled|1
+!endif
+
+  gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x4000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
+
+  # Size of the region used by UEFI in permanent memory (Reserved 64MB)
+  gArmPlatformTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x04000000
+
+  #
+  # ARM PrimeCell
+  #
+  ## Default Terminal Type
+  ## 0-PCANSI, 1-VT100, 2-VT00+, 3-UTF8, 4-TTYTERM
+#!if $(TTY_TERMINAL) == TRUE
+  gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
+#!else
+#  gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|1
+#!endif
+
+  #
+  # ARM Virtual Architectural Timer -- fetch frequency from KVM
+  #
+  gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|0
+
+!if $(HTTP_BOOT_ENABLE) == TRUE
+  gEfiNetworkPkgTokenSpaceGuid.PcdAllowHttpConnections|TRUE
+!endif
+
+  # Use MMIO for accessing Serial port registers.
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|TRUE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}
+
+  # Use MMIO for accessing RTC controller registers.
+  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|TRUE
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
+
+  #
+  # The maximum physical I/O addressability of the processor, set with
+  # BuildCpuHob().
+  #
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16
+
+[PcdsPatchableInModule.common]
+  #
+  # This will be overridden in the code
+  #
+  gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0
+  gArmTokenSpaceGuid.PcdSystemMemorySize|0x0
+
+  #
+  # The device tree base address is handed off by kvmtool.
+  # We are booting from RAM using the Linux kernel boot protocol,
+  # x0 will point to the DTB image in memory.
+  #
+  gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0
+
+  gArmTokenSpaceGuid.PcdFdBaseAddress|0x0
+  gArmTokenSpaceGuid.PcdFvBaseAddress|0x0
+
+  # we need to provide a resolution for this PCD that supports PcdSet64()
+  # being called from ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c,
+  # even though that call will be compiled out on this platform as it does
+  # not (and cannot) support the TPM2 driver stack
+  gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress|0x0
+
+[PcdsDynamicDefault.common]
+  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|3
+
+  gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|0x0
+  gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|0x0
+  gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0
+  gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0
+
+  #
+  # ARM General Interrupt Controller
+  #
+  gArmTokenSpaceGuid.PcdGicDistributorBase|0x0
+  gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x0
+  gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x0
+
+  #
+  # PCI settings
+  #
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration|TRUE
+
+  # set PcdPciExpressBaseAddress to MAX_UINT64, which signifies that this
+  # PCD and PcdPciDisableBusEnumeration above have not been assigned yet
+  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xFFFFFFFFFFFFFFFF
+
+  gArmTokenSpaceGuid.PcdPciIoTranslation|0x0
+
+  #
+  # Set video resolution for boot options and for text setup.
+  # PlatformDxe can set the former at runtime.
+  #
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|800
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|600
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|640
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|480
+
+  ## Force DTB
+  gArmVirtTokenSpaceGuid.PcdForceNoAcpi|TRUE
+
+  # Setup Flash storage variables
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x40000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x40000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x40000
+
+################################################################################
+#
+# Components Section - list of all EDK II Modules needed by this Platform
+#
+################################################################################
+[Components.common]
+  #
+  # PEI Phase modules
+  #
+  ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf {
+    <LibraryClasses>
+      ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
+      LzmaDecompressLib|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+      PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf
+      HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
+      PrePiHobListPointerLib|ArmPlatformPkg/Library/PrePiHobListPointerLib/PrePiHobListPointerLib.inf
+      MemoryAllocationLib|EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
+  }
+
+  #
+  # DXE
+  #
+  MdeModulePkg/Core/Dxe/DxeMain.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
+      DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+  }
+  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf {
+    <LibraryClasses>
+      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  }
+
+  #
+  # Architectural Protocols
+  #
+  ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
+      # don't use unaligned CopyMem () on the UEFI varstore NOR flash region
+      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
+  }
+
+!if $(SECURE_BOOT_ENABLE) == TRUE
+  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf {
+    <LibraryClasses>
+      NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
+  }
+  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
+!else
+  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+!endif
+  MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf {
+    <LibraryClasses>
+      NULL|ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
+  }
+
+  MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+  MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+  MdeModulePkg/Universal/Metronome/Metronome.inf
+  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
+
+  MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+  MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+  MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+  MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+  MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+
+  MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+  ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
+  ArmPkg/Drivers/TimerDxe/TimerDxe.inf {
+    <LibraryClasses>
+      NULL|ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.inf
+  }
+  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf {
+    <LibraryClasses>
+      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
+  }
+
+  MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+
+  #
+  # Platform Driver
+  #
+  ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
+  ArmVirtPkg/VirtioFdtDxe/VirtioFdtDxe.inf
+  ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf
+  ArmVirtPkg/HighMemDxe/HighMemDxe.inf
+  OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+  OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+  OvmfPkg/VirtioNetDxe/VirtioNet.inf
+  OvmfPkg/VirtioRngDxe/VirtioRng.inf
+
+  #
+  # FAT filesystem + GPT/MBR partitioning + UDF filesystem
+  #
+  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+  FatPkg/EnhancedFatDxe/Fat.inf
+  MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
+
+  #
+  # Bds
+  #
+  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf {
+    <LibraryClasses>
+      DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+  }
+  MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+  MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+  MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
+  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+  MdeModulePkg/Logo/LogoDxe.inf
+  MdeModulePkg/Application/UiApp/UiApp.inf {
+    <LibraryClasses>
+      NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
+      NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
+      NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
+  }
+
+!if $(ENABLE_NETWORK) == TRUE
+  #
+  # Networking stack
+  #
+  NetworkPkg/SnpDxe/SnpDxe.inf
+  NetworkPkg/DpcDxe/DpcDxe.inf
+  NetworkPkg/ArpDxe/ArpDxe.inf
+  NetworkPkg/Dhcp4Dxe/Dhcp4Dxe.inf
+  NetworkPkg/Ip4Dxe/Ip4Dxe.inf
+  NetworkPkg/MnpDxe/MnpDxe.inf
+  NetworkPkg/VlanConfigDxe/VlanConfigDxe.inf
+  NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.inf
+  NetworkPkg/Udp4Dxe/Udp4Dxe.inf
+  NetworkPkg/TcpDxe/TcpDxe.inf
+  NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf
+  NetworkPkg/IScsiDxe/IScsiDxe.inf
+!if $(HTTP_BOOT_ENABLE) == TRUE
+  NetworkPkg/DnsDxe/DnsDxe.inf
+  NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf
+  NetworkPkg/HttpDxe/HttpDxe.inf
+  NetworkPkg/HttpBootDxe/HttpBootDxe.inf
+!endif
+!endif
+  #
+  # SCSI Bus and Disk Driver
+  #
+  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+  #
+  # PCI support
+  #
+  ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf {
+    <LibraryClasses>
+      NULL|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+  }
+
+  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
+    <LibraryClasses>
+      PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
+  }
+
+  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf {
+    <LibraryClasses>
+      NULL|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+  }
+
+  OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
+  OvmfPkg/Virtio10Dxe/Virtio10.inf
diff --git a/ArmVirtPkg/ArmVirtKvmTool.fdf b/ArmVirtPkg/ArmVirtKvmTool.fdf
new file mode 100644
index 0000000000000000000000000000000000000000..8b794e6a1f3652f3262faa35b37f2f8d36d5438d
--- /dev/null
+++ b/ArmVirtPkg/ArmVirtKvmTool.fdf
@@ -0,0 +1,276 @@
+#
+#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+
+################################################################################
+#
+# FD Section
+# The [FD] Section is made up of the definition statements and a
+# description of what goes into  the Flash Device Image.  Each FD section
+# defines one flash "device" image.  A flash device image may be one of
+# the following: Removable media bootable image (like a boot floppy
+# image,) an Option ROM image (that would be "flashed" into an add-in
+# card,) a System "Flash"  image (that would be burned into a system's
+# flash) or an Update ("Capsule") image that will be used to update and
+# existing system flash.
+#
+################################################################################
+
+[FD.KVMTOOL_EFI]
+BaseAddress   = 0x00000000|gArmTokenSpaceGuid.PcdFdBaseAddress
+# The size in bytes of the FLASH Device
+Size          = 0x00200000|gArmTokenSpaceGuid.PcdFdSize
+ErasePolarity = 1
+
+# This one is tricky, it must be: BlockSize * NumBlocks = Size
+BlockSize     = 0x00001000
+NumBlocks     = 0x200
+
+################################################################################
+#
+# Following are lists of FD Region layout which correspond to the locations of different
+# images within the flash device.
+#
+# Regions must be defined in ascending order and may not overlap.
+#
+# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by
+# the pipe "|" character, followed by the size of the region, also in hex with the leading
+# "0x" characters. Like:
+# Offset|Size
+# PcdOffsetCName|PcdSizeCName
+# RegionType <FV, DATA, or FILE>
+#
+################################################################################
+
+#
+# Implement the Linux kernel header layout so that the loader will identify
+# it as something bootable, and execute it with a FDT pointer in x0 or r2.
+# This area will be reused to store a copy of the FDT so round it up to 32 KB.
+#
+0x00000000|0x00008000
+DATA = {
+!if $(ARCH) == AARCH64
+  0x01, 0x00, 0x00, 0x10,                         # code0: adr x1, .
+  0xff, 0x1f, 0x00, 0x14,                         # code1: b 0x8000
+  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, # text_offset: 512 KB
+  0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, # image_size: 2 MB
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # flags
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # res2
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # res3
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # res4
+  0x41, 0x52, 0x4d, 0x64,                         # magic: "ARM\x64"
+  0x00, 0x00, 0x00, 0x00                          # res5
+!else
+  0x08, 0x10, 0x4f, 0xe2, # adr r1, .
+  0x02, 0x00, 0xa0, 0xe1, # mov r0, r2 (DTB)
+  0x00, 0x00, 0xa0, 0xe1, # nop
+  0x00, 0x00, 0xa0, 0xe1, # nop
+  0x00, 0x00, 0xa0, 0xe1, # nop
+  0x00, 0x00, 0xa0, 0xe1, # nop
+  0x00, 0x00, 0xa0, 0xe1, # nop
+  0x00, 0x00, 0xa0, 0xe1, # nop
+
+  0xf6, 0x1f, 0x00, 0xea, # b 0x8000
+  0x18, 0x28, 0x6f, 0x01, # magic
+  0x00, 0x00, 0x00, 0x00, # start
+  0x00, 0x00, 0x20, 0x00, # image size: 2 MB
+  0x01, 0x02, 0x03, 0x04  # endiannness flag
+!endif
+}
+
+0x00008000|0x001f8000
+gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize
+FV = FVMAIN_COMPACT
+
+################################################################################
+#
+# FV Section
+#
+# [FV] section is used to define what components or modules are placed within a flash
+# device file.  This section also defines order the components and modules are positioned
+# within the image.  The [FV] section consists of define statements, set statements and
+# module statements.
+#
+################################################################################
+
+[FV.FvMain]
+FvNameGuid         = 64074afe-340a-4be6-94ba-91b5b4d0f71e
+BlockSize          = 0x40
+NumBlocks          = 0         # This FV gets compressed so make it just big enough
+FvAlignment        = 16        # FV alignment and FV attributes setting.
+ERASE_POLARITY     = 1
+MEMORY_MAPPED      = TRUE
+STICKY_WRITE       = TRUE
+LOCK_CAP           = TRUE
+LOCK_STATUS        = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP  = TRUE
+WRITE_STATUS       = TRUE
+WRITE_LOCK_CAP     = TRUE
+WRITE_LOCK_STATUS  = TRUE
+READ_DISABLED_CAP  = TRUE
+READ_ENABLED_CAP   = TRUE
+READ_STATUS        = TRUE
+READ_LOCK_CAP      = TRUE
+READ_LOCK_STATUS   = TRUE
+
+  INF MdeModulePkg/Core/Dxe/DxeMain.inf
+  INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+  INF ArmVirtPkg/VirtioFdtDxe/VirtioFdtDxe.inf
+  INF ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf
+  INF ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
+  INF ArmVirtPkg/HighMemDxe/HighMemDxe.inf
+
+  #
+  # PI DXE Drivers producing Architectural Protocols (EFI Services)
+  #
+  INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+  INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+  INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+  INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+  INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+
+!if $(SECURE_BOOT_ENABLE) == TRUE
+  INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
+!endif
+  INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+  INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+
+  INF  MdeModulePkg/Universal/Metronome/Metronome.inf
+  INF  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
+
+  INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+  #
+  # Multiple Console IO support
+  #
+  INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+  INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+  INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+  INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+  INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+
+  INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
+  INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
+  INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+  INF ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
+
+  #
+  # FAT filesystem + GPT/MBR partitioning + UDF filesystem
+  #
+  INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+  INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+  INF FatPkg/EnhancedFatDxe/Fat.inf
+  INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+  INF MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
+
+  #
+  # Platform Driver
+  #
+  INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+  INF OvmfPkg/VirtioNetDxe/VirtioNet.inf
+  INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+  INF OvmfPkg/VirtioRngDxe/VirtioRng.inf
+
+  #
+  # UEFI application (Shell Embedded Boot Loader)
+  #
+  INF ShellPkg/Application/Shell/Shell.inf
+  INF ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf
+
+  #
+  # Bds
+  #
+  INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+  INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+  INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+  INF MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
+  INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+  INF MdeModulePkg/Application/UiApp/UiApp.inf
+
+!if $(ENABLE_NETWORK) == TRUE
+  #
+  # Networking stack
+  #
+  INF NetworkPkg/SnpDxe/SnpDxe.inf
+  INF NetworkPkg/DpcDxe/DpcDxe.inf
+  INF NetworkPkg/ArpDxe/ArpDxe.inf
+  INF NetworkPkg/Dhcp4Dxe/Dhcp4Dxe.inf
+  INF NetworkPkg/Ip4Dxe/Ip4Dxe.inf
+  INF NetworkPkg/MnpDxe/MnpDxe.inf
+  INF NetworkPkg/VlanConfigDxe/VlanConfigDxe.inf
+  INF NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.inf
+  INF NetworkPkg/Udp4Dxe/Udp4Dxe.inf
+  INF NetworkPkg/TcpDxe/TcpDxe.inf
+  INF NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf
+  INF NetworkPkg/IScsiDxe/IScsiDxe.inf
+!if $(HTTP_BOOT_ENABLE) == TRUE
+  INF NetworkPkg/DnsDxe/DnsDxe.inf
+  INF NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf
+  INF NetworkPkg/HttpDxe/HttpDxe.inf
+  INF NetworkPkg/HttpBootDxe/HttpBootDxe.inf
+!endif
+!endif
+  #
+  # SCSI Bus and Disk Driver
+  #
+  INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+  INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+!if $(ARCH) == AARCH64
+  #
+  # EBC support
+  #
+  INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
+!endif
+
+  #
+  # PCI support
+  #
+  INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
+  INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+  INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+  INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
+  INF OvmfPkg/Virtio10Dxe/Virtio10.inf
+
+  #
+  # TianoCore logo (splash screen)
+  #
+  INF MdeModulePkg/Logo/LogoDxe.inf
+
+  #
+  # Ramdisk support
+  #
+  INF MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
+
+[FV.FVMAIN_COMPACT]
+FvAlignment        = 16
+ERASE_POLARITY     = 1
+MEMORY_MAPPED      = TRUE
+STICKY_WRITE       = TRUE
+LOCK_CAP           = TRUE
+LOCK_STATUS        = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP  = TRUE
+WRITE_STATUS       = TRUE
+WRITE_LOCK_CAP     = TRUE
+WRITE_LOCK_STATUS  = TRUE
+READ_DISABLED_CAP  = TRUE
+READ_ENABLED_CAP   = TRUE
+READ_STATUS        = TRUE
+READ_LOCK_CAP      = TRUE
+READ_LOCK_STATUS   = TRUE
+
+  INF ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
+
+  FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
+    SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE {
+      SECTION FV_IMAGE = FVMAIN
+    }
+  }
+
+!include ArmVirtRules.fdf.inc
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 10/11] ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (8 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14 12:28   ` [edk2-devel] " Laszlo Ersek
  2020-05-14  8:40 ` [PATCH v1 11/11] Maintainer.txt: Add Kvmtool emulated plat maintainer Sami Mujawar
  10 siblings, 1 reply; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, lersek, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

NorFlashDxe must use aligned MMIO accesses to
read data from flash as this is device memory.

The AlignedCopyMem() in NorFlashDxe was used to
copy the flash data which prevented unaligned
access to device memory. However, the compiler
could optimize the code to generate pre/post
indexed or LDP operations. This is a problem
for guest/virtual firmware as the hypervisor
code cannot get the syndrome information for
the trapped accesses.

To address the such issues, BaseMemoryLibMmio
library has been introduced to perform aligned
MMIO accesses.

The NorFlashDxe has been updated to use
CopyMem() instead of using AlignedCopyMem()
and therefore the NorFlashDxe must be linked
with BaseMemoryLibMmio.

This patch updates the workspace files to link
NorFlashDxe with BaseMemoryLibMmio for the
following platforms:
  - Arm Qemu
  - Arm Qemu Kernel

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 ArmVirtPkg/ArmVirtQemu.dsc       | 8 ++++++--
 ArmVirtPkg/ArmVirtQemuKernel.dsc | 8 ++++++--
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 3f649c91d8d6a2e3f3e62f35aa40906e048a15c4..82b7d54c2031fed60dccff38353d3ec19cfdefd0 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+#  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
 #  Copyright (c) 2014, Linaro Limited. All rights reserved.
 #  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
 #
@@ -384,7 +384,11 @@ [Components.common]
     <LibraryClasses>
       NULL|ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.inf
   }
-  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
+  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf {
+    <LibraryClasses>
+      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
+  }
+
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
 
   #
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index 2a6fd6bc06be1cc20d8c6f2bf00d88d593061edf..6cceb61e493c8c84f6564b120b0864ff817c3f31 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -1,5 +1,5 @@
 #
-#  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
+#  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
 #  Copyright (c) 2014, Linaro Limited. All rights reserved.
 #  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
 #
@@ -323,7 +323,11 @@ [Components.common]
     <LibraryClasses>
       NULL|ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.inf
   }
-  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
+  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf {
+    <LibraryClasses>
+      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
+  }
+
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
 
   #
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v1 11/11] Maintainer.txt: Add Kvmtool emulated plat maintainer
  2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
                   ` (9 preceding siblings ...)
  2020-05-14  8:40 ` [PATCH v1 10/11] ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio Sami Mujawar
@ 2020-05-14  8:40 ` Sami Mujawar
  2020-05-14 12:31   ` [edk2-devel] " Laszlo Ersek
  10 siblings, 1 reply; 40+ messages in thread
From: Sami Mujawar @ 2020-05-14  8:40 UTC (permalink / raw)
  To: devel
  Cc: Sami Mujawar, ard.biesheuvel, leif, michael.d.kinney,
	Matteo.Carlini, Laura.Moretta, nd

Kvmtool is a virtual machine manager that can be used
to launch guest partitions. It additionally emulates
some hardware components e.g. RTC, CFI etc. essentially
providing an emulated virtual platform for a guest
operating system (OS) to run.

A standards-based OS would need UEFI firmware support
for the Kvmtool emulated platform, for which additional
modules are added to ArmVirtPkg.
Adding myself as maintainer for these modules as
advised on mailing list discussion at
https://edk2.groups.io/g/devel/topic/30915279#30693

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---
 Maintainers.txt | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Maintainers.txt b/Maintainers.txt
index 896ac5821fc6602e25db79b9aa47e4c2329c530b..3006bc1ea2feb224f0f710831466c5a6a876e3ee 100644
--- a/Maintainers.txt
+++ b/Maintainers.txt
@@ -152,6 +152,13 @@ F: ArmVirtPkg/XenPlatformHasAcpiDtDxe/
 F: ArmVirtPkg/XenioFdtDxe/
 R: Julien Grall <julien@xen.org>
 
+ArmVirtPkg: Kvmtool emulated platform support
+F: ArmVirtPkg/ArmVirtKvmTool.*
+F: ArmVirtPkg/KvmtoolPlatformDxe/
+F: ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/
+F: ArmVirtPkg/Library/NorFlashKvmtoolLib/
+M: Sami Mujawar <sami.mujawar@arm.com>
+
 BaseTools
 F: BaseTools/
 W: https://github.com/tianocore/tianocore.github.io/wiki/BaseTools
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO
  2020-05-14  8:40 ` [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO Sami Mujawar
@ 2020-05-14  9:22   ` Ard Biesheuvel
  2020-05-14 17:21     ` Ard Biesheuvel
  2020-05-14 16:33   ` [edk2-devel] " Michael D Kinney
  1 sibling, 1 reply; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:22 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, michael.d.kinney, liming.gao, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

Hi Sami,

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Some device drivers perform copy operations on
> device memory, e.g. device drivers for a Flash
> device. On some architectures unaligned access
> to device memory regions is not permitted. To
> add to this if the device is virtualised then
> there are further restrictions on the type of
> load/store operations that can be performed
> on the device memory regions, e.g. on AARCH64,
> Pre/Post index or LDP operations cannot be
> used, as a trap to EL2 does not provide the
> syndrome information to the hypervisor.
> 

We are conflating two different things here:
- the use of unaligned accesses to read from device memory
- the use of load/store instructions that have multiple output 
registers, making it very difficult to emulate them in a virtual machine 
context.

I though that for the kvmtool port, we addressed the second issue by 
using a read-only memslot for the NOR flash when it is in array mode? 
IIRC, the issue only affects reads, as all writes to NOR flash device 
memory are already done using the proper MMIO accessors. If those MMIO 
accessors compile to something that does not work under emulation, you 
should be use the special IoLib implementation that exists for this use 
case:

   MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicArmVirt.inf

So that leaves the issue of unaligned accesses to device memory. This 
should not happen unless you are using BaseMemoryLibOptDxe for AARCH64, 
which deliberately uses overlapping loads and stores for performance. 
Any BASE library is built with -mstrict-align, and so any other C code 
implementation of BaseMemoryLib should work fine for reading for a 
read-only memslot mapped using device attributes.

So in summary, I don't think we need this library.



> To address these issues this patch introduces
> BaseMemoryLibMmio library which provides an
> implementation of Base memory library that
> uses aligned MMIO accesses.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>   MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf |  50 ++++
>   MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni |  15 +
>   MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c   |  62 ++++
>   MdePkg/Library/BaseMemoryLibMmio/CopyMem.c             | 149 ++++++++++
>   MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c      |  59 ++++
>   MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c |  50 ++++
>   MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c       | 304 ++++++++++++++++++++
>   MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c          | 143 +++++++++
>   MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h     | 248 ++++++++++++++++
>   MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c    |  63 ++++
>   MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c    |  62 ++++
>   MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c    |  63 ++++
>   MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c     |  95 ++++++
>   MdePkg/Library/BaseMemoryLibMmio/SetMem.c              |  83 ++++++
>   MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c     |  60 ++++
>   MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c     |  60 ++++
>   MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c     |  60 ++++
>   MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c       |  87 ++++++
>   MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c      |  52 ++++
>   19 files changed, 1765 insertions(+)
> 
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..3a61cb985a242a4ce7a2446c4efb9b78fb1d7b5d
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> @@ -0,0 +1,50 @@
> +## @file
> +#  Instance of Base Memory Library using Mmio operations.
> +#
> +#
> +#  Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = BaseMemoryLibMmio
> +  MODULE_UNI_FILE                = BaseMemoryLibMmio.uni
> +  FILE_GUID                      = 5724063D-9855-4B3A-8DEE-1F80ED07E096
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = BaseMemoryLib
> +
> +#
> +#  VALID_ARCHITECTURES           = ARM AARCH64
> +#
> +
> +[Sources]
> +  SetMem.c
> +  ScanMem64Wrapper.c
> +  ScanMem32Wrapper.c
> +  ScanMem16Wrapper.c
> +  ScanMem8Wrapper.c
> +  ZeroMemWrapper.c
> +  CompareMemWrapper.c
> +  SetMem64Wrapper.c
> +  SetMem32Wrapper.c
> +  SetMem16Wrapper.c
> +  SetMemWrapper.c
> +  CopyMemWrapper.c
> +  IsZeroBufferWrapper.c
> +  MemLibGeneric.c
> +  MemLibGuid.c
> +  CopyMem.c
> +  MemLibInternals.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  DebugLib
> +  BaseLib
> +  IoLib
> +
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni
> new file mode 100644
> index 0000000000000000000000000000000000000000..3dc99103e9a673902abcefe824d5cf5c19b258b8
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni
> @@ -0,0 +1,15 @@
> +// /** @file
> +// Instance of Base Memory Library using Mmio operations.
> +//
> +//
> +// Copyright (c) 2020, ARM Limited. All rights reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-US "Instance of Base Memory Library using Mmio operations"
> +
> +#string STR_MODULE_DESCRIPTION          #language en-US "Base Memory Library using Mmio operations"
> +
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..63e0e3ea583cb242a9242f483e8c952e48122e77
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
> @@ -0,0 +1,62 @@
> +/** @file
> +  CompareMem() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Compares the contents of two buffers.
> +
> +  This function compares Length bytes of SourceBuffer to Length bytes of DestinationBuffer.
> +  If all Length bytes of the two buffers are identical, then 0 is returned.  Otherwise, the
> +  value returned is the first mismatched byte in SourceBuffer subtracted from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
> +
> +  @param  DestinationBuffer A pointer to the destination buffer to compare.
> +  @param  SourceBuffer      A pointer to the source buffer to compare.
> +  @param  Length            The number of bytes to compare.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
> +                            mismatched byte in DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +CompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  if (Length == 0 || DestinationBuffer == SourceBuffer) {
> +    return 0;
> +  }
> +  ASSERT (DestinationBuffer != NULL);
> +  ASSERT (SourceBuffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)DestinationBuffer));
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)SourceBuffer));
> +
> +  return InternalMemCompareMem (DestinationBuffer, SourceBuffer, Length);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c b/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..84a207bf0f8a537b0832b5c4c9f6735122ee7851
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
> @@ -0,0 +1,149 @@
> +/** @file
> +  Implementation of the InternalMemCopyMem routine. This function is broken
> +  out into its own source file so that it can be excluded from a build for a
> +  particular platform easily if an optimized version is desired.
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2012 - 2020, ARM Ltd. All rights reserved.<BR>
> +  Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Copy Length bytes from Source to Destination.
> +
> +  @param  DestinationBuffer The target of the copy request.
> +  @param  SourceBuffer      The place to copy from.
> +  @param  Length            The number of bytes to copy.
> +
> +  @return Destination
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemCopyMem (
> +  OUT     VOID                      *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  )
> +{
> +  //
> +  // Declare the local variables that actually move the data elements as
> +  // volatile to prevent the optimizer from replacing this function with
> +  // the intrinsic memcpy()
> +  //
> +  volatile UINT8                    *Destination8;
> +  CONST UINT8                       *Source8;
> +  volatile UINT32                   *Destination32;
> +  CONST UINT32                      *Source32;
> +  volatile UINT64                   *Destination64;
> +  CONST UINT64                      *Source64;
> +  UINTN                             Alignment;
> +
> +  if ((((UINTN)DestinationBuffer & 0x7) == 0) &&
> +      (((UINTN)SourceBuffer & 0x7) == 0)      &&
> +      (Length >= 8)) {
> +    if (SourceBuffer > DestinationBuffer) {
> +      Destination64 = (UINT64*)DestinationBuffer;
> +      Source64 = (CONST UINT64*)SourceBuffer;
> +      while (Length >= 8) {
> +        MmioWrite64 ((UINTN)Destination64++, MmioRead64 ((UINTN)Source64++));
> +        Length -= 8;
> +      }
> +
> +      // Finish if there are still some bytes to copy
> +      Destination8 = (UINT8*)Destination64;
> +      Source8 = (CONST UINT8*)Source64;
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8++, MmioRead8 ((UINTN)Source8++));
> +      }
> +    } else if (SourceBuffer < DestinationBuffer) {
> +      Destination64 = (UINT64*)((UINTN)DestinationBuffer + Length);
> +      Source64 = (CONST UINT64*)((UINTN)SourceBuffer + Length);
> +
> +      // Destination64 and Source64 were aligned on a 64-bit boundary
> +      // but if length is not a multiple of 8 bytes then they won't be
> +      // anymore.
> +
> +      Alignment = Length & 0x7;
> +      if (Alignment != 0) {
> +        Destination8 = (UINT8*)Destination64;
> +        Source8 = (CONST UINT8*)Source64;
> +
> +        while (Alignment-- != 0) {
> +          MmioWrite8 ((UINTN)--Destination8, MmioRead8 ((UINTN)--Source8));
> +          --Length;
> +        }
> +        Destination64 = (UINT64*)Destination8;
> +        Source64 = (CONST UINT64*)Source8;
> +      }
> +
> +      while (Length > 0) {
> +        MmioWrite64 ((UINTN)--Destination64, MmioRead64 ((UINTN)--Source64));
> +        Length -= 8;
> +      }
> +    }
> +  } else if ((((UINTN)DestinationBuffer & 0x3) == 0)  &&
> +             (((UINTN)SourceBuffer & 0x3) == 0)       &&
> +             (Length >= 4)) {
> +    if (SourceBuffer > DestinationBuffer) {
> +      Destination32 = (UINT32*)DestinationBuffer;
> +      Source32 = (CONST UINT32*)SourceBuffer;
> +      while (Length >= 4) {
> +        MmioWrite32 ((UINTN)Destination32++, MmioRead32 ((UINTN)Source32++));
> +        Length -= 4;
> +      }
> +
> +      // Finish if there are still some bytes to copy
> +      Destination8 = (UINT8*)Destination32;
> +      Source8 = (CONST UINT8*)Source32;
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8++, MmioRead8 ((UINTN)Source8++));
> +      }
> +    } else if (SourceBuffer < DestinationBuffer) {
> +      Destination32 = (UINT32*)((UINTN)DestinationBuffer + Length);
> +      Source32 = (CONST UINT32*)((UINTN)SourceBuffer + Length);
> +
> +      // Destination32 and Source32 were aligned on a 32-bit boundary
> +      // but if length is not a multiple of 4 bytes then they won't be
> +      // anymore.
> +
> +      Alignment = Length & 0x3;
> +      if (Alignment != 0) {
> +        Destination8 = (UINT8*)Destination32;
> +        Source8 = (CONST UINT8*)Source32;
> +
> +        while (Alignment-- != 0) {
> +          MmioWrite8 ((UINTN)--Destination8, MmioRead8 ((UINTN)--Source8));
> +          --Length;
> +        }
> +        Destination32 = (UINT32*)Destination8;
> +        Source32 = (CONST UINT32*)Source8;
> +      }
> +
> +      while (Length > 0) {
> +        MmioWrite32 ((UINTN)--Destination32, MmioRead32 ((UINTN)--Source32));
> +        Length -= 4;
> +      }
> +    }
> +  } else {
> +    if (SourceBuffer > DestinationBuffer) {
> +      Destination8 = (UINT8*)DestinationBuffer;
> +      Source8 = (CONST UINT8*)SourceBuffer;
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8++, MmioRead8 ((UINTN)Source8++));
> +      }
> +    } else if (SourceBuffer < DestinationBuffer) {
> +      Destination8 = (UINT8*)DestinationBuffer + (Length - 1);
> +      Source8 = (CONST UINT8*)SourceBuffer + (Length - 1);
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8--, MmioRead8 ((UINTN)Source8--));
> +      }
> +    }
> +  }
> +  return DestinationBuffer;
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..d557bbb8904c2b07c644261290a62be6fc831c08
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
> @@ -0,0 +1,59 @@
> +/** @file
> +  CopyMem() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Copies a source buffer to a destination buffer, and returns the destination buffer.
> +
> +  This function copies Length bytes from SourceBuffer to DestinationBuffer, and returns
> +  DestinationBuffer.  The implementation must be reentrant, and it must handle the case
> +  where SourceBuffer overlaps DestinationBuffer.
> +
> +  If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
> +
> +  @param  DestinationBuffer   A pointer to the destination buffer of the memory copy.
> +  @param  SourceBuffer        A pointer to the source buffer of the memory copy.
> +  @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
> +
> +  @return DestinationBuffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +CopyMem (
> +  OUT VOID       *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  if (Length == 0) {
> +    return DestinationBuffer;
> +  }
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)DestinationBuffer));
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)SourceBuffer));
> +
> +  if (DestinationBuffer == SourceBuffer) {
> +    return DestinationBuffer;
> +  }
> +  return InternalMemCopyMem (DestinationBuffer, SourceBuffer, Length);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..9c3133c668c434839b0d9bf105bc7265eeb76a5b
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c
> @@ -0,0 +1,50 @@
> +/** @file
> +  Implementation of IsZeroBuffer function.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Checks if the contents of a buffer are all zeros.
> +
> +  This function checks whether the contents of a buffer are all zeros. If the
> +  contents are all zeros, return TRUE. Otherwise, return FALSE.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the buffer to be checked.
> +  @param  Length      The size of the buffer (in bytes) to be checked.
> +
> +  @retval TRUE        Contents of the buffer are all zeros.
> +  @retval FALSE       Contents of the buffer are not all zeros.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +IsZeroBuffer (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length
> +  )
> +{
> +  ASSERT (!(Buffer == NULL && Length > 0));
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  return InternalMemIsZeroBuffer (Buffer, Length);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c b/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..1c65b674230795e956c9d22f2b9c151c41839706
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
> @@ -0,0 +1,304 @@
> +/** @file
> +  Architecture Independent Base Memory Library Implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 16-bit value, and returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The count of 16-bit value to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem16 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  )
> +{
> +  volatile UINT16  *Destination16;
> +
> +  Destination16 = (UINT16*)Buffer;
> +  while (Length > 0) {
> +    MmioWrite16 ((UINTN)--Destination16, Value);
> +    Length -= 2;
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Fills a target buffer with a 32-bit value, and returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The count of 32-bit value to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem32 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  )
> +{
> +  volatile UINT32  *Destination32;
> +
> +  Destination32 = (UINT32*)Buffer;
> +  while (Length > 0) {
> +    MmioWrite32 ((UINTN)--Destination32, Value);
> +    Length -= 4;
> +  }
> +  return Buffer;
> +}
> +
> +/**
> +  Fills a target buffer with a 64-bit value, and returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The count of 64-bit value to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem64 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  )
> +{
> +  volatile UINT64  *Destination64;
> +
> +  Destination64 = (UINT64*)Buffer;
> +  while (Length > 0) {
> +    MmioWrite64 ((UINTN)--Destination64, Value);
> +    Length -= 8;
> +  }
> +  return Buffer;
> +}
> +
> +/**
> +  Set Buffer to 0 for Size bytes.
> +
> +  @param  Buffer Memory to set.
> +  @param  Length The number of bytes to set.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemZeroMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length
> +  )
> +{
> +  return InternalMemSetMem (Buffer, Length, 0);
> +}
> +
> +/**
> +  Compares two memory buffers of a given length.
> +
> +  @param  DestinationBuffer The first memory buffer.
> +  @param  SourceBuffer      The second memory buffer.
> +  @param  Length            Length of DestinationBuffer and SourceBuffer memory
> +                            regions to compare. Must be non-zero.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
> +                            mismatched byte in DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +InternalMemCompareMem (
> +  IN      CONST VOID                *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  )
> +{
> +  while ((--Length != 0) &&
> +         (MmioRead8 ((UINTN)DestinationBuffer) ==
> +          MmioRead8 ((UINTN)SourceBuffer))) {
> +    DestinationBuffer = (INT8*)DestinationBuffer + 1;
> +    SourceBuffer = (INT8*)SourceBuffer + 1;
> +  }
> +  return (INTN)MmioRead8 ((UINTN)DestinationBuffer) -
> +         (INTN)MmioRead8 ((UINTN)SourceBuffer);
> +}
> +
> +/**
> +  Scans a target buffer for an 8-bit value, and returns a pointer to the
> +  matching 8-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 8-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem8 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  )
> +{
> +  CONST UINT8                       *Pointer;
> +
> +  Pointer = (CONST UINT8*)Buffer;
> +  do {
> +    if (MmioRead8 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Scans a target buffer for a 16-bit value, and returns a pointer to the
> +  matching 16-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 16-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem16 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  )
> +{
> +  CONST UINT16                      *Pointer;
> +
> +  Pointer = (CONST UINT16*)Buffer;
> +  do {
> +    if (MmioRead16 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Scans a target buffer for a 32-bit value, and returns a pointer to the
> +  matching 32-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 32-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem32 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  )
> +{
> +  CONST UINT32                      *Pointer;
> +
> +  Pointer = (CONST UINT32*)Buffer;
> +  do {
> +    if (MmioRead32 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Scans a target buffer for a 64-bit value, and returns a pointer to the
> +  matching 64-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 64-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem64 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  )
> +{
> +  CONST UINT64                      *Pointer;
> +
> +  Pointer = (CONST UINT64*)Buffer;
> +  do {
> +    if (MmioRead64 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Checks whether the contents of a buffer are all zeros.
> +
> +  @param  Buffer  The pointer to the buffer to be checked.
> +  @param  Length  The size of the buffer (in bytes) to be checked.
> +
> +  @retval TRUE    Contents of the buffer are all zeros.
> +  @retval FALSE   Contents of the buffer are not all zeros.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +InternalMemIsZeroBuffer (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length
> +  )
> +{
> +  CONST UINT8 *BufferData;
> +  UINTN       Index;
> +
> +  BufferData = Buffer;
> +  for (Index = 0; Index < Length; Index++) {
> +    if (MmioRead8 ((UINTN)(BufferData + Index)) != 0) {
> +      return FALSE;
> +    }
> +  }
> +  return TRUE;
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c b/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..ce69e431309f4447a4e99251a86b5182123e5b97
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
> @@ -0,0 +1,143 @@
> +/** @file
> +  Implementation of GUID functions.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Copies a source GUID to a destination GUID.
> +
> +  This function copies the contents of the 128-bit GUID specified by SourceGuid
> +  to DestinationGuid, and returns DestinationGuid.
> +
> +  If DestinationGuid is NULL, then ASSERT().
> +  If SourceGuid is NULL, then ASSERT().
> +
> +  @param  DestinationGuid   A pointer to the destination GUID.
> +  @param  SourceGuid        A pointer to the source GUID.
> +
> +  @return DestinationGuid.
> +
> +**/
> +GUID *
> +EFIAPI
> +CopyGuid (
> +  OUT GUID       *DestinationGuid,
> +  IN CONST GUID  *SourceGuid
> +  )
> +{
> +  return InternalMemCopyMem (DestinationGuid, SourceGuid, sizeof (GUID));
> +}
> +
> +/**
> +  Compares two GUIDs.
> +
> +  This function compares Guid1 to Guid2.  If the GUIDs are identical then TRUE is returned.
> +  If there are any bit differences in the two GUIDs, then FALSE is returned.
> +
> +  If Guid1 is NULL, then ASSERT().
> +  If Guid2 is NULL, then ASSERT().
> +
> +  @param  Guid1       A pointer to a 128 bit GUID.
> +  @param  Guid2       A pointer to a 128 bit GUID.
> +
> +  @retval TRUE        Guid1 and Guid2 are identical.
> +  @retval FALSE       Guid1 and Guid2 are not identical.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +CompareGuid (
> +  IN CONST GUID  *Guid1,
> +  IN CONST GUID  *Guid2
> +  )
> +{
> +  return (0 == InternalMemCompareMem (Guid1, Guid2, sizeof (GUID)));
> +}
> +
> +/**
> +  Scans a target buffer for a GUID, and returns a pointer to the matching GUID
> +  in the target buffer.
> +
> +  This function searches the target buffer specified by Buffer and Length from
> +  the lowest address to the highest address at 128-bit increments for the 128-bit
> +  GUID value that matches Guid.  If a match is found, then a pointer to the matching
> +  GUID in the target buffer is returned.  If no match is found, then NULL is returned.
> +  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
> +  If Length is not aligned on a 128-bit boundary, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The number of bytes in Buffer to scan.
> +  @param  Guid    The value to search for in the target buffer.
> +
> +  @return A pointer to the matching Guid in the target buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanGuid (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN CONST GUID  *Guid
> +  )
> +{
> +  CONST GUID                        *GuidPtr;
> +
> +  ASSERT (((UINTN)Buffer & (sizeof (Guid->Data1) - 1)) == 0);
> +  ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer + 1));
> +  ASSERT ((Length & (sizeof (*GuidPtr) - 1)) == 0);
> +
> +  GuidPtr = (GUID*)Buffer;
> +  Buffer  = GuidPtr + Length / sizeof (*GuidPtr);
> +  while (GuidPtr < (CONST GUID*)Buffer) {
> +    if (CompareGuid (GuidPtr, Guid)) {
> +      return (VOID*)GuidPtr;
> +    }
> +    GuidPtr++;
> +  }
> +  return NULL;
> +}
> +
> +/**
> +  Checks if the given GUID is a zero GUID.
> +
> +  This function checks whether the given GUID is a zero GUID. If the GUID is
> +  identical to a zero GUID then TRUE is returned. Otherwise, FALSE is returned.
> +
> +  If Guid is NULL, then ASSERT().
> +
> +  @param  Guid        The pointer to a 128 bit GUID.
> +
> +  @retval TRUE        Guid is a zero GUID.
> +  @retval FALSE       Guid is not a zero GUID.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +IsZeroGuid (
> +  IN CONST GUID  *Guid
> +  )
> +{
> +  return InternalMemIsZeroBuffer (Guid, sizeof (GUID));
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h b/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..dc28a9078a8a707af8a83517d3756c6126093079
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
> @@ -0,0 +1,248 @@
> +/** @file
> +  Declaration of internal functions for Base Memory Library.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __MEM_LIB_INTERNALS__
> +#define __MEM_LIB_INTERNALS__
> +
> +#include <Base.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +
> +/**
> +  Copy Length bytes from Source to Destination.
> +
> +  @param  DestinationBuffer Target of copy
> +  @param  SourceBuffer      Place to copy from
> +  @param  Length            The number of bytes to copy
> +
> +  @return Destination
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemCopyMem (
> +  OUT     VOID                      *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  );
> +
> +/**
> +  Set Buffer to Value for Size bytes.
> +
> +  @param  Buffer   The memory to set.
> +  @param  Length   The number of bytes to set
> +  @param  Value    The value of the set operation.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  );
> +
> +/**
> +  Fills a target buffer with a 16-bit value, and returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The count of 16-bit value to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem16 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  );
> +
> +/**
> +  Fills a target buffer with a 32-bit value, and returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The count of 32-bit value to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem32 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  );
> +
> +/**
> +  Fills a target buffer with a 64-bit value, and returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The count of 64-bit value to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem64 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  );
> +
> +/**
> +  Set Buffer to 0 for Size bytes.
> +
> +  @param  Buffer The memory to set.
> +  @param  Length The number of bytes to set.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemZeroMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length
> +  );
> +
> +/**
> +  Compares two memory buffers of a given length.
> +
> +  @param  DestinationBuffer The first memory buffer.
> +  @param  SourceBuffer      The second memory buffer.
> +  @param  Length            The length of DestinationBuffer and SourceBuffer memory
> +                            regions to compare. Must be non-zero.
> +
> +  @return 0                 All Length bytes of the two buffers are identical.
> +  @retval Non-zero          The first mismatched byte in SourceBuffer subtracted from the first
> +                            mismatched byte in DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +InternalMemCompareMem (
> +  IN      CONST VOID                *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  );
> +
> +/**
> +  Scans a target buffer for an 8-bit value, and returns a pointer to the
> +  matching 8-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 8-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem8 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  );
> +
> +/**
> +  Scans a target buffer for a 16-bit value, and returns a pointer to the
> +  matching 16-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 16-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem16 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  );
> +
> +/**
> +  Scans a target buffer for a 32-bit value, and returns a pointer to the
> +  matching 32-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 32-bit value to scan. Must be non-zero.
> +  @param  Value   The value to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem32 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  );
> +
> +/**
> +  Scans a target buffer for a 64-bit value, and returns a pointer to the
> +  matching 64-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to scan.
> +  @param  Length  The count of 64-bit value to scan. Must be non-zero.
> +  @param  Value   The calue to search for in the target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem64 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  );
> +
> +/**
> +  Checks whether the contents of a buffer are all zeros.
> +
> +  @param  Buffer  The pointer to the buffer to be checked.
> +  @param  Length  The size of the buffer (in bytes) to be checked.
> +
> +  @retval TRUE    Contents of the buffer are all zeros.
> +  @retval FALSE   Contents of the buffer are not all zeros.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +InternalMemIsZeroBuffer (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length
> +  );
> +
> +#endif
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..ad9330b9938df9995a597dbabc1aa2744aa0d8c1
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
> @@ -0,0 +1,63 @@
> +/** @file
> +  ScanMem16() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for a 16-bit value, and returns a pointer to the matching 16-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified by Buffer and Length from the lowest
> +  address to the highest address for a 16-bit value that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 16-bit boundary, then ASSERT().
> +  If Length is not aligned on a 16-bit boundary, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer to scan.
> +  @param  Length      The number of bytes in Buffer to scan.
> +  @param  Value       The value to search for in the target buffer.
> +
> +  @return A pointer to the matching byte in the target buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem16 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT16      Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) == 0);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return (VOID*)InternalMemScanMem16 (Buffer, Length / sizeof (Value), Value);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..84675697d12016f92c46c08c65aca647288a8b99
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
> @@ -0,0 +1,62 @@
> +/** @file
> +  ScanMem32() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for a 32-bit value, and returns a pointer to the matching 32-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified by Buffer and Length from the lowest
> +  address to the highest address for a 32-bit value that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
> +  If Length is not aligned on a 32-bit boundary, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer to scan.
> +  @param  Length      The number of bytes in Buffer to scan.
> +  @param  Value       The value to search for in the target buffer.
> +
> +  @return A pointer to the matching byte in the target buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem32 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT32      Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) == 0);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return (VOID*)InternalMemScanMem32 (Buffer, Length / sizeof (Value), Value);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..df749dce457827fe070bad8b7c6071aae29ebb02
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
> @@ -0,0 +1,63 @@
> +/** @file
> +  ScanMem64() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for a 64-bit value, and returns a pointer to the matching 64-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified by Buffer and Length from the lowest
> +  address to the highest address for a 64-bit value that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 64-bit boundary, then ASSERT().
> +  If Length is not aligned on a 64-bit boundary, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer to scan.
> +  @param  Length      The number of bytes in Buffer to scan.
> +  @param  Value       The value to search for in the target buffer.
> +
> +  @return A pointer to the matching byte in the target buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem64 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT64      Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) == 0);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return (VOID*)InternalMemScanMem64 (Buffer, Length / sizeof (Value), Value);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..170981017dbe31cf5e0c3dabf26a4fea33f7a7d7
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
> @@ -0,0 +1,95 @@
> +/** @file
> +  ScanMem8() and ScanMemN() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for an 8-bit value, and returns a pointer to the matching 8-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified by Buffer and Length from the lowest
> +  address to the highest address for an 8-bit value that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer to scan.
> +  @param  Length      The number of bytes in Buffer to scan.
> +  @param  Value       The value to search for in the target buffer.
> +
> +  @return A pointer to the matching byte in the target buffer, or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem8 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT8       Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +
> +  return (VOID*)InternalMemScanMem8 (Buffer, Length, Value);
> +}
> +
> +/**
> +  Scans a target buffer for a UINTN sized value, and returns a pointer to the matching
> +  UINTN sized value in the target buffer.
> +
> +  This function searches the target buffer specified by Buffer and Length from the lowest
> +  address to the highest address for a UINTN sized value that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a UINTN boundary, then ASSERT().
> +  If Length is not aligned on a UINTN boundary, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer to scan.
> +  @param  Length      The number of bytes in Buffer to scan.
> +  @param  Value       The value to search for in the target buffer.
> +
> +  @return A pointer to the matching byte in the target buffer, or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMemN (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINTN       Value
> +  )
> +{
> +  if (sizeof (UINTN) == sizeof (UINT64)) {
> +    return ScanMem64 (Buffer, Length, (UINT64)Value);
> +  } else {
> +    return ScanMem32 (Buffer, Length, (UINT32)Value);
> +  }
> +}
> +
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..40255670c6f26eb72a82568f035720fc6fe75546
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
> @@ -0,0 +1,83 @@
> +/** @file
> +  Implementation of the EfiSetMem routine. This function is broken
> +  out into its own source file so that it can be excluded from a
> +  build for a particular platform easily if an optimized version
> +  is desired.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2012 - 2020, ARM Ltd. All rights reserved.<BR>
> +  Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Set Buffer to Value for Size bytes.
> +
> +  @param  Buffer   The memory to set.
> +  @param  Length   The number of bytes to set.
> +  @param  Value    The value of the set operation.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  )
> +{
> +  //
> +  // Declare the local variables that actually move the data elements as
> +  // volatile to prevent the optimizer from replacing this function with
> +  // the intrinsic memset()
> +  //
> +  volatile UINT8                    *Pointer8;
> +  volatile UINT32                   *Pointer32;
> +  volatile UINT64                   *Pointer64;
> +  UINT32                            Value32;
> +  UINT64                            Value64;
> +
> +  if ((((UINTN)Buffer & 0x7) == 0) && (Length >= 8)) {
> +    // Generate the 64bit value
> +    Value32 = (Value << 24) | (Value << 16) | (Value << 8) | Value;
> +    Value64 = LShiftU64 (Value32, 32) | Value32;
> +
> +    Pointer64 = (UINT64*)Buffer;
> +    while (Length >= 8) {
> +      MmioWrite64 ((UINTN)Pointer64++, Value64);
> +      Length -= 8;
> +    }
> +
> +    // Finish with bytes if needed
> +    Pointer8 = (UINT8*)Pointer64;
> +  } else if ((((UINTN)Buffer & 0x3) == 0) && (Length >= 4)) {
> +    // Generate the 32bit value
> +    Value32 = (Value << 24) | (Value << 16) | (Value << 8) | Value;
> +
> +    Pointer32 = (UINT32*)Buffer;
> +    while (Length >= 4) {
> +      MmioWrite32 ((UINTN)Pointer32++, Value32);
> +      Length -= 4;
> +    }
> +
> +    // Finish with bytes if needed
> +    Pointer8 = (UINT8*)Pointer32;
> +  } else {
> +    Pointer8 = (UINT8*)Buffer;
> +  }
> +  while (Length-- > 0) {
> +    MmioWrite8 ((UINTN)Pointer8++, Value);
> +  }
> +  return Buffer;
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..be785c5eb696ef6b913bf7bc0081a5f414c6f141
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
> @@ -0,0 +1,60 @@
> +/** @file
> +  SetMem16() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 16-bit value, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the 16-bit value specified by
> +  Value, and returns Buffer. Value is repeated every 16-bits in for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +  If Buffer is not aligned on a 16-bit boundary, then ASSERT().
> +  If Length is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The number of bytes in Buffer to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem16 (
> +  OUT VOID   *Buffer,
> +  IN UINTN   Length,
> +  IN UINT16  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) == 0);
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return InternalMemSetMem16 (Buffer, Length / sizeof (Value), Value);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..622c6eddccc88e846921782efc29e40f816ae499
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
> @@ -0,0 +1,60 @@
> +/** @file
> +  SetMem32() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 32-bit value, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the 32-bit value specified by
> +  Value, and returns Buffer. Value is repeated every 32-bits in for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
> +  If Length is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The number of bytes in Buffer to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem32 (
> +  OUT VOID   *Buffer,
> +  IN UINTN   Length,
> +  IN UINT32  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) == 0);
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return InternalMemSetMem32 (Buffer, Length / sizeof (Value), Value);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..7653eed85cd633be5aea439cf4ab62958dd62c47
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
> @@ -0,0 +1,60 @@
> +/** @file
> +  SetMem64() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 64-bit value, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the 64-bit value specified by
> +  Value, and returns Buffer. Value is repeated every 64-bits in for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +  If Buffer is not aligned on a 64-bit boundary, then ASSERT().
> +  If Length is not aligned on a 64-bit boundary, then ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The number of bytes in Buffer to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem64 (
> +  OUT VOID   *Buffer,
> +  IN UINTN   Length,
> +  IN UINT64  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) == 0);
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return InternalMemSetMem64 (Buffer, Length / sizeof (Value), Value);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..96dd956686d15b4b4cb25157d764849043d1b57b
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
> @@ -0,0 +1,87 @@
> +/** @file
> +  SetMem() and SetMemN() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a byte value, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with Value, and returns Buffer.
> +
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer    The memory to set.
> +  @param  Length    The number of bytes to set.
> +  @param  Value     The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length,
> +  IN UINT8  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Buffer));
> +
> +  return InternalMemSetMem (Buffer, Length, Value);
> +}
> +
> +/**
> +  Fills a target buffer with a value that is size UINTN, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the UINTN sized value specified by
> +  Value, and returns Buffer. Value is repeated every sizeof(UINTN) bytes for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +  If Buffer is not aligned on a UINTN boundary, then ASSERT().
> +  If Length is not aligned on a UINTN boundary, then ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to fill.
> +  @param  Length  The number of bytes in Buffer to fill.
> +  @param  Value   The value with which to fill Length bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMemN (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length,
> +  IN UINTN  Value
> +  )
> +{
> +  if (sizeof (UINTN) == sizeof (UINT64)) {
> +    return SetMem64 (Buffer, Length, (UINT64)Value);
> +  } else {
> +    return SetMem32 (Buffer, Length, (UINT32)Value);
> +  }
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c b/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..55246d121c6820d371af463792614c1d73676e6f
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
> @@ -0,0 +1,52 @@
> +/** @file
> +  ZeroMem() implementation.
> +
> +  The following BaseMemoryLib instances contain the same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with zeros, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with zeros, and returns Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer to fill with zeros.
> +  @param  Length      The number of bytes in Buffer to fill with zeros.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +ZeroMem (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer + 1));
> +  return InternalMemZeroMem (Buffer, Length);
> +}
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib
  2020-05-14  8:40 ` [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib Sami Mujawar
@ 2020-05-14  9:23   ` Ard Biesheuvel
  2020-05-14 16:21   ` Michael D Kinney
  1 sibling, 0 replies; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:23 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, michael.d.kinney, liming.gao, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> On some platforms the Serial 16550 UART is interfaced
> over PCI. To support such platforms the Serial 16550
> driver links with PciLib.
> 
> For platforms that do not interface the Serial 16550
> UART over PCI, the driver still needs to link with a
> PciLib library. Linking to the full implementation of
> the PCI library may not be possible during the early
> firmware boot stage.
> 
> To facilitate early firmware logs over the serial port
> this patch introduces a NULL PCI library implementation.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>

Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>

> ---
>   MdePkg/Library/PciLibNull/PciLibNull.c   | 1213 ++++++++++++++++++++
>   MdePkg/Library/PciLibNull/PciLibNull.inf |   25 +
>   2 files changed, 1238 insertions(+)
> 
> diff --git a/MdePkg/Library/PciLibNull/PciLibNull.c b/MdePkg/Library/PciLibNull/PciLibNull.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..c186ca9f86e5a0c860472b80209aae9b958a95d7
> --- /dev/null
> +++ b/MdePkg/Library/PciLibNull/PciLibNull.c
> @@ -0,0 +1,1213 @@
> +/** @file
> +  Provides a NULL implementation of PCI services used to access
> +  PCI Configuration Space.
> +
> +  Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Library/DebugLib.h>
> +
> +/**
> +  Registers a PCI device so PCI configuration registers may be accessed after
> +  SetVirtualAddressMap().
> +
> +  Registers the PCI device specified by Address so all the PCI configuration
> +  registers associated with that PCI device may be accessed after
> +  SetVirtualAddressMap() is called.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +
> +  @retval RETURN_SUCCESS           The PCI device was registered for runtime
> +                                   access.
> +  @retval RETURN_UNSUPPORTED       An attempt was made to call this function
> +                                   after ExitBootServices().
> +  @retval RETURN_UNSUPPORTED       The resources required to access the PCI
> +                                   device at runtime could not be mapped.
> +  @retval RETURN_OUT_OF_RESOURCES  There are not enough resources available to
> +                                   complete the registration.
> +
> +**/
> +RETURN_STATUS
> +EFIAPI
> +PciRegisterForRuntimeAccess (
> +  IN UINTN  Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return RETURN_UNSUPPORTED;
> +}
> +
> +/**
> +  Reads an 8-bit PCI configuration register.
> +
> +  Reads and returns the 8-bit PCI configuration register specified by Address.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +
> +  @return The read value from the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciRead8 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes an 8-bit PCI configuration register.
> +
> +  Writes the 8-bit PCI configuration register specified by Address with the
> +  value specified by Value. Value is returned. This function must guarantee
> +  that all PCI read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  Value   The value to write.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciWrite8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise OR of an 8-bit PCI configuration register with
> +  an 8-bit value.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 8-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
> +  value.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 8-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciAnd8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
> +  value, followed by a bitwise OR with another 8-bit value.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData,
> +  performs a bitwise OR between the result of the AND operation and
> +  the value specified by OrData, and writes the result to the 8-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI configuration register.
> +  @param  OrData  The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciAndThenOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     AndData,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in an 8-bit PCI configuration register. The bit field is
> +  specified by the StartBit and the EndBit. The value of the bit field is
> +  returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to read.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +
> +  @return The value of the bit field read from the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldRead8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI configuration register. The bit
> +  field is specified by the StartBit and the EndBit. All other bits in the
> +  destination PCI configuration register are preserved. The new value of the
> +  8-bit register is returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldWrite8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
> +  writes the result back to the bit field in the 8-bit port.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 8-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized. Extra left bits in OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
> +  AND, and writes the result back to the bit field in the 8-bit register.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 8-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldAnd8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit field in the
> +  8-bit port.
> +
> +  Reads the 8-bit PCI configuration register specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the read result and
> +  the value specified by AndData, and writes the result to the 8-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized. Extra left bits in both AndData and
> +  OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..7.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldAndThenOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     AndData,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a 16-bit PCI configuration register.
> +
> +  Reads and returns the 16-bit PCI configuration register specified by Address.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +
> +  @return The read value from the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciRead16 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a 16-bit PCI configuration register.
> +
> +  Writes the 16-bit PCI configuration register specified by Address with the
> +  value specified by Value. Value is returned. This function must guarantee
> +  that all PCI read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  Value   The value to write.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciWrite16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise OR of a 16-bit PCI configuration register with
> +  a 16-bit value.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 16-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
> +  value.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 16-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciAnd16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
> +  value, followed a  bitwise OR with another 16-bit value.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData,
> +  performs a bitwise OR between the result of the AND operation and
> +  the value specified by OrData, and writes the result to the 16-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI configuration register.
> +  @param  OrData  The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciAndThenOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    AndData,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in a 16-bit PCI configuration register. The bit field is
> +  specified by the StartBit and the EndBit. The value of the bit field is
> +  returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to read.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +
> +  @return The value of the bit field read from the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldRead16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI configuration register. The bit
> +  field is specified by the StartBit and the EndBit. All other bits in the
> +  destination PCI configuration register are preserved. The new value of the
> +  16-bit register is returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldWrite16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, and
> +  writes the result back to the bit field in the 16-bit port.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 16-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized. Extra left bits in OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
> +  AND, and writes the result back to the bit field in the 16-bit register.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 16-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldAnd16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit field in the
> +  16-bit port.
> +
> +  Reads the 16-bit PCI configuration register specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the read result and
> +  the value specified by AndData, and writes the result to the 16-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized. Extra left bits in both AndData and
> +  OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..15.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldAndThenOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    AndData,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a 32-bit PCI configuration register.
> +
> +  Reads and returns the 32-bit PCI configuration register specified by Address.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +
> +  @return The read value from the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciRead32 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a 32-bit PCI configuration register.
> +
> +  Writes the 32-bit PCI configuration register specified by Address with the
> +  value specified by Value. Value is returned. This function must guarantee
> +  that all PCI read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  Value   The value to write.
> +
> +  @return The value written to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciWrite32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise OR of a 32-bit PCI configuration register with
> +  a 32-bit value.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 32-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
> +  value.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 32-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciAnd32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
> +  value, followed a  bitwise OR with another 32-bit value.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData,
> +  performs a bitwise OR between the result of the AND operation and
> +  the value specified by OrData, and writes the result to the 32-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus, Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI configuration register.
> +  @param  OrData  The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciAndThenOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    AndData,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in a 32-bit PCI configuration register. The bit field is
> +  specified by the StartBit and the EndBit. The value of the bit field is
> +  returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to read.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +
> +  @return The value of the bit field read from the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldRead32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI configuration register. The bit
> +  field is specified by the StartBit and the EndBit. All other bits in the
> +  destination PCI configuration register are preserved. The new value of the
> +  32-bit register is returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldWrite32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
> +  writes the result back to the bit field in the 32-bit port.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise OR between the read result and the value specified by
> +  OrData, and writes the result to the 32-bit PCI configuration register
> +  specified by Address. The value written to the PCI configuration register is
> +  returned. This function must guarantee that all PCI read and write operations
> +  are serialized. Extra left bits in OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  OrData    The value to OR with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
> +  AND, and writes the result back to the bit field in the 32-bit register.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise AND between the read result and the value specified by AndData, and
> +  writes the result to the 32-bit PCI configuration register specified by
> +  Address. The value written to the PCI configuration register is returned.
> +  This function must guarantee that all PCI read and write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldAnd32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit field in the
> +  32-bit port.
> +
> +  Reads the 32-bit PCI configuration register specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the read result and
> +  the value specified by AndData, and writes the result to the 32-bit PCI
> +  configuration register specified by Address. The value written to the PCI
> +  configuration register is returned. This function must guarantee that all PCI
> +  read and write operations are serialized. Extra left bits in both AndData and
> +  OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to write.
> +  @param  StartBit  The ordinal of the least significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most significant bit in the bit field.
> +                    Range 0..31.
> +  @param  AndData   The value to AND with the PCI configuration register.
> +  @param  OrData    The value to OR with the result of the AND operation.
> +
> +  @return The value written back to the PCI configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldAndThenOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    AndData,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a range of PCI configuration registers into a caller supplied buffer.
> +
> +  Reads the range of PCI configuration registers specified by StartAddress and
> +  Size into the buffer specified by Buffer. This function only allows the PCI
> +  configuration registers from a single PCI function to be read. Size is
> +  returned. When possible 32-bit PCI configuration read cycles are used to read
> +  from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
> +  and 16-bit PCI configuration read cycles may be used at the beginning and the
> +  end of the range.
> +
> +  If StartAddress > 0x0FFFFFFF, then ASSERT().
> +  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
> +  If Size > 0 and Buffer is NULL, then ASSERT().
> +
> +  @param  StartAddress  Starting address that encodes the PCI Bus, Device,
> +                        Function and Register.
> +  @param  Size          Size in bytes of the transfer.
> +  @param  Buffer        Pointer to a buffer receiving the data read.
> +
> +  @return Size
> +
> +**/
> +UINTN
> +EFIAPI
> +PciReadBuffer (
> +  IN      UINTN                     StartAddress,
> +  IN      UINTN                     Size,
> +  OUT     VOID                      *Buffer
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Copies the data in a caller supplied buffer to a specified range of PCI
> +  configuration space.
> +
> +  Writes the range of PCI configuration registers specified by StartAddress and
> +  Size from the buffer specified by Buffer. This function only allows the PCI
> +  configuration registers from a single PCI function to be written. Size is
> +  returned. When possible 32-bit PCI configuration write cycles are used to
> +  write from StartAdress to StartAddress + Size. Due to alignment restrictions,
> +  8-bit and 16-bit PCI configuration write cycles may be used at the beginning
> +  and the end of the range.
> +
> +  If StartAddress > 0x0FFFFFFF, then ASSERT().
> +  If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
> +  If Size > 0 and Buffer is NULL, then ASSERT().
> +
> +  @param  StartAddress  Starting address that encodes the PCI Bus, Device,
> +                        Function and Register.
> +  @param  Size          Size in bytes of the transfer.
> +  @param  Buffer        Pointer to a buffer containing the data to write.
> +
> +  @return Size written to StartAddress.
> +
> +**/
> +UINTN
> +EFIAPI
> +PciWriteBuffer (
> +  IN      UINTN                     StartAddress,
> +  IN      UINTN                     Size,
> +  IN      VOID                      *Buffer
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> diff --git a/MdePkg/Library/PciLibNull/PciLibNull.inf b/MdePkg/Library/PciLibNull/PciLibNull.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..1778b4025e550939a6d13c5cc466567ce99ebaa5
> --- /dev/null
> +++ b/MdePkg/Library/PciLibNull/PciLibNull.inf
> @@ -0,0 +1,25 @@
> +#/** @file
> +#
> +#  Null implementation of Pcilib
> +#
> +#  Copyright (c) 2019, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = PciLibNull
> +  FILE_GUID                      = C2E95ECC-9A39-4293-9F52-4C82BA370952
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PciLib
> +
> +
> +[Sources]
> +  PciLibNull.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver
  2020-05-14  8:40 ` [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver Sami Mujawar
@ 2020-05-14  9:24   ` Ard Biesheuvel
  2020-05-15 10:50   ` André Przywara
  1 sibling, 0 replies; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:24 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, ray.ni, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Some virtual machine managers like kvmtool emulate the MC146818
> RTC controller in the MMIO space so that architectures that do
> not support I/O Mapped I/O can use the RTC. This patch adds MMIO
> support to the RTC controller driver.
> 
> The PCD PcdRtcUseMmio has been added to select I/O or MMIO support.
>    If PcdRtcUseMmio is:
>      TRUE  - Indicates the RTC port registers are in MMIO space.
>      FALSE - Indicates the RTC port registers are in I/O space.
>              Default is I/O space.
> 
> When MMIO support is selected (PcdRtcUseMmio == TRUE) the driver
> maps the MMIO region used by the RTC as runtime memory so that the
> RTC registers are accessible post ExitBootServices.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>

Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>

> ---
> 
> Notes:
>      v2:
>        - Code review comments incorporated.                              [Sami]
>      
>      v1:
>        - Add support to read/write from RTC registers using MMIO access  [Sami]
>        - Use wrapper functions for RtcRead/Write accessors               [Leif]
>          Ref: https://edk2.groups.io/g/devel/topic/30915281#30695
> 
>   PcAtChipsetPkg/PcAtChipsetPkg.dec                                          |   8 ++
>   PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c                         | 117 ++++++++++++++++--
>   PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h                         |  31 +++++
>   PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c                    | 130 +++++++++++++++++++-
>   PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf |   8 ++
>   5 files changed, 280 insertions(+), 14 deletions(-)
> 
> diff --git a/PcAtChipsetPkg/PcAtChipsetPkg.dec b/PcAtChipsetPkg/PcAtChipsetPkg.dec
> index 88de5cceea593176c3a2425a5963b66b789f2b9e..76d0c7eda69bb505914ba904e09c89de170f69ae 100644
> --- a/PcAtChipsetPkg/PcAtChipsetPkg.dec
> +++ b/PcAtChipsetPkg/PcAtChipsetPkg.dec
> @@ -6,6 +6,7 @@
>   #
>   # Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
>   # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
> @@ -142,5 +143,12 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
>     # @Prompt RTC Update Timeout Value.
>     gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000|UINT32|0x00000020
>   
> +  ## Indicates the RTC port registers are in MMIO space, or in I/O space.
> +  #  Default is I/O space.<BR><BR>
> +  #   TRUE  - RTC port registers are in MMIO space.<BR>
> +  #   FALSE - RTC port registers are in I/O space.<BR>
> +  # @Prompt RTC port registers use MMIO.
> +  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|FALSE|BOOLEAN|0x00000021
> +
>   [UserExtensions.TianoCore."ExtraFiles"]
>     PcAtChipsetPkgExtra.uni
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> index 52af17941786ef81c3911512ee64551724e67209..df8dea83ab27bbba12351096d1bfd9ea31accb60 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> @@ -3,6 +3,7 @@
>   
>   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>   Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
>   
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>   
> @@ -10,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   #include "PcRtc.h"
>   
> +extern EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
> +
>   //
>   // Days of month.
>   //
> @@ -21,6 +24,28 @@ UINTN mDayOfMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
>   CHAR16 mTimeZoneVariableName[] = L"RTC";
>   
>   /**
> +  A function pointer that evaluates to a function that reads the RTC content
> +  through its registers either using IO or MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +RTC_READ  RtcRead;
> +
> +/**
> +  A function pointer that evaluates to a function that reads the RTC content
> +  through its registers either using IO or MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +RTC_WRITE RtcWrite;
> +
> +/**
>     Compare the Hour, Minute and Second of the From time and the To time.
>   
>     Only compare H/M/S in EFI_TIME and ignore other fields here.
> @@ -54,41 +79,99 @@ IsWithinOneDay (
>     );
>   
>   /**
> -  Read RTC content through its registers.
> +  Read RTC content through its registers using IO access.
>   
> -  @param  Address  Address offset of RTC. It is recommended to use macros such as
> -                   RTC_ADDRESS_SECONDS.
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
>   
>     @return The data of UINT8 type read from RTC.
>   **/
> +STATIC
>   UINT8
> -RtcRead (
> +IoRtcRead (
>     IN  UINT8 Address
>     )
>   {
> -  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
> +  IoWrite8 (
> +    PcdGet8 (PcdRtcIndexRegister),
> +    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
> +    );
>     return IoRead8 (PcdGet8 (PcdRtcTargetRegister));
>   }
>   
>   /**
> -  Write RTC through its registers.
> +  Write RTC through its registers  using IO access.
>   
> -  @param  Address  Address offset of RTC. It is recommended to use macros such as
> -                   RTC_ADDRESS_SECONDS.
> -  @param  Data     The content you want to write into RTC.
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +  @param  Data      The content you want to write into RTC.
>   
>   **/
> +STATIC
>   VOID
> -RtcWrite (
> +IoRtcWrite (
>     IN  UINT8   Address,
>     IN  UINT8   Data
>     )
>   {
> -  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
> +  IoWrite8 (
> +    PcdGet8 (PcdRtcIndexRegister),
> +    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
> +    );
>     IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);
>   }
>   
>   /**
> +  Read RTC content through its registers using MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +STATIC
> +UINT8
> +MmioRtcRead (
> +  IN  UINT8 Address
> +  )
> +{
> +  MmioWrite8 (
> +    mRtcRegisterBase,
> +    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
> +    );
> +  return MmioRead8 (
> +           mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
> +             PcdGet8 (PcdRtcIndexRegister))
> +           );
> +}
> +
> +/**
> +  Write RTC through its registers using MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +  @param  Data      The content you want to write into RTC.
> +
> +**/
> +STATIC
> +VOID
> +MmioRtcWrite (
> +  IN  UINT8   Address,
> +  IN  UINT8   Data
> +  )
> +{
> +  MmioWrite8 (
> +    mRtcRegisterBase,
> +    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
> +    );
> +  MmioWrite8 (
> +    mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
> +      PcdGet8 (PcdRtcIndexRegister)),
> +    Data
> +    );
> +}
> +
> +/**
>     Initialize RTC.
>   
>     @param  Global            For global use inside this module.
> @@ -113,6 +196,18 @@ PcRtcInit (
>     BOOLEAN         Pending;
>   
>     //
> +  // Initialize the RtcRead and RtcWrite functions
> +  // based on the chosen IO/MMIO access.
> +  //
> +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> +    RtcRead = MmioRtcRead;
> +    RtcWrite = MmioRtcWrite;
> +  } else {
> +    RtcRead = IoRtcRead;
> +    RtcWrite = IoRtcWrite;
> +  }
> +
> +  //
>     // Acquire RTC Lock to make access to RTC atomic
>     //
>     if (!EfiAtRuntime ()) {
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> index 47293ce44c5a1f4792892892f7da40d7f0a5a001..e64dbbea48f7f0d2f317c65c2e4b93e7b1888efc 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> @@ -3,6 +3,7 @@
>   
>   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>   Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.<BR>
>   
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>   
> @@ -371,4 +372,34 @@ PcRtcAcpiTableChangeCallback (
>     IN EFI_EVENT        Event,
>     IN VOID             *Context
>     );
> +
> +/**
> +  Function pointer to Read RTC content through its registers.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +typedef
> +UINT8
> +(EFIAPI *RTC_READ) (
> +  IN  UINT8 Address
> +  );
> +
> +/**
> +  Function pointer to Write RTC through its registers.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +  @param  Data      The content you want to write into RTC.
> +
> +**/
> +typedef
> +VOID
> +(EFIAPI *RTC_WRITE) (
> +  IN  UINT8   Address,
> +  IN  UINT8   Data
> +  );
> +
>   #endif
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> index ccda6331373bfe4069b0a59495b5e5cc731c8fc8..5d5dbeaf970ca8eb291c1e094fd764d201f9071e 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> @@ -2,16 +2,32 @@
>     Provides Set/Get time operations.
>   
>   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>   
>   **/
>   
> +#include <Library/DxeServicesTableLib.h>
>   #include "PcRtc.h"
>   
>   PC_RTC_MODULE_GLOBALS  mModuleGlobal;
>   
>   EFI_HANDLE             mHandle = NULL;
>   
> +STATIC EFI_EVENT       mVirtualAddrChangeEvent;
> +
> +EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
> +
> +//
> +// Function pointer for the Rtc Read interface function
> +//
> +extern RTC_READ   RtcRead;
> +
> +//
> +// Function pointer for the Rtc Write interface function
> +//
> +extern RTC_WRITE  RtcWrite;
> +
>   /**
>     Returns the current time and date information, and the time-keeping capabilities
>     of the hardware platform.
> @@ -106,6 +122,33 @@ PcRtcEfiSetWakeupTime (
>   }
>   
>   /**
> +  Fixup internal data so that EFI can be called in virtual mode.
> +  Call the passed in Child Notify event and convert any pointers in
> +  lib to virtual mode.
> +
> +  @param[in]    Event   The Event that is being processed
> +  @param[in]    Context Event Context
> +**/
> +VOID
> +EFIAPI
> +LibRtcVirtualNotifyEvent (
> +  IN EFI_EVENT        Event,
> +  IN VOID             *Context
> +  )
> +{
> +  // Only needed if you are going to support the OS calling RTC functions in
> +  // virtual mode. You will need to call EfiConvertPointer (). To convert any
> +  // stored physical addresses to virtual address. After the OS transitions to
> +  // calling in virtual mode, all future runtime calls will be made in virtual
> +  // mode.
> +  EfiConvertPointer (0x0, (VOID**)&mRtcRegisterBase);
> +
> +  // Convert the RtcRead and RtcWrite pointers for runtime use.
> +  EfiConvertPointer (0x0, (VOID**)&RtcRead);
> +  EfiConvertPointer (0x0, (VOID**)&RtcWrite);
> +}
> +
> +/**
>     The user Entry Point for PcRTC module.
>   
>     This is the entry point for PcRTC module. It installs the UEFI runtime service
> @@ -125,12 +168,77 @@ InitializePcRtc (
>     IN EFI_SYSTEM_TABLE                      *SystemTable
>     )
>   {
> -  EFI_STATUS  Status;
> -  EFI_EVENT   Event;
> +  EFI_STATUS             Status;
> +  EFI_EVENT              Event;
> +  EFI_PHYSICAL_ADDRESS   RtcPageBase;
>   
>     EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK);
>     mModuleGlobal.CenturyRtcAddress = GetCenturyRtcAddress ();
>   
> +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> +    mRtcRegisterBase = PcdGet8 (PcdRtcIndexRegister);
> +    RtcPageBase = mRtcRegisterBase & ~(EFI_PAGE_SIZE - 1);
> +
> +    // Declare the controller as EFI_MEMORY_RUNTIME
> +    Status = gDS->AddMemorySpace (
> +                    EfiGcdMemoryTypeMemoryMappedIo,
> +                    RtcPageBase,
> +                    EFI_PAGE_SIZE,
> +                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    Status = gDS->AllocateMemorySpace (
> +                    EfiGcdAllocateAddress,
> +                    EfiGcdMemoryTypeMemoryMappedIo,
> +                    0,
> +                    EFI_PAGE_SIZE,
> +                    &RtcPageBase,
> +                    ImageHandle,
> +                    NULL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "Failed to allocate memory space. Status = %r\n",
> +        Status
> +        ));
> +      gDS->RemoveMemorySpace (
> +             RtcPageBase,
> +             EFI_PAGE_SIZE
> +             );
> +      return Status;
> +    }
> +
> +    Status = gDS->SetMemorySpaceAttributes (
> +                    RtcPageBase,
> +                    EFI_PAGE_SIZE,
> +                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "Failed to set memory attributes. Status = %r\n",
> +        Status
> +        ));
> +      gDS->FreeMemorySpace (
> +               RtcPageBase,
> +               EFI_PAGE_SIZE
> +               );
> +      gDS->RemoveMemorySpace (
> +             RtcPageBase,
> +             EFI_PAGE_SIZE
> +             );
> +      return Status;
> +    }
> +  }
> +
>     Status = PcRtcInit (&mModuleGlobal);
>     ASSERT_EFI_ERROR (Status);
>   
> @@ -165,7 +273,23 @@ InitializePcRtc (
>                     NULL,
>                     NULL
>                     );
> -  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> +    // Register for the virtual address change event
> +    Status = gBS->CreateEventEx (
> +                    EVT_NOTIFY_SIGNAL,
> +                    TPL_NOTIFY,
> +                    LibRtcVirtualNotifyEvent,
> +                    NULL,
> +                    &gEfiEventVirtualAddressChangeGuid,
> +                    &mVirtualAddrChangeEvent
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +  }
>   
>     return Status;
>   }
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> index c73ee98105e510f9e4e23c1a6c1e5c505325d2c9..3a373d11f8bfc7df0e4d00be8b43e90bfa06b192 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> @@ -6,6 +6,7 @@
>   #
>   # Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
>   # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
>   #
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
> @@ -48,6 +49,7 @@ [LibraryClasses]
>     BaseLib
>     PcdLib
>     ReportStatusCodeLib
> +  DxeServicesTableLib
>   
>   [Protocols]
>     gEfiRealTimeClockArchProtocolGuid             ## PRODUCES
> @@ -61,10 +63,13 @@ [Guids]
>     ## SOMETIMES_CONSUMES ## SystemTable
>     gEfiAcpiTableGuid
>   
> +  gEfiEventVirtualAddressChangeGuid
> +
>   [FixedPcd]
>     gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA     ## CONSUMES
>     gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB     ## CONSUMES
>     gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterD     ## CONSUMES
> +  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio                   ## CONSUMES
>   
>   [Pcd]
>     gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout   ## CONSUMES
> @@ -76,5 +81,8 @@ [Pcd]
>   [Depex]
>     gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
>   
> +[Depex.common.DXE_RUNTIME_DRIVER]
> +  gEfiCpuArchProtocolGuid
> +
>   [UserExtensions.TianoCore."ExtraFiles"]
>     PcRtcExtra.uni
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base
  2020-05-14  8:40 ` [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base Sami Mujawar
@ 2020-05-14  9:24   ` Ard Biesheuvel
  2020-05-27 11:48   ` [edk2-devel] " Philippe Mathieu-Daudé
  1 sibling, 0 replies; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:24 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Some virtual machine managers like kvmtool can relocate
> the devices in the system memory map. The information
> about the devices location in memory is described in the
> device tree. Therefore, the CFI memory region and the
> associated Non volatile storage variables need to be
> adjusted accordingly.
> 
> To support such use cases the non-volatile storage
> variable base PCD PcdFlashNvStorageVariableBase has
> been defined as a dynamic PCD.
> 
> The NOR flash driver was using the Flash non-volatile
> storage variable base PCD as a fixed PCD, thereby
> preventing runtime resolution of the variable base
> address.
> 
> Therefore update the NOR flash driver to load the
> PCD using PcdGet32 instead of FixedPcdGet32.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@arm.com>

> ---
>   ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
> index e248fdf6db94191648b5d33bf1a9263f446ee141..9cdd85096a463f69b3b864cecdeaf247e65f4f73 100644
> --- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
> +++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
> @@ -1,6 +1,6 @@
>   /*++ @file  NorFlashFvbDxe.c
>   
> - Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2011 - 2020, ARM Ltd. All rights reserved.<BR>
>   
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>   
> @@ -736,7 +736,7 @@ NorFlashFvbInitialize (
>         EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
>     ASSERT_EFI_ERROR (Status);
>   
> -  mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
> +  mFlashNvStorageVariableBase = PcdGet32 (PcdFlashNvStorageVariableBase);
>   
>     // Set the index of the first LBA for the FVB
>     Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize;
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14  8:40 ` [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver Sami Mujawar
@ 2020-05-14  9:29   ` Ard Biesheuvel
  2020-05-14 12:12     ` [edk2-devel] " Laszlo Ersek
  0 siblings, 1 reply; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:29 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, lersek, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Kvmtool is a virtual machine manager that enables
> hosting KVM guests. It essentially provides an
> emulated platform for guest operating systems.
> 
> Kvmtool hands of a device tree containing the
> current hardware configuration to the firmware.
> 
> A standards-based operating system would use
> ACPI to consume the platform hardware
> information, while some operating systems may
> prefer to use Device Tree.
> 
> The KvmtoolPlatformDxe performs the platform
> actions like determining if the firmware should
> expose ACPI or the Device Tree based hardware
> description to the operating system.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
> 
> Notes:
>      v2:
>        - Updated according to review comments.                     [Sami]
>      
>      v1:
>        - Add kvmtool platform driver to support loading platform   [Sami]
>          specific information.
>        - Keep code to initialise the variable storage PCDs in the  [Laszlo]
>          platform-specific FVB driver.
>        - Document code derived from                                [Laszlo]
>          "ArmVirtPkg/PlatformHasAcpiDtDxe"
>          Ref: https://edk2.groups.io/g/devel/topic/30915278#30757
> 
>   ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93 ++++++++++++++++++++
>   ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
>   2 files changed, 140 insertions(+)
> 
> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
> --- /dev/null
> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
> @@ -0,0 +1,93 @@
> +/** @file
> +
> +  The KvmtoolPlatformDxe performs the platform specific initialization like:
> +  - It decides if the firmware should expose ACPI or Device Tree-based
> +    hardware description to the operating system.
> +
> +  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Guid/VariableFormat.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/DxeServicesTableLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiDriverEntryPoint.h>
> +#include <Protocol/FdtClient.h>
> +
> +/** Decide if the firmware should expose ACPI tables or Device Tree and
> +    install the appropriate protocol interface.
> +
> +  Note: This function is derived from "ArmVirtPkg/PlatformHasAcpiDtDxe",
> +        by dropping the word size check, and the fw_cfg check.
> +
> +  @param [in]  ImageHandle  Handle for this image.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to install the
> +                                  protocols.
> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
> +
> +**/
> +STATIC
> +EFI_STATUS
> +PlatformHasAcpiDt (
> +  IN EFI_HANDLE           ImageHandle
> +  )
> +{
> +  if (!PcdGetBool (PcdForceNoAcpi)) {
> +    // Expose ACPI tables
> +    return gBS->InstallProtocolInterface (
> +                  &ImageHandle,
> +                  &gEdkiiPlatformHasAcpiGuid,
> +                  EFI_NATIVE_INTERFACE,
> +                  NULL
> +                  );
> +  }
> +
> +  // Expose the Device Tree.
> +  return gBS->InstallProtocolInterface (
> +                &ImageHandle,
> +                &gEdkiiPlatformHasDeviceTreeGuid,
> +                EFI_NATIVE_INTERFACE,
> +                NULL
> +                );
> +}
> +
> +/** Entry point for Kvmtool Platform Dxe
> +
> +  @param [in]  ImageHandle  Handle for this image.
> +  @param [in]  SystemTable  Pointer to the EFI system table.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to install the
> +                                  protocols.
> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +KvmtoolPlatformDxeEntryPoint (
> +  IN EFI_HANDLE           ImageHandle,
> +  IN EFI_SYSTEM_TABLE     *SystemTable
> +  )
> +{
> +  EFI_STATUS                     Status;
> +
> +  Status = PlatformHasAcpiDt (ImageHandle);
> +  if (EFI_ERROR (Status)) {
> +    goto Failed;
> +  }
> +
> +  return Status;
> +
> +Failed:
> +  ASSERT_EFI_ERROR (Status);
> +  CpuDeadLoop ();
> +
> +  return Status;
> +}

Please don't use CpuDeadLoop()s in your drivers.

Installing a protocol on an image handle like this should not ever fail, 
and if it does, it is unlikely to be an issue in the driver itself. So 
just use ASSERT_EFI_ERROR() here, and return EFI_SUCCESS.


> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..08a0fe5ce14469133479046385bdd48c22698639
> --- /dev/null
> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
> @@ -0,0 +1,47 @@
> +#/** @file
> +#
> +#  The KvmtoolPlatformDxe performs the platform specific initialization like:
> +#  - It decides if the firmware should expose ACPI or Device Tree-based
> +#    hardware description to the operating system.
> +#
> +#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = KvmtoolPlatformDxe
> +  FILE_GUID                      = 7479CCCD-D721-442A-8C73-A72DBB886669
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = KvmtoolPlatformDxeEntryPoint
> +
> +[Sources]
> +  KvmtoolPlatformDxe.c
> +
> +[Packages]
> +  ArmVirtPkg/ArmVirtPkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  DxeServicesTableLib
> +  MemoryAllocationLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +
> +[Guids]
> +  gEdkiiPlatformHasAcpiGuid       ## SOMETIMES_PRODUCES ## PROTOCOL
> +  gEdkiiPlatformHasDeviceTreeGuid ## SOMETIMES_PRODUCES ## PROTOCOL
> +
> +[Pcd]
> +  gArmVirtTokenSpaceGuid.PcdForceNoAcpi
> +
> +[Depex]
> +  TRUE
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map
  2020-05-14  8:40 ` [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map Sami Mujawar
@ 2020-05-14  9:30   ` Ard Biesheuvel
  2020-05-14 12:15   ` [edk2-devel] " Laszlo Ersek
  1 sibling, 0 replies; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:30 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, lersek, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Kvmtool is a virtual machine manager that enables
> hosting KVM guests. Kvmtool allows to vary the
> hardware configuration of the emulated platform
> it provides to the guest partition. It provides
> the current hardware configuration to the firmware
> by handing off a device tree containing the hardware
> information.
> 
> This library parses the kvmtool provided device
> tree and populates the system memory map for the
> kvmtool emulated platform.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>

Reviewed-by: Ard Biesheuvel <ard.biesheuvel@arm.com>

> ---
>   ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c   | 114 ++++++++++++++++++++
>   ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf |  42 ++++++++
>   2 files changed, 156 insertions(+)
> 
> diff --git a/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..0d353733478b2d097d160246007022990a9cbacb
> --- /dev/null
> +++ b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
> @@ -0,0 +1,114 @@
> +/** @file
> +
> +  Copyright (c) 2018, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +
> +// Number of Virtual Memory Map Descriptors
> +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS          5
> +
> +#define LOG_VM_MAP(txt)                       \
> +  DEBUG ((                                    \
> +    DEBUG_ERROR,                              \
> +    "%a: " #txt "\n"                          \
> +    "\tPhysicalBase: 0x%lX\n"                 \
> +    "\tVirtualBase: 0x%lX\n"                  \
> +    "\tLength: 0x%lX\n",                      \
> +    __FUNCTION__,                             \
> +    VirtualMemoryTable[Idx].PhysicalBase,     \
> +    VirtualMemoryTable[Idx].VirtualBase,      \
> +    VirtualMemoryTable[Idx].Length            \
> +    ));
> +
> +/**
> +  Return the Virtual Memory Map of your platform
> +
> +  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
> +  on your platform.
> +
> +  @param[out]   VirtualMemoryMap    Array of ARM_MEMORY_REGION_DESCRIPTOR
> +                                    describing a Physical-to-Virtual Memory
> +                                    mapping. This array must be ended by a
> +                                    zero-filled entry. The allocated memory
> +                                    will not be freed.
> +
> +**/
> +VOID
> +ArmVirtGetMemoryMap (
> +  OUT ARM_MEMORY_REGION_DESCRIPTOR   **VirtualMemoryMap
> +  )
> +{
> +  ARM_MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
> +  UINTN                          Idx = 0;
> +  EFI_PHYSICAL_ADDRESS           TopOfAddressSpace;
> +
> +  ASSERT (VirtualMemoryMap != NULL);
> +
> +  TopOfAddressSpace = LShiftU64 (1ULL, ArmGetPhysicalAddressBits ());
> +
> +  VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)
> +                        AllocatePages (
> +                          EFI_SIZE_TO_PAGES (
> +                            sizeof (ARM_MEMORY_REGION_DESCRIPTOR) *
> +                            MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
> +                            )
> +                          );
> +
> +  if (VirtualMemoryTable == NULL) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "%a: Error: Failed to Allocate Pages\n",
> +      __FUNCTION__
> +      ));
> +    return;
> +  }
> +
> +  // System DRAM
> +  VirtualMemoryTable[Idx].PhysicalBase = PcdGet64 (PcdSystemMemoryBase);
> +  VirtualMemoryTable[Idx].VirtualBase  = VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Length       = PcdGet64 (PcdSystemMemorySize);
> +  VirtualMemoryTable[Idx].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
> +  LOG_VM_MAP ("System DRAM Memory Map");
> +
> +  // Peripheral space before DRAM
> +  VirtualMemoryTable[++Idx].PhysicalBase = 0x0;
> +  VirtualMemoryTable[Idx].VirtualBase    = 0x0;
> +  VirtualMemoryTable[Idx].Length         = PcdGet64 (PcdSystemMemoryBase);
> +  VirtualMemoryTable[Idx].Attributes     = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
> +  LOG_VM_MAP ("Peripheral space before DRAM");
> +
> +  // Peripheral space after DRAM
> +  VirtualMemoryTable[++Idx].PhysicalBase = PcdGet64 (PcdSystemMemoryBase) +
> +                                           PcdGet64 (PcdSystemMemorySize);
> +  VirtualMemoryTable[Idx].VirtualBase    = VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Length         = TopOfAddressSpace -
> +                                           VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Attributes     = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
> +  LOG_VM_MAP ("Peripheral space after DRAM");
> +
> +  // Map the FV region as normal executable memory
> +  VirtualMemoryTable[++Idx].PhysicalBase = PcdGet64 (PcdFvBaseAddress);
> +  VirtualMemoryTable[Idx].VirtualBase  = VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Length       = FixedPcdGet32 (PcdFvSize);
> +  VirtualMemoryTable[Idx].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
> +  LOG_VM_MAP ("FV region");
> +
> +  // End of Table
> +  VirtualMemoryTable[++Idx].PhysicalBase  = 0;
> +  VirtualMemoryTable[Idx].VirtualBase     = 0;
> +  VirtualMemoryTable[Idx].Length          = 0;
> +  VirtualMemoryTable[Idx].Attributes      = (ARM_MEMORY_REGION_ATTRIBUTES)0;
> +
> +  ASSERT((Idx + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS);
> +
> +  *VirtualMemoryMap = VirtualMemoryTable;
> +}
> diff --git a/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..dbf4ceabe3ae0db5e743e1d9a575542dca32ed0a
> --- /dev/null
> +++ b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
> @@ -0,0 +1,42 @@
> +#/* @file
> +#
> +#  Copyright (c) 2018, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#*/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = KvmtoolVirtMemInfoLib
> +  FILE_GUID                      = B752E953-394F-462C-811C-F8BE35C8C071
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = ArmVirtMemInfoLib
> +
> +[Sources]
> +  KvmtoolVirtMemInfoLib.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  ArmVirtPkg/ArmVirtPkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  PcdLib
> +
> +[Pcd]
> +  gArmTokenSpaceGuid.PcdFvBaseAddress
> +  gArmTokenSpaceGuid.PcdSystemMemoryBase
> +  gArmTokenSpaceGuid.PcdSystemMemorySize
> +
> +[FixedPcd]
> +  gArmTokenSpaceGuid.PcdFvSize
> +
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib
  2020-05-14  8:40 ` [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib Sami Mujawar
@ 2020-05-14  9:32   ` Ard Biesheuvel
  2020-05-14 12:17     ` [edk2-devel] " Laszlo Ersek
  2020-05-27 11:59   ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:32 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, lersek, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Kvmtool places the base address of the CFI flash in
> the device tree it passes to UEFI. This library
> parses the kvmtool device tree to read the CFI base
> address and initialise the PCDs use by the NOR flash
> driver and the variable storage.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>   ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c      | 265 ++++++++++++++++++++
>   ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf |  50 ++++
>   2 files changed, 315 insertions(+)
> 
> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..2e43c2e21bc9ef7dd1dd198eebbd70c3b0b96d1c
> --- /dev/null
> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
> @@ -0,0 +1,265 @@
> +/** @file
> +   An instance of the NorFlashPlatformLib for Kvmtool platform.
> +
> + Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + **/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/NorFlashPlatformLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/FdtClient.h>
> +
> +/** Macro defining the maximum number of Flash Banks.
> + */
> +#define MAX_FLASH_BANKS       4
> +
> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];
> +STATIC UINTN                  mNorFlashDeviceCount = 0;
> +
> +/** This function performs platform specific actions to initialise
> +    the NOR flash, if required.
> +
> +  @retval EFI_SUCCESS           Success.
> +**/
> +EFI_STATUS
> +NorFlashPlatformInitialization (
> +  VOID
> +  )
> +{
> +  DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
> +  // Nothing to do here
> +  return EFI_SUCCESS;
> +}
> +
> +/** Initialise Non volatile Flash storage variables.
> +
> +  @param [in]  FlashDevice Pointer to the NOR Flash device.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_OUT_OF_RESOURCES  Insufficient flash storage space.
> +**/
> +EFI_STATUS
> +SetupVariableStore (
> +  IN NOR_FLASH_DESCRIPTION * FlashDevice
> +  )
> +{
> +  UINTN   FlashRegion;
> +  UINTN   FlashNvStorageVariableBase;
> +  UINTN   FlashNvStorageFtwWorkingBase;
> +  UINTN   FlashNvStorageFtwSpareBase;
> +  UINTN   FlashNvStorageVariableSize;
> +  UINTN   FlashNvStorageFtwWorkingSize;
> +  UINTN   FlashNvStorageFtwSpareSize;
> +
> +  FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
> +  FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
> +  FlashNvStorageFtwSpareSize =  PcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> +  if ((FlashNvStorageVariableSize == 0)   ||
> +      (FlashNvStorageFtwWorkingSize == 0) ||
> +      (FlashNvStorageFtwSpareSize == 0)) {
> +    DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Setup the variable store
> +  FlashRegion = FlashDevice->DeviceBaseAddress;
> +
> +  FlashNvStorageVariableBase = FlashRegion;
> +  FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
> +
> +  FlashNvStorageFtwWorkingBase = FlashRegion;
> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
> +
> +  FlashNvStorageFtwSpareBase = FlashRegion;
> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> +  if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
> +    DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PcdSet32S (
> +    PcdFlashNvStorageVariableBase,
> +    FlashNvStorageVariableBase
> +    );
> +
> +  PcdSet32S (
> +    PcdFlashNvStorageFtwWorkingBase,
> +    FlashNvStorageFtwWorkingBase
> +    );
> +
> +  PcdSet32S (
> +    PcdFlashNvStorageFtwSpareBase,
> +    FlashNvStorageFtwSpareBase
> +    );
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageVariableBase = 0x%x\n",
> +    FlashNvStorageVariableBase
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageVariableSize = 0x%x\n",
> +    FlashNvStorageVariableSize
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
> +    FlashNvStorageFtwWorkingBase
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
> +    FlashNvStorageFtwWorkingSize
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
> +    FlashNvStorageFtwSpareBase
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
> +    FlashNvStorageFtwSpareSize
> +    ));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Return the Flash devices on the platform.
> +
> +  @param [out]  NorFlashDescriptions    Pointer to the Flash device description.
> +  @param [out]  Count                   Number of Flash devices.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_NOT_FOUND         Flash device not found.
> +**/
> +EFI_STATUS
> +NorFlashPlatformGetDevices (
> +  OUT NOR_FLASH_DESCRIPTION   **NorFlashDescriptions,
> +  OUT UINT32                  *Count
> +  )
> +{
> +  if (mNorFlashDeviceCount > 0) {
> +    *NorFlashDescriptions = mNorFlashDevices;
> +    *Count = mNorFlashDeviceCount;
> +    return EFI_SUCCESS;
> +  }
> +  return EFI_NOT_FOUND;
> +}
> +
> +/** Entrypoint for NorFlashPlatformLib.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
> +  @retval EFI_NOT_FOUND           Flash device not found.
> +**/
> +EFI_STATUS
> +EFIAPI
> +NorFlashPlatformLibConstructor (
> +  IN  EFI_HANDLE          ImageHandle,
> +  IN  EFI_SYSTEM_TABLE  * SystemTable
> +  )
> +{
> +  FDT_CLIENT_PROTOCOL         *FdtClient;
> +  INT32                       Node;
> +  EFI_STATUS                  Status;
> +  EFI_STATUS                  FindNodeStatus;
> +  CONST UINT32                *Reg;
> +  UINT32                      PropSize;
> +  UINT64                      Base;
> +  UINT64                      Size;
> +
> +  if (mNorFlashDeviceCount != 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  &gFdtClientProtocolGuid,
> +                  NULL,
> +                  (VOID **)&FdtClient
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +

An ASSERT is sufficient here - the DEPEX ensures that this is guaranteed 
to succeed.

> +  for (FindNodeStatus = FdtClient->FindCompatibleNode (
> +                                     FdtClient,
> +                                     "cfi-flash",
> +                                     &Node
> +                                     );
> +       !EFI_ERROR (FindNodeStatus) && (mNorFlashDeviceCount < MAX_FLASH_BANKS);
> +       FindNodeStatus = FdtClient->FindNextCompatibleNode (
> +                                     FdtClient,
> +                                     "cfi-flash",
> +                                     Node,
> +                                     &Node
> +    )) {
> +    Status = FdtClient->GetNodeProperty (
> +                          FdtClient,
> +                          Node,
> +                          "reg",
> +                          (CONST VOID **)&Reg,
> +                          &PropSize
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
> +        __FUNCTION__, Status));
> +      continue;
> +    }
> +
> +    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
> +
> +    while ((PropSize >= (4 * sizeof (UINT32))) &&
> +           (mNorFlashDeviceCount < MAX_FLASH_BANKS)) {
> +      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
> +      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
> +      Reg += 4;
> +
> +      PropSize -= 4 * sizeof (UINT32);
> +
> +      //
> +      // Disregard any flash devices that overlap with the primary FV.
> +      // The firmware is not updatable from inside the guest anyway.
> +      //
> +      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
> +          (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {
> +        continue;
> +      }
> +
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
> +        mNorFlashDeviceCount,
> +        Base,
> +        Size
> +        ));
> +
> +      mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
> +      mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
> +      mNorFlashDevices[mNorFlashDeviceCount].Size              = (UINTN)Size;
> +      mNorFlashDevices[mNorFlashDeviceCount].BlockSize         = SIZE_256KB;
> +      mNorFlashDeviceCount++;
> +    }
> +  }
> +
> +  // Setup the variable store in the last bank
> +  if ((mNorFlashDeviceCount > 0) &&
> +      (mNorFlashDevices[mNorFlashDeviceCount - 1].DeviceBaseAddress != 0)) {
> +    return SetupVariableStore (&mNorFlashDevices[mNorFlashDeviceCount - 1]);
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..8bd6f730dcb52e597b418e59766c1566a9519789
> --- /dev/null
> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
> @@ -0,0 +1,50 @@
> +#/** @file
> +#
> +#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = NorFlashKvmtoolLib
> +  FILE_GUID                      = E75F07A1-B160-4893-BDD4-09E32FF847DC
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = NorFlashPlatformLib
> +  CONSTRUCTOR                    = NorFlashPlatformLibConstructor
> +
> +[Sources.common]
> +  NorFlashKvmtool.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  ArmVirtPkg/ArmVirtPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  DebugLib
> +  PcdLib
> +  UefiBootServicesTableLib
> +
> +[Protocols]
> +  gFdtClientProtocolGuid          ## CONSUMES
> +
> +[Pcd]
> +  gArmTokenSpaceGuid.PcdFvBaseAddress
> +  gArmTokenSpaceGuid.PcdFvSize
> +
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +
> +[Depex]
> +  gFdtClientProtocolGuid
> +
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform
  2020-05-14  8:40 ` [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform Sami Mujawar
@ 2020-05-14  9:56   ` Ard Biesheuvel
  2020-05-14 12:24   ` [edk2-devel] " Laszlo Ersek
  1 sibling, 0 replies; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14  9:56 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, lersek, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Kvmtool is a virtual machine manager that enables hosting
> KVM guests. Kvmtool emulates certain devices like serial
> port, RTC, etc. essentially providing an emulated platform.
> 
> This patch adds support for kvmtool emulated platform.
> 

Please use accurate terminology here. Unlike QEMU, kvmtool is *not* an 
emulator. It only supports running under KVM, where instructions are 
executed on the actual CPU, or decoded by the hypervisor for MMIO emulation.

> Following is a brief description of the firmware
> implementation choices:
> 
> - Serial Port: 16550 UART
>    On some platforms the 16550 UART is interfaced using
>    PCI. Therefore, the 16550 Serial port library is
>    dependent on the PCI library. The 16550 UART driver
>    checks the Device ID represented using the PCD
>    gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo
>    to determine if the UART is behind PCI.
>    If the Device ID is 0xFF then the serial 16550 UART
>    is not behind PCI. For such platforms a NULL
>    implementation of the PCI library has been provided
>    so that the serial output is available during the
>    early boot stages.
> 
>    On Kvmtool the Serial 16550 UART is not behind PCI,
>    and therefore makes use of PciLibNull library during
>    early boot stages. The DXE modules that make use of
>    PCI functionality explicitly include the library
>    BasePciLibPciExpress, so that the required PCI
>    functionality is available.
> 
>    The PcdSerialPciDeviceInfo is also set to 0xFF to
>    indicate that the Serial 16550 UART is not behind
>    PCI. The PCD PcdSerialUseMmio is also set to TRUE
>    to indicate MMIO accesses are required for the
>    UART registers.
> 
> - Dependency order for Flash
>    FaultTolerantWriteDxe makes use of PCDs (e.g.
>    PcdFlashNvStorageFtwSpareBase64 etc.), which in
>    case of kvmtool will be evaluated based on the CFI
>    flash base address read from the DT. These variables
>    are populated in the NorFlashPlatformLib loaded by
>    ArmVeNorFlashDxe.
> 
>    This results in a dependency issue with
>    FaultTolerantWriteDxe. To resolve this make the
>    NorFlashPlatformLib as a library dependency for
>    FaultTolerantWriteDxe.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
> 
> Notes:
>      v2:
>        - Updates to reflect review comments and support             [Sami]
>          for latest features emulated by kvmtool e.g. CFI.
>      
>      v1:
>        - Add support for Kvmtool emulated platform                  [Sami]
>        - Add more justification for platform and                    [Laszlo]
>          document platform maintainer.
>          Ref: https://edk2.groups.io/g/devel/topic/30915279#30693
> 
>   ArmVirtPkg/ArmVirtKvmTool.dsc | 408 ++++++++++++++++++++
>   ArmVirtPkg/ArmVirtKvmTool.fdf | 276 +++++++++++++
>   2 files changed, 684 insertions(+)
> 
> diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
> new file mode 100644
> index 0000000000000000000000000000000000000000..b2dc5eb2a09521c57a30babbee40749abdb7f7ff
> --- /dev/null
> +++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
> @@ -0,0 +1,408 @@
> +#  @file
> +#  Workspace file for KVMTool virtual platform.
> +#
> +#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#
> +
> +################################################################################
> +#
> +# Defines Section - statements that will be processed to create a Makefile.
> +#
> +################################################################################
> +[Defines]
> +  PLATFORM_NAME                  = ArmVirtKvmTool
> +  PLATFORM_GUID                  = 4CB2C61E-FA32-4130-8E37-54ABC71A1A43
> +  PLATFORM_VERSION               = 0.1
> +  DSC_SPECIFICATION              = 0x0001001B
> +!ifdef $(EDK2_OUT_DIR)

Can we remove this?

> +  OUTPUT_DIRECTORY               = $(EDK2_OUT_DIR)
> +!else
> +  OUTPUT_DIRECTORY               = Build/ArmVirtKvmTool-$(ARCH)
> +!endif
> +  SUPPORTED_ARCHITECTURES        = AARCH64|ARM
> +  BUILD_TARGETS                  = DEBUG|RELEASE
> +  SKUID_IDENTIFIER               = DEFAULT
> +  FLASH_DEFINITION               = ArmVirtPkg/ArmVirtKvmTool.fdf
> +
> +  #
> +  # Defines for default states.  These can be changed on the command line.
> +  # -D FLAG=VALUE
> +  #
> +  DEFINE SECURE_BOOT_ENABLE      = FALSE
> +  DEFINE HTTP_BOOT_ENABLE        = FALSE
> +  DEFINE TTY_TERMINAL            = TRUE
> +  DEFINE ENABLE_NETWORK          = TRUE
> +  DEFINE TPM2_ENABLE             = FALSE
> +

Please don't define bits and pieces you cannot make use of. This 
includes PCI, afaik


> +!include ArmVirtPkg/ArmVirt.dsc.inc
> +
> +[LibraryClasses.common]
> +  ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
> +  ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf
> +
> +  # Virtio Support
> +  VirtioLib|OvmfPkg/Library/VirtioLib/VirtioLib.inf
> +  VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
> +
> +  ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf
> +  ArmVirtMemInfoLib|ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
> +
> +  TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf
> +  NorFlashPlatformLib|ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
> +
> +  CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
> +
> +  # BDS Libraries
> +  UefiBootManagerLib|MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
> +  PlatformBootManagerLib|ArmPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> +  BootLogoLib|MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
> +
> +  CustomizedDisplayLib|MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
> +  FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
> +
> +  FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
> +  PciPcdProducerLib|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
> +  PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
> +  PciHostBridgeLib|ArmVirtPkg/Library/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
> +
> +!if $(HTTP_BOOT_ENABLE) == TRUE
> +  HttpLib|NetworkPkg/Library/DxeHttpLib/DxeHttpLib.inf
> +!endif
> +
> +!if $(TPM2_ENABLE) == FALSE
> +  TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
> +  AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
> +!endif
> +
> +[LibraryClasses.common, LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE, LibraryClasses.common.PEIM]
> +  # The 16550 Serial port library is dependent on PCI library.
> +  # A null implementation of the PCI Library has been provided so that
> +  # the serial output is available during the early boot stages.
> +  # The DXE modules that make use of PCI override the PciLibNull library
> +  # and are individually linked with the real PCI library.
> +  PciLib|MdePkg/Library/PciLibNull/PciLibNull.inf
> +  PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf
> +  SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
> +
> +[LibraryClasses.common.UEFI_DRIVER]
> +  UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
> +
> +[BuildOptions.ARM.EDKII.SEC, BuildOptions.ARM.EDKII.BASE]
> +  # Avoid MOVT/MOVW instruction pairs in code that may end up in the PIE
> +  # executable we build for the relocatable PrePi. They are not runtime
> +  # relocatable in ELF.
> +  *_CLANG35_*_CC_FLAGS = -mno-movt
> +
> +################################################################################
> +#
> +# Pcd Section - list of all EDK II PCD Entries defined by this Platform
> +#
> +################################################################################
> +
> +[PcdsFeatureFlag.common]
> +  ## If TRUE, Graphics Output Protocol will be installed on virtual handle created by ConsplitterDxe.
> +  #  It could be set FALSE to save size.
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport|TRUE
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE
> +
> +  gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|$(TPM2_ENABLE)
> +
> +[PcdsFixedAtBuild.common]
> +  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
> +
> +  gArmPlatformTokenSpaceGuid.PcdCoreCount|1
> +
> +!if $(ARCH) == AARCH64
> +  gArmTokenSpaceGuid.PcdVFPEnabled|1
> +!endif
> +
> +  gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x4000
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
> +
> +  # Size of the region used by UEFI in permanent memory (Reserved 64MB)
> +  gArmPlatformTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x04000000
> +
> +  #
> +  # ARM PrimeCell
> +  #
> +  ## Default Terminal Type
> +  ## 0-PCANSI, 1-VT100, 2-VT00+, 3-UTF8, 4-TTYTERM
> +#!if $(TTY_TERMINAL) == TRUE
> +  gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|4
> +#!else
> +#  gEfiMdePkgTokenSpaceGuid.PcdDefaultTerminalType|1
> +#!endif
> +
> +  #
> +  # ARM Virtual Architectural Timer -- fetch frequency from KVM
> +  #
> +  gArmTokenSpaceGuid.PcdArmArchTimerFreqInHz|0
> +
> +!if $(HTTP_BOOT_ENABLE) == TRUE
> +  gEfiNetworkPkgTokenSpaceGuid.PcdAllowHttpConnections|TRUE
> +!endif
> +
> +  # Use MMIO for accessing Serial port registers.
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio|TRUE
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}
> +
> +  # Use MMIO for accessing RTC controller registers.
> +  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|TRUE
> +
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange|FALSE
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdBootManagerMenuFile|{ 0x21, 0xaa, 0x2c, 0x46, 0x14, 0x76, 0x03, 0x45, 0x83, 0x6e, 0x8a, 0xb6, 0xf4, 0x66, 0x23, 0x31 }
> +
> +  #
> +  # The maximum physical I/O addressability of the processor, set with
> +  # BuildCpuHob().
> +  #
> +  gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|16
> +
> +[PcdsPatchableInModule.common]
> +  #
> +  # This will be overridden in the code
> +  #
> +  gArmTokenSpaceGuid.PcdSystemMemoryBase|0x0
> +  gArmTokenSpaceGuid.PcdSystemMemorySize|0x0
> +
> +  #
> +  # The device tree base address is handed off by kvmtool.
> +  # We are booting from RAM using the Linux kernel boot protocol,
> +  # x0 will point to the DTB image in memory.
> +  #
> +  gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress|0x0
> +
> +  gArmTokenSpaceGuid.PcdFdBaseAddress|0x0
> +  gArmTokenSpaceGuid.PcdFvBaseAddress|0x0
> +
> +  # we need to provide a resolution for this PCD that supports PcdSet64()
> +  # being called from ArmVirtPkg/Library/PlatformPeiLib/PlatformPeiLib.c,
> +  # even though that call will be compiled out on this platform as it does
> +  # not (and cannot) support the TPM2 driver stack
> +  gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress|0x0
> +
> +[PcdsDynamicDefault.common]
> +  gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|3
> +
> +  gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|0x0
> +  gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|0x0
> +  gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0
> +  gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0
> +
> +  #
> +  # ARM General Interrupt Controller
> +  #
> +  gArmTokenSpaceGuid.PcdGicDistributorBase|0x0
> +  gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x0
> +  gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x0
> +
> +  #
> +  # PCI settings
> +  #
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration|TRUE
> +
> +  # set PcdPciExpressBaseAddress to MAX_UINT64, which signifies that this
> +  # PCD and PcdPciDisableBusEnumeration above have not been assigned yet
> +  gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xFFFFFFFFFFFFFFFF
> +
> +  gArmTokenSpaceGuid.PcdPciIoTranslation|0x0
> +
> +  #
> +  # Set video resolution for boot options and for text setup.
> +  # PlatformDxe can set the former at runtime.
> +  #
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution|800
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution|600
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|640
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution|480
> +
> +  ## Force DTB
> +  gArmVirtTokenSpaceGuid.PcdForceNoAcpi|TRUE
> +
> +  # Setup Flash storage variables
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x40000
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x40000
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x40000
> +
> +################################################################################
> +#
> +# Components Section - list of all EDK II Modules needed by this Platform
> +#
> +################################################################################
> +[Components.common]
> +  #
> +  # PEI Phase modules
> +  #
> +  ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf {
> +    <LibraryClasses>
> +      ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
> +      LzmaDecompressLib|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
> +      PrePiLib|EmbeddedPkg/Library/PrePiLib/PrePiLib.inf
> +      HobLib|EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
> +      PrePiHobListPointerLib|ArmPlatformPkg/Library/PrePiHobListPointerLib/PrePiHobListPointerLib.inf
> +      MemoryAllocationLib|EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf
> +  }
> +
> +  #
> +  # DXE
> +  #
> +  MdeModulePkg/Core/Dxe/DxeMain.inf {
> +    <LibraryClasses>
> +      NULL|MdeModulePkg/Library/DxeCrc32GuidedSectionExtractLib/DxeCrc32GuidedSectionExtractLib.inf
> +      DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> +  }
> +  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf {
> +    <LibraryClasses>
> +      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> +  }
> +
> +  #
> +  # Architectural Protocols
> +  #
> +  ArmPkg/Drivers/CpuDxe/CpuDxe.inf
> +  MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
> +  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
> +    <LibraryClasses>
> +      NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
> +      NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
> +      # don't use unaligned CopyMem () on the UEFI varstore NOR flash region
> +      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> +  }
> +
> +!if $(SECURE_BOOT_ENABLE) == TRUE
> +  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf {
> +    <LibraryClasses>
> +      NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
> +  }
> +  SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
> +!else
> +  MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
> +!endif
> +  MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
> +  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf {
> +    <LibraryClasses>
> +      NULL|ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
> +  }
> +
> +  MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
> +  MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
> +  MdeModulePkg/Universal/Metronome/Metronome.inf
> +  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> +
> +  MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
> +  MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
> +  MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
> +  MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
> +  MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
> +
> +  MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
> +
> +  ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
> +  ArmPkg/Drivers/TimerDxe/TimerDxe.inf {
> +    <LibraryClasses>
> +      NULL|ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.inf
> +  }
> +  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf {
> +    <LibraryClasses>
> +      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> +  }
> +
> +  MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
> +
> +  #
> +  # Platform Driver
> +  #
> +  ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
> +  ArmVirtPkg/VirtioFdtDxe/VirtioFdtDxe.inf
> +  ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf
> +  ArmVirtPkg/HighMemDxe/HighMemDxe.inf
> +  OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
> +  OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
> +  OvmfPkg/VirtioNetDxe/VirtioNet.inf
> +  OvmfPkg/VirtioRngDxe/VirtioRng.inf
> +
> +  #
> +  # FAT filesystem + GPT/MBR partitioning + UDF filesystem
> +  #
> +  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
> +  MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
> +  MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
> +  FatPkg/EnhancedFatDxe/Fat.inf
> +  MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
> +
> +  #
> +  # Bds
> +  #
> +  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf {
> +    <LibraryClasses>
> +      DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
> +      PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> +  }
> +  MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
> +  MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
> +  MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
> +  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
> +  MdeModulePkg/Logo/LogoDxe.inf
> +  MdeModulePkg/Application/UiApp/UiApp.inf {
> +    <LibraryClasses>
> +      NULL|MdeModulePkg/Library/DeviceManagerUiLib/DeviceManagerUiLib.inf
> +      NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
> +      NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
> +  }
> +
> +!if $(ENABLE_NETWORK) == TRUE
> +  #
> +  # Networking stack
> +  #
> +  NetworkPkg/SnpDxe/SnpDxe.inf
> +  NetworkPkg/DpcDxe/DpcDxe.inf
> +  NetworkPkg/ArpDxe/ArpDxe.inf
> +  NetworkPkg/Dhcp4Dxe/Dhcp4Dxe.inf
> +  NetworkPkg/Ip4Dxe/Ip4Dxe.inf
> +  NetworkPkg/MnpDxe/MnpDxe.inf
> +  NetworkPkg/VlanConfigDxe/VlanConfigDxe.inf
> +  NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.inf
> +  NetworkPkg/Udp4Dxe/Udp4Dxe.inf
> +  NetworkPkg/TcpDxe/TcpDxe.inf
> +  NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf
> +  NetworkPkg/IScsiDxe/IScsiDxe.inf
> +!if $(HTTP_BOOT_ENABLE) == TRUE
> +  NetworkPkg/DnsDxe/DnsDxe.inf
> +  NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf
> +  NetworkPkg/HttpDxe/HttpDxe.inf
> +  NetworkPkg/HttpBootDxe/HttpBootDxe.inf
> +!endif
> +!endif
> +  #
> +  # SCSI Bus and Disk Driver
> +  #
> +  MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
> +  MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
> +
> +  #
> +  # PCI support
> +  #
> +  ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf {
> +    <LibraryClasses>
> +      NULL|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
> +  }
> +
> +  MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf {
> +    <LibraryClasses>
> +      PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
> +  }
> +
> +  MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf {
> +    <LibraryClasses>
> +      NULL|ArmVirtPkg/Library/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
> +  }
> +
> +  OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
> +  OvmfPkg/Virtio10Dxe/Virtio10.inf
> diff --git a/ArmVirtPkg/ArmVirtKvmTool.fdf b/ArmVirtPkg/ArmVirtKvmTool.fdf
> new file mode 100644
> index 0000000000000000000000000000000000000000..8b794e6a1f3652f3262faa35b37f2f8d36d5438d
> --- /dev/null
> +++ b/ArmVirtPkg/ArmVirtKvmTool.fdf
> @@ -0,0 +1,276 @@
> +#
> +#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#
> +
> +################################################################################
> +#
> +# FD Section
> +# The [FD] Section is made up of the definition statements and a
> +# description of what goes into  the Flash Device Image.  Each FD section
> +# defines one flash "device" image.  A flash device image may be one of
> +# the following: Removable media bootable image (like a boot floppy
> +# image,) an Option ROM image (that would be "flashed" into an add-in
> +# card,) a System "Flash"  image (that would be burned into a system's
> +# flash) or an Update ("Capsule") image that will be used to update and
> +# existing system flash.
> +#
> +################################################################################
> +
> +[FD.KVMTOOL_EFI]
> +BaseAddress   = 0x00000000|gArmTokenSpaceGuid.PcdFdBaseAddress
> +# The size in bytes of the FLASH Device
> +Size          = 0x00200000|gArmTokenSpaceGuid.PcdFdSize
> +ErasePolarity = 1
> +
> +# This one is tricky, it must be: BlockSize * NumBlocks = Size
> +BlockSize     = 0x00001000
> +NumBlocks     = 0x200
> +
> +################################################################################
> +#
> +# Following are lists of FD Region layout which correspond to the locations of different
> +# images within the flash device.
> +#
> +# Regions must be defined in ascending order and may not overlap.
> +#
> +# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by
> +# the pipe "|" character, followed by the size of the region, also in hex with the leading
> +# "0x" characters. Like:
> +# Offset|Size
> +# PcdOffsetCName|PcdSizeCName
> +# RegionType <FV, DATA, or FILE>
> +#
> +################################################################################
> +
> +#
> +# Implement the Linux kernel header layout so that the loader will identify
> +# it as something bootable, and execute it with a FDT pointer in x0 or r2.
> +# This area will be reused to store a copy of the FDT so round it up to 32 KB.
> +#
> +0x00000000|0x00008000
> +DATA = {
> +!if $(ARCH) == AARCH64
> +  0x01, 0x00, 0x00, 0x10,                         # code0: adr x1, .
> +  0xff, 0x1f, 0x00, 0x14,                         # code1: b 0x8000
> +  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, # text_offset: 512 KB
> +  0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, # image_size: 2 MB
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # flags
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # res2
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # res3
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # res4
> +  0x41, 0x52, 0x4d, 0x64,                         # magic: "ARM\x64"
> +  0x00, 0x00, 0x00, 0x00                          # res5
> +!else
> +  0x08, 0x10, 0x4f, 0xe2, # adr r1, .
> +  0x02, 0x00, 0xa0, 0xe1, # mov r0, r2 (DTB)
> +  0x00, 0x00, 0xa0, 0xe1, # nop
> +  0x00, 0x00, 0xa0, 0xe1, # nop
> +  0x00, 0x00, 0xa0, 0xe1, # nop
> +  0x00, 0x00, 0xa0, 0xe1, # nop
> +  0x00, 0x00, 0xa0, 0xe1, # nop
> +  0x00, 0x00, 0xa0, 0xe1, # nop
> +
> +  0xf6, 0x1f, 0x00, 0xea, # b 0x8000
> +  0x18, 0x28, 0x6f, 0x01, # magic
> +  0x00, 0x00, 0x00, 0x00, # start
> +  0x00, 0x00, 0x20, 0x00, # image size: 2 MB
> +  0x01, 0x02, 0x03, 0x04  # endiannness flag
> +!endif
> +}
> +
> +0x00008000|0x001f8000
> +gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize
> +FV = FVMAIN_COMPACT
> +
> +################################################################################
> +#
> +# FV Section
> +#
> +# [FV] section is used to define what components or modules are placed within a flash
> +# device file.  This section also defines order the components and modules are positioned
> +# within the image.  The [FV] section consists of define statements, set statements and
> +# module statements.
> +#
> +################################################################################
> +
> +[FV.FvMain]
> +FvNameGuid         = 64074afe-340a-4be6-94ba-91b5b4d0f71e
> +BlockSize          = 0x40
> +NumBlocks          = 0         # This FV gets compressed so make it just big enough
> +FvAlignment        = 16        # FV alignment and FV attributes setting.
> +ERASE_POLARITY     = 1
> +MEMORY_MAPPED      = TRUE
> +STICKY_WRITE       = TRUE
> +LOCK_CAP           = TRUE
> +LOCK_STATUS        = TRUE
> +WRITE_DISABLED_CAP = TRUE
> +WRITE_ENABLED_CAP  = TRUE
> +WRITE_STATUS       = TRUE
> +WRITE_LOCK_CAP     = TRUE
> +WRITE_LOCK_STATUS  = TRUE
> +READ_DISABLED_CAP  = TRUE
> +READ_ENABLED_CAP   = TRUE
> +READ_STATUS        = TRUE
> +READ_LOCK_CAP      = TRUE
> +READ_LOCK_STATUS   = TRUE
> +
> +  INF MdeModulePkg/Core/Dxe/DxeMain.inf
> +  INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
> +  INF ArmVirtPkg/VirtioFdtDxe/VirtioFdtDxe.inf
> +  INF ArmVirtPkg/FdtClientDxe/FdtClientDxe.inf
> +  INF ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
> +  INF ArmVirtPkg/HighMemDxe/HighMemDxe.inf
> +
> +  #
> +  # PI DXE Drivers producing Architectural Protocols (EFI Services)
> +  #
> +  INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf
> +  INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
> +  INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
> +  INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
> +  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> +  INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> +
> +!if $(SECURE_BOOT_ENABLE) == TRUE
> +  INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
> +!endif
> +  INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
> +  INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
> +
> +  INF  MdeModulePkg/Universal/Metronome/Metronome.inf
> +  INF  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> +
> +  INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
> +
> +  #
> +  # Multiple Console IO support
> +  #
> +  INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
> +  INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
> +  INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
> +  INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
> +  INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
> +
> +  INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
> +  INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
> +  INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
> +  INF ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
> +
> +  #
> +  # FAT filesystem + GPT/MBR partitioning + UDF filesystem
> +  #
> +  INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
> +  INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
> +  INF FatPkg/EnhancedFatDxe/Fat.inf
> +  INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
> +  INF MdeModulePkg/Universal/Disk/UdfDxe/UdfDxe.inf
> +
> +  #
> +  # Platform Driver
> +  #
> +  INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
> +  INF OvmfPkg/VirtioNetDxe/VirtioNet.inf
> +  INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
> +  INF OvmfPkg/VirtioRngDxe/VirtioRng.inf
> +
> +  #
> +  # UEFI application (Shell Embedded Boot Loader)
> +  #
> +  INF ShellPkg/Application/Shell/Shell.inf
> +  INF ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf
> +
> +  #
> +  # Bds
> +  #
> +  INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
> +  INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
> +  INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
> +  INF MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
> +  INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
> +  INF MdeModulePkg/Application/UiApp/UiApp.inf
> +
> +!if $(ENABLE_NETWORK) == TRUE
> +  #
> +  # Networking stack
> +  #
> +  INF NetworkPkg/SnpDxe/SnpDxe.inf
> +  INF NetworkPkg/DpcDxe/DpcDxe.inf
> +  INF NetworkPkg/ArpDxe/ArpDxe.inf
> +  INF NetworkPkg/Dhcp4Dxe/Dhcp4Dxe.inf
> +  INF NetworkPkg/Ip4Dxe/Ip4Dxe.inf
> +  INF NetworkPkg/MnpDxe/MnpDxe.inf
> +  INF NetworkPkg/VlanConfigDxe/VlanConfigDxe.inf
> +  INF NetworkPkg/Mtftp4Dxe/Mtftp4Dxe.inf
> +  INF NetworkPkg/Udp4Dxe/Udp4Dxe.inf
> +  INF NetworkPkg/TcpDxe/TcpDxe.inf
> +  INF NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf
> +  INF NetworkPkg/IScsiDxe/IScsiDxe.inf
> +!if $(HTTP_BOOT_ENABLE) == TRUE
> +  INF NetworkPkg/DnsDxe/DnsDxe.inf
> +  INF NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf
> +  INF NetworkPkg/HttpDxe/HttpDxe.inf
> +  INF NetworkPkg/HttpBootDxe/HttpBootDxe.inf
> +!endif
> +!endif
> +  #
> +  # SCSI Bus and Disk Driver
> +  #
> +  INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
> +  INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
> +
> +!if $(ARCH) == AARCH64
> +  #
> +  # EBC support
> +  #
> +  INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
> +!endif
> +
> +  #
> +  # PCI support
> +  #
> +  INF ArmPkg/Drivers/ArmPciCpuIo2Dxe/ArmPciCpuIo2Dxe.inf
> +  INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
> +  INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
> +  INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
> +  INF OvmfPkg/Virtio10Dxe/Virtio10.inf
> +
> +  #
> +  # TianoCore logo (splash screen)
> +  #
> +  INF MdeModulePkg/Logo/LogoDxe.inf
> +
> +  #
> +  # Ramdisk support
> +  #
> +  INF MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
> +
> +[FV.FVMAIN_COMPACT]
> +FvAlignment        = 16
> +ERASE_POLARITY     = 1
> +MEMORY_MAPPED      = TRUE
> +STICKY_WRITE       = TRUE
> +LOCK_CAP           = TRUE
> +LOCK_STATUS        = TRUE
> +WRITE_DISABLED_CAP = TRUE
> +WRITE_ENABLED_CAP  = TRUE
> +WRITE_STATUS       = TRUE
> +WRITE_LOCK_CAP     = TRUE
> +WRITE_LOCK_STATUS  = TRUE
> +READ_DISABLED_CAP  = TRUE
> +READ_ENABLED_CAP   = TRUE
> +READ_STATUS        = TRUE
> +READ_LOCK_CAP      = TRUE
> +READ_LOCK_STATUS   = TRUE
> +
> +  INF ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
> +
> +  FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
> +    SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE {
> +      SECTION FV_IMAGE = FVMAIN
> +    }
> +  }
> +
> +!include ArmVirtRules.fdf.inc
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14  9:29   ` Ard Biesheuvel
@ 2020-05-14 12:12     ` Laszlo Ersek
  2020-05-14 12:17       ` Ard Biesheuvel
  2020-05-14 12:20       ` Laszlo Ersek
  0 siblings, 2 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:12 UTC (permalink / raw)
  To: devel, ard.biesheuvel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 05/14/20 11:29, Ard Biesheuvel wrote:
> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>> Kvmtool is a virtual machine manager that enables
>> hosting KVM guests. It essentially provides an
>> emulated platform for guest operating systems.
>>
>> Kvmtool hands of a device tree containing the
>> current hardware configuration to the firmware.
>>
>> A standards-based operating system would use
>> ACPI to consume the platform hardware
>> information, while some operating systems may
>> prefer to use Device Tree.
>>
>> The KvmtoolPlatformDxe performs the platform
>> actions like determining if the firmware should
>> expose ACPI or the Device Tree based hardware
>> description to the operating system.
>>
>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>> ---
>>
>> Notes:
>>      v2:
>>        - Updated according to review comments.                     [Sami]
>>           v1:
>>        - Add kvmtool platform driver to support loading platform   [Sami]
>>          specific information.
>>        - Keep code to initialise the variable storage PCDs in the 
>> [Laszlo]
>>          platform-specific FVB driver.
>>        - Document code derived from                               
>> [Laszlo]
>>          "ArmVirtPkg/PlatformHasAcpiDtDxe"
>>          Ref: https://edk2.groups.io/g/devel/topic/30915278#30757
>>
>>   ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93
>> ++++++++++++++++++++
>>   ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
>>   2 files changed, 140 insertions(+)
>>
>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
>>
>> --- /dev/null
>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>> @@ -0,0 +1,93 @@
>> +/** @file
>> +
>> +  The KvmtoolPlatformDxe performs the platform specific
>> initialization like:
>> +  - It decides if the firmware should expose ACPI or Device Tree-based
>> +    hardware description to the operating system.
>> +
>> +  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Guid/VariableFormat.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/DxeServicesTableLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiDriverEntryPoint.h>
>> +#include <Protocol/FdtClient.h>
>> +
>> +/** Decide if the firmware should expose ACPI tables or Device Tree and
>> +    install the appropriate protocol interface.
>> +
>> +  Note: This function is derived from "ArmVirtPkg/PlatformHasAcpiDtDxe",
>> +        by dropping the word size check, and the fw_cfg check.
>> +
>> +  @param [in]  ImageHandle  Handle for this image.
>> +
>> +  @retval EFI_SUCCESS             Success.
>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>> install the
>> +                                  protocols.
>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>> +
>> +**/
>> +STATIC
>> +EFI_STATUS
>> +PlatformHasAcpiDt (
>> +  IN EFI_HANDLE           ImageHandle
>> +  )
>> +{
>> +  if (!PcdGetBool (PcdForceNoAcpi)) {
>> +    // Expose ACPI tables
>> +    return gBS->InstallProtocolInterface (
>> +                  &ImageHandle,
>> +                  &gEdkiiPlatformHasAcpiGuid,
>> +                  EFI_NATIVE_INTERFACE,
>> +                  NULL
>> +                  );
>> +  }
>> +
>> +  // Expose the Device Tree.
>> +  return gBS->InstallProtocolInterface (
>> +                &ImageHandle,
>> +                &gEdkiiPlatformHasDeviceTreeGuid,
>> +                EFI_NATIVE_INTERFACE,
>> +                NULL
>> +                );
>> +}
>> +
>> +/** Entry point for Kvmtool Platform Dxe
>> +
>> +  @param [in]  ImageHandle  Handle for this image.
>> +  @param [in]  SystemTable  Pointer to the EFI system table.
>> +
>> +  @retval EFI_SUCCESS             Success.
>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>> install the
>> +                                  protocols.
>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +KvmtoolPlatformDxeEntryPoint (
>> +  IN EFI_HANDLE           ImageHandle,
>> +  IN EFI_SYSTEM_TABLE     *SystemTable
>> +  )
>> +{
>> +  EFI_STATUS                     Status;
>> +
>> +  Status = PlatformHasAcpiDt (ImageHandle);
>> +  if (EFI_ERROR (Status)) {
>> +    goto Failed;
>> +  }
>> +
>> +  return Status;
>> +
>> +Failed:
>> +  ASSERT_EFI_ERROR (Status);
>> +  CpuDeadLoop ();
>> +
>> +  return Status;
>> +}
> 
> Please don't use CpuDeadLoop()s in your drivers.
> 
> Installing a protocol on an image handle like this should not ever fail,
> and if it does, it is unlikely to be an issue in the driver itself. So
> just use ASSERT_EFI_ERROR() here, and return EFI_SUCCESS.

I think Sami just followed the original code in
"ArmVirtPkg/PlatformHasAcpiDtDxe".

I'm fine either way:

Acked-by: Laszlo Ersek <lersek@redhat.com>

Different question:

Should we ask Sami to become a designated reviewer (in Maintainers.txt)
for the kvmtool-specific modules under ArmVirtPkg? Personally I'm
unlikely to use kvmtool.

Thanks
Laszlo

> 
> 
>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..08a0fe5ce14469133479046385bdd48c22698639
>>
>> --- /dev/null
>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
>> @@ -0,0 +1,47 @@
>> +#/** @file
>> +#
>> +#  The KvmtoolPlatformDxe performs the platform specific
>> initialization like:
>> +#  - It decides if the firmware should expose ACPI or Device Tree-based
>> +#    hardware description to the operating system.
>> +#
>> +#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>> +#
>> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +#**/
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = KvmtoolPlatformDxe
>> +  FILE_GUID                      = 7479CCCD-D721-442A-8C73-A72DBB886669
>> +  MODULE_TYPE                    = DXE_DRIVER
>> +  VERSION_STRING                 = 1.0
>> +  ENTRY_POINT                    = KvmtoolPlatformDxeEntryPoint
>> +
>> +[Sources]
>> +  KvmtoolPlatformDxe.c
>> +
>> +[Packages]
>> +  ArmVirtPkg/ArmVirtPkg.dec
>> +  EmbeddedPkg/EmbeddedPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  BaseMemoryLib
>> +  DebugLib
>> +  DxeServicesTableLib
>> +  MemoryAllocationLib
>> +  UefiBootServicesTableLib
>> +  UefiDriverEntryPoint
>> +
>> +[Guids]
>> +  gEdkiiPlatformHasAcpiGuid       ## SOMETIMES_PRODUCES ## PROTOCOL
>> +  gEdkiiPlatformHasDeviceTreeGuid ## SOMETIMES_PRODUCES ## PROTOCOL
>> +
>> +[Pcd]
>> +  gArmVirtTokenSpaceGuid.PcdForceNoAcpi
>> +
>> +[Depex]
>> +  TRUE
>>
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map
  2020-05-14  8:40 ` [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map Sami Mujawar
  2020-05-14  9:30   ` Ard Biesheuvel
@ 2020-05-14 12:15   ` Laszlo Ersek
  1 sibling, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:15 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

On 05/14/20 10:40, Sami Mujawar wrote:
> Kvmtool is a virtual machine manager that enables
> hosting KVM guests. Kvmtool allows to vary the
> hardware configuration of the emulated platform
> it provides to the guest partition. It provides
> the current hardware configuration to the firmware
> by handing off a device tree containing the hardware
> information.
> 
> This library parses the kvmtool provided device
> tree and populates the system memory map for the
> kvmtool emulated platform.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c   | 114 ++++++++++++++++++++
>  ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf |  42 ++++++++
>  2 files changed, 156 insertions(+)
> 
> diff --git a/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..0d353733478b2d097d160246007022990a9cbacb
> --- /dev/null
> +++ b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.c
> @@ -0,0 +1,114 @@
> +/** @file
> +
> +  Copyright (c) 2018, ARM Limited. All rights reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +
> +// Number of Virtual Memory Map Descriptors
> +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS          5
> +
> +#define LOG_VM_MAP(txt)                       \

(1) Please use "Txt" at least.

There are some other mild coding style discrepancies in this patch, but
I don't want to obsess about those.

With (1) fixed:

Acked-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo

> +  DEBUG ((                                    \
> +    DEBUG_ERROR,                              \
> +    "%a: " #txt "\n"                          \
> +    "\tPhysicalBase: 0x%lX\n"                 \
> +    "\tVirtualBase: 0x%lX\n"                  \
> +    "\tLength: 0x%lX\n",                      \
> +    __FUNCTION__,                             \
> +    VirtualMemoryTable[Idx].PhysicalBase,     \
> +    VirtualMemoryTable[Idx].VirtualBase,      \
> +    VirtualMemoryTable[Idx].Length            \
> +    ));
> +
> +/**
> +  Return the Virtual Memory Map of your platform
> +
> +  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
> +  on your platform.
> +
> +  @param[out]   VirtualMemoryMap    Array of ARM_MEMORY_REGION_DESCRIPTOR
> +                                    describing a Physical-to-Virtual Memory
> +                                    mapping. This array must be ended by a
> +                                    zero-filled entry. The allocated memory
> +                                    will not be freed.
> +
> +**/
> +VOID
> +ArmVirtGetMemoryMap (
> +  OUT ARM_MEMORY_REGION_DESCRIPTOR   **VirtualMemoryMap
> +  )
> +{
> +  ARM_MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
> +  UINTN                          Idx = 0;
> +  EFI_PHYSICAL_ADDRESS           TopOfAddressSpace;
> +
> +  ASSERT (VirtualMemoryMap != NULL);
> +
> +  TopOfAddressSpace = LShiftU64 (1ULL, ArmGetPhysicalAddressBits ());
> +
> +  VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)
> +                        AllocatePages (
> +                          EFI_SIZE_TO_PAGES (
> +                            sizeof (ARM_MEMORY_REGION_DESCRIPTOR) *
> +                            MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
> +                            )
> +                          );
> +
> +  if (VirtualMemoryTable == NULL) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "%a: Error: Failed to Allocate Pages\n",
> +      __FUNCTION__
> +      ));
> +    return;
> +  }
> +
> +  // System DRAM
> +  VirtualMemoryTable[Idx].PhysicalBase = PcdGet64 (PcdSystemMemoryBase);
> +  VirtualMemoryTable[Idx].VirtualBase  = VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Length       = PcdGet64 (PcdSystemMemorySize);
> +  VirtualMemoryTable[Idx].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
> +  LOG_VM_MAP ("System DRAM Memory Map");
> +
> +  // Peripheral space before DRAM
> +  VirtualMemoryTable[++Idx].PhysicalBase = 0x0;
> +  VirtualMemoryTable[Idx].VirtualBase    = 0x0;
> +  VirtualMemoryTable[Idx].Length         = PcdGet64 (PcdSystemMemoryBase);
> +  VirtualMemoryTable[Idx].Attributes     = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
> +  LOG_VM_MAP ("Peripheral space before DRAM");
> +
> +  // Peripheral space after DRAM
> +  VirtualMemoryTable[++Idx].PhysicalBase = PcdGet64 (PcdSystemMemoryBase) +
> +                                           PcdGet64 (PcdSystemMemorySize);
> +  VirtualMemoryTable[Idx].VirtualBase    = VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Length         = TopOfAddressSpace -
> +                                           VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Attributes     = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
> +  LOG_VM_MAP ("Peripheral space after DRAM");
> +
> +  // Map the FV region as normal executable memory
> +  VirtualMemoryTable[++Idx].PhysicalBase = PcdGet64 (PcdFvBaseAddress);
> +  VirtualMemoryTable[Idx].VirtualBase  = VirtualMemoryTable[Idx].PhysicalBase;
> +  VirtualMemoryTable[Idx].Length       = FixedPcdGet32 (PcdFvSize);
> +  VirtualMemoryTable[Idx].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
> +  LOG_VM_MAP ("FV region");
> +
> +  // End of Table
> +  VirtualMemoryTable[++Idx].PhysicalBase  = 0;
> +  VirtualMemoryTable[Idx].VirtualBase     = 0;
> +  VirtualMemoryTable[Idx].Length          = 0;
> +  VirtualMemoryTable[Idx].Attributes      = (ARM_MEMORY_REGION_ATTRIBUTES)0;
> +
> +  ASSERT((Idx + 1) <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS);
> +
> +  *VirtualMemoryMap = VirtualMemoryTable;
> +}
> diff --git a/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..dbf4ceabe3ae0db5e743e1d9a575542dca32ed0a
> --- /dev/null
> +++ b/ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/KvmtoolVirtMemInfoLib.inf
> @@ -0,0 +1,42 @@
> +#/* @file
> +#
> +#  Copyright (c) 2018, ARM Limited. All rights reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#*/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = KvmtoolVirtMemInfoLib
> +  FILE_GUID                      = B752E953-394F-462C-811C-F8BE35C8C071
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = ArmVirtMemInfoLib
> +
> +[Sources]
> +  KvmtoolVirtMemInfoLib.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  ArmVirtPkg/ArmVirtPkg.dec
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +  PcdLib
> +
> +[Pcd]
> +  gArmTokenSpaceGuid.PcdFvBaseAddress
> +  gArmTokenSpaceGuid.PcdSystemMemoryBase
> +  gArmTokenSpaceGuid.PcdSystemMemorySize
> +
> +[FixedPcd]
> +  gArmTokenSpaceGuid.PcdFvSize
> +
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14 12:12     ` [edk2-devel] " Laszlo Ersek
@ 2020-05-14 12:17       ` Ard Biesheuvel
  2020-05-14 16:05         ` Laszlo Ersek
  2020-05-14 12:20       ` Laszlo Ersek
  1 sibling, 1 reply; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14 12:17 UTC (permalink / raw)
  To: Laszlo Ersek, devel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 2:12 PM, Laszlo Ersek wrote:
> On 05/14/20 11:29, Ard Biesheuvel wrote:
>> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>>> Kvmtool is a virtual machine manager that enables
>>> hosting KVM guests. It essentially provides an
>>> emulated platform for guest operating systems.
>>>
>>> Kvmtool hands of a device tree containing the
>>> current hardware configuration to the firmware.
>>>
>>> A standards-based operating system would use
>>> ACPI to consume the platform hardware
>>> information, while some operating systems may
>>> prefer to use Device Tree.
>>>
>>> The KvmtoolPlatformDxe performs the platform
>>> actions like determining if the firmware should
>>> expose ACPI or the Device Tree based hardware
>>> description to the operating system.
>>>
>>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>>> ---
>>>
>>> Notes:
>>>       v2:
>>>         - Updated according to review comments.                     [Sami]
>>>            v1:
>>>         - Add kvmtool platform driver to support loading platform   [Sami]
>>>           specific information.
>>>         - Keep code to initialise the variable storage PCDs in the
>>> [Laszlo]
>>>           platform-specific FVB driver.
>>>         - Document code derived from
>>> [Laszlo]
>>>           "ArmVirtPkg/PlatformHasAcpiDtDxe"
>>>           Ref: https://edk2.groups.io/g/devel/topic/30915278#30757
>>>
>>>    ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93
>>> ++++++++++++++++++++
>>>    ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
>>>    2 files changed, 140 insertions(+)
>>>
>>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>> new file mode 100644
>>> index
>>> 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
>>>
>>> --- /dev/null
>>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>> @@ -0,0 +1,93 @@
>>> +/** @file
>>> +
>>> +  The KvmtoolPlatformDxe performs the platform specific
>>> initialization like:
>>> +  - It decides if the firmware should expose ACPI or Device Tree-based
>>> +    hardware description to the operating system.
>>> +
>>> +  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>>> +
>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +
>>> +**/
>>> +
>>> +#include <Guid/VariableFormat.h>
>>> +#include <Library/BaseLib.h>
>>> +#include <Library/BaseMemoryLib.h>
>>> +#include <Library/DebugLib.h>
>>> +#include <Library/DxeServicesTableLib.h>
>>> +#include <Library/UefiBootServicesTableLib.h>
>>> +#include <Library/UefiDriverEntryPoint.h>
>>> +#include <Protocol/FdtClient.h>
>>> +
>>> +/** Decide if the firmware should expose ACPI tables or Device Tree and
>>> +    install the appropriate protocol interface.
>>> +
>>> +  Note: This function is derived from "ArmVirtPkg/PlatformHasAcpiDtDxe",
>>> +        by dropping the word size check, and the fw_cfg check.
>>> +
>>> +  @param [in]  ImageHandle  Handle for this image.
>>> +
>>> +  @retval EFI_SUCCESS             Success.
>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>> install the
>>> +                                  protocols.
>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>> +
>>> +**/
>>> +STATIC
>>> +EFI_STATUS
>>> +PlatformHasAcpiDt (
>>> +  IN EFI_HANDLE           ImageHandle
>>> +  )
>>> +{
>>> +  if (!PcdGetBool (PcdForceNoAcpi)) {
>>> +    // Expose ACPI tables
>>> +    return gBS->InstallProtocolInterface (
>>> +                  &ImageHandle,
>>> +                  &gEdkiiPlatformHasAcpiGuid,
>>> +                  EFI_NATIVE_INTERFACE,
>>> +                  NULL
>>> +                  );
>>> +  }
>>> +
>>> +  // Expose the Device Tree.
>>> +  return gBS->InstallProtocolInterface (
>>> +                &ImageHandle,
>>> +                &gEdkiiPlatformHasDeviceTreeGuid,
>>> +                EFI_NATIVE_INTERFACE,
>>> +                NULL
>>> +                );
>>> +}
>>> +
>>> +/** Entry point for Kvmtool Platform Dxe
>>> +
>>> +  @param [in]  ImageHandle  Handle for this image.
>>> +  @param [in]  SystemTable  Pointer to the EFI system table.
>>> +
>>> +  @retval EFI_SUCCESS             Success.
>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>> install the
>>> +                                  protocols.
>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>> +
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +KvmtoolPlatformDxeEntryPoint (
>>> +  IN EFI_HANDLE           ImageHandle,
>>> +  IN EFI_SYSTEM_TABLE     *SystemTable
>>> +  )
>>> +{
>>> +  EFI_STATUS                     Status;
>>> +
>>> +  Status = PlatformHasAcpiDt (ImageHandle);
>>> +  if (EFI_ERROR (Status)) {
>>> +    goto Failed;
>>> +  }
>>> +
>>> +  return Status;
>>> +
>>> +Failed:
>>> +  ASSERT_EFI_ERROR (Status);
>>> +  CpuDeadLoop ();
>>> +
>>> +  return Status;
>>> +}
>>
>> Please don't use CpuDeadLoop()s in your drivers.
>>
>> Installing a protocol on an image handle like this should not ever fail,
>> and if it does, it is unlikely to be an issue in the driver itself. So
>> just use ASSERT_EFI_ERROR() here, and return EFI_SUCCESS.
> 
> I think Sami just followed the original code in
> "ArmVirtPkg/PlatformHasAcpiDtDxe".
> 
> I'm fine either way:
> 
> Acked-by: Laszlo Ersek <lersek@redhat.com>
> 
> Different question:
> 
> Should we ask Sami to become a designated reviewer (in Maintainers.txt)
> for the kvmtool-specific modules under ArmVirtPkg? Personally I'm
> unlikely to use kvmtool.
> 

Not sure if you saw patch 11/11, but I agree that in general, but for 
ArmVirtPkg in particular as well, having package level maintainers is 
sufficient, and there is no need for maintainer roles beyond that.

But let's discuss this in reply to 11/11



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib
  2020-05-14  9:32   ` Ard Biesheuvel
@ 2020-05-14 12:17     ` Laszlo Ersek
  0 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:17 UTC (permalink / raw)
  To: devel, ard.biesheuvel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 05/14/20 11:32, Ard Biesheuvel wrote:
> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>> Kvmtool places the base address of the CFI flash in
>> the device tree it passes to UEFI. This library
>> parses the kvmtool device tree to read the CFI base
>> address and initialise the PCDs use by the NOR flash
>> driver and the variable storage.
>>
>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>> ---
>>   ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c      | 265
>> ++++++++++++++++++++
>>   ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf |  50 ++++
>>   2 files changed, 315 insertions(+)
>>
>> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..2e43c2e21bc9ef7dd1dd198eebbd70c3b0b96d1c
>>
>> --- /dev/null
>> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> @@ -0,0 +1,265 @@
>> +/** @file
>> +   An instance of the NorFlashPlatformLib for Kvmtool platform.
>> +
>> + Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> + **/
>> +
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/NorFlashPlatformLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Protocol/FdtClient.h>
>> +
>> +/** Macro defining the maximum number of Flash Banks.
>> + */
>> +#define MAX_FLASH_BANKS       4
>> +
>> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];
>> +STATIC UINTN                  mNorFlashDeviceCount = 0;
>> +
>> +/** This function performs platform specific actions to initialise
>> +    the NOR flash, if required.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +**/
>> +EFI_STATUS
>> +NorFlashPlatformInitialization (
>> +  VOID
>> +  )
>> +{
>> +  DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
>> +  // Nothing to do here
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/** Initialise Non volatile Flash storage variables.
>> +
>> +  @param [in]  FlashDevice Pointer to the NOR Flash device.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
>> +  @retval EFI_OUT_OF_RESOURCES  Insufficient flash storage space.
>> +**/
>> +EFI_STATUS
>> +SetupVariableStore (
>> +  IN NOR_FLASH_DESCRIPTION * FlashDevice
>> +  )
>> +{
>> +  UINTN   FlashRegion;
>> +  UINTN   FlashNvStorageVariableBase;
>> +  UINTN   FlashNvStorageFtwWorkingBase;
>> +  UINTN   FlashNvStorageFtwSpareBase;
>> +  UINTN   FlashNvStorageVariableSize;
>> +  UINTN   FlashNvStorageFtwWorkingSize;
>> +  UINTN   FlashNvStorageFtwSpareSize;
>> +
>> +  FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
>> +  FlashNvStorageFtwWorkingSize = PcdGet32
>> (PcdFlashNvStorageFtwWorkingSize);
>> +  FlashNvStorageFtwSpareSize =  PcdGet32
>> (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  if ((FlashNvStorageVariableSize == 0)   ||
>> +      (FlashNvStorageFtwWorkingSize == 0) ||
>> +      (FlashNvStorageFtwSpareSize == 0)) {
>> +    DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  // Setup the variable store
>> +  FlashRegion = FlashDevice->DeviceBaseAddress;
>> +
>> +  FlashNvStorageVariableBase = FlashRegion;
>> +  FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
>> +
>> +  FlashNvStorageFtwWorkingBase = FlashRegion;
>> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
>> +
>> +  FlashNvStorageFtwSpareBase = FlashRegion;
>> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  if (FlashRegion > (FlashDevice->DeviceBaseAddress +
>> FlashDevice->Size)) {
>> +    DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageVariableBase,
>> +    FlashNvStorageVariableBase
>> +    );
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageFtwWorkingBase,
>> +    FlashNvStorageFtwWorkingBase
>> +    );
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageFtwSpareBase,
>> +    FlashNvStorageFtwSpareBase
>> +    );
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageVariableBase = 0x%x\n",
>> +    FlashNvStorageVariableBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageVariableSize = 0x%x\n",
>> +    FlashNvStorageVariableSize
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
>> +    FlashNvStorageFtwWorkingBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
>> +    FlashNvStorageFtwWorkingSize
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
>> +    FlashNvStorageFtwSpareBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
>> +    FlashNvStorageFtwSpareSize
>> +    ));
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/** Return the Flash devices on the platform.
>> +
>> +  @param [out]  NorFlashDescriptions    Pointer to the Flash device
>> description.
>> +  @param [out]  Count                   Number of Flash devices.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +  @retval EFI_NOT_FOUND         Flash device not found.
>> +**/
>> +EFI_STATUS
>> +NorFlashPlatformGetDevices (
>> +  OUT NOR_FLASH_DESCRIPTION   **NorFlashDescriptions,
>> +  OUT UINT32                  *Count
>> +  )
>> +{
>> +  if (mNorFlashDeviceCount > 0) {
>> +    *NorFlashDescriptions = mNorFlashDevices;
>> +    *Count = mNorFlashDeviceCount;
>> +    return EFI_SUCCESS;
>> +  }
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> +/** Entrypoint for NorFlashPlatformLib.
>> +
>> +  @param [in]  ImageHandle  The handle to the image.
>> +  @param [in]  SystemTable  Pointer to the System Table.
>> +
>> +  @retval EFI_SUCCESS             Success.
>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>> +  @retval EFI_NOT_FOUND           Flash device not found.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NorFlashPlatformLibConstructor (
>> +  IN  EFI_HANDLE          ImageHandle,
>> +  IN  EFI_SYSTEM_TABLE  * SystemTable
>> +  )
>> +{
>> +  FDT_CLIENT_PROTOCOL         *FdtClient;
>> +  INT32                       Node;
>> +  EFI_STATUS                  Status;
>> +  EFI_STATUS                  FindNodeStatus;
>> +  CONST UINT32                *Reg;
>> +  UINT32                      PropSize;
>> +  UINT64                      Base;
>> +  UINT64                      Size;
>> +
>> +  if (mNorFlashDeviceCount != 0) {
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  Status = gBS->LocateProtocol (
>> +                  &gFdtClientProtocolGuid,
>> +                  NULL,
>> +                  (VOID **)&FdtClient
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    ASSERT_EFI_ERROR (Status);
>> +    return Status;
>> +  }
>> +
> 
> An ASSERT is sufficient here - the DEPEX ensures that this is guaranteed
> to succeed.

with that:

Acked-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo

> 
>> +  for (FindNodeStatus = FdtClient->FindCompatibleNode (
>> +                                     FdtClient,
>> +                                     "cfi-flash",
>> +                                     &Node
>> +                                     );
>> +       !EFI_ERROR (FindNodeStatus) && (mNorFlashDeviceCount <
>> MAX_FLASH_BANKS);
>> +       FindNodeStatus = FdtClient->FindNextCompatibleNode (
>> +                                     FdtClient,
>> +                                     "cfi-flash",
>> +                                     Node,
>> +                                     &Node
>> +    )) {
>> +    Status = FdtClient->GetNodeProperty (
>> +                          FdtClient,
>> +                          Node,
>> +                          "reg",
>> +                          (CONST VOID **)&Reg,
>> +                          &PropSize
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status ==
>> %r)\n",
>> +        __FUNCTION__, Status));
>> +      continue;
>> +    }
>> +
>> +    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
>> +
>> +    while ((PropSize >= (4 * sizeof (UINT32))) &&
>> +           (mNorFlashDeviceCount < MAX_FLASH_BANKS)) {
>> +      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
>> +      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
>> +      Reg += 4;
>> +
>> +      PropSize -= 4 * sizeof (UINT32);
>> +
>> +      //
>> +      // Disregard any flash devices that overlap with the primary FV.
>> +      // The firmware is not updatable from inside the guest anyway.
>> +      //
>> +      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
>> +          (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {
>> +        continue;
>> +      }
>> +
>> +      DEBUG ((
>> +        DEBUG_INFO,
>> +        "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
>> +        mNorFlashDeviceCount,
>> +        Base,
>> +        Size
>> +        ));
>> +
>> +      mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress =
>> (UINTN)Base;
>> +      mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress =
>> (UINTN)Base;
>> +      mNorFlashDevices[mNorFlashDeviceCount].Size              =
>> (UINTN)Size;
>> +      mNorFlashDevices[mNorFlashDeviceCount].BlockSize         =
>> SIZE_256KB;
>> +      mNorFlashDeviceCount++;
>> +    }
>> +  }
>> +
>> +  // Setup the variable store in the last bank
>> +  if ((mNorFlashDeviceCount > 0) &&
>> +      (mNorFlashDevices[mNorFlashDeviceCount - 1].DeviceBaseAddress
>> != 0)) {
>> +    return SetupVariableStore (&mNorFlashDevices[mNorFlashDeviceCount
>> - 1]);
>> +  }
>> +
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> diff --git
>> a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..8bd6f730dcb52e597b418e59766c1566a9519789
>>
>> --- /dev/null
>> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> @@ -0,0 +1,50 @@
>> +#/** @file
>> +#
>> +#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
>> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +#**/
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = NorFlashKvmtoolLib
>> +  FILE_GUID                      = E75F07A1-B160-4893-BDD4-09E32FF847DC
>> +  MODULE_TYPE                    = DXE_DRIVER
>> +  VERSION_STRING                 = 1.0
>> +  LIBRARY_CLASS                  = NorFlashPlatformLib
>> +  CONSTRUCTOR                    = NorFlashPlatformLibConstructor
>> +
>> +[Sources.common]
>> +  NorFlashKvmtool.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  ArmPlatformPkg/ArmPlatformPkg.dec
>> +  ArmVirtPkg/ArmVirtPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  DebugLib
>> +  PcdLib
>> +  UefiBootServicesTableLib
>> +
>> +[Protocols]
>> +  gFdtClientProtocolGuid          ## CONSUMES
>> +
>> +[Pcd]
>> +  gArmTokenSpaceGuid.PcdFvBaseAddress
>> +  gArmTokenSpaceGuid.PcdFvSize
>> +
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +
>> +[Depex]
>> +  gFdtClientProtocolGuid
>> +
>>
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14 12:12     ` [edk2-devel] " Laszlo Ersek
  2020-05-14 12:17       ` Ard Biesheuvel
@ 2020-05-14 12:20       ` Laszlo Ersek
  1 sibling, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:20 UTC (permalink / raw)
  To: devel, ard.biesheuvel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 05/14/20 14:12, Laszlo Ersek wrote:
> On 05/14/20 11:29, Ard Biesheuvel wrote:
>> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>>> Kvmtool is a virtual machine manager that enables
>>> hosting KVM guests. It essentially provides an
>>> emulated platform for guest operating systems.
>>>
>>> Kvmtool hands of a device tree containing the
>>> current hardware configuration to the firmware.
>>>
>>> A standards-based operating system would use
>>> ACPI to consume the platform hardware
>>> information, while some operating systems may
>>> prefer to use Device Tree.
>>>
>>> The KvmtoolPlatformDxe performs the platform
>>> actions like determining if the firmware should
>>> expose ACPI or the Device Tree based hardware
>>> description to the operating system.
>>>
>>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>>> ---
>>>
>>> Notes:
>>>      v2:
>>>        - Updated according to review comments.                     [Sami]
>>>           v1:
>>>        - Add kvmtool platform driver to support loading platform   [Sami]
>>>          specific information.
>>>        - Keep code to initialise the variable storage PCDs in the 
>>> [Laszlo]
>>>          platform-specific FVB driver.
>>>        - Document code derived from                               
>>> [Laszlo]
>>>          "ArmVirtPkg/PlatformHasAcpiDtDxe"
>>>          Ref: https://edk2.groups.io/g/devel/topic/30915278#30757
>>>
>>>   ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93
>>> ++++++++++++++++++++
>>>   ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
>>>   2 files changed, 140 insertions(+)
>>>
>>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>> new file mode 100644
>>> index
>>> 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
>>>
>>> --- /dev/null
>>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>> @@ -0,0 +1,93 @@
>>> +/** @file
>>> +
>>> +  The KvmtoolPlatformDxe performs the platform specific
>>> initialization like:
>>> +  - It decides if the firmware should expose ACPI or Device Tree-based
>>> +    hardware description to the operating system.
>>> +
>>> +  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>>> +
>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +
>>> +**/
>>> +
>>> +#include <Guid/VariableFormat.h>
>>> +#include <Library/BaseLib.h>
>>> +#include <Library/BaseMemoryLib.h>
>>> +#include <Library/DebugLib.h>
>>> +#include <Library/DxeServicesTableLib.h>
>>> +#include <Library/UefiBootServicesTableLib.h>
>>> +#include <Library/UefiDriverEntryPoint.h>
>>> +#include <Protocol/FdtClient.h>
>>> +
>>> +/** Decide if the firmware should expose ACPI tables or Device Tree and
>>> +    install the appropriate protocol interface.
>>> +
>>> +  Note: This function is derived from "ArmVirtPkg/PlatformHasAcpiDtDxe",
>>> +        by dropping the word size check, and the fw_cfg check.
>>> +
>>> +  @param [in]  ImageHandle  Handle for this image.
>>> +
>>> +  @retval EFI_SUCCESS             Success.
>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>> install the
>>> +                                  protocols.
>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>> +
>>> +**/
>>> +STATIC
>>> +EFI_STATUS
>>> +PlatformHasAcpiDt (
>>> +  IN EFI_HANDLE           ImageHandle
>>> +  )
>>> +{
>>> +  if (!PcdGetBool (PcdForceNoAcpi)) {
>>> +    // Expose ACPI tables
>>> +    return gBS->InstallProtocolInterface (
>>> +                  &ImageHandle,
>>> +                  &gEdkiiPlatformHasAcpiGuid,
>>> +                  EFI_NATIVE_INTERFACE,
>>> +                  NULL
>>> +                  );
>>> +  }
>>> +
>>> +  // Expose the Device Tree.
>>> +  return gBS->InstallProtocolInterface (
>>> +                &ImageHandle,
>>> +                &gEdkiiPlatformHasDeviceTreeGuid,
>>> +                EFI_NATIVE_INTERFACE,
>>> +                NULL
>>> +                );
>>> +}
>>> +
>>> +/** Entry point for Kvmtool Platform Dxe
>>> +
>>> +  @param [in]  ImageHandle  Handle for this image.
>>> +  @param [in]  SystemTable  Pointer to the EFI system table.
>>> +
>>> +  @retval EFI_SUCCESS             Success.
>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>> install the
>>> +                                  protocols.
>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>> +
>>> +**/
>>> +EFI_STATUS
>>> +EFIAPI
>>> +KvmtoolPlatformDxeEntryPoint (
>>> +  IN EFI_HANDLE           ImageHandle,
>>> +  IN EFI_SYSTEM_TABLE     *SystemTable
>>> +  )
>>> +{
>>> +  EFI_STATUS                     Status;
>>> +
>>> +  Status = PlatformHasAcpiDt (ImageHandle);
>>> +  if (EFI_ERROR (Status)) {
>>> +    goto Failed;
>>> +  }
>>> +
>>> +  return Status;
>>> +
>>> +Failed:
>>> +  ASSERT_EFI_ERROR (Status);
>>> +  CpuDeadLoop ();
>>> +
>>> +  return Status;
>>> +}
>>
>> Please don't use CpuDeadLoop()s in your drivers.
>>
>> Installing a protocol on an image handle like this should not ever fail,
>> and if it does, it is unlikely to be an issue in the driver itself. So
>> just use ASSERT_EFI_ERROR() here, and return EFI_SUCCESS.
> 
> I think Sami just followed the original code in
> "ArmVirtPkg/PlatformHasAcpiDtDxe".
> 
> I'm fine either way:
> 
> Acked-by: Laszlo Ersek <lersek@redhat.com>
> 
> Different question:
> 
> Should we ask Sami to become a designated reviewer (in Maintainers.txt)
> for the kvmtool-specific modules under ArmVirtPkg? Personally I'm
> unlikely to use kvmtool.

Apologies -- I now see that I had requested that under v1 (in October
2018... a long time ago), and I've also found the last patch now. (I
guess I thought of documenting the new modules in Maintainers.txt in the
same patches that added the new modules, but end-of-series is fine too.)

Thanks!
Laszlo

> 
> Thanks
> Laszlo
> 
>>
>>
>>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
>>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
>>> new file mode 100644
>>> index
>>> 0000000000000000000000000000000000000000..08a0fe5ce14469133479046385bdd48c22698639
>>>
>>> --- /dev/null
>>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf
>>> @@ -0,0 +1,47 @@
>>> +#/** @file
>>> +#
>>> +#  The KvmtoolPlatformDxe performs the platform specific
>>> initialization like:
>>> +#  - It decides if the firmware should expose ACPI or Device Tree-based
>>> +#    hardware description to the operating system.
>>> +#
>>> +#  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>>> +#
>>> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>>> +#
>>> +#**/
>>> +
>>> +[Defines]
>>> +  INF_VERSION                    = 0x0001001B
>>> +  BASE_NAME                      = KvmtoolPlatformDxe
>>> +  FILE_GUID                      = 7479CCCD-D721-442A-8C73-A72DBB886669
>>> +  MODULE_TYPE                    = DXE_DRIVER
>>> +  VERSION_STRING                 = 1.0
>>> +  ENTRY_POINT                    = KvmtoolPlatformDxeEntryPoint
>>> +
>>> +[Sources]
>>> +  KvmtoolPlatformDxe.c
>>> +
>>> +[Packages]
>>> +  ArmVirtPkg/ArmVirtPkg.dec
>>> +  EmbeddedPkg/EmbeddedPkg.dec
>>> +  MdePkg/MdePkg.dec
>>> +  MdeModulePkg/MdeModulePkg.dec
>>> +
>>> +[LibraryClasses]
>>> +  BaseLib
>>> +  BaseMemoryLib
>>> +  DebugLib
>>> +  DxeServicesTableLib
>>> +  MemoryAllocationLib
>>> +  UefiBootServicesTableLib
>>> +  UefiDriverEntryPoint
>>> +
>>> +[Guids]
>>> +  gEdkiiPlatformHasAcpiGuid       ## SOMETIMES_PRODUCES ## PROTOCOL
>>> +  gEdkiiPlatformHasDeviceTreeGuid ## SOMETIMES_PRODUCES ## PROTOCOL
>>> +
>>> +[Pcd]
>>> +  gArmVirtTokenSpaceGuid.PcdForceNoAcpi
>>> +
>>> +[Depex]
>>> +  TRUE
>>>
>>
>>
>> 
>>
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform
  2020-05-14  8:40 ` [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform Sami Mujawar
  2020-05-14  9:56   ` Ard Biesheuvel
@ 2020-05-14 12:24   ` Laszlo Ersek
  1 sibling, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:24 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

On 05/14/20 10:40, Sami Mujawar wrote:
> Kvmtool is a virtual machine manager that enables hosting
> KVM guests. Kvmtool emulates certain devices like serial
> port, RTC, etc. essentially providing an emulated platform.
> 
> This patch adds support for kvmtool emulated platform.
> 
> Following is a brief description of the firmware
> implementation choices:
> 
> - Serial Port: 16550 UART
>   On some platforms the 16550 UART is interfaced using
>   PCI. Therefore, the 16550 Serial port library is
>   dependent on the PCI library. The 16550 UART driver
>   checks the Device ID represented using the PCD
>   gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo
>   to determine if the UART is behind PCI.
>   If the Device ID is 0xFF then the serial 16550 UART
>   is not behind PCI. For such platforms a NULL
>   implementation of the PCI library has been provided
>   so that the serial output is available during the
>   early boot stages.
> 
>   On Kvmtool the Serial 16550 UART is not behind PCI,
>   and therefore makes use of PciLibNull library during
>   early boot stages. The DXE modules that make use of
>   PCI functionality explicitly include the library
>   BasePciLibPciExpress, so that the required PCI
>   functionality is available.
> 
>   The PcdSerialPciDeviceInfo is also set to 0xFF to
>   indicate that the Serial 16550 UART is not behind
>   PCI. The PCD PcdSerialUseMmio is also set to TRUE
>   to indicate MMIO accesses are required for the
>   UART registers.
> 
> - Dependency order for Flash
>   FaultTolerantWriteDxe makes use of PCDs (e.g.
>   PcdFlashNvStorageFtwSpareBase64 etc.), which in
>   case of kvmtool will be evaluated based on the CFI
>   flash base address read from the DT. These variables
>   are populated in the NorFlashPlatformLib loaded by
>   ArmVeNorFlashDxe.
> 
>   This results in a dependency issue with
>   FaultTolerantWriteDxe. To resolve this make the
>   NorFlashPlatformLib as a library dependency for
>   FaultTolerantWriteDxe.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
> 
> Notes:
>     v2:
>       - Updates to reflect review comments and support             [Sami]
>         for latest features emulated by kvmtool e.g. CFI.
>     
>     v1:
>       - Add support for Kvmtool emulated platform                  [Sami]
>       - Add more justification for platform and                    [Laszlo]
>         document platform maintainer.
>         Ref: https://edk2.groups.io/g/devel/topic/30915279#30693
> 
>  ArmVirtPkg/ArmVirtKvmTool.dsc | 408 ++++++++++++++++++++
>  ArmVirtPkg/ArmVirtKvmTool.fdf | 276 +++++++++++++
>  2 files changed, 684 insertions(+)

Acked-by: Laszlo Ersek <lersek@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 10/11] ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio
  2020-05-14  8:40 ` [PATCH v1 10/11] ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio Sami Mujawar
@ 2020-05-14 12:28   ` Laszlo Ersek
  0 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:28 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

On 05/14/20 10:40, Sami Mujawar wrote:
> NorFlashDxe must use aligned MMIO accesses to
> read data from flash as this is device memory.
> 
> The AlignedCopyMem() in NorFlashDxe was used to
> copy the flash data which prevented unaligned
> access to device memory. However, the compiler
> could optimize the code to generate pre/post
> indexed or LDP operations. This is a problem
> for guest/virtual firmware as the hypervisor
> code cannot get the syndrome information for
> the trapped accesses.
> 
> To address the such issues, BaseMemoryLibMmio
> library has been introduced to perform aligned
> MMIO accesses.
> 
> The NorFlashDxe has been updated to use
> CopyMem() instead of using AlignedCopyMem()
> and therefore the NorFlashDxe must be linked
> with BaseMemoryLibMmio.
> 
> This patch updates the workspace files to link
> NorFlashDxe with BaseMemoryLibMmio for the
> following platforms:
>   - Arm Qemu
>   - Arm Qemu Kernel
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  ArmVirtPkg/ArmVirtQemu.dsc       | 8 ++++++--
>  ArmVirtPkg/ArmVirtQemuKernel.dsc | 8 ++++++--
>  2 files changed, 12 insertions(+), 4 deletions(-)

Based on Ard's comment under "MdePkg: Base Memory Lib instance using
MMIO" ("I don't think we need this library"), this patch would be
unnecessary too.

(This applies to the
"BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf"
resolutions in the previous patch as well, apparently.)

Thanks
Laszlo

> 
> diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
> index 3f649c91d8d6a2e3f3e62f35aa40906e048a15c4..82b7d54c2031fed60dccff38353d3ec19cfdefd0 100644
> --- a/ArmVirtPkg/ArmVirtQemu.dsc
> +++ b/ArmVirtPkg/ArmVirtQemu.dsc
> @@ -1,5 +1,5 @@
>  #
> -#  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
> +#  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
>  #  Copyright (c) 2014, Linaro Limited. All rights reserved.
>  #  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
>  #
> @@ -384,7 +384,11 @@ [Components.common]
>      <LibraryClasses>
>        NULL|ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.inf
>    }
> -  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
> +  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf {
> +    <LibraryClasses>
> +      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> +  }
> +
>    MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
>  
>    #
> diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
> index 2a6fd6bc06be1cc20d8c6f2bf00d88d593061edf..6cceb61e493c8c84f6564b120b0864ff817c3f31 100644
> --- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
> +++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
> @@ -1,5 +1,5 @@
>  #
> -#  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
> +#  Copyright (c) 2011-2020, ARM Limited. All rights reserved.
>  #  Copyright (c) 2014, Linaro Limited. All rights reserved.
>  #  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
>  #
> @@ -323,7 +323,11 @@ [Components.common]
>      <LibraryClasses>
>        NULL|ArmVirtPkg/Library/ArmVirtTimerFdtClientLib/ArmVirtTimerFdtClientLib.inf
>    }
> -  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf
> +  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.inf {
> +    <LibraryClasses>
> +      BaseMemoryLib|MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> +  }
> +
>    MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
>  
>    #
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 11/11] Maintainer.txt: Add Kvmtool emulated plat maintainer
  2020-05-14  8:40 ` [PATCH v1 11/11] Maintainer.txt: Add Kvmtool emulated plat maintainer Sami Mujawar
@ 2020-05-14 12:31   ` Laszlo Ersek
  0 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 12:31 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, michael.d.kinney, Matteo.Carlini,
	Laura.Moretta, nd

On 05/14/20 10:40, Sami Mujawar wrote:
> Kvmtool is a virtual machine manager that can be used
> to launch guest partitions. It additionally emulates
> some hardware components e.g. RTC, CFI etc. essentially
> providing an emulated virtual platform for a guest
> operating system (OS) to run.
> 
> A standards-based OS would need UEFI firmware support
> for the Kvmtool emulated platform, for which additional
> modules are added to ArmVirtPkg.
> Adding myself as maintainer for these modules as
> advised on mailing list discussion at
> https://edk2.groups.io/g/devel/topic/30915279#30693
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  Maintainers.txt | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/Maintainers.txt b/Maintainers.txt
> index 896ac5821fc6602e25db79b9aa47e4c2329c530b..3006bc1ea2feb224f0f710831466c5a6a876e3ee 100644
> --- a/Maintainers.txt
> +++ b/Maintainers.txt
> @@ -152,6 +152,13 @@ F: ArmVirtPkg/XenPlatformHasAcpiDtDxe/
>  F: ArmVirtPkg/XenioFdtDxe/
>  R: Julien Grall <julien@xen.org>
>  
> +ArmVirtPkg: Kvmtool emulated platform support
> +F: ArmVirtPkg/ArmVirtKvmTool.*
> +F: ArmVirtPkg/KvmtoolPlatformDxe/
> +F: ArmVirtPkg/Library/KvmtoolVirtMemInfoLib/
> +F: ArmVirtPkg/Library/NorFlashKvmtoolLib/
> +M: Sami Mujawar <sami.mujawar@arm.com>
> +
>  BaseTools
>  F: BaseTools/
>  W: https://github.com/tianocore/tianocore.github.io/wiki/BaseTools
> 

Reviewed-by: Laszlo Ersek <lersek@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14 12:17       ` Ard Biesheuvel
@ 2020-05-14 16:05         ` Laszlo Ersek
  2020-05-14 17:25           ` Ard Biesheuvel
  0 siblings, 1 reply; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-14 16:05 UTC (permalink / raw)
  To: Ard Biesheuvel, devel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 05/14/20 14:17, Ard Biesheuvel wrote:
> On 5/14/20 2:12 PM, Laszlo Ersek wrote:
>> On 05/14/20 11:29, Ard Biesheuvel wrote:
>>> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>>>> Kvmtool is a virtual machine manager that enables
>>>> hosting KVM guests. It essentially provides an
>>>> emulated platform for guest operating systems.
>>>>
>>>> Kvmtool hands of a device tree containing the
>>>> current hardware configuration to the firmware.
>>>>
>>>> A standards-based operating system would use
>>>> ACPI to consume the platform hardware
>>>> information, while some operating systems may
>>>> prefer to use Device Tree.
>>>>
>>>> The KvmtoolPlatformDxe performs the platform
>>>> actions like determining if the firmware should
>>>> expose ACPI or the Device Tree based hardware
>>>> description to the operating system.
>>>>
>>>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>>>> ---
>>>>
>>>> Notes:
>>>>       v2:
>>>>         - Updated according to review comments.                    
>>>> [Sami]
>>>>            v1:
>>>>         - Add kvmtool platform driver to support loading platform  
>>>> [Sami]
>>>>           specific information.
>>>>         - Keep code to initialise the variable storage PCDs in the
>>>> [Laszlo]
>>>>           platform-specific FVB driver.
>>>>         - Document code derived from
>>>> [Laszlo]
>>>>           "ArmVirtPkg/PlatformHasAcpiDtDxe"
>>>>           Ref: https://edk2.groups.io/g/devel/topic/30915278#30757
>>>>
>>>>    ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93
>>>> ++++++++++++++++++++
>>>>    ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
>>>>    2 files changed, 140 insertions(+)
>>>>
>>>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>>> new file mode 100644
>>>> index
>>>> 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
>>>>
>>>>
>>>> --- /dev/null
>>>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>>> @@ -0,0 +1,93 @@
>>>> +/** @file
>>>> +
>>>> +  The KvmtoolPlatformDxe performs the platform specific
>>>> initialization like:
>>>> +  - It decides if the firmware should expose ACPI or Device Tree-based
>>>> +    hardware description to the operating system.
>>>> +
>>>> +  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>>>> +
>>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>> +
>>>> +**/
>>>> +
>>>> +#include <Guid/VariableFormat.h>
>>>> +#include <Library/BaseLib.h>
>>>> +#include <Library/BaseMemoryLib.h>
>>>> +#include <Library/DebugLib.h>
>>>> +#include <Library/DxeServicesTableLib.h>
>>>> +#include <Library/UefiBootServicesTableLib.h>
>>>> +#include <Library/UefiDriverEntryPoint.h>
>>>> +#include <Protocol/FdtClient.h>
>>>> +
>>>> +/** Decide if the firmware should expose ACPI tables or Device Tree
>>>> and
>>>> +    install the appropriate protocol interface.
>>>> +
>>>> +  Note: This function is derived from
>>>> "ArmVirtPkg/PlatformHasAcpiDtDxe",
>>>> +        by dropping the word size check, and the fw_cfg check.
>>>> +
>>>> +  @param [in]  ImageHandle  Handle for this image.
>>>> +
>>>> +  @retval EFI_SUCCESS             Success.
>>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>>> install the
>>>> +                                  protocols.
>>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>>> +
>>>> +**/
>>>> +STATIC
>>>> +EFI_STATUS
>>>> +PlatformHasAcpiDt (
>>>> +  IN EFI_HANDLE           ImageHandle
>>>> +  )
>>>> +{
>>>> +  if (!PcdGetBool (PcdForceNoAcpi)) {
>>>> +    // Expose ACPI tables
>>>> +    return gBS->InstallProtocolInterface (
>>>> +                  &ImageHandle,
>>>> +                  &gEdkiiPlatformHasAcpiGuid,
>>>> +                  EFI_NATIVE_INTERFACE,
>>>> +                  NULL
>>>> +                  );
>>>> +  }
>>>> +
>>>> +  // Expose the Device Tree.
>>>> +  return gBS->InstallProtocolInterface (
>>>> +                &ImageHandle,
>>>> +                &gEdkiiPlatformHasDeviceTreeGuid,
>>>> +                EFI_NATIVE_INTERFACE,
>>>> +                NULL
>>>> +                );
>>>> +}
>>>> +
>>>> +/** Entry point for Kvmtool Platform Dxe
>>>> +
>>>> +  @param [in]  ImageHandle  Handle for this image.
>>>> +  @param [in]  SystemTable  Pointer to the EFI system table.
>>>> +
>>>> +  @retval EFI_SUCCESS             Success.
>>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>>> install the
>>>> +                                  protocols.
>>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>>> +
>>>> +**/
>>>> +EFI_STATUS
>>>> +EFIAPI
>>>> +KvmtoolPlatformDxeEntryPoint (
>>>> +  IN EFI_HANDLE           ImageHandle,
>>>> +  IN EFI_SYSTEM_TABLE     *SystemTable
>>>> +  )
>>>> +{
>>>> +  EFI_STATUS                     Status;
>>>> +
>>>> +  Status = PlatformHasAcpiDt (ImageHandle);
>>>> +  if (EFI_ERROR (Status)) {
>>>> +    goto Failed;
>>>> +  }
>>>> +
>>>> +  return Status;
>>>> +
>>>> +Failed:
>>>> +  ASSERT_EFI_ERROR (Status);
>>>> +  CpuDeadLoop ();
>>>> +
>>>> +  return Status;
>>>> +}
>>>
>>> Please don't use CpuDeadLoop()s in your drivers.
>>>
>>> Installing a protocol on an image handle like this should not ever fail,
>>> and if it does, it is unlikely to be an issue in the driver itself. So
>>> just use ASSERT_EFI_ERROR() here, and return EFI_SUCCESS.
>>
>> I think Sami just followed the original code in
>> "ArmVirtPkg/PlatformHasAcpiDtDxe".
>>
>> I'm fine either way:
>>
>> Acked-by: Laszlo Ersek <lersek@redhat.com>
>>
>> Different question:
>>
>> Should we ask Sami to become a designated reviewer (in Maintainers.txt)
>> for the kvmtool-specific modules under ArmVirtPkg? Personally I'm
>> unlikely to use kvmtool.
>>
> 
> Not sure if you saw patch 11/11, but I agree that in general, but for
> ArmVirtPkg in particular as well, having package level maintainers is
> sufficient, and there is no need for maintainer roles beyond that.

OK -- If you think patch#11 is unnecessary, I won't insist; I'd just
like to avoid the expectation for me to deeply review or regression-test
kvmtool stuff.

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib
  2020-05-14  8:40 ` [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib Sami Mujawar
  2020-05-14  9:23   ` Ard Biesheuvel
@ 2020-05-14 16:21   ` Michael D Kinney
  1 sibling, 0 replies; 40+ messages in thread
From: Michael D Kinney @ 2020-05-14 16:21 UTC (permalink / raw)
  To: Sami Mujawar, devel@edk2.groups.io, Kinney, Michael D
  Cc: ard.biesheuvel@arm.com, leif@nuviainc.com, Gao, Liming,
	Alexandru.Elisei@arm.com, Andre.Przywara@arm.com,
	Matteo.Carlini@arm.com, Laura.Moretta@arm.com, nd@arm.com

Sami,

Can the combination of BasePciLibPciExpress and BasePciExpressLib
be used for this use case?

Mike

> -----Original Message-----
> From: Sami Mujawar <sami.mujawar@arm.com>
> Sent: Thursday, May 14, 2020 1:40 AM
> To: devel@edk2.groups.io
> Cc: Sami Mujawar <sami.mujawar@arm.com>;
> ard.biesheuvel@arm.com; leif@nuviainc.com; Kinney,
> Michael D <michael.d.kinney@intel.com>; Gao, Liming
> <liming.gao@intel.com>; Alexandru.Elisei@arm.com;
> Andre.Przywara@arm.com; Matteo.Carlini@arm.com;
> Laura.Moretta@arm.com; nd@arm.com
> Subject: [PATCH v1 02/11] MdePkg: Add NULL
> implementation for PCILib
> 
> On some platforms the Serial 16550 UART is interfaced
> over PCI. To support such platforms the Serial 16550
> driver links with PciLib.
> 
> For platforms that do not interface the Serial 16550
> UART over PCI, the driver still needs to link with a
> PciLib library. Linking to the full implementation of
> the PCI library may not be possible during the early
> firmware boot stage.
> 
> To facilitate early firmware logs over the serial port
> this patch introduces a NULL PCI library
> implementation.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  MdePkg/Library/PciLibNull/PciLibNull.c   | 1213
> ++++++++++++++++++++
>  MdePkg/Library/PciLibNull/PciLibNull.inf |   25 +
>  2 files changed, 1238 insertions(+)
> 
> diff --git a/MdePkg/Library/PciLibNull/PciLibNull.c
> b/MdePkg/Library/PciLibNull/PciLibNull.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..c186ca9f86e5a
> 0c860472b80209aae9b958a95d7
> --- /dev/null
> +++ b/MdePkg/Library/PciLibNull/PciLibNull.c
> @@ -0,0 +1,1213 @@
> +/** @file
> +  Provides a NULL implementation of PCI services used
> to access
> +  PCI Configuration Space.
> +
> +  Copyright (c) 2019 - 2020, ARM Limited. All rights
> reserved.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Base.h>
> +#include <Library/DebugLib.h>
> +
> +/**
> +  Registers a PCI device so PCI configuration
> registers may be accessed after
> +  SetVirtualAddressMap().
> +
> +  Registers the PCI device specified by Address so all
> the PCI configuration
> +  registers associated with that PCI device may be
> accessed after
> +  SetVirtualAddressMap() is called.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +
> +  @retval RETURN_SUCCESS           The PCI device was
> registered for runtime
> +                                   access.
> +  @retval RETURN_UNSUPPORTED       An attempt was made
> to call this function
> +                                   after
> ExitBootServices().
> +  @retval RETURN_UNSUPPORTED       The resources
> required to access the PCI
> +                                   device at runtime
> could not be mapped.
> +  @retval RETURN_OUT_OF_RESOURCES  There are not
> enough resources available to
> +                                   complete the
> registration.
> +
> +**/
> +RETURN_STATUS
> +EFIAPI
> +PciRegisterForRuntimeAccess (
> +  IN UINTN  Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return RETURN_UNSUPPORTED;
> +}
> +
> +/**
> +  Reads an 8-bit PCI configuration register.
> +
> +  Reads and returns the 8-bit PCI configuration
> register specified by Address.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +
> +  @return The read value from the PCI configuration
> register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciRead8 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes an 8-bit PCI configuration register.
> +
> +  Writes the 8-bit PCI configuration register
> specified by Address with the
> +  value specified by Value. Value is returned. This
> function must guarantee
> +  that all PCI read and write operations are
> serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  Value   The value to write.
> +
> +  @return The value written to the PCI configuration
> register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciWrite8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise OR of an 8-bit PCI configuration
> register with
> +  an 8-bit value.
> +
> +  Reads the 8-bit PCI configuration register specified
> by Address, performs a
> +  bitwise OR between the read result and the value
> specified by
> +  OrData, and writes the result to the 8-bit PCI
> configuration register
> +  specified by Address. The value written to the PCI
> configuration register is
> +  returned. This function must guarantee that all PCI
> read and write operations
> +  are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of an 8-bit PCI configuration
> register with an 8-bit
> +  value.
> +
> +  Reads the 8-bit PCI configuration register specified
> by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData, and
> +  writes the result to the 8-bit PCI configuration
> register specified by
> +  Address. The value written to the PCI configuration
> register is returned.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciAnd8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of an 8-bit PCI configuration
> register with an 8-bit
> +  value, followed by a bitwise OR with another 8-bit
> value.
> +
> +  Reads the 8-bit PCI configuration register specified
> by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData,
> +  performs a bitwise OR between the result of the AND
> operation and
> +  the value specified by OrData, and writes the result
> to the 8-bit PCI
> +  configuration register specified by Address. The
> value written to the PCI
> +  configuration register is returned. This function
> must guarantee that all PCI
> +  read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI
> configuration register.
> +  @param  OrData  The value to OR with the result of
> the AND operation.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciAndThenOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINT8                     AndData,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in an 8-bit PCI configuration
> register. The bit field is
> +  specified by the StartBit and the EndBit. The value
> of the bit field is
> +  returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> read.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..7.
> +
> +  @return The value of the bit field read from the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldRead8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI
> configuration register. The bit
> +  field is specified by the StartBit and the EndBit.
> All other bits in the
> +  destination PCI configuration register are
> preserved. The new value of the
> +  8-bit register is returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldWrite8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit PCI configuration,
> performs a bitwise OR, and
> +  writes the result back to the bit field in the 8-bit
> port.
> +
> +  Reads the 8-bit PCI configuration register specified
> by Address, performs a
> +  bitwise OR between the read result and the value
> specified by
> +  OrData, and writes the result to the 8-bit PCI
> configuration register
> +  specified by Address. The value written to the PCI
> configuration register is
> +  returned. This function must guarantee that all PCI
> read and write operations
> +  are serialized. Extra left bits in OrData are
> stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  OrData    The value to OR with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit PCI configuration
> register, performs a bitwise
> +  AND, and writes the result back to the bit field in
> the 8-bit register.
> +
> +  Reads the 8-bit PCI configuration register specified
> by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData, and
> +  writes the result to the 8-bit PCI configuration
> register specified by
> +  Address. The value written to the PCI configuration
> register is returned.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  AndData   The value to AND with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldAnd8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in an 8-bit port, performs a
> bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit
> field in the
> +  8-bit port.
> +
> +  Reads the 8-bit PCI configuration register specified
> by Address, performs a
> +  bitwise AND followed by a bitwise OR between the
> read result and
> +  the value specified by AndData, and writes the
> result to the 8-bit PCI
> +  configuration register specified by Address. The
> value written to the PCI
> +  configuration register is returned. This function
> must guarantee that all PCI
> +  read and write operations are serialized. Extra left
> bits in both AndData and
> +  OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If StartBit is greater than 7, then ASSERT().
> +  If EndBit is greater than 7, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..7.
> +  @param  AndData   The value to AND with the PCI
> configuration register.
> +  @param  OrData    The value to OR with the result of
> the AND operation.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT8
> +EFIAPI
> +PciBitFieldAndThenOr8 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT8                     AndData,
> +  IN      UINT8                     OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a 16-bit PCI configuration register.
> +
> +  Reads and returns the 16-bit PCI configuration
> register specified by Address.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +
> +  @return The read value from the PCI configuration
> register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciRead16 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a 16-bit PCI configuration register.
> +
> +  Writes the 16-bit PCI configuration register
> specified by Address with the
> +  value specified by Value. Value is returned. This
> function must guarantee
> +  that all PCI read and write operations are
> serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  Value   The value to write.
> +
> +  @return The value written to the PCI configuration
> register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciWrite16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise OR of a 16-bit PCI configuration
> register with
> +  a 16-bit value.
> +
> +  Reads the 16-bit PCI configuration register
> specified by Address, performs a
> +  bitwise OR between the read result and the value
> specified by
> +  OrData, and writes the result to the 16-bit PCI
> configuration register
> +  specified by Address. The value written to the PCI
> configuration register is
> +  returned. This function must guarantee that all PCI
> read and write operations
> +  are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 16-bit PCI configuration
> register with a 16-bit
> +  value.
> +
> +  Reads the 16-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData, and
> +  writes the result to the 16-bit PCI configuration
> register specified by
> +  Address. The value written to the PCI configuration
> register is returned.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciAnd16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 16-bit PCI configuration
> register with a 16-bit
> +  value, followed a  bitwise OR with another 16-bit
> value.
> +
> +  Reads the 16-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData,
> +  performs a bitwise OR between the result of the AND
> operation and
> +  the value specified by OrData, and writes the result
> to the 16-bit PCI
> +  configuration register specified by Address. The
> value written to the PCI
> +  configuration register is returned. This function
> must guarantee that all PCI
> +  read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI
> configuration register.
> +  @param  OrData  The value to OR with the result of
> the AND operation.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciAndThenOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINT16                    AndData,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in a 16-bit PCI configuration
> register. The bit field is
> +  specified by the StartBit and the EndBit. The value
> of the bit field is
> +  returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> read.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..15.
> +
> +  @return The value of the bit field read from the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldRead16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI
> configuration register. The bit
> +  field is specified by the StartBit and the EndBit.
> All other bits in the
> +  destination PCI configuration register are
> preserved. The new value of the
> +  16-bit register is returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldWrite16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit PCI configuration,
> performs a bitwise OR, and
> +  writes the result back to the bit field in the 16-
> bit port.
> +
> +  Reads the 16-bit PCI configuration register
> specified by Address, performs a
> +  bitwise OR between the read result and the value
> specified by
> +  OrData, and writes the result to the 16-bit PCI
> configuration register
> +  specified by Address. The value written to the PCI
> configuration register is
> +  returned. This function must guarantee that all PCI
> read and write operations
> +  are serialized. Extra left bits in OrData are
> stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  OrData    The value to OR with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit PCI configuration
> register, performs a bitwise
> +  AND, and writes the result back to the bit field in
> the 16-bit register.
> +
> +  Reads the 16-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData, and
> +  writes the result to the 16-bit PCI configuration
> register specified by
> +  Address. The value written to the PCI configuration
> register is returned.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  AndData   The value to AND with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldAnd16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 16-bit port, performs a
> bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit
> field in the
> +  16-bit port.
> +
> +  Reads the 16-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the
> read result and
> +  the value specified by AndData, and writes the
> result to the 16-bit PCI
> +  configuration register specified by Address. The
> value written to the PCI
> +  configuration register is returned. This function
> must guarantee that all PCI
> +  read and write operations are serialized. Extra left
> bits in both AndData and
> +  OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 15, then ASSERT().
> +  If EndBit is greater than 15, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..15.
> +  @param  AndData   The value to AND with the PCI
> configuration register.
> +  @param  OrData    The value to OR with the result of
> the AND operation.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT16
> +EFIAPI
> +PciBitFieldAndThenOr16 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT16                    AndData,
> +  IN      UINT16                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a 32-bit PCI configuration register.
> +
> +  Reads and returns the 32-bit PCI configuration
> register specified by Address.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +
> +  @return The read value from the PCI configuration
> register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciRead32 (
> +  IN      UINTN                     Address
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a 32-bit PCI configuration register.
> +
> +  Writes the 32-bit PCI configuration register
> specified by Address with the
> +  value specified by Value. Value is returned. This
> function must guarantee
> +  that all PCI read and write operations are
> serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  Value   The value to write.
> +
> +  @return The value written to the PCI configuration
> register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciWrite32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise OR of a 32-bit PCI configuration
> register with
> +  a 32-bit value.
> +
> +  Reads the 32-bit PCI configuration register
> specified by Address, performs a
> +  bitwise OR between the read result and the value
> specified by
> +  OrData, and writes the result to the 32-bit PCI
> configuration register
> +  specified by Address. The value written to the PCI
> configuration register is
> +  returned. This function must guarantee that all PCI
> read and write operations
> +  are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  OrData  The value to OR with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 32-bit PCI configuration
> register with a 32-bit
> +  value.
> +
> +  Reads the 32-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData, and
> +  writes the result to the 32-bit PCI configuration
> register specified by
> +  Address. The value written to the PCI configuration
> register is returned.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciAnd32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Performs a bitwise AND of a 32-bit PCI configuration
> register with a 32-bit
> +  value, followed a  bitwise OR with another 32-bit
> value.
> +
> +  Reads the 32-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData,
> +  performs a bitwise OR between the result of the AND
> operation and
> +  the value specified by OrData, and writes the result
> to the 32-bit PCI
> +  configuration register specified by Address. The
> value written to the PCI
> +  configuration register is returned. This function
> must guarantee that all PCI
> +  read and write operations are serialized.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +
> +  @param  Address Address that encodes the PCI Bus,
> Device, Function and
> +                  Register.
> +  @param  AndData The value to AND with the PCI
> configuration register.
> +  @param  OrData  The value to OR with the result of
> the AND operation.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciAndThenOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINT32                    AndData,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field of a PCI configuration register.
> +
> +  Reads the bit field in a 32-bit PCI configuration
> register. The bit field is
> +  specified by the StartBit and the EndBit. The value
> of the bit field is
> +  returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> read.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..31.
> +
> +  @return The value of the bit field read from the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldRead32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Writes a bit field to a PCI configuration register.
> +
> +  Writes Value to the bit field of the PCI
> configuration register. The bit
> +  field is specified by the StartBit and the EndBit.
> All other bits in the
> +  destination PCI configuration register are
> preserved. The new value of the
> +  32-bit register is returned.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If Value is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  Value     New value of the bit field.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldWrite32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    Value
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit PCI configuration,
> performs a bitwise OR, and
> +  writes the result back to the bit field in the 32-
> bit port.
> +
> +  Reads the 32-bit PCI configuration register
> specified by Address, performs a
> +  bitwise OR between the read result and the value
> specified by
> +  OrData, and writes the result to the 32-bit PCI
> configuration register
> +  specified by Address. The value written to the PCI
> configuration register is
> +  returned. This function must guarantee that all PCI
> read and write operations
> +  are serialized. Extra left bits in OrData are
> stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If OrData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  OrData    The value to OR with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit PCI configuration
> register, performs a bitwise
> +  AND, and writes the result back to the bit field in
> the 32-bit register.
> +
> +  Reads the 32-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND between the read result and the value
> specified by AndData, and
> +  writes the result to the 32-bit PCI configuration
> register specified by
> +  Address. The value written to the PCI configuration
> register is returned.
> +  This function must guarantee that all PCI read and
> write operations are
> +  serialized. Extra left bits in AndData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  AndData   The value to AND with the PCI
> configuration register.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldAnd32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    AndData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a bit field in a 32-bit port, performs a
> bitwise AND followed by a
> +  bitwise OR, and writes the result back to the bit
> field in the
> +  32-bit port.
> +
> +  Reads the 32-bit PCI configuration register
> specified by Address, performs a
> +  bitwise AND followed by a bitwise OR between the
> read result and
> +  the value specified by AndData, and writes the
> result to the 32-bit PCI
> +  configuration register specified by Address. The
> value written to the PCI
> +  configuration register is returned. This function
> must guarantee that all PCI
> +  read and write operations are serialized. Extra left
> bits in both AndData and
> +  OrData are stripped.
> +
> +  If Address > 0x0FFFFFFF, then ASSERT().
> +  If Address is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If StartBit is greater than 31, then ASSERT().
> +  If EndBit is greater than 31, then ASSERT().
> +  If EndBit is less than StartBit, then ASSERT().
> +  If AndData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +  If OrData is larger than the bitmask value range
> specified by
> +    StartBit and EndBit, then ASSERT().
> +
> +  @param  Address   PCI configuration register to
> write.
> +  @param  StartBit  The ordinal of the least
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  EndBit    The ordinal of the most
> significant bit in the bit field.
> +                    Range 0..31.
> +  @param  AndData   The value to AND with the PCI
> configuration register.
> +  @param  OrData    The value to OR with the result of
> the AND operation.
> +
> +  @return The value written back to the PCI
> configuration register.
> +
> +**/
> +UINT32
> +EFIAPI
> +PciBitFieldAndThenOr32 (
> +  IN      UINTN                     Address,
> +  IN      UINTN                     StartBit,
> +  IN      UINTN                     EndBit,
> +  IN      UINT32                    AndData,
> +  IN      UINT32                    OrData
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Reads a range of PCI configuration registers into a
> caller supplied buffer.
> +
> +  Reads the range of PCI configuration registers
> specified by StartAddress and
> +  Size into the buffer specified by Buffer. This
> function only allows the PCI
> +  configuration registers from a single PCI function
> to be read. Size is
> +  returned. When possible 32-bit PCI configuration
> read cycles are used to read
> +  from StartAdress to StartAddress + Size. Due to
> alignment restrictions, 8-bit
> +  and 16-bit PCI configuration read cycles may be used
> at the beginning and the
> +  end of the range.
> +
> +  If StartAddress > 0x0FFFFFFF, then ASSERT().
> +  If ((StartAddress & 0xFFF) + Size) > 0x1000, then
> ASSERT().
> +  If Size > 0 and Buffer is NULL, then ASSERT().
> +
> +  @param  StartAddress  Starting address that encodes
> the PCI Bus, Device,
> +                        Function and Register.
> +  @param  Size          Size in bytes of the transfer.
> +  @param  Buffer        Pointer to a buffer receiving
> the data read.
> +
> +  @return Size
> +
> +**/
> +UINTN
> +EFIAPI
> +PciReadBuffer (
> +  IN      UINTN                     StartAddress,
> +  IN      UINTN                     Size,
> +  OUT     VOID                      *Buffer
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> +
> +/**
> +  Copies the data in a caller supplied buffer to a
> specified range of PCI
> +  configuration space.
> +
> +  Writes the range of PCI configuration registers
> specified by StartAddress and
> +  Size from the buffer specified by Buffer. This
> function only allows the PCI
> +  configuration registers from a single PCI function
> to be written. Size is
> +  returned. When possible 32-bit PCI configuration
> write cycles are used to
> +  write from StartAdress to StartAddress + Size. Due
> to alignment restrictions,
> +  8-bit and 16-bit PCI configuration write cycles may
> be used at the beginning
> +  and the end of the range.
> +
> +  If StartAddress > 0x0FFFFFFF, then ASSERT().
> +  If ((StartAddress & 0xFFF) + Size) > 0x1000, then
> ASSERT().
> +  If Size > 0 and Buffer is NULL, then ASSERT().
> +
> +  @param  StartAddress  Starting address that encodes
> the PCI Bus, Device,
> +                        Function and Register.
> +  @param  Size          Size in bytes of the transfer.
> +  @param  Buffer        Pointer to a buffer containing
> the data to write.
> +
> +  @return Size written to StartAddress.
> +
> +**/
> +UINTN
> +EFIAPI
> +PciWriteBuffer (
> +  IN      UINTN                     StartAddress,
> +  IN      UINTN                     Size,
> +  IN      VOID                      *Buffer
> +  )
> +{
> +  DEBUG ((DEBUG_ERROR, "ERROR: Function %a is not
> implemented\n", __func__));
> +  ASSERT (FALSE);
> +  return 0;
> +}
> diff --git a/MdePkg/Library/PciLibNull/PciLibNull.inf
> b/MdePkg/Library/PciLibNull/PciLibNull.inf
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..1778b4025e550
> 939a6d13c5cc466567ce99ebaa5
> --- /dev/null
> +++ b/MdePkg/Library/PciLibNull/PciLibNull.inf
> @@ -0,0 +1,25 @@
> +#/** @file
> +#
> +#  Null implementation of Pcilib
> +#
> +#  Copyright (c) 2019, ARM Limited. All rights
> reserved.
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = PciLibNull
> +  FILE_GUID                      = C2E95ECC-9A39-4293-
> 9F52-4C82BA370952
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PciLib
> +
> +
> +[Sources]
> +  PciLibNull.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> --
> 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO
  2020-05-14  8:40 ` [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO Sami Mujawar
  2020-05-14  9:22   ` Ard Biesheuvel
@ 2020-05-14 16:33   ` Michael D Kinney
  1 sibling, 0 replies; 40+ messages in thread
From: Michael D Kinney @ 2020-05-14 16:33 UTC (permalink / raw)
  To: devel@edk2.groups.io, sami.mujawar@arm.com, Kinney, Michael D
  Cc: ard.biesheuvel@arm.com, leif@nuviainc.com, Gao, Liming,
	Alexandru.Elisei@arm.com, Andre.Przywara@arm.com,
	Matteo.Carlini@arm.com, Laura.Moretta@arm.com, nd@arm.com

Sami,

This does not seem right to me.

BaseMemoryLib is for memory operations.

IoLib for I/O port and MMIO operations.

The IoLib already supports aligned buffer read/write
APIs for MMIO.  Why can’t the exiting IoLib APIs be
used for this use case.

  MmioReadBuffer8()
  MmioReadBuffer16()
  MmioReadBuffer32()
  MmioReadBuffer64()
  MmioWriteBuffer8()
  MmioWriteBuffer16()
  MmioWriteBuffer32()
  MmioWriteBuffer64()

By using MMIO from a BaseMemoryLib instance, a platform
that uses this instance may get unexpected caching behavior
because MMIO is typically uncached and the expectation is
that BaseMemoryLib uses the caching attributes of the range.
Reduced performance may also be see if use of uncached 
operations was not expected.

Mike

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On
> Behalf Of Sami Mujawar
> Sent: Thursday, May 14, 2020 1:40 AM
> To: devel@edk2.groups.io
> Cc: Sami Mujawar <sami.mujawar@arm.com>;
> ard.biesheuvel@arm.com; leif@nuviainc.com; Kinney,
> Michael D <michael.d.kinney@intel.com>; Gao, Liming
> <liming.gao@intel.com>; Alexandru.Elisei@arm.com;
> Andre.Przywara@arm.com; Matteo.Carlini@arm.com;
> Laura.Moretta@arm.com; nd@arm.com
> Subject: [edk2-devel] [PATCH v1 03/11] MdePkg: Base
> Memory Lib instance using MMIO
> 
> Some device drivers perform copy operations on
> device memory, e.g. device drivers for a Flash
> device. On some architectures unaligned access
> to device memory regions is not permitted. To
> add to this if the device is virtualised then
> there are further restrictions on the type of
> load/store operations that can be performed
> on the device memory regions, e.g. on AARCH64,
> Pre/Post index or LDP operations cannot be
> used, as a trap to EL2 does not provide the
> syndrome information to the hypervisor.
> 
> To address these issues this patch introduces
> BaseMemoryLibMmio library which provides an
> implementation of Base memory library that
> uses aligned MMIO accesses.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.inf
> |  50 ++++
>  MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.uni
> |  15 +
>  MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
> |  62 ++++
>  MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
> | 149 ++++++++++
>  MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
> |  59 ++++
>  MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.c
> |  50 ++++
>  MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
> | 304 ++++++++++++++++++++
>  MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
> | 143 +++++++++
>  MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
> | 248 ++++++++++++++++
>  MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
> |  63 ++++
>  MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
> |  62 ++++
>  MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
> |  63 ++++
>  MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
> |  95 ++++++
>  MdePkg/Library/BaseMemoryLibMmio/SetMem.c
> |  83 ++++++
>  MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
> |  60 ++++
>  MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
> |  60 ++++
>  MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
> |  60 ++++
>  MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
> |  87 ++++++
>  MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
> |  52 ++++
>  19 files changed, 1765 insertions(+)
> 
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.in
> f
> b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.in
> f
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..3a61cb985a242
> a4ce7a2446c4efb9b78fb1d7b5d
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.in
> f
> @@ -0,0 +1,50 @@
> +## @file
> +#  Instance of Base Memory Library using Mmio
> operations.
> +#
> +#
> +#  Copyright (c) 2020, ARM Limited. All rights
> reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = BaseMemoryLibMmio
> +  MODULE_UNI_FILE                =
> BaseMemoryLibMmio.uni
> +  FILE_GUID                      = 5724063D-9855-4B3A-
> 8DEE-1F80ED07E096
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = BaseMemoryLib
> +
> +#
> +#  VALID_ARCHITECTURES           = ARM AARCH64
> +#
> +
> +[Sources]
> +  SetMem.c
> +  ScanMem64Wrapper.c
> +  ScanMem32Wrapper.c
> +  ScanMem16Wrapper.c
> +  ScanMem8Wrapper.c
> +  ZeroMemWrapper.c
> +  CompareMemWrapper.c
> +  SetMem64Wrapper.c
> +  SetMem32Wrapper.c
> +  SetMem16Wrapper.c
> +  SetMemWrapper.c
> +  CopyMemWrapper.c
> +  IsZeroBufferWrapper.c
> +  MemLibGeneric.c
> +  MemLibGuid.c
> +  CopyMem.c
> +  MemLibInternals.h
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  DebugLib
> +  BaseLib
> +  IoLib
> +
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.un
> i
> b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.un
> i
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..3dc99103e9a67
> 3902abcefe824d5cf5c19b258b8
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/BaseMemoryLibMmio.un
> i
> @@ -0,0 +1,15 @@
> +// /** @file
> +// Instance of Base Memory Library using Mmio
> operations.
> +//
> +//
> +// Copyright (c) 2020, ARM Limited. All rights
> reserved.<BR>
> +//
> +// SPDX-License-Identifier: BSD-2-Clause-Patent
> +//
> +// **/
> +
> +
> +#string STR_MODULE_ABSTRACT             #language en-
> US "Instance of Base Memory Library using Mmio
> operations"
> +
> +#string STR_MODULE_DESCRIPTION          #language en-
> US "Base Memory Library using Mmio operations"
> +
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..63e0e3ea583cb
> 242a9242f483e8c952e48122e77
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/CompareMemWrapper.c
> @@ -0,0 +1,62 @@
> +/** @file
> +  CompareMem() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Compares the contents of two buffers.
> +
> +  This function compares Length bytes of SourceBuffer
> to Length bytes of DestinationBuffer.
> +  If all Length bytes of the two buffers are
> identical, then 0 is returned.  Otherwise, the
> +  value returned is the first mismatched byte in
> SourceBuffer subtracted from the first
> +  mismatched byte in DestinationBuffer.
> +
> +  If Length > 0 and DestinationBuffer is NULL, then
> ASSERT().
> +  If Length > 0 and SourceBuffer is NULL, then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS -
> DestinationBuffer + 1), then ASSERT().
> +  If Length is greater than (MAX_ADDRESS -
> SourceBuffer + 1), then ASSERT().
> +
> +  @param  DestinationBuffer A pointer to the
> destination buffer to compare.
> +  @param  SourceBuffer      A pointer to the source
> buffer to compare.
> +  @param  Length            The number of bytes to
> compare.
> +
> +  @return 0                 All Length bytes of the
> two buffers are identical.
> +  @retval Non-zero          The first mismatched byte
> in SourceBuffer subtracted from the first
> +                            mismatched byte in
> DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +CompareMem (
> +  IN CONST VOID  *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  if (Length == 0 || DestinationBuffer ==
> SourceBuffer) {
> +    return 0;
> +  }
> +  ASSERT (DestinationBuffer != NULL);
> +  ASSERT (SourceBuffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)DestinationBuffer));
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)SourceBuffer));
> +
> +  return InternalMemCompareMem (DestinationBuffer,
> SourceBuffer, Length);
> +}
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
> b/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..84a207bf0f8a5
> 37b0832b5c4c9f6735122ee7851
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/CopyMem.c
> @@ -0,0 +1,149 @@
> +/** @file
> +  Implementation of the InternalMemCopyMem routine.
> This function is broken
> +  out into its own source file so that it can be
> excluded from a build for a
> +  particular platform easily if an optimized version
> is desired.
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2012 - 2020, ARM Ltd. All rights
> reserved.<BR>
> +  Copyright (c) 2016, Linaro Ltd. All rights
> reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Copy Length bytes from Source to Destination.
> +
> +  @param  DestinationBuffer The target of the copy
> request.
> +  @param  SourceBuffer      The place to copy from.
> +  @param  Length            The number of bytes to
> copy.
> +
> +  @return Destination
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemCopyMem (
> +  OUT     VOID
> *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  )
> +{
> +  //
> +  // Declare the local variables that actually move
> the data elements as
> +  // volatile to prevent the optimizer from replacing
> this function with
> +  // the intrinsic memcpy()
> +  //
> +  volatile UINT8                    *Destination8;
> +  CONST UINT8                       *Source8;
> +  volatile UINT32                   *Destination32;
> +  CONST UINT32                      *Source32;
> +  volatile UINT64                   *Destination64;
> +  CONST UINT64                      *Source64;
> +  UINTN                             Alignment;
> +
> +  if ((((UINTN)DestinationBuffer & 0x7) == 0) &&
> +      (((UINTN)SourceBuffer & 0x7) == 0)      &&
> +      (Length >= 8)) {
> +    if (SourceBuffer > DestinationBuffer) {
> +      Destination64 = (UINT64*)DestinationBuffer;
> +      Source64 = (CONST UINT64*)SourceBuffer;
> +      while (Length >= 8) {
> +        MmioWrite64 ((UINTN)Destination64++,
> MmioRead64 ((UINTN)Source64++));
> +        Length -= 8;
> +      }
> +
> +      // Finish if there are still some bytes to copy
> +      Destination8 = (UINT8*)Destination64;
> +      Source8 = (CONST UINT8*)Source64;
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8++, MmioRead8
> ((UINTN)Source8++));
> +      }
> +    } else if (SourceBuffer < DestinationBuffer) {
> +      Destination64 =
> (UINT64*)((UINTN)DestinationBuffer + Length);
> +      Source64 = (CONST UINT64*)((UINTN)SourceBuffer +
> Length);
> +
> +      // Destination64 and Source64 were aligned on a
> 64-bit boundary
> +      // but if length is not a multiple of 8 bytes
> then they won't be
> +      // anymore.
> +
> +      Alignment = Length & 0x7;
> +      if (Alignment != 0) {
> +        Destination8 = (UINT8*)Destination64;
> +        Source8 = (CONST UINT8*)Source64;
> +
> +        while (Alignment-- != 0) {
> +          MmioWrite8 ((UINTN)--Destination8, MmioRead8
> ((UINTN)--Source8));
> +          --Length;
> +        }
> +        Destination64 = (UINT64*)Destination8;
> +        Source64 = (CONST UINT64*)Source8;
> +      }
> +
> +      while (Length > 0) {
> +        MmioWrite64 ((UINTN)--Destination64,
> MmioRead64 ((UINTN)--Source64));
> +        Length -= 8;
> +      }
> +    }
> +  } else if ((((UINTN)DestinationBuffer & 0x3) == 0)
> &&
> +             (((UINTN)SourceBuffer & 0x3) == 0)
> &&
> +             (Length >= 4)) {
> +    if (SourceBuffer > DestinationBuffer) {
> +      Destination32 = (UINT32*)DestinationBuffer;
> +      Source32 = (CONST UINT32*)SourceBuffer;
> +      while (Length >= 4) {
> +        MmioWrite32 ((UINTN)Destination32++,
> MmioRead32 ((UINTN)Source32++));
> +        Length -= 4;
> +      }
> +
> +      // Finish if there are still some bytes to copy
> +      Destination8 = (UINT8*)Destination32;
> +      Source8 = (CONST UINT8*)Source32;
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8++, MmioRead8
> ((UINTN)Source8++));
> +      }
> +    } else if (SourceBuffer < DestinationBuffer) {
> +      Destination32 =
> (UINT32*)((UINTN)DestinationBuffer + Length);
> +      Source32 = (CONST UINT32*)((UINTN)SourceBuffer +
> Length);
> +
> +      // Destination32 and Source32 were aligned on a
> 32-bit boundary
> +      // but if length is not a multiple of 4 bytes
> then they won't be
> +      // anymore.
> +
> +      Alignment = Length & 0x3;
> +      if (Alignment != 0) {
> +        Destination8 = (UINT8*)Destination32;
> +        Source8 = (CONST UINT8*)Source32;
> +
> +        while (Alignment-- != 0) {
> +          MmioWrite8 ((UINTN)--Destination8, MmioRead8
> ((UINTN)--Source8));
> +          --Length;
> +        }
> +        Destination32 = (UINT32*)Destination8;
> +        Source32 = (CONST UINT32*)Source8;
> +      }
> +
> +      while (Length > 0) {
> +        MmioWrite32 ((UINTN)--Destination32,
> MmioRead32 ((UINTN)--Source32));
> +        Length -= 4;
> +      }
> +    }
> +  } else {
> +    if (SourceBuffer > DestinationBuffer) {
> +      Destination8 = (UINT8*)DestinationBuffer;
> +      Source8 = (CONST UINT8*)SourceBuffer;
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8++, MmioRead8
> ((UINTN)Source8++));
> +      }
> +    } else if (SourceBuffer < DestinationBuffer) {
> +      Destination8 = (UINT8*)DestinationBuffer +
> (Length - 1);
> +      Source8 = (CONST UINT8*)SourceBuffer + (Length -
> 1);
> +      while (Length-- != 0) {
> +        MmioWrite8 ((UINTN)Destination8--, MmioRead8
> ((UINTN)Source8--));
> +      }
> +    }
> +  }
> +  return DestinationBuffer;
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..d557bbb8904c2
> b07c644261290a62be6fc831c08
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/CopyMemWrapper.c
> @@ -0,0 +1,59 @@
> +/** @file
> +  CopyMem() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Copies a source buffer to a destination buffer, and
> returns the destination buffer.
> +
> +  This function copies Length bytes from SourceBuffer
> to DestinationBuffer, and returns
> +  DestinationBuffer.  The implementation must be
> reentrant, and it must handle the case
> +  where SourceBuffer overlaps DestinationBuffer.
> +
> +  If Length is greater than (MAX_ADDRESS -
> DestinationBuffer + 1), then ASSERT().
> +  If Length is greater than (MAX_ADDRESS -
> SourceBuffer + 1), then ASSERT().
> +
> +  @param  DestinationBuffer   A pointer to the
> destination buffer of the memory copy.
> +  @param  SourceBuffer        A pointer to the source
> buffer of the memory copy.
> +  @param  Length              The number of bytes to
> copy from SourceBuffer to DestinationBuffer.
> +
> +  @return DestinationBuffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +CopyMem (
> +  OUT VOID       *DestinationBuffer,
> +  IN CONST VOID  *SourceBuffer,
> +  IN UINTN       Length
> +  )
> +{
> +  if (Length == 0) {
> +    return DestinationBuffer;
> +  }
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)DestinationBuffer));
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)SourceBuffer));
> +
> +  if (DestinationBuffer == SourceBuffer) {
> +    return DestinationBuffer;
> +  }
> +  return InternalMemCopyMem (DestinationBuffer,
> SourceBuffer, Length);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.
> c
> b/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.
> c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..9c3133c668c43
> 4839b0d9bf105bc7265eeb76a5b
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/IsZeroBufferWrapper.
> c
> @@ -0,0 +1,50 @@
> +/** @file
> +  Implementation of IsZeroBuffer function.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2016, Intel Corporation. All rights
> reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Checks if the contents of a buffer are all zeros.
> +
> +  This function checks whether the contents of a
> buffer are all zeros. If the
> +  contents are all zeros, return TRUE. Otherwise,
> return FALSE.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the buffer to be
> checked.
> +  @param  Length      The size of the buffer (in
> bytes) to be checked.
> +
> +  @retval TRUE        Contents of the buffer are all
> zeros.
> +  @retval FALSE       Contents of the buffer are not
> all zeros.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +IsZeroBuffer (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length
> +  )
> +{
> +  ASSERT (!(Buffer == NULL && Length > 0));
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  return InternalMemIsZeroBuffer (Buffer, Length);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
> b/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..1c65b67423079
> 5e956c9d22f2b9c151c41839706
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibGeneric.c
> @@ -0,0 +1,304 @@
> +/** @file
> +  Architecture Independent Base Memory Library
> Implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 16-bit value, and
> returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The count of 16-bit value to fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem16 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  )
> +{
> +  volatile UINT16  *Destination16;
> +
> +  Destination16 = (UINT16*)Buffer;
> +  while (Length > 0) {
> +    MmioWrite16 ((UINTN)--Destination16, Value);
> +    Length -= 2;
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Fills a target buffer with a 32-bit value, and
> returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The count of 32-bit value to fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem32 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  )
> +{
> +  volatile UINT32  *Destination32;
> +
> +  Destination32 = (UINT32*)Buffer;
> +  while (Length > 0) {
> +    MmioWrite32 ((UINTN)--Destination32, Value);
> +    Length -= 4;
> +  }
> +  return Buffer;
> +}
> +
> +/**
> +  Fills a target buffer with a 64-bit value, and
> returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The count of 64-bit value to fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem64 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  )
> +{
> +  volatile UINT64  *Destination64;
> +
> +  Destination64 = (UINT64*)Buffer;
> +  while (Length > 0) {
> +    MmioWrite64 ((UINTN)--Destination64, Value);
> +    Length -= 8;
> +  }
> +  return Buffer;
> +}
> +
> +/**
> +  Set Buffer to 0 for Size bytes.
> +
> +  @param  Buffer Memory to set.
> +  @param  Length The number of bytes to set.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemZeroMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length
> +  )
> +{
> +  return InternalMemSetMem (Buffer, Length, 0);
> +}
> +
> +/**
> +  Compares two memory buffers of a given length.
> +
> +  @param  DestinationBuffer The first memory buffer.
> +  @param  SourceBuffer      The second memory buffer.
> +  @param  Length            Length of
> DestinationBuffer and SourceBuffer memory
> +                            regions to compare. Must
> be non-zero.
> +
> +  @return 0                 All Length bytes of the
> two buffers are identical.
> +  @retval Non-zero          The first mismatched byte
> in SourceBuffer subtracted from the first
> +                            mismatched byte in
> DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +InternalMemCompareMem (
> +  IN      CONST VOID
> *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  )
> +{
> +  while ((--Length != 0) &&
> +         (MmioRead8 ((UINTN)DestinationBuffer) ==
> +          MmioRead8 ((UINTN)SourceBuffer))) {
> +    DestinationBuffer = (INT8*)DestinationBuffer + 1;
> +    SourceBuffer = (INT8*)SourceBuffer + 1;
> +  }
> +  return (INTN)MmioRead8 ((UINTN)DestinationBuffer) -
> +         (INTN)MmioRead8 ((UINTN)SourceBuffer);
> +}
> +
> +/**
> +  Scans a target buffer for an 8-bit value, and
> returns a pointer to the
> +  matching 8-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 8-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem8 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  )
> +{
> +  CONST UINT8                       *Pointer;
> +
> +  Pointer = (CONST UINT8*)Buffer;
> +  do {
> +    if (MmioRead8 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Scans a target buffer for a 16-bit value, and
> returns a pointer to the
> +  matching 16-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 16-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem16 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  )
> +{
> +  CONST UINT16                      *Pointer;
> +
> +  Pointer = (CONST UINT16*)Buffer;
> +  do {
> +    if (MmioRead16 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Scans a target buffer for a 32-bit value, and
> returns a pointer to the
> +  matching 32-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 32-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem32 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  )
> +{
> +  CONST UINT32                      *Pointer;
> +
> +  Pointer = (CONST UINT32*)Buffer;
> +  do {
> +    if (MmioRead32 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Scans a target buffer for a 64-bit value, and
> returns a pointer to the
> +  matching 64-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 64-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem64 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  )
> +{
> +  CONST UINT64                      *Pointer;
> +
> +  Pointer = (CONST UINT64*)Buffer;
> +  do {
> +    if (MmioRead64 ((UINTN)Pointer) == Value) {
> +      return Pointer;
> +    }
> +    ++Pointer;
> +  } while (--Length != 0);
> +  return NULL;
> +}
> +
> +/**
> +  Checks whether the contents of a buffer are all
> zeros.
> +
> +  @param  Buffer  The pointer to the buffer to be
> checked.
> +  @param  Length  The size of the buffer (in bytes) to
> be checked.
> +
> +  @retval TRUE    Contents of the buffer are all
> zeros.
> +  @retval FALSE   Contents of the buffer are not all
> zeros.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +InternalMemIsZeroBuffer (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length
> +  )
> +{
> +  CONST UINT8 *BufferData;
> +  UINTN       Index;
> +
> +  BufferData = Buffer;
> +  for (Index = 0; Index < Length; Index++) {
> +    if (MmioRead8 ((UINTN)(BufferData + Index)) != 0)
> {
> +      return FALSE;
> +    }
> +  }
> +  return TRUE;
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
> b/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..ce69e431309f4
> 447a4e99251a86b5182123e5b97
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/MemLibGuid.c
> @@ -0,0 +1,143 @@
> +/** @file
> +  Implementation of GUID functions.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Copies a source GUID to a destination GUID.
> +
> +  This function copies the contents of the 128-bit
> GUID specified by SourceGuid
> +  to DestinationGuid, and returns DestinationGuid.
> +
> +  If DestinationGuid is NULL, then ASSERT().
> +  If SourceGuid is NULL, then ASSERT().
> +
> +  @param  DestinationGuid   A pointer to the
> destination GUID.
> +  @param  SourceGuid        A pointer to the source
> GUID.
> +
> +  @return DestinationGuid.
> +
> +**/
> +GUID *
> +EFIAPI
> +CopyGuid (
> +  OUT GUID       *DestinationGuid,
> +  IN CONST GUID  *SourceGuid
> +  )
> +{
> +  return InternalMemCopyMem (DestinationGuid,
> SourceGuid, sizeof (GUID));
> +}
> +
> +/**
> +  Compares two GUIDs.
> +
> +  This function compares Guid1 to Guid2.  If the GUIDs
> are identical then TRUE is returned.
> +  If there are any bit differences in the two GUIDs,
> then FALSE is returned.
> +
> +  If Guid1 is NULL, then ASSERT().
> +  If Guid2 is NULL, then ASSERT().
> +
> +  @param  Guid1       A pointer to a 128 bit GUID.
> +  @param  Guid2       A pointer to a 128 bit GUID.
> +
> +  @retval TRUE        Guid1 and Guid2 are identical.
> +  @retval FALSE       Guid1 and Guid2 are not
> identical.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +CompareGuid (
> +  IN CONST GUID  *Guid1,
> +  IN CONST GUID  *Guid2
> +  )
> +{
> +  return (0 == InternalMemCompareMem (Guid1, Guid2,
> sizeof (GUID)));
> +}
> +
> +/**
> +  Scans a target buffer for a GUID, and returns a
> pointer to the matching GUID
> +  in the target buffer.
> +
> +  This function searches the target buffer specified
> by Buffer and Length from
> +  the lowest address to the highest address at 128-bit
> increments for the 128-bit
> +  GUID value that matches Guid.  If a match is found,
> then a pointer to the matching
> +  GUID in the target buffer is returned.  If no match
> is found, then NULL is returned.
> +  If Length is 0, then NULL is returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 128-bit boundary, then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The number of bytes in Buffer to
> scan.
> +  @param  Guid    The value to search for in the
> target buffer.
> +
> +  @return A pointer to the matching Guid in the target
> buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanGuid (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN CONST GUID  *Guid
> +  )
> +{
> +  CONST GUID                        *GuidPtr;
> +
> +  ASSERT (((UINTN)Buffer & (sizeof (Guid->Data1) - 1))
> == 0);
> +  ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer +
> 1));
> +  ASSERT ((Length & (sizeof (*GuidPtr) - 1)) == 0);
> +
> +  GuidPtr = (GUID*)Buffer;
> +  Buffer  = GuidPtr + Length / sizeof (*GuidPtr);
> +  while (GuidPtr < (CONST GUID*)Buffer) {
> +    if (CompareGuid (GuidPtr, Guid)) {
> +      return (VOID*)GuidPtr;
> +    }
> +    GuidPtr++;
> +  }
> +  return NULL;
> +}
> +
> +/**
> +  Checks if the given GUID is a zero GUID.
> +
> +  This function checks whether the given GUID is a
> zero GUID. If the GUID is
> +  identical to a zero GUID then TRUE is returned.
> Otherwise, FALSE is returned.
> +
> +  If Guid is NULL, then ASSERT().
> +
> +  @param  Guid        The pointer to a 128 bit GUID.
> +
> +  @retval TRUE        Guid is a zero GUID.
> +  @retval FALSE       Guid is not a zero GUID.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +IsZeroGuid (
> +  IN CONST GUID  *Guid
> +  )
> +{
> +  return InternalMemIsZeroBuffer (Guid, sizeof
> (GUID));
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
> b/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..dc28a9078a8a7
> 07af8a83517d3756c6126093079
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/MemLibInternals.h
> @@ -0,0 +1,248 @@
> +/** @file
> +  Declaration of internal functions for Base Memory
> Library.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +
> +  Copyright (c) 2006 - 2016, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef __MEM_LIB_INTERNALS__
> +#define __MEM_LIB_INTERNALS__
> +
> +#include <Base.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +
> +/**
> +  Copy Length bytes from Source to Destination.
> +
> +  @param  DestinationBuffer Target of copy
> +  @param  SourceBuffer      Place to copy from
> +  @param  Length            The number of bytes to
> copy
> +
> +  @return Destination
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemCopyMem (
> +  OUT     VOID
> *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  );
> +
> +/**
> +  Set Buffer to Value for Size bytes.
> +
> +  @param  Buffer   The memory to set.
> +  @param  Length   The number of bytes to set
> +  @param  Value    The value of the set operation.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  );
> +
> +/**
> +  Fills a target buffer with a 16-bit value, and
> returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The count of 16-bit value to fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem16 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  );
> +
> +/**
> +  Fills a target buffer with a 32-bit value, and
> returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The count of 32-bit value to fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem32 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  );
> +
> +/**
> +  Fills a target buffer with a 64-bit value, and
> returns the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The count of 64-bit value to fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem64 (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  );
> +
> +/**
> +  Set Buffer to 0 for Size bytes.
> +
> +  @param  Buffer The memory to set.
> +  @param  Length The number of bytes to set.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemZeroMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length
> +  );
> +
> +/**
> +  Compares two memory buffers of a given length.
> +
> +  @param  DestinationBuffer The first memory buffer.
> +  @param  SourceBuffer      The second memory buffer.
> +  @param  Length            The length of
> DestinationBuffer and SourceBuffer memory
> +                            regions to compare. Must
> be non-zero.
> +
> +  @return 0                 All Length bytes of the
> two buffers are identical.
> +  @retval Non-zero          The first mismatched byte
> in SourceBuffer subtracted from the first
> +                            mismatched byte in
> DestinationBuffer.
> +
> +**/
> +INTN
> +EFIAPI
> +InternalMemCompareMem (
> +  IN      CONST VOID
> *DestinationBuffer,
> +  IN      CONST VOID                *SourceBuffer,
> +  IN      UINTN                     Length
> +  );
> +
> +/**
> +  Scans a target buffer for an 8-bit value, and
> returns a pointer to the
> +  matching 8-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 8-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem8 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  );
> +
> +/**
> +  Scans a target buffer for a 16-bit value, and
> returns a pointer to the
> +  matching 16-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 16-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem16 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT16                    Value
> +  );
> +
> +/**
> +  Scans a target buffer for a 32-bit value, and
> returns a pointer to the
> +  matching 32-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 32-bit value to scan.
> Must be non-zero.
> +  @param  Value   The value to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem32 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT32                    Value
> +  );
> +
> +/**
> +  Scans a target buffer for a 64-bit value, and
> returns a pointer to the
> +  matching 64-bit value in the target buffer.
> +
> +  @param  Buffer  The pointer to the target buffer to
> scan.
> +  @param  Length  The count of 64-bit value to scan.
> Must be non-zero.
> +  @param  Value   The calue to search for in the
> target buffer.
> +
> +  @return The pointer to the first occurrence, or NULL
> if not found.
> +
> +**/
> +CONST VOID *
> +EFIAPI
> +InternalMemScanMem64 (
> +  IN      CONST VOID                *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT64                    Value
> +  );
> +
> +/**
> +  Checks whether the contents of a buffer are all
> zeros.
> +
> +  @param  Buffer  The pointer to the buffer to be
> checked.
> +  @param  Length  The size of the buffer (in bytes) to
> be checked.
> +
> +  @retval TRUE    Contents of the buffer are all
> zeros.
> +  @retval FALSE   Contents of the buffer are not all
> zeros.
> +
> +**/
> +BOOLEAN
> +EFIAPI
> +InternalMemIsZeroBuffer (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length
> +  );
> +
> +#endif
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..ad9330b9938df
> 9995a597dbabc1aa2744aa0d8c1
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem16Wrapper.c
> @@ -0,0 +1,63 @@
> +/** @file
> +  ScanMem16() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for a 16-bit value, and
> returns a pointer to the matching 16-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified
> by Buffer and Length from the lowest
> +  address to the highest address for a 16-bit value
> that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target
> buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is
> returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer
> to scan.
> +  @param  Length      The number of bytes in Buffer to
> scan.
> +  @param  Value       The value to search for in the
> target buffer.
> +
> +  @return A pointer to the matching byte in the target
> buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem16 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT16      Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) ==
> 0);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return (VOID*)InternalMemScanMem16 (Buffer, Length /
> sizeof (Value), Value);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..84675697d1201
> 6f92c46c08c65aca647288a8b99
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem32Wrapper.c
> @@ -0,0 +1,62 @@
> +/** @file
> +  ScanMem32() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for a 32-bit value, and
> returns a pointer to the matching 32-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified
> by Buffer and Length from the lowest
> +  address to the highest address for a 32-bit value
> that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target
> buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is
> returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer
> to scan.
> +  @param  Length      The number of bytes in Buffer to
> scan.
> +  @param  Value       The value to search for in the
> target buffer.
> +
> +  @return A pointer to the matching byte in the target
> buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem32 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT32      Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) ==
> 0);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return (VOID*)InternalMemScanMem32 (Buffer, Length /
> sizeof (Value), Value);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..df749dce45782
> 7fe070bad8b7c6071aae29ebb02
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem64Wrapper.c
> @@ -0,0 +1,63 @@
> +/** @file
> +  ScanMem64() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for a 64-bit value, and
> returns a pointer to the matching 64-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified
> by Buffer and Length from the lowest
> +  address to the highest address for a 64-bit value
> that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target
> buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is
> returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a 64-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 64-bit boundary, then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer
> to scan.
> +  @param  Length      The number of bytes in Buffer to
> scan.
> +  @param  Value       The value to search for in the
> target buffer.
> +
> +  @return A pointer to the matching byte in the target
> buffer or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem64 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT64      Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (((UINTN)Buffer & (sizeof (Value) - 1)) ==
> 0);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return (VOID*)InternalMemScanMem64 (Buffer, Length /
> sizeof (Value), Value);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..170981017dbe3
> 1cf5e0c3dabf26a4fea33f7a7d7
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/ScanMem8Wrapper.c
> @@ -0,0 +1,95 @@
> +/** @file
> +  ScanMem8() and ScanMemN() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Scans a target buffer for an 8-bit value, and
> returns a pointer to the matching 8-bit value
> +  in the target buffer.
> +
> +  This function searches the target buffer specified
> by Buffer and Length from the lowest
> +  address to the highest address for an 8-bit value
> that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target
> buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is
> returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer
> to scan.
> +  @param  Length      The number of bytes in Buffer to
> scan.
> +  @param  Value       The value to search for in the
> target buffer.
> +
> +  @return A pointer to the matching byte in the target
> buffer, or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMem8 (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINT8       Value
> +  )
> +{
> +  if (Length == 0) {
> +    return NULL;
> +  }
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +
> +  return (VOID*)InternalMemScanMem8 (Buffer, Length,
> Value);
> +}
> +
> +/**
> +  Scans a target buffer for a UINTN sized value, and
> returns a pointer to the matching
> +  UINTN sized value in the target buffer.
> +
> +  This function searches the target buffer specified
> by Buffer and Length from the lowest
> +  address to the highest address for a UINTN sized
> value that matches Value.  If a match is found,
> +  then a pointer to the matching byte in the target
> buffer is returned.  If no match is found,
> +  then NULL is returned.  If Length is 0, then NULL is
> returned.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Buffer is not aligned on a UINTN boundary, then
> ASSERT().
> +  If Length is not aligned on a UINTN boundary, then
> ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer
> to scan.
> +  @param  Length      The number of bytes in Buffer to
> scan.
> +  @param  Value       The value to search for in the
> target buffer.
> +
> +  @return A pointer to the matching byte in the target
> buffer, or NULL otherwise.
> +
> +**/
> +VOID *
> +EFIAPI
> +ScanMemN (
> +  IN CONST VOID  *Buffer,
> +  IN UINTN       Length,
> +  IN UINTN       Value
> +  )
> +{
> +  if (sizeof (UINTN) == sizeof (UINT64)) {
> +    return ScanMem64 (Buffer, Length, (UINT64)Value);
> +  } else {
> +    return ScanMem32 (Buffer, Length, (UINT32)Value);
> +  }
> +}
> +
> diff --git a/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..40255670c6f26
> eb72a82568f035720fc6fe75546
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMem.c
> @@ -0,0 +1,83 @@
> +/** @file
> +  Implementation of the EfiSetMem routine. This
> function is broken
> +  out into its own source file so that it can be
> excluded from a
> +  build for a particular platform easily if an
> optimized version
> +  is desired.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2012 - 2020, ARM Ltd. All rights
> reserved.<BR>
> +  Copyright (c) 2016, Linaro Ltd. All rights
> reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Set Buffer to Value for Size bytes.
> +
> +  @param  Buffer   The memory to set.
> +  @param  Length   The number of bytes to set.
> +  @param  Value    The value of the set operation.
> +
> +  @return Buffer
> +
> +**/
> +VOID *
> +EFIAPI
> +InternalMemSetMem (
> +  OUT     VOID                      *Buffer,
> +  IN      UINTN                     Length,
> +  IN      UINT8                     Value
> +  )
> +{
> +  //
> +  // Declare the local variables that actually move
> the data elements as
> +  // volatile to prevent the optimizer from replacing
> this function with
> +  // the intrinsic memset()
> +  //
> +  volatile UINT8                    *Pointer8;
> +  volatile UINT32                   *Pointer32;
> +  volatile UINT64                   *Pointer64;
> +  UINT32                            Value32;
> +  UINT64                            Value64;
> +
> +  if ((((UINTN)Buffer & 0x7) == 0) && (Length >= 8)) {
> +    // Generate the 64bit value
> +    Value32 = (Value << 24) | (Value << 16) | (Value
> << 8) | Value;
> +    Value64 = LShiftU64 (Value32, 32) | Value32;
> +
> +    Pointer64 = (UINT64*)Buffer;
> +    while (Length >= 8) {
> +      MmioWrite64 ((UINTN)Pointer64++, Value64);
> +      Length -= 8;
> +    }
> +
> +    // Finish with bytes if needed
> +    Pointer8 = (UINT8*)Pointer64;
> +  } else if ((((UINTN)Buffer & 0x3) == 0) && (Length
> >= 4)) {
> +    // Generate the 32bit value
> +    Value32 = (Value << 24) | (Value << 16) | (Value
> << 8) | Value;
> +
> +    Pointer32 = (UINT32*)Buffer;
> +    while (Length >= 4) {
> +      MmioWrite32 ((UINTN)Pointer32++, Value32);
> +      Length -= 4;
> +    }
> +
> +    // Finish with bytes if needed
> +    Pointer8 = (UINT8*)Pointer32;
> +  } else {
> +    Pointer8 = (UINT8*)Buffer;
> +  }
> +  while (Length-- > 0) {
> +    MmioWrite8 ((UINTN)Pointer8++, Value);
> +  }
> +  return Buffer;
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..be785c5eb696e
> f6b913bf7bc0081a5f414c6f141
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem16Wrapper.c
> @@ -0,0 +1,60 @@
> +/** @file
> +  SetMem16() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 16-bit value, and
> returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the
> 16-bit value specified by
> +  Value, and returns Buffer. Value is repeated every
> 16-bits in for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +  If Buffer is not aligned on a 16-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 16-bit boundary, then
> ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The number of bytes in Buffer to
> fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem16 (
> +  OUT VOID   *Buffer,
> +  IN UINTN   Length,
> +  IN UINT16  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) ==
> 0);
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return InternalMemSetMem16 (Buffer, Length / sizeof
> (Value), Value);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..622c6eddccc88
> e846921782efc29e40f816ae499
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem32Wrapper.c
> @@ -0,0 +1,60 @@
> +/** @file
> +  SetMem32() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 32-bit value, and
> returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the
> 32-bit value specified by
> +  Value, and returns Buffer. Value is repeated every
> 32-bits in for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +  If Buffer is not aligned on a 32-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 32-bit boundary, then
> ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The number of bytes in Buffer to
> fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem32 (
> +  OUT VOID   *Buffer,
> +  IN UINTN   Length,
> +  IN UINT32  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) ==
> 0);
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return InternalMemSetMem32 (Buffer, Length / sizeof
> (Value), Value);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..7653eed85cd63
> 3be5aea439cf4ab62958dd62c47
> --- /dev/null
> +++
> b/MdePkg/Library/BaseMemoryLibMmio/SetMem64Wrapper.c
> @@ -0,0 +1,60 @@
> +/** @file
> +  SetMem64() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2010, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a 64-bit value, and
> returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the
> 64-bit value specified by
> +  Value, and returns Buffer. Value is repeated every
> 64-bits in for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +  If Buffer is not aligned on a 64-bit boundary, then
> ASSERT().
> +  If Length is not aligned on a 64-bit boundary, then
> ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The number of bytes in Buffer to
> fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem64 (
> +  OUT VOID   *Buffer,
> +  IN UINTN   Length,
> +  IN UINT64  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +  ASSERT ((((UINTN)Buffer) & (sizeof (Value) - 1)) ==
> 0);
> +  ASSERT ((Length & (sizeof (Value) - 1)) == 0);
> +
> +  return InternalMemSetMem64 (Buffer, Length / sizeof
> (Value), Value);
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..96dd956686d15
> b4b4cb25157d764849043d1b57b
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/SetMemWrapper.c
> @@ -0,0 +1,87 @@
> +/** @file
> +  SetMem() and SetMemN() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with a byte value, and returns
> the target buffer.
> +
> +  This function fills Length bytes of Buffer with
> Value, and returns Buffer.
> +
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer    The memory to set.
> +  @param  Length    The number of bytes to set.
> +  @param  Value     The value with which to fill
> Length bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMem (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length,
> +  IN UINT8  Value
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT ((Length - 1) <= (MAX_ADDRESS -
> (UINTN)Buffer));
> +
> +  return InternalMemSetMem (Buffer, Length, Value);
> +}
> +
> +/**
> +  Fills a target buffer with a value that is size
> UINTN, and returns the target buffer.
> +
> +  This function fills Length bytes of Buffer with the
> UINTN sized value specified by
> +  Value, and returns Buffer. Value is repeated every
> sizeof(UINTN) bytes for Length
> +  bytes of Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +  If Buffer is not aligned on a UINTN boundary, then
> ASSERT().
> +  If Length is not aligned on a UINTN boundary, then
> ASSERT().
> +
> +  @param  Buffer  The pointer to the target buffer to
> fill.
> +  @param  Length  The number of bytes in Buffer to
> fill.
> +  @param  Value   The value with which to fill Length
> bytes of Buffer.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +SetMemN (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length,
> +  IN UINTN  Value
> +  )
> +{
> +  if (sizeof (UINTN) == sizeof (UINT64)) {
> +    return SetMem64 (Buffer, Length, (UINT64)Value);
> +  } else {
> +    return SetMem32 (Buffer, Length, (UINT32)Value);
> +  }
> +}
> diff --git
> a/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
> b/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
> new file mode 100644
> index
> 0000000000000000000000000000000000000000..55246d121c682
> 0d371af463792614c1d73676e6f
> --- /dev/null
> +++ b/MdePkg/Library/BaseMemoryLibMmio/ZeroMemWrapper.c
> @@ -0,0 +1,52 @@
> +/** @file
> +  ZeroMem() implementation.
> +
> +  The following BaseMemoryLib instances contain the
> same copy of this file:
> +
> +    BaseMemoryLib
> +    BaseMemoryLibMmio
> +    BaseMemoryLibMmx
> +    BaseMemoryLibSse2
> +    BaseMemoryLibRepStr
> +    BaseMemoryLibOptDxe
> +    BaseMemoryLibOptPei
> +    PeiMemoryLib
> +    UefiMemoryLib
> +
> +  Copyright (c) 2006 - 2018, Intel Corporation. All
> rights reserved.<BR>
> +  Copyright (c) 2020, ARM Ltd. All rights
> reserved.<BR>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include "MemLibInternals.h"
> +
> +/**
> +  Fills a target buffer with zeros, and returns the
> target buffer.
> +
> +  This function fills Length bytes of Buffer with
> zeros, and returns Buffer.
> +
> +  If Length > 0 and Buffer is NULL, then ASSERT().
> +  If Length is greater than (MAX_ADDRESS - Buffer +
> 1), then ASSERT().
> +
> +  @param  Buffer      The pointer to the target buffer
> to fill with zeros.
> +  @param  Length      The number of bytes in Buffer to
> fill with zeros.
> +
> +  @return Buffer.
> +
> +**/
> +VOID *
> +EFIAPI
> +ZeroMem (
> +  OUT VOID  *Buffer,
> +  IN UINTN  Length
> +  )
> +{
> +  if (Length == 0) {
> +    return Buffer;
> +  }
> +
> +  ASSERT (Buffer != NULL);
> +  ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer +
> 1));
> +  return InternalMemZeroMem (Buffer, Length);
> +}
> --
> 'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'
> 
> 
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO
  2020-05-14  9:22   ` Ard Biesheuvel
@ 2020-05-14 17:21     ` Ard Biesheuvel
  0 siblings, 0 replies; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14 17:21 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: leif, michael.d.kinney, liming.gao, Alexandru.Elisei,
	Andre.Przywara, Matteo.Carlini, Laura.Moretta, nd

On 5/14/20 11:22 AM, Ard Biesheuvel wrote:
> Hi Sami,
> 
> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>> Some device drivers perform copy operations on
>> device memory, e.g. device drivers for a Flash
>> device. On some architectures unaligned access
>> to device memory regions is not permitted. To
>> add to this if the device is virtualised then
>> there are further restrictions on the type of
>> load/store operations that can be performed
>> on the device memory regions, e.g. on AARCH64,
>> Pre/Post index or LDP operations cannot be
>> used, as a trap to EL2 does not provide the
>> syndrome information to the hypervisor.
>>
> 
> We are conflating two different things here:
> - the use of unaligned accesses to read from device memory
> - the use of load/store instructions that have multiple output 
> registers, making it very difficult to emulate them in a virtual machine 
> context.
> 
> I though that for the kvmtool port, we addressed the second issue by 
> using a read-only memslot for the NOR flash when it is in array mode? 
> IIRC, the issue only affects reads, as all writes to NOR flash device 
> memory are already done using the proper MMIO accessors. If those MMIO 
> accessors compile to something that does not work under emulation, you 
> should be use the special IoLib implementation that exists for this use 
> case:
> 
>    MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicArmVirt.inf
> 
> So that leaves the issue of unaligned accesses to device memory. This 
> should not happen unless you are using BaseMemoryLibOptDxe for AARCH64, 
> which deliberately uses overlapping loads and stores for performance. 
> Any BASE library is built with -mstrict-align, and so any other C code 
> implementation of BaseMemoryLib should work fine for reading for a 
> read-only memslot mapped using device attributes.
> 
> So in summary, I don't think we need this library.
> 

BTW I think the AlignedCopyMem() introduction predates the changes to 
use -mstrict-align for BASE libraries, and to use the ordinary 
BaseMemoryLib implementation for DXE_RUNTIME_DRIVER modules on AArch64.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14 16:05         ` Laszlo Ersek
@ 2020-05-14 17:25           ` Ard Biesheuvel
  2020-05-15  7:28             ` Laszlo Ersek
  0 siblings, 1 reply; 40+ messages in thread
From: Ard Biesheuvel @ 2020-05-14 17:25 UTC (permalink / raw)
  To: Laszlo Ersek, devel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 5/14/20 6:05 PM, Laszlo Ersek wrote:
> On 05/14/20 14:17, Ard Biesheuvel wrote:
>> On 5/14/20 2:12 PM, Laszlo Ersek wrote:
>>> On 05/14/20 11:29, Ard Biesheuvel wrote:
>>>> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>>>>> Kvmtool is a virtual machine manager that enables
>>>>> hosting KVM guests. It essentially provides an
>>>>> emulated platform for guest operating systems.
>>>>>
>>>>> Kvmtool hands of a device tree containing the
>>>>> current hardware configuration to the firmware.
>>>>>
>>>>> A standards-based operating system would use
>>>>> ACPI to consume the platform hardware
>>>>> information, while some operating systems may
>>>>> prefer to use Device Tree.
>>>>>
>>>>> The KvmtoolPlatformDxe performs the platform
>>>>> actions like determining if the firmware should
>>>>> expose ACPI or the Device Tree based hardware
>>>>> description to the operating system.
>>>>>
>>>>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>>>>> ---
>>>>>
>>>>> Notes:
>>>>>        v2:
>>>>>          - Updated according to review comments.
>>>>> [Sami]
>>>>>             v1:
>>>>>          - Add kvmtool platform driver to support loading platform
>>>>> [Sami]
>>>>>            specific information.
>>>>>          - Keep code to initialise the variable storage PCDs in the
>>>>> [Laszlo]
>>>>>            platform-specific FVB driver.
>>>>>          - Document code derived from
>>>>> [Laszlo]
>>>>>            "ArmVirtPkg/PlatformHasAcpiDtDxe"
>>>>>            Ref: https://edk2.groups.io/g/devel/topic/30915278#30757
>>>>>
>>>>>     ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c   | 93
>>>>> ++++++++++++++++++++
>>>>>     ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.inf | 47 ++++++++++
>>>>>     2 files changed, 140 insertions(+)
>>>>>
>>>>> diff --git a/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>>>> b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>>>> new file mode 100644
>>>>> index
>>>>> 0000000000000000000000000000000000000000..e7568f66f5ebeb0423fc1c10345cd8dad0800d94
>>>>>
>>>>>
>>>>> --- /dev/null
>>>>> +++ b/ArmVirtPkg/KvmtoolPlatformDxe/KvmtoolPlatformDxe.c
>>>>> @@ -0,0 +1,93 @@
>>>>> +/** @file
>>>>> +
>>>>> +  The KvmtoolPlatformDxe performs the platform specific
>>>>> initialization like:
>>>>> +  - It decides if the firmware should expose ACPI or Device Tree-based
>>>>> +    hardware description to the operating system.
>>>>> +
>>>>> +  Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>>>>> +
>>>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>>> +
>>>>> +**/
>>>>> +
>>>>> +#include <Guid/VariableFormat.h>
>>>>> +#include <Library/BaseLib.h>
>>>>> +#include <Library/BaseMemoryLib.h>
>>>>> +#include <Library/DebugLib.h>
>>>>> +#include <Library/DxeServicesTableLib.h>
>>>>> +#include <Library/UefiBootServicesTableLib.h>
>>>>> +#include <Library/UefiDriverEntryPoint.h>
>>>>> +#include <Protocol/FdtClient.h>
>>>>> +
>>>>> +/** Decide if the firmware should expose ACPI tables or Device Tree
>>>>> and
>>>>> +    install the appropriate protocol interface.
>>>>> +
>>>>> +  Note: This function is derived from
>>>>> "ArmVirtPkg/PlatformHasAcpiDtDxe",
>>>>> +        by dropping the word size check, and the fw_cfg check.
>>>>> +
>>>>> +  @param [in]  ImageHandle  Handle for this image.
>>>>> +
>>>>> +  @retval EFI_SUCCESS             Success.
>>>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>>>> install the
>>>>> +                                  protocols.
>>>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>>>> +
>>>>> +**/
>>>>> +STATIC
>>>>> +EFI_STATUS
>>>>> +PlatformHasAcpiDt (
>>>>> +  IN EFI_HANDLE           ImageHandle
>>>>> +  )
>>>>> +{
>>>>> +  if (!PcdGetBool (PcdForceNoAcpi)) {
>>>>> +    // Expose ACPI tables
>>>>> +    return gBS->InstallProtocolInterface (
>>>>> +                  &ImageHandle,
>>>>> +                  &gEdkiiPlatformHasAcpiGuid,
>>>>> +                  EFI_NATIVE_INTERFACE,
>>>>> +                  NULL
>>>>> +                  );
>>>>> +  }
>>>>> +
>>>>> +  // Expose the Device Tree.
>>>>> +  return gBS->InstallProtocolInterface (
>>>>> +                &ImageHandle,
>>>>> +                &gEdkiiPlatformHasDeviceTreeGuid,
>>>>> +                EFI_NATIVE_INTERFACE,
>>>>> +                NULL
>>>>> +                );
>>>>> +}
>>>>> +
>>>>> +/** Entry point for Kvmtool Platform Dxe
>>>>> +
>>>>> +  @param [in]  ImageHandle  Handle for this image.
>>>>> +  @param [in]  SystemTable  Pointer to the EFI system table.
>>>>> +
>>>>> +  @retval EFI_SUCCESS             Success.
>>>>> +  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to
>>>>> install the
>>>>> +                                  protocols.
>>>>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>>>>> +
>>>>> +**/
>>>>> +EFI_STATUS
>>>>> +EFIAPI
>>>>> +KvmtoolPlatformDxeEntryPoint (
>>>>> +  IN EFI_HANDLE           ImageHandle,
>>>>> +  IN EFI_SYSTEM_TABLE     *SystemTable
>>>>> +  )
>>>>> +{
>>>>> +  EFI_STATUS                     Status;
>>>>> +
>>>>> +  Status = PlatformHasAcpiDt (ImageHandle);
>>>>> +  if (EFI_ERROR (Status)) {
>>>>> +    goto Failed;
>>>>> +  }
>>>>> +
>>>>> +  return Status;
>>>>> +
>>>>> +Failed:
>>>>> +  ASSERT_EFI_ERROR (Status);
>>>>> +  CpuDeadLoop ();
>>>>> +
>>>>> +  return Status;
>>>>> +}
>>>>
>>>> Please don't use CpuDeadLoop()s in your drivers.
>>>>
>>>> Installing a protocol on an image handle like this should not ever fail,
>>>> and if it does, it is unlikely to be an issue in the driver itself. So
>>>> just use ASSERT_EFI_ERROR() here, and return EFI_SUCCESS.
>>>
>>> I think Sami just followed the original code in
>>> "ArmVirtPkg/PlatformHasAcpiDtDxe".
>>>
>>> I'm fine either way:
>>>
>>> Acked-by: Laszlo Ersek <lersek@redhat.com>
>>>
>>> Different question:
>>>
>>> Should we ask Sami to become a designated reviewer (in Maintainers.txt)
>>> for the kvmtool-specific modules under ArmVirtPkg? Personally I'm
>>> unlikely to use kvmtool.
>>>
>>
>> Not sure if you saw patch 11/11, but I agree that in general, but for
>> ArmVirtPkg in particular as well, having package level maintainers is
>> sufficient, and there is no need for maintainer roles beyond that.
> 
> OK -- If you think patch#11 is unnecessary, I won't insist; I'd just
> like to avoid the expectation for me to deeply review or regression-test
> kvmtool stuff.
> 

I don't think it is unnecessary. I think it should be clear who is in 
charge of these files if it isn't the top-level maintainers of the package.

We just have to decide whether designated reviewer or maintainer is the 
most appropriate. I am fine with either, and I am willing to share the 
burden with Sami too.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver
  2020-05-14 17:25           ` Ard Biesheuvel
@ 2020-05-15  7:28             ` Laszlo Ersek
  0 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2020-05-15  7:28 UTC (permalink / raw)
  To: Ard Biesheuvel, devel, Sami Mujawar
  Cc: leif, Alexandru.Elisei, Andre.Przywara, Matteo.Carlini,
	Laura.Moretta, nd

On 05/14/20 19:25, Ard Biesheuvel wrote:

> We just have to decide whether designated reviewer or maintainer is the
> most appropriate. I am fine with either, and I am willing to share the
> burden with Sami too.
> 

Ah, OK, sorry, I misunderstood -- I missed that we were discussing "R"
vs. "M" for "ArmVirtPkg: Kvmtool emulated platform support", and not
whether we should have a section at all for "ArmVirtPkg: Kvmtool
emulated platform support".

So with this in mind, I think "R" would be more appropriate. That seems
to be the tradition when subdividing packages (compare "ArmVirtPkg:
modules used on Xen", "MdeModulePkg: [...]", "OvmfPkg: [...]").

Thanks for clarifying!
Laszlo


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver
  2020-05-14  8:40 ` [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver Sami Mujawar
  2020-05-14  9:24   ` Ard Biesheuvel
@ 2020-05-15 10:50   ` André Przywara
  2020-05-27  0:37     ` [edk2-devel] " Guomin Jiang
  1 sibling, 1 reply; 40+ messages in thread
From: André Przywara @ 2020-05-15 10:50 UTC (permalink / raw)
  To: Sami Mujawar, devel
  Cc: ard.biesheuvel, leif, ray.ni, Alexandru.Elisei, Matteo.Carlini,
	Laura.Moretta, nd

On 14/05/2020 09:40, Sami Mujawar wrote:

Hi Sami,

many thanks for your work on that!

> Some virtual machine managers like kvmtool emulate the MC146818
> RTC controller in the MMIO space so that architectures that do
> not support I/O Mapped I/O can use the RTC. This patch adds MMIO
> support to the RTC controller driver.

Is there any chance you could read the MMIO base address from the DT? I
sent a kvmtool patch to add the missing DT node[1].
The compatible string would be "motorola,mc146818", with just the usual
reg property.
Maybe you could fall back to the current 0x70/0x71, if there is no DT node?

For a start, this low address (0x70/0x71) causes issues, so we probably
need to move this permanently.
But also we want to introduce a more flexible memory layout, so devices
can move depending on command line parameters.

It would be great if EDK-2 could cover that from the beginning, so that
we don't end up with compatibility issues.

Cheers,
Andre

[1] https://lists.cs.columbia.edu/pipermail/kvmarm/2020-May/040703.html
> 
> The PCD PcdRtcUseMmio has been added to select I/O or MMIO support.
>   If PcdRtcUseMmio is:
>     TRUE  - Indicates the RTC port registers are in MMIO space.
>     FALSE - Indicates the RTC port registers are in I/O space.
>             Default is I/O space.
> 
> When MMIO support is selected (PcdRtcUseMmio == TRUE) the driver
> maps the MMIO region used by the RTC as runtime memory so that the
> RTC registers are accessible post ExitBootServices.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
> 
> Notes:
>     v2:
>       - Code review comments incorporated.                              [Sami]
>     
>     v1:
>       - Add support to read/write from RTC registers using MMIO access  [Sami]
>       - Use wrapper functions for RtcRead/Write accessors               [Leif]
>         Ref: https://edk2.groups.io/g/devel/topic/30915281#30695
> 
>  PcAtChipsetPkg/PcAtChipsetPkg.dec                                          |   8 ++
>  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c                         | 117 ++++++++++++++++--
>  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h                         |  31 +++++
>  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c                    | 130 +++++++++++++++++++-
>  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf |   8 ++
>  5 files changed, 280 insertions(+), 14 deletions(-)
> 
> diff --git a/PcAtChipsetPkg/PcAtChipsetPkg.dec b/PcAtChipsetPkg/PcAtChipsetPkg.dec
> index 88de5cceea593176c3a2425a5963b66b789f2b9e..76d0c7eda69bb505914ba904e09c89de170f69ae 100644
> --- a/PcAtChipsetPkg/PcAtChipsetPkg.dec
> +++ b/PcAtChipsetPkg/PcAtChipsetPkg.dec
> @@ -6,6 +6,7 @@
>  #
>  # Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
>  # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
>  #
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -142,5 +143,12 @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
>    # @Prompt RTC Update Timeout Value.
>    gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000|UINT32|0x00000020
>  
> +  ## Indicates the RTC port registers are in MMIO space, or in I/O space.
> +  #  Default is I/O space.<BR><BR>
> +  #   TRUE  - RTC port registers are in MMIO space.<BR>
> +  #   FALSE - RTC port registers are in I/O space.<BR>
> +  # @Prompt RTC port registers use MMIO.
> +  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|FALSE|BOOLEAN|0x00000021
> +
>  [UserExtensions.TianoCore."ExtraFiles"]
>    PcAtChipsetPkgExtra.uni
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> index 52af17941786ef81c3911512ee64551724e67209..df8dea83ab27bbba12351096d1bfd9ea31accb60 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> @@ -3,6 +3,7 @@
>  
>  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>  Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
>  
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>  
> @@ -10,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  
>  #include "PcRtc.h"
>  
> +extern EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
> +
>  //
>  // Days of month.
>  //
> @@ -21,6 +24,28 @@ UINTN mDayOfMonth[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
>  CHAR16 mTimeZoneVariableName[] = L"RTC";
>  
>  /**
> +  A function pointer that evaluates to a function that reads the RTC content
> +  through its registers either using IO or MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +RTC_READ  RtcRead;
> +
> +/**
> +  A function pointer that evaluates to a function that reads the RTC content
> +  through its registers either using IO or MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +RTC_WRITE RtcWrite;
> +
> +/**
>    Compare the Hour, Minute and Second of the From time and the To time.
>  
>    Only compare H/M/S in EFI_TIME and ignore other fields here.
> @@ -54,41 +79,99 @@ IsWithinOneDay (
>    );
>  
>  /**
> -  Read RTC content through its registers.
> +  Read RTC content through its registers using IO access.
>  
> -  @param  Address  Address offset of RTC. It is recommended to use macros such as
> -                   RTC_ADDRESS_SECONDS.
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
>  
>    @return The data of UINT8 type read from RTC.
>  **/
> +STATIC
>  UINT8
> -RtcRead (
> +IoRtcRead (
>    IN  UINT8 Address
>    )
>  {
> -  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
> +  IoWrite8 (
> +    PcdGet8 (PcdRtcIndexRegister),
> +    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
> +    );
>    return IoRead8 (PcdGet8 (PcdRtcTargetRegister));
>  }
>  
>  /**
> -  Write RTC through its registers.
> +  Write RTC through its registers  using IO access.
>  
> -  @param  Address  Address offset of RTC. It is recommended to use macros such as
> -                   RTC_ADDRESS_SECONDS.
> -  @param  Data     The content you want to write into RTC.
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +  @param  Data      The content you want to write into RTC.
>  
>  **/
> +STATIC
>  VOID
> -RtcWrite (
> +IoRtcWrite (
>    IN  UINT8   Address,
>    IN  UINT8   Data
>    )
>  {
> -  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8) (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
> +  IoWrite8 (
> +    PcdGet8 (PcdRtcIndexRegister),
> +    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80))
> +    );
>    IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);
>  }
>  
>  /**
> +  Read RTC content through its registers using MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +STATIC
> +UINT8
> +MmioRtcRead (
> +  IN  UINT8 Address
> +  )
> +{
> +  MmioWrite8 (
> +    mRtcRegisterBase,
> +    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
> +    );
> +  return MmioRead8 (
> +           mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
> +             PcdGet8 (PcdRtcIndexRegister))
> +           );
> +}
> +
> +/**
> +  Write RTC through its registers using MMIO access.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +  @param  Data      The content you want to write into RTC.
> +
> +**/
> +STATIC
> +VOID
> +MmioRtcWrite (
> +  IN  UINT8   Address,
> +  IN  UINT8   Data
> +  )
> +{
> +  MmioWrite8 (
> +    mRtcRegisterBase,
> +    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
> +    );
> +  MmioWrite8 (
> +    mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
> +      PcdGet8 (PcdRtcIndexRegister)),
> +    Data
> +    );
> +}
> +
> +/**
>    Initialize RTC.
>  
>    @param  Global            For global use inside this module.
> @@ -113,6 +196,18 @@ PcRtcInit (
>    BOOLEAN         Pending;
>  
>    //
> +  // Initialize the RtcRead and RtcWrite functions
> +  // based on the chosen IO/MMIO access.
> +  //
> +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> +    RtcRead = MmioRtcRead;
> +    RtcWrite = MmioRtcWrite;
> +  } else {
> +    RtcRead = IoRtcRead;
> +    RtcWrite = IoRtcWrite;
> +  }
> +
> +  //
>    // Acquire RTC Lock to make access to RTC atomic
>    //
>    if (!EfiAtRuntime ()) {
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> index 47293ce44c5a1f4792892892f7da40d7f0a5a001..e64dbbea48f7f0d2f317c65c2e4b93e7b1888efc 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> @@ -3,6 +3,7 @@
>  
>  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>  Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.<BR>
>  
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>  
> @@ -371,4 +372,34 @@ PcRtcAcpiTableChangeCallback (
>    IN EFI_EVENT        Event,
>    IN VOID             *Context
>    );
> +
> +/**
> +  Function pointer to Read RTC content through its registers.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +
> +  @return The data of UINT8 type read from RTC.
> +**/
> +typedef
> +UINT8
> +(EFIAPI *RTC_READ) (
> +  IN  UINT8 Address
> +  );
> +
> +/**
> +  Function pointer to Write RTC through its registers.
> +
> +  @param  Address   Address offset of RTC. It is recommended to use
> +                    macros such as RTC_ADDRESS_SECONDS.
> +  @param  Data      The content you want to write into RTC.
> +
> +**/
> +typedef
> +VOID
> +(EFIAPI *RTC_WRITE) (
> +  IN  UINT8   Address,
> +  IN  UINT8   Data
> +  );
> +
>  #endif
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> index ccda6331373bfe4069b0a59495b5e5cc731c8fc8..5d5dbeaf970ca8eb291c1e094fd764d201f9071e 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> @@ -2,16 +2,32 @@
>    Provides Set/Get time operations.
>  
>  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>  
>  **/
>  
> +#include <Library/DxeServicesTableLib.h>
>  #include "PcRtc.h"
>  
>  PC_RTC_MODULE_GLOBALS  mModuleGlobal;
>  
>  EFI_HANDLE             mHandle = NULL;
>  
> +STATIC EFI_EVENT       mVirtualAddrChangeEvent;
> +
> +EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
> +
> +//
> +// Function pointer for the Rtc Read interface function
> +//
> +extern RTC_READ   RtcRead;
> +
> +//
> +// Function pointer for the Rtc Write interface function
> +//
> +extern RTC_WRITE  RtcWrite;
> +
>  /**
>    Returns the current time and date information, and the time-keeping capabilities
>    of the hardware platform.
> @@ -106,6 +122,33 @@ PcRtcEfiSetWakeupTime (
>  }
>  
>  /**
> +  Fixup internal data so that EFI can be called in virtual mode.
> +  Call the passed in Child Notify event and convert any pointers in
> +  lib to virtual mode.
> +
> +  @param[in]    Event   The Event that is being processed
> +  @param[in]    Context Event Context
> +**/
> +VOID
> +EFIAPI
> +LibRtcVirtualNotifyEvent (
> +  IN EFI_EVENT        Event,
> +  IN VOID             *Context
> +  )
> +{
> +  // Only needed if you are going to support the OS calling RTC functions in
> +  // virtual mode. You will need to call EfiConvertPointer (). To convert any
> +  // stored physical addresses to virtual address. After the OS transitions to
> +  // calling in virtual mode, all future runtime calls will be made in virtual
> +  // mode.
> +  EfiConvertPointer (0x0, (VOID**)&mRtcRegisterBase);
> +
> +  // Convert the RtcRead and RtcWrite pointers for runtime use.
> +  EfiConvertPointer (0x0, (VOID**)&RtcRead);
> +  EfiConvertPointer (0x0, (VOID**)&RtcWrite);
> +}
> +
> +/**
>    The user Entry Point for PcRTC module.
>  
>    This is the entry point for PcRTC module. It installs the UEFI runtime service
> @@ -125,12 +168,77 @@ InitializePcRtc (
>    IN EFI_SYSTEM_TABLE                      *SystemTable
>    )
>  {
> -  EFI_STATUS  Status;
> -  EFI_EVENT   Event;
> +  EFI_STATUS             Status;
> +  EFI_EVENT              Event;
> +  EFI_PHYSICAL_ADDRESS   RtcPageBase;
>  
>    EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK);
>    mModuleGlobal.CenturyRtcAddress = GetCenturyRtcAddress ();
>  
> +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> +    mRtcRegisterBase = PcdGet8 (PcdRtcIndexRegister);
> +    RtcPageBase = mRtcRegisterBase & ~(EFI_PAGE_SIZE - 1);
> +
> +    // Declare the controller as EFI_MEMORY_RUNTIME
> +    Status = gDS->AddMemorySpace (
> +                    EfiGcdMemoryTypeMemoryMappedIo,
> +                    RtcPageBase,
> +                    EFI_PAGE_SIZE,
> +                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
> +        Status
> +        ));
> +      return Status;
> +    }
> +
> +    Status = gDS->AllocateMemorySpace (
> +                    EfiGcdAllocateAddress,
> +                    EfiGcdMemoryTypeMemoryMappedIo,
> +                    0,
> +                    EFI_PAGE_SIZE,
> +                    &RtcPageBase,
> +                    ImageHandle,
> +                    NULL
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "Failed to allocate memory space. Status = %r\n",
> +        Status
> +        ));
> +      gDS->RemoveMemorySpace (
> +             RtcPageBase,
> +             EFI_PAGE_SIZE
> +             );
> +      return Status;
> +    }
> +
> +    Status = gDS->SetMemorySpaceAttributes (
> +                    RtcPageBase,
> +                    EFI_PAGE_SIZE,
> +                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> +                    );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((
> +        DEBUG_ERROR,
> +        "Failed to set memory attributes. Status = %r\n",
> +        Status
> +        ));
> +      gDS->FreeMemorySpace (
> +               RtcPageBase,
> +               EFI_PAGE_SIZE
> +               );
> +      gDS->RemoveMemorySpace (
> +             RtcPageBase,
> +             EFI_PAGE_SIZE
> +             );
> +      return Status;
> +    }
> +  }
> +
>    Status = PcRtcInit (&mModuleGlobal);
>    ASSERT_EFI_ERROR (Status);
>  
> @@ -165,7 +273,23 @@ InitializePcRtc (
>                    NULL,
>                    NULL
>                    );
> -  ASSERT_EFI_ERROR (Status);
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> +    // Register for the virtual address change event
> +    Status = gBS->CreateEventEx (
> +                    EVT_NOTIFY_SIGNAL,
> +                    TPL_NOTIFY,
> +                    LibRtcVirtualNotifyEvent,
> +                    NULL,
> +                    &gEfiEventVirtualAddressChangeGuid,
> +                    &mVirtualAddrChangeEvent
> +                    );
> +    ASSERT_EFI_ERROR (Status);
> +  }
>  
>    return Status;
>  }
> diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> index c73ee98105e510f9e4e23c1a6c1e5c505325d2c9..3a373d11f8bfc7df0e4d00be8b43e90bfa06b192 100644
> --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf
> @@ -6,6 +6,7 @@
>  #
>  # Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
>  # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
>  #
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
>  #
> @@ -48,6 +49,7 @@ [LibraryClasses]
>    BaseLib
>    PcdLib
>    ReportStatusCodeLib
> +  DxeServicesTableLib
>  
>  [Protocols]
>    gEfiRealTimeClockArchProtocolGuid             ## PRODUCES
> @@ -61,10 +63,13 @@ [Guids]
>    ## SOMETIMES_CONSUMES ## SystemTable
>    gEfiAcpiTableGuid
>  
> +  gEfiEventVirtualAddressChangeGuid
> +
>  [FixedPcd]
>    gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA     ## CONSUMES
>    gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB     ## CONSUMES
>    gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterD     ## CONSUMES
> +  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio                   ## CONSUMES
>  
>  [Pcd]
>    gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout   ## CONSUMES
> @@ -76,5 +81,8 @@ [Pcd]
>  [Depex]
>    gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
>  
> +[Depex.common.DXE_RUNTIME_DRIVER]
> +  gEfiCpuArchProtocolGuid
> +
>  [UserExtensions.TianoCore."ExtraFiles"]
>    PcRtcExtra.uni
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver
  2020-05-15 10:50   ` André Przywara
@ 2020-05-27  0:37     ` Guomin Jiang
  0 siblings, 0 replies; 40+ messages in thread
From: Guomin Jiang @ 2020-05-27  0:37 UTC (permalink / raw)
  To: devel@edk2.groups.io, andre.przywara@arm.com, Sami Mujawar
  Cc: ard.biesheuvel@arm.com, leif@nuviainc.com, Ni, Ray,
	Alexandru.Elisei@arm.com, Matteo.Carlini@arm.com,
	Laura.Moretta@arm.com, nd@arm.com

I am interest with the patch,

I am busy and may review it after August.

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of André
> Przywara
> Sent: Friday, May 15, 2020 6:51 PM
> To: Sami Mujawar <sami.mujawar@arm.com>; devel@edk2.groups.io
> Cc: ard.biesheuvel@arm.com; leif@nuviainc.com; Ni, Ray
> <ray.ni@intel.com>; Alexandru.Elisei@arm.com; Matteo.Carlini@arm.com;
> Laura.Moretta@arm.com; nd@arm.com
> Subject: Re: [edk2-devel] [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO
> Support to RTC driver
> 
> On 14/05/2020 09:40, Sami Mujawar wrote:
> 
> Hi Sami,
> 
> many thanks for your work on that!
> 
> > Some virtual machine managers like kvmtool emulate the MC146818 RTC
> > controller in the MMIO space so that architectures that do not support
> > I/O Mapped I/O can use the RTC. This patch adds MMIO support to the
> > RTC controller driver.
> 
> Is there any chance you could read the MMIO base address from the DT? I
> sent a kvmtool patch to add the missing DT node[1].
> The compatible string would be "motorola,mc146818", with just the usual reg
> property.
> Maybe you could fall back to the current 0x70/0x71, if there is no DT node?
> 
> For a start, this low address (0x70/0x71) causes issues, so we probably need
> to move this permanently.
> But also we want to introduce a more flexible memory layout, so devices can
> move depending on command line parameters.
> 
> It would be great if EDK-2 could cover that from the beginning, so that we
> don't end up with compatibility issues.
> 
> Cheers,
> Andre
> 
> [1] https://lists.cs.columbia.edu/pipermail/kvmarm/2020-May/040703.html
> >
> > The PCD PcdRtcUseMmio has been added to select I/O or MMIO support.
> >   If PcdRtcUseMmio is:
> >     TRUE  - Indicates the RTC port registers are in MMIO space.
> >     FALSE - Indicates the RTC port registers are in I/O space.
> >             Default is I/O space.
> >
> > When MMIO support is selected (PcdRtcUseMmio == TRUE) the driver
> maps
> > the MMIO region used by the RTC as runtime memory so that the RTC
> > registers are accessible post ExitBootServices.
> >
> > Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> > ---
> >
> > Notes:
> >     v2:
> >       - Code review comments incorporated.                              [Sami]
> >
> >     v1:
> >       - Add support to read/write from RTC registers using MMIO access
> [Sami]
> >       - Use wrapper functions for RtcRead/Write accessors               [Leif]
> >         Ref: https://edk2.groups.io/g/devel/topic/30915281#30695
> >
> >  PcAtChipsetPkg/PcAtChipsetPkg.dec                                          |   8 ++
> >  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c                         | 117
> ++++++++++++++++--
> >  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h                         |  31
> +++++
> >  PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c                    |
> 130 +++++++++++++++++++-
> >
> PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntime
> Dxe.inf |   8 ++
> >  5 files changed, 280 insertions(+), 14 deletions(-)
> >
> > diff --git a/PcAtChipsetPkg/PcAtChipsetPkg.dec
> > b/PcAtChipsetPkg/PcAtChipsetPkg.dec
> > index
> >
> 88de5cceea593176c3a2425a5963b66b789f2b9e..76d0c7eda69bb505914ba904
> e09c
> > 89de170f69ae 100644
> > --- a/PcAtChipsetPkg/PcAtChipsetPkg.dec
> > +++ b/PcAtChipsetPkg/PcAtChipsetPkg.dec
> > @@ -6,6 +6,7 @@
> >  #
> >  # Copyright (c) 2009 - 2019, Intel Corporation. All rights
> > reserved.<BR>  # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> > +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
> >  #
> >  # SPDX-License-Identifier: BSD-2-Clause-Patent  # @@ -142,5 +143,12
> > @@ [PcdsFixedAtBuild, PcdsPatchableInModule]
> >    # @Prompt RTC Update Timeout Value.
> >
> >
> gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout|100000
> |UIN
> > T32|0x00000020
> >
> > +  ## Indicates the RTC port registers are in MMIO space, or in I/O space.
> > +  #  Default is I/O space.<BR><BR>
> > +  #   TRUE  - RTC port registers are in MMIO space.<BR>
> > +  #   FALSE - RTC port registers are in I/O space.<BR>
> > +  # @Prompt RTC port registers use MMIO.
> > +
> > +
> gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio|FALSE|BOOLEAN|0x0000
> 0021
> > +
> >  [UserExtensions.TianoCore."ExtraFiles"]
> >    PcAtChipsetPkgExtra.uni
> > diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> > b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> > index
> >
> 52af17941786ef81c3911512ee64551724e67209..df8dea83ab27bbba12351096d
> 1bf
> > d9ea31accb60 100644
> > --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> > +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.c
> > @@ -3,6 +3,7 @@
> >
> >  Copyright (c) 2006 - 2018, Intel Corporation. All rights
> > reserved.<BR>  Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> > +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
> >
> >  SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > @@ -10,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> >  #include "PcRtc.h"
> >
> > +extern EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
> > +
> >  //
> >  // Days of month.
> >  //
> > @@ -21,6 +24,28 @@ UINTN mDayOfMonth[] = { 31, 29, 31, 30, 31, 30, 31,
> > 31, 30, 31, 30, 31 };
> >  CHAR16 mTimeZoneVariableName[] = L"RTC";
> >
> >  /**
> > +  A function pointer that evaluates to a function that reads the RTC
> > + content  through its registers either using IO or MMIO access.
> > +
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +
> > +  @return The data of UINT8 type read from RTC.
> > +**/
> > +RTC_READ  RtcRead;
> > +
> > +/**
> > +  A function pointer that evaluates to a function that reads the RTC
> > +content
> > +  through its registers either using IO or MMIO access.
> > +
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +
> > +  @return The data of UINT8 type read from RTC.
> > +**/
> > +RTC_WRITE RtcWrite;
> > +
> > +/**
> >    Compare the Hour, Minute and Second of the From time and the To time.
> >
> >    Only compare H/M/S in EFI_TIME and ignore other fields here.
> > @@ -54,41 +79,99 @@ IsWithinOneDay (
> >    );
> >
> >  /**
> > -  Read RTC content through its registers.
> > +  Read RTC content through its registers using IO access.
> >
> > -  @param  Address  Address offset of RTC. It is recommended to use
> macros such as
> > -                   RTC_ADDRESS_SECONDS.
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> >
> >    @return The data of UINT8 type read from RTC.
> >  **/
> > +STATIC
> >  UINT8
> > -RtcRead (
> > +IoRtcRead (
> >    IN  UINT8 Address
> >    )
> >  {
> > -  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8)
> > (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
> > +  IoWrite8 (
> > +    PcdGet8 (PcdRtcIndexRegister),
> > +    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) &
> 0x80))
> > +    );
> >    return IoRead8 (PcdGet8 (PcdRtcTargetRegister));  }
> >
> >  /**
> > -  Write RTC through its registers.
> > +  Write RTC through its registers  using IO access.
> >
> > -  @param  Address  Address offset of RTC. It is recommended to use
> macros such as
> > -                   RTC_ADDRESS_SECONDS.
> > -  @param  Data     The content you want to write into RTC.
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +  @param  Data      The content you want to write into RTC.
> >
> >  **/
> > +STATIC
> >  VOID
> > -RtcWrite (
> > +IoRtcWrite (
> >    IN  UINT8   Address,
> >    IN  UINT8   Data
> >    )
> >  {
> > -  IoWrite8 (PcdGet8 (PcdRtcIndexRegister), (UINT8) (Address | (UINT8)
> > (IoRead8 (PcdGet8 (PcdRtcIndexRegister)) & 0x80)));
> > +  IoWrite8 (
> > +    PcdGet8 (PcdRtcIndexRegister),
> > +    (UINT8)(Address | (UINT8)(IoRead8 (PcdGet8 (PcdRtcIndexRegister)) &
> 0x80))
> > +    );
> >    IoWrite8 (PcdGet8 (PcdRtcTargetRegister), Data);  }
> >
> >  /**
> > +  Read RTC content through its registers using MMIO access.
> > +
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +
> > +  @return The data of UINT8 type read from RTC.
> > +**/
> > +STATIC
> > +UINT8
> > +MmioRtcRead (
> > +  IN  UINT8 Address
> > +  )
> > +{
> > +  MmioWrite8 (
> > +    mRtcRegisterBase,
> > +    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
> > +    );
> > +  return MmioRead8 (
> > +           mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
> > +             PcdGet8 (PcdRtcIndexRegister))
> > +           );
> > +}
> > +
> > +/**
> > +  Write RTC through its registers using MMIO access.
> > +
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +  @param  Data      The content you want to write into RTC.
> > +
> > +**/
> > +STATIC
> > +VOID
> > +MmioRtcWrite (
> > +  IN  UINT8   Address,
> > +  IN  UINT8   Data
> > +  )
> > +{
> > +  MmioWrite8 (
> > +    mRtcRegisterBase,
> > +    (UINT8)(Address | (UINT8)(MmioRead8 (mRtcRegisterBase) & 0x80))
> > +    );
> > +  MmioWrite8 (
> > +    mRtcRegisterBase + (PcdGet8 (PcdRtcTargetRegister) -
> > +      PcdGet8 (PcdRtcIndexRegister)),
> > +    Data
> > +    );
> > +}
> > +
> > +/**
> >    Initialize RTC.
> >
> >    @param  Global            For global use inside this module.
> > @@ -113,6 +196,18 @@ PcRtcInit (
> >    BOOLEAN         Pending;
> >
> >    //
> > +  // Initialize the RtcRead and RtcWrite functions  // based on the
> > + chosen IO/MMIO access.
> > +  //
> > +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> > +    RtcRead = MmioRtcRead;
> > +    RtcWrite = MmioRtcWrite;
> > +  } else {
> > +    RtcRead = IoRtcRead;
> > +    RtcWrite = IoRtcWrite;
> > +  }
> > +
> > +  //
> >    // Acquire RTC Lock to make access to RTC atomic
> >    //
> >    if (!EfiAtRuntime ()) {
> > diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> > b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> > index
> >
> 47293ce44c5a1f4792892892f7da40d7f0a5a001..e64dbbea48f7f0d2f317c65c2e
> 4b
> > 93e7b1888efc 100644
> > --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> > +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtc.h
> > @@ -3,6 +3,7 @@
> >
> >  Copyright (c) 2006 - 2018, Intel Corporation. All rights
> > reserved.<BR>  Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> > +Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.<BR>
> >
> >  SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > @@ -371,4 +372,34 @@ PcRtcAcpiTableChangeCallback (
> >    IN EFI_EVENT        Event,
> >    IN VOID             *Context
> >    );
> > +
> > +/**
> > +  Function pointer to Read RTC content through its registers.
> > +
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +
> > +  @return The data of UINT8 type read from RTC.
> > +**/
> > +typedef
> > +UINT8
> > +(EFIAPI *RTC_READ) (
> > +  IN  UINT8 Address
> > +  );
> > +
> > +/**
> > +  Function pointer to Write RTC through its registers.
> > +
> > +  @param  Address   Address offset of RTC. It is recommended to use
> > +                    macros such as RTC_ADDRESS_SECONDS.
> > +  @param  Data      The content you want to write into RTC.
> > +
> > +**/
> > +typedef
> > +VOID
> > +(EFIAPI *RTC_WRITE) (
> > +  IN  UINT8   Address,
> > +  IN  UINT8   Data
> > +  );
> > +
> >  #endif
> > diff --git a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> > b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> > index
> >
> ccda6331373bfe4069b0a59495b5e5cc731c8fc8..5d5dbeaf970ca8eb291c1e094f
> d7
> > 64d201f9071e 100644
> > --- a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> > +++ b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcRtcEntry.c
> > @@ -2,16 +2,32 @@
> >    Provides Set/Get time operations.
> >
> >  Copyright (c) 2006 - 2018, Intel Corporation. All rights
> > reserved.<BR>
> > +Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.<BR>
> >  SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> >  **/
> >
> > +#include <Library/DxeServicesTableLib.h>
> >  #include "PcRtc.h"
> >
> >  PC_RTC_MODULE_GLOBALS  mModuleGlobal;
> >
> >  EFI_HANDLE             mHandle = NULL;
> >
> > +STATIC EFI_EVENT       mVirtualAddrChangeEvent;
> > +
> > +EFI_PHYSICAL_ADDRESS   mRtcRegisterBase;
> > +
> > +//
> > +// Function pointer for the Rtc Read interface function //
> > +extern RTC_READ   RtcRead;
> > +
> > +//
> > +// Function pointer for the Rtc Write interface function // extern
> > +RTC_WRITE  RtcWrite;
> > +
> >  /**
> >    Returns the current time and date information, and the time-keeping
> capabilities
> >    of the hardware platform.
> > @@ -106,6 +122,33 @@ PcRtcEfiSetWakeupTime (  }
> >
> >  /**
> > +  Fixup internal data so that EFI can be called in virtual mode.
> > +  Call the passed in Child Notify event and convert any pointers in
> > + lib to virtual mode.
> > +
> > +  @param[in]    Event   The Event that is being processed
> > +  @param[in]    Context Event Context
> > +**/
> > +VOID
> > +EFIAPI
> > +LibRtcVirtualNotifyEvent (
> > +  IN EFI_EVENT        Event,
> > +  IN VOID             *Context
> > +  )
> > +{
> > +  // Only needed if you are going to support the OS calling RTC
> > +functions in
> > +  // virtual mode. You will need to call EfiConvertPointer (). To
> > +convert any
> > +  // stored physical addresses to virtual address. After the OS
> > +transitions to
> > +  // calling in virtual mode, all future runtime calls will be made
> > +in virtual
> > +  // mode.
> > +  EfiConvertPointer (0x0, (VOID**)&mRtcRegisterBase);
> > +
> > +  // Convert the RtcRead and RtcWrite pointers for runtime use.
> > +  EfiConvertPointer (0x0, (VOID**)&RtcRead);
> > +  EfiConvertPointer (0x0, (VOID**)&RtcWrite); }
> > +
> > +/**
> >    The user Entry Point for PcRTC module.
> >
> >    This is the entry point for PcRTC module. It installs the UEFI
> > runtime service @@ -125,12 +168,77 @@ InitializePcRtc (
> >    IN EFI_SYSTEM_TABLE                      *SystemTable
> >    )
> >  {
> > -  EFI_STATUS  Status;
> > -  EFI_EVENT   Event;
> > +  EFI_STATUS             Status;
> > +  EFI_EVENT              Event;
> > +  EFI_PHYSICAL_ADDRESS   RtcPageBase;
> >
> >    EfiInitializeLock (&mModuleGlobal.RtcLock, TPL_CALLBACK);
> >    mModuleGlobal.CenturyRtcAddress = GetCenturyRtcAddress ();
> >
> > +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> > +    mRtcRegisterBase = PcdGet8 (PcdRtcIndexRegister);
> > +    RtcPageBase = mRtcRegisterBase & ~(EFI_PAGE_SIZE - 1);
> > +
> > +    // Declare the controller as EFI_MEMORY_RUNTIME
> > +    Status = gDS->AddMemorySpace (
> > +                    EfiGcdMemoryTypeMemoryMappedIo,
> > +                    RtcPageBase,
> > +                    EFI_PAGE_SIZE,
> > +                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> > +                    );
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((
> > +        DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
> > +        Status
> > +        ));
> > +      return Status;
> > +    }
> > +
> > +    Status = gDS->AllocateMemorySpace (
> > +                    EfiGcdAllocateAddress,
> > +                    EfiGcdMemoryTypeMemoryMappedIo,
> > +                    0,
> > +                    EFI_PAGE_SIZE,
> > +                    &RtcPageBase,
> > +                    ImageHandle,
> > +                    NULL
> > +                    );
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((
> > +        DEBUG_ERROR,
> > +        "Failed to allocate memory space. Status = %r\n",
> > +        Status
> > +        ));
> > +      gDS->RemoveMemorySpace (
> > +             RtcPageBase,
> > +             EFI_PAGE_SIZE
> > +             );
> > +      return Status;
> > +    }
> > +
> > +    Status = gDS->SetMemorySpaceAttributes (
> > +                    RtcPageBase,
> > +                    EFI_PAGE_SIZE,
> > +                    EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
> > +                    );
> > +    if (EFI_ERROR (Status)) {
> > +      DEBUG ((
> > +        DEBUG_ERROR,
> > +        "Failed to set memory attributes. Status = %r\n",
> > +        Status
> > +        ));
> > +      gDS->FreeMemorySpace (
> > +               RtcPageBase,
> > +               EFI_PAGE_SIZE
> > +               );
> > +      gDS->RemoveMemorySpace (
> > +             RtcPageBase,
> > +             EFI_PAGE_SIZE
> > +             );
> > +      return Status;
> > +    }
> > +  }
> > +
> >    Status = PcRtcInit (&mModuleGlobal);
> >    ASSERT_EFI_ERROR (Status);
> >
> > @@ -165,7 +273,23 @@ InitializePcRtc (
> >                    NULL,
> >                    NULL
> >                    );
> > -  ASSERT_EFI_ERROR (Status);
> > +  if (EFI_ERROR (Status)) {
> > +    ASSERT_EFI_ERROR (Status);
> > +    return Status;
> > +  }
> > +
> > +  if (FixedPcdGetBool (PcdRtcUseMmio)) {
> > +    // Register for the virtual address change event
> > +    Status = gBS->CreateEventEx (
> > +                    EVT_NOTIFY_SIGNAL,
> > +                    TPL_NOTIFY,
> > +                    LibRtcVirtualNotifyEvent,
> > +                    NULL,
> > +                    &gEfiEventVirtualAddressChangeGuid,
> > +                    &mVirtualAddrChangeEvent
> > +                    );
> > +    ASSERT_EFI_ERROR (Status);
> > +  }
> >
> >    return Status;
> >  }
> > diff --git
> >
> a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntim
> eD
> > xe.inf
> >
> b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntim
> eD
> > xe.inf index
> >
> c73ee98105e510f9e4e23c1a6c1e5c505325d2c9..3a373d11f8bfc7df0e4d00be8
> b43
> > e90bfa06b192 100644
> > ---
> >
> a/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntim
> eD
> > xe.inf
> > +++
> b/PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRunt
> > +++ imeDxe.inf
> > @@ -6,6 +6,7 @@
> >  #
> >  # Copyright (c) 2006 - 2019, Intel Corporation. All rights
> > reserved.<BR>  # Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
> > +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR>
> >  #
> >  # SPDX-License-Identifier: BSD-2-Clause-Patent  # @@ -48,6 +49,7 @@
> > [LibraryClasses]
> >    BaseLib
> >    PcdLib
> >    ReportStatusCodeLib
> > +  DxeServicesTableLib
> >
> >  [Protocols]
> >    gEfiRealTimeClockArchProtocolGuid             ## PRODUCES
> > @@ -61,10 +63,13 @@ [Guids]
> >    ## SOMETIMES_CONSUMES ## SystemTable
> >    gEfiAcpiTableGuid
> >
> > +  gEfiEventVirtualAddressChangeGuid
> > +
> >  [FixedPcd]
> >    gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterA     ##
> CONSUMES
> >    gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterB     ##
> CONSUMES
> >    gPcAtChipsetPkgTokenSpaceGuid.PcdInitialValueRtcRegisterD     ##
> CONSUMES
> > +  gPcAtChipsetPkgTokenSpaceGuid.PcdRtcUseMmio                   ##
> CONSUMES
> >
> >  [Pcd]
> >    gPcAtChipsetPkgTokenSpaceGuid.PcdRealTimeClockUpdateTimeout   ##
> CONSUMES
> > @@ -76,5 +81,8 @@ [Pcd]
> >  [Depex]
> >    gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
> >
> > +[Depex.common.DXE_RUNTIME_DRIVER]
> > +  gEfiCpuArchProtocolGuid
> > +
> >  [UserExtensions.TianoCore."ExtraFiles"]
> >    PcRtcExtra.uni
> >
> 
> 
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base
  2020-05-14  8:40 ` [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base Sami Mujawar
  2020-05-14  9:24   ` Ard Biesheuvel
@ 2020-05-27 11:48   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 40+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-05-27 11:48 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Some virtual machine managers like kvmtool can relocate
> the devices in the system memory map. The information
> about the devices location in memory is described in the
> device tree. Therefore, the CFI memory region and the
> associated Non volatile storage variables need to be
> adjusted accordingly.
> 
> To support such use cases the non-volatile storage
> variable base PCD PcdFlashNvStorageVariableBase has
> been defined as a dynamic PCD.
> 
> The NOR flash driver was using the Flash non-volatile
> storage variable base PCD as a fixed PCD, thereby
> preventing runtime resolution of the variable base
> address.
> 
> Therefore update the NOR flash driver to load the
> PCD using PcdGet32 instead of FixedPcdGet32.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
> index e248fdf6db94191648b5d33bf1a9263f446ee141..9cdd85096a463f69b3b864cecdeaf247e65f4f73 100644
> --- a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
> +++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
> @@ -1,6 +1,6 @@
>  /*++ @file  NorFlashFvbDxe.c
>  
> - Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
> + Copyright (c) 2011 - 2020, ARM Ltd. All rights reserved.<BR>
>  
>   SPDX-License-Identifier: BSD-2-Clause-Patent
>  
> @@ -736,7 +736,7 @@ NorFlashFvbInitialize (
>        EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
>    ASSERT_EFI_ERROR (Status);
>  
> -  mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
> +  mFlashNvStorageVariableBase = PcdGet32 (PcdFlashNvStorageVariableBase);
>  
>    // Set the index of the first LBA for the FVB
>    Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize;
> 

Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib
  2020-05-14  8:40 ` [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib Sami Mujawar
  2020-05-14  9:32   ` Ard Biesheuvel
@ 2020-05-27 11:59   ` Philippe Mathieu-Daudé
  2020-06-04  6:30     ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 40+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-05-27 11:59 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, lersek, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

Hi Sami,

On 5/14/20 10:40 AM, Sami Mujawar wrote:
> Kvmtool places the base address of the CFI flash in
> the device tree it passes to UEFI. This library
> parses the kvmtool device tree to read the CFI base
> address and initialise the PCDs use by the NOR flash
> driver and the variable storage.
> 
> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
> ---
>  ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c      | 265 ++++++++++++++++++++
>  ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf |  50 ++++
>  2 files changed, 315 insertions(+)
> 
> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..2e43c2e21bc9ef7dd1dd198eebbd70c3b0b96d1c
> --- /dev/null
> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
> @@ -0,0 +1,265 @@
> +/** @file
> +   An instance of the NorFlashPlatformLib for Kvmtool platform.
> +
> + Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + **/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/NorFlashPlatformLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Protocol/FdtClient.h>
> +
> +/** Macro defining the maximum number of Flash Banks.
> + */
> +#define MAX_FLASH_BANKS       4
> +
> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];

This is confuse, the macro define 4 banks to a flash device, but then
you declare an array of 4 flash devices.

I'm even more confused because I'm only aware of 2 devices on the Virt
machine. What am I missing?

> +STATIC UINTN                  mNorFlashDeviceCount = 0;
> +
> +/** This function performs platform specific actions to initialise
> +    the NOR flash, if required.
> +
> +  @retval EFI_SUCCESS           Success.
> +**/
> +EFI_STATUS
> +NorFlashPlatformInitialization (
> +  VOID
> +  )
> +{
> +  DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
> +  // Nothing to do here
> +  return EFI_SUCCESS;
> +}
> +
> +/** Initialise Non volatile Flash storage variables.
> +
> +  @param [in]  FlashDevice Pointer to the NOR Flash device.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
> +  @retval EFI_OUT_OF_RESOURCES  Insufficient flash storage space.
> +**/
> +EFI_STATUS
> +SetupVariableStore (
> +  IN NOR_FLASH_DESCRIPTION * FlashDevice
> +  )
> +{
> +  UINTN   FlashRegion;
> +  UINTN   FlashNvStorageVariableBase;
> +  UINTN   FlashNvStorageFtwWorkingBase;
> +  UINTN   FlashNvStorageFtwSpareBase;
> +  UINTN   FlashNvStorageVariableSize;
> +  UINTN   FlashNvStorageFtwWorkingSize;
> +  UINTN   FlashNvStorageFtwSpareSize;
> +
> +  FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
> +  FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
> +  FlashNvStorageFtwSpareSize =  PcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> +  if ((FlashNvStorageVariableSize == 0)   ||
> +      (FlashNvStorageFtwWorkingSize == 0) ||
> +      (FlashNvStorageFtwSpareSize == 0)) {
> +    DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Setup the variable store
> +  FlashRegion = FlashDevice->DeviceBaseAddress;
> +
> +  FlashNvStorageVariableBase = FlashRegion;
> +  FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
> +
> +  FlashNvStorageFtwWorkingBase = FlashRegion;
> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
> +
> +  FlashNvStorageFtwSpareBase = FlashRegion;
> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> +  if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
> +    DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  PcdSet32S (
> +    PcdFlashNvStorageVariableBase,
> +    FlashNvStorageVariableBase
> +    );
> +
> +  PcdSet32S (
> +    PcdFlashNvStorageFtwWorkingBase,
> +    FlashNvStorageFtwWorkingBase
> +    );
> +
> +  PcdSet32S (
> +    PcdFlashNvStorageFtwSpareBase,
> +    FlashNvStorageFtwSpareBase
> +    );
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageVariableBase = 0x%x\n",
> +    FlashNvStorageVariableBase
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageVariableSize = 0x%x\n",
> +    FlashNvStorageVariableSize
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
> +    FlashNvStorageFtwWorkingBase
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
> +    FlashNvStorageFtwWorkingSize
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
> +    FlashNvStorageFtwSpareBase
> +    ));
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
> +    FlashNvStorageFtwSpareSize
> +    ));
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/** Return the Flash devices on the platform.
> +
> +  @param [out]  NorFlashDescriptions    Pointer to the Flash device description.
> +  @param [out]  Count                   Number of Flash devices.
> +
> +  @retval EFI_SUCCESS           Success.
> +  @retval EFI_NOT_FOUND         Flash device not found.
> +**/
> +EFI_STATUS
> +NorFlashPlatformGetDevices (
> +  OUT NOR_FLASH_DESCRIPTION   **NorFlashDescriptions,
> +  OUT UINT32                  *Count
> +  )
> +{
> +  if (mNorFlashDeviceCount > 0) {
> +    *NorFlashDescriptions = mNorFlashDevices;
> +    *Count = mNorFlashDeviceCount;
> +    return EFI_SUCCESS;
> +  }
> +  return EFI_NOT_FOUND;
> +}
> +
> +/** Entrypoint for NorFlashPlatformLib.
> +
> +  @param [in]  ImageHandle  The handle to the image.
> +  @param [in]  SystemTable  Pointer to the System Table.
> +
> +  @retval EFI_SUCCESS             Success.
> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
> +  @retval EFI_NOT_FOUND           Flash device not found.
> +**/
> +EFI_STATUS
> +EFIAPI
> +NorFlashPlatformLibConstructor (
> +  IN  EFI_HANDLE          ImageHandle,
> +  IN  EFI_SYSTEM_TABLE  * SystemTable
> +  )
> +{
> +  FDT_CLIENT_PROTOCOL         *FdtClient;
> +  INT32                       Node;
> +  EFI_STATUS                  Status;
> +  EFI_STATUS                  FindNodeStatus;
> +  CONST UINT32                *Reg;
> +  UINT32                      PropSize;
> +  UINT64                      Base;
> +  UINT64                      Size;
> +
> +  if (mNorFlashDeviceCount != 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Status = gBS->LocateProtocol (
> +                  &gFdtClientProtocolGuid,
> +                  NULL,
> +                  (VOID **)&FdtClient
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    ASSERT_EFI_ERROR (Status);
> +    return Status;
> +  }
> +
> +  for (FindNodeStatus = FdtClient->FindCompatibleNode (
> +                                     FdtClient,
> +                                     "cfi-flash",
> +                                     &Node
> +                                     );
> +       !EFI_ERROR (FindNodeStatus) && (mNorFlashDeviceCount < MAX_FLASH_BANKS);
> +       FindNodeStatus = FdtClient->FindNextCompatibleNode (
> +                                     FdtClient,
> +                                     "cfi-flash",
> +                                     Node,
> +                                     &Node
> +    )) {
> +    Status = FdtClient->GetNodeProperty (
> +                          FdtClient,
> +                          Node,
> +                          "reg",
> +                          (CONST VOID **)&Reg,
> +                          &PropSize
> +                          );
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
> +        __FUNCTION__, Status));
> +      continue;
> +    }
> +
> +    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
> +
> +    while ((PropSize >= (4 * sizeof (UINT32))) &&
> +           (mNorFlashDeviceCount < MAX_FLASH_BANKS)) {
> +      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
> +      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
> +      Reg += 4;
> +
> +      PropSize -= 4 * sizeof (UINT32);
> +
> +      //
> +      // Disregard any flash devices that overlap with the primary FV.
> +      // The firmware is not updatable from inside the guest anyway.
> +      //
> +      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
> +          (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {
> +        continue;
> +      }
> +
> +      DEBUG ((
> +        DEBUG_INFO,
> +        "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
> +        mNorFlashDeviceCount,
> +        Base,
> +        Size
> +        ));
> +
> +      mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
> +      mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
> +      mNorFlashDevices[mNorFlashDeviceCount].Size              = (UINTN)Size;
> +      mNorFlashDevices[mNorFlashDeviceCount].BlockSize         = SIZE_256KB;

Hmm I'm worried that there is no contract enforcing the Virt machine to
use 256KiB sectors. Can we add a definition elsewhere and use it here,
instead of burying the fixed sector size here?

> +      mNorFlashDeviceCount++;
> +    }
> +  }
> +
> +  // Setup the variable store in the last bank
> +  if ((mNorFlashDeviceCount > 0) &&
> +      (mNorFlashDevices[mNorFlashDeviceCount - 1].DeviceBaseAddress != 0)) {
> +    return SetupVariableStore (&mNorFlashDevices[mNorFlashDeviceCount - 1]);
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
> new file mode 100644
> index 0000000000000000000000000000000000000000..8bd6f730dcb52e597b418e59766c1566a9519789
> --- /dev/null
> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
> @@ -0,0 +1,50 @@
> +#/** @file
> +#
> +#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = NorFlashKvmtoolLib
> +  FILE_GUID                      = E75F07A1-B160-4893-BDD4-09E32FF847DC
> +  MODULE_TYPE                    = DXE_DRIVER
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = NorFlashPlatformLib
> +  CONSTRUCTOR                    = NorFlashPlatformLibConstructor
> +
> +[Sources.common]
> +  NorFlashKvmtool.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  ArmVirtPkg/ArmVirtPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  DebugLib
> +  PcdLib
> +  UefiBootServicesTableLib
> +
> +[Protocols]
> +  gFdtClientProtocolGuid          ## CONSUMES
> +
> +[Pcd]
> +  gArmTokenSpaceGuid.PcdFvBaseAddress
> +  gArmTokenSpaceGuid.PcdFvSize
> +
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +
> +[Depex]
> +  gFdtClientProtocolGuid
> +
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib
  2020-05-27 11:59   ` Philippe Mathieu-Daudé
@ 2020-06-04  6:30     ` Philippe Mathieu-Daudé
  2020-06-04 15:00       ` Sami Mujawar
  0 siblings, 1 reply; 40+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-06-04  6:30 UTC (permalink / raw)
  To: devel, sami.mujawar
  Cc: ard.biesheuvel, leif, lersek, Alexandru.Elisei, Andre.Przywara,
	Matteo.Carlini, Laura.Moretta, nd

On 5/27/20 1:59 PM, Philippe Mathieu-Daudé wrote:
> Hi Sami,
> 
> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>> Kvmtool places the base address of the CFI flash in
>> the device tree it passes to UEFI. This library
>> parses the kvmtool device tree to read the CFI base
>> address and initialise the PCDs use by the NOR flash
>> driver and the variable storage.
>>
>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>> ---
>>  ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c      | 265 ++++++++++++++++++++
>>  ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf |  50 ++++
>>  2 files changed, 315 insertions(+)
>>
>> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..2e43c2e21bc9ef7dd1dd198eebbd70c3b0b96d1c
>> --- /dev/null
>> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> @@ -0,0 +1,265 @@
>> +/** @file
>> +   An instance of the NorFlashPlatformLib for Kvmtool platform.
>> +
>> + Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> + **/
>> +
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/NorFlashPlatformLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Protocol/FdtClient.h>
>> +
>> +/** Macro defining the maximum number of Flash Banks.
>> + */
>> +#define MAX_FLASH_BANKS       4
>> +
>> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];
> 
> This is confuse, the macro define 4 banks to a flash device, but then
> you declare an array of 4 flash devices.
> 
> I'm even more confused because I'm only aware of 2 devices on the Virt
> machine. What am I missing?

Pinging again in case this question has been missed.

> 
>> +STATIC UINTN                  mNorFlashDeviceCount = 0;
>> +
>> +/** This function performs platform specific actions to initialise
>> +    the NOR flash, if required.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +**/
>> +EFI_STATUS
>> +NorFlashPlatformInitialization (
>> +  VOID
>> +  )
>> +{
>> +  DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
>> +  // Nothing to do here
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/** Initialise Non volatile Flash storage variables.
>> +
>> +  @param [in]  FlashDevice Pointer to the NOR Flash device.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
>> +  @retval EFI_OUT_OF_RESOURCES  Insufficient flash storage space.
>> +**/
>> +EFI_STATUS
>> +SetupVariableStore (
>> +  IN NOR_FLASH_DESCRIPTION * FlashDevice
>> +  )
>> +{
>> +  UINTN   FlashRegion;
>> +  UINTN   FlashNvStorageVariableBase;
>> +  UINTN   FlashNvStorageFtwWorkingBase;
>> +  UINTN   FlashNvStorageFtwSpareBase;
>> +  UINTN   FlashNvStorageVariableSize;
>> +  UINTN   FlashNvStorageFtwWorkingSize;
>> +  UINTN   FlashNvStorageFtwSpareSize;
>> +
>> +  FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
>> +  FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
>> +  FlashNvStorageFtwSpareSize =  PcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  if ((FlashNvStorageVariableSize == 0)   ||
>> +      (FlashNvStorageFtwWorkingSize == 0) ||
>> +      (FlashNvStorageFtwSpareSize == 0)) {
>> +    DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  // Setup the variable store
>> +  FlashRegion = FlashDevice->DeviceBaseAddress;
>> +
>> +  FlashNvStorageVariableBase = FlashRegion;
>> +  FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
>> +
>> +  FlashNvStorageFtwWorkingBase = FlashRegion;
>> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
>> +
>> +  FlashNvStorageFtwSpareBase = FlashRegion;
>> +  FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
>> +    DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageVariableBase,
>> +    FlashNvStorageVariableBase
>> +    );
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageFtwWorkingBase,
>> +    FlashNvStorageFtwWorkingBase
>> +    );
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageFtwSpareBase,
>> +    FlashNvStorageFtwSpareBase
>> +    );
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageVariableBase = 0x%x\n",
>> +    FlashNvStorageVariableBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageVariableSize = 0x%x\n",
>> +    FlashNvStorageVariableSize
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
>> +    FlashNvStorageFtwWorkingBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
>> +    FlashNvStorageFtwWorkingSize
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
>> +    FlashNvStorageFtwSpareBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
>> +    FlashNvStorageFtwSpareSize
>> +    ));
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/** Return the Flash devices on the platform.
>> +
>> +  @param [out]  NorFlashDescriptions    Pointer to the Flash device description.
>> +  @param [out]  Count                   Number of Flash devices.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +  @retval EFI_NOT_FOUND         Flash device not found.
>> +**/
>> +EFI_STATUS
>> +NorFlashPlatformGetDevices (
>> +  OUT NOR_FLASH_DESCRIPTION   **NorFlashDescriptions,
>> +  OUT UINT32                  *Count
>> +  )
>> +{
>> +  if (mNorFlashDeviceCount > 0) {
>> +    *NorFlashDescriptions = mNorFlashDevices;
>> +    *Count = mNorFlashDeviceCount;
>> +    return EFI_SUCCESS;
>> +  }
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> +/** Entrypoint for NorFlashPlatformLib.
>> +
>> +  @param [in]  ImageHandle  The handle to the image.
>> +  @param [in]  SystemTable  Pointer to the System Table.
>> +
>> +  @retval EFI_SUCCESS             Success.
>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>> +  @retval EFI_NOT_FOUND           Flash device not found.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NorFlashPlatformLibConstructor (
>> +  IN  EFI_HANDLE          ImageHandle,
>> +  IN  EFI_SYSTEM_TABLE  * SystemTable
>> +  )
>> +{
>> +  FDT_CLIENT_PROTOCOL         *FdtClient;
>> +  INT32                       Node;
>> +  EFI_STATUS                  Status;
>> +  EFI_STATUS                  FindNodeStatus;
>> +  CONST UINT32                *Reg;
>> +  UINT32                      PropSize;
>> +  UINT64                      Base;
>> +  UINT64                      Size;
>> +
>> +  if (mNorFlashDeviceCount != 0) {
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  Status = gBS->LocateProtocol (
>> +                  &gFdtClientProtocolGuid,
>> +                  NULL,
>> +                  (VOID **)&FdtClient
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    ASSERT_EFI_ERROR (Status);
>> +    return Status;
>> +  }
>> +
>> +  for (FindNodeStatus = FdtClient->FindCompatibleNode (
>> +                                     FdtClient,
>> +                                     "cfi-flash",
>> +                                     &Node
>> +                                     );
>> +       !EFI_ERROR (FindNodeStatus) && (mNorFlashDeviceCount < MAX_FLASH_BANKS);
>> +       FindNodeStatus = FdtClient->FindNextCompatibleNode (
>> +                                     FdtClient,
>> +                                     "cfi-flash",
>> +                                     Node,
>> +                                     &Node
>> +    )) {
>> +    Status = FdtClient->GetNodeProperty (
>> +                          FdtClient,
>> +                          Node,
>> +                          "reg",
>> +                          (CONST VOID **)&Reg,
>> +                          &PropSize
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
>> +        __FUNCTION__, Status));
>> +      continue;
>> +    }
>> +
>> +    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
>> +
>> +    while ((PropSize >= (4 * sizeof (UINT32))) &&
>> +           (mNorFlashDeviceCount < MAX_FLASH_BANKS)) {
>> +      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
>> +      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
>> +      Reg += 4;
>> +
>> +      PropSize -= 4 * sizeof (UINT32);
>> +
>> +      //
>> +      // Disregard any flash devices that overlap with the primary FV.
>> +      // The firmware is not updatable from inside the guest anyway.
>> +      //
>> +      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
>> +          (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {
>> +        continue;
>> +      }
>> +
>> +      DEBUG ((
>> +        DEBUG_INFO,
>> +        "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
>> +        mNorFlashDeviceCount,
>> +        Base,
>> +        Size
>> +        ));
>> +
>> +      mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
>> +      mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
>> +      mNorFlashDevices[mNorFlashDeviceCount].Size              = (UINTN)Size;
>> +      mNorFlashDevices[mNorFlashDeviceCount].BlockSize         = SIZE_256KB;
> 
> Hmm I'm worried that there is no contract enforcing the Virt machine to
> use 256KiB sectors. Can we add a definition elsewhere and use it here,
> instead of burying the fixed sector size here?
> 
>> +      mNorFlashDeviceCount++;
>> +    }
>> +  }
>> +
>> +  // Setup the variable store in the last bank
>> +  if ((mNorFlashDeviceCount > 0) &&
>> +      (mNorFlashDevices[mNorFlashDeviceCount - 1].DeviceBaseAddress != 0)) {
>> +    return SetupVariableStore (&mNorFlashDevices[mNorFlashDeviceCount - 1]);
>> +  }
>> +
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..8bd6f730dcb52e597b418e59766c1566a9519789
>> --- /dev/null
>> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> @@ -0,0 +1,50 @@
>> +#/** @file
>> +#
>> +#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
>> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +#**/
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = NorFlashKvmtoolLib
>> +  FILE_GUID                      = E75F07A1-B160-4893-BDD4-09E32FF847DC
>> +  MODULE_TYPE                    = DXE_DRIVER
>> +  VERSION_STRING                 = 1.0
>> +  LIBRARY_CLASS                  = NorFlashPlatformLib
>> +  CONSTRUCTOR                    = NorFlashPlatformLibConstructor
>> +
>> +[Sources.common]
>> +  NorFlashKvmtool.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  ArmPlatformPkg/ArmPlatformPkg.dec
>> +  ArmVirtPkg/ArmVirtPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  DebugLib
>> +  PcdLib
>> +  UefiBootServicesTableLib
>> +
>> +[Protocols]
>> +  gFdtClientProtocolGuid          ## CONSUMES
>> +
>> +[Pcd]
>> +  gArmTokenSpaceGuid.PcdFvBaseAddress
>> +  gArmTokenSpaceGuid.PcdFvSize
>> +
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +
>> +[Depex]
>> +  gFdtClientProtocolGuid
>> +
>>
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [edk2-devel] [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib
  2020-06-04  6:30     ` Philippe Mathieu-Daudé
@ 2020-06-04 15:00       ` Sami Mujawar
  0 siblings, 0 replies; 40+ messages in thread
From: Sami Mujawar @ 2020-06-04 15:00 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, devel@edk2.groups.io
  Cc: Ard Biesheuvel, leif@nuviainc.com, lersek@redhat.com,
	Alexandru Elisei, Andre Przywara, Matteo Carlini, Laura Moretta,
	nd

Hi Philippe,

Thank you for reviewing this patch.
Please find my answers inline marked [SAMI]

Regards,

Sami Mujawar

-----Original Message-----
From: Philippe Mathieu-Daudé <philmd@redhat.com> 
Sent: 04 June 2020 07:31 AM
To: devel@edk2.groups.io; Sami Mujawar <Sami.Mujawar@arm.com>
Cc: Ard Biesheuvel <Ard.Biesheuvel@arm.com>; leif@nuviainc.com; lersek@redhat.com; Alexandru Elisei <Alexandru.Elisei@arm.com>; Andre Przywara <Andre.Przywara@arm.com>; Matteo Carlini <Matteo.Carlini@arm.com>; Laura Moretta <Laura.Moretta@arm.com>; nd <nd@arm.com>
Subject: Re: [edk2-devel] [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib

On 5/27/20 1:59 PM, Philippe Mathieu-Daudé wrote:
> Hi Sami,
> 
> On 5/14/20 10:40 AM, Sami Mujawar wrote:
>> Kvmtool places the base address of the CFI flash in the device tree 
>> it passes to UEFI. This library parses the kvmtool device tree to 
>> read the CFI base address and initialise the PCDs use by the NOR 
>> flash driver and the variable storage.
>>
>> Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
>> ---
>>  ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c      | 265 ++++++++++++++++++++
>>  ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf |  50 
>> ++++
>>  2 files changed, 315 insertions(+)
>>
>> diff --git a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c 
>> b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> new file mode 100644
>> index 
>> 0000000000000000000000000000000000000000..2e43c2e21bc9ef7dd1dd198eebb
>> d70c3b0b96d1c
>> --- /dev/null
>> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
>> @@ -0,0 +1,265 @@
>> +/** @file
>> +   An instance of the NorFlashPlatformLib for Kvmtool platform.
>> +
>> + Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> + **/
>> +
>> +#include <Library/BaseLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/NorFlashPlatformLib.h> #include 
>> +<Library/UefiBootServicesTableLib.h>
>> +#include <Protocol/FdtClient.h>
>> +
>> +/** Macro defining the maximum number of Flash Banks.
>> + */
>> +#define MAX_FLASH_BANKS       4
>> +
>> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[MAX_FLASH_BANKS];
> 
> This is confuse, the macro define 4 banks to a flash device, but then 
> you declare an array of 4 flash devices.
> 
> I'm even more confused because I'm only aware of 2 devices on the Virt 
> machine. What am I missing?

Pinging again in case this question has been missed.
[SAMI] The macro MAX_FLASH_BANKS should be changed to MAX_FLASH_DEVICES. I will send an updated patch with this fixed.
On kvmtool, there is only one flash device currently as this is all that is needed. However, in the future if more flash devices are provided then this code can handle multiple flash devices.
[/SAMI]
> 
>> +STATIC UINTN                  mNorFlashDeviceCount = 0;
>> +
>> +/** This function performs platform specific actions to initialise
>> +    the NOR flash, if required.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +**/
>> +EFI_STATUS
>> +NorFlashPlatformInitialization (
>> +  VOID
>> +  )
>> +{
>> +  DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
>> +  // Nothing to do here
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/** Initialise Non volatile Flash storage variables.
>> +
>> +  @param [in]  FlashDevice Pointer to the NOR Flash device.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +  @retval EFI_INVALID_PARAMETER A parameter is invalid.
>> +  @retval EFI_OUT_OF_RESOURCES  Insufficient flash storage space.
>> +**/
>> +EFI_STATUS
>> +SetupVariableStore (
>> +  IN NOR_FLASH_DESCRIPTION * FlashDevice
>> +  )
>> +{
>> +  UINTN   FlashRegion;
>> +  UINTN   FlashNvStorageVariableBase;
>> +  UINTN   FlashNvStorageFtwWorkingBase;
>> +  UINTN   FlashNvStorageFtwSpareBase;
>> +  UINTN   FlashNvStorageVariableSize;
>> +  UINTN   FlashNvStorageFtwWorkingSize;
>> +  UINTN   FlashNvStorageFtwSpareSize;
>> +
>> +  FlashNvStorageVariableSize = PcdGet32 
>> + (PcdFlashNvStorageVariableSize);  FlashNvStorageFtwWorkingSize = 
>> + PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
>> +  FlashNvStorageFtwSpareSize =  PcdGet32 
>> + (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  if ((FlashNvStorageVariableSize == 0)   ||
>> +      (FlashNvStorageFtwWorkingSize == 0) ||
>> +      (FlashNvStorageFtwSpareSize == 0)) {
>> +    DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  // Setup the variable store
>> +  FlashRegion = FlashDevice->DeviceBaseAddress;
>> +
>> +  FlashNvStorageVariableBase = FlashRegion;  FlashRegion += PcdGet32 
>> + (PcdFlashNvStorageVariableSize);
>> +
>> +  FlashNvStorageFtwWorkingBase = FlashRegion;  FlashRegion += 
>> + PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
>> +
>> +  FlashNvStorageFtwSpareBase = FlashRegion;  FlashRegion += PcdGet32 
>> + (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
>> +    DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
>> +    return EFI_OUT_OF_RESOURCES;
>> +  }
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageVariableBase,
>> +    FlashNvStorageVariableBase
>> +    );
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageFtwWorkingBase,
>> +    FlashNvStorageFtwWorkingBase
>> +    );
>> +
>> +  PcdSet32S (
>> +    PcdFlashNvStorageFtwSpareBase,
>> +    FlashNvStorageFtwSpareBase
>> +    );
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageVariableBase = 0x%x\n",
>> +    FlashNvStorageVariableBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageVariableSize = 0x%x\n",
>> +    FlashNvStorageVariableSize
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
>> +    FlashNvStorageFtwWorkingBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
>> +    FlashNvStorageFtwWorkingSize
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
>> +    FlashNvStorageFtwSpareBase
>> +    ));
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
>> +    FlashNvStorageFtwSpareSize
>> +    ));
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/** Return the Flash devices on the platform.
>> +
>> +  @param [out]  NorFlashDescriptions    Pointer to the Flash device description.
>> +  @param [out]  Count                   Number of Flash devices.
>> +
>> +  @retval EFI_SUCCESS           Success.
>> +  @retval EFI_NOT_FOUND         Flash device not found.
>> +**/
>> +EFI_STATUS
>> +NorFlashPlatformGetDevices (
>> +  OUT NOR_FLASH_DESCRIPTION   **NorFlashDescriptions,
>> +  OUT UINT32                  *Count
>> +  )
>> +{
>> +  if (mNorFlashDeviceCount > 0) {
>> +    *NorFlashDescriptions = mNorFlashDevices;
>> +    *Count = mNorFlashDeviceCount;
>> +    return EFI_SUCCESS;
>> +  }
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> +/** Entrypoint for NorFlashPlatformLib.
>> +
>> +  @param [in]  ImageHandle  The handle to the image.
>> +  @param [in]  SystemTable  Pointer to the System Table.
>> +
>> +  @retval EFI_SUCCESS             Success.
>> +  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
>> +  @retval EFI_NOT_FOUND           Flash device not found.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +NorFlashPlatformLibConstructor (
>> +  IN  EFI_HANDLE          ImageHandle,
>> +  IN  EFI_SYSTEM_TABLE  * SystemTable
>> +  )
>> +{
>> +  FDT_CLIENT_PROTOCOL         *FdtClient;
>> +  INT32                       Node;
>> +  EFI_STATUS                  Status;
>> +  EFI_STATUS                  FindNodeStatus;
>> +  CONST UINT32                *Reg;
>> +  UINT32                      PropSize;
>> +  UINT64                      Base;
>> +  UINT64                      Size;
>> +
>> +  if (mNorFlashDeviceCount != 0) {
>> +    return EFI_SUCCESS;
>> +  }
>> +
>> +  Status = gBS->LocateProtocol (
>> +                  &gFdtClientProtocolGuid,
>> +                  NULL,
>> +                  (VOID **)&FdtClient
>> +                  );
>> +  if (EFI_ERROR (Status)) {
>> +    ASSERT_EFI_ERROR (Status);
>> +    return Status;
>> +  }
>> +
>> +  for (FindNodeStatus = FdtClient->FindCompatibleNode (
>> +                                     FdtClient,
>> +                                     "cfi-flash",
>> +                                     &Node
>> +                                     );
>> +       !EFI_ERROR (FindNodeStatus) && (mNorFlashDeviceCount < MAX_FLASH_BANKS);
>> +       FindNodeStatus = FdtClient->FindNextCompatibleNode (
>> +                                     FdtClient,
>> +                                     "cfi-flash",
>> +                                     Node,
>> +                                     &Node
>> +    )) {
>> +    Status = FdtClient->GetNodeProperty (
>> +                          FdtClient,
>> +                          Node,
>> +                          "reg",
>> +                          (CONST VOID **)&Reg,
>> +                          &PropSize
>> +                          );
>> +    if (EFI_ERROR (Status)) {
>> +      DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",
>> +        __FUNCTION__, Status));
>> +      continue;
>> +    }
>> +
>> +    ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
>> +
>> +    while ((PropSize >= (4 * sizeof (UINT32))) &&
>> +           (mNorFlashDeviceCount < MAX_FLASH_BANKS)) {
>> +      Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
>> +      Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
>> +      Reg += 4;
>> +
>> +      PropSize -= 4 * sizeof (UINT32);
>> +
>> +      //
>> +      // Disregard any flash devices that overlap with the primary FV.
>> +      // The firmware is not updatable from inside the guest anyway.
>> +      //
>> +      if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
>> +          (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {
>> +        continue;
>> +      }
>> +
>> +      DEBUG ((
>> +        DEBUG_INFO,
>> +        "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
>> +        mNorFlashDeviceCount,
>> +        Base,
>> +        Size
>> +        ));
>> +
>> +      mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
>> +      mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
>> +      mNorFlashDevices[mNorFlashDeviceCount].Size              = (UINTN)Size;
>> +      mNorFlashDevices[mNorFlashDeviceCount].BlockSize         = SIZE_256KB;
> 
> Hmm I'm worried that there is no contract enforcing the Virt machine 
> to use 256KiB sectors. Can we add a definition elsewhere and use it 
> here, instead of burying the fixed sector size here?
> 
>> +      mNorFlashDeviceCount++;
>> +    }
>> +  }
>> +
>> +  // Setup the variable store in the last bank  if 
>> + ((mNorFlashDeviceCount > 0) &&
>> +      (mNorFlashDevices[mNorFlashDeviceCount - 1].DeviceBaseAddress != 0)) {
>> +    return SetupVariableStore 
>> + (&mNorFlashDevices[mNorFlashDeviceCount - 1]);  }
>> +
>> +  return EFI_NOT_FOUND;
>> +}
>> +
>> diff --git 
>> a/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf 
>> b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> new file mode 100644
>> index 
>> 0000000000000000000000000000000000000000..8bd6f730dcb52e597b418e59766
>> c1566a9519789
>> --- /dev/null
>> +++ b/ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtoolLib.inf
>> @@ -0,0 +1,50 @@
>> +#/** @file
>> +#
>> +#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR> #  
>> +SPDX-License-Identifier: BSD-2-Clause-Patent # #**/
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = NorFlashKvmtoolLib
>> +  FILE_GUID                      = E75F07A1-B160-4893-BDD4-09E32FF847DC
>> +  MODULE_TYPE                    = DXE_DRIVER
>> +  VERSION_STRING                 = 1.0
>> +  LIBRARY_CLASS                  = NorFlashPlatformLib
>> +  CONSTRUCTOR                    = NorFlashPlatformLibConstructor
>> +
>> +[Sources.common]
>> +  NorFlashKvmtool.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  ArmPlatformPkg/ArmPlatformPkg.dec
>> +  ArmVirtPkg/ArmVirtPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  DebugLib
>> +  PcdLib
>> +  UefiBootServicesTableLib
>> +
>> +[Protocols]
>> +  gFdtClientProtocolGuid          ## CONSUMES
>> +
>> +[Pcd]
>> +  gArmTokenSpaceGuid.PcdFvBaseAddress
>> +  gArmTokenSpaceGuid.PcdFvSize
>> +
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +
>> +[Depex]
>> +  gFdtClientProtocolGuid
>> +
>>
> 


^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2020-06-04 15:00 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-05-14  8:40 [PATCH v2 00/11] Kvmtool guest firmware support for Arm Sami Mujawar
2020-05-14  8:40 ` [PATCH v2 01/11] PcAtChipsetPkg: Add MMIO Support to RTC driver Sami Mujawar
2020-05-14  9:24   ` Ard Biesheuvel
2020-05-15 10:50   ` André Przywara
2020-05-27  0:37     ` [edk2-devel] " Guomin Jiang
2020-05-14  8:40 ` [PATCH v1 02/11] MdePkg: Add NULL implementation for PCILib Sami Mujawar
2020-05-14  9:23   ` Ard Biesheuvel
2020-05-14 16:21   ` Michael D Kinney
2020-05-14  8:40 ` [PATCH v1 03/11] MdePkg: Base Memory Lib instance using MMIO Sami Mujawar
2020-05-14  9:22   ` Ard Biesheuvel
2020-05-14 17:21     ` Ard Biesheuvel
2020-05-14 16:33   ` [edk2-devel] " Michael D Kinney
2020-05-14  8:40 ` [PATCH v1 04/11] ArmPlatformPkg: Use MMIO to read device memory Sami Mujawar
2020-05-14  8:40 ` [PATCH v1 05/11] ArmPlatformPkg: Dynamic flash variable base Sami Mujawar
2020-05-14  9:24   ` Ard Biesheuvel
2020-05-27 11:48   ` [edk2-devel] " Philippe Mathieu-Daudé
2020-05-14  8:40 ` [PATCH v2 06/11] ArmVirtPkg: Add kvmtool platform driver Sami Mujawar
2020-05-14  9:29   ` Ard Biesheuvel
2020-05-14 12:12     ` [edk2-devel] " Laszlo Ersek
2020-05-14 12:17       ` Ard Biesheuvel
2020-05-14 16:05         ` Laszlo Ersek
2020-05-14 17:25           ` Ard Biesheuvel
2020-05-15  7:28             ` Laszlo Ersek
2020-05-14 12:20       ` Laszlo Ersek
2020-05-14  8:40 ` [PATCH v1 07/11] ArmVirtPkg: kvmtool platform memory map Sami Mujawar
2020-05-14  9:30   ` Ard Biesheuvel
2020-05-14 12:15   ` [edk2-devel] " Laszlo Ersek
2020-05-14  8:40 ` [PATCH v1 08/11] ArmVirtPkg: Add Kvmtool NOR flash lib Sami Mujawar
2020-05-14  9:32   ` Ard Biesheuvel
2020-05-14 12:17     ` [edk2-devel] " Laszlo Ersek
2020-05-27 11:59   ` Philippe Mathieu-Daudé
2020-06-04  6:30     ` Philippe Mathieu-Daudé
2020-06-04 15:00       ` Sami Mujawar
2020-05-14  8:40 ` [PATCH v2 09/11] ArmVirtPkg: Support for kvmtool emulated platform Sami Mujawar
2020-05-14  9:56   ` Ard Biesheuvel
2020-05-14 12:24   ` [edk2-devel] " Laszlo Ersek
2020-05-14  8:40 ` [PATCH v1 10/11] ArmVirtPkg: Link NorFlashDxe with BaseMemoryLibMmio Sami Mujawar
2020-05-14 12:28   ` [edk2-devel] " Laszlo Ersek
2020-05-14  8:40 ` [PATCH v1 11/11] Maintainer.txt: Add Kvmtool emulated plat maintainer Sami Mujawar
2020-05-14 12:31   ` [edk2-devel] " Laszlo Ersek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox