@@ -33,9 +33,12 @@ pub unsafe fn entry_point_el1(arg0: u64, arg1: u64, arg2: u64, arg3: u64, entry_
3333 // Setup EL1
3434 // SAFETY: We are configuring HCR_EL2 to allow EL1 execution.
3535 unsafe {
36+ setup_stage2 ( ) ;
37+
3638 let mut hcr = arch:: hcr_el2:: read ( ) ;
3739 hcr |= arch:: hcr_el2:: RW ;
3840 hcr |= arch:: hcr_el2:: TSC ;
41+ hcr |= arch:: hcr_el2:: VM ;
3942 hcr &= !arch:: hcr_el2:: IMO ;
4043 arch:: hcr_el2:: write ( hcr) ;
4144 }
@@ -81,6 +84,37 @@ pub unsafe fn entry_point_el1(arg0: u64, arg1: u64, arg2: u64, arg3: u64, entry_
8184 }
8285}
8386
87+ fn setup_stage2 ( ) {
88+ debug ! ( "Setting up stage 2 page table" ) ;
89+ let idmap = Box :: new ( PlatformImpl :: make_stage2_pagetable ( ) ) ;
90+
91+ let root_pa = idmap. root_address ( ) . 0 ;
92+ debug ! ( "Root PA: {root_pa:#x}" ) ;
93+ let idmap = Box :: leak ( idmap) ;
94+
95+ // Activate the page table
96+ // SAFETY: We are initializing the Stage 2 translation. The guest is not running yet.
97+ unsafe {
98+ let ttbr = idmap. activate ( ) ;
99+ debug ! ( "idmap.activate() returned ttbr={ttbr:#x}" ) ;
100+
101+ let vtcr = arch:: vtcr_el2:: PS_40BIT
102+ | arch:: vtcr_el2:: TG0_4KB
103+ | arch:: vtcr_el2:: SH0_INNER
104+ | arch:: vtcr_el2:: ORGN0_WB_RA_WA
105+ | arch:: vtcr_el2:: IRGN0_WB_RA_WA
106+ | arch:: vtcr_el2:: SL0_L0
107+ | arch:: vtcr_el2:: T0SZ_40BIT ;
108+ debug ! ( "Writing VTCR_EL2={vtcr:#x}..." ) ;
109+ arch:: vtcr_el2:: write ( vtcr) ;
110+
111+ arch:: tlbi_vmalls12e1 ( ) ;
112+ arch:: dsb ( ) ;
113+ arch:: isb ( ) ;
114+ debug ! ( "Stage 2 activation complete." ) ;
115+ }
116+ }
117+
84118/// Returns to EL1.
85119///
86120/// This function executes the `eret` instruction to return to EL1 with the provided arguments.
@@ -122,13 +156,53 @@ pub fn handle_sync_lower(mut register_state: RegisterStateRef) {
122156 }
123157 }
124158 }
125- ExceptionClass :: Unknown ( _ ) => {
159+ ExceptionClass :: Unknown ( val ) => {
126160 panic ! (
127- "Unexpected sync_lower, far={:#x}, register_state={register_state:?}" ,
161+ "Unexpected sync_lower, esr={esr:#x}, ec={val:#x}, far={:#x}, register_state={register_state:?}" ,
128162 far( ) ,
129163 ) ;
130164 }
165+ ExceptionClass :: DataAbortLowerEL => {
166+ inject_data_abort ( & mut register_state) ;
167+ }
168+ }
169+ }
170+
171+ fn inject_data_abort ( register_state : & mut RegisterStateRef ) {
172+ // SAFETY: We are modifying the saved register state to redirect execution.
173+ let regs = unsafe { register_state. get_mut ( ) } ;
174+ let fault_addr = far ( ) ;
175+ let syndrome = esr ( ) ;
176+
177+ debug ! ( "Injecting data abort to guest: fault_addr={fault_addr:#x}, syndrome={syndrome:#x}" ) ;
178+
179+ // Read guest VBAR
180+ let vbar = arch:: vbar_el1:: read ( ) ;
181+ assert ! (
182+ vbar != 0 ,
183+ "Guest VBAR_EL1 is 0, cannot inject data abort. Fault addr: {fault_addr:#x}"
184+ ) ;
185+ let handler = vbar + 0x200 ; // Current EL with SPx Sync
186+
187+ // Save current context to guest EL1 regs
188+ // SAFETY: We are accessing EL1 system registers to inject exception.
189+ unsafe {
190+ arch:: elr_el1:: write ( regs. elr as u64 ) ;
191+ arch:: spsr_el1:: write ( regs. spsr ) ;
192+ arch:: esr_el1:: write ( syndrome) ;
193+ arch:: far_el1:: write ( fault_addr) ;
194+ }
195+
196+ // Redirect execution
197+ #[ expect(
198+ clippy:: cast_possible_truncation,
199+ reason = "only 64-bit target is supported"
200+ ) ]
201+ {
202+ regs. elr = handler as usize ;
131203 }
204+ // Mask all interrupts (DAIF) and set mode to EL1h (0x5)
205+ regs. spsr = 0x3C5 ;
132206}
133207
134208const AARCH64_INSTRUCTION_LENGTH : usize = 4 ;
@@ -311,6 +385,8 @@ enum ExceptionClass {
311385 HvcTrappedInAArch64 ,
312386 /// SMC instruction execution in `AArch64` state.
313387 SmcTrappedInAArch64 ,
388+ /// Data Abort taken without a change in Exception Level.
389+ DataAbortLowerEL ,
314390 #[ allow( unused) ]
315391 /// Unknown exception class.
316392 Unknown ( u8 ) ,
@@ -321,6 +397,7 @@ impl ExceptionClass {
321397 match value {
322398 0x16 => Self :: HvcTrappedInAArch64 ,
323399 0x17 => Self :: SmcTrappedInAArch64 ,
400+ 0x24 => Self :: DataAbortLowerEL ,
324401 _ => Self :: Unknown ( value) ,
325402 }
326403 }
0 commit comments