/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2021 SUSE LLC * * x86-specific KVM helper functions and structures */ #ifndef KVM_X86_H_ #define KVM_X86_H_ #include "kvm_test.h" #define PAGESIZE 0x1000 #define KVM_GDT_SIZE 32 /* Interrupts */ #define X86_INTR_COUNT 256 #define INTR_ZERODIV 0 #define INTR_DEBUG 1 #define INTR_NMI 2 #define INTR_BREAKPOINT 3 #define INTR_OVERFLOW 4 #define INTR_BOUND_RANGE_EXC 5 #define INTR_BAD_OPCODE 6 #define INTR_DEVICE_ERROR 7 #define INTR_DOUBLE_FAULT 8 #define INTR_INVALID_TSS 10 #define INTR_SEGFAULT 11 #define INTR_STACK_FAULT 12 #define INTR_GPF 13 #define INTR_PAGE_FAULT 14 #define INTR_FPU_ERROR 16 #define INTR_ALIGNMENT_ERROR 17 #define INTR_MACHINE_CHECK 18 #define INTR_SIMD_ERROR 19 #define INTR_VIRT_ERROR 20 #define INTR_CPE 21 #define INTR_HV_INJECTION 28 #define INTR_VMM_COMM 29 #define INTR_SECURITY_ERROR 30 /* Segment descriptor flags */ #define SEGTYPE_LDT 0x02 #define SEGTYPE_TSS 0x09 #define SEGTYPE_TSS_BUSY 0x0b #define SEGTYPE_CALL_GATE 0x0c #define SEGTYPE_INTR_GATE 0x0e #define SEGTYPE_TRAP_GATE 0x0f #define SEGTYPE_RODATA 0x10 #define SEGTYPE_RWDATA 0x12 #define SEGTYPE_STACK 0x16 #define SEGTYPE_CODE 0x1a #define SEGTYPE_MASK 0x1f #define SEGFLAG_NSYSTEM 0x10 #define SEGFLAG_PRESENT 0x80 #define SEGFLAG_CODE64 0x200 #define SEGFLAG_32BIT 0x400 #define SEGFLAG_PAGE_LIMIT 0x800 /* CPUID constants */ #define CPUID_GET_INPUT_RANGE 0x80000000 #define CPUID_GET_EXT_FEATURES 0x80000001 #define CPUID_GET_SVM_FEATURES 0x8000000a /* Model-specific CPU register constants */ #define MSR_SYSENTER_CS 0x174 #define MSR_SYSENTER_ESP 0x175 #define MSR_SYSENTER_EIP 0x176 #define MSR_EFER 0xc0000080 #define MSR_STAR 0xc0000081 #define MSR_LSTAR 0xc0000082 #define MSR_CSTAR 0xc0000083 #define MSR_SFMASK 0xc0000084 #define MSR_FS_BASE 0xc0000100 #define MSR_GS_BASE 0xc0000101 #define MSR_KERNEL_GS_BASE 0xc0000102 #define MSR_VM_CR 0xc0010114 #define MSR_VM_HSAVE_PA 0xc0010117 #define EFER_SCE (1 << 0) /* SYSCALL/SYSRET instructions enabled */ #define EFER_LME (1 << 8) /* CPU is running in 64bit mode */ #define EFER_LMA (1 << 10) /* CPU uses 64bit memory paging (read-only) */ #define EFER_NXE (1 << 11) /* Execute disable bit active */ #define EFER_SVME (1 << 12) /* AMD SVM instructions enabled */ #define VM_CR_DPD (1 << 0) #define VM_CR_R_INIT (1 << 1) #define VM_CR_DIS_A20M (1 << 2) #define VM_CR_LOCK (1 << 3) #define VM_CR_SVMDIS (1 << 4) /* Control register constants */ #define CR4_VME (1 << 0) #define CR4_PVI (1 << 1) #define CR4_TSD (1 << 2) #define CR4_DE (1 << 3) #define CR4_PSE (1 << 4) #define CR4_PAE (1 << 5) #define CR4_MCE (1 << 6) #define CR4_PGE (1 << 7) #define CR4_PCE (1 << 8) #define CR4_OSFXSR (1 << 9) #define CR4_OSXMMEXCPT (1 << 10) #define CR4_UMIP (1 << 11) #define CR4_LA57 (1 << 12) #define CR4_VMXE (1 << 13) #define CR4_SMXE (1 << 14) #define CR4_FSGSBASE (1 << 16) #define CR4_PCIDE (1 << 17) #define CR4_OSXSAVE (1 << 18) #define CR4_KL (1 << 19) #define CR4_SMEP (1 << 20) #define CR4_SMAP (1 << 21) #define CR4_PKE (1 << 22) #define CR4_CET (1 << 23) #define CR4_PKS (1 << 24) struct intr_descriptor { uint16_t offset_lo; uint16_t selector; uint8_t ist; uint8_t flags; #if defined(__x86_64__) uint64_t offset_hi; /* top 16 bits must be set to 0 */ uint16_t padding; #else /* defined(__x86_64__) */ uint16_t offset_hi; #endif /* defined(__x86_64__) */ } __attribute__((__packed__)); struct segment_descriptor { unsigned int limit_lo : 16; unsigned int baseaddr_lo : 24; unsigned int flags_lo : 8; unsigned int limit_hi : 4; unsigned int flags_hi : 4; unsigned int baseaddr_hi : 8; } __attribute__((__packed__)); struct segment_descriptor64 { unsigned int limit_lo : 16; unsigned int baseaddr_lo : 24; unsigned int flags_lo : 8; unsigned int limit_hi : 4; unsigned int flags_hi : 4; uint64_t baseaddr_hi : 40; uint32_t reserved; } __attribute__((__packed__)); struct page_table_entry_pae { unsigned int present: 1; unsigned int writable: 1; unsigned int user_access: 1; unsigned int write_through: 1; unsigned int disable_cache: 1; unsigned int accessed: 1; unsigned int dirty: 1; unsigned int page_type: 1; unsigned int global: 1; unsigned int padding: 3; uint64_t address: 40; unsigned int padding2: 7; unsigned int prot_key: 4; unsigned int noexec: 1; } __attribute__((__packed__)); struct kvm_cpuid { unsigned int eax, ebx, ecx, edx; }; struct kvm_cregs { unsigned long cr0, cr2, cr3, cr4; }; struct kvm_sregs { uint16_t cs, ds, es, fs, gs, ss; }; struct kvm_regs64 { uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp; uint64_t r8, r9, r10, r11, r12, r13, r14, r15; }; extern struct page_table_entry_pae kvm_pagetable[]; extern struct intr_descriptor kvm_idt[X86_INTR_COUNT]; extern struct segment_descriptor kvm_gdt[KVM_GDT_SIZE]; /* Page table helper functions */ uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry); /* Segment descriptor table functions */ void kvm_set_segment_descriptor(struct segment_descriptor *dst, uint64_t baseaddr, uint32_t limit, unsigned int flags); void kvm_parse_segment_descriptor(struct segment_descriptor *src, uint64_t *baseaddr, uint32_t *limit, unsigned int *flags); int kvm_find_free_descriptor(const struct segment_descriptor *table, size_t size); unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, size_t tabsize, void *stack_base); /* Functions for querying CPU info and status */ void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf); void kvm_read_cregs(struct kvm_cregs *buf); void kvm_read_sregs(struct kvm_sregs *buf); uint64_t kvm_rdmsr(unsigned int msr); void kvm_wrmsr(unsigned int msr, uint64_t value); /* Low-level interrupt handlers, DO NOT call directly */ void kvm_handle_bad_exception(void); void kvm_handle_zerodiv(void); void kvm_handle_debug(void); void kvm_handle_nmi(void); void kvm_handle_breakpoint(void); void kvm_handle_overflow(void); void kvm_handle_bound_range_exc(void); void kvm_handle_bad_opcode(void); void kvm_handle_device_error(void); void kvm_handle_double_fault(void); void kvm_handle_invalid_tss(void); void kvm_handle_segfault(void); void kvm_handle_stack_fault(void); void kvm_handle_gpf(void); void kvm_handle_page_fault(void); void kvm_handle_fpu_error(void); void kvm_handle_alignment_error(void); void kvm_handle_machine_check(void); void kvm_handle_simd_error(void); void kvm_handle_virt_error(void); void kvm_handle_cpe(void); void kvm_handle_hv_injection(void); void kvm_handle_vmm_comm(void); void kvm_handle_security_error(void); #endif /* KVM_X86_H_ */