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