diff options
| -rw-r--r-- | arch/arm64/kvm/sys_regs.c | 87 | ||||
| -rw-r--r-- | arch/arm64/kvm/sys_regs.h | 4 | ||||
| -rw-r--r-- | arch/arm64/kvm/sys_regs_generic_v8.c | 2 |
3 files changed, 45 insertions, 48 deletions
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 545a72ae8b01..d2650e84faf2 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c | |||
| @@ -97,18 +97,16 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, | |||
| 97 | struct sys_reg_params *p, | 97 | struct sys_reg_params *p, |
| 98 | const struct sys_reg_desc *r) | 98 | const struct sys_reg_desc *r) |
| 99 | { | 99 | { |
| 100 | unsigned long val; | ||
| 101 | bool was_enabled = vcpu_has_cache_enabled(vcpu); | 100 | bool was_enabled = vcpu_has_cache_enabled(vcpu); |
| 102 | 101 | ||
| 103 | BUG_ON(!p->is_write); | 102 | BUG_ON(!p->is_write); |
| 104 | 103 | ||
| 105 | val = *vcpu_reg(vcpu, p->Rt); | ||
| 106 | if (!p->is_aarch32) { | 104 | if (!p->is_aarch32) { |
| 107 | vcpu_sys_reg(vcpu, r->reg) = val; | 105 | vcpu_sys_reg(vcpu, r->reg) = p->regval; |
| 108 | } else { | 106 | } else { |
| 109 | if (!p->is_32bit) | 107 | if (!p->is_32bit) |
| 110 | vcpu_cp15_64_high(vcpu, r->reg) = val >> 32; | 108 | vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval); |
| 111 | vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL; | 109 | vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval); |
| 112 | } | 110 | } |
| 113 | 111 | ||
| 114 | kvm_toggle_cache(vcpu, was_enabled); | 112 | kvm_toggle_cache(vcpu, was_enabled); |
| @@ -125,13 +123,10 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu, | |||
| 125 | struct sys_reg_params *p, | 123 | struct sys_reg_params *p, |
| 126 | const struct sys_reg_desc *r) | 124 | const struct sys_reg_desc *r) |
| 127 | { | 125 | { |
| 128 | u64 val; | ||
| 129 | |||
| 130 | if (!p->is_write) | 126 | if (!p->is_write) |
| 131 | return read_from_write_only(vcpu, p); | 127 | return read_from_write_only(vcpu, p); |
| 132 | 128 | ||
| 133 | val = *vcpu_reg(vcpu, p->Rt); | 129 | vgic_v3_dispatch_sgi(vcpu, p->regval); |
| 134 | vgic_v3_dispatch_sgi(vcpu, val); | ||
| 135 | 130 | ||
| 136 | return true; | 131 | return true; |
| 137 | } | 132 | } |
| @@ -153,7 +148,7 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu, | |||
| 153 | if (p->is_write) { | 148 | if (p->is_write) { |
| 154 | return ignore_write(vcpu, p); | 149 | return ignore_write(vcpu, p); |
| 155 | } else { | 150 | } else { |
| 156 | *vcpu_reg(vcpu, p->Rt) = (1 << 3); | 151 | p->regval = (1 << 3); |
| 157 | return true; | 152 | return true; |
| 158 | } | 153 | } |
| 159 | } | 154 | } |
| @@ -167,7 +162,7 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, | |||
| 167 | } else { | 162 | } else { |
| 168 | u32 val; | 163 | u32 val; |
| 169 | asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val)); | 164 | asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val)); |
| 170 | *vcpu_reg(vcpu, p->Rt) = val; | 165 | p->regval = val; |
| 171 | return true; | 166 | return true; |
| 172 | } | 167 | } |
| 173 | } | 168 | } |
| @@ -204,13 +199,13 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, | |||
| 204 | const struct sys_reg_desc *r) | 199 | const struct sys_reg_desc *r) |
| 205 | { | 200 | { |
| 206 | if (p->is_write) { | 201 | if (p->is_write) { |
| 207 | vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt); | 202 | vcpu_sys_reg(vcpu, r->reg) = p->regval; |
| 208 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | 203 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; |
| 209 | } else { | 204 | } else { |
| 210 | *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg); | 205 | p->regval = vcpu_sys_reg(vcpu, r->reg); |
| 211 | } | 206 | } |
| 212 | 207 | ||
| 213 | trace_trap_reg(__func__, r->reg, p->is_write, *vcpu_reg(vcpu, p->Rt)); | 208 | trace_trap_reg(__func__, r->reg, p->is_write, p->regval); |
| 214 | 209 | ||
| 215 | return true; | 210 | return true; |
| 216 | } | 211 | } |
| @@ -228,7 +223,7 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu, | |||
| 228 | struct sys_reg_params *p, | 223 | struct sys_reg_params *p, |
| 229 | u64 *dbg_reg) | 224 | u64 *dbg_reg) |
| 230 | { | 225 | { |
| 231 | u64 val = *vcpu_reg(vcpu, p->Rt); | 226 | u64 val = p->regval; |
| 232 | 227 | ||
| 233 | if (p->is_32bit) { | 228 | if (p->is_32bit) { |
| 234 | val &= 0xffffffffUL; | 229 | val &= 0xffffffffUL; |
| @@ -243,12 +238,9 @@ static inline void dbg_to_reg(struct kvm_vcpu *vcpu, | |||
| 243 | struct sys_reg_params *p, | 238 | struct sys_reg_params *p, |
| 244 | u64 *dbg_reg) | 239 | u64 *dbg_reg) |
| 245 | { | 240 | { |
| 246 | u64 val = *dbg_reg; | 241 | p->regval = *dbg_reg; |
| 247 | |||
| 248 | if (p->is_32bit) | 242 | if (p->is_32bit) |
| 249 | val &= 0xffffffffUL; | 243 | p->regval &= 0xffffffffUL; |
| 250 | |||
| 251 | *vcpu_reg(vcpu, p->Rt) = val; | ||
| 252 | } | 244 | } |
| 253 | 245 | ||
| 254 | static inline bool trap_bvr(struct kvm_vcpu *vcpu, | 246 | static inline bool trap_bvr(struct kvm_vcpu *vcpu, |
| @@ -697,10 +689,10 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu, | |||
| 697 | u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1); | 689 | u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1); |
| 698 | u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT); | 690 | u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT); |
| 699 | 691 | ||
| 700 | *vcpu_reg(vcpu, p->Rt) = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | | 692 | p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | |
| 701 | (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | | 693 | (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | |
| 702 | (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) | | 694 | (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) |
| 703 | (6 << 16) | (el3 << 14) | (el3 << 12)); | 695 | | (6 << 16) | (el3 << 14) | (el3 << 12)); |
| 704 | return true; | 696 | return true; |
| 705 | } | 697 | } |
| 706 | } | 698 | } |
| @@ -710,10 +702,10 @@ static bool trap_debug32(struct kvm_vcpu *vcpu, | |||
| 710 | const struct sys_reg_desc *r) | 702 | const struct sys_reg_desc *r) |
| 711 | { | 703 | { |
| 712 | if (p->is_write) { | 704 | if (p->is_write) { |
| 713 | vcpu_cp14(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt); | 705 | vcpu_cp14(vcpu, r->reg) = p->regval; |
| 714 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | 706 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; |
| 715 | } else { | 707 | } else { |
| 716 | *vcpu_reg(vcpu, p->Rt) = vcpu_cp14(vcpu, r->reg); | 708 | p->regval = vcpu_cp14(vcpu, r->reg); |
| 717 | } | 709 | } |
| 718 | 710 | ||
| 719 | return true; | 711 | return true; |
| @@ -740,12 +732,12 @@ static inline bool trap_xvr(struct kvm_vcpu *vcpu, | |||
| 740 | u64 val = *dbg_reg; | 732 | u64 val = *dbg_reg; |
| 741 | 733 | ||
| 742 | val &= 0xffffffffUL; | 734 | val &= 0xffffffffUL; |
| 743 | val |= *vcpu_reg(vcpu, p->Rt) << 32; | 735 | val |= p->regval << 32; |
| 744 | *dbg_reg = val; | 736 | *dbg_reg = val; |
| 745 | 737 | ||
| 746 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; | 738 | vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; |
| 747 | } else { | 739 | } else { |
| 748 | *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32; | 740 | p->regval = *dbg_reg >> 32; |
| 749 | } | 741 | } |
| 750 | 742 | ||
| 751 | trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); | 743 | trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); |
| @@ -1062,12 +1054,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, | |||
| 1062 | { | 1054 | { |
| 1063 | struct sys_reg_params params; | 1055 | struct sys_reg_params params; |
| 1064 | u32 hsr = kvm_vcpu_get_hsr(vcpu); | 1056 | u32 hsr = kvm_vcpu_get_hsr(vcpu); |
| 1057 | int Rt = (hsr >> 5) & 0xf; | ||
| 1065 | int Rt2 = (hsr >> 10) & 0xf; | 1058 | int Rt2 = (hsr >> 10) & 0xf; |
| 1066 | 1059 | ||
| 1067 | params.is_aarch32 = true; | 1060 | params.is_aarch32 = true; |
| 1068 | params.is_32bit = false; | 1061 | params.is_32bit = false; |
| 1069 | params.CRm = (hsr >> 1) & 0xf; | 1062 | params.CRm = (hsr >> 1) & 0xf; |
| 1070 | params.Rt = (hsr >> 5) & 0xf; | ||
| 1071 | params.is_write = ((hsr & 1) == 0); | 1063 | params.is_write = ((hsr & 1) == 0); |
| 1072 | 1064 | ||
| 1073 | params.Op0 = 0; | 1065 | params.Op0 = 0; |
| @@ -1076,15 +1068,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, | |||
| 1076 | params.CRn = 0; | 1068 | params.CRn = 0; |
| 1077 | 1069 | ||
| 1078 | /* | 1070 | /* |
| 1079 | * Massive hack here. Store Rt2 in the top 32bits so we only | 1071 | * Make a 64-bit value out of Rt and Rt2. As we use the same trap |
| 1080 | * have one register to deal with. As we use the same trap | ||
| 1081 | * backends between AArch32 and AArch64, we get away with it. | 1072 | * backends between AArch32 and AArch64, we get away with it. |
| 1082 | */ | 1073 | */ |
| 1083 | if (params.is_write) { | 1074 | if (params.is_write) { |
| 1084 | u64 val = *vcpu_reg(vcpu, params.Rt); | 1075 | params.regval = vcpu_get_reg(vcpu, Rt) & 0xffffffff; |
| 1085 | val &= 0xffffffff; | 1076 | params.regval |= vcpu_get_reg(vcpu, Rt2) << 32; |
| 1086 | val |= *vcpu_reg(vcpu, Rt2) << 32; | ||
| 1087 | *vcpu_reg(vcpu, params.Rt) = val; | ||
| 1088 | } | 1077 | } |
| 1089 | 1078 | ||
| 1090 | if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) | 1079 | if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) |
| @@ -1095,11 +1084,10 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu, | |||
| 1095 | unhandled_cp_access(vcpu, ¶ms); | 1084 | unhandled_cp_access(vcpu, ¶ms); |
| 1096 | 1085 | ||
| 1097 | out: | 1086 | out: |
| 1098 | /* Do the opposite hack for the read side */ | 1087 | /* Split up the value between registers for the read side */ |
| 1099 | if (!params.is_write) { | 1088 | if (!params.is_write) { |
| 1100 | u64 val = *vcpu_reg(vcpu, params.Rt); | 1089 | vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval)); |
| 1101 | val >>= 32; | 1090 | vcpu_set_reg(vcpu, Rt2, upper_32_bits(params.regval)); |
| 1102 | *vcpu_reg(vcpu, Rt2) = val; | ||
| 1103 | } | 1091 | } |
| 1104 | 1092 | ||
| 1105 | return 1; | 1093 | return 1; |
| @@ -1118,21 +1106,24 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu, | |||
| 1118 | { | 1106 | { |
| 1119 | struct sys_reg_params params; | 1107 | struct sys_reg_params params; |
| 1120 | u32 hsr = kvm_vcpu_get_hsr(vcpu); | 1108 | u32 hsr = kvm_vcpu_get_hsr(vcpu); |
| 1109 | int Rt = (hsr >> 5) & 0xf; | ||
| 1121 | 1110 | ||
| 1122 | params.is_aarch32 = true; | 1111 | params.is_aarch32 = true; |
| 1123 | params.is_32bit = true; | 1112 | params.is_32bit = true; |
| 1124 | params.CRm = (hsr >> 1) & 0xf; | 1113 | params.CRm = (hsr >> 1) & 0xf; |
| 1125 | params.Rt = (hsr >> 5) & 0xf; | 1114 | params.regval = vcpu_get_reg(vcpu, Rt); |
| 1126 | params.is_write = ((hsr & 1) == 0); | 1115 | params.is_write = ((hsr & 1) == 0); |
| 1127 | params.CRn = (hsr >> 10) & 0xf; | 1116 | params.CRn = (hsr >> 10) & 0xf; |
| 1128 | params.Op0 = 0; | 1117 | params.Op0 = 0; |
| 1129 | params.Op1 = (hsr >> 14) & 0x7; | 1118 | params.Op1 = (hsr >> 14) & 0x7; |
| 1130 | params.Op2 = (hsr >> 17) & 0x7; | 1119 | params.Op2 = (hsr >> 17) & 0x7; |
| 1131 | 1120 | ||
| 1132 | if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific)) | 1121 | if (!emulate_cp(vcpu, ¶ms, target_specific, nr_specific) || |
| 1133 | return 1; | 1122 | !emulate_cp(vcpu, ¶ms, global, nr_global)) { |
| 1134 | if (!emulate_cp(vcpu, ¶ms, global, nr_global)) | 1123 | if (!params.is_write) |
| 1124 | vcpu_set_reg(vcpu, Rt, params.regval); | ||
| 1135 | return 1; | 1125 | return 1; |
| 1126 | } | ||
| 1136 | 1127 | ||
| 1137 | unhandled_cp_access(vcpu, ¶ms); | 1128 | unhandled_cp_access(vcpu, ¶ms); |
| 1138 | return 1; | 1129 | return 1; |
| @@ -1230,6 +1221,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
| 1230 | { | 1221 | { |
| 1231 | struct sys_reg_params params; | 1222 | struct sys_reg_params params; |
| 1232 | unsigned long esr = kvm_vcpu_get_hsr(vcpu); | 1223 | unsigned long esr = kvm_vcpu_get_hsr(vcpu); |
| 1224 | int Rt = (esr >> 5) & 0x1f; | ||
| 1225 | int ret; | ||
| 1233 | 1226 | ||
| 1234 | trace_kvm_handle_sys_reg(esr); | 1227 | trace_kvm_handle_sys_reg(esr); |
| 1235 | 1228 | ||
| @@ -1240,10 +1233,14 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
| 1240 | params.CRn = (esr >> 10) & 0xf; | 1233 | params.CRn = (esr >> 10) & 0xf; |
| 1241 | params.CRm = (esr >> 1) & 0xf; | 1234 | params.CRm = (esr >> 1) & 0xf; |
| 1242 | params.Op2 = (esr >> 17) & 0x7; | 1235 | params.Op2 = (esr >> 17) & 0x7; |
| 1243 | params.Rt = (esr >> 5) & 0x1f; | 1236 | params.regval = vcpu_get_reg(vcpu, Rt); |
| 1244 | params.is_write = !(esr & 1); | 1237 | params.is_write = !(esr & 1); |
| 1245 | 1238 | ||
| 1246 | return emulate_sys_reg(vcpu, ¶ms); | 1239 | ret = emulate_sys_reg(vcpu, ¶ms); |
| 1240 | |||
| 1241 | if (!params.is_write) | ||
| 1242 | vcpu_set_reg(vcpu, Rt, params.regval); | ||
| 1243 | return ret; | ||
| 1247 | } | 1244 | } |
| 1248 | 1245 | ||
| 1249 | /****************************************************************************** | 1246 | /****************************************************************************** |
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 953abfc4b017..dbbb01cfbee9 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h | |||
| @@ -28,7 +28,7 @@ struct sys_reg_params { | |||
| 28 | u8 CRn; | 28 | u8 CRn; |
| 29 | u8 CRm; | 29 | u8 CRm; |
| 30 | u8 Op2; | 30 | u8 Op2; |
| 31 | u8 Rt; | 31 | u64 regval; |
| 32 | bool is_write; | 32 | bool is_write; |
| 33 | bool is_aarch32; | 33 | bool is_aarch32; |
| 34 | bool is_32bit; /* Only valid if is_aarch32 is true */ | 34 | bool is_32bit; /* Only valid if is_aarch32 is true */ |
| @@ -79,7 +79,7 @@ static inline bool ignore_write(struct kvm_vcpu *vcpu, | |||
| 79 | static inline bool read_zero(struct kvm_vcpu *vcpu, | 79 | static inline bool read_zero(struct kvm_vcpu *vcpu, |
| 80 | struct sys_reg_params *p) | 80 | struct sys_reg_params *p) |
| 81 | { | 81 | { |
| 82 | *vcpu_reg(vcpu, p->Rt) = 0; | 82 | p->regval = 0; |
| 83 | return true; | 83 | return true; |
| 84 | } | 84 | } |
| 85 | 85 | ||
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c index ccd3e359b800..ed90578fa120 100644 --- a/arch/arm64/kvm/sys_regs_generic_v8.c +++ b/arch/arm64/kvm/sys_regs_generic_v8.c | |||
| @@ -37,7 +37,7 @@ static bool access_actlr(struct kvm_vcpu *vcpu, | |||
| 37 | if (p->is_write) | 37 | if (p->is_write) |
| 38 | return ignore_write(vcpu, p); | 38 | return ignore_write(vcpu, p); |
| 39 | 39 | ||
| 40 | *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1); | 40 | p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1); |
| 41 | return true; | 41 | return true; |
| 42 | } | 42 | } |
| 43 | 43 | ||
