From patchwork Fri Jan 20 18:44:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 92096 Delivered-To: patches@linaro.org Received: by 10.182.3.34 with SMTP id 2csp196955obz; Fri, 20 Jan 2017 10:44:45 -0800 (PST) X-Received: by 10.28.10.68 with SMTP id 65mr4715078wmk.63.1484937885411; Fri, 20 Jan 2017 10:44:45 -0800 (PST) Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id r186si4431789wmd.5.2017.01.20.10.44.45 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 10:44:45 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1cUeB2-00046h-GY; Fri, 20 Jan 2017 18:44:44 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Liviu Ionescu , Michael Davidsaver Subject: [PATCH 1/6] armv7m: MRS/MSR: handle unprivileged access Date: Fri, 20 Jan 2017 18:44:38 +0000 Message-Id: <1484937883-1068-2-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> References: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> From: Michael Davidsaver The MRS and MSR instruction handling has a number of flaws: * unprivileged accesses should only be able to read CONTROL and the xPSR subfields, and only write APSR (others RAZ/WI) * privileged access should not be able to write xPSR subfields other than APSR * accesses to unimplemented registers should log as guest errors, not abort QEMU Signed-off-by: Michael Davidsaver Reviewed-by: Peter Maydell [PMM: rewrote commit message] Signed-off-by: Peter Maydell --- target/arm/helper.c | 79 +++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 42 deletions(-) -- 2.7.4 diff --git a/target/arm/helper.c b/target/arm/helper.c index 7111c8c..ad23de3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8243,23 +8243,32 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) { - ARMCPU *cpu = arm_env_get_cpu(env); + uint32_t mask; + unsigned el = arm_current_el(env); + + /* First handle registers which unprivileged can read */ + + switch (reg) { + case 0 ... 7: /* xPSR sub-fields */ + mask = 0; + if ((reg & 1) && el) { + mask |= 0x000001ff; /* IPSR (unpriv. reads as zero) */ + } + if (!(reg & 4)) { + mask |= 0xf8000000; /* APSR */ + } + /* EPSR reads as zero */ + return xpsr_read(env) & mask; + break; + case 20: /* CONTROL */ + return env->v7m.control; + } + + if (el == 0) { + return 0; /* unprivileged reads others as zero */ + } switch (reg) { - case 0: /* APSR */ - return xpsr_read(env) & 0xf8000000; - case 1: /* IAPSR */ - return xpsr_read(env) & 0xf80001ff; - case 2: /* EAPSR */ - return xpsr_read(env) & 0xff00fc00; - case 3: /* xPSR */ - return xpsr_read(env) & 0xff00fdff; - case 5: /* IPSR */ - return xpsr_read(env) & 0x000001ff; - case 6: /* EPSR */ - return xpsr_read(env) & 0x0700fc00; - case 7: /* IEPSR */ - return xpsr_read(env) & 0x0700edff; case 8: /* MSP */ return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13]; case 9: /* PSP */ @@ -8271,40 +8280,26 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) return env->v7m.basepri; case 19: /* FAULTMASK */ return (env->daif & PSTATE_F) != 0; - case 20: /* CONTROL */ - return env->v7m.control; default: - /* ??? For debugging only. */ - cpu_abort(CPU(cpu), "Unimplemented system register read (%d)\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special" + " register %d\n", reg); return 0; } } void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) { - ARMCPU *cpu = arm_env_get_cpu(env); + if (arm_current_el(env) == 0 && reg > 7) { + /* only xPSR sub-fields may be written by unprivileged */ + return; + } switch (reg) { - case 0: /* APSR */ - xpsr_write(env, val, 0xf8000000); - break; - case 1: /* IAPSR */ - xpsr_write(env, val, 0xf8000000); - break; - case 2: /* EAPSR */ - xpsr_write(env, val, 0xfe00fc00); - break; - case 3: /* xPSR */ - xpsr_write(env, val, 0xfe00fc00); - break; - case 5: /* IPSR */ - /* IPSR bits are readonly. */ - break; - case 6: /* EPSR */ - xpsr_write(env, val, 0x0600fc00); - break; - case 7: /* IEPSR */ - xpsr_write(env, val, 0x0600fc00); + case 0 ... 7: /* xPSR sub-fields */ + /* only APSR is actually writable */ + if (reg & 4) { + xpsr_write(env, val, 0xf8000000); /* APSR */ + } break; case 8: /* MSP */ if (env->v7m.current_sp) @@ -8345,8 +8340,8 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) switch_v7m_sp(env, (val & 2) != 0); break; default: - /* ??? For debugging only. */ - cpu_abort(CPU(cpu), "Unimplemented system register write (%d)\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special" + " register %d\n", reg); return; } } From patchwork Fri Jan 20 18:44:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 92099 Delivered-To: patches@linaro.org Received: by 10.182.3.34 with SMTP id 2csp196966obz; Fri, 20 Jan 2017 10:44:47 -0800 (PST) X-Received: by 10.84.233.133 with SMTP id l5mr23710147plk.129.1484937887615; Fri, 20 Jan 2017 10:44:47 -0800 (PST) Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id l24si7544429pgn.200.2017.01.20.10.44.46 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 10:44:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1cUeB2-00046s-VS; Fri, 20 Jan 2017 18:44:44 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Liviu Ionescu , Michael Davidsaver Subject: [PATCH 2/6] armv7m: Replace armv7m.hack with unassigned_access handler Date: Fri, 20 Jan 2017 18:44:39 +0000 Message-Id: <1484937883-1068-3-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> References: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> From: Michael Davidsaver For v7m we need to catch attempts to execute from special addresses at 0xfffffff0 and above. Previously we did this with the aid of a hacky special purpose lump of memory in the address space and a check in translate.c for whether we were translating code at those addresses. We can implement this more cleanly using a CPU unassigned access handler which throws the exception if the unassigned access is for one of the special addresses. Signed-off-by: Michael Davidsaver [PMM: * drop the deletion of the "don't interrupt if PC is magic" code in arm_v7m_cpu_exec_interrupt() -- this is still required * don't generate an exception for unassigned accesses which aren't to the magic address -- although doing this is in theory correct in practice it will break currently working guests which rely on the RAZ/WI behaviour when they touch devices which we haven't modelled. * trigger EXCP_EXCEPTION_EXIT on is_exec, not !is_write ] Signed-off-by: Peter Maydell --- hw/arm/armv7m.c | 8 -------- target/arm/cpu.c | 28 ++++++++++++++++++++++++++++ target/arm/translate.c | 12 ++++++------ 3 files changed, 34 insertions(+), 14 deletions(-) -- 2.7.4 Reviewed-by: Alex Bennée diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 49d3078..0c9ca7b 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -180,7 +180,6 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, uint64_t entry; uint64_t lowaddr; int big_endian; - MemoryRegion *hack = g_new(MemoryRegion, 1); if (cpu_model == NULL) { cpu_model = "cortex-m3"; @@ -225,13 +224,6 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, } } - /* Hack to map an additional page of ram at the top of the address - space. This stops qemu complaining about executing code outside RAM - when returning from an exception. */ - memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000, &error_fatal); - vmstate_register_ram_global(hack); - memory_region_add_subregion(system_memory, 0xfffff000, hack); - qemu_register_reset(armv7m_reset, cpu); return nvic; } diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 3f2cdb6..47759c9 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -292,6 +292,33 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) +static void arm_v7m_unassigned_access(CPUState *cpu, hwaddr addr, + bool is_write, bool is_exec, int opaque, + unsigned size) +{ + ARMCPU *arm = ARM_CPU(cpu); + CPUARMState *env = &arm->env; + + /* ARMv7-M interrupt return works by loading a magic value into the PC. + * On real hardware the load causes the return to occur. The qemu + * implementation performs the jump normally, then does the exception + * return by throwing a special exception when when the CPU tries to + * execute code at the magic address. + */ + if (env->v7m.exception != 0 && addr >= 0xfffffff0 && is_exec) { + cpu->exception_index = EXCP_EXCEPTION_EXIT; + cpu_loop_exit(cpu); + } + + /* In real hardware an attempt to access parts of the address space + * with nothing there will usually cause an external abort. + * However our QEMU board models are often missing device models where + * the guest can boot anyway with the default read-as-zero/writes-ignored + * behaviour that you get without a QEMU unassigned_access hook. + * So just return here to retain that default behaviour. + */ +} + static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { CPUClass *cc = CPU_GET_CLASS(cs); @@ -1016,6 +1043,7 @@ static void arm_v7m_class_init(ObjectClass *oc, void *data) cc->do_interrupt = arm_v7m_cpu_do_interrupt; #endif + cc->do_unassigned_access = arm_v7m_unassigned_access; cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt; } diff --git a/target/arm/translate.c b/target/arm/translate.c index c9186b6..a7c2abe 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -11719,12 +11719,12 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) break; } #else - if (dc->pc >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) { - /* We always get here via a jump, so know we are not in a - conditional execution block. */ - gen_exception_internal(EXCP_EXCEPTION_EXIT); - dc->is_jmp = DISAS_EXC; - break; + if (arm_dc_feature(dc, ARM_FEATURE_M)) { + /* Branches to the magic exception-return addresses should + * already have been caught via the arm_v7m_unassigned_access hook, + * and never get here. + */ + assert(dc->pc < 0xfffffff0); } #endif From patchwork Fri Jan 20 18:44:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 92102 Delivered-To: patches@linaro.org Received: by 10.182.3.34 with SMTP id 2csp196976obz; Fri, 20 Jan 2017 10:44:49 -0800 (PST) X-Received: by 10.99.174.4 with SMTP id q4mr17991233pgf.178.1484937889567; Fri, 20 Jan 2017 10:44:49 -0800 (PST) Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id f17si7552194pge.120.2017.01.20.10.44.48 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 10:44:49 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1cUeB3-00047B-EN; Fri, 20 Jan 2017 18:44:45 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Liviu Ionescu , Michael Davidsaver Subject: [PATCH 3/6] armv7m: Explicit error for bad vector table Date: Fri, 20 Jan 2017 18:44:40 +0000 Message-Id: <1484937883-1068-4-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> References: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> From: Michael Davidsaver Give an explicit error and abort when a load from the vector table fails. Architecturally this should HardFault (which will then immediately fail to load the HardFault vector and go into Lockup). Since we don't model Lockup, just report this guest error via cpu_abort(). This is more helpful than the previous behaviour of reading a zero, which is the address of the reset stack pointer and not a sensible location to jump to. Signed-off-by: Michael Davidsaver Reviewed-by: Peter Maydell [PMM: expanded commit message] Signed-off-by: Peter Maydell --- target/arm/helper.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) -- 2.7.4 Reviewed-by: Alex Bennée diff --git a/target/arm/helper.c b/target/arm/helper.c index ad23de3..8edb08c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6014,6 +6014,30 @@ static void arm_log_exception(int idx) } } +static uint32_t arm_v7m_load_vector(ARMCPU *cpu) + +{ + CPUState *cs = CPU(cpu); + CPUARMState *env = &cpu->env; + MemTxResult result; + hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4; + uint32_t addr; + + addr = address_space_ldl(cs->as, vec, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + /* Architecturally this should cause a HardFault setting HSFR.VECTTBL, + * which would then be immediately followed by our failing to load + * the entry vector for that HardFault, which is a Lockup case. + * Since we don't model Lockup, we just report this guest error + * via cpu_abort(). + */ + cpu_abort(cs, "Failed to read from exception vector table " + "entry %08x\n", (unsigned)vec); + } + return addr; +} + void arm_v7m_cpu_do_interrupt(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); @@ -6095,7 +6119,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) /* Clear IT bits */ env->condexec_bits = 0; env->regs[14] = lr; - addr = ldl_phys(cs->as, env->v7m.vecbase + env->v7m.exception * 4); + addr = arm_v7m_load_vector(cpu); env->regs[15] = addr & 0xfffffffe; env->thumb = addr & 1; } From patchwork Fri Jan 20 18:44:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 92097 Delivered-To: patches@linaro.org Received: by 10.182.3.34 with SMTP id 2csp196960obz; Fri, 20 Jan 2017 10:44:46 -0800 (PST) X-Received: by 10.28.158.74 with SMTP id h71mr4882856wme.59.1484937886468; Fri, 20 Jan 2017 10:44:46 -0800 (PST) Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id c6si8924016wrd.136.2017.01.20.10.44.46 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 10:44:46 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1cUeB4-00047R-0X; Fri, 20 Jan 2017 18:44:46 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Liviu Ionescu , Michael Davidsaver Subject: [PATCH 4/6] hw/registerfields.h: Pull FIELD etc macros out of hw/register.h Date: Fri, 20 Jan 2017 18:44:41 +0000 Message-Id: <1484937883-1068-5-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> References: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> hw/register.h provides macros like FIELD which make it easy to define shift, mask and length constants for the fields within a register. Unfortunately register.h also includes a lot of other things, some of which will only compile in the softmmu build. Pull the FIELD macro and friends out into a separate header file, so they can be used in places like target/arm files which also get built in the user-only configs. Signed-off-by: Peter Maydell --- include/hw/register.h | 47 +---------------------------------- include/hw/registerfields.h | 60 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 include/hw/registerfields.h -- 2.7.4 Reviewed-by: Alistair Francis Reviewed-by: Alex Bennée diff --git a/include/hw/register.h b/include/hw/register.h index 8c12233..8bff5fb 100644 --- a/include/hw/register.h +++ b/include/hw/register.h @@ -13,6 +13,7 @@ #include "hw/qdev-core.h" #include "exec/memory.h" +#include "hw/registerfields.h" typedef struct RegisterInfo RegisterInfo; typedef struct RegisterAccessInfo RegisterAccessInfo; @@ -206,50 +207,4 @@ RegisterInfoArray *register_init_block32(DeviceState *owner, void register_finalize_block(RegisterInfoArray *r_array); -/* Define constants for a 32 bit register */ - -/* This macro will define A_FOO, for the byte address of a register - * as well as R_FOO for the uint32_t[] register number (A_FOO / 4). - */ -#define REG32(reg, addr) \ - enum { A_ ## reg = (addr) }; \ - enum { R_ ## reg = (addr) / 4 }; - -/* Define SHIFT, LENGTH and MASK constants for a field within a register */ - -/* This macro will define FOO_BAR_MASK, FOO_BAR_SHIFT and FOO_BAR_LENGTH - * constants for field BAR in register FOO. - */ -#define FIELD(reg, field, shift, length) \ - enum { R_ ## reg ## _ ## field ## _SHIFT = (shift)}; \ - enum { R_ ## reg ## _ ## field ## _LENGTH = (length)}; \ - enum { R_ ## reg ## _ ## field ## _MASK = \ - MAKE_64BIT_MASK(shift, length)}; - -/* Extract a field from a register */ -#define FIELD_EX32(storage, reg, field) \ - extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ - R_ ## reg ## _ ## field ## _LENGTH) - -/* Extract a field from an array of registers */ -#define ARRAY_FIELD_EX32(regs, reg, field) \ - FIELD_EX32((regs)[R_ ## reg], reg, field) - -/* Deposit a register field. - * Assigning values larger then the target field will result in - * compilation warnings. - */ -#define FIELD_DP32(storage, reg, field, val) ({ \ - struct { \ - unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ - } v = { .v = val }; \ - uint32_t d; \ - d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ - R_ ## reg ## _ ## field ## _LENGTH, v.v); \ - d; }) - -/* Deposit a field to array of registers. */ -#define ARRAY_FIELD_DP32(regs, reg, field, val) \ - (regs)[R_ ## reg] = FIELD_DP32((regs)[R_ ## reg], reg, field, val); - #endif diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h new file mode 100644 index 0000000..af101d5 --- /dev/null +++ b/include/hw/registerfields.h @@ -0,0 +1,60 @@ +/* + * Register Definition API: field macros + * + * Copyright (c) 2016 Xilinx Inc. + * Copyright (c) 2013 Peter Crosthwaite + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#ifndef REGISTERFIELDS_H +#define REGISTERFIELDS_H + +/* Define constants for a 32 bit register */ + +/* This macro will define A_FOO, for the byte address of a register + * as well as R_FOO for the uint32_t[] register number (A_FOO / 4). + */ +#define REG32(reg, addr) \ + enum { A_ ## reg = (addr) }; \ + enum { R_ ## reg = (addr) / 4 }; + +/* Define SHIFT, LENGTH and MASK constants for a field within a register */ + +/* This macro will define FOO_BAR_MASK, FOO_BAR_SHIFT and FOO_BAR_LENGTH + * constants for field BAR in register FOO. + */ +#define FIELD(reg, field, shift, length) \ + enum { R_ ## reg ## _ ## field ## _SHIFT = (shift)}; \ + enum { R_ ## reg ## _ ## field ## _LENGTH = (length)}; \ + enum { R_ ## reg ## _ ## field ## _MASK = \ + MAKE_64BIT_MASK(shift, length)}; + +/* Extract a field from a register */ +#define FIELD_EX32(storage, reg, field) \ + extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH) + +/* Extract a field from an array of registers */ +#define ARRAY_FIELD_EX32(regs, reg, field) \ + FIELD_EX32((regs)[R_ ## reg], reg, field) + +/* Deposit a register field. + * Assigning values larger then the target field will result in + * compilation warnings. + */ +#define FIELD_DP32(storage, reg, field, val) ({ \ + struct { \ + unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ + } v = { .v = val }; \ + uint32_t d; \ + d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH, v.v); \ + d; }) + +/* Deposit a field to array of registers. */ +#define ARRAY_FIELD_DP32(regs, reg, field, val) \ + (regs)[R_ ## reg] = FIELD_DP32((regs)[R_ ## reg], reg, field, val); + +#endif From patchwork Fri Jan 20 18:44:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 92098 Delivered-To: patches@linaro.org Received: by 10.182.3.34 with SMTP id 2csp196963obz; Fri, 20 Jan 2017 10:44:47 -0800 (PST) X-Received: by 10.28.27.14 with SMTP id b14mr4372258wmb.82.1484937887029; Fri, 20 Jan 2017 10:44:47 -0800 (PST) Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id v61si8903580wrc.210.2017.01.20.10.44.46 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 10:44:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1cUeB4-00047i-H7; Fri, 20 Jan 2017 18:44:46 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Liviu Ionescu , Michael Davidsaver Subject: [PATCH 5/6] armv7m: Fix reads of CONTROL register bit 1 Date: Fri, 20 Jan 2017 18:44:42 +0000 Message-Id: <1484937883-1068-6-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> References: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> From: Michael Davidsaver The v7m CONTROL register bit 1 is SPSEL, which indicates the stack being used. We were storing this information not in v7m.control but in the separate v7m.other_sp structure field. Unfortunately, the code handling reads of the CONTROL register didn't take account of this, and so if SPSEL was updated by an exception entry or exit then a subsequent guest read of CONTROL would get the wrong value. Using a separate structure field doesn't really gain us anything in efficiency, so drop this unnecessary complexity in favour of simply storing all the bits in v7m.control. This is a migration compatibility break for M profile CPUs only. Signed-off-by: Michael Davidsaver [PMM: rewrote commit message; use deposit32(); use FIELD to define constants for masking and shifting of CONTROL register fields ] Signed-off-by: Peter Maydell --- target/arm/cpu.h | 1 - target/arm/internals.h | 7 +++++++ target/arm/helper.c | 35 +++++++++++++++++++++++------------ target/arm/machine.c | 6 ++---- 4 files changed, 32 insertions(+), 17 deletions(-) -- 2.7.4 Reviewed-by: Alex Bennée diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 151a5d7..521c11b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -405,7 +405,6 @@ typedef struct CPUARMState { uint32_t vecbase; uint32_t basepri; uint32_t control; - int current_sp; int exception; } v7m; diff --git a/target/arm/internals.h b/target/arm/internals.h index 3cae5ff..2e65bc1 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -25,6 +25,8 @@ #ifndef TARGET_ARM_INTERNALS_H #define TARGET_ARM_INTERNALS_H +#include "hw/registerfields.h" + /* register banks for CPU modes */ #define BANK_USRSYS 0 #define BANK_SVC 1 @@ -75,6 +77,11 @@ static const char * const excnames[] = { */ #define GTIMER_SCALE 16 +/* Bit definitions for the v7M CONTROL register */ +FIELD(V7M_CONTROL, NPRIV, 0, 1) +FIELD(V7M_CONTROL, SPSEL, 1, 1) +FIELD(V7M_CONTROL, FPCA, 2, 1) + /* * 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() diff --git a/target/arm/helper.c b/target/arm/helper.c index 8edb08c..dc383d1 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5947,14 +5947,19 @@ static uint32_t v7m_pop(CPUARMState *env) } /* Switch to V7M main or process stack pointer. */ -static void switch_v7m_sp(CPUARMState *env, int process) +static void switch_v7m_sp(CPUARMState *env, bool new_spsel) { uint32_t tmp; - if (env->v7m.current_sp != process) { + bool old_spsel = env->v7m.control & R_V7M_CONTROL_SPSEL_MASK; + + if (old_spsel != new_spsel) { tmp = env->v7m.other_sp; env->v7m.other_sp = env->regs[13]; env->regs[13] = tmp; - env->v7m.current_sp = process; + + env->v7m.control = deposit32(env->v7m.control, + R_V7M_CONTROL_SPSEL_SHIFT, + R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); } } @@ -6049,8 +6054,9 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) arm_log_exception(cs->exception_index); lr = 0xfffffff1; - if (env->v7m.current_sp) + if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) { lr |= 4; + } if (env->v7m.exception == 0) lr |= 8; @@ -8294,9 +8300,11 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) switch (reg) { case 8: /* MSP */ - return env->v7m.current_sp ? env->v7m.other_sp : env->regs[13]; + return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ? + env->v7m.other_sp : env->regs[13]; case 9: /* PSP */ - return env->v7m.current_sp ? env->regs[13] : env->v7m.other_sp; + return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ? + env->regs[13] : env->v7m.other_sp; case 16: /* PRIMASK */ return (env->daif & PSTATE_I) != 0; case 17: /* BASEPRI */ @@ -8326,16 +8334,18 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) } break; case 8: /* MSP */ - if (env->v7m.current_sp) + if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) { env->v7m.other_sp = val; - else + } else { env->regs[13] = val; + } break; case 9: /* PSP */ - if (env->v7m.current_sp) + if (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) { env->regs[13] = val; - else + } else { env->v7m.other_sp = val; + } break; case 16: /* PRIMASK */ if (val & 1) { @@ -8360,8 +8370,9 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) } break; case 20: /* CONTROL */ - env->v7m.control = val & 3; - switch_v7m_sp(env, (val & 2) != 0); + switch_v7m_sp(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); + env->v7m.control = val & (R_V7M_CONTROL_SPSEL_MASK | + R_V7M_CONTROL_NPRIV_MASK); break; default: qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special" diff --git a/target/arm/machine.c b/target/arm/machine.c index d90943b..8ed24bf 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -96,15 +96,13 @@ static bool m_needed(void *opaque) static const VMStateDescription vmstate_m = { .name = "cpu/m", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = m_needed, .fields = (VMStateField[]) { - VMSTATE_UINT32(env.v7m.other_sp, ARMCPU), VMSTATE_UINT32(env.v7m.vecbase, ARMCPU), VMSTATE_UINT32(env.v7m.basepri, ARMCPU), VMSTATE_UINT32(env.v7m.control, ARMCPU), - VMSTATE_INT32(env.v7m.current_sp, ARMCPU), VMSTATE_INT32(env.v7m.exception, ARMCPU), VMSTATE_END_OF_LIST() } From patchwork Fri Jan 20 18:44:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 92100 Delivered-To: patches@linaro.org Received: by 10.182.3.34 with SMTP id 2csp196967obz; Fri, 20 Jan 2017 10:44:47 -0800 (PST) X-Received: by 10.223.176.16 with SMTP id f16mr4106169wra.113.1484937887696; Fri, 20 Jan 2017 10:44:47 -0800 (PST) Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id r126si4392203wmb.109.2017.01.20.10.44.47 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 10:44:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1cUeB5-00048A-5Q; Fri, 20 Jan 2017 18:44:47 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, Liviu Ionescu , Michael Davidsaver Subject: [PATCH 6/6] armv7m: Clear FAULTMASK on return from non-NMI exceptions Date: Fri, 20 Jan 2017 18:44:43 +0000 Message-Id: <1484937883-1068-7-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> References: <1484937883-1068-1-git-send-email-peter.maydell@linaro.org> From: Michael Davidsaver FAULTMASK must be cleared on return from all exceptions other than NMI. Signed-off-by: Michael Davidsaver Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) -- 2.7.4 Reviewed-by: Alex Bennée diff --git a/target/arm/helper.c b/target/arm/helper.c index dc383d1..cfbc622 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5969,8 +5969,13 @@ static void do_v7m_exception_exit(CPUARMState *env) uint32_t xpsr; type = env->regs[15]; - if (env->v7m.exception != 0) + if (env->v7m.exception != ARMV7M_EXCP_NMI) { + /* Auto-clear FAULTMASK on return from other than NMI */ + env->daif &= ~PSTATE_F; + } + if (env->v7m.exception != 0) { armv7m_nvic_complete_irq(env->nvic, env->v7m.exception); + } /* Switch to the target stack. */ switch_v7m_sp(env, (type & 4) != 0);