2018-06-13 09:55:44 -04:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* xen_vmcall_test
*
* Copyright © 2020 Amazon . com , Inc . or its affiliates .
*
* Userspace hypercall testing
*/
# include "test_util.h"
# include "kvm_util.h"
# include "processor.h"
# define HCALL_REGION_GPA 0xc0000000ULL
# define HCALL_REGION_SLOT 10
# define INPUTVALUE 17
# define ARGVALUE(x) (0xdeadbeef5a5a0000UL + x)
# define RETVALUE 0xcafef00dfbfbffffUL
2018-06-13 09:55:44 -04:00
# define XEN_HYPERCALL_MSR 0x40000200
# define HV_GUEST_OS_ID_MSR 0x40000000
# define HV_HYPERCALL_MSR 0x40000001
# define HVCALL_SIGNAL_EVENT 0x005d
# define HV_STATUS_INVALID_ALIGNMENT 4
2018-06-13 09:55:44 -04:00
static void guest_code ( void )
{
unsigned long rax = INPUTVALUE ;
unsigned long rdi = ARGVALUE ( 1 ) ;
unsigned long rsi = ARGVALUE ( 2 ) ;
unsigned long rdx = ARGVALUE ( 3 ) ;
2018-06-13 09:55:44 -04:00
unsigned long rcx ;
2018-06-13 09:55:44 -04:00
register unsigned long r10 __asm__ ( " r10 " ) = ARGVALUE ( 4 ) ;
register unsigned long r8 __asm__ ( " r8 " ) = ARGVALUE ( 5 ) ;
register unsigned long r9 __asm__ ( " r9 " ) = ARGVALUE ( 6 ) ;
/* First a direct invocation of 'vmcall' */
__asm__ __volatile__ ( " vmcall " :
" =a " ( rax ) :
" a " ( rax ) , " D " ( rdi ) , " S " ( rsi ) , " d " ( rdx ) ,
" r " ( r10 ) , " r " ( r8 ) , " r " ( r9 ) ) ;
GUEST_ASSERT ( rax = = RETVALUE ) ;
2018-06-13 09:55:44 -04:00
/* Fill in the Xen hypercall page */
2018-06-13 09:55:44 -04:00
__asm__ __volatile__ ( " wrmsr " : : " c " ( XEN_HYPERCALL_MSR ) ,
" a " ( HCALL_REGION_GPA & 0xffffffff ) ,
" d " ( HCALL_REGION_GPA > > 32 ) ) ;
2018-06-13 09:55:44 -04:00
/* Set Hyper-V Guest OS ID */
__asm__ __volatile__ ( " wrmsr " : : " c " ( HV_GUEST_OS_ID_MSR ) ,
" a " ( 0x5a ) , " d " ( 0 ) ) ;
/* Hyper-V hypercall page */
u64 msrval = HCALL_REGION_GPA + PAGE_SIZE + 1 ;
__asm__ __volatile__ ( " wrmsr " : : " c " ( HV_HYPERCALL_MSR ) ,
" a " ( msrval & 0xffffffff ) ,
" d " ( msrval > > 32 ) ) ;
/* Invoke a Xen hypercall */
2018-06-13 09:55:44 -04:00
__asm__ __volatile__ ( " call *%1 " : " =a " ( rax ) :
" r " ( HCALL_REGION_GPA + INPUTVALUE * 32 ) ,
" a " ( rax ) , " D " ( rdi ) , " S " ( rsi ) , " d " ( rdx ) ,
" r " ( r10 ) , " r " ( r8 ) , " r " ( r9 ) ) ;
GUEST_ASSERT ( rax = = RETVALUE ) ;
2018-06-13 09:55:44 -04:00
/* Invoke a Hyper-V hypercall */
rax = 0 ;
rcx = HVCALL_SIGNAL_EVENT ; /* code */
rdx = 0x5a5a5a5a ; /* ingpa (badly aligned) */
__asm__ __volatile__ ( " call *%1 " : " =a " ( rax ) :
" r " ( HCALL_REGION_GPA + PAGE_SIZE ) ,
" a " ( rax ) , " c " ( rcx ) , " d " ( rdx ) ,
" r " ( r8 ) ) ;
GUEST_ASSERT ( rax = = HV_STATUS_INVALID_ALIGNMENT ) ;
2018-06-13 09:55:44 -04:00
GUEST_DONE ( ) ;
}
int main ( int argc , char * argv [ ] )
{
2022-05-27 16:24:02 -07:00
unsigned int xen_caps ;
2022-02-15 17:33:28 -08:00
struct kvm_vcpu * vcpu ;
struct kvm_vm * vm ;
2022-05-27 16:24:02 -07:00
xen_caps = kvm_check_cap ( KVM_CAP_XEN_HVM ) ;
TEST_REQUIRE ( xen_caps & KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL ) ;
2018-06-13 09:55:44 -04:00
2022-02-15 17:33:28 -08:00
vm = vm_create_with_one_vcpu ( & vcpu , guest_code ) ;
2022-06-02 13:41:33 -07:00
vcpu_set_hv_cpuid ( vcpu ) ;
2018-06-13 09:55:44 -04:00
struct kvm_xen_hvm_config hvmc = {
. flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL ,
. msr = XEN_HYPERCALL_MSR ,
} ;
vm_ioctl ( vm , KVM_XEN_HVM_CONFIG , & hvmc ) ;
2018-06-13 09:55:44 -04:00
/* Map a region for the hypercall pages */
2018-06-13 09:55:44 -04:00
vm_userspace_mem_region_add ( vm , VM_MEM_SRC_ANONYMOUS ,
2021-02-10 10:26:06 -08:00
HCALL_REGION_GPA , HCALL_REGION_SLOT , 2 , 0 ) ;
2021-06-22 13:05:22 -07:00
virt_map ( vm , HCALL_REGION_GPA , HCALL_REGION_GPA , 2 ) ;
2018-06-13 09:55:44 -04:00
for ( ; ; ) {
2022-02-15 17:33:28 -08:00
volatile struct kvm_run * run = vcpu - > run ;
2018-06-13 09:55:44 -04:00
struct ucall uc ;
2022-06-02 13:41:33 -07:00
vcpu_run ( vcpu ) ;
2018-06-13 09:55:44 -04:00
if ( run - > exit_reason = = KVM_EXIT_XEN ) {
ASSERT_EQ ( run - > xen . type , KVM_EXIT_XEN_HCALL ) ;
ASSERT_EQ ( run - > xen . u . hcall . cpl , 0 ) ;
ASSERT_EQ ( run - > xen . u . hcall . longmode , 1 ) ;
ASSERT_EQ ( run - > xen . u . hcall . input , INPUTVALUE ) ;
ASSERT_EQ ( run - > xen . u . hcall . params [ 0 ] , ARGVALUE ( 1 ) ) ;
ASSERT_EQ ( run - > xen . u . hcall . params [ 1 ] , ARGVALUE ( 2 ) ) ;
ASSERT_EQ ( run - > xen . u . hcall . params [ 2 ] , ARGVALUE ( 3 ) ) ;
ASSERT_EQ ( run - > xen . u . hcall . params [ 3 ] , ARGVALUE ( 4 ) ) ;
ASSERT_EQ ( run - > xen . u . hcall . params [ 4 ] , ARGVALUE ( 5 ) ) ;
ASSERT_EQ ( run - > xen . u . hcall . params [ 5 ] , ARGVALUE ( 6 ) ) ;
run - > xen . u . hcall . result = RETVALUE ;
continue ;
}
TEST_ASSERT ( run - > exit_reason = = KVM_EXIT_IO ,
" Got exit_reason other than KVM_EXIT_IO: %u (%s) \n " ,
run - > exit_reason ,
exit_reason_str ( run - > exit_reason ) ) ;
2022-06-02 13:41:33 -07:00
switch ( get_ucall ( vcpu , & uc ) ) {
2018-06-13 09:55:44 -04:00
case UCALL_ABORT :
2022-06-15 19:31:16 +00:00
REPORT_GUEST_ASSERT ( uc ) ;
2018-06-13 09:55:44 -04:00
/* NOT REACHED */
case UCALL_SYNC :
break ;
case UCALL_DONE :
goto done ;
default :
TEST_FAIL ( " Unknown ucall 0x%lx. " , uc . cmd ) ;
}
}
done :
kvm_vm_free ( vm ) ;
return 0 ;
}