* [PATCH 1/4] KVM: arm64: Allow userspace to change MIDR_EL1
2025-02-10 15:49 [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Sebastian Ott
@ 2025-02-10 15:49 ` Sebastian Ott
2025-02-10 18:12 ` Oliver Upton
2025-02-10 15:49 ` [PATCH 2/4] KVM: arm64: Allow userspace to change REVIDR_EL1 Sebastian Ott
` (3 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Sebastian Ott @ 2025-02-10 15:49 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Shameer Kolothum
Cc: Cornelia Huck, Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
Enable VMMs to write MIDR_EL1 by treating it as a VM ID register.
Since MIDR_EL1 is not handled as a proper arm64_ftr_reg apply only
a sanity check against the writable mask to ensure the reserved
bits are 0.
Signed-off-by: Sebastian Ott <sebott@redhat.com>
---
arch/arm64/include/asm/kvm_host.h | 3 +++
arch/arm64/kvm/sys_regs.c | 37 +++++++++++++++++++++++++++----
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 7cfa024de4e3..3db8c773339e 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -373,6 +373,7 @@ struct kvm_arch {
#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
u64 id_regs[KVM_ARM_ID_REG_NUM];
+ u64 midr_el1;
u64 ctr_el0;
/* Masks for VNCR-backed and general EL2 sysregs */
@@ -1469,6 +1470,8 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
switch (reg) {
case sys_reg(3, 0, 0, 1, 0) ... sys_reg(3, 0, 0, 7, 7):
return &ka->id_regs[IDREG_IDX(reg)];
+ case SYS_MIDR_EL1:
+ return &ka->midr_el1;
case SYS_CTR_EL0:
return &ka->ctr_el0;
default:
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 82430c1e1dd0..cc94bed7299d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1666,7 +1666,7 @@ static bool is_feature_id_reg(u32 encoding)
*/
static inline bool is_vm_ftr_id_reg(u32 id)
{
- if (id == SYS_CTR_EL0)
+ if (id == SYS_CTR_EL0 || id == SYS_MIDR_EL1)
return true;
return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 &&
@@ -1999,6 +1999,22 @@ static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
return 0;
}
+static bool skip_feature_check(u32 reg)
+{
+ return (reg == SYS_MIDR_EL1);
+}
+
+/*
+ * For non ftr regs do a limited test against the writable mask only.
+ */
+static int arm64_check_mask(const struct sys_reg_desc *rd, u64 val)
+{
+ if ((rd->val & val) != val)
+ return -EINVAL;
+
+ return 0;
+}
+
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
u64 val)
{
@@ -2021,7 +2037,11 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
return ret;
}
- ret = arm64_check_features(vcpu, rd, val);
+ if (skip_feature_check(id))
+ ret = arm64_check_mask(rd, val);
+ else
+ ret = arm64_check_features(vcpu, rd, val);
+
if (!ret)
kvm_set_vm_id_reg(vcpu->kvm, id, val);
@@ -2493,6 +2513,15 @@ static bool access_mdcr(struct kvm_vcpu *vcpu,
return true;
}
+#define FUNCTION_RESET(reg) \
+ static u64 reset_##reg(struct kvm_vcpu *v, \
+ const struct sys_reg_desc *r) \
+ { \
+ return read_sysreg(reg); \
+ }
+
+FUNCTION_RESET(midr_el1)
+
/*
* Architected system registers.
@@ -2542,6 +2571,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
+ { ID_DESC(MIDR_EL1), .set_user = set_id_reg, .visibility = id_visibility,
+ .reset = reset_midr_el1, .val = (u32)-1 },
{ SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
/*
@@ -4594,13 +4625,11 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id,
return ((struct sys_reg_desc *)r)->val; \
}
-FUNCTION_INVARIANT(midr_el1)
FUNCTION_INVARIANT(revidr_el1)
FUNCTION_INVARIANT(aidr_el1)
/* ->val is filled in by kvm_sys_reg_table_init() */
static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = {
- { SYS_DESC(SYS_MIDR_EL1), NULL, reset_midr_el1 },
{ SYS_DESC(SYS_REVIDR_EL1), NULL, reset_revidr_el1 },
{ SYS_DESC(SYS_AIDR_EL1), NULL, reset_aidr_el1 },
};
--
2.42.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 1/4] KVM: arm64: Allow userspace to change MIDR_EL1
2025-02-10 15:49 ` [PATCH 1/4] KVM: arm64: Allow userspace to change MIDR_EL1 Sebastian Ott
@ 2025-02-10 18:12 ` Oliver Upton
2025-02-11 12:43 ` Sebastian Ott
0 siblings, 1 reply; 8+ messages in thread
From: Oliver Upton @ 2025-02-10 18:12 UTC (permalink / raw)
To: Sebastian Ott
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Shameer Kolothum, Cornelia Huck,
Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
Hi Sebastian,
On Mon, Feb 10, 2025 at 04:49:50PM +0100, Sebastian Ott wrote:
> Enable VMMs to write MIDR_EL1 by treating it as a VM ID register.
> Since MIDR_EL1 is not handled as a proper arm64_ftr_reg apply only
> a sanity check against the writable mask to ensure the reserved
> bits are 0.
How exactly does the VMM's MIDR_EL1 find its way to the guest? VPIDR_EL2
is still set to the hardware value.
> @@ -2021,7 +2037,11 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> return ret;
> }
>
> - ret = arm64_check_features(vcpu, rd, val);
> + if (skip_feature_check(id))
> + ret = arm64_check_mask(rd, val);
> + else
> + ret = arm64_check_features(vcpu, rd, val);
> +
Can you add a new implementation of ->set_user() for MIDR/REVIDR/AIDR
instead?
> @@ -2542,6 +2571,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>
> { SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
>
> + { ID_DESC(MIDR_EL1), .set_user = set_id_reg, .visibility = id_visibility,
> + .reset = reset_midr_el1, .val = (u32)-1 },
nit: GENMASK() instead of truncation by casting.
--
Thanks,
Oliver
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH 1/4] KVM: arm64: Allow userspace to change MIDR_EL1
2025-02-10 18:12 ` Oliver Upton
@ 2025-02-11 12:43 ` Sebastian Ott
0 siblings, 0 replies; 8+ messages in thread
From: Sebastian Ott @ 2025-02-11 12:43 UTC (permalink / raw)
To: Oliver Upton
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Shameer Kolothum, Cornelia Huck,
Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
Hi Oliver,
On Mon, 10 Feb 2025, Oliver Upton wrote:
> On Mon, Feb 10, 2025 at 04:49:50PM +0100, Sebastian Ott wrote:
>> Enable VMMs to write MIDR_EL1 by treating it as a VM ID register.
>> Since MIDR_EL1 is not handled as a proper arm64_ftr_reg apply only
>> a sanity check against the writable mask to ensure the reserved
>> bits are 0.
>
> How exactly does the VMM's MIDR_EL1 find its way to the guest? VPIDR_EL2
> is still set to the hardware value.
Ouch. Completely missed that part, sry.
>
>> @@ -2021,7 +2037,11 @@ static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>> return ret;
>> }
>>
>> - ret = arm64_check_features(vcpu, rd, val);
>> + if (skip_feature_check(id))
>> + ret = arm64_check_mask(rd, val);
>> + else
>> + ret = arm64_check_features(vcpu, rd, val);
>> +
>
> Can you add a new implementation of ->set_user() for MIDR/REVIDR/AIDR
> instead?
Yes, sure.
>> @@ -2542,6 +2571,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>>
>> { SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
>>
>> + { ID_DESC(MIDR_EL1), .set_user = set_id_reg, .visibility = id_visibility,
>> + .reset = reset_midr_el1, .val = (u32)-1 },
>
> nit: GENMASK() instead of truncation by casting.
All done. I add a test and send out V2.
Thanks a lot!
Sebastian
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/4] KVM: arm64: Allow userspace to change REVIDR_EL1
2025-02-10 15:49 [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Sebastian Ott
2025-02-10 15:49 ` [PATCH 1/4] KVM: arm64: Allow userspace to change MIDR_EL1 Sebastian Ott
@ 2025-02-10 15:49 ` Sebastian Ott
2025-02-10 15:49 ` [PATCH 3/4] KVM: arm64: Allow userspace to change AIDR_EL1 Sebastian Ott
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Sebastian Ott @ 2025-02-10 15:49 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Shameer Kolothum
Cc: Cornelia Huck, Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
Enable VMMs to write REVIDR_EL1 by treating it as a VM ID register.
Signed-off-by: Sebastian Ott <sebott@redhat.com>
---
arch/arm64/include/asm/kvm_host.h | 3 +++
arch/arm64/kvm/sys_regs.c | 11 +++++++----
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 3db8c773339e..c8fba4111b77 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -374,6 +374,7 @@ struct kvm_arch {
u64 id_regs[KVM_ARM_ID_REG_NUM];
u64 midr_el1;
+ u64 revidr_el1;
u64 ctr_el0;
/* Masks for VNCR-backed and general EL2 sysregs */
@@ -1472,6 +1473,8 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
return &ka->id_regs[IDREG_IDX(reg)];
case SYS_MIDR_EL1:
return &ka->midr_el1;
+ case SYS_REVIDR_EL1:
+ return &ka->revidr_el1;
case SYS_CTR_EL0:
return &ka->ctr_el0;
default:
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index cc94bed7299d..0ab2b2c79881 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1666,7 +1666,8 @@ static bool is_feature_id_reg(u32 encoding)
*/
static inline bool is_vm_ftr_id_reg(u32 id)
{
- if (id == SYS_CTR_EL0 || id == SYS_MIDR_EL1)
+ if (id == SYS_CTR_EL0 || id == SYS_MIDR_EL1 ||
+ id == SYS_REVIDR_EL1)
return true;
return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 &&
@@ -2001,7 +2002,8 @@ static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
static bool skip_feature_check(u32 reg)
{
- return (reg == SYS_MIDR_EL1);
+ return (reg == SYS_MIDR_EL1) ||
+ (reg == SYS_REVIDR_EL1);
}
/*
@@ -2521,6 +2523,7 @@ static bool access_mdcr(struct kvm_vcpu *vcpu,
}
FUNCTION_RESET(midr_el1)
+FUNCTION_RESET(revidr_el1)
/*
@@ -2574,6 +2577,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ ID_DESC(MIDR_EL1), .set_user = set_id_reg, .visibility = id_visibility,
.reset = reset_midr_el1, .val = (u32)-1 },
{ SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
+ { ID_DESC(REVIDR_EL1), .set_user = set_id_reg, .visibility = id_visibility,
+ .reset = reset_revidr_el1, .val = -1ULL },
/*
* ID regs: all ID_SANITISED() entries here must have corresponding
@@ -4625,12 +4630,10 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id,
return ((struct sys_reg_desc *)r)->val; \
}
-FUNCTION_INVARIANT(revidr_el1)
FUNCTION_INVARIANT(aidr_el1)
/* ->val is filled in by kvm_sys_reg_table_init() */
static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = {
- { SYS_DESC(SYS_REVIDR_EL1), NULL, reset_revidr_el1 },
{ SYS_DESC(SYS_AIDR_EL1), NULL, reset_aidr_el1 },
};
--
2.42.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 3/4] KVM: arm64: Allow userspace to change AIDR_EL1
2025-02-10 15:49 [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Sebastian Ott
2025-02-10 15:49 ` [PATCH 1/4] KVM: arm64: Allow userspace to change MIDR_EL1 Sebastian Ott
2025-02-10 15:49 ` [PATCH 2/4] KVM: arm64: Allow userspace to change REVIDR_EL1 Sebastian Ott
@ 2025-02-10 15:49 ` Sebastian Ott
2025-02-10 15:49 ` [PATCH 4/4] KVM: arm64: trap guest access for REVIDR_EL1 and AIDR_EL1 Sebastian Ott
2025-02-10 18:16 ` [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Oliver Upton
4 siblings, 0 replies; 8+ messages in thread
From: Sebastian Ott @ 2025-02-10 15:49 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Shameer Kolothum
Cc: Cornelia Huck, Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
Enable VMMs to write AIDR_EL1 by treating it as a VM ID register.
Since this was the last invariant register remove all the stuff
that was needed to handle these.
Signed-off-by: Sebastian Ott <sebott@redhat.com>
---
arch/arm64/include/asm/kvm_host.h | 3 ++
arch/arm64/kvm/sys_regs.c | 90 +++----------------------------
2 files changed, 10 insertions(+), 83 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index c8fba4111b77..de735e2ad9ce 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -375,6 +375,7 @@ struct kvm_arch {
u64 midr_el1;
u64 revidr_el1;
+ u64 aidr_el1;
u64 ctr_el0;
/* Masks for VNCR-backed and general EL2 sysregs */
@@ -1475,6 +1476,8 @@ static inline u64 *__vm_id_reg(struct kvm_arch *ka, u32 reg)
return &ka->midr_el1;
case SYS_REVIDR_EL1:
return &ka->revidr_el1;
+ case SYS_AIDR_EL1:
+ return &ka->aidr_el1;
case SYS_CTR_EL0:
return &ka->ctr_el0;
default:
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 0ab2b2c79881..7d588fedb50a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1667,7 +1667,7 @@ static bool is_feature_id_reg(u32 encoding)
static inline bool is_vm_ftr_id_reg(u32 id)
{
if (id == SYS_CTR_EL0 || id == SYS_MIDR_EL1 ||
- id == SYS_REVIDR_EL1)
+ id == SYS_REVIDR_EL1 || id == SYS_AIDR_EL1)
return true;
return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 &&
@@ -2003,7 +2003,8 @@ static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
static bool skip_feature_check(u32 reg)
{
return (reg == SYS_MIDR_EL1) ||
- (reg == SYS_REVIDR_EL1);
+ (reg == SYS_REVIDR_EL1) ||
+ (reg == SYS_AIDR_EL1);
}
/*
@@ -2524,6 +2525,7 @@ static bool access_mdcr(struct kvm_vcpu *vcpu,
FUNCTION_RESET(midr_el1)
FUNCTION_RESET(revidr_el1)
+FUNCTION_RESET(aidr_el1)
/*
@@ -2850,6 +2852,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
.set_user = set_clidr, .val = ~CLIDR_EL1_RES0 },
{ SYS_DESC(SYS_CCSIDR2_EL1), undef_access },
{ SYS_DESC(SYS_SMIDR_EL1), undef_access },
+ { ID_DESC(AIDR_EL1), .set_user = set_id_reg, .visibility = id_visibility,
+ .reset = reset_aidr_el1, .val = -1ULL },
{ SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 },
ID_FILTERED(CTR_EL0, ctr_el0,
CTR_EL0_DIC_MASK |
@@ -4614,61 +4618,6 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id,
return r;
}
-/*
- * These are the invariant sys_reg registers: we let the guest see the
- * host versions of these, so they're part of the guest state.
- *
- * A future CPU may provide a mechanism to present different values to
- * the guest, or a future kvm may trap them.
- */
-
-#define FUNCTION_INVARIANT(reg) \
- static u64 reset_##reg(struct kvm_vcpu *v, \
- const struct sys_reg_desc *r) \
- { \
- ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \
- return ((struct sys_reg_desc *)r)->val; \
- }
-
-FUNCTION_INVARIANT(aidr_el1)
-
-/* ->val is filled in by kvm_sys_reg_table_init() */
-static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = {
- { SYS_DESC(SYS_AIDR_EL1), NULL, reset_aidr_el1 },
-};
-
-static int get_invariant_sys_reg(u64 id, u64 __user *uaddr)
-{
- const struct sys_reg_desc *r;
-
- r = get_reg_by_id(id, invariant_sys_regs,
- ARRAY_SIZE(invariant_sys_regs));
- if (!r)
- return -ENOENT;
-
- return put_user(r->val, uaddr);
-}
-
-static int set_invariant_sys_reg(u64 id, u64 __user *uaddr)
-{
- const struct sys_reg_desc *r;
- u64 val;
-
- r = get_reg_by_id(id, invariant_sys_regs,
- ARRAY_SIZE(invariant_sys_regs));
- if (!r)
- return -ENOENT;
-
- if (get_user(val, uaddr))
- return -EFAULT;
-
- /* This is what we mean by invariant: you can't change it. */
- if (r->val != val)
- return -EINVAL;
-
- return 0;
-}
-
static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
{
u32 val;
@@ -4750,15 +4699,10 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{
void __user *uaddr = (void __user *)(unsigned long)reg->addr;
- int err;
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
return demux_c15_get(vcpu, reg->id, uaddr);
- err = get_invariant_sys_reg(reg->id, uaddr);
- if (err != -ENOENT)
- return err;
-
return kvm_sys_reg_get_user(vcpu, reg,
sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
}
@@ -4794,15 +4738,10 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{
void __user *uaddr = (void __user *)(unsigned long)reg->addr;
- int err;
if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
return demux_c15_set(vcpu, reg->id, uaddr);
- err = set_invariant_sys_reg(reg->id, uaddr);
- if (err != -ENOENT)
- return err;
-
return kvm_sys_reg_set_user(vcpu, reg,
sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
}
@@ -4891,23 +4830,13 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
{
- return ARRAY_SIZE(invariant_sys_regs)
- + num_demux_regs()
- + walk_sys_regs(vcpu, (u64 __user *)NULL);
+ return num_demux_regs() + walk_sys_regs(vcpu, (u64 __user *)NULL);
}
int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
{
- unsigned int i;
int err;
- /* Then give them all the invariant registers' indices. */
- for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) {
- if (put_user(sys_reg_to_index(&invariant_sys_regs[i]), uindices))
- return -EFAULT;
- uindices++;
- }
-
err = walk_sys_regs(vcpu, uindices);
if (err < 0)
return err;
@@ -5133,16 +5062,11 @@ int __init kvm_sys_reg_table_init(void)
valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), true);
valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), true);
valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), true);
- valid &= check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs), false);
valid &= check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs), false);
if (!valid)
return -EINVAL;
- /* We abuse the reset function to overwrite the table itself. */
- for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
- invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);
-
ret = populate_nv_trap_config();
for (i = 0; !ret && i < ARRAY_SIZE(sys_reg_descs); i++)
--
2.42.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH 4/4] KVM: arm64: trap guest access for REVIDR_EL1 and AIDR_EL1
2025-02-10 15:49 [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Sebastian Ott
` (2 preceding siblings ...)
2025-02-10 15:49 ` [PATCH 3/4] KVM: arm64: Allow userspace to change AIDR_EL1 Sebastian Ott
@ 2025-02-10 15:49 ` Sebastian Ott
2025-02-10 18:16 ` [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Oliver Upton
4 siblings, 0 replies; 8+ messages in thread
From: Sebastian Ott @ 2025-02-10 15:49 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Shameer Kolothum
Cc: Cornelia Huck, Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
Setup a trap for guest access of REVIDR_EL1 and AIDR_EL1 when
the VMs value differs from hardware.
Signed-off-by: Sebastian Ott <sebott@redhat.com>
---
arch/arm64/kvm/sys_regs.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 7d588fedb50a..2918872e3d2a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -4910,6 +4910,10 @@ static void vcpu_set_hcr(struct kvm_vcpu *vcpu)
else
vcpu->arch.hcr_el2 |= HCR_TID2;
+ if ((kvm_read_vm_id_reg(kvm, SYS_REVIDR_EL1) != read_sysreg(REVIDR_EL1)) ||
+ (kvm_read_vm_id_reg(kvm, SYS_AIDR_EL1) != read_sysreg(AIDR_EL1)))
+ vcpu->arch.hcr_el2 |= HCR_TID1;
+
if (vcpu_el1_is_32bit(vcpu))
vcpu->arch.hcr_el2 &= ~HCR_RW;
--
2.42.0
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR
2025-02-10 15:49 [PATCH 0/4] KVM: arm64: writable MIDR/REVIDR Sebastian Ott
` (3 preceding siblings ...)
2025-02-10 15:49 ` [PATCH 4/4] KVM: arm64: trap guest access for REVIDR_EL1 and AIDR_EL1 Sebastian Ott
@ 2025-02-10 18:16 ` Oliver Upton
4 siblings, 0 replies; 8+ messages in thread
From: Oliver Upton @ 2025-02-10 18:16 UTC (permalink / raw)
To: Sebastian Ott
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Shameer Kolothum, Cornelia Huck,
Eric Auger, linux-arm-kernel, kvmarm, linux-kernel
On Mon, Feb 10, 2025 at 04:49:49PM +0100, Sebastian Ott wrote:
> Based on prior discussion [1] this series allows VMMs to change
> MIDR/REVIDR to enable migration between machines that differ in
> these registers. Since these are used for errata handling the
> errata management series [2] is a prerequisite for this one.
>
> Note that guest access to MIDR_EL1 is not trapped.
>
> [1] https://lore.kernel.org/kvmarm/20250124151732.6072-1-shameerali.kolothum.thodi@huawei.com/T/#mb855bc51714095a164a7b26bb8bead1606e4b753
> [2] https://lore.kernel.org/kvmarm/20250205132222.55816-1-shameerali.kolothum.thodi@huawei.com/T/
>
> Sebastian Ott (4):
> KVM: arm64: Allow userspace to change MIDR_EL1
> KVM: arm64: Allow userspace to change REVIDR_EL1
> KVM: arm64: Allow userspace to change AIDR_EL1
> KVM: arm64: trap guest access for REVIDR_EL1 and AIDR_EL1
Please reorganize the series such that guest accesses to REVIDR/AIDR are
trapped as soon as we allow userspace to change them. Also, can you
extend the set_id_regs selftest to assert that the guest sees the
correct value for these registers?
--
Thanks,
Oliver
^ permalink raw reply [flat|nested] 8+ messages in thread