mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
Fixes for ARM and x86, plus selftest patches and nicer structs
for nested state save/restore. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJdC7NHAAoJEL/70l94x66DHm0H/R8L80sWe1OJbHHK8caPpwm2 mPt6JNcG/ysbG/uoMuVsdRAjZsg9l8JZB9xfA2m/ZPQQThjSG/WX0rU+gWMMI3X8 8ZbN4BCFoiNpOzOkhmStwzMWnvovKvMfhFW0BAI3HLUfM9A+XyVvNM/JbLOvEMRk WB2SxYRc38ZvIbi8eXgsoFrVyLFB2Fj/0jps4FbKnkjkl37PTDehYLWQ1pt9KsWS 2KdGoXm7/18ottqf0DPfLe0hiiiDuK3akKz7WQBMsAJHi4Fm5j39NuseeRdlablk uE4vM/sVaLn4xwM9JfrsBl9TzZ2qHsOTRlMQG4iNWjEAuPKa45lt0Jo7OBs6DSY= =Lzxe -----END PGP SIGNATURE----- Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm Pull kvm fixes from Paolo Bonzini: "Fixes for ARM and x86, plus selftest patches and nicer structs for nested state save/restore" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: KVM: nVMX: reorganize initial steps of vmx_set_nested_state KVM: arm/arm64: Fix emulated ptimer irq injection tests: kvm: Check for a kernel warning kvm: tests: Sort tests in the Makefile alphabetically KVM: x86/mmu: Allocate PAE root array when using SVM's 32-bit NPT KVM: x86: Modify struct kvm_nested_state to have explicit fields for data KVM: fix typo in documentation KVM: nVMX: use correct clean fields when copying from eVMCS KVM: arm/arm64: vgic: Fix kvm_device leak in vgic_its_destroy KVM: arm64: Filter out invalid core register IDs in KVM_GET_REG_LIST KVM: arm64: Implement vq_present() as a macro
This commit is contained in:
commit
b3e978337b
17 changed files with 405 additions and 145 deletions
|
|
@ -392,7 +392,7 @@ struct kvm_sync_regs {
|
|||
|
||||
struct kvm_vmx_nested_state {
|
||||
__u64 vmxon_pa;
|
||||
__u64 vmcs_pa;
|
||||
__u64 vmcs12_pa;
|
||||
|
||||
struct {
|
||||
__u16 flags;
|
||||
|
|
|
|||
1
tools/testing/selftests/kvm/.gitignore
vendored
1
tools/testing/selftests/kvm/.gitignore
vendored
|
|
@ -2,6 +2,7 @@
|
|||
/x86_64/evmcs_test
|
||||
/x86_64/hyperv_cpuid
|
||||
/x86_64/kvm_create_max_vcpus
|
||||
/x86_64/mmio_warning_test
|
||||
/x86_64/platform_info_test
|
||||
/x86_64/set_sregs_test
|
||||
/x86_64/smm_test
|
||||
|
|
|
|||
|
|
@ -11,23 +11,24 @@ LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebi
|
|||
LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c
|
||||
LIBKVM_aarch64 = lib/aarch64/processor.c
|
||||
|
||||
TEST_GEN_PROGS_x86_64 = x86_64/platform_info_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/state_test
|
||||
TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/smm_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/kvm_create_max_vcpus
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
|
||||
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/sync_regs_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
|
||||
TEST_GEN_PROGS_x86_64 += dirty_log_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
|
||||
TEST_GEN_PROGS_x86_64 += clear_dirty_log_test
|
||||
TEST_GEN_PROGS_x86_64 += dirty_log_test
|
||||
|
||||
TEST_GEN_PROGS_aarch64 += dirty_log_test
|
||||
TEST_GEN_PROGS_aarch64 += clear_dirty_log_test
|
||||
TEST_GEN_PROGS_aarch64 += dirty_log_test
|
||||
|
||||
TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M))
|
||||
LIBKVM += $(LIBKVM_$(UNAME_M))
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_size,
|
|||
void *guest_code);
|
||||
void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code);
|
||||
|
||||
bool vm_is_unrestricted_guest(struct kvm_vm *vm);
|
||||
|
||||
struct kvm_userspace_memory_region *
|
||||
kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start,
|
||||
uint64_t end);
|
||||
|
|
|
|||
|
|
@ -303,6 +303,8 @@ static inline unsigned long get_xmm(int n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool is_intel_cpu(void);
|
||||
|
||||
struct kvm_x86_state;
|
||||
struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid);
|
||||
void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
|
|
|
|||
|
|
@ -1583,3 +1583,39 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva)
|
|||
{
|
||||
return addr_gpa2hva(vm, addr_gva2gpa(vm, gva));
|
||||
}
|
||||
|
||||
/*
|
||||
* Is Unrestricted Guest
|
||||
*
|
||||
* Input Args:
|
||||
* vm - Virtual Machine
|
||||
*
|
||||
* Output Args: None
|
||||
*
|
||||
* Return: True if the unrestricted guest is set to 'Y', otherwise return false.
|
||||
*
|
||||
* Check if the unrestricted guest flag is enabled.
|
||||
*/
|
||||
bool vm_is_unrestricted_guest(struct kvm_vm *vm)
|
||||
{
|
||||
char val = 'N';
|
||||
size_t count;
|
||||
FILE *f;
|
||||
|
||||
if (vm == NULL) {
|
||||
/* Ensure that the KVM vendor-specific module is loaded. */
|
||||
f = fopen(KVM_DEV_PATH, "r");
|
||||
TEST_ASSERT(f != NULL, "Error in opening KVM dev file: %d",
|
||||
errno);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
f = fopen("/sys/module/kvm_intel/parameters/unrestricted_guest", "r");
|
||||
if (f) {
|
||||
count = fread(&val, sizeof(char), 1, f);
|
||||
TEST_ASSERT(count == 1, "Unable to read from param file.");
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return val == 'Y';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1137,3 +1137,19 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s
|
|||
r);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_intel_cpu(void)
|
||||
{
|
||||
int eax, ebx, ecx, edx;
|
||||
const uint32_t *chunk;
|
||||
const int leaf = 0;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"cpuid"
|
||||
: /* output */ "=a"(eax), "=b"(ebx),
|
||||
"=c"(ecx), "=d"(edx)
|
||||
: /* input */ "0"(leaf), "2"(0));
|
||||
|
||||
chunk = (const uint32_t *)("GenuineIntel");
|
||||
return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]);
|
||||
}
|
||||
|
|
|
|||
126
tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
Normal file
126
tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* mmio_warning_test
|
||||
*
|
||||
* Copyright (C) 2019, Google LLC.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
*
|
||||
* Test that we don't get a kernel warning when we call KVM_RUN after a
|
||||
* triple fault occurs. To get the triple fault to occur we call KVM_RUN
|
||||
* on a VCPU that hasn't been properly setup.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <kvm_util.h>
|
||||
#include <linux/kvm.h>
|
||||
#include <processor.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <test_util.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define NTHREAD 4
|
||||
#define NPROCESS 5
|
||||
|
||||
struct thread_context {
|
||||
int kvmcpu;
|
||||
struct kvm_run *run;
|
||||
};
|
||||
|
||||
void *thr(void *arg)
|
||||
{
|
||||
struct thread_context *tc = (struct thread_context *)arg;
|
||||
int res;
|
||||
int kvmcpu = tc->kvmcpu;
|
||||
struct kvm_run *run = tc->run;
|
||||
|
||||
res = ioctl(kvmcpu, KVM_RUN, 0);
|
||||
printf("ret1=%d exit_reason=%d suberror=%d\n",
|
||||
res, run->exit_reason, run->internal.suberror);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test(void)
|
||||
{
|
||||
int i, kvm, kvmvm, kvmcpu;
|
||||
pthread_t th[NTHREAD];
|
||||
struct kvm_run *run;
|
||||
struct thread_context tc;
|
||||
|
||||
kvm = open("/dev/kvm", O_RDWR);
|
||||
TEST_ASSERT(kvm != -1, "failed to open /dev/kvm");
|
||||
kvmvm = ioctl(kvm, KVM_CREATE_VM, 0);
|
||||
TEST_ASSERT(kvmvm != -1, "KVM_CREATE_VM failed");
|
||||
kvmcpu = ioctl(kvmvm, KVM_CREATE_VCPU, 0);
|
||||
TEST_ASSERT(kvmcpu != -1, "KVM_CREATE_VCPU failed");
|
||||
run = (struct kvm_run *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED,
|
||||
kvmcpu, 0);
|
||||
tc.kvmcpu = kvmcpu;
|
||||
tc.run = run;
|
||||
srand(getpid());
|
||||
for (i = 0; i < NTHREAD; i++) {
|
||||
pthread_create(&th[i], NULL, thr, (void *)(uintptr_t)&tc);
|
||||
usleep(rand() % 10000);
|
||||
}
|
||||
for (i = 0; i < NTHREAD; i++)
|
||||
pthread_join(th[i], NULL);
|
||||
}
|
||||
|
||||
int get_warnings_count(void)
|
||||
{
|
||||
int warnings;
|
||||
FILE *f;
|
||||
|
||||
f = popen("dmesg | grep \"WARNING:\" | wc -l", "r");
|
||||
fscanf(f, "%d", &warnings);
|
||||
fclose(f);
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int warnings_before, warnings_after;
|
||||
|
||||
if (!is_intel_cpu()) {
|
||||
printf("Must be run on an Intel CPU, skipping test\n");
|
||||
exit(KSFT_SKIP);
|
||||
}
|
||||
|
||||
if (vm_is_unrestricted_guest(NULL)) {
|
||||
printf("Unrestricted guest must be disabled, skipping test\n");
|
||||
exit(KSFT_SKIP);
|
||||
}
|
||||
|
||||
warnings_before = get_warnings_count();
|
||||
|
||||
for (int i = 0; i < NPROCESS; ++i) {
|
||||
int status;
|
||||
int pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
exit(1);
|
||||
if (pid == 0) {
|
||||
test();
|
||||
exit(0);
|
||||
}
|
||||
while (waitpid(pid, &status, __WALL) != pid)
|
||||
;
|
||||
}
|
||||
|
||||
warnings_after = get_warnings_count();
|
||||
TEST_ASSERT(warnings_before == warnings_after,
|
||||
"Warnings found in kernel. Run 'dmesg' to inspect them.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ void set_revision_id_for_vmcs12(struct kvm_nested_state *state,
|
|||
u32 vmcs12_revision)
|
||||
{
|
||||
/* Set revision_id in vmcs12 to vmcs12_revision. */
|
||||
memcpy(state->data, &vmcs12_revision, sizeof(u32));
|
||||
memcpy(&state->data, &vmcs12_revision, sizeof(u32));
|
||||
}
|
||||
|
||||
void set_default_state(struct kvm_nested_state *state)
|
||||
|
|
@ -95,9 +95,9 @@ void set_default_vmx_state(struct kvm_nested_state *state, int size)
|
|||
KVM_STATE_NESTED_EVMCS;
|
||||
state->format = 0;
|
||||
state->size = size;
|
||||
state->vmx.vmxon_pa = 0x1000;
|
||||
state->vmx.vmcs_pa = 0x2000;
|
||||
state->vmx.smm.flags = 0;
|
||||
state->hdr.vmx.vmxon_pa = 0x1000;
|
||||
state->hdr.vmx.vmcs12_pa = 0x2000;
|
||||
state->hdr.vmx.smm.flags = 0;
|
||||
set_revision_id_for_vmcs12(state, VMCS12_REVISION);
|
||||
}
|
||||
|
||||
|
|
@ -123,39 +123,47 @@ void test_vmx_nested_state(struct kvm_vm *vm)
|
|||
/*
|
||||
* We cannot virtualize anything if the guest does not have VMX
|
||||
* enabled. We expect KVM_SET_NESTED_STATE to return 0 if vmxon_pa
|
||||
* is set to -1ull.
|
||||
* is set to -1ull, but the flags must be zero.
|
||||
*/
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = -1ull;
|
||||
state->hdr.vmx.vmxon_pa = -1ull;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
state->hdr.vmx.vmcs12_pa = -1ull;
|
||||
state->flags = KVM_STATE_NESTED_EVMCS;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
state->flags = 0;
|
||||
test_nested_state(vm, state);
|
||||
|
||||
/* Enable VMX in the guest CPUID. */
|
||||
vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
|
||||
|
||||
/* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
|
||||
/*
|
||||
* Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
|
||||
* setting the nested state but flags other than eVMCS must be clear.
|
||||
*/
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = -1ull;
|
||||
state->vmx.smm.flags = 1;
|
||||
state->hdr.vmx.vmxon_pa = -1ull;
|
||||
state->hdr.vmx.vmcs12_pa = -1ull;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
state->flags = KVM_STATE_NESTED_EVMCS;
|
||||
test_nested_state(vm, state);
|
||||
|
||||
/* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
|
||||
state->hdr.vmx.smm.flags = 1;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/* It is invalid to have vmxon_pa == -1ull and vmcs_pa != -1ull. */
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = -1ull;
|
||||
state->vmx.vmcs_pa = 0;
|
||||
state->hdr.vmx.vmxon_pa = -1ull;
|
||||
state->flags = 0;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/*
|
||||
* Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
|
||||
* setting the nested state.
|
||||
*/
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = -1ull;
|
||||
state->vmx.vmcs_pa = -1ull;
|
||||
test_nested_state(vm, state);
|
||||
|
||||
/* It is invalid to have vmxon_pa set to a non-page aligned address. */
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = 1;
|
||||
state->hdr.vmx.vmxon_pa = 1;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/*
|
||||
|
|
@ -165,7 +173,7 @@ void test_vmx_nested_state(struct kvm_vm *vm)
|
|||
set_default_vmx_state(state, state_sz);
|
||||
state->flags = KVM_STATE_NESTED_GUEST_MODE |
|
||||
KVM_STATE_NESTED_RUN_PENDING;
|
||||
state->vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
|
||||
state->hdr.vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/*
|
||||
|
|
@ -174,14 +182,14 @@ void test_vmx_nested_state(struct kvm_vm *vm)
|
|||
* KVM_STATE_NESTED_SMM_VMXON
|
||||
*/
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.smm.flags = ~(KVM_STATE_NESTED_SMM_GUEST_MODE |
|
||||
state->hdr.vmx.smm.flags = ~(KVM_STATE_NESTED_SMM_GUEST_MODE |
|
||||
KVM_STATE_NESTED_SMM_VMXON);
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/* Outside SMM, SMM flags must be zero. */
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->flags = 0;
|
||||
state->vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
|
||||
state->hdr.vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/* Size must be large enough to fit kvm_nested_state and vmcs12. */
|
||||
|
|
@ -191,8 +199,8 @@ void test_vmx_nested_state(struct kvm_vm *vm)
|
|||
|
||||
/* vmxon_pa cannot be the same address as vmcs_pa. */
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = 0;
|
||||
state->vmx.vmcs_pa = 0;
|
||||
state->hdr.vmx.vmxon_pa = 0;
|
||||
state->hdr.vmx.vmcs12_pa = 0;
|
||||
test_nested_state_expect_einval(vm, state);
|
||||
|
||||
/* The revision id for vmcs12 must be VMCS12_REVISION. */
|
||||
|
|
@ -205,16 +213,16 @@ void test_vmx_nested_state(struct kvm_vm *vm)
|
|||
* it again.
|
||||
*/
|
||||
set_default_vmx_state(state, state_sz);
|
||||
state->vmx.vmxon_pa = -1ull;
|
||||
state->vmx.vmcs_pa = -1ull;
|
||||
state->hdr.vmx.vmxon_pa = -1ull;
|
||||
state->hdr.vmx.vmcs12_pa = -1ull;
|
||||
state->flags = 0;
|
||||
test_nested_state(vm, state);
|
||||
vcpu_nested_state_get(vm, VCPU_ID, state);
|
||||
TEST_ASSERT(state->size >= sizeof(*state) && state->size <= state_sz,
|
||||
"Size must be between %d and %d. The size returned was %d.",
|
||||
sizeof(*state), state_sz, state->size);
|
||||
TEST_ASSERT(state->vmx.vmxon_pa == -1ull, "vmxon_pa must be -1ull.");
|
||||
TEST_ASSERT(state->vmx.vmcs_pa == -1ull, "vmcs_pa must be -1ull.");
|
||||
TEST_ASSERT(state->hdr.vmx.vmxon_pa == -1ull, "vmxon_pa must be -1ull.");
|
||||
TEST_ASSERT(state->hdr.vmx.vmcs12_pa == -1ull, "vmcs_pa must be -1ull.");
|
||||
|
||||
free(state);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue