-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
KVM: selftests: Add a test for the KVM_S390_MEM_OP ioctl
Check that we can write and read the guest memory with this s390x ioctl, and that some error cases are handled correctly. Signed-off-by: Thomas Huth <thuth@redhat.com> Link: https://lkml.kernel.org/r/20190829130732.580-1-thuth@redhat.com Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
- Loading branch information
Thomas Huth
authored and
Christian Borntraeger
committed
Aug 29, 2019
1 parent
b4d863c
commit be6f55a
Showing
2 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Test for s390x KVM_S390_MEM_OP | ||
* | ||
* Copyright (C) 2019, Red Hat, Inc. | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/ioctl.h> | ||
|
||
#include "test_util.h" | ||
#include "kvm_util.h" | ||
|
||
#define VCPU_ID 1 | ||
|
||
static uint8_t mem1[65536]; | ||
static uint8_t mem2[65536]; | ||
|
||
static void guest_code(void) | ||
{ | ||
int i; | ||
|
||
for (;;) { | ||
for (i = 0; i < sizeof(mem2); i++) | ||
mem2[i] = mem1[i]; | ||
GUEST_SYNC(0); | ||
} | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
struct kvm_vm *vm; | ||
struct kvm_run *run; | ||
struct kvm_s390_mem_op ksmo; | ||
int rv, i, maxsize; | ||
|
||
setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ | ||
|
||
maxsize = kvm_check_cap(KVM_CAP_S390_MEM_OP); | ||
if (!maxsize) { | ||
fprintf(stderr, "CAP_S390_MEM_OP not supported -> skip test\n"); | ||
exit(KSFT_SKIP); | ||
} | ||
if (maxsize > sizeof(mem1)) | ||
maxsize = sizeof(mem1); | ||
|
||
/* Create VM */ | ||
vm = vm_create_default(VCPU_ID, 0, guest_code); | ||
run = vcpu_state(vm, VCPU_ID); | ||
|
||
for (i = 0; i < sizeof(mem1); i++) | ||
mem1[i] = i * i + i; | ||
|
||
/* Set the first array */ | ||
ksmo.gaddr = addr_gva2gpa(vm, (uintptr_t)mem1); | ||
ksmo.flags = 0; | ||
ksmo.size = maxsize; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 0; | ||
vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
|
||
/* Let the guest code copy the first array to the second */ | ||
vcpu_run(vm, VCPU_ID); | ||
TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, | ||
"Unexpected exit reason: %u (%s)\n", | ||
run->exit_reason, | ||
exit_reason_str(run->exit_reason)); | ||
|
||
memset(mem2, 0xaa, sizeof(mem2)); | ||
|
||
/* Get the second array */ | ||
ksmo.gaddr = (uintptr_t)mem2; | ||
ksmo.flags = 0; | ||
ksmo.size = maxsize; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_READ; | ||
ksmo.buf = (uintptr_t)mem2; | ||
ksmo.ar = 0; | ||
vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
|
||
TEST_ASSERT(!memcmp(mem1, mem2, maxsize), | ||
"Memory contents do not match!"); | ||
|
||
/* Check error conditions - first bad size: */ | ||
ksmo.gaddr = (uintptr_t)mem1; | ||
ksmo.flags = 0; | ||
ksmo.size = -1; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 0; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv == -1 && errno == E2BIG, "ioctl allows insane sizes"); | ||
|
||
/* Zero size: */ | ||
ksmo.gaddr = (uintptr_t)mem1; | ||
ksmo.flags = 0; | ||
ksmo.size = 0; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 0; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv == -1 && (errno == EINVAL || errno == ENOMEM), | ||
"ioctl allows 0 as size"); | ||
|
||
/* Bad flags: */ | ||
ksmo.gaddr = (uintptr_t)mem1; | ||
ksmo.flags = -1; | ||
ksmo.size = maxsize; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 0; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows all flags"); | ||
|
||
/* Bad operation: */ | ||
ksmo.gaddr = (uintptr_t)mem1; | ||
ksmo.flags = 0; | ||
ksmo.size = maxsize; | ||
ksmo.op = -1; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 0; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows bad operations"); | ||
|
||
/* Bad guest address: */ | ||
ksmo.gaddr = ~0xfffUL; | ||
ksmo.flags = KVM_S390_MEMOP_F_CHECK_ONLY; | ||
ksmo.size = maxsize; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 0; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv > 0, "ioctl does not report bad guest memory access"); | ||
|
||
/* Bad host address: */ | ||
ksmo.gaddr = (uintptr_t)mem1; | ||
ksmo.flags = 0; | ||
ksmo.size = maxsize; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = 0; | ||
ksmo.ar = 0; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv == -1 && errno == EFAULT, | ||
"ioctl does not report bad host memory address"); | ||
|
||
/* Bad access register: */ | ||
run->psw_mask &= ~(3UL << (63 - 17)); | ||
run->psw_mask |= 1UL << (63 - 17); /* Enable AR mode */ | ||
vcpu_run(vm, VCPU_ID); /* To sync new state to SIE block */ | ||
ksmo.gaddr = (uintptr_t)mem1; | ||
ksmo.flags = 0; | ||
ksmo.size = maxsize; | ||
ksmo.op = KVM_S390_MEMOP_LOGICAL_WRITE; | ||
ksmo.buf = (uintptr_t)mem1; | ||
ksmo.ar = 17; | ||
rv = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_MEM_OP, &ksmo); | ||
TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows ARs > 15"); | ||
run->psw_mask &= ~(3UL << (63 - 17)); /* Disable AR mode */ | ||
vcpu_run(vm, VCPU_ID); /* Run to sync new state */ | ||
|
||
kvm_vm_free(vm); | ||
|
||
return 0; | ||
} |