Initial commit

This commit is contained in:
Your Name
2026-04-23 17:07:55 +08:00
commit b7e39e063b
16725 changed files with 1625565 additions and 0 deletions
@@ -0,0 +1,36 @@
COMPATIBLE_MACHINE = "fvp-baser-aemv8r64"
FILESEXTRAPATHS:prepend := "${THISDIR}/files/${MACHINE}:"
SRC_URI:append = " \
file://0001-aarch64-Rename-labels-and-prepare-for-lower-EL-booti.patch \
file://0002-aarch64-Prepare-for-EL1-booting.patch \
file://0003-aarch64-Prepare-for-lower-EL-booting.patch \
file://0004-gic-v3-Prepare-for-gicv3-with-EL2.patch \
file://0005-aarch64-Prepare-for-booting-with-EL2.patch \
file://0006-aarch64-Introduce-EL2-boot-code-for-Armv8-R-AArch64.patch \
file://0007-Allow-enable-psci-to-choose-between-smc-and-hvc.patch \
file://0008-aarch64-Disable-CNTPCT_EL0-trap-for-v8-R64.patch \
file://0009-lds-Mark-the-mem-range.patch \
file://0010-common-Introduce-the-libfdt.patch \
file://0011-common-Add-essential-libc-functions.patch \
file://0012-Makefile-Add-the-libfdt-to-the-Makefile-system.patch \
file://0013-platform-Add-print_hex-func.patch \
file://0014-common-Add-mem-usage-to-memreserve.patch \
file://0015-boot-Add-the-enable-keep-el-compile-option.patch \
file://0016-Makefile-Change-COUNTER_FREQ-to-100-MHz.patch \
file://0017-PSCI-Apply-flush-cache-after-setting-branch_data.patch \
file://0018-PSCI-Add-function-call-entry-point.patch \
file://0019-lds-Rearrange-and-mark-the-sections.patch \
file://0020-common-Provide-firmware-info-using-libfdt.patch \
file://0021-boot-Enable-firmware-node-initialization.patch \
"
BOOT_WRAPPER_AARCH64_CMDLINE = "\
earlycon console=ttyAMA0 loglevel=8 rootfstype=ext4 root=/dev/vda1 rw"
EXTRA_OECONF += "--enable-psci=hvc --enable-keep-el"
TUNE_CCARGS = ""
BOOT_WRAPPER_AARCH64_KERNEL = "u-boot.bin"
do_deploy[depends] += "u-boot:do_deploy"
@@ -0,0 +1,4 @@
MACHINE_BOOT_WRAPPER_AARCH64_REQUIRE ?= ""
MACHINE_BOOT_WRAPPER_AARCH64_REQUIRE:fvp-baser-aemv8r64 ?= "boot-wrapper-aarch64-fvp-baser-aemv8r64.inc"
require ${MACHINE_BOOT_WRAPPER_AARCH64_REQUIRE}
@@ -0,0 +1,135 @@
From 545f6950ae4dc55b4974986aa9629adb16eaf4e1 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 May 2021 07:25:00 +0100
Subject: [PATCH] aarch64: Rename labels and prepare for lower EL booting
Prepare for booting from lower EL. Rename *_el3 relavant labels with
*_el_max and *_no_el3 with *_keep_el. Since the original _no_el3 means
"We neither do init sequence at this highest EL nor drop to lower EL
when entering to kernel", we rename it with _keep_el to make it more
clear for lower EL initialisation.
Upstream-Status: Pending
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
---
arch/aarch64/boot.S | 28 ++++++++++++++++++++--------
arch/aarch64/psci.S | 9 +++++----
arch/aarch64/spin.S | 4 ++--
3 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index d682ba5..fab694e 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -34,18 +34,30 @@ ASM_FUNC(_start)
/*
* EL3 initialisation
+ * Boot sequence
+ * If CurrentEL == EL3, then goto EL3 initialisation and drop to
+ * lower EL before entering the kernel.
+ * Else, no initialisation and keep the current EL before
+ * entering the kernel.
*/
mrs x0, CurrentEL
cmp x0, #CURRENTEL_EL3
- b.eq 1f
+ b.eq el3_init
+ /*
+ * We stay in the current EL for entering the kernel
+ */
mov w0, #1
- ldr x1, =flag_no_el3
+ ldr x1, =flag_keep_el
str w0, [x1]
- b start_no_el3
+ b start_keep_el
-1: mov x0, #0x30 // RES1
+ /*
+ * EL3 initialisation
+ */
+el3_init:
+ mov x0, #0x30 // RES1
orr x0, x0, #(1 << 0) // Non-secure EL1
orr x0, x0, #(1 << 8) // HVC enable
@@ -145,7 +157,7 @@ ASM_FUNC(_start)
bl gic_secure_init
- b start_el3
+ b start_el_max
err_invalid_id:
b .
@@ -172,7 +184,7 @@ ASM_FUNC(jump_kernel)
bl find_logical_id
bl setup_stack // Reset stack pointer
- ldr w0, flag_no_el3
+ ldr w0, flag_keep_el
cmp w0, #0 // Prepare Z flag
mov x0, x20
@@ -181,7 +193,7 @@ ASM_FUNC(jump_kernel)
mov x3, x23
b.eq 1f
- br x19 // No EL3
+ br x19 // Keep current EL
1: mov x4, #SPSR_KERNEL
@@ -199,5 +211,5 @@ ASM_FUNC(jump_kernel)
.data
.align 3
-flag_no_el3:
+flag_keep_el:
.long 0
diff --git a/arch/aarch64/psci.S b/arch/aarch64/psci.S
index 8bd224b..7b8919a 100644
--- a/arch/aarch64/psci.S
+++ b/arch/aarch64/psci.S
@@ -79,7 +79,7 @@ smc_exit:
ldp x18, x19, [sp], #16
eret
-ASM_FUNC(start_el3)
+ASM_FUNC(start_el_max)
ldr x0, =vector
bl setup_vector
@@ -89,10 +89,11 @@ ASM_FUNC(start_el3)
b psci_first_spin
/*
- * This PSCI implementation requires EL3. Without EL3 we'll only boot the
- * primary cpu, all others will be trapped in an infinite loop.
+ * This PSCI implementation requires the highest EL(EL3 or Armv8-R EL2).
+ * Without the highest EL, we'll only boot the primary cpu, all othersr
+ * will be trapped in an infinite loop.
*/
-ASM_FUNC(start_no_el3)
+ASM_FUNC(start_keep_el)
cpuid x0, x1
bl find_logical_id
cbz x0, psci_first_spin
diff --git a/arch/aarch64/spin.S b/arch/aarch64/spin.S
index 1ea1c0b..bfb1d47 100644
--- a/arch/aarch64/spin.S
+++ b/arch/aarch64/spin.S
@@ -12,8 +12,8 @@
.text
-ASM_FUNC(start_el3)
-ASM_FUNC(start_no_el3)
+ASM_FUNC(start_el_max)
+ASM_FUNC(start_keep_el)
cpuid x0, x1
bl find_logical_id
@@ -0,0 +1,48 @@
From bad32d3fc127a421be416b17e4f7d6d514f06abb Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 May 2021 07:25:00 +0100
Subject: [PATCH] aarch64: Prepare for EL1 booting
When booting from EL1, add a check and skip the init of
sctlr_el2 in jump_kernel
Upstream-Status: Pending
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
arch/aarch64/boot.S | 6 +++++-
arch/aarch64/include/asm/cpu.h | 1 +
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index fab694e..5105b41 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -177,10 +177,14 @@ ASM_FUNC(jump_kernel)
ldr x0, =SCTLR_EL1_KERNEL
msr sctlr_el1, x0
+ mrs x0, CurrentEL
+ cmp x0, #CURRENTEL_EL2
+ b.lt 1f
+
ldr x0, =SCTLR_EL2_KERNEL
msr sctlr_el2, x0
- cpuid x0, x1
+1: cpuid x0, x1
bl find_logical_id
bl setup_stack // Reset stack pointer
diff --git a/arch/aarch64/include/asm/cpu.h b/arch/aarch64/include/asm/cpu.h
index 49d3f86..3767da3 100644
--- a/arch/aarch64/include/asm/cpu.h
+++ b/arch/aarch64/include/asm/cpu.h
@@ -11,6 +11,7 @@
#define MPIDR_ID_BITS 0xff00ffffff
+#define CURRENTEL_EL2 (2 << 2)
#define CURRENTEL_EL3 (3 << 2)
/*
@@ -0,0 +1,55 @@
From 252cbd36e51414b60ab68306f9c38e358709494d Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 May 2021 07:25:00 +0100
Subject: [PATCH] aarch64: Prepare for lower EL booting
Save SPSR_KERNEL into spsr_to_elx during el3_init.
The jump_kernel will load spsr_to_elx into spsr_el3.
This change will make it easier to control whether drop to lower EL
before jumping to the kernel.
Upstream-Status: Pending
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
arch/aarch64/boot.S | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index 5105b41..243198d 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -151,7 +151,16 @@ el3_init:
mov x0, #ZCR_EL3_LEN_MAX // SVE: Enable full vector len
msr ZCR_EL3, x0 // for EL2.
-1:
+ /*
+ * Save SPSR_KERNEL into spsr_to_elx.
+ * The jump_kernel will load spsr_to_elx into spsr_el3
+ */
+1: mov w0, #SPSR_KERNEL
+ ldr x1, =spsr_to_elx
+ str w0, [x1]
+ b el_max_init
+
+el_max_init:
ldr x0, =COUNTER_FREQ
msr cntfrq_el0, x0
@@ -199,7 +208,7 @@ ASM_FUNC(jump_kernel)
b.eq 1f
br x19 // Keep current EL
-1: mov x4, #SPSR_KERNEL
+1: ldr w4, spsr_to_elx
/*
* If bit 0 of the kernel address is set, we're entering in AArch32
@@ -217,3 +226,5 @@ ASM_FUNC(jump_kernel)
.align 3
flag_keep_el:
.long 0
+spsr_to_elx:
+ .long 0
@@ -0,0 +1,105 @@
From bff110a95a5e4c9db2d61e629b4aa4b84530201e Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 May 2021 07:25:00 +0100
Subject: [PATCH] gic-v3: Prepare for gicv3 with EL2
This is a preparation for allowing boot-wrapper configuring the gicv3
with EL2.
When confiuring with EL2, since there is no ICC_CTLR_EL2, the
ICC_CTLR_EL3 cannot be replaced with ICC_CTLR_EL2 simply.
See [https://developer.arm.com/documentation/ihi0069/latest/].
As the caller, gic_secure_init expects the ICC_CTLR to be written,
we change the function into gic_init_icc_ctlr(). In the GIC spec,
the r/w bits in this register ([6:0]) either affect EL3 IRQ routing
(not applicable since no EL3), non-secure IRQ handling (not applicable
since only secure state in Armv8-R aarch64), or are aliased to
ICC_CTLR_EL1 bits.
So, based on this, the new gic_init_icc_ctlr() would be:
When currentEL is EL3, init ICC_CTLR_EL3 as before.
When currentEL is not EL3, init ICC_CTLR_EL1 with ICC_CTLR_EL1_RESET.
Upstream-Status: Pending
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
arch/aarch32/include/asm/gic-v3.h | 7 +++++++
arch/aarch64/include/asm/gic-v3.h | 23 ++++++++++++++++++++---
common/gic-v3.c | 2 +-
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/arch/aarch32/include/asm/gic-v3.h b/arch/aarch32/include/asm/gic-v3.h
index 65f38de..11e7bc7 100644
--- a/arch/aarch32/include/asm/gic-v3.h
+++ b/arch/aarch32/include/asm/gic-v3.h
@@ -9,6 +9,8 @@
#ifndef __ASM_AARCH32_GICV3_H
#define __ASM_AARCH32_GICV3_H
+#define ICC_CTLR_RESET (0UL)
+
static inline void gic_write_icc_sre(uint32_t val)
{
asm volatile ("mcr p15, 6, %0, c12, c12, 5" : : "r" (val));
@@ -19,4 +21,9 @@ static inline void gic_write_icc_ctlr(uint32_t val)
asm volatile ("mcr p15, 6, %0, c12, c12, 4" : : "r" (val));
}
+static inline void gic_init_icc_ctlr()
+{
+ gic_write_icc_ctlr(ICC_CTLR_RESET);
+}
+
#endif
diff --git a/arch/aarch64/include/asm/gic-v3.h b/arch/aarch64/include/asm/gic-v3.h
index 5b32380..090ab0b 100644
--- a/arch/aarch64/include/asm/gic-v3.h
+++ b/arch/aarch64/include/asm/gic-v3.h
@@ -15,14 +15,31 @@
#define ICC_CTLR_EL3 "S3_6_C12_C12_4"
#define ICC_PMR_EL1 "S3_0_C4_C6_0"
+#define ICC_CTLR_EL3_RESET (0UL)
+#define ICC_CTLR_EL1_RESET (0UL)
+
+static inline uint32_t current_el(void)
+{
+ uint32_t val;
+
+ asm volatile ("mrs %0, CurrentEL" : "=r" (val));
+ return val;
+}
+
static inline void gic_write_icc_sre(uint32_t val)
{
- asm volatile ("msr " ICC_SRE_EL3 ", %0" : : "r" (val));
+ if (current_el() == CURRENTEL_EL3)
+ asm volatile ("msr " ICC_SRE_EL3 ", %0" : : "r" (val));
+ else
+ asm volatile ("msr " ICC_SRE_EL2 ", %0" : : "r" (val));
}
-static inline void gic_write_icc_ctlr(uint32_t val)
+static inline void gic_init_icc_ctlr()
{
- asm volatile ("msr " ICC_CTLR_EL3 ", %0" : : "r" (val));
+ if (current_el() == CURRENTEL_EL3)
+ asm volatile ("msr " ICC_CTLR_EL3 ", %0" : : "r" (ICC_CTLR_EL3_RESET));
+ else
+ asm volatile ("msr " ICC_CTLR_EL1 ", %0" : : "r" (ICC_CTLR_EL1_RESET));
}
#endif
diff --git a/common/gic-v3.c b/common/gic-v3.c
index 6207007..a0fe564 100644
--- a/common/gic-v3.c
+++ b/common/gic-v3.c
@@ -117,6 +117,6 @@ void gic_secure_init(void)
gic_write_icc_sre(ICC_SRE_Enable | ICC_SRE_DIB | ICC_SRE_DFB | ICC_SRE_SRE);
isb();
- gic_write_icc_ctlr(0);
+ gic_init_icc_ctlr();
isb();
}
@@ -0,0 +1,63 @@
From ba955efb35ce1d41b562190d7c2fbcbcf8ef97ff Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 May 2021 07:25:00 +0100
Subject: [PATCH] aarch64: Prepare for booting with EL2
Prepare for allowing boot-wrapper to be entered in EL2.
Detect current EL and set the corresponding EL registers.
Upstream-Status: Pending
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
---
arch/aarch64/boot.S | 8 ++++++++
arch/aarch64/utils.S | 10 +++++++++-
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index 243198d..3593ca5 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -216,10 +216,18 @@ ASM_FUNC(jump_kernel)
*/
bfi x4, x19, #5, #1
+ mrs x5, CurrentEL
+ cmp x5, #CURRENTEL_EL2
+ b.eq 1f
+
msr elr_el3, x19
msr spsr_el3, x4
eret
+1: msr elr_el2, x19
+ msr spsr_el2, x4
+ eret
+
.ltorg
.data
diff --git a/arch/aarch64/utils.S b/arch/aarch64/utils.S
index 85c7f8a..f02a249 100644
--- a/arch/aarch64/utils.S
+++ b/arch/aarch64/utils.S
@@ -34,10 +34,18 @@ ASM_FUNC(find_logical_id)
ret
/*
- * Setup EL3 vectors
+ * Setup EL3/EL2 vectors
* x0: vector address
*/
ASM_FUNC(setup_vector)
+ mrs x1, CurrentEL
+ cmp x1, #CURRENTEL_EL2
+ b.eq 1f
+
msr VBAR_EL3, x0
isb
ret
+
+1: msr VBAR_EL2, x0
+ isb
+ ret
@@ -0,0 +1,182 @@
From 8e44fac113d935affed1550480631f3fe7f30584 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 May 2021 07:25:00 +0100
Subject: [PATCH] aarch64: Introduce EL2 boot code for Armv8-R AArch64
The Armv8-R AArch64 profile does not support the EL3 exception level.
The Armv8-R AArch64 profile allows for an (optional) VMSAv8-64 MMU
at EL1, which allows to run off-the-shelf Linux. However EL2 only
supports a PMSA, which is not supported by Linux, so we need to drop
into EL1 before entering the kernel.
We add a new err_invalid_arch symbol as a dead loop. If we detect the
current Armv8-R aarch64 only supports with PMSA, meaning we cannot boot
Linux anymore, then we jump to err_invalid_arch.
During Armv8-R aarch64 init, to make sure nothing unexpected traps into
EL2, we auto-detect and config FIEN and EnSCXT in HCR_EL2.
The boot sequence is:
If CurrentEL == EL3, then goto EL3 initialisation and drop to lower EL
before entering the kernel.
If CurrentEL == EL2 && id_aa64mmfr0_el1.MSA == 0xf (Armv8-R aarch64),
if id_aa64mmfr0_el1.MSA_frac == 0x2,
then goto Armv8-R AArch64 initialisation and drop to EL1 before
entering the kernel.
else, which means VMSA unsupported and cannot boot Linux,
goto err_invalid_arch (dead loop).
Else, no initialisation and keep the current EL before entering the
kernel.
Upstream-Status: Pending
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
---
arch/aarch64/boot.S | 92 +++++++++++++++++++++++++++++++++-
arch/aarch64/include/asm/cpu.h | 2 +
2 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index 3593ca5..a219ea7 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -37,16 +37,24 @@ ASM_FUNC(_start)
* Boot sequence
* If CurrentEL == EL3, then goto EL3 initialisation and drop to
* lower EL before entering the kernel.
+ * If CurrentEL == EL2 && id_aa64mmfr0_el1.MSA == 0xf, then
+ * If id_aa64mmfr0_el1.MSA_frac == 0x2, then goto
+ * Armv8-R AArch64 initialisation and drop to EL1 before
+ * entering the kernel.
+ * Else, which means VMSA unsupported and cannot boot Linux,
+ * goto err_invalid_arch (dead loop).
* Else, no initialisation and keep the current EL before
* entering the kernel.
*/
mrs x0, CurrentEL
- cmp x0, #CURRENTEL_EL3
- b.eq el3_init
+ cmp x0, #CURRENTEL_EL2
+ bgt el3_init
+ beq el2_init
/*
* We stay in the current EL for entering the kernel
*/
+keep_el:
mov w0, #1
ldr x1, =flag_keep_el
str w0, [x1]
@@ -160,6 +168,85 @@ el3_init:
str w0, [x1]
b el_max_init
+ /*
+ * EL2 Armv8-R AArch64 initialisation
+ */
+el2_init:
+ /* Detect Armv8-R AArch64 */
+ mrs x1, id_aa64mmfr0_el1
+ /*
+ * Check MSA, bits [51:48]:
+ * 0xf means Armv8-R AArch64.
+ * If not 0xf, proceed in Armv8-A EL2.
+ */
+ ubfx x0, x1, #48, #4 // MSA
+ cmp x0, 0xf
+ bne keep_el
+ /*
+ * Check MSA_frac, bits [55:52]:
+ * 0x2 means EL1&0 translation regime also supports VMSAv8-64.
+ */
+ ubfx x0, x1, #52, #4 // MSA_frac
+ cmp x0, 0x2
+ /*
+ * If not 0x2, no VMSA, so cannot boot Linux and dead loop.
+ * Also, since the architecture guarantees that those CPUID
+ * fields never lose features when the value in a field
+ * increases, we use blt to cover it.
+ */
+ blt err_invalid_arch
+
+ mrs x0, midr_el1
+ msr vpidr_el2, x0
+
+ mrs x0, mpidr_el1
+ msr vmpidr_el2, x0
+
+ mov x0, #(1 << 31) // VTCR_MSA: VMSAv8-64 support
+ msr vtcr_el2, x0
+
+ /* Init HCR_EL2 */
+ mov x0, #(1 << 31) // RES1: Armv8-R aarch64 only
+
+ mrs x1, id_aa64pfr0_el1
+ ubfx x2, x1, #56, 4 // ID_AA64PFR0_EL1.CSV2
+ cmp x2, 0x2
+ b.lt 1f
+ /*
+ * Disable trap when accessing SCTXNUM_EL0 or SCTXNUM_EL1
+ * if FEAT_CSV2.
+ */
+ orr x0, x0, #(1 << 53) // HCR_EL2.EnSCXT
+
+1: ubfx x2, x1, #28, 4 // ID_AA64PFR0_EL1.RAS
+ cmp x2, 0x2
+ b.lt 1f
+ /* Disable trap when accessing ERXPFGCDN_EL1 if FEAT_RASv1p1. */
+ orr x0, x0, #(1 << 47) // HCR_EL2.FIEN
+
+ /* Enable pointer authentication if present */
+1: mrs x1, id_aa64isar1_el1
+ /*
+ * If ID_AA64ISAR1_EL1.{GPI, GPA, API, APA} == {0000, 0000, 0000, 0000}
+ * then HCR_EL2.APK and HCR_EL2.API are RES 0.
+ * Else
+ * set HCR_EL2.APK and HCR_EL2.API.
+ */
+ ldr x2, =(((0xff) << 24) | (0xff << 4))
+ and x1, x1, x2
+ cbz x1, 1f
+
+ orr x0, x0, #(1 << 40) // HCR_EL2.APK
+ orr x0, x0, #(1 << 41) // HCR_EL2.API
+
+1: msr hcr_el2, x0
+ isb
+
+ mov w0, #SPSR_KERNEL_EL1
+ ldr x1, =spsr_to_elx
+ str w0, [x1]
+ // fall through
+
el_max_init:
ldr x0, =COUNTER_FREQ
msr cntfrq_el0, x0
@@ -169,6 +256,7 @@ el_max_init:
b start_el_max
err_invalid_id:
+err_invalid_arch:
b .
/*
diff --git a/arch/aarch64/include/asm/cpu.h b/arch/aarch64/include/asm/cpu.h
index 3767da3..3c0e00d 100644
--- a/arch/aarch64/include/asm/cpu.h
+++ b/arch/aarch64/include/asm/cpu.h
@@ -25,6 +25,7 @@
#define SPSR_I (1 << 7) /* IRQ masked */
#define SPSR_F (1 << 6) /* FIQ masked */
#define SPSR_T (1 << 5) /* Thumb */
+#define SPSR_EL1H (5 << 0) /* EL1 Handler mode */
#define SPSR_EL2H (9 << 0) /* EL2 Handler mode */
#define SPSR_HYP (0x1a << 0) /* M[3:0] = hyp, M[4] = AArch32 */
@@ -50,6 +51,7 @@
#else
#define SCTLR_EL1_KERNEL SCTLR_EL1_RES1
#define SPSR_KERNEL (SPSR_A | SPSR_D | SPSR_I | SPSR_F | SPSR_EL2H)
+#define SPSR_KERNEL_EL1 (SPSR_A | SPSR_D | SPSR_I | SPSR_F | SPSR_EL1H)
#endif
#ifndef __ASSEMBLY__
@@ -0,0 +1,89 @@
From 0b9a966b8a28961b078215ee7169e32a976d5e7d Mon Sep 17 00:00:00 2001
From: Qi Feng <qi.feng@arm.com>
Date: Wed, 26 May 2021 17:52:01 +0800
Subject: [PATCH] Allow --enable-psci to choose between smc and hvc
According to Armv8-R AArch64 manual [1], Armv8-R AArch64 does not
support smc:
- Pseudocode for AArch64.CheckForSMCUndefOrTrap has this snippet:
if !HaveEL(EL3) || PSTATE.EL == EL0 then
UNDEFINED;
And Armv8-R AArch64 does not have EL3.
- In the document of HCR_EL2 TSC bit:
If EL3 is not implemented and HCR_EL2.NV is 0, it is IMPLEMENTATION
DEFINED whether this bit is:
- RES0.
- Implemented with the functionality as described in HCR_EL2.TSC.
So hvc is needed in this situation. And due to the lack of libfdt, the
psci method cannot be modified at runtime.
To use smc, use --enable-psci or --enable-psci=smc.
To use hvc, use --enable-psci=hvc.
[1]: https://developer.arm.com/documentation/ddi0600/latest/
Issue-Id: SCM-2654
Upstream-Status: Pending
Signed-off-by: Qi Feng <qi.feng@arm.com>
Change-Id: Ib8afabdad2d98bc37371d165bbb6f1f9b88bfc87
Upstream-Status: Pending
Signed-off-by: Huifeng Zhang <Huifeng.Zhang@arm.com>
---
Makefile.am | 10 +++++-----
configure.ac | 14 +++++++++-----
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 5731a19..fc66662 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,11 +50,11 @@ endif
if PSCI
ARCH_OBJ += psci.o
COMMON_OBJ += psci.o
-PSCI_NODE := psci { \
- compatible = \"arm,psci\"; \
- method = \"smc\"; \
- cpu_on = <$(PSCI_CPU_ON)>; \
- cpu_off = <$(PSCI_CPU_OFF)>; \
+PSCI_NODE := psci { \
+ compatible = \"arm,psci\"; \
+ method = \"$(PSCI_METHOD)\"; \
+ cpu_on = <$(PSCI_CPU_ON)>; \
+ cpu_off = <$(PSCI_CPU_OFF)>; \
};
CPU_NODES := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/addpsci.pl $(KERNEL_DTB))
else
diff --git a/configure.ac b/configure.ac
index 9e3b722..53e51be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,13 +83,17 @@ AS_IF([test "x$X_IMAGE" != "x"],
# Allow a user to pass --enable-psci
AC_ARG_ENABLE([psci],
AS_HELP_STRING([--disable-psci], [disable the psci boot method]),
- [USE_PSCI=$enableval], [USE_PSCI="yes"])
-AM_CONDITIONAL([PSCI], [test "x$USE_PSCI" = "xyes"])
-AS_IF([test "x$USE_PSCI" = "xyes"], [], [USE_PSCI=no])
-
-AS_IF([test "x$USE_PSCI" != "xyes" -a "x$KERNEL_ES" = "x32"],
+ [case "${enableval}" in
+ yes|smc) USE_PSCI=smc ;;
+ hvc) USE_PSCI=hvc ;;
+ *) AC_MSG_ERROR([Bad value "${enableval}" for --enable-psci. Use "smc" or "hvc"]) ;;
+ esac], [USE_PSCI="yes"])
+AM_CONDITIONAL([PSCI], [test "x$USE_PSCI" = "xyes" -o "x$USE_PSCI" = "xsmc" -o "x$USE_PSCI" = "xhvc"])
+
+AS_IF([test "x$USE_PSCI" = "xno" -a "x$KERNEL_ES" = "x32"],
[AC_MSG_ERROR([With an AArch32 kernel, boot method must be PSCI.])]
)
+AC_SUBST([PSCI_METHOD], [$USE_PSCI])
# Allow a user to pass --with-initrd
AC_ARG_WITH([initrd],
@@ -0,0 +1,48 @@
From 521c121eccb386aca7c75d92528e495546adccec Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Mon, 25 Oct 2021 17:09:13 +0800
Subject: [PATCH] aarch64: Disable CNTPCT_EL0 trap for v8-R64
To allow EL1 to access CNTPCT_EL0 without traping into EL2, we need to
set CNTHCTL_EL2.EL1PCTEN to 1.
For v8-R64, the CNTHCTL_EL2 register follows the v8-A architecture.
However, as described in the v8-A architecture profile, the
CNTHCTL_EL2's bit assignments are different according to whether the
FEAT_VHE is implemented.
Since v8-R64 does not support FEAT_VHE, we do not need to detect
FEAT_VHE. We can simply set CNTHCTL_EL2.EL1PCTEN to 1.
Issue-ID: SCM-3508
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I4147e66341c8153312021e6f2ab67d0037246da1
---
arch/aarch64/boot.S | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index a219ea7..27b1139 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -240,6 +240,18 @@ el2_init:
orr x0, x0, #(1 << 41) // HCR_EL2.API
1: msr hcr_el2, x0
+
+ /*
+ * To disable trap when accessing CNTPCT_EL0, we need to set
+ * CNTHCTL_EL2.EL1PCTEN to 1. However, the CNTHCTL_EL2 bit assignments
+ * are different according to whether the FEAT_VHE is implemented.
+ *
+ * For Armv8-R AArch64, FEAT_VHE is not supported, so we do not need to
+ * detect FEAT_VHE(ID_AA64MMFR1_EL1.VH) and simply set
+ * CNTHCTL_EL2.EL1PCTEN to 1.
+ */
+ mov x0, #1 // CNTHCTL_EL2.EL1PCTEN
+ msr cnthctl_el2, x0
isb
mov w0, #SPSR_KERNEL_EL1
@@ -0,0 +1,38 @@
From 780df234d98db81485b1f351f902a68def35c9d4 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 2 Nov 2021 15:10:28 +0800
Subject: [PATCH] lds: Mark the mem range
Add firmware_start and firmware_end, so that we can use them to
calculate the mem range of boot-wrapper and then set the range to
/memreserve/ of dtb.
Issue-ID: SCM-3815
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: Idc5a2894e193c75381049a0f359b4b2a51c567ee
---
model.lds.S | 2 ++
1 file changed, 2 insertions(+)
diff --git a/model.lds.S b/model.lds.S
index d4e7e13..ab98ddf 100644
--- a/model.lds.S
+++ b/model.lds.S
@@ -64,6 +64,7 @@ SECTIONS
#endif
.boot PHYS_OFFSET: {
+ PROVIDE(firmware_start = .);
*(.init)
*(.text*)
*(.data* .rodata* .bss* COMMON)
@@ -76,6 +77,7 @@ SECTIONS
mbox = .;
QUAD(0x0)
}
+ PROVIDE(firmware_end = .);
ASSERT(etext <= (PHYS_OFFSET + TEXT_LIMIT), ".text overflow!")
}
@@ -0,0 +1,101 @@
From e2eff4f80e65cb3fcbe6345b5376a6bf7de7e2cc Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 28 Dec 2021 17:28:25 +0800
Subject: [PATCH] common: Add essential libc functions
The libfdt uses some of the libc functions, e.g. memcmp, memmove,
strlen .etc. Add them in lib.c.
The code is copied from TF-A (v2.5) [1] project, which is under the
terms of BSD license. It is the same with boot-wrapper.
[1]: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
Issue-Id: SCM-3814
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: If3b55b00afa8694c7522df989a41e0b38eda1d38
---
common/lib.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/common/lib.c b/common/lib.c
index fcf5f69..0be1c4a 100644
--- a/common/lib.c
+++ b/common/lib.c
@@ -32,4 +32,73 @@ void *memset(void *s, int c, size_t n)
return s;
}
-/* TODO: memmove and memcmp could also be called */
+int memcmp(const void *s1, const void *s2, size_t len)
+{
+ const unsigned char *s = s1;
+ const unsigned char *d = s2;
+ unsigned char sc;
+ unsigned char dc;
+
+ while (len--) {
+ sc = *s++;
+ dc = *d++;
+ if (sc - dc)
+ return (sc - dc);
+ }
+
+ return 0;
+}
+
+void *memmove(void *dst, const void *src, size_t len)
+{
+ if ((size_t)dst - (size_t)src >= len) {
+ /* destination not in source data, so can safely use memcpy */
+ return memcpy(dst, src, len);
+ } else {
+ /* copy backwards... */
+ const char *end = dst;
+ const char *s = (const char *)src + len;
+ char *d = (char *)dst + len;
+ while (d != end)
+ *--d = *--s;
+ }
+ return dst;
+}
+
+void *memchr(const void *src, int c, size_t len)
+{
+ const unsigned char *s = src;
+
+ while (len--) {
+ if (*s == (unsigned char)c)
+ return (void *) s;
+ s++;
+ }
+
+ return NULL;
+}
+
+char *strrchr(const char *p, int ch)
+{
+ char *save;
+ char c;
+
+ c = ch;
+ for (save = NULL;; ++p) {
+ if (*p == c)
+ save = (char *)p;
+ if (*p == '\0')
+ return (save);
+ }
+ /* NOTREACHED */
+}
+
+size_t strlen(const char *s)
+{
+ const char *cursor = s;
+
+ while (*cursor)
+ cursor++;
+
+ return cursor - s;
+}
@@ -0,0 +1,61 @@
From f4d5cf4c3424598a2b3bb391717313b70c79ea28 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 28 Dec 2021 17:42:48 +0800
Subject: [PATCH] Makefile: Add the libfdt to the Makefile system
Add the libfdt into Makefile system. The libfdt uses const value and
thus gcc will enable the stack guard. The stack guard will fail the
compile. Add -fno-stack-protector to fix it.
Issue-Id: SCM-3814
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I472bc28cdc5cde3b22461a4b7d7a3752ae382b4b
---
Makefile.am | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index fc66662..ab2c3a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,6 +36,9 @@ PSCI_CPU_OFF := 0x84000002
COMMON_SRC := common/
COMMON_OBJ := boot.o bakery_lock.o platform.o lib.o
+LIBFDT_SRC := common/libfdt/
+LIBFDT_OBJS := fdt.o fdt_ro.o fdt_rw.o
+
ARCH_OBJ := boot.o stack.o utils.o
if BOOTWRAPPER_32
@@ -127,11 +130,12 @@ CFLAGS += -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
CFLAGS += -Wall -fomit-frame-pointer
CFLAGS += -ffreestanding -nostdlib
CFLAGS += -fno-stack-protector
+CFLAGS += -fno-stack-protector
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -fno-pic -fno-pie
LDFLAGS += --gc-sections
-OBJ := $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ))
+OBJ := $(addprefix $(ARCH_SRC),$(ARCH_OBJ)) $(addprefix $(COMMON_SRC),$(COMMON_OBJ)) $(addprefix $(LIBFDT_SRC),$(LIBFDT_OBJS))
# Don't lookup all prerequisites in $(top_srcdir), only the source files. When
# building outside the source tree $(ARCH_SRC) needs to be created.
@@ -152,10 +156,13 @@ $(ARCH_SRC):
$(COMMON_SRC):
$(MKDIR_P) $@
+$(LIBFDT_SRC):
+ $(MKDIR_P) $@
+
%.o: %.S Makefile | $(ARCH_SRC)
$(CC) $(CPPFLAGS) -D__ASSEMBLY__ $(CFLAGS) $(DEFINES) -c -o $@ $<
-%.o: %.c Makefile | $(COMMON_SRC)
+%.o: %.c Makefile | $(COMMON_SRC) $(LIBFDT_SRC)
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c -o $@ $<
model.lds: $(LD_SCRIPT) Makefile
@@ -0,0 +1,67 @@
From f0ece5e8cac761a76a86df7204bae7c6ef09215f Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Wed, 29 Dec 2021 10:50:21 +0800
Subject: [PATCH] platform: Add print_hex func
Refine the print functions, and add a new print_hex func to print hex
numbers.
Issue-Id: SCM-3814
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: Ic960345d9ef0b41d81d30c4a4dbd9c31139907c4
---
common/platform.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/common/platform.c b/common/platform.c
index d11f568..8269392 100644
--- a/common/platform.c
+++ b/common/platform.c
@@ -30,20 +30,37 @@
#define V2M_SYS(reg) ((void *)SYSREGS_BASE + V2M_SYS_##reg)
#endif
-static void print_string(const char *str)
+static void print_char(const char c)
{
uint32_t flags;
+ do {
+ flags = raw_readl(PL011(UARTFR));
+ } while (flags & PL011_UARTFR_FIFO_FULL);
+ raw_writel(c, PL011(UARTDR));
+
+ do {
+ flags = raw_readl(PL011(UARTFR));
+ } while (flags & PL011_UARTFR_BUSY);
+}
+
+void print_string(const char *str)
+{
while (*str) {
- do
- flags = raw_readl(PL011(UARTFR));
- while (flags & PL011_UARTFR_FIFO_FULL);
+ print_char(*str++);
+ }
+}
- raw_writel(*str++, PL011(UARTDR));
+#define HEX_CHARS_PER_INT (2 * sizeof(int))
+
+void print_hex(unsigned int val)
+{
- do
- flags = raw_readl(PL011(UARTFR));
- while (flags & PL011_UARTFR_BUSY);
+ const char hex_chars[16] = "0123456789abcdef";
+ int i;
+ for (i = HEX_CHARS_PER_INT - 1; i >= 0; i--) {
+ int v = (val >> (4 * i)) & 0xf;
+ print_char(hex_chars[v]);
}
}
@@ -0,0 +1,96 @@
From f4704146e1af9f6e0a2220db6b39a328c813fac1 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Wed, 19 Jan 2022 16:19:02 +0800
Subject: [PATCH] common: Add mem usage to /memreserve/
Set /memreserve/ to prevent next boot stages from overrding PSCI
services with libfdt.
Issue-Id: SCM-3815
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I2ea80cdf736a910fa2c3deb622e21d50f04be960
---
Makefile.am | 2 +-
common/boot.c | 1 +
common/device_tree.c | 34 ++++++++++++++++++++++++++++++++++
include/boot.h | 1 +
4 files changed, 37 insertions(+), 1 deletion(-)
create mode 100644 common/device_tree.c
diff --git a/Makefile.am b/Makefile.am
index ab2c3a9..e905602 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,7 +34,7 @@ endif
PSCI_CPU_OFF := 0x84000002
COMMON_SRC := common/
-COMMON_OBJ := boot.o bakery_lock.o platform.o lib.o
+COMMON_OBJ := boot.o bakery_lock.o platform.o lib.o device_tree.o
LIBFDT_SRC := common/libfdt/
LIBFDT_OBJS := fdt.o fdt_ro.o fdt_rw.o
diff --git a/common/boot.c b/common/boot.c
index c74d34c..ee2bea0 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -63,6 +63,7 @@ void __noreturn first_spin(unsigned int cpu, unsigned long *mbox,
{
if (cpu == 0) {
init_platform();
+ dt_add_memreserve();
*mbox = (unsigned long)&entrypoint;
sevl();
diff --git a/common/device_tree.c b/common/device_tree.c
new file mode 100644
index 0000000..4d0876c
--- /dev/null
+++ b/common/device_tree.c
@@ -0,0 +1,34 @@
+/*
+ * device_tree.c - Basic device tree node handler
+ *
+ * Copyright (C) 2021 ARM Limited. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE.txt file.
+ */
+#include <libfdt.h>
+
+extern unsigned long dtb;
+extern char firmware_start[], firmware_end[];
+
+extern void print_string(const char *str);
+
+static void *blob;
+
+
+void dt_add_memreserve(void)
+{
+ int ret;
+
+ blob = (void*)&dtb;
+ print_string("Add /memreserve/\n\r");
+
+ fdt_open_into(blob, blob, fdt_totalsize(blob) +
+ sizeof(struct fdt_reserve_entry));
+ ret = fdt_add_mem_rsv(blob, (uint64_t)firmware_start,
+ (uint64_t)(firmware_end - firmware_start));
+
+ if(ret < 0) {
+ print_string("reserve mem add err\n\r");
+ }
+}
diff --git a/include/boot.h b/include/boot.h
index d75e013..c3e2ec1 100644
--- a/include/boot.h
+++ b/include/boot.h
@@ -16,4 +16,5 @@ void __noreturn spin(unsigned long *mbox, unsigned long invalid, int is_entry);
void __noreturn first_spin(unsigned int cpu, unsigned long *mbox,
unsigned long invalid_addr);
+void dt_add_memreserve(void);
#endif
@@ -0,0 +1,102 @@
From 5995f83592aea874f5b423538e36675e2204582b Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 4 Jan 2022 17:01:55 +0800
Subject: [PATCH] boot: Add the --enable-keep-el compile option
Add --enable-keep-el compile option to enable boot-wrapper booting next
stage at EL2.
The Armv8R AArch64 boots at EL2. If the next stage requires EL2 booting,
the boot-wrapper should not drop to EL1.
Currently, this option only works for Armv8R AArch64. Also, to work with
Linux PSCI, this option will cause secondary cores booting at EL1.
Issue-Id: SCM-3813
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I3ba9c87cf0b59d163ca433f74c9e3a46e5ca2c63
---
Makefile.am | 4 ++++
arch/aarch64/boot.S | 6 +++++-
common/psci.c | 6 ++++++
configure.ac | 5 +++++
4 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index e905602..6604baa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -33,6 +33,10 @@ PSCI_CPU_ON := 0xc4000003
endif
PSCI_CPU_OFF := 0x84000002
+if KEEP_EL
+DEFINES += -DKEEP_EL
+endif
+
COMMON_SRC := common/
COMMON_OBJ := boot.o bakery_lock.o platform.o lib.o device_tree.o
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index 27b1139..c079d22 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -254,7 +254,11 @@ el2_init:
msr cnthctl_el2, x0
isb
+#ifdef KEEP_EL
+ mov w0, #SPSR_KERNEL
+#else
mov w0, #SPSR_KERNEL_EL1
+#endif
ldr x1, =spsr_to_elx
str w0, [x1]
// fall through
@@ -334,5 +338,5 @@ ASM_FUNC(jump_kernel)
.align 3
flag_keep_el:
.long 0
-spsr_to_elx:
+ASM_DATA(spsr_to_elx)
.long 0
diff --git a/common/psci.c b/common/psci.c
index a0e8700..945780b 100644
--- a/common/psci.c
+++ b/common/psci.c
@@ -18,6 +18,8 @@
#error "No MPIDRs provided"
#endif
+extern unsigned int spsr_to_elx;
+
static unsigned long branch_table[NR_CPUS];
bakery_ticket_t branch_table_lock[NR_CPUS];
@@ -44,6 +46,10 @@ static int psci_cpu_on(unsigned long target_mpidr, unsigned long address)
ret = psci_store_address(cpu, address);
bakery_unlock(branch_table_lock, this_cpu);
+#ifdef KEEP_EL
+ spsr_to_elx = SPSR_KERNEL_EL1;
+#endif
+
return ret;
}
diff --git a/configure.ac b/configure.ac
index 53e51be..0e07db3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,6 +25,11 @@ AS_IF([test "x$BOOTWRAPPER_ES" = x32 -a "x$KERNEL_ES" != x32],
[AC_MSG_ERROR([a 32-bit boot-wrapper cannot launch a 64-bit kernel])]
)
+AC_ARG_ENABLE([keep-el],
+ AC_HELP_STRING([--enable-keep-el], [keep exception level when start kernel]),
+ [KEEP_EL=yes], [KEEP_EL=no])
+AM_CONDITIONAL([KEEP_EL], [test "x$KEEP_EL" = xyes])
+
# Allow a user to pass --with-kernel-dir
AC_ARG_WITH([kernel-dir],
AS_HELP_STRING([--with-kernel-dir], [specify the root Linux kernel build directory (required)]),
@@ -0,0 +1,31 @@
From 0c0695cd3160ccdb95bae29b7668918015c0b6aa Mon Sep 17 00:00:00 2001
From: Peter Hoyes <Peter.Hoyes@arm.com>
Date: Tue, 1 Feb 2022 11:28:46 +0000
Subject: [PATCH] Makefile: Change COUNTER_FREQ to 100 MHz
Older Arm Fast Models (AEM < RevC) had a base frequency of 24 MHz. but
the RevC base models use 100 MHz. There is not a robust method of
determining the configured base frequency at runtime, so update
COUNTER_FREQ to be 100 MHz.
Issue-Id: SCM-3871
Upstream-Status: Pending
Signed-off-by: Peter Hoyes <Peter.Hoyes@arm.com>
Change-Id: Ia9ad0f8ee488d1a887791f1fa1d8f3bf9c5887fd
---
Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index 6604baa..cc6504e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ SCRIPT_DIR := $(top_srcdir)/scripts
PHYS_OFFSET := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findmem.pl $(KERNEL_DTB))
UART_BASE := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,pl011')
SYSREGS_BASE := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,vexpress-sysreg' 2> /dev/null)
-COUNTER_FREQ := 24000000
+COUNTER_FREQ := 100000000
CPU_IDS := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findcpuids.pl $(KERNEL_DTB))
NR_CPUS := $(shell echo $(CPU_IDS) | tr ',' ' ' | wc -w)
@@ -0,0 +1,49 @@
From fa73d885be85eee4369b292ec601e7b024a68807 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 2 Nov 2021 10:48:39 +0800
Subject: [PATCH] PSCI: Apply flush cache after setting branch_data
For v8-R64, Hypervisor calls boot-wrapper's PSCI service using simple
function call (instead of hvc).
In this case, hypervisor's main core has enabled MPU and cache, but
the secondary cores which are spinning have not enabled cache.
That means if the main core set the branch_data to 1 to boot other
cores, the secondary cores cannot see the change of branch_data and
also cannot break the spin.
Thus, the PSCI service in boot-wrapper needs a cache flush after
setting branch_data in order to let other cores see the change.
Issue-ID: SCM-3816
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: Ifc282091c54d8fb2ffdb8cfa7fd3ffc1f4be717e
---
common/psci.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/common/psci.c b/common/psci.c
index 945780b..6efc695 100644
--- a/common/psci.c
+++ b/common/psci.c
@@ -24,12 +24,18 @@ static unsigned long branch_table[NR_CPUS];
bakery_ticket_t branch_table_lock[NR_CPUS];
+static inline void flush_per_cpu_data(void *data)
+{
+ asm volatile ("dc cvac, %0" : : "r" (data));
+}
+
static int psci_store_address(unsigned int cpu, unsigned long address)
{
if (branch_table[cpu] != PSCI_ADDR_INVALID)
return PSCI_RET_ALREADY_ON;
branch_table[cpu] = address;
+ flush_per_cpu_data((void*)&(branch_table[cpu]));
return PSCI_RET_SUCCESS;
}
@@ -0,0 +1,71 @@
From 9da48e3433b919868650cd60e28827273a42c63b Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 25 Jan 2022 14:56:36 +0800
Subject: [PATCH] PSCI: Add function call entry point
The max exception level of Armv8R AArch64 is EL2, which means it has no
exclusive EL for firmware. That is, firmware and hypervisors have to share
the EL2. Also, hypervisors cannot call firmware services via a 'smc'
instruction. Thus, boot-wrapper has to provide a function entry point
for Armv8R AArch64.
Issue-Id: SCM-3816
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I06ec8e50298603155c6d8ae2330e71db2f111182
---
common/psci.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/common/psci.c b/common/psci.c
index 6efc695..8fdefb5 100644
--- a/common/psci.c
+++ b/common/psci.c
@@ -20,6 +20,8 @@
extern unsigned int spsr_to_elx;
+unsigned long flag_from_smc_fn[NR_CPUS];
+
static unsigned long branch_table[NR_CPUS];
bakery_ticket_t branch_table_lock[NR_CPUS];
@@ -49,12 +51,14 @@ static int psci_cpu_on(unsigned long target_mpidr, unsigned long address)
return PSCI_RET_INVALID_PARAMETERS;
bakery_lock(branch_table_lock, this_cpu);
- ret = psci_store_address(cpu, address);
- bakery_unlock(branch_table_lock, this_cpu);
-
#ifdef KEEP_EL
- spsr_to_elx = SPSR_KERNEL_EL1;
+ if (!flag_from_smc_fn[this_cpu]) {
+ spsr_to_elx = SPSR_KERNEL_EL1;
+ flush_per_cpu_data((void*)&(spsr_to_elx));
+ }
#endif
+ ret = psci_store_address(cpu, address);
+ bakery_unlock(branch_table_lock, this_cpu);
return ret;
}
@@ -90,6 +94,18 @@ long psci_call(unsigned long fid, unsigned long arg1, unsigned long arg2)
}
}
+long smc_fn_entry(unsigned long fid, unsigned long arg1, unsigned long arg2)
+{
+ long ret;
+ unsigned int this_cpu = this_cpu_logical_id();
+
+ flag_from_smc_fn[this_cpu] = 1;
+ ret = psci_call(fid, arg1, arg2);
+ flag_from_smc_fn[this_cpu] = 0;
+
+ return ret;
+}
+
void __noreturn psci_first_spin(unsigned int cpu)
{
if (cpu == MPIDR_INVALID)
@@ -0,0 +1,58 @@
From 7c5e40d9f8699a55ac2187c035429c643e6d0ef0 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Tue, 2 Nov 2021 15:10:28 +0800
Subject: [PATCH] lds: Rearrange and mark the sections
To make it possible for the next stage to protect sections with MPU,
boot-wrapper needs to provide the text and data section information.
By rearranging the .data .rodata and .vector sections, all sections
can be split into 2 big sections:
- RO and Executable
- RW and Non-Executable
Add firmware_data to mark the boundry, thus:
firmware_start to firmware_data - 1 indicates RO and Executable section,
firmware_data to firmware_end - 1 indicates RW and Non-Executable
section.
Also, the firmware_data and firmware_end should align with 64 bytes,
since Armv8R AArch64 MPU requires it.
Issue-ID: SCM-3816
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I55342aa7492f2c7b5c16ab9a6472c8cb45cff8fd
---
model.lds.S | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/model.lds.S b/model.lds.S
index ab98ddf..85451f9 100644
--- a/model.lds.S
+++ b/model.lds.S
@@ -63,12 +63,16 @@ SECTIONS
}
#endif
+#define FIRMWARE_ALIGN . = ALIGN(1 << 6)
.boot PHYS_OFFSET: {
PROVIDE(firmware_start = .);
*(.init)
*(.text*)
- *(.data* .rodata* .bss* COMMON)
*(.vectors)
+ *(.rodata*)
+ FIRMWARE_ALIGN;
+ PROVIDE(firmware_data = .);
+ *(.data* .bss* COMMON)
*(.stack)
PROVIDE(etext = .);
}
@@ -77,6 +81,7 @@ SECTIONS
mbox = .;
QUAD(0x0)
}
+ FIRMWARE_ALIGN;
PROVIDE(firmware_end = .);
ASSERT(etext <= (PHYS_OFFSET + TEXT_LIMIT), ".text overflow!")
@@ -0,0 +1,342 @@
From 3c1140c29c39561848056fb4b9a03042b00279f3 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Wed, 29 Dec 2021 15:17:38 +0800
Subject: [PATCH] common: Provide firmware info using libfdt
Boot-wrapper uses libfdt to provide more info in device tree.
We add a new node to include those new firmware relevant infomation.
The new node defined as follows:
fw-shared-info {
compatible = "firmware,shared_info";
#address-cells = <0x02>;
#size-cells = <0x02>;
version = "1.0";
regions = <START_ADDR_HIGH START_ADDR_LOW SIZE_HIGH SIZE_LOW
0x0 0x80000000 0x0 0x400000
0x0 0x90000000 0x0 0x400000
0x0 0xA0000000 0x0 0x400000>;
regions-permission = "RX", "R", "RWX", "RW";
regions-cache = "Cache", "NCache", "Cache", "Device"
function_entry = <ENTRY_ADDR_HIGH ENRTY_ADDR_LOW>;
};
The node path is /fw-shared-info.
For boot-wrapper, in real case, it will be:
fw-shared-info {
compatible = "firmware,shared_info";
#address-cells = <0x02>;
#size-cells = <0x02>;
version = "1.0";
regions = <0x0 firmware_start 0x0 firmware_code_size
0x0 firmware_data 0x0 firmware_data_size>;
regions-permission = "RX", "RW";
regions-cache = "Cache", "Cache";
function_entry = <0x0 smc_fn_entry>;
};
Issue-Id: SCM-3816
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: I6ebc59ce2bd3939b0fe066720d57821eaa1bed27
---
common/device_tree.c | 271 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 270 insertions(+), 1 deletion(-)
diff --git a/common/device_tree.c b/common/device_tree.c
index 4d0876c..7f7befc 100644
--- a/common/device_tree.c
+++ b/common/device_tree.c
@@ -8,13 +8,225 @@
*/
#include <libfdt.h>
+#define DEVICE_TREE_DEBUG 1
+
+#define FW_NODE_NAME "/fw-shared-info"
+#define FW_COMPAT "firmware,shared_info"
+#define FW_INFO_VER "1.0"
+
+#ifdef BOOTWRAPPER_32
+#define CELL_NUM 1
+#define VAL_TYPE uint32_t
+#else
+#define CELL_NUM 2
+#define VAL_TYPE uint64_t
+#endif
+
+#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
+
extern unsigned long dtb;
-extern char firmware_start[], firmware_end[];
+extern char firmware_start[], firmware_data[], firmware_end[];
+
+extern long smc_fn_entry(unsigned long, unsigned long, unsigned long);
extern void print_string(const char *str);
+extern void print_hex(unsigned int val);
static void *blob;
+static char *realloc_node(char *fdt, const char *name)
+{
+ int delta;
+ int new_sz;
+ /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
+ delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
+ + FDT_TAGSIZE;
+ new_sz = fdt_totalsize(fdt) + delta;
+ fdt_open_into(fdt, fdt, new_sz);
+ return fdt;
+}
+
+static int create_node(const char *node_name)
+{
+ int node = 0;
+ char *p;
+
+ p = strrchr(node_name, '/');
+ if (!p) {
+ print_string("node name without '/'\r\n");
+ return -1;
+ }
+ *p = '\0';
+
+ blob = realloc_node(blob, p + 1);
+
+ if (p > node_name) {
+ node = fdt_path_offset(blob, node_name);
+ if (node < 0) {
+ print_string("no node name\r\n");
+ return -1;
+ }
+ }
+
+ node = fdt_add_subnode(blob, node, p + 1);
+ if (node < 0) {
+ print_string("add subnode err\r\n");
+ return -1;
+ }
+
+ return node;
+}
+
+static int dt_create_fw_node(void) {
+ int fw_node;
+
+ fw_node = fdt_path_offset(blob, FW_NODE_NAME);
+
+ if(fw_node < 0) {
+ fw_node = create_node(FW_NODE_NAME);
+ }
+
+ return fw_node;
+}
+
+static char *realloc_property(char *fdt, int nodeoffset, const char *name,
+ int newlen)
+{
+ int delta = 0;
+ int oldlen = 0;
+ int new_sz;
+
+ if (!fdt_get_property(fdt, nodeoffset, name, &oldlen))
+ delta = sizeof(struct fdt_property) + strlen(name) + 1;
+
+ if (newlen > oldlen)
+ delta += ALIGN(newlen) - ALIGN(oldlen);
+
+ new_sz = fdt_totalsize(fdt) + delta;
+ fdt_open_into(fdt, fdt, new_sz);
+ return fdt;
+}
+
+static void dt_set_prop(int node, char *property, void *buf, int len)
+{
+ int err;
+
+ err = fdt_setprop(blob, node, property, buf, len);
+ if (err == -FDT_ERR_NOSPACE) {
+ blob = realloc_property(blob, node, property, len);
+ err = fdt_setprop(blob, node, property, buf, len);
+ }
+ if (err) {
+ print_string("fdt error\n\r");
+ }
+}
+
+static void dt_set_prop_u32(int node, char *property, uint32_t val)
+{
+ fdt32_t fdt_val = cpu_to_fdt32(val);
+ int len = sizeof(fdt32_t);
+
+ dt_set_prop(node, property, (void*)&fdt_val, len);
+}
+
+static void dt_set_prop_u64(int node, char *property, uint64_t val)
+{
+ fdt64_t fdt_val = cpu_to_fdt64(val);
+ int len = sizeof(fdt64_t);
+
+ dt_set_prop(node, property, (void*)&fdt_val, len);
+}
+
+/* This dt_set_prop_u32_array maybe unused according to the BOOTWRAPPER_32 */
+__attribute__((unused))
+static void dt_set_prop_u32_array(int node, char *property, uint32_t *vals,
+ int size)
+{
+ fdt32_t *fdt_vals = (fdt32_t*)vals;
+ int len = sizeof(fdt32_t) * size;
+
+ for (int i = 0; i < size; i++) {
+ fdt_vals[i] = cpu_to_fdt32(vals[i]);
+ }
+
+ dt_set_prop(node, property, (void*)fdt_vals, len);
+}
+
+static void dt_set_prop_u64_array(int node, char *property, uint64_t *vals,
+ int size)
+{
+ fdt64_t *fdt_vals = (fdt64_t*)vals;
+ int len = sizeof(fdt64_t) * size;
+
+ for (int i = 0; i < size; i++) {
+ fdt_vals[i] = cpu_to_fdt64(vals[i]);
+ }
+
+ dt_set_prop(node, property, (void*)fdt_vals, len);
+}
+
+#if DEVICE_TREE_DEBUG
+static void dt_dump_string(const void *s, int len)
+{
+ char *sub = (char*)s;
+ int sublen;
+ while(*sub && ((uint64_t)sub - (uint64_t)s) < len) {
+ sublen = strlen(sub) + 1;
+ print_string(sub);
+ print_string(" ");
+ sub += sublen;
+ }
+ print_string("\n\r");
+}
+
+static void dt_dump_fdt32_array(const void *vals, int len)
+{
+ fdt32_t *fdt_vals = (fdt32_t*)vals;
+ len = len / sizeof(fdt32_t);
+ for (int i = 0; i < len; i++) {
+ print_hex(fdt32_to_cpu(fdt_vals[i]));
+ print_string(" ");
+ }
+ print_string("\n\r");
+}
+
+static void dt_dump(int node, char *property, char type)
+{
+ const void *val;
+ int len;
+
+ val = fdt_getprop(blob, node, property, &len);
+ print_string(property);
+ print_string(": ");
+
+ if (type == 's') {
+ /* string type */
+ dt_dump_string(val, len);
+ return;
+ }
+
+ /* uint type */
+ dt_dump_fdt32_array(val, len);
+}
+
+void dt_dump_all(int node)
+{
+ if (node >= 0) {
+ print_string(FW_NODE_NAME" info:\r\n");
+ dt_dump(node, "compatible", 's');
+ dt_dump(node, "version", 's');
+ dt_dump(node, "function_entry", 'i');
+ dt_dump(node, "address-cells", 'i');
+ dt_dump(node, "size-cells", 'i');
+ dt_dump(node, "regions", 'i');
+ dt_dump(node, "regions-permission", 's');
+ dt_dump(node, "regions-cache", 's');
+ print_string("\r\n");
+ }
+}
+#else
+void dt_dump_all(int node) { (void*)node; return; }
+#endif
void dt_add_memreserve(void)
{
@@ -32,3 +244,60 @@ void dt_add_memreserve(void)
print_string("reserve mem add err\n\r");
}
}
+
+void dt_fw_node_init(int enable)
+{
+ int fw_node;
+
+ VAL_TYPE regions[] = {
+ /* code region: start, end, ro, x, cachable */
+ (VAL_TYPE)firmware_start,
+ (VAL_TYPE)(firmware_data - firmware_start),
+ /* data region: start, end, rw, xn, cachable */
+ (VAL_TYPE)firmware_data,
+ (VAL_TYPE)(firmware_end - firmware_data),
+ };
+ int regions_num = sizeof(regions) / sizeof(VAL_TYPE);
+ char regions_permission[] = "RX\0RW";
+ char regions_cache[] = "Cache\0Cache";
+
+ if (!enable)
+ return;
+
+ print_string("Prepare "FW_NODE_NAME" node\n\r");
+
+ blob = (void*)&dtb;
+
+ if(fdt_path_offset(blob, "/psci") < 0) {
+ print_string("/psci node not found\n\r");
+ return;
+ }
+
+ fw_node = dt_create_fw_node();
+
+ if(fw_node < 0) {
+ print_string(FW_NODE_NAME" node create err\n\r");
+ }
+
+ dt_set_prop(fw_node, "compatible", FW_COMPAT, sizeof(FW_COMPAT));
+ dt_set_prop(fw_node, "version", FW_INFO_VER, sizeof(FW_INFO_VER));
+
+ dt_set_prop_u32(fw_node, "address-cells", CELL_NUM);
+ dt_set_prop_u32(fw_node, "size-cells", CELL_NUM);
+ dt_set_prop(fw_node, "regions-permission", regions_permission,
+ sizeof(regions_permission));
+ dt_set_prop(fw_node, "regions-cache", regions_cache,
+ sizeof(regions_cache));
+
+#ifdef BOOTWRAPPER_32
+ dt_set_prop_u32_array(fw_node, "regions", regions, regions_num);
+ dt_set_prop_u32(fw_node, "function_entry", (VAL_TYPE)smc_fn_entry);
+#else
+ dt_set_prop_u64_array(fw_node, "regions", regions, regions_num);
+ dt_set_prop_u64(fw_node, "function_entry", (VAL_TYPE)smc_fn_entry);
+#endif
+
+ fdt_pack(blob);
+
+ dt_dump_all(fw_node);
+}
@@ -0,0 +1,95 @@
From b1105e862e8f770fc195bc20e9c64d231dd32f66 Mon Sep 17 00:00:00 2001
From: Jaxson Han <jaxson.han@arm.com>
Date: Wed, 29 Dec 2021 15:33:17 +0800
Subject: [PATCH] boot: Enable firmware node initialization
Enable the firmware node initialization, so that the next stage
(hypervisor) could share the EL2 with firmware (boot-wrapper). The next
stage (hypervisor) get the smccc entry point, code/data sections, the
sections attrs and firmware node version and so on.
It is worth noting that this EL2 sharing mechanism is only for Armv8R
AArch64, thus add flag_v8r to record if the arch is Armv8R AArch64.
Enable the firmware node initialization only if it is Armv8R AArch64.
Also, we increase the stack size to 1024 to fix the stack overflow issue
when using the libfdt.
Add -fno-builtin options to CFLAGS to avoid the issue that the 'memset'
in common/lib.c conflicts with builtin 'memset' function. GCC version
>= 10 will have an incorrect compilation without -fno-builtin;
Issue-Id: SCM-3816
Upstream-Status: Inappropriate [other]
Implementation pending further discussion
Signed-off-by: Jaxson Han <jaxson.han@arm.com>
Change-Id: Ib274485a34d26215595fd0cd737be86610289817
---
Makefile.am | 4 ++--
arch/aarch64/boot.S | 6 ++++++
common/boot.c | 4 ++++
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index cc6504e..fbe6b81 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,7 +23,7 @@ DEFINES += -DCPU_IDS=$(CPU_IDS)
DEFINES += -DNR_CPUS=$(NR_CPUS)
DEFINES += $(if $(SYSREGS_BASE), -DSYSREGS_BASE=$(SYSREGS_BASE), )
DEFINES += -DUART_BASE=$(UART_BASE)
-DEFINES += -DSTACK_SIZE=256
+DEFINES += -DSTACK_SIZE=1024
if KERNEL_32
DEFINES += -DKERNEL_32
@@ -134,7 +134,7 @@ CFLAGS += -I$(top_srcdir)/include/ -I$(top_srcdir)/$(ARCH_SRC)/include/
CFLAGS += -Wall -fomit-frame-pointer
CFLAGS += -ffreestanding -nostdlib
CFLAGS += -fno-stack-protector
-CFLAGS += -fno-stack-protector
+CFLAGS += -fno-stack-protector -fno-builtin
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -fno-pic -fno-pie
LDFLAGS += --gc-sections
diff --git a/arch/aarch64/boot.S b/arch/aarch64/boot.S
index c079d22..daaa674 100644
--- a/arch/aarch64/boot.S
+++ b/arch/aarch64/boot.S
@@ -261,6 +261,10 @@ el2_init:
#endif
ldr x1, =spsr_to_elx
str w0, [x1]
+
+ mov w0, #1
+ ldr x1, =flag_v8r
+ str w0, [x1]
// fall through
el_max_init:
@@ -340,3 +344,5 @@ flag_keep_el:
.long 0
ASM_DATA(spsr_to_elx)
.long 0
+ASM_DATA(flag_v8r)
+ .long 0
diff --git a/common/boot.c b/common/boot.c
index ee2bea0..38b2dca 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -11,6 +11,9 @@
extern unsigned long entrypoint;
extern unsigned long dtb;
+extern unsigned int flag_v8r;
+
+extern void dt_fw_node_init(int enable);
void init_platform(void);
@@ -64,6 +67,7 @@ void __noreturn first_spin(unsigned int cpu, unsigned long *mbox,
if (cpu == 0) {
init_platform();
dt_add_memreserve();
+ dt_fw_node_init(flag_v8r == 1);
*mbox = (unsigned long)&entrypoint;
sevl();