Skip to content

Commit

Permalink
arm baremetal: SVC explain where the imm16 can be retrieved
Browse files Browse the repository at this point in the history
Use upper case hex literals on all PRIXnn.

.gitignore /out.docker
  • Loading branch information
cirosantilli committed Jul 16, 2019
1 parent b1bfd46 commit b38e2b0
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 75 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,5 +1,7 @@
# Important directories.
/out
# https://github.com/cirosantilli/linux-kernel-module-cheat#docker
/out.docker
/data

# Temporary files.
Expand Down
86 changes: 64 additions & 22 deletions README.adoc
Expand Up @@ -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"
....

Expand Down Expand Up @@ -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
Expand All @@ -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 <<arm-esr-register>>:

....
ESR 0x5600ABCD
ESR.EC 0x15
ESR.EC.ISS.imm16 0xABCD
....

The other important register is the <<arm-elr-register>>, 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 <<qemu-d-tracing>>:

....
./run \
Expand All @@ -14725,7 +14753,7 @@ Both QEMU and gem5 are able to trace interrupts in addition to instructions, and
;
....

contains:
the output contains:

....
----------------
Expand All @@ -14742,7 +14770,7 @@ IN:
0x40000a00: 14000225 b #0x40001294
....

and:
And with <<gem5-tracing>>:

....
./run \
Expand All @@ -14753,7 +14781,7 @@ and:
;
....

contains:
the output contains:

....
4000: system.cpu A0 T0 : @main+8 : svc #0x0 : IntAlu : flags=(IsSerializeAfter|IsNonSpeculative|IsSyscall)
Expand Down Expand Up @@ -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: <<arm-svc-instruction>>

Documentation: <<armarm8-db>> D12.2.36 "ESR_EL1, Exception Syndrome Register (EL1)".

===== ARM ELR register

Exception Link Register.

See example at: <<arm-svc-instruction>>

==== ARM multicore

....
Expand Down
93 changes: 53 additions & 40 deletions baremetal/arch/aarch64/svc.c
Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion baremetal/arch/aarch64/svc_asm.S
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions baremetal/arch/aarch64/timer.c
Expand Up @@ -5,7 +5,7 @@
#include <lkmc/gicv3.h>

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 */
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion baremetal/lib/aarch64.S
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion gem5-bench-cache
Expand Up @@ -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"
Expand Down
6 changes: 5 additions & 1 deletion lkmc/aarch64.h
Expand Up @@ -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]!; \
Expand Down
1 change: 1 addition & 0 deletions path_properties.py
Expand Up @@ -310,6 +310,7 @@ def get(path):
),
'return1.S': {'exit_status': 1},
'semihost_exit.S': {'requires_semihosting': True},
'svc.c': {'cc_pedantic': False},
'timer.c': {'skip_run_unclassified': True},
},
)
Expand Down
2 changes: 1 addition & 1 deletion userland/linux/rand_check.c
Expand Up @@ -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);
}

0 comments on commit b38e2b0

Please sign in to comment.