@@ -90,8 +90,11 @@ static int vmpu_fault_recovery_mpu(uint32_t pc, uint32_t sp, uint32_t fault_addr
9090 const MpuRegion * region ;
9191 uint8_t mask , index , page ;
9292
93- /* No recovery is possible if the MPU syndrome register is not valid. */
94- if (fault_status == (SCB_CFSR_MMARVALID_Msk | SCB_CFSR_DACCVIOL_Msk )) {
93+ /* No recovery is possible if the MPU syndrome register is not valid or
94+ * this is not a stacking fault (where the MPU syndrome register would not
95+ * be valid, but we can still recover). */
96+ if (!((fault_status == (SCB_CFSR_MMARVALID_Msk | SCB_CFSR_DACCVIOL_Msk )) ||
97+ (fault_status & (SCB_CFSR_MSTKERR_Msk | SCB_CFSR_MUNSTKERR_Msk )))) {
9598 return 0 ;
9699 }
97100
@@ -112,7 +115,7 @@ static int vmpu_fault_recovery_mpu(uint32_t pc, uint32_t sp, uint32_t fault_addr
112115 return 1 ;
113116}
114117
115- void vmpu_sys_mux_handler (uint32_t lr , uint32_t msp )
118+ uint32_t vmpu_sys_mux_handler (uint32_t lr , uint32_t msp )
116119{
117120 uint32_t psp , pc ;
118121 uint32_t fault_addr , fault_status ;
@@ -127,29 +130,45 @@ void vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
127130
128131 switch (ipsr ) {
129132 case MemoryManagement_IRQn :
130- /* Currently we only support recovery from unprivileged mode. */
131- if (lr & 0x4 ) {
133+ fault_status = VMPU_SCB_MMFSR ;
134+
135+ /* If we are having an unstacking fault, we can't read the pc
136+ * at fault. */
137+ if (fault_status & (SCB_CFSR_MSTKERR_Msk | SCB_CFSR_MUNSTKERR_Msk )) {
138+ /* Fake pc */
139+ pc = 0x0 ;
140+
141+ /* The stack pointer is at fault. MMFAR doesn't contain a
142+ * valid fault address. */
143+ fault_addr = lr & 0x4 ? psp : msp ;
144+ } else {
132145 /* pc at fault */
133- pc = vmpu_unpriv_uint32_read (psp + (6 * 4 ));
146+ if (lr & 0x4 ) {
147+ pc = vmpu_unpriv_uint32_read (psp + (6 * 4 ));
148+ } else {
149+ /* We can be privileged here if we tried doing an ldrt or
150+ * strt to a region not currently loaded in the MPU. In
151+ * such cases, we are reading from the msp and shouldn't go
152+ * through vmpu_unpriv_uint32_read. A box wouldn't have
153+ * access to our stack. */
154+ pc = * (uint32_t * ) (msp + (6 * 4 ));
155+ }
134156
135157 /* Backup fault address and status */
136158 fault_addr = SCB -> MMFAR ;
137- fault_status = VMPU_SCB_MMFSR ;
138-
139- /* Check if the fault is an MPU fault. */
140- if (vmpu_fault_recovery_mpu (pc , psp , fault_addr , fault_status )) {
141- VMPU_SCB_MMFSR = fault_status ;
142- return ;
143- }
159+ }
144160
145- /* If recovery was not successful, throw an error and halt . */
146- DEBUG_FAULT ( FAULT_MEMMANAGE , lr , psp );
161+ /* Check if the fault is an MPU fault . */
162+ if ( vmpu_fault_recovery_mpu ( pc , psp , fault_addr , fault_status )) {
147163 VMPU_SCB_MMFSR = fault_status ;
148- HALT_ERROR (PERMISSION_DENIED , "Access to restricted resource denied" );
149- } else {
150- DEBUG_FAULT (FAULT_MEMMANAGE , lr , msp );
151- HALT_ERROR (FAULT_MEMMANAGE , "Cannot recover from privileged MemManage fault" );
164+ return lr ;
152165 }
166+
167+ /* If recovery was not successful, throw an error and halt. */
168+ DEBUG_FAULT (FAULT_MEMMANAGE , lr , lr & 0x4 ? psp : msp );
169+ VMPU_SCB_MMFSR = fault_status ;
170+ HALT_ERROR (PERMISSION_DENIED , "Access to restricted resource denied" );
171+ lr = debug_box_enter_from_priv (lr );
153172 break ;
154173
155174 case BusFault_IRQn :
@@ -173,16 +192,13 @@ void vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
173192 /* Check if the fault is the special register corner case. */
174193 if (!vmpu_fault_recovery_bus (pc , psp , fault_addr , fault_status )) {
175194 VMPU_SCB_BFSR = fault_status ;
176- return ;
195+ return lr ;
177196 }
178-
179- /* If recovery was not successful, throw an error and halt. */
180- DEBUG_FAULT (FAULT_BUS , lr , psp );
181- HALT_ERROR (PERMISSION_DENIED , "Access to restricted resource denied" );
182- } else {
183- DEBUG_FAULT (FAULT_BUS , lr , msp );
184- HALT_ERROR (FAULT_BUS , "Cannot recover from privileged bus fault" );
185197 }
198+
199+ /* If recovery was not successful, throw an error and halt. */
200+ DEBUG_FAULT (FAULT_BUS , lr , lr & 0x4 ? psp : msp );
201+ HALT_ERROR (PERMISSION_DENIED , "Access to restricted resource denied" );
186202 break ;
187203
188204 case UsageFault_IRQn :
@@ -193,6 +209,7 @@ void vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
193209 case HardFault_IRQn :
194210 DEBUG_FAULT (FAULT_HARD , lr , lr & 0x4 ? psp : msp );
195211 HALT_ERROR (FAULT_HARD , "Cannot recover from a hard fault." );
212+ lr = debug_box_enter_from_priv (lr );
196213 break ;
197214
198215 case DebugMonitor_IRQn :
@@ -212,6 +229,8 @@ void vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
212229 HALT_ERROR (NOT_ALLOWED , "Active IRQn(%i) is not a system interrupt" , ipsr );
213230 break ;
214231 }
232+
233+ return lr ;
215234}
216235
217236static int vmpu_mem_push_page_acl_iterator (uint8_t mask , uint8_t index )
0 commit comments