aarch64: detect exception level at runtime, cached accessor
Punch list §25 item 0.4 complete. Adds aarch64_current_el() in arch.c: reads CurrentEL[3:2] on first call, caches the result (CurrentEL cannot change post-ExitBootServices, so every consumer gets the same answer without repeating the MRS). Called from arch_interrupts_init() in interrupts.c -- the earliest point with both a working console (up since M1) and a genuine first consumer (vector installation is the first EL-dependent operation) -- and the detected level is printed to the boot log there. Declared via extern-in-place in interrupts.c rather than added to the shared arch.h: "exception level" has no amd64/riscv64 equivalent, matching the convention already used for riscv64_timer_rearm() in item 0.3. Verified on real QEMU output: "AArch64: running at EL1", correctly positioned immediately before "IDT installed." in the serial log. Boots clean, dict_hash 0x3d4e1daf289da94f unchanged from the item 0.1-0.3 baseline. Scope: this item establishes the detection and exposes it; it does not yet change VBAR/ELR/SPSR or timer-register selection to use it. arch_interrupts_init() still writes VBAR_EL1 unconditionally, and now says so explicitly in its own doc comment -- if aarch64_current_el() ever reports 2 on real hardware, exceptions taken at EL2 vector through VBAR_EL2, which nothing programs yet. That gap is items 0.5 (vectors/saved-state) and 0.7 (CNTP vs CNTHP) to close, per FABRIC.md's GAP-B3 finding. The boot-log EL2 case prints a note pointing at both. Only aarch64-scoped files touched (arch.c, interrupts.c) -- no shared loader or header changed, so amd64 and riscv64 are provably unaffected; not rebuilt for this item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5784d8a1a8
commit
f43f3f4482
@@ -14,6 +14,44 @@
|
||||
/* Installed by isr.S — installs VBAR_EL1 */
|
||||
extern void aarch64_install_vectors(void);
|
||||
|
||||
/* -1 = not yet read. Cached rather than re-read on every call: CurrentEL
|
||||
* cannot change during the kernel's lifetime post-ExitBootServices, and a
|
||||
* cached value gives every consumer (vector install, GIC timer register
|
||||
* selection) the same answer without repeating the MRS. */
|
||||
static int s_current_el = -1;
|
||||
|
||||
/**
|
||||
* @brief Return the AArch64 exception level the kernel is running at.
|
||||
*
|
||||
* Reads @c CurrentEL (bits [3:2] hold the EL number, [1:0] are RES0) on
|
||||
* first call and caches the result; every later call returns the cached
|
||||
* value. Safe to call at any point in boot, including before
|
||||
* @c console_init() — the read itself has no dependency, only the
|
||||
* printing of it does (see @c arch_interrupts_init() in @c interrupts.c,
|
||||
* the earliest point at which both this and a working console are
|
||||
* available).
|
||||
*
|
||||
* EDK2 on QEMU's aarch64 @c virt machine has been observed to leave the
|
||||
* kernel at either EL1 or EL2 depending on firmware build; nothing in this
|
||||
* tree may assume one over the other (FABRIC.md §25.7.1 GAP-B3). Every
|
||||
* EL-dependent choice — @c VBAR_EL1 vs @c VBAR_EL2, the @c ELR_ELx /
|
||||
* @c SPSR_ELx saved-state pair, and @c CNTP_*_EL0 vs @c CNTHP_*_EL2 — must
|
||||
* read this accessor rather than hardcode a level.
|
||||
*
|
||||
* @return 1 or 2. Never 0 or 3: a UEFI application that survived far enough
|
||||
* to reach this call cannot be running at EL0 (unprivileged) or EL3
|
||||
* (secure monitor — QEMU's virt firmware runs the kernel at EL1/EL2).
|
||||
*/
|
||||
int aarch64_current_el(void)
|
||||
{
|
||||
if (s_current_el < 0) {
|
||||
uint64_t current_el;
|
||||
__asm__ volatile ("mrs %0, CurrentEL" : "=r"(current_el));
|
||||
s_current_el = (int)((current_el >> 2) & 0x3);
|
||||
}
|
||||
return s_current_el;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform the earliest AArch64 architecture initialisation (no-op).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user