From patchwork Fri May 23 02:30:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Herring X-Patchwork-Id: 351704 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3702514007B for ; Fri, 23 May 2014 12:33:57 +1000 (EST) Received: from localhost ([::1]:40642 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WnfIx-0000jV-4h for incoming@patchwork.ozlabs.org; Thu, 22 May 2014 22:33:55 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33783) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WnfG1-00048B-2g for qemu-devel@nongnu.org; Thu, 22 May 2014 22:31:03 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WnfFc-0003o5-09 for qemu-devel@nongnu.org; Thu, 22 May 2014 22:30:52 -0400 Received: from mail-ob0-x234.google.com ([2607:f8b0:4003:c01::234]:49998) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WnfFb-0003nm-Dv for qemu-devel@nongnu.org; Thu, 22 May 2014 22:30:27 -0400 Received: by mail-ob0-f180.google.com with SMTP id va2so4771829obc.39 for ; Thu, 22 May 2014 19:30:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=F7OlxtVIeKHdaC5BxcigRQ4yrFD+cjcJnzAjVvcrOHg=; b=yJscvm0TExgLbj8oX5fxIc9gL+mq3RgGXoxTr2xJise14/qVts5/xTT/KJoJImLOfP 4SnFBMfl0/Z3qxaIIzx5OnE46IgFlluartwk33nv60SlOZgTvW7LZdKoaSWDHNU3nGW/ dpB5hulWuLatWPkYC4LonFw9GyD08Wy6GeG1JVm3qpdcTUZpX0JEa8Hy8+02FeUx5PDS NUzO9zzSdmphs6g5wDyF4OPJJ/viGDsAFh0UQi+eW4LvY+RgGwo6SpPi0Xy0fd6ZmAVW PlUvHPymD8/IzO6aVT51mfFp8uGH8sn1v9Wakl2UTywUBN/SOMxe5zovbM1dYSZ7iv6F 1bfw== X-Received: by 10.182.43.132 with SMTP id w4mr1506007obl.41.1400812226924; Thu, 22 May 2014 19:30:26 -0700 (PDT) Received: from localhost.localdomain (66-90-144-10.dyn.grandenetworks.net. [66.90.144.10]) by mx.google.com with ESMTPSA id fm8sm5542727oeb.10.2014.05.22.19.30.26 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 22 May 2014 19:30:26 -0700 (PDT) From: Rob Herring To: Peter Maydell Date: Thu, 22 May 2014 21:30:06 -0500 Message-Id: <1400812209-26743-4-git-send-email-robherring2@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1400812209-26743-1-git-send-email-robherring2@gmail.com> References: <1400812209-26743-1-git-send-email-robherring2@gmail.com> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:4003:c01::234 Cc: Rob Herring , Peter Crosthwaite , qemu-devel@nongnu.org, Christoffer Dall Subject: [Qemu-devel] [PATCH v2 3/6] target-arm: add hvc and smc exception emulation handling infrastructure X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Rob Herring Add the infrastructure to handle and emulate hvc and smc exceptions. This will enable emulation of things such as PSCI calls. This commit does not change the behavior and will exit with unknown exception. Signed-off-by: Rob Herring Reviewed-by: Peter Maydell --- v2: - add syn_aa32_smc - add missing syndrome calls - properly handle unhandled SMC/HVC emulation as undefined instruction exception - Move PSCI bits in arm_cpu_do_hvc/smc to next patch - fix immediate value for thumb hvc target-arm/cpu-qom.h | 3 +++ target-arm/cpu.h | 2 ++ target-arm/helper-a64.c | 32 ++++++++++++++++++++++++++++---- target-arm/helper.c | 30 ++++++++++++++++++++++++++++++ target-arm/internals.h | 20 ++++++++++++++++++++ target-arm/translate-a64.c | 13 ++++++++++--- target-arm/translate.c | 24 +++++++++++++++++------- 7 files changed, 110 insertions(+), 14 deletions(-) -- 1.9.1 diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index f835900..d2ff087 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -195,6 +195,9 @@ extern const struct VMStateDescription vmstate_arm_cpu; void register_cp_regs_for_features(ARMCPU *cpu); void init_cpreg_list(ARMCPU *cpu); +bool arm_cpu_do_hvc(CPUState *cs); +bool arm_cpu_do_smc(CPUState *cs); + void arm_cpu_do_interrupt(CPUState *cpu); void arm_v7m_cpu_do_interrupt(CPUState *cpu); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c83f249..905ba02 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -51,6 +51,8 @@ #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ #define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ #define EXCP_STREX 10 +#define EXCP_HVC 11 +#define EXCP_SMC 12 #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index 84411b4..e3dcca8 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -466,14 +466,11 @@ void aarch64_cpu_do_interrupt(CPUState *cs) env->exception.syndrome); } - env->cp15.esr_el1 = env->exception.syndrome; - env->cp15.far_el1 = env->exception.vaddress; - switch (cs->exception_index) { case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n", - env->cp15.far_el1); + env->exception.vaddress); break; case EXCP_BKPT: case EXCP_UDEF: @@ -485,10 +482,37 @@ void aarch64_cpu_do_interrupt(CPUState *cs) case EXCP_FIQ: addr += 0x100; break; + case EXCP_HVC: + if (arm_cpu_do_hvc(cs)) { + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "Unhandled HVC exception\n"); + env->exception.syndrome = syn_uncategorized(); + if (is_a64(env)) { + env->pc -= 4; + } else { + env->regs[15] -= 4; + } + break; + case EXCP_SMC: + if (arm_cpu_do_smc(cs)) { + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "Unhandled SMC exception\n"); + env->exception.syndrome = syn_uncategorized(); + if (is_a64(env)) { + env->pc -= 4; + } else { + env->regs[15] -= 4; + } + break; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } + env->cp15.esr_el1 = env->exception.syndrome; + env->cp15.far_el1 = env->exception.vaddress; + if (is_a64(env)) { env->banked_spsr[0] = pstate_read(env); env->sp_el[arm_current_pl(env)] = env->xregs[31]; diff --git a/target-arm/helper.c b/target-arm/helper.c index 1307473..552e601 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3255,6 +3255,16 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) env->thumb = addr & 1; } +bool arm_cpu_do_hvc(CPUState *cs) +{ + return false; +} + +bool arm_cpu_do_smc(CPUState *cs) +{ + return false; +} + /* Handle a CPU exception. */ void arm_cpu_do_interrupt(CPUState *cs) { @@ -3357,6 +3367,26 @@ void arm_cpu_do_interrupt(CPUState *cs) mask = CPSR_A | CPSR_I | CPSR_F; offset = 4; break; + case EXCP_HVC: + if (arm_cpu_do_hvc(cs)) { + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "Unhandled HVC exception\n"); + new_mode = ARM_CPU_MODE_UND; + addr = 0x04; + mask = CPSR_A | CPSR_I; + offset = 4; + break; + case EXCP_SMC: + if (arm_cpu_do_smc(cs)) { + return; + } + qemu_log_mask(LOG_GUEST_ERROR, "Unhandled SMC exception\n"); + new_mode = ARM_CPU_MODE_UND; + addr = 0x04; + mask = CPSR_A | CPSR_I; + offset = 4; + break; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); return; /* Never happens. Keep compiler happy. */ diff --git a/target-arm/internals.h b/target-arm/internals.h index d63a975..52a284f 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -184,6 +184,26 @@ static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb) | (is_thumb ? 0 : ARM_EL_IL); } +static inline uint32_t syn_aa64_hvc(uint32_t imm16) +{ + return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); +} + +static inline uint32_t syn_aa32_hvc(uint32_t imm16) +{ + return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); +} + +static inline uint32_t syn_aa64_smc(uint32_t imm16) +{ + return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); +} + +static inline uint32_t syn_aa32_smc(void) +{ + return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL; +} + static inline uint32_t syn_aa64_bkpt(uint32_t imm16) { return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index b62db4d..d5e3624 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1449,11 +1449,18 @@ static void disas_exc(DisasContext *s, uint32_t insn) /* SVC, HVC, SMC; since we don't support the Virtualization * or TrustZone extensions these all UNDEF except SVC. */ - if (op2_ll != 1) { - unallocated_encoding(s); + switch (op2_ll) { + case 1: + gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); + break; + case 2: + gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16)); + break; + case 3: + gen_exception_insn(s, 0, EXCP_SMC, syn_aa64_smc(imm16)); break; } - gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); + unallocated_encoding(s); break; case 1: if (op2_ll != 0) { diff --git a/target-arm/translate.c b/target-arm/translate.c index a4d920b..c108bc7 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7727,9 +7727,14 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) case 7: { int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4); - /* SMC instruction (op1 == 3) - and undefined instructions (op1 == 0 || op1 == 2) - will trap */ + /* HVC and SMC instructions */ + if (op1 == 2) { + gen_exception_insn(s, 0, EXCP_HVC, syn_aa32_hvc(imm16)); + break; + } else if (op1 == 3) { + gen_exception_insn(s, 0, EXCP_SMC, syn_aa32_smc()); + break; + } if (op1 != 1) { goto illegal_op; } @@ -9555,10 +9560,15 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw goto illegal_op; if (insn & (1 << 26)) { - /* Secure monitor call (v6Z) */ - qemu_log_mask(LOG_UNIMP, - "arm: unimplemented secure monitor call\n"); - goto illegal_op; /* not implemented. */ + if (!(insn & (1 << 20))) { + /* Hypervisor call (v7) */ + uint32_t imm16 = extract32(insn, 0, 12); + imm16 |= extract32(insn, 16, 4) << 12; + gen_exception_insn(s, 0, EXCP_HVC, syn_aa32_hvc(imm16)); + } else { + /* Secure monitor call (v6+) */ + gen_exception_insn(s, 0, EXCP_SMC, syn_aa32_smc()); + } } else { op = (insn >> 20) & 7; switch (op) {