diff mbox series

[v2,3/6] KVM: arm64: Allow guest to set the OSLK bit

Message ID 20211102094651.2071532-4-oupton@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: arm64: Emulate the OS lock | expand

Commit Message

Oliver Upton Nov. 2, 2021, 9:46 a.m. UTC
Allow writes to OSLAR and forward the OSLK bit to OSLSR. Change the
reset value of the OSLK bit to 1. Allow the value to be migrated by
making OSLSR_EL1.OSLK writable from userspace.

Signed-off-by: Oliver Upton <oupton@google.com>
---
 arch/arm64/include/asm/sysreg.h |  6 ++++++
 arch/arm64/kvm/sys_regs.c       | 35 +++++++++++++++++++++++++--------
 2 files changed, 33 insertions(+), 8 deletions(-)

Comments

Reiji Watanabe Nov. 4, 2021, 3:31 a.m. UTC | #1
On Tue, Nov 2, 2021 at 2:47 AM Oliver Upton <oupton@google.com> wrote:
>
> Allow writes to OSLAR and forward the OSLK bit to OSLSR. Change the
> reset value of the OSLK bit to 1. Allow the value to be migrated by
> making OSLSR_EL1.OSLK writable from userspace.
>
> Signed-off-by: Oliver Upton <oupton@google.com>
> ---
>  arch/arm64/include/asm/sysreg.h |  6 ++++++
>  arch/arm64/kvm/sys_regs.c       | 35 +++++++++++++++++++++++++--------
>  2 files changed, 33 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index b268082d67ed..6ba4dc97b69d 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -127,7 +127,13 @@
>  #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_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 0326b3df0736..acd8aa2e5a44 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,10 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
>         if (err)
>                 return err;
>
> -       if (val != rd->val)
> +       if ((val | SYS_OSLSR_OSLK) != rd->val)
>                 return -EINVAL;
>
> +       __vcpu_sys_reg(vcpu, rd->reg) = val;
>         return 0;
>  }
>
> @@ -1176,10 +1199,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)
> @@ -1456,8 +1475,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, 0x0000000A,
>                 .set_user = set_oslsr_el1, },

Reviewed-by: Reiji Watanabe <reijiw@google.com>

I assume the reason why you changed the reset value for the
register is because Arm ARM says "the On a Cold reset,
this field resets to 1".

"4.82 KVM_ARM_VCPU_INIT" in Documentation/virt/kvm/api.rst says:
-------------------------------------------------------------
  - System registers: Reset to their architecturally defined
    values as for a warm reset to EL1 (resp. SVC)
-------------------------------------------------------------

Since Arm ARM doesn't say anything about a warm reset for the field,
I would guess the bit doesn't necessarily need to be set.

Thanks,
Reiji


>         { SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
>         { SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
> @@ -1930,7 +1949,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.33.1.1089.g2158813163f-goog
>
Ricardo Koller Nov. 4, 2021, 3:47 a.m. UTC | #2
On Wed, Nov 03, 2021 at 08:31:35PM -0700, Reiji Watanabe wrote:
> On Tue, Nov 2, 2021 at 2:47 AM Oliver Upton <oupton@google.com> wrote:
> >
> > Allow writes to OSLAR and forward the OSLK bit to OSLSR. Change the
> > reset value of the OSLK bit to 1. Allow the value to be migrated by
> > making OSLSR_EL1.OSLK writable from userspace.
> >
> > Signed-off-by: Oliver Upton <oupton@google.com>
> > ---
> >  arch/arm64/include/asm/sysreg.h |  6 ++++++
> >  arch/arm64/kvm/sys_regs.c       | 35 +++++++++++++++++++++++++--------
> >  2 files changed, 33 insertions(+), 8 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> > index b268082d67ed..6ba4dc97b69d 100644
> > --- a/arch/arm64/include/asm/sysreg.h
> > +++ b/arch/arm64/include/asm/sysreg.h
> > @@ -127,7 +127,13 @@
> >  #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_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 0326b3df0736..acd8aa2e5a44 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,10 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> >         if (err)
> >                 return err;
> >
> > -       if (val != rd->val)
> > +       if ((val | SYS_OSLSR_OSLK) != rd->val)
> >                 return -EINVAL;
> >
> > +       __vcpu_sys_reg(vcpu, rd->reg) = val;
> >         return 0;
> >  }
> >
> > @@ -1176,10 +1199,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)
> > @@ -1456,8 +1475,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, 0x0000000A,
> >                 .set_user = set_oslsr_el1, },
> 
> Reviewed-by: Reiji Watanabe <reijiw@google.com>
> 
> I assume the reason why you changed the reset value for the
> register is because Arm ARM says "the On a Cold reset,
> this field resets to 1".
> 
> "4.82 KVM_ARM_VCPU_INIT" in Documentation/virt/kvm/api.rst says:
> -------------------------------------------------------------
>   - System registers: Reset to their architecturally defined
>     values as for a warm reset to EL1 (resp. SVC)
> -------------------------------------------------------------
> 
> Since Arm ARM doesn't say anything about a warm reset for the field,
> I would guess the bit doesn't necessarily need to be set.

That would be great, because it would avoid the migration issue that
Oliver described in [PATCH v2 4/6]:

	There is an issue, though, with migration: older KVM will not show
	OSLSR_EL1 on KVM_GET_REG_LIST. However, in order to provide an
	architectural OS Lock, its reset value must be 1 (enabled). This would
	all have the effect of discarding the guest's OS lock value and
	blocking all debug exceptions intended for the guest until the next
	reboot.

> 
> Thanks,
> Reiji
> 
> 
> >         { SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
> >         { SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
> > @@ -1930,7 +1949,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.33.1.1089.g2158813163f-goog
> >
Oliver Upton Nov. 4, 2021, 4:40 a.m. UTC | #3
On Wed, Nov 03, 2021 at 08:47:42PM -0700, Ricardo Koller wrote:
> On Wed, Nov 03, 2021 at 08:31:35PM -0700, Reiji Watanabe wrote:
> > On Tue, Nov 2, 2021 at 2:47 AM Oliver Upton <oupton@google.com> wrote:
> > >
> > > Allow writes to OSLAR and forward the OSLK bit to OSLSR. Change the
> > > reset value of the OSLK bit to 1. Allow the value to be migrated by
> > > making OSLSR_EL1.OSLK writable from userspace.
> > >
> > > Signed-off-by: Oliver Upton <oupton@google.com>
> > > ---
> > >  arch/arm64/include/asm/sysreg.h |  6 ++++++
> > >  arch/arm64/kvm/sys_regs.c       | 35 +++++++++++++++++++++++++--------
> > >  2 files changed, 33 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> > > index b268082d67ed..6ba4dc97b69d 100644
> > > --- a/arch/arm64/include/asm/sysreg.h
> > > +++ b/arch/arm64/include/asm/sysreg.h
> > > @@ -127,7 +127,13 @@
> > >  #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_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 0326b3df0736..acd8aa2e5a44 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,10 @@ static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
> > >         if (err)
> > >                 return err;
> > >
> > > -       if (val != rd->val)
> > > +       if ((val | SYS_OSLSR_OSLK) != rd->val)
> > >                 return -EINVAL;
> > >
> > > +       __vcpu_sys_reg(vcpu, rd->reg) = val;
> > >         return 0;
> > >  }
> > >
> > > @@ -1176,10 +1199,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)
> > > @@ -1456,8 +1475,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, 0x0000000A,
> > >                 .set_user = set_oslsr_el1, },
> > 
> > Reviewed-by: Reiji Watanabe <reijiw@google.com>
> > 
> > I assume the reason why you changed the reset value for the
> > register is because Arm ARM says "the On a Cold reset,
> > this field resets to 1".
> > 
> > "4.82 KVM_ARM_VCPU_INIT" in Documentation/virt/kvm/api.rst says:
> > -------------------------------------------------------------
> >   - System registers: Reset to their architecturally defined
> >     values as for a warm reset to EL1 (resp. SVC)
> > -------------------------------------------------------------
> > 
> > Since Arm ARM doesn't say anything about a warm reset for the field,
> > I would guess the bit doesn't necessarily need to be set.
> 
> That would be great, because it would avoid the migration issue that
> Oliver described in [PATCH v2 4/6]:

Yeah, awesome! Means I can be even lazier and things will "Just Work"
:-)

--
Oliver
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b268082d67ed..6ba4dc97b69d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -127,7 +127,13 @@ 
 #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_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 0326b3df0736..acd8aa2e5a44 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,10 @@  static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
 	if (err)
 		return err;
 
-	if (val != rd->val)
+	if ((val | SYS_OSLSR_OSLK) != rd->val)
 		return -EINVAL;
 
+	__vcpu_sys_reg(vcpu, rd->reg) = val;
 	return 0;
 }
 
@@ -1176,10 +1199,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)
@@ -1456,8 +1475,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, 0x0000000A,
 		.set_user = set_oslsr_el1, },
 	{ SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi },
 	{ SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi },
@@ -1930,7 +1949,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 },