Merge branch 'kvm-arm64/copro-no-more' into kvmarm-master/next
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Коммит
149f120edb
|
@ -1,38 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2012,2013 - ARM Ltd
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* Derived from arch/arm/include/asm/kvm_coproc.h
|
||||
* Copyright (C) 2012 Rusty Russell IBM Corporation
|
||||
*/
|
||||
|
||||
#ifndef __ARM64_KVM_COPROC_H__
|
||||
#define __ARM64_KVM_COPROC_H__
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct kvm_sys_reg_table {
|
||||
const struct sys_reg_desc *table;
|
||||
size_t num;
|
||||
};
|
||||
|
||||
int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_sys_reg(struct kvm_vcpu *vcpu);
|
||||
|
||||
#define kvm_coproc_table_init kvm_sys_reg_table_init
|
||||
void kvm_sys_reg_table_init(void);
|
||||
|
||||
struct kvm_one_reg;
|
||||
int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
|
||||
int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
|
||||
|
||||
#endif /* __ARM64_KVM_COPROC_H__ */
|
|
@ -203,48 +203,6 @@ enum vcpu_sysreg {
|
|||
NR_SYS_REGS /* Nothing after this line! */
|
||||
};
|
||||
|
||||
/* 32bit mapping */
|
||||
#define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
|
||||
#define c0_CSSELR (CSSELR_EL1 * 2)/* Cache Size Selection Register */
|
||||
#define c1_SCTLR (SCTLR_EL1 * 2) /* System Control Register */
|
||||
#define c1_ACTLR (ACTLR_EL1 * 2) /* Auxiliary Control Register */
|
||||
#define c1_CPACR (CPACR_EL1 * 2) /* Coprocessor Access Control */
|
||||
#define c2_TTBR0 (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
|
||||
#define c2_TTBR0_high (c2_TTBR0 + 1) /* TTBR0 top 32 bits */
|
||||
#define c2_TTBR1 (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
|
||||
#define c2_TTBR1_high (c2_TTBR1 + 1) /* TTBR1 top 32 bits */
|
||||
#define c2_TTBCR (TCR_EL1 * 2) /* Translation Table Base Control R. */
|
||||
#define c3_DACR (DACR32_EL2 * 2)/* Domain Access Control Register */
|
||||
#define c5_DFSR (ESR_EL1 * 2) /* Data Fault Status Register */
|
||||
#define c5_IFSR (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
|
||||
#define c5_ADFSR (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
|
||||
#define c5_AIFSR (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
|
||||
#define c6_DFAR (FAR_EL1 * 2) /* Data Fault Address Register */
|
||||
#define c6_IFAR (c6_DFAR + 1) /* Instruction Fault Address Register */
|
||||
#define c7_PAR (PAR_EL1 * 2) /* Physical Address Register */
|
||||
#define c7_PAR_high (c7_PAR + 1) /* PAR top 32 bits */
|
||||
#define c10_PRRR (MAIR_EL1 * 2) /* Primary Region Remap Register */
|
||||
#define c10_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */
|
||||
#define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */
|
||||
#define c13_CID (CONTEXTIDR_EL1 * 2) /* Context ID Register */
|
||||
#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
|
||||
#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
|
||||
#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
|
||||
#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
|
||||
#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
|
||||
#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
|
||||
|
||||
#define cp14_DBGDSCRext (MDSCR_EL1 * 2)
|
||||
#define cp14_DBGBCR0 (DBGBCR0_EL1 * 2)
|
||||
#define cp14_DBGBVR0 (DBGBVR0_EL1 * 2)
|
||||
#define cp14_DBGBXVR0 (cp14_DBGBVR0 + 1)
|
||||
#define cp14_DBGWCR0 (DBGWCR0_EL1 * 2)
|
||||
#define cp14_DBGWVR0 (DBGWVR0_EL1 * 2)
|
||||
#define cp14_DBGDCCINT (MDCCINT_EL1 * 2)
|
||||
#define cp14_DBGVCR (DBGVCR32_EL2 * 2)
|
||||
|
||||
#define NR_COPRO_REGS (NR_SYS_REGS * 2)
|
||||
|
||||
struct kvm_cpu_context {
|
||||
struct user_pt_regs regs; /* sp = sp_el0 */
|
||||
|
||||
|
@ -255,10 +213,7 @@ struct kvm_cpu_context {
|
|||
|
||||
struct user_fpsimd_state fp_regs;
|
||||
|
||||
union {
|
||||
u64 sys_regs[NR_SYS_REGS];
|
||||
u32 copro[NR_COPRO_REGS];
|
||||
};
|
||||
u64 sys_regs[NR_SYS_REGS];
|
||||
|
||||
struct kvm_vcpu *__hyp_running_vcpu;
|
||||
};
|
||||
|
@ -556,15 +511,6 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* CP14 and CP15 live in the same array, as they are backed by the
|
||||
* same system registers.
|
||||
*/
|
||||
#define CPx_BIAS IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)
|
||||
|
||||
#define vcpu_cp14(v,r) ((v)->arch.ctxt.copro[(r) ^ CPx_BIAS])
|
||||
#define vcpu_cp15(v,r) ((v)->arch.ctxt.copro[(r) ^ CPx_BIAS])
|
||||
|
||||
struct kvm_vm_stat {
|
||||
ulong remote_tlb_flush;
|
||||
};
|
||||
|
@ -589,6 +535,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
|
|||
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
|
||||
int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
|
||||
int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
|
||||
|
||||
unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
|
||||
int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
|
||||
int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
|
||||
|
||||
int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events);
|
||||
|
||||
|
@ -651,6 +603,17 @@ void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
|
|||
int handle_exit(struct kvm_vcpu *vcpu, int exception_index);
|
||||
void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index);
|
||||
|
||||
int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu);
|
||||
int kvm_handle_sys_reg(struct kvm_vcpu *vcpu);
|
||||
|
||||
void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
|
||||
|
||||
void kvm_sys_reg_table_init(void);
|
||||
|
||||
/* MMIO helpers */
|
||||
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
|
||||
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#include <kvm/arm_hypercalls.h>
|
||||
|
@ -1541,7 +1540,7 @@ static int init_subsystems(void)
|
|||
goto out;
|
||||
|
||||
kvm_perf_init();
|
||||
kvm_coproc_table_init();
|
||||
kvm_sys_reg_table_init();
|
||||
|
||||
out:
|
||||
on_each_cpu(_kvm_arch_hardware_disable, NULL, 1);
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <asm/fpsimd.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/sigcontext.h>
|
||||
|
||||
#include "trace.h"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <asm/esr.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
|
|
|
@ -69,26 +69,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
|
|||
#define DFSR_FSC_EXTABT_LPAE 0x10
|
||||
#define DFSR_FSC_EXTABT_nLPAE 0x08
|
||||
#define DFSR_LPAE BIT(9)
|
||||
|
||||
static bool pre_fault_synchronize(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
preempt_disable();
|
||||
if (vcpu->arch.sysregs_loaded_on_cpu) {
|
||||
kvm_arch_vcpu_put(vcpu);
|
||||
return true;
|
||||
}
|
||||
|
||||
preempt_enable();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void post_fault_synchronize(struct kvm_vcpu *vcpu, bool loaded)
|
||||
{
|
||||
if (loaded) {
|
||||
kvm_arch_vcpu_load(vcpu, smp_processor_id());
|
||||
preempt_enable();
|
||||
}
|
||||
}
|
||||
#define TTBCR_EAE BIT(31)
|
||||
|
||||
static void inject_undef32(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
|
@ -100,39 +81,36 @@ static void inject_undef32(struct kvm_vcpu *vcpu)
|
|||
* Modelled after TakeDataAbortException() and TakePrefetchAbortException
|
||||
* pseudocode.
|
||||
*/
|
||||
static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
|
||||
unsigned long addr)
|
||||
static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr)
|
||||
{
|
||||
u32 *far, *fsr;
|
||||
bool is_lpae;
|
||||
bool loaded;
|
||||
u64 far;
|
||||
u32 fsr;
|
||||
|
||||
loaded = pre_fault_synchronize(vcpu);
|
||||
/* Give the guest an IMPLEMENTATION DEFINED exception */
|
||||
if (vcpu_read_sys_reg(vcpu, TCR_EL1) & TTBCR_EAE) {
|
||||
fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE;
|
||||
} else {
|
||||
/* no need to shuffle FS[4] into DFSR[10] as its 0 */
|
||||
fsr = DFSR_FSC_EXTABT_nLPAE;
|
||||
}
|
||||
|
||||
far = vcpu_read_sys_reg(vcpu, FAR_EL1);
|
||||
|
||||
if (is_pabt) {
|
||||
vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_IABT |
|
||||
KVM_ARM64_PENDING_EXCEPTION);
|
||||
far = &vcpu_cp15(vcpu, c6_IFAR);
|
||||
fsr = &vcpu_cp15(vcpu, c5_IFSR);
|
||||
far &= GENMASK(31, 0);
|
||||
far |= (u64)addr << 32;
|
||||
vcpu_write_sys_reg(vcpu, fsr, IFSR32_EL2);
|
||||
} else { /* !iabt */
|
||||
vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_DABT |
|
||||
KVM_ARM64_PENDING_EXCEPTION);
|
||||
far = &vcpu_cp15(vcpu, c6_DFAR);
|
||||
fsr = &vcpu_cp15(vcpu, c5_DFSR);
|
||||
far &= GENMASK(63, 32);
|
||||
far |= addr;
|
||||
vcpu_write_sys_reg(vcpu, fsr, ESR_EL1);
|
||||
}
|
||||
|
||||
*far = addr;
|
||||
|
||||
/* Give the guest an IMPLEMENTATION DEFINED exception */
|
||||
is_lpae = (vcpu_cp15(vcpu, c2_TTBCR) >> 31);
|
||||
if (is_lpae) {
|
||||
*fsr = DFSR_LPAE | DFSR_FSC_EXTABT_LPAE;
|
||||
} else {
|
||||
/* no need to shuffle FS[4] into DFSR[10] as its 0 */
|
||||
*fsr = DFSR_FSC_EXTABT_nLPAE;
|
||||
}
|
||||
|
||||
post_fault_synchronize(vcpu, loaded);
|
||||
vcpu_write_sys_reg(vcpu, far, FAR_EL1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <asm/ptrace.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/virt.h>
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <asm/debug-monitors.h>
|
||||
#include <asm/esr.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_coproc.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_hyp.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
|
@ -128,6 +127,24 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void get_access_mask(const struct sys_reg_desc *r, u64 *mask, u64 *shift)
|
||||
{
|
||||
switch (r->aarch32_map) {
|
||||
case AA32_LO:
|
||||
*mask = GENMASK_ULL(31, 0);
|
||||
*shift = 0;
|
||||
break;
|
||||
case AA32_HI:
|
||||
*mask = GENMASK_ULL(63, 32);
|
||||
*shift = 32;
|
||||
break;
|
||||
default:
|
||||
*mask = GENMASK_ULL(63, 0);
|
||||
*shift = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic accessor for VM registers. Only called as long as HCR_TVM
|
||||
* is set. If the guest enables the MMU, we stop trapping the VM
|
||||
|
@ -138,26 +155,21 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
|
|||
const struct sys_reg_desc *r)
|
||||
{
|
||||
bool was_enabled = vcpu_has_cache_enabled(vcpu);
|
||||
u64 val;
|
||||
int reg = r->reg;
|
||||
u64 val, mask, shift;
|
||||
|
||||
BUG_ON(!p->is_write);
|
||||
|
||||
/* See the 32bit mapping in kvm_host.h */
|
||||
if (p->is_aarch32)
|
||||
reg = r->reg / 2;
|
||||
get_access_mask(r, &mask, &shift);
|
||||
|
||||
if (!p->is_aarch32 || !p->is_32bit) {
|
||||
val = p->regval;
|
||||
if (~mask) {
|
||||
val = vcpu_read_sys_reg(vcpu, r->reg);
|
||||
val &= ~mask;
|
||||
} else {
|
||||
val = vcpu_read_sys_reg(vcpu, reg);
|
||||
if (r->reg % 2)
|
||||
val = (p->regval << 32) | (u64)lower_32_bits(val);
|
||||
else
|
||||
val = ((u64)upper_32_bits(val) << 32) |
|
||||
lower_32_bits(p->regval);
|
||||
val = 0;
|
||||
}
|
||||
vcpu_write_sys_reg(vcpu, val, reg);
|
||||
|
||||
val |= (p->regval & (mask >> shift)) << shift;
|
||||
vcpu_write_sys_reg(vcpu, val, r->reg);
|
||||
|
||||
kvm_toggle_cache(vcpu, was_enabled);
|
||||
return true;
|
||||
|
@ -167,17 +179,13 @@ static bool access_actlr(struct kvm_vcpu *vcpu,
|
|||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u64 mask, shift;
|
||||
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
p->regval = vcpu_read_sys_reg(vcpu, ACTLR_EL1);
|
||||
|
||||
if (p->is_aarch32) {
|
||||
if (r->Op2 & 2)
|
||||
p->regval = upper_32_bits(p->regval);
|
||||
else
|
||||
p->regval = lower_32_bits(p->regval);
|
||||
}
|
||||
get_access_mask(r, &mask, &shift);
|
||||
p->regval = (vcpu_read_sys_reg(vcpu, r->reg) & mask) >> shift;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -204,7 +212,7 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
|
|||
* equivalent to ICC_SGI0R_EL1, as there is no "alternative" secure
|
||||
* group.
|
||||
*/
|
||||
if (p->is_aarch32) {
|
||||
if (p->Op0 == 0) { /* AArch32 */
|
||||
switch (p->Op1) {
|
||||
default: /* Keep GCC quiet */
|
||||
case 0: /* ICC_SGI1R */
|
||||
|
@ -215,7 +223,7 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
|
|||
g1 = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
} else { /* AArch64 */
|
||||
switch (p->Op2) {
|
||||
default: /* Keep GCC quiet */
|
||||
case 5: /* ICC_SGI1R_EL1 */
|
||||
|
@ -357,26 +365,30 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
|
|||
*/
|
||||
static void reg_to_dbg(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *rd,
|
||||
u64 *dbg_reg)
|
||||
{
|
||||
u64 val = p->regval;
|
||||
u64 mask, shift, val;
|
||||
|
||||
if (p->is_32bit) {
|
||||
val &= 0xffffffffUL;
|
||||
val |= ((*dbg_reg >> 32) << 32);
|
||||
}
|
||||
get_access_mask(rd, &mask, &shift);
|
||||
|
||||
val = *dbg_reg;
|
||||
val &= ~mask;
|
||||
val |= (p->regval & (mask >> shift)) << shift;
|
||||
*dbg_reg = val;
|
||||
|
||||
vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
|
||||
}
|
||||
|
||||
static void dbg_to_reg(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *rd,
|
||||
u64 *dbg_reg)
|
||||
{
|
||||
p->regval = *dbg_reg;
|
||||
if (p->is_32bit)
|
||||
p->regval &= 0xffffffffUL;
|
||||
u64 mask, shift;
|
||||
|
||||
get_access_mask(rd, &mask, &shift);
|
||||
p->regval = (*dbg_reg & mask) >> shift;
|
||||
}
|
||||
|
||||
static bool trap_bvr(struct kvm_vcpu *vcpu,
|
||||
|
@ -386,9 +398,9 @@ static bool trap_bvr(struct kvm_vcpu *vcpu,
|
|||
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
|
||||
|
||||
if (p->is_write)
|
||||
reg_to_dbg(vcpu, p, dbg_reg);
|
||||
reg_to_dbg(vcpu, p, rd, dbg_reg);
|
||||
else
|
||||
dbg_to_reg(vcpu, p, dbg_reg);
|
||||
dbg_to_reg(vcpu, p, rd, dbg_reg);
|
||||
|
||||
trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
|
||||
|
||||
|
@ -428,9 +440,9 @@ static bool trap_bcr(struct kvm_vcpu *vcpu,
|
|||
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
|
||||
|
||||
if (p->is_write)
|
||||
reg_to_dbg(vcpu, p, dbg_reg);
|
||||
reg_to_dbg(vcpu, p, rd, dbg_reg);
|
||||
else
|
||||
dbg_to_reg(vcpu, p, dbg_reg);
|
||||
dbg_to_reg(vcpu, p, rd, dbg_reg);
|
||||
|
||||
trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
|
||||
|
||||
|
@ -471,9 +483,9 @@ static bool trap_wvr(struct kvm_vcpu *vcpu,
|
|||
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
|
||||
|
||||
if (p->is_write)
|
||||
reg_to_dbg(vcpu, p, dbg_reg);
|
||||
reg_to_dbg(vcpu, p, rd, dbg_reg);
|
||||
else
|
||||
dbg_to_reg(vcpu, p, dbg_reg);
|
||||
dbg_to_reg(vcpu, p, rd, dbg_reg);
|
||||
|
||||
trace_trap_reg(__func__, rd->reg, p->is_write,
|
||||
vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]);
|
||||
|
@ -514,9 +526,9 @@ static bool trap_wcr(struct kvm_vcpu *vcpu,
|
|||
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
|
||||
|
||||
if (p->is_write)
|
||||
reg_to_dbg(vcpu, p, dbg_reg);
|
||||
reg_to_dbg(vcpu, p, rd, dbg_reg);
|
||||
else
|
||||
dbg_to_reg(vcpu, p, dbg_reg);
|
||||
dbg_to_reg(vcpu, p, rd, dbg_reg);
|
||||
|
||||
trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
|
||||
|
||||
|
@ -1246,10 +1258,6 @@ static bool access_csselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
|||
{
|
||||
int reg = r->reg;
|
||||
|
||||
/* See the 32bit mapping in kvm_host.h */
|
||||
if (p->is_aarch32)
|
||||
reg = r->reg / 2;
|
||||
|
||||
if (p->is_write)
|
||||
vcpu_write_sys_reg(vcpu, p->regval, reg);
|
||||
else
|
||||
|
@ -1720,66 +1728,27 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu,
|
|||
}
|
||||
}
|
||||
|
||||
static bool trap_debug32(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
vcpu_cp14(vcpu, r->reg) = p->regval;
|
||||
vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
|
||||
} else {
|
||||
p->regval = vcpu_cp14(vcpu, r->reg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* AArch32 debug register mappings
|
||||
/*
|
||||
* AArch32 debug register mappings
|
||||
*
|
||||
* AArch32 DBGBVRn is mapped to DBGBVRn_EL1[31:0]
|
||||
* AArch32 DBGBXVRn is mapped to DBGBVRn_EL1[63:32]
|
||||
*
|
||||
* All control registers and watchpoint value registers are mapped to
|
||||
* the lower 32 bits of their AArch64 equivalents. We share the trap
|
||||
* handlers with the above AArch64 code which checks what mode the
|
||||
* system is in.
|
||||
* None of the other registers share their location, so treat them as
|
||||
* if they were 64bit.
|
||||
*/
|
||||
|
||||
static bool trap_xvr(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
|
||||
|
||||
if (p->is_write) {
|
||||
u64 val = *dbg_reg;
|
||||
|
||||
val &= 0xffffffffUL;
|
||||
val |= p->regval << 32;
|
||||
*dbg_reg = val;
|
||||
|
||||
vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY;
|
||||
} else {
|
||||
p->regval = *dbg_reg >> 32;
|
||||
}
|
||||
|
||||
trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DBG_BCR_BVR_WCR_WVR(n) \
|
||||
/* DBGBVRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_bvr, NULL, n }, \
|
||||
/* DBGBCRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_bcr, NULL, n }, \
|
||||
/* DBGWVRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_wvr, NULL, n }, \
|
||||
/* DBGWCRn */ \
|
||||
#define DBG_BCR_BVR_WCR_WVR(n) \
|
||||
/* DBGBVRn */ \
|
||||
{ AA32(LO), Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_bvr, NULL, n }, \
|
||||
/* DBGBCRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_bcr, NULL, n }, \
|
||||
/* DBGWVRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_wvr, NULL, n }, \
|
||||
/* DBGWCRn */ \
|
||||
{ Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_wcr, NULL, n }
|
||||
|
||||
#define DBGBXVR(n) \
|
||||
{ Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_xvr, NULL, n }
|
||||
#define DBGBXVR(n) \
|
||||
{ AA32(HI), Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_bvr, NULL, n }
|
||||
|
||||
/*
|
||||
* Trapped cp14 registers. We generally ignore most of the external
|
||||
|
@ -1797,9 +1766,9 @@ static const struct sys_reg_desc cp14_regs[] = {
|
|||
{ Op1( 0), CRn( 0), CRm( 1), Op2( 0), trap_raz_wi },
|
||||
DBG_BCR_BVR_WCR_WVR(1),
|
||||
/* DBGDCCINT */
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32, NULL, cp14_DBGDCCINT },
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug_regs, NULL, MDCCINT_EL1 },
|
||||
/* DBGDSCRext */
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32, NULL, cp14_DBGDSCRext },
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug_regs, NULL, MDSCR_EL1 },
|
||||
DBG_BCR_BVR_WCR_WVR(2),
|
||||
/* DBGDTR[RT]Xint */
|
||||
{ Op1( 0), CRn( 0), CRm( 3), Op2( 0), trap_raz_wi },
|
||||
|
@ -1814,7 +1783,7 @@ static const struct sys_reg_desc cp14_regs[] = {
|
|||
{ Op1( 0), CRn( 0), CRm( 6), Op2( 2), trap_raz_wi },
|
||||
DBG_BCR_BVR_WCR_WVR(6),
|
||||
/* DBGVCR */
|
||||
{ Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32, NULL, cp14_DBGVCR },
|
||||
{ Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug_regs, NULL, DBGVCR32_EL2 },
|
||||
DBG_BCR_BVR_WCR_WVR(7),
|
||||
DBG_BCR_BVR_WCR_WVR(8),
|
||||
DBG_BCR_BVR_WCR_WVR(9),
|
||||
|
@ -1900,19 +1869,29 @@ static const struct sys_reg_desc cp14_64_regs[] = {
|
|||
*/
|
||||
static const struct sys_reg_desc cp15_regs[] = {
|
||||
{ Op1( 0), CRn( 0), CRm( 0), Op2( 1), access_ctr },
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, c1_SCTLR },
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 1), access_actlr },
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 3), access_actlr },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
|
||||
{ Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, c3_DACR },
|
||||
{ Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, c5_DFSR },
|
||||
{ Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, c5_IFSR },
|
||||
{ Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, c5_ADFSR },
|
||||
{ Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, c5_AIFSR },
|
||||
{ Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, c6_DFAR },
|
||||
{ Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, c6_IFAR },
|
||||
{ Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, SCTLR_EL1 },
|
||||
/* ACTLR */
|
||||
{ AA32(LO), Op1( 0), CRn( 1), CRm( 0), Op2( 1), access_actlr, NULL, ACTLR_EL1 },
|
||||
/* ACTLR2 */
|
||||
{ AA32(HI), Op1( 0), CRn( 1), CRm( 0), Op2( 3), access_actlr, NULL, ACTLR_EL1 },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, TTBR0_EL1 },
|
||||
{ Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, TTBR1_EL1 },
|
||||
/* TTBCR */
|
||||
{ AA32(LO), Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, TCR_EL1 },
|
||||
/* TTBCR2 */
|
||||
{ AA32(HI), Op1( 0), CRn( 2), CRm( 0), Op2( 3), access_vm_reg, NULL, TCR_EL1 },
|
||||
{ Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, DACR32_EL2 },
|
||||
/* DFSR */
|
||||
{ Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, ESR_EL1 },
|
||||
{ Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, IFSR32_EL2 },
|
||||
/* ADFSR */
|
||||
{ Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, AFSR0_EL1 },
|
||||
/* AIFSR */
|
||||
{ Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, AFSR1_EL1 },
|
||||
/* DFAR */
|
||||
{ AA32(LO), Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, FAR_EL1 },
|
||||
/* IFAR */
|
||||
{ AA32(HI), Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, FAR_EL1 },
|
||||
|
||||
/*
|
||||
* DC{C,I,CI}SW operations:
|
||||
|
@ -1938,15 +1917,19 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|||
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pminten },
|
||||
{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovs },
|
||||
|
||||
{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
|
||||
{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
|
||||
{ Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 },
|
||||
{ Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 },
|
||||
/* PRRR/MAIR0 */
|
||||
{ AA32(LO), Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, MAIR_EL1 },
|
||||
/* NMRR/MAIR1 */
|
||||
{ AA32(HI), Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, MAIR_EL1 },
|
||||
/* AMAIR0 */
|
||||
{ AA32(LO), Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, AMAIR_EL1 },
|
||||
/* AMAIR1 */
|
||||
{ AA32(HI), Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, AMAIR_EL1 },
|
||||
|
||||
/* ICC_SRE */
|
||||
{ Op1( 0), CRn(12), CRm(12), Op2( 5), access_gic_sre },
|
||||
|
||||
{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
|
||||
{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, CONTEXTIDR_EL1 },
|
||||
|
||||
/* Arch Tmers */
|
||||
{ SYS_DESC(SYS_AARCH32_CNTP_TVAL), access_arch_timer },
|
||||
|
@ -2021,14 +2004,14 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|||
|
||||
{ Op1(1), CRn( 0), CRm( 0), Op2(0), access_ccsidr },
|
||||
{ Op1(1), CRn( 0), CRm( 0), Op2(1), access_clidr },
|
||||
{ Op1(2), CRn( 0), CRm( 0), Op2(0), access_csselr, NULL, c0_CSSELR },
|
||||
{ Op1(2), CRn( 0), CRm( 0), Op2(0), access_csselr, NULL, CSSELR_EL1 },
|
||||
};
|
||||
|
||||
static const struct sys_reg_desc cp15_64_regs[] = {
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
|
||||
{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, TTBR0_EL1 },
|
||||
{ Op1( 0), CRn( 0), CRm( 9), Op2( 0), access_pmu_evcntr },
|
||||
{ Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI1R */
|
||||
{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
|
||||
{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, TTBR1_EL1 },
|
||||
{ Op1( 1), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_ASGI1R */
|
||||
{ Op1( 2), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI0R */
|
||||
{ SYS_DESC(SYS_AARCH32_CNTP_CVAL), access_arch_timer },
|
||||
|
@ -2172,8 +2155,6 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
|
|||
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
||||
int Rt2 = (esr >> 10) & 0x1f;
|
||||
|
||||
params.is_aarch32 = true;
|
||||
params.is_32bit = false;
|
||||
params.CRm = (esr >> 1) & 0xf;
|
||||
params.is_write = ((esr & 1) == 0);
|
||||
|
||||
|
@ -2223,8 +2204,6 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
|
|||
u32 esr = kvm_vcpu_get_esr(vcpu);
|
||||
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
||||
|
||||
params.is_aarch32 = true;
|
||||
params.is_32bit = true;
|
||||
params.CRm = (esr >> 1) & 0xf;
|
||||
params.regval = vcpu_get_reg(vcpu, Rt);
|
||||
params.is_write = ((esr & 1) == 0);
|
||||
|
@ -2318,8 +2297,6 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)
|
|||
|
||||
trace_kvm_handle_sys_reg(esr);
|
||||
|
||||
params.is_aarch32 = false;
|
||||
params.is_32bit = false;
|
||||
params.Op0 = (esr >> 20) & 3;
|
||||
params.Op1 = (esr >> 14) & 0x7;
|
||||
params.CRn = (esr >> 10) & 0xf;
|
||||
|
|
|
@ -19,14 +19,18 @@ struct sys_reg_params {
|
|||
u8 Op2;
|
||||
u64 regval;
|
||||
bool is_write;
|
||||
bool is_aarch32;
|
||||
bool is_32bit; /* Only valid if is_aarch32 is true */
|
||||
};
|
||||
|
||||
struct sys_reg_desc {
|
||||
/* Sysreg string for debug */
|
||||
const char *name;
|
||||
|
||||
enum {
|
||||
AA32_ZEROHIGH,
|
||||
AA32_LO,
|
||||
AA32_HI,
|
||||
} aarch32_map;
|
||||
|
||||
/* MRS/MSR instruction which accesses it. */
|
||||
u8 Op0;
|
||||
u8 Op1;
|
||||
|
@ -153,6 +157,7 @@ const struct sys_reg_desc *find_reg_by_id(u64 id,
|
|||
const struct sys_reg_desc table[],
|
||||
unsigned int num);
|
||||
|
||||
#define AA32(_x) .aarch32_map = AA32_##_x
|
||||
#define Op0(_x) .Op0 = _x
|
||||
#define Op1(_x) .Op1 = _x
|
||||
#define CRn(_x) .CRn = _x
|
||||
|
|
|
@ -268,8 +268,6 @@ int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id,
|
|||
|
||||
params.regval = *reg;
|
||||
params.is_write = is_write;
|
||||
params.is_aarch32 = false;
|
||||
params.is_32bit = false;
|
||||
|
||||
if (find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs,
|
||||
ARRAY_SIZE(gic_v3_icc_reg_descs)))
|
||||
|
@ -288,8 +286,6 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id,
|
|||
if (is_write)
|
||||
params.regval = *reg;
|
||||
params.is_write = is_write;
|
||||
params.is_aarch32 = false;
|
||||
params.is_32bit = false;
|
||||
|
||||
r = find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs,
|
||||
ARRAY_SIZE(gic_v3_icc_reg_descs));
|
||||
|
|
Загрузка…
Ссылка в новой задаче