mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	KVM: arm64: Expose SMC/HVC width to userspace
When returning to userspace to handle a SMCCC call, we consistently
set PC to point to the instruction immediately after the HVC/SMC.
However, should userspace need to know the exact address of the
trapping instruction, it needs to know about the *size* of that
instruction. For AArch64, this is pretty easy. For AArch32, this
is a bit more funky, as Thumb has 16bit encodings for both HVC
and SMC.
Expose this to userspace with a new flag that directly derives
from ESR_EL2.IL. Also update the documentation to reflect the PC
state at the point of exit.
Finally, this fixes a small buglet where the hypercall.{args,ret}
fields would not be cleared on exit, and could contain some
random junk.
Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/86pm8iv8tj.wl-maz@kernel.org
			
			
This commit is contained in:
		
							parent
							
								
									60e7dade49
								
							
						
					
					
						commit
						0e5c9a9d65
					
				
					 3 changed files with 21 additions and 6 deletions
				
			
		| 
						 | 
				
			
			@ -6244,6 +6244,14 @@ Definition of ``flags``:
 | 
			
		|||
   conduit to initiate the SMCCC call. If this bit is 0 then the guest
 | 
			
		||||
   used the HVC conduit for the SMCCC call.
 | 
			
		||||
 | 
			
		||||
 - ``KVM_HYPERCALL_EXIT_16BIT``: Indicates that the guest used a 16bit
 | 
			
		||||
   instruction to initiate the SMCCC call. If this bit is 0 then the
 | 
			
		||||
   guest used a 32bit instruction. An AArch64 guest always has this
 | 
			
		||||
   bit set to 0.
 | 
			
		||||
 | 
			
		||||
At the point of exit, PC points to the instruction immediately following
 | 
			
		||||
the trapping instruction.
 | 
			
		||||
 | 
			
		||||
::
 | 
			
		||||
 | 
			
		||||
		/* KVM_EXIT_TPR_ACCESS */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -491,7 +491,8 @@ struct kvm_smccc_filter {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
/* arm64-specific KVM_EXIT_HYPERCALL flags */
 | 
			
		||||
#define KVM_HYPERCALL_EXIT_SMC	(1U << 0)
 | 
			
		||||
#define KVM_HYPERCALL_EXIT_SMC		(1U << 0)
 | 
			
		||||
#define KVM_HYPERCALL_EXIT_16BIT	(1U << 1)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -222,13 +222,19 @@ static void kvm_prepare_hypercall_exit(struct kvm_vcpu *vcpu, u32 func_id)
 | 
			
		|||
{
 | 
			
		||||
	u8 ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
 | 
			
		||||
	struct kvm_run *run = vcpu->run;
 | 
			
		||||
 | 
			
		||||
	run->exit_reason = KVM_EXIT_HYPERCALL;
 | 
			
		||||
	run->hypercall.nr = func_id;
 | 
			
		||||
	run->hypercall.flags = 0;
 | 
			
		||||
	u64 flags = 0;
 | 
			
		||||
 | 
			
		||||
	if (ec == ESR_ELx_EC_SMC32 || ec == ESR_ELx_EC_SMC64)
 | 
			
		||||
		run->hypercall.flags |= KVM_HYPERCALL_EXIT_SMC;
 | 
			
		||||
		flags |= KVM_HYPERCALL_EXIT_SMC;
 | 
			
		||||
 | 
			
		||||
	if (!kvm_vcpu_trap_il_is32bit(vcpu))
 | 
			
		||||
		flags |= KVM_HYPERCALL_EXIT_16BIT;
 | 
			
		||||
 | 
			
		||||
	run->exit_reason = KVM_EXIT_HYPERCALL;
 | 
			
		||||
	run->hypercall = (typeof(run->hypercall)) {
 | 
			
		||||
		.nr	= func_id,
 | 
			
		||||
		.flags	= flags,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue