|
9 | 9 | // because the stack itself is in BSS, so BSS must be zeroed before the stack is
|
10 | 10 | // set up.
|
11 | 11 |
|
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 |
14 | 29 |
|
15 | 30 | .balign 0x10
|
16 | 31 | .globl _start
|
17 | 32 | _start:
|
18 | 33 |
|
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 |
21 | 48 | // as the return address will be wiped out.
|
22 | 49 |
|
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 |
28 | 55 | 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] |
32 | 59 | b 1b
|
33 | 60 | 2:
|
34 | 61 |
|
35 | 62 | // Set up the stack space.
|
36 | 63 |
|
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 |
54 | 74 |
|
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`. |
56 | 76 |
|
57 |
| - str x0, [sp, #-16]! |
| 77 | + str x19, [sp, #-16]! |
58 | 78 |
|
59 | 79 | // NEON and FP setup for EL1. The compiler can use SIMD as an
|
60 | 80 | // optimization because the target specific options set in the `rustc`
|
@@ -88,41 +108,82 @@ _start:
|
88 | 108 | // If the main function exited, call into the Debug Interface, or
|
89 | 109 | // break.
|
90 | 110 |
|
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 |
94 | 134 |
|
95 |
| - .macro EXCEPTION_ENTRY source, kind |
| 135 | + .macro EXCEPTION_ENTRY source_and_kind |
96 | 136 | .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. |
100 | 161 | b .
|
101 | 162 | .endm
|
102 | 163 |
|
103 | 164 | // Vector table must be aligned to a 2KB boundary.
|
104 | 165 | .balign 0x800
|
105 | 166 | _vector_table_el1:
|
106 | 167 | // 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 |
111 | 172 |
|
112 | 173 | // 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 |
117 | 178 |
|
118 | 179 | // 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 |
123 | 184 |
|
124 | 185 | // 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 |
0 commit comments