mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20171006' into staging
target-arm: * v8M: more preparatory work * nvic: reset properly rather than leaving the nvic in a weird state * xlnx-zynqmp: Mark the "xlnx, zynqmp" device with user_creatable = false * sd: fix out-of-bounds check for multi block reads * arm: Fix SMC reporting to EL2 when QEMU provides PSCI # gpg: Signature made Fri 06 Oct 2017 16:58:15 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20171006: nvic: Add missing code for writing SHCSR.HARDFAULTPENDED bit target/arm: Factor out "get mmuidx for specified security state" target/arm: Fix calculation of secure mm_idx values target/arm: Implement security attribute lookups for memory accesses nvic: Implement Security Attribution Unit registers target/arm: Add v8M support to exception entry code target/arm: Add support for restoring v8M additional state context target/arm: Update excret sanity checks for v8M target/arm: Add new-in-v8M SFSR and SFAR target/arm: Don't warn about exception return with PC low bit set for v8M target/arm: Warn about restoring to unaligned stack target/arm: Check for xPSR mismatch usage faults earlier for v8M target/arm: Restore SPSEL to correct CONTROL register on exception return target/arm: Restore security state on exception return target/arm: Prepare for CONTROL.SPSEL being nonzero in Handler mode target/arm: Don't switch to target stack early in v7M exception return nvic: Clear the vector arrays and prigroup on reset hw/arm/xlnx-zynqmp: Mark the "xlnx, zynqmp" device with user_creatable = false hw/sd: fix out-of-bounds check for multi block reads arm: Fix SMC reporting to EL2 when QEMU provides PSCI Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -440,6 +440,8 @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
dc->props = xlnx_zynqmp_props;
|
||||
dc->realize = xlnx_zynqmp_realize;
|
||||
/* Reason: Uses serial_hds in realize function, thus can't be used twice */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo xlnx_zynqmp_type_info = {
|
||||
|
||||
+157
-1
@@ -616,7 +616,7 @@ bool armv7m_nvic_acknowledge_irq(void *opaque)
|
||||
vec->active = 1;
|
||||
vec->pending = 0;
|
||||
|
||||
env->v7m.exception = s->vectpending;
|
||||
write_v7m_exception(env, s->vectpending);
|
||||
|
||||
nvic_irq_update(s);
|
||||
|
||||
@@ -1017,6 +1017,76 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
||||
goto bad_offset;
|
||||
}
|
||||
return cpu->env.pmsav8.mair1[attrs.secure];
|
||||
case 0xdd0: /* SAU_CTRL */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.sau.ctrl;
|
||||
case 0xdd4: /* SAU_TYPE */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->sau_sregion;
|
||||
case 0xdd8: /* SAU_RNR */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.sau.rnr;
|
||||
case 0xddc: /* SAU_RBAR */
|
||||
{
|
||||
int region = cpu->env.sau.rnr;
|
||||
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
if (region >= cpu->sau_sregion) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.sau.rbar[region];
|
||||
}
|
||||
case 0xde0: /* SAU_RLAR */
|
||||
{
|
||||
int region = cpu->env.sau.rnr;
|
||||
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
if (region >= cpu->sau_sregion) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.sau.rlar[region];
|
||||
}
|
||||
case 0xde4: /* SFSR */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.v7m.sfsr;
|
||||
case 0xde8: /* SFAR */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return 0;
|
||||
}
|
||||
return cpu->env.v7m.sfar;
|
||||
default:
|
||||
bad_offset:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
|
||||
@@ -1160,6 +1230,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
||||
s->sec_vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
|
||||
s->sec_vectors[ARMV7M_EXCP_USAGE].enabled =
|
||||
(value & (1 << 18)) != 0;
|
||||
s->sec_vectors[ARMV7M_EXCP_HARD].pending = (value & (1 << 21)) != 0;
|
||||
/* SecureFault not banked, but RAZ/WI to NS */
|
||||
s->vectors[ARMV7M_EXCP_SECURE].active = (value & (1 << 4)) != 0;
|
||||
s->vectors[ARMV7M_EXCP_SECURE].enabled = (value & (1 << 19)) != 0;
|
||||
@@ -1368,6 +1439,86 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value,
|
||||
* only affect cacheability, and we don't implement caching.
|
||||
*/
|
||||
break;
|
||||
case 0xdd0: /* SAU_CTRL */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return;
|
||||
}
|
||||
cpu->env.sau.ctrl = value & 3;
|
||||
case 0xdd4: /* SAU_TYPE */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
break;
|
||||
case 0xdd8: /* SAU_RNR */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return;
|
||||
}
|
||||
if (value >= cpu->sau_sregion) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "SAU region out of range %"
|
||||
PRIu32 "/%" PRIu32 "\n",
|
||||
value, cpu->sau_sregion);
|
||||
} else {
|
||||
cpu->env.sau.rnr = value;
|
||||
}
|
||||
break;
|
||||
case 0xddc: /* SAU_RBAR */
|
||||
{
|
||||
int region = cpu->env.sau.rnr;
|
||||
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return;
|
||||
}
|
||||
if (region >= cpu->sau_sregion) {
|
||||
return;
|
||||
}
|
||||
cpu->env.sau.rbar[region] = value & ~0x1f;
|
||||
tlb_flush(CPU(cpu));
|
||||
break;
|
||||
}
|
||||
case 0xde0: /* SAU_RLAR */
|
||||
{
|
||||
int region = cpu->env.sau.rnr;
|
||||
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return;
|
||||
}
|
||||
if (region >= cpu->sau_sregion) {
|
||||
return;
|
||||
}
|
||||
cpu->env.sau.rlar[region] = value & ~0x1c;
|
||||
tlb_flush(CPU(cpu));
|
||||
break;
|
||||
}
|
||||
case 0xde4: /* SFSR */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return;
|
||||
}
|
||||
cpu->env.v7m.sfsr &= ~value; /* W1C */
|
||||
break;
|
||||
case 0xde8: /* SFAR */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
if (!attrs.secure) {
|
||||
return;
|
||||
}
|
||||
cpu->env.v7m.sfsr = value;
|
||||
break;
|
||||
case 0xf00: /* Software Triggered Interrupt Register */
|
||||
{
|
||||
int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ;
|
||||
@@ -1782,6 +1933,11 @@ static void armv7m_nvic_reset(DeviceState *dev)
|
||||
int resetprio;
|
||||
NVICState *s = NVIC(dev);
|
||||
|
||||
memset(s->vectors, 0, sizeof(s->vectors));
|
||||
memset(s->sec_vectors, 0, sizeof(s->sec_vectors));
|
||||
s->prigroup[M_REG_NS] = 0;
|
||||
s->prigroup[M_REG_S] = 0;
|
||||
|
||||
s->vectors[ARMV7M_EXCP_NMI].enabled = 1;
|
||||
/* MEM, BUS, and USAGE are enabled through
|
||||
* the System Handler Control register
|
||||
|
||||
+6
-6
@@ -1797,8 +1797,13 @@ uint8_t sd_read_data(SDState *sd)
|
||||
break;
|
||||
|
||||
case 18: /* CMD18: READ_MULTIPLE_BLOCK */
|
||||
if (sd->data_offset == 0)
|
||||
if (sd->data_offset == 0) {
|
||||
if (sd->data_start + io_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
return 0x00;
|
||||
}
|
||||
BLK_READ_BLOCK(sd->data_start, io_len);
|
||||
}
|
||||
ret = sd->data[sd->data_offset ++];
|
||||
|
||||
if (sd->data_offset >= io_len) {
|
||||
@@ -1812,11 +1817,6 @@ uint8_t sd_read_data(SDState *sd)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd->data_start + io_len > sd->size) {
|
||||
sd->card_status |= ADDRESS_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -285,6 +285,18 @@ static void arm_cpu_reset(CPUState *s)
|
||||
env->pmsav8.mair1[M_REG_S] = 0;
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
if (cpu->sau_sregion > 0) {
|
||||
memset(env->sau.rbar, 0, sizeof(*env->sau.rbar) * cpu->sau_sregion);
|
||||
memset(env->sau.rlar, 0, sizeof(*env->sau.rlar) * cpu->sau_sregion);
|
||||
}
|
||||
env->sau.rnr = 0;
|
||||
/* SAU_CTRL reset value is IMPDEF; we choose 0, which is what
|
||||
* the Cortex-M33 does.
|
||||
*/
|
||||
env->sau.ctrl = 0;
|
||||
}
|
||||
|
||||
set_flush_to_zero(1, &env->vfp.standard_fp_status);
|
||||
set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
|
||||
set_default_nan_mode(1, &env->vfp.standard_fp_status);
|
||||
@@ -873,6 +885,20 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
||||
uint32_t nr = cpu->sau_sregion;
|
||||
|
||||
if (nr > 0xff) {
|
||||
error_setg(errp, "v8M SAU #regions invalid %" PRIu32, nr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr) {
|
||||
env->sau.rbar = g_new0(uint32_t, nr);
|
||||
env->sau.rlar = g_new0(uint32_t, nr);
|
||||
}
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
set_feature(env, ARM_FEATURE_VBAR);
|
||||
}
|
||||
@@ -1141,6 +1167,7 @@ static void cortex_m4_initfn(Object *obj)
|
||||
cpu->midr = 0x410fc240; /* r0p0 */
|
||||
cpu->pmsav7_dregion = 8;
|
||||
}
|
||||
|
||||
static void arm_v7m_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
|
||||
+50
-10
@@ -443,8 +443,10 @@ typedef struct CPUARMState {
|
||||
uint32_t cfsr[M_REG_NUM_BANKS]; /* Configurable Fault Status */
|
||||
uint32_t hfsr; /* HardFault Status */
|
||||
uint32_t dfsr; /* Debug Fault Status Register */
|
||||
uint32_t sfsr; /* Secure Fault Status Register */
|
||||
uint32_t mmfar[M_REG_NUM_BANKS]; /* MemManage Fault Address */
|
||||
uint32_t bfar; /* BusFault Address */
|
||||
uint32_t sfar; /* Secure Fault Address Register */
|
||||
unsigned mpu_ctrl[M_REG_NUM_BANKS]; /* MPU_CTRL */
|
||||
int exception;
|
||||
uint32_t primask[M_REG_NUM_BANKS];
|
||||
@@ -566,6 +568,14 @@ typedef struct CPUARMState {
|
||||
uint32_t mair1[M_REG_NUM_BANKS];
|
||||
} pmsav8;
|
||||
|
||||
/* v8M SAU */
|
||||
struct {
|
||||
uint32_t *rbar;
|
||||
uint32_t *rlar;
|
||||
uint32_t rnr;
|
||||
uint32_t ctrl;
|
||||
} sau;
|
||||
|
||||
void *nvic;
|
||||
const struct arm_boot_info *boot_info;
|
||||
/* Store GICv3CPUState to access from this struct */
|
||||
@@ -661,6 +671,8 @@ struct ARMCPU {
|
||||
bool has_mpu;
|
||||
/* PMSAv7 MPU number of supported regions */
|
||||
uint32_t pmsav7_dregion;
|
||||
/* v8M SAU number of supported regions */
|
||||
uint32_t sau_sregion;
|
||||
|
||||
/* PSCI conduit used to invoke PSCI methods
|
||||
* 0 - disabled, 1 - smc, 2 - hvc
|
||||
@@ -991,6 +1003,11 @@ void pmccntr_sync(CPUARMState *env);
|
||||
#define PSTATE_MODE_EL1t 4
|
||||
#define PSTATE_MODE_EL0t 0
|
||||
|
||||
/* Write a new value to v7m.exception, thus transitioning into or out
|
||||
* of Handler mode; this may result in a change of active stack pointer.
|
||||
*/
|
||||
void write_v7m_exception(CPUARMState *env, uint32_t new_exc);
|
||||
|
||||
/* Map EL and handler into a PSTATE_MODE. */
|
||||
static inline unsigned int aarch64_pstate_mode(unsigned int el, bool handler)
|
||||
{
|
||||
@@ -1071,7 +1088,8 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||
env->condexec_bits |= (val >> 8) & 0xfc;
|
||||
}
|
||||
if (mask & XPSR_EXCP) {
|
||||
env->v7m.exception = val & XPSR_EXCP;
|
||||
/* Note that this only happens on exception exit */
|
||||
write_v7m_exception(env, val & XPSR_EXCP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1254,6 +1272,16 @@ FIELD(V7M_DFSR, DWTTRAP, 2, 1)
|
||||
FIELD(V7M_DFSR, VCATCH, 3, 1)
|
||||
FIELD(V7M_DFSR, EXTERNAL, 4, 1)
|
||||
|
||||
/* V7M SFSR bits */
|
||||
FIELD(V7M_SFSR, INVEP, 0, 1)
|
||||
FIELD(V7M_SFSR, INVIS, 1, 1)
|
||||
FIELD(V7M_SFSR, INVER, 2, 1)
|
||||
FIELD(V7M_SFSR, AUVIOL, 3, 1)
|
||||
FIELD(V7M_SFSR, INVTRAN, 4, 1)
|
||||
FIELD(V7M_SFSR, LSPERR, 5, 1)
|
||||
FIELD(V7M_SFSR, SFARVALID, 6, 1)
|
||||
FIELD(V7M_SFSR, LSERR, 7, 1)
|
||||
|
||||
/* v7M MPU_CTRL bits */
|
||||
FIELD(V7M_MPU_CTRL, ENABLE, 0, 1)
|
||||
FIELD(V7M_MPU_CTRL, HFNMIENA, 1, 1)
|
||||
@@ -2301,21 +2329,33 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the MMU index for a v7M CPU in the specified security state */
|
||||
static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env,
|
||||
bool secstate)
|
||||
{
|
||||
int el = arm_current_el(env);
|
||||
ARMMMUIdx mmu_idx;
|
||||
|
||||
if (el == 0) {
|
||||
mmu_idx = secstate ? ARMMMUIdx_MSUser : ARMMMUIdx_MUser;
|
||||
} else {
|
||||
mmu_idx = secstate ? ARMMMUIdx_MSPriv : ARMMMUIdx_MPriv;
|
||||
}
|
||||
|
||||
if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) {
|
||||
mmu_idx = secstate ? ARMMMUIdx_MSNegPri : ARMMMUIdx_MNegPri;
|
||||
}
|
||||
|
||||
return mmu_idx;
|
||||
}
|
||||
|
||||
/* Determine the current mmu_idx to use for normal loads/stores */
|
||||
static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
|
||||
{
|
||||
int el = arm_current_el(env);
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
ARMMMUIdx mmu_idx = el == 0 ? ARMMMUIdx_MUser : ARMMMUIdx_MPriv;
|
||||
|
||||
if (armv7m_nvic_neg_prio_requested(env->nvic, env->v7m.secure)) {
|
||||
mmu_idx = ARMMMUIdx_MNegPri;
|
||||
}
|
||||
|
||||
if (env->v7m.secure) {
|
||||
mmu_idx += ARMMMUIdx_MSUser;
|
||||
}
|
||||
ARMMMUIdx mmu_idx = arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
|
||||
|
||||
return arm_to_core_mmu_idx(mmu_idx);
|
||||
}
|
||||
|
||||
+609
-84
File diff suppressed because it is too large
Load Diff
@@ -71,6 +71,21 @@ FIELD(V7M_EXCRET, DCRS, 5, 1)
|
||||
FIELD(V7M_EXCRET, S, 6, 1)
|
||||
FIELD(V7M_EXCRET, RES1, 7, 25) /* including the must-be-1 prefix */
|
||||
|
||||
/* We use a few fake FSR values for internal purposes in M profile.
|
||||
* M profile cores don't have A/R format FSRs, but currently our
|
||||
* get_phys_addr() code assumes A/R profile and reports failures via
|
||||
* an A/R format FSR value. We then translate that into the proper
|
||||
* M profile exception and FSR status bit in arm_v7m_cpu_do_interrupt().
|
||||
* Mostly the FSR values we use for this are those defined for v7PMSA,
|
||||
* since we share some of that codepath. A few kinds of fault are
|
||||
* only for M profile and have no A/R equivalent, though, so we have
|
||||
* to pick a value from the reserved range (which we never otherwise
|
||||
* generate) to use for these.
|
||||
* These values will never be visible to the guest.
|
||||
*/
|
||||
#define M_FAKE_FSR_NSC_EXEC 0xf /* NS executing in S&NSC memory */
|
||||
#define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */
|
||||
|
||||
/*
|
||||
* For AArch64, map a given EL to an index in the banked_spsr array.
|
||||
* Note that this mapping and the AArch32 mapping defined in bank_number()
|
||||
|
||||
@@ -242,6 +242,13 @@ static bool s_rnr_vmstate_validate(void *opaque, int version_id)
|
||||
return cpu->env.pmsav7.rnr[M_REG_S] < cpu->pmsav7_dregion;
|
||||
}
|
||||
|
||||
static bool sau_rnr_vmstate_validate(void *opaque, int version_id)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
return cpu->env.sau.rnr < cpu->sau_sregion;
|
||||
}
|
||||
|
||||
static bool m_security_needed(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
@@ -276,6 +283,15 @@ static const VMStateDescription vmstate_m_security = {
|
||||
VMSTATE_UINT32(env.v7m.ccr[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.mmfar[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.cfsr[M_REG_S], ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.sfsr, ARMCPU),
|
||||
VMSTATE_UINT32(env.v7m.sfar, ARMCPU),
|
||||
VMSTATE_VARRAY_UINT32(env.sau.rbar, ARMCPU, sau_sregion, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_VARRAY_UINT32(env.sau.rlar, ARMCPU, sau_sregion, 0,
|
||||
vmstate_info_uint32, uint32_t),
|
||||
VMSTATE_UINT32(env.sau.rnr, ARMCPU),
|
||||
VMSTATE_VALIDATE("SAU_RNR is valid", sau_rnr_vmstate_validate),
|
||||
VMSTATE_UINT32(env.sau.ctrl, ARMCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
+17
-10
@@ -953,22 +953,29 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
|
||||
*/
|
||||
bool undef = arm_feature(env, ARM_FEATURE_AARCH64) ? smd : smd && !secure;
|
||||
|
||||
if (arm_is_psci_call(cpu, EXCP_SMC)) {
|
||||
/* If PSCI is enabled and this looks like a valid PSCI call then
|
||||
* that overrides the architecturally mandated SMC behaviour.
|
||||
if (!arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
|
||||
/* If we have no EL3 then SMC always UNDEFs and can't be
|
||||
* trapped to EL2. PSCI-via-SMC is a sort of ersatz EL3
|
||||
* firmware within QEMU, and we want an EL2 guest to be able
|
||||
* to forbid its EL1 from making PSCI calls into QEMU's
|
||||
* "firmware" via HCR.TSC, so for these purposes treat
|
||||
* PSCI-via-SMC as implying an EL3.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arm_feature(env, ARM_FEATURE_EL3)) {
|
||||
/* If we have no EL3 then SMC always UNDEFs */
|
||||
undef = true;
|
||||
} else if (!secure && cur_el == 1 && (env->cp15.hcr_el2 & HCR_TSC)) {
|
||||
/* In NS EL1, HCR controlled routing to EL2 has priority over SMD. */
|
||||
/* In NS EL1, HCR controlled routing to EL2 has priority over SMD.
|
||||
* We also want an EL2 guest to be able to forbid its EL1 from
|
||||
* making PSCI calls into QEMU's "firmware" via HCR.TSC.
|
||||
*/
|
||||
raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
|
||||
}
|
||||
|
||||
if (undef) {
|
||||
/* If PSCI is enabled and this looks like a valid PSCI call then
|
||||
* suppress the UNDEF -- we'll catch the SMC exception and
|
||||
* implement the PSCI call behaviour there.
|
||||
*/
|
||||
if (undef && !arm_is_psci_call(cpu, EXCP_SMC)) {
|
||||
raise_exception(env, EXCP_UDEF, syn_uncategorized(),
|
||||
exception_target_el(env));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user