Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini:
"A bit late... I got sidetracked by back-from-vacation routines and
conferences. But most of these patches are already a few weeks old and
things look more calm on the mailing list than what this pull request
would suggest.
x86:
- missing TLB flush
- nested virtualization fixes for SMM (secure boot on nested
hypervisor) and other nested SVM fixes
- syscall fuzzing fixes
- live migration fix for AMD SEV
- mirror VMs now work for SEV-ES too
- fixes for reset
- possible out-of-bounds access in IOAPIC emulation
- fix enlightened VMCS on Windows 2022
ARM:
- Add missing FORCE target when building the EL2 object
- Fix a PMU probe regression on some platforms
Generic:
- KCSAN fixes
selftests:
- random fixes, mostly for clang compilation"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (43 commits)
selftests: KVM: Explicitly use movq to read xmm registers
selftests: KVM: Call ucall_init when setting up in rseq_test
KVM: Remove tlbs_dirty
KVM: X86: Synchronize the shadow pagetable before link it
KVM: X86: Fix missed remote tlb flush in rmap_write_protect()
KVM: x86: nSVM: don't copy virt_ext from vmcb12
KVM: x86: nSVM: test eax for 4K alignment for GP errata workaround
KVM: x86: selftests: test simultaneous uses of V_IRQ from L1 and L0
KVM: x86: nSVM: restore int_vector in svm_clear_vintr
kvm: x86: Add AMD PMU MSRs to msrs_to_save_all[]
KVM: x86: nVMX: re-evaluate emulation_required on nested VM exit
KVM: x86: nVMX: don't fail nested VM entry on invalid guest state if !from_vmentry
KVM: x86: VMX: synthesize invalid VM exit when emulating invalid guest state
KVM: x86: nSVM: refactor svm_leave_smm and smm_enter_smm
KVM: x86: SVM: call KVM_REQ_GET_NESTED_STATE_PAGES on exit from SMM mode
KVM: x86: reset pdptrs_from_userspace when exiting smm
KVM: x86: nSVM: restore the L1 host state prior to resuming nested guest on SMM exit
KVM: nVMX: Filter out all unsupported controls when eVMCS was activated
KVM: KVM: Use cpumask_available() to check for NULL cpumask when kicking vCPUs
KVM: Clean up benign vcpu->cpu data races when kicking vCPUs
...
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
/x86_64/smm_test
|
||||
/x86_64/state_test
|
||||
/x86_64/svm_vmcall_test
|
||||
/x86_64/svm_int_ctl_test
|
||||
/x86_64/sync_regs_test
|
||||
/x86_64/tsc_msrs_test
|
||||
/x86_64/userspace_msr_exit_test
|
||||
|
||||
@@ -56,6 +56,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/smm_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/state_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/userspace_msr_exit_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test
|
||||
|
||||
@@ -371,9 +371,7 @@ static void help(char *name)
|
||||
printf(" -v: specify the number of vCPUs to run.\n");
|
||||
printf(" -o: Overlap guest memory accesses instead of partitioning\n"
|
||||
" them into a separate region of memory for each vCPU.\n");
|
||||
printf(" -s: specify the type of memory that should be used to\n"
|
||||
" back the guest data region.\n\n");
|
||||
backing_src_help();
|
||||
backing_src_help("-s");
|
||||
puts("");
|
||||
exit(0);
|
||||
}
|
||||
@@ -381,7 +379,7 @@ static void help(char *name)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct test_params params = {
|
||||
.backing_src = VM_MEM_SRC_ANONYMOUS,
|
||||
.backing_src = DEFAULT_VM_MEM_SRC,
|
||||
.vcpu_memory_bytes = DEFAULT_PER_VCPU_MEM_SIZE,
|
||||
.vcpus = 1,
|
||||
};
|
||||
|
||||
@@ -179,7 +179,7 @@ static void *uffd_handler_thread_fn(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pollfd[0].revents & POLLIN)
|
||||
if (!(pollfd[0].revents & POLLIN))
|
||||
continue;
|
||||
|
||||
r = read(uffd, &msg, sizeof(msg));
|
||||
@@ -416,7 +416,7 @@ static void help(char *name)
|
||||
{
|
||||
puts("");
|
||||
printf("usage: %s [-h] [-m vm_mode] [-u uffd_mode] [-d uffd_delay_usec]\n"
|
||||
" [-b memory] [-t type] [-v vcpus] [-o]\n", name);
|
||||
" [-b memory] [-s type] [-v vcpus] [-o]\n", name);
|
||||
guest_modes_help();
|
||||
printf(" -u: use userfaultfd to handle vCPU page faults. Mode is a\n"
|
||||
" UFFD registration mode: 'MISSING' or 'MINOR'.\n");
|
||||
@@ -426,8 +426,7 @@ static void help(char *name)
|
||||
printf(" -b: specify the size of the memory region which should be\n"
|
||||
" demand paged by each vCPU. e.g. 10M or 3G.\n"
|
||||
" Default: 1G\n");
|
||||
printf(" -t: The type of backing memory to use. Default: anonymous\n");
|
||||
backing_src_help();
|
||||
backing_src_help("-s");
|
||||
printf(" -v: specify the number of vCPUs to run.\n");
|
||||
printf(" -o: Overlap guest memory accesses instead of partitioning\n"
|
||||
" them into a separate region of memory for each vCPU.\n");
|
||||
@@ -439,14 +438,14 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
|
||||
struct test_params p = {
|
||||
.src_type = VM_MEM_SRC_ANONYMOUS,
|
||||
.src_type = DEFAULT_VM_MEM_SRC,
|
||||
.partition_vcpu_memory_access = true,
|
||||
};
|
||||
int opt;
|
||||
|
||||
guest_modes_append_default();
|
||||
|
||||
while ((opt = getopt(argc, argv, "hm:u:d:b:t:v:o")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hm:u:d:b:s:v:o")) != -1) {
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
guest_modes_cmdline(optarg);
|
||||
@@ -465,7 +464,7 @@ int main(int argc, char *argv[])
|
||||
case 'b':
|
||||
guest_percpu_mem_size = parse_size(optarg);
|
||||
break;
|
||||
case 't':
|
||||
case 's':
|
||||
p.src_type = parse_backing_src_type(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
@@ -485,7 +484,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (p.uffd_mode == UFFDIO_REGISTER_MODE_MINOR &&
|
||||
!backing_src_is_shared(p.src_type)) {
|
||||
TEST_FAIL("userfaultfd MINOR mode requires shared memory; pick a different -t");
|
||||
TEST_FAIL("userfaultfd MINOR mode requires shared memory; pick a different -s");
|
||||
}
|
||||
|
||||
for_each_guest_mode(run_test, &p);
|
||||
|
||||
@@ -118,42 +118,64 @@ static inline void disable_dirty_logging(struct kvm_vm *vm, int slots)
|
||||
toggle_dirty_logging(vm, slots, false);
|
||||
}
|
||||
|
||||
static void get_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
|
||||
uint64_t nr_pages)
|
||||
static void get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots)
|
||||
{
|
||||
uint64_t slot_pages = nr_pages / slots;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < slots; i++) {
|
||||
int slot = PERF_TEST_MEM_SLOT_INDEX + i;
|
||||
unsigned long *slot_bitmap = bitmap + i * slot_pages;
|
||||
|
||||
kvm_vm_get_dirty_log(vm, slot, slot_bitmap);
|
||||
kvm_vm_get_dirty_log(vm, slot, bitmaps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_dirty_log(struct kvm_vm *vm, int slots, unsigned long *bitmap,
|
||||
uint64_t nr_pages)
|
||||
static void clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[],
|
||||
int slots, uint64_t pages_per_slot)
|
||||
{
|
||||
uint64_t slot_pages = nr_pages / slots;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < slots; i++) {
|
||||
int slot = PERF_TEST_MEM_SLOT_INDEX + i;
|
||||
unsigned long *slot_bitmap = bitmap + i * slot_pages;
|
||||
|
||||
kvm_vm_clear_dirty_log(vm, slot, slot_bitmap, 0, slot_pages);
|
||||
kvm_vm_clear_dirty_log(vm, slot, bitmaps[i], 0, pages_per_slot);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long **alloc_bitmaps(int slots, uint64_t pages_per_slot)
|
||||
{
|
||||
unsigned long **bitmaps;
|
||||
int i;
|
||||
|
||||
bitmaps = malloc(slots * sizeof(bitmaps[0]));
|
||||
TEST_ASSERT(bitmaps, "Failed to allocate bitmaps array.");
|
||||
|
||||
for (i = 0; i < slots; i++) {
|
||||
bitmaps[i] = bitmap_zalloc(pages_per_slot);
|
||||
TEST_ASSERT(bitmaps[i], "Failed to allocate slot bitmap.");
|
||||
}
|
||||
|
||||
return bitmaps;
|
||||
}
|
||||
|
||||
static void free_bitmaps(unsigned long *bitmaps[], int slots)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < slots; i++)
|
||||
free(bitmaps[i]);
|
||||
|
||||
free(bitmaps);
|
||||
}
|
||||
|
||||
static void run_test(enum vm_guest_mode mode, void *arg)
|
||||
{
|
||||
struct test_params *p = arg;
|
||||
pthread_t *vcpu_threads;
|
||||
struct kvm_vm *vm;
|
||||
unsigned long *bmap;
|
||||
unsigned long **bitmaps;
|
||||
uint64_t guest_num_pages;
|
||||
uint64_t host_num_pages;
|
||||
uint64_t pages_per_slot;
|
||||
int vcpu_id;
|
||||
struct timespec start;
|
||||
struct timespec ts_diff;
|
||||
@@ -171,7 +193,9 @@ static void run_test(enum vm_guest_mode mode, void *arg)
|
||||
guest_num_pages = (nr_vcpus * guest_percpu_mem_size) >> vm_get_page_shift(vm);
|
||||
guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages);
|
||||
host_num_pages = vm_num_host_pages(mode, guest_num_pages);
|
||||
bmap = bitmap_zalloc(host_num_pages);
|
||||
pages_per_slot = host_num_pages / p->slots;
|
||||
|
||||
bitmaps = alloc_bitmaps(p->slots, pages_per_slot);
|
||||
|
||||
if (dirty_log_manual_caps) {
|
||||
cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2;
|
||||
@@ -239,7 +263,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
|
||||
iteration, ts_diff.tv_sec, ts_diff.tv_nsec);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
get_dirty_log(vm, p->slots, bmap, host_num_pages);
|
||||
get_dirty_log(vm, bitmaps, p->slots);
|
||||
ts_diff = timespec_elapsed(start);
|
||||
get_dirty_log_total = timespec_add(get_dirty_log_total,
|
||||
ts_diff);
|
||||
@@ -248,7 +272,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
|
||||
|
||||
if (dirty_log_manual_caps) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
clear_dirty_log(vm, p->slots, bmap, host_num_pages);
|
||||
clear_dirty_log(vm, bitmaps, p->slots, pages_per_slot);
|
||||
ts_diff = timespec_elapsed(start);
|
||||
clear_dirty_log_total = timespec_add(clear_dirty_log_total,
|
||||
ts_diff);
|
||||
@@ -281,7 +305,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
|
||||
clear_dirty_log_total.tv_nsec, avg.tv_sec, avg.tv_nsec);
|
||||
}
|
||||
|
||||
free(bmap);
|
||||
free_bitmaps(bitmaps, p->slots);
|
||||
free(vcpu_threads);
|
||||
perf_test_destroy_vm(vm);
|
||||
}
|
||||
@@ -308,11 +332,9 @@ static void help(char *name)
|
||||
printf(" -v: specify the number of vCPUs to run.\n");
|
||||
printf(" -o: Overlap guest memory accesses instead of partitioning\n"
|
||||
" them into a separate region of memory for each vCPU.\n");
|
||||
printf(" -s: specify the type of memory that should be used to\n"
|
||||
" back the guest data region.\n\n");
|
||||
backing_src_help("-s");
|
||||
printf(" -x: Split the memory region into this number of memslots.\n"
|
||||
" (default: 1)");
|
||||
backing_src_help();
|
||||
" (default: 1)\n");
|
||||
puts("");
|
||||
exit(0);
|
||||
}
|
||||
@@ -324,7 +346,7 @@ int main(int argc, char *argv[])
|
||||
.iterations = TEST_HOST_LOOP_N,
|
||||
.wr_fract = 1,
|
||||
.partition_vcpu_memory_access = true,
|
||||
.backing_src = VM_MEM_SRC_ANONYMOUS,
|
||||
.backing_src = DEFAULT_VM_MEM_SRC,
|
||||
.slots = 1,
|
||||
};
|
||||
int opt;
|
||||
|
||||
@@ -90,6 +90,8 @@ enum vm_mem_backing_src_type {
|
||||
NUM_SRC_TYPES,
|
||||
};
|
||||
|
||||
#define DEFAULT_VM_MEM_SRC VM_MEM_SRC_ANONYMOUS
|
||||
|
||||
struct vm_mem_backing_src_alias {
|
||||
const char *name;
|
||||
uint32_t flag;
|
||||
@@ -102,7 +104,7 @@ size_t get_trans_hugepagesz(void);
|
||||
size_t get_def_hugetlb_pagesz(void);
|
||||
const struct vm_mem_backing_src_alias *vm_mem_backing_src_alias(uint32_t i);
|
||||
size_t get_backing_src_pagesz(uint32_t i);
|
||||
void backing_src_help(void);
|
||||
void backing_src_help(const char *flag);
|
||||
enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name);
|
||||
long get_run_delay(void);
|
||||
|
||||
|
||||
@@ -312,37 +312,37 @@ static inline void set_xmm(int n, unsigned long val)
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned long v1di __attribute__ ((vector_size (8)));
|
||||
#define GET_XMM(__xmm) \
|
||||
({ \
|
||||
unsigned long __val; \
|
||||
asm volatile("movq %%"#__xmm", %0" : "=r"(__val) : : #__xmm); \
|
||||
__val; \
|
||||
})
|
||||
|
||||
static inline unsigned long get_xmm(int n)
|
||||
{
|
||||
assert(n >= 0 && n <= 7);
|
||||
|
||||
register v1di xmm0 __asm__("%xmm0");
|
||||
register v1di xmm1 __asm__("%xmm1");
|
||||
register v1di xmm2 __asm__("%xmm2");
|
||||
register v1di xmm3 __asm__("%xmm3");
|
||||
register v1di xmm4 __asm__("%xmm4");
|
||||
register v1di xmm5 __asm__("%xmm5");
|
||||
register v1di xmm6 __asm__("%xmm6");
|
||||
register v1di xmm7 __asm__("%xmm7");
|
||||
switch (n) {
|
||||
case 0:
|
||||
return (unsigned long)xmm0;
|
||||
return GET_XMM(xmm0);
|
||||
case 1:
|
||||
return (unsigned long)xmm1;
|
||||
return GET_XMM(xmm1);
|
||||
case 2:
|
||||
return (unsigned long)xmm2;
|
||||
return GET_XMM(xmm2);
|
||||
case 3:
|
||||
return (unsigned long)xmm3;
|
||||
return GET_XMM(xmm3);
|
||||
case 4:
|
||||
return (unsigned long)xmm4;
|
||||
return GET_XMM(xmm4);
|
||||
case 5:
|
||||
return (unsigned long)xmm5;
|
||||
return GET_XMM(xmm5);
|
||||
case 6:
|
||||
return (unsigned long)xmm6;
|
||||
return GET_XMM(xmm6);
|
||||
case 7:
|
||||
return (unsigned long)xmm7;
|
||||
return GET_XMM(xmm7);
|
||||
}
|
||||
|
||||
/* never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -456,10 +456,7 @@ static void help(char *name)
|
||||
" (default: 1G)\n");
|
||||
printf(" -v: specify the number of vCPUs to run\n"
|
||||
" (default: 1)\n");
|
||||
printf(" -s: specify the type of memory that should be used to\n"
|
||||
" back the guest data region.\n"
|
||||
" (default: anonymous)\n\n");
|
||||
backing_src_help();
|
||||
backing_src_help("-s");
|
||||
puts("");
|
||||
}
|
||||
|
||||
@@ -468,7 +465,7 @@ int main(int argc, char *argv[])
|
||||
int max_vcpus = kvm_check_cap(KVM_CAP_MAX_VCPUS);
|
||||
struct test_params p = {
|
||||
.test_mem_size = DEFAULT_TEST_MEM_SIZE,
|
||||
.src_type = VM_MEM_SRC_ANONYMOUS,
|
||||
.src_type = DEFAULT_VM_MEM_SRC,
|
||||
};
|
||||
int opt;
|
||||
|
||||
|
||||
@@ -283,13 +283,22 @@ size_t get_backing_src_pagesz(uint32_t i)
|
||||
}
|
||||
}
|
||||
|
||||
void backing_src_help(void)
|
||||
static void print_available_backing_src_types(const char *prefix)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("Available backing src types:\n");
|
||||
printf("%sAvailable backing src types:\n", prefix);
|
||||
|
||||
for (i = 0; i < NUM_SRC_TYPES; i++)
|
||||
printf("\t%s\n", vm_mem_backing_src_alias(i)->name);
|
||||
printf("%s %s\n", prefix, vm_mem_backing_src_alias(i)->name);
|
||||
}
|
||||
|
||||
void backing_src_help(const char *flag)
|
||||
{
|
||||
printf(" %s: specify the type of memory that should be used to\n"
|
||||
" back the guest data region. (default: %s)\n",
|
||||
flag, vm_mem_backing_src_alias(DEFAULT_VM_MEM_SRC)->name);
|
||||
print_available_backing_src_types(" ");
|
||||
}
|
||||
|
||||
enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name)
|
||||
@@ -300,7 +309,7 @@ enum vm_mem_backing_src_type parse_backing_src_type(const char *type_name)
|
||||
if (!strcmp(type_name, vm_mem_backing_src_alias(i)->name))
|
||||
return i;
|
||||
|
||||
backing_src_help();
|
||||
print_available_backing_src_types("");
|
||||
TEST_FAIL("Unknown backing src type: %s", type_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ int main(int argc, char *argv[])
|
||||
* CPU affinity.
|
||||
*/
|
||||
vm = vm_create_default(VCPU_ID, 0, guest_code);
|
||||
ucall_init(vm, NULL);
|
||||
|
||||
pthread_create(&migration_thread, NULL, migration_worker, 0);
|
||||
|
||||
|
||||
@@ -116,12 +116,12 @@ struct st_time {
|
||||
uint64_t st_time;
|
||||
};
|
||||
|
||||
static int64_t smccc(uint32_t func, uint32_t arg)
|
||||
static int64_t smccc(uint32_t func, uint64_t arg)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
asm volatile(
|
||||
"mov x0, %1\n"
|
||||
"mov w0, %w1\n"
|
||||
"mov x1, %2\n"
|
||||
"hvc #0\n"
|
||||
"mov %0, x0\n"
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* svm_int_ctl_test
|
||||
*
|
||||
* Copyright (C) 2021, Red Hat, Inc.
|
||||
*
|
||||
* Nested SVM testing: test simultaneous use of V_IRQ from L1 and L0.
|
||||
*/
|
||||
|
||||
#include "test_util.h"
|
||||
#include "kvm_util.h"
|
||||
#include "processor.h"
|
||||
#include "svm_util.h"
|
||||
#include "apic.h"
|
||||
|
||||
#define VCPU_ID 0
|
||||
|
||||
static struct kvm_vm *vm;
|
||||
|
||||
bool vintr_irq_called;
|
||||
bool intr_irq_called;
|
||||
|
||||
#define VINTR_IRQ_NUMBER 0x20
|
||||
#define INTR_IRQ_NUMBER 0x30
|
||||
|
||||
static void vintr_irq_handler(struct ex_regs *regs)
|
||||
{
|
||||
vintr_irq_called = true;
|
||||
}
|
||||
|
||||
static void intr_irq_handler(struct ex_regs *regs)
|
||||
{
|
||||
x2apic_write_reg(APIC_EOI, 0x00);
|
||||
intr_irq_called = true;
|
||||
}
|
||||
|
||||
static void l2_guest_code(struct svm_test_data *svm)
|
||||
{
|
||||
/* This code raises interrupt INTR_IRQ_NUMBER in the L1's LAPIC,
|
||||
* and since L1 didn't enable virtual interrupt masking,
|
||||
* L2 should receive it and not L1.
|
||||
*
|
||||
* L2 also has virtual interrupt 'VINTR_IRQ_NUMBER' pending in V_IRQ
|
||||
* so it should also receive it after the following 'sti'.
|
||||
*/
|
||||
x2apic_write_reg(APIC_ICR,
|
||||
APIC_DEST_SELF | APIC_INT_ASSERT | INTR_IRQ_NUMBER);
|
||||
|
||||
__asm__ __volatile__(
|
||||
"sti\n"
|
||||
"nop\n"
|
||||
);
|
||||
|
||||
GUEST_ASSERT(vintr_irq_called);
|
||||
GUEST_ASSERT(intr_irq_called);
|
||||
|
||||
__asm__ __volatile__(
|
||||
"vmcall\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void l1_guest_code(struct svm_test_data *svm)
|
||||
{
|
||||
#define L2_GUEST_STACK_SIZE 64
|
||||
unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
|
||||
struct vmcb *vmcb = svm->vmcb;
|
||||
|
||||
x2apic_enable();
|
||||
|
||||
/* Prepare for L2 execution. */
|
||||
generic_svm_setup(svm, l2_guest_code,
|
||||
&l2_guest_stack[L2_GUEST_STACK_SIZE]);
|
||||
|
||||
/* No virtual interrupt masking */
|
||||
vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
|
||||
|
||||
/* No intercepts for real and virtual interrupts */
|
||||
vmcb->control.intercept &= ~(1ULL << INTERCEPT_INTR | INTERCEPT_VINTR);
|
||||
|
||||
/* Make a virtual interrupt VINTR_IRQ_NUMBER pending */
|
||||
vmcb->control.int_ctl |= V_IRQ_MASK | (0x1 << V_INTR_PRIO_SHIFT);
|
||||
vmcb->control.int_vector = VINTR_IRQ_NUMBER;
|
||||
|
||||
run_guest(vmcb, svm->vmcb_gpa);
|
||||
GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL);
|
||||
GUEST_DONE();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
vm_vaddr_t svm_gva;
|
||||
|
||||
nested_svm_check_supported();
|
||||
|
||||
vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code);
|
||||
|
||||
vm_init_descriptor_tables(vm);
|
||||
vcpu_init_descriptor_tables(vm, VCPU_ID);
|
||||
|
||||
vm_install_exception_handler(vm, VINTR_IRQ_NUMBER, vintr_irq_handler);
|
||||
vm_install_exception_handler(vm, INTR_IRQ_NUMBER, intr_irq_handler);
|
||||
|
||||
vcpu_alloc_svm(vm, &svm_gva);
|
||||
vcpu_args_set(vm, VCPU_ID, 1, svm_gva);
|
||||
|
||||
struct kvm_run *run = vcpu_state(vm, VCPU_ID);
|
||||
struct ucall uc;
|
||||
|
||||
vcpu_run(vm, VCPU_ID);
|
||||
TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
|
||||
"Got exit_reason other than KVM_EXIT_IO: %u (%s)\n",
|
||||
run->exit_reason,
|
||||
exit_reason_str(run->exit_reason));
|
||||
|
||||
switch (get_ucall(vm, VCPU_ID, &uc)) {
|
||||
case UCALL_ABORT:
|
||||
TEST_FAIL("%s", (const char *)uc.args[0]);
|
||||
break;
|
||||
/* NOT REACHED */
|
||||
case UCALL_DONE:
|
||||
goto done;
|
||||
default:
|
||||
TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
|
||||
}
|
||||
done:
|
||||
kvm_vm_free(vm);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user