@@ -2196,16 +2196,6 @@ static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
2196
2196
* guest...
2197
2197
*/
2198
2198
static const struct sys_reg_desc sys_reg_descs [] = {
2199
- { SYS_DESC (SYS_DC_ISW ), access_dcsw },
2200
- { SYS_DESC (SYS_DC_IGSW ), access_dcgsw },
2201
- { SYS_DESC (SYS_DC_IGDSW ), access_dcgsw },
2202
- { SYS_DESC (SYS_DC_CSW ), access_dcsw },
2203
- { SYS_DESC (SYS_DC_CGSW ), access_dcgsw },
2204
- { SYS_DESC (SYS_DC_CGDSW ), access_dcgsw },
2205
- { SYS_DESC (SYS_DC_CISW ), access_dcsw },
2206
- { SYS_DESC (SYS_DC_CIGSW ), access_dcgsw },
2207
- { SYS_DESC (SYS_DC_CIGDSW ), access_dcgsw },
2208
-
2209
2199
DBG_BCR_BVR_WCR_WVR_EL1 (0 ),
2210
2200
DBG_BCR_BVR_WCR_WVR_EL1 (1 ),
2211
2201
{ SYS_DESC (SYS_MDCCINT_EL1 ), trap_debug_regs , reset_val , MDCCINT_EL1 , 0 },
@@ -2737,6 +2727,18 @@ static const struct sys_reg_desc sys_reg_descs[] = {
2737
2727
EL2_REG (SP_EL2 , NULL , reset_unknown , 0 ),
2738
2728
};
2739
2729
2730
+ static struct sys_reg_desc sys_insn_descs [] = {
2731
+ { SYS_DESC (SYS_DC_ISW ), access_dcsw },
2732
+ { SYS_DESC (SYS_DC_IGSW ), access_dcgsw },
2733
+ { SYS_DESC (SYS_DC_IGDSW ), access_dcgsw },
2734
+ { SYS_DESC (SYS_DC_CSW ), access_dcsw },
2735
+ { SYS_DESC (SYS_DC_CGSW ), access_dcgsw },
2736
+ { SYS_DESC (SYS_DC_CGDSW ), access_dcgsw },
2737
+ { SYS_DESC (SYS_DC_CISW ), access_dcsw },
2738
+ { SYS_DESC (SYS_DC_CIGSW ), access_dcgsw },
2739
+ { SYS_DESC (SYS_DC_CIGDSW ), access_dcgsw },
2740
+ };
2741
+
2740
2742
static const struct sys_reg_desc * first_idreg ;
2741
2743
2742
2744
static bool trap_dbgdidr (struct kvm_vcpu * vcpu ,
@@ -3429,6 +3431,24 @@ static bool emulate_sys_reg(struct kvm_vcpu *vcpu,
3429
3431
return false;
3430
3432
}
3431
3433
3434
+ static int emulate_sys_instr (struct kvm_vcpu * vcpu , struct sys_reg_params * p )
3435
+ {
3436
+ const struct sys_reg_desc * r ;
3437
+
3438
+ /* Search from the system instruction table. */
3439
+ r = find_reg (p , sys_insn_descs , ARRAY_SIZE (sys_insn_descs ));
3440
+
3441
+ if (likely (r )) {
3442
+ perform_access (vcpu , p , r );
3443
+ } else {
3444
+ kvm_err ("Unsupported guest sys instruction at: %lx\n" ,
3445
+ * vcpu_pc (vcpu ));
3446
+ print_sys_reg_instr (p );
3447
+ kvm_inject_undefined (vcpu );
3448
+ }
3449
+ return 1 ;
3450
+ }
3451
+
3432
3452
static void kvm_reset_id_regs (struct kvm_vcpu * vcpu )
3433
3453
{
3434
3454
const struct sys_reg_desc * idreg = first_idreg ;
@@ -3476,7 +3496,8 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
3476
3496
}
3477
3497
3478
3498
/**
3479
- * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access
3499
+ * kvm_handle_sys_reg -- handles a system instruction or mrs/msr instruction
3500
+ * trap on a guest execution
3480
3501
* @vcpu: The VCPU pointer
3481
3502
*/
3482
3503
int kvm_handle_sys_reg (struct kvm_vcpu * vcpu )
@@ -3493,12 +3514,19 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)
3493
3514
params = esr_sys64_to_params (esr );
3494
3515
params .regval = vcpu_get_reg (vcpu , Rt );
3495
3516
3496
- if (!emulate_sys_reg (vcpu , & params ))
3517
+ /* System registers have Op0=={2,3}, as per DDI487 J.a C5.1.2 */
3518
+ if (params .Op0 == 2 || params .Op0 == 3 ) {
3519
+ if (!emulate_sys_reg (vcpu , & params ))
3520
+ return 1 ;
3521
+
3522
+ if (!params .is_write )
3523
+ vcpu_set_reg (vcpu , Rt , params .regval );
3524
+
3497
3525
return 1 ;
3526
+ }
3498
3527
3499
- if (!params .is_write )
3500
- vcpu_set_reg (vcpu , Rt , params .regval );
3501
- return 1 ;
3528
+ /* Hints, PSTATE (Op0 == 0) and System instructions (Op0 == 1) */
3529
+ return emulate_sys_instr (vcpu , & params );
3502
3530
}
3503
3531
3504
3532
/******************************************************************************
@@ -3952,6 +3980,7 @@ int __init kvm_sys_reg_table_init(void)
3952
3980
valid &= check_sysreg_table (cp15_regs , ARRAY_SIZE (cp15_regs ), true);
3953
3981
valid &= check_sysreg_table (cp15_64_regs , ARRAY_SIZE (cp15_64_regs ), true);
3954
3982
valid &= check_sysreg_table (invariant_sys_regs , ARRAY_SIZE (invariant_sys_regs ), false);
3983
+ valid &= check_sysreg_table (sys_insn_descs , ARRAY_SIZE (sys_insn_descs ), false);
3955
3984
3956
3985
if (!valid )
3957
3986
return - EINVAL ;
0 commit comments