aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2018-03-28 03:45:34 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2018-04-04 13:11:00 -0400
commit6089ae0bd5e15fc150adce5bc694e87e00513825 (patch)
tree68ef0918d9b8680cd4b9de9109a090eef63a5849
parent783e9e51266ebb7f78c606a53cb0fa41bb7c31a0 (diff)
kvm: selftests: add sync_regs_test
This includes the infrastructure to map the test into the guest and run code from the test program inside a VM. Signed-off-by: Ken Hofsass <hofsass@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--tools/testing/selftests/kvm/Makefile3
-rw-r--r--tools/testing/selftests/kvm/include/kvm_util.h3
-rw-r--r--tools/testing/selftests/kvm/lib/elf.c197
-rw-r--r--tools/testing/selftests/kvm/lib/io.c158
-rw-r--r--tools/testing/selftests/kvm/lib/x86.c3
-rw-r--r--tools/testing/selftests/kvm/sync_regs_test.c232
6 files changed, 595 insertions, 1 deletions
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 6aade26e9ca2..dc44de904797 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -3,10 +3,11 @@ all:
3top_srcdir = ../../../../ 3top_srcdir = ../../../../
4UNAME_M := $(shell uname -m) 4UNAME_M := $(shell uname -m)
5 5
6LIBKVM = lib/assert.c lib/kvm_util.c lib/sparsebit.c 6LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c
7LIBKVM_x86_64 = lib/x86.c 7LIBKVM_x86_64 = lib/x86.c
8 8
9TEST_GEN_PROGS_x86_64 = set_sregs_test 9TEST_GEN_PROGS_x86_64 = set_sregs_test
10TEST_GEN_PROGS_x86_64 += sync_regs_test
10 11
11TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) 12TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M))
12LIBKVM += $(LIBKVM_$(UNAME_M)) 13LIBKVM += $(LIBKVM_$(UNAME_M))
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index d2e3e23bfbd3..57974ad46373 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -57,6 +57,9 @@ void kvm_vm_free(struct kvm_vm *vmp);
57int kvm_memcmp_hva_gva(void *hva, 57int kvm_memcmp_hva_gva(void *hva,
58 struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); 58 struct kvm_vm *vm, const vm_vaddr_t gva, size_t len);
59 59
60void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
61 uint32_t data_memslot, uint32_t pgd_memslot);
62
60void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); 63void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent);
61void vcpu_dump(FILE *stream, struct kvm_vm *vm, 64void vcpu_dump(FILE *stream, struct kvm_vm *vm,
62 uint32_t vcpuid, uint8_t indent); 65 uint32_t vcpuid, uint8_t indent);
diff --git a/tools/testing/selftests/kvm/lib/elf.c b/tools/testing/selftests/kvm/lib/elf.c
new file mode 100644
index 000000000000..5eb857584aa3
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/elf.c
@@ -0,0 +1,197 @@
1/*
2 * tools/testing/selftests/kvm/lib/elf.c
3 *
4 * Copyright (C) 2018, Google LLC.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2.
7 */
8
9#include "test_util.h"
10
11#include <bits/endian.h>
12#include <linux/elf.h>
13
14#include "kvm_util.h"
15#include "kvm_util_internal.h"
16
17static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
18{
19 off_t offset_rv;
20
21 /* Open the ELF file. */
22 int fd;
23 fd = open(filename, O_RDONLY);
24 TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
25 " filename: %s\n"
26 " rv: %i errno: %i", filename, fd, errno);
27
28 /* Read in and validate ELF Identification Record.
29 * The ELF Identification record is the first 16 (EI_NIDENT) bytes
30 * of the ELF header, which is at the beginning of the ELF file.
31 * For now it is only safe to read the first EI_NIDENT bytes. Once
32 * read and validated, the value of e_ehsize can be used to determine
33 * the real size of the ELF header.
34 */
35 unsigned char ident[EI_NIDENT];
36 test_read(fd, ident, sizeof(ident));
37 TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
38 && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
39 "ELF MAGIC Mismatch,\n"
40 " filename: %s\n"
41 " ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
42 " Expected: %02x %02x %02x %02x",
43 filename,
44 ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
45 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
46 TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
47 "Current implementation only able to handle ELFCLASS64,\n"
48 " filename: %s\n"
49 " ident[EI_CLASS]: %02x\n"
50 " expected: %02x",
51 filename,
52 ident[EI_CLASS], ELFCLASS64);
53 TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
54 && (ident[EI_DATA] == ELFDATA2LSB))
55 || ((BYTE_ORDER == BIG_ENDIAN)
56 && (ident[EI_DATA] == ELFDATA2MSB)), "Current "
57 "implementation only able to handle\n"
58 "cases where the host and ELF file endianness\n"
59 "is the same:\n"
60 " host BYTE_ORDER: %u\n"
61 " host LITTLE_ENDIAN: %u\n"
62 " host BIG_ENDIAN: %u\n"
63 " ident[EI_DATA]: %u\n"
64 " ELFDATA2LSB: %u\n"
65 " ELFDATA2MSB: %u",
66 BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
67 ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
68 TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
69 "Current implementation only able to handle current "
70 "ELF version,\n"
71 " filename: %s\n"
72 " ident[EI_VERSION]: %02x\n"
73 " expected: %02x",
74 filename, ident[EI_VERSION], EV_CURRENT);
75
76 /* Read in the ELF header.
77 * With the ELF Identification portion of the ELF header
78 * validated, especially that the value at EI_VERSION is
79 * as expected, it is now safe to read the entire ELF header.
80 */
81 offset_rv = lseek(fd, 0, SEEK_SET);
82 TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
83 " rv: %zi expected: %i", offset_rv, 0);
84 test_read(fd, hdrp, sizeof(*hdrp));
85 TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
86 "Unexpected physical header size,\n"
87 " hdrp->e_phentsize: %x\n"
88 " expected: %zx",
89 hdrp->e_phentsize, sizeof(Elf64_Phdr));
90 TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
91 "Unexpected section header size,\n"
92 " hdrp->e_shentsize: %x\n"
93 " expected: %zx",
94 hdrp->e_shentsize, sizeof(Elf64_Shdr));
95}
96
97/* VM ELF Load
98 *
99 * Input Args:
100 * filename - Path to ELF file
101 *
102 * Output Args: None
103 *
104 * Input/Output Args:
105 * vm - Pointer to opaque type that describes the VM.
106 *
107 * Return: None, TEST_ASSERT failures for all error conditions
108 *
109 * Loads the program image of the ELF file specified by filename,
110 * into the virtual address space of the VM pointed to by vm. On entry
111 * the VM needs to not be using any of the virtual address space used
112 * by the image and it needs to have sufficient available physical pages, to
113 * back the virtual pages used to load the image.
114 */
115void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
116 uint32_t data_memslot, uint32_t pgd_memslot)
117{
118 off_t offset, offset_rv;
119 Elf64_Ehdr hdr;
120
121 /* Open the ELF file. */
122 int fd;
123 fd = open(filename, O_RDONLY);
124 TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
125 " filename: %s\n"
126 " rv: %i errno: %i", filename, fd, errno);
127
128 /* Read in the ELF header. */
129 elfhdr_get(filename, &hdr);
130
131 /* For each program header.
132 * The following ELF header members specify the location
133 * and size of the program headers:
134 *
135 * e_phoff - File offset to start of program headers
136 * e_phentsize - Size of each program header
137 * e_phnum - Number of program header entries
138 */
139 for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
140 /* Seek to the beginning of the program header. */
141 offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
142 offset_rv = lseek(fd, offset, SEEK_SET);
143 TEST_ASSERT(offset_rv == offset,
144 "Failed to seek to begining of program header %u,\n"
145 " filename: %s\n"
146 " rv: %jd errno: %i",
147 n1, filename, (intmax_t) offset_rv, errno);
148
149 /* Read in the program header. */
150 Elf64_Phdr phdr;
151 test_read(fd, &phdr, sizeof(phdr));
152
153 /* Skip if this header doesn't describe a loadable segment. */
154 if (phdr.p_type != PT_LOAD)
155 continue;
156
157 /* Allocate memory for this segment within the VM. */
158 TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
159 "memsize of 0,\n"
160 " phdr index: %u p_memsz: 0x%" PRIx64,
161 n1, (uint64_t) phdr.p_memsz);
162 vm_vaddr_t seg_vstart = phdr.p_vaddr;
163 seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1);
164 vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
165 seg_vend |= vm->page_size - 1;
166 size_t seg_size = seg_vend - seg_vstart + 1;
167
168 vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart,
169 data_memslot, pgd_memslot);
170 TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
171 "virtual memory for segment at requested min addr,\n"
172 " segment idx: %u\n"
173 " seg_vstart: 0x%lx\n"
174 " vaddr: 0x%lx",
175 n1, seg_vstart, vaddr);
176 memset(addr_gva2hva(vm, vaddr), 0, seg_size);
177 /* TODO(lhuemill): Set permissions of each memory segment
178 * based on the least-significant 3 bits of phdr.p_flags.
179 */
180
181 /* Load portion of initial state that is contained within
182 * the ELF file.
183 */
184 if (phdr.p_filesz) {
185 offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
186 TEST_ASSERT(offset_rv == phdr.p_offset,
187 "Seek to program segment offset failed,\n"
188 " program header idx: %u errno: %i\n"
189 " offset_rv: 0x%jx\n"
190 " expected: 0x%jx\n",
191 n1, errno, (intmax_t) offset_rv,
192 (intmax_t) phdr.p_offset);
193 test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
194 phdr.p_filesz);
195 }
196 }
197}
diff --git a/tools/testing/selftests/kvm/lib/io.c b/tools/testing/selftests/kvm/lib/io.c
new file mode 100644
index 000000000000..cff869ffe6ee
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/io.c
@@ -0,0 +1,158 @@
1/*
2 * tools/testing/selftests/kvm/lib/io.c
3 *
4 * Copyright (C) 2018, Google LLC.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2.
7 */
8
9#include "test_util.h"
10
11/* Test Write
12 *
13 * A wrapper for write(2), that automatically handles the following
14 * special conditions:
15 *
16 * + Interrupted system call (EINTR)
17 * + Write of less than requested amount
18 * + Non-block return (EAGAIN)
19 *
20 * For each of the above, an additional write is performed to automatically
21 * continue writing the requested data.
22 * There are also many cases where write(2) can return an unexpected
23 * error (e.g. EIO). Such errors cause a TEST_ASSERT failure.
24 *
25 * Note, for function signature compatibility with write(2), this function
26 * returns the number of bytes written, but that value will always be equal
27 * to the number of requested bytes. All other conditions in this and
28 * future enhancements to this function either automatically issue another
29 * write(2) or cause a TEST_ASSERT failure.
30 *
31 * Args:
32 * fd - Opened file descriptor to file to be written.
33 * count - Number of bytes to write.
34 *
35 * Output:
36 * buf - Starting address of data to be written.
37 *
38 * Return:
39 * On success, number of bytes written.
40 * On failure, a TEST_ASSERT failure is caused.
41 */
42ssize_t test_write(int fd, const void *buf, size_t count)
43{
44 ssize_t rc;
45 ssize_t num_written = 0;
46 size_t num_left = count;
47 const char *ptr = buf;
48
49 /* Note: Count of zero is allowed (see "RETURN VALUE" portion of
50 * write(2) manpage for details.
51 */
52 TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count);
53
54 do {
55 rc = write(fd, ptr, num_left);
56
57 switch (rc) {
58 case -1:
59 TEST_ASSERT(errno == EAGAIN || errno == EINTR,
60 "Unexpected write failure,\n"
61 " rc: %zi errno: %i", rc, errno);
62 continue;
63
64 case 0:
65 TEST_ASSERT(false, "Unexpected EOF,\n"
66 " rc: %zi num_written: %zi num_left: %zu",
67 rc, num_written, num_left);
68 break;
69
70 default:
71 TEST_ASSERT(rc >= 0, "Unexpected ret from write,\n"
72 " rc: %zi errno: %i", rc, errno);
73 num_written += rc;
74 num_left -= rc;
75 ptr += rc;
76 break;
77 }
78 } while (num_written < count);
79
80 return num_written;
81}
82
83/* Test Read
84 *
85 * A wrapper for read(2), that automatically handles the following
86 * special conditions:
87 *
88 * + Interrupted system call (EINTR)
89 * + Read of less than requested amount
90 * + Non-block return (EAGAIN)
91 *
92 * For each of the above, an additional read is performed to automatically
93 * continue reading the requested data.
94 * There are also many cases where read(2) can return an unexpected
95 * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. Note,
96 * it is expected that the file opened by fd at the current file position
97 * contains at least the number of requested bytes to be read. A TEST_ASSERT
98 * failure is produced if an End-Of-File condition occurs, before all the
99 * data is read. It is the callers responsibility to assure that sufficient
100 * data exists.
101 *
102 * Note, for function signature compatibility with read(2), this function
103 * returns the number of bytes read, but that value will always be equal
104 * to the number of requested bytes. All other conditions in this and
105 * future enhancements to this function either automatically issue another
106 * read(2) or cause a TEST_ASSERT failure.
107 *
108 * Args:
109 * fd - Opened file descriptor to file to be read.
110 * count - Number of bytes to read.
111 *
112 * Output:
113 * buf - Starting address of where to write the bytes read.
114 *
115 * Return:
116 * On success, number of bytes read.
117 * On failure, a TEST_ASSERT failure is caused.
118 */
119ssize_t test_read(int fd, void *buf, size_t count)
120{
121 ssize_t rc;
122 ssize_t num_read = 0;
123 size_t num_left = count;
124 char *ptr = buf;
125
126 /* Note: Count of zero is allowed (see "If count is zero" portion of
127 * read(2) manpage for details.
128 */
129 TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count);
130
131 do {
132 rc = read(fd, ptr, num_left);
133
134 switch (rc) {
135 case -1:
136 TEST_ASSERT(errno == EAGAIN || errno == EINTR,
137 "Unexpected read failure,\n"
138 " rc: %zi errno: %i", rc, errno);
139 break;
140
141 case 0:
142 TEST_ASSERT(false, "Unexpected EOF,\n"
143 " rc: %zi num_read: %zi num_left: %zu",
144 rc, num_read, num_left);
145 break;
146
147 default:
148 TEST_ASSERT(rc > 0, "Unexpected ret from read,\n"
149 " rc: %zi errno: %i", rc, errno);
150 num_read += rc;
151 num_left -= rc;
152 ptr += rc;
153 break;
154 }
155 } while (num_read < count);
156
157 return num_read;
158}
diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86.c
index 12df46280b23..2f17675f4275 100644
--- a/tools/testing/selftests/kvm/lib/x86.c
+++ b/tools/testing/selftests/kvm/lib/x86.c
@@ -687,6 +687,9 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code)
687 /* Create VM */ 687 /* Create VM */
688 vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES, O_RDWR); 688 vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES, O_RDWR);
689 689
690 /* Setup guest code */
691 kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
692
690 /* Setup IRQ Chip */ 693 /* Setup IRQ Chip */
691 vm_create_irqchip(vm); 694 vm_create_irqchip(vm);
692 695
diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/sync_regs_test.c
new file mode 100644
index 000000000000..428e9473f5e2
--- /dev/null
+++ b/tools/testing/selftests/kvm/sync_regs_test.c
@@ -0,0 +1,232 @@
1/*
2 * Test for x86 KVM_CAP_SYNC_REGS
3 *
4 * Copyright (C) 2018, Google LLC.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2.
7 *
8 * Verifies expected behavior of x86 KVM_CAP_SYNC_REGS functionality,
9 * including requesting an invalid register set, updates to/from values
10 * in kvm_run.s.regs when kvm_valid_regs and kvm_dirty_regs are toggled.
11 */
12
13#define _GNU_SOURCE /* for program_invocation_short_name */
14#include <fcntl.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <sys/ioctl.h>
19
20#include "test_util.h"
21#include "kvm_util.h"
22#include "x86.h"
23
24#define VCPU_ID 5
25#define PORT_HOST_SYNC 0x1000
26
27static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
28{
29 __asm__ __volatile__("in %[port], %%al"
30 :
31 : [port]"d"(port), "D"(arg0), "S"(arg1)
32 : "rax");
33}
34
35#define exit_to_l0(_port, _arg0, _arg1) \
36 __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
37
38#define GUEST_ASSERT(_condition) do { \
39 if (!(_condition)) \
40 exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\
41} while (0)
42
43void guest_code(void)
44{
45 for (;;) {
46 exit_to_l0(PORT_HOST_SYNC, "hello", 0);
47 asm volatile ("inc %r11");
48 }
49}
50
51static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
52{
53#define REG_COMPARE(reg) \
54 TEST_ASSERT(left->reg == right->reg, \
55 "Register " #reg \
56 " values did not match: 0x%llx, 0x%llx\n", \
57 left->reg, right->reg)
58 REG_COMPARE(rax);
59 REG_COMPARE(rbx);
60 REG_COMPARE(rcx);
61 REG_COMPARE(rdx);
62 REG_COMPARE(rsi);
63 REG_COMPARE(rdi);
64 REG_COMPARE(rsp);
65 REG_COMPARE(rbp);
66 REG_COMPARE(r8);
67 REG_COMPARE(r9);
68 REG_COMPARE(r10);
69 REG_COMPARE(r11);
70 REG_COMPARE(r12);
71 REG_COMPARE(r13);
72 REG_COMPARE(r14);
73 REG_COMPARE(r15);
74 REG_COMPARE(rip);
75 REG_COMPARE(rflags);
76#undef REG_COMPARE
77}
78
79static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right)
80{
81}
82
83static void compare_vcpu_events(struct kvm_vcpu_events *left,
84 struct kvm_vcpu_events *right)
85{
86}
87
88int main(int argc, char *argv[])
89{
90 struct kvm_vm *vm;
91 struct kvm_run *run;
92 struct kvm_regs regs;
93 struct kvm_sregs sregs;
94 struct kvm_vcpu_events events;
95 int rv, cap;
96
97 /* Tell stdout not to buffer its content */
98 setbuf(stdout, NULL);
99
100 cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
101 TEST_ASSERT((unsigned long)cap == KVM_SYNC_X86_VALID_FIELDS,
102 "KVM_CAP_SYNC_REGS (0x%x) != KVM_SYNC_X86_VALID_FIELDS (0x%lx)\n",
103 cap, KVM_SYNC_X86_VALID_FIELDS);
104
105 /* Create VM */
106 vm = vm_create_default(VCPU_ID, guest_code);
107
108 run = vcpu_state(vm, VCPU_ID);
109
110 /* Request reading invalid register set from VCPU. */
111 run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS << 1;
112 rv = _vcpu_run(vm, VCPU_ID);
113 TEST_ASSERT(rv < 0 && errno == EINVAL,
114 "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
115 rv);
116 vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
117
118 /* Request setting invalid register set into VCPU. */
119 run->kvm_dirty_regs = KVM_SYNC_X86_VALID_FIELDS << 1;
120 rv = _vcpu_run(vm, VCPU_ID);
121 TEST_ASSERT(rv < 0 && errno == EINVAL,
122 "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
123 rv);
124 vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
125
126 /* Request and verify all valid register sets. */
127 /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */
128 run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS;
129 rv = _vcpu_run(vm, VCPU_ID);
130 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
131 "Unexpected exit reason: %u (%s),\n",
132 run->exit_reason,
133 exit_reason_str(run->exit_reason));
134
135 vcpu_regs_get(vm, VCPU_ID, &regs);
136 compare_regs(&regs, &run->s.regs.regs);
137
138 vcpu_sregs_get(vm, VCPU_ID, &sregs);
139 compare_sregs(&sregs, &run->s.regs.sregs);
140
141 vcpu_events_get(vm, VCPU_ID, &events);
142 compare_vcpu_events(&events, &run->s.regs.events);
143
144 /* Set and verify various register values. */
145 run->s.regs.regs.r11 = 0xBAD1DEA;
146 run->s.regs.sregs.apic_base = 1 << 11;
147 /* TODO run->s.regs.events.XYZ = ABC; */
148
149 run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS;
150 run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS;
151 rv = _vcpu_run(vm, VCPU_ID);
152 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
153 "Unexpected exit reason: %u (%s),\n",
154 run->exit_reason,
155 exit_reason_str(run->exit_reason));
156 TEST_ASSERT(run->s.regs.regs.r11 == 0xBAD1DEA + 1,
157 "r11 sync regs value incorrect 0x%llx.",
158 run->s.regs.regs.r11);
159 TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11,
160 "apic_base sync regs value incorrect 0x%llx.",
161 run->s.regs.sregs.apic_base);
162
163 vcpu_regs_get(vm, VCPU_ID, &regs);
164 compare_regs(&regs, &run->s.regs.regs);
165
166 vcpu_sregs_get(vm, VCPU_ID, &sregs);
167 compare_sregs(&sregs, &run->s.regs.sregs);
168
169 vcpu_events_get(vm, VCPU_ID, &events);
170 compare_vcpu_events(&events, &run->s.regs.events);
171
172 /* Clear kvm_dirty_regs bits, verify new s.regs values are
173 * overwritten with existing guest values.
174 */
175 run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS;
176 run->kvm_dirty_regs = 0;
177 run->s.regs.regs.r11 = 0xDEADBEEF;
178 rv = _vcpu_run(vm, VCPU_ID);
179 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
180 "Unexpected exit reason: %u (%s),\n",
181 run->exit_reason,
182 exit_reason_str(run->exit_reason));
183 TEST_ASSERT(run->s.regs.regs.r11 != 0xDEADBEEF,
184 "r11 sync regs value incorrect 0x%llx.",
185 run->s.regs.regs.r11);
186
187 /* Clear kvm_valid_regs bits and kvm_dirty_bits.
188 * Verify s.regs values are not overwritten with existing guest values
189 * and that guest values are not overwritten with kvm_sync_regs values.
190 */
191 run->kvm_valid_regs = 0;
192 run->kvm_dirty_regs = 0;
193 run->s.regs.regs.r11 = 0xAAAA;
194 regs.r11 = 0xBAC0;
195 vcpu_regs_set(vm, VCPU_ID, &regs);
196 rv = _vcpu_run(vm, VCPU_ID);
197 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
198 "Unexpected exit reason: %u (%s),\n",
199 run->exit_reason,
200 exit_reason_str(run->exit_reason));
201 TEST_ASSERT(run->s.regs.regs.r11 == 0xAAAA,
202 "r11 sync regs value incorrect 0x%llx.",
203 run->s.regs.regs.r11);
204 vcpu_regs_get(vm, VCPU_ID, &regs);
205 TEST_ASSERT(regs.r11 == 0xBAC0 + 1,
206 "r11 guest value incorrect 0x%llx.",
207 regs.r11);
208
209 /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten
210 * with existing guest values but that guest values are overwritten
211 * with kvm_sync_regs values.
212 */
213 run->kvm_valid_regs = 0;
214 run->kvm_dirty_regs = KVM_SYNC_X86_VALID_FIELDS;
215 run->s.regs.regs.r11 = 0xBBBB;
216 rv = _vcpu_run(vm, VCPU_ID);
217 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
218 "Unexpected exit reason: %u (%s),\n",
219 run->exit_reason,
220 exit_reason_str(run->exit_reason));
221 TEST_ASSERT(run->s.regs.regs.r11 == 0xBBBB,
222 "r11 sync regs value incorrect 0x%llx.",
223 run->s.regs.regs.r11);
224 vcpu_regs_get(vm, VCPU_ID, &regs);
225 TEST_ASSERT(regs.r11 == 0xBBBB + 1,
226 "r11 guest value incorrect 0x%llx.",
227 regs.r11);
228
229 kvm_vm_free(vm);
230
231 return 0;
232}