diff mbox series

[v2,5/5] KVM: arm64: uapi: Add kvm_debug_exit_arch.hsr_high

Message ID 20220421100547.873761-6-alexandru.elisei@arm.com (mailing list archive)
State New, archived
Headers show
Series arm64: Treat ESR_ELx as a 64-bit register | expand

Commit Message

Alexandru Elisei April 21, 2022, 10:05 a.m. UTC
When userspace is debugging a VM, the kvm_debug_exit_arch part of the
kvm_run struct contains arm64 specific debug information: the ESR_EL2
value, encoded in the field "hsr", and the address of the instruction
that caused the exception, encoded in the field "far".

Linux has moved to treating ESR_EL2 as a 64-bit register, but unfortunately
kvm_debug_exit_arch.hsr cannot be changed because that would change the
memory layout of the struct on big endian machines:

Current layout:			| Layout with "hsr" extended to 64 bits:
				|
offset 0: ESR_EL2[31:0] (hsr)   | offset 0: ESR_EL2[61:32] (hsr[61:32])
offset 4: padding		| offset 4: ESR_EL2[31:0]  (hsr[31:0])
offset 8: FAR_EL2[61:0] (far)	| offset 8: FAR_EL2[61:0]  (far)

which breaks existing code.

The padding is inserted by the compiler because the "far" field must be
aligned to 8 bytes (each field must be naturally aligned - aapcs64 [1],
page 18), and the struct itself must be aligned to 8 bytes (the struct must
be aligned to the maximum alignment of its fields - aapcs64, page 18),
which means that "hsr" must be aligned to 8 bytes as it is the first field
in the struct.

To avoid changing the struct size and layout for the existing fields, add a
new field, "hsr_high", which replaces the existing padding. "hsr_high" will
be used to hold the ESR_EL2[61:32] bits of the register. The memory layout,
both on big and little endian machine, becomes:

offset 0: ESR_EL2[31:0]  (hsr)
offset 4: ESR_EL2[61:32] (hsr_high)
offset 8: FAR_EL2[61:0]  (far)

The padding that the compiler inserts for the current struct layout is
unitialized. To prevent an updated userspace running on an old kernel
mistaking the padding for a valid "hsr_high" value, add a new flag,
KVM_DEBUG_ARCH_HSR_HIGH_VALID, to kvm_run->flags to let userspace know that
"hsr_high" holds a valid ESR_EL2[61:32] value.

[1] https://github.com/ARM-software/abi-aa/releases/download/2021Q3/aapcs64.pdf

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---
 arch/arm64/include/uapi/asm/kvm.h | 2 ++
 arch/arm64/kvm/handle_exit.c      | 2 ++
 2 files changed, 4 insertions(+)

Comments

Marc Zyngier April 21, 2022, 12:58 p.m. UTC | #1
On Thu, 21 Apr 2022 11:05:47 +0100,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> index 93d92130d36c..fd5b6773e3a2 100644
> --- a/arch/arm64/kvm/handle_exit.c
> +++ b/arch/arm64/kvm/handle_exit.c
> @@ -121,6 +121,8 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
>  
>  	run->exit_reason = KVM_EXIT_DEBUG;
>  	run->debug.arch.hsr = lower_32_bits(esr);
> +	run->debug.arch.hsr_high = upper_32_bits(esr);
> +	run->flags |= KVM_DEBUG_ARCH_HSR_HIGH_VALID;

Who will eventually clear this flag? I'm concerned that it could be
misinterpreted by other userspace paths, as once you get a debug exit
on this vcpu, it will always be set.

Probably only a matter of clearing flags on all the other exit paths.

Also, please document the flag in the API file (only a couple of x86
flags are there so far).

Thanks,

	M.
Alexandru Elisei April 21, 2022, 3:22 p.m. UTC | #2
Hi,

On Thu, Apr 21, 2022 at 01:58:52PM +0100, Marc Zyngier wrote:
> On Thu, 21 Apr 2022 11:05:47 +0100,
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > 
> > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> > index 93d92130d36c..fd5b6773e3a2 100644
> > --- a/arch/arm64/kvm/handle_exit.c
> > +++ b/arch/arm64/kvm/handle_exit.c
> > @@ -121,6 +121,8 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
> >  
> >  	run->exit_reason = KVM_EXIT_DEBUG;
> >  	run->debug.arch.hsr = lower_32_bits(esr);
> > +	run->debug.arch.hsr_high = upper_32_bits(esr);
> > +	run->flags |= KVM_DEBUG_ARCH_HSR_HIGH_VALID;
> 
> Who will eventually clear this flag? I'm concerned that it could be
> misinterpreted by other userspace paths, as once you get a debug exit
> on this vcpu, it will always be set.
> 
> Probably only a matter of clearing flags on all the other exit paths.

I missed this part, I was under the impression that kvm_run->flags was
already cleared on every exit (that's why it's bitwise OR'ed with the
flag).

kvm_arch_vcpu_ioctl_run() always sets exit_reason = KVM_EXIT_UNKNOWN, so I
guess if we want to be consistent, kvm_run->flags should be cleared at the
same time. Unless you want KVM to clear flags for all exit reasons *except*
KVM_EXIT_UNKNOWN.

I prefer clearing flags in kvm_arch_vcpu_ioctl_run() as that looks to me
like the least error prone way to do it, and if in the future an exit
reason wants to preserve flags across KVM_RUN ioctls we can add a check for
that particular situation.

> 
> Also, please document the flag in the API file (only a couple of x86
> flags are there so far).

Sure thing, will do.

Thanks,
Alex
Marc Zyngier April 22, 2022, 7:30 a.m. UTC | #3
On Thu, 21 Apr 2022 16:22:00 +0100,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> Hi,
> 
> On Thu, Apr 21, 2022 at 01:58:52PM +0100, Marc Zyngier wrote:
> > On Thu, 21 Apr 2022 11:05:47 +0100,
> > Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > > 
> > > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> > > index 93d92130d36c..fd5b6773e3a2 100644
> > > --- a/arch/arm64/kvm/handle_exit.c
> > > +++ b/arch/arm64/kvm/handle_exit.c
> > > @@ -121,6 +121,8 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
> > >  
> > >  	run->exit_reason = KVM_EXIT_DEBUG;
> > >  	run->debug.arch.hsr = lower_32_bits(esr);
> > > +	run->debug.arch.hsr_high = upper_32_bits(esr);
> > > +	run->flags |= KVM_DEBUG_ARCH_HSR_HIGH_VALID;
> > 
> > Who will eventually clear this flag? I'm concerned that it could be
> > misinterpreted by other userspace paths, as once you get a debug exit
> > on this vcpu, it will always be set.
> > 
> > Probably only a matter of clearing flags on all the other exit paths.
> 
> I missed this part, I was under the impression that kvm_run->flags was
> already cleared on every exit (that's why it's bitwise OR'ed with the
> flag).
> 
> kvm_arch_vcpu_ioctl_run() always sets exit_reason = KVM_EXIT_UNKNOWN, so I
> guess if we want to be consistent, kvm_run->flags should be cleared at the
> same time. Unless you want KVM to clear flags for all exit reasons *except*
> KVM_EXIT_UNKNOWN.
> 
> I prefer clearing flags in kvm_arch_vcpu_ioctl_run() as that looks to me
> like the least error prone way to do it, and if in the future an exit
> reason wants to preserve flags across KVM_RUN ioctls we can add a check for
> that particular situation.

It seems entirely reasonable to reset exit_reason and flags together.

> 
> > 
> > Also, please document the flag in the API file (only a couple of x86
> > flags are there so far).
> 
> Sure thing, will do.

Thanks,

	M.
diff mbox series

Patch

diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c1b6ddc02d2f..695324b6f92e 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -139,8 +139,10 @@  struct kvm_guest_debug_arch {
 	__u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS];
 };
 
+#define KVM_DEBUG_ARCH_HSR_HIGH_VALID	1
 struct kvm_debug_exit_arch {
 	__u32 hsr;
+	__u32 hsr_high;	/* ESR_EL2[61:32] */
 	__u64 far;	/* used for watchpoints */
 };
 
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 93d92130d36c..fd5b6773e3a2 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -121,6 +121,8 @@  static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
 
 	run->exit_reason = KVM_EXIT_DEBUG;
 	run->debug.arch.hsr = lower_32_bits(esr);
+	run->debug.arch.hsr_high = upper_32_bits(esr);
+	run->flags |= KVM_DEBUG_ARCH_HSR_HIGH_VALID;
 
 	if (ESR_ELx_EC(esr) == ESR_ELx_EC_WATCHPT_LOW)
 		run->debug.arch.far = vcpu->arch.fault.far_el2;