public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH edk2-platforms 0/3] Add Platform-Generic Packages to support Windows IoT Core
@ 2018-07-17  2:05 Chris Co
  2018-07-17  2:05 ` [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Chris Co @ 2018-07-17  2:05 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

REF: https://github.com/christopherco/edk2-platforms/tree/import_mspkg_v1

This patch adds a Platform/Microsoft directory to hold libraries and drivers
that are specific to supporting Windows IoT Core but not necessarily specific to a
Platform or Silicon.

SdMmc DXE driver enables Windows IoT Core boot from SD or eMMC.  It also contains feature
enhancements that were missing from the derived Mmc driver.

Lauterbach debug library is not Windows-specific but was a useful debug library during our
initial Windows IoT Core platform enabling.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>

Christopher Co (3):
  Platform/Microsoft: Add SdMmc Dxe Driver
  Platform/Microsoft: Add MsPkg
  Platform/Microsoft: Add Lauterbach debug library

 Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c                                                |  526 ++++++
 Platform/Microsoft/Drivers/SdMmcDxe/Debug.c                                                  |  358 ++++
 Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c                                               | 1774 ++++++++++++++++++++
 Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h                                               |  231 +++
 Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c                                                 |  611 +++++++
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c                                                  |  892 ++++++++++
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h                                                  |  529 ++++++
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf                                             |   50 +
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h                                                |  506 ++++++
 Platform/Microsoft/Include/Protocol/RpmbIo.h                                                 |  262 +++
 Platform/Microsoft/Include/Protocol/Sdhc.h                                                   |  197 +++
 Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c   |  142 ++
 Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf |   41 +
 Platform/Microsoft/MsPkg.dec                                                                 |   42 +
 Platform/Microsoft/MsPkg.dsc                                                                 |   32 +
 15 files changed, 6193 insertions(+)
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/Debug.c
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
 create mode 100644 Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h
 create mode 100644 Platform/Microsoft/Include/Protocol/RpmbIo.h
 create mode 100644 Platform/Microsoft/Include/Protocol/Sdhc.h
 create mode 100644 Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c
 create mode 100644 Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf
 create mode 100644 Platform/Microsoft/MsPkg.dec
 create mode 100644 Platform/Microsoft/MsPkg.dsc

-- 
2.16.2.gvfs.1.33.gf5370f1



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

* [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver
  2018-07-17  2:05 [PATCH edk2-platforms 0/3] Add Platform-Generic Packages to support Windows IoT Core Chris Co
@ 2018-07-17  2:05 ` Chris Co
  2018-07-31 20:33   ` Leif Lindholm
  2018-07-17  2:05 ` [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg Chris Co
  2018-07-17  2:05 ` [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library Chris Co
  2 siblings, 1 reply; 13+ messages in thread
From: Chris Co @ 2018-07-17  2:05 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This SdMmc driver adds support to boot Windows from SD and eMMC.
It implements RPMB protocol support for eMMC, unique device path
creation for each slot on the SD bus, high speed modes,
eMMC bus width auto-detection, and support for high capacity
SDXC cards.

Derived from: EmbeddedPkg\Universal\MmcDxe

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
---
 Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c    |  526 ++++++
 Platform/Microsoft/Drivers/SdMmcDxe/Debug.c      |  358 ++++
 Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c   | 1774 ++++++++++++++++++++
 Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h   |  231 +++
 Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c     |  611 +++++++
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c      |  892 ++++++++++
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h      |  529 ++++++
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf |   50 +
 Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h    |  506 ++++++
 Platform/Microsoft/Include/Protocol/RpmbIo.h     |  262 +++
 Platform/Microsoft/Include/Protocol/Sdhc.h       |  197 +++
 11 files changed, 5936 insertions(+)

diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c b/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c
new file mode 100644
index 000000000000..07acd7b7b3f7
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c
@@ -0,0 +1,526 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+VOID
+BenchmarkIo (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN SD_TRANSFER_DIRECTION  TransferDirection,
+  IN UINT32                 MediaId,
+  IN UINTN                  BufferSize,
+  IN UINT32                 Iterations
+  );
+
+EFI_STATUS
+IoBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN SD_TRANSFER_DIRECTION  TransferDirection,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  IN OUT VOID               *Buffer
+  );
+
+VOID
+SortIoReadStatsByTotalTransferTime (
+  IN IoReadStatsEntry*   Table,
+  IN UINT32              NumEntries
+  )
+{
+  // Using the simple insertion sort
+  UINT32 Idx;
+  for (Idx = 1; Idx < NumEntries; ++Idx) {
+    IoReadStatsEntry CurrEntry = Table[Idx];
+    UINT32 J = Idx;
+    while (J > 0 &&
+           Table[J - 1].TotalTransferTimeUs < CurrEntry.TotalTransferTimeUs) {
+      Table[J] = Table[J - 1];
+      --J;
+    }
+    Table[J] = CurrEntry;
+  }
+}
+
+VOID
+BenchmarkIo (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN SD_TRANSFER_DIRECTION  TransferDirection,
+  IN UINT32                 MediaId,
+  IN UINTN                  BufferSize,
+  IN UINT32                 Iterations
+  )
+{
+  ASSERT (Iterations > 0);
+
+  EFI_STATUS Status;
+  UINT32 BufferSizeKB = INT_DIV_ROUND (BufferSize, 1024);
+  VOID* Buffer = AllocateZeroPool (BufferSize);
+  if (Buffer == NULL) {
+    LOG_ERROR ("BenchmarkIo() : No enough memory to allocate %dKB buffer", BufferSizeKB);
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  UINT32 CurrIteration = Iterations;
+  UINT64 TotalTransfersTimeUs = 0;
+
+  while (CurrIteration--) {
+    UINT64 StartTime = GetPerformanceCounter ();
+
+    Status = IoBlocks (
+      This,
+      TransferDirection,
+      MediaId,
+      0, // Lba
+      BufferSize,
+      Buffer
+    );
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+
+    UINT64 EndTime = GetPerformanceCounter ();
+    TotalTransfersTimeUs += (((EndTime - StartTime) * 1000000UL) / gHpcTicksPerSeconds);
+  }
+
+  UINT32 KBps = (UINT32) (((UINT64) BufferSizeKB * (UINT64) Iterations * 1000000UL) / TotalTransfersTimeUs);
+  LOG_INFO (
+    "- BenchmarkIo(%a, %dKB)\t: Xfr Avg:%dus\t%dKBps\t%dMBps",
+    (TransferDirection == SdTransferDirectionRead) ? "Read" : "Write",
+    BufferSizeKB,
+    (UINT32) (TotalTransfersTimeUs / Iterations),
+    KBps,
+    INT_DIV_ROUND (KBps, 1024));
+
+Exit:
+  if (Buffer != NULL) {
+    FreePool (Buffer);
+  }
+}
+
+EFI_STATUS
+IoBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN SD_TRANSFER_DIRECTION  TransferDirection,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  IN OUT VOID               *Buffer
+  )
+{
+  SDHC_INSTANCE *HostInst;
+  EFI_STATUS Status;
+  CONST SD_COMMAND *Cmd;
+  UINT32 BlockCount;
+
+  HostInst = SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This);
+  ASSERT (HostInst);
+  ASSERT (HostInst->HostExt);
+
+  if (This->Media->MediaId != MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+    goto Exit;
+  }
+
+  if (Buffer == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  // Check if a Card is Present
+  if (!HostInst->BlockIo.Media->MediaPresent) {
+    Status = EFI_NO_MEDIA;
+    goto Exit;
+  }
+
+  // Reading 0 Byte is valid
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if ((TransferDirection == SdTransferDirectionWrite) && (This->Media->ReadOnly == TRUE)) {
+    Status = EFI_WRITE_PROTECTED;
+    goto Exit;
+  }
+
+    // The buffer size must be an exact multiple of the block size
+  if ((BufferSize % This->Media->BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    goto Exit;
+  }
+
+  BlockCount = BufferSize / This->Media->BlockSize;
+
+  // All blocks must be within the device
+  if ((Lba + BlockCount - 1) > (This->Media->LastBlock)) {
+    LOG_ERROR (
+      "Data span is out of media address range. (Media Last Block LBA = 0x%lx"
+      "Data Last Block LBA = 0x%lx)",
+      This->Media->LastBlock,
+      (Lba + BlockCount - 1));
+
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  // Check the alignment
+  if ((This->Media->IoAlign > 2) && (((UINTN) Buffer & (This->Media->IoAlign - 1)) != 0)) {
+    LOG_ERROR (
+      "Invalid buffer address alignment (Buffer = %p, IoAlign = %d)",
+      Buffer,
+      This->Media->IoAlign);
+
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if (TransferDirection == SdTransferDirectionRead) {
+    if (BlockCount == 1) {
+      Cmd = &CmdReadSingleBlock;
+    } else {
+      Cmd = &CmdReadMultiBlock;
+    }
+  } else {
+    if (BlockCount == 1) {
+      Cmd = &CmdWriteSingleBlock;
+    } else {
+      Cmd = &CmdWriteMultiBlock;
+    }
+  }
+
+  CONST UINT32 DataCommandRetryCount = 3;
+  CONST UINT32 MaxTransferSize =
+    HostInst->HostCapabilities.MaximumBlockCount * This->Media->BlockSize;
+  UINT32 Retry;
+  UINT32 BytesRemaining = BufferSize;
+  UINTN CurrentBufferSize;
+  VOID *CurrentBuffer = Buffer;
+  UINT32 CurrentLba = (UINT32) Lba;
+
+  for (; BytesRemaining > 0;) {
+    if (BytesRemaining < MaxTransferSize) {
+      CurrentBufferSize = BytesRemaining;
+    } else {
+      CurrentBufferSize = MaxTransferSize;
+    }
+
+    for (Retry = 0; Retry < DataCommandRetryCount; ++Retry) {
+      Status = SdhcSendDataCommand (
+        HostInst,
+        Cmd,
+        CurrentLba,
+        CurrentBufferSize,
+        CurrentBuffer);
+
+      if (!EFI_ERROR (Status)) {
+        if (Retry > 0) {
+          LOG_TRACE ("SdhcSendDataCommand succeeded after %d retry", Retry);
+        }
+        break;
+      }
+
+      // On SdhcSendDataCommand return, proper error recovery has been performed
+      // and it should be safe to retry the same transfer.
+
+      LOG_ERROR ("SdhcSendDataCommand failed on retry %d", Retry);
+    }
+
+    BytesRemaining -= CurrentBufferSize;
+    CurrentLba += CurrentBufferSize / This->Media->BlockSize;
+    CurrentBuffer = (VOID*) ((UINTN) CurrentBuffer + CurrentBufferSize);
+  }
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "IoBlocks(%c, LBA:0x%08lx, Size(B):0x%x): SdhcSendDataCommand() failed. %r",
+      ((TransferDirection == SdTransferDirectionRead) ? 'R' : 'W'),
+      Lba,
+      BufferSize,
+      Status);
+  }
+
+  return Status;
+}
+
+// EFI_BLOCK_IO Protocol Callbacks
+
+/**
+  Reset the block device.
+
+  This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+  It resets the block device hardware.
+  ExtendedVerification is ignored in this implementation.
+
+  @param  This                   Indicates a pointer to the calling context.
+  @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive
+                                 verification operation of the device during reset.
+
+  @retval EFI_SUCCESS            The block device was reset.
+  @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReset (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN BOOLEAN                ExtendedVerification
+  )
+{
+  LOG_TRACE ("BlockIoReset()");
+
+  SDHC_INSTANCE *HostInst = SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This);
+  return SoftReset (HostInst);
+}
+
+/**
+  Reads the requested number of blocks from the device.
+
+  This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+  It reads the requested number of blocks from the device.
+  All the blocks are read, or an error is returned.
+
+  @param  This                   Indicates a pointer to the calling context.
+  @param  MediaId                The media ID that the read request is for.
+  @param  Lba                    The starting logical block address to read from on the device.
+  @param  BufferSize             The size of the Buffer in bytes.
+                                 This must be a multiple of the intrinsic block size of the device.
+  @param  Buffer                 A pointer to the destination buffer for the data. The caller is
+                                 responsible for either having implicit or explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS            The data was read correctly from the device.
+  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the read operation.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+  @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
+                                 or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReadBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  OUT VOID                  *Buffer
+  )
+{
+  LOG_TRACE ("BlockIoReadBlocks()");
+
+#if SDMMC_BENCHMARK_IO
+  static BOOLEAN BenchmarkDone = FALSE;
+  if (!BenchmarkDone) {
+
+    LOG_INFO ("Benchmarking BlockIo Read");
+
+    UINT32 CurrByteSize = 512;
+    CONST UINT32 MaxByteSize = 8388608; // 8MB Max
+    for (; CurrByteSize <= MaxByteSize; CurrByteSize *= 2) {
+      BenchmarkIo (This, SdTransferDirectionRead, MediaId, CurrByteSize, 10);
+    }
+
+    BenchmarkDone = TRUE;
+  }
+#endif // SDMMC_BENCHMARK_IO
+
+#if SDMMC_COLLECT_STATISTICS
+  UINT32 NumBlocks = BufferSize / This->Media->BlockSize;
+  SDHC_INSTANCE *HostInst = SDHC_INSTANCE_FROM_BLOCK_IO_THIS (This);
+  CONST UINT32 TableSize = ARRAYSIZE (HostInst->IoReadStats);
+  IoReadStatsEntry *CurrentReadEntry = NULL;
+
+  UINT32 BlockIdx;
+  for (BlockIdx = 0; BlockIdx < TableSize; ++BlockIdx) {
+    IoReadStatsEntry *Entry = HostInst->IoReadStats + BlockIdx;
+    // Reached end of table and didn't find a match, append an entry
+    if (Entry->NumBlocks == 0) {
+      ++HostInst->IoReadStatsNumEntries;
+      Entry->NumBlocks = NumBlocks;
+    }
+
+    if (Entry->NumBlocks == NumBlocks) {
+      CurrentReadEntry = Entry;
+      ++Entry->Count;
+      break;
+    }
+  }
+  ASSERT (BlockIdx < TableSize);
+
+  UINT64 StartTime = GetPerformanceCounter ();
+
+  EFI_STATUS Status = IoBlocks (
+    This,
+    SdTransferDirectionRead,
+    MediaId,
+    Lba,
+    BufferSize,
+    Buffer
+  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  UINT64 EndTime = GetPerformanceCounter ();
+
+  ASSERT (CurrentReadEntry != NULL);
+  CurrentReadEntry->TotalTransferTimeUs +=
+    (UINT32) (((EndTime - StartTime) * 1000000UL) / gHpcTicksPerSeconds);
+
+  //
+  // Run statistics and dump updates
+  //
+  SortIoReadStatsByTotalTransferTime (
+    HostInst->IoReadStats,
+    HostInst->IoReadStatsNumEntries);
+
+  IoReadStatsEntry *MaxNumBlocksEntry = HostInst->IoReadStats;
+  IoReadStatsEntry *MaxCountEntry = HostInst->IoReadStats;
+  UINT32 TotalReadTimeUs = 0;
+  UINT32 TotalReadBlocksCount = 0;
+
+  LOG_INFO (" #Blks\tCnt\tAvg(us)\tAll(us)");
+
+  for (BlockIdx = 0; BlockIdx < HostInst->IoReadStatsNumEntries; ++BlockIdx) {
+    IoReadStatsEntry *CurrEntry = HostInst->IoReadStats + BlockIdx;
+
+    if (CurrEntry->NumBlocks > MaxNumBlocksEntry->NumBlocks) {
+      MaxNumBlocksEntry = CurrEntry;
+    }
+
+    if (CurrEntry->Count > MaxCountEntry->Count) {
+      MaxCountEntry = CurrEntry;
+    }
+
+    TotalReadTimeUs += CurrEntry->TotalTransferTimeUs;
+    TotalReadBlocksCount += (CurrEntry->NumBlocks * CurrEntry->Count);
+
+    // Show only the top 5 time consuming transfers
+    if (BlockIdx < 5) {
+      LOG_INFO (
+        " %d\t%d\t%d\t%d",
+        (UINT32) CurrEntry->NumBlocks,
+        (UINT32) CurrEntry->Count,
+        (UINT32) (CurrEntry->TotalTransferTimeUs / CurrEntry->Count),
+        (UINT32) CurrEntry->TotalTransferTimeUs);
+    }
+  }
+
+  LOG_INFO (
+    "MaxNumBlocksEntry: %d %d %dus",
+    (UINT32) MaxNumBlocksEntry->NumBlocks,
+    (UINT32) MaxNumBlocksEntry->Count,
+    (UINT32) MaxNumBlocksEntry->TotalTransferTimeUs);
+
+  LOG_INFO (
+    "MaxCountEntry: %d %d %dus",
+    (UINT32) MaxCountEntry->NumBlocks,
+    (UINT32) MaxCountEntry->Count,
+    (UINT32) MaxCountEntry->TotalTransferTimeUs);
+
+  LOG_INFO (
+    "UEFI spent %dus~%ds reading %dMB from SDCard\n",
+    TotalReadTimeUs,
+    INT_DIV_ROUND (TotalReadTimeUs, 1000000),
+    INT_DIV_ROUND (TotalReadBlocksCount * This->Media->BlockSize, (1024 * 1024)));
+Exit:
+  return Status;
+
+#else
+  return IoBlocks (This, SdTransferDirectionRead, MediaId, Lba, BufferSize, Buffer);
+#endif // SDMMC_COLLECT_STATISTICS
+}
+
+/**
+  Writes a specified number of blocks to the device.
+
+  This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+  It writes a specified number of blocks to the device.
+  All blocks are written, or an error is returned.
+
+  @param  This                   Indicates a pointer to the calling context.
+  @param  MediaId                The media ID that the write request is for.
+  @param  Lba                    The starting logical block address to be written.
+  @param  BufferSize             The size of the Buffer in bytes.
+                                 This must be a multiple of the intrinsic block size of the device.
+  @param  Buffer                 Pointer to the source buffer for the data.
+
+  @retval EFI_SUCCESS            The data were written correctly to the device.
+  @retval EFI_WRITE_PROTECTED    The device cannot be written to.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+  @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
+  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the write operation.
+  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic
+                                 block size of the device.
+  @retval EFI_INVALID_PARAMETER  The write request contains LBAs that are not valid,
+                                 or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoWriteBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  IN VOID                   *Buffer
+  )
+{
+  LOG_TRACE ("BlockIoWriteBlocks()");
+
+  return IoBlocks (This, SdTransferDirectionWrite, MediaId, Lba, BufferSize, Buffer);
+}
+
+/**
+  Flushes all modified data to a physical block device.
+
+  @param  This                   Indicates a pointer to the calling context.
+
+  @retval EFI_SUCCESS            All outstanding data were written correctly to the device.
+  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to write data.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoFlushBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This
+  )
+{
+  LOG_TRACE ("BlockIoFlushBlocks()");
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c b/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c
new file mode 100644
index 000000000000..8fcef9f229ab
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/Debug.c
@@ -0,0 +1,358 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+CONST CHAR8 *mStrUnit[] = { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit/s",
+                            "Unknown", "Unknown", "Unknown", "Unknown" };
+CONST CHAR8 *mStrValue[] = { "UNDEF", "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5", "5.0",
+                             "Unknown", "Unknown", "Unknown", "Unknown" };
+
+VOID
+PrintCid (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  LOG_INFO ("- PrintCid");;
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    SD_CID *Cid = &HostInst->CardInfo.Registers.Sd.Cid;
+    LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID);
+    LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID);
+    LOG_INFO (
+      "\t- Product name: %c%c%c%c%c",
+      Cid->PNM[4],
+      Cid->PNM[3],
+      Cid->PNM[2],
+      Cid->PNM[1],
+      Cid->PNM[0]);
+
+    LOG_INFO (
+      "\t- Manufacturing date: %d/%d",
+      (UINT32) (Cid->MDT & 0xF),
+      (UINT32) (((Cid->MDT >> 4) & 0x3F) + 2000));
+    LOG_INFO ("\t- Product serial number: 0x%X", Cid->PSN);
+    LOG_INFO ("\t- Product revision: %d", (UINT32) Cid->PRV);
+
+    LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID);
+    LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID);
+  } else {
+    MMC_CID *Cid = &HostInst->CardInfo.Registers.Mmc.Cid;
+    LOG_INFO ("\t- Manufacturer ID: 0x%x", (UINT32) Cid->MID);
+    LOG_INFO ("\t- OEM ID: 0x%x", (UINT32) Cid->OID);
+    LOG_INFO (
+      "\t- Product name: %c%c%c%c%c%c\n",
+      Cid->PNM[5],
+      Cid->PNM[4],
+      Cid->PNM[3],
+      Cid->PNM[2],
+      Cid->PNM[1],
+      Cid->PNM[0]);
+
+    LOG_INFO (
+      "\t- Manufacturing date: %d/%d",
+      (UINT32) (Cid->MDT >> 4),
+      (UINT32) (Cid->MDT & 0xF) + 1997);
+
+    LOG_INFO ("\t- Product serial number: 0x%X", Cid->PSN);
+    LOG_INFO ("\t- Product revision: %d", (UINT32) Cid->PRV);
+  }
+}
+
+VOID
+PrintCsd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  LOG_INFO ("- PrintCsd");
+
+  UINT32 CardSizeGB =
+    (UINT32) INT_DIV_ROUND (HostInst->CardInfo.ByteCapacity, (UINT64) (1024 * 1024 * 1024));
+
+  LOG_INFO (
+    "\t- CardSize: %ld~%dGB, BlockSize:%d LastBlock LBA:0x%08x",
+    HostInst->CardInfo.ByteCapacity,
+    CardSizeGB,
+    HostInst->BlockIo.Media->BlockSize,
+    (UINT32) HostInst->BlockIo.Media->LastBlock);
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    SD_CSD *Csd = &HostInst->CardInfo.Registers.Sd.Csd;
+    if (Csd->CSD_STRUCTURE == 0) {
+      LOG_INFO ("- SD CSD Version 1.01-1.10/Version 2.00/Standard Capacity");
+    } else if (Csd->CSD_STRUCTURE == 1) {
+      LOG_INFO ("- SD CSD Version 2.00/High Capacity");
+    } else {
+      LOG_INFO ("- SD CSD Version Higher than v3.3");
+    }
+
+    LOG_INFO (
+      "\t- SW Write Protect: Temp:%d Permanent:%d",
+      (UINT32) Csd->TMP_WRITE_PROTECT,
+      (UINT32) Csd->PERM_WRITE_PROTECT);
+
+    LOG_INFO ("\t- Supported card command class: 0x%X", Csd->CCC);
+
+    LOG_INFO (
+      "\t- Speed: %a %a (TRAN_SPEED:%x)",
+      mStrValue[(Csd->TRAN_SPEED >> 3) & 0xF],
+      mStrUnit[Csd->TRAN_SPEED & 7],
+      (UINT32) Csd->TRAN_SPEED);
+
+    LOG_INFO (
+      "\t- Maximum Read Data Block: %d (READ_BL_LEN:%x)",
+      (UINT32) (1 << Csd->READ_BL_LEN),
+      (UINT32) Csd->READ_BL_LEN);
+
+    LOG_INFO (
+      "\t- Maximum Write Data Block: %d (WRITE_BL_LEN:%x)",
+      (UINT32) (1 << Csd->WRITE_BL_LEN),
+      (UINT32) Csd->WRITE_BL_LEN);
+
+    if (!Csd->FILE_FORMAT_GRP) {
+      if (Csd->FILE_FORMAT == 0) {
+        LOG_INFO ("\t- Format (0): Hard disk-like file system with partition table");
+      } else if (Csd->FILE_FORMAT == 1) {
+        LOG_INFO ("\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)");
+      } else if (Csd->FILE_FORMAT == 2) {
+        LOG_INFO ("\t- Format (2): Universal File Format");
+      } else {
+        LOG_INFO ("\t- Format (3): Others/Unknown");
+      }
+    } else {
+      LOG_INFO ("\t- Format: Reserved");
+    }
+  } else {
+    MMC_CSD *Csd = &HostInst->CardInfo.Registers.Mmc.Csd;
+    MMC_EXT_CSD *ExtCsd = &HostInst->CardInfo.Registers.Mmc.ExtCsd;
+
+    if (ExtCsd->CardType & MmcExtCsdCardTypeNormalSpeed) {
+      LOG_INFO ("\t- Normal-Speed MMC @ 26MHz");
+    }
+
+    if (ExtCsd->CardType & MmcExtCsdCardTypeHighSpeed) {
+      LOG_INFO ("\t- High-Speed MMC @ 52MHz");
+    }
+
+    if (ExtCsd->CardType & MmcExtCsdCardTypeDdr1v8) {
+      LOG_INFO ("\t- High-Speed DDR MMC @ 52MHz - 1.8V or 3V I/O");
+    }
+
+    if (ExtCsd->CardType & MmcExtCsdCardTypeDdr1v2) {
+      LOG_INFO ("\t- High-Speed DDR MMC @ 52MHz - 1.2VI/O");
+    }
+
+    LOG_INFO (
+      "\t- SW Write Protect: Temp:%d Permenant:%d",
+      (UINT32) Csd->TMP_WRITE_PROTECT,
+      (UINT32) Csd->PERM_WRITE_PROTECT);
+
+    LOG_INFO ("\t- SpecVersion: %d.x", (UINT32) Csd->SPEC_VERS);
+    LOG_INFO ("\t- Supported card command class: 0x%X", Csd->CCC);
+
+    LOG_INFO (
+      "\t- Current Max Speed: %a %a (TRAN_SPEED:%x)",
+      mStrValue[(Csd->TRAN_SPEED >> 3) & 0xF],
+      mStrUnit[Csd->TRAN_SPEED & 7],
+      (UINT32) Csd->TRAN_SPEED);
+
+    LOG_INFO (
+      "\t- Maximum Read Data Block: %d (READ_BL_LEN:%x)",
+      (UINT32) (1 << Csd->READ_BL_LEN),
+      (UINT32) Csd->READ_BL_LEN);
+
+    LOG_INFO (
+      "\t- Maximum Write Data Block: %d (WRITE_BL_LEN:%x)",
+      (UINT32) (1 << Csd->WRITE_BL_LEN),
+      (UINT32) Csd->WRITE_BL_LEN);
+
+    if (!Csd->FILE_FORMAT_GRP) {
+      if (Csd->FILE_FORMAT == 0) {
+        LOG_INFO ("\t- Format (0): Hard disk-like file system with partition table");
+      } else if (Csd->FILE_FORMAT == 1) {
+        LOG_INFO ("\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)");
+      } else if (Csd->FILE_FORMAT == 2) {
+        LOG_INFO ("\t- Format (2): Universal File Format");
+      } else {
+        LOG_INFO ("\t- Format (3): Others/Unknown");
+      }
+    } else {
+      LOG_INFO ("\t- Format: Reserved");
+    }
+  }
+}
+
+VOID
+GetAndPrintCardStatus (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  CARD_STATUS CardStatus;
+  EFI_STATUS Status;
+
+  //
+  // If the card has not been selected, then we can't get its status
+  //
+  if (HostInst->CardInfo.RCA == 0x0) {
+    return;
+  }
+
+  Status = SdhcSendCommand (HostInst, &CmdSendStatus, 0);
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  CardStatus.AsUint32 = HostInst->CmdResponse[0];
+  PrintCardStatus (HostInst, CardStatus);
+}
+
+VOID
+PrintCardStatus (
+  IN SDHC_INSTANCE  *HostInst,
+  IN CARD_STATUS    CardStatus
+  )
+{
+  switch (HostInst->CardInfo.CardFunction) {
+  case CardFunctionSd:
+    LOG_INFO (
+      "Status: APP_CMD:%d READY_FOR_DATA:%d CURRENT_STATE:%d(%a) "
+      "CARD_IS_LOCKED:%d",
+      CardStatus.Fields.APP_CMD,
+      CardStatus.Fields.READY_FOR_DATA,
+      CardStatus.Fields.CURRENT_STATE,
+      CardStateToString (CardStatus.Fields.CURRENT_STATE),
+      CardStatus.Fields.CARD_IS_LOCKED);
+
+    break;
+
+  case CardFunctionMmc:
+    LOG_INFO (
+      "Status: APP_CMD:%d URGENT_BKOPS:%d READY_FOR_DATA:%d "
+      "CURRENT_STATE:%d(%a) CARD_IS_LOCKED:%d",
+      CardStatus.Fields.APP_CMD,
+      CardStatus.Fields.URGENT_BKOPS,
+      CardStatus.Fields.READY_FOR_DATA,
+      CardStatus.Fields.CURRENT_STATE,
+      CardStateToString (CardStatus.Fields.CURRENT_STATE),
+      CardStatus.Fields.CARD_IS_LOCKED);
+
+    break;
+
+  default:
+    ASSERT (FALSE);
+  }
+
+  if (IsCardStatusError (HostInst, CardStatus)) {
+    LOG_INFO ("Errors:");
+
+    if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+      if (CardStatus.Fields.AKE_SEQ_ERROR) {
+        LOG_INFO ("\t- SWITCH_ERROR");
+      }
+    }
+
+    if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+      if (CardStatus.Fields.SWITCH_ERROR) {
+        LOG_INFO ("\t- SWITCH_ERROR");
+      }
+
+      if (CardStatus.Fields.OVERRUN) {
+        LOG_INFO ("\t- OVERRUN");
+      }
+
+      if (CardStatus.Fields.UNDERRUN) {
+        LOG_INFO ("\t- UNDERRUN");
+      }
+    }
+
+    if (CardStatus.Fields.ERASE_RESET) {
+      LOG_INFO ("\t- ERASE_RESET");
+    }
+
+    if (CardStatus.Fields.WP_ERASE_SKIP) {
+      LOG_INFO ("\t- WP_ERASE_SKIP");
+    }
+
+    if (CardStatus.Fields.CID_CSD_OVERWRITE) {
+      LOG_INFO ("\t- CID_CSD_OVERWRITE");
+    }
+
+    if (CardStatus.Fields.ERROR) {
+      LOG_INFO ("\t- ERROR");
+    }
+
+    if (CardStatus.Fields.CC_ERROR) {
+      LOG_INFO ("\t- CC_ERROR");
+    }
+
+    if (CardStatus.Fields.CARD_ECC_FAILED) {
+      LOG_INFO ("\t- CARD_ECC_FAILED");
+    }
+
+    if (CardStatus.Fields.ILLEGAL_COMMAND) {
+      LOG_INFO ("\t- ILLEGAL_COMMAND");
+    }
+
+    if (CardStatus.Fields.COM_CRC_ERROR) {
+      LOG_INFO ("\t- COM_CRC_ERROR");
+    }
+
+    if (CardStatus.Fields.LOCK_UNLOCK_FAILED) {
+      LOG_INFO ("\t- LOCK_UNLOCK_FAILED");
+    }
+
+    if (CardStatus.Fields.WP_VIOLATION) {
+      LOG_INFO ("\t- WP_VIOLATION");
+    }
+
+    if (CardStatus.Fields.ERASE_PARAM) {
+      LOG_INFO ("\t- ERASE_PARAM");
+    }
+
+    if (CardStatus.Fields.ERASE_SEQ_ERROR) {
+      LOG_INFO ("\t- ERASE_SEQ_ERROR");
+    }
+
+    if (CardStatus.Fields.BLOCK_LEN_ERROR) {
+      LOG_INFO ("\t- BLOCK_LEN_ERROR");
+    }
+
+    if (CardStatus.Fields.ADDRESS_MISALIGN) {
+      LOG_INFO ("\t- ADDRESS_MISALIGN");
+    }
+
+    if (CardStatus.Fields.ADDRESS_OUT_OF_RANGE) {
+      LOG_INFO ("\t- ADDRESS_OUT_OF_RANGE");
+    }
+  }
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c
new file mode 100644
index 000000000000..d635fa6a1ef4
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c
@@ -0,0 +1,1774 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+EFI_STATUS
+InitializeDevice (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  LOG_TRACE ("InitializDevice()");
+  ASSERT (!HostInst->SlotInitialized);
+
+#if SDMMC_BENCHMARK_IO
+  UINT64 InitializationStartTime = HpcTimerStart ();
+#endif // SDMMC_BENCHMARK_IO
+
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  ASSERT (HostExt);
+  EFI_STATUS Status;
+
+  ASSERT (HostInst->BlockIo.Media->MediaPresent);
+
+  ZeroMem (&HostInst->CardInfo, sizeof (HostInst->CardInfo));
+  //
+  // SD/MMC cards on reset start in default normal speed mode
+  //
+  HostInst->CardInfo.CurrentSpeedMode = CardSpeedModeNormalSpeed;
+
+  Status = HostExt->SoftwareReset (HostExt, SdhcResetTypeAll);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("HostExt->SoftwareReset() failed. %r", Status);
+    return Status;
+  }
+
+  Status = HostExt->SetClock (HostExt, SD_IDENT_MODE_CLOCK_FREQ_HZ);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("HostExt->SetClock() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcQueryCardType (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcQueryCardType() failed. %r", Status);
+    return Status;
+  }
+
+  switch (HostInst->CardInfo.CardFunction) {
+  case CardFunctionComboSdSdio:
+    LOG_ERROR ("Combo SD/SDIO function is not supported");
+    return EFI_UNSUPPORTED;
+  case CardFunctionSdio:
+    LOG_ERROR ("SDIO function is not supported");
+    return EFI_UNSUPPORTED;
+  case CardFunctionSd:
+    Status = InitializeSdDevice (HostInst);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("InitializeSdDevice() failed. %r", Status);
+      return Status;
+    }
+    break;
+  case CardFunctionMmc:
+    Status = InitializeMmcDevice (HostInst);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("InitializeMmcDevice() failed. %r", Status);
+      return Status;
+    }
+    break;
+  default:
+    LOG_ASSERT ("Unknown device function");
+    return EFI_UNSUPPORTED;
+  }
+
+  PrintCid (HostInst);
+  PrintCsd (HostInst);
+
+  Status = SdhcSetBlockLength (HostInst, SD_BLOCK_LENGTH_BYTES);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSetBlockLength() failed. %r", Status);
+    return Status;
+  }
+
+  ASSERT (HostInst->CardInfo.CardFunction == CardFunctionSd ||
+          HostInst->CardInfo.CardFunction == CardFunctionMmc);
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    HostInst->BlockIo.Media->RemovableMedia = TRUE;
+    HostInst->BlockIo.Media->MediaId = HostInst->CardInfo.Registers.Sd.Cid.PSN;
+  } else {
+    //
+    // Assume BGA form factor eMMC
+    //
+    HostInst->BlockIo.Media->RemovableMedia = FALSE;
+
+    //
+    // Use the card product serial number as MediaId
+    //
+    HostInst->BlockIo.Media->MediaId = HostInst->CardInfo.Registers.Mmc.Cid.PSN;
+  }
+
+  HostInst->SlotInitialized = TRUE;
+
+#if SDMMC_BENCHMARK_IO
+  UINT64 ElapsedTimeMs = HpcTimerElapsedMilliseconds (InitializationStartTime);
+  LOG_INFO ("Initialization completed in %ldms", ElapsedTimeMs);
+#endif // SDMMC_BENCHMARK_IO
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeSdDevice (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+
+  Status = SdhcSendOpCondSd (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendOpCondSd() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendCidAll (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCidAll() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendRelativeAddr (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendRelativeAddr() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendCid (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCid() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendCsd (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCsd() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSelectDevice (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSelectDevice() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSwitchBusWidthSd (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSwitchBusWidthSd() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSwitchSpeedModeSd (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSwitchSpeedModeSd() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSetMaxClockFrequency (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSetMaxClockFrequency() failed. %r", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeMmcDevice (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+
+  Status = SdhcSendCidAll (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCidAll() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendRelativeAddr (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendRelativeAddr() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendCid (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCid() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendCsd (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCsd() failed. %r", Status);
+    return Status;
+  }
+
+  if (HostInst->CardInfo.Registers.Mmc.Csd.SPEC_VERS < MMC_MIN_SUPPORTED_SPEC_VERS) {
+    LOG_ERROR (
+      "MMC %d.x is not supported, Minimum supported is MMC %d.x",
+      HostInst->CardInfo.Registers.Mmc.Csd.SPEC_VERS,
+      MMC_MIN_SUPPORTED_SPEC_VERS);
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = SdhcSelectDevice (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSelectDevice() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSendExtCsdMmc (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendExtCsdMmc() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSwitchSpeedModeMmc (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSwitchSpeedModeMmc() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSwitchBusWidthMmc (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSwitchBusWidthMmc() failed. %r", Status);
+    return Status;
+  }
+
+  Status = SdhcSetMaxClockFrequency (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSetMaxClockFrequency() failed. %r", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcRecoverFromErrors (
+  IN SDHC_INSTANCE      *HostInst,
+  IN CONST SD_COMMAND   *Cmd
+  )
+{
+  EFI_STATUS Status;
+  CARD_STATUS CardStatus;
+  EFI_SDHC_PROTOCOL *HostExt;
+
+  LOG_TRACE (
+    "*** %cCMD%d Error recovery sequence start ***",
+    (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+    (UINT32) Cmd->Index);
+
+  HostExt = HostInst->HostExt;
+  HostInst->ErrorRecoveryAttemptCount += 1;
+
+  if (HostInst->ErrorRecoveryAttemptCount > SDMMC_ERROR_RECOVERY_ATTEMPT_THRESHOLD) {
+    LOG_ERROR ("RecursiveErrorRecoveryCount exceeded the threshold. Error is unrecoverable!");
+    Status = EFI_PROTOCOL_ERROR;
+    goto Exit;
+  }
+
+  GetAndPrintCardStatus (HostInst);
+
+  LOG_TRACE ("Reseting CMD line ...");
+  Status = HostExt->SoftwareReset (HostExt, SdhcResetTypeCmd);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("HostExt->SoftwareReset(SdhcResetTypeCmd) failed. %r", Status);
+  }
+
+  if (Cmd->TransferType != SdTransferTypeNone &&
+      Cmd->TransferType != SdTransferTypeUndefined) {
+
+    LOG_TRACE ("Reseting DAT line ...");
+    Status = HostExt->SoftwareReset (HostExt, SdhcResetTypeData);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("HostExt->SoftwareReset(SdhcResetTypeData) failed. %r", Status);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    LOG_TRACE ("CMD and/or DATA normal error recovery failed, trying SDHC soft-reset");
+    Status = SoftReset (HostInst);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("All trials to recover from errors failed. %r");
+      goto Exit;
+    }
+  }
+
+  if (CmdsAreEqual (Cmd, &CmdWriteMultiBlock) ||
+      CmdsAreEqual (Cmd, &CmdReadMultiBlock)) {
+
+    Status = SdhcSendStatus (HostInst, &CardStatus);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("SdhcSendStatus() failed. (Status = %r)", Status);
+      goto Exit;
+    }
+
+    if (CardStatus.Fields.CURRENT_STATE != CardStateTran) {
+      LOG_TRACE ("Stopping transmission ...");
+      Status = SdhcStopTransmission (HostInst);
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+
+      //
+      // Multi read/write failure reason will be written in the STOP_TRANSMISSION
+      // response as part of the card status error flags.
+      //
+      CardStatus.AsUint32 = HostInst->CmdResponse[0];
+      PrintCardStatus (HostInst, CardStatus);
+    }
+  }
+
+Exit:
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "*** %cCMD%d Error recovery sequence failed "
+      "(Status = %r, ErrorRecoveryAttemptCount = %d) ***",
+      (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+      (UINT32) Cmd->Index,
+      Status,
+      HostInst->ErrorRecoveryAttemptCount);
+
+  } else {
+    LOG_TRACE (
+      "*** %cCMD%d Error recovery sequence completed successfully "
+      "(ErrorRecoveryAttemptCount = %d) ***",
+      (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+      (UINT32) Cmd->Index,
+      HostInst->ErrorRecoveryAttemptCount);
+  }
+
+  HostInst->ErrorRecoveryAttemptCount -= 1;
+
+  return Status;
+}
+
+EFI_STATUS
+SdhcSendCommandHelper (
+  IN SDHC_INSTANCE        *HostInst,
+  IN CONST SD_COMMAND     *Cmd,
+  IN UINT32               Arg,
+  IN SD_COMMAND_XFR_INFO  *XfrInfo
+  )
+{
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  EFI_STATUS Status;
+  CARD_STATUS CardStatus;
+
+  if (Cmd->Class == SdCommandClassApp) {
+    UINT32 CmdAppArg = HostInst->CardInfo.RCA << 16;
+    Status = HostExt->SendCommand (HostExt, &CmdAppSd, CmdAppArg, NULL);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "HostExt->SendCommand(%cCMD%d, 0x%08x) failed. %r",
+        (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+        (UINT32) Cmd->Index,
+        CmdAppArg,
+        Status);
+
+      return Status;
+    }
+  }
+
+  Status = HostExt->SendCommand (HostExt, Cmd, Arg, XfrInfo);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "HostExt->SendCommand(%cCMD%d, 0x%08x) failed. %r",
+      (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+      (UINT32) Cmd->Index,
+      Arg,
+      Status);
+
+    return Status;
+  }
+
+  Status = HostExt->ReceiveResponse (HostExt, Cmd, HostInst->CmdResponse);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("HostExt->ReceiveResponse() failed. %r", Status);
+    return Status;
+  }
+
+  if ((Cmd->ResponseType == SdResponseTypeR1) ||
+    (Cmd->ResponseType == SdResponseTypeR1B)) {
+
+    CardStatus.AsUint32 = HostInst->CmdResponse[0];
+
+    if (IsCardStatusError (HostInst, CardStatus)) {
+      LOG_ERROR (
+        "%cCMD%d card status error detected",
+        (Cmd->Class == SdCommandClassApp ? 'A' : ' '),
+        (UINT32) Cmd->Index);
+
+      PrintCardStatus (HostInst, CardStatus);
+
+      return EFI_DEVICE_ERROR;
+    }
+  }
+
+  HostInst->PreLastSuccessfulCmd = HostInst->LastSuccessfulCmd;
+  HostInst->LastSuccessfulCmd = Cmd;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendCommand (
+  IN SDHC_INSTANCE      *HostInst,
+  IN CONST SD_COMMAND   *Cmd,
+  IN UINT32             Arg
+  )
+{
+  EFI_STATUS Status;
+
+  Status = SdhcSendCommandHelper (HostInst, Cmd, Arg, NULL);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("Send no-data command failed. %r", Status);
+    SdhcRecoverFromErrors (HostInst, Cmd);
+    return Status;
+  }
+
+  //
+  // SWITCH command can change card state to prog, we should wait the card to
+  // transfer back to tran state and rais the READY_FOR_DATA flag to make sure
+  // that switch operation was completed successfully
+  //
+  if (CmdsAreEqual (Cmd, &CmdSwitchMmc) ||
+      CmdsAreEqual (Cmd, &CmdSwitchSd)) {
+    Status = SdhcWaitForTranStateAndReadyForData (HostInst);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "SdhcWaitForTranStateAndReadyForData() failed after successful "
+        "SWITCH command. (Status = %r)",
+        Status);
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendDataCommand (
+  IN SDHC_INSTANCE      *HostInst,
+  IN CONST SD_COMMAND   *Cmd,
+  IN UINT32             Arg,
+  IN UINT32             BufferByteSize,
+  IN VOID               *Buffer
+  )
+{
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  SD_COMMAND_XFR_INFO XfrInfo;
+  EFI_STATUS Status;
+
+  ASSERT (BufferByteSize % SD_BLOCK_LENGTH_BYTES == 0);
+  XfrInfo.BlockCount = BufferByteSize / SD_BLOCK_LENGTH_BYTES;
+  XfrInfo.BlockSize = SD_BLOCK_LENGTH_BYTES;
+  XfrInfo.Buffer = Buffer;
+
+  Status = SdhcSendCommandHelper (HostInst, Cmd, Arg, &XfrInfo);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  if (Cmd->TransferDirection == SdTransferDirectionRead) {
+    Status = HostExt->ReadBlockData (
+      HostExt,
+      BufferByteSize,
+      (UINT32*) Buffer);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "HostExt->ReadBlockData(Size: 0x%xB) failed. %r",
+        BufferByteSize,
+        Status);
+      goto Exit;
+    }
+  } else {
+    ASSERT (Cmd->TransferDirection == SdTransferDirectionWrite);
+    Status = HostExt->WriteBlockData (
+      HostExt,
+      BufferByteSize,
+      (UINT32*) Buffer);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "HostExt->WriteBlockData(Size: 0x%xB) failed. %r",
+        BufferByteSize,
+        Status);
+      goto Exit;
+    }
+  }
+
+  //
+  // If this is an open-ended multi-block read/write then explicitly send
+  // STOP_TRANSMISSION. A multi-block read/write with pre-defined block count
+  // will be preceeded with SET_BLOCK_COUNT.
+  //
+  if ((CmdsAreEqual (Cmd, &CmdWriteMultiBlock) ||
+       CmdsAreEqual (Cmd, &CmdReadMultiBlock)) &&
+       ((HostInst->LastSuccessfulCmd == NULL) ||
+        !CmdsAreEqual (HostInst->PreLastSuccessfulCmd, &CmdSetBlockCount))) {
+
+    Status = SdhcStopTransmission (HostInst);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("SdhcStopTransmission() failed. (Status = %r)", Status);
+      goto Exit;
+    }
+  }
+
+  Status = SdhcWaitForTranStateAndReadyForData (HostInst);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+Exit:
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("Send data command failed. %r", Status);
+    SdhcRecoverFromErrors (HostInst, Cmd);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+SdhcGoIdleState (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  return SdhcSendCommand (HostInst, &CmdGoIdleState, 0);
+}
+
+EFI_STATUS
+SdhcQueryCardType (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status = SdhcGoIdleState (HostInst);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  HostInst->CardInfo.CardFunction = CardFunctionUnknown;
+
+  Status = SdhcSendIfCondSd (HostInst);
+  if (!EFI_ERROR (Status)) {
+    HostInst->CardInfo.CardFunction = CardFunctionSd;
+  }
+
+  Status = SdhcSendOpCondSdio (HostInst);
+  if (!EFI_ERROR (Status)) {
+    if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+      //
+      // SD/SDIO Combo Device
+      //
+      HostInst->CardInfo.CardFunction = CardFunctionComboSdSdio;
+    } else {
+      HostInst->CardInfo.CardFunction = CardFunctionSdio;
+    }
+  }
+
+  if (HostInst->CardInfo.CardFunction != CardFunctionSd &&
+      HostInst->CardInfo.CardFunction != CardFunctionSdio &&
+      HostInst->CardInfo.CardFunction != CardFunctionComboSdSdio) {
+    Status = SdhcGoIdleState (HostInst);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Status = SdhcSendOpCondMmc (HostInst);
+    if (!EFI_ERROR (Status)) {
+      HostInst->CardInfo.CardFunction = CardFunctionMmc;
+    }
+  }
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionUnknown) {
+    return EFI_NO_MEDIA;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcWaitForTranStateAndReadyForData (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+  UINT32 Retry;
+  CARD_STATUS CardStatus;
+
+  Status = SdhcSendStatus (HostInst, &CardStatus);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Retry = SDMMC_POLL_WAIT_COUNT;
+
+  while (((!CardStatus.Fields.READY_FOR_DATA && Retry) ||
+    (CardStatus.Fields.CURRENT_STATE != CardStateTran)) &&
+         Retry) {
+
+    gBS->Stall (SDMMC_POLL_WAIT_TIME_US);
+    --Retry;
+
+    Status = SdhcSendStatus (HostInst, &CardStatus);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  if (!Retry) {
+    LOG_ERROR ("Time-out waiting for card READY_FOR_DATA status flag");
+    PrintCardStatus (HostInst, CardStatus);
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendCid (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+
+  EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendCid, CmdArg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    gBS->CopyMem (
+      (VOID*) &HostInst->CardInfo.Registers.Sd.Cid,
+      (VOID*) HostInst->CmdResponse,
+      sizeof (SD_CID));
+
+  } else if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+    gBS->CopyMem (
+      (VOID*) &HostInst->CardInfo.Registers.Mmc.Cid,
+      (VOID*) HostInst->CmdResponse,
+      sizeof (MMC_CID));
+
+    C_ASSERT (sizeof (HostInst->RpmbIo.Cid) == EFI_RPMB_CID_SIZE);
+    gBS->CopyMem (
+      (VOID*) &HostInst->RpmbIo.Cid,
+      (VOID*) HostInst->CmdResponse,
+      EFI_RPMB_CID_SIZE);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendCsd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+
+  EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendCsd, CmdArg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  UINT32 MaxBlockLen;
+  UINT64 ByteCapacity = 0;
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    gBS->CopyMem (
+      (VOID*) &HostInst->CardInfo.Registers.Sd.Csd,
+      (VOID*) HostInst->CmdResponse,
+      sizeof (SD_CSD));
+    if (HostInst->CardInfo.Registers.Sd.Csd.CSD_STRUCTURE == 0) {
+      SD_CSD* Csd = (SD_CSD*) &HostInst->CardInfo.Registers.Sd.Csd;
+      UINT32 DeviceSize = ((Csd->C_SIZEHigh10 << 2) | Csd->C_SIZELow2);
+      UINT32 MULT = 1 << (Csd->C_SIZE_MULT + 2);
+      UINT32 BLOCKNR = (DeviceSize + 1) * MULT;
+      MaxBlockLen = 1 << Csd->READ_BL_LEN;
+      ByteCapacity = BLOCKNR * MaxBlockLen;
+    } else {
+      SD_CSD_2* Csd2 = (SD_CSD_2*) &HostInst->CardInfo.Registers.Sd.Csd;
+      MaxBlockLen = 1 << Csd2->READ_BL_LEN;
+      ByteCapacity = (UINT64) (Csd2->C_SIZE + 1) * 512llu * 1024llu;
+    }
+  } else if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+    gBS->CopyMem (
+      (VOID*) &HostInst->CardInfo.Registers.Mmc.Csd,
+      (VOID*) HostInst->CmdResponse,
+      sizeof (MMC_CSD));
+    //
+    // HighCapacity MMC requires reading EXT_CSD to calculate capacity
+    //
+    if (!HostInst->CardInfo.HighCapacity) {
+      MMC_CSD* Csd = (MMC_CSD*) &HostInst->CardInfo.Registers.Mmc.Csd;
+      UINT32 DeviceSize = ((Csd->C_SIZEHigh10 << 2) | Csd->C_SIZELow2);
+      UINT32 MULT = 1 << (Csd->C_SIZE_MULT + 2);
+      UINT32 BLOCKNR = (DeviceSize + 1) * MULT;
+      MaxBlockLen = 1 << Csd->READ_BL_LEN;
+      ByteCapacity = BLOCKNR * MaxBlockLen;
+    }
+  }
+
+  HostInst->CardInfo.ByteCapacity = ByteCapacity;
+  HostInst->BlockIo.Media->BlockSize = SD_BLOCK_LENGTH_BYTES;
+  UINT64 NumBlocks = (ByteCapacity / SD_BLOCK_LENGTH_BYTES);
+
+  if (NumBlocks > 0) {
+    HostInst->BlockIo.Media->LastBlock = (NumBlocks - 1);
+  } else {
+    HostInst->BlockIo.Media->LastBlock = 0;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSelectDevice (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+  return SdhcSendCommand (HostInst, &CmdSelect, CmdArg);
+}
+
+EFI_STATUS
+SdhcDeselectDevice (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  return SdhcSendCommand (HostInst, &CmdDeselect, 0);
+}
+
+EFI_STATUS
+SdhcSendAppCmd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+  return SdhcSendCommand (HostInst, &CmdAppSd, CmdArg);
+}
+
+EFI_STATUS
+SdhcStopTransmission (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+  return SdhcSendCommand (HostInst, &CmdStopTransmission, CmdArg);
+}
+
+EFI_STATUS
+SdhcSendCidAll (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  return SdhcSendCommand (HostInst, &CmdSendCidAll, 0);
+}
+
+EFI_STATUS
+SdhcSendRelativeAddr (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = 0;
+
+  //
+  // Unlike SD memory, MMC cards don't publish their RCA, instead it should be
+  // manually assigned by the SDHC
+  //
+  if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+    HostInst->CardInfo.RCA = 0xCCCC;
+    CmdArg = HostInst->CardInfo.RCA << 16;
+  }
+
+  EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendRelativeAddr, CmdArg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (HostInst->CardInfo.CardFunction != CardFunctionMmc) {
+    HostInst->CardInfo.RCA = (HostInst->CmdResponse[0] >> 16);
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CalculateCardMaxFreq (
+  IN SDHC_INSTANCE *HostInst,
+  OUT UINT32* MaxClkFreqHz
+  )
+{
+  ASSERT (HostInst != NULL);
+  ASSERT (MaxClkFreqHz != NULL);
+
+  SD_CSD *Csd = &HostInst->CardInfo.Registers.Sd.Csd;
+  UINT32 TransferRateBitPerSecond = 0;
+  UINT32 TimeValue = 0;
+  UINT32 TRAN_SPEED;
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    TRAN_SPEED = HostInst->CardInfo.Registers.Sd.Csd.TRAN_SPEED;
+  } else {
+    TRAN_SPEED = HostInst->CardInfo.Registers.Mmc.Csd.TRAN_SPEED;
+  }
+
+  // Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
+  switch (TRAN_SPEED & 0x7) { // 2
+  case 0: // 100kbit/s
+    TransferRateBitPerSecond = 100 * 1000;
+    break;
+
+  case 1: // 1Mbit/s
+    TransferRateBitPerSecond = 1 * 1000 * 1000;
+    break;
+
+  case 2: // 10Mbit/s
+    TransferRateBitPerSecond = 10 * 1000 * 1000;
+    break;
+
+  case 3: // 100Mbit/s
+    TransferRateBitPerSecond = 100 * 1000 * 1000;
+    break;
+
+  default:
+    LOG_ERROR ("Invalid parameter");
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //Calculate Time value (Bits 6:3 of TRAN_SPEED)
+  switch ((TRAN_SPEED >> 3) & 0xF) { // 6
+  case 0x1:
+    TimeValue = 10;
+    break;
+
+  case 0x2:
+    TimeValue = 12;
+    break;
+
+  case 0x3:
+    TimeValue = 13;
+    break;
+
+  case 0x4:
+    TimeValue = 15;
+    break;
+
+  case 0x5:
+    TimeValue = 20;
+    break;
+
+  case 0x6:
+    if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+      TimeValue = 25;
+    } else {
+      TimeValue = 26;
+    }
+    break;
+
+  case 0x7:
+    TimeValue = 30;
+    break;
+
+  case 0x8:
+    TimeValue = 35;
+    break;
+
+  case 0x9:
+    TimeValue = 40;
+    break;
+
+  case 0xA:
+    TimeValue = 45;
+    break;
+
+  case 0xB:
+    if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+      TimeValue = 50;
+    } else {
+      TimeValue = 52;
+    }
+    break;
+
+  case 0xC:
+    TimeValue = 55;
+    break;
+
+  case 0xD:
+    TimeValue = 60;
+    break;
+
+  case 0xE:
+    TimeValue = 70;
+    break;
+
+  case 0xF:
+    TimeValue = 80;
+    break;
+
+  default:
+    LOG_ERROR ("Invalid parameter");
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *MaxClkFreqHz = (TransferRateBitPerSecond * TimeValue) / 10;
+
+  LOG_TRACE (
+    "TransferRateUnitId=%d TimeValue*10=%d, CardFrequency=%dKHz",
+    (Csd->TRAN_SPEED & 0x7),
+    TimeValue,
+    *MaxClkFreqHz / 1000);
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSetMaxClockFrequency (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  EFI_STATUS Status;
+  UINT32 MaxClkFreqHz = 0;
+
+  //
+  // Currently only NormalSpeed and HighSpeed supported
+  //
+  ASSERT (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeNormalSpeed ||
+          HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed);
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    Status = CalculateCardMaxFreq (HostInst, &MaxClkFreqHz);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } else {
+    if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeNormalSpeed) {
+      Status = CalculateCardMaxFreq (HostInst, &MaxClkFreqHz);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    } else if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed) {
+      MaxClkFreqHz = MMC_HIGH_SPEED_MODE_CLOCK_FREQ_HZ;
+    }
+  }
+
+  Status = HostExt->SetClock (HostExt, MaxClkFreqHz);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSetBlockLength (
+  IN SDHC_INSTANCE  *HostInst,
+  IN UINT32         BlockByteLength
+  )
+{
+  LOG_TRACE ("SdhcSetBlockLength(BlockByteLength=%d)", BlockByteLength);
+
+  return SdhcSendCommand (HostInst, &CmdSetBlockLength, BlockByteLength);
+}
+
+EFI_STATUS
+SdhcSetBlockCount (
+  IN SDHC_INSTANCE  *HostInst,
+  IN UINT32         BlockCount,
+  IN BOOLEAN        ReliableWrite
+  )
+{
+  UINT32 CmdArg;
+
+  LOG_TRACE (
+    "SdhcSetBlockCount(BlockCount=%d, ReliableWrite=%d)",
+    BlockCount,
+    ReliableWrite);
+
+  //
+  // JEDEC Standard No. 84-A441, Page 76
+  //
+  // Set bit[31] as 1 to indicate Reliable Write type of programming access.
+  //
+
+  if (ReliableWrite) {
+    CmdArg = BlockCount | (1 << 31);
+  } else {
+    CmdArg = BlockCount;
+  }
+
+  return SdhcSendCommand (HostInst, &CmdSetBlockCount, CmdArg);
+}
+
+EFI_STATUS
+SdhcSendStatus (
+  IN SDHC_INSTANCE  *HostInst,
+  OUT CARD_STATUS   *CardStatus
+  )
+{
+  EFI_STATUS Status;
+  UINT32 CmdArg;
+
+  LOG_TRACE ("SdhcSendStatus()");
+
+  CmdArg = HostInst->CardInfo.RCA << 16;
+
+  Status = SdhcSendCommand (HostInst, &CmdSendStatus, CmdArg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardStatus->AsUint32 = HostInst->CmdResponse[0];
+
+  return EFI_SUCCESS;
+}
+
+//
+// SD Specific Functions
+//
+
+EFI_STATUS
+SdhcSendScrSd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  UINT32 CmdArg = HostInst->CardInfo.RCA << 16;
+  EFI_STATUS Status;
+
+  Status = SdhcSendDataCommand (
+    HostInst,
+    &CmdAppSendScrSd,
+    CmdArg,
+    sizeof (HostInst->BlockBuffer),
+    HostInst->BlockBuffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  gBS->CopyMem (
+    &HostInst->CardInfo.Registers.Sd.Scr,
+    HostInst->BlockBuffer,
+    sizeof (SD_SCR));
+
+  SD_SCR *Scr = (SD_SCR*) &HostInst->BlockBuffer;
+  LOG_TRACE ("SD_SCR:");
+  LOG_TRACE ("  SD_SPEC=%d", (UINT32) Scr->SD_SPEC);
+  LOG_TRACE ("  SD_SPEC3=%d", (UINT32) Scr->SD_SPEC3);
+  LOG_TRACE (
+    "  SD_BUS_WIDTHS=%x, 1-Bit?%d, 4-Bit?%d",
+    (UINT32) Scr->SD_BUS_WIDTH,
+    (UINT32) ((Scr->SD_BUS_WIDTH & BIT1) ? 1 : 0),
+    (UINT32) ((Scr->SD_BUS_WIDTH & BIT2) ? 1 : 0));
+  LOG_TRACE (
+    "  CMD_SUPPORT=%x, CMD23?%d, CMD20?%d",
+    (UINT32) Scr->CMD_SUPPORT,
+    (UINT32) ((Scr->CMD_SUPPORT & BIT2) ? 1 : 0),
+    (UINT32) ((Scr->CMD_SUPPORT & BIT1) ? 1 : 0));
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendIfCondSd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  SEND_IF_COND_ARG CmdArg = { 0 };
+
+  //
+  // Recommended check pattern per SD Specs
+  //
+  CmdArg.Fields.CheckPattern = 0xAA;
+
+  //
+  // Our current implementation does not support more than HighSpeed voltage 2V7-3V6 (i.e no 1V8)
+  //
+  CmdArg.Fields.VoltageSupplied = SD_CMD8_VOLTAGE_27_36;
+
+  EFI_STATUS Status = SdhcSendCommand (HostInst, &CmdSendIfCondSd, CmdArg.AsUint32);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SEND_IF_COND_CMD_RESPONSE CmdStatus;
+  CmdStatus.AsUint32 = HostInst->CmdResponse[0];
+
+  if (CmdStatus.Fields.CheckPattern != CmdArg.Fields.CheckPattern ||
+      CmdStatus.Fields.VoltageSupplied != CmdArg.Fields.VoltageSupplied) {
+    return EFI_UNSUPPORTED;
+  }
+
+  HostInst->CardInfo.HasExtendedOcr = TRUE;
+
+  return EFI_SUCCESS;;
+}
+
+EFI_STATUS
+SdhcSendOpCondSd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+
+  //
+  // With arg set to 0, it means read OCR
+  //
+  Status = SdhcSendCommand (HostInst, &CmdAppSendOpCondSd, 0);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  HostInst->CardInfo.Registers.Sd.Ocr.AsUint32 = HostInst->CmdResponse[0];
+
+  SD_SEND_OP_COND_ARG CmdArg = { 0 };
+  UINT32 Retry = SDMMC_POLL_WAIT_COUNT;
+  SD_OCR Ocr;
+  SD_OCR_EX *OcrEx;
+
+  CmdArg.Fields.VoltageWindow = HostInst->CardInfo.Registers.Sd.Ocr.Fields.VoltageWindow;
+  //
+  // Host support for High Capacity is assumed
+  //
+  CmdArg.Fields.HCS = 1;
+
+  while (Retry) {
+    Status = SdhcSendCommand (HostInst, &CmdAppSendOpCondSd, CmdArg.AsUint32);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Ocr.AsUint32 = HostInst->CmdResponse[0];
+
+    if (Ocr.Fields.PowerUp) {
+      LOG_TRACE ("SD Card PowerUp Complete");
+      if (HostInst->CardInfo.HasExtendedOcr) {
+        OcrEx = (SD_OCR_EX*) &Ocr;
+        if (OcrEx->Fields.CCS) {
+          LOG_TRACE ("Card is SD2.0 or later HighCapacity SDHC or SDXC");
+          HostInst->CardInfo.HighCapacity = TRUE;
+        } else {
+          LOG_TRACE ("Card is SD2.0 or later StandardCapacity SDSC");
+          HostInst->CardInfo.HighCapacity = FALSE;
+        }
+      }
+      break;
+    }
+    gBS->Stall (SDMMC_POLL_WAIT_TIME_US);
+    --Retry;
+  }
+
+  if (!Retry) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+SdhcSwitchBusWidthSd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  EFI_STATUS Status;
+  UINT32 CmdArg;
+
+  //Status = SdhcSendScrSd(HostInst);
+  //if (EFI_ERROR(Status)) {
+  //    return Status;
+  //}
+
+  CmdArg = 0x2; // 4-bit
+  Status = SdhcSendCommand (HostInst, &CmdAppSetBusWidthSd, CmdArg);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = HostExt->SetBusWidth (HostExt, SdBusWidth4Bit);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchSpeedModeSd (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  return EFI_SUCCESS;
+}
+
+//
+// SDIO Specific Functions
+//
+
+EFI_STATUS
+SdhcSendOpCondSdio (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  return SdhcSendCommand (HostInst, &CmdSendOpCondSdio, 0);
+}
+
+//
+// Mmc Specific Functions
+//
+
+EFI_STATUS
+SdhcSendOpCondMmc (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+  MMC_SEND_OP_COND_ARG CmdArg = { 0 };
+  UINT32 Retry = SDMMC_POLL_WAIT_COUNT;
+  MMC_OCR *Ocr = &HostInst->CardInfo.Registers.Mmc.Ocr;
+
+  CmdArg.Fields.VoltageWindow = SD_OCR_HIGH_VOLTAGE_WINDOW;
+  CmdArg.Fields.AccessMode = SdOcrAccessSectorMode;
+
+  while (Retry) {
+    Status = SdhcSendCommand (HostInst, &CmdSendOpCondMmc, CmdArg.AsUint32);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    HostInst->CardInfo.Registers.Mmc.Ocr.AsUint32 = HostInst->CmdResponse[0];
+
+    if (Ocr->Fields.PowerUp) {
+      LOG_TRACE ("MMC Card PowerUp Complete");
+      if (Ocr->Fields.AccessMode == SdOcrAccessSectorMode) {
+        LOG_TRACE ("Card is MMC HighCapacity");
+        HostInst->CardInfo.HighCapacity = TRUE;
+      } else {
+        LOG_TRACE ("Card is MMC StandardCapacity");
+        HostInst->CardInfo.HighCapacity = FALSE;
+      }
+
+      if ((Ocr->Fields.VoltageWindow & SD_OCR_HIGH_VOLTAGE_WINDOW) != SD_OCR_HIGH_VOLTAGE_WINDOW) {
+        LOG_ERROR (
+          "MMC Card does not support High Voltage, expected profile:%x actual profile:%x",
+          (UINT32) SD_OCR_HIGH_VOLTAGE_WINDOW,
+          (UINT32) Ocr->Fields.VoltageWindow);
+        return EFI_UNSUPPORTED;
+      }
+
+      break;
+    }
+    gBS->Stall (SDMMC_POLL_WAIT_TIME_US);
+    --Retry;
+  }
+
+  if (!Retry) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchBusWidthMmc (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  EFI_STATUS Status;
+  UINT32 CmdArg;
+  SD_BUS_WIDTH BusWidth = SdBusWidth8Bit;
+  MMC_EXT_CSD *ExtCsd = &HostInst->CardInfo.Registers.Mmc.ExtCsd;
+  UINT8 ExtCsdPowerClass;
+  MMC_SWITCH_CMD_ARG SwitchCmdArg;
+
+  Status = SdhcSendExtCsdMmc (HostInst);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Figure out current requirements for target bus width. An inrease in current consumption
+  // may require switching the card to a higher power class
+  //
+  if (BusWidth == SdBusWidth8Bit) {
+    if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed) {
+      ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_8BIT (ExtCsd->PowerClass52Mhz36V);
+    } else {
+      ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_8BIT (ExtCsd->PowerClass26Mhz36V);
+    }
+  } else if (BusWidth == SdBusWidth4Bit) {
+    if (HostInst->CardInfo.CurrentSpeedMode == CardSpeedModeHighSpeed) {
+      ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_4BIT (ExtCsd->PowerClass52Mhz36V);
+    } else {
+      ExtCsdPowerClass = MMC_EXT_CSD_POWER_CLASS_4BIT (ExtCsd->PowerClass26Mhz36V);
+    }
+  } else {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Only do power class switch if the target bus width requires more current than the
+  // allowed by the current power class in EXT_CSD
+  //
+  if (ExtCsdPowerClass > HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass) {
+    CmdArg = ExtCsdPowerClass;
+    CmdArg <<= 8;
+    CmdArg |= 0x03BB0000;
+    Status = SdhcSendCommand (
+      HostInst,
+      &CmdSwitchMmc,
+      CmdArg);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("Error detected on switching PowerClass function");
+      return Status;
+    }
+
+    Status = SdhcSendExtCsdMmc (HostInst);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    //
+    // Sanity check that wanted power-class are set per requested
+    //
+    if (HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass != ExtCsdPowerClass) {
+      LOG_ERROR (
+        "MMC EXT_CSD not reporting correct PowerClass after switch. Expected:%x Actual:%x",
+        (UINT32) ExtCsdPowerClass,
+        (UINT32) HostInst->CardInfo.Registers.Mmc.ExtCsd.PowerClass);
+      return EFI_PROTOCOL_ERROR;
+    }
+  }
+
+  //
+  // Switch bus width
+  //
+  SwitchCmdArg.AsUint32 = 0;
+  SwitchCmdArg.Fields.Access = MmcSwitchCmdAccessTypeWriteByte;
+  SwitchCmdArg.Fields.Index = MmcExtCsdBitIndexBusWidth;
+
+  if (BusWidth == SdBusWidth8Bit) {
+    SwitchCmdArg.Fields.Value = MmcExtCsdBusWidth8Bit;
+  } else {
+    SwitchCmdArg.Fields.Value = MmcExtCsdBusWidth4Bit;
+  }
+
+  Status = SdhcSendCommand (
+    HostInst,
+    &CmdSwitchMmc,
+    SwitchCmdArg.AsUint32);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("Error detected on switching BusWidth function");
+    return Status;
+  }
+
+  Status = HostExt->SetBusWidth (HostExt, BusWidth);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchSpeedModeMmc (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+  MMC_SWITCH_CMD_ARG CmdArg;
+
+  CmdArg.AsUint32 = 0;
+  CmdArg.Fields.Access = MmcSwitchCmdAccessTypeWriteByte;
+  CmdArg.Fields.Index = MmcExtCsdBitIndexHsTiming;
+  CmdArg.Fields.Value = 1;
+
+  Status = SdhcSendCommand (
+    HostInst,
+    &CmdSwitchMmc,
+    CmdArg.AsUint32);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("Error detected on switching HighSpeed function");
+    return Status;
+  }
+
+  HostInst->CardInfo.CurrentSpeedMode = CardSpeedModeHighSpeed;
+
+  Status = SdhcSendExtCsdMmc (HostInst);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (!HostInst->CardInfo.Registers.Mmc.ExtCsd.HighSpeedTiming) {
+    LOG_ERROR ("MMC EXT_CSD not reporting HighSpeed timing after switch");
+    return EFI_PROTOCOL_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSendExtCsdMmc (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+  UINT32 CmdArg;
+  MMC_EXT_CSD *ExtCsd;
+
+  CmdArg = HostInst->CardInfo.RCA << 16;
+  ExtCsd = &HostInst->CardInfo.Registers.Mmc.ExtCsd;
+
+  Status = SdhcSendDataCommand (
+    HostInst,
+    &CmdSendExtCsdMmc,
+    CmdArg,
+    sizeof (HostInst->BlockBuffer),
+    HostInst->BlockBuffer);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  gBS->CopyMem (ExtCsd, HostInst->BlockBuffer, sizeof (MMC_EXT_CSD));
+
+  HostInst->CardInfo.ByteCapacity = (UINT64) ExtCsd->SectorCount * 512llu;
+  HostInst->BlockIo.Media->LastBlock = ExtCsd->SectorCount - 1;
+
+  HostInst->RpmbIo.ReliableSectorCount = ExtCsd->ReliableWriteSectorCount;
+  HostInst->RpmbIo.RpmbSizeMult = ExtCsd->RpmbSizeMult;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SdhcSwitchPartitionMmc (
+  IN SDHC_INSTANCE                  *HostInst,
+  IN MMC_EXT_CSD_PARTITION_ACCESS   Partition
+  )
+{
+  EFI_STATUS Status;
+  MMC_SWITCH_CMD_ARG CmdArg;
+  MMC_EXT_CSD_PARTITION_CONFIG PartConfig;
+
+  LOG_TRACE (
+    "SdhcSwitchPartitionMmc(Partition=%a)",
+    MmcPartitionAccessToString (Partition));
+
+  PartConfig.AsUint8 = HostInst->CardInfo.Registers.Mmc.ExtCsd.PartitionConfig;
+  PartConfig.Fields.PARTITION_ACCESS = Partition;
+
+  //
+  // Write the partition type to EXT_CSD[PARTITION_CONFIG].PARTITION_ACCESS
+  //
+
+  ZeroMem (&CmdArg, sizeof (MMC_SWITCH_CMD_ARG));
+  CmdArg.Fields.Access = MmcSwitchCmdAccessTypeWriteByte;
+  CmdArg.Fields.Index = MmcExtCsdBitIndexPartitionConfig;
+  CmdArg.Fields.Value = PartConfig.AsUint8;
+
+  Status = SdhcSendCommand (HostInst, &CmdSwitchMmc, CmdArg.AsUint32);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSendCommand failed. (Status = %r)");
+    return Status;
+  }
+
+  //
+  // Re-read the EXT_CSD to verify the partition switch physically happenned
+  //
+  Status = SdhcSendExtCsdMmc (HostInst);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  PartConfig.AsUint8 = HostInst->CardInfo.Registers.Mmc.ExtCsd.PartitionConfig;
+  if (PartConfig.Fields.PARTITION_ACCESS != Partition) {
+    LOG_ERROR (
+      "Current partition indicated by EXT_CSD doesn't match the "
+      "partition the MMC should have switched to. Expected:%a Actual:%a",
+      MmcPartitionAccessToString (Partition),
+      MmcPartitionAccessToString (PartConfig.Fields.PARTITION_ACCESS));
+
+    return EFI_DEVICE_ERROR;
+  }
+
+  LOG_TRACE (
+    "Switched from partition %a to %a successfully",
+    MmcPartitionAccessToString (HostInst->CurrentMmcPartition),
+    MmcPartitionAccessToString (Partition));
+
+  HostInst->CurrentMmcPartition = Partition;
+
+  return EFI_SUCCESS;
+}
+
+//
+// SD command definitions
+//
+
+CONST SD_COMMAND CmdGoIdleState =
+{ 0,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeNone,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendOpCondMmc =
+{ 1,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR3,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendCidAll =
+{ 2,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR2,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendRelativeAddr =
+{ 3,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR6,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendOpCondSdio =
+{ 5,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR4,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSwitchSd =
+{ 6,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdSwitchMmc =
+{ 6,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1B,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdAppSetBusWidthSd =
+{ 6,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSelect =
+{ 7,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1B,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdDeselect =
+{ 7,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeNone,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendIfCondSd =
+{ 8,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR6,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendExtCsdMmc =
+{ 8,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdSendCsd =
+{ 9,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR2,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendCid =
+{ 10,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR2,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSwitchVoltageSd =
+{ 11,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdStopTransmission =
+{ 12,
+ SdCommandTypeAbort,
+ SdCommandClassStandard,
+ SdResponseTypeR1B,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdSendStatus =
+{ 13,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdBusTestReadMmc =
+{ 14,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdSetBlockLength =
+{ 16,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdReadSingleBlock =
+{ 17,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdReadMultiBlock =
+{ 18,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeMultiBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdBusTestWriteMmc =
+{ 19,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionWrite };
+
+CONST SD_COMMAND CmdSetBlockCount =
+{ 23,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdWriteSingleBlock =
+{ 24,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionWrite };
+
+CONST SD_COMMAND CmdWriteMultiBlock =
+{ 25,
+ SdCommandTypeUndefined,
+ SdCommandClassStandard,
+ SdResponseTypeR1,
+ SdTransferTypeMultiBlock,
+ SdTransferDirectionWrite };
+
+CONST SD_COMMAND CmdAppSendOpCondSd =
+{ 41,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR3,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdAppSetClrCardDetectSd =
+{ 42,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
+
+CONST SD_COMMAND CmdAppSendScrSd =
+{ 51,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeSingleBlock,
+ SdTransferDirectionRead };
+
+CONST SD_COMMAND CmdAppSd =
+{ 55,
+ SdCommandTypeUndefined,
+ SdCommandClassApp,
+ SdResponseTypeR1,
+ SdTransferTypeNone,
+ SdTransferDirectionUndefined };
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h
new file mode 100644
index 000000000000..24cb9909373b
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h
@@ -0,0 +1,231 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __PROTOCOL_H__
+#define __PROTOCOL_H__
+
+EFI_STATUS
+InitializeDevice (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+InitializeSdDevice (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+InitializeMmcDevice (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendCommand (
+  IN SDHC_INSTANCE      *HostInst,
+  IN CONST SD_COMMAND   *Cmd,
+  IN UINT32             Arg
+  );
+
+EFI_STATUS
+SdhcSendDataCommand (
+  IN SDHC_INSTANCE      *HostInst,
+  IN CONST SD_COMMAND   *Cmd,
+  IN UINT32             Arg,
+  IN UINT32             BufferByteSize,
+  IN OUT VOID           *Buffer
+  );
+
+// SD/SDIO/MMC Generic Functions
+
+EFI_STATUS
+SdhcRecoverFromErrors (
+  IN SDHC_INSTANCE      *HostInst,
+  IN CONST SD_COMMAND   *Cmd
+  );
+
+EFI_STATUS
+SdhcQueryCardType (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcGoIdleState (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendCidAll (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendRelativeAddr (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcWaitForTranStateAndReadyForData (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendCid (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendCsd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendAppCmd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSelectDevice (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcDeselectDevice (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcStopTransmission (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSetMaxClockFrequency (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSetBlockLength (
+  IN SDHC_INSTANCE  *HostInst,
+  IN UINT32          BlockByteLength
+  );
+
+EFI_STATUS
+SdhcSetBlockCount (
+  IN SDHC_INSTANCE  *HostInst,
+  IN UINT32         BlockCount,
+  IN BOOLEAN        ReliableWrite
+  );
+
+EFI_STATUS
+SdhcSendStatus (
+  IN SDHC_INSTANCE  *HostInst,
+  OUT CARD_STATUS   *CardStatus
+  );
+
+// SD Specific Functions
+
+EFI_STATUS
+SdhcSendScrSd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendOpCondSd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendIfCondSd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSwitchBusWidthSd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSwitchSpeedModeSd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+// SDIO Specific Functions
+
+EFI_STATUS
+SdhcSendOpCondSdio (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+// MMC Specific Functions
+
+EFI_STATUS
+SdhcSendOpCondMmc (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSwitchBusWidthMmc (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+
+EFI_STATUS
+SdhcSwitchSpeedModeMmc (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSendExtCsdMmc (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+EFI_STATUS
+SdhcSwitchPartitionMmc (
+  IN SDHC_INSTANCE                  *HostInst,
+  IN MMC_EXT_CSD_PARTITION_ACCESS   Partition
+  );
+
+// SD/MMC Commands
+
+extern CONST SD_COMMAND CmdGoIdleState;
+extern CONST SD_COMMAND CmdSendOpCondMmc;
+extern CONST SD_COMMAND CmdSendCidAll;
+extern CONST SD_COMMAND CmdSendRelativeAddr;
+extern CONST SD_COMMAND CmdSendOpCondSdio;
+extern CONST SD_COMMAND CmdSwitchSd;
+extern CONST SD_COMMAND CmdSwitchMmc;
+extern CONST SD_COMMAND CmdAppSetBusWidthSd;
+extern CONST SD_COMMAND CmdSelect;
+extern CONST SD_COMMAND CmdDeselect;
+extern CONST SD_COMMAND CmdSendIfCondSd;
+extern CONST SD_COMMAND CmdSendExtCsdMmc;
+extern CONST SD_COMMAND CmdSendCsd;
+extern CONST SD_COMMAND CmdSendCid;
+extern CONST SD_COMMAND CmdSwitchVoltageSd;
+extern CONST SD_COMMAND CmdStopTransmission;
+extern CONST SD_COMMAND CmdSendStatus;
+extern CONST SD_COMMAND CmdBusTestReadMmc;
+extern CONST SD_COMMAND CmdSetBlockLength;
+extern CONST SD_COMMAND CmdReadSingleBlock;
+extern CONST SD_COMMAND CmdReadMultiBlock;
+extern CONST SD_COMMAND CmdBusTestWriteMmc;
+extern CONST SD_COMMAND CmdSetBlockCount;
+extern CONST SD_COMMAND CmdWriteSingleBlock;
+extern CONST SD_COMMAND CmdWriteMultiBlock;
+extern CONST SD_COMMAND CmdAppSendOpCondSd;
+extern CONST SD_COMMAND CmdAppSetClrCardDetectSd;
+extern CONST SD_COMMAND CmdAppSendScrSd;
+extern CONST SD_COMMAND CmdAppSd;
+
+#endif // __PROTOCOL_H__
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c b/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c
new file mode 100644
index 000000000000..69ca29a6aba9
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c
@@ -0,0 +1,611 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+C_ASSERT(sizeof(EFI_RPMB_DATA_PACKET) == SD_BLOCK_LENGTH_BYTES);
+
+EFI_RPMB_DATA_PACKET ResultRequest = {
+  { 0 }, // Stuff
+  { 0 }, // MAC
+  { 0 }, // Data
+  { 0 }, // Nonce
+  { 0 }, // WriteCounter
+  { 0 }, // Address
+  { 0 }, // PacketCount
+  { 0 }, // OperationResult
+  { 0x00, EFI_RPMB_REQUEST_RESULT_REQUEST } // RequestType
+};
+
+// JEDEC Standard No. 84-A441:
+// Byte order of the RPMB data frame is MSB first, e.g. Write Counter MSB [11]
+// is storing the upmost byte of the counter value.
+
+VOID
+Uint16ToRpmbBytes (
+  IN UINT16   Value,
+  OUT UINT8   *RpmbBytes
+  )
+{
+  ASSERT (RpmbBytes != NULL);
+
+  RpmbBytes[0] = (UINT8) (Value >> 8);
+  RpmbBytes[1] = (UINT8) (Value & 0xF);
+}
+
+
+UINT16
+RpmbBytesToUint16 (
+  IN CONST UINT8  *RpmbBytes
+  )
+{
+  ASSERT (RpmbBytes != NULL);
+
+  return ((UINT16) RpmbBytes[0] << 8) | ((UINT16) RpmbBytes[1]);
+}
+
+EFI_STATUS
+RpmbRead (
+  IN SDHC_INSTANCE          *HostInst,
+  IN EFI_RPMB_DATA_PACKET   *Request,
+  OUT EFI_RPMB_DATA_BUFFER  *Response
+  )
+{
+  EFI_STATUS Status;
+
+  Status = SdhcSetBlockCount (HostInst, 1, FALSE);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSetBlockCount() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  Status = SdhcSendDataCommand (
+    HostInst,
+    &CmdWriteMultiBlock,
+    0, // LBA argument is ignored for RPMB access, the eMMC will use instead the Address
+       // field of the RPMB packet
+    sizeof (*Request),
+    Request);
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "Failed to write the Read request data packet. (Status = %r)",
+      Status);
+
+    return Status;
+  }
+
+  Status = SdhcSetBlockCount (HostInst, Response->PacketCount, FALSE);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSetBlockCount() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  Status = SdhcSendDataCommand (
+    HostInst,
+    &CmdReadMultiBlock,
+    0, // LBA argument is ignored for RPMB access, the eMMC will use instead the Address
+       // field of the RPMB packet
+    Response->PacketCount * sizeof(*Response->Packets),
+    Response->Packets);
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "Failed to read the Read request data packet. (Status = %r)",
+      Status);
+
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbWrite (
+  IN SDHC_INSTANCE          *HostInst,
+  IN EFI_RPMB_DATA_BUFFER   *Request
+  )
+{
+  EFI_STATUS Status;
+
+  Status = SdhcSetBlockCount (HostInst, Request->PacketCount, TRUE);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SdhcSetBlockCount() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  Status = SdhcSendDataCommand (
+    HostInst,
+    &CmdWriteMultiBlock,
+    0, // LBA argument is ignored for RPMB access, the eMMC will use instead the Address
+       // field of the RPMB packet
+    Request->PacketCount * sizeof(*Request->Packets),
+    Request->Packets);
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "Failed to write the Read request data packet. (Status = %r)",
+      Status);
+
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbQueryResult (
+  IN SDHC_INSTANCE          *HostInst,
+  OUT EFI_RPMB_DATA_PACKET  *Response
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+  ResponseBuffer.PacketCount = 1;
+  ResponseBuffer.Packets = Response;
+
+  Status = RpmbRead (HostInst, &ResultRequest, &ResponseBuffer);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRead() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbProgramKeyRequest (
+  IN SDHC_INSTANCE          *HostInst,
+  IN EFI_RPMB_DATA_PACKET   *Request,
+  OUT EFI_RPMB_DATA_PACKET  *Response
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER RequestBuffer;
+
+  RequestBuffer.PacketCount = 1;
+  RequestBuffer.Packets = Request;
+
+  Status = RpmbWrite (HostInst, &RequestBuffer);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbWrite() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  Status = RpmbQueryResult (HostInst, Response);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbQueryResult() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbReadCounterRequest (
+  IN SDHC_INSTANCE          *HostInst,
+  IN EFI_RPMB_DATA_PACKET   *Request,
+  OUT EFI_RPMB_DATA_PACKET  *Response
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+  ResponseBuffer.PacketCount = 1;
+  ResponseBuffer.Packets = Response;
+
+  Status = RpmbRead (HostInst, Request, &ResponseBuffer);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRead() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbAuthenticatedWriteRequest (
+  IN SDHC_INSTANCE          *HostInst,
+  IN EFI_RPMB_DATA_BUFFER   *Request,
+  OUT EFI_RPMB_DATA_PACKET  *Response
+  )
+{
+  EFI_STATUS Status;
+
+  Status = RpmbWrite (HostInst, Request);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbWrite() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  Status = RpmbQueryResult (HostInst, Response);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbQueryResult() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RpmbAuthenticatedReadRequest (
+  IN SDHC_INSTANCE          *HostInst,
+  IN EFI_RPMB_DATA_PACKET   *Request,
+  OUT EFI_RPMB_DATA_BUFFER  *Response
+  )
+{
+  EFI_STATUS Status;
+
+  Status = RpmbRead (HostInst, Request, Response);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRead() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+VOID
+RpmbHexDump (
+  IN CONST UINT8  *Bytes,
+  IN UINTN        Len
+  )
+{
+  UINTN i;
+
+  for (i = 0; i < Len; i++) {
+    if ((i > 0) && (i % 16) == 0) {
+      LOG_VANILLA_TRACE ("\n");
+    }
+    LOG_VANILLA_TRACE ("%02x ", *Bytes);
+    ++Bytes;
+  }
+  LOG_VANILLA_TRACE ("\n");
+}
+
+VOID
+RpmbDumpPacket (
+  IN EFI_RPMB_DATA_PACKET *Packet
+  )
+{
+  LOG_TRACE ("*** RPMB Packet Dump (Packet = %p) ***", Packet);
+  LOG_TRACE ("- Write Counter");
+  RpmbHexDump (Packet->WriteCounter, EFI_RPMB_PACKET_WCOUNTER_SIZE);
+  LOG_TRACE ("- Address:");
+  RpmbHexDump (Packet->Address, EFI_RPMB_PACKET_ADDRESS_SIZE);
+  LOG_TRACE ("- Block Count:");
+  RpmbHexDump (Packet->BlockCount, EFI_RPMB_PACKET_BLOCKCOUNT_SIZE);
+  LOG_TRACE ("- Result:");
+  RpmbHexDump (Packet->OperationResult, EFI_RPMB_PACKET_RESULT_SIZE);
+  LOG_TRACE ("- Req/Res Type:");
+  RpmbHexDump (Packet->RequestOrResponseType, EFI_RPMB_PACKET_TYPE_SIZE);
+}
+
+EFI_STATUS
+RpmbRequest (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_BUFFER   *Request,
+  OUT EFI_RPMB_DATA_BUFFER  *Response
+  )
+{
+  EFI_STATUS Status;
+  SDHC_INSTANCE *HostInst;
+  MMC_EXT_CSD_PARTITION_ACCESS CurrentPartition;
+  EFI_STATUS SwitchStatus;
+  BOOLEAN SwitchPartition;
+  UINT16 RequestType;
+
+  SwitchPartition = FALSE;
+  Status = EFI_SUCCESS;
+  SwitchStatus = EFI_SUCCESS;
+
+  ASSERT (This);
+  ASSERT (Request);
+  ASSERT (Response);
+
+  HostInst = SDHC_INSTANCE_FROM_RPMB_IO_THIS (This);
+  ASSERT (HostInst);
+  ASSERT (HostInst->HostExt);
+
+  CurrentPartition = HostInst->CurrentMmcPartition;
+
+  SwitchStatus = SdhcSwitchPartitionMmc (HostInst, MmcExtCsdPartitionAccessRpmb);
+  if (EFI_ERROR (SwitchStatus)) {
+
+    LOG_ERROR (
+      "SdhcSwitchPartitionMmc() failed. (SwitchStatus = %r)",
+      SwitchStatus);
+
+    goto Exit;
+  }
+
+  SwitchPartition = TRUE;
+
+  ASSERT (Request->PacketCount > 0);
+  ASSERT (Request->Packets != NULL);
+  RequestType = RpmbBytesToUint16 (Request->Packets[0].RequestOrResponseType);
+
+  switch (RequestType) {
+  case EFI_RPMB_REQUEST_PROGRAM_KEY:
+    Status = RpmbProgramKeyRequest (HostInst, Request->Packets, Response->Packets);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("RpmbProgramKeyRequest() failed. (Status = %r)", Status);
+      goto Exit;
+    }
+    break;
+
+  case EFI_RPMB_REQUEST_COUNTER_VALUE:
+    Status = RpmbReadCounterRequest (HostInst, Request->Packets, Response->Packets);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("RpmbReadCounterRequest() failed. (Status = %r)", Status);
+      goto Exit;
+    }
+    break;
+
+  case EFI_RPMB_REQUEST_AUTH_READ:
+    Status = RpmbAuthenticatedReadRequest (HostInst, Request->Packets, Response);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("RpmbAuthenticatedReadRequest() failed. (Status = %r)", Status);
+      goto Exit;
+    }
+    break;
+
+  case EFI_RPMB_REQUEST_AUTH_WRITE:
+    Status = RpmbAuthenticatedWriteRequest (HostInst, Request, Response->Packets);
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR ("RpmbAuthenticatedWriteRequest() failed. (Status = %r)", Status);
+      goto Exit;
+    }
+    break;
+
+  default:
+
+    ASSERT (FALSE);
+  }
+
+Exit:
+
+  if (SwitchPartition) {
+    SwitchStatus = SdhcSwitchPartitionMmc (HostInst, CurrentPartition);
+    if (EFI_ERROR (SwitchStatus)) {
+
+      LOG_ERROR (
+        "SdhcSwitchPartitionMmc() failed. (SwitchStatus = %r)",
+        SwitchStatus);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  } else {
+    return SwitchStatus;
+  }
+}
+
+/** Authentication key programming request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ProgrammingRequest A data packet describing a key programming request.
+  @param[out] ResultResponse A caller allocated data packet which will receive the
+  key programming result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during key programming any other eMMC internal failure is reported
+  in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoProgramKey (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ProgrammingRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ResultResponse
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER RequestBuffer;
+  EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+  LOG_TRACE ("RpmbIoProgramKey()");
+
+  if ((This == NULL) || (ProgrammingRequest == NULL) || (ResultResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (RpmbBytesToUint16 (ProgrammingRequest->RequestOrResponseType) != EFI_RPMB_REQUEST_PROGRAM_KEY) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RequestBuffer.PacketCount = 1;
+  RequestBuffer.Packets = ProgrammingRequest;
+
+  ResponseBuffer.PacketCount = 1;
+  ResponseBuffer.Packets = ResultResponse;
+
+  Status = RpmbRequest (This, &RequestBuffer, &ResponseBuffer);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return Status;
+}
+
+/** Reading of the write counter value request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ReadRequest A data packet describing a read counter value request.
+  @param[out] ReadResponse A caller allocated data packet which will receive
+  the counter value read response. If counter has expired bit 7 is set to 1 in
+  returned Result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during counter read or any other eMMC internal failure is reported
+  in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoReadCounter (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ReadRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ReadResponse
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER RequestBuffer;
+  EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+  LOG_TRACE ("RpmbIoReadCounter()");
+
+  if ((This == NULL) || (ReadRequest == NULL) || (ReadResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (RpmbBytesToUint16 (ReadRequest->RequestOrResponseType) != EFI_RPMB_REQUEST_COUNTER_VALUE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RequestBuffer.PacketCount = 1;
+  RequestBuffer.Packets = ReadRequest;
+
+  ResponseBuffer.PacketCount = 1;
+  ResponseBuffer.Packets = ReadResponse;
+
+  Status = RpmbRequest (This, &RequestBuffer, &ResponseBuffer);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return Status;
+}
+
+/** Authenticated data write request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] WriteRequest A sequence of data packets describing data write
+  requests and holds the data to be written.
+  @param[out] ResultResponse A caller allocated data packet which will receive
+  the data write programming result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during data programming or any other eMMC internal failure is reported
+  in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedWrite (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_BUFFER   *Request,
+  OUT EFI_RPMB_DATA_PACKET  *Response
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER ResponseBuffer;
+
+  LOG_TRACE ("RpmbIoAuthenticatedWrite()");
+
+  if ((This == NULL) || (Request == NULL) || (Response == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Request->Packets == NULL) || (Request->PacketCount == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (RpmbBytesToUint16 (Request->Packets->RequestOrResponseType) != EFI_RPMB_REQUEST_AUTH_WRITE) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ResponseBuffer.PacketCount = 1;
+  ResponseBuffer.Packets = Response;
+
+  Status = RpmbRequest (This, Request, &ResponseBuffer);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return Status;
+}
+
+/** Authenticated data read request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ReadRequest A data packet that describes a data read request.
+  @param[out] ReadResponse A caller allocated data packets which will receive
+  the data read.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during data fetch from the eMMC or any other eMMC internal failure
+  is reported in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedRead (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ReadRequest,
+  OUT EFI_RPMB_DATA_BUFFER  *ReadResponse
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_DATA_BUFFER RequestBuffer;
+
+  LOG_TRACE ("RpmbIoAuthenticatedRead()");
+
+  if ((This == NULL) || (ReadRequest == NULL) || (ReadResponse == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((ReadResponse->Packets == NULL) || (ReadResponse->PacketCount == 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (RpmbBytesToUint16 (ReadRequest->RequestOrResponseType) != EFI_RPMB_REQUEST_AUTH_READ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  RequestBuffer.PacketCount = 1;
+  RequestBuffer.Packets = ReadRequest;
+
+  Status = RpmbRequest (This, &RequestBuffer, ReadResponse);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("RpmbRequest() failed. (Status = %r)", Status);
+    return Status;
+  }
+
+  return Status;
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c
new file mode 100644
index 000000000000..bf4ec4ba8954
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c
@@ -0,0 +1,892 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Sdhc.h>
+#include <Protocol/RpmbIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SdMmcHw.h"
+#include "SdMmc.h"
+#include "Protocol.h"
+
+// A template EFI_BLOCK_IO media to use for creating new EFI_BLOCK_IO protocols
+// for new SDHC instances.
+EFI_BLOCK_IO_MEDIA gSdhcMediaTemplate = {
+  0,                      // MediaId
+  TRUE,                   // RemovableMedia
+  FALSE,                  // MediaPresent
+  FALSE,                  // LogicalPartition
+  FALSE,                  // ReadOnly
+  FALSE,                  // WriteCaching
+  SD_BLOCK_LENGTH_BYTES,  // BlockSize
+  4,                      // IoAlign
+  0,                      // Pad
+  0                       // LastBlock
+};
+
+// This structure is serviced as a header.Its next field points to the first root
+// bridge device node.
+LIST_ENTRY  gSdhcInstancePool;
+UINT32 gNextSdhcInstanceId = 0;
+
+// Event triggered by the timer to check if any cards have been removed
+// or if new ones have been plugged in.
+EFI_EVENT gCheckCardsEvent;
+
+// The ARM high-performance counter frequency.
+UINT64 gHpcTicksPerSeconds = 0;
+
+VOID
+EFIAPI
+CheckCardsCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+EFI_STATUS
+EFIAPI
+UninstallAllProtocols (
+  IN SDHC_INSTANCE *HostInst
+  );
+
+BOOLEAN
+EFIAPI
+IsRpmbInstalledOnTheSystem (
+  VOID
+  );
+
+/** Initialize the SDHC Pool to support multiple SD/MMC devices.
+**/
+VOID
+InitializeSdhcPool (
+  VOID
+  )
+{
+  InitializeListHead (&gSdhcInstancePool);
+}
+
+/** Insert a new SDHC instance in the host pool.
+
+  @param[in] HostInst The SDHC instance context data.
+**/
+VOID
+InsertSdhcInstance (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  InsertTailList (&gSdhcInstancePool, &(HostInst->Link));
+}
+
+/** Removes an existing SDHC instance context data from the host pool.
+
+  @param[in] HostInst The SDHC instance data.
+**/
+VOID
+RemoveSdhcInstance (
+  IN SDHC_INSTANCE  *HostInst
+)
+{
+  RemoveEntryList (&(HostInst->Link));
+}
+
+/** Creates a new SDHC instance context data.
+
+  It initializes the context data but does not attempt to perform any hardware
+  access nor install any EFI protocol. This happens later on when a card presence
+  state changes during the card check callback.
+
+  @param[in] HostExt The EFI_SDHC_PROTOCOL instance data to use as the basis for
+  SDHC instance context data creation.
+
+  @retval An SDHC instance context data on successful instance creation and return
+  NULL otherwise.
+**/
+SDHC_INSTANCE*
+CreateSdhcInstance (
+  IN EFI_SDHC_PROTOCOL  *HostExt
+  )
+{
+  EFI_STATUS Status;
+  SDHC_INSTANCE *HostInst = NULL;
+
+  HostInst = AllocateZeroPool (sizeof (SDHC_INSTANCE));
+  if (HostInst == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  HostInst->Signature = SDHC_INSTANCE_SIGNATURE;
+  HostInst->InstanceId = gNextSdhcInstanceId;
+  HostInst->HostExt = HostExt;
+
+  HostExt->GetCapabilities (HostExt, &HostInst->HostCapabilities);
+  ASSERT (HostInst->HostCapabilities.MaximumBlockSize > 0);
+  ASSERT (HostInst->HostCapabilities.MaximumBlockCount > 0);
+
+  // We will support 512 byte blocks only.
+  if (HostInst->HostCapabilities.MaximumBlockSize < SD_BLOCK_LENGTH_BYTES) {
+    LOG_ERROR (
+      "Unsupported max block size of %d bytes",
+      HostInst->HostCapabilities.MaximumBlockSize);
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  LOG_TRACE (
+    "Host Capabilities: MaximumBlockSize:%d MaximumBlockCount:%d",
+    HostInst->HostCapabilities.MaximumBlockSize,
+    HostInst->HostCapabilities.MaximumBlockCount);
+
+  HostInst->DevicePathProtocolInstalled = FALSE;
+  HostInst->BlockIoProtocolInstalled = FALSE;
+  HostInst->RpmbIoProtocolInstalled = FALSE;
+
+  // Initialize BlockIo Protocol.
+
+  HostInst->BlockIo.Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA), &gSdhcMediaTemplate);
+  if (HostInst->BlockIo.Media == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  HostInst->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION;
+  HostInst->BlockIo.Reset = BlockIoReset;
+  HostInst->BlockIo.ReadBlocks = BlockIoReadBlocks;
+  HostInst->BlockIo.WriteBlocks = BlockIoWriteBlocks;
+  HostInst->BlockIo.FlushBlocks = BlockIoFlushBlocks;
+
+  // Initialize DevicePath Protocol.
+
+  SDHC_DEVICE_PATH *DevicePath = &HostInst->DevicePath;
+
+  // Initialize device path based on SDHC DeviceId and delay SlotNode initialization
+  // until the card in Slot0 is type identified.
+
+  DevicePath->SdhcNode.Header.Type = HARDWARE_DEVICE_PATH;
+  DevicePath->SdhcNode.Header.SubType = HW_VENDOR_DP;
+  *((UINT16*) &DevicePath->SdhcNode.Header.Length) = SDHC_NODE_PATH_LENGTH;
+  DevicePath->SdhcId = HostInst->HostExt->SdhcId;
+  GUID SdhcDevicePathGuid = SDHC_DEVICE_PATH_GUID;
+  CopyGuid (&DevicePath->SdhcNode.Guid, &SdhcDevicePathGuid);
+
+  SetDevicePathEndNode (&DevicePath->EndNode);
+
+  // Initialize RpmbIo Protocol.
+
+  HostInst->RpmbIo.Revision = EFI_RPMB_IO_PROTOCOL_REVISION;
+  HostInst->RpmbIo.AuthenticatedRead = RpmbIoAuthenticatedRead;
+  HostInst->RpmbIo.AuthenticatedWrite = RpmbIoAuthenticatedWrite;
+  HostInst->RpmbIo.ProgramKey = RpmbIoProgramKey;
+  HostInst->RpmbIo.ReadCounter = RpmbIoReadCounter;
+
+  // Don't publish any protocol yet, until the SDHC device is fully initialized and
+  // ready for IO.
+
+  ++gNextSdhcInstanceId;
+
+  Status = EFI_SUCCESS;
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    if (HostInst != NULL && HostInst->BlockIo.Media != NULL) {
+      FreePool (HostInst->BlockIo.Media);
+      HostInst->BlockIo.Media = NULL;
+    }
+
+    if (HostInst != NULL) {
+      FreePool (HostInst);
+      HostInst = NULL;
+    }
+  }
+
+  return HostInst;
+}
+
+/** Destroys an existing SDHC instance context data.
+
+  It uninstalls all protocols installed on that instance, free allocated memory
+  and invokes the SDHC clean-up callback.
+
+  @param[in] HostInst The SDHC instance context data to destroy.
+
+  @retval EFI_SUCCESS on successful destruction and cleanup, return an EFI error
+  code otherwise.
+**/
+EFI_STATUS
+DestroySdhcInstance (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+
+  Status = UninstallAllProtocols (HostInst);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Free Memory allocated for the EFI_BLOCK_IO protocol
+  if (HostInst->BlockIo.Media) {
+    FreePool (HostInst->BlockIo.Media);
+  }
+
+  HostInst->HostExt->Cleanup (HostInst->HostExt);
+  HostInst->HostExt = NULL;
+
+  FreePool (HostInst);
+
+  return EFI_SUCCESS;
+}
+
+// UEFI Driver Model EFI_DRIVER_BINDING_PROTOCOL Callbacks
+
+/**
+    Tests to see if this driver supports a given controller. If a child device is provided,
+    it further tests to see if this driver supports creating a handle for the specified child device.
+
+    @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+    @param ControllerHandle     The handle of the controller to test. This handle must support a protocol
+                                interface that supplies an I/O abstraction to the driver. Sometimes
+                                just the presence of this I/O abstraction is enough for the driver to
+                                determine if it supports ControllerHandle. Sometimes, the driver may
+                                use the services of the I/O abstraction to determine if this driver
+                                supports ControllerHandle.
+    @param RemainingDevicePath  A pointer to the remaining portion of a device path. For bus drivers,
+                                if this parameter is not NULL, then the bus driver must determine if
+                                the bus controller specified by ControllerHandle and the child controller
+                                specified by RemainingDevicePath
+**/
+EFI_STATUS
+EFIAPI
+SdMmcDriverSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS Status;
+  EFI_SDHC_PROTOCOL *HostExt;
+  EFI_DEV_PATH_PTR Node;
+
+  // Check RemainingDevicePath validation.
+  if (RemainingDevicePath != NULL) {
+
+    // Check if RemainingDevicePath is the End of Device Path Node,
+    // if yes, go on checking other conditions.
+    if (!IsDevicePathEnd (RemainingDevicePath)) {
+
+      // If RemainingDevicePath isn't the End of Device Path Node,
+      // check its validation.
+
+      Node.DevPath = RemainingDevicePath;
+      if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
+          Node.DevPath->SubType != HW_VENDOR_DP ||
+          DevicePathNodeLength (Node.DevPath) != sizeof (VENDOR_DEVICE_PATH)) {
+        Status = EFI_UNSUPPORTED;
+        goto Exit;
+      }
+    }
+  }
+
+  // Check if SDHC protocol is installed by platform.
+
+  Status = gBS->OpenProtocol (
+    Controller,
+    &gEfiSdhcProtocolGuid,
+    (VOID **) &HostExt,
+    This->DriverBindingHandle,
+    Controller,
+    EFI_OPEN_PROTOCOL_BY_DRIVER);
+  if (Status == EFI_ALREADY_STARTED) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  // Close the SDHC used to perform the supported test.
+  gBS->CloseProtocol (
+    Controller,
+    &gEfiSdhcProtocolGuid,
+    This->DriverBindingHandle,
+    Controller);
+
+Exit:
+  return Status;
+}
+
+/**
+    Starts a device controller or a bus controller. The Start() and Stop() services of the
+    EFI_DRIVER_BINDING_PROTOCOL mirror each other.
+
+    @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+    @param ControllerHandle     The handle of the controller to start. This handle must support a
+                                protocol interface that supplies an I/O abstraction to the driver.
+    @param RemainingDevicePath  A pointer to the remaining portion of a device path. For a bus driver,
+                                if this parameter is NULL, then handles for all the children of Controller
+                                are created by this driver.
+                                If this parameter is not NULL and the first Device Path Node is not
+                                the End of Device Path Node, then only the handle for the child device
+                                specified by the first Device Path Node of RemainingDevicePath is created
+                                by this driver.
+                                If the first Device Path Node of RemainingDevicePath is the End of Device
+                                Path Node, no child handle is created by this driver.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcDriverStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+{
+  EFI_STATUS Status;
+  SDHC_INSTANCE *HostInst;
+  EFI_SDHC_PROTOCOL *HostExt;
+
+  LOG_TRACE ("SdMmcDriverStart()");
+
+  // Check RemainingDevicePath validation.
+  if (RemainingDevicePath != NULL) {
+
+    // Check if RemainingDevicePath is the End of Device Path Node,
+    // if yes, return EFI_SUCCESS.
+    if (IsDevicePathEnd (RemainingDevicePath)) {
+      Status = EFI_SUCCESS;
+      goto Exit;
+    }
+  }
+
+  // Get the SDHC protocol.
+
+  Status = gBS->OpenProtocol (
+    Controller,
+    &gEfiSdhcProtocolGuid,
+    (VOID **) &HostExt,
+    This->DriverBindingHandle,
+    Controller,
+    EFI_OPEN_PROTOCOL_BY_DRIVER);
+  if (EFI_ERROR (Status)) {
+    if (Status == EFI_ALREADY_STARTED) {
+      Status = EFI_SUCCESS;
+    }
+    goto Exit;
+  }
+
+  HostInst = CreateSdhcInstance (HostExt);
+  if (HostInst != NULL) {
+    HostInst->MmcHandle = Controller;
+    InsertSdhcInstance (HostInst);
+
+    LOG_INFO (
+      "SDHC%d instance creation completed. Detecting card presence...",
+      HostInst->HostExt->SdhcId);
+
+    // Detect card presence now which will initialize the SDHC.
+    CheckCardsCallback (NULL, NULL);
+  } else {
+    LOG_ERROR ("CreateSdhcInstance failed. %r", Status);
+  }
+
+Exit:
+  return Status;
+}
+
+/**
+    Stops a device controller or a bus controller. The Start() and Stop() services of the
+    EFI_DRIVER_BINDING_PROTOCOL mirror each other.
+
+    @param This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+                                Type EFI_DRIVER_BINDING_PROTOCOL is defined in Section 10.1.
+    @param ControllerHandle     A handle to the device being stopped. The handle must support a bus
+                                specific I/O protocol for the driver to use to stop the device.
+    @param NumberOfChildren     The number of child device handles in ChildHandleBuffer.
+    @param ChildHandleBuffer    An array of child handles to be freed. May be NULL if NumberOfChildren is 0.
+**/
+EFI_STATUS
+EFIAPI
+SdMmcDriverStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN UINTN                        NumberOfChildren,
+  IN EFI_HANDLE                   *ChildHandleBuffer
+  )
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+  LIST_ENTRY *CurrentLink;
+  SDHC_INSTANCE *HostInst;
+
+  LOG_TRACE ("SdMmcDriverStop()");
+
+  // For each registered SDHC instance.
+  CurrentLink = gSdhcInstancePool.ForwardLink;
+  while (CurrentLink != NULL && CurrentLink != &gSdhcInstancePool && (Status == EFI_SUCCESS)) {
+    HostInst = SDHC_INSTANCE_FROM_LINK (CurrentLink);
+    ASSERT (HostInst != NULL);
+
+    // Close gEfiMmcHostProtocolGuid opened on the SDHC.
+    Status = gBS->CloseProtocol (
+      Controller,
+      &gEfiSdhcProtocolGuid,
+      (VOID **) &HostInst->HostExt,
+      This->DriverBindingHandle);
+
+    // Remove SDHC instance from the pool.
+    RemoveSdhcInstance (HostInst);
+
+    // Destroy SDHC instance.
+    DestroySdhcInstance (HostInst);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SoftReset (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_SDHC_PROTOCOL *HostExt = HostInst->HostExt;
+  EFI_STATUS Status;
+  CHAR16 *DevicePathText = NULL;
+
+  ASSERT (HostInst->HostExt != NULL);
+  LOG_TRACE ("Performing Soft-Reset for SDHC%d", HostExt->SdhcId);
+
+  Status = UninstallAllProtocols (HostInst);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  HostInst->SlotInitialized = FALSE;
+
+  // Clear all media settings regardless of card presence.
+  HostInst->BlockIo.Media->MediaId = 0;
+  HostInst->BlockIo.Media->RemovableMedia = FALSE;
+  HostInst->BlockIo.Media->MediaPresent = FALSE;
+  HostInst->BlockIo.Media->LogicalPartition = FALSE;
+  HostInst->BlockIo.Media->WriteCaching = FALSE;
+  HostInst->BlockIo.Media->BlockSize = 0;
+  HostInst->BlockIo.Media->IoAlign = 4;
+  HostInst->BlockIo.Media->LastBlock = 0;
+  HostInst->BlockIo.Media->LowestAlignedLba = 0;
+  HostInst->BlockIo.Media->LogicalBlocksPerPhysicalBlock = 0;
+  HostInst->BlockIo.Media->OptimalTransferLengthGranularity = 0;
+  HostInst->BlockIo.Media->ReadOnly = FALSE;
+
+  HostInst->RpmbIo.ReliableSectorCount = 0;
+  HostInst->RpmbIo.RpmbSizeMult = 0;
+  ZeroMem (HostInst->RpmbIo.Cid, sizeof (HostInst->RpmbIo.Cid));
+
+  HostInst->BlockIo.Media->MediaPresent = HostInst->HostExt->IsCardPresent (HostInst->HostExt);
+  if (!HostInst->BlockIo.Media->MediaPresent) {
+    // Even if the media is not present, we`d like to communicate that status up
+    // to the storage stack by means of installing the BlockIo protocol.
+    Status =
+      gBS->InstallMultipleProtocolInterfaces (
+        &HostInst->MmcHandle,
+        &gEfiBlockIoProtocolGuid,
+        &HostInst->BlockIo,
+        NULL);
+
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "SoftReset(): Failed installing EFI_BLOCK_IO_PROTOCOL interface. %r",
+        Status);
+
+      goto Exit;
+    }
+
+    HostInst->BlockIoProtocolInstalled = TRUE;
+    LOG_INFO ("SDHC%d media not present, skipping device initialization", HostExt->SdhcId);
+    goto Exit;
+  } else {
+    HostInst->BlockIo.Media->ReadOnly = HostExt->IsReadOnly (HostExt);
+    if (HostInst->BlockIo.Media->ReadOnly) {
+      LOG_INFO ("SDHC%d media is read-only", HostExt->SdhcId);
+    }
+  }
+
+  Status = InitializeDevice (HostInst);
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR ("SoftReset(): InitializeDevice() failed. %r", Status);
+    goto Exit;
+  }
+
+  // Update SlotNode subtype based on the card type identified.
+  // Note that we only support 1 slot per SDHC, i.e It is assumed that no more
+  // than 1 SD/MMC card connected to the same SDHC block on the system.
+  SDHC_DEVICE_PATH *DevicePath = &HostInst->DevicePath;
+  if (HostInst->CardInfo.CardFunction == CardFunctionSd) {
+    DevicePath->SlotNode.SD.Header.Type = MESSAGING_DEVICE_PATH;
+    DevicePath->SlotNode.SD.Header.SubType = MSG_SD_DP;
+    *((UINT16*) &DevicePath->SlotNode.SD.Header.Length) = sizeof (SD_DEVICE_PATH);
+    DevicePath->SlotNode.SD.SlotNumber = 0;
+  } else {
+    ASSERT (HostInst->CardInfo.CardFunction == CardFunctionMmc);
+    DevicePath->SlotNode.MMC.Header.Type = MESSAGING_DEVICE_PATH;
+    DevicePath->SlotNode.MMC.Header.SubType = MSG_EMMC_DP;
+    *((UINT16*) &DevicePath->SlotNode.MMC.Header.Length) = sizeof (EMMC_DEVICE_PATH);
+    DevicePath->SlotNode.MMC.SlotNumber = 0;
+  }
+
+  // Print a text representation of the Slot device path.
+  DevicePathText = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*) DevicePath, FALSE, FALSE);
+
+  if (DevicePathText == NULL) {
+    LOG_ERROR ("SoftReset(): ConvertDevicePathToText() failed.");
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  LOG_INFO ("Recognized device: %s", DevicePathText);
+
+  Status =
+    gBS->InstallMultipleProtocolInterfaces (
+      &HostInst->MmcHandle,
+      &gEfiBlockIoProtocolGuid,
+      &HostInst->BlockIo,
+      NULL);
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "SoftReset(): Failed installing EFI_BLOCK_IO_PROTOCOL interface. %r",
+      Status);
+
+    goto Exit;
+  }
+
+  HostInst->BlockIoProtocolInstalled = TRUE;
+
+  Status =
+    gBS->InstallMultipleProtocolInterfaces (
+      &HostInst->MmcHandle,
+      &gEfiDevicePathProtocolGuid,
+      &HostInst->DevicePath,
+      NULL);
+
+  if (EFI_ERROR (Status)) {
+    LOG_ERROR (
+      "SoftReset(): Failed installing EFI_DEVICE_PATH_PROTOCOL interface. %r",
+      Status);
+
+    goto Exit;
+  }
+
+  HostInst->DevicePathProtocolInstalled = TRUE;
+
+  if (HostInst->CardInfo.CardFunction == CardFunctionMmc) {
+
+    if (!IsRpmbInstalledOnTheSystem ()) {
+      Status =
+        gBS->InstallMultipleProtocolInterfaces (
+          &HostInst->MmcHandle,
+          &gEfiRpmbIoProtocolGuid,
+          &HostInst->RpmbIo,
+          NULL);
+
+      if (EFI_ERROR (Status)) {
+        LOG_ERROR (
+          "SoftReset(): Failed installing EFI_RPMB_IO_PROTOCOL interface. %r",
+          Status);
+
+        goto Exit;
+      }
+
+      LOG_INFO ("RpmbIo protocol installed for MMC: %s", DevicePathText);
+
+      HostInst->RpmbIoProtocolInstalled = TRUE;
+
+      // Track current partition in a separate variable to void having to
+      // ready the MMC EXT_CSD everytime we do partition switch to have
+      // an updated current partition. SdhostSwitchPartitionMmc will keep
+      // track of that variable.
+
+      MMC_EXT_CSD_PARTITION_CONFIG partConfig;
+      partConfig.AsUint8 = HostInst->CardInfo.Registers.Mmc.ExtCsd.PartitionConfig;
+      HostInst->CurrentMmcPartition =
+        (MMC_EXT_CSD_PARTITION_ACCESS) partConfig.Fields.PARTITION_ACCESS;
+
+    } else {
+      LOG_ERROR (
+        "SoftReset(): RpmbIo protocol is already installed on the system. "
+        "The requirement is that only 1 MMC on the system should have RpmbIo "
+        "protocol installed. Skipping RpmbIo protocol installation for %s",
+        DevicePathText);
+    }
+  }
+
+  LOG_TRACE ("All required protocols installed successfully for %s", DevicePathText);
+
+Exit:
+
+  // On error we should uninstall all protocols except BlockIo, it should
+  // always be present since it represents the SDHC physical existance not
+  // the card, other protocols are card dependant and are pure representation
+  // of one or more card features
+  if (EFI_ERROR (Status)) {
+    if (HostInst->RpmbIoProtocolInstalled) {
+      Status =
+        gBS->UninstallMultipleProtocolInterfaces (
+          HostInst->MmcHandle,
+          &gEfiRpmbIoProtocolGuid,
+          &HostInst->RpmbIo,
+          NULL);
+
+      if (EFI_ERROR (Status)) {
+        LOG_ERROR (
+          "SoftReset(): Failed to uninstall EFI_RPMB_IO_PROTOCOL interface. %r",
+          Status);
+      } else {
+        HostInst->RpmbIoProtocolInstalled = FALSE;
+      }
+    }
+
+    if (HostInst->DevicePathProtocolInstalled) {
+      Status =
+        gBS->UninstallMultipleProtocolInterfaces (
+          HostInst->MmcHandle,
+          &gEfiDevicePathProtocolGuid,
+          &HostInst->DevicePath,
+          NULL);
+
+      if (EFI_ERROR (Status)) {
+        LOG_ERROR (
+          "SoftReset(): Failed to uninstall EFI_DEVICE_PATH_PROTOCOL interface. %r",
+          Status);
+      } else {
+        HostInst->DevicePathProtocolInstalled = FALSE;
+      }
+    }
+  }
+
+  if (DevicePathText != NULL) {
+    FreePool (DevicePathText);
+  }
+
+  return Status;
+}
+
+VOID
+EFIAPI
+CheckCardsCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  LIST_ENTRY *CurrentLink;
+  SDHC_INSTANCE *HostInst;
+  EFI_STATUS Status;
+  BOOLEAN IsCardPresent;
+  BOOLEAN CardEjected;
+  BOOLEAN CardInserted;
+
+  // For each registered SDHC instance
+  CurrentLink = gSdhcInstancePool.ForwardLink;
+  while (CurrentLink != NULL && CurrentLink != &gSdhcInstancePool) {
+    HostInst = SDHC_INSTANCE_FROM_LINK (CurrentLink);
+    ASSERT (HostInst != NULL);
+
+    IsCardPresent = HostInst->HostExt->IsCardPresent (HostInst->HostExt);
+
+    // If card is present and not initialized or card no more present but was previously
+    // initialized, then reset the instance
+    //
+    // Present Initialized  Outcome
+    // T       T            No action
+    // T       F            Reset
+    // F       T            Reset
+    // F       F            No action
+
+    CardEjected = HostInst->BlockIo.Media->MediaPresent && !IsCardPresent;
+    if (CardEjected) {
+      LOG_INFO ("Card ejected from SDHC%d slot", HostInst->HostExt->SdhcId);
+    }
+
+    CardInserted = !HostInst->BlockIo.Media->MediaPresent && IsCardPresent;
+    if (CardInserted) {
+      LOG_INFO ("Card inserted into SDHC%d slot", HostInst->HostExt->SdhcId);
+    }
+
+    if (CardEjected || CardInserted) {
+      Status = SoftReset (HostInst);
+      if (EFI_ERROR (Status)) {
+        LOG_ERROR ("SoftReset() failed. %r", Status);
+      }
+    }
+
+    CurrentLink = CurrentLink->ForwardLink;
+  }
+}
+
+BOOLEAN
+EFIAPI
+IsRpmbInstalledOnTheSystem (
+  VOID
+  )
+{
+  EFI_STATUS Status;
+  EFI_RPMB_IO_PROTOCOL rpmbIo;
+
+  Status = gBS->LocateProtocol (
+    &gEfiRpmbIoProtocolGuid,
+    NULL,
+    (VOID **) &rpmbIo);
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+EFI_STATUS
+EFIAPI
+UninstallAllProtocols (
+  IN SDHC_INSTANCE  *HostInst
+  )
+{
+  EFI_STATUS Status;
+
+  LOG_TRACE ("Uninstalling SDHC%d all protocols", HostInst->HostExt->SdhcId);
+
+  if (HostInst->BlockIoProtocolInstalled) {
+    Status =
+      gBS->UninstallMultipleProtocolInterfaces (
+        HostInst->MmcHandle,
+        &gEfiBlockIoProtocolGuid,
+        &HostInst->BlockIo,
+        NULL);
+
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "UninstallAllProtocols(): Failed to uninstall EFI_BLOCK_IO_PROTOCOL. "
+        "(Status = %r)",
+        Status);
+
+      return Status;
+    }
+
+    HostInst->BlockIoProtocolInstalled = FALSE;
+  }
+
+  if (HostInst->RpmbIoProtocolInstalled) {
+    Status =
+      gBS->UninstallMultipleProtocolInterfaces (
+        HostInst->MmcHandle,
+        &gEfiRpmbIoProtocolGuid,
+        &HostInst->RpmbIo,
+        NULL);
+
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "UninstallAllProtocols(): Failed to uninstall EFI_RPMB_IO_PROTOCOL. "
+        "(Status = %r)",
+        Status);
+
+      return Status;
+    }
+
+    HostInst->RpmbIoProtocolInstalled = FALSE;
+  }
+
+  if (HostInst->DevicePathProtocolInstalled) {
+    Status =
+      gBS->UninstallMultipleProtocolInterfaces (
+        HostInst->MmcHandle,
+        &gEfiDevicePathProtocolGuid,
+        &HostInst->DevicePath,
+        NULL);
+
+    if (EFI_ERROR (Status)) {
+      LOG_ERROR (
+        "UninstallAllProtocols(): Failed to uninstall EFI_DEVICE_PATH_PROTOCOL. "
+        "(Status = %r)",
+        Status);
+
+      return Status;
+    }
+
+    HostInst->DevicePathProtocolInstalled = FALSE;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcDriverBindingCallbacks = {
+  SdMmcDriverSupported,
+  SdMmcDriverStart,
+  SdMmcDriverStop,
+  0xa,
+  NULL,
+  NULL
+};
+
+EFI_STATUS
+EFIAPI
+SdMmcDxeInitialize (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  LOG_TRACE ("SdMmcDxeInitialize");
+
+  InitializeSdhcPool ();
+
+  // Install driver model protocols.
+  Status = EfiLibInstallDriverBindingComponentName2 (
+    ImageHandle,
+    SystemTable,
+    &gSdMmcDriverBindingCallbacks,
+    ImageHandle,
+    NULL,
+    NULL);
+  ASSERT_EFI_ERROR (Status);
+
+  // Use a timer to detect if a card has been plugged in or removed.
+  Status = gBS->CreateEvent (
+    EVT_NOTIFY_SIGNAL | EVT_TIMER,
+    TPL_CALLBACK,
+    CheckCardsCallback,
+    NULL,
+    &gCheckCardsEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->SetTimer (
+    gCheckCardsEvent,
+    TimerPeriodic,
+    (UINT64) (10 * 1000 * SDMMC_CHECK_CARD_INTERVAL_MS)); // 200 ms
+  ASSERT_EFI_ERROR (Status);
+
+  gHpcTicksPerSeconds = GetPerformanceCounterProperties (NULL, NULL);
+  ASSERT (gHpcTicksPerSeconds != 0);
+
+  return Status;
+}
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h
new file mode 100644
index 000000000000..c5c363fb963c
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h
@@ -0,0 +1,529 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SDMMC_H__
+#define __SDMMC_H__
+
+// Define with non-zero to collect IO statistics and dump it to the terminal.
+#define SDMMC_COLLECT_STATISTICS  0
+
+// Define with non-zero to benchmark IO on the first MmcReadBlocks call and
+// dump to the terminal.
+#define SDMMC_BENCHMARK_IO        0
+
+// Lower bound of 2s poll wait time (200 x 10ms)
+#define SDMMC_POLL_WAIT_COUNT     200
+#define SDMMC_POLL_WAIT_TIME_US   10000
+
+// The period at which to check the presence state of each card on each
+// registered SDHC instance.
+#define SDMMC_CHECK_CARD_INTERVAL_MS 1000
+
+// The number of recursive error recoveries to reach before considering the
+// failure fatal, and not attempting more error recoveries.
+#define SDMMC_ERROR_RECOVERY_ATTEMPT_THRESHOLD    3
+
+// Logging Macros
+
+#define LOG_TRACE_FMT_HELPER(FMT, ...)  "SdMmc[T]:" FMT "%a\n", __VA_ARGS__
+
+#define LOG_INFO_FMT_HELPER(FMT, ...)   "SdMmc[I]:" FMT "%a\n", __VA_ARGS__
+
+#define LOG_ERROR_FMT_HELPER(FMT, ...) \
+  "SdMmc[E]:" FMT " (%a: %a, %d)\n", __VA_ARGS__
+
+#define LOG_INFO(...) \
+  DEBUG((DEBUG_INIT, LOG_INFO_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_VANILLA_TRACE(...) \
+  DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, __VA_ARGS__))
+
+#define LOG_TRACE(...) \
+  DEBUG((DEBUG_VERBOSE | DEBUG_BLKIO, LOG_TRACE_FMT_HELPER(__VA_ARGS__, "")))
+
+#define LOG_ERROR(...) \
+  DEBUG((DEBUG_ERROR, LOG_ERROR_FMT_HELPER(__VA_ARGS__, __FUNCTION__, __FILE__, __LINE__)))
+
+#define LOG_ASSERT(TXT) ASSERT(!"SdMmc[A]: " TXT "\n")
+
+#ifndef C_ASSERT
+#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
+#endif // C_ASSERT
+
+// Perform Integer division DIVIDEND/DIVISOR and return the result rounded up
+// or down to the nearest integer, where 3.5 and 3.75 are near 4, while 3.25
+// is near 3.
+#define INT_DIV_ROUND(DIVIDEND, DIVISOR) \
+  (((DIVIDEND) + ((DIVISOR) / 2)) / (DIVISOR))
+
+typedef struct {
+  UINT16  NumBlocks;
+  UINT16  Count;
+  UINT32  TotalTransferTimeUs;
+} IoReadStatsEntry;
+
+// Device Path Definitions
+//
+// eMMC and SD device paths got introduced in UEFI 2.6
+// Remove definitions below once code base migrates to UEFI 2.6
+
+#ifndef MSG_SD_DP
+// SD (Secure Digital) Device Path SubType.
+#define MSG_SD_DP   0x1A
+
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  Header;
+  UINT8                     SlotNumber;
+} SD_DEVICE_PATH;
+#endif // MSG_SD_DP
+
+#ifndef MSG_EMMC_DP
+// EMMC (Embedded MMC) Device Path SubType.
+#define MSG_EMMC_DP   0x1D
+
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  Header;
+  UINT8                     SlotNumber;
+} EMMC_DEVICE_PATH;
+#endif // MSG_EMMC_DP
+
+typedef struct {
+  VENDOR_DEVICE_PATH  SdhcNode;
+  UINT32              SdhcId;
+  union {
+    EMMC_DEVICE_PATH  MMC;
+    SD_DEVICE_PATH    SD;
+  } SlotNode;
+  EFI_DEVICE_PATH     EndNode;
+} SDHC_DEVICE_PATH;
+
+// GUID {AAFB8DAA-7340-43AC-8D49-0CCE14812489}
+#define SDHC_DEVICE_PATH_GUID \
+  { 0xaafb8daa, 0x7340, 0x43ac, { 0x8d, 0x49, 0xc, 0xce, 0x14, 0x81, 0x24, 0x89 } }
+
+// Size of SDHC node including the Sdhc ID field
+#define SDHC_NODE_PATH_LENGTH (sizeof(VENDOR_DEVICE_PATH) + sizeof(UINT32))
+
+typedef struct {
+  UINTN                         Signature;
+  LIST_ENTRY                    Link;
+  UINT32                        InstanceId;
+  EFI_HANDLE                    MmcHandle;
+  BOOLEAN                       SlotInitialized;
+  BOOLEAN                       Disabled;
+  SDHC_DEVICE_PATH              DevicePath;
+  EFI_BLOCK_IO_PROTOCOL         BlockIo;
+  EFI_RPMB_IO_PROTOCOL          RpmbIo;
+  EFI_SDHC_PROTOCOL             *HostExt;
+  SDHC_CAPABILITIES             HostCapabilities;
+  BOOLEAN                       DevicePathProtocolInstalled;
+  BOOLEAN                       BlockIoProtocolInstalled;
+  BOOLEAN                       RpmbIoProtocolInstalled;
+  MMC_EXT_CSD_PARTITION_ACCESS  CurrentMmcPartition;
+  CARD_INFO                     CardInfo;
+  UINT32                        BlockBuffer[SD_BLOCK_WORD_COUNT];
+  UINT32                        CmdResponse[4];
+  CONST SD_COMMAND              *PreLastSuccessfulCmd;
+  CONST SD_COMMAND              *LastSuccessfulCmd;
+  UINT32                        ErrorRecoveryAttemptCount;
+#ifdef MMC_COLLECT_STATISTICS
+  IoReadStatsEntry              IoReadStats[1024];
+  UINT32                        IoReadStatsNumEntries;
+#endif // COLLECT_IO_STATISTICS
+} SDHC_INSTANCE;
+
+#define SDHC_INSTANCE_SIGNATURE   SIGNATURE_32('s', 'd', 'h', 'c')
+#define SDHC_INSTANCE_FROM_BLOCK_IO_THIS(a) \
+  CR(a, SDHC_INSTANCE, BlockIo, SDHC_INSTANCE_SIGNATURE)
+#define SDHC_INSTANCE_FROM_LINK(a) \
+  CR(a, SDHC_INSTANCE, Link, SDHC_INSTANCE_SIGNATURE)
+#define SDHC_INSTANCE_FROM_RPMB_IO_THIS(a) \
+  CR (a, SDHC_INSTANCE, RpmbIo, SDHC_INSTANCE_SIGNATURE)
+
+// The ARM high-performance counter frequency
+extern UINT64 gHpcTicksPerSeconds;
+
+// EFI_BLOCK_IO Protocol Callbacks
+
+/**
+  Reset the block device.
+
+  This function implements EFI_BLOCK_IO_PROTOCOL.Reset().
+  It resets the block device hardware.
+  ExtendedVerification is ignored in this implementation.
+
+  @param  This                   Indicates a pointer to the calling context.
+  @param  ExtendedVerification   Indicates that the driver may perform a more exhaustive
+                                 verification operation of the device during reset.
+
+  @retval EFI_SUCCESS            The block device was reset.
+  @retval EFI_DEVICE_ERROR       The block device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReset (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN BOOLEAN                ExtendedVerification
+  );
+
+/**
+  Reads the requested number of blocks from the device.
+
+  This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks().
+  It reads the requested number of blocks from the device.
+  All the blocks are read, or an error is returned.
+
+  @param  This                   Indicates a pointer to the calling context.
+  @param  MediaId                The media ID that the read request is for.
+  @param  Lba                    The starting logical block address to read from on the device.
+  @param  BufferSize             The size of the Buffer in bytes.
+                                 This must be a multiple of the intrinsic block size of the device.
+  @param  Buffer                 A pointer to the destination buffer for the data. The caller is
+                                 responsible for either having implicit or explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS            The data was read correctly from the device.
+  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the read operation.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+  @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
+  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic block size of the device.
+  @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,
+                                 or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoReadBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  OUT VOID                  *Buffer
+  );
+
+/**
+  Writes a specified number of blocks to the device.
+
+  This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks().
+  It writes a specified number of blocks to the device.
+  All blocks are written, or an error is returned.
+
+  @param  This                   Indicates a pointer to the calling context.
+  @param  MediaId                The media ID that the write request is for.
+  @param  Lba                    The starting logical block address to be written.
+  @param  BufferSize             The size of the Buffer in bytes.
+                                 This must be a multiple of the intrinsic block size of the device.
+  @param  Buffer                 Pointer to the source buffer for the data.
+
+  @retval EFI_SUCCESS            The data were written correctly to the device.
+  @retval EFI_WRITE_PROTECTED    The device cannot be written to.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+  @retval EFI_MEDIA_CHANGED      The MediaId is not for the current media.
+  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to perform the write operation.
+  @retval EFI_BAD_BUFFER_SIZE    The BufferSize parameter is not a multiple of the intrinsic
+                                 block size of the device.
+  @retval EFI_INVALID_PARAMETER  The write request contains LBAs that are not valid,
+                                 or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoWriteBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL  *This,
+  IN UINT32                 MediaId,
+  IN EFI_LBA                Lba,
+  IN UINTN                  BufferSize,
+  IN VOID                   *Buffer
+  );
+
+/**
+  Flushes all modified data to a physical block device.
+
+  @param  This                   Indicates a pointer to the calling context.
+
+  @retval EFI_SUCCESS            All outstanding data were written correctly to the device.
+  @retval EFI_DEVICE_ERROR       The device reported an error while attempting to write data.
+  @retval EFI_NO_MEDIA           There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BlockIoFlushBlocks (
+  IN EFI_BLOCK_IO_PROTOCOL *This
+  );
+
+// EFI_RPMPB_IO Protocol Callbacks
+
+/** Authentication key programming request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ProgrammingRequest A data packet describing a key programming request.
+  @param[out] ResultResponse A caller allocated data packet which will receive the
+  key programming result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during key programming any other eMMC internal failure is reported
+  in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoProgramKey (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *Request,
+  OUT EFI_RPMB_DATA_PACKET  *ResultResponse
+  );
+
+/** Reading of the write counter value request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ReadRequest A data packet describing a read counter value request.
+  @param[out] ReadResponse A caller allocated data packet which will receive
+  the counter value read response. If counter has expired bit 7 is set to 1 in
+  returned Result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during counter read or any other eMMC internal failure is reported
+  in the Result field of the returned response data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoReadCounter (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ReadRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ReadResponse
+  );
+
+/** Authenticated data write request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] WriteRequest A sequence of data packets describing data write
+  requests and holds the data to be written.
+  @param[out] ResultResponse A caller allocated data packet which will receive
+  the data write programming result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during data programming or any other eMMC internal failure is reported
+  in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedWrite (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_BUFFER   *WriteRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ResultResponse
+  );
+
+/** Authenticated data read request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ReadRequest A data packet that describes a data read request.
+  @param[out] ReadResponse A caller allocated data packets which will receive
+  the data read.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during data fetch from the eMMC or any other eMMC internal failure
+  is reported in the Result field of the returned data packet.
+**/
+EFI_STATUS
+EFIAPI
+RpmbIoAuthenticatedRead (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ReadRequest,
+  OUT EFI_RPMB_DATA_BUFFER  *ReadResponse
+  );
+
+// Helper Functions
+
+EFI_STATUS
+EFIAPI
+SoftReset (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+// Debugging Helpers
+
+VOID
+PrintCsd (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+VOID
+PrintCid (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+VOID
+PrintCardStatus (
+  IN SDHC_INSTANCE  *HostInst,
+  IN CARD_STATUS    CardStatus
+  );
+
+VOID
+GetAndPrintCardStatus (
+  IN SDHC_INSTANCE  *HostInst
+  );
+
+// Inlined Helper Functions
+
+__inline__
+static
+CONST CHAR8*
+MmcPartitionAccessToString (
+  IN MMC_EXT_CSD_PARTITION_ACCESS   Partition
+  )
+{
+  switch (Partition) {
+  case MmcExtCsdPartitionAccessUserArea:
+    return "UserArea";
+  case MmcExtCsdPartitionAccessBootPartition1:
+    return "Boot1";
+  case MmcExtCsdPartitionAccessBootPartition2:
+    return "Boot2";
+  case MmcExtCsdPartitionAccessRpmb:
+    return "RPMB";
+  case MmcExtCsdPartitionAccessGpp1:
+    return "GeneralPurpose1";
+  case MmcExtCsdPartitionAccessGpp2:
+    return "GeneralPurpose2";
+  case MmcExtCsdPartitionAccessGpp3:
+    return "GeneralPurpose3";
+  case MmcExtCsdPartitionAccessGpp4:
+    return "GeneralPurpose4";
+  default:
+    return "Unknown";
+  }
+}
+
+__inline__
+static
+CONST CHAR8*
+CardStateToString (
+  IN CARD_STATE   State
+  )
+{
+  switch (State) {
+  case CardStateIdle:
+    return "Idle";
+  case CardStateReady:
+    return "Ready";
+  case CardStateIdent:
+    return "Ident";
+  case CardStateStdby:
+    return "Stdby";
+  case CardStateTran:
+    return "Tran";
+  case CardStateData:
+    return "Data";
+  case CardStateRcv:
+    return "Rcv";
+  case CardStatePrg:
+    return "Prg";
+  case CardStateDis:
+    return "Dis";
+  case CardStateBtst:
+    return "Btst";
+  case CardStateSlp:
+    return "Slp";
+  default:
+    return "Reserved";
+  }
+}
+
+__inline__
+static
+BOOLEAN
+IsCardStatusError (
+  IN SDHC_INSTANCE  *HostInst,
+  IN CARD_STATUS    CardStatus
+  )
+{
+  ASSERT (HostInst != NULL);
+
+  switch (HostInst->CardInfo.CardFunction) {
+  case CardFunctionSd:
+    return CardStatus.AsUint32 & SD_CARD_STATUS_ERROR_MASK;
+  case CardFunctionMmc:
+    return CardStatus.AsUint32 & MMC_CARD_STATUS_ERROR_MASK;
+  default:
+    ASSERT (FALSE);
+    return FALSE;
+  }
+}
+
+__inline__
+static
+BOOLEAN
+CmdsAreEqual (
+  IN CONST SD_COMMAND   *Left,
+  IN CONST SD_COMMAND   *Right
+  )
+{
+  ASSERT (Left != NULL);
+  ASSERT (Right != NULL);
+
+  if (Left != Right) {
+    return (Left->Class == Right->Class) &&
+      (Left->Index == Right->Index) &&
+      (Left->ResponseType == Right->ResponseType) &&
+      (Left->TransferDirection == Right->TransferDirection) &&
+      (Left->TransferType == Right->TransferType) &&
+      (Left->Type == Right->Type);
+  }
+
+  return TRUE;
+}
+
+// Timing Helpers
+
+/** Gets the current high-performance counter tick count.
+
+  The returned tick count is considered as a time stamp and can used later in
+  elapsed time calculations.
+
+  @retval Current high-performance counter tick count.
+**/
+__inline__
+static
+UINT64
+HpcTimerStart (
+  VOID
+  )
+{
+  return GetPerformanceCounter ();
+}
+
+/** Calculates the elapsed milliseconds since a specific timer time stamp.
+
+  @param[in] TimerStartTimestamp The high-performance counter tick count to use
+  as the starting point in elapsed time calculation.
+
+  @retval The milliseconds elapsed.
+**/
+__inline__
+static
+UINT64
+HpcTimerElapsedMilliseconds (
+  IN UINT64   TimerStartTimestamp
+  )
+{
+  return (((GetPerformanceCounter () - TimerStartTimestamp) * 1000UL) /
+          gHpcTicksPerSeconds);
+}
+
+#endif // __SDMMC_H__
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
new file mode 100644
index 000000000000..c8c45d07f1ed
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
@@ -0,0 +1,50 @@
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = SdMmcDxe
+  FILE_GUID                      = 16738C4A-8044-4DD8-B68E-58A53CEFF5D9
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = SdMmcDxeInitialize
+
+[Sources.common]
+  SdMmc.c
+  BlockIo.c
+  Debug.c
+  Protocol.c
+  RpmbIo.c
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  Platform/Microsoft/MsPkg.dec
+  Platform/Microsoft/OpteeClientPkg/OpteeClientPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  UefiLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  TimerLib
+
+[Protocols]
+  gEfiDiskIoProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gEfiSdhcProtocolGuid
+  gEfiRpmbIoProtocolGuid
+
+[Depex]
+  TRUE
diff --git a/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h
new file mode 100644
index 000000000000..b5683a6e260d
--- /dev/null
+++ b/Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h
@@ -0,0 +1,506 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SDMMCHW_H__
+#define __SDMMCHW_H__
+
+#pragma pack(1)
+
+#define SD_BLOCK_LENGTH_BYTES               512
+#define SD_BLOCK_WORD_COUNT                 (SD_BLOCK_LENGTH_BYTES / sizeof (UINT32))
+#define SD_IDENT_MODE_CLOCK_FREQ_HZ         400000    // 400 KHz
+#define MMC_HIGH_SPEED_MODE_CLOCK_FREQ_HZ   52000000  // 52 MHz
+
+typedef enum {
+  CardSpeedModeUndefined = 0,
+  CardSpeedModeNormalSpeed,
+  CardSpeedModeHighSpeed
+} CARD_SPEED_MODE;
+
+typedef enum {
+  CardFunctionUnknown = 0,
+  CardFunctionSd,
+  CardFunctionSdio,
+  CardFunctionComboSdSdio,
+  CardFunctionMmc
+} CARD_FUNCTION;
+
+typedef enum {
+  CardStateIdle = 0,
+  CardStateReady,
+  CardStateIdent,
+  CardStateStdby,
+  CardStateTran,
+  CardStateData,
+  CardStateRcv,
+  CardStatePrg,
+  CardStateDis,
+  CardStateBtst,
+  CardStateSlp
+} CARD_STATE;
+
+typedef union {
+  UINT32 AsUint32;
+  struct {
+    UINT32 RESERVED_1 : 2;            // [1:0]
+    UINT32 RESERVED_2 : 1;            // [2]
+    UINT32 AKE_SEQ_ERROR : 1;         // [3] SD
+    UINT32 RESERVED_3 : 1;            // [4]
+    UINT32 APP_CMD : 1;               // [5]
+    UINT32 URGENT_BKOPS : 1;          // [6] MMC
+    UINT32 SWITCH_ERROR : 1;          // [7] MMC
+    UINT32 READY_FOR_DATA : 1;        // [8]
+    UINT32 CURRENT_STATE : 4;         // [12:9]
+    UINT32 ERASE_RESET : 1;           // [13]
+    UINT32 RESERVED_4 : 1;            // [14]
+    UINT32 WP_ERASE_SKIP : 1;         // [15]
+    UINT32 CID_CSD_OVERWRITE : 1;     // [16]
+    UINT32 OVERRUN : 1;               // [17] MMC
+    UINT32 UNDERRUN : 1;              // [18] MMC
+    UINT32 ERROR : 1;                 // [19]
+    UINT32 CC_ERROR : 1;              // [20]
+    UINT32 CARD_ECC_FAILED : 1;       // [21]
+    UINT32 ILLEGAL_COMMAND : 1;       // [22]
+    UINT32 COM_CRC_ERROR : 1;         // [23]
+    UINT32 LOCK_UNLOCK_FAILED : 1;    // [24]
+    UINT32 CARD_IS_LOCKED : 1;        // [25]
+    UINT32 WP_VIOLATION : 1;          // [26]
+    UINT32 ERASE_PARAM : 1;           // [27]
+    UINT32 ERASE_SEQ_ERROR : 1;       // [28]
+    UINT32 BLOCK_LEN_ERROR : 1;       // [29]
+    UINT32 ADDRESS_MISALIGN : 1;      // [30]
+    UINT32 ADDRESS_OUT_OF_RANGE : 1;  // [31]
+  } Fields;
+} CARD_STATUS;
+
+#define MMC_CARD_STATUS_ERROR_MASK \
+          (BIT7 | BIT13 | BIT15 | BIT16 | BIT17 | BIT18 | BIT19 | BIT20 | \
+          BIT21 | BIT22 | BIT23 | BIT24 | BIT26 | BIT27 | BIT28 | BIT29 | \
+          BIT30 | BIT31)
+
+#define SD_CARD_STATUS_ERROR_MASK \
+          (BIT3 | BIT13 | BIT15 | BIT16 | BIT19 | BIT20 | \
+          BIT21 | BIT22 | BIT23 | BIT24 | BIT26 | BIT27 | BIT28 | BIT29 | \
+          BIT30 | BIT31)
+
+typedef union {
+  UINT32 AsUint32;
+  struct {
+    UINT32 CheckPattern : 8;
+    UINT32 VoltageSupplied : 4;
+    UINT32 RESERVED_1 : 16;
+    UINT32 CommandIndex : 6;
+  } Fields;
+} SEND_IF_COND_ARG;
+
+typedef SEND_IF_COND_ARG SEND_IF_COND_CMD_RESPONSE;
+
+// definition for VoltageAccepted in SD_CMD8_STATUS
+
+#define SD_CMD8_VOLTAGE_27_36   0x01
+#define SD_CMD8_VOLTAGE_LOW     0x02
+
+typedef union {
+  UINT32 AsUint32;
+  struct {
+    UINT32 VoltageWindow : 24;  // [23:0] Maps to OCR[0:23]
+    UINT32 S18R : 1;            // [24] Switching to 1.8V Request
+                                // 0b: Use Current signal voltage, 1b: Switch to 1.8V signal voltage
+
+    UINT32 RESERVED_1 : 3;      // [27:25]
+    UINT32 XPC : 1;             // SDXC Power Control [28] 0b: Power Saving, 1b: Max Performance
+    UINT32 RESERVED_2 : 1;      // [29]
+    UINT32 HCS : 1;             // Host Capacity Support [30] 0b: SDSC, 1b: SDHC or SDXC
+    UINT32 RESERVED_3 : 1;      // [31]
+  } Fields;
+} SD_SEND_OP_COND_ARG;
+
+typedef union {
+  UINT32 AsUint32;
+  struct {
+    UINT32 VoltageWindow : 24;  // [23:0] Voltage profile
+    UINT32 RESERVED_1 : 5;      // Reserved
+    UINT32 AccessMode : 2;      // 00b (byte mode), 10b (sector mode)
+    UINT32 PowerUp : 1;         // This bit is set to LOW if the card has not finished the power up routine
+  } Fields;
+} SD_OCR;
+
+typedef union {
+  UINT32 AsUint32;
+  struct {
+    UINT32 VoltageWindow : 24;  // [23:0] Voltage profile
+    UINT32 S18A : 1;            // [24] Switching to 1.8V Accepted
+    UINT32 RESERVED_1 : 5;      // Reserved [29:25]
+    UINT32 CCS : 1;             // Card Capacity Status [30]
+    UINT32 PowerUp : 1;         // This bit is set to LOW if the card has not finished the power up routine [31]
+  } Fields;
+} SD_OCR_EX;
+
+typedef struct {
+  UINT16 MDT : 12;        // Manufacturing date [19:8]
+  UINT16 RESERVED_1 : 4;  // Reserved [23:20]
+  UINT32 PSN;             // Product serial number [55:24]
+  UINT8 PRV;              // Product revision [63:56]
+  UINT8 PNM[5];           // Product name [64:103]
+  UINT16 OID;             // OEM/Application ID [119:104]
+  UINT8 MID;              // Manufacturer ID [127:120]
+} SD_CID;
+
+typedef struct {
+  UINT16 MDT : 8;         // Manufacturing date [15:8]
+  UINT32 PSN;             // Product serial number [47:16]
+  UINT8 PRV;              // Product revision [55:48]
+  UINT8 PNM[6];           // Product name [103:56]
+  UINT8 OID;              // OEM/Application ID [111:104]
+  UINT8 CBX : 2;          // Card/BGA [113:112]
+  UINT8 RESERVED_1 : 6;   // [119:114]
+  UINT8 MID;              // Manufacturer ID [127:120]
+} MMC_CID;
+
+typedef struct {
+  UINT8 RESERVED_1 : 2;           // Reserved [9:8]
+  UINT8 FILE_FORMAT : 2;          // File format [11:10]
+  UINT8 TMP_WRITE_PROTECT : 1;    // Temporary write protection [12:12]
+  UINT8 PERM_WRITE_PROTECT : 1;   // Permanent write protection [13:13]
+  UINT8 COPY : 1;                 // Copy flag (OTP) [14:14]
+  UINT8 FILE_FORMAT_GRP : 1;      // File format group [15:15]
+  UINT16 RESERVED_2 : 5;          // Reserved [20:16]
+  UINT16 WRITE_BL_PARTIAL : 1;    // Partial blocks for write allowed [21:21]
+  UINT16 WRITE_BL_LEN : 4;        // Max. write data block length [25:22]
+  UINT16 R2W_FACTOR : 3;          // Write speed factor [28:26]
+  UINT16 RESERVED_3 : 2;          // Reserved [30:29]
+  UINT16 WP_GRP_ENABLE : 1;       // Write protect group enable [31:31]
+  UINT32 WP_GRP_SIZE : 7;         // Write protect group size [38:32]
+  UINT32 SECTOR_SIZE : 7;         // Erase sector size [45:39]
+  UINT32 ERASE_BLK_EN : 1;        // Erase single block enable [46:46]
+  UINT32 C_SIZE_MULT : 3;         // Device size multiplier [49:47]
+  UINT32 VDD_W_CURR_MAX : 3;      // Max. write current @ VDD max [52:50]
+  UINT32 VDD_W_CURR_MIN : 3;      // Max. write current @ VDD min [55:53]
+  UINT32 VDD_R_CURR_MAX : 3;      // Max. read current @ VDD max [58:56]
+  UINT32 VDD_R_CURR_MIN : 3;      // Max. read current @ VDD min [61:59]
+  UINT32 C_SIZELow2 : 2;          // Device size [63:62]
+  UINT32 C_SIZEHigh10 : 10;       // Device size [73:64]
+  UINT32 RESERVED_4 : 2;          // Reserved [75:74]
+  UINT32 DSR_IMP : 1;             // DSR implemented [76:76]
+  UINT32 READ_BLK_MISALIGN : 1;   // Read block misalignment [77:77]
+  UINT32 WRITE_BLK_MISALIGN : 1;  // Write block misalignment [78:78]
+  UINT32 READ_BL_PARTIAL : 1;     // Partial blocks for read allowed [79:79]
+  UINT32 READ_BL_LEN : 4;         // Max. read data block length [83:80]
+  UINT32 CCC : 12;                // Card command classes [95:84]
+  UINT8 TRAN_SPEED;               // Max. bus clock frequency [103:96]
+  UINT8 NSAC;                     // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+  UINT8 TAAC;                     // Data read access-time 1 [119:112]
+  UINT8 RESERVED_5 : 6;           // Reserved [125:120]
+  UINT8 CSD_STRUCTURE : 2;        // CSD structure [127:126]
+} SD_CSD;
+
+typedef struct {
+  UINT8 RESERVED_1 : 2;           // Reserved [9:8]
+  UINT8 FILE_FORMAT : 2;          // File format [11:10]
+  UINT8 TMP_WRITE_PROTECT : 1;    // Temporary write protection [12:12]
+  UINT8 PERM_WRITE_PROTECT : 1;   // Permanent write protection [13:13]
+  UINT8 COPY : 1;                 // Copy flag (OTP) [14:14]
+  UINT8 FILE_FORMAT_GRP : 1;      // File format group [15:15]
+  UINT16 RESERVED_2 : 5;          // Reserved [20:16]
+  UINT16 WRITE_BL_PARTIAL : 1;    // Partial blocks for write allowed [21:21]
+  UINT16 WRITE_BL_LEN : 4;        // Max. write data block length [25:22]
+  UINT16 R2W_FACTOR : 3;          // Write speed factor [28:26]
+  UINT16 RESERVED_3 : 2;          // Reserved [30:29]
+  UINT16 WP_GRP_ENABLE : 1;       // Write protect group enable [31:31]
+  UINT16 WP_GRP_SIZE : 7;         // Write protect group size [38:32]
+  UINT16 SECTOR_SIZE : 7;         // Erase sector size [45:39]
+  UINT16 ERASE_BLK_EN : 1;        // Erase single block enable [46:46]
+  UINT16 RESERVED_4 : 1;          // Reserved [47:47]
+  UINT32 C_SIZE : 22;             // Device size [63:62]
+  UINT32 RESERVED_5 : 6;          // Reserved [75:74]
+  UINT32 DSR_IMP : 1;             // DSR implemented [76:76]
+  UINT32 READ_BLK_MISALIGN : 1;   // Read block misalignment [77:77]
+  UINT32 WRITE_BLK_MISALIGN : 1;  // Write block misalignment [78:78]
+  UINT32 READ_BL_PARTIAL : 1;     // Partial blocks for read allowed [79:79]
+  UINT16 READ_BL_LEN : 4;         // Max. read data block length [83:80]
+  UINT16 CCC : 12;                // Card command classes [95:84]
+  UINT8 TRAN_SPEED;               // Max. bus clock frequency [103:96]
+  UINT8 NSAC;                     // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+  UINT8 TAAC;                     // Data read access-time 1 [119:112]
+  UINT8 RESERVED_6 : 6;           // Reserved [125:120]
+  UINT8 CSD_STRUCTURE : 2;        // CSD structure [127:126]
+} SD_CSD_2;
+
+typedef struct {
+  UINT8 ECC : 2;                  // ECC code [9:8]
+  UINT8 FILE_FORMAT : 2;          // File format [11:10]
+  UINT8 TMP_WRITE_PROTECT : 1;    // Temporary write protection [12:12]
+  UINT8 PERM_WRITE_PROTECT : 1;   // Permanent write protection [13:13]
+  UINT8 COPY : 1;                 // Copy flag (OTP) [14:14]
+  UINT8 FILE_FORMAT_GRP : 1;      // File format group [15:15]
+  UINT16 CONTENT_PROT_APP : 1;    // Content protection application [16:16]
+  UINT16 RESERVED_1 : 4;          // Reserved [20:17]
+  UINT16 WRITE_BL_PARTIAL : 1;    // Partial blocks for write allowed [21:21]
+  UINT16 WRITE_BL_LEN : 4;        // Max. write data block length [25:22]
+  UINT16 R2W_FACTOR : 3;          // Write speed factor [28:26]
+  UINT16 DEFAULT_ECC : 2;         // Manufacturer default ECC [30:29]
+  UINT16 WP_GRP_ENABLE : 1;       // Write protect group enable [31:31]
+  UINT32 WP_GRP_SIZE : 5;         // Write protect group size [36:32]
+  UINT32 ERASE_GRP_MULT : 5;      // Erase group size multiplier [41:37]
+  UINT32 ERASE_GRP_SIZE : 5;      // Erase sector size [46:42]
+  UINT32 C_SIZE_MULT : 3;         // Device size multiplier [49:47]
+  UINT32 VDD_W_CURR_MAX : 3;      // Max. write current @ VDD max [52:50]
+  UINT32 VDD_W_CURR_MIN : 3;      // Max. write current @ VDD min [55:53]
+  UINT32 VDD_R_CURR_MAX : 3;      // Max. read current @ VDD max [58:56]
+  UINT32 VDD_R_CURR_MIN : 3;      // Max. read current @ VDD min [61:59]
+  UINT32 C_SIZELow2 : 2;          // Device size [63:62]
+  UINT32 C_SIZEHigh10 : 10;       // Device size [73:64]
+  UINT32 RESERVED_4 : 2;          // Reserved [75:74]
+  UINT32 DSR_IMP : 1;             // DSR implemented [76:76]
+  UINT32 READ_BLK_MISALIGN : 1;   // Read block misalignment [77:77]
+  UINT32 WRITE_BLK_MISALIGN : 1;  // Write block misalignment [78:78]
+  UINT32 READ_BL_PARTIAL : 1;     // Partial blocks for read allowed [79:79]
+  UINT32 READ_BL_LEN : 4;         // Max. read data block length [83:80]
+  UINT32 CCC : 12;                // Card command classes [95:84]
+  UINT8 TRAN_SPEED;               // Max. bus clock frequency [103:96]
+  UINT8 NSAC;                     // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]
+  UINT8 TAAC;                     // Data read access-time 1 [119:112]
+  UINT8 RESERVED_5 : 2;           // Reserved [121:120]
+  UINT8 SPEC_VERS : 4;            // System specification version [125:122]
+  UINT8 CSD_STRUCTURE : 2;        // CSD structure [127:126]
+} MMC_CSD;
+
+// We support spec version 4.X and higher
+// If CSD.SPEC_VERS indicates a version 4.0 or higher, the card is a high speed card and supports
+// SWITCH and SEND_EXT_CSD commands. Otherwise the card is an old MMC card.
+#define MMC_MIN_SUPPORTED_SPEC_VERS     4
+
+typedef struct {
+
+  // Host modifiable modes
+
+  UINT8 Reserved26[134];
+  UINT8 BadBlockManagement;
+  UINT8 Reserved25;
+  UINT32 EnhancedUserDataStartAddress;
+  UINT8 EnhancedUserDataAreaSize[3];
+  UINT8 GpPartSizeMult[12];
+  UINT8 PartitioningSetting;
+  UINT8 PartitionsAttribute;
+  UINT8 MaxEnhancedAreaSize[3];
+  UINT8 PartitioningSupport;
+  UINT8 Reserved24;
+  UINT8 HwResetFunc;
+  UINT8 Reserved23[5];
+  UINT8 RpmbSizeMult;
+  UINT8 FwConfig;
+  UINT8 Reserved22;
+  UINT8 UserWriteProt;
+  UINT8 Reserved21;
+  UINT8 BootWriteProt;
+  UINT8 Reserved20;
+  UINT8 EraseGroupDef;
+  UINT8 Reserved19;
+  UINT8 BootBusWidth;
+  UINT8 BootConfigProt;
+  UINT8 PartitionConfig;
+  UINT8 Reserved18;
+  UINT8 ErasedMemContent;
+  UINT8 Reserved17;
+  UINT8 BusWidth;
+  UINT8 Reserved16;
+  UINT8 HighSpeedTiming;
+  UINT8 Reserved15;
+  UINT8 PowerClass;
+  UINT8 Reserved14;
+  UINT8 CmdSetRevision;
+  UINT8 Reserved13;
+  UINT8 CmdSet;
+
+  // Non-modifiable properties
+
+  UINT8 ExtendedCsdRevision;
+  UINT8 Reserved12;
+  UINT8 CsdStructureVersion;
+  UINT8 Reserved11;
+  UINT8 CardType;
+  UINT8 Reserved10[3];
+  UINT8 PowerClass52Mhz195V;
+  UINT8 PowerClass26Mhz195V;
+  UINT8 PowerClass52Mhz36V;
+  UINT8 PowerClass26Mhz36V;
+  UINT8 Reserved9;
+  UINT8 MinReadPerf4bit26Mhz;
+  UINT8 MinWritePerf4bit26Mhz;
+  UINT8 MinReadPerf8bit26Mhz;
+  UINT8 MinWritePerf8bit26Mhz;
+  UINT8 MinReadPerf8bit52Mhz;
+  UINT8 MinWritePerf8bit52Mhz;
+  UINT8 Reserved8;
+  UINT32 SectorCount;
+  UINT8 Reserved7;
+  UINT8 SleepAwakeTimeout;
+  UINT8 Reserved6;
+  UINT8 SleepCurrentVccq;
+  UINT8 SleepCurrentVcc;
+  UINT8 HighCapacityWriteProtectSize;
+  UINT8 ReliableWriteSectorCount;
+  UINT8 HighCapacityEraseTimeout;
+  UINT8 HighCapacityEraseSize;
+  UINT8 AccessSize;
+  UINT8 BootPartitionSize;
+  UINT8 Reserved5;
+  UINT8 BootInfo;
+  UINT8 SecureTrimMultiplier;
+  UINT8 SecureEraseMultiplier;
+  UINT8 SecureFeatureSupport;
+  UINT8 TrimMultiplier;
+  UINT8 Reserved4;
+  UINT8 MinReadPerf8bit52MhzDdr;
+  UINT8 MinWritePerf8bit52MhzDdr;
+  UINT16 Reserved3;
+  UINT8 PowerClass52MhzDdr36V;
+  UINT8 PowerClass52MhzDdr195V;
+  UINT8 Reserved2;
+  UINT8 InitTimeoutAfterPartitioning;
+  UINT8 Reserved1[262];
+  UINT8 SupportedCmdSets;
+  UINT8 Reserved[7];
+} MMC_EXT_CSD;
+
+typedef enum {
+  MmcExtCsdCardTypeNormalSpeed = 0x01,
+  MmcExtCsdCardTypeHighSpeed = 0x02,
+  MmcExtCsdCardTypeDdr1v8 = 0x04,
+  MmcExtCsdCardTypeDdr1v2 = 0x08
+} MmcExtCsdCardType;
+
+typedef enum {
+  MmcExtCsdBusWidth1Bit = 0,
+  MmcExtCsdBusWidth4Bit = 1,
+  MmcExtCsdBusWidth8Bit = 2
+} MmcExtCsdBusWidth;
+
+typedef enum {
+  MmcExtCsdPartitionAccessUserArea,
+  MmcExtCsdPartitionAccessBootPartition1,
+  MmcExtCsdPartitionAccessBootPartition2,
+  MmcExtCsdPartitionAccessRpmb,
+  MmcExtCsdPartitionAccessGpp1,
+  MmcExtCsdPartitionAccessGpp2,
+  MmcExtCsdPartitionAccessGpp3,
+  MmcExtCsdPartitionAccessGpp4,
+} MMC_EXT_CSD_PARTITION_ACCESS;
+
+typedef enum {
+  MmcExtCsdBootPartitionEnableNotBootEnabled,
+  MmcExtCsdBootPartitionBootPartition1BootEnabled,
+  MmcExtCsdBootPartitionBootPartition2BootEnabled,
+  MmcExtCsdBootPartitionUserAreaBootEnabled = 7,
+} MMC_EXT_CSD_BOOT_PARTITION_ENABLE;
+
+typedef union {
+  UINT8 AsUint8;
+  struct {
+    UINT8 PARTITION_ACCESS : 3;       // [2:0]
+    UINT8 BOOT_PARTITION_ENABLE : 3;  // [5:3]
+    UINT8 BOOT_ACK : 1;               // [6]
+    UINT8 RESERVED_1 : 1;             // [7]
+  } Fields;
+} MMC_EXT_CSD_PARTITION_CONFIG;
+
+typedef enum {
+  MmcExtCsdBitIndexPartitionConfig = 179,
+  MmcExtCsdBitIndexBusWidth = 183,
+  MmcExtCsdBitIndexHsTiming = 185
+} MMC_EXT_CSD_BIT_INDEX;
+
+typedef enum {
+  MmcSwitchCmdAccessTypeCommandSet,
+  MmcSwitchCmdAccessTypeSetBits,
+  MmcSwitchCmdAccessTypeClearBits,
+  MmcSwitchCmdAccessTypeWriteByte
+} MMC_SWITCH_CMD_ACCESS_TYPE;
+
+typedef union {
+  UINT32 AsUint32;
+  struct {
+    UINT32 CmdSet : 3;      // [2:0]
+    UINT32 RESERVED_1 : 5;  // Set to 0 [7:3]
+    UINT32 Value : 8;       // [15:8]
+    UINT32 Index : 8;       // [23:16]
+    UINT32 Access : 2;      // A value from MMC_SWITCH_CMD_ACCESS_TYPE [25:24]
+    UINT32 RESERVED_2 : 6;  // Set to 0 [31:26]
+  } Fields;
+} MMC_SWITCH_CMD_ARG;
+
+// Bits [3:0] code the current consumption for the 4 bit bus configuration
+#define MMC_EXT_CSD_POWER_CLASS_4BIT(X)         ((X) & 0xF)
+
+// Bits [7:4] code the current consumption for the 8 bit bus configuration
+#define MMC_EXT_CSD_POWER_CLASS_8BIT(X)         ((X) >> 4)
+
+typedef struct {
+  UINT32 RESERVED_1;
+  UINT32 CMD_SUPPORT : 2;
+  UINT32 RESERVED_2 : 9;
+  UINT32 EX_SECURITY : 4;
+  UINT32 SD_SPEC3 : 1;
+  UINT32 SD_BUS_WIDTH : 4;
+  UINT32 SD_SECURITY : 3;
+  UINT32 DATA_STAT_AFTER_ERASE : 1;
+  UINT32 SD_SPEC : 4;
+  UINT32 SCR_STRUCTURE : 4;
+} SD_SCR;
+
+typedef SD_OCR MMC_OCR;
+typedef SD_OCR MMC_SEND_OP_COND_ARG;
+
+typedef enum {
+  SdOcrAccessByteMode = 0,
+  SdOcrAccessSectorMode = 2
+} SD_OCR_ACCESS;
+
+// Voltage window that covers from 2.8V and up to 3.6V
+#define SD_OCR_HIGH_VOLTAGE_WINDOW        0x00FF8000
+
+typedef struct {
+  SD_OCR Ocr;
+  SD_CID Cid;
+  SD_CSD Csd;
+  SD_SCR Scr;
+} SD_REGISTERS;
+
+typedef struct {
+  MMC_OCR Ocr;
+  MMC_CID Cid;
+  MMC_CSD Csd;
+  MMC_EXT_CSD ExtCsd;
+} MMC_REGISTERS;
+
+typedef struct {
+  UINT32              RCA;
+  CARD_FUNCTION       CardFunction;
+  BOOLEAN             HasExtendedOcr;
+  BOOLEAN             HighCapacity;
+  UINT64              ByteCapacity;
+  CARD_SPEED_MODE     CurrentSpeedMode;
+
+  union {
+    SD_REGISTERS Sd;
+    MMC_REGISTERS Mmc;
+  } Registers;
+
+} CARD_INFO;
+
+#pragma pack()
+
+#endif // __SDMMCHW_H__
+
diff --git a/Platform/Microsoft/Include/Protocol/RpmbIo.h b/Platform/Microsoft/Include/Protocol/RpmbIo.h
new file mode 100644
index 000000000000..ed37f7c4fc06
--- /dev/null
+++ b/Platform/Microsoft/Include/Protocol/RpmbIo.h
@@ -0,0 +1,262 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+/**
+*
+*  RPMB IO protocol is an interface implementation for the Replay Protected Memory
+*  Block (RPMB) as defined by JEDEC Standard for MultiMediaCard specs 4.41.
+*
+*  This protocol abstracts the RPMB operations to allow EFI boot services environment
+*  to perform eMMC RPMB operations without specific knowledge about the card type or
+*  the host controller.
+*
+**/
+
+#ifndef __RPMB_IO_H__
+#define __RPMB_IO_H__
+
+// Global ID for the RPMB IO Protocol {FBAEE5B2-08B0-41B8-B0B0-86B72EED1BB6}
+#define EFI_RPMB_IO_PROTOCOL_GUID \
+  { 0xfbaee5b2, 0x8b0, 0x41b8, { 0xb0, 0xb0, 0x86, 0xb7, 0x2e, 0xed, 0x1b, 0xb6 } };
+
+#define EFI_RPMB_IO_PROTOCOL_REVISION  0x00010000
+
+// RPMB Request Message Types
+
+#define EFI_RPMB_REQUEST_PROGRAM_KEY     0x0001  // Authentication key programming request
+#define EFI_RPMB_REQUEST_COUNTER_VALUE   0x0002  // Reading of the Write Counter value -request
+#define EFI_RPMB_REQUEST_AUTH_WRITE      0x0003  // Authenticated data write request
+#define EFI_RPMB_REQUEST_AUTH_READ       0x0004  // Authenticated data read request
+#define EFI_RPMB_REQUEST_RESULT_REQUEST  0x0005  // Result read request
+
+// RPMB Response Message Types
+
+#define EFI_RPMB_RESPONSE_PROGRAM_KEY    0x0100  // Authentication key programming response
+#define EFI_RPMB_RESPONSE_COUNTER_VALUE  0x0200  // Reading of the Write Counter value -response
+#define EFI_RPMB_RESPONSE_AUTH_WRITE     0x0300  // Authenticated data write response
+#define EFI_RPMB_RESPONSE_AUTH_READ      0x0400  // Authenticated data read response
+
+// RPMB Operation Results
+
+#define EFI_RPMB_OK                     0  // Operation OK
+#define EFI_RPMB_ERROR_GENERAL          1  // General failure
+#define EFI_RPMB_ERROR_AUTH             2  // Authentication failure (MAC comparison not matching, MAC calculation failure)
+#define EFI_RPMB_ERROR_COUNTER          3  // Counter failure (counters not matching in comparison, counter incrementing failure)
+#define EFI_RPMB_ERROR_ADDRESS          4  // Address failure (address out of range, wrong address alignment)
+#define EFI_RPMB_ERROR_WRITE            5  // Write failure (data/counter/result write failure)
+#define EFI_RPMB_ERROR_READ             6  // Read failure (data/counter/result read failure)
+#define EFI_RPMB_ERROR_KEY              7  // Authentication Key not yet programmed
+
+#define EFI_RPMB_ERROR_MASK             0x7
+#define EFI_RPMB_ERROR_CNT_EXPIRED_BIT  0x80
+
+// RPMB Data Frame fields size in bytes.
+
+#define EFI_RPMB_PACKET_STUFF_SIZE       196
+#define EFI_RPMB_PACKET_KEY_MAC_SIZE     32
+#define EFI_RPMB_PACKET_DATA_SIZE        256
+#define EFI_RPMB_PACKET_NONCE_SIZE       16
+#define EFI_RPMB_PACKET_WCOUNTER_SIZE    4
+#define EFI_RPMB_PACKET_ADDRESS_SIZE     2
+#define EFI_RPMB_PACKET_BLOCKCOUNT_SIZE  2
+#define EFI_RPMB_PACKET_RESULT_SIZE      2
+#define EFI_RPMB_PACKET_TYPE_SIZE        2
+
+// Everything in the RPMB Data Frame is hashed except the Stuff and the MAC itself.
+#define EFI_RPMB_PACKET_DATA_HASH_SIZE ( \
+  sizeof(EFI_RPMB_DATA_PACKET) - \
+  offsetof(EFI_RPMB_DATA_PACKET, PacketData) \
+  )
+
+// CID register is 16 byte
+#define EFI_RPMB_CID_SIZE 16
+
+/** The data frame to access the replay protected memory area.
+
+  NOTE: Byte order of the RPMB data frame is MSB first, e.g. Write Counter MSB
+  [11] is storing the upmost byte of the counter value.
+**/
+#pragma pack(1)
+typedef struct {
+  UINT8  Stuff[EFI_RPMB_PACKET_STUFF_SIZE];
+
+  UINT8  KeyOrMAC[EFI_RPMB_PACKET_KEY_MAC_SIZE];             // The authentication key or the message authentication code (MAC) depending
+                                                             // on the request/response type. The MAC will be delivered in the last (or the
+                                                             // only) block of data.
+
+  UINT8  PacketData[EFI_RPMB_PACKET_DATA_SIZE];              // Data to be written or read by signed access.
+  UINT8  Nonce[EFI_RPMB_PACKET_NONCE_SIZE];                  // Random number generated by the host for the Requests and copied to the
+                                                             // Response by the eMMC Replay Protected Memory Block engine.
+
+  UINT8  WriteCounter[EFI_RPMB_PACKET_WCOUNTER_SIZE];        // Counter value for the total amount of the successful authenticated data write
+                                                             // requests made by the host.
+
+  UINT8  Address[EFI_RPMB_PACKET_ADDRESS_SIZE];              // Address of the data to be programmed to or read from the Replay Protected
+                                                             // Memory Block. Address is the serial number of the accessed half sector
+                                                             // (256B). Address argument in CMD 18 and CMD 25 will be ignored.
+
+  UINT8  BlockCount[EFI_RPMB_PACKET_BLOCKCOUNT_SIZE];        // Number of blocks (half sectors, 256B) requested to be read/programmed. This
+                                                             // value is equal to the count value in CMD23 argument.
+
+  UINT8  OperationResult[EFI_RPMB_PACKET_RESULT_SIZE];       // Includes information about the status of the write counter (valid, expired)
+                                                             // and successfulness of the access made to the Replay Protected Memory Block.
+
+  UINT8  RequestOrResponseType[EFI_RPMB_PACKET_TYPE_SIZE];   // Defines the type of request and response to/from the memory.
+} EFI_RPMB_DATA_PACKET;
+#pragma pack()
+
+typedef struct {
+  EFI_RPMB_DATA_PACKET  *Packets;
+  UINTN                 PacketCount;   // The number of RPMB Frames/Packets which is
+                                       //also the number of half sectors (256Byte) to
+                                       // be read/programmed since each RPBM frame
+                                       //holds 256Bytes of data.
+} EFI_RPMB_DATA_BUFFER;
+
+typedef struct _EFI_RPMB_IO_PROTOCOL EFI_RPMB_IO_PROTOCOL;
+
+/** Authentication key programming request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ProgrammingRequest A data packet describing a key programming request.
+  @param[out] ResultResponse A caller allocated data packet which will receive the
+  key programming result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during key programming any other eMMC internal failure is reported
+  in the Result field of the returned response data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_PROGRAM_KEY) (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ProgrammingRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ResultResponse
+  );
+
+/** Reading of the write counter value request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ReadRequest A data packet describing a read counter value request.
+  @param[out] ReadResponse A caller allocated data packet which will receive
+  the counter value read response. If counter has expired bit 7 is set to 1 in
+  returned Result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during counter read or any other eMMC internal failure is reported
+  in the Result field of the returned response data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_READ_COUNTER) (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ReadRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ReadResponse
+  );
+
+/** Authenticated data write request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] WriteRequest A sequence of data packets describing data write
+  requests and holds the data to be written.
+  @param[out] ResultResponse A caller allocated data packet which will receive
+  the data write programming result.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during data programming or any other eMMC internal failure is reported
+  in the Result field of the returned data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_AUTHENTICATED_WRITE) (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_BUFFER   *WriteRequest,
+  OUT EFI_RPMB_DATA_PACKET  *ResultResponse
+  );
+
+/** Authenticated data read request.
+
+  @param[in] This Indicates a pointer to the calling context.
+  @param[in] ReadRequest A data packet that describes a data read request.
+  @param[out] ReadResponse A caller allocated data packets which will receive
+  the data read.
+
+  @retval EFI_SUCCESS RPMB communication sequence with the eMMC succeeded
+  according to specs, other values are returned in case of any protocol error.
+  Failure during data fetch from the eMMC or any other eMMC internal failure
+  is reported in the Result field of the returned data packet.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_RPMB_AUTHENTICATED_READ) (
+  IN EFI_RPMB_IO_PROTOCOL   *This,
+  IN EFI_RPMB_DATA_PACKET   *ReadRequest,
+  OUT EFI_RPMB_DATA_BUFFER  *ReadResponse
+  );
+
+struct _EFI_RPMB_IO_PROTOCOL {
+  UINT64  Revision;
+  UINT8   Cid[EFI_RPMB_CID_SIZE];   // MMC Card IDentification (CID) register.
+
+  UINT8   ReliableSectorCount;      // Reliable write sector count as defined by the REL_WR_SEC_C field of the
+                                    // MMC EXT_CSD register.
+
+  UINT8   RpmbSizeMult;             // RPMB sector size multiplier as defined by the RPMB_SIZE_MULT field of the
+                                    // MMC EXT_CSD register.
+                                    // The RPMB partition size is calculated from the register by using the
+                                    // following equation: RPMB partition size = 128kB x RPMB_SIZE_MULT
+
+  // Protocol Callbacks
+
+  EFI_RPMB_PROGRAM_KEY          ProgramKey;
+  EFI_RPMB_READ_COUNTER         ReadCounter;
+  EFI_RPMB_AUTHENTICATED_WRITE  AuthenticatedWrite;
+  EFI_RPMB_AUTHENTICATED_READ   AuthenticatedRead;
+};
+
+__inline__
+static
+CONST CHAR16*
+RpmbOperationResultToString (
+  UINT16 OperationResult
+  )
+{
+  switch (OperationResult) {
+    case EFI_RPMB_OK:
+      return L"Operation OK";
+    case EFI_RPMB_ERROR_GENERAL:
+      return L"General failure";
+    case EFI_RPMB_ERROR_AUTH:
+      return L"Authentication failure";
+    case EFI_RPMB_ERROR_COUNTER:
+      return L"Counter failure";
+    case EFI_RPMB_ERROR_ADDRESS:
+      return L"Address failure";
+    case EFI_RPMB_ERROR_WRITE:
+      return L"Write failure";
+    case EFI_RPMB_ERROR_READ:
+      return L"Read failure";
+    case EFI_RPMB_ERROR_KEY:
+      return L"Authentication key not yet programmed";
+    default:
+      return L"Undefined operation result";
+  }
+}
+
+extern EFI_GUID gEfiRpmbIoProtocolGuid;
+
+#endif // __RPMB_IO_H__
diff --git a/Platform/Microsoft/Include/Protocol/Sdhc.h b/Platform/Microsoft/Include/Protocol/Sdhc.h
new file mode 100644
index 000000000000..381cd823de0c
--- /dev/null
+++ b/Platform/Microsoft/Include/Protocol/Sdhc.h
@@ -0,0 +1,197 @@
+/** @file
+*
+*  Copyright (c) Microsoft Corporation. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#ifndef __SDHC_H__
+#define __SDHC_H__
+
+//
+// Global ID for the SDHC Protocol {46055B0F-992A-4AD7-8F81-148186FFDF72}
+//
+#define EFI_SDHC_PROTOCOL_GUID \
+    { 0x46055b0f, 0x992a, 0x4ad7, { 0x8f, 0x81, 0x14, 0x81, 0x86, 0xff, 0xdf, 0x72 } };
+
+typedef UINT16 SD_COMMAND_INDEX;
+
+typedef enum {
+    SdCommandTypeUndefined = 0,
+    SdCommandTypeSuspend,
+    SdCommandTypeResume,
+    SdCommandTypeAbort
+} SD_COMMAND_TYPE;
+
+typedef enum {
+    SdCommandClassUndefined = 0,
+    SdCommandClassStandard,
+    SdCommandClassApp
+} SD_COMMAND_CLASS;
+
+typedef enum {
+    SdResponseTypeUndefined = 0,
+    SdResponseTypeNone,
+    SdResponseTypeR1,
+    SdResponseTypeR1B,
+    SdResponseTypeR2,
+    SdResponseTypeR3,
+    SdResponseTypeR4,
+    SdResponseTypeR5,
+    SdResponseTypeR5B,
+    SdResponseTypeR6
+} SD_RESPONSE_TYPE;
+
+typedef enum {
+    SdTransferTypeUndefined = 0,
+    SdTransferTypeNone,
+    SdTransferTypeSingleBlock,
+    SdTransferTypeMultiBlock,
+    SdTransferTypeMultiBlockNoStop
+} SD_TRANSFER_TYPE;
+
+typedef enum {
+    SdTransferDirectionUndefined = 0,
+    SdTransferDirectionRead,
+    SdTransferDirectionWrite
+} SD_TRANSFER_DIRECTION;
+
+typedef struct {
+    SD_COMMAND_INDEX Index;
+    SD_COMMAND_TYPE Type;
+    SD_COMMAND_CLASS Class;
+    SD_RESPONSE_TYPE ResponseType;
+    SD_TRANSFER_TYPE TransferType;
+    SD_TRANSFER_DIRECTION TransferDirection;
+} SD_COMMAND;
+
+typedef struct {
+    UINT32 BlockSize;
+    UINT32 BlockCount;
+    VOID* Buffer;
+} SD_COMMAND_XFR_INFO;
+
+typedef enum {
+    SdBusWidthUndefined = 0,
+    SdBusWidth1Bit = 1,
+    SdBusWidth4Bit = 4,
+    SdBusWidth8Bit = 8
+} SD_BUS_WIDTH;
+
+typedef enum {
+    SdhcResetTypeUndefined = 0,
+    SdhcResetTypeAll,
+    SdhcResetTypeCmd,
+    SdhcResetTypeData
+} SDHC_RESET_TYPE;
+
+typedef struct {
+  UINT32 MaximumBlockSize;
+  UINT32 MaximumBlockCount;
+} SDHC_CAPABILITIES;
+//
+// Forward declaration for EFI_SDHC_PROTOCOL
+//
+typedef struct _EFI_SDHC_PROTOCOL EFI_SDHC_PROTOCOL;
+
+typedef VOID (EFIAPI *SDHC_GET_CAPABILITIES) (
+  IN EFI_SDHC_PROTOCOL *This,
+  OUT SDHC_CAPABILITIES *Capabilities
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SOFTWARERESET) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN SDHC_RESET_TYPE ResetType
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SETCLOCK) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN UINT32 TargetFreqHz
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SETBUSWIDTH) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN SD_BUS_WIDTH BusWidth
+  );
+
+typedef BOOLEAN (EFIAPI *SDHC_ISCARDPRESENT) (
+  IN EFI_SDHC_PROTOCOL *This
+  );
+
+typedef BOOLEAN (EFIAPI *SDHC_ISREADONLY) (
+  IN EFI_SDHC_PROTOCOL *This
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_SENDCOMMAND) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN const SD_COMMAND *Cmd,
+  IN UINT32 Argument,
+  IN OPTIONAL const SD_COMMAND_XFR_INFO *XfrInfo
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_RECEIVERESPONSE) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN const SD_COMMAND *Cmd,
+  OUT UINT32 *Buffer
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_READBLOCKDATA) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN UINTN LengthInBytes,
+  OUT UINT32 *Buffer
+  );
+
+typedef EFI_STATUS (EFIAPI *SDHC_WRITEBLOCKDATA) (
+  IN EFI_SDHC_PROTOCOL *This,
+  IN UINTN LengthInBytes,
+  IN const UINT32 *Buffer
+  );
+
+typedef VOID (EFIAPI *SDHC_CLEANUP) (
+  IN EFI_SDHC_PROTOCOL *This
+  );
+
+struct _EFI_SDHC_PROTOCOL {
+  UINT32                   Revision;
+
+  //
+  // A unique ID that identify the SDHC device among other
+  // SDHC devices on the system
+  //
+  UINT32                   SdhcId;
+
+  //
+  // Context area allocated by the SDHC driver
+  //
+  VOID                     *PrivateContext;
+
+  //
+  // SDHHC Callbacks
+  //
+  SDHC_GET_CAPABILITIES    GetCapabilities;
+  SDHC_SOFTWARERESET       SoftwareReset;
+  SDHC_SETCLOCK            SetClock;
+  SDHC_SETBUSWIDTH         SetBusWidth;
+  SDHC_ISCARDPRESENT       IsCardPresent;
+  SDHC_ISREADONLY          IsReadOnly;
+  SDHC_SENDCOMMAND         SendCommand;
+  SDHC_RECEIVERESPONSE     ReceiveResponse;
+  SDHC_READBLOCKDATA       ReadBlockData;
+  SDHC_WRITEBLOCKDATA      WriteBlockData;
+  SDHC_CLEANUP             Cleanup;
+};
+
+#define SDHC_PROTOCOL_INTERFACE_REVISION    0x00010000    // 1.0
+
+extern EFI_GUID gEfiSdhcProtocolGuid;
+
+#endif // __SDHC_H__
+
-- 
2.16.2.gvfs.1.33.gf5370f1



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

* [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg
  2018-07-17  2:05 [PATCH edk2-platforms 0/3] Add Platform-Generic Packages to support Windows IoT Core Chris Co
  2018-07-17  2:05 ` [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
@ 2018-07-17  2:05 ` Chris Co
  2018-07-31 20:38   ` Leif Lindholm
  2018-07-17  2:05 ` [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library Chris Co
  2 siblings, 1 reply; 13+ messages in thread
From: Chris Co @ 2018-07-17  2:05 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

MsPkg is a collection of libraries and drivers that are specific
to supporting Windows IoT Core but are not Platform/Silicon specific.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
---
 Platform/Microsoft/MsPkg.dec | 42 ++++++++++++++++++++
 Platform/Microsoft/MsPkg.dsc | 32 +++++++++++++++
 2 files changed, 74 insertions(+)

diff --git a/Platform/Microsoft/MsPkg.dec b/Platform/Microsoft/MsPkg.dec
new file mode 100644
index 000000000000..ff17a016943c
--- /dev/null
+++ b/Platform/Microsoft/MsPkg.dec
@@ -0,0 +1,42 @@
+#/** @file
+#  A package that contains generic headers and components.
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010005
+  PACKAGE_NAME                   = MsPkg
+  PACKAGE_GUID                   = DC909FB7-F45E-4D7F-BF10-327BD9BFA21C
+  PACKAGE_VERSION                = 0.1
+
+[Includes.common]
+  Include                        # Root include for the package
+
+[LibraryClasses.common]
+
+[Guids.common]
+  gMsPkgTokenSpaceGuid = { 0x3ecb4bb9, 0xb80a, 0x4efd, { 0x92, 0xb8, 0x3a, 0x16, 0xe0, 0xc8, 0x19, 0xb } }
+
+[PcdsFixedAtBuild.common]
+  gMsPkgTokenSpaceGuid.PcdSecureBootEnable|FALSE|BOOLEAN|0x00
+
+  #
+  # The DevicePath to a partition on a writeable media used for logging and misc
+  # storage purposes. SD card DevicePath example:
+  # gMsPkgTokenSpaceGuid.PcdStorageMediaPartitionDevicePath|L"VenHw(AAFB8DAA-7340-43AC-8D49-0CCE14812489,03000000)/SD(0x0)/HD(1,MBR,0xAE420040,0x1000,0x20000)"
+  #
+  gMsPkgTokenSpaceGuid.PcdStorageMediaPartitionDevicePath|L""|VOID*|0x03
+
+[Protocols.common]
+  gEfiSdhcProtocolGuid = { 0x46055b0f, 0x992a, 0x4ad7, { 0x8f, 0x81, 0x14, 0x81, 0x86, 0xff, 0xdf, 0x72 } }
+  gEfiRpmbIoProtocolGuid = { 0xfbaee5b2, 0x8b0, 0x41b8, { 0xb0, 0xb0, 0x86, 0xb7, 0x2e, 0xed, 0x1b, 0xb6 } }
diff --git a/Platform/Microsoft/MsPkg.dsc b/Platform/Microsoft/MsPkg.dsc
new file mode 100644
index 000000000000..b43902cbb04d
--- /dev/null
+++ b/Platform/Microsoft/MsPkg.dsc
@@ -0,0 +1,32 @@
+## @file
+#  A package that contains generic headers and components.
+#
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#   This program and the accompanying materials
+#   are licensed and made available under the terms and conditions of the BSD License
+#   which accompanies this distribution. The full text of the license may be found at
+#   http://opensource.org/licenses/bsd-license.
+#
+#   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+##
+
+[Defines]
+  PLATFORM_NAME                  = MsPkg
+  PLATFORM_GUID                  = 2F78367E-9C74-4FBE-82E7-1D2DAAF18CC6
+  PLATFORM_VERSION               = 0.01
+  DSC_SPECIFICATION              = 0x00010005
+  OUTPUT_DIRECTORY               = Build/MsPkg
+  SUPPORTED_ARCHITECTURES        = ARM|AARCH64
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
+
+[PcdsFeatureFlag]
+
+[PcdsFixedAtBuild]
+
+[LibraryClasses]
+
+[Components]
+  Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
-- 
2.16.2.gvfs.1.33.gf5370f1



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

* [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library
  2018-07-17  2:05 [PATCH edk2-platforms 0/3] Add Platform-Generic Packages to support Windows IoT Core Chris Co
  2018-07-17  2:05 ` [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
  2018-07-17  2:05 ` [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg Chris Co
@ 2018-07-17  2:05 ` Chris Co
  2018-07-31 20:56   ` Leif Lindholm
  2 siblings, 1 reply; 13+ messages in thread
From: Chris Co @ 2018-07-17  2:05 UTC (permalink / raw)
  To: edk2-devel@lists.01.org; +Cc: Ard Biesheuvel, Leif Lindholm, Michael D Kinney

This debug library provides support for importing symbols to
debug using Lauterbach.

Derived from: ArmPkg\Library\DebugPeCoffExtraActionLib

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Christopher Co <christopher.co@microsoft.com>
---
 Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c   | 142 ++++++++++++++++++++
 Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf |  41 ++++++
 2 files changed, 183 insertions(+)

diff --git a/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c
new file mode 100644
index 000000000000..0adfacdbe5cf
--- /dev/null
+++ b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c
@@ -0,0 +1,142 @@
+/**@file
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
+Portions copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/PeCoffLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/PrintLib.h>
+
+
+/**
+  If the build is done on cygwin the paths are cygpaths.
+  /cygdrive/c/tmp.txt vs c:\tmp.txt so we need to convert
+  them to work with RVD commands
+
+  @param  Name  Path to convert if needed
+
+**/
+CHAR8 *
+DeCygwinPathIfNeeded (
+  IN  CHAR8   *Name,
+  IN  CHAR8   *Temp,
+  IN  UINTN   Size
+  )
+{
+  CHAR8   *Ptr;
+  UINTN   Index;
+  UINTN   Index2;
+
+  Ptr = AsciiStrStr (Name, "/cygdrive/");
+  if (Ptr == NULL) {
+    return Name;
+  }
+
+  for (Index = 9, Index2 = 0; (Index < (Size + 9)) && (Ptr[Index] != '\0'); Index++, Index2++) {
+    Temp[Index2] = Ptr[Index];
+    if (Temp[Index2] == '/') {
+      Temp[Index2] = '\\' ;
+  }
+
+    if (Index2 == 1) {
+      Temp[Index2 - 1] = Ptr[Index];
+      Temp[Index2] = ':';
+    }
+  }
+
+  return Temp;
+}
+
+
+/**
+  Performs additional actions after a PE/COFF image has been loaded and relocated.
+
+  If ImageContext is NULL, then ASSERT().
+
+  @param  ImageContext  Pointer to the image context structure that describes the
+                        PE/COFF image that has already been loaded and relocated.
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageExtraAction (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  )
+{
+#if !defined(MDEPKG_NDEBUG)
+  CHAR8 Temp[512];
+#endif
+
+  if (ImageContext->PdbPointer) {
+#ifdef __CC_ARM
+#if (__ARMCC_VERSION < 500000)
+    // Print out the command for the RVD debugger to load symbols for this image
+    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "load /a /ni /np %a &0x%p\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
+#else
+    // Print out the command for the DS-5 to load symbols for this image
+    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "add-symbol-file %a 0x%p\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
+#endif
+#elif __GNUC__
+    // This may not work correctly if you generate PE/COFF directlyas then the Offset would not be required
+    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Data.load.elf %a /reloc .text at 0x%p /nocode /noclear\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
+#else
+    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Loading driver at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN) ImageContext->ImageAddress, FUNCTION_ENTRY_POINT (ImageContext->EntryPoint)));
+#endif
+  } else {
+    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Loading driver at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN) ImageContext->ImageAddress, FUNCTION_ENTRY_POINT (ImageContext->EntryPoint)));
+  }
+}
+
+
+
+/**
+  Performs additional actions just before a PE/COFF image is unloaded.  Any resources
+  that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
+
+  If ImageContext is NULL, then ASSERT().
+
+  @param  ImageContext  Pointer to the image context structure that describes the
+                        PE/COFF image that is being unloaded.
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderUnloadImageExtraAction (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  )
+{
+#if !defined(MDEPKG_NDEBUG)
+  CHAR8 Temp[512];
+#endif
+
+  if (ImageContext->PdbPointer) {
+#ifdef __CC_ARM
+    // Print out the command for the RVD debugger to load symbols for this image
+    DEBUG ((DEBUG_ERROR, "unload symbols_only %a\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp))));
+#elif __GNUC__
+    // This may not work correctly if you generate PE/COFF directlyas then the Offset would not be required
+    DEBUG ((DEBUG_ERROR, "remove-symbol-file %a 0x%08x\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
+#else
+    DEBUG ((DEBUG_ERROR, "Unloading %a\n", ImageContext->PdbPointer));
+#endif
+  } else {
+    DEBUG ((DEBUG_ERROR, "Unloading driver at 0x%11p\n", (VOID *)(UINTN) ImageContext->ImageAddress));
+  }
+}
diff --git a/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf
new file mode 100644
index 000000000000..2cfc51b0578f
--- /dev/null
+++ b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf
@@ -0,0 +1,41 @@
+#/** @file
+# PeCoff extra action libary for DXE phase that run Unix emulator.
+#
+# Lib to provide memory journal status code reporting Routines
+# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution.  The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = LauterbachPeCoffExtraActionLib
+  FILE_GUID                      = F5D296F5-C546-431F-8CAC-3E91043B452D
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PeCoffExtraActionLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = ARM
+#
+
+[Sources.common]
+  LauterbachPeCoffExtraActionLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  DebugLib
-- 
2.16.2.gvfs.1.33.gf5370f1



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

* Re: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver
  2018-07-17  2:05 ` [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
@ 2018-07-31 20:33   ` Leif Lindholm
  2018-08-02  0:05     ` Chris Co
  0 siblings, 1 reply; 13+ messages in thread
From: Leif Lindholm @ 2018-07-31 20:33 UTC (permalink / raw)
  To: Chris Co; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

Hi Chris,

On Tue, Jul 17, 2018 at 02:05:42AM +0000, Chris Co wrote:
> This SdMmc driver adds support to boot Windows from SD and eMMC.
> It implements RPMB protocol support for eMMC, unique device path
> creation for each slot on the SD bus, high speed modes,
> eMMC bus width auto-detection, and support for high capacity
> SDXC cards.
> 
> Derived from: EmbeddedPkg\Universal\MmcDxe

Hmm, I'm already slightly unhappy that we have duplication between
EmbeddedPkg and MdeModulePkg (not to mention the extra fork for
Marvell's XenonDxe).

I'm obviously keen for the added functionality to be available to more
platforms. Is there any way for this support to be added into either
the EmbeddedPkg or the MdeModulePkg driver?

(Deferring comments on specific content.)

/
    Leif

> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Christopher Co <christopher.co@microsoft.com>
> ---
>  Platform/Microsoft/Drivers/SdMmcDxe/BlockIo.c    |  526 ++++++
>  Platform/Microsoft/Drivers/SdMmcDxe/Debug.c      |  358 ++++
>  Platform/Microsoft/Drivers/SdMmcDxe/Protocol.c   | 1774 ++++++++++++++++++++
>  Platform/Microsoft/Drivers/SdMmcDxe/Protocol.h   |  231 +++
>  Platform/Microsoft/Drivers/SdMmcDxe/RpmbIo.c     |  611 +++++++
>  Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.c      |  892 ++++++++++
>  Platform/Microsoft/Drivers/SdMmcDxe/SdMmc.h      |  529 ++++++
>  Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf |   50 +
>  Platform/Microsoft/Drivers/SdMmcDxe/SdMmcHw.h    |  506 ++++++
>  Platform/Microsoft/Include/Protocol/RpmbIo.h     |  262 +++
>  Platform/Microsoft/Include/Protocol/Sdhc.h       |  197 +++
>  11 files changed, 5936 insertions(+)


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

* Re: [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg
  2018-07-17  2:05 ` [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg Chris Co
@ 2018-07-31 20:38   ` Leif Lindholm
  0 siblings, 0 replies; 13+ messages in thread
From: Leif Lindholm @ 2018-07-31 20:38 UTC (permalink / raw)
  To: Chris Co; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

On Tue, Jul 17, 2018 at 02:05:43AM +0000, Chris Co wrote:
> MsPkg is a collection of libraries and drivers that are specific
> to supporting Windows IoT Core but are not Platform/Silicon specific.

Minor comments inline.

> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Christopher Co <christopher.co@microsoft.com>
> ---
>  Platform/Microsoft/MsPkg.dec | 42 ++++++++++++++++++++
>  Platform/Microsoft/MsPkg.dsc | 32 +++++++++++++++
>  2 files changed, 74 insertions(+)
> 
> diff --git a/Platform/Microsoft/MsPkg.dec b/Platform/Microsoft/MsPkg.dec
> new file mode 100644
> index 000000000000..ff17a016943c
> --- /dev/null
> +++ b/Platform/Microsoft/MsPkg.dec
> @@ -0,0 +1,42 @@
> +#/** @file
> +#  A package that contains generic headers and components.
> +#
> +#  Copyright (c) Microsoft Corporation. All rights reserved.

Please add a year to the copyright statement.

> +#
> +#  This program and the accompanying materials
> +#  are licensed and made available under the terms and conditions of the BSD License
> +#  which accompanies this distribution.  The full text of the license may be found at
> +#  http://opensource.org/licenses/bsd-license.php
> +#
> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +#**/
> +
> +[Defines]
> +  DEC_SPECIFICATION              = 0x00010005

0x0001001a is the current version, unless there's a specific reason
for holding back.

> +  PACKAGE_NAME                   = MsPkg
> +  PACKAGE_GUID                   = DC909FB7-F45E-4D7F-BF10-327BD9BFA21C
> +  PACKAGE_VERSION                = 0.1
> +
> +[Includes.common]
> +  Include                        # Root include for the package
> +
> +[LibraryClasses.common]
> +
> +[Guids.common]
> +  gMsPkgTokenSpaceGuid = { 0x3ecb4bb9, 0xb80a, 0x4efd, { 0x92, 0xb8, 0x3a, 0x16, 0xe0, 0xc8, 0x19, 0xb } }
> +
> +[PcdsFixedAtBuild.common]
> +  gMsPkgTokenSpaceGuid.PcdSecureBootEnable|FALSE|BOOLEAN|0x00
> +
> +  #
> +  # The DevicePath to a partition on a writeable media used for logging and misc
> +  # storage purposes. SD card DevicePath example:
> +  # gMsPkgTokenSpaceGuid.PcdStorageMediaPartitionDevicePath|L"VenHw(AAFB8DAA-7340-43AC-8D49-0CCE14812489,03000000)/SD(0x0)/HD(1,MBR,0xAE420040,0x1000,0x20000)"
> +  #
> +  gMsPkgTokenSpaceGuid.PcdStorageMediaPartitionDevicePath|L""|VOID*|0x03
> +
> +[Protocols.common]
> +  gEfiSdhcProtocolGuid = { 0x46055b0f, 0x992a, 0x4ad7, { 0x8f, 0x81, 0x14, 0x81, 0x86, 0xff, 0xdf, 0x72 } }
> +  gEfiRpmbIoProtocolGuid = { 0xfbaee5b2, 0x8b0, 0x41b8, { 0xb0, 0xb0, 0x86, 0xb7, 0x2e, 0xed, 0x1b, 0xb6 } }

Please sort by name alphabetically where no other more logical
ordering exists.

> diff --git a/Platform/Microsoft/MsPkg.dsc b/Platform/Microsoft/MsPkg.dsc
> new file mode 100644
> index 000000000000..b43902cbb04d
> --- /dev/null
> +++ b/Platform/Microsoft/MsPkg.dsc
> @@ -0,0 +1,32 @@
> +## @file
> +#  A package that contains generic headers and components.
> +#
> +#  Copyright (c) Microsoft Corporation. All rights reserved.

Year.

> +#
> +#   This program and the accompanying materials
> +#   are licensed and made available under the terms and conditions of the BSD License
> +#   which accompanies this distribution. The full text of the license may be found at
> +#   http://opensource.org/licenses/bsd-license.
> +#
> +#   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +#   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> +  PLATFORM_NAME                  = MsPkg
> +  PLATFORM_GUID                  = 2F78367E-9C74-4FBE-82E7-1D2DAAF18CC6
> +  PLATFORM_VERSION               = 0.01
> +  DSC_SPECIFICATION              = 0x00010005

0x0001001a

> +  OUTPUT_DIRECTORY               = Build/MsPkg
> +  SUPPORTED_ARCHITECTURES        = ARM|AARCH64
> +  BUILD_TARGETS                  = DEBUG|RELEASE

DEBUG|NOOPT|RELEASE ?

/
    Leif

> +  SKUID_IDENTIFIER               = DEFAULT
> +
> +[PcdsFeatureFlag]
> +
> +[PcdsFixedAtBuild]
> +
> +[LibraryClasses]
> +
> +[Components]
> +  Platform/Microsoft/Drivers/SdMmcDxe/SdMmcDxe.inf
> -- 
> 2.16.2.gvfs.1.33.gf5370f1
> 


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

* Re: [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library
  2018-07-17  2:05 ` [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library Chris Co
@ 2018-07-31 20:56   ` Leif Lindholm
  2018-07-31 20:59     ` Ard Biesheuvel
  0 siblings, 1 reply; 13+ messages in thread
From: Leif Lindholm @ 2018-07-31 20:56 UTC (permalink / raw)
  To: Chris Co; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

On Tue, Jul 17, 2018 at 02:05:45AM +0000, Chris Co wrote:
> This debug library provides support for importing symbols to
> debug using Lauterbach.
> 
> Derived from: ArmPkg\Library\DebugPeCoffExtraActionLib

I'm not seeing any difference between this one and the original other
than the addition of the Microsoft copyright statement and updating of
the debug printouts to modern style.

I would be happy to take this as a patch to the original, but I don't
see what benefit this copy brings. What prevents you from using the
original?

/
    Leif

> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Leif Lindholm <leif.lindholm@linaro.org>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Christopher Co <christopher.co@microsoft.com>
> ---
>  Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c   | 142 ++++++++++++++++++++
>  Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf |  41 ++++++
>  2 files changed, 183 insertions(+)
> 
> diff --git a/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c
> new file mode 100644
> index 000000000000..0adfacdbe5cf
> --- /dev/null
> +++ b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.c
> @@ -0,0 +1,142 @@
> +/**@file
> +
> +Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
> +Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
> +Portions copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.<BR>
> +Copyright (c) Microsoft Corporation. All rights reserved.<BR>
> +
> +This program and the accompanying materials
> +are licensed and made available under the terms and conditions of the BSD License
> +which accompanies this distribution.  The full text of the license may be found at
> +http://opensource.org/licenses/bsd-license.php
> +
> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +
> +**/
> +
> +#include <PiDxe.h>
> +#include <Library/PeCoffLib.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/PeCoffExtraActionLib.h>
> +#include <Library/PrintLib.h>
> +
> +
> +/**
> +  If the build is done on cygwin the paths are cygpaths.
> +  /cygdrive/c/tmp.txt vs c:\tmp.txt so we need to convert
> +  them to work with RVD commands
> +
> +  @param  Name  Path to convert if needed
> +
> +**/
> +CHAR8 *
> +DeCygwinPathIfNeeded (
> +  IN  CHAR8   *Name,
> +  IN  CHAR8   *Temp,
> +  IN  UINTN   Size
> +  )
> +{
> +  CHAR8   *Ptr;
> +  UINTN   Index;
> +  UINTN   Index2;
> +
> +  Ptr = AsciiStrStr (Name, "/cygdrive/");
> +  if (Ptr == NULL) {
> +    return Name;
> +  }
> +
> +  for (Index = 9, Index2 = 0; (Index < (Size + 9)) && (Ptr[Index] != '\0'); Index++, Index2++) {
> +    Temp[Index2] = Ptr[Index];
> +    if (Temp[Index2] == '/') {
> +      Temp[Index2] = '\\' ;
> +  }
> +
> +    if (Index2 == 1) {
> +      Temp[Index2 - 1] = Ptr[Index];
> +      Temp[Index2] = ':';
> +    }
> +  }
> +
> +  return Temp;
> +}
> +
> +
> +/**
> +  Performs additional actions after a PE/COFF image has been loaded and relocated.
> +
> +  If ImageContext is NULL, then ASSERT().
> +
> +  @param  ImageContext  Pointer to the image context structure that describes the
> +                        PE/COFF image that has already been loaded and relocated.
> +
> +**/
> +VOID
> +EFIAPI
> +PeCoffLoaderRelocateImageExtraAction (
> +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> +  )
> +{
> +#if !defined(MDEPKG_NDEBUG)
> +  CHAR8 Temp[512];
> +#endif
> +
> +  if (ImageContext->PdbPointer) {
> +#ifdef __CC_ARM
> +#if (__ARMCC_VERSION < 500000)
> +    // Print out the command for the RVD debugger to load symbols for this image
> +    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "load /a /ni /np %a &0x%p\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
> +#else
> +    // Print out the command for the DS-5 to load symbols for this image
> +    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "add-symbol-file %a 0x%p\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
> +#endif
> +#elif __GNUC__
> +    // This may not work correctly if you generate PE/COFF directlyas then the Offset would not be required
> +    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Data.load.elf %a /reloc .text at 0x%p /nocode /noclear\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
> +#else
> +    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Loading driver at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN) ImageContext->ImageAddress, FUNCTION_ENTRY_POINT (ImageContext->EntryPoint)));
> +#endif
> +  } else {
> +    DEBUG ((DEBUG_LOAD | DEBUG_INFO, "Loading driver at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN) ImageContext->ImageAddress, FUNCTION_ENTRY_POINT (ImageContext->EntryPoint)));
> +  }
> +}
> +
> +
> +
> +/**
> +  Performs additional actions just before a PE/COFF image is unloaded.  Any resources
> +  that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
> +
> +  If ImageContext is NULL, then ASSERT().
> +
> +  @param  ImageContext  Pointer to the image context structure that describes the
> +                        PE/COFF image that is being unloaded.
> +
> +**/
> +VOID
> +EFIAPI
> +PeCoffLoaderUnloadImageExtraAction (
> +  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
> +  )
> +{
> +#if !defined(MDEPKG_NDEBUG)
> +  CHAR8 Temp[512];
> +#endif
> +
> +  if (ImageContext->PdbPointer) {
> +#ifdef __CC_ARM
> +    // Print out the command for the RVD debugger to load symbols for this image
> +    DEBUG ((DEBUG_ERROR, "unload symbols_only %a\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp))));
> +#elif __GNUC__
> +    // This may not work correctly if you generate PE/COFF directlyas then the Offset would not be required
> +    DEBUG ((DEBUG_ERROR, "remove-symbol-file %a 0x%08x\n", DeCygwinPathIfNeeded (ImageContext->PdbPointer, Temp, sizeof (Temp)), (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)));
> +#else
> +    DEBUG ((DEBUG_ERROR, "Unloading %a\n", ImageContext->PdbPointer));
> +#endif
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "Unloading driver at 0x%11p\n", (VOID *)(UINTN) ImageContext->ImageAddress));
> +  }
> +}
> diff --git a/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf
> new file mode 100644
> index 000000000000..2cfc51b0578f
> --- /dev/null
> +++ b/Platform/Microsoft/Library/LauterbachPeCoffExtraActionLib/LauterbachPeCoffExtraActionLib.inf
> @@ -0,0 +1,41 @@
> +#/** @file
> +# PeCoff extra action libary for DXE phase that run Unix emulator.
> +#
> +# Lib to provide memory journal status code reporting Routines
> +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
> +# Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
> +# Copyright (c) Microsoft Corporation. All rights reserved.<BR>
> +#
> +# This program and the accompanying materials
> +# are licensed and made available under the terms and conditions of the BSD License
> +# which accompanies this distribution.  The full text of the license may be found at
> +# http://opensource.org/licenses/bsd-license.php
> +#
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +#
> +#
> +#**/
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010005
> +  BASE_NAME                      = LauterbachPeCoffExtraActionLib
> +  FILE_GUID                      = F5D296F5-C546-431F-8CAC-3E91043B452D
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = PeCoffExtraActionLib
> +
> +#
> +# The following information is for reference only and not required by the build tools.
> +#
> +#  VALID_ARCHITECTURES           = ARM
> +#
> +
> +[Sources.common]
> +  LauterbachPeCoffExtraActionLib.c
> +
> +[Packages]
> +  MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> +  DebugLib
> -- 
> 2.16.2.gvfs.1.33.gf5370f1
> 


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

* Re: [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library
  2018-07-31 20:56   ` Leif Lindholm
@ 2018-07-31 20:59     ` Ard Biesheuvel
  2018-08-01  9:39       ` Leif Lindholm
  0 siblings, 1 reply; 13+ messages in thread
From: Ard Biesheuvel @ 2018-07-31 20:59 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: Chris Co, edk2-devel@lists.01.org, Michael D Kinney

On 31 July 2018 at 22:56, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Tue, Jul 17, 2018 at 02:05:45AM +0000, Chris Co wrote:
>> This debug library provides support for importing symbols to
>> debug using Lauterbach.
>>
>> Derived from: ArmPkg\Library\DebugPeCoffExtraActionLib
>
> I'm not seeing any difference between this one and the original other
> than the addition of the Microsoft copyright statement and updating of
> the debug printouts to modern style.
>
> I would be happy to take this as a patch to the original, but I don't
> see what benefit this copy brings. What prevents you from using the
> original?
>

The 'data.load.elf' statement in
PeCoffLoaderRelocateImageExtraAction() is particular to Lauterbach


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

* Re: [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library
  2018-07-31 20:59     ` Ard Biesheuvel
@ 2018-08-01  9:39       ` Leif Lindholm
  2018-08-02  1:27         ` Chris Co
  0 siblings, 1 reply; 13+ messages in thread
From: Leif Lindholm @ 2018-08-01  9:39 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: Chris Co, edk2-devel@lists.01.org, Michael D Kinney

On Tue, Jul 31, 2018 at 10:59:22PM +0200, Ard Biesheuvel wrote:
> On 31 July 2018 at 22:56, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > On Tue, Jul 17, 2018 at 02:05:45AM +0000, Chris Co wrote:
> >> This debug library provides support for importing symbols to
> >> debug using Lauterbach.
> >>
> >> Derived from: ArmPkg\Library\DebugPeCoffExtraActionLib
> >
> > I'm not seeing any difference between this one and the original other
> > than the addition of the Microsoft copyright statement and updating of
> > the debug printouts to modern style.
> >
> > I would be happy to take this as a patch to the original, but I don't
> > see what benefit this copy brings. What prevents you from using the
> > original?
> 
> The 'data.load.elf' statement in
> PeCoffLoaderRelocateImageExtraAction() is particular to Lauterbach

Oh, right.

That (original) code badly needs reformatting.

Still, if that's the only difference - and in a debug printout, why
fork the module?

If there is a way to identify which debugger is being used, use that.
If not, dump all the possible strings.

We really don't want a situation where you need to hard-code which
debugger you are using for a specific platform. And even if that is
unavoidable, it needs to live in the main edk2 repository.

/
    Leif


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

* Re: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver
  2018-07-31 20:33   ` Leif Lindholm
@ 2018-08-02  0:05     ` Chris Co
  2018-08-02 11:38       ` Leif Lindholm
  0 siblings, 1 reply; 13+ messages in thread
From: Chris Co @ 2018-08-02  0:05 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

Hi Leif,

> -----Original Message-----
> From: Leif Lindholm <leif.lindholm@linaro.org>
> Sent: Tuesday, July 31, 2018 1:33 PM
> To: Chris Co <Christopher.Co@microsoft.com>
> Cc: edk2-devel@lists.01.org; Ard Biesheuvel <ard.biesheuvel@linaro.org>;
> Michael D Kinney <michael.d.kinney@intel.com>
> Subject: Re: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc
> Dxe Driver
> 
> Hi Chris,
> 
> On Tue, Jul 17, 2018 at 02:05:42AM +0000, Chris Co wrote:
> > This SdMmc driver adds support to boot Windows from SD and eMMC.
> > It implements RPMB protocol support for eMMC, unique device path
> > creation for each slot on the SD bus, high speed modes, eMMC bus width
> > auto-detection, and support for high capacity SDXC cards.
> >
> > Derived from: EmbeddedPkg\Universal\MmcDxe
> 
> Hmm, I'm already slightly unhappy that we have duplication between
> EmbeddedPkg and MdeModulePkg (not to mention the extra fork for
> Marvell's XenonDxe).
> 
> I'm obviously keen for the added functionality to be available to more
> platforms. Is there any way for this support to be added into either the
> EmbeddedPkg or the MdeModulePkg driver?
> 

Understood - from talking with the other developers, we duplicated since we didn't know if these changes would be desired in edk2 core.  As part of the review, do let me know if changes would be better placed in edk2 core instead of platform.  I will be happy to refactor and submit patches to edk2 core.

Chris

> (Deferring comments on specific content.)
> 
> /
>     Leif
> 


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

* Re: [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library
  2018-08-01  9:39       ` Leif Lindholm
@ 2018-08-02  1:27         ` Chris Co
  2018-08-02 11:22           ` Leif Lindholm
  0 siblings, 1 reply; 13+ messages in thread
From: Chris Co @ 2018-08-02  1:27 UTC (permalink / raw)
  To: Leif Lindholm, Ard Biesheuvel; +Cc: edk2-devel@lists.01.org, Michael D Kinney



> -----Original Message-----
> From: Leif Lindholm <leif.lindholm@linaro.org>
> Sent: Wednesday, August 1, 2018 2:39 AM
> To: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Cc: Chris Co <Christopher.Co@microsoft.com>; edk2-devel@lists.01.org;
> Michael D Kinney <michael.d.kinney@intel.com>
> Subject: Re: [PATCH edk2-platforms 3/3] Platform/Microsoft: Add
> Lauterbach debug library
> 
> On Tue, Jul 31, 2018 at 10:59:22PM +0200, Ard Biesheuvel wrote:
> > On 31 July 2018 at 22:56, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> > > On Tue, Jul 17, 2018 at 02:05:45AM +0000, Chris Co wrote:
> > >> This debug library provides support for importing symbols to debug
> > >> using Lauterbach.
> > >>
> > >> Derived from: ArmPkg\Library\DebugPeCoffExtraActionLib
> > >
> > > I'm not seeing any difference between this one and the original
> > > other than the addition of the Microsoft copyright statement and
> > > updating of the debug printouts to modern style.
> > >
> > > I would be happy to take this as a patch to the original, but I
> > > don't see what benefit this copy brings. What prevents you from
> > > using the original?
> >
> > The 'data.load.elf' statement in
> > PeCoffLoaderRelocateImageExtraAction() is particular to Lauterbach
> 
> Oh, right.
> 
> That (original) code badly needs reformatting.
> 
> Still, if that's the only difference - and in a debug printout, why fork the
> module?
> 
> If there is a way to identify which debugger is being used, use that.
> If not, dump all the possible strings.
> 

Currently I didn't find a way to identify the debugger being used.  Default behavior of the original code assumes ARM platforms use DS5 debugger.  I could introduce a PCD or compile flag so the developer can indicate DS5 vs Lauterbach debugger and key the debug print off of that.
Regarding dumping all possible strings, I am not sure exactly how the DS5 output string is being used.  i.e. does the DS5 software receive the serial info directly?  If so, does it expect to see a specific format?  Is the software resilient enough that it can handle the Lauterbach spew on the same channel?

> We really don't want a situation where you need to hard-code which
> debugger you are using for a specific platform. And even if that is
> unavoidable, it needs to live in the main edk2 repository.
> 

Agreed

> /
>     Leif




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

* Re: [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library
  2018-08-02  1:27         ` Chris Co
@ 2018-08-02 11:22           ` Leif Lindholm
  0 siblings, 0 replies; 13+ messages in thread
From: Leif Lindholm @ 2018-08-02 11:22 UTC (permalink / raw)
  To: Chris Co; +Cc: Ard Biesheuvel, edk2-devel@lists.01.org, Michael D Kinney

On Thu, Aug 02, 2018 at 01:27:16AM +0000, Chris Co wrote:
> > > The 'data.load.elf' statement in
> > > PeCoffLoaderRelocateImageExtraAction() is particular to Lauterbach
> > 
> > Oh, right.
> > 
> > That (original) code badly needs reformatting.
> > 
> > Still, if that's the only difference - and in a debug printout, why fork the
> > module?
> > 
> > If there is a way to identify which debugger is being used, use that.
> > If not, dump all the possible strings.
> 
> Currently I didn't find a way to identify the debugger being used.

Well, it was worth a shot.

> Default behavior of the original code assumes ARM platforms use DS5
> debugger.  I could introduce a PCD or compile flag so the developer
> can indicate DS5 vs Lauterbach debugger and key the debug print off
> of that.

That would certainly be preferable over keeping a separate copy.
If we find a way to determine dynamically, that would be better.

Maybe it could even be worth to have a dynamic pcd and a menu setting,
defaulting to just printing module names and addresses/sizes if no
specific debugger has been selected? (Where the default could be
platform-specific.)

I have some theory about adding information to qemu fw_cfg to let EDK2
know it's being debugged, but clearly that won't help real platforms.

> Regarding dumping all possible strings, I am not sure exactly how
> the DS5 output string is being used.  i.e. does the DS5 software
> receive the serial info directly?  If so, does it expect to see a
> specific format?  Is the software resilient enough that it can
> handle the Lauterbach spew on the same channel?

So, this predates my involvement with edk2 - but I think it was just
added so you could copy/paste the command line needed to get symbols
in your debugger for a specific file.
(I will note here that the DS5 syntax is also suspiciously like GDB
syntax.)

/
    Leif


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

* Re: [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver
  2018-08-02  0:05     ` Chris Co
@ 2018-08-02 11:38       ` Leif Lindholm
  0 siblings, 0 replies; 13+ messages in thread
From: Leif Lindholm @ 2018-08-02 11:38 UTC (permalink / raw)
  To: Chris Co; +Cc: edk2-devel@lists.01.org, Ard Biesheuvel, Michael D Kinney

On Thu, Aug 02, 2018 at 12:05:38AM +0000, Chris Co wrote:
> > Hmm, I'm already slightly unhappy that we have duplication between
> > EmbeddedPkg and MdeModulePkg (not to mention the extra fork for
> > Marvell's XenonDxe).
> > 
> > I'm obviously keen for the added functionality to be available to more
> > platforms. Is there any way for this support to be added into either the
> > EmbeddedPkg or the MdeModulePkg driver?
> 
> Understood - from talking with the other developers, we duplicated
> since we didn't know if these changes would be desired in edk2 core.
> As part of the review, do let me know if changes would be better
> placed in edk2 core instead of platform.

EDK2 has a history of copy-and-modify rather than refactoring code to
fit multiple cases. I am very strongly pushing for a shift towards the
latter.

Also, since we know there are more consumers than can be found in the
public trees, my threshold for at what point it's useful to add new
functionality in the core is very low.

Particularly for Sd/(e)Mmc, my goal is to integrate the EmbeddedPkg
and MdeModulePkg drivers back together at some point.

> I will be happy to refactor and submit patches to edk2 core.

Thanks!

/
    Leif


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

end of thread, other threads:[~2018-08-02 11:38 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-07-17  2:05 [PATCH edk2-platforms 0/3] Add Platform-Generic Packages to support Windows IoT Core Chris Co
2018-07-17  2:05 ` [PATCH edk2-platforms 1/3] Platform/Microsoft: Add SdMmc Dxe Driver Chris Co
2018-07-31 20:33   ` Leif Lindholm
2018-08-02  0:05     ` Chris Co
2018-08-02 11:38       ` Leif Lindholm
2018-07-17  2:05 ` [PATCH edk2-platforms 2/3] Platform/Microsoft: Add MsPkg Chris Co
2018-07-31 20:38   ` Leif Lindholm
2018-07-17  2:05 ` [PATCH edk2-platforms 3/3] Platform/Microsoft: Add Lauterbach debug library Chris Co
2018-07-31 20:56   ` Leif Lindholm
2018-07-31 20:59     ` Ard Biesheuvel
2018-08-01  9:39       ` Leif Lindholm
2018-08-02  1:27         ` Chris Co
2018-08-02 11:22           ` Leif Lindholm

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