1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Helpers used for nested SVM testing 4 * Largely inspired from KVM unit test svm.c 5 * 6 * Copyright (C) 2020, Red Hat, Inc. 7 */ 8 9 #include "test_util.h" 10 #include "kvm_util.h" 11 #include "processor.h" 12 #include "svm_util.h" 13 14 #define SEV_DEV_PATH "/dev/sev" 15 16 /* Allocate memory regions for nested SVM tests. 17 * 18 * Input Args: 19 * vm - The VM to allocate guest-virtual addresses in. 20 * 21 * Output Args: 22 * p_svm_gva - The guest virtual address for the struct svm_test_data. 23 * 24 * Return: 25 * Pointer to structure with the addresses of the SVM areas. 26 */ 27 struct svm_test_data * 28 vcpu_alloc_svm(struct kvm_vm *vm, gva_t *p_svm_gva) 29 { 30 gva_t svm_gva = vm_alloc_page(vm); 31 struct svm_test_data *svm = addr_gva2hva(vm, svm_gva); 32 33 svm->vmcb = (void *)vm_alloc_page(vm); 34 svm->vmcb_hva = addr_gva2hva(vm, (uintptr_t)svm->vmcb); 35 svm->vmcb_gpa = addr_gva2gpa(vm, (uintptr_t)svm->vmcb); 36 37 svm->save_area = (void *)vm_alloc_page(vm); 38 svm->save_area_hva = addr_gva2hva(vm, (uintptr_t)svm->save_area); 39 svm->save_area_gpa = addr_gva2gpa(vm, (uintptr_t)svm->save_area); 40 41 svm->msr = (void *)vm_alloc_page(vm); 42 svm->msr_hva = addr_gva2hva(vm, (uintptr_t)svm->msr); 43 svm->msr_gpa = addr_gva2gpa(vm, (uintptr_t)svm->msr); 44 memset(svm->msr_hva, 0, getpagesize()); 45 46 svm->stack = (void *)vm_alloc_stack(vm, 1); 47 48 if (vm->stage2_mmu.pgd_created) 49 svm->ncr3_gpa = vm->stage2_mmu.pgd; 50 51 *p_svm_gva = svm_gva; 52 return svm; 53 } 54 55 static void vmcb_set_seg(struct vmcb_seg *seg, u16 selector, 56 u64 base, u32 limit, u32 attr) 57 { 58 seg->selector = selector; 59 seg->attrib = attr; 60 seg->limit = limit; 61 seg->base = base; 62 } 63 64 void vm_enable_npt(struct kvm_vm *vm) 65 { 66 struct pte_masks pte_masks; 67 68 TEST_ASSERT(kvm_cpu_has_npt(), "KVM doesn't supported nested NPT"); 69 70 /* 71 * NPTs use the same PTE format, but deliberately drop the C-bit as the 72 * per-VM shared vs. private information is only meant for stage-1. 73 */ 74 pte_masks = vm->mmu.arch.pte_masks; 75 pte_masks.c = 0; 76 77 /* NPT walks are treated as user accesses, so set the 'user' bit. */ 78 pte_masks.always_set = pte_masks.user; 79 80 tdp_mmu_init(vm, vm->mmu.pgtable_levels, &pte_masks); 81 } 82 83 void generic_svm_setup(struct svm_test_data *svm, void *guest_rip) 84 { 85 struct vmcb *vmcb = svm->vmcb; 86 u64 vmcb_gpa = svm->vmcb_gpa; 87 struct vmcb_save_area *save = &vmcb->save; 88 struct vmcb_control_area *ctrl = &vmcb->control; 89 u32 data_seg_attr = 3 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 90 | SVM_SELECTOR_DB_MASK | SVM_SELECTOR_G_MASK; 91 u32 code_seg_attr = 9 | SVM_SELECTOR_S_MASK | SVM_SELECTOR_P_MASK 92 | SVM_SELECTOR_L_MASK | SVM_SELECTOR_G_MASK; 93 u64 efer; 94 95 efer = rdmsr(MSR_EFER); 96 wrmsr(MSR_EFER, efer | EFER_SVME); 97 wrmsr(MSR_VM_HSAVE_PA, svm->save_area_gpa); 98 99 memset(vmcb, 0, sizeof(*vmcb)); 100 asm volatile ("vmsave %0\n\t" : : "a" (vmcb_gpa) : "memory"); 101 vmcb_set_seg(&save->es, get_es(), 0, -1U, data_seg_attr); 102 vmcb_set_seg(&save->cs, get_cs(), 0, -1U, code_seg_attr); 103 vmcb_set_seg(&save->ss, get_ss(), 0, -1U, data_seg_attr); 104 vmcb_set_seg(&save->ds, get_ds(), 0, -1U, data_seg_attr); 105 vmcb_set_seg(&save->gdtr, 0, get_gdt().address, get_gdt().size, 0); 106 vmcb_set_seg(&save->idtr, 0, get_idt().address, get_idt().size, 0); 107 108 ctrl->asid = 1; 109 save->cpl = 0; 110 save->efer = rdmsr(MSR_EFER); 111 asm volatile ("mov %%cr4, %0" : "=r"(save->cr4) : : "memory"); 112 asm volatile ("mov %%cr3, %0" : "=r"(save->cr3) : : "memory"); 113 asm volatile ("mov %%cr0, %0" : "=r"(save->cr0) : : "memory"); 114 asm volatile ("mov %%dr7, %0" : "=r"(save->dr7) : : "memory"); 115 asm volatile ("mov %%dr6, %0" : "=r"(save->dr6) : : "memory"); 116 asm volatile ("mov %%cr2, %0" : "=r"(save->cr2) : : "memory"); 117 save->g_pat = rdmsr(MSR_IA32_CR_PAT); 118 save->dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR); 119 ctrl->intercept = (1ULL << INTERCEPT_VMRUN) | 120 (1ULL << INTERCEPT_VMMCALL); 121 ctrl->msrpm_base_pa = svm->msr_gpa; 122 123 vmcb->save.rip = (u64)guest_rip; 124 vmcb->save.rsp = (u64)svm->stack; 125 guest_regs.rdi = (u64)svm; 126 127 if (svm->ncr3_gpa) { 128 ctrl->misc_ctl |= SVM_MISC_ENABLE_NP; 129 ctrl->nested_cr3 = svm->ncr3_gpa; 130 } 131 } 132 133 /* 134 * save/restore 64-bit general registers except rax, rip, rsp 135 * which are directly handed through the VMCB guest processor state 136 */ 137 #define SVM_SWITCH_GPRS_ASM \ 138 GUEST_SWITCH_GPR_ASM(rbx) \ 139 GUEST_SWITCH_GPR_ASM(rcx) \ 140 GUEST_SWITCH_GPR_ASM(rdx) \ 141 GUEST_SWITCH_GPR_ASM(rbp) \ 142 GUEST_SWITCH_GPR_ASM(rsi) \ 143 GUEST_SWITCH_GPR_ASM(rdi) \ 144 GUEST_SWITCH_GPR_ASM(r8) \ 145 GUEST_SWITCH_GPR_ASM(r9) \ 146 GUEST_SWITCH_GPR_ASM(r10) \ 147 GUEST_SWITCH_GPR_ASM(r11) \ 148 GUEST_SWITCH_GPR_ASM(r12) \ 149 GUEST_SWITCH_GPR_ASM(r13) \ 150 GUEST_SWITCH_GPR_ASM(r14) \ 151 GUEST_SWITCH_GPR_ASM(r15) 152 153 /* 154 * selftests do not use interrupts so we dropped clgi/sti/cli/stgi 155 * for now. Registers involved in SVM_SWITCH_GPRS_ASM are eventually 156 * unmodified so they do not need to be in the clobber list. 157 */ 158 void run_guest(struct vmcb *vmcb, u64 vmcb_gpa) 159 { 160 asm volatile ( 161 "vmload %[vmcb_gpa]\n\t" 162 "mov " GUEST_REG(rflags) ", %%r15\n\t" 163 "mov %%r15, %[vmcb_rflags]\n\t" 164 "mov " GUEST_REG(rax) ", %%r15\n\t" 165 "mov %%r15, %[vmcb_rax]\n\t" 166 SVM_SWITCH_GPRS_ASM 167 "vmrun %[vmcb_gpa]\n\t" 168 SVM_SWITCH_GPRS_ASM 169 "mov %[vmcb_rflags], %%r15\n\t" 170 "mov %%r15, " GUEST_REG(rflags) "\n\t" 171 "mov %[vmcb_rax], %%r15\n\t" // rax 172 "mov %%r15, " GUEST_REG(rax) "\n\t" 173 "vmsave %[vmcb_gpa]\n\t" 174 : [vmcb_rflags] "+m" (vmcb->save.rflags), 175 [vmcb_rax] "+m" (vmcb->save.rax) 176 : [vmcb_gpa] "a" (vmcb_gpa), 177 GUEST_REGS_OFFSETS 178 : "r15", "memory"); 179 } 180 181 /* 182 * Open SEV_DEV_PATH if available, otherwise exit the entire program. 183 * 184 * Return: 185 * The opened file descriptor of /dev/sev. 186 */ 187 int open_sev_dev_path_or_exit(void) 188 { 189 return open_path_or_exit(SEV_DEV_PATH, 0); 190 } 191