From cf4ed0f11d4db8d8002e63a4e77478b1fb5bf8cf 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: Thu, 12 Dec 2019 00:00:04 +0000 Subject: [PATCH] factor out baremetal aarch64 dump_regs.c for kernel module usage Create dump-regs section. --- README.adoc | 42 ++++++++++++++++++++++- baremetal/arch/aarch64/dump_regs.c | 39 +++------------------ baremetal/arch/arm/dump_regs.c | 2 +- kernel_modules/dump_regs.c | 25 ++++++++++++++ lkmc/aarch64_dump_regs.h | 55 ++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 37 deletions(-) create mode 100644 kernel_modules/dump_regs.c create mode 100644 lkmc/aarch64_dump_regs.h diff --git a/README.adoc b/README.adoc index cdf9cc7..d3c750c 100644 --- a/README.adoc +++ b/README.adoc @@ -9082,6 +9082,46 @@ QEMU does not seem able to boot ELF files like `vmlinux`: https://superuser.com/ Converting `arch/*` images to `vmlinux` is possible in theory x86 with https://github.com/torvalds/linux/blob/v5.1/scripts/extract-vmlinux[`extract-vmlinux`] but we didn't get any gem5 boots working from images generated like that for some reason, see: https://github.com/cirosantilli/linux-kernel-module-cheat/issues/79 +=== Kernel modules + +[[dump-regs]] +==== dump_regs + +The following kernel modules and <> executables dump and disassemble various registers which cannot be observed from userland (usually "system registers", "control registers"): + +* link:kernel_modules/dump_regs.c[] +* link:baremetal/arch/aarch64/dump_regs.c[] +* link:baremetal/arch/arm/dump_regs.c[] + +Some of those programs are using: + +* link:lkmc/aarch64_dump_regs.h[] + +Alternatively, you can also get their value from inside <> with: + +.... +info registers all +.... + +or the short version: + +.... +i r a +.... + +or to get just specific registers, e.g. just ARMv8's SCTLR: + +.... +i r SCTLR +.... + +but it is sometimes just more convenient to run an executable to get the registers at the point of interest. + +See also: + +* https://stackoverflow.com/questions/5429137/how-to-print-register-values-in-gdb/31340294#31340294 +* https://stackoverflow.com/questions/24169614/how-to-show-all-x86-control-registers-when-debugging-the-linux-kernel-in-gdb-thr/59311764#59311764 + == Xen TODO: get prototype working and then properly integrate: @@ -18386,7 +18426,7 @@ SEV is not the only thing that can wake up a WFE, it is only an explicit softwar WFE and SEV are usable from userland, and are part of an efficient spinlock implementation, which maybe is not something that userland should ever tho and just stick to mutexes? -There is a control bit `SCTLR_EL1.nTWE` that determines if WFE is trapped or not, i.e.: is that bit is set, then it is trapped and EL0 execution raises an exception in EL1. Linux v5.2.1 does not seem to trap however, tested with `--trace ExecAll` in a full system simulation. But then, how does the kernel prevent CPUs from going to sleep randomly and instead reschedules other tasks? Does the kernel check if CPUs are in WFE when it wakes up on the timer, and only then reschedules? This would allow for userland to implement fast spinlocks if the spinlock returns faster than the timer. The kernel seems to setup NTWE at: +There is a control bit `SCTLR_EL1.nTWE` that determines if WFE is trapped or not, i.e.: is that bit is set, then it is trapped and EL0 execution raises an exception in EL1. Linux v5.2.1 does not seem to trap however, tested with `--trace ExecAll` and the <> in a full system simulation. But then, how does the kernel prevent CPUs from going to sleep randomly and instead reschedules other tasks? Does the kernel check if CPUs are in WFE when it wakes up on the timer, and only then reschedules? This would allow for userland to implement fast spinlocks if the spinlock returns faster than the timer. The kernel seems to setup NTWE at: include/asm/sysreg.h diff --git a/baremetal/arch/aarch64/dump_regs.c b/baremetal/arch/aarch64/dump_regs.c index 201cbb8..1f799a6 100644 --- a/baremetal/arch/aarch64/dump_regs.c +++ b/baremetal/arch/aarch64/dump_regs.c @@ -1,42 +1,11 @@ -/* Dump registers that cannot be read from EL0. */ +/* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */ #include #include +#include + int main(void) { - uint32_t sctlr_el1; - __asm__ ("mrs %0, sctlr_el1" : "=r" (sctlr_el1) : :); - printf("SCTLR_EL1 0x%" PRIX32 "\n", sctlr_el1); - printf("SCTLR_EL1.A 0x%" PRIX32 "\n", (sctlr_el1 >> 1) & 1); - /* https://cirosantilli.com/linux-kernel-module-cheat#arm-paging */ - printf("SCTLR_EL1.M 0x%" PRIX32 "\n", (sctlr_el1 >> 0) & 1); - - uint64_t id_aa64pfr0_el1; - __asm__ ("mrs %0, id_aa64pfr0_el1" : "=r" (id_aa64pfr0_el1) : :); - printf("ID_AA64PFR0_EL1 0x%" PRIX64 "\n", id_aa64pfr0_el1); - printf("ID_AA64PFR0_EL1.SVE 0x%" PRIX64 "\n", (id_aa64pfr0_el1 >> 32) & 0xF); - - uint64_t CurrentEL; - __asm__ ("mrs %0, CurrentEL;" : "=r" (CurrentEL) : :); - printf("CurrentEL 0x%" PRIX64 "\n", CurrentEL); - /* https://cirosantilli.com/linux-kernel-module-cheat#arm-exception-levels */ - printf("CurrentEL.EL 0x%" PRIX64 "\n", CurrentEL >> 2); - - /* https://cirosantilli.com/linux-kernel-module-cheat#arm-paging */ - { - uint64_t tcr_el1; - __asm__ ("mrs %0, tcr_el1;" : "=r" (tcr_el1) : :); - printf("TCR_EL1 0x%" PRIX64 "\n", tcr_el1); - printf("TCR_EL1.A1 0x%" PRIX64 "\n", (tcr_el1 >> 22) & 1); - - uint64_t ttbr0_el1; - __asm__ ("mrs %0, ttbr0_el1;" : "=r" (ttbr0_el1) : :); - printf("TTBR0_EL1 0x%" PRIX64 "\n", ttbr0_el1); - - uint64_t ttbr1_el1; - __asm__ ("mrs %0, ttbr1_el1;" : "=r" (ttbr1_el1) : :); - printf("TTBR1_EL1 0x%" PRIX64 "\n", ttbr1_el1); - } - + LKMC_DUMP_SYSTEM_REGS; return 0; } diff --git a/baremetal/arch/arm/dump_regs.c b/baremetal/arch/arm/dump_regs.c index 2300320..40400eb 100644 --- a/baremetal/arch/arm/dump_regs.c +++ b/baremetal/arch/arm/dump_regs.c @@ -1,4 +1,4 @@ -/* Dump registers that cannot be read from EL0. */ +/* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */ #include #include diff --git a/kernel_modules/dump_regs.c b/kernel_modules/dump_regs.c new file mode 100644 index 0000000..c533a33 --- /dev/null +++ b/kernel_modules/dump_regs.c @@ -0,0 +1,25 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */ + +#include +#include + +#define LKMC_DUMP_SYSTEM_REGS_PRINTF pr_info +#if defined(__aarch64__) +#include +#else +#define LKMC_DO_NOTHING +#endif + +static int myinit(void) +{ +#if !defined(LKMC_DO_NOTHING) + LKMC_DUMP_SYSTEM_REGS; +#endif + return 0; +} + +static void myexit(void) {} + +module_init(myinit) +module_exit(myexit) +MODULE_LICENSE("GPL"); diff --git a/lkmc/aarch64_dump_regs.h b/lkmc/aarch64_dump_regs.h new file mode 100644 index 0000000..6d210b4 --- /dev/null +++ b/lkmc/aarch64_dump_regs.h @@ -0,0 +1,55 @@ +#ifndef LKMC_AARCH64_DUMP_REGS_H +#define LKMC_AARCH64_DUMP_REGS_H + +/* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */ + +#ifndef LKMC_DUMP_SYSTEM_REGS_PRINTF +#define LKMC_DUMP_SYSTEM_REGS_PRINTF printf +#endif + +#ifndef PRIX32 +#define PRIX32 "x" +#endif + +#ifndef PRIX64 +#define PRIX64 "llx" +#endif + +/* Dump registers that are only visible from privileged levels of the system. */ +#define LKMC_DUMP_SYSTEM_REGS \ + uint32_t sctlr_el1; \ + __asm__ ("mrs %0, sctlr_el1" : "=r" (sctlr_el1) : :); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("SCTLR_EL1 0x%" PRIX32 "\n", sctlr_el1); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("SCTLR_EL1.nTWE 0x%" PRIX32 "\n", (sctlr_el1 >> 18) & 1); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("SCTLR_EL1.A 0x%" PRIX32 "\n", (sctlr_el1 >> 1) & 1); \ + /* https://cirosantilli.com/linux-kernel-module-cheat#arm-paging */ \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("SCTLR_EL1.M 0x%" PRIX32 "\n", (sctlr_el1 >> 0) & 1); \ + \ + uint64_t id_aa64pfr0_el1; \ + __asm__ ("mrs %0, id_aa64pfr0_el1" : "=r" (id_aa64pfr0_el1) : :); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("ID_AA64PFR0_EL1 0x%" PRIX64 "\n", id_aa64pfr0_el1); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("ID_AA64PFR0_EL1.SVE 0x%" PRIX64 "\n", (id_aa64pfr0_el1 >> 32) & 0xF); \ + \ + uint64_t CurrentEL; \ + __asm__ ("mrs %0, CurrentEL;" : "=r" (CurrentEL) : :); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("CurrentEL 0x%" PRIX64 "\n", CurrentEL); \ + /* https://cirosantilli.com/linux-kernel-module-cheat#arm-exception-levels */ \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("CurrentEL.EL 0x%" PRIX64 "\n", CurrentEL >> 2); \ + \ + /* https://cirosantilli.com/linux-kernel-module-cheat#arm-paging */ \ + { \ + uint64_t tcr_el1; \ + __asm__ ("mrs %0, tcr_el1;" : "=r" (tcr_el1) : :); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("TCR_EL1 0x%" PRIX64 "\n", tcr_el1); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("TCR_EL1.A1 0x%" PRIX64 "\n", (tcr_el1 >> 22) & 1); \ + \ + uint64_t ttbr0_el1; \ + __asm__ ("mrs %0, ttbr0_el1;" : "=r" (ttbr0_el1) : :); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("TTBR0_EL1 0x%" PRIX64 "\n", ttbr0_el1); \ + \ + uint64_t ttbr1_el1; \ + __asm__ ("mrs %0, ttbr1_el1;" : "=r" (ttbr1_el1) : :); \ + LKMC_DUMP_SYSTEM_REGS_PRINTF("TTBR1_EL1 0x%" PRIX64 "\n", ttbr1_el1); \ + } + +#endif