diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/AArch64/ArchPrePi.c b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/AArch64/ArchPrePi.c
new file mode 100644
index 000000000000..217986107e44
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/AArch64/ArchPrePi.c
@@ -0,0 +1,33 @@
+/** @file
+*
+*  Copyright (c) 2011-2013, 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 "PrePi.h"
+
+#include <Chipset/AArch64.h>
+
+VOID
+ArchInitialize (
+  VOID
+  )
+{
+  // Enable Floating Point
+  if (FixedPcdGet32 (PcdVFPEnabled)) {
+    ArmEnableVFP ();
+  }
+
+  if (ArmReadCurrentEL () == AARCH64_EL2) {
+    // Trap General Exceptions. All exceptions that would be routed to EL1 are routed to EL2
+    ArmWriteHcr (ARM_HCR_TGE);
+  }
+}
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/AArch64/ModuleEntryPoint.S b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/AArch64/ModuleEntryPoint.S
new file mode 100644
index 000000000000..568d0086d662
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/AArch64/ModuleEntryPoint.S
@@ -0,0 +1,180 @@
+//
+//  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+//  Copyright (c) 2015, Linaro 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 <AsmMacroIoLibV8.h>
+#include <Base.h>
+#include <Library/PcdLib.h>
+#include <AutoGen.h>
+
+.text
+.align 3
+
+GCC_ASM_IMPORT(ArmPlatformIsPrimaryCore)
+GCC_ASM_IMPORT(ArmReadMpidr)
+GCC_ASM_IMPORT(ArmPlatformPeiBootAction)
+GCC_ASM_IMPORT(ArmPlatformStackSet)
+GCC_ASM_EXPORT(_ModuleEntryPoint)
+
+StartupAddr:        .8byte ASM_PFX(CEntryPoint)
+
+ASM_PFX(_ModuleEntryPoint):
+  //
+  // We are built as a ET_DYN PIE executable, so we need to process all
+  // relative relocations regardless of whether or not we are executing from
+  // the same offset we were linked at. This is only possible if we are
+  // running from RAM.
+  //
+  adr   x8, __reloc_base
+  adr   x9, __reloc_start
+  adr   x10, __reloc_end
+
+.Lreloc_loop:
+  cmp   x9, x10
+  bhs   .Lreloc_done
+
+  //
+  // AArch64 uses the ELF64 RELA format, which means each entry in the
+  // relocation table consists of
+  //
+  //   UINT64 offset          : the relative offset of the value that needs to
+  //                            be relocated
+  //   UINT64 info            : relocation type and symbol index (the latter is
+  //                            not used for R_AARCH64_RELATIVE relocations)
+  //   UINT64 addend          : value to be added to the value being relocated
+  //
+  ldp   x11, x12, [x9], #24   // read offset into x11 and info into x12
+  cmp   x12, #0x403           // check info == R_AARCH64_RELATIVE?
+  bne   .Lreloc_loop          // not a relative relocation? then skip
+
+  ldr   x12, [x9, #-8]        // read addend into x12
+  add   x12, x12, x8          // add reloc base to addend to get relocated value
+  str   x12, [x11, x8]        // write relocated value at offset
+  b     .Lreloc_loop
+.Lreloc_done:
+
+  // Do early platform specific actions
+  bl    ASM_PFX(ArmPlatformPeiBootAction)
+
+  // Get ID of this CPU in Multicore system
+  bl    ASM_PFX(ArmReadMpidr)
+  // Keep a copy of the MpId register value
+  mov   x10, x0
+
+// Check if we can install the stack at the top of the System Memory or if we need
+// to install the stacks at the bottom of the Firmware Device (case the FD is located
+// at the top of the DRAM)
+_SetupStackPosition:
+  // Compute Top of System Memory
+  ldr   x1, PcdGet64 (PcdSystemMemoryBase)
+  ldr   x2, PcdGet64 (PcdSystemMemorySize)
+  sub   x2, x2, #1
+  add   x1, x1, x2      // x1 = SystemMemoryTop = PcdSystemMemoryBase + PcdSystemMemorySize
+
+  // Calculate Top of the Firmware Device
+  ldr   x2, PcdGet64 (PcdFdBaseAddress)
+  ldr   w3, PcdGet32 (PcdFdSize)
+  sub   x3, x3, #1
+  add   x3, x3, x2      // x3 = FdTop = PcdFdBaseAddress + PcdFdSize
+
+  // UEFI Memory Size (stacks are allocated in this region)
+  LoadConstantToReg (FixedPcdGet32(PcdSystemMemoryUefiRegionSize), x4)
+
+  //
+  // Reserve the memory for the UEFI region (contain stacks on its top)
+  //
+
+  // Calculate how much space there is between the top of the Firmware and the Top of the System Memory
+  subs  x0, x1, x3   // x0 = SystemMemoryTop - FdTop
+  b.mi  _SetupStack  // Jump if negative (FdTop > SystemMemoryTop). Case when the PrePi is in XIP memory outside of the DRAM
+  cmp   x0, x4
+  b.ge  _SetupStack
+
+  // Case the top of stacks is the FdBaseAddress
+  mov   x1, x2
+
+_SetupStack:
+  // x1 contains the top of the stack (and the UEFI Memory)
+
+  // Because the 'push' instruction is equivalent to 'stmdb' (decrement before), we need to increment
+  // one to the top of the stack. We check if incrementing one does not overflow (case of DRAM at the
+  // top of the memory space)
+  adds  x11, x1, #1
+  b.cs  _SetupOverflowStack
+
+_SetupAlignedStack:
+  mov   x1, x11
+  b     _GetBaseUefiMemory
+
+_SetupOverflowStack:
+  // Case memory at the top of the address space. Ensure the top of the stack is EFI_PAGE_SIZE
+  // aligned (4KB)
+  LoadConstantToReg (EFI_PAGE_MASK, x11)
+  and   x11, x11, x1
+  sub   x1, x1, x11
+
+_GetBaseUefiMemory:
+  // Calculate the Base of the UEFI Memory
+  sub   x11, x1, x4
+
+_GetStackBase:
+  // r1 = The top of the Mpcore Stacks
+  // Stack for the primary core = PrimaryCoreStack
+  LoadConstantToReg (FixedPcdGet32(PcdCPUCorePrimaryStackSize), x2)
+  sub   x12, x1, x2
+
+  // Stack for the secondary core = Number of Cores - 1
+  LoadConstantToReg (FixedPcdGet32(PcdCoreCount), x0)
+  sub   x0, x0, #1
+  LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecondaryStackSize), x1)
+  mul   x1, x1, x0
+  sub   x12, x12, x1
+
+  // x12 = The base of the MpCore Stacks (primary stack & secondary stacks)
+  mov   x0, x12
+  mov   x1, x10
+  //ArmPlatformStackSet(StackBase, MpId, PrimaryStackSize, SecondaryStackSize)
+  LoadConstantToReg (FixedPcdGet32(PcdCPUCorePrimaryStackSize), x2)
+  LoadConstantToReg (FixedPcdGet32(PcdCPUCoreSecondaryStackSize), x3)
+  bl    ASM_PFX(ArmPlatformStackSet)
+
+  // Is it the Primary Core ?
+  mov   x0, x10
+  bl    ASM_PFX(ArmPlatformIsPrimaryCore)
+  cmp   x0, #1
+  bne   _PrepareArguments
+
+_ReserveGlobalVariable:
+  LoadConstantToReg (FixedPcdGet32(PcdPeiGlobalVariableSize), x0)
+  // InitializePrimaryStack($GlobalVariableSize, $Tmp1, $Tmp2)
+  InitializePrimaryStack(x0, x1, x2)
+
+_PrepareArguments:
+  mov   x0, x10
+  mov   x1, x11
+  mov   x2, x12
+  mov   x3, sp
+
+  // Move sec startup address into a data register
+  // Ensure we're jumping to FV version of the code (not boot remapped alias)
+  ldr   x4, StartupAddr
+
+  // Jump to PrePiCore C code
+  //    x0 = MpId
+  //    x1 = UefiMemoryBase
+  //    x2 = StacksBase
+  //    x3 = GlobalVariableBase
+  blr   x4
+
+_NeverReturn:
+  b _NeverReturn
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
new file mode 100755
index 000000000000..86cf870b79ac
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf
@@ -0,0 +1,108 @@
+#/** @file
+#
+#  Copyright (c) 2011-2014, ARM Ltd. All rights reserved.<BR>
+#  Copyright (c) 2015, Linaro Ltd. 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                      = ArmVirtPrePiUniCoreRelocatable
+  FILE_GUID                      = f7d9fd14-9335-4389-80c5-334d6abfcced
+  MODULE_TYPE                    = SEC
+  VALID_ARCHITECTURES            = AARCH64
+  VERSION_STRING                 = 1.0
+
+[Sources]
+  PrePi.c
+
+[Sources.AArch64]
+  AArch64/ArchPrePi.c
+  AArch64/ModuleEntryPoint.S
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationPkg.dec
+  IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  ArmLib
+  IoLib
+  TimerLib
+  SerialPortLib
+  ExtractGuidedSectionLib
+  LzmaDecompressLib
+  PeCoffGetEntryPointLib
+  PrePiLib
+  ArmPlatformLib
+  ArmPlatformStackLib
+  MemoryAllocationLib
+  HobLib
+  PrePiHobListPointerLib
+  PlatformPeiLib
+  MemoryInitPeiLib
+
+[Ppis]
+  gArmMpCoreInfoPpiGuid
+
+[Guids]
+  gArmGlobalVariableGuid
+  gArmMpCoreInfoGuid
+
+[FeaturePcd]
+  gEmbeddedTokenSpaceGuid.PcdPrePiProduceMemoryTypeInformationHob
+  gArmPlatformTokenSpaceGuid.PcdSendSgiToBringUpSecondaryCores
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString
+
+  gArmTokenSpaceGuid.PcdVFPEnabled
+
+  gArmTokenSpaceGuid.PcdFdSize
+  gArmTokenSpaceGuid.PcdFvSize
+
+  gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize
+  gArmPlatformTokenSpaceGuid.PcdCPUCoreSecondaryStackSize
+
+  gArmPlatformTokenSpaceGuid.PcdPeiGlobalVariableSize
+
+  gArmPlatformTokenSpaceGuid.PcdSystemMemoryUefiRegionSize
+
+  gArmPlatformTokenSpaceGuid.PcdCoreCount
+
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize
+  gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
+
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIReclaimMemory
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiACPIMemoryNVS
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiReservedMemoryType
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesData
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesCode
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiBootServicesData
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderCode
+  gEmbeddedTokenSpaceGuid.PcdMemoryTypeEfiLoaderData
+
+[Pcd]
+  gArmTokenSpaceGuid.PcdSystemMemoryBase
+  gArmTokenSpaceGuid.PcdSystemMemorySize
+  gArmVirtualizationTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+  gArmTokenSpaceGuid.PcdFdBaseAddress
+  gArmTokenSpaceGuid.PcdFvBaseAddress
+
+[BuildOptions]
+  GCC:*_*_AARCH64_DLINK_FLAGS = -pie -T $(MODULE_DIR)/Scripts/PrePi-PIE.lds
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/LzmaDecompress.h b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/LzmaDecompress.h
new file mode 100644
index 000000000000..a79ff343d231
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/LzmaDecompress.h
@@ -0,0 +1,103 @@
+/** @file
+  LZMA Decompress Library header file
+
+  Copyright (c) 2006 - 2010, Intel 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.
+
+**/
+
+#ifndef __LZMA_DECOMPRESS_H___
+#define __LZMA_DECOMPRESS_H___
+
+/**
+  Examines a GUIDed section and returns the size of the decoded buffer and the
+  size of an scratch buffer required to actually decode the data in a GUIDed section.
+
+  Examines a GUIDed section specified by InputSection.
+  If GUID for InputSection does not match the GUID that this handler supports,
+  then RETURN_UNSUPPORTED is returned.
+  If the required information can not be retrieved from InputSection,
+  then RETURN_INVALID_PARAMETER is returned.
+  If the GUID of InputSection does match the GUID that this handler supports,
+  then the size required to hold the decoded buffer is returned in OututBufferSize,
+  the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field
+  from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute.
+
+  If InputSection is NULL, then ASSERT().
+  If OutputBufferSize is NULL, then ASSERT().
+  If ScratchBufferSize is NULL, then ASSERT().
+  If SectionAttribute is NULL, then ASSERT().
+
+
+  @param[in]  InputSection       A pointer to a GUIDed section of an FFS formatted file.
+  @param[out] OutputBufferSize   A pointer to the size, in bytes, of an output buffer required
+                                 if the buffer specified by InputSection were decoded.
+  @param[out] ScratchBufferSize  A pointer to the size, in bytes, required as scratch space
+                                 if the buffer specified by InputSection were decoded.
+  @param[out] SectionAttribute   A pointer to the attributes of the GUIDed section. See the Attributes
+                                 field of EFI_GUID_DEFINED_SECTION in the PI Specification.
+
+  @retval  RETURN_SUCCESS            The information about InputSection was returned.
+  @retval  RETURN_UNSUPPORTED        The section specified by InputSection does not match the GUID this handler supports.
+  @retval  RETURN_INVALID_PARAMETER  The information can not be retrieved from the section specified by InputSection.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaGuidedSectionGetInfo (
+  IN  CONST VOID  *InputSection,
+  OUT UINT32      *OutputBufferSize,
+  OUT UINT32      *ScratchBufferSize,
+  OUT UINT16      *SectionAttribute
+  );
+
+/**
+  Decompress a LZAM compressed GUIDed section into a caller allocated output buffer.
+
+  Decodes the GUIDed section specified by InputSection.
+  If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned.
+  If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned.
+  If the GUID of InputSection does match the GUID that this handler supports, then InputSection
+  is decoded into the buffer specified by OutputBuffer and the authentication status of this
+  decode operation is returned in AuthenticationStatus.  If the decoded buffer is identical to the
+  data in InputSection, then OutputBuffer is set to point at the data in InputSection.  Otherwise,
+  the decoded data will be placed in caller allocated buffer specified by OutputBuffer.
+
+  If InputSection is NULL, then ASSERT().
+  If OutputBuffer is NULL, then ASSERT().
+  If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
+  If AuthenticationStatus is NULL, then ASSERT().
+
+
+  @param[in]  InputSection  A pointer to a GUIDed section of an FFS formatted file.
+  @param[out] OutputBuffer  A pointer to a buffer that contains the result of a decode operation.
+  @param[out] ScratchBuffer A caller allocated buffer that may be required by this function
+                            as a scratch buffer to perform the decode operation.
+  @param[out] AuthenticationStatus
+                            A pointer to the authentication status of the decoded output buffer.
+                            See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+                            section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must
+                            never be set by this handler.
+
+  @retval  RETURN_SUCCESS            The buffer specified by InputSection was decoded.
+  @retval  RETURN_UNSUPPORTED        The section specified by InputSection does not match the GUID this handler supports.
+  @retval  RETURN_INVALID_PARAMETER  The section specified by InputSection can not be decoded.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaGuidedSectionExtraction (
+  IN CONST  VOID    *InputSection,
+  OUT       VOID    **OutputBuffer,
+  OUT       VOID    *ScratchBuffer,        OPTIONAL
+  OUT       UINT32  *AuthenticationStatus
+  );
+
+#endif // __LZMADECOMPRESS_H__
+
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/PrePi.c b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/PrePi.c
new file mode 100755
index 000000000000..0772805890f2
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/PrePi.c
@@ -0,0 +1,203 @@
+/** @file
+*
+*  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 <PiPei.h>
+
+#include <Library/PrePiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PrePiHobListPointerLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PerformanceLib.h>
+
+#include <Ppi/GuidedSectionExtraction.h>
+#include <Ppi/ArmMpCoreInfo.h>
+#include <Guid/LzmaDecompress.h>
+#include <Guid/ArmGlobalVariableHob.h>
+
+#include "PrePi.h"
+#include "LzmaDecompress.h"
+
+// Not used when PrePi in run in XIP mode
+UINTN mGlobalVariableBase = 0;
+
+EFI_STATUS
+EFIAPI
+ExtractGuidedSectionLibConstructor (
+  VOID
+  );
+
+EFI_STATUS
+EFIAPI
+LzmaDecompressLibConstructor (
+  VOID
+  );
+
+VOID
+EFIAPI
+BuildGlobalVariableHob (
+  IN EFI_PHYSICAL_ADDRESS         GlobalVariableBase,
+  IN UINT32                       GlobalVariableSize
+  )
+{
+  ARM_HOB_GLOBAL_VARIABLE  *Hob;
+
+  Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, sizeof (ARM_HOB_GLOBAL_VARIABLE));
+  ASSERT(Hob != NULL);
+
+  CopyGuid (&(Hob->Header.Name), &gArmGlobalVariableGuid);
+  Hob->GlobalVariableBase = GlobalVariableBase;
+  Hob->GlobalVariableSize = GlobalVariableSize;
+}
+
+EFI_STATUS
+GetPlatformPpi (
+  IN  EFI_GUID  *PpiGuid,
+  OUT VOID      **Ppi
+  )
+{
+  UINTN                   PpiListSize;
+  UINTN                   PpiListCount;
+  EFI_PEI_PPI_DESCRIPTOR  *PpiList;
+  UINTN                   Index;
+
+  PpiListSize = 0;
+  ArmPlatformGetPlatformPpiList (&PpiListSize, &PpiList);
+  PpiListCount = PpiListSize / sizeof(EFI_PEI_PPI_DESCRIPTOR);
+  for (Index = 0; Index < PpiListCount; Index++, PpiList++) {
+    if (CompareGuid (PpiList->Guid, PpiGuid) == TRUE) {
+      *Ppi = PpiList->Ppi;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_NOT_FOUND;
+}
+
+VOID
+PrePiMain (
+  IN  UINTN                     UefiMemoryBase,
+  IN  UINTN                     StacksBase,
+  IN  UINTN                     GlobalVariableBase,
+  IN  UINT64                    StartTimeStamp
+  )
+{
+  EFI_HOB_HANDOFF_INFO_TABLE*   HobList;
+  EFI_STATUS                    Status;
+  CHAR8                         Buffer[100];
+  UINTN                         CharCount;
+  UINTN                         StacksSize;
+
+  // Initialize the architecture specific bits
+  ArchInitialize ();
+
+  // Initialize the Serial Port
+  SerialPortInitialize ();
+  CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"UEFI firmware (version %s built at %a on %a)\n\r",
+    (CHAR16*)PcdGetPtr(PcdFirmwareVersionString), __TIME__, __DATE__);
+  SerialPortWrite ((UINT8 *) Buffer, CharCount);
+
+  // Declare the PI/UEFI memory region
+  HobList = HobConstructor (
+    (VOID*)UefiMemoryBase,
+    FixedPcdGet32 (PcdSystemMemoryUefiRegionSize),
+    (VOID*)UefiMemoryBase,
+    (VOID*)StacksBase  // The top of the UEFI Memory is reserved for the stacks
+    );
+  PrePeiSetHobList (HobList);
+
+  // Initialize MMU and Memory HOBs (Resource Descriptor HOBs)
+  Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize));
+  ASSERT_EFI_ERROR (Status);
+
+  // Create the Stacks HOB (reserve the memory for all stacks)
+  StacksSize = PcdGet32 (PcdCPUCorePrimaryStackSize);
+  BuildStackHob (StacksBase, StacksSize);
+
+  // Declare the Global Variable HOB
+  BuildGlobalVariableHob (GlobalVariableBase, FixedPcdGet32 (PcdPeiGlobalVariableSize));
+
+  //TODO: Call CpuPei as a library
+  BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize));
+
+  // Set the Boot Mode
+  SetBootMode (ArmPlatformGetBootMode ());
+
+  // Initialize Platform HOBs (CpuHob and FvHob)
+  Status = PlatformPeim ();
+  ASSERT_EFI_ERROR (Status);
+
+  // Now, the HOB List has been initialized, we can register performance information
+  PERF_START (NULL, "PEI", NULL, StartTimeStamp);
+
+  // SEC phase needs to run library constructors by hand.
+  ExtractGuidedSectionLibConstructor ();
+  LzmaDecompressLibConstructor ();
+
+  // Build HOBs to pass up our version of stuff the DXE Core needs to save space
+  BuildPeCoffLoaderHob ();
+  BuildExtractSectionHob (
+    &gLzmaCustomDecompressGuid,
+    LzmaGuidedSectionGetInfo,
+    LzmaGuidedSectionExtraction
+    );
+
+  // Assume the FV that contains the SEC (our code) also contains a compressed FV.
+  Status = DecompressFirstFv ();
+  ASSERT_EFI_ERROR (Status);
+
+  // Load the DXE Core and transfer control to it
+  Status = LoadDxeCoreFromFv (NULL, 0);
+  ASSERT_EFI_ERROR (Status);
+}
+
+VOID
+CEntryPoint (
+  IN  UINTN                     MpId,
+  IN  UINTN                     UefiMemoryBase,
+  IN  UINTN                     StacksBase,
+  IN  UINTN                     GlobalVariableBase
+  )
+{
+  UINT64   StartTimeStamp;
+
+  // Initialize the platform specific controllers
+  ArmPlatformInitialize (MpId);
+
+  if (PerformanceMeasurementEnabled ()) {
+    // Initialize the Timer Library to setup the Timer HW controller
+    TimerConstructor ();
+    // We cannot call yet the PerformanceLib because the HOB List has not been initialized
+    StartTimeStamp = GetPerformanceCounter ();
+  } else {
+    StartTimeStamp = 0;
+  }
+
+  // Data Cache enabled on Primary core when MMU is enabled.
+  ArmDisableDataCache ();
+  // Invalidate Data cache
+  ArmInvalidateDataCache ();
+  // Invalidate instruction cache
+  ArmInvalidateInstructionCache ();
+  // Enable Instruction Caches on all cores.
+  ArmEnableInstructionCache ();
+
+  // Define the Global Variable region
+  mGlobalVariableBase = GlobalVariableBase;
+
+  PrePiMain (UefiMemoryBase, StacksBase, GlobalVariableBase, StartTimeStamp);
+
+  // DXE Core should always load and never return
+  ASSERT (FALSE);
+}
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/PrePi.h b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/PrePi.h
new file mode 100644
index 000000000000..517429fab9a4
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/PrePi.h
@@ -0,0 +1,77 @@
+/** @file
+*
+*  Copyright (c) 2011-2012, 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 _PREPI_H_
+#define _PREPI_H_
+
+#include <PiPei.h>
+
+#include <Library/PcdLib.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HobLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/ArmPlatformLib.h>
+
+#define SerialPrint(txt)  SerialPortWrite (txt, AsciiStrLen(txt)+1);
+
+RETURN_STATUS
+EFIAPI
+TimerConstructor (
+  VOID
+  );
+
+VOID
+PrePiMain (
+  IN  UINTN                     UefiMemoryBase,
+  IN  UINTN                     StacksBase,
+  IN  UINTN                     GlobalVariableBase,
+  IN  UINT64                    StartTimeStamp
+  );
+
+EFI_STATUS
+EFIAPI
+MemoryPeim (
+  IN EFI_PHYSICAL_ADDRESS       UefiMemoryBase,
+  IN UINT64                     UefiMemorySize
+  );
+
+EFI_STATUS
+EFIAPI
+PlatformPeim (
+  VOID
+  );
+
+// Either implemented by PrePiLib or by MemoryInitPei
+VOID
+BuildMemoryTypeInformationHob (
+  VOID
+  );
+
+EFI_STATUS
+GetPlatformPpi (
+  IN  EFI_GUID  *PpiGuid,
+  OUT VOID      **Ppi
+  );
+
+// Initialize the Architecture specific controllers
+VOID
+ArchInitialize (
+  VOID
+  );
+
+#endif /* _PREPI_H_ */
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/Scripts/PrePi-PIE.lds b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/Scripts/PrePi-PIE.lds
new file mode 100644
index 000000000000..32af0696aa6b
--- /dev/null
+++ b/ArmPlatformPkg/ArmVirtualizationPkg/PrePi/Scripts/PrePi-PIE.lds
@@ -0,0 +1,42 @@
+#/** @file
+#
+#  Copyright (c) 2015, Linaro Ltd. 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.
+#
+#**/
+
+SECTIONS
+{
+  .text 0x0 : {
+    PROVIDE(__reloc_base = .);
+
+    *(.text .text*)
+    *(.got .got*)
+    *(.rodata .rodata*)
+    *(.data .data*)
+
+    . = ALIGN(0x20);
+    PROVIDE(__reloc_start = .);
+    *(.rela .rela*)
+    PROVIDE(__reloc_end = .);
+  }
+  .bss ALIGN(0x20) : { *(.bss .bss*) }
+
+  /DISCARD/ : {
+    *(.note.GNU-stack)
+    *(.gnu_debuglink)
+    *(.interp)
+    *(.dynamic)
+    *(.dynsym)
+    *(.dynstr)
+    *(.hash)
+    *(.comment)
+  }
+}
