factor out baremetal aarch64 dump_regs.c for kernel module usage

Create dump-regs section.
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-12-12 00:00:04 +00:00
parent 6f9fbfdcd8
commit cf4ed0f11d
5 changed files with 126 additions and 37 deletions

View File

@@ -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 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 <<baremetal>> 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 <<gdb>> 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 == Xen
TODO: get prototype working and then properly integrate: 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? 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 <<dump-regs,dump_regs kernel module>> 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 include/asm/sysreg.h

View File

@@ -1,42 +1,11 @@
/* Dump registers that cannot be read from EL0. */ /* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */
#include <stdio.h> #include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <lkmc/aarch64_dump_regs.h>
int main(void) { int main(void) {
uint32_t sctlr_el1; LKMC_DUMP_SYSTEM_REGS;
__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);
}
return 0; return 0;
} }

View File

@@ -1,4 +1,4 @@
/* Dump registers that cannot be read from EL0. */ /* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */
#include <stdio.h> #include <stdio.h>
#include <inttypes.h> #include <inttypes.h>

View File

@@ -0,0 +1,25 @@
/* https://cirosantilli.com/linux-kernel-module-cheat#dump-regs */
#include <linux/module.h>
#include <linux/kernel.h>
#define LKMC_DUMP_SYSTEM_REGS_PRINTF pr_info
#if defined(__aarch64__)
#include <lkmc/aarch64_dump_regs.h>
#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");

55
lkmc/aarch64_dump_regs.h Normal file
View File

@@ -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