Skip to content

Commit d4f8592

Browse files
schlacfrankjaa
authored andcommitted
selftests: kvm: s390: Add test fixture and simple VM setup tests
Add a uc_kvm fixture to create and destroy a ucontrol VM. * uc_sie_assertions asserts basic settings in the SIE as setup by the kernel. * uc_attr_mem_limit asserts the memory limit is max value and cannot be set (not supported). * uc_no_dirty_log asserts dirty log is not supported. Signed-off-by: Christoph Schlameuss <[email protected]> Reviewed-by: Claudio Imbrenda <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Janosch Frank <[email protected]> Message-ID: <[email protected]>
1 parent 011901f commit d4f8592

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

tools/testing/selftests/kvm/s390x/ucontrol_test.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@
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 */
1721
int 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

Comments
 (0)