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
@@ -2049,7 +2049,7 @@ on until there is a tick on all three architectures (§16.1, §16.5).*
|
||||
configured rate within measurement noise. Verify the SBI extension is present before
|
||||
relying on it; if it is absent, stop and report rather than falling back silently.
|
||||
|
||||
- [ ] **0.4 — aarch64: determine the exception level at runtime.**
|
||||
- [x] **0.4 — aarch64: determine the exception level at runtime.**
|
||||
Read `CurrentEL` once, early, and let it govern **everything EL-dependent**, not just the
|
||||
timer (B3): the vector base register (`VBAR_EL1` vs `VBAR_EL2` — today's `isr.S` writes
|
||||
`VBAR_EL1` unconditionally, which is never consulted for exceptions taken at EL2), the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-03T22:22:04Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-03T22:28:54Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
tick_number,elapsed_ns,tick_interval_ns,cache_hits_delta,bucket_hits_delta,word_executions_delta,hot_word_count,avg_word_heat_q48,window_width,actual_window_size,predicted_label_hits,jitter_bits,apic_ticks,time_trust_q48,variance_q48,vm_call_depth_max,hera_heat_q48,hermes_heat_q48,artemis_heat_q48
|
||||
1,10000,10000,0,0,183,4,45,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
2,20000,10000,0,0,173,5,44,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
3,30000,10000,0,0,184,6,60,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
4,40000,10000,0,0,174,8,71,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
5,50000,10000,0,0,150,9,78,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
6,60000,10000,0,0,159,11,73,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
7,70000,10000,0,0,188,15,71,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
8,80000,10000,0,0,214,16,83,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
9,90000,10000,0,0,216,19,82,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
10,100000,10000,0,0,222,21,84,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
11,110000,10000,0,0,207,23,86,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
12,120000,10000,0,0,189,26,83,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
13,130000,10000,0,0,221,28,80,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
14,140000,10000,0,0,204,29,83,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
15,150000,10000,0,0,203,30,82,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
16,160000,10000,0,0,201,32,83,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
17,170000,10000,0,0,190,34,86,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
18,180000,10000,0,0,170,35,73,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
19,190000,10000,0,0,154,28,44,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
20,200000,10000,0,0,154,28,41,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
21,210000,10000,0,0,153,32,39,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
22,220000,10000,0,0,167,35,42,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
23,230000,10000,0,0,176,37,41,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
24,240000,10000,0,0,175,37,39,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
25,250000,10000,0,0,196,38,37,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
26,260000,10000,0,0,192,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
27,270000,10000,0,0,158,40,38,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
28,280000,10000,0,0,158,40,35,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
29,290000,10000,0,0,164,41,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
30,300000,10000,0,0,154,43,39,685,685,0,0,0,65536,0,0,65536,0,0
|
||||
31,310000,10000,0,0,172,46,35,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
32,320000,10000,0,0,180,49,34,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
33,330000,10000,0,0,145,51,35,567,567,0,0,0,65536,0,0,65536,0,0
|
||||
34,340000,10000,0,0,203,53,37,582,582,0,0,0,65536,0,0,65536,0,0
|
||||
35,350000,10000,0,0,154,55,39,731,731,0,0,0,65536,0,0,65536,0,0
|
||||
36,360000,10000,0,0,144,57,37,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
37,370000,10000,0,0,144,57,35,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
38,380000,10000,0,0,132,57,34,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
39,390000,10000,0,0,180,57,32,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
40,400000,10000,0,0,220,63,29,4096,0,0,0,0,65536,0,0,65536,0,0
|
||||
41,410000,10000,0,0,215,64,28,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
42,420000,10000,0,0,208,68,29,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
43,430000,10000,0,0,177,72,27,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
44,440000,10000,0,0,199,77,28,4096,24,0,0,0,65536,0,0,65536,0,0
|
||||
45,450000,10000,0,0,223,82,26,4096,30,0,0,0,65536,0,0,65536,0,0
|
||||
46,460000,10000,0,0,202,85,24,4096,67,0,0,0,65536,0,0,65536,0,0
|
||||
47,470000,10000,0,0,218,91,25,4096,198,0,0,0,65536,0,0,65536,0,0
|
||||
48,480000,10000,0,0,221,92,26,4096,350,0,0,0,65536,0,0,65536,0,0
|
||||
49,490000,10000,0,0,225,97,26,4096,528,0,0,0,65536,0,0,65536,0,0
|
||||
50,500000,10000,0,0,214,100,27,4096,694,0,0,0,65536,0,0,65536,0,0
|
||||
51,510000,10000,0,0,227,102,28,4096,883,0,0,0,65536,0,0,65536,0,0
|
||||
52,520000,10000,0,0,208,102,29,4096,1043,0,0,0,65536,0,0,65536,0,0
|
||||
53,530000,10000,0,0,207,102,30,4096,1202,0,0,0,65536,0,0,65536,0,0
|
||||
54,540000,10000,0,0,200,102,31,4096,1319,0,0,0,65536,0,0,65536,0,0
|
||||
55,550000,10000,0,0,205,103,32,4096,1464,0,0,0,65536,0,0,65536,0,0
|
||||
56,560000,10000,0,0,211,103,32,4096,1620,0,0,0,65536,0,0,65536,0,0
|
||||
57,570000,10000,0,0,193,110,33,4096,1712,0,0,0,65536,0,0,65536,0,0
|
||||
58,580000,10000,0,0,190,5,67,4096,1775,0,0,0,65536,0,0,65536,0,0
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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).
|
||||
*
|
||||
|
||||
@@ -17,6 +17,12 @@ volatile const char *g_sk_fault_word = (void *)0;
|
||||
/* Defined in isr.S */
|
||||
extern void aarch64_install_vectors(void);
|
||||
|
||||
/* Defined in arch.c. Extern-declared here rather than in the shared arch.h:
|
||||
* "exception level" has no amd64/riscv64 equivalent, so it does not belong
|
||||
* in the cross-ISA header — same convention as riscv64_timer_rearm() in
|
||||
* arch/riscv64/interrupts.c. */
|
||||
extern int aarch64_current_el(void);
|
||||
|
||||
/**
|
||||
* @brief Print a 64-bit value as "0xNNNNNNNNNNNNNNNN" to the kernel console.
|
||||
*
|
||||
@@ -91,12 +97,26 @@ void aarch64_exception_handler(void)
|
||||
/**
|
||||
* @brief Install the AArch64 exception vector table (M4 milestone).
|
||||
*
|
||||
* Calls @c aarch64_install_vectors() (defined in @c isr.S) which writes
|
||||
* the address of the vector table base into @c VBAR_EL1 (Vector Base
|
||||
* Address Register, EL1). After this instruction all EL1 exceptions
|
||||
* First reads and reports the exception level via @c aarch64_current_el()
|
||||
* (punch-list item 0.4) — this is the earliest point in boot with both a
|
||||
* working console (up since M1) and a genuine need for the answer (vector
|
||||
* installation is the first EL-dependent operation). The read itself is
|
||||
* cheap and safe far earlier than this; only the console print is gated on
|
||||
* this call site.
|
||||
*
|
||||
* Then calls @c aarch64_install_vectors() (defined in @c isr.S) which
|
||||
* writes the address of the vector table base into @c VBAR_EL1 (Vector
|
||||
* Base Address Register, EL1). After this instruction all EL1 exceptions
|
||||
* (synchronous, IRQ, FIQ, SError) dispatch through the 512-byte-aligned
|
||||
* vector table assembled in @c isr.S.
|
||||
*
|
||||
* **@c VBAR_EL1 is written unconditionally regardless of the detected
|
||||
* level.** If @c aarch64_current_el() reports EL2, this is a known gap:
|
||||
* exceptions taken at EL2 vector through @c VBAR_EL2, which nothing here
|
||||
* programs, and installing EL2-aware vectors is punch-list item 0.5's
|
||||
* scope, not this one's. Item 0.4 establishes the detection every later
|
||||
* EL-dependent item must consult; it does not yet make use of it here.
|
||||
*
|
||||
* On AArch64 there is no IDT and no PIC to disable; the GIC replaces
|
||||
* both. The @c arch_interrupts_init() name is kept identical across all
|
||||
* ISAs so that @c kernel_main() can call the same symbol regardless of
|
||||
@@ -107,5 +127,12 @@ void aarch64_exception_handler(void)
|
||||
*/
|
||||
void arch_interrupts_init(void)
|
||||
{
|
||||
int el = aarch64_current_el();
|
||||
console_puts("AArch64: running at EL");
|
||||
console_putc((char)('0' + el));
|
||||
console_println(el == 2
|
||||
? " (VBAR_EL2/CNTHP_*_EL2 required — not yet wired, see item 0.5/0.7)"
|
||||
: "");
|
||||
|
||||
aarch64_install_vectors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user