1f08c3bdfSopenharmony_ciLTP KVM Test API
2f08c3bdfSopenharmony_ci================
3f08c3bdfSopenharmony_ci
4f08c3bdfSopenharmony_ciTesting KVM is more complex than other Linux features. Some KVM bugs allow
5f08c3bdfSopenharmony_ciuserspace code running inside the virtual machine to bypass (emulated) hardware
6f08c3bdfSopenharmony_ciaccess restrictions and elevate its privileges inside the guest operating
7f08c3bdfSopenharmony_cisystem. The worst types of KVM bugs may even allow the guest code to crash or
8f08c3bdfSopenharmony_cicompromise the physical host. KVM tests therefore need to be split into two
9f08c3bdfSopenharmony_cicomponents – a KVM controller program running on the physical host and a guest
10f08c3bdfSopenharmony_cipayload program running inside the VM. The cooperation of these two components
11f08c3bdfSopenharmony_ciallows testing even of bugs that somehow cross the virtualization boundary.
12f08c3bdfSopenharmony_ci
13f08c3bdfSopenharmony_ciNOTE: See also
14f08c3bdfSopenharmony_ci      https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines],
15f08c3bdfSopenharmony_ci      https://github.com/linux-test-project/ltp/wiki/C-Test-Case-Tutorial[C Test Case Tutorial],
16f08c3bdfSopenharmony_ci      https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API].
17f08c3bdfSopenharmony_ci
18f08c3bdfSopenharmony_ci1. Basic KVM test structure
19f08c3bdfSopenharmony_ci---------------------------
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_ciKVM tests are simple C source files containing both the KVM controller code
22f08c3bdfSopenharmony_ciand the guest payload code separated by `#ifdef COMPILE_PAYLOAD` preprocessor
23f08c3bdfSopenharmony_cicondition. The file will be compiled twice. Once to compile the payload part,
24f08c3bdfSopenharmony_cionce to compile the KVM controller part and embed the payload binary inside.
25f08c3bdfSopenharmony_ciThe result is a single self-contained binary that'll execute the embedded
26f08c3bdfSopenharmony_cipayload inside a KVM virtual machine and print results in the same format as
27f08c3bdfSopenharmony_cia normal LTP test.
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ciA KVM test source should start with `#include "kvm_test.h"` instead of the
30f08c3bdfSopenharmony_ciusual `tst_test.h`. The `kvm_test.h` header file will include the other basic
31f08c3bdfSopenharmony_ciheaders appropriate for the current compilation pass. Everything else in the
32f08c3bdfSopenharmony_cisource file should be enclosed in `#ifdef COMPILE_PAYLOAD ... #else ... #endif`
33f08c3bdfSopenharmony_cicondition, including any other header file includes. Note that the standard
34f08c3bdfSopenharmony_ciLTP headers are not available in the payload compilation pass, only the KVM
35f08c3bdfSopenharmony_ciguest library headers can be included.
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci.Example KVM test
38f08c3bdfSopenharmony_ci[source,c]
39f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
40f08c3bdfSopenharmony_ci#include "kvm_test.h"
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_ci#ifdef COMPILE_PAYLOAD
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci/* Guest payload code */
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_civoid main(void)
47f08c3bdfSopenharmony_ci{
48f08c3bdfSopenharmony_ci	tst_res(TPASS, "Hello, world!");
49f08c3bdfSopenharmony_ci}
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci#else /* COMPILE_PAYLOAD */
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci/* KVM controller code */
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_cistatic struct tst_test test = {
56f08c3bdfSopenharmony_ci	.test_all = tst_kvm_run,
57f08c3bdfSopenharmony_ci	.setup = tst_kvm_setup,
58f08c3bdfSopenharmony_ci	.cleanup = tst_kvm_cleanup,
59f08c3bdfSopenharmony_ci};
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ci#endif /* COMPILE_PAYLOAD */
62f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ciThe KVM controller code is a normal LTP test and needs to define an instance
65f08c3bdfSopenharmony_ciof `struct tst_test` with metadata and the usual setup, cleanup, and test
66f08c3bdfSopenharmony_cifunctions. Basic implementation of all three functions is provided by the KVM
67f08c3bdfSopenharmony_cihost library.
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ciOn the other hand, the payload is essentially a tiny kernel that'll run
70f08c3bdfSopenharmony_cion bare virtual hardware. It cannot access any files, Linux syscalls, standard
71f08c3bdfSopenharmony_cilibrary functions, etc. except for the small subset provided by the KVM guest
72f08c3bdfSopenharmony_cilibrary. The payload code must define a `void main(void)` function which will
73f08c3bdfSopenharmony_cibe the VM entry point of the test.
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci2. KVM host library
76f08c3bdfSopenharmony_ci-------------------
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ciThe KVM host library provides helper functions for creating and running
79f08c3bdfSopenharmony_cia minimal KVM virtual machine.
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci2.1 Data structures
82f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ci[source,c]
85f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
86f08c3bdfSopenharmony_cistruct tst_kvm_instance {
87f08c3bdfSopenharmony_ci	int vm_fd, vcpu_fd;
88f08c3bdfSopenharmony_ci	struct kvm_run *vcpu_info;
89f08c3bdfSopenharmony_ci	size_t vcpu_info_size;
90f08c3bdfSopenharmony_ci	struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS];
91f08c3bdfSopenharmony_ci	struct tst_kvm_result *result;
92f08c3bdfSopenharmony_ci};
93f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci`struct tst_kvm_instance` holds the file descriptors and memory buffers
96f08c3bdfSopenharmony_ciof a single KVM virtual machine:
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci- `int vm_fd` is the main VM file descriptor created by `ioctl(KVM_CREATE_VM)`
99f08c3bdfSopenharmony_ci- `int vcpu_fd` is the virtual CPU filedescriptor created by
100f08c3bdfSopenharmony_ci  `ioctl(KVM_CREATE_VCPU)`
101f08c3bdfSopenharmony_ci- `struct kvm_run *vcpu_info` is the VCPU state structure created by
102f08c3bdfSopenharmony_ci  `mmap(vcpu_fd)`
103f08c3bdfSopenharmony_ci- `size_t vcpu_info_size` is the size of `vcpu_info` buffer
104f08c3bdfSopenharmony_ci- `struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS]` is the list
105f08c3bdfSopenharmony_ci  of memory slots defined in this VM. Unused memory slots have zero
106f08c3bdfSopenharmony_ci  in the `userspace_addr` field.
107f08c3bdfSopenharmony_ci- `struct tst_kvm_result *result` is a buffer for passing test result data
108f08c3bdfSopenharmony_ci  from the VM to the controller program, mainly `tst_res()`/`tst_brk()` flags
109f08c3bdfSopenharmony_ci  and messages.
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci[source,c]
112f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
113f08c3bdfSopenharmony_cistruct tst_kvm_result {
114f08c3bdfSopenharmony_ci	int32_t result;
115f08c3bdfSopenharmony_ci	int32_t lineno;
116f08c3bdfSopenharmony_ci	uint64_t file_addr;
117f08c3bdfSopenharmony_ci	char message[0];
118f08c3bdfSopenharmony_ci};
119f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_ci`struct tst_kvm_result` is used to pass test results and synchronization data
122f08c3bdfSopenharmony_cibetween the KVM guest and the controller program. Most often, it is used
123f08c3bdfSopenharmony_cito pass `tst_res()` and `tst_brk()` messages from the VM, but special values
124f08c3bdfSopenharmony_cican also be used to send control flow requests both ways.
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ci- `int32_t result` is the message type, either one of the `TPASS`, `TFAIL`,
127f08c3bdfSopenharmony_ci  `TWARN`, `TBROK`, `TINFO` flags or a special control flow value. Errno flags
128f08c3bdfSopenharmony_ci  are not supported.
129f08c3bdfSopenharmony_ci- `int32_t lineno` is the line number for `tst_res()`/`tst_brk()` messages.
130f08c3bdfSopenharmony_ci- `uint64_t file_addr` is the VM address of the filename string for
131f08c3bdfSopenharmony_ci  `tst_res()`/`tst_brk()` messages.
132f08c3bdfSopenharmony_ci- `char message[0]` is the buffer for arbitrary message data, most often used
133f08c3bdfSopenharmony_ci  to pass `tst_res()`/`tst_brk()` message strings.
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_ci2.2 Working with virtual machines
136f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ciThe KVM host library provides default implementation of the setup, cleanup
139f08c3bdfSopenharmony_ciand test functions for `struct tst_test` in cases where you do not need
140f08c3bdfSopenharmony_cito customize the VM configuration. You can either assign these functions
141f08c3bdfSopenharmony_cito the `struct tst_test` instance directly or call them from your own function
142f08c3bdfSopenharmony_cithat does some additional steps. All three function must be used together.
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_ci- `void tst_kvm_setup(void)`
145f08c3bdfSopenharmony_ci- `void tst_kvm_run(void)`
146f08c3bdfSopenharmony_ci- `void tst_kvm_cleanup(void)`
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_ciNote: `tst_kvm_run()` calls `tst_free_all()`. Calling it will free all
149f08c3bdfSopenharmony_cipreviously allocated guarded buffers.
150f08c3bdfSopenharmony_ci
151f08c3bdfSopenharmony_ci- `void tst_kvm_validate_result(int value)` – Validate whether the value
152f08c3bdfSopenharmony_ci  returned in `struct tst_kvm_result.result` can be safely passed
153f08c3bdfSopenharmony_ci  to `tst_res()` or `tst_brk()`. If the value is not valid, the controller
154f08c3bdfSopenharmony_ci  program will be terminated with error.
155f08c3bdfSopenharmony_ci
156f08c3bdfSopenharmony_ci- `uint64_t tst_kvm_get_phys_address(const struct tst_kvm_instance *inst,
157f08c3bdfSopenharmony_ci  uint64_t addr)` – Converts pointer value (virtual address) from KVM virtual
158f08c3bdfSopenharmony_ci  machine `inst` to the corresponding physical address. Returns 0 if
159f08c3bdfSopenharmony_ci  the virtual address is not mapped to any physical address. If virtual memory
160f08c3bdfSopenharmony_ci  mapping is not enabled in the VM or not available on the arch at all, this
161f08c3bdfSopenharmony_ci  function simply returns `addr` as is.
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci- `int tst_kvm_find_phys_memslot(const struct tst_kvm_instance *inst,
164f08c3bdfSopenharmony_ci  uint64_t paddr)` – Returns index of the memory slot in KVM virtual machine
165f08c3bdfSopenharmony_ci  `inst` which contains the physical address `paddr`. If the address is not
166f08c3bdfSopenharmony_ci  backed by a memory buffer, returns -1.
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_ci- `int tst_kvm_find_memslot(const struct tst_kvm_instance *inst,
169f08c3bdfSopenharmony_ci  uint64_t addr)` – Returns index of the memory slot in KVM virtual machine
170f08c3bdfSopenharmony_ci  `inst` which contains the virtual address `addr`. If the virtual address
171f08c3bdfSopenharmony_ci  is not mapped to a valid physical address backed by a memory buffer,
172f08c3bdfSopenharmony_ci  returns -1.
173f08c3bdfSopenharmony_ci
174f08c3bdfSopenharmony_ci- `void *tst_kvm_get_memptr(const struct tst_kvm_instance *inst,
175f08c3bdfSopenharmony_ci  uint64_t addr)` – Converts pointer value (virtual address) from KVM virtual
176f08c3bdfSopenharmony_ci  machine `inst` to host-side pointer.
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ci- `void *tst_kvm_alloc_memory(struct tst_kvm_instance *inst, unsigned int slot,
179f08c3bdfSopenharmony_ci  uint64_t baseaddr, size_t size, unsigned int flags)` – Allocates a guarded
180f08c3bdfSopenharmony_ci  buffer of given `size` in bytes and installs it into specified memory `slot`
181f08c3bdfSopenharmony_ci  of the KVM virtual machine `inst` at base address `baseaddr`. The buffer
182f08c3bdfSopenharmony_ci  will be automatically page aligned at both ends. See the kernel
183f08c3bdfSopenharmony_ci  documentation of `KVM_SET_USER_MEMORY_REGION` ioctl for list of valid
184f08c3bdfSopenharmony_ci  `flags`. Returns pointer to page-aligned beginning of the allocated buffer.
185f08c3bdfSopenharmony_ci  The actual requested `baseaddr` will be located at
186f08c3bdfSopenharmony_ci  `ret + baseaddr % pagesize`.
187f08c3bdfSopenharmony_ci
188f08c3bdfSopenharmony_ci- `struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd)` – Get a list of supported
189f08c3bdfSopenharmony_ci  virtual CPU features returned by `ioctl(KVM_GET_SUPPORTED_CPUID)`.
190f08c3bdfSopenharmony_ci  The argument must be an open file descriptor returned by `open("/dev/kvm")`.
191f08c3bdfSopenharmony_ci
192f08c3bdfSopenharmony_ci- `void tst_kvm_create_instance(struct tst_kvm_instance *inst,
193f08c3bdfSopenharmony_ci  size_t ram_size)` – Creates and fully initializes a new KVM virtual machine
194f08c3bdfSopenharmony_ci  with at least `ram_size` bytes of memory. The VM instance info will be
195f08c3bdfSopenharmony_ci  stored in `inst`.
196f08c3bdfSopenharmony_ci
197f08c3bdfSopenharmony_ci- `int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno)` –
198f08c3bdfSopenharmony_ci  Executes the program installed in KVM virtual machine `inst`. Any result
199f08c3bdfSopenharmony_ci  messages returned by the VM will be automatically printed to controller
200f08c3bdfSopenharmony_ci  program output. Returns zero. If `exp_errno` is non-zero, the VM execution
201f08c3bdfSopenharmony_ci  syscall is allowed to fail with the `exp_errno` error code and
202f08c3bdfSopenharmony_ci  `tst_kvm_run_instance()` will return -1 instead of terminating the test.
203f08c3bdfSopenharmony_ci
204f08c3bdfSopenharmony_ci- `void tst_kvm_destroy_instance(struct tst_kvm_instance *inst)` – Deletes
205f08c3bdfSopenharmony_ci  the KVM virtual machine `inst`. Note that the guarded buffers assigned
206f08c3bdfSopenharmony_ci  to the VM by `tst_kvm_create_instance()` or `tst_kvm_alloc_memory()` will
207f08c3bdfSopenharmony_ci  not be freed.
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ciThe KVM host library does not provide any way to reset a VM instance back
210f08c3bdfSopenharmony_cito initial state. Running multiple iterations of the test requires destroying
211f08c3bdfSopenharmony_cithe old VM instance and creating a new one. Otherwise the VM will exit
212f08c3bdfSopenharmony_ciwithout reporting any results on the second iteration and the test will fail.
213f08c3bdfSopenharmony_ciThe `tst_kvm_run()` function handles this issue correctly.
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_ci3. KVM guest library
216f08c3bdfSopenharmony_ci--------------------
217f08c3bdfSopenharmony_ci
218f08c3bdfSopenharmony_ciThe KVM guest library provides a minimal implementation of both the LTP
219f08c3bdfSopenharmony_citest library and the standard C library functions. Do not try to include
220f08c3bdfSopenharmony_cithe usual LTP or C headers in guest payload code, it will not work.
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_ci3.1 Standard C functions
223f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~~~
224f08c3bdfSopenharmony_ci
225f08c3bdfSopenharmony_ci`#include "kvm_test.h"`
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_ciThe functions listed below are implemented according to the C standard:
228f08c3bdfSopenharmony_ci
229f08c3bdfSopenharmony_ci- `void *memset(void *dest, int val, size_t size)`
230f08c3bdfSopenharmony_ci- `void *memzero(void *dest, size_t size)`
231f08c3bdfSopenharmony_ci- `void *memcpy(void *dest, const void *src, size_t size)`
232f08c3bdfSopenharmony_ci- `char *strcpy(char *dest, const char *src)`
233f08c3bdfSopenharmony_ci- `char *strcat(char *dest, const char *src)`
234f08c3bdfSopenharmony_ci- `size_t strlen(const char *str)`
235f08c3bdfSopenharmony_ci
236f08c3bdfSopenharmony_ci3.2 LTP library functions
237f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~~~~
238f08c3bdfSopenharmony_ci
239f08c3bdfSopenharmony_ci`#include "kvm_test.h"`
240f08c3bdfSopenharmony_ci
241f08c3bdfSopenharmony_ciThe KVM guest library currently provides the LTP functions for reporting test
242f08c3bdfSopenharmony_ciresults. All standard result flags except for `T*ERRNO` are supported
243f08c3bdfSopenharmony_ciwith the same rules as usual. However, the printf-like formatting is not
244f08c3bdfSopenharmony_ciimplemented yet.
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_ci- `void tst_res(int result, const char *message)`
247f08c3bdfSopenharmony_ci- `void tst_brk(int result, const char *message) __attribute__((noreturn))`
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_ciA handful of useful macros is also available:
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci- `TST_TEST_TCONF(message)` – Generates a test program that will simply print
252f08c3bdfSopenharmony_ci  a `TCONF` message and exit. This is useful when the real test cannot be
253f08c3bdfSopenharmony_ci  built due to missing dependencies or arch limitations.
254f08c3bdfSopenharmony_ci
255f08c3bdfSopenharmony_ci- `ARRAY_SIZE(arr)` – Returns the number of items in statically allocated
256f08c3bdfSopenharmony_ci  array `arr`.
257f08c3bdfSopenharmony_ci
258f08c3bdfSopenharmony_ci- `LTP_ALIGN(x, a)` – Aligns integer `x` to be a multiple of `a`, which
259f08c3bdfSopenharmony_ci  must be a power of 2.
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci3.3 Arch independent functions
262f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci`#include "kvm_test.h"`
265f08c3bdfSopenharmony_ci
266f08c3bdfSopenharmony_ciMemory management in KVM guest library currently uses only primitive linear
267f08c3bdfSopenharmony_cibuffer for memory allocation. There are no checks whether the VM can allocate
268f08c3bdfSopenharmony_cimore memory and the already allocated memory cannot be freed.
269f08c3bdfSopenharmony_ci
270f08c3bdfSopenharmony_ci- `void *tst_heap_alloc(size_t size)` – Allocates a block of memory on the heap.
271f08c3bdfSopenharmony_ci
272f08c3bdfSopenharmony_ci- `void *tst_heap_alloc_aligned(size_t size, size_t align)` – Allocates
273f08c3bdfSopenharmony_ci  a block of memory on the heap with the starting address aligned to given
274f08c3bdfSopenharmony_ci  value.
275f08c3bdfSopenharmony_ci
276f08c3bdfSopenharmony_ci3.4 x86 specific functions
277f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~~~~~
278f08c3bdfSopenharmony_ci
279f08c3bdfSopenharmony_ci`#include "kvm_test.h"` +
280f08c3bdfSopenharmony_ci`#include "kvm_x86.h"`
281f08c3bdfSopenharmony_ci
282f08c3bdfSopenharmony_ci- `struct kvm_interrupt_frame` – Opaque arch-dependent structure which holds
283f08c3bdfSopenharmony_ci  interrupt frame information. Use the functions below to get individual values:
284f08c3bdfSopenharmony_ci
285f08c3bdfSopenharmony_ci- `uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm)` –
286f08c3bdfSopenharmony_ci  Get instruction pointer value from interrupt frame structure. This may be
287f08c3bdfSopenharmony_ci  the instruction which caused an interrupt or the one immediately after,
288f08c3bdfSopenharmony_ci  depending on the interrupt vector semantics.
289f08c3bdfSopenharmony_ci
290f08c3bdfSopenharmony_ci- `int (*tst_interrupt_callback)(void *userdata,
291f08c3bdfSopenharmony_ci  struct kvm_interrupt_frame *ifrm, unsigned long errcode)` – Interrupt handler
292f08c3bdfSopenharmony_ci  callback prototype. When an interrupt occurs, the assigned callback function
293f08c3bdfSopenharmony_ci  will be passed the `userdata` pointer that was given
294f08c3bdfSopenharmony_ci  to `tst_set_interrupt_callback()`, interrupt frame `ifrm` and the error
295f08c3bdfSopenharmony_ci  code `errcode` defined by the interrupt vector semantics. If the interrupt
296f08c3bdfSopenharmony_ci  vector does not generate an error code, `errcode` will be set to zero.
297f08c3bdfSopenharmony_ci  The callback function must return 0 if the interrupt was successfully
298f08c3bdfSopenharmony_ci  handled and test execution should resume. Non-zero return value means that
299f08c3bdfSopenharmony_ci  the interrupt could not be handled and the test will terminate with error.
300f08c3bdfSopenharmony_ci
301f08c3bdfSopenharmony_ci- `void tst_set_interrupt_callback(unsigned int vector,
302f08c3bdfSopenharmony_ci  tst_interrupt_callback func, void *userdata)` – Register new interrupt
303f08c3bdfSopenharmony_ci  handler callback function `func` for interrupt `vector`. The `userdata`
304f08c3bdfSopenharmony_ci  argument is an arbitrary pointer that will be passed to `func()` every time
305f08c3bdfSopenharmony_ci  it gets called. The previous interrupt handler callback will be removed.
306f08c3bdfSopenharmony_ci  Setting `func` to `NULL` will remove any existing interrupt handler
307f08c3bdfSopenharmony_ci  from `vector` and the interrupt will become fatal error.
308f08c3bdfSopenharmony_ci
309f08c3bdfSopenharmony_ci[source,c]
310f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
311f08c3bdfSopenharmony_cistruct page_table_entry_pae {
312f08c3bdfSopenharmony_ci	unsigned int present: 1;
313f08c3bdfSopenharmony_ci	unsigned int writable: 1;
314f08c3bdfSopenharmony_ci	unsigned int user_access: 1;
315f08c3bdfSopenharmony_ci	unsigned int write_through: 1;
316f08c3bdfSopenharmony_ci	unsigned int disable_cache: 1;
317f08c3bdfSopenharmony_ci	unsigned int accessed: 1;
318f08c3bdfSopenharmony_ci	unsigned int dirty: 1;
319f08c3bdfSopenharmony_ci	unsigned int page_type: 1;
320f08c3bdfSopenharmony_ci	unsigned int global: 1;
321f08c3bdfSopenharmony_ci	unsigned int padding: 3;
322f08c3bdfSopenharmony_ci	uint64_t address: 40;
323f08c3bdfSopenharmony_ci	unsigned int padding2: 7;
324f08c3bdfSopenharmony_ci	unsigned int prot_key: 4;
325f08c3bdfSopenharmony_ci	unsigned int noexec: 1;
326f08c3bdfSopenharmony_ci} __attribute__((__packed__));
327f08c3bdfSopenharmony_ci
328f08c3bdfSopenharmony_cistruct kvm_cpuid {
329f08c3bdfSopenharmony_ci	unsigned int eax, ebx, ecx, edx;
330f08c3bdfSopenharmony_ci};
331f08c3bdfSopenharmony_ci
332f08c3bdfSopenharmony_cistruct kvm_cregs {
333f08c3bdfSopenharmony_ci	unsigned long cr0, cr2, cr3, cr4;
334f08c3bdfSopenharmony_ci};
335f08c3bdfSopenharmony_ci
336f08c3bdfSopenharmony_cistruct kvm_sregs {
337f08c3bdfSopenharmony_ci	uint16_t cs, ds, es, fs, gs, ss;
338f08c3bdfSopenharmony_ci};
339f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
340f08c3bdfSopenharmony_ci
341f08c3bdfSopenharmony_ci`struct page_table_entry_pae` is the page table entry structure for PAE and
342f08c3bdfSopenharmony_ci64bit paging modes. See Intel(R) 64 and IA-32 Architectures Software
343f08c3bdfSopenharmony_ciDeveloper's Manual, Volume 3, Chapter 4 for explanation of the fields.
344f08c3bdfSopenharmony_ci
345f08c3bdfSopenharmony_ci- `uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry)`
346f08c3bdfSopenharmony_ci  – Returns the physical address of the memory page referenced by the given
347f08c3bdfSopenharmony_ci  page table `entry`. Depending on memory mapping changes done by the test,
348f08c3bdfSopenharmony_ci  the physical address may not be a valid pointer. The caller must determine
349f08c3bdfSopenharmony_ci  whether the address points to another page table entry or a data page, using
350f08c3bdfSopenharmony_ci  the known position in page table hierarchy and `entry->page_type`. Returns
351f08c3bdfSopenharmony_ci  zero if the `entry` does not reference any memory page.
352f08c3bdfSopenharmony_ci
353f08c3bdfSopenharmony_ci- `void kvm_set_segment_descriptor(struct segment_descriptor *dst, uint64_t baseaddr, uint32_t limit, unsigned int flags)` -
354f08c3bdfSopenharmony_ci  Fill the `dst` segment descriptor with given values. The maximum value
355f08c3bdfSopenharmony_ci  of `limit` is `0xfffff` (inclusive) regardless of `flags`.
356f08c3bdfSopenharmony_ci
357f08c3bdfSopenharmony_ci- `void kvm_parse_segment_descriptor(struct segment_descriptor *src, uint64_t *baseaddr, uint32_t *limit, unsigned int *flags)` -
358f08c3bdfSopenharmony_ci  Parse data in the `src` segment descriptor and copy them to variables
359f08c3bdfSopenharmony_ci  pointed to by the other arguments. Any parameter except the first one can
360f08c3bdfSopenharmony_ci  be `NULL`.
361f08c3bdfSopenharmony_ci
362f08c3bdfSopenharmony_ci- `int kvm_find_free_descriptor(const struct segment_descriptor *table, size_t size)` -
363f08c3bdfSopenharmony_ci  Find the first segment descriptor in `table` which does not have
364f08c3bdfSopenharmony_ci  the `SEGFLAG_PRESENT` bit set. The function handles double-size descriptors
365f08c3bdfSopenharmony_ci  correctly. Returns index of the first available descriptor or -1 if all
366f08c3bdfSopenharmony_ci  `size` descriptors are taken.
367f08c3bdfSopenharmony_ci
368f08c3bdfSopenharmony_ci- `unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, size_t tabsize, void *stack_base)` -
369f08c3bdfSopenharmony_ci  Convenience function for registering a stack segment descriptor. It'll
370f08c3bdfSopenharmony_ci  automatically find a free slot in `table` and fill the necessary flags.
371f08c3bdfSopenharmony_ci  The `stack_base` pointer must point to the bottom of the stack.
372f08c3bdfSopenharmony_ci
373f08c3bdfSopenharmony_ci- `void kvm_get_cpuid(unsigned int eax, unsigned int ecx,
374f08c3bdfSopenharmony_ci  struct kvm_cpuid *buf)` – Executes the CPUID instruction with the given
375f08c3bdfSopenharmony_ci  `eax` and `ecx` arguments and stores the results in `buf`.
376f08c3bdfSopenharmony_ci
377f08c3bdfSopenharmony_ci- `void kvm_read_cregs(struct kvm_cregs *buf)` – Copies the current values
378f08c3bdfSopenharmony_ci  of control registers to `buf`.
379f08c3bdfSopenharmony_ci
380f08c3bdfSopenharmony_ci- `void kvm_read_sregs(struct kvm_sregs *buf)` - Copies the current values
381f08c3bdfSopenharmony_ci  of segment registers to `buf`.
382f08c3bdfSopenharmony_ci
383f08c3bdfSopenharmony_ci- `uint64_t kvm_rdmsr(unsigned int msr)` – Returns the current value
384f08c3bdfSopenharmony_ci  of model-specific register `msr`.
385f08c3bdfSopenharmony_ci
386f08c3bdfSopenharmony_ci- `void kvm_wrmsr(unsigned int msr, uint64_t value)` – Stores `value`
387f08c3bdfSopenharmony_ci  into model-specific register `msr`.
388f08c3bdfSopenharmony_ci
389f08c3bdfSopenharmony_ci- `void kvm_exit(void) __attribute__((noreturn))` – Terminate the test.
390f08c3bdfSopenharmony_ci  Similar to calling `exit(0)` in a regular LTP test, although `kvm_exit()`
391f08c3bdfSopenharmony_ci  will terminate only one iteration of the test, not the whole host process.
392f08c3bdfSopenharmony_ci
393f08c3bdfSopenharmony_ciSee Intel(R) 64 and IA-32 Architectures Software Developer's Manual
394f08c3bdfSopenharmony_cifor documentation of standard and model-specific x86 registers.
395f08c3bdfSopenharmony_ci
396f08c3bdfSopenharmony_ci3.5 AMD SVM helper functions
397f08c3bdfSopenharmony_ci~~~~~~~~~~~~~~~~~~~~~~~~~~~~
398f08c3bdfSopenharmony_ci
399f08c3bdfSopenharmony_ci`#include "kvm_test.h"` +
400f08c3bdfSopenharmony_ci`#include "kvm_x86.h"` +
401f08c3bdfSopenharmony_ci`#include "kvm_x86_svm.h"`
402f08c3bdfSopenharmony_ci
403f08c3bdfSopenharmony_ciThe KVM guest library provides basic helper functions for creating and running
404f08c3bdfSopenharmony_cinested virtual machines using the AMD SVM technology.
405f08c3bdfSopenharmony_ci
406f08c3bdfSopenharmony_ci.Example code to execute nested VM
407f08c3bdfSopenharmony_ci[source,c]
408f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
409f08c3bdfSopenharmony_ciint guest_main(void)
410f08c3bdfSopenharmony_ci{
411f08c3bdfSopenharmony_ci	...
412f08c3bdfSopenharmony_ci	return 0;
413f08c3bdfSopenharmony_ci}
414f08c3bdfSopenharmony_ci
415f08c3bdfSopenharmony_civoid main(void)
416f08c3bdfSopenharmony_ci{
417f08c3bdfSopenharmony_ci	struct kvm_svm_vcpu *vm;
418f08c3bdfSopenharmony_ci
419f08c3bdfSopenharmony_ci	kvm_init_svm();
420f08c3bdfSopenharmony_ci	vm = kvm_create_svm_vcpu(guest_main, 1);
421f08c3bdfSopenharmony_ci	kvm_svm_vmrun(vm);
422f08c3bdfSopenharmony_ci}
423f08c3bdfSopenharmony_ci-------------------------------------------------------------------------------
424f08c3bdfSopenharmony_ci
425f08c3bdfSopenharmony_ci- `int kvm_is_svm_supported(void)` - Returns non-zero value if the CPU
426f08c3bdfSopenharmony_ci  supports AMD SVM, otherwise returns 0.
427f08c3bdfSopenharmony_ci
428f08c3bdfSopenharmony_ci- `int kvm_get_svm_state(void)` - Returns non-zero value if SVM is currently
429f08c3bdfSopenharmony_ci  enabled, otherwise returns 0.
430f08c3bdfSopenharmony_ci
431f08c3bdfSopenharmony_ci- `void kvm_set_svm_state(int enabled)` - Enable or disable SVM according
432f08c3bdfSopenharmony_ci  to argument. If SVM is disabled by host or not supported, the test will exit
433f08c3bdfSopenharmony_ci  with `TCONF`.
434f08c3bdfSopenharmony_ci
435f08c3bdfSopenharmony_ci- `void kvm_init_svm(void)` - Enable and fully initialize SVM, including
436f08c3bdfSopenharmony_ci  allocating and setting up host save area VMCB. If SVM is disabled by host or
437f08c3bdfSopenharmony_ci  not supported, the test will exit with `TCONF`.
438f08c3bdfSopenharmony_ci
439f08c3bdfSopenharmony_ci- `struct kvm_vmcb *kvm_alloc_vmcb(void)` - Allocate new VMCB structure
440f08c3bdfSopenharmony_ci  with correct memory alignment and fill it with zeroes.
441f08c3bdfSopenharmony_ci
442f08c3bdfSopenharmony_ci- `void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, unsigned int state)` -
443f08c3bdfSopenharmony_ci  Set SVM intercept bit `id` to given `state`.
444f08c3bdfSopenharmony_ci
445f08c3bdfSopenharmony_ci- `void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, void *rsp, int (*guest_main)(void))` -
446f08c3bdfSopenharmony_ci  Initialize new SVM virtual machine. The `asid` parameter is the nested
447f08c3bdfSopenharmony_ci  page table ID. The `ss` and `rsp` parameters set the stack segment and stack
448f08c3bdfSopenharmony_ci  pointer values, respectively. The `guest_main` parameter sets the code entry
449f08c3bdfSopenharmony_ci  point of the virtual machine. All control registers, segment registers
450f08c3bdfSopenharmony_ci  (except stack segment register), GDTR and IDTR will be copied
451f08c3bdfSopenharmony_ci  from the current CPU state.
452f08c3bdfSopenharmony_ci
453f08c3bdfSopenharmony_ci- `struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), int alloc_stack)` -
454f08c3bdfSopenharmony_ci  Convenience function for allocating and initializing new SVM virtual CPU.
455f08c3bdfSopenharmony_ci  The `guest_main` parameter is passed to `kvm_init_guest_vmcb()`,
456f08c3bdfSopenharmony_ci  the `alloc_stack` parameter controls whether a new 8KB stack will be
457f08c3bdfSopenharmony_ci  allocated and registered in GDT. Interception will be enabled for `VMSAVE`
458f08c3bdfSopenharmony_ci  and `HLT` instructions. If you set `alloc_stack` to zero, you must configure
459f08c3bdfSopenharmony_ci  the stack segment register and stack pointer manually.
460f08c3bdfSopenharmony_ci
461f08c3bdfSopenharmony_ci- `void kvm_svm_vmrun(struct kvm_svm_vcpu *cpu)` - Start or continue execution
462f08c3bdfSopenharmony_ci  of a nested virtual machine. Beware that FPU state is not saved.  Do not use
463f08c3bdfSopenharmony_ci  floating point types or values in nested guest code. Also do not use
464f08c3bdfSopenharmony_ci  `tst_res()` or `tst_brk()` functions in nested guest code.
465f08c3bdfSopenharmony_ci
466f08c3bdfSopenharmony_ciSee AMD64 Architecture Programmer's Manual Volume 2 for documentation
467f08c3bdfSopenharmony_ciof the Secure Virtual Machine (SVM) technology.
468f08c3bdfSopenharmony_ci
469f08c3bdfSopenharmony_ci4. KVM guest environment
470f08c3bdfSopenharmony_ci------------------------
471f08c3bdfSopenharmony_ci
472f08c3bdfSopenharmony_ciKVM guest payload execution begins with bootstrap code which will perform
473f08c3bdfSopenharmony_cithe minimal guest environment setup required for running C code:
474f08c3bdfSopenharmony_ci
475f08c3bdfSopenharmony_ci- Activate the appropriate CPU execution mode (IA-32 protected mode
476f08c3bdfSopenharmony_ci  on 32-bit x86 or the 64-bit mode on x86_64).
477f08c3bdfSopenharmony_ci- Create indentity mapping (virtual address = physical address) of the lower
478f08c3bdfSopenharmony_ci  2GB memory region, even if parts of the region are not backed by any host
479f08c3bdfSopenharmony_ci  memory buffers. The memory region above 2GB threshold is left unmapped
480f08c3bdfSopenharmony_ci  except for one memory page reserved for the `struct tst_kvm_result` buffer.
481f08c3bdfSopenharmony_ci- Initialize 8KB stack.
482f08c3bdfSopenharmony_ci- Install default interrupt handlers for standard CPU exception vectors.
483f08c3bdfSopenharmony_ci
484f08c3bdfSopenharmony_ciWhen the environment setup is complete, bootstrap will call `void main(void)`
485f08c3bdfSopenharmony_cifunction implemented by the test program. To finish execution of guest payload,
486f08c3bdfSopenharmony_cithe test can either return from the `main()` function or call `kvm_exit()`
487f08c3bdfSopenharmony_ciat any point.
488