18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Test for s390x KVM_S390_MEM_OP 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019, Red Hat, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <stdio.h> 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include <string.h> 118c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "test_util.h" 148c2ecf20Sopenharmony_ci#include "kvm_util.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define VCPU_ID 1 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic uint8_t mem1[65536]; 198c2ecf20Sopenharmony_cistatic uint8_t mem2[65536]; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void guest_code(void) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci int i; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci for (;;) { 268c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(mem2); i++) 278c2ecf20Sopenharmony_ci mem2[i] = mem1[i]; 288c2ecf20Sopenharmony_ci GUEST_SYNC(0); 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct kvm_vm *vm; 358c2ecf20Sopenharmony_ci struct kvm_run *run; 368c2ecf20Sopenharmony_ci struct kvm_s390_mem_op ksmo; 378c2ecf20Sopenharmony_ci int rv, i, maxsize; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci maxsize = kvm_check_cap(KVM_CAP_S390_MEM_OP); 428c2ecf20Sopenharmony_ci if (!maxsize) { 438c2ecf20Sopenharmony_ci print_skip("CAP_S390_MEM_OP not supported"); 448c2ecf20Sopenharmony_ci exit(KSFT_SKIP); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci if (maxsize > sizeof(mem1)) 478c2ecf20Sopenharmony_ci maxsize = sizeof(mem1); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Create VM */ 508c2ecf20Sopenharmony_ci vm = vm_create_default(VCPU_ID, 0, guest_code); 518c2ecf20Sopenharmony_ci run = vcpu_state(vm, VCPU_ID); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(mem1); i++) 548c2ecf20Sopenharmony_ci mem1[i] = i * i + i; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* Set the first array */ 578c2ecf20Sopenharmony_ci ksmo.gaddr = addr_gva2gpa(vm, (uintptr_t)mem1); 588c2ecf20Sopenharmony_ci ksmo.flags = 0; 598c2ecf20Sopenharmony_ci ksmo.size = maxsize; 608c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 618c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 628c2ecf20Sopenharmony_ci ksmo.ar = 0; 638c2ecf20Sopenharmony_ci vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Let the guest code copy the first array to the second */ 668c2ecf20Sopenharmony_ci vcpu_run(vm, VCPU_ID); 678c2ecf20Sopenharmony_ci TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, 688c2ecf20Sopenharmony_ci "Unexpected exit reason: %u (%s)\n", 698c2ecf20Sopenharmony_ci run->exit_reason, 708c2ecf20Sopenharmony_ci exit_reason_str(run->exit_reason)); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci memset(mem2, 0xaa, sizeof(mem2)); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Get the second array */ 758c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem2; 768c2ecf20Sopenharmony_ci ksmo.flags = 0; 778c2ecf20Sopenharmony_ci ksmo.size = maxsize; 788c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_READ; 798c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem2; 808c2ecf20Sopenharmony_ci ksmo.ar = 0; 818c2ecf20Sopenharmony_ci vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci TEST_ASSERT(!memcmp(mem1, mem2, maxsize), 848c2ecf20Sopenharmony_ci "Memory contents do not match!"); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* Check error conditions - first bad size: */ 878c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem1; 888c2ecf20Sopenharmony_ci ksmo.flags = 0; 898c2ecf20Sopenharmony_ci ksmo.size = -1; 908c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 918c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 928c2ecf20Sopenharmony_ci ksmo.ar = 0; 938c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 948c2ecf20Sopenharmony_ci TEST_ASSERT(rv == -1 && errno == E2BIG, "ioctl allows insane sizes"); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* Zero size: */ 978c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem1; 988c2ecf20Sopenharmony_ci ksmo.flags = 0; 998c2ecf20Sopenharmony_ci ksmo.size = 0; 1008c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 1018c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 1028c2ecf20Sopenharmony_ci ksmo.ar = 0; 1038c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 1048c2ecf20Sopenharmony_ci TEST_ASSERT(rv == -1 && (errno == EINVAL || errno == ENOMEM), 1058c2ecf20Sopenharmony_ci "ioctl allows 0 as size"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Bad flags: */ 1088c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem1; 1098c2ecf20Sopenharmony_ci ksmo.flags = -1; 1108c2ecf20Sopenharmony_ci ksmo.size = maxsize; 1118c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 1128c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 1138c2ecf20Sopenharmony_ci ksmo.ar = 0; 1148c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 1158c2ecf20Sopenharmony_ci TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows all flags"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Bad operation: */ 1188c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem1; 1198c2ecf20Sopenharmony_ci ksmo.flags = 0; 1208c2ecf20Sopenharmony_ci ksmo.size = maxsize; 1218c2ecf20Sopenharmony_ci ksmo.op = -1; 1228c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 1238c2ecf20Sopenharmony_ci ksmo.ar = 0; 1248c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 1258c2ecf20Sopenharmony_ci TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows bad operations"); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Bad guest address: */ 1288c2ecf20Sopenharmony_ci ksmo.gaddr = ~0xfffUL; 1298c2ecf20Sopenharmony_ci ksmo.flags = KVM_S390_MEMOP_F_CHECK_ONLY; 1308c2ecf20Sopenharmony_ci ksmo.size = maxsize; 1318c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 1328c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 1338c2ecf20Sopenharmony_ci ksmo.ar = 0; 1348c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 1358c2ecf20Sopenharmony_ci TEST_ASSERT(rv > 0, "ioctl does not report bad guest memory access"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Bad host address: */ 1388c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem1; 1398c2ecf20Sopenharmony_ci ksmo.flags = 0; 1408c2ecf20Sopenharmony_ci ksmo.size = maxsize; 1418c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 1428c2ecf20Sopenharmony_ci ksmo.buf = 0; 1438c2ecf20Sopenharmony_ci ksmo.ar = 0; 1448c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 1458c2ecf20Sopenharmony_ci TEST_ASSERT(rv == -1 && errno == EFAULT, 1468c2ecf20Sopenharmony_ci "ioctl does not report bad host memory address"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Bad access register: */ 1498c2ecf20Sopenharmony_ci run->psw_mask &= ~(3UL << (63 - 17)); 1508c2ecf20Sopenharmony_ci run->psw_mask |= 1UL << (63 - 17); /* Enable AR mode */ 1518c2ecf20Sopenharmony_ci vcpu_run(vm, VCPU_ID); /* To sync new state to SIE block */ 1528c2ecf20Sopenharmony_ci ksmo.gaddr = (uintptr_t)mem1; 1538c2ecf20Sopenharmony_ci ksmo.flags = 0; 1548c2ecf20Sopenharmony_ci ksmo.size = maxsize; 1558c2ecf20Sopenharmony_ci ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; 1568c2ecf20Sopenharmony_ci ksmo.buf = (uintptr_t)mem1; 1578c2ecf20Sopenharmony_ci ksmo.ar = 17; 1588c2ecf20Sopenharmony_ci rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); 1598c2ecf20Sopenharmony_ci TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows ARs > 15"); 1608c2ecf20Sopenharmony_ci run->psw_mask &= ~(3UL << (63 - 17)); /* Disable AR mode */ 1618c2ecf20Sopenharmony_ci vcpu_run(vm, VCPU_ID); /* Run to sync new state */ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci kvm_vm_free(vm); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 167