diff --git a/.gitignore b/.gitignore index 9a22940..f59f955 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Important directories. /out +# https://github.com/cirosantilli/linux-kernel-module-cheat#docker +/out.docker /data # Temporary files. diff --git a/README.adoc b/README.adoc index 3d7771b..76b2747 100644 --- a/README.adoc +++ b/README.adoc @@ -10148,7 +10148,7 @@ Behaviour breakdown: So we take a performance measurement approach instead: .... -./gem5-bench-cache --arch aarch64 +./gem5-bench-cache -- --arch aarch64 cat "$(./getvar --arch aarch64 run_dir)/bench-cache.txt" .... @@ -14672,26 +14672,29 @@ Sources: Sample output for the C one: .... -daif 0x3c0 -spsel 0x1 -vbar_el1 0x40000800 +DAIF 0x3C0 +SPSEL 0x1 +VBAR_EL1 0x40000800 +after_svc 0x4000209c lkmc_vector_trap_handler exc_type 0x11 exc_type is LKMC_VECTOR_SYNC_SPX -ESR 0x56000042 -SP 0x4200bba8 -ELR 0x40002470 -SPSR 0x600003c5 +ESR 0x5600ABCD +ESR.EC 0x15 +ESR.EC.ISS.imm16 0xABCD +SP 0x4200C510 +ELR 0x4000209C +SPSR 0x600003C5 x0 0x0 x1 0x1 -x2 0x14 -x3 0x14 -x4 0x40008390 -x5 0xfffffff8 -x6 0x4200ba28 -x7 0x0 -x8 0x0 -x9 0x13 +x2 0x15 +x3 0x15 +x4 0x4000A178 +x5 0xFFFFFFF6 +x6 0x4200C390 +x7 0x78 +x8 0x1 +x9 0x14 x10 0x0 x11 0x0 x12 0x0 @@ -14711,11 +14714,36 @@ x25 0x0 x26 0x0 x27 0x0 x28 0x0 -x29 0x4200bba8 -x30 0x4000246c +x29 0x4200C510 +x30 0x40002064 .... -Both QEMU and gem5 are able to trace interrupts in addition to instructions, and it is instructive to enable both and have a look at the traces: +The C code does an: + +.... +svc 0xABCD +.... + +and the value 0xABCD appears at the bottom of <>: + +.... +ESR 0x5600ABCD +ESR.EC 0x15 +ESR.EC.ISS.imm16 0xABCD +.... + +The other important register is the <>, which contains the return address after the exception. + +From the output, we can see that it matches the value as obtained by taking the address of a label placed just after the SVC: + +.... +after_svc 0x4000209c +ELR 0x4000209C +.... + +Both QEMU and gem5 are able to trace interrupts in addition to instructions, and it is instructive to enable both and have a look at the traces. + +With <>: .... ./run \ @@ -14725,7 +14753,7 @@ Both QEMU and gem5 are able to trace interrupts in addition to instructions, and ; .... -contains: +the output contains: .... ---------------- @@ -14742,7 +14770,7 @@ IN: 0x40000a00: 14000225 b #0x40001294 .... -and: +And with <>: .... ./run \ @@ -14753,7 +14781,7 @@ and: ; .... -contains: +the output contains: .... 4000: system.cpu A0 T0 : @main+8 : svc #0x0 : IntAlu : flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall) @@ -14818,6 +14846,20 @@ Bibliography: * https://stackoverflow.com/questions/44991264/armv8-exception-vectors-and-handling * https://stackoverflow.com/questions/44198483/arm-timers-and-interrupts +===== ARM ESR register + +Exception Syndrome Register. + +See example at: <> + +Documentation: <> D12.2.36 "ESR_EL1, Exception Syndrome Register (EL1)". + +===== ARM ELR register + +Exception Link Register. + +See example at: <> + ==== ARM multicore .... diff --git a/baremetal/arch/aarch64/svc.c b/baremetal/arch/aarch64/svc.c index 85262a8..a9337f7 100644 --- a/baremetal/arch/aarch64/svc.c +++ b/baremetal/arch/aarch64/svc.c @@ -11,55 +11,68 @@ int myvar = 0; void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception) { puts("lkmc_vector_trap_handler"); - printf("exc_type 0x%" PRIx64 "\n", exception->exc_type); + printf("exc_type 0x%" PRIX64 "\n", exception->exc_type); if (exception->exc_type == LKMC_VECTOR_SYNC_SPX) { puts("exc_type is LKMC_VECTOR_SYNC_SPX"); } - printf("ESR 0x%" PRIx64 "\n", exception->exc_esr); - printf("SP 0x%" PRIx64 "\n", exception->exc_sp); - printf("ELR 0x%" PRIx64 "\n", exception->exc_elr); - printf("SPSR 0x%" PRIx64 "\n", exception->exc_spsr); - printf("x0 0x%" PRIx64 "\n", exception->x0); - printf("x1 0x%" PRIx64 "\n", exception->x1); - printf("x2 0x%" PRIx64 "\n", exception->x2); - printf("x3 0x%" PRIx64 "\n", exception->x3); - printf("x4 0x%" PRIx64 "\n", exception->x4); - printf("x5 0x%" PRIx64 "\n", exception->x5); - printf("x6 0x%" PRIx64 "\n", exception->x6); - printf("x7 0x%" PRIx64 "\n", exception->x7); - printf("x8 0x%" PRIx64 "\n", exception->x8); - printf("x9 0x%" PRIx64 "\n", exception->x9); - printf("x10 0x%" PRIx64 "\n", exception->x10); - printf("x11 0x%" PRIx64 "\n", exception->x11); - printf("x12 0x%" PRIx64 "\n", exception->x12); - printf("x13 0x%" PRIx64 "\n", exception->x13); - printf("x14 0x%" PRIx64 "\n", exception->x14); - printf("x15 0x%" PRIx64 "\n", exception->x15); - printf("x16 0x%" PRIx64 "\n", exception->x16); - printf("x17 0x%" PRIx64 "\n", exception->x17); - printf("x18 0x%" PRIx64 "\n", exception->x18); - printf("x19 0x%" PRIx64 "\n", exception->x19); - printf("x20 0x%" PRIx64 "\n", exception->x20); - printf("x21 0x%" PRIx64 "\n", exception->x21); - printf("x22 0x%" PRIx64 "\n", exception->x22); - printf("x23 0x%" PRIx64 "\n", exception->x23); - printf("x24 0x%" PRIx64 "\n", exception->x24); - printf("x25 0x%" PRIx64 "\n", exception->x25); - printf("x26 0x%" PRIx64 "\n", exception->x26); - printf("x27 0x%" PRIx64 "\n", exception->x27); - printf("x28 0x%" PRIx64 "\n", exception->x28); - printf("x29 0x%" PRIx64 "\n", exception->x29); - printf("x30 0x%" PRIx64 "\n", exception->x30); + printf("ESR 0x%" PRIX64 "\n", exception->exc_esr); + uint64_t esr_ec = (exception->exc_esr >> 26) & 0x3F; + uint64_t iss = exception->exc_esr & 0xFFFFFF; + printf("ESR.EC 0x%" PRIX64 "\n", esr_ec); + if ( + esr_ec == LKMC_ESR_EC_SVC_AARCH32 || + esr_ec == LKMC_ESR_EC_SVC_AARCH64 + ) { + printf("ESR.EC.ISS.imm16 0x%" PRIX64 "\n", iss & 0xFFFF); + } + printf("SP 0x%" PRIX64 "\n", exception->exc_sp); + printf("ELR 0x%" PRIX64 "\n", exception->exc_elr); + printf("SPSR 0x%" PRIX64 "\n", exception->exc_spsr); + printf("x0 0x%" PRIX64 "\n", exception->x0); + printf("x1 0x%" PRIX64 "\n", exception->x1); + printf("x2 0x%" PRIX64 "\n", exception->x2); + printf("x3 0x%" PRIX64 "\n", exception->x3); + printf("x4 0x%" PRIX64 "\n", exception->x4); + printf("x5 0x%" PRIX64 "\n", exception->x5); + printf("x6 0x%" PRIX64 "\n", exception->x6); + printf("x7 0x%" PRIX64 "\n", exception->x7); + printf("x8 0x%" PRIX64 "\n", exception->x8); + printf("x9 0x%" PRIX64 "\n", exception->x9); + printf("x10 0x%" PRIX64 "\n", exception->x10); + printf("x11 0x%" PRIX64 "\n", exception->x11); + printf("x12 0x%" PRIX64 "\n", exception->x12); + printf("x13 0x%" PRIX64 "\n", exception->x13); + printf("x14 0x%" PRIX64 "\n", exception->x14); + printf("x15 0x%" PRIX64 "\n", exception->x15); + printf("x16 0x%" PRIX64 "\n", exception->x16); + printf("x17 0x%" PRIX64 "\n", exception->x17); + printf("x18 0x%" PRIX64 "\n", exception->x18); + printf("x19 0x%" PRIX64 "\n", exception->x19); + printf("x20 0x%" PRIX64 "\n", exception->x20); + printf("x21 0x%" PRIX64 "\n", exception->x21); + printf("x22 0x%" PRIX64 "\n", exception->x22); + printf("x23 0x%" PRIX64 "\n", exception->x23); + printf("x24 0x%" PRIX64 "\n", exception->x24); + printf("x25 0x%" PRIX64 "\n", exception->x25); + printf("x26 0x%" PRIX64 "\n", exception->x26); + printf("x27 0x%" PRIX64 "\n", exception->x27); + printf("x28 0x%" PRIX64 "\n", exception->x28); + printf("x29 0x%" PRIX64 "\n", exception->x29); + printf("x30 0x%" PRIX64 "\n", exception->x30); myvar = 1; } int main(void) { /* View initial relevant register values. */ - printf("daif 0x%" PRIx32 "\n", lkmc_sysreg_daif_read()); - printf("spsel 0x%" PRIx32 "\n", lkmc_sysreg_spsel_read()); - printf("vbar_el1 0x%" PRIx64 "\n", lkmc_sysreg_vbar_el1_read()); + printf("DAIF 0x%" PRIX32 "\n", lkmc_sysreg_daif_read()); + printf("SPSEL 0x%" PRIX32 "\n", lkmc_sysreg_spsel_read()); + printf("VBAR_EL1 0x%" PRIX64 "\n", lkmc_sysreg_vbar_el1_read()); + /* https://stackoverflow.com/questions/1777990/is-it-possible-to-store-the-address-of-a-label-in-a-variable-and-use-goto-to-jum */ + printf("after_svc %p\n", &&after_svc); assert(myvar == 0); - LKMC_SVC(0x42); + /* Max 16-bits. */ + LKMC_SVC(0xABCD); +after_svc: assert(myvar == 1); return 0; } diff --git a/baremetal/arch/aarch64/svc_asm.S b/baremetal/arch/aarch64/svc_asm.S index 697baf5..8dd8fb5 100644 --- a/baremetal/arch/aarch64/svc_asm.S +++ b/baremetal/arch/aarch64/svc_asm.S @@ -5,7 +5,7 @@ .global main main: /* Do the svc. */ - svc 0 + svc 0xABCD /* Confirm that svc was called and modified myvar. */ ldr x0, myvar diff --git a/baremetal/arch/aarch64/timer.c b/baremetal/arch/aarch64/timer.c index 78cff53..3bf6b5d 100644 --- a/baremetal/arch/aarch64/timer.c +++ b/baremetal/arch/aarch64/timer.c @@ -5,7 +5,7 @@ #include void lkmc_vector_trap_handler(LkmcVectorExceptionFrame *exception __attribute__((unused))) { - printf("CNTVCT_EL0 0x%" PRIx64 "\n", lkmc_sysreg_cntvct_el0_read()); + printf("CNTVCT_EL0 0x%" PRIX64 "\n", lkmc_sysreg_cntvct_el0_read()); } #define CNTV_CTL_ENABLE (1 << 0) /* Enables the timer */ @@ -30,14 +30,14 @@ void enable_irq(void) { int main(void) { /* Initial state. */ - printf("CNTV_CTL_EL0 0x%" PRIx32 "\n", lkmc_sysreg_cntv_ctl_el0_read()); - printf("CNTFRQ_EL0 0x%" PRIx64 "\n", lkmc_sysreg_cntfrq_el0_read()); - printf("CNTV_CVAL_EL0 0x%" PRIx64 "\n", lkmc_sysreg_cntv_cval_el0_read()); + printf("CNTV_CTL_EL0 0x%" PRIX32 "\n", lkmc_sysreg_cntv_ctl_el0_read()); + printf("CNTFRQ_EL0 0x%" PRIX64 "\n", lkmc_sysreg_cntfrq_el0_read()); + printf("CNTV_CVAL_EL0 0x%" PRIX64 "\n", lkmc_sysreg_cntv_cval_el0_read()); /* Get the counter value many times to watch the time pass. */ - printf("CNTVCT_EL0 0x%" PRIx64 "\n", lkmc_sysreg_cntvct_el0_read()); - printf("CNTVCT_EL0 0x%" PRIx64 "\n", lkmc_sysreg_cntvct_el0_read()); - printf("CNTVCT_EL0 0x%" PRIx64 "\n", lkmc_sysreg_cntvct_el0_read()); + printf("CNTVCT_EL0 0x%" PRIX64 "\n", lkmc_sysreg_cntvct_el0_read()); + printf("CNTVCT_EL0 0x%" PRIX64 "\n", lkmc_sysreg_cntvct_el0_read()); + printf("CNTVCT_EL0 0x%" PRIX64 "\n", lkmc_sysreg_cntvct_el0_read()); /**/ gic_v3_initialize(); @@ -66,7 +66,7 @@ int main(void) { /* TODO crashes gem5. */ puts("cntfrq_el0 = 1"); lkmc_sysreg_cntfrq_el0_write(1); - printf("cntfrq_el0 0x%" PRIx64 "\n", lkmc_sysreg_cntfrq_el0_read()); + printf("cntfrq_el0 0x%" PRIX64 "\n", lkmc_sysreg_cntfrq_el0_read()); #endif return 0; diff --git a/baremetal/lib/aarch64.S b/baremetal/lib/aarch64.S index 9281cc4..eb73ed4 100644 --- a/baremetal/lib/aarch64.S +++ b/baremetal/lib/aarch64.S @@ -28,7 +28,10 @@ lkmc_start: LKMC_VECTOR_TABLE -/* Default trap handler. */ +/* Default handler for exceptions. This is called after some basic + * setup done on the initial handler. Since this is a weak symbol, + * you can redefine it in your own example, and your definition + * will take precedence. */ LKMC_WEAK(lkmc_vector_trap_handler) ldr x0, =lkmc_vector_trap_handler_error_message bl puts diff --git a/gem5-bench-cache b/gem5-bench-cache index d1d0476..5edf722 100755 --- a/gem5-bench-cache +++ b/gem5-bench-cache @@ -67,7 +67,7 @@ bench-all() ( if "$generate_checkpoints"; then # Create the checkpoints after the kernel boot. - cpt_cmd="-E '/gem5.sh'" + cpt_cmd="--eval './gem5.sh'" # RESTORE_INVESTIGATION ## 5 #./eeval "$cmd $cpt_cmd -- $cache_large --cpu-type=HPI" diff --git a/lkmc/aarch64.h b/lkmc/aarch64.h index 16e6581..2856686 100644 --- a/lkmc/aarch64.h +++ b/lkmc/aarch64.h @@ -92,14 +92,18 @@ main_after_prologue: \ #define LKMC_VECTOR_EXC_FRAME_SIZE (288) /* sizeof(lkmc_vector_exception_frame) */ #define LKMC_VECTOR_EXC_EXC_TYPE_OFFSET (0) /* offsetof(lkmc_vector_exception_frame, exc_type) */ -#define LKMC_VECTOR_EXC_EXC_ESR_OFFSE (8) /* offsetof(lkmc_vector_exception_frame, exc_esr) */ +#define LKMC_VECTOR_EXC_EXC_ESR_OFFSET (8) /* offsetof(lkmc_vector_exception_frame, exc_esr) */ #define LKMC_VECTOR_EXC_EXC_SP_OFFSET (16) /* offsetof(lkmc_vector_exception_frame, exc_sp) */ #define LKMC_VECTOR_EXC_EXC_ELR_OFFSET (24) /* offsetof(lkmc_vector_exception_frame, exc_elr) */ #define LKMC_VECTOR_EXC_EXC_SPSR_OFFSET (32) /* offsetof(lkmc_vector_exception_frame, exc_spsr) */ +#define LKMC_ESR_EC_SVC_AARCH32 (0x11) +#define LKMC_ESR_EC_SVC_AARCH64 (0x15) + #define LKMC_VECTOR_FUNC_ALIGN .align 2 #define LKMC_VECTOR_SYMBOL_PREFIX lkmc_vector_ +/* Push several registers on the stack to match LkmcVectorExceptionFrame. */ #define LKMC_VECTOR_BUILD_TRAPFRAME(exc_type) \ stp x29, x30, [sp, -16]!; \ stp x27, x28, [sp, -16]!; \ diff --git a/path_properties.py b/path_properties.py index b6b4cc5..196a943 100644 --- a/path_properties.py +++ b/path_properties.py @@ -310,6 +310,7 @@ path_properties_tuples = ( ), 'return1.S': {'exit_status': 1}, 'semihost_exit.S': {'requires_semihosting': True}, + 'svc.c': {'cc_pedantic': False}, 'timer.c': {'skip_run_unclassified': True}, }, ) diff --git a/userland/linux/rand_check.c b/userland/linux/rand_check.c index 9b6fbbc..c63c9de 100644 --- a/userland/linux/rand_check.c +++ b/userland/linux/rand_check.c @@ -36,6 +36,6 @@ int main(__attribute__((unused)) int argc, char **argv) { /* /dev/urandom */ fp = fopen("/dev/urandom", "rb"); fread(&uint64, sizeof(uint64), 1, fp); - printf("/dev/urandom = %" PRIx64 "\n", uint64); + printf("/dev/urandom = %" PRIX64 "\n", uint64); fclose(fp); }