1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Test code for the s390x kvm ucontrol interface 4 * 5 * Copyright IBM Corp. 2024 6 * 7 * Authors: 8 * Christoph Schlameuss <schlameuss@linux.ibm.com> 9 */ 10 #include "debug_print.h" 11 #include "kselftest_harness.h" 12 #include "kvm_util.h" 13 #include "processor.h" 14 #include "sie.h" 15 16 #include <linux/capability.h> 17 #include <linux/sizes.h> 18 19 #define VM_MEM_SIZE (4 * SZ_1M) 20 21 /* so directly declare capget to check caps without libcap */ 22 int capget(cap_user_header_t header, cap_user_data_t data); 23 24 /** 25 * In order to create user controlled virtual machines on S390, 26 * check KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL 27 * as privileged user (SYS_ADMIN). 28 */ 29 void require_ucontrol_admin(void) 30 { 31 struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; 32 struct __user_cap_header_struct hdr = { 33 .version = _LINUX_CAPABILITY_VERSION_3, 34 }; 35 int rc; 36 37 rc = capget(&hdr, data); 38 TEST_ASSERT_EQ(0, rc); 39 TEST_REQUIRE((data->effective & CAP_TO_MASK(CAP_SYS_ADMIN)) > 0); 40 41 TEST_REQUIRE(kvm_has_cap(KVM_CAP_S390_UCONTROL)); 42 } 43 44 /* Test program setting some registers and looping */ 45 extern char test_gprs_asm[]; 46 asm("test_gprs_asm:\n" 47 "xgr %r0, %r0\n" 48 "lgfi %r1,1\n" 49 "lgfi %r2,2\n" 50 "lgfi %r3,3\n" 51 "lgfi %r4,4\n" 52 "lgfi %r5,5\n" 53 "lgfi %r6,6\n" 54 "lgfi %r7,7\n" 55 "0:\n" 56 " diag 0,0,0x44\n" 57 " ahi %r0,1\n" 58 " j 0b\n" 59 ); 60 61 FIXTURE(uc_kvm) 62 { 63 struct kvm_s390_sie_block *sie_block; 64 struct kvm_run *run; 65 uintptr_t base_gpa; 66 uintptr_t code_gpa; 67 uintptr_t base_hva; 68 uintptr_t code_hva; 69 int kvm_run_size; 70 void *vm_mem; 71 int vcpu_fd; 72 int kvm_fd; 73 int vm_fd; 74 }; 75 76 /** 77 * create VM with single vcpu, map kvm_run and SIE control block for easy access 78 */ 79 FIXTURE_SETUP(uc_kvm) 80 { 81 struct kvm_s390_vm_cpu_processor info; 82 int rc; 83 84 require_ucontrol_admin(); 85 86 self->kvm_fd = open_kvm_dev_path_or_exit(); 87 self->vm_fd = ioctl(self->kvm_fd, KVM_CREATE_VM, KVM_VM_S390_UCONTROL); 88 ASSERT_GE(self->vm_fd, 0); 89 90 kvm_device_attr_get(self->vm_fd, KVM_S390_VM_CPU_MODEL, 91 KVM_S390_VM_CPU_PROCESSOR, &info); 92 TH_LOG("create VM 0x%llx", info.cpuid); 93 94 self->vcpu_fd = ioctl(self->vm_fd, KVM_CREATE_VCPU, 0); 95 ASSERT_GE(self->vcpu_fd, 0); 96 97 self->kvm_run_size = ioctl(self->kvm_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); 98 ASSERT_GE(self->kvm_run_size, sizeof(struct kvm_run)) 99 TH_LOG(KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, self->kvm_run_size)); 100 self->run = (struct kvm_run *)mmap(NULL, self->kvm_run_size, 101 PROT_READ | PROT_WRITE, MAP_SHARED, self->vcpu_fd, 0); 102 ASSERT_NE(self->run, MAP_FAILED); 103 /** 104 * For virtual cpus that have been created with S390 user controlled 105 * virtual machines, the resulting vcpu fd can be memory mapped at page 106 * offset KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of 107 * the virtual cpu's hardware control block. 108 */ 109 self->sie_block = (struct kvm_s390_sie_block *)mmap(NULL, PAGE_SIZE, 110 PROT_READ | PROT_WRITE, MAP_SHARED, 111 self->vcpu_fd, KVM_S390_SIE_PAGE_OFFSET << PAGE_SHIFT); 112 ASSERT_NE(self->sie_block, MAP_FAILED); 113 114 TH_LOG("VM created %p %p", self->run, self->sie_block); 115 116 self->base_gpa = 0; 117 self->code_gpa = self->base_gpa + (3 * SZ_1M); 118 119 self->vm_mem = aligned_alloc(SZ_1M, VM_MEM_SIZE); 120 ASSERT_NE(NULL, self->vm_mem) TH_LOG("malloc failed %u", errno); 121 self->base_hva = (uintptr_t)self->vm_mem; 122 self->code_hva = self->base_hva - self->base_gpa + self->code_gpa; 123 struct kvm_s390_ucas_mapping map = { 124 .user_addr = self->base_hva, 125 .vcpu_addr = self->base_gpa, 126 .length = VM_MEM_SIZE, 127 }; 128 TH_LOG("ucas map %p %p 0x%llx", 129 (void *)map.user_addr, (void *)map.vcpu_addr, map.length); 130 rc = ioctl(self->vcpu_fd, KVM_S390_UCAS_MAP, &map); 131 ASSERT_EQ(0, rc) TH_LOG("ucas map result %d not expected, %s", 132 rc, strerror(errno)); 133 134 TH_LOG("page in %p", (void *)self->base_gpa); 135 rc = ioctl(self->vcpu_fd, KVM_S390_VCPU_FAULT, self->base_gpa); 136 ASSERT_EQ(0, rc) TH_LOG("vcpu fault (%p) result %d not expected, %s", 137 (void *)self->base_hva, rc, strerror(errno)); 138 139 self->sie_block->cpuflags &= ~CPUSTAT_STOPPED; 140 } 141 142 FIXTURE_TEARDOWN(uc_kvm) 143 { 144 munmap(self->sie_block, PAGE_SIZE); 145 munmap(self->run, self->kvm_run_size); 146 close(self->vcpu_fd); 147 close(self->vm_fd); 148 close(self->kvm_fd); 149 free(self->vm_mem); 150 } 151 152 TEST_F(uc_kvm, uc_sie_assertions) 153 { 154 /* assert interception of Code 08 (Program Interruption) is set */ 155 EXPECT_EQ(0, self->sie_block->ecb & ECB_SPECI); 156 } 157 158 TEST_F(uc_kvm, uc_attr_mem_limit) 159 { 160 u64 limit; 161 struct kvm_device_attr attr = { 162 .group = KVM_S390_VM_MEM_CTRL, 163 .attr = KVM_S390_VM_MEM_LIMIT_SIZE, 164 .addr = (unsigned long)&limit, 165 }; 166 int rc; 167 168 rc = ioctl(self->vm_fd, KVM_GET_DEVICE_ATTR, &attr); 169 EXPECT_EQ(0, rc); 170 EXPECT_EQ(~0UL, limit); 171 172 /* assert set not supported */ 173 rc = ioctl(self->vm_fd, KVM_SET_DEVICE_ATTR, &attr); 174 EXPECT_EQ(-1, rc); 175 EXPECT_EQ(EINVAL, errno); 176 } 177 178 TEST_F(uc_kvm, uc_no_dirty_log) 179 { 180 struct kvm_dirty_log dlog; 181 int rc; 182 183 rc = ioctl(self->vm_fd, KVM_GET_DIRTY_LOG, &dlog); 184 EXPECT_EQ(-1, rc); 185 EXPECT_EQ(EINVAL, errno); 186 } 187 188 /** 189 * Assert HPAGE CAP cannot be enabled on UCONTROL VM 190 */ 191 TEST(uc_cap_hpage) 192 { 193 int rc, kvm_fd, vm_fd, vcpu_fd; 194 struct kvm_enable_cap cap = { 195 .cap = KVM_CAP_S390_HPAGE_1M, 196 }; 197 198 require_ucontrol_admin(); 199 200 kvm_fd = open_kvm_dev_path_or_exit(); 201 vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, KVM_VM_S390_UCONTROL); 202 ASSERT_GE(vm_fd, 0); 203 204 /* assert hpages are not supported on ucontrol vm */ 205 rc = ioctl(vm_fd, KVM_CHECK_EXTENSION, KVM_CAP_S390_HPAGE_1M); 206 EXPECT_EQ(0, rc); 207 208 /* Test that KVM_CAP_S390_HPAGE_1M can't be enabled for a ucontrol vm */ 209 rc = ioctl(vm_fd, KVM_ENABLE_CAP, cap); 210 EXPECT_EQ(-1, rc); 211 EXPECT_EQ(EINVAL, errno); 212 213 /* assert HPAGE CAP is rejected after vCPU creation */ 214 vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0); 215 ASSERT_GE(vcpu_fd, 0); 216 rc = ioctl(vm_fd, KVM_ENABLE_CAP, cap); 217 EXPECT_EQ(-1, rc); 218 EXPECT_EQ(EBUSY, errno); 219 220 close(vcpu_fd); 221 close(vm_fd); 222 close(kvm_fd); 223 } 224 225 /* verify SIEIC exit 226 * * fail on codes not expected in the test cases 227 */ 228 static bool uc_handle_sieic(FIXTURE_DATA(uc_kvm) * self) 229 { 230 struct kvm_s390_sie_block *sie_block = self->sie_block; 231 struct kvm_run *run = self->run; 232 233 /* check SIE interception code */ 234 pr_info("sieic: 0x%.2x 0x%.4x 0x%.4x\n", 235 run->s390_sieic.icptcode, 236 run->s390_sieic.ipa, 237 run->s390_sieic.ipb); 238 switch (run->s390_sieic.icptcode) { 239 case ICPT_INST: 240 /* end execution in caller on intercepted instruction */ 241 pr_info("sie instruction interception\n"); 242 return false; 243 case ICPT_OPEREXC: 244 /* operation exception */ 245 TEST_FAIL("sie exception on %.4x%.8x", sie_block->ipa, sie_block->ipb); 246 default: 247 TEST_FAIL("UNEXPECTED SIEIC CODE %d", run->s390_sieic.icptcode); 248 } 249 return true; 250 } 251 252 /* verify VM state on exit */ 253 static bool uc_handle_exit(FIXTURE_DATA(uc_kvm) * self) 254 { 255 struct kvm_run *run = self->run; 256 257 switch (run->exit_reason) { 258 case KVM_EXIT_S390_SIEIC: 259 return uc_handle_sieic(self); 260 default: 261 pr_info("exit_reason %2d not handled\n", run->exit_reason); 262 } 263 return true; 264 } 265 266 /* run the VM until interrupted */ 267 static int uc_run_once(FIXTURE_DATA(uc_kvm) * self) 268 { 269 int rc; 270 271 rc = ioctl(self->vcpu_fd, KVM_RUN, NULL); 272 print_run(self->run, self->sie_block); 273 print_regs(self->run); 274 pr_debug("run %d / %d %s\n", rc, errno, strerror(errno)); 275 return rc; 276 } 277 278 static void uc_assert_diag44(FIXTURE_DATA(uc_kvm) * self) 279 { 280 struct kvm_s390_sie_block *sie_block = self->sie_block; 281 282 /* assert vm was interrupted by diag 0x0044 */ 283 TEST_ASSERT_EQ(KVM_EXIT_S390_SIEIC, self->run->exit_reason); 284 TEST_ASSERT_EQ(ICPT_INST, sie_block->icptcode); 285 TEST_ASSERT_EQ(0x8300, sie_block->ipa); 286 TEST_ASSERT_EQ(0x440000, sie_block->ipb); 287 } 288 289 TEST_F(uc_kvm, uc_gprs) 290 { 291 struct kvm_sync_regs *sync_regs = &self->run->s.regs; 292 struct kvm_run *run = self->run; 293 struct kvm_regs regs = {}; 294 295 /* Set registers to values that are different from the ones that we expect below */ 296 for (int i = 0; i < 8; i++) 297 sync_regs->gprs[i] = 8; 298 run->kvm_dirty_regs |= KVM_SYNC_GPRS; 299 300 /* copy test_gprs_asm to code_hva / code_gpa */ 301 TH_LOG("copy code %p to vm mapped memory %p / %p", 302 &test_gprs_asm, (void *)self->code_hva, (void *)self->code_gpa); 303 memcpy((void *)self->code_hva, &test_gprs_asm, PAGE_SIZE); 304 305 /* DAT disabled + 64 bit mode */ 306 run->psw_mask = 0x0000000180000000ULL; 307 run->psw_addr = self->code_gpa; 308 309 /* run and expect interception of diag 44 */ 310 ASSERT_EQ(0, uc_run_once(self)); 311 ASSERT_EQ(false, uc_handle_exit(self)); 312 uc_assert_diag44(self); 313 314 /* Retrieve and check guest register values */ 315 ASSERT_EQ(0, ioctl(self->vcpu_fd, KVM_GET_REGS, ®s)); 316 for (int i = 0; i < 8; i++) { 317 ASSERT_EQ(i, regs.gprs[i]); 318 ASSERT_EQ(i, sync_regs->gprs[i]); 319 } 320 321 /* run and expect interception of diag 44 again */ 322 ASSERT_EQ(0, uc_run_once(self)); 323 ASSERT_EQ(false, uc_handle_exit(self)); 324 uc_assert_diag44(self); 325 326 /* check continued increment of register 0 value */ 327 ASSERT_EQ(0, ioctl(self->vcpu_fd, KVM_GET_REGS, ®s)); 328 ASSERT_EQ(1, regs.gprs[0]); 329 ASSERT_EQ(1, sync_regs->gprs[0]); 330 } 331 332 TEST_HARNESS_MAIN 333