aboutsummaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-10-24 19:37:33 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-10-24 19:37:34 +0100
commitfe4c04071f702e008da7db06d0a220b27e1ab3ac (patch)
tree97c3699d2cd15ec48436d53218178b903389f6e3 /target-arm
parent45b567d645c22fb79f4698a13396718084f7cf72 (diff)
parentcc083d8a25e0a886c3cd4bea0bf57ac4e896fa3f (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20161024' into staging
target-arm queue: * support variable (runtime-determined) page sizes, for a nearly-20% speedup of TCG for ARMv7 and v8 CPUs with 4K pages * ptimer: add tests, support more flexible behaviour around what happens on the "zero" tick, use ptimer for a9gtimer * virt: ACPI: Add IORT Structure definition * i2c: Fix SMBus read transactions to avoid double events * timer: stm32f2xx_timer: add check for prescaler value * QOMify musicpal, pxa2xx_gpio, strongarm, pl110 * target-arm: Implement new HLT trap for semihosting * i2c: Add asserts for second smbus i2c_start_transfer() # gpg: Signature made Mon 24 Oct 2016 18:24:17 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-20161024: (32 commits) i2c: Add asserts for second smbus i2c_start_transfer() target-arm: Implement new HLT trap for semihosting hw/display: QOM'ify pl110.c hw/arm: QOM'ify strongarm.c hw/arm: QOM'ify pxa2xx_gpio.c hw/arm: QOM'ify musicpal.c timer: stm32f2xx_timer: add check for prescaler value i2c: Fix SMBus read transactions to avoid double events timer: a9gtimer: remove loop to auto-increment comparator ARM: Virt: ACPI: Build an IORT table with RC and ITS nodes ACPI: Add IORT Structure definition tests: Add tests for the ARM MPTimer arm_mptimer: Convert to use ptimer tests: ptimer: Replace 10000 with 1 tests: ptimer: Change the copyright comment tests: ptimer: Add tests for "no counter round down" policy hw/ptimer: Add "no counter round down" policy tests: ptimer: Add tests for "no immediate reload" policy hw/ptimer: Add "no immediate reload" policy tests: ptimer: Add tests for "no immediate trigger" policy ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/cpu.c24
-rw-r--r--target-arm/cpu.h11
-rw-r--r--target-arm/helper.c11
-rw-r--r--target-arm/translate.c54
4 files changed, 89 insertions, 11 deletions
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 1b9540e085..c94a324540 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -576,6 +576,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
ARMCPU *cpu = ARM_CPU(dev);
ARMCPUClass *acc = ARM_CPU_GET_CLASS(dev);
CPUARMState *env = &cpu->env;
+ int pagebits;
/* Some features automatically imply others: */
if (arm_feature(env, ARM_FEATURE_V8)) {
@@ -631,6 +632,29 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
set_feature(env, ARM_FEATURE_THUMB_DSP);
}
+ if (arm_feature(env, ARM_FEATURE_V7) &&
+ !arm_feature(env, ARM_FEATURE_M) &&
+ !arm_feature(env, ARM_FEATURE_MPU)) {
+ /* v7VMSA drops support for the old ARMv5 tiny pages, so we
+ * can use 4K pages.
+ */
+ pagebits = 12;
+ } else {
+ /* For CPUs which might have tiny 1K pages, or which have an
+ * MPU and might have small region sizes, stick with 1K pages.
+ */
+ pagebits = 10;
+ }
+ if (!set_preferred_target_page_bits(pagebits)) {
+ /* This can only ever happen for hotplugging a CPU, or if
+ * the board code incorrectly creates a CPU which it has
+ * promised via minimum_page_size that it will not.
+ */
+ error_setg(errp, "This CPU requires a smaller page size than the "
+ "system is using");
+ return;
+ }
+
if (cpu->reset_hivecs) {
cpu->reset_sctlr |= (1 << 13);
}
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 2218c00dad..9d75227e04 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -52,7 +52,7 @@
#define EXCP_SMC 13 /* Secure Monitor Call */
#define EXCP_VIRQ 14
#define EXCP_VFIQ 15
-#define EXCP_SEMIHOST 16 /* semihosting call (A64 only) */
+#define EXCP_SEMIHOST 16 /* semihosting call */
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
@@ -1766,10 +1766,11 @@ bool write_cpustate_to_list(ARMCPU *cpu);
#if defined(CONFIG_USER_ONLY)
#define TARGET_PAGE_BITS 12
#else
-/* The ARM MMU allows 1k pages. */
-/* ??? Linux doesn't actually use these, and they're deprecated in recent
- architecture revisions. Maybe a configure option to disable them. */
-#define TARGET_PAGE_BITS 10
+/* ARMv7 and later CPUs have 4K pages minimum, but ARMv5 and v6
+ * have to support 1K tiny pages.
+ */
+#define TARGET_PAGE_BITS_VARY
+#define TARGET_PAGE_BITS_MIN 10
#endif
#if defined(TARGET_AARCH64)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index cb83ee2008..25b15dc100 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6573,12 +6573,19 @@ static inline bool check_for_semihosting(CPUState *cs)
/* Only intercept calls from privileged modes, to provide some
* semblance of security.
*/
- if (!semihosting_enabled() ||
- ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)) {
+ if (cs->exception_index != EXCP_SEMIHOST &&
+ (!semihosting_enabled() ||
+ ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) {
return false;
}
switch (cs->exception_index) {
+ case EXCP_SEMIHOST:
+ /* This is always a semihosting call; the "is this usermode"
+ * and "is semihosting enabled" checks have been done at
+ * translate time.
+ */
+ break;
case EXCP_SWI:
/* Check for semihosting interrupt. */
if (env->thumb) {
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 164b52a0d0..ef62f8b0c4 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -28,6 +28,7 @@
#include "qemu/log.h"
#include "qemu/bitops.h"
#include "arm_ldst.h"
+#include "exec/semihost.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@@ -1144,6 +1145,33 @@ static inline void gen_lookup_tb(DisasContext *s)
s->is_jmp = DISAS_JUMP;
}
+static inline void gen_hlt(DisasContext *s, int imm)
+{
+ /* HLT. This has two purposes.
+ * Architecturally, it is an external halting debug instruction.
+ * Since QEMU doesn't implement external debug, we treat this as
+ * it is required for halting debug disabled: it will UNDEF.
+ * Secondly, "HLT 0x3C" is a T32 semihosting trap instruction,
+ * and "HLT 0xF000" is an A32 semihosting syscall. These traps
+ * must trigger semihosting even for ARMv7 and earlier, where
+ * HLT was an undefined encoding.
+ * In system mode, we don't allow userspace access to
+ * semihosting, to provide some semblance of security
+ * (and for consistency with our 32-bit semihosting).
+ */
+ if (semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+ s->current_el != 0 &&
+#endif
+ (imm == (s->thumb ? 0x3c : 0xf000))) {
+ gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
+ return;
+ }
+
+ gen_exception_insn(s, s->thumb ? 2 : 4, EXCP_UDEF, syn_uncategorized(),
+ default_exception_el(s));
+}
+
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
TCGv_i32 var)
{
@@ -8395,6 +8423,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
{
int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
switch (op1) {
+ case 0:
+ /* HLT */
+ gen_hlt(s, imm16);
+ break;
case 1:
/* bkpt */
ARCH(5);
@@ -8419,7 +8451,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
gen_smc(s);
break;
default:
- goto illegal_op;
+ g_assert_not_reached();
}
break;
}
@@ -11451,19 +11483,33 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
break;
}
- case 0xa: /* rev */
+ case 0xa: /* rev, and hlt */
+ {
+ int op1 = extract32(insn, 6, 2);
+
+ if (op1 == 2) {
+ /* HLT */
+ int imm6 = extract32(insn, 0, 6);
+
+ gen_hlt(s, imm6);
+ break;
+ }
+
+ /* Otherwise this is rev */
ARCH(6);
rn = (insn >> 3) & 0x7;
rd = insn & 0x7;
tmp = load_reg(s, rn);
- switch ((insn >> 6) & 3) {
+ switch (op1) {
case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
case 1: gen_rev16(tmp); break;
case 3: gen_revsh(tmp); break;
- default: goto illegal_op;
+ default:
+ g_assert_not_reached();
}
store_reg(s, rd, tmp);
break;
+ }
case 6:
switch ((insn >> 5) & 7) {