Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle armv8m unpriv_access with SAU #486

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 24 additions & 99 deletions core/vmpu/src/mpu_armv8m/vmpu_armv8m_unpriv_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,110 +15,35 @@
* limitations under the License.
*/
#include <uvisor.h>
#include <stdbool.h>
#include "context.h"
#include "debug.h"
#include "vmpu.h"
#include "halt.h"
#include "vmpu_mpu.h"
#include "vmpu_unpriv_access.h"
#include <stdbool.h>

#define TT_RESP_IREGION_Pos 24U
#define TT_RESP_IREGION_Msk (0xFFUL << TT_RESP_IREGION_Pos)

#define TT_RESP_IRVALID_Pos 23U
#define TT_RESP_IRVALID_Msk (1UL << TT_RESP_IRVALID_Pos)

#define TT_RESP_S_Pos 22U
#define TT_RESP_S_Msk (1UL << TT_RESP_S_Pos)

#define TT_RESP_NSRW_Pos 21U
#define TT_RESP_NSRW_Msk (1UL << TT_RESP_NSRW_Pos)

#define TT_RESP_NSR_Pos 20U
#define TT_RESP_NSR_Msk (1UL << TT_RESP_NSR_Pos)

#define TT_RESP_RW_Pos 19U
#define TT_RESP_RW_Msk (1UL << TT_RESP_RW_Pos)

#define TT_RESP_R_Pos 18U
#define TT_RESP_R_Msk (1UL << TT_RESP_R_Pos)

#define TT_RESP_SRVALID_Pos 17U
#define TT_RESP_SRVALID_Msk (1UL << TT_RESP_SRVALID_Pos)

#define TT_RESP_MRVALID_Pos 16U
#define TT_RESP_MRVALID_Msk (1UL << TT_RESP_MRVALID_Pos)

#define TT_RESP_SREGION_Pos 8U
#define TT_RESP_SREGION_Msk (0xFFUL << TT_RESP_SREGION_Pos)

#define TT_RESP_MREGION_Pos 0U
#define TT_RESP_MREGION_Msk (0xFFUL << TT_RESP_MREGION_Pos)


static uint32_t vmpu_unpriv_test_range(uint32_t addr, uint32_t size)
{
if (!size) size = 1;
uint32_t response_lower, response_upper;
uint32_t test_addr_lower = addr & ~31UL;
uint32_t test_addr_upper = (addr + size - 1) & ~31UL;

/* Test lower address. */
asm volatile (
"tta %[response], %[addr]"
: [response] "=r" (response_lower)
: [addr] "r" (test_addr_lower)
);
if (test_addr_lower != test_addr_upper) {
/* Test upper address. */
asm volatile (
"tta %[response], %[addr]"
: [response] "=r" (response_upper)
: [addr] "r" (test_addr_upper)
);
/* If lower and upper do not have the same S|SRVALID|SREGION, then it's definitely not the same region. */
if (((response_lower ^ response_upper) & (TT_RESP_S_Msk | TT_RESP_SRVALID_Msk | TT_RESP_SREGION_Msk))) {
/* Upper memory region has different SAU region than lower memory region! */
return 0;
}
/* Both memory locations have the same non-secure SAU region and therefore same properties.
* No Secure SAU region can be inbetween due to SAU region overlap rules. */
response_lower &= response_upper;
}

return response_lower & (TT_RESP_NSRW_Msk | TT_RESP_NSR_Msk | TT_RESP_RW_Msk | TT_RESP_R_Msk |
TT_RESP_S_Msk | TT_RESP_SRVALID_Msk | TT_RESP_SREGION_Msk);
}

extern int vmpu_fault_recovery_mpu(uint32_t pc, uint32_t sp, uint32_t fault_addr, uint32_t fault_status);

uint32_t vmpu_unpriv_access(uint32_t addr, uint32_t size, uint32_t data)
{
unsigned int tries = 0;
while(1) {
if ((vmpu_unpriv_test_range(addr, UVISOR_UNPRIV_ACCESS_SIZE(size)) & (TT_RESP_NSRW_Msk | TT_RESP_SRVALID_Msk)) == (TT_RESP_NSRW_Msk | TT_RESP_SRVALID_Msk)) {
switch(size) {
case UVISOR_UNPRIV_ACCESS_READ(1):
return *((uint8_t *) addr);
case UVISOR_UNPRIV_ACCESS_READ(2):
return *((uint16_t *) addr);
case UVISOR_UNPRIV_ACCESS_READ(4):
return *((uint32_t *) addr);
case UVISOR_UNPRIV_ACCESS_WRITE(1):
*((uint8_t *) addr) = (uint8_t) data;
return 0;
case UVISOR_UNPRIV_ACCESS_WRITE(2):
*((uint16_t *) addr) = (uint16_t) data;
return 0;
case UVISOR_UNPRIV_ACCESS_WRITE(4):
*((uint32_t *) addr) = data;
return 0;
default:
break;
}
break;
}
if (++tries > 1 || !vmpu_fault_recovery_mpu(0, 0, addr, 0)) {
break;
// This operation could be slow since we are scanning all the regions defined for the box
// an implementation using the TTA command is faster but causes misses since it works with the MPU
if (vmpu_buffer_access_is_ok(g_active_box, (const void *) addr, UVISOR_UNPRIV_ACCESS_SIZE(size))){
switch(size) {
case UVISOR_UNPRIV_ACCESS_READ(1):
return *((uint8_t *) addr);
case UVISOR_UNPRIV_ACCESS_READ(2):
return *((uint16_t *) addr);
case UVISOR_UNPRIV_ACCESS_READ(4):
return *((uint32_t *) addr);
case UVISOR_UNPRIV_ACCESS_WRITE(1):
*((uint8_t *) addr) = (uint8_t) data;
return 0;
case UVISOR_UNPRIV_ACCESS_WRITE(2):
*((uint16_t *) addr) = (uint16_t) data;
return 0;
case UVISOR_UNPRIV_ACCESS_WRITE(4):
*((uint32_t *) addr) = data;
return 0;
default:
break;
}
}
HALT_ERROR(PERMISSION_DENIED, "Access to restricted resource denied");
Expand Down