···30923092flag KVM_S390_MEMOP_F_INJECT_EXCEPTION is set in the "flags" field.3093309330943094The start address of the memory region has to be specified in the "gaddr"30953095-field, and the length of the region in the "size" field. "buf" is the buffer30963096-supplied by the userspace application where the read data should be written30973097-to for KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written30983098-is stored for a KVM_S390_MEMOP_LOGICAL_WRITE. "buf" is unused and can be NULL30993099-when KVM_S390_MEMOP_F_CHECK_ONLY is specified. "ar" designates the access31003100-register number to be used.30953095+field, and the length of the region in the "size" field (which must not30963096+be 0). The maximum value for "size" can be obtained by checking the30973097+KVM_CAP_S390_MEM_OP capability. "buf" is the buffer supplied by the30983098+userspace application where the read data should be written to for30993099+KVM_S390_MEMOP_LOGICAL_READ, or where the data that should be written is31003100+stored for a KVM_S390_MEMOP_LOGICAL_WRITE. When KVM_S390_MEMOP_F_CHECK_ONLY31013101+is specified, "buf" is unused and can be NULL. "ar" designates the access31023102+register number to be used; the valid range is 0..15.3101310331023104The "reserved" field is meant for future extensions. It is not used by31033105KVM with the currently defined set of flags.
+6
arch/s390/include/uapi/asm/kvm.h
···231231#define KVM_SYNC_GSCB (1UL << 9)232232#define KVM_SYNC_BPBC (1UL << 10)233233#define KVM_SYNC_ETOKEN (1UL << 11)234234+235235+#define KVM_SYNC_S390_VALID_FIELDS \236236+ (KVM_SYNC_PREFIX | KVM_SYNC_GPRS | KVM_SYNC_ACRS | KVM_SYNC_CRS | \237237+ KVM_SYNC_ARCH0 | KVM_SYNC_PFAULT | KVM_SYNC_VRS | KVM_SYNC_RICCB | \238238+ KVM_SYNC_FPRS | KVM_SYNC_GSCB | KVM_SYNC_BPBC | KVM_SYNC_ETOKEN)239239+234240/* length and alignment of the sdnx as a power of two */235241#define SDNXC 8236242#define SDNXL (1UL << SDNXC)
+5-1
arch/s390/kvm/kvm-s390.c
···39983998 if (kvm_run->immediate_exit)39993999 return -EINTR;4000400040014001+ if (kvm_run->kvm_valid_regs & ~KVM_SYNC_S390_VALID_FIELDS ||40024002+ kvm_run->kvm_dirty_regs & ~KVM_SYNC_S390_VALID_FIELDS)40034003+ return -EINVAL;40044004+40014005 vcpu_load(vcpu);4002400640034007 if (guestdbg_exit_pending(vcpu)) {···42594255 const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION42604256 | KVM_S390_MEMOP_F_CHECK_ONLY;4261425742624262- if (mop->flags & ~supported_flags)42584258+ if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size)42634259 return -EINVAL;4264426042654261 if (mop->size > MEM_OP_MAX_SIZE)
···2626/* The memory slot index to track dirty pages */2727#define TEST_MEM_SLOT_INDEX 128282929-/* Default guest test memory offset, 1G */3030-#define DEFAULT_GUEST_TEST_MEM 0x400000002929+/* Default guest test virtual memory offset */3030+#define DEFAULT_GUEST_TEST_MEM 0xc000000031313232/* How many pages to dirty for each guest loop */3333#define TEST_PAGES_PER_LOOP 1024···37373838/* Interval for each host loop (ms) */3939#define TEST_HOST_LOOP_INTERVAL 10UL4040+4141+/* Dirty bitmaps are always little endian, so we need to swap on big endian */4242+#if defined(__s390x__)4343+# define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7)4444+# define test_bit_le(nr, addr) \4545+ test_bit((nr) ^ BITOP_LE_SWIZZLE, addr)4646+# define set_bit_le(nr, addr) \4747+ set_bit((nr) ^ BITOP_LE_SWIZZLE, addr)4848+# define clear_bit_le(nr, addr) \4949+ clear_bit((nr) ^ BITOP_LE_SWIZZLE, addr)5050+# define test_and_set_bit_le(nr, addr) \5151+ test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, addr)5252+# define test_and_clear_bit_le(nr, addr) \5353+ test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, addr)5454+#else5555+# define test_bit_le test_bit5656+# define set_bit_le set_bit5757+# define clear_bit_le clear_bit5858+# define test_and_set_bit_le test_and_set_bit5959+# define test_and_clear_bit_le test_and_clear_bit6060+#endif40614162/*4263 * Guest/Host shared variables. Ensure addr_gva2hva() and/or···9069 */9170static void guest_code(void)9271{7272+ uint64_t addr;9373 int i;7474+7575+ /*7676+ * On s390x, all pages of a 1M segment are initially marked as dirty7777+ * when a page of the segment is written to for the very first time.7878+ * To compensate this specialty in this test, we need to touch all7979+ * pages during the first iteration.8080+ */8181+ for (i = 0; i < guest_num_pages; i++) {8282+ addr = guest_test_virt_mem + i * guest_page_size;8383+ *(uint64_t *)addr = READ_ONCE(iteration);8484+ }94859586 while (true) {9687 for (i = 0; i < TEST_PAGES_PER_LOOP; i++) {9797- uint64_t addr = guest_test_virt_mem;8888+ addr = guest_test_virt_mem;9889 addr += (READ_ONCE(random_array[i]) % guest_num_pages)9990 * guest_page_size;10091 addr &= ~(host_page_size - 1);···191158 value_ptr = host_test_mem + page * host_page_size;192159193160 /* If this is a special page that we were tracking... */194194- if (test_and_clear_bit(page, host_bmap_track)) {161161+ if (test_and_clear_bit_le(page, host_bmap_track)) {195162 host_track_next_count++;196196- TEST_ASSERT(test_bit(page, bmap),163163+ TEST_ASSERT(test_bit_le(page, bmap),197164 "Page %"PRIu64" should have its dirty bit "198165 "set in this iteration but it is missing",199166 page);200167 }201168202202- if (test_bit(page, bmap)) {169169+ if (test_bit_le(page, bmap)) {203170 host_dirty_count++;204171 /*205172 * If the bit is set, the value written onto···242209 * should report its dirtyness in the243210 * next run244211 */245245- set_bit(page, host_bmap_track);212212+ set_bit_le(page, host_bmap_track);246213 }247214 }248215 }···326293 * case where the size is not aligned to 64 pages.327294 */328295 guest_num_pages = (1ul << (30 - guest_page_shift)) + 16;296296+#ifdef __s390x__297297+ /* Round up to multiple of 1M (segment size) */298298+ guest_num_pages = (guest_num_pages + 0xff) & ~0xffUL;299299+#endif329300 host_page_size = getpagesize();330301 host_num_pages = (guest_num_pages * guest_page_size) / host_page_size +331302 !!((guest_num_pages * guest_page_size) % host_page_size);···340303 } else {341304 guest_test_phys_mem = phys_offset;342305 }306306+307307+#ifdef __s390x__308308+ /* Align to 1M (segment size) */309309+ guest_test_phys_mem &= ~((1 << 20) - 1);310310+#endif343311344312 DEBUG("guest physical test memory offset: 0x%lx\n", guest_test_phys_mem);345313···379337 vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());380338#endif381339#ifdef __aarch64__382382- ucall_init(vm, UCALL_MMIO, NULL);340340+ ucall_init(vm, NULL);383341#endif384342385343 /* Export the shared variables to the guest */···495453 vm_guest_mode_params_init(VM_MODE_P48V48_4K, true, true);496454 vm_guest_mode_params_init(VM_MODE_P48V48_64K, true, true);497455 }456456+#endif457457+#ifdef __s390x__458458+ vm_guest_mode_params_init(VM_MODE_P40V48_4K, true, true);498459#endif499460500461 while ((opt = getopt(argc, argv, "hi:I:p:m:")) != -1) {
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * ucall support. A ucall is a "hypercall to userspace".44+ *55+ * Copyright (C) 2018, Red Hat, Inc.66+ */77+#include "kvm_util.h"88+#include "../kvm_util_internal.h"99+1010+static vm_vaddr_t *ucall_exit_mmio_addr;1111+1212+static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa)1313+{1414+ if (kvm_userspace_memory_region_find(vm, gpa, gpa + 1))1515+ return false;1616+1717+ virt_pg_map(vm, gpa, gpa, 0);1818+1919+ ucall_exit_mmio_addr = (vm_vaddr_t *)gpa;2020+ sync_global_to_guest(vm, ucall_exit_mmio_addr);2121+2222+ return true;2323+}2424+2525+void ucall_init(struct kvm_vm *vm, void *arg)2626+{2727+ vm_paddr_t gpa, start, end, step, offset;2828+ unsigned int bits;2929+ bool ret;3030+3131+ if (arg) {3232+ gpa = (vm_paddr_t)arg;3333+ ret = ucall_mmio_init(vm, gpa);3434+ TEST_ASSERT(ret, "Can't set ucall mmio address to %lx", gpa);3535+ return;3636+ }3737+3838+ /*3939+ * Find an address within the allowed physical and virtual address4040+ * spaces, that does _not_ have a KVM memory region associated with4141+ * it. Identity mapping an address like this allows the guest to4242+ * access it, but as KVM doesn't know what to do with it, it4343+ * will assume it's something userspace handles and exit with4444+ * KVM_EXIT_MMIO. Well, at least that's how it works for AArch64.4545+ * Here we start with a guess that the addresses around 5/8th4646+ * of the allowed space are unmapped and then work both down and4747+ * up from there in 1/16th allowed space sized steps.4848+ *4949+ * Note, we need to use VA-bits - 1 when calculating the allowed5050+ * virtual address space for an identity mapping because the upper5151+ * half of the virtual address space is the two's complement of the5252+ * lower and won't match physical addresses.5353+ */5454+ bits = vm->va_bits - 1;5555+ bits = vm->pa_bits < bits ? vm->pa_bits : bits;5656+ end = 1ul << bits;5757+ start = end * 5 / 8;5858+ step = end / 16;5959+ for (offset = 0; offset < end - start; offset += step) {6060+ if (ucall_mmio_init(vm, start - offset))6161+ return;6262+ if (ucall_mmio_init(vm, start + offset))6363+ return;6464+ }6565+ TEST_ASSERT(false, "Can't find a ucall mmio address");6666+}6767+6868+void ucall_uninit(struct kvm_vm *vm)6969+{7070+ ucall_exit_mmio_addr = 0;7171+ sync_global_to_guest(vm, ucall_exit_mmio_addr);7272+}7373+7474+void ucall(uint64_t cmd, int nargs, ...)7575+{7676+ struct ucall uc = {7777+ .cmd = cmd,7878+ };7979+ va_list va;8080+ int i;8181+8282+ nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS;8383+8484+ va_start(va, nargs);8585+ for (i = 0; i < nargs; ++i)8686+ uc.args[i] = va_arg(va, uint64_t);8787+ va_end(va);8888+8989+ *ucall_exit_mmio_addr = (vm_vaddr_t)&uc;9090+}9191+9292+uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)9393+{9494+ struct kvm_run *run = vcpu_state(vm, vcpu_id);9595+ struct ucall ucall = {};9696+9797+ if (run->exit_reason == KVM_EXIT_MMIO &&9898+ run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) {9999+ vm_vaddr_t gva;100100+101101+ TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8,102102+ "Unexpected ucall exit mmio address access");103103+ memcpy(&gva, run->mmio.data, sizeof(gva));104104+ memcpy(&ucall, addr_gva2hva(vm, gva), sizeof(ucall));105105+106106+ vcpu_run_complete_io(vm, vcpu_id);107107+ if (uc)108108+ memcpy(uc, &ucall, sizeof(ucall));109109+ }110110+111111+ return ucall.cmd;112112+}
+56
tools/testing/selftests/kvm/lib/s390x/ucall.c
···11+// SPDX-License-Identifier: GPL-2.022+/*33+ * ucall support. A ucall is a "hypercall to userspace".44+ *55+ * Copyright (C) 2019 Red Hat, Inc.66+ */77+#include "kvm_util.h"88+99+void ucall_init(struct kvm_vm *vm, void *arg)1010+{1111+}1212+1313+void ucall_uninit(struct kvm_vm *vm)1414+{1515+}1616+1717+void ucall(uint64_t cmd, int nargs, ...)1818+{1919+ struct ucall uc = {2020+ .cmd = cmd,2121+ };2222+ va_list va;2323+ int i;2424+2525+ nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS;2626+2727+ va_start(va, nargs);2828+ for (i = 0; i < nargs; ++i)2929+ uc.args[i] = va_arg(va, uint64_t);3030+ va_end(va);3131+3232+ /* Exit via DIAGNOSE 0x501 (normally used for breakpoints) */3333+ asm volatile ("diag 0,%0,0x501" : : "a"(&uc) : "memory");3434+}3535+3636+uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)3737+{3838+ struct kvm_run *run = vcpu_state(vm, vcpu_id);3939+ struct ucall ucall = {};4040+4141+ if (run->exit_reason == KVM_EXIT_S390_SIEIC &&4242+ run->s390_sieic.icptcode == 4 &&4343+ (run->s390_sieic.ipa >> 8) == 0x83 && /* 0x83 means DIAGNOSE */4444+ (run->s390_sieic.ipb >> 16) == 0x501) {4545+ int reg = run->s390_sieic.ipa & 0xf;4646+4747+ memcpy(&ucall, addr_gva2hva(vm, run->s.regs.gprs[reg]),4848+ sizeof(ucall));4949+5050+ vcpu_run_complete_io(vm, vcpu_id);5151+ if (uc)5252+ memcpy(uc, &ucall, sizeof(ucall));5353+ }5454+5555+ return ucall.cmd;5656+}
-157
tools/testing/selftests/kvm/lib/ucall.c
···11-// SPDX-License-Identifier: GPL-2.022-/*33- * ucall support. A ucall is a "hypercall to userspace".44- *55- * Copyright (C) 2018, Red Hat, Inc.66- */77-#include "kvm_util.h"88-#include "kvm_util_internal.h"99-1010-#define UCALL_PIO_PORT ((uint16_t)0x1000)1111-1212-static ucall_type_t ucall_type;1313-static vm_vaddr_t *ucall_exit_mmio_addr;1414-1515-static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa)1616-{1717- if (kvm_userspace_memory_region_find(vm, gpa, gpa + 1))1818- return false;1919-2020- virt_pg_map(vm, gpa, gpa, 0);2121-2222- ucall_exit_mmio_addr = (vm_vaddr_t *)gpa;2323- sync_global_to_guest(vm, ucall_exit_mmio_addr);2424-2525- return true;2626-}2727-2828-void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg)2929-{3030- ucall_type = type;3131- sync_global_to_guest(vm, ucall_type);3232-3333- if (type == UCALL_PIO)3434- return;3535-3636- if (type == UCALL_MMIO) {3737- vm_paddr_t gpa, start, end, step, offset;3838- unsigned bits;3939- bool ret;4040-4141- if (arg) {4242- gpa = (vm_paddr_t)arg;4343- ret = ucall_mmio_init(vm, gpa);4444- TEST_ASSERT(ret, "Can't set ucall mmio address to %lx", gpa);4545- return;4646- }4747-4848- /*4949- * Find an address within the allowed physical and virtual address5050- * spaces, that does _not_ have a KVM memory region associated with5151- * it. Identity mapping an address like this allows the guest to5252- * access it, but as KVM doesn't know what to do with it, it5353- * will assume it's something userspace handles and exit with5454- * KVM_EXIT_MMIO. Well, at least that's how it works for AArch64.5555- * Here we start with a guess that the addresses around 5/8th5656- * of the allowed space are unmapped and then work both down and5757- * up from there in 1/16th allowed space sized steps.5858- *5959- * Note, we need to use VA-bits - 1 when calculating the allowed6060- * virtual address space for an identity mapping because the upper6161- * half of the virtual address space is the two's complement of the6262- * lower and won't match physical addresses.6363- */6464- bits = vm->va_bits - 1;6565- bits = vm->pa_bits < bits ? vm->pa_bits : bits;6666- end = 1ul << bits;6767- start = end * 5 / 8;6868- step = end / 16;6969- for (offset = 0; offset < end - start; offset += step) {7070- if (ucall_mmio_init(vm, start - offset))7171- return;7272- if (ucall_mmio_init(vm, start + offset))7373- return;7474- }7575- TEST_ASSERT(false, "Can't find a ucall mmio address");7676- }7777-}7878-7979-void ucall_uninit(struct kvm_vm *vm)8080-{8181- ucall_type = 0;8282- sync_global_to_guest(vm, ucall_type);8383- ucall_exit_mmio_addr = 0;8484- sync_global_to_guest(vm, ucall_exit_mmio_addr);8585-}8686-8787-static void ucall_pio_exit(struct ucall *uc)8888-{8989-#ifdef __x86_64__9090- asm volatile("in %[port], %%al"9191- : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax");9292-#endif9393-}9494-9595-static void ucall_mmio_exit(struct ucall *uc)9696-{9797- *ucall_exit_mmio_addr = (vm_vaddr_t)uc;9898-}9999-100100-void ucall(uint64_t cmd, int nargs, ...)101101-{102102- struct ucall uc = {103103- .cmd = cmd,104104- };105105- va_list va;106106- int i;107107-108108- nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS;109109-110110- va_start(va, nargs);111111- for (i = 0; i < nargs; ++i)112112- uc.args[i] = va_arg(va, uint64_t);113113- va_end(va);114114-115115- switch (ucall_type) {116116- case UCALL_PIO:117117- ucall_pio_exit(&uc);118118- break;119119- case UCALL_MMIO:120120- ucall_mmio_exit(&uc);121121- break;122122- };123123-}124124-125125-uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)126126-{127127- struct kvm_run *run = vcpu_state(vm, vcpu_id);128128- struct ucall ucall = {};129129- bool got_ucall = false;130130-131131-#ifdef __x86_64__132132- if (ucall_type == UCALL_PIO && run->exit_reason == KVM_EXIT_IO &&133133- run->io.port == UCALL_PIO_PORT) {134134- struct kvm_regs regs;135135- vcpu_regs_get(vm, vcpu_id, ®s);136136- memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(ucall));137137- got_ucall = true;138138- }139139-#endif140140- if (ucall_type == UCALL_MMIO && run->exit_reason == KVM_EXIT_MMIO &&141141- run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) {142142- vm_vaddr_t gva;143143- TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8,144144- "Unexpected ucall exit mmio address access");145145- memcpy(&gva, run->mmio.data, sizeof(gva));146146- memcpy(&ucall, addr_gva2hva(vm, gva), sizeof(ucall));147147- got_ucall = true;148148- }149149-150150- if (got_ucall) {151151- vcpu_run_complete_io(vm, vcpu_id);152152- if (uc)153153- memcpy(uc, &ucall, sizeof(ucall));154154- }155155-156156- return ucall.cmd;157157-}