mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-28 23:46:55 +00:00
target/arm: Implement NSACR gating of floating point
The NSACR register allows secure code to configure the FPU to be inaccessible to non-secure code. If the NSACR.CP10 bit is set then: * NS accesses to the FPU trap as UNDEF (ie to NS EL1 or EL2) * CPACR.{CP10,CP11} behave as if RAZ/WI * HCPTR.{TCP11,TCP10} behave as if RAO/WI Note that we do not implement the NSACR.NSASEDIS bit which gates only access to Advanced SIMD, in the same way that we don't implement the equivalent CPACR.ASEDIS and HCPTR.TASE. Backports commit fc1120a7f5f2d4b601003205c598077d3eb11ad2 from qemu
This commit is contained in:
parent
7c32498b7f
commit
230f8a091a
|
@ -784,9 +784,36 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
}
|
||||
value &= mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* For A-profile AArch32 EL3 (but not M-profile secure mode), if NSACR.CP10
|
||||
* is 0 then CPACR.{CP11,CP10} ignore writes and read as 0b00.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) &&
|
||||
!arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) {
|
||||
value &= ~(0xf << 20);
|
||||
value |= env->cp15.cpacr_el1 & (0xf << 20);
|
||||
}
|
||||
|
||||
env->cp15.cpacr_el1 = value;
|
||||
}
|
||||
|
||||
static uint64_t cpacr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/*
|
||||
* For A-profile AArch32 EL3 (but not M-profile secure mode), if NSACR.CP10
|
||||
* is 0 then CPACR.{CP11,CP10} ignore writes and read as 0b00.
|
||||
*/
|
||||
uint64_t value = env->cp15.cpacr_el1;
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) &&
|
||||
!arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) {
|
||||
value &= ~(0xf << 20);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static void cpacr_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/* Call cpacr_write() so that we reset with the correct RAO bits set
|
||||
|
@ -852,7 +879,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
|
|||
{ .name = "CPACR", .state = ARM_CP_STATE_BOTH, .opc0 = 3,
|
||||
.crn = 1, .crm = 0, .opc1 = 0, .opc2 = 2, .accessfn = cpacr_access,
|
||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.cpacr_el1),
|
||||
.resetfn = cpacr_reset, .writefn = cpacr_write },
|
||||
.resetfn = cpacr_reset, .writefn = cpacr_write, .readfn = cpacr_read },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
|
@ -4494,6 +4521,36 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void cptr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/*
|
||||
* For A-profile AArch32 EL3, if NSACR.CP10
|
||||
* is 0 then HCPTR.{TCP11,TCP10} ignore writes and read as 1.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) &&
|
||||
!arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) {
|
||||
value &= ~(0x3 << 10);
|
||||
value |= env->cp15.cptr_el[2] & (0x3 << 10);
|
||||
}
|
||||
env->cp15.cptr_el[2] = value;
|
||||
}
|
||||
|
||||
static uint64_t cptr_el2_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
/*
|
||||
* For A-profile AArch32 EL3, if NSACR.CP10
|
||||
* is 0 then HCPTR.{TCP11,TCP10} ignore writes and read as 1.
|
||||
*/
|
||||
uint64_t value = env->cp15.cptr_el[2];
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) &&
|
||||
!arm_is_secure(env) && !extract32(env->cp15.nsacr, 10, 1)) {
|
||||
value |= 0x3 << 10;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo el2_cp_reginfo[] = {
|
||||
{ .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_IO,
|
||||
|
@ -4541,7 +4598,8 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
|
|||
{ .name = "CPTR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2,
|
||||
.access = PL2_RW, .accessfn = cptr_access, .resetvalue = 0,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.cptr_el[2]) },
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.cptr_el[2]),
|
||||
.readfn = cptr_el2_read, .writefn = cptr_el2_write },
|
||||
{ .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0,
|
||||
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[2]),
|
||||
|
@ -13363,6 +13421,19 @@ int fp_exception_el(CPUARMState *env, int cur_el)
|
|||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NSACR allows A-profile AArch32 EL3 and M-profile secure mode
|
||||
* to control non-secure access to the FPU. It doesn't have any
|
||||
* effect if EL3 is AArch64 or if EL3 doesn't exist at all.
|
||||
*/
|
||||
if ((arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3) &&
|
||||
cur_el <= 2 && !arm_is_secure_below_el3(env))) {
|
||||
if (!extract32(env->cp15.nsacr, 10, 1)) {
|
||||
/* FP insns act as UNDEF */
|
||||
return cur_el == 2 ? 2 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* For the CPTR registers we don't need to guard with an ARM_FEATURE
|
||||
* check because zero bits in the registers mean "don't trap".
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue