From 62d2152f39158f33ecfcee9c629382e4d30052d6 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: Fri, 15 Feb 2019 00:00:00 +0000 Subject: [PATCH] baremetal: working aarch64 svc example adapted from takeharukato Not yet generalized for usage on multiple files. --- README.adoc | 17 ++- baremetal/arch/aarch64/regs.S | 5 +- baremetal/arch/aarch64/svc_asm.S | 240 +++++++++++++++++++++++++++++++ 3 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 baremetal/arch/aarch64/svc_asm.S diff --git a/README.adoc b/README.adoc index 739a7b8..fe758a4 100644 --- a/README.adoc +++ b/README.adoc @@ -8967,7 +8967,13 @@ less "$(./getvar --arch aarch64 run_dir)/trace.txt" Output the trace to stdout instead of a file: .... -./run --arch aarch64 --eval 'm5 exit' --emulator gem5 --trace Exec --trace-stdout +./run \ + --arch aarch64 \ + --emulator gem5 \ + --eval 'm5 exit' \ + --trace Exec \ + --trace-stdout \ +; .... This would produce a lot of output however, so you will likely not want that when tracing a Linux kernel boot instructions. But it can be very convenient for smaller traces. @@ -11201,6 +11207,14 @@ output: Setup a handler for `svc`, do an `svc`, and observe that the handler got called and returned: +.... +./run --arch aarch64 --baremetal arch/aarch64/svc_asm +.... + +Source: link:baremetal/arch/aarch64/svc_asm.S[] + +TODO: factor out the above, and make it also work on C: + .... ./run --arch aarch64 --baremetal arch/aarch64/svc .... @@ -11261,6 +11275,7 @@ This reset value is defined `UNKNOWN` by <> D10.2.116 "VBAR_EL1, Vector Bibliography: +* https://github.com/torvalds/linux/blob/v4.20/arch/arm64/kernel/entry.S#L430 this is where the kernel defines the vector table * https://github.com/dwelch67/qemu_arm_samples/tree/07162ba087111e0df3f44fd857d1b4e82458a56d/swi01 * https://github.com/NienfengYao/armv8-bare-metal/blob/572c6f95880e70aa92fe9fed4b8ad7697082a764/vector.S#L168 * https://stackoverflow.com/questions/51094092/how-to-make-timer-irq-work-on-qemu-machine-virt-cpu-cortex-a57 diff --git a/baremetal/arch/aarch64/regs.S b/baremetal/arch/aarch64/regs.S index 49df8cb..894e0d1 100644 --- a/baremetal/arch/aarch64/regs.S +++ b/baremetal/arch/aarch64/regs.S @@ -1,6 +1,7 @@ /* Test that we can move: * - set registers - * - read x30 */ + * - read x30 + */ .global main main: mov x0, #1 @@ -23,6 +24,6 @@ main: fmov d31, #2.5 /* test-gdb-d31 */ - /* Exit required since we meesed up with x30 which is the lr. */ + /* Exit required since we messed up with x30 which is the lr. */ mov x0, #0 bl exit diff --git a/baremetal/arch/aarch64/svc_asm.S b/baremetal/arch/aarch64/svc_asm.S new file mode 100644 index 0000000..0feb7da --- /dev/null +++ b/baremetal/arch/aarch64/svc_asm.S @@ -0,0 +1,240 @@ +/* TODO factor it out to make reusable. */ + +.global main +main: + /* Load the vector table. */ + ldr x0, =vector_table + msr vbar_el1, x0 + + /* Do the svc. */ + svc 0 + + /* Confirm that svc was called and modified myvar. */ + ldr x0, myvar + ldr x1, mynewvar + cmp x0, x1 + beq 1f + bl common_assert_fail +1: + + /* Go home. */ + ret + +common_trap_handler: + /* Modify myvar as a visible side effect. */ + ldr x0, mynewvar + ldr x1, =myvar + str x0, [x1] + ret + +myvar: + .quad 0x0 +mynewvar: + .quad 0x12346789ABCDEF0 + +/* .h + * + * Adapted from: https://github.com/takeharukato/sample-tsk-sw/blob/ce7973aa5d46c9eedb58309de43df3b09d4f8d8d/hal/aarch64/vector.S + */ + +#define AARCH64_EXC_SYNC_SP0 (0x1) +#define AARCH64_EXC_IRQ_SP0 (0x2) +#define AARCH64_EXC_FIQ_SP0 (0x3) +#define AARCH64_EXC_SERR_SP0 (0x4) + +#define AARCH64_EXC_SYNC_SPX (0x11) +#define AARCH64_EXC_IRQ_SPX (0x12) +#define AARCH64_EXC_FIQ_SPX (0x13) +#define AARCH64_EXC_SERR_SPX (0x14) + +#define AARCH64_EXC_SYNC_AARCH64 (0x21) +#define AARCH64_EXC_IRQ_AARCH64 (0x22) +#define AARCH64_EXC_FIQ_AARCH64 (0x23) +#define AARCH64_EXC_SERR_AARCH64 (0x24) + +#define AARCH64_EXC_SYNC_AARCH32 (0x31) +#define AARCH64_EXC_IRQ_AARCH32 (0x32) +#define AARCH64_EXC_FIQ_AARCH32 (0x33) +#define AARCH64_EXC_SERR_AARCH32 (0x34) + +#if !defined(__ASSEMBLER__) +#include +typedef struct _exception_frame{ + uint64_t exc_type; + uint64_t exc_esr; + uint64_t exc_sp; + uint64_t exc_elr; + uint64_t exc_spsr; + uint64_t x0; + uint64_t x1; + uint64_t x2; + uint64_t x3; + uint64_t x4; + uint64_t x5; + uint64_t x6; + uint64_t x7; + uint64_t x8; + uint64_t x9; + uint64_t x10; + uint64_t x11; + uint64_t x12; + uint64_t x13; + uint64_t x14; + uint64_t x15; + uint64_t x16; + uint64_t x17; + uint64_t x18; + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t x29; + uint64_t x30; +} exception_frame; +void common_trap_handler(exception_frame *exception); +#endif + +/* .S */ + +#define EXC_FRAME_SIZE (288) /* sizeof(exception_frame) */ +#define EXC_EXC_TYPE_OFFSET (0) /* offsetof(exception_frame, exc_type) */ +#define EXC_EXC_ESR_OFFSET (8) /* offsetof(exception_frame, exc_esr) */ +#define EXC_EXC_SP_OFFSET (16) /* offsetof(exception_frame, exc_sp) */ +#define EXC_EXC_ELR_OFFSET (24) /* offsetof(exception_frame, exc_elr) */ +#define EXC_EXC_SPSR_OFFSET (32) /* offsetof(exception_frame, exc_spsr) */ + +#define BUILD_TRAPFRAME(exc_type) \ + stp x29, x30, [sp, -16]!; \ + stp x27, x28, [sp, -16]!; \ + stp x25, x26, [sp, -16]!; \ + stp x23, x24, [sp, -16]!; \ + stp x21, x22, [sp, -16]!; \ + stp x19, x20, [sp, -16]!; \ + stp x17, x18, [sp, -16]!; \ + stp x15, x16, [sp, -16]!; \ + stp x13, x14, [sp, -16]!; \ + stp x11, x12, [sp, -16]!; \ + stp x9, x10, [sp, -16]!; \ + stp x7, x8, [sp, -16]!; \ + stp x5, x6, [sp, -16]!; \ + stp x3, x4, [sp, -16]!; \ + stp x1, x2, [sp, -16]!; \ + mrs x21, spsr_el1; \ + stp x21, x0, [sp, -16]!; \ + mrs x21, elr_el1; \ + stp xzr, x21, [sp, -16]!; \ + mov x21, (exc_type); \ + mrs x22, esr_el1; \ + stp x21, x22, [sp, -16]! + +#define STORE_TRAPED_SP \ + mrs x21, sp_el0; \ + str x21, [sp, EXC_EXC_SP_OFFSET] + +#define CALL_COMMON_TRAP_HANDLER \ + mov x0, sp; \ + bl common_trap_handler + +#define STORE_NESTED_SP \ + mov x21, sp; \ + add x21, x21, EXC_FRAME_SIZE; \ + str x21, [sp, EXC_EXC_SP_OFFSET] + +#define RESTORE_TRAPED_SP \ + ldr x21, [sp, EXC_EXC_SP_OFFSET]; \ + msr sp_el0, x21 + +#define RESTORE_TRAPFRAME \ + add sp, sp, 16; \ + ldp x21, x22, [sp], 16; \ + msr elr_el1, x22; \ + ldp x21, x0, [sp], 16; \ + msr spsr_el1, x21; \ + ldp x1, x2, [sp], 16; \ + ldp x3, x4, [sp], 16; \ + ldp x5, x6, [sp], 16; \ + ldp x7, x8, [sp], 16; \ + ldp x9, x10, [sp], 16; \ + ldp x11, x12, [sp], 16; \ + ldp x13, x14, [sp], 16; \ + ldp x15, x16, [sp], 16; \ + ldp x17, x18, [sp], 16; \ + ldp x19, x20, [sp], 16; \ + ldp x21, x22, [sp], 16; \ + ldp x23, x24, [sp], 16; \ + ldp x25, x26, [sp], 16; \ + ldp x27, x28, [sp], 16; \ + ldp x29, x30, [sp], 16; \ + eret + +#define VECTOR_ENTRY(func_name) \ + .align 7; \ + b func_name + +#define VECTOR_FUNC_ALIGN .align 2 + +#define VECTOR_FUNC(func_name, func_id) \ + VECTOR_FUNC_ALIGN; \ +func_name:; \ + BUILD_TRAPFRAME(func_id); \ + STORE_TRAPED_SP; \ + CALL_COMMON_TRAP_HANDLER; \ + RESTORE_TRAPED_SP; \ + RESTORE_TRAPFRAME + +#define VECTOR_FUNC_NESTED(func_name, func_id) \ + VECTOR_FUNC_ALIGN; \ +func_name:; \ + BUILD_TRAPFRAME(func_id); \ + STORE_NESTED_SP; \ + CALL_COMMON_TRAP_HANDLER; \ + RESTORE_TRAPFRAME + + .align 11 + .global vector_table +vector_table: + VECTOR_ENTRY(_curr_el_sp0_sync) + VECTOR_ENTRY(_curr_el_sp0_irq) + VECTOR_ENTRY(_curr_el_sp0_fiq) + VECTOR_ENTRY(_curr_el_sp0_serror) + + VECTOR_ENTRY(_curr_el_spx_sync) + VECTOR_ENTRY(_curr_el_spx_irq) + VECTOR_ENTRY(_curr_el_spx_fiq) + VECTOR_ENTRY(_curr_el_spx_serror) + + VECTOR_ENTRY(_lower_el_aarch64_sync) + VECTOR_ENTRY(_lower_el_aarch64_irq) + VECTOR_ENTRY(_lower_el_aarch64_fiq) + VECTOR_ENTRY(_lower_el_aarch64_serror) + + VECTOR_ENTRY(_lower_el_aarch32_sync) + VECTOR_ENTRY(_lower_el_aarch32_irq) + VECTOR_ENTRY(_lower_el_aarch32_fiq) + VECTOR_ENTRY(_lower_el_aarch32_serror) + + VECTOR_FUNC(_curr_el_sp0_sync, AARCH64_EXC_SYNC_SP0) + VECTOR_FUNC(_curr_el_sp0_irq, AARCH64_EXC_IRQ_SP0) + VECTOR_FUNC(_curr_el_sp0_fiq, AARCH64_EXC_FIQ_SP0) + VECTOR_FUNC(_curr_el_sp0_serror, AARCH64_EXC_SERR_SP0) + + VECTOR_FUNC_NESTED(_curr_el_spx_sync, AARCH64_EXC_SYNC_SPX) + VECTOR_FUNC_NESTED(_curr_el_spx_irq, AARCH64_EXC_IRQ_SPX) + VECTOR_FUNC_NESTED(_curr_el_spx_fiq, AARCH64_EXC_FIQ_SPX) + VECTOR_FUNC_NESTED(_curr_el_spx_serror, AARCH64_EXC_SERR_SPX) + + VECTOR_FUNC(_lower_el_aarch64_sync, AARCH64_EXC_SYNC_AARCH64) + VECTOR_FUNC(_lower_el_aarch64_irq, AARCH64_EXC_IRQ_AARCH64) + VECTOR_FUNC(_lower_el_aarch64_fiq, AARCH64_EXC_FIQ_AARCH64) + VECTOR_FUNC(_lower_el_aarch64_serror, AARCH64_EXC_SERR_AARCH64) + + VECTOR_FUNC(_lower_el_aarch32_sync, AARCH64_EXC_SYNC_AARCH32) + VECTOR_FUNC(_lower_el_aarch32_irq, AARCH64_EXC_IRQ_AARCH32) + VECTOR_FUNC(_lower_el_aarch32_fiq, AARCH64_EXC_FIQ_AARCH32) + VECTOR_FUNC(_lower_el_aarch32_serror, AARCH64_EXC_SERR_AARCH32)