99 */
1010#include "kselftest_harness.h"
1111#include "kvm_util.h"
12+ #include "processor.h"
13+ #include "sie.h"
1214
1315#include <linux/capability.h>
1416#include <linux/sizes.h>
1517
18+ #define VM_MEM_SIZE (4 * SZ_1M)
19+
1620/* so directly declare capget to check caps without libcap */
1721int capget (cap_user_header_t header , cap_user_data_t data );
1822
@@ -36,6 +40,133 @@ void require_ucontrol_admin(void)
3640 TEST_REQUIRE (kvm_has_cap (KVM_CAP_S390_UCONTROL ));
3741}
3842
43+ FIXTURE (uc_kvm )
44+ {
45+ struct kvm_s390_sie_block * sie_block ;
46+ struct kvm_run * run ;
47+ uintptr_t base_gpa ;
48+ uintptr_t code_gpa ;
49+ uintptr_t base_hva ;
50+ uintptr_t code_hva ;
51+ int kvm_run_size ;
52+ void * vm_mem ;
53+ int vcpu_fd ;
54+ int kvm_fd ;
55+ int vm_fd ;
56+ };
57+
58+ /**
59+ * create VM with single vcpu, map kvm_run and SIE control block for easy access
60+ */
61+ FIXTURE_SETUP (uc_kvm )
62+ {
63+ struct kvm_s390_vm_cpu_processor info ;
64+ int rc ;
65+
66+ require_ucontrol_admin ();
67+
68+ self -> kvm_fd = open_kvm_dev_path_or_exit ();
69+ self -> vm_fd = ioctl (self -> kvm_fd , KVM_CREATE_VM , KVM_VM_S390_UCONTROL );
70+ ASSERT_GE (self -> vm_fd , 0 );
71+
72+ kvm_device_attr_get (self -> vm_fd , KVM_S390_VM_CPU_MODEL ,
73+ KVM_S390_VM_CPU_PROCESSOR , & info );
74+ TH_LOG ("create VM 0x%llx" , info .cpuid );
75+
76+ self -> vcpu_fd = ioctl (self -> vm_fd , KVM_CREATE_VCPU , 0 );
77+ ASSERT_GE (self -> vcpu_fd , 0 );
78+
79+ self -> kvm_run_size = ioctl (self -> kvm_fd , KVM_GET_VCPU_MMAP_SIZE , NULL );
80+ ASSERT_GE (self -> kvm_run_size , sizeof (struct kvm_run ))
81+ TH_LOG (KVM_IOCTL_ERROR (KVM_GET_VCPU_MMAP_SIZE , self -> kvm_run_size ));
82+ self -> run = (struct kvm_run * )mmap (NULL , self -> kvm_run_size ,
83+ PROT_READ | PROT_WRITE , MAP_SHARED , self -> vcpu_fd , 0 );
84+ ASSERT_NE (self -> run , MAP_FAILED );
85+ /**
86+ * For virtual cpus that have been created with S390 user controlled
87+ * virtual machines, the resulting vcpu fd can be memory mapped at page
88+ * offset KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of
89+ * the virtual cpu's hardware control block.
90+ */
91+ self -> sie_block = (struct kvm_s390_sie_block * )mmap (NULL , PAGE_SIZE ,
92+ PROT_READ | PROT_WRITE , MAP_SHARED ,
93+ self -> vcpu_fd , KVM_S390_SIE_PAGE_OFFSET << PAGE_SHIFT );
94+ ASSERT_NE (self -> sie_block , MAP_FAILED );
95+
96+ TH_LOG ("VM created %p %p" , self -> run , self -> sie_block );
97+
98+ self -> base_gpa = 0 ;
99+ self -> code_gpa = self -> base_gpa + (3 * SZ_1M );
100+
101+ self -> vm_mem = aligned_alloc (SZ_1M , VM_MEM_SIZE );
102+ ASSERT_NE (NULL , self -> vm_mem ) TH_LOG ("malloc failed %u" , errno );
103+ self -> base_hva = (uintptr_t )self -> vm_mem ;
104+ self -> code_hva = self -> base_hva - self -> base_gpa + self -> code_gpa ;
105+ struct kvm_s390_ucas_mapping map = {
106+ .user_addr = self -> base_hva ,
107+ .vcpu_addr = self -> base_gpa ,
108+ .length = VM_MEM_SIZE ,
109+ };
110+ TH_LOG ("ucas map %p %p 0x%llx" ,
111+ (void * )map .user_addr , (void * )map .vcpu_addr , map .length );
112+ rc = ioctl (self -> vcpu_fd , KVM_S390_UCAS_MAP , & map );
113+ ASSERT_EQ (0 , rc ) TH_LOG ("ucas map result %d not expected, %s" ,
114+ rc , strerror (errno ));
115+
116+ TH_LOG ("page in %p" , (void * )self -> base_gpa );
117+ rc = ioctl (self -> vcpu_fd , KVM_S390_VCPU_FAULT , self -> base_gpa );
118+ ASSERT_EQ (0 , rc ) TH_LOG ("vcpu fault (%p) result %d not expected, %s" ,
119+ (void * )self -> base_hva , rc , strerror (errno ));
120+
121+ self -> sie_block -> cpuflags &= ~CPUSTAT_STOPPED ;
122+ }
123+
124+ FIXTURE_TEARDOWN (uc_kvm )
125+ {
126+ munmap (self -> sie_block , PAGE_SIZE );
127+ munmap (self -> run , self -> kvm_run_size );
128+ close (self -> vcpu_fd );
129+ close (self -> vm_fd );
130+ close (self -> kvm_fd );
131+ free (self -> vm_mem );
132+ }
133+
134+ TEST_F (uc_kvm , uc_sie_assertions )
135+ {
136+ /* assert interception of Code 08 (Program Interruption) is set */
137+ EXPECT_EQ (0 , self -> sie_block -> ecb & ECB_SPECI );
138+ }
139+
140+ TEST_F (uc_kvm , uc_attr_mem_limit )
141+ {
142+ u64 limit ;
143+ struct kvm_device_attr attr = {
144+ .group = KVM_S390_VM_MEM_CTRL ,
145+ .attr = KVM_S390_VM_MEM_LIMIT_SIZE ,
146+ .addr = (unsigned long )& limit ,
147+ };
148+ int rc ;
149+
150+ rc = ioctl (self -> vm_fd , KVM_GET_DEVICE_ATTR , & attr );
151+ EXPECT_EQ (0 , rc );
152+ EXPECT_EQ (~0UL , limit );
153+
154+ /* assert set not supported */
155+ rc = ioctl (self -> vm_fd , KVM_SET_DEVICE_ATTR , & attr );
156+ EXPECT_EQ (-1 , rc );
157+ EXPECT_EQ (EINVAL , errno );
158+ }
159+
160+ TEST_F (uc_kvm , uc_no_dirty_log )
161+ {
162+ struct kvm_dirty_log dlog ;
163+ int rc ;
164+
165+ rc = ioctl (self -> vm_fd , KVM_GET_DIRTY_LOG , & dlog );
166+ EXPECT_EQ (-1 , rc );
167+ EXPECT_EQ (EINVAL , errno );
168+ }
169+
39170/**
40171 * Assert HPAGE CAP cannot be enabled on UCONTROL VM
41172 */
0 commit comments