Skip to content

Commit 814ee09

Browse files
authored
openhcl_boot, arm64: let VBAR_EL1 entries use crash registers (#1874)
When the bootshim fails on arm64 in the low-level paths/ways, it'll just spin. Enlighten the VBAR_EL1 entries to write to the crash registers to have diagnostics if something goes wrong early in the early code, e.g. when servicing. Few other fixes included, seemed appropriate: * do not use `weak _DYNAMIC` as that hides the issues with the toolchain and leads to hard to diagnose failures, * do not spin on relocation failures, * install `VBAR_EL1` as early as possible, * always inline the `fault` and `dead_loop` intrinsics. Tested by inserting `brk` in various places in the asm. Observed the crash report on the host.
1 parent ce83fab commit 814ee09

File tree

5 files changed

+134
-59
lines changed

5 files changed

+134
-59
lines changed

openhcl/minimal_rt/src/arch/aarch64/intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ unsafe extern "C" fn __stack_chk_fail() {
7474
}
7575

7676
/// Causes a processor fault.
77-
#[inline]
77+
#[inline(always)]
7878
pub fn fault() -> ! {
7979
// SAFETY: faults the processor, so the program ends.
8080
unsafe {
@@ -84,7 +84,7 @@ pub fn fault() -> ! {
8484
}
8585

8686
/// Spins forever, preserving some context in the registers.
87-
#[inline]
87+
#[inline(always)]
8888
pub fn dead_loop(code0: u64, code1: u64, code2: u64) -> ! {
8989
// SAFETY: no safety requirements.
9090
unsafe {

openhcl/minimal_rt/src/reloc.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
macro_rules! panic_no_relocs {
1313
($code:expr) => {{
1414
let _code = $code;
15-
crate::arch::dead_loop(_code as u64, line!() as u64, file!().as_ptr() as u64);
15+
crate::arch::fault();
16+
// Uncomment for local debugging. Can't spin forever in the official build.
17+
// crate::arch::dead_loop(_code as u64, line!() as u64, file!().as_ptr() as u64);
1618
}};
1719
}
1820

openhcl/openhcl_boot/src/arch/aarch64/entry.S

Lines changed: 115 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,52 +9,72 @@
99
// because the stack itself is in BSS, so BSS must be zeroed before the stack is
1010
// set up.
1111

12-
.weak _DYNAMIC
13-
.hidden _DYNAMIC
12+
// Not all distro's have toolchains whose linker script facilitates emitting
13+
// _DYNAMIC. In case of the linking failures due to missing _DYNAMIC, blame on
14+
// the toolchain's default linker script (maybe we should provide our own one).
15+
//
16+
// Adding something like ".weak _DYNAMIC" masks that issue, and makes the bootloader
17+
// fail when relocating the image as that won't point to the correct location.
18+
19+
.extern _DYNAMIC
20+
21+
// Calls into the platform's debug interface
22+
23+
.macro SMC_CALL_DEBUG_INTERFACE
24+
mov x0, 6
25+
movk x0, 0x8600, lsl 16
26+
smc #0
27+
brk #0xffff
28+
.endm
1429

1530
.balign 0x10
1631
.globl _start
1732
_start:
1833

19-
// Clean BSS, avoid using x0 as it contains the IGVM parameter.
20-
// NOTE: the stack space is allocated in BSS, and can't use function calls
34+
// Save the x0 which contains the IGVM parameter to the first scratch non-volatile register.
35+
36+
mov x19, x0
37+
38+
// Set the EL1 vector base address register to point to the vector table
39+
// at the earliest possible point.
40+
41+
adrp x0, _vector_table_el1
42+
add x0, x0, :lo12:_vector_table_el1
43+
msr VBAR_EL1, x0
44+
isb
45+
46+
// Clean BSS.
47+
// NOTE: the stack space is allocated in BSS, and one can't use function calls yet
2148
// as the return address will be wiped out.
2249

23-
adrp x1, __bss_start__
24-
add x1, x1, :lo12:__bss_start__ // X1 contains the BSS start
25-
adrp x2, __bss_end__
26-
add x2, x2, :lo12:__bss_end__
27-
sub x2, x2, x1 // X2 contains the BSS length
50+
adrp x0, __bss_start__
51+
add x0, x0, :lo12:__bss_start__ // X0 contains the BSS start
52+
adrp x1, __bss_end__
53+
add x1, x1, :lo12:__bss_end__
54+
sub x1, x1, x0 // X2 contains the BSS length
2855
1:
29-
cbz x2, 2f
30-
sub x2, x2, 1
31-
strb wzr, [x1,x2]
56+
cbz x1, 2f
57+
sub x1, x1, 1
58+
strb wzr, [x0,x1]
3259
b 1b
3360
2:
3461

3562
// Set up the stack space.
3663

37-
adrp x1, {stack}
38-
add x1, x1, :lo12:{stack}
39-
mov x2, {STACK_COOKIE_LO} // Lower 16 bits of the stack cookie
40-
movk x2, {STACK_COOKIE_HI}, lsl 16 // Higher 16 bits of the stack cookie, keep the lower bits
41-
str x2, [x1] // Store the stack cookie at the bottom
42-
add x1, x1, {STACK_SIZE} // Stack size
43-
sub x1, x1, #8 // Leave 8 bytes for the stack cookie at the top
44-
str x2, [x1] // Store the stack cookie at the top
45-
sub x1, x1, #8 // Set the stack pointer
46-
mov sp, x1
47-
48-
// Set the vector table up.
49-
50-
adrp x1, _vector_table_el1
51-
add x1, x1, :lo12:_vector_table_el1
52-
msr VBAR_EL1, x1
53-
isb
64+
adrp x0, {stack}
65+
add x0, x0, :lo12:{stack}
66+
mov x1, {STACK_COOKIE_LO} // Lower 16 bits of the stack cookie
67+
movk x1, {STACK_COOKIE_HI}, lsl 16 // Higher 16 bits of the stack cookie, keep the lower bits
68+
str x1, [x0] // Store the stack cookie at the bottom
69+
add x0, x0, {STACK_SIZE} // Stack size
70+
sub x0, x0, #8 // Leave 8 bytes for the stack cookie at the top
71+
str x1, [x0] // Store the stack cookie at the top
72+
sub x0, x0, #8 // Set the stack pointer
73+
mov sp, x0
5474

55-
// Push x0 to the stack, its value has to be passed to `start`.
75+
// Push `x19` (the IGVM parameter copied from x0) to the stack, its value has to be passed to `start`.
5676

57-
str x0, [sp, #-16]!
77+
str x19, [sp, #-16]!
5878

5979
// NEON and FP setup for EL1. The compiler can use SIMD as an
6080
// optimization because the target specific options set in the `rustc`
@@ -88,41 +108,82 @@ _start:
88108
// If the main function exited, call into the Debug Interface, or
89109
// break.
90110

91-
mov x0, 6
92-
movk x0, 0x8600, lsl 16
93-
smc #0
111+
SMC_CALL_DEBUG_INTERFACE
112+
113+
// This macro is used to connect to the hypervisor and run the enlightened
114+
// crash reporting from the handlers in the exception table. Using Rust or stack
115+
// might be problematic at the time of the crash if the stack is corrupted or the
116+
// image is not relocated.
117+
//
118+
// Save the value to `x5`.
119+
// Clobbers `x0`-`x6`.
120+
//
121+
// N.B. Using the combination of `ldr` and `=` for loading constants is safe w/o
122+
// relocation as it produces PC-relative addresses or movz/movk instructions if
123+
// the immediate value fits.
124+
125+
.macro SET_VP_REGISTER64 vp_reg_name, val
126+
ldr x0, =0x100010051 // Input: 1 argument, fast, HvCallSetVpRegisters
127+
mov x1, #0xffffffffffffffff // This partition
128+
mov x2, #0xfffffffe // This VP
129+
ldr x3, =\vp_reg_name
130+
mov x4, #0 // Padding
131+
mov x6, #0 // Upper 64 bits of the value
132+
hvc #1 // Hyper-V ABI
133+
.endm
94134

95-
.macro EXCEPTION_ENTRY source, kind
135+
.macro EXCEPTION_ENTRY source_and_kind
96136
.align 7
97-
b .
98-
mov x0, \source
99-
mov x1, \kind
137+
// Connect to the hypervisor as can't assume that has been done already.
138+
// No harm if that is done any number of times.
139+
140+
mov x5, {OHCL_LOADER_OSID}
141+
SET_VP_REGISTER64 {HV_REGISTER_OSID}
142+
143+
// Report the crash data
144+
145+
mov x5, \source_and_kind
146+
SET_VP_REGISTER64 {HV_REGISTER_GUEST_CRASH_P0}
147+
mrs x5, PAR_EL1
148+
SET_VP_REGISTER64 {HV_REGISTER_GUEST_CRASH_P1}
149+
mrs x5, ELR_EL1
150+
SET_VP_REGISTER64 {HV_REGISTER_GUEST_CRASH_P2}
151+
mrs x5, ESR_EL1
152+
SET_VP_REGISTER64 {HV_REGISTER_GUEST_CRASH_P3}
153+
mov x5, 0 // No message
154+
SET_VP_REGISTER64 {HV_REGISTER_GUEST_CRASH_P4}
155+
mov x5, {GUEST_CRASH_CTRL}
156+
SET_VP_REGISTER64 {HV_REGISTER_GUEST_CRASH_CTRL}
157+
158+
SMC_CALL_DEBUG_INTERFACE
159+
160+
// If nothing of the above has made the code break, spin forever.
100161
b .
101162
.endm
102163

103164
// Vector table must be aligned to a 2KB boundary.
104165
.balign 0x800
105166
_vector_table_el1:
106167
// Target and source at same exception level with source SP = SP_EL0
107-
EXCEPTION_ENTRY #0x0, #0x0 // Synchronous exception
108-
EXCEPTION_ENTRY #0x0, #0x1 // IRQ
109-
EXCEPTION_ENTRY #0x0, #0x2 // FIQ
110-
EXCEPTION_ENTRY #0x0, #0x3 // SError
168+
EXCEPTION_ENTRY 0x00 // Synchronous exception
169+
EXCEPTION_ENTRY 0x01 // IRQ
170+
EXCEPTION_ENTRY 0x02 // FIQ
171+
EXCEPTION_ENTRY 0x03 // SError
111172

112173
// Target and source at same exception level with source SP = SP_ELx
113-
EXCEPTION_ENTRY #0x1, #0x0 // Synchronous exception
114-
EXCEPTION_ENTRY #0x1, #0x1 // IRQ
115-
EXCEPTION_ENTRY #0x1, #0x2 // FIQ
116-
EXCEPTION_ENTRY #0x1, #0x3 // SError
174+
EXCEPTION_ENTRY 0x10 // Synchronous exception
175+
EXCEPTION_ENTRY 0x11 // IRQ
176+
EXCEPTION_ENTRY 0x12 // FIQ
177+
EXCEPTION_ENTRY 0x13 // SError
117178

118179
// Source is at lower exception level running on AArch64
119-
EXCEPTION_ENTRY #0x2, #0x0 // Synchronous exception
120-
EXCEPTION_ENTRY #0x2, #0x1 // IRQ
121-
EXCEPTION_ENTRY #0x2, #0x2 // FIQ
122-
EXCEPTION_ENTRY #0x2, #0x3 // SError
180+
EXCEPTION_ENTRY 0x20 // Synchronous exception
181+
EXCEPTION_ENTRY 0x21 // IRQ
182+
EXCEPTION_ENTRY 0x22 // FIQ
183+
EXCEPTION_ENTRY 0x23 // SError
123184

124185
// Source is at lower exception level running on AArch32
125-
EXCEPTION_ENTRY #0x3, #0x0 // Synchronous exception
126-
EXCEPTION_ENTRY #0x3, #0x1 // IRQ
127-
EXCEPTION_ENTRY #0x3, #0x2 // FIQ
128-
EXCEPTION_ENTRY #0x3, #0x3 // SError
186+
EXCEPTION_ENTRY 0x30 // Synchronous exception
187+
EXCEPTION_ENTRY 0x31 // IRQ
188+
EXCEPTION_ENTRY 0x32 // FIQ
189+
EXCEPTION_ENTRY 0x33 // SError

openhcl/openhcl_boot/src/arch/aarch64/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,17 @@ core::arch::global_asm! {
2626
STACK_COOKIE_LO = const (crate::rt::STACK_COOKIE as u16),
2727
STACK_COOKIE_HI = const ((crate::rt::STACK_COOKIE >> 16) as u16),
2828
STACK_SIZE = const crate::rt::STACK_SIZE,
29+
HV_REGISTER_OSID = const hvdef::HvArm64RegisterName::GuestOsId.0,
30+
OHCL_LOADER_OSID = const hvdef::hypercall::HvGuestOsMicrosoft::new()
31+
.with_os_id(1)
32+
.into_bits(),
33+
HV_REGISTER_GUEST_CRASH_P0 = const hvdef::HvArm64RegisterName::GuestCrashP0.0,
34+
HV_REGISTER_GUEST_CRASH_P1 = const hvdef::HvArm64RegisterName::GuestCrashP1.0,
35+
HV_REGISTER_GUEST_CRASH_P2 = const hvdef::HvArm64RegisterName::GuestCrashP2.0,
36+
HV_REGISTER_GUEST_CRASH_P3 = const hvdef::HvArm64RegisterName::GuestCrashP3.0,
37+
HV_REGISTER_GUEST_CRASH_P4 = const hvdef::HvArm64RegisterName::GuestCrashP4.0,
38+
HV_REGISTER_GUEST_CRASH_CTRL = const hvdef::HvArm64RegisterName::GuestCrashCtl.0,
39+
GUEST_CRASH_CTRL = const hvdef::GuestCrashCtl::new()
40+
.with_no_crash_dump(true)
41+
.with_crash_notify(true).into_bits()
2942
}

tmk/tmk_core/src/aarch64.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ use super::Scope;
1010
#[cfg(minimal_rt)]
1111
mod entry {
1212
core::arch::global_asm! {
13-
".weak _DYNAMIC",
14-
".hidden _DYNAMIC",
13+
".extern _DYNAMIC",
1514
".globl _start",
1615
"_start:",
1716
"mov x19, x0",

0 commit comments

Comments
 (0)