* [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock
@ 2021-12-14 17:28 Oliver Upton
2021-12-14 17:28 ` [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined Oliver Upton
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
KVM does not implement the debug architecture to the letter of the
specification. One such issue is the fact that KVM treats the OS Lock as
RAZ/WI, rather than emulating its behavior on hardware. This series adds
emulation support for the OS Lock to KVM. Emulation is warranted as the
OS Lock affects debug exceptions taken from all ELs, and is not limited
to only the context of the guest.
The 1st patch is a correctness fix for the OSLSR register, ensuring
the trap handler actually is written to suggest WO behavior. Note that
the changed code should never be reached on a correct implementation, as
hardware should generate the undef, not KVM.
The 2nd patch adds the necessary context to track guest values of the
OS Lock bit and exposes the value to userspace for the sake of
migration.
The 3rd patch makes the OSLK bit writable in OSLAR_EL1 (from the guest)
and OSLSR_EL1 (from userspace), but does nothing with its value.
The 4th patch actually implements the OS Lock behavior, disabling all
debug exceptions (except breakpoint instructions) from the perspective
of the guest. This is done by disabling MDE and SS in MDSCR_EL1.
The 5th patch asserts that OSLSR_EL1 is exposed by KVM to userspace
through the KVM_GET_REG_LIST ioctl. Lastly, the 6th patch asserts that
no debug exceptions are routed to the guest when the OSLK bit is set.
This series applies cleanly to 5.16-rc4. Tested on an Ampere Altra
machine with the included selftests patches.
Oliver Upton (6):
KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined
KVM: arm64: Stash OSLSR_EL1 in the cpu context
KVM: arm64: Allow guest to set the OSLK bit
KVM: arm64: Emulate the OS Lock
selftests: KVM: Add OSLSR_EL1 to the list of blessed regs
selftests: KVM: Test OS lock behavior
arch/arm64/include/asm/kvm_host.h | 6 ++
arch/arm64/include/asm/sysreg.h | 9 +++
arch/arm64/kvm/debug.c | 26 ++++++-
arch/arm64/kvm/sys_regs.c | 74 ++++++++++++++-----
.../selftests/kvm/aarch64/debug-exceptions.c | 58 ++++++++++++++-
.../selftests/kvm/aarch64/get-reg-list.c | 1 +
6 files changed, 151 insertions(+), 23 deletions(-)
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
@ 2021-12-14 17:28 ` Oliver Upton
2021-12-15 11:39 ` Mark Rutland
2021-12-14 17:28 ` [PATCH v4 2/6] KVM: arm64: Stash OSLSR_EL1 in the cpu context Oliver Upton
` (4 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
Any valid implementation of the architecture should generate an
undefined exception for writes to a read-only register, such as
OSLSR_EL1. Nonetheless, the KVM handler actually implements write-ignore
behavior.
Align the trap handler for OSLSR_EL1 with hardware behavior. If such a
write ever traps to EL2, inject an undef into the guest and print a
warning.
Reviewed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Oliver Upton <oupton@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 e3ec1a44f94d..11b4212c2036 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -292,7 +292,7 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
const struct sys_reg_desc *r)
{
if (p->is_write) {
- return ignore_write(vcpu, p);
+ return write_to_read_only(vcpu, p, r);
} else {
p->regval = (1 << 3);
return true;
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* [PATCH v4 2/6] KVM: arm64: Stash OSLSR_EL1 in the cpu context
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
2021-12-14 17:28 ` [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined Oliver Upton
@ 2021-12-14 17:28 ` Oliver Upton
2021-12-15 11:57 ` Mark Rutland
2021-12-14 17:28 ` [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit Oliver Upton
` (3 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
An upcoming change to KVM will context switch the OS Lock status between
guest/host. Add OSLSR_EL1 to the cpu context and handle guest reads
using the stored value.
Wire up a custom handler for writes from userspace and prevent any of
the invariant bits from changing.
Reviewed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Oliver Upton <oupton@google.com>
---
arch/arm64/include/asm/kvm_host.h | 2 ++
arch/arm64/kvm/sys_regs.c | 31 ++++++++++++++++++++++++-------
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 2a5f7f38006f..53fc8a6eaf1c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -172,8 +172,10 @@ enum vcpu_sysreg {
PAR_EL1, /* Physical Address Register */
MDSCR_EL1, /* Monitor Debug System Control Register */
MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
+ OSLSR_EL1, /* OS Lock Status Register */
DISR_EL1, /* Deferred Interrupt Status Register */
+
/* Performance Monitors Registers */
PMCR_EL0, /* Control Register */
PMSELR_EL0, /* Event Counter Selection Register */
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 11b4212c2036..7bf350b3d9cd 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -291,12 +291,28 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
- if (p->is_write) {
+ if (p->is_write)
return write_to_read_only(vcpu, p, r);
- } else {
- p->regval = (1 << 3);
- return true;
- }
+
+ p->regval = __vcpu_sys_reg(vcpu, r->reg);
+ return true;
+}
+
+static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+ const struct kvm_one_reg *reg, void __user *uaddr)
+{
+ u64 id = sys_reg_to_index(rd);
+ u64 val;
+ int err;
+
+ err = reg_from_user(&val, uaddr, id);
+ if (err)
+ return err;
+
+ if (val != rd->val)
+ return -EINVAL;
+
+ return 0;
}
static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
@@ -1448,7 +1464,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ SYS_DESC(SYS_MDRAR_EL1), trap_raz_wi },
{ SYS_DESC(SYS_OSLAR_EL1), trap_raz_wi },
- { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1 },
+ { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, 0x00000008,
+ .set_user = set_oslsr_el1, },
{ SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
{ SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
{ SYS_DESC(SYS_DBGCLAIMSET_EL1), trap_raz_wi },
@@ -1923,7 +1940,7 @@ static const struct sys_reg_desc cp14_regs[] = {
{ Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_raz_wi },
DBGBXVR(1),
/* DBGOSLSR */
- { Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1 },
+ { Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1, NULL, OSLSR_EL1 },
DBGBXVR(2),
DBGBXVR(3),
/* DBGOSDLR */
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
2021-12-14 17:28 ` [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined Oliver Upton
2021-12-14 17:28 ` [PATCH v4 2/6] KVM: arm64: Stash OSLSR_EL1 in the cpu context Oliver Upton
@ 2021-12-14 17:28 ` Oliver Upton
2021-12-15 12:15 ` Mark Rutland
2021-12-14 17:28 ` [PATCH v4 4/6] KVM: arm64: Emulate the OS Lock Oliver Upton
` (2 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
Allow writes to OSLAR and forward the OSLK bit to OSLSR. Do nothing with
the value for now.
Reviewed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Oliver Upton <oupton@google.com>
---
arch/arm64/include/asm/sysreg.h | 9 ++++++++
arch/arm64/kvm/sys_regs.c | 39 ++++++++++++++++++++++++++-------
2 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 16b3f1a1d468..46f800bda045 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -129,7 +129,16 @@
#define SYS_DBGWCRn_EL1(n) sys_reg(2, 0, 0, n, 7)
#define SYS_MDRAR_EL1 sys_reg(2, 0, 1, 0, 0)
#define SYS_OSLAR_EL1 sys_reg(2, 0, 1, 0, 4)
+
+#define SYS_OSLAR_OSLK BIT(0)
+
#define SYS_OSLSR_EL1 sys_reg(2, 0, 1, 1, 4)
+
+#define SYS_OSLSR_OSLK BIT(1)
+
+#define SYS_OSLSR_OSLM_MASK (BIT(3) | BIT(0))
+#define SYS_OSLSR_OSLM BIT(3)
+
#define SYS_OSDLR_EL1 sys_reg(2, 0, 1, 3, 4)
#define SYS_DBGPRCR_EL1 sys_reg(2, 0, 1, 4, 4)
#define SYS_DBGCLAIMSET_EL1 sys_reg(2, 0, 7, 8, 6)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 7bf350b3d9cd..5188a74095e3 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -44,6 +44,10 @@
* 64bit interface.
*/
+static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
+static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
+static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
+
static bool read_from_write_only(struct kvm_vcpu *vcpu,
struct sys_reg_params *params,
const struct sys_reg_desc *r)
@@ -287,6 +291,24 @@ static bool trap_loregion(struct kvm_vcpu *vcpu,
return trap_raz_wi(vcpu, p, r);
}
+static bool trap_oslar_el1(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ u64 oslsr;
+
+ if (!p->is_write)
+ return read_from_write_only(vcpu, p, r);
+
+ /* Forward the OSLK bit to OSLSR */
+ oslsr = __vcpu_sys_reg(vcpu, OSLSR_EL1) & ~SYS_OSLSR_OSLK;
+ if (p->regval & SYS_OSLAR_OSLK)
+ oslsr |= SYS_OSLSR_OSLK;
+
+ __vcpu_sys_reg(vcpu, OSLSR_EL1) = oslsr;
+ return true;
+}
+
static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
@@ -309,9 +331,14 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
if (err)
return err;
- if (val != rd->val)
+ /*
+ * The only modifiable bit is the OSLK bit. Refuse the write if
+ * userspace attempts to change any other bit in the register.
+ */
+ if ((val & ~SYS_OSLSR_OSLK) != SYS_OSLSR_OSLM)
return -EINVAL;
+ __vcpu_sys_reg(vcpu, rd->reg) = val;
return 0;
}
@@ -1180,10 +1207,6 @@ static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
return __access_id_reg(vcpu, p, r, true);
}
-static int reg_from_user(u64 *val, const void __user *uaddr, u64 id);
-static int reg_to_user(void __user *uaddr, const u64 *val, u64 id);
-static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
-
/* Visibility overrides for SVE-specific control registers */
static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
const struct sys_reg_desc *rd)
@@ -1463,8 +1486,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
DBG_BCR_BVR_WCR_WVR_EL1(15),
{ SYS_DESC(SYS_MDRAR_EL1), trap_raz_wi },
- { SYS_DESC(SYS_OSLAR_EL1), trap_raz_wi },
- { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, 0x00000008,
+ { SYS_DESC(SYS_OSLAR_EL1), trap_oslar_el1 },
+ { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, SYS_OSLSR_OSLM,
.set_user = set_oslsr_el1, },
{ SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
{ SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
@@ -1937,7 +1960,7 @@ static const struct sys_reg_desc cp14_regs[] = {
DBGBXVR(0),
/* DBGOSLAR */
- { Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_raz_wi },
+ { Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_oslar_el1 },
DBGBXVR(1),
/* DBGOSLSR */
{ Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1, NULL, OSLSR_EL1 },
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* [PATCH v4 4/6] KVM: arm64: Emulate the OS Lock
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
` (2 preceding siblings ...)
2021-12-14 17:28 ` [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit Oliver Upton
@ 2021-12-14 17:28 ` Oliver Upton
2021-12-14 17:28 ` [PATCH v4 5/6] selftests: KVM: Add OSLSR_EL1 to the list of blessed regs Oliver Upton
2021-12-14 17:28 ` [PATCH v4 6/6] selftests: KVM: Test OS lock behavior Oliver Upton
5 siblings, 0 replies; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
The OS lock blocks all debug exceptions at every EL. To date, KVM has
not implemented the OS lock for its guests, despite the fact that it is
mandatory per the architecture. Simple context switching between the
guest and host is not appropriate, as its effects are not constrained to
the guest context.
Emulate the OS Lock by clearing MDE and SS in MDSCR_EL1, thereby
blocking all but software breakpoint instructions.
Signed-off-by: Oliver Upton <oupton@google.com>
---
arch/arm64/include/asm/kvm_host.h | 4 ++++
arch/arm64/kvm/debug.c | 26 ++++++++++++++++++++++----
arch/arm64/kvm/sys_regs.c | 6 +++---
3 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 53fc8a6eaf1c..e5a06ff1cba6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -726,6 +726,10 @@ void kvm_arm_vcpu_init_debug(struct kvm_vcpu *vcpu);
void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
+
+#define kvm_vcpu_os_lock_enabled(vcpu) \
+ (!!(__vcpu_sys_reg(vcpu, OSLSR_EL1) & SYS_OSLSR_OSLK))
+
int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr);
int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index db9361338b2a..4fd5c216c4bb 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -105,9 +105,11 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
* - Userspace is using the hardware to debug the guest
* (KVM_GUESTDBG_USE_HW is set).
* - The guest is not using debug (KVM_ARM64_DEBUG_DIRTY is clear).
+ * - The guest has enabled the OS Lock (debug exceptions are blocked).
*/
if ((vcpu->guest_debug & KVM_GUESTDBG_USE_HW) ||
- !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY))
+ !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY) ||
+ kvm_vcpu_os_lock_enabled(vcpu))
vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2);
@@ -160,8 +162,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
kvm_arm_setup_mdcr_el2(vcpu);
- /* Is Guest debugging in effect? */
- if (vcpu->guest_debug) {
+ /* Check if we need to use the debug registers. */
+ if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
/* Save guest debug state */
save_guest_debug_regs(vcpu);
@@ -223,6 +225,19 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu)
trace_kvm_arm_set_regset("WAPTS", get_num_wrps(),
&vcpu->arch.debug_ptr->dbg_wcr[0],
&vcpu->arch.debug_ptr->dbg_wvr[0]);
+
+ /*
+ * The OS Lock blocks debug exceptions in all ELs when it is
+ * enabled. If the guest has enabled the OS Lock, constrain its
+ * effects to the guest. Emulate the behavior by clearing
+ * MDSCR_EL1.MDE. In so doing, we ensure that host debug
+ * exceptions are unaffected by guest configuration of the OS
+ * Lock.
+ */
+ } else if (kvm_vcpu_os_lock_enabled(vcpu)) {
+ mdscr = vcpu_read_sys_reg(vcpu, MDSCR_EL1);
+ mdscr &= ~DBG_MDSCR_MDE;
+ vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1);
}
}
@@ -244,7 +259,10 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu)
{
trace_kvm_arm_clear_debug(vcpu->guest_debug);
- if (vcpu->guest_debug) {
+ /*
+ * Restore the guest's debug registers if we were using them.
+ */
+ if (vcpu->guest_debug || kvm_vcpu_os_lock_enabled(vcpu)) {
restore_guest_debug_regs(vcpu);
/*
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5188a74095e3..50a6966aab1b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1457,9 +1457,9 @@ static unsigned int mte_visibility(const struct kvm_vcpu *vcpu,
* Debug handling: We do trap most, if not all debug related system
* registers. The implementation is good enough to ensure that a guest
* can use these with minimal performance degradation. The drawback is
- * that we don't implement any of the external debug, none of the
- * OSlock protocol. This should be revisited if we ever encounter a
- * more demanding guest...
+ * that we don't implement any of the external debug architecture.
+ * This should be revisited if we ever encounter a more demanding
+ * guest...
*/
static const struct sys_reg_desc sys_reg_descs[] = {
{ SYS_DESC(SYS_DC_ISW), access_dcsw },
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* [PATCH v4 5/6] selftests: KVM: Add OSLSR_EL1 to the list of blessed regs
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
` (3 preceding siblings ...)
2021-12-14 17:28 ` [PATCH v4 4/6] KVM: arm64: Emulate the OS Lock Oliver Upton
@ 2021-12-14 17:28 ` Oliver Upton
2021-12-14 17:28 ` [PATCH v4 6/6] selftests: KVM: Test OS lock behavior Oliver Upton
5 siblings, 0 replies; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
OSLSR_EL1 is now part of the visible system register state. Add it to
the get-reg-list selftest to ensure we keep it that way.
Signed-off-by: Oliver Upton <oupton@google.com>
---
tools/testing/selftests/kvm/aarch64/get-reg-list.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
index cc898181faab..0c7c39a16b3f 100644
--- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c
+++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c
@@ -761,6 +761,7 @@ static __u64 base_regs[] = {
ARM64_SYS_REG(2, 0, 0, 15, 6),
ARM64_SYS_REG(2, 0, 0, 15, 7),
ARM64_SYS_REG(2, 4, 0, 7, 0), /* DBGVCR32_EL2 */
+ ARM64_SYS_REG(2, 0, 1, 1, 4), /* OSLSR_EL1 */
ARM64_SYS_REG(3, 0, 0, 0, 5), /* MPIDR_EL1 */
ARM64_SYS_REG(3, 0, 0, 1, 0), /* ID_PFR0_EL1 */
ARM64_SYS_REG(3, 0, 0, 1, 1), /* ID_PFR1_EL1 */
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* [PATCH v4 6/6] selftests: KVM: Test OS lock behavior
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
` (4 preceding siblings ...)
2021-12-14 17:28 ` [PATCH v4 5/6] selftests: KVM: Add OSLSR_EL1 to the list of blessed regs Oliver Upton
@ 2021-12-14 17:28 ` Oliver Upton
5 siblings, 0 replies; 13+ messages in thread
From: Oliver Upton @ 2021-12-14 17:28 UTC (permalink / raw)
To: kvmarm
Cc: kvm, Marc Zyngier, James Morse, Alexandru Elisei,
Suzuki K Poulose, linux-arm-kernel, Andrew Jones, Peter Shier,
Ricardo Koller, Reiji Watanabe, Oliver Upton
KVM now correctly handles the OS Lock for its guests. When set, KVM
blocks all debug exceptions originating from the guest. Add test cases
to the debug-exceptions test to assert that software breakpoint,
hardware breakpoint, watchpoint, and single-step exceptions are in fact
blocked.
Signed-off-by: Oliver Upton <oupton@google.com>
---
.../selftests/kvm/aarch64/debug-exceptions.c | 58 ++++++++++++++++++-
1 file changed, 56 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c
index ea189d83abf7..63b2178210c4 100644
--- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c
+++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c
@@ -23,7 +23,7 @@
#define SPSR_D (1 << 9)
#define SPSR_SS (1 << 21)
-extern unsigned char sw_bp, hw_bp, bp_svc, bp_brk, hw_wp, ss_start;
+extern unsigned char sw_bp, sw_bp2, hw_bp, hw_bp2, bp_svc, bp_brk, hw_wp, ss_start;
static volatile uint64_t sw_bp_addr, hw_bp_addr;
static volatile uint64_t wp_addr, wp_data_addr;
static volatile uint64_t svc_addr;
@@ -47,6 +47,14 @@ static void reset_debug_state(void)
isb();
}
+static void enable_os_lock(void)
+{
+ write_sysreg(1, oslar_el1);
+ isb();
+
+ GUEST_ASSERT(read_sysreg(oslsr_el1) & 2);
+}
+
static void install_wp(uint64_t addr)
{
uint32_t wcr;
@@ -99,6 +107,7 @@ static void guest_code(void)
GUEST_SYNC(0);
/* Software-breakpoint */
+ reset_debug_state();
asm volatile("sw_bp: brk #0");
GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp));
@@ -152,6 +161,51 @@ static void guest_code(void)
GUEST_ASSERT_EQ(ss_addr[1], PC(ss_start) + 4);
GUEST_ASSERT_EQ(ss_addr[2], PC(ss_start) + 8);
+ GUEST_SYNC(6);
+
+ /* OS Lock does not block software-breakpoint */
+ reset_debug_state();
+ enable_os_lock();
+ sw_bp_addr = 0;
+ asm volatile("sw_bp2: brk #0");
+ GUEST_ASSERT_EQ(sw_bp_addr, PC(sw_bp2));
+
+ GUEST_SYNC(7);
+
+ /* OS Lock blocking hardware-breakpoint */
+ reset_debug_state();
+ enable_os_lock();
+ install_hw_bp(PC(hw_bp2));
+ hw_bp_addr = 0;
+ asm volatile("hw_bp2: nop");
+ GUEST_ASSERT_EQ(hw_bp_addr, 0);
+
+ GUEST_SYNC(8);
+
+ /* OS Lock blocking watchpoint */
+ reset_debug_state();
+ enable_os_lock();
+ write_data = '\0';
+ wp_data_addr = 0;
+ install_wp(PC(write_data));
+ write_data = 'x';
+ GUEST_ASSERT_EQ(write_data, 'x');
+ GUEST_ASSERT_EQ(wp_data_addr, 0);
+
+ GUEST_SYNC(9);
+
+ /* OS Lock blocking single-step */
+ reset_debug_state();
+ enable_os_lock();
+ ss_addr[0] = 0;
+ install_ss();
+ ss_idx = 0;
+ asm volatile("mrs x0, esr_el1\n\t"
+ "add x0, x0, #1\n\t"
+ "msr daifset, #8\n\t"
+ : : : "x0");
+ GUEST_ASSERT_EQ(ss_addr[0], 0);
+
GUEST_DONE();
}
@@ -223,7 +277,7 @@ int main(int argc, char *argv[])
vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT,
ESR_EC_SVC64, guest_svc_handler);
- for (stage = 0; stage < 7; stage++) {
+ for (stage = 0; stage < 11; stage++) {
vcpu_run(vm, VCPU_ID);
switch (get_ucall(vm, VCPU_ID, &uc)) {
--
2.34.1.173.g76aa8bc2d0-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] 13+ messages in thread
* Re: [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined
2021-12-14 17:28 ` [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined Oliver Upton
@ 2021-12-15 11:39 ` Mark Rutland
2021-12-15 13:09 ` Oliver Upton
0 siblings, 1 reply; 13+ messages in thread
From: Mark Rutland @ 2021-12-15 11:39 UTC (permalink / raw)
To: Oliver Upton; +Cc: kvmarm, kvm, Marc Zyngier, Peter Shier, linux-arm-kernel
Hi Oliver,
On Tue, Dec 14, 2021 at 05:28:07PM +0000, Oliver Upton wrote:
> Any valid implementation of the architecture should generate an
> undefined exception for writes to a read-only register, such as
> OSLSR_EL1. Nonetheless, the KVM handler actually implements write-ignore
> behavior.
>
> Align the trap handler for OSLSR_EL1 with hardware behavior. If such a
> write ever traps to EL2, inject an undef into the guest and print a
> warning.
I think this can still be read amibguously, since we don't explicitly state
that writes to OSLSR_EL1 should never trap (and the implications of being
UNDEFINED are subtle). How about:
| Writes to OSLSR_EL1 are UNDEFINED and should never trap from EL1 to EL2, but
| the KVM trap handler for OSLSR_EL1 handlees writes via ignore_write(). This
| is confusing to readers of the code, but shouldn't have any functional impact.
|
| For clarity, use write_to_read_only() rather than ignore_write(). If a trap
| is unexpectedly taken to EL2 in violation of the architecture, this will
| WARN_ONCE() and inject an undef into the guest.
With that:
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Mark.
> Reviewed-by: Reiji Watanabe <reijiw@google.com>
> Signed-off-by: Oliver Upton <oupton@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 e3ec1a44f94d..11b4212c2036 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -292,7 +292,7 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
> const struct sys_reg_desc *r)
> {
> if (p->is_write) {
> - return ignore_write(vcpu, p);
> + return write_to_read_only(vcpu, p, r);
> } else {
> p->regval = (1 << 3);
> return true;
> --
> 2.34.1.173.g76aa8bc2d0-goog
>
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
_______________________________________________
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] 13+ messages in thread
* Re: [PATCH v4 2/6] KVM: arm64: Stash OSLSR_EL1 in the cpu context
2021-12-14 17:28 ` [PATCH v4 2/6] KVM: arm64: Stash OSLSR_EL1 in the cpu context Oliver Upton
@ 2021-12-15 11:57 ` Mark Rutland
0 siblings, 0 replies; 13+ messages in thread
From: Mark Rutland @ 2021-12-15 11:57 UTC (permalink / raw)
To: Oliver Upton; +Cc: kvmarm, kvm, Marc Zyngier, Peter Shier, linux-arm-kernel
On Tue, Dec 14, 2021 at 05:28:08PM +0000, Oliver Upton wrote:
> An upcoming change to KVM will context switch the OS Lock status between
> guest/host. Add OSLSR_EL1 to the cpu context and handle guest reads
> using the stored value.
The "context switch" wording is stale here, since later patches emulate the
behaviour of the OS lock (and explain why a context switch isn't appropriate).
That first sentence needs to change to something like:
| An upcoming change to KVM will emulate the OS Lock from the PoV of the guest.
> Wire up a custom handler for writes from userspace and prevent any of
> the invariant bits from changing.
>
> Reviewed-by: Reiji Watanabe <reijiw@google.com>
> Signed-off-by: Oliver Upton <oupton@google.com>
> ---
> arch/arm64/include/asm/kvm_host.h | 2 ++
> arch/arm64/kvm/sys_regs.c | 31 ++++++++++++++++++++++++-------
> 2 files changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 2a5f7f38006f..53fc8a6eaf1c 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -172,8 +172,10 @@ enum vcpu_sysreg {
> PAR_EL1, /* Physical Address Register */
> MDSCR_EL1, /* Monitor Debug System Control Register */
> MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
> + OSLSR_EL1, /* OS Lock Status Register */
> DISR_EL1, /* Deferred Interrupt Status Register */
>
> +
I don't think this whitespace needed to change.
> /* Performance Monitors Registers */
> PMCR_EL0, /* Control Register */
> PMSELR_EL0, /* Event Counter Selection Register */
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 11b4212c2036..7bf350b3d9cd 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -291,12 +291,28 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
> struct sys_reg_params *p,
> const struct sys_reg_desc *r)
> {
> - if (p->is_write) {
> + if (p->is_write)
> return write_to_read_only(vcpu, p, r);
> - } else {
> - p->regval = (1 << 3);
> - return true;
> - }
> +
> + p->regval = __vcpu_sys_reg(vcpu, r->reg);
> + return true;
> +}
> +
> +static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> + const struct kvm_one_reg *reg, void __user *uaddr)
> +{
> + u64 id = sys_reg_to_index(rd);
> + u64 val;
> + int err;
> +
> + err = reg_from_user(&val, uaddr, id);
> + if (err)
> + return err;
> +
> + if (val != rd->val)
> + return -EINVAL;
Bit 1 isn't invariant; why can't the user set that? If there's a rationale,
that needs to be stated in the commit message.
> +
> + return 0;
> }
>
> static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
> @@ -1448,7 +1464,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>
> { SYS_DESC(SYS_MDRAR_EL1), trap_raz_wi },
> { SYS_DESC(SYS_OSLAR_EL1), trap_raz_wi },
> - { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1 },
> + { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, 0x00000008,
Could we add mnemonics for this to <asm/sysreg.h>, e.g.
#define OSLSR_EL1_OSLM_LOCK_NI 0
#define OSLSR_EL1_OSLM_LOCK_IMPLEMENTED BIT(3)
... and use that here for clarity?
Thanks,
Mark.
> + .set_user = set_oslsr_el1, },
> { SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
> { SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
> { SYS_DESC(SYS_DBGCLAIMSET_EL1), trap_raz_wi },
> @@ -1923,7 +1940,7 @@ static const struct sys_reg_desc cp14_regs[] = {
> { Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_raz_wi },
> DBGBXVR(1),
> /* DBGOSLSR */
> - { Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1 },
> + { Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1, NULL, OSLSR_EL1 },
> DBGBXVR(2),
> DBGBXVR(3),
> /* DBGOSDLR */
> --
> 2.34.1.173.g76aa8bc2d0-goog
>
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
_______________________________________________
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] 13+ messages in thread
* Re: [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit
2021-12-14 17:28 ` [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit Oliver Upton
@ 2021-12-15 12:15 ` Mark Rutland
2022-02-03 17:37 ` Oliver Upton
0 siblings, 1 reply; 13+ messages in thread
From: Mark Rutland @ 2021-12-15 12:15 UTC (permalink / raw)
To: Oliver Upton; +Cc: kvmarm, kvm, Marc Zyngier, Peter Shier, linux-arm-kernel
On Tue, Dec 14, 2021 at 05:28:09PM +0000, Oliver Upton wrote:
> Allow writes to OSLAR and forward the OSLK bit to OSLSR. Do nothing with
> the value for now.
>
> Reviewed-by: Reiji Watanabe <reijiw@google.com>
> Signed-off-by: Oliver Upton <oupton@google.com>
> ---
> arch/arm64/include/asm/sysreg.h | 9 ++++++++
> arch/arm64/kvm/sys_regs.c | 39 ++++++++++++++++++++++++++-------
> 2 files changed, 40 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 16b3f1a1d468..46f800bda045 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -129,7 +129,16 @@
> #define SYS_DBGWCRn_EL1(n) sys_reg(2, 0, 0, n, 7)
> #define SYS_MDRAR_EL1 sys_reg(2, 0, 1, 0, 0)
> #define SYS_OSLAR_EL1 sys_reg(2, 0, 1, 0, 4)
> +
> +#define SYS_OSLAR_OSLK BIT(0)
> +
> #define SYS_OSLSR_EL1 sys_reg(2, 0, 1, 1, 4)
> +
> +#define SYS_OSLSR_OSLK BIT(1)
> +
> +#define SYS_OSLSR_OSLM_MASK (BIT(3) | BIT(0))
> +#define SYS_OSLSR_OSLM BIT(3)
Since `OSLM` is the field as a whole, I think this should have another level of
hierarchy, e.g.
#define SYS_OSLSR_OSLM_MASK (BIT(3) | BIT(0))
#define SYS_OSLSR_OSLM_NI 0
#define SYS_OSLSR_OSLM_OSLK BIT(3)
[...]
> +static bool trap_oslar_el1(struct kvm_vcpu *vcpu,
> + struct sys_reg_params *p,
> + const struct sys_reg_desc *r)
> +{
> + u64 oslsr;
> +
> + if (!p->is_write)
> + return read_from_write_only(vcpu, p, r);
> +
> + /* Forward the OSLK bit to OSLSR */
> + oslsr = __vcpu_sys_reg(vcpu, OSLSR_EL1) & ~SYS_OSLSR_OSLK;
> + if (p->regval & SYS_OSLAR_OSLK)
> + oslsr |= SYS_OSLSR_OSLK;
> +
> + __vcpu_sys_reg(vcpu, OSLSR_EL1) = oslsr;
> + return true;
> +}
Does changing this affect existing userspace? Previosuly it could read
OSLAR_EL1 as 0, whereas now that should be rejected.
That might be fine, and if so, it would be good to call that out in the commit
message.
[...]
> @@ -309,9 +331,14 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> if (err)
> return err;
>
> - if (val != rd->val)
> + /*
> + * The only modifiable bit is the OSLK bit. Refuse the write if
> + * userspace attempts to change any other bit in the register.
> + */
> + if ((val & ~SYS_OSLSR_OSLK) != SYS_OSLSR_OSLM)
> return -EINVAL;
How about:
if ((val ^ rd->val) & ~SYS_OSLSR_OSLK)
return -EINVAL;
... so that we don't need to hard-code the expected value here, and can more
easily change it in future?
[...]
> @@ -1463,8 +1486,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
> DBG_BCR_BVR_WCR_WVR_EL1(15),
>
> { SYS_DESC(SYS_MDRAR_EL1), trap_raz_wi },
> - { SYS_DESC(SYS_OSLAR_EL1), trap_raz_wi },
> - { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, 0x00000008,
> + { SYS_DESC(SYS_OSLAR_EL1), trap_oslar_el1 },
> + { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, SYS_OSLSR_OSLM,
> .set_user = set_oslsr_el1, },
> { SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
> { SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
> @@ -1937,7 +1960,7 @@ static const struct sys_reg_desc cp14_regs[] = {
>
> DBGBXVR(0),
> /* DBGOSLAR */
> - { Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_raz_wi },
> + { Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_oslar_el1 },
As above, I have a slight concern that this could adversely affect existing
userspace, but I can also believe that's fine.
Thanks,
Mark.
_______________________________________________
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] 13+ messages in thread
* Re: [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined
2021-12-15 11:39 ` Mark Rutland
@ 2021-12-15 13:09 ` Oliver Upton
2021-12-15 14:32 ` Mark Rutland
0 siblings, 1 reply; 13+ messages in thread
From: Oliver Upton @ 2021-12-15 13:09 UTC (permalink / raw)
To: Mark Rutland; +Cc: kvmarm, kvm, Marc Zyngier, Peter Shier, linux-arm-kernel
Hi Mark,
On Wed, Dec 15, 2021 at 11:39:58AM +0000, Mark Rutland wrote:
> Hi Oliver,
>
> On Tue, Dec 14, 2021 at 05:28:07PM +0000, Oliver Upton wrote:
> > Any valid implementation of the architecture should generate an
> > undefined exception for writes to a read-only register, such as
> > OSLSR_EL1. Nonetheless, the KVM handler actually implements write-ignore
> > behavior.
> >
> > Align the trap handler for OSLSR_EL1 with hardware behavior. If such a
> > write ever traps to EL2, inject an undef into the guest and print a
> > warning.
>
> I think this can still be read amibguously, since we don't explicitly state
> that writes to OSLSR_EL1 should never trap (and the implications of being
> UNDEFINED are subtle). How about:
>
> | Writes to OSLSR_EL1 are UNDEFINED and should never trap from EL1 to EL2, but
> | the KVM trap handler for OSLSR_EL1 handlees writes via ignore_write(). This
> | is confusing to readers of the code, but shouldn't have any functional impact.
> |
> | For clarity, use write_to_read_only() rather than ignore_write(). If a trap
> | is unexpectedly taken to EL2 in violation of the architecture, this will
> | WARN_ONCE() and inject an undef into the guest.
Agreed, I like your suggested changelog better :-)
> With that:
>
> Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Thanks!
--
Best,
Oliver
_______________________________________________
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] 13+ messages in thread
* Re: [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined
2021-12-15 13:09 ` Oliver Upton
@ 2021-12-15 14:32 ` Mark Rutland
0 siblings, 0 replies; 13+ messages in thread
From: Mark Rutland @ 2021-12-15 14:32 UTC (permalink / raw)
To: Oliver Upton; +Cc: kvmarm, kvm, Marc Zyngier, Peter Shier, linux-arm-kernel
On Wed, Dec 15, 2021 at 01:09:28PM +0000, Oliver Upton wrote:
> Hi Mark,
>
> On Wed, Dec 15, 2021 at 11:39:58AM +0000, Mark Rutland wrote:
> > Hi Oliver,
> >
> > On Tue, Dec 14, 2021 at 05:28:07PM +0000, Oliver Upton wrote:
> > > Any valid implementation of the architecture should generate an
> > > undefined exception for writes to a read-only register, such as
> > > OSLSR_EL1. Nonetheless, the KVM handler actually implements write-ignore
> > > behavior.
> > >
> > > Align the trap handler for OSLSR_EL1 with hardware behavior. If such a
> > > write ever traps to EL2, inject an undef into the guest and print a
> > > warning.
> >
> > I think this can still be read amibguously, since we don't explicitly state
> > that writes to OSLSR_EL1 should never trap (and the implications of being
> > UNDEFINED are subtle). How about:
> >
> > | Writes to OSLSR_EL1 are UNDEFINED and should never trap from EL1 to EL2, but
> > | the KVM trap handler for OSLSR_EL1 handlees writes via ignore_write(). This
Whoops, with s/handlees/handles/
> > | is confusing to readers of the code, but shouldn't have any functional impact.
> > |
> > | For clarity, use write_to_read_only() rather than ignore_write(). If a trap
> > | is unexpectedly taken to EL2 in violation of the architecture, this will
> > | WARN_ONCE() and inject an undef into the guest.
>
> Agreed, I like your suggested changelog better :-)
Cool!
Mark.
>
> > With that:
> >
> > Reviewed-by: Mark Rutland <mark.rutland@arm.com>
>
> Thanks!
>
> --
> Best,
> Oliver
_______________________________________________
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] 13+ messages in thread
* Re: [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit
2021-12-15 12:15 ` Mark Rutland
@ 2022-02-03 17:37 ` Oliver Upton
0 siblings, 0 replies; 13+ messages in thread
From: Oliver Upton @ 2022-02-03 17:37 UTC (permalink / raw)
To: Mark Rutland; +Cc: kvmarm, kvm, Marc Zyngier, Peter Shier, linux-arm-kernel
Hi Mark,
Sorry for the delay on my end..
On Wed, Dec 15, 2021 at 4:15 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > +static bool trap_oslar_el1(struct kvm_vcpu *vcpu,
> > + struct sys_reg_params *p,
> > + const struct sys_reg_desc *r)
> > +{
> > + u64 oslsr;
> > +
> > + if (!p->is_write)
> > + return read_from_write_only(vcpu, p, r);
> > +
> > + /* Forward the OSLK bit to OSLSR */
> > + oslsr = __vcpu_sys_reg(vcpu, OSLSR_EL1) & ~SYS_OSLSR_OSLK;
> > + if (p->regval & SYS_OSLAR_OSLK)
> > + oslsr |= SYS_OSLSR_OSLK;
> > +
> > + __vcpu_sys_reg(vcpu, OSLSR_EL1) = oslsr;
> > + return true;
> > +}
>
> Does changing this affect existing userspace? Previosuly it could read
> OSLAR_EL1 as 0, whereas now that should be rejected.
>
> That might be fine, and if so, it would be good to call that out in the commit
> message.
I do not believe we expose OSLAR_EL1 to userspace. Attempts to read it
return -ENOENT. The access will go through get_invariant_sys_reg(),
which cannot find a corresponding entry in the invariant_sys_regs
array.
[...]
> > @@ -309,9 +331,14 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> > if (err)
> > return err;
> >
> > - if (val != rd->val)
> > + /*
> > + * The only modifiable bit is the OSLK bit. Refuse the write if
> > + * userspace attempts to change any other bit in the register.
> > + */
> > + if ((val & ~SYS_OSLSR_OSLK) != SYS_OSLSR_OSLM)
> > return -EINVAL;
>
> How about:
>
> if ((val ^ rd->val) & ~SYS_OSLSR_OSLK)
> return -EINVAL;
>
> ... so that we don't need to hard-code the expected value here, and can more
> easily change it in future?
Nice and clean. Thanks!
--
Best,
Oliver
_______________________________________________
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] 13+ messages in thread
end of thread, other threads:[~2022-02-03 17:42 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-14 17:28 [PATCH v4 0/6] KVM: arm64: Emulate the OS Lock Oliver Upton
2021-12-14 17:28 ` [PATCH v4 1/6] KVM: arm64: Correctly treat writes to OSLSR_EL1 as undefined Oliver Upton
2021-12-15 11:39 ` Mark Rutland
2021-12-15 13:09 ` Oliver Upton
2021-12-15 14:32 ` Mark Rutland
2021-12-14 17:28 ` [PATCH v4 2/6] KVM: arm64: Stash OSLSR_EL1 in the cpu context Oliver Upton
2021-12-15 11:57 ` Mark Rutland
2021-12-14 17:28 ` [PATCH v4 3/6] KVM: arm64: Allow guest to set the OSLK bit Oliver Upton
2021-12-15 12:15 ` Mark Rutland
2022-02-03 17:37 ` Oliver Upton
2021-12-14 17:28 ` [PATCH v4 4/6] KVM: arm64: Emulate the OS Lock Oliver Upton
2021-12-14 17:28 ` [PATCH v4 5/6] selftests: KVM: Add OSLSR_EL1 to the list of blessed regs Oliver Upton
2021-12-14 17:28 ` [PATCH v4 6/6] selftests: KVM: Test OS lock behavior Oliver Upton
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).