From bade0a85e7179f37fa18725051b46ba2f7c20d48 Mon Sep 17 00:00:00 2001 From: Piotr Tworek Date: Fri, 11 Feb 2022 00:36:49 +0100 Subject: [PATCH] base-hw: Implement CPU core identification for Cortex-A55. According to ARM Cortex-A55 Core Technical Reference Manual r1p0 the lowest 8 bits (Aff0) of MPIDR register represent thread IDs within a multi-threaded core. The actual core identification bits are in Aff1. This layout can be identified by checking the MT bit of MPIDR register. Basically, if MT=1 core id is in Aff1, if MT=0 core id is in Aff0. Without this change Genode will identify all CPU cores on A55 as primary (0) core. Its worth to mention that Cortex-A55 by itself is not a multi-threaded CPU. Aff0 values are always expected to be 0 for pure A55 cores. A55 cores can however be paired with cores that are multi-threaded. To support such big.LITTLE CPUs in Genode we'd probably need to add a different mechanism for mapping MPIDR values to logical, contignous core IDs which Genode expects. Ref: https://developer.arm.com/documentation/100442/0100/register-descriptions/aarch64-system-registers/mpidr-el1--multiprocessor-affinity-register--el1?lang=en --- .../src/bootstrap/spec/arm_64/cortex_a53_mmu.cc | 7 ++----- repos/base-hw/src/bootstrap/spec/arm_64/crt0.s | 4 ++++ repos/base-hw/src/core/spec/arm_v8/cpu.h | 2 +- repos/base-hw/src/include/hw/spec/arm_64/cpu.h | 15 ++++++++++++++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc b/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc index 9f9a354b81..e0a80d13bf 100644 --- a/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc +++ b/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc @@ -138,11 +138,8 @@ static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr, unsigned Bootstrap::Platform::enable_mmu() { - static volatile bool primary_cpu = true; - bool primary = primary_cpu; - if (primary) primary_cpu = false; - - unsigned cpu_id = (Cpu::Mpidr::read() & 0xff); + unsigned const cpu_id { Cpu::current_core_id() }; + bool const primary { cpu_id == 0 }; Cpu::Ttbr::access_t ttbr = Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base); diff --git a/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s b/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s index 7517485e70..882916783d 100644 --- a/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s +++ b/repos/base-hw/src/bootstrap/spec/arm_64/crt0.s @@ -16,6 +16,10 @@ */ .macro _cpu_number mrs x0, mpidr_el1 + and x8, x0, #(1<<24) /* MT bit */ + cbz x8, 1f + lsr x0, x0, #8 +1: and x0, x0, #0b11111111 .endm diff --git a/repos/base-hw/src/core/spec/arm_v8/cpu.h b/repos/base-hw/src/core/spec/arm_v8/cpu.h index 29fa1f547a..a9ca159ea3 100644 --- a/repos/base-hw/src/core/spec/arm_v8/cpu.h +++ b/repos/base-hw/src/core/spec/arm_v8/cpu.h @@ -106,7 +106,7 @@ struct Genode::Cpu : Hw::Arm_64_cpu /** * Return kernel name of the executing CPU */ - static unsigned executing_id() { return Cpu::Mpidr::read() & 0xff; } + static unsigned executing_id() { return Cpu::current_core_id(); } static size_t cache_line_size(); static void clear_memory_region(addr_t const addr, diff --git a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h index d3d0ef0117..a3599a8dfd 100644 --- a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h +++ b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h @@ -141,7 +141,12 @@ struct Hw::Arm_64_cpu SYSTEM_REGISTER(64, Mair_el1, mair_el1); SYSTEM_REGISTER(64, Mair_el2, mair_el2); - SYSTEM_REGISTER(64, Mpidr, mpidr_el1); + SYSTEM_REGISTER(64, Mpidr, mpidr_el1, + struct Aff0 : Bitfield<0, 8> {}; + struct Aff1 : Bitfield<8, 8> {}; + struct Aff2 : Bitfield<16, 8> {}; + struct MT : Bitfield<24, 1> {}; + ); SYSTEM_REGISTER(32, Pmcr_el0, pmcr_el0); SYSTEM_REGISTER(32, Pmcntenset_el0, pmcntenset_el0); @@ -256,6 +261,14 @@ struct Hw::Arm_64_cpu using Cntpct = Cntpct_el0; using Cntp_tval = Cntp_tval_el0; + static inline unsigned current_core_id() + { + Mpidr::access_t mpidr = Mpidr::read(); + if (Mpidr::MT::get(mpidr)) + return (unsigned)Mpidr::Aff1::get(mpidr); + return (unsigned)Mpidr::Aff0::get(mpidr); + } + static inline void wait_for_xchg(volatile int * addr, int new_value, int expected_value)