mirror of https://github.com/acidanthera/audk.git
ArmVirtPkg/XenRelocatablePlatformLib: rewrite DTB memory node retrieval in C
Parsing the DTB early on using a handcoded assembly routine is a pointless waste of brain cycles, since the UEFI firmware always executes from RAM under Xen. So instead, set up a temporary stack in the memory region at the beginning of the image, and use the libfdt C library. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Acked-by: Laszlo Ersek <lersek@redhat.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19330 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
ce44ee32d3
commit
03b6bed17e
|
@ -1,237 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2014, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Theory of operation
|
|
||||||
* -------------------
|
|
||||||
*
|
|
||||||
* This code parses a Flattened Device Tree binary (DTB) to find the base of
|
|
||||||
* system RAM. It is written in assembly so that it can be executed before a
|
|
||||||
* stack has been set up.
|
|
||||||
*
|
|
||||||
* To find the base of system RAM, we have to traverse the FDT to find a memory
|
|
||||||
* node. In the context of this implementation, the first node that has a
|
|
||||||
* device_type property with the value 'memory' and a 'reg' property is
|
|
||||||
* acceptable, and the name of the node (memory[@xxx]) is ignored, as are any
|
|
||||||
* other nodes that match the above constraints.
|
|
||||||
*
|
|
||||||
* In pseudo code, this implementation does the following:
|
|
||||||
*
|
|
||||||
* for each node {
|
|
||||||
* have_device_type = false
|
|
||||||
* have_reg = false
|
|
||||||
*
|
|
||||||
* for each property {
|
|
||||||
* if property value == 'memory' {
|
|
||||||
* if property name == 'device_type' {
|
|
||||||
* have_device_type = true
|
|
||||||
* }
|
|
||||||
* } else {
|
|
||||||
* if property name == 'reg' {
|
|
||||||
* have_reg = true
|
|
||||||
* membase = property value[0]
|
|
||||||
* memsize = property value[1]
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* if have_device_type and have_reg {
|
|
||||||
* return membase and memsize
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* return NOT_FOUND
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FDT_MAGIC 0xedfe0dd0
|
|
||||||
|
|
||||||
#define FDT_BEGIN_NODE 0x1
|
|
||||||
#define FDT_END_NODE 0x2
|
|
||||||
#define FDT_PROP 0x3
|
|
||||||
#define FDT_END 0x9
|
|
||||||
|
|
||||||
xMEMSIZE .req x0 // recorded system RAM size
|
|
||||||
xMEMBASE .req x1 // recorded system RAM base
|
|
||||||
|
|
||||||
xLR .req x8 // our preserved link register
|
|
||||||
xDTP .req x9 // pointer to traverse the DT structure
|
|
||||||
xSTRTAB .req x10 // pointer to the DTB string table
|
|
||||||
xMEMNODE .req x11 // bit field to record found properties
|
|
||||||
|
|
||||||
#define HAVE_REG 0x1
|
|
||||||
#define HAVE_DEVICE_TYPE 0x2
|
|
||||||
|
|
||||||
.text
|
|
||||||
.align 3
|
|
||||||
_memory:
|
|
||||||
.asciz "memory"
|
|
||||||
_reg:
|
|
||||||
.asciz "reg"
|
|
||||||
_device_type:
|
|
||||||
.asciz "device_type"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compare strings in x4 and x5, return in w7
|
|
||||||
*/
|
|
||||||
.align 3
|
|
||||||
strcmp:
|
|
||||||
ldrb w2, [x4], #1
|
|
||||||
ldrb w3, [x5], #1
|
|
||||||
subs w7, w2, w3
|
|
||||||
cbz w2, 0f
|
|
||||||
cbz w3, 0f
|
|
||||||
beq strcmp
|
|
||||||
0: ret
|
|
||||||
|
|
||||||
.globl find_memnode
|
|
||||||
find_memnode:
|
|
||||||
// preserve link register
|
|
||||||
mov xLR, x30
|
|
||||||
mov xDTP, x0
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the DTB magic at offset 0
|
|
||||||
*/
|
|
||||||
movz w4, #(FDT_MAGIC & 0xffff)
|
|
||||||
movk w4, #(FDT_MAGIC >> 16), lsl #16
|
|
||||||
ldr w5, [xDTP]
|
|
||||||
cmp w4, w5
|
|
||||||
bne err_invalid_magic
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the string offset and store it for later use
|
|
||||||
*/
|
|
||||||
ldr w4, [xDTP, #12]
|
|
||||||
rev w4, w4
|
|
||||||
add xSTRTAB, xDTP, x4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the struct offset and add it to the DT pointer
|
|
||||||
*/
|
|
||||||
ldr w5, [xDTP, #8]
|
|
||||||
rev w5, w5
|
|
||||||
add xDTP, xDTP, x5
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check current tag for FDT_BEGIN_NODE
|
|
||||||
*/
|
|
||||||
ldr w5, [xDTP]
|
|
||||||
rev w5, w5
|
|
||||||
cmp w5, #FDT_BEGIN_NODE
|
|
||||||
bne err_unexpected_begin_tag
|
|
||||||
|
|
||||||
begin_node:
|
|
||||||
mov xMEMNODE, #0
|
|
||||||
add xDTP, xDTP, #4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Advance xDTP past NULL terminated string
|
|
||||||
*/
|
|
||||||
0: ldrb w4, [xDTP], #1
|
|
||||||
cbnz w4, 0b
|
|
||||||
|
|
||||||
next_tag:
|
|
||||||
/*
|
|
||||||
* Align the DT pointer xDTP to the next 32-bit boundary
|
|
||||||
*/
|
|
||||||
add xDTP, xDTP, #3
|
|
||||||
and xDTP, xDTP, #~3
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the next tag, could be BEGIN_NODE, END_NODE, PROP, END
|
|
||||||
*/
|
|
||||||
ldr w5, [xDTP]
|
|
||||||
rev w5, w5
|
|
||||||
cmp w5, #FDT_BEGIN_NODE
|
|
||||||
beq begin_node
|
|
||||||
cmp w5, #FDT_END_NODE
|
|
||||||
beq end_node
|
|
||||||
cmp w5, #FDT_PROP
|
|
||||||
beq prop_node
|
|
||||||
cmp w5, #FDT_END
|
|
||||||
beq err_end_of_fdt
|
|
||||||
b err_unexpected_tag
|
|
||||||
|
|
||||||
prop_node:
|
|
||||||
/*
|
|
||||||
* If propname == 'reg', record as membase and memsize
|
|
||||||
* If propname == 'device_type' and value == 'memory',
|
|
||||||
* set the 'is_memnode' flag for this node
|
|
||||||
*/
|
|
||||||
ldr w6, [xDTP, #4]
|
|
||||||
add xDTP, xDTP, #12
|
|
||||||
rev w6, w6
|
|
||||||
mov x5, xDTP
|
|
||||||
adr x4, _memory
|
|
||||||
bl strcmp
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get handle to property name
|
|
||||||
*/
|
|
||||||
ldr w5, [xDTP, #-4]
|
|
||||||
rev w5, w5
|
|
||||||
add x5, xSTRTAB, x5
|
|
||||||
|
|
||||||
cbz w7, check_device_type
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for 'reg' property
|
|
||||||
*/
|
|
||||||
adr x4, _reg
|
|
||||||
bl strcmp
|
|
||||||
cbnz w7, inc_and_next_tag
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extract two 64-bit quantities from the 'reg' property. These values
|
|
||||||
* will only be used if the node also turns out to have a device_type
|
|
||||||
* property with a value of 'memory'.
|
|
||||||
*
|
|
||||||
* NOTE: xDTP is only guaranteed to be 32 bit aligned, and we are most
|
|
||||||
* likely executing with the MMU off, so we cannot use 64 bit
|
|
||||||
* wide accesses here.
|
|
||||||
*/
|
|
||||||
ldp w4, w5, [xDTP]
|
|
||||||
orr xMEMBASE, x4, x5, lsl #32
|
|
||||||
ldp w4, w5, [xDTP, #8]
|
|
||||||
orr xMEMSIZE, x4, x5, lsl #32
|
|
||||||
rev xMEMBASE, xMEMBASE
|
|
||||||
rev xMEMSIZE, xMEMSIZE
|
|
||||||
orr xMEMNODE, xMEMNODE, #HAVE_REG
|
|
||||||
b inc_and_next_tag
|
|
||||||
|
|
||||||
check_device_type:
|
|
||||||
/*
|
|
||||||
* Check whether the current property's name is 'device_type'
|
|
||||||
*/
|
|
||||||
adr x4, _device_type
|
|
||||||
bl strcmp
|
|
||||||
cbnz w7, inc_and_next_tag
|
|
||||||
orr xMEMNODE, xMEMNODE, #HAVE_DEVICE_TYPE
|
|
||||||
|
|
||||||
inc_and_next_tag:
|
|
||||||
add xDTP, xDTP, x6
|
|
||||||
b next_tag
|
|
||||||
|
|
||||||
end_node:
|
|
||||||
/*
|
|
||||||
* Check for device_type = memory and reg = xxxx
|
|
||||||
* If we have both, we are done
|
|
||||||
*/
|
|
||||||
add xDTP, xDTP, #4
|
|
||||||
cmp xMEMNODE, #(HAVE_REG | HAVE_DEVICE_TYPE)
|
|
||||||
bne next_tag
|
|
||||||
|
|
||||||
ret xLR
|
|
||||||
|
|
||||||
err_invalid_magic:
|
|
||||||
err_unexpected_begin_tag:
|
|
||||||
err_unexpected_tag:
|
|
||||||
err_end_of_fdt:
|
|
||||||
wfi
|
|
|
@ -30,9 +30,6 @@ GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCore)
|
||||||
GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCoreMask)
|
GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCoreMask)
|
||||||
GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
|
GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
|
||||||
|
|
||||||
.LFdtMagic:
|
|
||||||
.byte 0xd0, 0x0d, 0xfe, 0xed
|
|
||||||
|
|
||||||
.LArm64LinuxMagic:
|
.LArm64LinuxMagic:
|
||||||
.byte 0x41, 0x52, 0x4d, 0x64
|
.byte 0x41, 0x52, 0x4d, 0x64
|
||||||
|
|
||||||
|
@ -43,17 +40,15 @@ GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
|
||||||
// );
|
// );
|
||||||
ASM_PFX(ArmPlatformPeiBootAction):
|
ASM_PFX(ArmPlatformPeiBootAction):
|
||||||
mov x29, x30 // preserve LR
|
mov x29, x30 // preserve LR
|
||||||
|
mov x28, x0 // preserve DTB pointer
|
||||||
|
mov x27, x1 // preserve base of image pointer
|
||||||
|
|
||||||
//
|
//
|
||||||
// If we are booting from RAM using the Linux kernel boot protocol, x0 will
|
// If we are booting from RAM using the Linux kernel boot protocol, x0 will
|
||||||
// point to the DTB image in memory. Otherwise, we are just coming out of
|
// point to the DTB image in memory. Otherwise, we are just coming out of
|
||||||
// reset, and x0 will be 0. Check also the FDT magic.
|
// reset, and x0 will be 0.
|
||||||
//
|
//
|
||||||
cbz x0, .Lout
|
cbz x0, .Lout
|
||||||
ldr w8, .LFdtMagic
|
|
||||||
ldr w9, [x0]
|
|
||||||
cmp w8, w9
|
|
||||||
bne .Lout
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// The base of the runtime image has been preserved in x1. Check whether
|
// The base of the runtime image has been preserved in x1. Check whether
|
||||||
|
@ -80,36 +75,30 @@ ASM_PFX(ArmPlatformPeiBootAction):
|
||||||
str x1, [x8]
|
str x1, [x8]
|
||||||
str x7, [x9]
|
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
|
// 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
|
// image header at the base of this image (defined in the FDF), and record the
|
||||||
// pointer in PcdDeviceTreeInitialBaseAddress.
|
// pointer in PcdDeviceTreeInitialBaseAddress.
|
||||||
//
|
//
|
||||||
adr x8, PcdGet64 (PcdDeviceTreeInitialBaseAddress)
|
adr x8, PcdGet64 (PcdDeviceTreeInitialBaseAddress)
|
||||||
add x1, x1, #0x40
|
add x27, x27, #0x40
|
||||||
str x1, [x8]
|
str x27, [x8]
|
||||||
|
|
||||||
ldr w8, [x0, #4] // get DTB size (BE)
|
mov x0, x27
|
||||||
mov x9, x1
|
mov x1, x28
|
||||||
rev w8, w8
|
bl CopyFdt
|
||||||
add x8, x8, x0
|
|
||||||
0:ldp x6, x7, [x0], #16
|
|
||||||
stp x6, x7, [x9], #16
|
|
||||||
cmp x0, x8
|
|
||||||
blt 0b
|
|
||||||
|
|
||||||
//
|
|
||||||
// Discover the memory size and offset from the DTB, and record in the
|
|
||||||
// respective PCDs
|
|
||||||
//
|
|
||||||
mov x0, x1
|
|
||||||
bl find_memnode // returns (size, base) size in (x0, x1)
|
|
||||||
cbz x0, .Lout
|
|
||||||
|
|
||||||
adr x8, PcdGet64 (PcdSystemMemorySize)
|
|
||||||
adr x9, PcdGet64 (PcdSystemMemoryBase)
|
|
||||||
str x0, [x8]
|
|
||||||
str x1, [x9]
|
|
||||||
|
|
||||||
.Lout:
|
.Lout:
|
||||||
ret x29
|
ret x29
|
||||||
|
|
|
@ -32,14 +32,15 @@
|
||||||
IoLib
|
IoLib
|
||||||
ArmLib
|
ArmLib
|
||||||
PrintLib
|
PrintLib
|
||||||
|
FdtLib
|
||||||
|
|
||||||
[Sources.common]
|
[Sources.common]
|
||||||
RelocatableVirt.c
|
RelocatableVirt.c
|
||||||
XenVirtMem.c
|
XenVirtMem.c
|
||||||
|
FdtParser.c
|
||||||
|
|
||||||
[Sources.AARCH64]
|
[Sources.AARCH64]
|
||||||
AARCH64/RelocatableVirtHelper.S
|
AARCH64/RelocatableVirtHelper.S
|
||||||
AARCH64/MemnodeParser.S
|
|
||||||
|
|
||||||
[FeaturePcd]
|
[FeaturePcd]
|
||||||
gEmbeddedTokenSpaceGuid.PcdCacheEnable
|
gEmbeddedTokenSpaceGuid.PcdCacheEnable
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CopyMem (FdtDest, FdtSource, fdt_totalsize (FdtSource));
|
||||||
|
}
|
Loading…
Reference in New Issue