diff --git a/install.sh b/install.sh index b13e8a66..d6864f09 100755 --- a/install.sh +++ b/install.sh @@ -3,6 +3,7 @@ #LINUX_VERSION="5.4.55" LINUX_VERSION="5.7.12" LINUX_VERSION="5.8.12" +LINUX_VERSION="5.11.4" LINUX_URL="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${LINUX_VERSION}.tar.xz" #QEMU_VERSION="4.2.0" diff --git a/patches/kvm/v5.11/0001-merged-kAFL-kvm-patch.patch b/patches/kvm/v5.11/0001-merged-kAFL-kvm-patch.patch new file mode 100644 index 00000000..2e0e0c5d --- /dev/null +++ b/patches/kvm/v5.11/0001-merged-kAFL-kvm-patch.patch @@ -0,0 +1,1449 @@ +From 4566db970d96b5e6777d20f8de91c098855d6343 Mon Sep 17 00:00:00 2001 +From: Sandesh Kenjana Ashok +Date: Mon, 15 Feb 2021 22:51:12 +0100 +Subject: [PATCH] [KVM] VMX PT upstream patch v5.11 +X-Copyright-Info: ############################################################### +X-Copyright-Info: ## +X-Copyright-Info: ## This file is part of Redqueen. +X-Copyright-Info: ## +X-Copyright-Info: ## (C) Sergej Schumilo, 2019 +X-Copyright-Info: ## (C) Cornelius Aschermann, 2019 +X-Copyright-Info: ## +X-Copyright-Info: ## With adaptations by Steffen Schulz +X-Copyright-Info: ## Sandesh Kenjana Ashok +X-Copyright-Info: ## (C) 2021, Intel Corporation +X-Copyright-Info: ## +X-Copyright-Info: ## SPDX-License-Identifier: GPL-2.0-or-later +X-Copyright-Info: ## +X-Copyright-Info: ############################################################### + +Signed-off-by: Sandesh Kenjana Ashok +--- + arch/x86/include/asm/kvm_host.h | 10 + + arch/x86/include/uapi/asm/kvm.h | 6 + + arch/x86/include/uapi/asm/vmx.h | 4 +- + arch/x86/kvm/Kconfig | 6 + + arch/x86/kvm/Makefile | 1 + + arch/x86/kvm/svm/svm.c | 15 + + arch/x86/kvm/vmx/vmx.c | 73 ++- + arch/x86/kvm/vmx/vmx.h | 27 +- + arch/x86/kvm/vmx/vmx_pt.c | 761 ++++++++++++++++++++++++++++++++ + arch/x86/kvm/vmx/vmx_pt.h | 33 ++ + arch/x86/kvm/x86.c | 119 ++++- + include/uapi/linux/kvm.h | 60 +++ + 12 files changed, 1105 insertions(+), 10 deletions(-) + create mode 100644 arch/x86/kvm/vmx/vmx_pt.c + create mode 100644 arch/x86/kvm/vmx/vmx_pt.h + +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 3d6616f6f6ef..3af75fd5c706 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -983,6 +983,10 @@ struct kvm_arch { + + bool disabled_lapic_found; + ++#ifdef CONFIG_KVM_VMX_PT ++ uint64_t printk_addr; ++#endif ++ + bool x2apic_format; + bool x2apic_broadcast_quirk_disabled; + +@@ -1271,6 +1275,12 @@ struct kvm_x86_ops { + + int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq, + uint32_t guest_irq, bool set); ++ ++#ifdef CONFIG_KVM_VMX_PT ++ int (*setup_trace_fd)(struct kvm_vcpu *vcpu); ++ int (*vmx_pt_enabled)(void); ++#endif ++ + void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu); + bool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *vcpu); + +diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h +index 8e76d3701db3..286d5b7a98ae 100644 +--- a/arch/x86/include/uapi/asm/kvm.h ++++ b/arch/x86/include/uapi/asm/kvm.h +@@ -399,6 +399,12 @@ struct kvm_sync_regs { + struct kvm_vcpu_events events; + }; + ++/* vmx_pt */ ++struct vmx_pt_filter_iprs { ++ __u64 a; ++ __u64 b; ++}; ++ + #define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) + #define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) + #define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) +diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h +index ada955c5ebb6..ada7a58382f3 100644 +--- a/arch/x86/include/uapi/asm/vmx.h ++++ b/arch/x86/include/uapi/asm/vmx.h +@@ -89,6 +89,7 @@ + #define EXIT_REASON_XRSTORS 64 + #define EXIT_REASON_UMWAIT 67 + #define EXIT_REASON_TPAUSE 68 ++#define EXIT_REASON_TOPA_FULL 69 + + #define VMX_EXIT_REASONS \ + { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ +@@ -150,7 +151,8 @@ + { EXIT_REASON_XSAVES, "XSAVES" }, \ + { EXIT_REASON_XRSTORS, "XRSTORS" }, \ + { EXIT_REASON_UMWAIT, "UMWAIT" }, \ +- { EXIT_REASON_TPAUSE, "TPAUSE" } ++ { EXIT_REASON_TPAUSE, "TPAUSE" }, \ ++ { EXIT_REASON_TOPA_FULL, "TOPA_FULL" } + + #define VMX_EXIT_REASON_FLAGS \ + { VMX_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" } +diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig +index 7ac592664c52..8c63d3543411 100644 +--- a/arch/x86/kvm/Kconfig ++++ b/arch/x86/kvm/Kconfig +@@ -110,4 +110,10 @@ config KVM_MMU_AUDIT + This option adds a R/W kVM module parameter 'mmu_audit', which allows + auditing of KVM MMU events at runtime. + ++config KVM_VMX_PT ++ bool "KVM extension for Intel Processor Trace" ++ depends on KVM_INTEL ++ help ++ Provides support for Intel Processor Trace in vmx mode. ++ + endif # VIRTUALIZATION +diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile +index 4bd14ab01323..b1107bffac78 100644 +--- a/arch/x86/kvm/Makefile ++++ b/arch/x86/kvm/Makefile +@@ -21,6 +21,7 @@ kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \ + + kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \ + vmx/evmcs.o vmx/nested.o vmx/posted_intr.o ++kvm-intel-$(CONFIG_KVM_VMX_PT) += vmx/vmx_pt.o + kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o svm/sev.o + + obj-$(CONFIG_KVM) += kvm.o +diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c +index 3442d44ca53b..008c3e8f8517 100644 +--- a/arch/x86/kvm/svm/svm.c ++++ b/arch/x86/kvm/svm/svm.c +@@ -4418,6 +4418,16 @@ static int svm_vm_init(struct kvm *kvm) + return 0; + } + ++#ifdef CONFIG_KVM_VMX_PT ++static int setup_trace_fd_stub(struct kvm_vcpu *vcpu){ ++ return -EINVAL; ++} ++static int vmx_pt_is_enabled(void){ ++ /* AMD CPUs do not support Intel PT */ ++ return -EINVAL; ++} ++#endif ++ + static struct kvm_x86_ops svm_x86_ops __initdata = { + .hardware_unsetup = svm_hardware_teardown, + .hardware_enable = svm_hardware_enable, +@@ -4519,6 +4529,11 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { + .pmu_ops = &amd_pmu_ops, + .nested_ops = &svm_nested_ops, + ++#ifdef CONFIG_KVM_VMX_PT ++ .setup_trace_fd = setup_trace_fd_stub, ++ .vmx_pt_enabled = vmx_pt_is_enabled, ++#endif ++ + .deliver_posted_interrupt = svm_deliver_avic_intr, + .dy_apicv_has_pending_interrupt = svm_dy_apicv_has_pending_interrupt, + .update_pi_irte = svm_update_pi_irte, +diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c +index eb69fef57485..1769f3942cec 100644 +--- a/arch/x86/kvm/vmx/vmx.c ++++ b/arch/x86/kvm/vmx/vmx.c +@@ -62,6 +62,10 @@ + #include "vmx.h" + #include "x86.h" + ++#ifdef CONFIG_KVM_VMX_PT ++#include "vmx_pt.h" ++#endif ++ + MODULE_AUTHOR("Qumranet"); + MODULE_LICENSE("GPL"); + +@@ -945,7 +949,7 @@ static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx, + vm_exit_controls_setbit(vmx, exit); + } + +-static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, ++void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, + u64 guest_val, u64 host_val, bool entry_only) + { + int i, j = 0; +@@ -2554,10 +2558,16 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, + vmcs_conf->revision_id = vmx_msr_low; + + vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; +- vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; + vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control; ++#ifdef CONFIG_KVM_VMX_PT ++ vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control | 0x80000; ++ vmcs_conf->vmexit_ctrl = _vmexit_control | 0x1000000; ++ vmcs_conf->vmentry_ctrl = _vmentry_control | 0x20000; ++#else ++ vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; + vmcs_conf->vmexit_ctrl = _vmexit_control; + vmcs_conf->vmentry_ctrl = _vmentry_control; ++#endif + + #if IS_ENABLED(CONFIG_HYPERV) + if (enlightened_vmcs) +@@ -5600,6 +5610,15 @@ static int handle_encls(struct kvm_vcpu *vcpu) + return 1; + } + ++static int handle_topa_main_full(struct kvm_vcpu *vcpu) ++{ ++ /* ++ * Exit to userspace for buffer parsing & reset ++ */ ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_TOPA_MAIN_FULL; ++ return 0; ++} ++ + /* + * The exit handlers return 1 if the exit was handled fully and guest execution + * may resume. Otherwise they set the kvm_run parameter to indicate what needs +@@ -5656,6 +5675,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { + [EXIT_REASON_VMFUNC] = handle_vmx_instruction, + [EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer, + [EXIT_REASON_ENCLS] = handle_encls, ++ [EXIT_REASON_TOPA_FULL] = handle_topa_main_full, + }; + + static const int kvm_vmx_max_exit_handlers = +@@ -6372,11 +6392,21 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu) + static void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu) + { + struct vcpu_vmx *vmx = to_vmx(vcpu); ++#ifdef CONFIG_KVM_VMX_PT ++ bool topa_full = vmx_pt_vmexit(vmx->vmx_pt_config); ++#endif + + if (vmx->exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT) + handle_external_interrupt_irqoff(vcpu); + else if (vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI) + handle_exception_nmi_irqoff(vmx); ++ ++#ifdef CONFIG_KVM_VMX_PT ++ // VMX-PT: Check TOPA status and maybe override exit_reason for user exit ++ if (topa_full) { ++ vmx->exit_reason = EXIT_REASON_TOPA_FULL; ++ } ++#endif + } + + /* +@@ -6655,6 +6685,10 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) + + trace_kvm_entry(vcpu); + ++#ifdef CONFIG_KVM_VMX_PT ++ vmx_pt_vmentry(vmx->vmx_pt_config); ++#endif ++ + if (vmx->ple_window_dirty) { + vmx->ple_window_dirty = false; + vmcs_write32(PLE_WINDOW, vmx->ple_window); +@@ -6817,6 +6851,10 @@ static void vmx_free_vcpu(struct kvm_vcpu *vcpu) + free_vpid(vmx->vpid); + nested_vmx_free_vcpu(vcpu); + free_loaded_vmcs(vmx->loaded_vmcs); ++ ++#ifdef CONFIG_KVM_VMX_PT ++ vmx_pt_destroy(vmx, &(vmx->vmx_pt_config)); ++#endif + } + + static int vmx_create_vcpu(struct kvm_vcpu *vcpu) +@@ -6944,6 +6982,14 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu) + + vmx->ept_pointer = INVALID_PAGE; + ++#ifdef CONFIG_KVM_VMX_PT ++ err = vmx_pt_setup(vmx, &(vmx->vmx_pt_config)); ++ if (err) { ++ printk(KERN_ERR "[VMX-PT] Error in vmx_pt_setup(). Exit.\n"); ++ goto free_vmcs; ++ } ++#endif ++ + return 0; + + free_vmcs: +@@ -7587,6 +7633,16 @@ static int vmx_cpu_dirty_log_size(void) + return enable_pml ? PML_ENTITY_NUM : 0; + } + ++#ifdef CONFIG_KVM_VMX_PT ++static int vmx_pt_setup_fd(struct kvm_vcpu *vcpu){ ++ return vmx_pt_create_fd(to_vmx(vcpu)->vmx_pt_config); ++} ++ ++static int vmx_pt_is_enabled(void){ ++ return vmx_pt_enabled(); ++} ++#endif ++ + static struct kvm_x86_ops vmx_x86_ops __initdata = { + .hardware_unsetup = hardware_unsetup, + +@@ -7699,6 +7755,11 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { + + .update_pi_irte = pi_update_irte, + ++#ifdef CONFIG_KVM_VMX_PT ++ .setup_trace_fd = vmx_pt_setup_fd, ++ .vmx_pt_enabled = vmx_pt_is_enabled, ++#endif ++ + #ifdef CONFIG_X86_64 + .set_hv_timer = vmx_set_hv_timer, + .cancel_hv_timer = vmx_cancel_hv_timer, +@@ -7922,6 +7983,10 @@ static void vmx_exit(void) + synchronize_rcu(); + #endif + ++#ifdef CONFIG_KVM_VMX_PT ++ vmx_pt_exit(); ++#endif ++ + kvm_exit(); + + #if IS_ENABLED(CONFIG_HYPERV) +@@ -8027,6 +8092,10 @@ static int __init vmx_init(void) + if (!enable_ept) + allow_smaller_maxphyaddr = true; + ++#ifdef CONFIG_KVM_VMX_PT ++ vmx_pt_init(); ++#endif ++ + return 0; + } + module_init(vmx_init); +diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h +index 9d3a557949ac..584ee6049052 100644 +--- a/arch/x86/kvm/vmx/vmx.h ++++ b/arch/x86/kvm/vmx/vmx.h +@@ -210,6 +210,10 @@ struct vcpu_vmx { + + u32 secondary_exec_control; + ++#ifdef CONFIG_KVM_VMX_PT ++ struct vcpu_vmx_pt* vmx_pt_config; ++#endif ++ + /* + * loaded_vmcs points to the VMCS currently used in this vcpu. For a + * non-nested (L1) guest, it always points to vmcs01. For a nested +@@ -347,9 +351,10 @@ static inline u8 vmx_get_rvi(void) + return vmcs_read16(GUEST_INTR_STATUS) & 0xff; + } + +-#define BUILD_CONTROLS_SHADOW(lname, uname) \ ++#define BUILD_CONTROLS_SHADOW(lname, uname, mask) \ + static inline void lname##_controls_set(struct vcpu_vmx *vmx, u32 val) \ + { \ ++ val = val | mask; \ + if (vmx->loaded_vmcs->controls_shadow.lname != val) { \ + vmcs_write32(uname, val); \ + vmx->loaded_vmcs->controls_shadow.lname = val; \ +@@ -367,11 +372,16 @@ static inline void lname##_controls_clearbit(struct vcpu_vmx *vmx, u32 val) \ + { \ + lname##_controls_set(vmx, lname##_controls_get(vmx) & ~val); \ + } +-BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS) +-BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS) +-BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL) +-BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL) +-BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL) ++#ifdef CONFIG_KVM_VMX_PT ++BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS, 0x20000ULL) ++BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS, 0x1000000ULL) ++#else ++BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS, 0x0ULL) ++BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS, 0x0ULL) ++#endif ++BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL, 0x0ULL) ++BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL, 0x0ULL) ++BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL, 0x0ULL) + + static inline void vmx_register_cache_reset(struct kvm_vcpu *vcpu) + { +@@ -491,4 +501,9 @@ static inline bool vmx_guest_state_valid(struct kvm_vcpu *vcpu) + + void dump_vmcs(void); + ++#ifdef CONFIG_KVM_VMX_PT ++void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, ++ u64 guest_val, u64 host_val, bool entry_only); ++#endif ++ + #endif /* __KVM_X86_VMX_H */ +diff --git a/arch/x86/kvm/vmx/vmx_pt.c b/arch/x86/kvm/vmx/vmx_pt.c +new file mode 100644 +index 000000000000..66746456312d +--- /dev/null ++++ b/arch/x86/kvm/vmx/vmx_pt.c +@@ -0,0 +1,761 @@ ++/* ++ * This file is part of Redqueen. ++ * ++ * (C) Sergej Schumilo, 2019 ++ * (C) Cornelius Aschermann, 2019 ++ * ++ * With adaptations by Steffen Schulz ++ * (C) 2020, Intel Corporation ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++/* ++ * Kernel AFL Intel PT / VMX Driver (KVM Extension) ++ * vmx_pt enables tracing for kvm vcpus. ++ */ ++ ++#include "vmx.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "vmx_pt.h" ++ ++#define PRINT_FEATURE(msr_val, bit_val, str) \ ++ if(msr_val & bit_val){ PRINT_INFO("\t [*] " str ":"); } \ ++ else { PRINT_INFO("\t [ ] " str ":"); } ++ ++#define HEXDUMP_RANGE 128 ++ ++#define TRACE_TOPA_PMI 0x80000000000000 ++ ++#define TOPA_MASK_OR_TABLE_OFFSET 0x00000000FFFFFF80 ++#define TOPA_OUTPUT_OFFSET 0xFFFFFFFF00000000 ++ ++#define ADDR0_EN BIT(32) ++#define ADDR1_EN BIT(36) ++#define ADDR2_EN BIT(40) ++#define ADDR3_EN BIT(44) ++ ++#define PSB_MASK (0x0 << 24) ++#define TOPA_STOP BIT(4) ++#define TOPA_INT BIT(2) ++#define TOPA_END BIT(0) ++#define TOPA_SIZE_SHIFT 6 ++ ++#define PRINT_INFO(msg) printk(KERN_INFO "[VMX-PT] Info:\t%s\n", (msg)) ++#define PRINT_ERROR(msg) printk(KERN_ERR "[VMX-PT] Error:\t%s\n", (msg)) ++ ++ ++#define TOPA_MAIN_ORDER 9 /* 2MB */ ++#define TOPA_FALLBACK_ORDER 6 /* 256KB */ ++ ++#define TOPA_MAIN_SIZE ((1 << TOPA_MAIN_ORDER)*(1 << PAGE_SHIFT)) ++#define TOPA_FALLBACK_SIZE ((1 << TOPA_FALLBACK_ORDER)*(1 << PAGE_SHIFT)) ++ ++//#define DEBUG ++ ++ ++struct vcpu_vmx_pt { ++ /* hacky vcpu reverse reference */ ++ struct vcpu_vmx *vmx; ++ ++ /* configuration */ ++ u64 ia32_rtit_ctrl_msr; ++ ++ /* IP-Filtering */ ++ bool ia32_rtit_addr_configured[4][2]; ++ u64 ia32_rtit_addr_0[2]; ++ u64 ia32_rtit_addr_1[2]; ++ u64 ia32_rtit_addr_2[2]; ++ u64 ia32_rtit_addr_3[2]; ++ ++ /* CR3-Filtering */ ++ u64 ia32_rtit_cr3_match; ++ ++ /* ToPA */ ++ u64 topa_pt_region; ++ u64 ia32_rtit_output_base; ++ u64 ia32_rtit_output_mask_ptrs; ++ ++ u64 ia32_rtit_output_base_init; ++ u64 ia32_rtit_output_mask_ptrs_init; ++ ++ ++ void* topa_main_buf_virt_addr; ++ void* topa_fallback_buf_virt_addr; ++ void* topa_virt_addr; ++ ++ bool configured; ++ uint8_t cpu; ++ bool reset; ++}; ++ ++struct hypercall_hook_object ++{ ++ u64 rip; ++ struct hlist_node node; ++}; ++ ++u8 enabled; ++ ++#ifdef DEBUG ++static inline void vmx_pt_dump_trace_data(struct vcpu_vmx_pt *vmx_pt); ++#endif ++void vmx_pt_enable(struct vcpu_vmx_pt *vmx_pt_config); ++void vmx_pt_disable(struct vcpu_vmx_pt *vmx_pt_config); ++ ++ ++/*===========================================================================* ++ * vmx/pt userspace interface * ++ *===========================================================================*/ ++ ++static int vmx_pt_release(struct inode *inode, struct file *filp); ++static long vmx_pt_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); ++static int vmx_pt_mmap(struct file *filp, struct vm_area_struct *vma); ++ ++static struct file_operations vmx_pt_fops = { ++ .release = vmx_pt_release, ++ .unlocked_ioctl = vmx_pt_ioctl, ++ .mmap = vmx_pt_mmap, ++ .llseek = noop_llseek, ++}; ++ ++inline static long vmx_pt_get_data_size(struct vcpu_vmx_pt *vmx_pt) ++{ ++ /* get size of traced data */ ++ u64 topa_base = READ_ONCE(vmx_pt->ia32_rtit_output_mask_ptrs); ++ //rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, topa_base); ++ ++ if (topa_base & TOPA_MASK_OR_TABLE_OFFSET) { ++ return (TOPA_MAIN_SIZE + (topa_base>>32)); ++ } ++ return (topa_base>>32); ++} ++ ++static void topa_reset(struct vcpu_vmx_pt *vmx_pt) ++{ ++#ifdef DEBUG ++ if (vmx_pt_get_data_size(vmx_pt) >= TOPA_MAIN_SIZE) ++ printk(KERN_WARNING "Main TOPA buffer exhausted! %lx >= %x?\n", ++ vmx_pt_get_data_size(vmx_pt), TOPA_MAIN_SIZE+TOPA_FALLBACK_SIZE); ++#endif ++ ++ vmx_pt->ia32_rtit_output_base = vmx_pt->ia32_rtit_output_base_init; ++ vmx_pt->ia32_rtit_output_mask_ptrs = vmx_pt->ia32_rtit_output_mask_ptrs_init; ++} ++ ++ ++static long vmx_pt_check_overflow(struct vcpu_vmx_pt *vmx_pt){ ++ /* check for upcoming ToPA entry overflow and / or raised PMI */ ++ long bytes = vmx_pt_get_data_size(vmx_pt); ++ ++ topa_reset(vmx_pt); ++ return bytes; ++} ++ ++static int vmx_pt_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct vcpu_vmx_pt *vmx_pt_config = filp->private_data; ++ ++ /* refrence http://www.makelinux.net/books/lkd2/ch14lev1sec2 */ ++ if ((vma->vm_end-vma->vm_start) > (TOPA_MAIN_SIZE+TOPA_FALLBACK_SIZE)){ ++ return -EINVAL; ++ } ++ vma->vm_flags = (VM_READ | VM_SHARED | VM_DENYWRITE); ++ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ if ((vma->vm_end-vma->vm_start) > (TOPA_MAIN_SIZE)){ ++ if(remap_pfn_range(vma, vma->vm_start, (__pa((void *)vmx_pt_config->topa_main_buf_virt_addr) >> PAGE_SHIFT), TOPA_MAIN_SIZE, vma->vm_page_prot)){ ++ return -EAGAIN; ++ } ++ if(remap_pfn_range(vma, vma->vm_start+TOPA_MAIN_SIZE, (__pa((void *)vmx_pt_config->topa_fallback_buf_virt_addr) >> PAGE_SHIFT), (vma->vm_end-vma->vm_start)-TOPA_MAIN_SIZE, vma->vm_page_prot)){ ++ return -EAGAIN; ++ } ++ } ++ else { ++ if(remap_pfn_range(vma, vma->vm_start, (__pa((void *)vmx_pt_config->topa_main_buf_virt_addr) >> PAGE_SHIFT), (vma->vm_end-vma->vm_start), vma->vm_page_prot)){ ++ return -EAGAIN; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static int vmx_pt_release(struct inode *inode, struct file *filp) ++{ ++#ifdef DEBUG ++ PRINT_INFO("file closed ..."); ++#endif ++ return 0; ++} ++ ++static long vmx_pt_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) ++{ ++ ++ void __user *argp; ++ struct vmx_pt_filter_iprs filter_iprs; ++ ++ struct vcpu_vmx_pt *vmx_pt_config = filp->private_data; ++ bool is_configured = vmx_pt_config->configured; ++ long r = -EINVAL; ++ ++ switch (ioctl) { ++ case KVM_VMX_PT_CONFIGURE_ADDR0: ++ if(!is_configured) { ++ argp = (void __user *)arg; ++ if (!copy_from_user(&filter_iprs, argp, sizeof(filter_iprs))){ ++#ifdef DEBUG ++ printk("Intel PT ADDR0 configured... (%llx / %llx)", filter_iprs.a, filter_iprs.b); ++#endif ++ vmx_pt_config->ia32_rtit_addr_0[0] = filter_iprs.a; ++ vmx_pt_config->ia32_rtit_addr_0[1] = filter_iprs.b; ++ vmx_pt_config->ia32_rtit_addr_configured[0][0] = true; ++ vmx_pt_config->ia32_rtit_addr_configured[0][1] = true; ++ r = 0; ++ } ++ } ++ break; ++ case KVM_VMX_PT_CONFIGURE_ADDR1: ++ if(!is_configured) { ++ argp = (void __user *)arg; ++ if (!copy_from_user(&filter_iprs, argp, sizeof(filter_iprs))){ ++ vmx_pt_config->ia32_rtit_addr_1[0] = filter_iprs.a; ++ vmx_pt_config->ia32_rtit_addr_1[1] = filter_iprs.b; ++ vmx_pt_config->ia32_rtit_addr_configured[1][0] = true; ++ vmx_pt_config->ia32_rtit_addr_configured[1][1] = true; ++ r = 0; ++ } ++ } ++ break; ++ case KVM_VMX_PT_CONFIGURE_ADDR2: ++ if(!is_configured) { ++ argp = (void __user *)arg; ++ if (!copy_from_user(&filter_iprs, argp, sizeof(filter_iprs))){ ++ vmx_pt_config->ia32_rtit_addr_2[0] = filter_iprs.a; ++ vmx_pt_config->ia32_rtit_addr_2[1] = filter_iprs.b; ++ vmx_pt_config->ia32_rtit_addr_configured[2][0] = true; ++ vmx_pt_config->ia32_rtit_addr_configured[2][1] = true; ++ r = 0; ++ } ++ } ++ break; ++ case KVM_VMX_PT_CONFIGURE_ADDR3: ++ if(!is_configured) { ++ argp = (void __user *)arg; ++ if (!copy_from_user(&filter_iprs, argp, sizeof(filter_iprs))){ ++ vmx_pt_config->ia32_rtit_addr_3[0] = filter_iprs.a; ++ vmx_pt_config->ia32_rtit_addr_3[1] = filter_iprs.b; ++ vmx_pt_config->ia32_rtit_addr_configured[3][0] = true; ++ vmx_pt_config->ia32_rtit_addr_configured[3][1] = true; ++ r = 0; ++ } ++ } ++ break; ++ case KVM_VMX_PT_ENABLE_ADDR0: ++ if((!is_configured) && vmx_pt_config->ia32_rtit_addr_configured[0][0] && vmx_pt_config->ia32_rtit_addr_configured[0][1]){ ++#ifdef DEBUG ++ printk("Intel PT ADDR0 enabled..."); ++#endif ++ vmx_pt_config->ia32_rtit_ctrl_msr |= ADDR0_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_ENABLE_ADDR1: ++ if((!is_configured) && vmx_pt_config->ia32_rtit_addr_configured[1][0] && vmx_pt_config->ia32_rtit_addr_configured[1][1]){ ++ vmx_pt_config->ia32_rtit_ctrl_msr |= ADDR1_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_ENABLE_ADDR2: ++ if((!is_configured) && vmx_pt_config->ia32_rtit_addr_configured[2][0] && vmx_pt_config->ia32_rtit_addr_configured[2][1]){ ++ vmx_pt_config->ia32_rtit_ctrl_msr |= ADDR2_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_ENABLE_ADDR3: ++ if((!is_configured) && vmx_pt_config->ia32_rtit_addr_configured[3][0] && vmx_pt_config->ia32_rtit_addr_configured[3][1]){ ++ vmx_pt_config->ia32_rtit_ctrl_msr |= ADDR3_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_DISABLE_ADDR0: ++ if((!is_configured) && (vmx_pt_config->ia32_rtit_ctrl_msr & ADDR0_EN)){ ++ vmx_pt_config->ia32_rtit_ctrl_msr ^= ADDR0_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_DISABLE_ADDR1: ++ if((!is_configured) && (vmx_pt_config->ia32_rtit_ctrl_msr & ADDR1_EN)){ ++ vmx_pt_config->ia32_rtit_ctrl_msr ^= ADDR1_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_DISABLE_ADDR2: ++ if((!is_configured) && (vmx_pt_config->ia32_rtit_ctrl_msr & ADDR2_EN)){ ++ vmx_pt_config->ia32_rtit_ctrl_msr ^= ADDR2_EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_DISABLE_ADDR3: ++ if((!is_configured) && (vmx_pt_config->ia32_rtit_ctrl_msr & ADDR3_EN)){ ++ vmx_pt_config->ia32_rtit_ctrl_msr ^= ADDR3_EN; ++ r = 0; ++ } ++ break; ++ ++ case KVM_VMX_PT_CONFIGURE_CR3: ++#ifdef DEBUG ++ PRINT_INFO("KVM_VMX_PT_CONFIGURE_CR3..."); ++#endif ++ if(!is_configured) { ++ vmx_pt_config->ia32_rtit_cr3_match = arg; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_ENABLE_CR3: ++ /* we just assume that cr3=NULL is invalid... */ ++ if((!is_configured) && vmx_pt_config->ia32_rtit_cr3_match){ ++ vmx_pt_config->ia32_rtit_ctrl_msr |= RTIT_CTL_CR3EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_DISABLE_CR3: ++ if((!is_configured) && (vmx_pt_config->ia32_rtit_ctrl_msr & RTIT_CTL_CR3EN)){ ++ vmx_pt_config->ia32_rtit_ctrl_msr ^= RTIT_CTL_CR3EN; ++ r = 0; ++ } ++ break; ++ case KVM_VMX_PT_ENABLE: ++ if(!is_configured) { ++ //PRINT_INFO("Intel PT enabled..."); ++ vmx_pt_enable(vmx_pt_config); ++ } ++ r = 0; ++ break; ++ case KVM_VMX_PT_DISABLE: ++ if(is_configured) { ++ //PRINT_INFO("Intel PT disabled..."); ++ r = vmx_pt_get_data_size(vmx_pt_config); ++ vmx_pt_disable(vmx_pt_config); ++ vmx_pt_config->reset = true; ++ } ++ else{ ++ r = -EINVAL; ++ } ++ break; ++ case KVM_VMX_PT_CHECK_TOPA_OVERFLOW: ++ r = vmx_pt_check_overflow(vmx_pt_config); ++ if(r){ ++ vmx_pt_config->reset = true; ++#ifdef DEBUG ++ printk("KVM_VMX_PT_CHECK_TOPA_OVERFLOW %ld\n", r); ++#endif ++ } ++ break; ++ case KVM_VMX_PT_GET_TOPA_SIZE: ++ r = (TOPA_MAIN_SIZE + TOPA_FALLBACK_SIZE); ++ break; ++ } ++ return r; ++} ++ ++int vmx_pt_create_fd(struct vcpu_vmx_pt *vmx_pt_config){ ++ if (enabled){ ++ return anon_inode_getfd("vmx-pt", &vmx_pt_fops, vmx_pt_config, O_RDWR | O_CLOEXEC); ++ } ++ else { ++ return 0; ++ } ++} ++ ++/*===========================================================================* ++ ++ * vmx/pt vcpu entry/exit * ++ *===========================================================================*/ ++ ++static inline void vmx_pt_reconfigure_cpu(struct vcpu_vmx_pt *vmx_pt){ ++ ++ uint64_t status; ++ rdmsrl(MSR_IA32_RTIT_STATUS, status); ++ ++ /* reset TOPA stopped/error status */ ++ if (status & RTIT_STATUS_STOPPED) { ++ status ^= (RTIT_STATUS_STOPPED | RTIT_STATUS_ERROR); ++ } ++ ++ /* set PacketByteBnt = 0 */ ++ //status &= 0xFFFE0000FFFFFFFF; ++ status &= ~(RTIT_STATUS_BYTECNT); ++ wrmsrl(MSR_IA32_RTIT_STATUS, status); ++ ++ /* reconfigure CR3-Filtering */ ++ wrmsrl(MSR_IA32_RTIT_CR3_MATCH, vmx_pt->ia32_rtit_cr3_match); ++ ++ /* reconfigure IP-Filtering */ ++ wrmsrl(MSR_IA32_RTIT_ADDR0_A, vmx_pt->ia32_rtit_addr_0[0]); ++ wrmsrl(MSR_IA32_RTIT_ADDR0_B, vmx_pt->ia32_rtit_addr_0[1]); ++ wrmsrl(MSR_IA32_RTIT_ADDR1_A, vmx_pt->ia32_rtit_addr_1[0]); ++ wrmsrl(MSR_IA32_RTIT_ADDR1_B, vmx_pt->ia32_rtit_addr_1[1]); ++ wrmsrl(MSR_IA32_RTIT_ADDR2_A, vmx_pt->ia32_rtit_addr_2[0]); ++ wrmsrl(MSR_IA32_RTIT_ADDR2_B, vmx_pt->ia32_rtit_addr_2[1]); ++ wrmsrl(MSR_IA32_RTIT_ADDR3_A, vmx_pt->ia32_rtit_addr_3[0]); ++ wrmsrl(MSR_IA32_RTIT_ADDR3_B, vmx_pt->ia32_rtit_addr_3[1]); ++ ++ wrmsrl(MSR_IA32_RTIT_OUTPUT_BASE, vmx_pt->ia32_rtit_output_base); ++ wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, vmx_pt->ia32_rtit_output_mask_ptrs); ++ ++} ++ ++#ifdef DEBUG ++static inline void vmx_pt_dump_trace_data(struct vcpu_vmx_pt *vmx_pt){ ++ int i; ++ u64 cksum = 0; ++ PRINT_INFO("Intel PT trace data:"); ++ print_hex_dump(KERN_DEBUG, "ToPA data: ", DUMP_PREFIX_OFFSET, 16, 8, vmx_pt->topa_main_buf_virt_addr, HEXDUMP_RANGE, true); ++ ++ for(i = 0; i < HEXDUMP_RANGE; i++){ ++ cksum += ((u8*)vmx_pt->topa_main_buf_virt_addr)[i]; ++ } ++ printk("CHECKSUM: %lld\n", cksum); ++} ++#endif ++ ++static inline void vmx_pt_check_error(void) ++{ ++ u64 status; ++ rdmsrl(MSR_IA32_RTIT_STATUS, status); ++ ++ /* ++ if (status & RTIT_STATUS_ERROR) { ++ PRINT_INFO("MSR_IA32_RTIT_STATUS -> ERROR?"); ++ } ++ */ ++ ++ if (status & RTIT_STATUS_STOPPED) { ++ PRINT_ERROR("MSR_IA32_RTIT_STATUS -> STOPPED"); ++ } ++ ++ if (status & RTIT_STATUS_BUFFOVF) { ++ PRINT_ERROR("MSR_IA32_RTIT_STATUS -> BUFFOVF"); ++ } ++} ++ ++bool vmx_pt_vmentry(struct vcpu_vmx_pt *vmx_pt) ++{ ++ if (enabled && vmx_pt && vmx_pt->configured) { ++ ++ vmx_pt_check_error(); ++ vmx_pt->cpu = raw_smp_processor_id(); ++ vmx_pt_reconfigure_cpu(vmx_pt); ++ } ++ return false; ++} ++ ++/* return true if ToPA main region is full */ ++bool vmx_pt_vmexit(struct vcpu_vmx_pt *vmx_pt) ++{ ++ if (enabled && (vmx_pt != NULL)) { ++ if (vmx_pt->configured) { ++ if (vmx_pt->cpu != raw_smp_processor_id()) { ++ printk("CPU ERROR! %d != %d", vmx_pt->cpu, raw_smp_processor_id()); ++ } ++ vmx_pt_check_error(); ++ rdmsrl(MSR_IA32_RTIT_OUTPUT_BASE, vmx_pt->ia32_rtit_output_base); ++ rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, vmx_pt->ia32_rtit_output_mask_ptrs); ++ wmb(); ++ ++ if (vmx_pt_get_data_size(vmx_pt) >= TOPA_MAIN_SIZE) { ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++/*===========================================================================* ++ * vmx/pt vcpu setup * ++ *===========================================================================*/ ++ ++static int vmx_pt_setup_topa(struct vcpu_vmx_pt *vmx_pt) ++{ ++ unsigned long main_buffer, fallback_buffer; ++ u64 *topa; ++ int n; ++ ++ main_buffer = __get_free_pages(GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO, TOPA_MAIN_ORDER); ++ if (!main_buffer) { ++ PRINT_ERROR("Cannot allocate main ToPA buffer!"); ++ return -ENOMEM; ++ } ++ ++ fallback_buffer = __get_free_pages(GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO, TOPA_FALLBACK_ORDER); ++ if (!fallback_buffer) { ++ PRINT_ERROR("Cannot allocate fallback ToPA buffer!"); ++ goto free_topa_buffer1; ++ } ++ ++ topa = (u64 *)__get_free_page(GFP_KERNEL|__GFP_ZERO); ++ if (!topa) { ++ PRINT_ERROR("Cannot allocate ToPA table!"); ++ goto free_topa_buffer2; ++ } ++ ++ memset((u64 *)main_buffer, 0x0, TOPA_MAIN_SIZE); ++ memset((u64 *)fallback_buffer, 0x0, TOPA_FALLBACK_SIZE); ++ ++ /* VMX / PT ToPA ++ * +---------------------------------------+ ++ * |ToPA Entry_A (TOPA_ORDER/2, INT) | <------------------------\ (1. start tracing, send LVT PMI if this region is full) ++ * |ToPA Entry_B (TOPA_ORDER/2) [Fallback] | ptr to intial ToPA entry | (2. fallback area) ++ * |Topa Entry_C (PTR, END) |--------------------------/ (3. force tracing stop, ptr to Entry_A) ++ * +---------------------------------------+ ++ */ ++ ++ n = 0; ++ topa[n++] = (u64)__pa(main_buffer) | (TOPA_MAIN_ORDER << TOPA_SIZE_SHIFT) | TOPA_INT; ++ topa[n++] = (u64)__pa(fallback_buffer) | (TOPA_FALLBACK_ORDER << TOPA_SIZE_SHIFT) | TOPA_STOP; ++ topa[n] = (u64)__pa(topa) | TOPA_END; ++ ++ vmx_pt->topa_pt_region = (u64)topa; ++ vmx_pt->ia32_rtit_output_base = __pa(topa); ++ vmx_pt->ia32_rtit_output_mask_ptrs = 0x7fLL; ++ ++ vmx_pt->ia32_rtit_output_base_init = __pa(topa); ++ vmx_pt->ia32_rtit_output_mask_ptrs_init = 0x7fLL; ++ ++ vmx_pt->topa_main_buf_virt_addr = (void*)main_buffer; ++ vmx_pt->topa_fallback_buf_virt_addr = (void*)fallback_buffer; ++ vmx_pt->topa_virt_addr = (void*)topa; ++ ++ vmx_pt->reset = true; ++ ++ return 0; ++ ++ free_topa_buffer2: ++ free_pages(fallback_buffer, TOPA_FALLBACK_ORDER); ++ free_topa_buffer1: ++ free_pages(main_buffer, TOPA_MAIN_ORDER); ++ return -ENOMEM; ++} ++ ++#ifdef DEBUG ++static void vmx_pt_print_msrs(u64 ia32_rtit_ctrl_msr){ ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_TRACEEN, "RTIT_CTL_TRACEEN"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_OS, "RTIT_CTL_OS"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_USR, "RTIT_CTL_USR"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_TOPA, "RTIT_CTL_TOPA"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_BRANCH_EN, "RTIT_CTL_BRANCH_EN"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_CR3EN, "RTIT_CTL_CR3EN"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_MTC_EN, "RTIT_CTL_MTC_EN"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, RTIT_CTL_TSC_EN, "RTIT_CTL_TSC_EN"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, ADDR0_EN, "ADDR0_CFG"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, ADDR1_EN, "ADDR1_CFG"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, ADDR2_EN, "ADDR2_CFG"); ++ PRINT_FEATURE(ia32_rtit_ctrl_msr, ADDR3_EN, "ADDR3_CFG"); ++} ++#endif ++ ++static inline void vmx_pt_setup_msrs(struct vcpu_vmx_pt *vmx_pt){ ++ /* Disable: MTCEn, TSCEn, DisRTC, CYCEn, TraceEN ++ * Enable: OS, CR3Filtering, ToPA, BranchEN ++ */ ++ int i; ++ ++ //vmx_pt->ia32_rtit_ctrl_msr = 0ULL; ++ WRITE_ONCE(vmx_pt->ia32_rtit_ctrl_msr, (!RTIT_CTL_TRACEEN) | RTIT_CTL_OS | RTIT_CTL_USR | RTIT_CTL_TOPA | RTIT_CTL_BRANCH_EN | RTIT_CTL_DISRETC | PSB_MASK); ++ //vmx_pt->ia32_rtit_ctrl_msr = (!RTIT_CTL_TRACEEN) | RTIT_CTL_OS | RTIT_CTL_USR | RTIT_CTL_TOPA | RTIT_CTL_BRANCH_EN | RTIT_CTL_DISRETC | RTIT_CTL_PSB_FREQ; ++ ++ for (i = 0; i < 4; i++){ ++ WRITE_ONCE(vmx_pt->ia32_rtit_addr_configured[i][0], false); ++ WRITE_ONCE(vmx_pt->ia32_rtit_addr_configured[i][1], false); ++ } ++ ++ vmx_pt->ia32_rtit_addr_0[0] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_0[1] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_1[0] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_1[1] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_2[0] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_2[1] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_3[0] = (u64)NULL; ++ vmx_pt->ia32_rtit_addr_3[1] = (u64)NULL; ++ ++ vmx_pt->ia32_rtit_cr3_match = (u64)NULL; ++} ++ ++static inline void vmx_pt_setup_vmx_autoload_msr(struct vcpu_vmx_pt *vmx_pt_config, bool enable_vmx_pt){ ++ u64 guest_val, host_val; ++ host_val = READ_ONCE(vmx_pt_config->ia32_rtit_ctrl_msr); ++ ++ /* check and unset IA32_RTIT_CTL_MSR.TraceEn for host msr */ ++ if (host_val & RTIT_CTL_TRACEEN){ ++ host_val ^= RTIT_CTL_TRACEEN; ++ } ++ ++ guest_val = host_val; ++ if(enable_vmx_pt) ++ guest_val |= RTIT_CTL_TRACEEN; ++ ++#ifdef DEBUG ++ printk("GUEST: %llx\n", guest_val); ++ PRINT_INFO("MSR_IA32_RTIT_CTL guest features:"); ++ vmx_pt_print_msrs(guest_val); ++ PRINT_INFO("MSR_IA32_RTIT_CTL host features:"); ++ vmx_pt_print_msrs(host_val); ++#endif ++ add_atomic_switch_msr(vmx_pt_config->vmx, MSR_IA32_RTIT_CTL, guest_val, host_val, false); ++} ++ ++void vmx_pt_enable(struct vcpu_vmx_pt *vmx_pt_config){ ++ if (!vmx_pt_config->configured){ ++ vmx_pt_config->configured = true; ++ vmx_pt_setup_vmx_autoload_msr(vmx_pt_config, true); ++ } ++} ++ ++void vmx_pt_disable(struct vcpu_vmx_pt *vmx_pt_config){ ++ if (vmx_pt_config->configured){ ++ vmx_pt_config->configured = false; ++ vmx_pt_setup_vmx_autoload_msr(vmx_pt_config, false); ++ wmb(); ++ //vmx_pt_config->ia32_rtit_output_mask_ptrs = 0x7fLL; ++ //wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, vmx_pt_config->ia32_rtit_output_mask_ptrs); ++ topa_reset(vmx_pt_config); ++ } ++} ++ ++int vmx_pt_setup(struct vcpu_vmx *vmx, struct vcpu_vmx_pt **vmx_pt_config){ ++ int ret_val; ++ if (enabled){ ++ ret_val = 0; ++ *vmx_pt_config = kmalloc(sizeof(struct vcpu_vmx_pt), GFP_KERNEL); ++ (*vmx_pt_config)->vmx = vmx; ++ (*vmx_pt_config)->configured = false; ++ ++ vmx_pt_setup_msrs(*vmx_pt_config); ++ ret_val = vmx_pt_setup_topa(*vmx_pt_config); ++ if (ret_val) ++ goto setup_fail1; ++#ifdef DEBUG ++ PRINT_INFO("Setup finished..."); ++#endif ++ return 0; ++ ++ setup_fail1: ++ PRINT_INFO("ToPA setup failed..."); ++ ++ kfree(*vmx_pt_config); ++ *vmx_pt_config = NULL; ++ return ret_val; ++ } ++ *vmx_pt_config = NULL; ++ return 0; ++} ++ ++void vmx_pt_destroy(struct vcpu_vmx *vmx, struct vcpu_vmx_pt **vmx_pt_config){ ++ u64 value; ++ rdmsrl(MSR_IA32_RTIT_CTL, value); ++#ifdef DEBUG ++ vmx_pt_print_msrs(value); ++ vmx_pt_dump_trace_data(*vmx_pt_config); ++#endif ++ ++ free_pages((u64)(*vmx_pt_config)->topa_main_buf_virt_addr, TOPA_MAIN_ORDER); ++ free_pages((u64)(*vmx_pt_config)->topa_fallback_buf_virt_addr, TOPA_FALLBACK_ORDER); ++ free_page((u64)(*vmx_pt_config)->topa_virt_addr); ++ ++ kfree(*vmx_pt_config); ++ *vmx_pt_config = NULL; ++#ifdef DEBUG ++ PRINT_INFO("Struct freed..."); ++#endif ++} ++ ++/*===========================================================================* ++ * vmx/pt initialization * ++ *===========================================================================*/ ++ ++static int vmx_pt_check_support(void) ++{ ++ /* ++ * Let's assume that all presented logical cpu cores provide the following features: ++ * - Intel PT ++ * - VMX supported tracing ++ * - ToPA support for multiple reagions (otherwise it is hard to prevent ToPA overflows) ++ * - Payloads are stored as IP not as LIP ++ * - ADDRn_CFG = 3 ++ */ ++ unsigned a, b, c, d; ++ //unsigned a1, b1, c1, d1; ++ u64 msr_value; ++ ++ cpuid(0, &a, &b, &c, &d); ++ if (a < 0x14) { ++ PRINT_ERROR("Not enough CPUID support for PT!"); ++ return -EIO; ++ } ++ cpuid_count(0x07, 0, &a, &b, &c, &d); ++ if ((b & BIT(25)) == 0) { ++ PRINT_ERROR("No PT support!"); ++ return -EIO; ++ } ++ cpuid_count(0x14, 0, &a, &b, &c, &d); ++ if (!(c & BIT(0))) { ++ PRINT_ERROR("No ToPA support!"); ++ return -EIO; ++ } ++ ++ if ((c & BIT(31))){ ++ PRINT_ERROR("IP Payloads are LIP!"); ++ return -EIO; ++ } ++ ++ if (!(c & BIT(1))) { ++ PRINT_ERROR("Only one ToPA block supported!"); ++ return -EIO; ++ } ++ ++ if (!(b & BIT(2))) { ++ PRINT_ERROR("No IP-Filtering support!"); ++ return -EIO; ++ } ++ ++ rdmsrl(MSR_IA32_VMX_MISC, msr_value); ++ if (!(msr_value & BIT(14))){ ++ PRINT_ERROR("VMX operations are not supported in Intel PT tracing mode!"); ++ return -EIO; ++ } ++ ++ /* todo check ADDRn_CFG support */ ++ return 0; ++} ++ ++int vmx_pt_enabled(void) ++{ ++ return (int)enabled; ++} ++ ++void vmx_pt_init(void) ++{ ++ enabled = !vmx_pt_check_support(); ++ if (enabled) { ++ PRINT_INFO("CPU is supported!"); ++ } ++} ++ ++void vmx_pt_exit(void) ++{ ++ PRINT_INFO("Disabled."); ++} +diff --git a/arch/x86/kvm/vmx/vmx_pt.h b/arch/x86/kvm/vmx/vmx_pt.h +new file mode 100644 +index 000000000000..5ee14151ded2 +--- /dev/null ++++ b/arch/x86/kvm/vmx/vmx_pt.h +@@ -0,0 +1,33 @@ ++/* ++ * This file is part of Redqueen. ++ * ++ * (C) Sergej Schumilo, 2019 ++ * (C) Cornelius Aschermann, 2019 ++ * ++ * With adaptations by Steffen Schulz ++ * (C) 2020, Intel Corporation ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ */ ++ ++#ifndef __VMX_PT_H__ ++#define __VMX_PT_H__ ++ ++#include "vmx.h" ++ ++struct vcpu_vmx_pt; ++ ++int vmx_pt_create_fd(struct vcpu_vmx_pt *vmx_pt_config); ++ ++bool vmx_pt_vmentry(struct vcpu_vmx_pt *vmx_pt); ++bool vmx_pt_vmexit(struct vcpu_vmx_pt *vmx_pt); ++ ++int vmx_pt_setup(struct vcpu_vmx *vmx, struct vcpu_vmx_pt **vmx_pt_config); ++void vmx_pt_destroy(struct vcpu_vmx *vmx, struct vcpu_vmx_pt **vmx_pt_config); ++ ++void vmx_pt_init(void); ++void vmx_pt_exit(void); ++ ++int vmx_pt_enabled(void); ++ ++#endif +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 1b404e4d7dd8..1527b834b4f3 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -3939,6 +3939,12 @@ long kvm_arch_dev_ioctl(struct file *filp, + case KVM_GET_SUPPORTED_HV_CPUID: + r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp); + break; ++#ifdef CONFIG_KVM_VMX_PT ++ case KVM_VMX_PT_SUPPORTED: { ++ r = kvm_x86_ops.vmx_pt_enabled(); ++ break; ++ } ++#endif + default: + r = -EINVAL; + break; +@@ -5031,6 +5037,12 @@ long kvm_arch_vcpu_ioctl(struct file *filp, + case KVM_GET_SUPPORTED_HV_CPUID: + r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp); + break; ++#ifdef CONFIG_KVM_VMX_PT ++ case KVM_VMX_PT_SETUP_FD: { ++ r = kvm_x86_ops.setup_trace_fd(vcpu); ++ break; ++ } ++#endif + default: + r = -EINVAL; + } +@@ -8112,6 +8124,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) + { + unsigned long nr, a0, a1, a2, a3, ret; + int op_64_bit; ++ struct kvm *kvm = vcpu->kvm; + + if (kvm_hv_hypercall_enabled(vcpu->kvm)) + return kvm_hv_hypercall(vcpu); +@@ -8133,6 +8146,107 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) + a3 &= 0xFFFFFFFF; + } + ++#ifdef CONFIG_KVM_VMX_PT ++ /* kAFL Hypercall Interface (ring 0) */ ++ if(kvm_x86_ops.get_cpl(vcpu) == 0) { ++ if(kvm->arch.printk_addr && kvm->arch.printk_addr == kvm_rip_read(vcpu)){ ++ printk("KVM_EXIT_KAFL_PRINTK\n"); ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_PRINTK; ++ return 0; ++ } ++ } ++ ++ /* kAFL Hypercall interface */ ++ if (nr == HYPERCALL_KAFL_RAX_ID) { ++ int r = 0; ++ vcpu->run->hypercall.longmode = op_64_bit; ++ switch(a0){ ++ case (KVM_EXIT_KAFL_ACQUIRE-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_ACQUIRE; ++ break; ++ case (KVM_EXIT_KAFL_GET_PAYLOAD-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_GET_PAYLOAD; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_GET_PROGRAM-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_GET_PROGRAM; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_GET_ARGV-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_GET_ARGV; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_RELEASE-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_RELEASE; ++ break; ++ case (KVM_EXIT_KAFL_SUBMIT_CR3-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_SUBMIT_CR3; ++ vcpu->run->hypercall.args[0] = kvm_read_cr3(vcpu); ++ break; ++ case (KVM_EXIT_KAFL_SUBMIT_PANIC-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_SUBMIT_PANIC; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_SUBMIT_KASAN-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_SUBMIT_KASAN; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_PANIC-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_PANIC; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_KASAN-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_KASAN; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_TIMEOUT-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_TIMEOUT; ++ vcpu->run->hypercall.args[0] = 0; ++ break; ++ case (KVM_EXIT_KAFL_LOCK-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_LOCK; ++ break; ++ case (KVM_EXIT_KAFL_INFO-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_INFO; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_NEXT_PAYLOAD-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_NEXT_PAYLOAD; ++ break; ++ case (KVM_EXIT_KAFL_PRINTF-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_PRINTF; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_PRINTK_ADDR-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_PRINTK_ADDR; ++ kvm->arch.printk_addr = a1 + 0x3; /* 3 bytes vmcall offset */ ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ /* user space only exit reasons */ ++ case (KVM_EXIT_KAFL_USER_RANGE_ADVISE-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_USER_RANGE_ADVISE; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_USER_SUBMIT_MODE-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_USER_SUBMIT_MODE; ++ vcpu->run->hypercall.args[0] = a1; ++ break; ++ case (KVM_EXIT_KAFL_USER_FAST_ACQUIRE-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_USER_FAST_ACQUIRE; ++ vcpu->run->hypercall.args[0] = kvm_read_cr3(vcpu); ++ break; ++ case (KVM_EXIT_KAFL_USER_ABORT-KAFL_EXIT_OFFSET): ++ vcpu->run->exit_reason = KVM_EXIT_KAFL_USER_ABORT; ++ break; ++ default: ++ r = -KVM_EPERM; ++ break; ++ } ++ kvm_skip_emulated_instruction(vcpu); ++ return r; ++ } ++#endif ++ + if (kvm_x86_ops.get_cpl(vcpu) != 0) { + ret = -KVM_EPERM; + goto out; +@@ -8178,7 +8292,6 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) + if (!op_64_bit) + ret = (u32)ret; + kvm_rax_write(vcpu, ret); +- + ++vcpu->stat.hypercalls; + return kvm_skip_emulated_instruction(vcpu); + } +@@ -10524,6 +10637,10 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, + if (!size) + vm_munmap(hva, old_npages * PAGE_SIZE); + ++#ifdef CONFIG_KVM_VMX_PT ++ kvm->arch.printk_addr = 0; ++#endif ++ + return (void __user *)hva; + } + EXPORT_SYMBOL_GPL(__x86_set_memory_region); +diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h +index 374c67875cdb..e741a7509ade 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -218,6 +218,36 @@ struct kvm_hyperv_exit { + + #define KVM_S390_GET_SKEYS_NONE 1 + #define KVM_S390_SKEYS_MAX 1048576 ++#define HYPERCALL_KAFL_RAX_ID 0x01f ++#define KAFL_EXIT_OFFSET 100 ++ ++#define KVM_EXIT_KAFL_ACQUIRE 100 ++#define KVM_EXIT_KAFL_GET_PAYLOAD 101 ++#define KVM_EXIT_KAFL_GET_PROGRAM 102 ++#define KVM_EXIT_KAFL_GET_ARGV 103 ++#define KVM_EXIT_KAFL_RELEASE 104 ++#define KVM_EXIT_KAFL_SUBMIT_CR3 105 ++#define KVM_EXIT_KAFL_SUBMIT_PANIC 106 ++#define KVM_EXIT_KAFL_SUBMIT_KASAN 107 ++#define KVM_EXIT_KAFL_PANIC 108 ++#define KVM_EXIT_KAFL_KASAN 109 ++#define KVM_EXIT_KAFL_LOCK 110 ++#define KVM_EXIT_KAFL_INFO 111 ++#define KVM_EXIT_KAFL_NEXT_PAYLOAD 112 ++#define KVM_EXIT_KAFL_PRINTF 113 ++ ++/* Kernel Printf Debugger */ ++#define KVM_EXIT_KAFL_PRINTK_ADDR 114 ++#define KVM_EXIT_KAFL_PRINTK 115 ++ ++/* user space only exit reasons */ ++#define KVM_EXIT_KAFL_USER_RANGE_ADVISE 116 ++#define KVM_EXIT_KAFL_USER_SUBMIT_MODE 117 ++#define KVM_EXIT_KAFL_USER_FAST_ACQUIRE 118 ++#define KVM_EXIT_KAFL_TOPA_MAIN_FULL 119 ++#define KVM_EXIT_KAFL_USER_ABORT 120 ++#define KVM_EXIT_KAFL_TIMEOUT 121 ++ + + #define KVM_EXIT_UNKNOWN 0 + #define KVM_EXIT_EXCEPTION 1 +@@ -1766,4 +1796,34 @@ struct kvm_dirty_gfn { + __u64 offset; + }; + ++/* ++ * ioctls for vmx_pt fds ++ */ ++#define KVM_VMX_PT_SETUP_FD _IO(KVMIO, 0xd0) /* apply vmx_pt fd (via vcpu fd ioctl)*/ ++#define KVM_VMX_PT_CONFIGURE_ADDR0 _IOW(KVMIO, 0xd1, __u64) /* configure IP-filtering for addr0_a & addr0_b */ ++#define KVM_VMX_PT_CONFIGURE_ADDR1 _IOW(KVMIO, 0xd2, __u64) /* configure IP-filtering for addr1_a & addr1_b */ ++#define KVM_VMX_PT_CONFIGURE_ADDR2 _IOW(KVMIO, 0xd3, __u64) /* configure IP-filtering for addr2_a & addr2_b */ ++#define KVM_VMX_PT_CONFIGURE_ADDR3 _IOW(KVMIO, 0xd4, __u64) /* configure IP-filtering for addr3_a & addr3_b */ ++ ++#define KVM_VMX_PT_CONFIGURE_CR3 _IOW(KVMIO, 0xd5, __u64) /* setup CR3 filtering value */ ++#define KVM_VMX_PT_ENABLE _IO(KVMIO, 0xd6) /* enable and lock configuration */ ++#define KVM_VMX_PT_GET_TOPA_SIZE _IOR(KVMIO, 0xd7, __u32) /* get defined ToPA size */ ++#define KVM_VMX_PT_DISABLE _IO(KVMIO, 0xd8) /* enable and lock configuration */ ++#define KVM_VMX_PT_CHECK_TOPA_OVERFLOW _IO(KVMIO, 0xd9) /* check for ToPA overflow */ ++ ++#define KVM_VMX_PT_ENABLE_ADDR0 _IO(KVMIO, 0xaa) /* enable IP-filtering for addr0 */ ++#define KVM_VMX_PT_ENABLE_ADDR1 _IO(KVMIO, 0xab) /* enable IP-filtering for addr1 */ ++#define KVM_VMX_PT_ENABLE_ADDR2 _IO(KVMIO, 0xac) /* enable IP-filtering for addr2 */ ++#define KVM_VMX_PT_ENABLE_ADDR3 _IO(KVMIO, 0xad) /* enable IP-filtering for addr3 */ ++ ++#define KVM_VMX_PT_DISABLE_ADDR0 _IO(KVMIO, 0xae) /* disable IP-filtering for addr0 */ ++#define KVM_VMX_PT_DISABLE_ADDR1 _IO(KVMIO, 0xaf) /* disable IP-filtering for addr1 */ ++#define KVM_VMX_PT_DISABLE_ADDR2 _IO(KVMIO, 0xe0) /* disable IP-filtering for addr2 */ ++#define KVM_VMX_PT_DISABLE_ADDR3 _IO(KVMIO, 0xe1) /* disable IP-filtering for addr3 */ ++ ++#define KVM_VMX_PT_ENABLE_CR3 _IO(KVMIO, 0xe2) /* enable CR3 filtering */ ++#define KVM_VMX_PT_DISABLE_CR3 _IO(KVMIO, 0xe3) /* disable CR3 filtering */ ++ ++#define KVM_VMX_PT_SUPPORTED _IO(KVMIO, 0xe4) ++ + #endif /* __LINUX_KVM_H */ +-- +2.25.1 + diff --git a/sha256sums.lst b/sha256sums.lst index 2c8b479e..60857c11 100644 --- a/sha256sums.lst +++ b/sha256sums.lst @@ -4,3 +4,4 @@ cc0b3fd38e80efdac3d8501b7e4670912f5acf345e0f07c4822210c3de4bf940 linux-5.4.55.t 2f13a92a0fa5c8b69ff0796b59b86b080bbb92ebad5d301a7724dd06b5e78cb6 qemu-5.0.0.tar.xz d3481d4108ce211a053ef15be69af1bdd9dde1510fda80d92be0f6c3e98768f0 qemu-4.2.0.tar.xz 02ff5aa5e63fc7f119341e915a811c5346ba468cc485546e2d9b15abf03f8a52 linux-5.8.12.tar.xz +88e59fafc9653cb7eef501cef3eda677843027735fd11325a75e353b10770dc5 linux-5.11.4.tar.xz