2019-06-04 08:11:15 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2018-03-27 09:49:19 +00:00
|
|
|
/*
|
|
|
|
* tools/testing/selftests/kvm/include/kvm_util.h
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018, Google LLC.
|
|
|
|
*/
|
|
|
|
#ifndef SELFTEST_KVM_UTIL_H
|
2018-09-18 17:54:26 +00:00
|
|
|
#define SELFTEST_KVM_UTIL_H
|
2018-03-27 09:49:19 +00:00
|
|
|
|
|
|
|
#include "test_util.h"
|
|
|
|
|
|
|
|
#include "asm/kvm.h"
|
2020-04-10 23:16:59 +00:00
|
|
|
#include "linux/list.h"
|
2018-03-27 09:49:19 +00:00
|
|
|
#include "linux/kvm.h"
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
|
|
|
#include "sparsebit.h"
|
|
|
|
|
2021-03-18 14:56:29 +00:00
|
|
|
#define KVM_DEV_PATH "/dev/kvm"
|
2020-12-18 14:17:34 +00:00
|
|
|
#define KVM_MAX_VCPUS 512
|
2018-03-27 09:49:19 +00:00
|
|
|
|
2020-03-10 09:15:54 +00:00
|
|
|
/*
|
|
|
|
* Callers of kvm_util only have an incomplete/opaque description of the
|
2018-03-27 09:49:19 +00:00
|
|
|
* 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 */
|
2018-09-18 17:54:28 +00:00
|
|
|
#define KVM_UTIL_MIN_VADDR 0x2000
|
2018-03-27 09:49:19 +00:00
|
|
|
|
|
|
|
#define DEFAULT_GUEST_PHY_PAGES 512
|
|
|
|
#define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000
|
2018-09-18 17:54:28 +00:00
|
|
|
#define DEFAULT_STACK_PGS 5
|
2018-03-27 09:49:19 +00:00
|
|
|
|
|
|
|
enum vm_guest_mode {
|
2018-09-18 17:54:33 +00:00
|
|
|
VM_MODE_P52V48_4K,
|
|
|
|
VM_MODE_P52V48_64K,
|
2018-11-06 13:57:11 +00:00
|
|
|
VM_MODE_P48V48_4K,
|
|
|
|
VM_MODE_P48V48_64K,
|
2018-09-18 17:54:35 +00:00
|
|
|
VM_MODE_P40V48_4K,
|
|
|
|
VM_MODE_P40V48_64K,
|
2019-08-30 01:36:18 +00:00
|
|
|
VM_MODE_PXXV48_4K, /* For 48bits VA but ANY bits PA */
|
2021-06-08 12:39:54 +00:00
|
|
|
VM_MODE_P47V64_4K,
|
2018-09-18 17:54:33 +00:00
|
|
|
NUM_VM_MODES,
|
2018-03-27 09:49:19 +00:00
|
|
|
};
|
|
|
|
|
2019-08-30 01:36:18 +00:00
|
|
|
#if defined(__aarch64__)
|
2020-11-11 12:26:29 +00:00
|
|
|
|
|
|
|
#define VM_MODE_DEFAULT VM_MODE_P40V48_4K
|
|
|
|
#define MIN_PAGE_SHIFT 12U
|
|
|
|
#define ptes_per_page(page_size) ((page_size) / 8)
|
|
|
|
|
2019-08-30 01:36:18 +00:00
|
|
|
#elif defined(__x86_64__)
|
2020-11-11 12:26:29 +00:00
|
|
|
|
|
|
|
#define VM_MODE_DEFAULT VM_MODE_PXXV48_4K
|
|
|
|
#define MIN_PAGE_SHIFT 12U
|
|
|
|
#define ptes_per_page(page_size) ((page_size) / 8)
|
|
|
|
|
|
|
|
#elif defined(__s390x__)
|
|
|
|
|
2021-06-08 12:39:54 +00:00
|
|
|
#define VM_MODE_DEFAULT VM_MODE_P47V64_4K
|
2020-11-11 12:26:29 +00:00
|
|
|
#define MIN_PAGE_SHIFT 12U
|
|
|
|
#define ptes_per_page(page_size) ((page_size) / 16)
|
|
|
|
|
2019-05-23 16:43:04 +00:00
|
|
|
#endif
|
|
|
|
|
2020-11-11 12:26:29 +00:00
|
|
|
#define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT)
|
|
|
|
#define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE)
|
|
|
|
|
2020-12-18 14:17:33 +00:00
|
|
|
struct vm_guest_mode_params {
|
|
|
|
unsigned int pa_bits;
|
|
|
|
unsigned int va_bits;
|
|
|
|
unsigned int page_size;
|
|
|
|
unsigned int page_shift;
|
|
|
|
};
|
|
|
|
extern const struct vm_guest_mode_params vm_guest_mode_params[];
|
|
|
|
|
2021-05-11 20:21:20 +00:00
|
|
|
int open_kvm_dev_path_or_exit(void);
|
2018-03-27 09:49:19 +00:00
|
|
|
int kvm_check_cap(long cap);
|
2018-08-20 17:32:16 +00:00
|
|
|
int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap);
|
2020-10-27 23:10:44 +00:00
|
|
|
int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id,
|
|
|
|
struct kvm_enable_cap *cap);
|
|
|
|
void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size);
|
2021-03-30 08:08:51 +00:00
|
|
|
const char *vm_guest_mode_string(uint32_t i);
|
2018-03-27 09:49:19 +00:00
|
|
|
|
|
|
|
struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm);
|
|
|
|
void kvm_vm_free(struct kvm_vm *vmp);
|
2018-07-26 11:19:23 +00:00
|
|
|
void kvm_vm_restart(struct kvm_vm *vmp, int perm);
|
|
|
|
void kvm_vm_release(struct kvm_vm *vmp);
|
2018-08-22 07:20:00 +00:00
|
|
|
void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log);
|
kvm: introduce manual dirty log reprotect
There are two problems with KVM_GET_DIRTY_LOG. First, and less important,
it can take kvm->mmu_lock for an extended period of time. Second, its user
can actually see many false positives in some cases. The latter is due
to a benign race like this:
1. KVM_GET_DIRTY_LOG returns a set of dirty pages and write protects
them.
2. The guest modifies the pages, causing them to be marked ditry.
3. Userspace actually copies the pages.
4. KVM_GET_DIRTY_LOG returns those pages as dirty again, even though
they were not written to since (3).
This is especially a problem for large guests, where the time between
(1) and (3) can be substantial. This patch introduces a new
capability which, when enabled, makes KVM_GET_DIRTY_LOG not
write-protect the pages it returns. Instead, userspace has to
explicitly clear the dirty log bits just before using the content
of the page. The new KVM_CLEAR_DIRTY_LOG ioctl can also operate on a
64-page granularity rather than requiring to sync a full memslot;
this way, the mmu_lock is taken for small amounts of time, and
only a small amount of time will pass between write protection
of pages and the sending of their content.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2018-10-23 00:36:47 +00:00
|
|
|
void kvm_vm_clear_dirty_log(struct kvm_vm *vm, int slot, void *log,
|
|
|
|
uint64_t first_page, uint32_t num_pages);
|
2020-10-01 01:22:37 +00:00
|
|
|
uint32_t kvm_vm_reset_dirty_ring(struct kvm_vm *vm);
|
2018-03-27 09:49:19 +00:00
|
|
|
|
2018-09-18 17:54:28 +00:00
|
|
|
int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva,
|
|
|
|
size_t len);
|
2018-03-27 09:49:19 +00:00
|
|
|
|
2021-06-22 20:05:13 +00:00
|
|
|
void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename);
|
2018-03-28 07:45:34 +00:00
|
|
|
|
2018-03-27 09:49:19 +00:00
|
|
|
void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent);
|
2020-03-10 09:15:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* VM VCPU Dump
|
|
|
|
*
|
|
|
|
* Input Args:
|
|
|
|
* stream - Output FILE stream
|
|
|
|
* vm - Virtual Machine
|
|
|
|
* vcpuid - VCPU ID
|
|
|
|
* indent - Left margin indent amount
|
|
|
|
*
|
|
|
|
* Output Args: None
|
|
|
|
*
|
|
|
|
* Return: None
|
|
|
|
*
|
|
|
|
* Dumps the current state of the VCPU specified by @vcpuid, within the VM
|
|
|
|
* given by @vm, to the FILE stream given by @stream.
|
|
|
|
*/
|
2018-09-18 17:54:28 +00:00
|
|
|
void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid,
|
|
|
|
uint8_t indent);
|
2018-03-27 09:49:19 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-09-18 17:54:28 +00:00
|
|
|
void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl,
|
|
|
|
void *arg);
|
2018-12-10 17:21:58 +00:00
|
|
|
int _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl,
|
|
|
|
void *arg);
|
2018-03-27 09:49:19 +00:00
|
|
|
void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
|
2021-03-18 15:16:23 +00:00
|
|
|
int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg);
|
2020-09-29 15:09:44 +00:00
|
|
|
void kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
|
|
|
|
int _kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg);
|
2018-03-27 09:49:19 +00:00
|
|
|
void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
|
2020-02-18 21:07:33 +00:00
|
|
|
void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa);
|
2020-04-10 23:17:00 +00:00
|
|
|
void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot);
|
2019-06-04 17:13:46 +00:00
|
|
|
void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid);
|
2018-03-27 09:49:19 +00:00
|
|
|
vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
|
2018-09-18 17:54:28 +00:00
|
|
|
uint32_t data_memslot, uint32_t pgd_memslot);
|
2018-08-22 07:20:00 +00:00
|
|
|
void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
|
2020-03-13 15:56:43 +00:00
|
|
|
unsigned int npages, uint32_t pgd_memslot);
|
2018-03-27 09:49:19 +00:00
|
|
|
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);
|
KVM: selftests: create alias mappings when using shared memory
When a memory region is added with a src_type specifying that it should
use some kind of shared memory, also create an alias mapping to the same
underlying physical pages.
And, add an API so tests can get access to these alias addresses.
Basically, for a guest physical address, let us look up the analogous
host *alias* address.
In a future commit, we'll modify the demand paging test to take
advantage of this to exercise UFFD minor faults. The idea is, we
pre-fault the underlying pages *via the alias*. When the *guest*
faults, it gets a "minor" fault (PTEs don't exist yet, but a page is
already in the page cache). Then, the userfaultfd theads can handle the
fault: they could potentially modify the underlying memory *via the
alias* if they wanted to, and then they install the PTEs and let the
guest carry on via a UFFDIO_CONTINUE ioctl.
Reviewed-by: Ben Gardon <bgardon@google.com>
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Message-Id: <20210519200339.829146-9-axelrasmussen@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2021-05-19 20:03:37 +00:00
|
|
|
void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa);
|
2020-03-10 09:15:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Address Guest Virtual to Guest Physical
|
|
|
|
*
|
|
|
|
* Input Args:
|
|
|
|
* vm - Virtual Machine
|
|
|
|
* gva - VM virtual address
|
|
|
|
*
|
|
|
|
* Output Args: None
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* Equivalent VM physical address
|
|
|
|
*
|
|
|
|
* Returns the VM physical address of the translated VM virtual
|
|
|
|
* address given by @gva.
|
|
|
|
*/
|
2018-03-27 09:49:19 +00:00
|
|
|
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);
|
2020-10-01 01:22:37 +00:00
|
|
|
int vcpu_get_fd(struct kvm_vm *vm, uint32_t vcpuid);
|
2019-03-13 23:49:31 +00:00
|
|
|
void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid);
|
2020-05-05 20:50:00 +00:00
|
|
|
void vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid,
|
|
|
|
struct kvm_guest_debug *debug);
|
2018-03-27 09:49:19 +00:00
|
|
|
void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid,
|
2018-09-18 17:54:28 +00:00
|
|
|
struct kvm_mp_state *mp_state);
|
2020-10-29 20:17:01 +00:00
|
|
|
struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid);
|
2018-09-18 17:54:28 +00:00
|
|
|
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);
|
2020-03-10 09:15:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* VM VCPU Args Set
|
|
|
|
*
|
|
|
|
* Input Args:
|
|
|
|
* vm - Virtual Machine
|
|
|
|
* vcpuid - VCPU ID
|
|
|
|
* num - number of arguments
|
|
|
|
* ... - arguments, each of type uint64_t
|
|
|
|
*
|
|
|
|
* Output Args: None
|
|
|
|
*
|
|
|
|
* Return: None
|
|
|
|
*
|
|
|
|
* Sets the first @num function input registers of the VCPU with @vcpuid,
|
|
|
|
* per the C calling convention of the architecture, to the values given
|
|
|
|
* as variable args. Each of the variable args is expected to be of type
|
|
|
|
* uint64_t. The maximum @num can be is specific to the architecture.
|
|
|
|
*/
|
2018-03-27 09:49:19 +00:00
|
|
|
void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...);
|
2020-03-10 09:15:54 +00:00
|
|
|
|
2018-09-18 17:54:28 +00:00
|
|
|
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);
|
2020-01-31 10:02:03 +00:00
|
|
|
void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid,
|
|
|
|
struct kvm_fpu *fpu);
|
|
|
|
void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid,
|
|
|
|
struct kvm_fpu *fpu);
|
|
|
|
void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg);
|
|
|
|
void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg);
|
2019-05-23 16:43:02 +00:00
|
|
|
#ifdef __KVM_HAVE_VCPU_EVENTS
|
2018-03-27 09:49:19 +00:00
|
|
|
void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid,
|
2018-09-18 17:54:28 +00:00
|
|
|
struct kvm_vcpu_events *events);
|
2018-03-27 09:49:19 +00:00
|
|
|
void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid,
|
2018-09-18 17:54:28 +00:00
|
|
|
struct kvm_vcpu_events *events);
|
2019-05-23 16:43:02 +00:00
|
|
|
#endif
|
2019-05-23 09:31:14 +00:00
|
|
|
#ifdef __x86_64__
|
2019-05-02 18:31:41 +00:00
|
|
|
void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid,
|
|
|
|
struct kvm_nested_state *state);
|
|
|
|
int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid,
|
|
|
|
struct kvm_nested_state *state, bool ignore_error);
|
2019-05-23 09:31:14 +00:00
|
|
|
#endif
|
2020-10-01 01:22:37 +00:00
|
|
|
void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid);
|
2018-03-27 09:49:19 +00:00
|
|
|
|
2021-04-05 16:39:41 +00:00
|
|
|
int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr);
|
|
|
|
int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr);
|
2021-04-07 13:59:37 +00:00
|
|
|
int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd);
|
2021-04-05 16:39:41 +00:00
|
|
|
int kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test);
|
|
|
|
int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
|
|
|
|
void *val, bool write);
|
|
|
|
int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr,
|
|
|
|
void *val, bool write);
|
|
|
|
|
2018-03-27 09:49:19 +00:00
|
|
|
const char *exit_reason_str(unsigned int exit_reason);
|
|
|
|
|
|
|
|
void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot);
|
2020-03-10 09:15:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* VM Virtual Page Map
|
|
|
|
*
|
|
|
|
* Input Args:
|
|
|
|
* vm - Virtual Machine
|
|
|
|
* vaddr - VM Virtual Address
|
|
|
|
* paddr - VM Physical Address
|
|
|
|
* memslot - Memory region slot for new virtual translation tables
|
|
|
|
*
|
|
|
|
* Output Args: None
|
|
|
|
*
|
|
|
|
* Return: None
|
|
|
|
*
|
|
|
|
* Within @vm, creates a virtual translation for the page starting
|
|
|
|
* at @vaddr to the page starting at @paddr.
|
|
|
|
*/
|
2018-03-27 09:49:19 +00:00
|
|
|
void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
|
2020-03-10 09:15:54 +00:00
|
|
|
uint32_t memslot);
|
|
|
|
|
2018-09-18 17:54:28 +00:00
|
|
|
vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
|
|
|
|
uint32_t memslot);
|
2018-09-18 17:54:29 +00:00
|
|
|
vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
|
|
|
|
vm_paddr_t paddr_min, uint32_t memslot);
|
2018-03-27 09:49:19 +00:00
|
|
|
|
2020-03-10 09:15:54 +00:00
|
|
|
/*
|
|
|
|
* Create a VM with reasonable defaults
|
|
|
|
*
|
|
|
|
* Input Args:
|
|
|
|
* vcpuid - The id of the single VCPU to add to the VM.
|
2020-03-13 15:56:43 +00:00
|
|
|
* extra_mem_pages - The number of extra pages to add (this will
|
2020-03-10 09:15:54 +00:00
|
|
|
* decide how much extra space we will need to
|
|
|
|
* setup the page tables using memslot 0)
|
|
|
|
* guest_code - The vCPU's entry point
|
|
|
|
*
|
|
|
|
* Output Args: None
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* Pointer to opaque structure that describes the created VM.
|
|
|
|
*/
|
2020-03-13 15:56:43 +00:00
|
|
|
struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
|
2018-08-22 07:19:59 +00:00
|
|
|
void *guest_code);
|
2020-03-10 09:15:54 +00:00
|
|
|
|
2020-11-11 12:26:30 +00:00
|
|
|
/* Same as vm_create_default, but can be used for more than one vcpu */
|
|
|
|
struct kvm_vm *vm_create_default_with_vcpus(uint32_t nr_vcpus, uint64_t extra_mem_pages,
|
|
|
|
uint32_t num_percpu_pages, void *guest_code,
|
|
|
|
uint32_t vcpuids[]);
|
|
|
|
|
2021-06-08 23:38:16 +00:00
|
|
|
/* Like vm_create_default_with_vcpus, but accepts mode and slot0 memory as a parameter */
|
2020-11-11 12:26:30 +00:00
|
|
|
struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
|
2021-06-08 23:38:16 +00:00
|
|
|
uint64_t slot0_mem_pages, uint64_t extra_mem_pages,
|
|
|
|
uint32_t num_percpu_pages, void *guest_code,
|
|
|
|
uint32_t vcpuids[]);
|
2020-11-11 12:26:30 +00:00
|
|
|
|
2020-03-10 09:15:54 +00:00
|
|
|
/*
|
|
|
|
* Adds a vCPU with reasonable defaults (e.g. a stack)
|
|
|
|
*
|
|
|
|
* Input Args:
|
|
|
|
* vm - Virtual Machine
|
|
|
|
* vcpuid - The id of the VCPU to add to the VM.
|
|
|
|
* guest_code - The vCPU's entry point
|
|
|
|
*/
|
2018-03-27 09:49:19 +00:00
|
|
|
void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code);
|
|
|
|
|
2019-05-31 14:14:52 +00:00
|
|
|
bool vm_is_unrestricted_guest(struct kvm_vm *vm);
|
|
|
|
|
2019-08-30 01:36:19 +00:00
|
|
|
unsigned int vm_get_page_size(struct kvm_vm *vm);
|
|
|
|
unsigned int vm_get_page_shift(struct kvm_vm *vm);
|
2021-05-21 17:38:28 +00:00
|
|
|
uint64_t vm_get_max_gfn(struct kvm_vm *vm);
|
2020-04-10 23:17:04 +00:00
|
|
|
int vm_get_fd(struct kvm_vm *vm);
|
2019-08-30 01:36:19 +00:00
|
|
|
|
2020-03-13 15:56:44 +00:00
|
|
|
unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size);
|
2020-02-14 14:59:20 +00:00
|
|
|
unsigned int vm_num_host_pages(enum vm_guest_mode mode, unsigned int num_guest_pages);
|
|
|
|
unsigned int vm_num_guest_pages(enum vm_guest_mode mode, unsigned int num_host_pages);
|
|
|
|
static inline unsigned int
|
|
|
|
vm_adjust_num_guest_pages(enum vm_guest_mode mode, unsigned int num_guest_pages)
|
|
|
|
{
|
2020-03-12 10:40:55 +00:00
|
|
|
unsigned int n;
|
|
|
|
n = vm_num_guest_pages(mode, vm_num_host_pages(mode, num_guest_pages));
|
|
|
|
#ifdef __s390x__
|
|
|
|
/* s390 requires 1M aligned guest sizes */
|
|
|
|
n = (n + 255) & ~255;
|
|
|
|
#endif
|
|
|
|
return n;
|
2020-02-14 14:59:20 +00:00
|
|
|
}
|
|
|
|
|
2018-03-27 09:49:19 +00:00
|
|
|
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);
|
|
|
|
|
2018-09-18 17:54:25 +00:00
|
|
|
#define sync_global_to_guest(vm, g) ({ \
|
|
|
|
typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \
|
|
|
|
memcpy(_p, &(g), sizeof(g)); \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define sync_global_from_guest(vm, g) ({ \
|
|
|
|
typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \
|
|
|
|
memcpy(&(g), _p, sizeof(g)); \
|
|
|
|
})
|
|
|
|
|
2020-10-12 19:47:15 +00:00
|
|
|
void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid);
|
|
|
|
|
2018-09-18 17:54:25 +00:00
|
|
|
/* Common ucalls */
|
|
|
|
enum {
|
|
|
|
UCALL_NONE,
|
|
|
|
UCALL_SYNC,
|
|
|
|
UCALL_ABORT,
|
|
|
|
UCALL_DONE,
|
|
|
|
};
|
2018-08-22 07:19:57 +00:00
|
|
|
|
2018-09-18 17:54:25 +00:00
|
|
|
#define UCALL_MAX_ARGS 6
|
2018-08-22 07:19:57 +00:00
|
|
|
|
2018-09-18 17:54:25 +00:00
|
|
|
struct ucall {
|
|
|
|
uint64_t cmd;
|
|
|
|
uint64_t args[UCALL_MAX_ARGS];
|
|
|
|
};
|
2018-08-22 07:19:57 +00:00
|
|
|
|
2019-07-31 15:15:23 +00:00
|
|
|
void ucall_init(struct kvm_vm *vm, void *arg);
|
2018-09-18 17:54:25 +00:00
|
|
|
void ucall_uninit(struct kvm_vm *vm);
|
|
|
|
void ucall(uint64_t cmd, int nargs, ...);
|
|
|
|
uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc);
|
|
|
|
|
2020-05-26 21:51:07 +00:00
|
|
|
#define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \
|
|
|
|
ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4)
|
2018-09-18 17:54:25 +00:00
|
|
|
#define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage)
|
|
|
|
#define GUEST_DONE() ucall(UCALL_DONE, 0)
|
2020-04-10 23:17:01 +00:00
|
|
|
#define __GUEST_ASSERT(_condition, _nargs, _args...) do { \
|
|
|
|
if (!(_condition)) \
|
|
|
|
ucall(UCALL_ABORT, 2 + _nargs, \
|
|
|
|
"Failed guest assert: " \
|
|
|
|
#_condition, __LINE__, _args); \
|
2018-09-18 17:54:25 +00:00
|
|
|
} while (0)
|
2018-08-22 07:19:57 +00:00
|
|
|
|
2020-04-10 23:17:01 +00:00
|
|
|
#define GUEST_ASSERT(_condition) \
|
|
|
|
__GUEST_ASSERT((_condition), 0, 0)
|
|
|
|
|
|
|
|
#define GUEST_ASSERT_1(_condition, arg1) \
|
|
|
|
__GUEST_ASSERT((_condition), 1, (arg1))
|
|
|
|
|
|
|
|
#define GUEST_ASSERT_2(_condition, arg1, arg2) \
|
|
|
|
__GUEST_ASSERT((_condition), 2, (arg1), (arg2))
|
|
|
|
|
|
|
|
#define GUEST_ASSERT_3(_condition, arg1, arg2, arg3) \
|
|
|
|
__GUEST_ASSERT((_condition), 3, (arg1), (arg2), (arg3))
|
|
|
|
|
|
|
|
#define GUEST_ASSERT_4(_condition, arg1, arg2, arg3, arg4) \
|
|
|
|
__GUEST_ASSERT((_condition), 4, (arg1), (arg2), (arg3), (arg4))
|
|
|
|
|
2018-03-27 09:49:19 +00:00
|
|
|
#endif /* SELFTEST_KVM_UTIL_H */
|