Skip to content

Commit 767e794

Browse files
committed
K64F vMPU: Use the MPU fault address
When recovering from an MPU fault on K64F, we were using the bus fault syndrome register. This register does not contain a valid address when the bus fault is imprecise. On the other hand, the syndrome register for the MPU module always contains a valid register when an MPU fault occur. This commit introduces 2 `inline` APIs to fetch and clear the fault status for a given slave port, and uses them to recover from a potential MPU fault. This fixes a bug found in release builds of our `blinky` example, where some faults were imprecise. Fixes: * 2c565f8 Implement recovering from page heap faults
1 parent f455482 commit 767e794

File tree

2 files changed

+86
-5
lines changed

2 files changed

+86
-5
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#ifndef __VMPU_FREESCALE_K64_H__
18+
#define __VMPU_FREESCALE_K64_H__
19+
20+
/* MPU fault status codes */
21+
#define VMPU_FAULT_NONE (-1)
22+
#define VMPU_FAULT_MULTIPLE (-2)
23+
24+
/** Get the slave port number from the MPU->CESR SPERR field.
25+
* @returns The slave port number, or a negative value to signal an error
26+
* @retval \ref VMPU_FAULT_NONE No MPU violation found
27+
* @retval \ref VMPU_FAULT_MULTIPLE Multiple MPU violations found
28+
*/
29+
UVISOR_FORCEINLINE int vmpu_fault_get_slave_port(void)
30+
{
31+
uint32_t mpu_cesr_sperr = (MPU->CESR & MPU_CESR_SPERR_MASK) >> MPU_CESR_SPERR_SHIFT;
32+
switch (mpu_cesr_sperr) {
33+
case 0x00:
34+
return VMPU_FAULT_NONE;
35+
case 0x01:
36+
return 4;
37+
case 0x02:
38+
return 3;
39+
case 0x04:
40+
return 2;
41+
case 0x08:
42+
return 1;
43+
case 0x10:
44+
return 0;
45+
default:
46+
return VMPU_FAULT_MULTIPLE;
47+
}
48+
}
49+
50+
/** Clear the fault bits in the MPU->CESR SPERR field.
51+
* @note We only clear the fault required by the input argument. If there are
52+
* multiple faults only one will be cleared.
53+
* @param slave_port[in] Slave port number for which the fault must be
54+
* cleared
55+
*/
56+
UVISOR_FORCEINLINE void vmpu_fault_clear_slave_port(int slave_port)
57+
{
58+
/* We only clear the bits if the slave port is valid. */
59+
if (slave_port >= 0 && slave_port <= 4) {
60+
uint32_t slave_port_bits = 1 << ((uint32_t) slave_port);
61+
MPU->CESR |= (slave_port_bits << MPU_CESR_SPERR_SHIFT) & MPU_CESR_SPERR_SHIFT;
62+
}
63+
}
64+
65+
#endif /* __VMPU_FREESCALE_K64_H__ */

core/system/src/mpu/vmpu_freescale_k64.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@
2222
#include "svc.h"
2323
#include "unvic.h"
2424
#include "vmpu.h"
25+
#include "vmpu_freescale_k64.h"
2526
#include "vmpu_freescale_k64_aips.h"
2627
#include "vmpu_freescale_k64_mem.h"
2728
#include "page_allocator_faults.h"
2829

2930
uint32_t g_box_mem_pos;
3031

31-
static int vmpu_fault_recovery_mpu(uint32_t pc, uint32_t sp, uint32_t fault_addr, uint32_t fault_status)
32+
static int vmpu_fault_recovery_mpu(uint32_t pc, uint32_t sp, uint32_t fault_addr)
3233
{
33-
(void) fault_status;
3434
uint32_t start_addr, end_addr;
3535
uint8_t page;
3636

@@ -92,9 +92,25 @@ void vmpu_sys_mux_handler(uint32_t lr, uint32_t msp)
9292
fault_status = VMPU_SCB_BFSR;
9393

9494
/* check if the fault is an MPU fault */
95-
if (MPU->CESR >> 27 && !vmpu_fault_recovery_mpu(pc, psp, fault_addr, fault_status)) {
96-
VMPU_SCB_BFSR = fault_status;
97-
return;
95+
int slave_port = vmpu_fault_get_slave_port();
96+
if (slave_port >= 0) {
97+
/* If the fault comes from the MPU module, we don't use the
98+
* bus fault syndrome register, but the MPU one. */
99+
fault_addr = MPU->SP[slave_port].EAR;
100+
101+
/* Check if we can recover from the MPU fault. */
102+
if (!vmpu_fault_recovery_mpu(pc, psp, fault_addr)) {
103+
/* We clear the bus fault status anyway. */
104+
VMPU_SCB_BFSR = fault_status;
105+
106+
/* We also clear the MPU fault status bit. */
107+
vmpu_fault_clear_slave_port(slave_port);
108+
109+
/* Recover from the exception. */
110+
return;
111+
}
112+
} else if (slave_port == VMPU_FAULT_MULTIPLE) {
113+
DPRINTF("Multiple MPU violations found.\r\n");
98114
}
99115

100116
/* check if the fault is the special register corner case */

0 commit comments

Comments
 (0)