From f28191a735e11b34323caa96ed42b3366a07f5b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Wed, 21 Aug 2019 00:00:00 +0000 Subject: [PATCH] baremetal aarch64: create C version of multicore.S as well Attempted to do the same for arm, but it failed. --- README.adoc | 39 ++++++++++---- baremetal/arch/aarch64/multicore.c | 45 ++++++++++++++++ baremetal/arch/aarch64/no_bootloader/exit.S | 8 +++ .../multicore_asm.S} | 29 +++++++---- .../aarch64/no_bootloader/semihost_exit.S | 10 ++-- baremetal/arch/aarch64/semihost_exit.S | 2 + baremetal/arch/aarch64/svc.c | 2 +- baremetal/arch/aarch64/timer.c | 2 +- baremetal/arch/arm/multicore.c | 37 +++++++++++++ .../multicore_asm.S} | 22 ++++---- baremetal/lib/aarch64.S | 10 ++++ baremetal/lib/arm.S | 10 ++++ baremetal/lib/syscalls.c | 48 +++-------------- baremetal/lib/syscalls_asm.S | 35 +++++++++++++ build-baremetal | 11 +++- lkmc.c | 52 ++++++++++++++++++- lkmc.h | 7 ++- lkmc/aarch64.h | 21 +++++--- lkmc/arm.h | 12 +++++ lkmc/arm_aarch64.h | 12 +++++ path_properties.py | 11 +++- 21 files changed, 336 insertions(+), 89 deletions(-) create mode 100644 baremetal/arch/aarch64/multicore.c create mode 100644 baremetal/arch/aarch64/no_bootloader/exit.S rename baremetal/arch/aarch64/{multicore.S => no_bootloader/multicore_asm.S} (84%) create mode 100644 baremetal/arch/arm/multicore.c rename baremetal/arch/arm/{multicore.S => no_bootloader/multicore_asm.S} (68%) create mode 100644 baremetal/lib/syscalls_asm.S create mode 100644 lkmc/arm_aarch64.h diff --git a/README.adoc b/README.adoc index 5bba950..d156368 100644 --- a/README.adoc +++ b/README.adoc @@ -15470,15 +15470,23 @@ Semihosting is implemented both on some real devices and on simulators such as Q It is documented at: https://developer.arm.com/docs/100863/latest/introduction -For example, the following code makes QEMU exit: +For example, all the following code make QEMU exit: .... ./run --arch arm --baremetal baremetal/arch/arm/semihost_exit.S +./run --arch arm --baremetal baremetal/arch/arm/no_bootloader/semihost_exit.S +./run --arch aarch64 --baremetal baremetal/arch/aarch64/semihost_exit.S +./run --arch aarch64 --baremetal baremetal/arch/aarch64/no_bootloader/semihost_exit.S .... -Source: link:baremetal/arch/arm/no_bootloader/semihost_exit.S[] +Sources: -That program program contains the code: +* link:baremetal/arch/arm/semihost_exit.S[] +* link:baremetal/arch/arm/no_bootloader/semihost_exit.S[] +* link:baremetal/arch/aarch64/semihost_exit.S[] +* link:baremetal/arch/aarch64/no_bootloader/semihost_exit.S[] + +That `arm` program program contains the code: .... mov r0, #0x18 @@ -16171,17 +16179,26 @@ See the example at: xref:arm-svc-instruction[xrefstyle=full] ==== ARM multicore +Examples: + .... -./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.S --cpus 2 -./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.S --cpus 2 --emulator gem5 -./run --arch arm --baremetal baremetal/arch/aarch64/multicore.S --cpus 2 -./run --arch arm --baremetal baremetal/arch/aarch64/multicore.S --cpus 2 --emulator gem5 +./run --arch aarch64 --baremetal baremetal/arch/aarch64/no_bootloader/multicore_asm.S --cpus 2 +./run --arch aarch64 --baremetal baremetal/arch/aarch64/no_bootloader/multicore_asm.S --cpus 2 --emulator gem5 +./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.c --cpus 2 +./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.c --cpus 2 --emulator gem5 +./run --arch arm --baremetal baremetal/arch/arm/no_bootloader/multicore_asm.S --cpus 2 +./run --arch arm --baremetal baremetal/arch/arm/no_bootloader/multicore_asm.S --cpus 2 --emulator gem5 +# TODO not working, hangs. +# ./run --arch arm --baremetal baremetal/arch/arm/multicore.c --cpus 2 +./run --arch arm --baremetal baremetal/arch/arm/multicore.c --cpus 2 --emulator gem5 .... Sources: -* link:baremetal/arch/aarch64/multicore.S[] -* link:baremetal/arch/arm/multicore.S[] +* link:baremetal/arch/aarch64/no_bootloader/multicore_asm.S[] +* link:baremetal/arch/aarch64/multicore.c[] +* link:baremetal/arch/arm/no_bootloader/multicore_asm.S[] +* link:baremetal/arch/arm/multicore.c[] CPU 0 of this program enters a spinlock loop: it repeatedly checks if a given memory address is 1. @@ -16190,7 +16207,7 @@ So, we need CPU 1 to come to the rescue and set that memory address to 1, otherw Don't believe me? Then try: .... -./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.S --cpus 1 +./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.c --cpus 1 .... and watch it hang forever. @@ -16198,7 +16215,7 @@ and watch it hang forever. Note that if you try the same thing on gem5: .... -./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.S --cpus 1 --emulator gem5 +./run --arch aarch64 --baremetal baremetal/arch/aarch64/multicore.c --cpus 1 --emulator gem5 .... then the gem5 actually exits with <> as opposed to the expected: diff --git a/baremetal/arch/aarch64/multicore.c b/baremetal/arch/aarch64/multicore.c new file mode 100644 index 0000000..151ed35 --- /dev/null +++ b/baremetal/arch/aarch64/multicore.c @@ -0,0 +1,45 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#arm-multicore + * + * Beware: things will blow up if the stack for CPU0 grow too much and + * reaches that of CPU1. This is why it is so hard to do multithreading + * without an OS that manages paging. + */ + +#include + +uint64_t spinlock = 0; + +__asm__( +".text\n" +".global lkmc_cpu_not_0\n" +"lkmc_cpu_not_0:\n" +/* Put all CPUs except CPU1 to sleep. */ +" cmp x0, 1\n" +" bne .Lsleep_forever\n" +/* Prepare the stack for CPU1. This is what we need + * this assembly function for. */ +" ldr x0, =(stack_top - 0x1000)\n" +" mov sp, x0\n" +" bl main_cpu1\n" +".Lsleep_forever:\n" +" wfe\n" +" b .Lsleep_forever\n" +); + +static void main_cpu1(void) { + spinlock = 1; + lkmc_arm_aarch64_dmb(sy); + lkmc_arm_aarch64_sev(); + while (1) { + lkmc_arm_aarch64_wfe(); + } +} + +int main(void) { +#if !LKMC_GEM5 + lkmc_aarch64_psci_cpu_on(1, (uint64_t)main_cpu1, 0); +#endif + while (!spinlock) { + lkmc_arm_aarch64_wfe(); + } +} diff --git a/baremetal/arch/aarch64/no_bootloader/exit.S b/baremetal/arch/aarch64/no_bootloader/exit.S new file mode 100644 index 0000000..5ce2a2b --- /dev/null +++ b/baremetal/arch/aarch64/no_bootloader/exit.S @@ -0,0 +1,8 @@ +/* Test _exit. */ + +#include + +.global lkmc_start +lkmc_start: + mov x0, 0 + bl _exit diff --git a/baremetal/arch/aarch64/multicore.S b/baremetal/arch/aarch64/no_bootloader/multicore_asm.S similarity index 84% rename from baremetal/arch/aarch64/multicore.S rename to baremetal/arch/aarch64/no_bootloader/multicore_asm.S index 6f91d0e..d0a270f 100644 --- a/baremetal/arch/aarch64/multicore.S +++ b/baremetal/arch/aarch64/no_bootloader/multicore_asm.S @@ -1,11 +1,15 @@ -/* https://cirosantilli.com/linux-kernel-module-cheat#arm-multicore */ +/* https://cirosantilli.com/linux-kernel-module-cheat#arm-multicore + * + * This has to be in no_bootloader + */ #include -LKMC_PROLOGUE +.global lkmc_start +lkmc_start: /* Reset spinlock. */ mov x0, 0 - ldr x1, =spinlock + ldr x1, =.Lspinlock str x0, [x1] /* Read cpu id into x1. @@ -14,11 +18,11 @@ LKMC_PROLOGUE */ mrs x1, mpidr_el1 ands x1, x1, 3 - beq cpu0_only + beq .Lcpu0_only .Lcpu1_only: /* Only CPU 1 reaches this point and sets the spinlock. */ mov x0, 1 - ldr x1, =spinlock + ldr x1, =.Lspinlock str x0, [x1] /* Ensure that CPU 0 sees the write right now. * Optional, but could save some useless CPU 1 loops. @@ -34,7 +38,7 @@ LKMC_PROLOGUE */ wfe b .Lcpu1_sleep_forever -cpu0_only: +.Lcpu0_only: /* Only CPU 0 reaches this point. */ #if !LKMC_GEM5 @@ -61,11 +65,14 @@ cpu0_only: hvc 0 #endif -spinlock_start: - ldr x0, spinlock +.Lspinlock_start: + ldr x0, .Lspinlock /* Hint CPU 0 to enter low power mode. */ wfe - cbz x0, spinlock_start -LKMC_EPILOGUE -spinlock: + cbz x0, .Lspinlock_start + + mov x0, 0 + bl _exit + +.Lspinlock: .skip 8 diff --git a/baremetal/arch/aarch64/no_bootloader/semihost_exit.S b/baremetal/arch/aarch64/no_bootloader/semihost_exit.S index 20295d3..c91d81c 100644 --- a/baremetal/arch/aarch64/no_bootloader/semihost_exit.S +++ b/baremetal/arch/aarch64/no_bootloader/semihost_exit.S @@ -1,15 +1,19 @@ -/* https://cirosantilli.com/linux-kernel-module-cheat#semihosting */ +/* https://cirosantilli.com/linux-kernel-module-cheat#semihosting + * + * Since our stack pointer is not setup, we justa allocate a memory + * region to contain the semihosting arguments, which must be in memory. + */ .global lkmc_start lkmc_start: mov x1, 0x26 movk x1, 2, lsl 16 - ldr x2, =semihost_args + ldr x2, =.Lsemihost_args str x1, [x2, 0] mov x0, 0 str x0, [x2, 8] mov x1, x2 mov w0, 0x18 hlt 0xf000 -semihost_args: +.Lsemihost_args: .skip 16 diff --git a/baremetal/arch/aarch64/semihost_exit.S b/baremetal/arch/aarch64/semihost_exit.S index ce09a36..3c835b9 100644 --- a/baremetal/arch/aarch64/semihost_exit.S +++ b/baremetal/arch/aarch64/semihost_exit.S @@ -1,3 +1,5 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#semihosting */ + .global main main: /* 0x20026 == ADP_Stopped_ApplicationExit */ diff --git a/baremetal/arch/aarch64/svc.c b/baremetal/arch/aarch64/svc.c index 4f132b1..62e1746 100644 --- a/baremetal/arch/aarch64/svc.c +++ b/baremetal/arch/aarch64/svc.c @@ -71,7 +71,7 @@ int main(void) { printf("&after_svc %p\n", &&after_svc); assert(myvar == 0); /* Max 16-bits. */ - lkmc_svc(0xABCD); + lkmc_arm_aarch64_svc(0xABCD); after_svc: assert(myvar == 1); return 0; diff --git a/baremetal/arch/aarch64/timer.c b/baremetal/arch/aarch64/timer.c index 46b94f9..34dbf13 100644 --- a/baremetal/arch/aarch64/timer.c +++ b/baremetal/arch/aarch64/timer.c @@ -113,7 +113,7 @@ int main(void) { enable_irq(); } while (1) { - lkmc_wfi(); + lkmc_arm_aarch64_wfi(); } return 0; } diff --git a/baremetal/arch/arm/multicore.c b/baremetal/arch/arm/multicore.c new file mode 100644 index 0000000..c29ea76 --- /dev/null +++ b/baremetal/arch/arm/multicore.c @@ -0,0 +1,37 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#arm-multicore */ + +#include + +uint64_t spinlock = 0; + +__asm__( +".syntax unified\n" +".text\n" +".global lkmc_cpu_not_0\n" +"lkmc_cpu_not_0:\n" +" cmp r0, 1\n" +" bne .Lsleep_forever\n" +" ldr sp, =(stack_top - 0x1000)\n" +" bl main_cpu1\n" +".Lsleep_forever:\n" +" wfe\n" +" b .Lsleep_forever\n" +); + +static void main_cpu1(void) { + spinlock = 1; + lkmc_arm_aarch64_dmb(sy); + lkmc_arm_aarch64_sev(); + while (1) { + lkmc_arm_aarch64_wfe(); + } +} + +int main(void) { +#if !LKMC_GEM5 + lkmc_arm_psci_cpu_on(1, (uint32_t)main_cpu1, 0); +#endif + while (!spinlock) { + lkmc_arm_aarch64_wfe(); + } +} diff --git a/baremetal/arch/arm/multicore.S b/baremetal/arch/arm/no_bootloader/multicore_asm.S similarity index 68% rename from baremetal/arch/arm/multicore.S rename to baremetal/arch/arm/no_bootloader/multicore_asm.S index 82df24a..ba87d4e 100644 --- a/baremetal/arch/arm/multicore.S +++ b/baremetal/arch/arm/no_bootloader/multicore_asm.S @@ -2,24 +2,25 @@ #include -LKMC_PROLOGUE +.global lkmc_start +lkmc_start: mov r0, 0 - ldr r1, =spinlock + ldr r1, =.Lspinlock str r0, [r1] /* Get CPU ID. */ mrc p15, 0, r1, c0, c0, 5 ands r1, r1, 3 - beq cpu0_only + beq .Lcpu0_only .Lcpu1_only: mov r0, 1 - ldr r1, =spinlock + ldr r1, =.Lspinlock str r0, [r1] dmb sy sev .Lcpu1_sleep_forever: wfe b .Lcpu1_sleep_forever -cpu0_only: +.Lcpu0_only: #if !LKMC_GEM5 /* PSCI CPU_ON. */ ldr r0, =0x84000003 @@ -28,11 +29,12 @@ cpu0_only: mov r3, 0 hvc 0 #endif -spinlock_start: - ldr r0, spinlock +.Lspinlock_start: + ldr r0, .Lspinlock wfe cmp r0, 0 - beq spinlock_start -LKMC_EPILOGUE -spinlock: + beq .Lspinlock_start + mov r0, 0 + bl _exit +.Lspinlock: .skip 4 diff --git a/baremetal/lib/aarch64.S b/baremetal/lib/aarch64.S index 351ddef..63c8b5a 100644 --- a/baremetal/lib/aarch64.S +++ b/baremetal/lib/aarch64.S @@ -2,6 +2,11 @@ .global lkmc_start lkmc_start: + /* Make all CPUs except CPU0 sleep by default. */ + mrs x0, mpidr_el1 + ands x0, x0, 3 + bne lkmc_cpu_not_0 + /* Load the vector table. */ ldr x0, =lkmc_vector_table msr vbar_el1, x0 @@ -41,3 +46,8 @@ LKMC_WEAK(lkmc_vector_trap_handler) bl abort lkmc_vector_trap_handler_error_message: .asciz "error: unexpected interrupt" + +/* Default action for CPUs besides the first one: sleep forever. */ +LKMC_WEAK(lkmc_cpu_not_0) + wfe + b lkmc_cpu_not_0 diff --git a/baremetal/lib/arm.S b/baremetal/lib/arm.S index 6f0d149..eb7d314 100644 --- a/baremetal/lib/arm.S +++ b/baremetal/lib/arm.S @@ -2,6 +2,11 @@ .global lkmc_start lkmc_start: + /* Make all CPUs except CPU0 sleep by default. */ + mrc p15, 0, r0, c0, c0, 5 + ands r0, r0, 3 + bne lkmc_cpu_not_0 + /* Prepare the stack for main, mandatory for C code. */ ldr sp, =stack_top @@ -28,3 +33,8 @@ lkmc_start: /* If main returns, exit. */ bl exit + +/* Default action for CPUs besides the first one: sleep forever. */ +LKMC_WEAK(lkmc_cpu_not_0) + wfe + b lkmc_cpu_not_0 diff --git a/baremetal/lib/syscalls.c b/baremetal/lib/syscalls.c index 647d1cd..af4c464 100644 --- a/baremetal/lib/syscalls.c +++ b/baremetal/lib/syscalls.c @@ -3,14 +3,6 @@ #include #include -#include - -void lkmc_baremetal_on_exit_callback(int status, void *arg) { - (void)arg; - if (status != 0) { - printf("lkmc_exit_status_%d\n", status); - } -} enum { UART_FR_RXFE = 0x10, @@ -19,44 +11,18 @@ enum { #define UART_DR(baseaddr) (*(unsigned int *)(baseaddr)) #define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6)) +void lkmc_baremetal_on_exit_callback(int status, void *arg) { + (void)arg; + if (status != 0) { + printf("lkmc_exit_status_%d\n", status); + } +} + int _close(int file) { LKMC_UNUSED(file); return -1; } -void _exit(int status) { - LKMC_UNUSED(status); -#if LKMC_GEM5 - LKMC_M5OPS_EXIT; -#else -#if defined(__arm__) - __asm__ __volatile__ ( - "mov r0, #0x18\n" - "ldr r1, =#0x20026\n" - "svc 0x00123456\n" - : - : - : "r0", "r1" - ); -#elif defined(__aarch64__) - /* TODO actually use the exit value here, just for fun. */ - __asm__ __volatile__ ( - "mov x1, #0x26\n" \ - "movk x1, #2, lsl #16\n" \ - "str x1, [sp,#0]\n" \ - "mov x0, #0\n" \ - "str x0, [sp,#8]\n" \ - "mov x1, sp\n" \ - "mov w0, #0x18\n" \ - "hlt 0xf000\n" - : - : - : "x0", "x1" - ); -#endif -#endif -} - int _fstat(int file, struct stat *st) { LKMC_UNUSED(file); st->st_mode = S_IFCHR; diff --git a/baremetal/lib/syscalls_asm.S b/baremetal/lib/syscalls_asm.S new file mode 100644 index 0000000..a1bcd9f --- /dev/null +++ b/baremetal/lib/syscalls_asm.S @@ -0,0 +1,35 @@ +#include + +/* This is implemented in assembly so that it does not use the stack, + * and thus can be called safely from programs without the bootloader. + * C signature: + * + * void _exit(int status) + * + * If only there was a GCC attribute to create such a function! + */ +.text +.global _exit +_exit: +#if LKMC_GEM5 + LKMC_M5OPS_EXIT_ASM +#else +/* Use semihosting: + * https://github.com/cirosantilli/linux-kernel-module-cheat#semihosting */ +#if defined(__arm__) + mov r0, #0x18 + ldr r1, =#0x20026 + svc 0x00123456 +#elif defined(__aarch64__) + mov x1, 0x26 + movk x1, 2, lsl 16 + ldr x2, =.Lsemihost_args + str x1, [x2, 0] + str x0, [x2, 8] + mov x1, x2 + mov w0, 0x18 + hlt 0xf000 +.Lsemihost_args: + .skip 16 +#endif +#endif diff --git a/build-baremetal b/build-baremetal index 32ddbb3..e71d466 100755 --- a/build-baremetal +++ b/build-baremetal @@ -45,6 +45,14 @@ Build the baremetal examples with crosstool-NG. self.env['baremetal_build_lib_dir'], syscalls_basename_noext + self.env['obj_ext'] ) + syscalls_asm_src = os.path.join( + self.env['baremetal_source_lib_dir'], + syscalls_basename_noext + '_asm' + self.env['asm_ext'] + ) + syscalls_asm_obj = os.path.join( + self.env['baremetal_build_lib_dir'], + syscalls_basename_noext + '_asm' + self.env['obj_ext'] + ) cc_flags = [ '-I', self.env['root_dir'], LF, '-O{}'.format(self.env['optimization_level']), LF, @@ -93,6 +101,7 @@ Build the baremetal examples with crosstool-NG. (bootloader_src, extra_obj_baremetal_bootloader), (self.env['common_c'], extra_obj_lkmc_common), (syscalls_src, syscalls_obj), + (syscalls_asm_src, syscalls_asm_obj), ]: self._build_one( in_path=in_path, @@ -123,7 +132,7 @@ Build the baremetal examples with crosstool-NG. self.env['baremetal_link_script'], self.env['common_h'] ], - 'extra_objs': [syscalls_obj], + 'extra_objs': [syscalls_obj, syscalls_asm_obj], 'extra_objs_baremetal_bootloader': [extra_obj_baremetal_bootloader], 'extra_objs_lkmc_common': [extra_obj_lkmc_common], 'in_path': in_path, diff --git a/lkmc.c b/lkmc.c index 405c9eb..292a750 100644 --- a/lkmc.c +++ b/lkmc.c @@ -68,7 +68,30 @@ void lkmc_print_newline() { printf("\n"); } -#if defined(__aarch64__) +#if defined(__arm__) + +void lkmc_arm_psci_cpu_on( + uint32_t target_cpu, + uint32_t entry_point_address, + uint32_t context_id +) { + register int r0 __asm__ ("r0") = 0x84000003; + register int r1 __asm__ ("r1") = target_cpu; + register int r2 __asm__ ("r2") = entry_point_address; + register int r3 __asm__ ("r3") = context_id; + __asm__ __volatile__( + "hvc 0\n" + : + : "r" (r0), + "r" (r1), + "r" (r2), + "r" (r3) + : + ); +} + +#elif defined(__aarch64__) + #define LKMC_SYSREG_READ_WRITE(nbits, name) \ LKMC_CONCAT(LKMC_CONCAT(uint, nbits), _t) LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, read_), name)(void) { \ LKMC_CONCAT(LKMC_CONCAT(uint, nbits), _t) name; \ @@ -83,4 +106,31 @@ void lkmc_print_newline() { } LKMC_SYSREG_OPS #undef LKMC_SYSREG_READ_WRITE + +uint64_t lkmc_aarch64_cpu_id() { + /* TODO: cores beyond 4th? + * Mnemonic: Main Processor ID Register + */ + return lkmc_sysreg_read_mpidr_el1() & 3; +} + +void lkmc_aarch64_psci_cpu_on( + uint64_t target_cpu, + uint64_t entry_point_address, + uint64_t context_id +) { + register int w0 __asm__ ("w0") = 0xc4000003; + register int x1 __asm__ ("x1") = target_cpu; + register int x2 __asm__ ("x2") = entry_point_address; + register int x3 __asm__ ("x3") = context_id; + __asm__ __volatile__( + "hvc 0\n" + : + : "r" (w0), + "r" (x1), + "r" (x2), + "r" (x3) + : + ); +} #endif diff --git a/lkmc.h b/lkmc.h index 2bbf376..3570d9e 100644 --- a/lkmc.h +++ b/lkmc.h @@ -1,4 +1,7 @@ -/* https://cirosantilli.com/linux-kernel-module-cheat#lkmc-c */ +/* https://cirosantilli.com/linux-kernel-module-cheat#lkmc-c + * + * This toplevel header includes all the lkmc/ *.h headers. + */ #ifndef LKMC_H #define LKMC_H @@ -69,4 +72,6 @@ void lkmc_assert_memcmp(const void *s1, const void *s2, size_t n, uint32_t line) #error #endif +#include + #endif diff --git a/lkmc/aarch64.h b/lkmc/aarch64.h index 1c8ad9b..7907f37 100644 --- a/lkmc/aarch64.h +++ b/lkmc/aarch64.h @@ -1,6 +1,8 @@ #ifndef LKMC_AARCH64_H #define LKMC_AARCH64_H +#include + #define LKMC_ASSERT_EQ(reg, const) \ mov x0, reg; \ ldr x1, const; \ @@ -292,10 +294,7 @@ typedef struct { } LkmcVectorExceptionFrame; void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception); - -/* Misc assembly instructions. */ -#define lkmc_svc(immediate) __asm__ __volatile__("svc " #immediate : : : ) -#define lkmc_wfi() __asm__ __volatile__ ("wfi" : : : "memory") +void lkmc_cpu_not_0(uint64_t cpuid); /* Sysreg read and write functions, e.g.: * @@ -310,16 +309,26 @@ void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception); void LKMC_CONCAT(LKMC_CONCAT(LKMC_SYSREG_SYMBOL_PREFIX, print_), name)(void); #define LKMC_SYSREG_OPS \ LKMC_SYSREG_READ_WRITE(32, cntv_ctl_el0) \ - LKMC_SYSREG_READ_WRITE(64, daif) \ - LKMC_SYSREG_READ_WRITE(32, spsel) \ LKMC_SYSREG_READ_WRITE(64, cntfrq_el0) \ LKMC_SYSREG_READ_WRITE(64, cntv_cval_el0) \ LKMC_SYSREG_READ_WRITE(64, cntv_tval_el0) \ LKMC_SYSREG_READ_WRITE(64, cntvct_el0) \ + LKMC_SYSREG_READ_WRITE(64, daif) \ + LKMC_SYSREG_READ_WRITE(64, mpidr_el1) \ LKMC_SYSREG_READ_WRITE(64, sp_el1) \ + LKMC_SYSREG_READ_WRITE(32, spsel) \ LKMC_SYSREG_READ_WRITE(64, vbar_el1) LKMC_SYSREG_OPS #undef LKMC_SYSREG_READ_WRITE +/* Determine what is the ID of the currently running CPU. */ +uint64_t lkmc_aarch64_cpu_id(); + +void lkmc_aarch64_psci_cpu_on( + uint64_t target_cpu, + uint64_t entry_point_address, + uint64_t context_id +); + #endif #endif diff --git a/lkmc/arm.h b/lkmc/arm.h index ec81ccc..020c259 100644 --- a/lkmc/arm.h +++ b/lkmc/arm.h @@ -1,8 +1,20 @@ #ifndef LKMC_ARM_H #define LKMC_ARM_H +#include + #if defined(__ASSEMBLER__) + .syntax unified + +#else + +void lkmc_arm_psci_cpu_on( + uint32_t target_cpu, + uint32_t entry_point_address, + uint32_t context_id +); + #endif #define LKMC_ASSERT_EQ(reg, const) \ diff --git a/lkmc/arm_aarch64.h b/lkmc/arm_aarch64.h new file mode 100644 index 0000000..7297689 --- /dev/null +++ b/lkmc/arm_aarch64.h @@ -0,0 +1,12 @@ +#ifndef LKMC_ARM_AARCH64_H +#define LKMC_ARM_AARCH64_H + +/* Stuff that is common between arm and aarch64. */ +#define lkmc_arm_aarch64_wfe() __asm__ __volatile__ ("wfe" : : : ) +#define lkmc_arm_aarch64_dmb(type) __asm__ __volatile__ ("dmb " #type : : : "memory") +#define lkmc_arm_aarch64_sev(immediate) __asm__ __volatile__("sev" : : : ) +#define lkmc_arm_aarch64_hvc(immediate) __asm__ __volatile__("hvc " #immediate : : : ) +#define lkmc_arm_aarch64_svc(immediate) __asm__ __volatile__("svc " #immediate : : : ) +#define lkmc_arm_aarch64_wfi() __asm__ __volatile__ ("wfi" : : : ) + +#endif diff --git a/path_properties.py b/path_properties.py index 29357e0..9ed29e7 100644 --- a/path_properties.py +++ b/path_properties.py @@ -284,11 +284,17 @@ path_properties_tuples = ( 'arm': ( {'allowed_archs': {'arm'}}, { - 'multicore.S': {'test_run_args': {'cpus': 2}}, + 'multicore.c': { + # It is hard to get visibility into what is going on + # in that one due to the multicore business. + 'skip_run_unclassified': True, + 'test_run_args': {'cpus': 2} + }, 'no_bootloader': ( {'extra_objs_disable_baremetal_bootloader': True}, { 'gem5_exit.S': {'requires_m5ops': True}, + 'multicore_asm.S': {'test_run_args': {'cpus': 2}}, 'semihost_exit.S': {'requires_semihosting': True}, } ), @@ -300,11 +306,12 @@ path_properties_tuples = ( 'aarch64': ( {'allowed_archs': {'aarch64'}}, { - 'multicore.S': {'test_run_args': {'cpus': 2}}, + 'multicore.c': {'test_run_args': {'cpus': 2}}, 'no_bootloader': ( {'extra_objs_disable_baremetal_bootloader': True}, { 'gem5_exit.S': {'requires_m5ops': True}, + 'multicore_asm.S': {'test_run_args': {'cpus': 2}}, 'semihost_exit.S': {'requires_semihosting': True}, 'wfe_loop.S': {'more_than_1s': True}, }