qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Peter Crosthwaite" <peter.crosthwaite@xilinx.com>,
	patches@linaro.org, "Michael Matz" <matz@suse.de>,
	"Alexander Graf" <agraf@suse.de>,
	"Will Newton" <will.newton@linaro.org>,
	"Dirk Mueller" <dmueller@suse.de>,
	"Laurent Desnogues" <laurent.desnogues@gmail.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	kvmarm@lists.cs.columbia.edu,
	"Christoffer Dall" <christoffer.dall@linaro.org>,
	"Richard Henderson" <rth@twiddle.net>
Subject: [Qemu-devel] [PATCH v5 16/37] target-arm: Implement SP_EL0, SP_EL1
Date: Fri, 28 Mar 2014 16:10:03 +0000	[thread overview]
Message-ID: <1396023024-2262-17-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1396023024-2262-1-git-send-email-peter.maydell@linaro.org>

Implement handling for the AArch64 SP_EL0 system register.
This holds the EL0 stack pointer, and is only accessible when
it's not being used as the stack pointer, ie when we're in EL1
and EL1 is using its own stack pointer. We also provide a
definition of the SP_EL1 register; this isn't guest visible
as a system register for an implementation like QEMU which
doesn't provide EL2 or EL3; however it is useful for ensuring
the underlying state is migrated.

We need to update the state fields in the CPU state whenever
we switch stack pointers; this happens when we take an exception
and also when SPSEL is used to change the bit in PSTATE which
indicates which stack pointer EL1 should use.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h       |  2 ++
 target-arm/helper.c    | 34 ++++++++++++++++++++++++++++++++++
 target-arm/internals.h | 25 +++++++++++++++++++++++++
 target-arm/kvm64.c     | 37 ++++++++++++++++++++++++++++++++++---
 target-arm/machine.c   |  7 ++++---
 target-arm/op_helper.c |  2 +-
 6 files changed, 100 insertions(+), 7 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ecdd7a7..28b9bda 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -163,6 +163,7 @@ typedef struct CPUARMState {
     uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
 
     uint64_t elr_el1; /* AArch64 ELR_EL1 */
+    uint64_t sp_el[2]; /* AArch64 banked stack pointers */
 
     /* System control coprocessor (cp15) */
     struct {
@@ -434,6 +435,7 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
  * Only these are valid when in AArch64 mode; in
  * AArch32 mode SPSRs are basically CPSR-format.
  */
+#define PSTATE_SP (1U)
 #define PSTATE_M (0xFU)
 #define PSTATE_nRW (1U << 4)
 #define PSTATE_F (1U << 6)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 276ecf2..27a3dc2 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1783,6 +1783,27 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
     return cpu->dcz_blocksize | dzp_bit;
 }
 
+static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    if (!env->pstate & PSTATE_SP) {
+        /* Access to SP_EL0 is undefined if it's being used as
+         * the stack pointer.
+         */
+        return CP_ACCESS_TRAP_UNCATEGORIZED;
+    }
+    return CP_ACCESS_OK;
+}
+
+static uint64_t spsel_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    return env->pstate & PSTATE_SP;
+}
+
+static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val)
+{
+    update_spsel(env, val);
+}
+
 static const ARMCPRegInfo v8_cp_reginfo[] = {
     /* Minimal set of EL0-visible registers. This will need to be expanded
      * significantly for system emulation of AArch64 CPUs.
@@ -1915,6 +1936,19 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .type = ARM_CP_NO_MIGRATE,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
+    /* We rely on the access checks not allowing the guest to write to the
+     * state field when SPSel indicates that it's being used as the stack
+     * pointer.
+     */
+    { .name = "SP_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 1, .opc2 = 0,
+      .access = PL1_RW, .accessfn = sp_el0_access,
+      .type = ARM_CP_NO_MIGRATE,
+      .fieldoffset = offsetof(CPUARMState, sp_el[0]) },
+    { .name = "SPSel", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
+      .type = ARM_CP_NO_MIGRATE,
+      .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
     REGINFO_SENTINEL
 };
 
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 5c427cc..f7ea404 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -60,6 +60,31 @@ enum arm_fprounding {
 
 int arm_rmode_to_sf(int rmode);
 
+static inline void update_spsel(CPUARMState *env, uint32_t imm)
+{
+    /* Update PSTATE SPSel bit; this requires us to update the
+     * working stack pointer in xregs[31].
+     */
+    if (!((imm ^ env->pstate) & PSTATE_SP)) {
+        return;
+    }
+    env->pstate = deposit32(env->pstate, 0, 1, imm);
+
+    /* EL0 has no access rights to update SPSel, and this code
+     * assumes we are updating SP for EL1 while running as EL1.
+     */
+    assert(arm_current_pl(env) == 1);
+    if (env->pstate & PSTATE_SP) {
+        /* Switch from using SP_EL0 to using SP_ELx */
+        env->sp_el[0] = env->xregs[31];
+        env->xregs[31] = env->sp_el[1];
+    } else {
+        /* Switch from SP_EL0 to SP_ELx */
+        env->sp_el[1] = env->xregs[31];
+        env->xregs[31] = env->sp_el[0];
+    }
+}
+
 /* Valid Syndrome Register EC field values */
 enum arm_exception_class {
     EC_UNCATEGORIZED          = 0x00,
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index ee72748..39c4364 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -121,8 +121,24 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         }
     }
 
+    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+     * QEMU side we keep the current SP in xregs[31] as well.
+     */
+    if (env->pstate & PSTATE_SP) {
+        env->sp_el[1] = env->xregs[31];
+    } else {
+        env->sp_el[0] = env->xregs[31];
+    }
+
     reg.id = AARCH64_CORE_REG(regs.sp);
-    reg.addr = (uintptr_t) &env->xregs[31];
+    reg.addr = (uintptr_t) &env->sp_el[0];
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(sp_el1);
+    reg.addr = (uintptr_t) &env->sp_el[1];
     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
     if (ret) {
         return ret;
@@ -152,7 +168,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     }
 
     /* TODO:
-     * SP_EL1
      * SPSR[]
      * FP state
      * system registers
@@ -180,7 +195,14 @@ int kvm_arch_get_registers(CPUState *cs)
     }
 
     reg.id = AARCH64_CORE_REG(regs.sp);
-    reg.addr = (uintptr_t) &env->xregs[31];
+    reg.addr = (uintptr_t) &env->sp_el[0];
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(sp_el1);
+    reg.addr = (uintptr_t) &env->sp_el[1];
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
     if (ret) {
         return ret;
@@ -194,6 +216,15 @@ int kvm_arch_get_registers(CPUState *cs)
     }
     pstate_write(env, val);
 
+    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+     * QEMU side we keep the current SP in xregs[31] as well.
+     */
+    if (env->pstate & PSTATE_SP) {
+        env->xregs[31] = env->sp_el[1];
+    } else {
+        env->xregs[31] = env->sp_el[0];
+    }
+
     reg.id = AARCH64_CORE_REG(regs.pc);
     reg.addr = (uintptr_t) &env->pc;
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 42b1c90..c2c0780 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
 
 const VMStateDescription vmstate_arm_cpu = {
     .name = "cpu",
-    .version_id = 15,
-    .minimum_version_id = 15,
-    .minimum_version_id_old = 15,
+    .version_id = 16,
+    .minimum_version_id = 16,
+    .minimum_version_id_old = 16,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -244,6 +244,7 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
         VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
         VMSTATE_UINT64(env.elr_el1, ARMCPU),
+        VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
         /* The length-check must come before the arrays to avoid
          * incoming data possibly overflowing the array.
          */
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 51edd90..64a33dd 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -371,7 +371,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
 
     switch (op) {
     case 0x05: /* SPSel */
-        env->pstate = deposit32(env->pstate, 0, 1, imm);
+        update_spsel(env, imm);
         break;
     case 0x1e: /* DAIFSet */
         env->daif |= (imm << 6) & PSTATE_DAIF;
-- 
1.9.0

  parent reply	other threads:[~2014-03-28 16:10 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-28 16:09 [Qemu-devel] [PATCH v5 00/37] AArch64 system emulation Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 01/37] target-arm: Split out private-to-target functions into internals.h Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 02/37] target-arm: Implement AArch64 DAIF system register Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 03/37] target-arm: Define exception record for AArch64 exceptions Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 04/37] target-arm: Provide correct syndrome information for cpreg access traps Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 05/37] target-arm: Add support for generating exceptions with syndrome information Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 06/37] target-arm: Provide syndrome information for MMU faults Peter Maydell
2014-04-01  3:10   ` Peter Crosthwaite
2014-04-04 13:25     ` Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 07/37] target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 08/37] target-arm: A64: Add assertion that FP access was checked Peter Maydell
2014-04-01  3:24   ` Peter Crosthwaite
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 09/37] target-arm: Fix VFP enables for AArch32 EL0 under AArch64 EL1 Peter Maydell
2014-04-01  3:30   ` Peter Crosthwaite
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 10/37] target-arm: Add v8 mmu translation support Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 11/37] target-arm: Don't mention PMU in debug feature register Peter Maydell
2014-04-01 13:19   ` Christopher Covington
2014-04-01 13:43     ` Peter Maydell
2014-03-28 16:09 ` [Qemu-devel] [PATCH v5 12/37] target-arm: A64: Implement DC ZVA Peter Maydell
2014-03-28 18:42   ` Richard Henderson
2014-04-04 14:12     ` Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 13/37] target-arm: Use dedicated CPU state fields for ARM946 access bit registers Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 14/37] target-arm: Implement AArch64 views of fault status and data registers Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 15/37] target-arm: Add AArch64 ELR_EL1 register Peter Maydell
2014-03-28 16:10 ` Peter Maydell [this message]
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 17/37] target-arm: Implement AArch64 SPSR_EL1 Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 18/37] target-arm: Move arm_log_exception() into internals.h Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 19/37] target-arm: Implement AArch64 EL1 exception handling Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 20/37] target-arm: Implement ARMv8 MVFR registers Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 21/37] target-arm: Add Cortex-A57 processor Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 22/37] hw/arm/virt: Add support for Cortex-A57 Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 23/37] target-arm: Implement AArch64 views of AArch32 ID registers Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 24/37] target-arm: Implement AArch64 view of CONTEXTIDR Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 25/37] target-arm: Implement AArch64 view of ACTLR Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 26/37] target-arm: Implement ISR_EL1 register Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 27/37] target-arm: Remove THUMB2EE feature from AArch64 'any' CPU Peter Maydell
2014-04-02 12:20   ` Peter Crosthwaite
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 28/37] target-arm: Don't expose wildcard ID register definitions for ARMv8 Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 29/37] target-arm: Replace wildcarded cpreg definitions with precise ones " Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 30/37] target-arm: Implement auxiliary fault status registers Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 31/37] target-arm: Implement AArch64 address translation operations Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 32/37] target-arm: Implement RVBAR register Peter Maydell
2014-04-04  5:17   ` Peter Crosthwaite
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 33/37] target-arm: Implement Cortex-A57 implementation-defined system registers Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 34/37] target-arm: Implement CBAR for Cortex-A57 Peter Maydell
2014-04-04  5:32   ` Peter Crosthwaite
2014-04-04  8:25     ` Peter Maydell
2014-04-04 12:32       ` Peter Crosthwaite
2014-04-04 13:05         ` Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 35/37] target-arm: Make Cortex-A15 CBAR read-only Peter Maydell
2014-04-04  5:33   ` Peter Crosthwaite
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 36/37] target-arm: Handle the CPU being in AArch32 mode in the AArch64 set_pc Peter Maydell
2014-03-28 16:10 ` [Qemu-devel] [PATCH v5 37/37] target-arm: Dump 32-bit CPU state if 64 bit CPU is in AArch32 Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1396023024-2262-17-git-send-email-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=agraf@suse.de \
    --cc=alex.bennee@linaro.org \
    --cc=christoffer.dall@linaro.org \
    --cc=dmueller@suse.de \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=laurent.desnogues@gmail.com \
    --cc=matz@suse.de \
    --cc=patches@linaro.org \
    --cc=peter.crosthwaite@xilinx.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    --cc=will.newton@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).