diff --git a/README.adoc b/README.adoc index daaab1d..d2f3c0f 100644 --- a/README.adoc +++ b/README.adoc @@ -18450,7 +18450,14 @@ The WFE and SEV instructions are just hints: a compliant implementation can trea Concrete examples of the instruction can be seen at: * link:userland/arch/aarch64/nostartfiles/wfe.S[] -* <> +* link:userland/arch/aarch64/freestanding/linux/wfe.S[] +* link:userland/arch/aarch64/freestanding/linux/wfe_wfe.S[]: run WFE twice, because gem5 390a74f59934b85d91489f8a563450d8321b602d does not sleep on the first, see also: <> +* link:baremetal/arch/aarch64/no_bootloader/wfe_loop.S[], see: <> +* link:userland/arch/aarch64/inline_asm/wfe_sev.cpp[]: one Linux thread runs WFE and the other runs SEV to wake it up +* <> shows baremetal examples where WFE sleeps and another thread wakes it up: +** link:baremetal/arch/arm/multicore.c[] +** link:baremetal/arch/aarch64/multicore.c[] +** link:baremetal/arch/arm/no_bootloader/multicore_asm.S[] However, likely no implementation likely does (TODO confirm), since: @@ -18541,6 +18548,42 @@ The following Raspberry Pi bibliography helped us get this sample up and running For how userland spinlocks and mutexes are implemented see <>. +====== gem5 ARM WFE + +gem5 390a74f59934b85d91489f8a563450d8321b602d does not sleep on the first WFE on either syscall emulation or full system, because the code does: + +.... +Fault WfeInst::execute( + ExecContext *xc, Trace::InstRecord *traceData) const +{ +[...] + if (SevMailbox == 1) { + SevMailbox = 0; + PseudoInst::quiesceSkip(tc); + } else if (tc->getCpuPtr()->getInterruptController( + tc->threadId())->checkInterrupts(tc)) { + PseudoInst::quiesceSkip(tc); + } else { + fault = trapWFx(tc, cpsr, scr, true); + if (fault == NoFault) { + PseudoInst::quiesce(tc); + } else { + PseudoInst::quiesceSkip(tc); + } + } +.... + +where https://en.wiktionary.org/wiki/quiescent["quiesce" means "sleep"] for laymen like Ciro, and `quiesceSkip` means don't sleep. + +`SevMailbox` is read from `MISCREG_SEV_MAILBOX` which is initialized to `1` at: + +.... +ISA::clear() +{ +[...] + miscRegs[MISCREG_SEV_MAILBOX] = 1; +.... + ====== ARM YIELD instruction https://stackoverflow.com/questions/59311066/how-does-the-arm-yield-instruction-inform-other-threads-that-they-could-start-a diff --git a/path_properties.py b/path_properties.py index 93f7678..3653e30 100644 --- a/path_properties.py +++ b/path_properties.py @@ -526,9 +526,28 @@ path_properties_tuples = ( { 'freestanding': freestanding_properties, 'sve_addvl.c': {'arm_sve': True}, + 'wfe_sev.c': { + # gem5 bug, WFE not waking up on syscall emulation, + # TODO link to bug report. + 'more_than_1s': True, + 'test_run_args': { + 'cpus': 2, + }, + }, }, ), - 'freestanding': freestanding_properties, + 'freestanding': ( + freestanding_properties, + { + 'linux': ( + {}, + { + 'wfe.S': {'more_than_1s': True}, + 'wfe_wfe.S': {'more_than_1s': True}, + } + ), + } + ), 'lkmc_assert_eq_fail.S': {'signal_received': signal.Signals.SIGABRT}, 'lkmc_assert_memcmp_fail.S': {'signal_received': signal.Signals.SIGABRT}, 'nostartfiles': ( @@ -536,6 +555,7 @@ path_properties_tuples = ( { # https://github.com/cirosantilli/linux-kernel-module-cheat/issues/107 'exit.S': {'skip_run_unclassified': True}, + 'wfe.S': {'more_than_1s': True}, } ), 'udf.S': { diff --git a/userland/arch/aarch64/freestanding/linux/wfe.S b/userland/arch/aarch64/freestanding/linux/wfe.S new file mode 100644 index 0000000..674b8e2 --- /dev/null +++ b/userland/arch/aarch64/freestanding/linux/wfe.S @@ -0,0 +1,12 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#arm-wfe-and-sev-instructions */ + +.text +.global _start +_start: +asm_main_after_prologue: + wfe + + /* exit */ + mov x0, 0 + mov x8, 93 + svc 0 diff --git a/userland/arch/aarch64/freestanding/linux/wfe_wfe.S b/userland/arch/aarch64/freestanding/linux/wfe_wfe.S new file mode 100644 index 0000000..3cfbaa2 --- /dev/null +++ b/userland/arch/aarch64/freestanding/linux/wfe_wfe.S @@ -0,0 +1,13 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#arm-wfe-and-sev-instructions */ + +.text +.global _start +_start: +asm_main_after_prologue: + wfe + wfe + + /* exit */ + mov x0, 0 + mov x8, 93 + svc 0 diff --git a/userland/arch/aarch64/inline_asm/wfe_sev.cpp b/userland/arch/aarch64/inline_asm/wfe_sev.cpp new file mode 100644 index 0000000..f2c00fb --- /dev/null +++ b/userland/arch/aarch64/inline_asm/wfe_sev.cpp @@ -0,0 +1,29 @@ +// https://cirosantilli.com/linux-kernel-module-cheat#arm-wfe-and-sev-instructions + +#include +#include +#include +#include + +std::atomic_ulong done; + +void myfunc() { + unsigned long new_val = 1; + __asm__ __volatile__ ("wfe;wfe;" : "+r" (new_val) : :); + done.store(new_val); +} + +int main(int argc, char **argv) { + bool do_sev = true; + if (argc > 1) { + do_sev = (argv[1][0] != '0'); + } + done.store(0); + std::thread thread; + thread = std::thread(myfunc); + while (!done.load()) { + if (do_sev) + __asm__ __volatile__ ("sev"); + } + thread.join(); +}