mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
factor out baremetal aarch64 dump_regs.c for kernel module usage
Create dump-regs section.
This commit is contained in:
42
README.adoc
42
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
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
25
kernel_modules/dump_regs.c
Normal file
25
kernel_modules/dump_regs.c
Normal 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
55
lkmc/aarch64_dump_regs.h
Normal 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
|
||||||
Reference in New Issue
Block a user