diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-07-04 17:32:24 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-07-04 17:32:24 +0100 |
commit | 57dfc2c4d51e770ed3f617e5d1456d1e2bacf3f0 (patch) | |
tree | eb9d22fab4d2b8948668cc95c9e836633760e5b0 /hw | |
parent | c3e1d838cfa5aac1a6210c8ddf182d0ef7d95dd8 (diff) | |
parent | 89a11ff756410aecb87d2c774df6e45dbf4105c1 (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190704-1' into staging
target-arm queue:
* more code-movement to separate TCG-only functions into their own files
* Correct VMOV_imm_dp handling of short vectors
* Execute Thumb instructions when their condbits are 0xf
* armv7m_systick: Forbid non-privileged accesses
* Use _ra versions of cpu_stl_data() in v7M helpers
* v8M: Check state of exception being returned from
* v8M: Forcibly clear negative-priority exceptions on deactivate
# gpg: Signature made Thu 04 Jul 2019 17:31:22 BST
# gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg: issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20190704-1:
target/arm: Correct VMOV_imm_dp handling of short vectors
target/arm: Execute Thumb instructions when their condbits are 0xf
hw/timer/armv7m_systick: Forbid non-privileged accesses
target/arm: Use _ra versions of cpu_stl_data() in v7M helpers
target/arm: v8M: Check state of exception being returned from
arm v8M: Forcibly clear negative-priority exceptions on deactivate
target/arm/helper: Move M profile routines to m_helper.c
target/arm: Restrict semi-hosting to TCG
target/arm: Move debug routines to debug_helper.c
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/intc/armv7m_nvic.c | 54 | ||||
-rw-r--r-- | hw/timer/armv7m_systick.c | 26 |
2 files changed, 68 insertions, 12 deletions
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index b8ede30b3c..9f8f0d3ff5 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -812,15 +812,45 @@ void armv7m_nvic_get_pending_irq_info(void *opaque, int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) { NVICState *s = (NVICState *)opaque; - VecInfo *vec; + VecInfo *vec = NULL; int ret; assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq); - if (secure && exc_is_banked(irq)) { - vec = &s->sec_vectors[irq]; - } else { - vec = &s->vectors[irq]; + /* + * For negative priorities, v8M will forcibly deactivate the appropriate + * NMI or HardFault regardless of what interrupt we're being asked to + * deactivate (compare the DeActivate() pseudocode). This is a guard + * against software returning from NMI or HardFault with a corrupted + * IPSR and leaving the CPU in a negative-priority state. + * v7M does not do this, but simply deactivates the requested interrupt. + */ + if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) { + switch (armv7m_nvic_raw_execution_priority(s)) { + case -1: + if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) { + vec = &s->vectors[ARMV7M_EXCP_HARD]; + } else { + vec = &s->sec_vectors[ARMV7M_EXCP_HARD]; + } + break; + case -2: + vec = &s->vectors[ARMV7M_EXCP_NMI]; + break; + case -3: + vec = &s->sec_vectors[ARMV7M_EXCP_HARD]; + break; + default: + break; + } + } + + if (!vec) { + if (secure && exc_is_banked(irq)) { + vec = &s->sec_vectors[irq]; + } else { + vec = &s->vectors[irq]; + } } trace_nvic_complete_irq(irq, secure); @@ -830,7 +860,19 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) return -1; } - ret = nvic_rettobase(s); + /* + * If this is a configurable exception and it is currently + * targeting the opposite security state from the one we're trying + * to complete it for, this counts as an illegal exception return. + * We still need to deactivate whatever vector the logic above has + * selected, though, as it might not be the same as the one for the + * requested exception number. + */ + if (!exc_is_banked(irq) && exc_targets_secure(s, irq) != secure) { + ret = -1; + } else { + ret = nvic_rettobase(s); + } vec->active = 0; if (vec->level) { diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c index a17317ce2f..94640743b5 100644 --- a/hw/timer/armv7m_systick.c +++ b/hw/timer/armv7m_systick.c @@ -75,11 +75,17 @@ static void systick_timer_tick(void *opaque) } } -static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size) +static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data, + unsigned size, MemTxAttrs attrs) { SysTickState *s = opaque; uint32_t val; + if (attrs.user) { + /* Generate BusFault for unprivileged accesses */ + return MEMTX_ERROR; + } + switch (addr) { case 0x0: /* SysTick Control and Status. */ val = s->control; @@ -121,14 +127,21 @@ static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size) } trace_systick_read(addr, val, size); - return val; + *data = val; + return MEMTX_OK; } -static void systick_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) +static MemTxResult systick_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) { SysTickState *s = opaque; + if (attrs.user) { + /* Generate BusFault for unprivileged accesses */ + return MEMTX_ERROR; + } + trace_systick_write(addr, value, size); switch (addr) { @@ -172,11 +185,12 @@ static void systick_write(void *opaque, hwaddr addr, qemu_log_mask(LOG_GUEST_ERROR, "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr); } + return MEMTX_OK; } static const MemoryRegionOps systick_ops = { - .read = systick_read, - .write = systick_write, + .read_with_attrs = systick_read, + .write_with_attrs = systick_write, .endianness = DEVICE_NATIVE_ENDIAN, .valid.min_access_size = 4, .valid.max_access_size = 4, |