ArmVirtPkg: introduce new ArmQemuRelocatablePlatformLib
This introduces ArmQemuRelocatablePlatformLib, which started out as a straight copy of ArmXenRelocatablePlatformLib, but has been modified so that ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf can be used with QEMU as well as with Xen. It retains the self relocation and FDT parsing for the system memory, but uses the QEMU MMU layout. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Acked-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
		@@ -0,0 +1,157 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					#  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 <AsmMacroIoLibV8.h>
 | 
				
			||||||
 | 
					#include <Base.h>
 | 
				
			||||||
 | 
					#include <Library/ArmLib.h>
 | 
				
			||||||
 | 
					#include <Library/PcdLib.h>
 | 
				
			||||||
 | 
					#include <AutoGen.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.text
 | 
				
			||||||
 | 
					.align 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformPeiBootAction)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformIsPrimaryCore)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformGetPrimaryCoreMpId)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformGetCorePosition)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmGetPhysAddrTop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCore)
 | 
				
			||||||
 | 
					GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCoreMask)
 | 
				
			||||||
 | 
					GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.LArm64LinuxMagic:
 | 
				
			||||||
 | 
					  .byte   0x41, 0x52, 0x4d, 0x64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VOID
 | 
				
			||||||
 | 
					// ArmPlatformPeiBootAction (
 | 
				
			||||||
 | 
					//   VOID   *DeviceTreeBaseAddress,   // passed by loader in x0
 | 
				
			||||||
 | 
					//   VOID   *ImageBase                // passed by FDF trampoline in x1
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformPeiBootAction):
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // If we are booting from RAM using the Linux kernel boot protocol, x0 will
 | 
				
			||||||
 | 
					  // point to the DTB image in memory. Otherwise, use the default value defined
 | 
				
			||||||
 | 
					  // by the platform.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  cbnz  x0, 0f
 | 
				
			||||||
 | 
					  ldr   x0, PcdGet64 (PcdDeviceTreeInitialBaseAddress)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					0:mov   x29, x30            // preserve LR
 | 
				
			||||||
 | 
					  mov   x28, x0             // preserve DTB pointer
 | 
				
			||||||
 | 
					  mov   x27, x1             // preserve base of image pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // The base of the runtime image has been preserved in x1. Check whether
 | 
				
			||||||
 | 
					  // the expected magic number can be found in the header.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  ldr   w8, .LArm64LinuxMagic
 | 
				
			||||||
 | 
					  ldr   w9, [x1, #0x38]
 | 
				
			||||||
 | 
					  cmp   w8, w9
 | 
				
			||||||
 | 
					  bne   .Lout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // OK, so far so good. We have confirmed that we likely have a DTB and are
 | 
				
			||||||
 | 
					  // booting via the arm64 Linux boot protocol. Update the base-of-image PCD
 | 
				
			||||||
 | 
					  // to the actual relocated value, and add the shift of PcdFdBaseAddress to
 | 
				
			||||||
 | 
					  // PcdFvBaseAddress as well
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  adr   x8, PcdGet64 (PcdFdBaseAddress)
 | 
				
			||||||
 | 
					  adr   x9, PcdGet64 (PcdFvBaseAddress)
 | 
				
			||||||
 | 
					  ldr   x6, [x8]
 | 
				
			||||||
 | 
					  ldr   x7, [x9]
 | 
				
			||||||
 | 
					  sub   x7, x7, x6
 | 
				
			||||||
 | 
					  add   x7, x7, x1
 | 
				
			||||||
 | 
					  str   x1, [x8]
 | 
				
			||||||
 | 
					  str   x7, [x9]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Discover the memory size and offset from the DTB, and record in the
 | 
				
			||||||
 | 
					  // respective PCDs. This will also return false if a corrupt DTB is
 | 
				
			||||||
 | 
					  // encountered. Since we are calling a C function, use the window at the
 | 
				
			||||||
 | 
					  // beginning of the FD image as a temp stack.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  adr   x1, PcdGet64 (PcdSystemMemorySize)
 | 
				
			||||||
 | 
					  adr   x2, PcdGet64 (PcdSystemMemoryBase)
 | 
				
			||||||
 | 
					  mov   sp, x7
 | 
				
			||||||
 | 
					  bl    FindMemnode
 | 
				
			||||||
 | 
					  cbz   x0, .Lout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Copy the DTB to the slack space right after the 64 byte arm64/Linux style
 | 
				
			||||||
 | 
					  // image header at the base of this image (defined in the FDF), and record the
 | 
				
			||||||
 | 
					  // pointer in PcdDeviceTreeInitialBaseAddress.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  adr   x8, PcdGet64 (PcdDeviceTreeInitialBaseAddress)
 | 
				
			||||||
 | 
					  add   x27, x27, #0x40
 | 
				
			||||||
 | 
					  str   x27, [x8]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mov   x0, x27
 | 
				
			||||||
 | 
					  mov   x1, x28
 | 
				
			||||||
 | 
					  bl    CopyFdt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Lout:
 | 
				
			||||||
 | 
					  ret    x29
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UINTN
 | 
				
			||||||
 | 
					//ArmPlatformGetPrimaryCoreMpId (
 | 
				
			||||||
 | 
					//  VOID
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformGetPrimaryCoreMpId):
 | 
				
			||||||
 | 
					  LoadConstantToReg (_gPcd_FixedAtBuild_PcdArmPrimaryCore, x0)
 | 
				
			||||||
 | 
					  ldrh   w0, [x0]
 | 
				
			||||||
 | 
					  ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UINTN
 | 
				
			||||||
 | 
					//ArmPlatformIsPrimaryCore (
 | 
				
			||||||
 | 
					//  IN UINTN MpId
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformIsPrimaryCore):
 | 
				
			||||||
 | 
					  mov   x0, #1
 | 
				
			||||||
 | 
					  ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UINTN
 | 
				
			||||||
 | 
					//ArmPlatformGetCorePosition (
 | 
				
			||||||
 | 
					//  IN UINTN MpId
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					// With this function: CorePos = (ClusterId * 4) + CoreId
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformGetCorePosition):
 | 
				
			||||||
 | 
					  and   x1, x0, #ARM_CORE_MASK
 | 
				
			||||||
 | 
					  and   x0, x0, #ARM_CLUSTER_MASK
 | 
				
			||||||
 | 
					  add   x0, x1, x0, LSR #6
 | 
				
			||||||
 | 
					  ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//EFI_PHYSICAL_ADDRESS
 | 
				
			||||||
 | 
					//GetPhysAddrTop (
 | 
				
			||||||
 | 
					//  VOID
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					ASM_PFX(ArmGetPhysAddrTop):
 | 
				
			||||||
 | 
					  mrs   x0, id_aa64mmfr0_el1
 | 
				
			||||||
 | 
					  adr   x1, .LPARanges
 | 
				
			||||||
 | 
					  and   x0, x0, #7
 | 
				
			||||||
 | 
					  ldrb  w1, [x1, x0]
 | 
				
			||||||
 | 
					  mov   x0, #1
 | 
				
			||||||
 | 
					  lsl   x0, x0, x1
 | 
				
			||||||
 | 
					  ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Bits 0..2 of the AA64MFR0_EL1 system register encode the size of the
 | 
				
			||||||
 | 
					// physical address space support on this CPU:
 | 
				
			||||||
 | 
					// 0 == 32 bits, 1 == 36 bits, etc etc
 | 
				
			||||||
 | 
					// 6 and 7 are reserved
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					.LPARanges:
 | 
				
			||||||
 | 
					  .byte 32, 36, 40, 42, 44, 48, -1, -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ASM_FUNCTION_REMOVE_IF_UNREFERENCED
 | 
				
			||||||
@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					#  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
 | 
				
			||||||
 | 
					#  Copyright (c) 2014, 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 <AsmMacroIoLib.h>
 | 
				
			||||||
 | 
					#include <Base.h>
 | 
				
			||||||
 | 
					#include <Library/ArmLib.h>
 | 
				
			||||||
 | 
					#include <Library/PcdLib.h>
 | 
				
			||||||
 | 
					#include <AutoGen.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.text
 | 
				
			||||||
 | 
					.align 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformPeiBootAction)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformIsPrimaryCore)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformGetPrimaryCoreMpId)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmPlatformGetCorePosition)
 | 
				
			||||||
 | 
					GCC_ASM_EXPORT(ArmGetPhysAddrTop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCore)
 | 
				
			||||||
 | 
					GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCoreMask)
 | 
				
			||||||
 | 
					GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.LArm32LinuxMagic:
 | 
				
			||||||
 | 
					  .byte   0x18, 0x28, 0x6f, 0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformPeiBootAction):
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // If we are booting from RAM using the Linux kernel boot protocol, r0 will
 | 
				
			||||||
 | 
					  // point to the DTB image in memory. Otherwise, use the default value defined
 | 
				
			||||||
 | 
					  // by the platform.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  teq   r0, #0
 | 
				
			||||||
 | 
					  bne   0f
 | 
				
			||||||
 | 
					  ldr   r0, =PcdGet64 (PcdDeviceTreeInitialBaseAddress)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					0:mov   r11, r14            // preserve LR
 | 
				
			||||||
 | 
					  mov   r10, r0             // preserve DTB pointer
 | 
				
			||||||
 | 
					  mov   r9, r1              // preserve base of image pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // The base of the runtime image has been preserved in r1. Check whether
 | 
				
			||||||
 | 
					  // the expected magic number can be found in the header.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  ldr   r8, .LArm32LinuxMagic
 | 
				
			||||||
 | 
					  ldr   r7, [r1, #0x24]
 | 
				
			||||||
 | 
					  cmp   r7, r8
 | 
				
			||||||
 | 
					  bne   .Lout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // OK, so far so good. We have confirmed that we likely have a DTB and are
 | 
				
			||||||
 | 
					  // booting via the ARM Linux boot protocol. Update the base-of-image PCD
 | 
				
			||||||
 | 
					  // to the actual relocated value, and add the shift of PcdFdBaseAddress to
 | 
				
			||||||
 | 
					  // PcdFvBaseAddress as well
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  ldr   r8, =PcdGet64 (PcdFdBaseAddress)
 | 
				
			||||||
 | 
					  ldr   r7, =PcdGet64 (PcdFvBaseAddress)
 | 
				
			||||||
 | 
					  ldr   r6, [r8]
 | 
				
			||||||
 | 
					  ldr   r5, [r7]
 | 
				
			||||||
 | 
					  sub   r5, r5, r6
 | 
				
			||||||
 | 
					  add   r5, r5, r1
 | 
				
			||||||
 | 
					  str   r1, [r8]
 | 
				
			||||||
 | 
					  str   r5, [r7]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Discover the memory size and offset from the DTB, and record in the
 | 
				
			||||||
 | 
					  // respective PCDs. This will also return false if a corrupt DTB is
 | 
				
			||||||
 | 
					  // encountered. Since we are calling a C function, use the window at the
 | 
				
			||||||
 | 
					  // beginning of the FD image as a temp stack.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  ldr   r1, =PcdGet64 (PcdSystemMemorySize)
 | 
				
			||||||
 | 
					  ldr   r2, =PcdGet64 (PcdSystemMemoryBase)
 | 
				
			||||||
 | 
					  mov   sp, r5
 | 
				
			||||||
 | 
					  bl    FindMemnode
 | 
				
			||||||
 | 
					  teq   r0, #0
 | 
				
			||||||
 | 
					  beq   .Lout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Copy the DTB to the slack space right after the 64 byte arm64/Linux style
 | 
				
			||||||
 | 
					  // image header at the base of this image (defined in the FDF), and record the
 | 
				
			||||||
 | 
					  // pointer in PcdDeviceTreeInitialBaseAddress.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  ldr   r8, =PcdGet64 (PcdDeviceTreeInitialBaseAddress)
 | 
				
			||||||
 | 
					  add   r9, r9, #0x40
 | 
				
			||||||
 | 
					  str   r9, [r8]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mov   r0, r9
 | 
				
			||||||
 | 
					  mov   r1, r10
 | 
				
			||||||
 | 
					  bl    CopyFdt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.Lout:
 | 
				
			||||||
 | 
					  bx    r11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UINTN
 | 
				
			||||||
 | 
					//ArmPlatformGetPrimaryCoreMpId (
 | 
				
			||||||
 | 
					//  VOID
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformGetPrimaryCoreMpId):
 | 
				
			||||||
 | 
					  LoadConstantToReg (_gPcd_FixedAtBuild_PcdArmPrimaryCore, r0)
 | 
				
			||||||
 | 
					  ldr    r0, [r0]
 | 
				
			||||||
 | 
					  bx     lr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UINTN
 | 
				
			||||||
 | 
					//ArmPlatformIsPrimaryCore (
 | 
				
			||||||
 | 
					//  IN UINTN MpId
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformIsPrimaryCore):
 | 
				
			||||||
 | 
					  mov   r0, #1
 | 
				
			||||||
 | 
					  bx    lr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//UINTN
 | 
				
			||||||
 | 
					//ArmPlatformGetCorePosition (
 | 
				
			||||||
 | 
					//  IN UINTN MpId
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					// With this function: CorePos = (ClusterId * 4) + CoreId
 | 
				
			||||||
 | 
					ASM_PFX(ArmPlatformGetCorePosition):
 | 
				
			||||||
 | 
					  and   r1, r0, #ARM_CORE_MASK
 | 
				
			||||||
 | 
					  and   r0, r0, #ARM_CLUSTER_MASK
 | 
				
			||||||
 | 
					  add   r0, r1, r0, LSR #6
 | 
				
			||||||
 | 
					  bx    lr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//EFI_PHYSICAL_ADDRESS
 | 
				
			||||||
 | 
					//GetPhysAddrTop (
 | 
				
			||||||
 | 
					//  VOID
 | 
				
			||||||
 | 
					//  );
 | 
				
			||||||
 | 
					ASM_PFX(ArmGetPhysAddrTop):
 | 
				
			||||||
 | 
					  mov   r0, #0x00000000
 | 
				
			||||||
 | 
					  mov   r1, #0x10000
 | 
				
			||||||
 | 
					  bx    lr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					#/* @file
 | 
				
			||||||
 | 
					#  Copyright (c) 2011-2015, ARM Limited. All rights reserved.
 | 
				
			||||||
 | 
					#  Copyright (c) 2014, 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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Defines]
 | 
				
			||||||
 | 
					  INF_VERSION                    = 0x00010005
 | 
				
			||||||
 | 
					  BASE_NAME                      = ArmXenRelocatablePlatformLib
 | 
				
			||||||
 | 
					  FILE_GUID                      = c8602718-4faa-4119-90ca-cae72509ac4c
 | 
				
			||||||
 | 
					  MODULE_TYPE                    = BASE
 | 
				
			||||||
 | 
					  VERSION_STRING                 = 1.0
 | 
				
			||||||
 | 
					  LIBRARY_CLASS                  = ArmPlatformLib|SEC PEIM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Packages]
 | 
				
			||||||
 | 
					  MdePkg/MdePkg.dec
 | 
				
			||||||
 | 
					  MdeModulePkg/MdeModulePkg.dec
 | 
				
			||||||
 | 
					  EmbeddedPkg/EmbeddedPkg.dec
 | 
				
			||||||
 | 
					  ArmPkg/ArmPkg.dec
 | 
				
			||||||
 | 
					  ArmPlatformPkg/ArmPlatformPkg.dec
 | 
				
			||||||
 | 
					  ArmVirtPkg/ArmVirtPkg.dec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[LibraryClasses]
 | 
				
			||||||
 | 
					  IoLib
 | 
				
			||||||
 | 
					  ArmLib
 | 
				
			||||||
 | 
					  PrintLib
 | 
				
			||||||
 | 
					  FdtLib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Sources.common]
 | 
				
			||||||
 | 
					  RelocatableVirt.c
 | 
				
			||||||
 | 
					  QemuVirtMem.c
 | 
				
			||||||
 | 
					  FdtParser.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Sources.AARCH64]
 | 
				
			||||||
 | 
					  AARCH64/RelocatableVirtHelper.S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Sources.ARM]
 | 
				
			||||||
 | 
					  ARM/RelocatableVirtHelper.S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[FeaturePcd]
 | 
				
			||||||
 | 
					  gEmbeddedTokenSpaceGuid.PcdCacheEnable
 | 
				
			||||||
 | 
					  gArmPlatformTokenSpaceGuid.PcdSystemMemoryInitializeInSec
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[PatchPcd]
 | 
				
			||||||
 | 
					  gArmVirtTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdFdBaseAddress
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdFvBaseAddress
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdSystemMemoryBase
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdSystemMemorySize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[FixedPcd]
 | 
				
			||||||
 | 
					  gArmPlatformTokenSpaceGuid.PcdCoreCount
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdArmPrimaryCoreMask
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdArmPrimaryCore
 | 
				
			||||||
 | 
					  gArmTokenSpaceGuid.PcdFdSize
 | 
				
			||||||
 | 
					  gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize
 | 
				
			||||||
							
								
								
									
										92
									
								
								ArmVirtPkg/Library/ArmQemuRelocatablePlatformLib/FdtParser.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								ArmVirtPkg/Library/ArmQemuRelocatablePlatformLib/FdtParser.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2015, Linaro Ltd. 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 <Include/libfdt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOLEAN
 | 
				
			||||||
 | 
					FindMemnode (
 | 
				
			||||||
 | 
					  IN  VOID    *DeviceTreeBlob,
 | 
				
			||||||
 | 
					  OUT UINT64  *SystemMemoryBase,
 | 
				
			||||||
 | 
					  OUT UINT64  *SystemMemorySize
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  INT32         MemoryNode;
 | 
				
			||||||
 | 
					  INT32         AddressCells;
 | 
				
			||||||
 | 
					  INT32         SizeCells;
 | 
				
			||||||
 | 
					  INT32         Length;
 | 
				
			||||||
 | 
					  CONST INT32   *Prop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (fdt_check_header (DeviceTreeBlob) != 0) {
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Look for a node called "memory" at the lowest level of the tree
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  MemoryNode = fdt_path_offset (DeviceTreeBlob, "/memory");
 | 
				
			||||||
 | 
					  if (MemoryNode <= 0) {
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Retrieve the #address-cells and #size-cells properties
 | 
				
			||||||
 | 
					  // from the root node, or use the default if not provided.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  AddressCells = 1;
 | 
				
			||||||
 | 
					  SizeCells = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Prop = fdt_getprop (DeviceTreeBlob, 0, "#address-cells", &Length);
 | 
				
			||||||
 | 
					  if (Length == 4) {
 | 
				
			||||||
 | 
					    AddressCells = fdt32_to_cpu (*Prop);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Prop = fdt_getprop (DeviceTreeBlob, 0, "#size-cells", &Length);
 | 
				
			||||||
 | 
					  if (Length == 4) {
 | 
				
			||||||
 | 
					    SizeCells = fdt32_to_cpu (*Prop);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Now find the 'reg' property of the /memory node, and read the first
 | 
				
			||||||
 | 
					  // range listed.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  Prop = fdt_getprop (DeviceTreeBlob, MemoryNode, "reg", &Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (Length < (AddressCells + SizeCells) * sizeof (INT32)) {
 | 
				
			||||||
 | 
					    return FALSE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (AddressCells == 1) {
 | 
				
			||||||
 | 
					    *SystemMemoryBase = fdt32_to_cpu (*Prop);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    *SystemMemoryBase = fdt64_to_cpu (*(UINT64 *)Prop);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  Prop += AddressCells;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (SizeCells == 1) {
 | 
				
			||||||
 | 
					    *SystemMemorySize = fdt32_to_cpu (*Prop);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    *SystemMemorySize = fdt64_to_cpu (*(UINT64 *)Prop);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VOID
 | 
				
			||||||
 | 
					CopyFdt (
 | 
				
			||||||
 | 
					  IN    VOID    *FdtDest,
 | 
				
			||||||
 | 
					  IN    VOID    *FdtSource
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  fdt_pack(FdtSource);
 | 
				
			||||||
 | 
					  CopyMem (FdtDest, FdtSource, fdt_totalsize (FdtSource));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								ArmVirtPkg/Library/ArmQemuRelocatablePlatformLib/QemuVirtMem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								ArmVirtPkg/Library/ArmQemuRelocatablePlatformLib/QemuVirtMem.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					/** @file
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*  Copyright (c) 2014, 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 <Library/ArmPlatformLib.h>
 | 
				
			||||||
 | 
					#include <Library/DebugLib.h>
 | 
				
			||||||
 | 
					#include <Library/BaseMemoryLib.h>
 | 
				
			||||||
 | 
					#include <Library/PcdLib.h>
 | 
				
			||||||
 | 
					#include <Library/IoLib.h>
 | 
				
			||||||
 | 
					#include <Library/MemoryAllocationLib.h>
 | 
				
			||||||
 | 
					#include <ArmPlatform.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Number of Virtual Memory Map Descriptors
 | 
				
			||||||
 | 
					#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS          5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DDR attributes
 | 
				
			||||||
 | 
					#define DDR_ATTRIBUTES_CACHED    ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
 | 
				
			||||||
 | 
					#define DDR_ATTRIBUTES_UNCACHED  ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EFI_PHYSICAL_ADDRESS
 | 
				
			||||||
 | 
					ArmGetPhysAddrTop (
 | 
				
			||||||
 | 
					  VOID
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  Return the Virtual Memory Map of your platform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
 | 
				
			||||||
 | 
					  on your platform.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @param[out]   VirtualMemoryMap    Array of ARM_MEMORY_REGION_DESCRIPTOR
 | 
				
			||||||
 | 
					                                    describing a Physical-to-Virtual Memory
 | 
				
			||||||
 | 
					                                    mapping. This array must be ended by a
 | 
				
			||||||
 | 
					                                    zero-filled entry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					VOID
 | 
				
			||||||
 | 
					ArmPlatformGetVirtualMemoryMap (
 | 
				
			||||||
 | 
					  IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  ARM_MEMORY_REGION_DESCRIPTOR  *VirtualMemoryTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT (VirtualMemoryMap != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  VirtualMemoryTable = AllocatePages (
 | 
				
			||||||
 | 
					                         EFI_SIZE_TO_PAGES (
 | 
				
			||||||
 | 
					                           sizeof (ARM_MEMORY_REGION_DESCRIPTOR)
 | 
				
			||||||
 | 
					                           * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
 | 
				
			||||||
 | 
					                           )
 | 
				
			||||||
 | 
					                         );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (VirtualMemoryTable == NULL) {
 | 
				
			||||||
 | 
					    DEBUG ((EFI_D_ERROR, "%a: Error: Failed AllocatePages()\n", __FUNCTION__));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // System DRAM
 | 
				
			||||||
 | 
					  VirtualMemoryTable[0].PhysicalBase = PcdGet64 (PcdSystemMemoryBase);
 | 
				
			||||||
 | 
					  VirtualMemoryTable[0].VirtualBase  = VirtualMemoryTable[0].PhysicalBase;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[0].Length       = PcdGet64 (PcdSystemMemorySize);
 | 
				
			||||||
 | 
					  VirtualMemoryTable[0].Attributes   = DDR_ATTRIBUTES_CACHED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DEBUG ((EFI_D_INFO, "%a: Dumping System DRAM Memory Map:\n"
 | 
				
			||||||
 | 
					      "\tPhysicalBase: 0x%lX\n"
 | 
				
			||||||
 | 
					      "\tVirtualBase: 0x%lX\n"
 | 
				
			||||||
 | 
					      "\tLength: 0x%lX\n",
 | 
				
			||||||
 | 
					      __FUNCTION__,
 | 
				
			||||||
 | 
					      VirtualMemoryTable[0].PhysicalBase,
 | 
				
			||||||
 | 
					      VirtualMemoryTable[0].VirtualBase,
 | 
				
			||||||
 | 
					      VirtualMemoryTable[0].Length));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Peripheral space before DRAM
 | 
				
			||||||
 | 
					  VirtualMemoryTable[1].PhysicalBase = 0x0;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[1].VirtualBase  = 0x0;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[1].Length       = VirtualMemoryTable[0].PhysicalBase;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[1].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Peripheral space after DRAM
 | 
				
			||||||
 | 
					  VirtualMemoryTable[2].PhysicalBase = VirtualMemoryTable[0].Length + VirtualMemoryTable[1].Length;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[2].VirtualBase  = VirtualMemoryTable[2].PhysicalBase;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[2].Length       = MIN (1ULL << FixedPcdGet8 (PcdPrePiCpuMemorySize),
 | 
				
			||||||
 | 
					                                         ArmGetPhysAddrTop ()) -
 | 
				
			||||||
 | 
					                                       VirtualMemoryTable[2].PhysicalBase;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[2].Attributes   = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Remap the FD region as normal executable memory
 | 
				
			||||||
 | 
					  VirtualMemoryTable[3].PhysicalBase = PcdGet64 (PcdFdBaseAddress);
 | 
				
			||||||
 | 
					  VirtualMemoryTable[3].VirtualBase  = VirtualMemoryTable[3].PhysicalBase;
 | 
				
			||||||
 | 
					  VirtualMemoryTable[3].Length       = FixedPcdGet32 (PcdFdSize);
 | 
				
			||||||
 | 
					  VirtualMemoryTable[3].Attributes   = DDR_ATTRIBUTES_CACHED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // End of Table
 | 
				
			||||||
 | 
					  ZeroMem (&VirtualMemoryTable[4], sizeof (ARM_MEMORY_REGION_DESCRIPTOR));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *VirtualMemoryMap = VirtualMemoryTable;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					/** @file
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
 | 
				
			||||||
 | 
					*  Copyright (c) 2014, Linaro Limited. All rights reserved.
 | 
				
			||||||
 | 
					*  Copyright (c) 2014, Red Hat, Inc.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*  This program and the accompanying materials
 | 
				
			||||||
 | 
					*  are licensed and made available under the terms and conditions of the BSD License
 | 
				
			||||||
 | 
					*  which accompanies this distribution.  The full text of the license may be found at
 | 
				
			||||||
 | 
					*  http://opensource.org/licenses/bsd-license.php
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
				
			||||||
 | 
					*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
				
			||||||
 | 
					*
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <Library/IoLib.h>
 | 
				
			||||||
 | 
					#include <Library/ArmPlatformLib.h>
 | 
				
			||||||
 | 
					#include <Library/DebugLib.h>
 | 
				
			||||||
 | 
					#include <ArmPlatform.h>
 | 
				
			||||||
 | 
					#include <Pi/PiBootMode.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  Return the current Boot Mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  This function returns the boot reason on the platform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @return   Return the current Boot Mode of the platform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					EFI_BOOT_MODE
 | 
				
			||||||
 | 
					ArmPlatformGetBootMode (
 | 
				
			||||||
 | 
					  VOID
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return BOOT_WITH_FULL_CONFIGURATION;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  This function is called by PrePeiCore, in the SEC phase.
 | 
				
			||||||
 | 
					**/
 | 
				
			||||||
 | 
					RETURN_STATUS
 | 
				
			||||||
 | 
					ArmPlatformInitialize (
 | 
				
			||||||
 | 
					  IN  UINTN                     MpId
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // We are relying on ArmPlatformInitializeSystemMemory () being called from
 | 
				
			||||||
 | 
					  // InitializeMemory (), which only occurs if the following feature is disabled
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  ASSERT (!FeaturePcdGet (PcdSystemMemoryInitializeInSec));
 | 
				
			||||||
 | 
					  return RETURN_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VOID
 | 
				
			||||||
 | 
					ArmPlatformInitializeSystemMemory (
 | 
				
			||||||
 | 
					  VOID
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VOID
 | 
				
			||||||
 | 
					ArmPlatformGetPlatformPpiList (
 | 
				
			||||||
 | 
					  OUT UINTN                   *PpiListSize,
 | 
				
			||||||
 | 
					  OUT EFI_PEI_PPI_DESCRIPTOR  **PpiList
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  *PpiListSize = 0;
 | 
				
			||||||
 | 
					  *PpiList = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user