mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-27 12:04:27 +01:00
arm WFE: add some userland examples
This commit is contained in:
45
README.adoc
45
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:
|
Concrete examples of the instruction can be seen at:
|
||||||
|
|
||||||
* link:userland/arch/aarch64/nostartfiles/wfe.S[]
|
* link:userland/arch/aarch64/nostartfiles/wfe.S[]
|
||||||
* <<arm-baremetal-multicore>>
|
* 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: <<gem5-arm-wfe>>
|
||||||
|
* link:baremetal/arch/aarch64/no_bootloader/wfe_loop.S[], see: <<gem5-simulate-limit-reached>>
|
||||||
|
* link:userland/arch/aarch64/inline_asm/wfe_sev.cpp[]: one Linux thread runs WFE and the other runs SEV to wake it up
|
||||||
|
* <<arm-baremetal-multicore>> 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:
|
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 <<userland-mutex-implementation>>.
|
For how userland spinlocks and mutexes are implemented see <<userland-mutex-implementation>>.
|
||||||
|
|
||||||
|
====== 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
|
====== ARM YIELD instruction
|
||||||
|
|
||||||
https://stackoverflow.com/questions/59311066/how-does-the-arm-yield-instruction-inform-other-threads-that-they-could-start-a
|
https://stackoverflow.com/questions/59311066/how-does-the-arm-yield-instruction-inform-other-threads-that-they-could-start-a
|
||||||
|
|||||||
@@ -526,9 +526,28 @@ path_properties_tuples = (
|
|||||||
{
|
{
|
||||||
'freestanding': freestanding_properties,
|
'freestanding': freestanding_properties,
|
||||||
'sve_addvl.c': {'arm_sve': True},
|
'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_eq_fail.S': {'signal_received': signal.Signals.SIGABRT},
|
||||||
'lkmc_assert_memcmp_fail.S': {'signal_received': signal.Signals.SIGABRT},
|
'lkmc_assert_memcmp_fail.S': {'signal_received': signal.Signals.SIGABRT},
|
||||||
'nostartfiles': (
|
'nostartfiles': (
|
||||||
@@ -536,6 +555,7 @@ path_properties_tuples = (
|
|||||||
{
|
{
|
||||||
# https://github.com/cirosantilli/linux-kernel-module-cheat/issues/107
|
# https://github.com/cirosantilli/linux-kernel-module-cheat/issues/107
|
||||||
'exit.S': {'skip_run_unclassified': True},
|
'exit.S': {'skip_run_unclassified': True},
|
||||||
|
'wfe.S': {'more_than_1s': True},
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
'udf.S': {
|
'udf.S': {
|
||||||
|
|||||||
12
userland/arch/aarch64/freestanding/linux/wfe.S
Normal file
12
userland/arch/aarch64/freestanding/linux/wfe.S
Normal file
@@ -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
|
||||||
13
userland/arch/aarch64/freestanding/linux/wfe_wfe.S
Normal file
13
userland/arch/aarch64/freestanding/linux/wfe_wfe.S
Normal file
@@ -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
|
||||||
29
userland/arch/aarch64/inline_asm/wfe_sev.cpp
Normal file
29
userland/arch/aarch64/inline_asm/wfe_sev.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// https://cirosantilli.com/linux-kernel-module-cheat#arm-wfe-and-sev-instructions
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user