Skip to content

Commit c317c6d

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/aarch32-raz-idregs into kvmarm-master/next
* kvm-arm64/aarch32-raz-idregs: : . : Rework AArch32 ID registers exposed by KVM on AArch64-only : systems by treating them as RAZ/WI instead as UNKOWN as : architected, which allows them to be trivially migrated : between different systems. : : Patches courtesy of Oliver Upton. : . KVM: selftests: Add test for AArch32 ID registers KVM: arm64: Treat 32bit ID registers as RAZ/WI on 64bit-only system KVM: arm64: Add a visibility bit to ignore user writes KVM: arm64: Spin off helper for calling visibility hook KVM: arm64: Drop raz parameter from read_id_reg() KVM: arm64: Remove internal accessor helpers for id regs KVM: arm64: Use visibility hook to treat ID regs as RAZ Signed-off-by: Marc Zyngier <[email protected]>
2 parents b90cb10 + 797b845 commit c317c6d

File tree

5 files changed

+259
-86
lines changed

5 files changed

+259
-86
lines changed

arch/arm64/kvm/sys_regs.c

Lines changed: 71 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,13 +1063,12 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
10631063
}
10641064

10651065
/* Read a sanitised cpufeature ID register by sys_reg_desc */
1066-
static u64 read_id_reg(const struct kvm_vcpu *vcpu,
1067-
struct sys_reg_desc const *r, bool raz)
1066+
static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r)
10681067
{
10691068
u32 id = reg_to_encoding(r);
10701069
u64 val;
10711070

1072-
if (raz)
1071+
if (sysreg_visible_as_raz(vcpu, r))
10731072
return 0;
10741073

10751074
val = read_sanitised_ftr_reg(id);
@@ -1145,34 +1144,37 @@ static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
11451144
return 0;
11461145
}
11471146

1148-
/* cpufeature ID register access trap handlers */
1149-
1150-
static bool __access_id_reg(struct kvm_vcpu *vcpu,
1151-
struct sys_reg_params *p,
1152-
const struct sys_reg_desc *r,
1153-
bool raz)
1147+
static unsigned int aa32_id_visibility(const struct kvm_vcpu *vcpu,
1148+
const struct sys_reg_desc *r)
11541149
{
1155-
if (p->is_write)
1156-
return write_to_read_only(vcpu, p, r);
1150+
/*
1151+
* AArch32 ID registers are UNKNOWN if AArch32 isn't implemented at any
1152+
* EL. Promote to RAZ/WI in order to guarantee consistency between
1153+
* systems.
1154+
*/
1155+
if (!kvm_supports_32bit_el0())
1156+
return REG_RAZ | REG_USER_WI;
11571157

1158-
p->regval = read_id_reg(vcpu, r, raz);
1159-
return true;
1158+
return id_visibility(vcpu, r);
11601159
}
11611160

1161+
static unsigned int raz_visibility(const struct kvm_vcpu *vcpu,
1162+
const struct sys_reg_desc *r)
1163+
{
1164+
return REG_RAZ;
1165+
}
1166+
1167+
/* cpufeature ID register access trap handlers */
1168+
11621169
static bool access_id_reg(struct kvm_vcpu *vcpu,
11631170
struct sys_reg_params *p,
11641171
const struct sys_reg_desc *r)
11651172
{
1166-
bool raz = sysreg_visible_as_raz(vcpu, r);
1167-
1168-
return __access_id_reg(vcpu, p, r, raz);
1169-
}
1173+
if (p->is_write)
1174+
return write_to_read_only(vcpu, p, r);
11701175

1171-
static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
1172-
struct sys_reg_params *p,
1173-
const struct sys_reg_desc *r)
1174-
{
1175-
return __access_id_reg(vcpu, p, r, true);
1176+
p->regval = read_id_reg(vcpu, r);
1177+
return true;
11761178
}
11771179

11781180
/* Visibility overrides for SVE-specific control registers */
@@ -1208,7 +1210,7 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
12081210
return -EINVAL;
12091211

12101212
/* We can only differ with CSV[23], and anything else is an error */
1211-
val ^= read_id_reg(vcpu, rd, false);
1213+
val ^= read_id_reg(vcpu, rd);
12121214
val &= ~((0xFUL << ID_AA64PFR0_CSV2_SHIFT) |
12131215
(0xFUL << ID_AA64PFR0_CSV3_SHIFT));
12141216
if (val)
@@ -1227,45 +1229,21 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
12271229
* are stored, and for set_id_reg() we don't allow the effective value
12281230
* to be changed.
12291231
*/
1230-
static int __get_id_reg(const struct kvm_vcpu *vcpu,
1231-
const struct sys_reg_desc *rd, u64 *val,
1232-
bool raz)
1233-
{
1234-
*val = read_id_reg(vcpu, rd, raz);
1235-
return 0;
1236-
}
1237-
1238-
static int __set_id_reg(const struct kvm_vcpu *vcpu,
1239-
const struct sys_reg_desc *rd, u64 val,
1240-
bool raz)
1241-
{
1242-
/* This is what we mean by invariant: you can't change it. */
1243-
if (val != read_id_reg(vcpu, rd, raz))
1244-
return -EINVAL;
1245-
1246-
return 0;
1247-
}
1248-
12491232
static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
12501233
u64 *val)
12511234
{
1252-
bool raz = sysreg_visible_as_raz(vcpu, rd);
1253-
1254-
return __get_id_reg(vcpu, rd, val, raz);
1235+
*val = read_id_reg(vcpu, rd);
1236+
return 0;
12551237
}
12561238

12571239
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
12581240
u64 val)
12591241
{
1260-
bool raz = sysreg_visible_as_raz(vcpu, rd);
1261-
1262-
return __set_id_reg(vcpu, rd, val, raz);
1263-
}
1242+
/* This is what we mean by invariant: you can't change it. */
1243+
if (val != read_id_reg(vcpu, rd))
1244+
return -EINVAL;
12641245

1265-
static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
1266-
u64 val)
1267-
{
1268-
return __set_id_reg(vcpu, rd, val, true);
1246+
return 0;
12691247
}
12701248

12711249
static int get_raz_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
@@ -1367,16 +1345,26 @@ static unsigned int mte_visibility(const struct kvm_vcpu *vcpu,
13671345
.visibility = id_visibility, \
13681346
}
13691347

1348+
/* sys_reg_desc initialiser for known cpufeature ID registers */
1349+
#define AA32_ID_SANITISED(name) { \
1350+
SYS_DESC(SYS_##name), \
1351+
.access = access_id_reg, \
1352+
.get_user = get_id_reg, \
1353+
.set_user = set_id_reg, \
1354+
.visibility = aa32_id_visibility, \
1355+
}
1356+
13701357
/*
13711358
* sys_reg_desc initialiser for architecturally unallocated cpufeature ID
13721359
* register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
13731360
* (1 <= crm < 8, 0 <= Op2 < 8).
13741361
*/
13751362
#define ID_UNALLOCATED(crm, op2) { \
13761363
Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \
1377-
.access = access_raz_id_reg, \
1378-
.get_user = get_raz_reg, \
1379-
.set_user = set_raz_id_reg, \
1364+
.access = access_id_reg, \
1365+
.get_user = get_id_reg, \
1366+
.set_user = set_id_reg, \
1367+
.visibility = raz_visibility \
13801368
}
13811369

13821370
/*
@@ -1386,9 +1374,10 @@ static unsigned int mte_visibility(const struct kvm_vcpu *vcpu,
13861374
*/
13871375
#define ID_HIDDEN(name) { \
13881376
SYS_DESC(SYS_##name), \
1389-
.access = access_raz_id_reg, \
1390-
.get_user = get_raz_reg, \
1391-
.set_user = set_raz_id_reg, \
1377+
.access = access_id_reg, \
1378+
.get_user = get_id_reg, \
1379+
.set_user = set_id_reg, \
1380+
.visibility = raz_visibility, \
13921381
}
13931382

13941383
/*
@@ -1452,33 +1441,33 @@ static const struct sys_reg_desc sys_reg_descs[] = {
14521441

14531442
/* AArch64 mappings of the AArch32 ID registers */
14541443
/* CRm=1 */
1455-
ID_SANITISED(ID_PFR0_EL1),
1456-
ID_SANITISED(ID_PFR1_EL1),
1457-
ID_SANITISED(ID_DFR0_EL1),
1444+
AA32_ID_SANITISED(ID_PFR0_EL1),
1445+
AA32_ID_SANITISED(ID_PFR1_EL1),
1446+
AA32_ID_SANITISED(ID_DFR0_EL1),
14581447
ID_HIDDEN(ID_AFR0_EL1),
1459-
ID_SANITISED(ID_MMFR0_EL1),
1460-
ID_SANITISED(ID_MMFR1_EL1),
1461-
ID_SANITISED(ID_MMFR2_EL1),
1462-
ID_SANITISED(ID_MMFR3_EL1),
1448+
AA32_ID_SANITISED(ID_MMFR0_EL1),
1449+
AA32_ID_SANITISED(ID_MMFR1_EL1),
1450+
AA32_ID_SANITISED(ID_MMFR2_EL1),
1451+
AA32_ID_SANITISED(ID_MMFR3_EL1),
14631452

14641453
/* CRm=2 */
1465-
ID_SANITISED(ID_ISAR0_EL1),
1466-
ID_SANITISED(ID_ISAR1_EL1),
1467-
ID_SANITISED(ID_ISAR2_EL1),
1468-
ID_SANITISED(ID_ISAR3_EL1),
1469-
ID_SANITISED(ID_ISAR4_EL1),
1470-
ID_SANITISED(ID_ISAR5_EL1),
1471-
ID_SANITISED(ID_MMFR4_EL1),
1472-
ID_SANITISED(ID_ISAR6_EL1),
1454+
AA32_ID_SANITISED(ID_ISAR0_EL1),
1455+
AA32_ID_SANITISED(ID_ISAR1_EL1),
1456+
AA32_ID_SANITISED(ID_ISAR2_EL1),
1457+
AA32_ID_SANITISED(ID_ISAR3_EL1),
1458+
AA32_ID_SANITISED(ID_ISAR4_EL1),
1459+
AA32_ID_SANITISED(ID_ISAR5_EL1),
1460+
AA32_ID_SANITISED(ID_MMFR4_EL1),
1461+
AA32_ID_SANITISED(ID_ISAR6_EL1),
14731462

14741463
/* CRm=3 */
1475-
ID_SANITISED(MVFR0_EL1),
1476-
ID_SANITISED(MVFR1_EL1),
1477-
ID_SANITISED(MVFR2_EL1),
1464+
AA32_ID_SANITISED(MVFR0_EL1),
1465+
AA32_ID_SANITISED(MVFR1_EL1),
1466+
AA32_ID_SANITISED(MVFR2_EL1),
14781467
ID_UNALLOCATED(3,3),
1479-
ID_SANITISED(ID_PFR2_EL1),
1468+
AA32_ID_SANITISED(ID_PFR2_EL1),
14801469
ID_HIDDEN(ID_DFR1_EL1),
1481-
ID_SANITISED(ID_MMFR5_EL1),
1470+
AA32_ID_SANITISED(ID_MMFR5_EL1),
14821471
ID_UNALLOCATED(3,7),
14831472

14841473
/* AArch64 ID registers */
@@ -2809,6 +2798,9 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
28092798
if (!r)
28102799
return -ENOENT;
28112800

2801+
if (sysreg_user_write_ignore(vcpu, r))
2802+
return 0;
2803+
28122804
if (r->set_user) {
28132805
ret = (r->set_user)(vcpu, r, val);
28142806
} else {

arch/arm64/kvm/sys_regs.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ struct sys_reg_desc {
8686

8787
#define REG_HIDDEN (1 << 0) /* hidden from userspace and guest */
8888
#define REG_RAZ (1 << 1) /* RAZ from userspace and guest */
89+
#define REG_USER_WI (1 << 2) /* WI from userspace only */
8990

9091
static __printf(2, 3)
9192
inline void print_sys_reg_msg(const struct sys_reg_params *p,
@@ -136,22 +137,31 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
136137
__vcpu_sys_reg(vcpu, r->reg) = r->val;
137138
}
138139

139-
static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
140-
const struct sys_reg_desc *r)
140+
static inline unsigned int sysreg_visibility(const struct kvm_vcpu *vcpu,
141+
const struct sys_reg_desc *r)
141142
{
142143
if (likely(!r->visibility))
143-
return false;
144+
return 0;
144145

145-
return r->visibility(vcpu, r) & REG_HIDDEN;
146+
return r->visibility(vcpu, r);
147+
}
148+
149+
static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
150+
const struct sys_reg_desc *r)
151+
{
152+
return sysreg_visibility(vcpu, r) & REG_HIDDEN;
146153
}
147154

148155
static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
149156
const struct sys_reg_desc *r)
150157
{
151-
if (likely(!r->visibility))
152-
return false;
158+
return sysreg_visibility(vcpu, r) & REG_RAZ;
159+
}
153160

154-
return r->visibility(vcpu, r) & REG_RAZ;
161+
static inline bool sysreg_user_write_ignore(const struct kvm_vcpu *vcpu,
162+
const struct sys_reg_desc *r)
163+
{
164+
return sysreg_visibility(vcpu, r) & REG_USER_WI;
155165
}
156166

157167
static inline int cmp_sys_reg(const struct sys_reg_desc *i1,

tools/testing/selftests/kvm/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
2+
/aarch64/aarch32_id_regs
23
/aarch64/arch_timer
34
/aarch64/debug-exceptions
45
/aarch64/get-reg-list

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test
144144
# Compiled outputs used by test targets
145145
TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test
146146

147+
TEST_GEN_PROGS_aarch64 += aarch64/aarch32_id_regs
147148
TEST_GEN_PROGS_aarch64 += aarch64/arch_timer
148149
TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
149150
TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list

0 commit comments

Comments
 (0)