forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kvm: selftests: add API testing infrastructure
Testsuite contributed by Google and cleaned up by myself for inclusion in Linux. Signed-off-by: Ken Hofsass <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
- Loading branch information
Showing
12 changed files
with
5,813 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
all: | ||
|
||
top_srcdir = ../../../../ | ||
UNAME_M := $(shell uname -m) | ||
|
||
LIBKVM = lib/assert.c lib/kvm_util.c lib/sparsebit.c | ||
LIBKVM_x86_64 = lib/x86.c | ||
|
||
TEST_GEN_PROGS_x86_64 = set_sregs_test | ||
|
||
TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) | ||
LIBKVM += $(LIBKVM_$(UNAME_M)) | ||
|
||
INSTALL_HDR_PATH = $(top_srcdir)/usr | ||
LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ | ||
CFLAGS += -O2 -g -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) | ||
|
||
# After inclusion, $(OUTPUT) is defined and | ||
# $(TEST_GEN_PROGS) starts with $(OUTPUT)/ | ||
include ../lib.mk | ||
|
||
STATIC_LIBS := $(OUTPUT)/libkvm.a | ||
LIBKVM_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM)) | ||
EXTRA_CLEAN += $(LIBKVM_OBJ) $(STATIC_LIBS) | ||
|
||
x := $(shell mkdir -p $(sort $(dir $(LIBKVM_OBJ)))) | ||
$(LIBKVM_OBJ): $(OUTPUT)/%.o: %.c | ||
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ | ||
|
||
$(OUTPUT)/libkvm.a: $(LIBKVM_OBJ) | ||
$(AR) crs $@ $^ | ||
|
||
$(LINUX_HDR_PATH): | ||
make -C $(top_srcdir) headers_install | ||
|
||
all: $(STATIC_LIBS) $(LINUX_HDR_PATH) | ||
$(TEST_GEN_PROGS): $(STATIC_LIBS) | ||
$(TEST_GEN_PROGS) $(LIBKVM_OBJ): | $(LINUX_HDR_PATH) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* tools/testing/selftests/kvm/include/kvm_util.h | ||
* | ||
* Copyright (C) 2018, Google LLC. | ||
* | ||
* This work is licensed under the terms of the GNU GPL, version 2. | ||
* | ||
*/ | ||
#ifndef SELFTEST_KVM_UTIL_H | ||
#define SELFTEST_KVM_UTIL_H 1 | ||
|
||
#include "test_util.h" | ||
|
||
#include "asm/kvm.h" | ||
#include "linux/kvm.h" | ||
#include <sys/ioctl.h> | ||
|
||
#include "sparsebit.h" | ||
|
||
/* | ||
* Memslots can't cover the gfn starting at this gpa otherwise vCPUs can't be | ||
* created. Only applies to VMs using EPT. | ||
*/ | ||
#define KVM_DEFAULT_IDENTITY_MAP_ADDRESS 0xfffbc000ul | ||
|
||
|
||
/* Callers of kvm_util only have an incomplete/opaque description of the | ||
* structure kvm_util is using to maintain the state of a VM. | ||
*/ | ||
struct kvm_vm; | ||
|
||
typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ | ||
typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ | ||
|
||
/* Minimum allocated guest virtual and physical addresses */ | ||
#define KVM_UTIL_MIN_VADDR 0x2000 | ||
|
||
#define DEFAULT_GUEST_PHY_PAGES 512 | ||
#define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 | ||
#define DEFAULT_STACK_PGS 5 | ||
|
||
enum vm_guest_mode { | ||
VM_MODE_FLAT48PG, | ||
}; | ||
|
||
enum vm_mem_backing_src_type { | ||
VM_MEM_SRC_ANONYMOUS, | ||
VM_MEM_SRC_ANONYMOUS_THP, | ||
VM_MEM_SRC_ANONYMOUS_HUGETLB, | ||
}; | ||
|
||
int kvm_check_cap(long cap); | ||
|
||
struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); | ||
void kvm_vm_free(struct kvm_vm *vmp); | ||
|
||
int kvm_memcmp_hva_gva(void *hva, | ||
struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); | ||
|
||
void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); | ||
void vcpu_dump(FILE *stream, struct kvm_vm *vm, | ||
uint32_t vcpuid, uint8_t indent); | ||
|
||
void vm_create_irqchip(struct kvm_vm *vm); | ||
|
||
void vm_userspace_mem_region_add(struct kvm_vm *vm, | ||
enum vm_mem_backing_src_type src_type, | ||
uint64_t guest_paddr, uint32_t slot, uint64_t npages, | ||
uint32_t flags); | ||
|
||
void vcpu_ioctl(struct kvm_vm *vm, | ||
uint32_t vcpuid, unsigned long ioctl, void *arg); | ||
void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); | ||
void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); | ||
void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); | ||
vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | ||
uint32_t data_memslot, uint32_t pgd_memslot); | ||
void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); | ||
void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); | ||
vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); | ||
vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva); | ||
|
||
struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); | ||
void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); | ||
int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); | ||
void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | ||
struct kvm_mp_state *mp_state); | ||
void vcpu_regs_get(struct kvm_vm *vm, | ||
uint32_t vcpuid, struct kvm_regs *regs); | ||
void vcpu_regs_set(struct kvm_vm *vm, | ||
uint32_t vcpuid, struct kvm_regs *regs); | ||
void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); | ||
void vcpu_sregs_get(struct kvm_vm *vm, | ||
uint32_t vcpuid, struct kvm_sregs *sregs); | ||
void vcpu_sregs_set(struct kvm_vm *vm, | ||
uint32_t vcpuid, struct kvm_sregs *sregs); | ||
int _vcpu_sregs_set(struct kvm_vm *vm, | ||
uint32_t vcpuid, struct kvm_sregs *sregs); | ||
void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
struct kvm_vcpu_events *events); | ||
void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
struct kvm_vcpu_events *events); | ||
|
||
const char *exit_reason_str(unsigned int exit_reason); | ||
|
||
void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot); | ||
void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, | ||
uint32_t pgd_memslot); | ||
vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, | ||
vm_paddr_t paddr_min, uint32_t memslot); | ||
|
||
void kvm_get_supported_cpuid(struct kvm_cpuid2 *cpuid); | ||
void vcpu_set_cpuid( | ||
struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid); | ||
|
||
struct kvm_cpuid2 *allocate_kvm_cpuid2(void); | ||
struct kvm_cpuid_entry2 * | ||
find_cpuid_index_entry(struct kvm_cpuid2 *cpuid, uint32_t function, | ||
uint32_t index); | ||
|
||
static inline struct kvm_cpuid_entry2 * | ||
find_cpuid_entry(struct kvm_cpuid2 *cpuid, uint32_t function) | ||
{ | ||
return find_cpuid_index_entry(cpuid, function, 0); | ||
} | ||
|
||
struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code); | ||
void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); | ||
|
||
struct kvm_userspace_memory_region * | ||
kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | ||
uint64_t end); | ||
|
||
struct kvm_dirty_log * | ||
allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); | ||
|
||
int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); | ||
|
||
#endif /* SELFTEST_KVM_UTIL_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* tools/testing/selftests/kvm/include/sparsebit.h | ||
* | ||
* Copyright (C) 2018, Google LLC. | ||
* | ||
* This work is licensed under the terms of the GNU GPL, version 2. | ||
* | ||
* | ||
* Header file that describes API to the sparsebit library. | ||
* This library provides a memory efficient means of storing | ||
* the settings of bits indexed via a uint64_t. Memory usage | ||
* is reasonable, significantly less than (2^64 / 8) bytes, as | ||
* long as bits that are mostly set or mostly cleared are close | ||
* to each other. This library is efficient in memory usage | ||
* even in the case where most bits are set. | ||
*/ | ||
|
||
#ifndef _TEST_SPARSEBIT_H_ | ||
#define _TEST_SPARSEBIT_H_ | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
struct sparsebit; | ||
typedef uint64_t sparsebit_idx_t; | ||
typedef uint64_t sparsebit_num_t; | ||
|
||
struct sparsebit *sparsebit_alloc(void); | ||
void sparsebit_free(struct sparsebit **sbitp); | ||
void sparsebit_copy(struct sparsebit *dstp, struct sparsebit *src); | ||
|
||
bool sparsebit_is_set(struct sparsebit *sbit, sparsebit_idx_t idx); | ||
bool sparsebit_is_set_num(struct sparsebit *sbit, | ||
sparsebit_idx_t idx, sparsebit_num_t num); | ||
bool sparsebit_is_clear(struct sparsebit *sbit, sparsebit_idx_t idx); | ||
bool sparsebit_is_clear_num(struct sparsebit *sbit, | ||
sparsebit_idx_t idx, sparsebit_num_t num); | ||
sparsebit_num_t sparsebit_num_set(struct sparsebit *sbit); | ||
bool sparsebit_any_set(struct sparsebit *sbit); | ||
bool sparsebit_any_clear(struct sparsebit *sbit); | ||
bool sparsebit_all_set(struct sparsebit *sbit); | ||
bool sparsebit_all_clear(struct sparsebit *sbit); | ||
sparsebit_idx_t sparsebit_first_set(struct sparsebit *sbit); | ||
sparsebit_idx_t sparsebit_first_clear(struct sparsebit *sbit); | ||
sparsebit_idx_t sparsebit_next_set(struct sparsebit *sbit, sparsebit_idx_t prev); | ||
sparsebit_idx_t sparsebit_next_clear(struct sparsebit *sbit, sparsebit_idx_t prev); | ||
sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *sbit, | ||
sparsebit_idx_t start, sparsebit_num_t num); | ||
sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *sbit, | ||
sparsebit_idx_t start, sparsebit_num_t num); | ||
|
||
void sparsebit_set(struct sparsebit *sbitp, sparsebit_idx_t idx); | ||
void sparsebit_set_num(struct sparsebit *sbitp, sparsebit_idx_t start, | ||
sparsebit_num_t num); | ||
void sparsebit_set_all(struct sparsebit *sbitp); | ||
|
||
void sparsebit_clear(struct sparsebit *sbitp, sparsebit_idx_t idx); | ||
void sparsebit_clear_num(struct sparsebit *sbitp, | ||
sparsebit_idx_t start, sparsebit_num_t num); | ||
void sparsebit_clear_all(struct sparsebit *sbitp); | ||
|
||
void sparsebit_dump(FILE *stream, struct sparsebit *sbit, | ||
unsigned int indent); | ||
void sparsebit_validate_internal(struct sparsebit *sbit); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* _TEST_SPARSEBIT_H_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* tools/testing/selftests/kvm/include/test_util.h | ||
* | ||
* Copyright (C) 2018, Google LLC. | ||
* | ||
* This work is licensed under the terms of the GNU GPL, version 2. | ||
* | ||
*/ | ||
|
||
#ifndef TEST_UTIL_H | ||
#define TEST_UTIL_H 1 | ||
|
||
#include <stdlib.h> | ||
#include <stdarg.h> | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <inttypes.h> | ||
#include <errno.h> | ||
#include <unistd.h> | ||
#include <fcntl.h> | ||
|
||
ssize_t test_write(int fd, const void *buf, size_t count); | ||
ssize_t test_read(int fd, void *buf, size_t count); | ||
int test_seq_read(const char *path, char **bufp, size_t *sizep); | ||
|
||
void test_assert(bool exp, const char *exp_str, | ||
const char *file, unsigned int line, const char *fmt, ...); | ||
|
||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) | ||
|
||
#define TEST_ASSERT(e, fmt, ...) \ | ||
test_assert((e), #e, __FILE__, __LINE__, fmt, ##__VA_ARGS__) | ||
|
||
#define ASSERT_EQ(a, b) do { \ | ||
typeof(a) __a = (a); \ | ||
typeof(b) __b = (b); \ | ||
TEST_ASSERT(__a == __b, \ | ||
"ASSERT_EQ(%s, %s) failed.\n" \ | ||
"\t%s is %#lx\n" \ | ||
"\t%s is %#lx", \ | ||
#a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ | ||
} while (0) | ||
|
||
#endif /* TEST_UTIL_H */ |
Oops, something went wrong.