Commit 22447828 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull KVM fixes from Paolo Bonzini:
 "ARM fixes:

   - Another state update on exit to userspace fix

   - Prevent the creation of mixed 32/64 VMs

   - Fix regression with irqbypass not restarting the guest on failed
     connect

   - Fix regression with debug register decoding resulting in
     overlapping access

   - Commit exception state on exit to usrspace

   - Fix the MMU notifier return values

   - Add missing 'static' qualifiers in the new host stage-2 code

  x86 fixes:

   - fix guest missed wakeup with assigned devices

   - fix WARN reported by syzkaller

   - do not use BIT() in UAPI headers

   - make the kvm_amd.avic parameter bool

  PPC fixes:

   - make halt polling heuristics consistent with other architectures

  selftests:

   - various fixes

   - new performance selftest memslot_perf_test

   - test UFFD minor faults in demand_paging_test"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (44 commits)
  selftests: kvm: fix overlapping addresses in memslot_perf_test
  KVM: X86: Kill off ctxt->ud
  KVM: X86: Fix warning caused by stale emulation context
  KVM: X86: Use kvm_get_linear_rip() in single-step and #DB/#BP interception
  KVM: x86/mmu: Fix comment mentioning skip_4k
  KVM: VMX: update vcpu posted-interrupt descriptor when assigning device
  KVM: rename KVM_REQ_PENDING_TIMER to KVM_REQ_UNBLOCK
  KVM: x86: add start_assignment hook to kvm_x86_ops
  KVM: LAPIC: Narrow the timer latency between wait_lapic_expire and world switch
  selftests: kvm: do only 1 memslot_perf_test run by default
  KVM: X86: Use _BITUL() macro in UAPI headers
  KVM: selftests: add shared hugetlbfs backing source type
  KVM: selftests: allow using UFFD minor faults for demand paging
  KVM: selftests: create alias mappings when using shared memory
  KVM: selftests: add shmem backing source type
  KVM: selftests: refactor vm_mem_backing_src_type flags
  KVM: selftests: allow different backing source types
  KVM: selftests: compute correct demand paging size
  KVM: selftests: simplify setup_demand_paging error handling
  KVM: selftests: Print a message if /dev/kvm is missing
  ...
parents 866c4b8a 000ac429
...@@ -314,7 +314,6 @@ struct x86_emulate_ctxt { ...@@ -314,7 +314,6 @@ struct x86_emulate_ctxt {
int interruptibility; int interruptibility;
bool perm_ok; /* do not check permissions if true */ bool perm_ok; /* do not check permissions if true */
bool ud; /* inject an #UD if host doesn't support insn */
bool tf; /* TF value before instruction (after for syscall/sysret) */ bool tf; /* TF value before instruction (after for syscall/sysret) */
bool have_exception; bool have_exception;
...@@ -491,7 +490,7 @@ enum x86_intercept { ...@@ -491,7 +490,7 @@ enum x86_intercept {
#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
#endif #endif
int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len); int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len, int emulation_type);
bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt); bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt);
#define EMULATION_FAILED -1 #define EMULATION_FAILED -1
#define EMULATION_OK 0 #define EMULATION_OK 0
......
...@@ -1598,11 +1598,19 @@ static void __kvm_wait_lapic_expire(struct kvm_vcpu *vcpu) ...@@ -1598,11 +1598,19 @@ static void __kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc()); guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
apic->lapic_timer.advance_expire_delta = guest_tsc - tsc_deadline; apic->lapic_timer.advance_expire_delta = guest_tsc - tsc_deadline;
if (lapic_timer_advance_dynamic) {
adjust_lapic_timer_advance(vcpu, apic->lapic_timer.advance_expire_delta);
/*
* If the timer fired early, reread the TSC to account for the
* overhead of the above adjustment to avoid waiting longer
* than is necessary.
*/
if (guest_tsc < tsc_deadline)
guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
}
if (guest_tsc < tsc_deadline) if (guest_tsc < tsc_deadline)
__wait_lapic_expire(vcpu, tsc_deadline - guest_tsc); __wait_lapic_expire(vcpu, tsc_deadline - guest_tsc);
if (lapic_timer_advance_dynamic)
adjust_lapic_timer_advance(vcpu, apic->lapic_timer.advance_expire_delta);
} }
void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu) void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu)
...@@ -1661,7 +1669,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn) ...@@ -1661,7 +1669,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn)
} }
atomic_inc(&apic->lapic_timer.pending); atomic_inc(&apic->lapic_timer.pending);
kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu); kvm_make_request(KVM_REQ_UNBLOCK, vcpu);
if (from_timer_fn) if (from_timer_fn)
kvm_vcpu_kick(vcpu); kvm_vcpu_kick(vcpu);
} }
......
...@@ -1192,9 +1192,9 @@ bool kvm_tdp_mmu_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) ...@@ -1192,9 +1192,9 @@ bool kvm_tdp_mmu_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
} }
/* /*
* Remove write access from all the SPTEs mapping GFNs [start, end). If * Remove write access from all SPTEs at or above min_level that map GFNs
* skip_4k is set, SPTEs that map 4k pages, will not be write-protected. * [start, end). Returns true if an SPTE has been changed and the TLBs need to
* Returns true if an SPTE has been changed and the TLBs need to be flushed. * be flushed.
*/ */
static bool wrprot_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, static bool wrprot_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root,
gfn_t start, gfn_t end, int min_level) gfn_t start, gfn_t end, int min_level)
......
...@@ -28,10 +28,8 @@ ...@@ -28,10 +28,8 @@
#include "svm.h" #include "svm.h"
/* enable / disable AVIC */ /* enable / disable AVIC */
int avic; bool avic;
#ifdef CONFIG_X86_LOCAL_APIC module_param(avic, bool, S_IRUGO);
module_param(avic, int, S_IRUGO);
#endif
#define SVM_AVIC_DOORBELL 0xc001011b #define SVM_AVIC_DOORBELL 0xc001011b
......
...@@ -1010,9 +1010,7 @@ static __init int svm_hardware_setup(void) ...@@ -1010,9 +1010,7 @@ static __init int svm_hardware_setup(void)
} }
if (avic) { if (avic) {
if (!npt_enabled || if (!npt_enabled || !boot_cpu_has(X86_FEATURE_AVIC)) {
!boot_cpu_has(X86_FEATURE_AVIC) ||
!IS_ENABLED(CONFIG_X86_LOCAL_APIC)) {
avic = false; avic = false;
} else { } else {
pr_info("AVIC enabled\n"); pr_info("AVIC enabled\n");
......
...@@ -480,7 +480,7 @@ extern struct kvm_x86_nested_ops svm_nested_ops; ...@@ -480,7 +480,7 @@ extern struct kvm_x86_nested_ops svm_nested_ops;
#define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL #define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL
extern int avic; extern bool avic;
static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data) static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
{ {
......
...@@ -90,8 +90,7 @@ static inline bool cpu_has_vmx_preemption_timer(void) ...@@ -90,8 +90,7 @@ static inline bool cpu_has_vmx_preemption_timer(void)
static inline bool cpu_has_vmx_posted_intr(void) static inline bool cpu_has_vmx_posted_intr(void)
{ {
return IS_ENABLED(CONFIG_X86_LOCAL_APIC) && return vmcs_config.pin_based_exec_ctrl & PIN_BASED_POSTED_INTR;
vmcs_config.pin_based_exec_ctrl & PIN_BASED_POSTED_INTR;
} }
static inline bool cpu_has_load_ia32_efer(void) static inline bool cpu_has_load_ia32_efer(void)
......
...@@ -237,6 +237,20 @@ bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu) ...@@ -237,6 +237,20 @@ bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu)
} }
/*
* Bail out of the block loop if the VM has an assigned
* device, but the blocking vCPU didn't reconfigure the
* PI.NV to the wakeup vector, i.e. the assigned device
* came along after the initial check in pi_pre_block().
*/
void vmx_pi_start_assignment(struct kvm *kvm)
{
if (!irq_remapping_cap(IRQ_POSTING_CAP))
return;
kvm_make_all_cpus_request(kvm, KVM_REQ_UNBLOCK);
}
/* /*
* pi_update_irte - set IRTE for Posted-Interrupts * pi_update_irte - set IRTE for Posted-Interrupts
* *
......
...@@ -95,5 +95,6 @@ void __init pi_init_cpu(int cpu); ...@@ -95,5 +95,6 @@ void __init pi_init_cpu(int cpu);
bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu); bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu);
int pi_update_irte(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq, int pi_update_irte(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq,
bool set); bool set);
void vmx_pi_start_assignment(struct kvm *kvm);
#endif /* __KVM_X86_VMX_POSTED_INTR_H */ #endif /* __KVM_X86_VMX_POSTED_INTR_H */
...@@ -4843,7 +4843,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu) ...@@ -4843,7 +4843,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
struct vcpu_vmx *vmx = to_vmx(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu);
struct kvm_run *kvm_run = vcpu->run; struct kvm_run *kvm_run = vcpu->run;
u32 intr_info, ex_no, error_code; u32 intr_info, ex_no, error_code;
unsigned long cr2, rip, dr6; unsigned long cr2, dr6;
u32 vect_info; u32 vect_info;
vect_info = vmx->idt_vectoring_info; vect_info = vmx->idt_vectoring_info;
...@@ -4933,8 +4933,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu) ...@@ -4933,8 +4933,7 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
vmx->vcpu.arch.event_exit_inst_len = vmx->vcpu.arch.event_exit_inst_len =
vmcs_read32(VM_EXIT_INSTRUCTION_LEN); vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
kvm_run->exit_reason = KVM_EXIT_DEBUG; kvm_run->exit_reason = KVM_EXIT_DEBUG;
rip = kvm_rip_read(vcpu); kvm_run->debug.arch.pc = kvm_get_linear_rip(vcpu);
kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
kvm_run->debug.arch.exception = ex_no; kvm_run->debug.arch.exception = ex_no;
break; break;
case AC_VECTOR: case AC_VECTOR:
...@@ -7721,6 +7720,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { ...@@ -7721,6 +7720,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
.nested_ops = &vmx_nested_ops, .nested_ops = &vmx_nested_ops,
.update_pi_irte = pi_update_irte, .update_pi_irte = pi_update_irte,
.start_assignment = vmx_pi_start_assignment,
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
.set_hv_timer = vmx_set_hv_timer, .set_hv_timer = vmx_set_hv_timer,
......
...@@ -3105,6 +3105,8 @@ static void record_steal_time(struct kvm_vcpu *vcpu) ...@@ -3105,6 +3105,8 @@ static void record_steal_time(struct kvm_vcpu *vcpu)
st->preempted & KVM_VCPU_FLUSH_TLB); st->preempted & KVM_VCPU_FLUSH_TLB);
if (xchg(&st->preempted, 0) & KVM_VCPU_FLUSH_TLB) if (xchg(&st->preempted, 0) & KVM_VCPU_FLUSH_TLB)
kvm_vcpu_flush_tlb_guest(vcpu); kvm_vcpu_flush_tlb_guest(vcpu);
} else {
st->preempted = 0;
} }
vcpu->arch.st.preempted = 0; vcpu->arch.st.preempted = 0;
...@@ -7226,6 +7228,11 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) ...@@ -7226,6 +7228,11 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK); BUILD_BUG_ON(HF_SMM_MASK != X86EMUL_SMM_MASK);
BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK); BUILD_BUG_ON(HF_SMM_INSIDE_NMI_MASK != X86EMUL_SMM_INSIDE_NMI_MASK);
ctxt->interruptibility = 0;
ctxt->have_exception = false;
ctxt->exception.vector = -1;
ctxt->perm_ok = false;
init_decode_cache(ctxt); init_decode_cache(ctxt);
vcpu->arch.emulate_regs_need_sync_from_vcpu = false; vcpu->arch.emulate_regs_need_sync_from_vcpu = false;
} }
...@@ -7561,14 +7568,7 @@ int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type, ...@@ -7561,14 +7568,7 @@ int x86_decode_emulated_instruction(struct kvm_vcpu *vcpu, int emulation_type,
kvm_vcpu_check_breakpoint(vcpu, &r)) kvm_vcpu_check_breakpoint(vcpu, &r))
return r; return r;
ctxt->interruptibility = 0; r = x86_decode_insn(ctxt, insn, insn_len, emulation_type);
ctxt->have_exception = false;
ctxt->exception.vector = -1;
ctxt->perm_ok = false;
ctxt->ud = emulation_type & EMULTYPE_TRAP_UD;
r = x86_decode_insn(ctxt, insn, insn_len);
trace_kvm_emulate_insn_start(vcpu); trace_kvm_emulate_insn_start(vcpu);
++vcpu->stat.insn_emulation; ++vcpu->stat.insn_emulation;
...@@ -8360,6 +8360,9 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id) ...@@ -8360,6 +8360,9 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id)
vcpu->stat.directed_yield_attempted++; vcpu->stat.directed_yield_attempted++;
if (single_task_running())
goto no_yield;
rcu_read_lock(); rcu_read_lock();
map = rcu_dereference(vcpu->kvm->arch.apic_map); map = rcu_dereference(vcpu->kvm->arch.apic_map);
...@@ -9496,7 +9499,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu) ...@@ -9496,7 +9499,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu)
if (r <= 0) if (r <= 0)
break; break;
kvm_clear_request(KVM_REQ_PENDING_TIMER, vcpu); kvm_clear_request(KVM_REQ_UNBLOCK, vcpu);
if (kvm_cpu_has_pending_timer(vcpu)) if (kvm_cpu_has_pending_timer(vcpu))
kvm_inject_pending_timer_irqs(vcpu); kvm_inject_pending_timer_irqs(vcpu);
...@@ -10115,8 +10118,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, ...@@ -10115,8 +10118,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
kvm_update_dr7(vcpu); kvm_update_dr7(vcpu);
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
vcpu->arch.singlestep_rip = kvm_rip_read(vcpu) + vcpu->arch.singlestep_rip = kvm_get_linear_rip(vcpu);
get_segment_base(vcpu, VCPU_SREG_CS);
/* /*
* Trigger an rflags update that will inject or remove the trace * Trigger an rflags update that will inject or remove the trace
...@@ -11499,7 +11501,8 @@ bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu) ...@@ -11499,7 +11501,8 @@ bool kvm_arch_can_dequeue_async_page_present(struct kvm_vcpu *vcpu)
void kvm_arch_start_assignment(struct kvm *kvm) void kvm_arch_start_assignment(struct kvm *kvm)
{ {
atomic_inc(&kvm->arch.assigned_device_count); if (atomic_inc_return(&kvm->arch.assigned_device_count) == 1)
static_call_cond(kvm_x86_start_assignment)(kvm);
} }
EXPORT_SYMBOL_GPL(kvm_arch_start_assignment); EXPORT_SYMBOL_GPL(kvm_arch_start_assignment);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sched/stat.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/minmax.h> #include <linux/minmax.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -146,7 +147,7 @@ static inline bool is_error_page(struct page *page) ...@@ -146,7 +147,7 @@ static inline bool is_error_page(struct page *page)
*/ */
#define KVM_REQ_TLB_FLUSH (0 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_TLB_FLUSH (0 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
#define KVM_REQ_MMU_RELOAD (1 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_MMU_RELOAD (1 | KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
#define KVM_REQ_PENDING_TIMER 2 #define KVM_REQ_UNBLOCK 2
#define KVM_REQ_UNHALT 3 #define KVM_REQ_UNHALT 3
#define KVM_REQUEST_ARCH_BASE 8 #define KVM_REQUEST_ARCH_BASE 8
...@@ -265,6 +266,11 @@ static inline bool kvm_vcpu_mapped(struct kvm_host_map *map) ...@@ -265,6 +266,11 @@ static inline bool kvm_vcpu_mapped(struct kvm_host_map *map)
return !!map->hva; return !!map->hva;
} }
static inline bool kvm_vcpu_can_poll(ktime_t cur, ktime_t stop)
{
return single_task_running() && !need_resched() && ktime_before(cur, stop);
}
/* /*
* Sometimes a large or cross-page mmio needs to be broken up into separate * Sometimes a large or cross-page mmio needs to be broken up into separate
* exits for userspace servicing. * exits for userspace servicing.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Note: you must update KVM_API_VERSION if you change this interface. * Note: you must update KVM_API_VERSION if you change this interface.
*/ */
#include <linux/const.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
...@@ -1879,8 +1880,8 @@ struct kvm_hyperv_eventfd { ...@@ -1879,8 +1880,8 @@ struct kvm_hyperv_eventfd {
* conversion after harvesting an entry. Also, it must not skip any * conversion after harvesting an entry. Also, it must not skip any
* dirty bits, so that dirty bits are always harvested in sequence. * dirty bits, so that dirty bits are always harvested in sequence.
*/ */
#define KVM_DIRTY_GFN_F_DIRTY BIT(0) #define KVM_DIRTY_GFN_F_DIRTY _BITUL(0)
#define KVM_DIRTY_GFN_F_RESET BIT(1) #define KVM_DIRTY_GFN_F_RESET _BITUL(1)
#define KVM_DIRTY_GFN_F_MASK 0x3 #define KVM_DIRTY_GFN_F_MASK 0x3
/* /*
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Note: you must update KVM_API_VERSION if you change this interface. * Note: you must update KVM_API_VERSION if you change this interface.
*/ */
#include <linux/const.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
...@@ -1879,8 +1880,8 @@ struct kvm_hyperv_eventfd { ...@@ -1879,8 +1880,8 @@ struct kvm_hyperv_eventfd {
* conversion after harvesting an entry. Also, it must not skip any * conversion after harvesting an entry. Also, it must not skip any
* dirty bits, so that dirty bits are always harvested in sequence. * dirty bits, so that dirty bits are always harvested in sequence.
*/ */
#define KVM_DIRTY_GFN_F_DIRTY BIT(0) #define KVM_DIRTY_GFN_F_DIRTY _BITUL(0)
#define KVM_DIRTY_GFN_F_RESET BIT(1) #define KVM_DIRTY_GFN_F_RESET _BITUL(1)
#define KVM_DIRTY_GFN_F_MASK 0x3 #define KVM_DIRTY_GFN_F_MASK 0x3
/* /*
......
...@@ -41,5 +41,6 @@ ...@@ -41,5 +41,6 @@
/kvm_create_max_vcpus /kvm_create_max_vcpus
/kvm_page_table_test /kvm_page_table_test
/memslot_modification_stress_test /memslot_modification_stress_test
/memslot_perf_test
/set_memory_region_test /set_memory_region_test
/steal_time /steal_time
...@@ -33,7 +33,7 @@ ifeq ($(ARCH),s390) ...@@ -33,7 +33,7 @@ ifeq ($(ARCH),s390)
UNAME_M := s390x UNAME_M := s390x
endif endif
LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/rbtree.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c
LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S
LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c
LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c
...@@ -74,6 +74,7 @@ TEST_GEN_PROGS_x86_64 += hardware_disable_test ...@@ -74,6 +74,7 @@ TEST_GEN_PROGS_x86_64 += hardware_disable_test
TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
TEST_GEN_PROGS_x86_64 += kvm_page_table_test TEST_GEN_PROGS_x86_64 += kvm_page_table_test
TEST_GEN_PROGS_x86_64 += memslot_modification_stress_test TEST_GEN_PROGS_x86_64 += memslot_modification_stress_test
TEST_GEN_PROGS_x86_64 += memslot_perf_test
TEST_GEN_PROGS_x86_64 += set_memory_region_test TEST_GEN_PROGS_x86_64 += set_memory_region_test
TEST_GEN_PROGS_x86_64 += steal_time TEST_GEN_PROGS_x86_64 += steal_time
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define _GNU_SOURCE /* for pipe2 */ #define _GNU_SOURCE /* for pipe2 */
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
static int nr_vcpus = 1; static int nr_vcpus = 1;
static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE;
static size_t demand_paging_size;
static char *guest_data_prototype; static char *guest_data_prototype;
static void *vcpu_worker(void *data) static void *vcpu_worker(void *data)
...@@ -71,36 +73,51 @@ static void *vcpu_worker(void *data) ...@@ -71,36 +73,51 @@ static void *vcpu_worker(void *data)
return NULL; return NULL;
} }
static int handle_uffd_page_request(int uffd, uint64_t addr) static int handle_uffd_page_request(int uffd_mode, int uffd, uint64_t addr)
{ {
pid_t tid; pid_t tid = syscall(__NR_gettid);
struct timespec start; struct timespec start;
struct timespec ts_diff; struct timespec ts_diff;
struct uffdio_copy copy;
int r; int r;
tid = syscall(__NR_gettid); clock_gettime(CLOCK_MONOTONIC, &start);
copy.src = (uint64_t)guest_data_prototype; if (uffd_mode == UFFDIO_REGISTER_MODE_MISSING) {
copy.dst = addr; struct uffdio_copy copy;
copy.len = perf_test_args.host_page_size;
copy.mode = 0;
clock_gettime(CLOCK_MONOTONIC, &start); copy.src = (uint64_t)guest_data_prototype;
copy.dst = addr;
copy.len = demand_paging_size;
copy.mode = 0;
r = ioctl(uffd, UFFDIO_COPY, &copy); r = ioctl(uffd, UFFDIO_COPY, &copy);
if (r == -1) { if (r == -1) {
pr_info("Failed Paged in 0x%lx from thread %d with errno: %d\n", pr_info("Failed UFFDIO_COPY in 0x%lx from thread %d with errno: %d\n",
addr, tid, errno); addr, tid, errno);
return r; return r;
}
} else if (uffd_mode == UFFDIO_REGISTER_MODE_MINOR) {
struct uffdio_continue cont = {0};
cont.range.start = addr;
cont.range.len = demand_paging_size;
r = ioctl(uffd, UFFDIO_CONTINUE, &cont);
if (r == -1) {
pr_info("Failed UFFDIO_CONTINUE in 0x%lx from thread %d with errno: %d\n",
addr, tid, errno);
return r;
}
} else {
TEST_FAIL("Invalid uffd mode %d", uffd_mode);
} }
ts_diff = timespec_elapsed(start); ts_diff = timespec_elapsed(start);
PER_PAGE_DEBUG("UFFDIO_COPY %d \t%ld ns\n", tid, PER_PAGE_DEBUG("UFFD page-in %d \t%ld ns\n", tid,
timespec_to_ns(ts_diff)); timespec_to_ns(ts_diff));
PER_PAGE_DEBUG("Paged in %ld bytes at 0x%lx from thread %d\n", PER_PAGE_DEBUG("Paged in %ld bytes at 0x%lx from thread %d\n",
perf_test_args.host_page_size, addr, tid); demand_paging_size, addr, tid);
return 0; return 0;
} }
...@@ -108,6 +125,7 @@ static int handle_uffd_page_request(int uffd, uint64_t addr) ...@@ -108,6 +125,7 @@ static int handle_uffd_page_request(int uffd, uint64_t addr)
bool quit_uffd_thread; bool quit_uffd_thread;
struct uffd_handler_args { struct uffd_handler_args {
int uffd_mode;
int uffd; int uffd;
int pipefd; int pipefd;
useconds_t delay; useconds_t delay;
...@@ -169,7 +187,7 @@ static void *uffd_handler_thread_fn(void *arg) ...@@ -169,7 +187,7 @@ static void *uffd_handler_thread_fn(void *arg)
if (r == -1) { if (r == -1) {
if (errno == EAGAIN) if (errno == EAGAIN)
continue; continue;
pr_info("Read of uffd gor errno %d", errno); pr_info("Read of uffd got errno %d\n", errno);
return NULL; return NULL;
} }
...@@ -184,7 +202,7 @@ static void *uffd_handler_thread_fn(void *arg)