* [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3}
@ 2023-07-10 19:24 Jing Zhang
2023-07-10 19:24 ` [PATCH v5 1/6] KVM: arm64: Use guest ID register values for the sake of emulation Jing Zhang
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
This patch series enable userspace writable for below idregs:
ID_AA64DFR0_EL1, ID_DFR0_EL1, ID_AA64PFR0_EL1, ID_AA64MMFR{0, 1, 2, 3}_EL1.
It is based on v6.5-rc1 which contains infrastructure for writable idregs.
A selftest is added to verify that KVM handles the writings from user space
correctly.
A relevant patch from Oliver is picked from [3].
---
* v4 -> v5
- Rebase on v6.4-rc1 which contains infrastructure for writable idregs.
- Use guest ID registers values for the sake of emulation.
- Added a selftest to verify idreg userspace writing.
* v3 -> v4
- Rebase on v11 of writable idregs series at [2].
* v2 -> v3
- Rebase on v6 of writable idregs series.
- Enable writable for ID_AA64PFR0_EL1 and ID_AA64MMFR{0, 1, 2}_EL1.
* v1 -> v2
- Rebase on latest patch series [1] of enabling writable ID register.
[1] https://lore.kernel.org/all/20230402183735.3011540-1-jingzhangos@google.com
[2] https://lore.kernel.org/all/20230602005118.2899664-1-jingzhangos@google.com
[3] https://lore.kernel.org/kvmarm/20230623205232.2837077-1-oliver.upton@linux.dev
[v1] https://lore.kernel.org/all/20230326011950.405749-1-jingzhangos@google.com
[v2] https://lore.kernel.org/all/20230403003723.3199828-1-jingzhangos@google.com
[v3] https://lore.kernel.org/all/20230405172146.297208-1-jingzhangos@google.com
---
Jing Zhang (5):
KVM: arm64: Use guest ID register values for the sake of emulation
KVM: arm64: Enable writable for ID_AA64DFR0_EL1 and ID_DFR0_EL1
KVM: arm64: Enable writable for ID_AA64PFR0_EL1
KVM: arm64: Enable writable for ID_AA64MMFR{0, 1, 2, 3}_EL1
KVM: arm64: selftests: Test for setting ID register from usersapce
Oliver Upton (1):
KVM: arm64: Reject attempts to set invalid debug arch version
arch/arm64/kvm/sys_regs.c | 62 +++++--
tools/testing/selftests/kvm/Makefile | 1 +
.../selftests/kvm/aarch64/set_id_regs.c | 163 ++++++++++++++++++
3 files changed, 213 insertions(+), 13 deletions(-)
create mode 100644 tools/testing/selftests/kvm/aarch64/set_id_regs.c
base-commit: 06c2afb862f9da8dc5efa4b6076a0e48c3fbaaa5
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v5 1/6] KVM: arm64: Use guest ID register values for the sake of emulation
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
@ 2023-07-10 19:24 ` Jing Zhang
2023-07-10 19:24 ` [PATCH v5 2/6] KVM: arm64: Enable writable for ID_AA64DFR0_EL1 and ID_DFR0_EL1 Jing Zhang
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
Since KVM now supports per-VM ID registers, use per-VM ID register
values for the sake of emulation for DBGDIDR and LORegion.
Signed-off-by: Jing Zhang <jingzhangos@google.com>
---
arch/arm64/kvm/sys_regs.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index bd3431823ec5..c1a5ec1a016e 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -379,7 +379,7 @@ static bool trap_loregion(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
- u64 val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+ u64 val = IDREG(vcpu->kvm, SYS_ID_AA64MMFR1_EL1);
u32 sr = reg_to_encoding(r);
if (!(val & (0xfUL << ID_AA64MMFR1_EL1_LO_SHIFT))) {
@@ -2429,8 +2429,8 @@ static bool trap_dbgdidr(struct kvm_vcpu *vcpu,
if (p->is_write) {
return ignore_write(vcpu, p);
} else {
- u64 dfr = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
- u64 pfr = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+ u64 dfr = IDREG(vcpu->kvm, SYS_ID_AA64DFR0_EL1);
+ u64 pfr = IDREG(vcpu->kvm, SYS_ID_AA64PFR0_EL1);
u32 el3 = !!cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR0_EL1_EL3_SHIFT);
p->regval = ((((dfr >> ID_AA64DFR0_EL1_WRPs_SHIFT) & 0xf) << 28) |
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v5 2/6] KVM: arm64: Enable writable for ID_AA64DFR0_EL1 and ID_DFR0_EL1
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
2023-07-10 19:24 ` [PATCH v5 1/6] KVM: arm64: Use guest ID register values for the sake of emulation Jing Zhang
@ 2023-07-10 19:24 ` Jing Zhang
2023-07-10 19:24 ` [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version Jing Zhang
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
All valid fields in ID_AA64DFR0_EL1 and ID_DFR0_EL1 are writable
from usrespace with this change.
Signed-off-by: Jing Zhang <jingzhangos@google.com>
---
arch/arm64/kvm/sys_regs.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c1a5ec1a016e..0160ef9cfe18 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1980,7 +1980,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
.set_user = set_id_dfr0_el1,
.visibility = aa32_id_visibility,
.reset = read_sanitised_id_dfr0_el1,
- .val = ID_DFR0_EL1_PerfMon_MASK, },
+ .val = GENMASK(63, 0), },
ID_HIDDEN(ID_AFR0_EL1),
AA32_ID_SANITISED(ID_MMFR0_EL1),
AA32_ID_SANITISED(ID_MMFR1_EL1),
@@ -2029,7 +2029,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
.get_user = get_id_reg,
.set_user = set_id_aa64dfr0_el1,
.reset = read_sanitised_id_aa64dfr0_el1,
- .val = ID_AA64DFR0_EL1_PMUVer_MASK, },
+ .val = GENMASK(63, 0), },
ID_SANITISED(ID_AA64DFR1_EL1),
ID_UNALLOCATED(5,2),
ID_UNALLOCATED(5,3),
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
2023-07-10 19:24 ` [PATCH v5 1/6] KVM: arm64: Use guest ID register values for the sake of emulation Jing Zhang
2023-07-10 19:24 ` [PATCH v5 2/6] KVM: arm64: Enable writable for ID_AA64DFR0_EL1 and ID_DFR0_EL1 Jing Zhang
@ 2023-07-10 19:24 ` Jing Zhang
2023-07-10 20:18 ` Oliver Upton
2023-07-10 19:24 ` [PATCH v5 4/6] KVM: arm64: Enable writable for ID_AA64PFR0_EL1 Jing Zhang
` (2 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
From: Oliver Upton <oliver.upton@linux.dev>
The debug architecture is mandatory in ARMv8, so KVM should not allow
userspace to configure a vCPU with less than that. Of course, this isn't
handled elegantly by the generic ID register plumbing, as the respective
ID register fields have a nonzero starting value.
Add an explicit check for debug versions less than v8 of the
architecture.
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Jing Zhang <jingzhangos@google.com>
---
arch/arm64/kvm/sys_regs.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 0160ef9cfe18..c44504038ae9 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1496,6 +1496,7 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
const struct sys_reg_desc *rd,
u64 val)
{
+ u8 debugver = SYS_FIELD_GET(ID_AA64DFR0_EL1, DebugVer, val);
u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val);
/*
@@ -1515,6 +1516,13 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
val &= ~ID_AA64DFR0_EL1_PMUVer_MASK;
+ /*
+ * ID_AA64DFR0_EL1.DebugVer is one of those awkward fields with a
+ * nonzero minimum safe value.
+ */
+ if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
+ return -EINVAL;
+
return set_id_reg(vcpu, rd, val);
}
@@ -1536,6 +1544,7 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
u64 val)
{
u8 perfmon = SYS_FIELD_GET(ID_DFR0_EL1, PerfMon, val);
+ u8 copdbg = SYS_FIELD_GET(ID_DFR0_EL1, CopDbg, val);
if (perfmon == ID_DFR0_EL1_PerfMon_IMPDEF) {
val &= ~ID_DFR0_EL1_PerfMon_MASK;
@@ -1551,6 +1560,9 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
if (perfmon != 0 && perfmon < ID_DFR0_EL1_PerfMon_PMUv3)
return -EINVAL;
+ if (copdbg < ID_DFR0_EL1_CopDbg_Armv8)
+ return -EINVAL;
+
return set_id_reg(vcpu, rd, val);
}
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v5 4/6] KVM: arm64: Enable writable for ID_AA64PFR0_EL1
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
` (2 preceding siblings ...)
2023-07-10 19:24 ` [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version Jing Zhang
@ 2023-07-10 19:24 ` Jing Zhang
2023-07-10 19:24 ` [PATCH v5 5/6] KVM: arm64: Enable writable for ID_AA64MMFR{0, 1, 2, 3}_EL1 Jing Zhang
2023-07-10 19:24 ` [PATCH v5 6/6] KVM: arm64: selftests: Test for setting ID register from usersapce Jing Zhang
5 siblings, 0 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
All valid fields in ID_AA64PFR0_EL1 are writable from usrespace
with this change.
Signed-off-by: Jing Zhang <jingzhangos@google.com>
---
arch/arm64/kvm/sys_regs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c44504038ae9..967ecd57a86a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2026,7 +2026,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
.get_user = get_id_reg,
.set_user = set_id_reg,
.reset = read_sanitised_id_aa64pfr0_el1,
- .val = ID_AA64PFR0_EL1_CSV2_MASK | ID_AA64PFR0_EL1_CSV3_MASK, },
+ .val = GENMASK(63, 0), },
ID_SANITISED(ID_AA64PFR1_EL1),
ID_UNALLOCATED(4,2),
ID_UNALLOCATED(4,3),
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v5 5/6] KVM: arm64: Enable writable for ID_AA64MMFR{0, 1, 2, 3}_EL1
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
` (3 preceding siblings ...)
2023-07-10 19:24 ` [PATCH v5 4/6] KVM: arm64: Enable writable for ID_AA64PFR0_EL1 Jing Zhang
@ 2023-07-10 19:24 ` Jing Zhang
2023-07-10 19:24 ` [PATCH v5 6/6] KVM: arm64: selftests: Test for setting ID register from usersapce Jing Zhang
5 siblings, 0 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
Enable writable from userspace for ID_AA64MMFR{0, 1, 2, 3}_EL1.
Added a macro for defining general writable idregs.
Signed-off-by: Jing Zhang <jingzhangos@google.com>
---
arch/arm64/kvm/sys_regs.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 967ecd57a86a..78ccc95624fa 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1340,9 +1340,6 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT);
val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS);
break;
- case SYS_ID_AA64MMFR2_EL1:
- val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
- break;
case SYS_ID_MMFR4_EL1:
val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX);
break;
@@ -1566,6 +1563,18 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
return set_id_reg(vcpu, rd, val);
}
+static u64 read_sanitised_id_aa64mmfr2_el1(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
+{
+ u64 val;
+ u32 id = reg_to_encoding(rd);
+
+ val = read_sanitised_ftr_reg(id);
+ val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK;
+
+ return val;
+}
+
/*
* cpufeature ID register user accessors
*
@@ -1840,6 +1849,16 @@ static unsigned int elx2_visibility(const struct kvm_vcpu *vcpu,
.val = 0, \
}
+#define ID_SANITISED_WRITABLE(name) { \
+ SYS_DESC(SYS_##name), \
+ .access = access_id_reg, \
+ .get_user = get_id_reg, \
+ .set_user = set_id_reg, \
+ .visibility = id_visibility, \
+ .reset = kvm_read_sanitised_id_reg, \
+ .val = GENMASK(63, 0), \
+}
+
/* sys_reg_desc initialiser for known cpufeature ID registers */
#define AA32_ID_SANITISED(name) { \
SYS_DESC(SYS_##name), \
@@ -2061,10 +2080,15 @@ static const struct sys_reg_desc sys_reg_descs[] = {
ID_UNALLOCATED(6,7),
/* CRm=7 */
- ID_SANITISED(ID_AA64MMFR0_EL1),
- ID_SANITISED(ID_AA64MMFR1_EL1),
- ID_SANITISED(ID_AA64MMFR2_EL1),
- ID_SANITISED(ID_AA64MMFR3_EL1),
+ ID_SANITISED_WRITABLE(ID_AA64MMFR0_EL1),
+ ID_SANITISED_WRITABLE(ID_AA64MMFR1_EL1),
+ { SYS_DESC(SYS_ID_AA64MMFR2_EL1),
+ .access = access_id_reg,
+ .get_user = get_id_reg,
+ .set_user = set_id_reg,
+ .reset = read_sanitised_id_aa64mmfr2_el1,
+ .val = GENMASK(63, 0), },
+ ID_SANITISED_WRITABLE(ID_AA64MMFR3_EL1),
ID_UNALLOCATED(7,4),
ID_UNALLOCATED(7,5),
ID_UNALLOCATED(7,6),
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v5 6/6] KVM: arm64: selftests: Test for setting ID register from usersapce
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
` (4 preceding siblings ...)
2023-07-10 19:24 ` [PATCH v5 5/6] KVM: arm64: Enable writable for ID_AA64MMFR{0, 1, 2, 3}_EL1 Jing Zhang
@ 2023-07-10 19:24 ` Jing Zhang
5 siblings, 0 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 19:24 UTC (permalink / raw)
To: KVM, KVMARM, ARMLinux, Marc Zyngier, Oliver Upton
Cc: Will Deacon, Paolo Bonzini, James Morse, Alexandru Elisei,
Suzuki K Poulose, Fuad Tabba, Reiji Watanabe,
Raghavendra Rao Ananta, Suraj Jitindar Singh, Cornelia Huck,
Jing Zhang
Add a test to verify setting ID registers from userapce is handled
correctly by KVM.
Signed-off-by: Jing Zhang <jingzhangos@google.com>
---
tools/testing/selftests/kvm/Makefile | 1 +
.../selftests/kvm/aarch64/set_id_regs.c | 163 ++++++++++++++++++
2 files changed, 164 insertions(+)
create mode 100644 tools/testing/selftests/kvm/aarch64/set_id_regs.c
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index c692cc86e7da..87ceadc1292a 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -144,6 +144,7 @@ TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
TEST_GEN_PROGS_aarch64 += aarch64/hypercalls
TEST_GEN_PROGS_aarch64 += aarch64/page_fault_test
TEST_GEN_PROGS_aarch64 += aarch64/psci_test
+TEST_GEN_PROGS_aarch64 += aarch64/set_id_regs
TEST_GEN_PROGS_aarch64 += aarch64/smccc_filter
TEST_GEN_PROGS_aarch64 += aarch64/vcpu_width_config
TEST_GEN_PROGS_aarch64 += aarch64/vgic_init
diff --git a/tools/testing/selftests/kvm/aarch64/set_id_regs.c b/tools/testing/selftests/kvm/aarch64/set_id_regs.c
new file mode 100644
index 000000000000..e2242ef36bab
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/set_id_regs.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * set_id_regs - Test for setting ID register from usersapce.
+ *
+ * Copyright (c) 2023 Google LLC.
+ *
+ *
+ * Test that KVM supports setting ID registers from userspace and handles the
+ * feature set correctly.
+ */
+
+#include <stdint.h>
+#include "kvm_util.h"
+#include "processor.h"
+#include "test_util.h"
+#include <linux/bitfield.h>
+
+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
+#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
+
+struct reg_feature {
+ uint64_t reg;
+ uint64_t ftr_mask;
+};
+
+static void guest_code(void)
+{
+ for (;;)
+ GUEST_SYNC(0);
+}
+
+static struct reg_feature lower_safe_reg_ftrs[] = {
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), ARM64_FEATURE_MASK(ID_AA64DFR0_BRPS) },
+ { KVM_ARM64_SYS_REG(SYS_ID_DFR0_EL1), ARM64_FEATURE_MASK(ID_DFR0_COPDBG) },
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), ARM64_FEATURE_MASK(ID_AA64PFR0_EL3) },
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN4) },
+};
+
+static void test_user_set_lower_safe(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lower_safe_reg_ftrs); i++) {
+ struct reg_feature *reg_ftr = lower_safe_reg_ftrs + i;
+ uint64_t val, new_val, ftr;
+
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ftr = field_get(reg_ftr->ftr_mask, val);
+
+ /* Set a safe value for the feature */
+ if (ftr > 0)
+ ftr--;
+
+ val &= ~reg_ftr->ftr_mask;
+ val |= field_prep(reg_ftr->ftr_mask, ftr);
+
+ vcpu_set_reg(vcpu, reg_ftr->reg, val);
+ vcpu_get_reg(vcpu, reg_ftr->reg, &new_val);
+ ASSERT_EQ(new_val, val);
+ }
+}
+
+static struct reg_feature exact_reg_ftrs[] = {
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER) },
+};
+
+static void test_user_set_exact(struct kvm_vcpu *vcpu)
+{
+ int i, r;
+
+ for (i = 0; i < ARRAY_SIZE(exact_reg_ftrs); i++) {
+ struct reg_feature *reg_ftr = exact_reg_ftrs + i;
+ uint64_t val, old_val, ftr;
+
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ftr = field_get(reg_ftr->ftr_mask, val);
+ old_val = val;
+
+ /* Exact match */
+ vcpu_set_reg(vcpu, reg_ftr->reg, val);
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ASSERT_EQ(val, old_val);
+
+ /* Smaller value */
+ if (ftr > 0)
+ ftr--;
+ val &= ~reg_ftr->ftr_mask;
+ val |= field_prep(reg_ftr->ftr_mask, ftr);
+ r = __vcpu_set_reg(vcpu, reg_ftr->reg, val);
+ TEST_ASSERT(r < 0 && errno == EINVAL,
+ "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ASSERT_EQ(val, old_val);
+
+ /* Bigger value */
+ ftr += 2;
+ val &= ~reg_ftr->ftr_mask;
+ val |= field_prep(reg_ftr->ftr_mask, ftr);
+ r = __vcpu_set_reg(vcpu, reg_ftr->reg, val);
+ TEST_ASSERT(r < 0 && errno == EINVAL,
+ "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ASSERT_EQ(val, old_val);
+ }
+}
+
+static struct reg_feature fail_reg_ftrs[] = {
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), ARM64_FEATURE_MASK(ID_AA64DFR0_WRPS) },
+ { KVM_ARM64_SYS_REG(SYS_ID_DFR0_EL1), ARM64_FEATURE_MASK(ID_DFR0_MPROFDBG) },
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), ARM64_FEATURE_MASK(ID_AA64PFR0_EL2) },
+ { KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN64) },
+};
+
+static void test_user_set_fail(struct kvm_vcpu *vcpu)
+{
+ int i, r;
+
+ for (i = 0; i < ARRAY_SIZE(fail_reg_ftrs); i++) {
+ struct reg_feature *reg_ftr = fail_reg_ftrs + i;
+ uint64_t val, old_val, ftr;
+
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ftr = field_get(reg_ftr->ftr_mask, val);
+
+ /* Set a invalid value (too big) for the feature */
+ ftr++;
+
+ old_val = val;
+ val &= ~reg_ftr->ftr_mask;
+ val |= field_prep(reg_ftr->ftr_mask, ftr);
+
+ r = __vcpu_set_reg(vcpu, reg_ftr->reg, val);
+ TEST_ASSERT(r < 0 && errno == EINVAL,
+ "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
+
+ vcpu_get_reg(vcpu, reg_ftr->reg, &val);
+ ASSERT_EQ(val, old_val);
+ }
+}
+
+int main(void)
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_vm *vm;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+ ksft_print_header();
+ ksft_set_plan(3);
+
+ test_user_set_lower_safe(vcpu);
+ ksft_test_result_pass("test_user_set_lower_safe\n");
+
+ test_user_set_exact(vcpu);
+ ksft_test_result_pass("test_user_set_exact\n");
+
+ test_user_set_fail(vcpu);
+ ksft_test_result_pass("test_user_set_fail\n");
+
+ kvm_vm_free(vm);
+
+ ksft_finished();
+}
--
2.41.0.255.g8b1d071c50-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version
2023-07-10 19:24 ` [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version Jing Zhang
@ 2023-07-10 20:18 ` Oliver Upton
2023-07-10 20:54 ` Jing Zhang
0 siblings, 1 reply; 9+ messages in thread
From: Oliver Upton @ 2023-07-10 20:18 UTC (permalink / raw)
To: Jing Zhang
Cc: KVM, KVMARM, ARMLinux, Marc Zyngier, Will Deacon, Paolo Bonzini,
James Morse, Alexandru Elisei, Suzuki K Poulose, Fuad Tabba,
Reiji Watanabe, Raghavendra Rao Ananta, Suraj Jitindar Singh,
Cornelia Huck
Jing,
On Mon, Jul 10, 2023 at 07:24:26PM +0000, Jing Zhang wrote:
> From: Oliver Upton <oliver.upton@linux.dev>
>
> The debug architecture is mandatory in ARMv8, so KVM should not allow
> userspace to configure a vCPU with less than that. Of course, this isn't
> handled elegantly by the generic ID register plumbing, as the respective
> ID register fields have a nonzero starting value.
>
> Add an explicit check for debug versions less than v8 of the
> architecture.
>
> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
> Signed-off-by: Jing Zhang <jingzhangos@google.com>
This patch should be ordered before the change that permits writes to
the DebugVer field (i.e. the previous patch). While we're at it, there's
another set of prerequisites for actually making the field writable.
As Suraj pointed out earlier, we need to override the type of the field
to be FTR_LOWER_SAFE instead of EXACT. Beyond that, KVM limits the field
to 0x6, which is the minimum value for an ARMv8 implementation. We can
relax this limitation up to v8p8, as I believe all of the changes are to
external debug and wouldn't affect a KVM guest.
Below is my (untested) diff on top of your series for both of these
changes.
--
Thanks,
Oliver
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 78ccc95624fa..35c4ab8cb5c8 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1216,8 +1216,14 @@ static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
/* Some features have different safe value type in KVM than host features */
switch (id) {
case SYS_ID_AA64DFR0_EL1:
- if (kvm_ftr.shift == ID_AA64DFR0_EL1_PMUVer_SHIFT)
+ switch (kvm_ftr.shift) {
+ case ID_AA64DFR0_EL1_PMUVer_SHIFT:
kvm_ftr.type = FTR_LOWER_SAFE;
+ break;
+ case ID_AA64DFR0_EL1_DebugVer_SHIFT:
+ kvm_ftr.type = FTR_LOWER_SAFE;
+ break;
+ }
break;
case SYS_ID_DFR0_EL1:
if (kvm_ftr.shift == ID_DFR0_EL1_PerfMon_SHIFT)
@@ -1466,14 +1472,22 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
return val;
}
+#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit) \
+({ \
+ u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
+ (val) &= ~reg##_##field##_MASK; \
+ (val) |= FIELD_PREP(reg##_##field##_MASK, \
+ min(__f_val, (u64)reg##_##field##_##limit)); \
+ (val); \
+})
+
static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
const struct sys_reg_desc *rd)
{
u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
/* Limit debug to ARMv8.0 */
- val &= ~ID_AA64DFR0_EL1_DebugVer_MASK;
- val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, IMP);
+ val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
/*
* Only initialize the PMU version if the vCPU was configured with one.
@@ -1529,6 +1543,8 @@ static u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu,
u8 perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
u64 val = read_sanitised_ftr_reg(SYS_ID_DFR0_EL1);
+ val = ID_REG_LIMIT_FIELD_ENUM(val, ID_DFR0_EL1, CopDbg, Debugv8p8);
+
val &= ~ID_DFR0_EL1_PerfMon_MASK;
if (kvm_vcpu_has_pmu(vcpu))
val |= SYS_FIELD_PREP(ID_DFR0_EL1, PerfMon, perfmon);
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version
2023-07-10 20:18 ` Oliver Upton
@ 2023-07-10 20:54 ` Jing Zhang
0 siblings, 0 replies; 9+ messages in thread
From: Jing Zhang @ 2023-07-10 20:54 UTC (permalink / raw)
To: Oliver Upton
Cc: KVM, KVMARM, ARMLinux, Marc Zyngier, Will Deacon, Paolo Bonzini,
James Morse, Alexandru Elisei, Suzuki K Poulose, Fuad Tabba,
Reiji Watanabe, Raghavendra Rao Ananta, Suraj Jitindar Singh,
Cornelia Huck
Hi Oliver,
On Mon, Jul 10, 2023 at 1:18 PM Oliver Upton <oliver.upton@linux.dev> wrote:
>
> Jing,
>
> On Mon, Jul 10, 2023 at 07:24:26PM +0000, Jing Zhang wrote:
> > From: Oliver Upton <oliver.upton@linux.dev>
> >
> > The debug architecture is mandatory in ARMv8, so KVM should not allow
> > userspace to configure a vCPU with less than that. Of course, this isn't
> > handled elegantly by the generic ID register plumbing, as the respective
> > ID register fields have a nonzero starting value.
> >
> > Add an explicit check for debug versions less than v8 of the
> > architecture.
> >
> > Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
> > Signed-off-by: Jing Zhang <jingzhangos@google.com>
>
> This patch should be ordered before the change that permits writes to
> the DebugVer field (i.e. the previous patch). While we're at it, there's
> another set of prerequisites for actually making the field writable.
>
> As Suraj pointed out earlier, we need to override the type of the field
> to be FTR_LOWER_SAFE instead of EXACT. Beyond that, KVM limits the field
> to 0x6, which is the minimum value for an ARMv8 implementation. We can
> relax this limitation up to v8p8, as I believe all of the changes are to
> external debug and wouldn't affect a KVM guest.
>
> Below is my (untested) diff on top of your series for both of these
> changes.
>
> --
> Thanks,
> Oliver
>
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 78ccc95624fa..35c4ab8cb5c8 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1216,8 +1216,14 @@ static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
> /* Some features have different safe value type in KVM than host features */
> switch (id) {
> case SYS_ID_AA64DFR0_EL1:
> - if (kvm_ftr.shift == ID_AA64DFR0_EL1_PMUVer_SHIFT)
> + switch (kvm_ftr.shift) {
> + case ID_AA64DFR0_EL1_PMUVer_SHIFT:
> kvm_ftr.type = FTR_LOWER_SAFE;
> + break;
> + case ID_AA64DFR0_EL1_DebugVer_SHIFT:
> + kvm_ftr.type = FTR_LOWER_SAFE;
> + break;
> + }
> break;
> case SYS_ID_DFR0_EL1:
> if (kvm_ftr.shift == ID_DFR0_EL1_PerfMon_SHIFT)
> @@ -1466,14 +1472,22 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
> return val;
> }
>
> +#define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit) \
> +({ \
> + u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
> + (val) &= ~reg##_##field##_MASK; \
> + (val) |= FIELD_PREP(reg##_##field##_MASK, \
> + min(__f_val, (u64)reg##_##field##_##limit)); \
> + (val); \
> +})
> +
> static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
> const struct sys_reg_desc *rd)
> {
> u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);
>
> /* Limit debug to ARMv8.0 */
> - val &= ~ID_AA64DFR0_EL1_DebugVer_MASK;
> - val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, IMP);
> + val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
>
> /*
> * Only initialize the PMU version if the vCPU was configured with one.
> @@ -1529,6 +1543,8 @@ static u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu,
> u8 perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit());
> u64 val = read_sanitised_ftr_reg(SYS_ID_DFR0_EL1);
>
> + val = ID_REG_LIMIT_FIELD_ENUM(val, ID_DFR0_EL1, CopDbg, Debugv8p8);
> +
> val &= ~ID_DFR0_EL1_PerfMon_MASK;
> if (kvm_vcpu_has_pmu(vcpu))
> val |= SYS_FIELD_PREP(ID_DFR0_EL1, PerfMon, perfmon);
>
Thanks for the details. Will improve it in the next version.
Jing
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2023-07-10 20:55 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-10 19:24 [PATCH v5 0/6] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2, 3} Jing Zhang
2023-07-10 19:24 ` [PATCH v5 1/6] KVM: arm64: Use guest ID register values for the sake of emulation Jing Zhang
2023-07-10 19:24 ` [PATCH v5 2/6] KVM: arm64: Enable writable for ID_AA64DFR0_EL1 and ID_DFR0_EL1 Jing Zhang
2023-07-10 19:24 ` [PATCH v5 3/6] KVM: arm64: Reject attempts to set invalid debug arch version Jing Zhang
2023-07-10 20:18 ` Oliver Upton
2023-07-10 20:54 ` Jing Zhang
2023-07-10 19:24 ` [PATCH v5 4/6] KVM: arm64: Enable writable for ID_AA64PFR0_EL1 Jing Zhang
2023-07-10 19:24 ` [PATCH v5 5/6] KVM: arm64: Enable writable for ID_AA64MMFR{0, 1, 2, 3}_EL1 Jing Zhang
2023-07-10 19:24 ` [PATCH v5 6/6] KVM: arm64: selftests: Test for setting ID register from usersapce Jing Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).