|
|
|
|
@@ -2023,20 +2023,22 @@ static const struct sys_reg_desc cp14_64_regs[] = {
|
|
|
|
|
{ Op1( 0), CRm( 2), .access = trap_raz_wi },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define CP15_PMU_SYS_REG(_map, _Op1, _CRn, _CRm, _Op2) \
|
|
|
|
|
AA32(_map), \
|
|
|
|
|
Op1(_Op1), CRn(_CRn), CRm(_CRm), Op2(_Op2), \
|
|
|
|
|
.visibility = pmu_visibility
|
|
|
|
|
|
|
|
|
|
/* Macro to expand the PMEVCNTRn register */
|
|
|
|
|
#define PMU_PMEVCNTR(n) \
|
|
|
|
|
/* PMEVCNTRn */ \
|
|
|
|
|
{ Op1(0), CRn(0b1110), \
|
|
|
|
|
CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
|
|
|
|
|
access_pmu_evcntr }
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 0b1110, \
|
|
|
|
|
(0b1000 | (((n) >> 3) & 0x3)), ((n) & 0x7)), \
|
|
|
|
|
.access = access_pmu_evcntr }
|
|
|
|
|
|
|
|
|
|
/* Macro to expand the PMEVTYPERn register */
|
|
|
|
|
#define PMU_PMEVTYPER(n) \
|
|
|
|
|
/* PMEVTYPERn */ \
|
|
|
|
|
{ Op1(0), CRn(0b1110), \
|
|
|
|
|
CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
|
|
|
|
|
access_pmu_evtyper }
|
|
|
|
|
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 0b1110, \
|
|
|
|
|
(0b1100 | (((n) >> 3) & 0x3)), ((n) & 0x7)), \
|
|
|
|
|
.access = access_pmu_evtyper }
|
|
|
|
|
/*
|
|
|
|
|
* Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
|
|
|
|
|
* depending on the way they are accessed (as a 32bit or a 64bit
|
|
|
|
|
@@ -2076,25 +2078,25 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|
|
|
|
{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
|
|
|
|
|
|
|
|
|
|
/* PMU */
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcnten },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcnten },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovs },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
|
|
|
|
|
{ AA32(LO), Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
|
|
|
|
|
{ AA32(LO), Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(14), Op2( 0), access_pmuserenr },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pminten },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pminten },
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovs },
|
|
|
|
|
{ AA32(HI), Op1( 0), CRn( 9), CRm(14), Op2( 4), access_pmceid },
|
|
|
|
|
{ AA32(HI), Op1( 0), CRn( 9), CRm(14), Op2( 5), access_pmceid },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 0), .access = access_pmcr },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 1), .access = access_pmcnten },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 2), .access = access_pmcnten },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 3), .access = access_pmovs },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 4), .access = access_pmswinc },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 5), .access = access_pmselr },
|
|
|
|
|
{ CP15_PMU_SYS_REG(LO, 0, 9, 12, 6), .access = access_pmceid },
|
|
|
|
|
{ CP15_PMU_SYS_REG(LO, 0, 9, 12, 7), .access = access_pmceid },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 13, 0), .access = access_pmu_evcntr },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 13, 1), .access = access_pmu_evtyper },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 13, 2), .access = access_pmu_evcntr },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 0), .access = access_pmuserenr },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 1), .access = access_pminten },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 2), .access = access_pminten },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 3), .access = access_pmovs },
|
|
|
|
|
{ CP15_PMU_SYS_REG(HI, 0, 9, 14, 4), .access = access_pmceid },
|
|
|
|
|
{ CP15_PMU_SYS_REG(HI, 0, 9, 14, 5), .access = access_pmceid },
|
|
|
|
|
/* PMMIR */
|
|
|
|
|
{ Op1( 0), CRn( 9), CRm(14), Op2( 6), trap_raz_wi },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 6), .access = trap_raz_wi },
|
|
|
|
|
|
|
|
|
|
/* PRRR/MAIR0 */
|
|
|
|
|
{ AA32(LO), Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, MAIR_EL1 },
|
|
|
|
|
@@ -2179,7 +2181,7 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|
|
|
|
PMU_PMEVTYPER(29),
|
|
|
|
|
PMU_PMEVTYPER(30),
|
|
|
|
|
/* PMCCFILTR */
|
|
|
|
|
{ Op1(0), CRn(14), CRm(15), Op2(7), access_pmu_evtyper },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 14, 15, 7), .access = access_pmu_evtyper },
|
|
|
|
|
|
|
|
|
|
{ Op1(1), CRn( 0), CRm( 0), Op2(0), access_ccsidr },
|
|
|
|
|
{ Op1(1), CRn( 0), CRm( 0), Op2(1), access_clidr },
|
|
|
|
|
@@ -2188,7 +2190,7 @@ static const struct sys_reg_desc cp15_regs[] = {
|
|
|
|
|
|
|
|
|
|
static const struct sys_reg_desc cp15_64_regs[] = {
|
|
|
|
|
{ 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 },
|
|
|
|
|
{ CP15_PMU_SYS_REG(DIRECT, 0, 0, 9, 0), .access = 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, TTBR1_EL1 },
|
|
|
|
|
{ Op1( 1), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_ASGI1R */
|
|
|
|
|
@@ -2255,27 +2257,27 @@ static void perform_access(struct kvm_vcpu *vcpu,
|
|
|
|
|
* @table: array of trap descriptors
|
|
|
|
|
* @num: size of the trap descriptor array
|
|
|
|
|
*
|
|
|
|
|
* Return 0 if the access has been handled, and -1 if not.
|
|
|
|
|
* Return true if the access has been handled, false if not.
|
|
|
|
|
*/
|
|
|
|
|
static int emulate_cp(struct kvm_vcpu *vcpu,
|
|
|
|
|
struct sys_reg_params *params,
|
|
|
|
|
const struct sys_reg_desc *table,
|
|
|
|
|
size_t num)
|
|
|
|
|
static bool emulate_cp(struct kvm_vcpu *vcpu,
|
|
|
|
|
struct sys_reg_params *params,
|
|
|
|
|
const struct sys_reg_desc *table,
|
|
|
|
|
size_t num)
|
|
|
|
|
{
|
|
|
|
|
const struct sys_reg_desc *r;
|
|
|
|
|
|
|
|
|
|
if (!table)
|
|
|
|
|
return -1; /* Not handled */
|
|
|
|
|
return false; /* Not handled */
|
|
|
|
|
|
|
|
|
|
r = find_reg(params, table, num);
|
|
|
|
|
|
|
|
|
|
if (r) {
|
|
|
|
|
perform_access(vcpu, params, r);
|
|
|
|
|
return 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Not handled */
|
|
|
|
|
return -1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void unhandled_cp_access(struct kvm_vcpu *vcpu,
|
|
|
|
|
@@ -2313,7 +2315,7 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
|
|
|
|
|
size_t nr_global)
|
|
|
|
|
{
|
|
|
|
|
struct sys_reg_params params;
|
|
|
|
|
u32 esr = kvm_vcpu_get_esr(vcpu);
|
|
|
|
|
u64 esr = kvm_vcpu_get_esr(vcpu);
|
|
|
|
|
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
|
|
|
|
int Rt2 = (esr >> 10) & 0x1f;
|
|
|
|
|
|
|
|
|
|
@@ -2339,7 +2341,7 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
|
|
|
|
|
* potential register operation in the case of a read and return
|
|
|
|
|
* with success.
|
|
|
|
|
*/
|
|
|
|
|
if (!emulate_cp(vcpu, ¶ms, global, nr_global)) {
|
|
|
|
|
if (emulate_cp(vcpu, ¶ms, global, nr_global)) {
|
|
|
|
|
/* Split up the value between registers for the read side */
|
|
|
|
|
if (!params.is_write) {
|
|
|
|
|
vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval));
|
|
|
|
|
@@ -2353,34 +2355,144 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool emulate_sys_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *params);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The CP10 ID registers are architecturally mapped to AArch64 feature
|
|
|
|
|
* registers. Abuse that fact so we can rely on the AArch64 handler for accesses
|
|
|
|
|
* from AArch32.
|
|
|
|
|
*/
|
|
|
|
|
static bool kvm_esr_cp10_id_to_sys64(u64 esr, struct sys_reg_params *params)
|
|
|
|
|
{
|
|
|
|
|
u8 reg_id = (esr >> 10) & 0xf;
|
|
|
|
|
bool valid;
|
|
|
|
|
|
|
|
|
|
params->is_write = ((esr & 1) == 0);
|
|
|
|
|
params->Op0 = 3;
|
|
|
|
|
params->Op1 = 0;
|
|
|
|
|
params->CRn = 0;
|
|
|
|
|
params->CRm = 3;
|
|
|
|
|
|
|
|
|
|
/* CP10 ID registers are read-only */
|
|
|
|
|
valid = !params->is_write;
|
|
|
|
|
|
|
|
|
|
switch (reg_id) {
|
|
|
|
|
/* MVFR0 */
|
|
|
|
|
case 0b0111:
|
|
|
|
|
params->Op2 = 0;
|
|
|
|
|
break;
|
|
|
|
|
/* MVFR1 */
|
|
|
|
|
case 0b0110:
|
|
|
|
|
params->Op2 = 1;
|
|
|
|
|
break;
|
|
|
|
|
/* MVFR2 */
|
|
|
|
|
case 0b0101:
|
|
|
|
|
params->Op2 = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
valid = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (valid)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
kvm_pr_unimpl("Unhandled cp10 register %s: %u\n",
|
|
|
|
|
params->is_write ? "write" : "read", reg_id);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* kvm_handle_cp10_id() - Handles a VMRS trap on guest access to a 'Media and
|
|
|
|
|
* VFP Register' from AArch32.
|
|
|
|
|
* @vcpu: The vCPU pointer
|
|
|
|
|
*
|
|
|
|
|
* MVFR{0-2} are architecturally mapped to the AArch64 MVFR{0-2}_EL1 registers.
|
|
|
|
|
* Work out the correct AArch64 system register encoding and reroute to the
|
|
|
|
|
* AArch64 system register emulation.
|
|
|
|
|
*/
|
|
|
|
|
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu)
|
|
|
|
|
{
|
|
|
|
|
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
|
|
|
|
u64 esr = kvm_vcpu_get_esr(vcpu);
|
|
|
|
|
struct sys_reg_params params;
|
|
|
|
|
|
|
|
|
|
/* UNDEF on any unhandled register access */
|
|
|
|
|
if (!kvm_esr_cp10_id_to_sys64(esr, ¶ms)) {
|
|
|
|
|
kvm_inject_undefined(vcpu);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (emulate_sys_reg(vcpu, ¶ms))
|
|
|
|
|
vcpu_set_reg(vcpu, Rt, params.regval);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* kvm_emulate_cp15_id_reg() - Handles an MRC trap on a guest CP15 access where
|
|
|
|
|
* CRn=0, which corresponds to the AArch32 feature
|
|
|
|
|
* registers.
|
|
|
|
|
* @vcpu: the vCPU pointer
|
|
|
|
|
* @params: the system register access parameters.
|
|
|
|
|
*
|
|
|
|
|
* Our cp15 system register tables do not enumerate the AArch32 feature
|
|
|
|
|
* registers. Conveniently, our AArch64 table does, and the AArch32 system
|
|
|
|
|
* register encoding can be trivially remapped into the AArch64 for the feature
|
|
|
|
|
* registers: Append op0=3, leaving op1, CRn, CRm, and op2 the same.
|
|
|
|
|
*
|
|
|
|
|
* According to DDI0487G.b G7.3.1, paragraph "Behavior of VMSAv8-32 32-bit
|
|
|
|
|
* System registers with (coproc=0b1111, CRn==c0)", read accesses from this
|
|
|
|
|
* range are either UNKNOWN or RES0. Rerouting remains architectural as we
|
|
|
|
|
* treat undefined registers in this range as RAZ.
|
|
|
|
|
*/
|
|
|
|
|
static int kvm_emulate_cp15_id_reg(struct kvm_vcpu *vcpu,
|
|
|
|
|
struct sys_reg_params *params)
|
|
|
|
|
{
|
|
|
|
|
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
|
|
|
|
|
|
|
|
|
/* Treat impossible writes to RO registers as UNDEFINED */
|
|
|
|
|
if (params->is_write) {
|
|
|
|
|
unhandled_cp_access(vcpu, params);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
params->Op0 = 3;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* All registers where CRm > 3 are known to be UNKNOWN/RAZ from AArch32.
|
|
|
|
|
* Avoid conflicting with future expansion of AArch64 feature registers
|
|
|
|
|
* and simply treat them as RAZ here.
|
|
|
|
|
*/
|
|
|
|
|
if (params->CRm > 3)
|
|
|
|
|
params->regval = 0;
|
|
|
|
|
else if (!emulate_sys_reg(vcpu, params))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
vcpu_set_reg(vcpu, Rt, params->regval);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* kvm_handle_cp_32 -- handles a mrc/mcr trap on a guest CP14/CP15 access
|
|
|
|
|
* @vcpu: The VCPU pointer
|
|
|
|
|
* @run: The kvm_run struct
|
|
|
|
|
*/
|
|
|
|
|
static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
|
|
|
|
|
struct sys_reg_params *params,
|
|
|
|
|
const struct sys_reg_desc *global,
|
|
|
|
|
size_t nr_global)
|
|
|
|
|
{
|
|
|
|
|
struct sys_reg_params params;
|
|
|
|
|
u32 esr = kvm_vcpu_get_esr(vcpu);
|
|
|
|
|
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
|
|
|
|
|
|
|
|
|
params.CRm = (esr >> 1) & 0xf;
|
|
|
|
|
params.regval = vcpu_get_reg(vcpu, Rt);
|
|
|
|
|
params.is_write = ((esr & 1) == 0);
|
|
|
|
|
params.CRn = (esr >> 10) & 0xf;
|
|
|
|
|
params.Op0 = 0;
|
|
|
|
|
params.Op1 = (esr >> 14) & 0x7;
|
|
|
|
|
params.Op2 = (esr >> 17) & 0x7;
|
|
|
|
|
params->regval = vcpu_get_reg(vcpu, Rt);
|
|
|
|
|
|
|
|
|
|
if (!emulate_cp(vcpu, ¶ms, global, nr_global)) {
|
|
|
|
|
if (!params.is_write)
|
|
|
|
|
vcpu_set_reg(vcpu, Rt, params.regval);
|
|
|
|
|
if (emulate_cp(vcpu, params, global, nr_global)) {
|
|
|
|
|
if (!params->is_write)
|
|
|
|
|
vcpu_set_reg(vcpu, Rt, params->regval);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unhandled_cp_access(vcpu, ¶ms);
|
|
|
|
|
unhandled_cp_access(vcpu, params);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2391,7 +2503,20 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
|
|
|
|
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu)
|
|
|
|
|
{
|
|
|
|
|
return kvm_handle_cp_32(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs));
|
|
|
|
|
struct sys_reg_params params;
|
|
|
|
|
|
|
|
|
|
params = esr_cp1x_32_to_params(kvm_vcpu_get_esr(vcpu));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Certain AArch32 ID registers are handled by rerouting to the AArch64
|
|
|
|
|
* system register table. Registers in the ID range where CRm=0 are
|
|
|
|
|
* excluded from this scheme as they do not trivially map into AArch64
|
|
|
|
|
* system register encodings.
|
|
|
|
|
*/
|
|
|
|
|
if (params.Op1 == 0 && params.CRn == 0 && params.CRm)
|
|
|
|
|
return kvm_emulate_cp15_id_reg(vcpu, ¶ms);
|
|
|
|
|
|
|
|
|
|
return kvm_handle_cp_32(vcpu, ¶ms, cp15_regs, ARRAY_SIZE(cp15_regs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int kvm_handle_cp14_64(struct kvm_vcpu *vcpu)
|
|
|
|
|
@@ -2401,7 +2526,11 @@ int kvm_handle_cp14_64(struct kvm_vcpu *vcpu)
|
|
|
|
|
|
|
|
|
|
int kvm_handle_cp14_32(struct kvm_vcpu *vcpu)
|
|
|
|
|
{
|
|
|
|
|
return kvm_handle_cp_32(vcpu, cp14_regs, ARRAY_SIZE(cp14_regs));
|
|
|
|
|
struct sys_reg_params params;
|
|
|
|
|
|
|
|
|
|
params = esr_cp1x_32_to_params(kvm_vcpu_get_esr(vcpu));
|
|
|
|
|
|
|
|
|
|
return kvm_handle_cp_32(vcpu, ¶ms, cp14_regs, ARRAY_SIZE(cp14_regs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool is_imp_def_sys_reg(struct sys_reg_params *params)
|
|
|
|
|
@@ -2410,7 +2539,14 @@ static bool is_imp_def_sys_reg(struct sys_reg_params *params)
|
|
|
|
|
return params->Op0 == 3 && (params->CRn & 0b1011) == 0b1011;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int emulate_sys_reg(struct kvm_vcpu *vcpu,
|
|
|
|
|
/**
|
|
|
|
|
* emulate_sys_reg - Emulate a guest access to an AArch64 system register
|
|
|
|
|
* @vcpu: The VCPU pointer
|
|
|
|
|
* @params: Decoded system register parameters
|
|
|
|
|
*
|
|
|
|
|
* Return: true if the system register access was successful, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
static bool emulate_sys_reg(struct kvm_vcpu *vcpu,
|
|
|
|
|
struct sys_reg_params *params)
|
|
|
|
|
{
|
|
|
|
|
const struct sys_reg_desc *r;
|
|
|
|
|
@@ -2419,7 +2555,10 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
|
|
|
|
|
|
|
|
|
|
if (likely(r)) {
|
|
|
|
|
perform_access(vcpu, params, r);
|
|
|
|
|
} else if (is_imp_def_sys_reg(params)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_imp_def_sys_reg(params)) {
|
|
|
|
|
kvm_inject_undefined(vcpu);
|
|
|
|
|
} else {
|
|
|
|
|
print_sys_reg_msg(params,
|
|
|
|
|
@@ -2427,7 +2566,7 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
|
|
|
|
|
*vcpu_pc(vcpu), *vcpu_cpsr(vcpu));
|
|
|
|
|
kvm_inject_undefined(vcpu);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -2455,18 +2594,18 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)
|
|
|
|
|
struct sys_reg_params params;
|
|
|
|
|
unsigned long esr = kvm_vcpu_get_esr(vcpu);
|
|
|
|
|
int Rt = kvm_vcpu_sys_get_rt(vcpu);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
trace_kvm_handle_sys_reg(esr);
|
|
|
|
|
|
|
|
|
|
params = esr_sys64_to_params(esr);
|
|
|
|
|
params.regval = vcpu_get_reg(vcpu, Rt);
|
|
|
|
|
|
|
|
|
|
ret = emulate_sys_reg(vcpu, ¶ms);
|
|
|
|
|
if (!emulate_sys_reg(vcpu, ¶ms))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (!params.is_write)
|
|
|
|
|
vcpu_set_reg(vcpu, Rt, params.regval);
|
|
|
|
|
return ret;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
|