1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker * Copyright (C) 2021 SUSE LLC <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker *
5*49cdfc7eSAndroid Build Coastguard Worker * x86-specific KVM helper functions
6*49cdfc7eSAndroid Build Coastguard Worker */
7*49cdfc7eSAndroid Build Coastguard Worker
8*49cdfc7eSAndroid Build Coastguard Worker #include "kvm_x86_svm.h"
9*49cdfc7eSAndroid Build Coastguard Worker
10*49cdfc7eSAndroid Build Coastguard Worker void kvm_svm_guest_entry(void);
11*49cdfc7eSAndroid Build Coastguard Worker
12*49cdfc7eSAndroid Build Coastguard Worker struct kvm_interrupt_frame {
13*49cdfc7eSAndroid Build Coastguard Worker uintptr_t eip, cs, eflags, esp, ss;
14*49cdfc7eSAndroid Build Coastguard Worker };
15*49cdfc7eSAndroid Build Coastguard Worker
16*49cdfc7eSAndroid Build Coastguard Worker const char *tst_interrupt_names[INTERRUPT_COUNT] = {
17*49cdfc7eSAndroid Build Coastguard Worker "Division by zero",
18*49cdfc7eSAndroid Build Coastguard Worker "Debug interrupt",
19*49cdfc7eSAndroid Build Coastguard Worker "Non-maskable interrupt",
20*49cdfc7eSAndroid Build Coastguard Worker "Breakpoint",
21*49cdfc7eSAndroid Build Coastguard Worker "Arithmetic overflow",
22*49cdfc7eSAndroid Build Coastguard Worker "Bound range exception",
23*49cdfc7eSAndroid Build Coastguard Worker "Illegal instruction error",
24*49cdfc7eSAndroid Build Coastguard Worker "Device not available error",
25*49cdfc7eSAndroid Build Coastguard Worker "Double fault",
26*49cdfc7eSAndroid Build Coastguard Worker NULL,
27*49cdfc7eSAndroid Build Coastguard Worker "Invalid TSS error",
28*49cdfc7eSAndroid Build Coastguard Worker "Segment not present error",
29*49cdfc7eSAndroid Build Coastguard Worker "Stack segment fault",
30*49cdfc7eSAndroid Build Coastguard Worker "General protection fault",
31*49cdfc7eSAndroid Build Coastguard Worker "Page fault",
32*49cdfc7eSAndroid Build Coastguard Worker NULL,
33*49cdfc7eSAndroid Build Coastguard Worker "Floating point exception",
34*49cdfc7eSAndroid Build Coastguard Worker "Alignment error",
35*49cdfc7eSAndroid Build Coastguard Worker "Machine check exception",
36*49cdfc7eSAndroid Build Coastguard Worker "SIMD floating point exception",
37*49cdfc7eSAndroid Build Coastguard Worker "Virtualization exception",
38*49cdfc7eSAndroid Build Coastguard Worker "Control protection exception",
39*49cdfc7eSAndroid Build Coastguard Worker NULL,
40*49cdfc7eSAndroid Build Coastguard Worker NULL,
41*49cdfc7eSAndroid Build Coastguard Worker NULL,
42*49cdfc7eSAndroid Build Coastguard Worker NULL,
43*49cdfc7eSAndroid Build Coastguard Worker NULL,
44*49cdfc7eSAndroid Build Coastguard Worker NULL,
45*49cdfc7eSAndroid Build Coastguard Worker "Hypervisor injection exception",
46*49cdfc7eSAndroid Build Coastguard Worker "VMM communication exception",
47*49cdfc7eSAndroid Build Coastguard Worker "Security exception",
48*49cdfc7eSAndroid Build Coastguard Worker NULL
49*49cdfc7eSAndroid Build Coastguard Worker };
50*49cdfc7eSAndroid Build Coastguard Worker
51*49cdfc7eSAndroid Build Coastguard Worker static uintptr_t intr_handlers[] = {
52*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_zerodiv,
53*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_debug,
54*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_nmi,
55*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_breakpoint,
56*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_overflow,
57*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bound_range_exc,
58*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_opcode,
59*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_device_error,
60*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_double_fault,
61*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
62*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_invalid_tss,
63*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_segfault,
64*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_stack_fault,
65*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_gpf,
66*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_page_fault,
67*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
68*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_fpu_error,
69*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_alignment_error,
70*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_machine_check,
71*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_simd_error,
72*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_virt_error,
73*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_cpe,
74*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
75*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
76*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
77*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
78*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
79*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
80*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_hv_injection,
81*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_vmm_comm,
82*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_security_error,
83*49cdfc7eSAndroid Build Coastguard Worker (uintptr_t)kvm_handle_bad_exception,
84*49cdfc7eSAndroid Build Coastguard Worker 0
85*49cdfc7eSAndroid Build Coastguard Worker };
86*49cdfc7eSAndroid Build Coastguard Worker
kvm_set_intr_handler(unsigned int id,uintptr_t func)87*49cdfc7eSAndroid Build Coastguard Worker static void kvm_set_intr_handler(unsigned int id, uintptr_t func)
88*49cdfc7eSAndroid Build Coastguard Worker {
89*49cdfc7eSAndroid Build Coastguard Worker memset(kvm_idt + id, 0, sizeof(kvm_idt[0]));
90*49cdfc7eSAndroid Build Coastguard Worker kvm_idt[id].offset_lo = func & 0xffff;
91*49cdfc7eSAndroid Build Coastguard Worker kvm_idt[id].offset_hi = func >> 16;
92*49cdfc7eSAndroid Build Coastguard Worker kvm_idt[id].selector = 8;
93*49cdfc7eSAndroid Build Coastguard Worker kvm_idt[id].flags = 0x8f; /* type = 0xf, P = 1 */
94*49cdfc7eSAndroid Build Coastguard Worker }
95*49cdfc7eSAndroid Build Coastguard Worker
kvm_init_interrupts(void)96*49cdfc7eSAndroid Build Coastguard Worker void kvm_init_interrupts(void)
97*49cdfc7eSAndroid Build Coastguard Worker {
98*49cdfc7eSAndroid Build Coastguard Worker int i;
99*49cdfc7eSAndroid Build Coastguard Worker
100*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; intr_handlers[i]; i++)
101*49cdfc7eSAndroid Build Coastguard Worker kvm_set_intr_handler(i, intr_handlers[i]);
102*49cdfc7eSAndroid Build Coastguard Worker
103*49cdfc7eSAndroid Build Coastguard Worker for (; i < X86_INTR_COUNT; i++)
104*49cdfc7eSAndroid Build Coastguard Worker kvm_set_intr_handler(i, (uintptr_t)kvm_handle_bad_exception);
105*49cdfc7eSAndroid Build Coastguard Worker }
106*49cdfc7eSAndroid Build Coastguard Worker
kvm_get_page_address_pae(const struct page_table_entry_pae * entry)107*49cdfc7eSAndroid Build Coastguard Worker uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry)
108*49cdfc7eSAndroid Build Coastguard Worker {
109*49cdfc7eSAndroid Build Coastguard Worker if (!entry->present)
110*49cdfc7eSAndroid Build Coastguard Worker return 0;
111*49cdfc7eSAndroid Build Coastguard Worker
112*49cdfc7eSAndroid Build Coastguard Worker return entry->address << 12;
113*49cdfc7eSAndroid Build Coastguard Worker }
114*49cdfc7eSAndroid Build Coastguard Worker
115*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
kvm_set_segment_descriptor64(struct segment_descriptor64 * dst,uint64_t baseaddr,uint32_t limit,unsigned int flags)116*49cdfc7eSAndroid Build Coastguard Worker static void kvm_set_segment_descriptor64(struct segment_descriptor64 *dst,
117*49cdfc7eSAndroid Build Coastguard Worker uint64_t baseaddr, uint32_t limit, unsigned int flags)
118*49cdfc7eSAndroid Build Coastguard Worker {
119*49cdfc7eSAndroid Build Coastguard Worker
120*49cdfc7eSAndroid Build Coastguard Worker dst->baseaddr_lo = baseaddr & 0xffffff;
121*49cdfc7eSAndroid Build Coastguard Worker dst->baseaddr_hi = baseaddr >> 24;
122*49cdfc7eSAndroid Build Coastguard Worker dst->limit_lo = limit & 0xffff;
123*49cdfc7eSAndroid Build Coastguard Worker dst->limit_hi = limit >> 16;
124*49cdfc7eSAndroid Build Coastguard Worker dst->flags_lo = flags & 0xff;
125*49cdfc7eSAndroid Build Coastguard Worker dst->flags_hi = (flags >> 8) & 0xf;
126*49cdfc7eSAndroid Build Coastguard Worker dst->reserved = 0;
127*49cdfc7eSAndroid Build Coastguard Worker }
128*49cdfc7eSAndroid Build Coastguard Worker #endif
129*49cdfc7eSAndroid Build Coastguard Worker
kvm_set_segment_descriptor(struct segment_descriptor * dst,uint64_t baseaddr,uint32_t limit,unsigned int flags)130*49cdfc7eSAndroid Build Coastguard Worker void kvm_set_segment_descriptor(struct segment_descriptor *dst,
131*49cdfc7eSAndroid Build Coastguard Worker uint64_t baseaddr, uint32_t limit, unsigned int flags)
132*49cdfc7eSAndroid Build Coastguard Worker {
133*49cdfc7eSAndroid Build Coastguard Worker if (limit >> 20)
134*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "Segment limit out of range");
135*49cdfc7eSAndroid Build Coastguard Worker
136*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
137*49cdfc7eSAndroid Build Coastguard Worker /* System descriptors have double size in 64bit mode */
138*49cdfc7eSAndroid Build Coastguard Worker if (!(flags & SEGFLAG_NSYSTEM)) {
139*49cdfc7eSAndroid Build Coastguard Worker kvm_set_segment_descriptor64((struct segment_descriptor64 *)dst,
140*49cdfc7eSAndroid Build Coastguard Worker baseaddr, limit, flags);
141*49cdfc7eSAndroid Build Coastguard Worker return;
142*49cdfc7eSAndroid Build Coastguard Worker }
143*49cdfc7eSAndroid Build Coastguard Worker #endif
144*49cdfc7eSAndroid Build Coastguard Worker
145*49cdfc7eSAndroid Build Coastguard Worker if (baseaddr >> 32)
146*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "Segment base address out of range");
147*49cdfc7eSAndroid Build Coastguard Worker
148*49cdfc7eSAndroid Build Coastguard Worker dst->baseaddr_lo = baseaddr & 0xffffff;
149*49cdfc7eSAndroid Build Coastguard Worker dst->baseaddr_hi = baseaddr >> 24;
150*49cdfc7eSAndroid Build Coastguard Worker dst->limit_lo = limit & 0xffff;
151*49cdfc7eSAndroid Build Coastguard Worker dst->limit_hi = limit >> 16;
152*49cdfc7eSAndroid Build Coastguard Worker dst->flags_lo = flags & 0xff;
153*49cdfc7eSAndroid Build Coastguard Worker dst->flags_hi = (flags >> 8) & 0xf;
154*49cdfc7eSAndroid Build Coastguard Worker }
155*49cdfc7eSAndroid Build Coastguard Worker
kvm_parse_segment_descriptor(struct segment_descriptor * src,uint64_t * baseaddr,uint32_t * limit,unsigned int * flags)156*49cdfc7eSAndroid Build Coastguard Worker void kvm_parse_segment_descriptor(struct segment_descriptor *src,
157*49cdfc7eSAndroid Build Coastguard Worker uint64_t *baseaddr, uint32_t *limit, unsigned int *flags)
158*49cdfc7eSAndroid Build Coastguard Worker {
159*49cdfc7eSAndroid Build Coastguard Worker if (baseaddr) {
160*49cdfc7eSAndroid Build Coastguard Worker *baseaddr = (((uint64_t)src->baseaddr_hi) << 24) |
161*49cdfc7eSAndroid Build Coastguard Worker src->baseaddr_lo;
162*49cdfc7eSAndroid Build Coastguard Worker }
163*49cdfc7eSAndroid Build Coastguard Worker
164*49cdfc7eSAndroid Build Coastguard Worker if (limit)
165*49cdfc7eSAndroid Build Coastguard Worker *limit = (((uint32_t)src->limit_hi) << 16) | src->limit_lo;
166*49cdfc7eSAndroid Build Coastguard Worker
167*49cdfc7eSAndroid Build Coastguard Worker if (flags)
168*49cdfc7eSAndroid Build Coastguard Worker *flags = (((uint32_t)src->flags_hi) << 8) | src->flags_lo;
169*49cdfc7eSAndroid Build Coastguard Worker }
170*49cdfc7eSAndroid Build Coastguard Worker
kvm_find_free_descriptor(const struct segment_descriptor * table,size_t size)171*49cdfc7eSAndroid Build Coastguard Worker int kvm_find_free_descriptor(const struct segment_descriptor *table,
172*49cdfc7eSAndroid Build Coastguard Worker size_t size)
173*49cdfc7eSAndroid Build Coastguard Worker {
174*49cdfc7eSAndroid Build Coastguard Worker const struct segment_descriptor *ptr;
175*49cdfc7eSAndroid Build Coastguard Worker size_t i;
176*49cdfc7eSAndroid Build Coastguard Worker
177*49cdfc7eSAndroid Build Coastguard Worker for (i = 1, ptr = table + 1; i < size; i++, ptr++) {
178*49cdfc7eSAndroid Build Coastguard Worker if (!(ptr->flags_lo & SEGFLAG_PRESENT))
179*49cdfc7eSAndroid Build Coastguard Worker return i;
180*49cdfc7eSAndroid Build Coastguard Worker
181*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
182*49cdfc7eSAndroid Build Coastguard Worker /* System descriptors have double size in 64bit mode */
183*49cdfc7eSAndroid Build Coastguard Worker if (!(ptr->flags_lo & SEGFLAG_NSYSTEM)) {
184*49cdfc7eSAndroid Build Coastguard Worker ptr++;
185*49cdfc7eSAndroid Build Coastguard Worker i++;
186*49cdfc7eSAndroid Build Coastguard Worker }
187*49cdfc7eSAndroid Build Coastguard Worker #endif
188*49cdfc7eSAndroid Build Coastguard Worker }
189*49cdfc7eSAndroid Build Coastguard Worker
190*49cdfc7eSAndroid Build Coastguard Worker return -1;
191*49cdfc7eSAndroid Build Coastguard Worker }
192*49cdfc7eSAndroid Build Coastguard Worker
kvm_create_stack_descriptor(struct segment_descriptor * table,size_t tabsize,void * stack_base)193*49cdfc7eSAndroid Build Coastguard Worker unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table,
194*49cdfc7eSAndroid Build Coastguard Worker size_t tabsize, void *stack_base)
195*49cdfc7eSAndroid Build Coastguard Worker {
196*49cdfc7eSAndroid Build Coastguard Worker int ret = kvm_find_free_descriptor(table, tabsize);
197*49cdfc7eSAndroid Build Coastguard Worker
198*49cdfc7eSAndroid Build Coastguard Worker if (ret < 0)
199*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "Descriptor table is full");
200*49cdfc7eSAndroid Build Coastguard Worker
201*49cdfc7eSAndroid Build Coastguard Worker kvm_set_segment_descriptor(table + ret, 0,
202*49cdfc7eSAndroid Build Coastguard Worker (((uintptr_t)stack_base) - 1) >> 12, SEGTYPE_STACK |
203*49cdfc7eSAndroid Build Coastguard Worker SEGFLAG_PRESENT | SEGFLAG_32BIT | SEGFLAG_PAGE_LIMIT);
204*49cdfc7eSAndroid Build Coastguard Worker return ret;
205*49cdfc7eSAndroid Build Coastguard Worker }
206*49cdfc7eSAndroid Build Coastguard Worker
kvm_get_cpuid(unsigned int eax,unsigned int ecx,struct kvm_cpuid * buf)207*49cdfc7eSAndroid Build Coastguard Worker void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf)
208*49cdfc7eSAndroid Build Coastguard Worker {
209*49cdfc7eSAndroid Build Coastguard Worker asm (
210*49cdfc7eSAndroid Build Coastguard Worker "cpuid\n"
211*49cdfc7eSAndroid Build Coastguard Worker : "=a" (buf->eax), "=b" (buf->ebx), "=c" (buf->ecx),
212*49cdfc7eSAndroid Build Coastguard Worker "=d" (buf->edx)
213*49cdfc7eSAndroid Build Coastguard Worker : "0" (eax), "2" (ecx)
214*49cdfc7eSAndroid Build Coastguard Worker );
215*49cdfc7eSAndroid Build Coastguard Worker }
216*49cdfc7eSAndroid Build Coastguard Worker
kvm_rdmsr(unsigned int msr)217*49cdfc7eSAndroid Build Coastguard Worker uint64_t kvm_rdmsr(unsigned int msr)
218*49cdfc7eSAndroid Build Coastguard Worker {
219*49cdfc7eSAndroid Build Coastguard Worker unsigned int ret_lo, ret_hi;
220*49cdfc7eSAndroid Build Coastguard Worker
221*49cdfc7eSAndroid Build Coastguard Worker asm (
222*49cdfc7eSAndroid Build Coastguard Worker "rdmsr\n"
223*49cdfc7eSAndroid Build Coastguard Worker : "=a" (ret_lo), "=d" (ret_hi)
224*49cdfc7eSAndroid Build Coastguard Worker : "c" (msr)
225*49cdfc7eSAndroid Build Coastguard Worker );
226*49cdfc7eSAndroid Build Coastguard Worker
227*49cdfc7eSAndroid Build Coastguard Worker return (((uint64_t)ret_hi) << 32) | ret_lo;
228*49cdfc7eSAndroid Build Coastguard Worker }
229*49cdfc7eSAndroid Build Coastguard Worker
kvm_wrmsr(unsigned int msr,uint64_t value)230*49cdfc7eSAndroid Build Coastguard Worker void kvm_wrmsr(unsigned int msr, uint64_t value)
231*49cdfc7eSAndroid Build Coastguard Worker {
232*49cdfc7eSAndroid Build Coastguard Worker uint32_t val_lo = value & 0xffffffff, val_hi = value >> 32;
233*49cdfc7eSAndroid Build Coastguard Worker
234*49cdfc7eSAndroid Build Coastguard Worker asm (
235*49cdfc7eSAndroid Build Coastguard Worker "wrmsr\n"
236*49cdfc7eSAndroid Build Coastguard Worker :
237*49cdfc7eSAndroid Build Coastguard Worker : "a" (val_lo), "d" (val_hi), "c" (msr)
238*49cdfc7eSAndroid Build Coastguard Worker );
239*49cdfc7eSAndroid Build Coastguard Worker }
240*49cdfc7eSAndroid Build Coastguard Worker
kvm_get_interrupt_ip(const struct kvm_interrupt_frame * ifrm)241*49cdfc7eSAndroid Build Coastguard Worker uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm)
242*49cdfc7eSAndroid Build Coastguard Worker {
243*49cdfc7eSAndroid Build Coastguard Worker return ifrm->eip;
244*49cdfc7eSAndroid Build Coastguard Worker }
245*49cdfc7eSAndroid Build Coastguard Worker
kvm_is_svm_supported(void)246*49cdfc7eSAndroid Build Coastguard Worker int kvm_is_svm_supported(void)
247*49cdfc7eSAndroid Build Coastguard Worker {
248*49cdfc7eSAndroid Build Coastguard Worker struct kvm_cpuid buf;
249*49cdfc7eSAndroid Build Coastguard Worker
250*49cdfc7eSAndroid Build Coastguard Worker kvm_get_cpuid(CPUID_GET_INPUT_RANGE, 0, &buf);
251*49cdfc7eSAndroid Build Coastguard Worker
252*49cdfc7eSAndroid Build Coastguard Worker if (buf.eax < CPUID_GET_EXT_FEATURES)
253*49cdfc7eSAndroid Build Coastguard Worker return 0;
254*49cdfc7eSAndroid Build Coastguard Worker
255*49cdfc7eSAndroid Build Coastguard Worker kvm_get_cpuid(CPUID_GET_EXT_FEATURES, 0, &buf);
256*49cdfc7eSAndroid Build Coastguard Worker return buf.ecx & 0x4;
257*49cdfc7eSAndroid Build Coastguard Worker }
258*49cdfc7eSAndroid Build Coastguard Worker
kvm_get_svm_state(void)259*49cdfc7eSAndroid Build Coastguard Worker int kvm_get_svm_state(void)
260*49cdfc7eSAndroid Build Coastguard Worker {
261*49cdfc7eSAndroid Build Coastguard Worker return kvm_rdmsr(MSR_EFER) & EFER_SVME;
262*49cdfc7eSAndroid Build Coastguard Worker }
263*49cdfc7eSAndroid Build Coastguard Worker
kvm_set_svm_state(int enabled)264*49cdfc7eSAndroid Build Coastguard Worker void kvm_set_svm_state(int enabled)
265*49cdfc7eSAndroid Build Coastguard Worker {
266*49cdfc7eSAndroid Build Coastguard Worker uint64_t value;
267*49cdfc7eSAndroid Build Coastguard Worker
268*49cdfc7eSAndroid Build Coastguard Worker if (!kvm_is_svm_supported())
269*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TCONF, "CPU does not support SVM");
270*49cdfc7eSAndroid Build Coastguard Worker
271*49cdfc7eSAndroid Build Coastguard Worker if (kvm_rdmsr(MSR_VM_CR) & VM_CR_SVMDIS)
272*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TCONF, "SVM is supported but disabled");
273*49cdfc7eSAndroid Build Coastguard Worker
274*49cdfc7eSAndroid Build Coastguard Worker value = kvm_rdmsr(MSR_EFER);
275*49cdfc7eSAndroid Build Coastguard Worker
276*49cdfc7eSAndroid Build Coastguard Worker if (enabled)
277*49cdfc7eSAndroid Build Coastguard Worker value |= EFER_SVME;
278*49cdfc7eSAndroid Build Coastguard Worker else
279*49cdfc7eSAndroid Build Coastguard Worker value &= ~EFER_SVME;
280*49cdfc7eSAndroid Build Coastguard Worker
281*49cdfc7eSAndroid Build Coastguard Worker kvm_wrmsr(MSR_EFER, value);
282*49cdfc7eSAndroid Build Coastguard Worker }
283*49cdfc7eSAndroid Build Coastguard Worker
kvm_alloc_vmcb(void)284*49cdfc7eSAndroid Build Coastguard Worker struct kvm_vmcb *kvm_alloc_vmcb(void)
285*49cdfc7eSAndroid Build Coastguard Worker {
286*49cdfc7eSAndroid Build Coastguard Worker struct kvm_vmcb *ret;
287*49cdfc7eSAndroid Build Coastguard Worker
288*49cdfc7eSAndroid Build Coastguard Worker ret = tst_heap_alloc_aligned(sizeof(struct kvm_vmcb), PAGESIZE);
289*49cdfc7eSAndroid Build Coastguard Worker memset(ret, 0, sizeof(struct kvm_vmcb));
290*49cdfc7eSAndroid Build Coastguard Worker return ret;
291*49cdfc7eSAndroid Build Coastguard Worker }
292*49cdfc7eSAndroid Build Coastguard Worker
kvm_init_svm(void)293*49cdfc7eSAndroid Build Coastguard Worker void kvm_init_svm(void)
294*49cdfc7eSAndroid Build Coastguard Worker {
295*49cdfc7eSAndroid Build Coastguard Worker kvm_set_svm_state(1);
296*49cdfc7eSAndroid Build Coastguard Worker kvm_wrmsr(MSR_VM_HSAVE_PA, (uintptr_t)kvm_alloc_vmcb());
297*49cdfc7eSAndroid Build Coastguard Worker }
298*49cdfc7eSAndroid Build Coastguard Worker
kvm_vmcb_copy_gdt_descriptor(struct kvm_vmcb_descriptor * dst,unsigned int gdt_id)299*49cdfc7eSAndroid Build Coastguard Worker void kvm_vmcb_copy_gdt_descriptor(struct kvm_vmcb_descriptor *dst,
300*49cdfc7eSAndroid Build Coastguard Worker unsigned int gdt_id)
301*49cdfc7eSAndroid Build Coastguard Worker {
302*49cdfc7eSAndroid Build Coastguard Worker uint64_t baseaddr;
303*49cdfc7eSAndroid Build Coastguard Worker uint32_t limit;
304*49cdfc7eSAndroid Build Coastguard Worker unsigned int flags;
305*49cdfc7eSAndroid Build Coastguard Worker
306*49cdfc7eSAndroid Build Coastguard Worker if (gdt_id >= KVM_GDT_SIZE)
307*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "GDT descriptor ID out of range");
308*49cdfc7eSAndroid Build Coastguard Worker
309*49cdfc7eSAndroid Build Coastguard Worker kvm_parse_segment_descriptor(kvm_gdt + gdt_id, &baseaddr, &limit,
310*49cdfc7eSAndroid Build Coastguard Worker &flags);
311*49cdfc7eSAndroid Build Coastguard Worker
312*49cdfc7eSAndroid Build Coastguard Worker if (!(flags & SEGFLAG_PRESENT)) {
313*49cdfc7eSAndroid Build Coastguard Worker memset(dst, 0, sizeof(struct kvm_vmcb_descriptor));
314*49cdfc7eSAndroid Build Coastguard Worker return;
315*49cdfc7eSAndroid Build Coastguard Worker }
316*49cdfc7eSAndroid Build Coastguard Worker
317*49cdfc7eSAndroid Build Coastguard Worker if (flags & SEGFLAG_PAGE_LIMIT)
318*49cdfc7eSAndroid Build Coastguard Worker limit = (limit << 12) | 0xfff;
319*49cdfc7eSAndroid Build Coastguard Worker
320*49cdfc7eSAndroid Build Coastguard Worker dst->selector = gdt_id << 3;
321*49cdfc7eSAndroid Build Coastguard Worker dst->attrib = flags;
322*49cdfc7eSAndroid Build Coastguard Worker dst->limit = limit;
323*49cdfc7eSAndroid Build Coastguard Worker dst->base = baseaddr;
324*49cdfc7eSAndroid Build Coastguard Worker }
325*49cdfc7eSAndroid Build Coastguard Worker
kvm_vmcb_set_intercept(struct kvm_vmcb * vmcb,unsigned int id,unsigned int state)326*49cdfc7eSAndroid Build Coastguard Worker void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id,
327*49cdfc7eSAndroid Build Coastguard Worker unsigned int state)
328*49cdfc7eSAndroid Build Coastguard Worker {
329*49cdfc7eSAndroid Build Coastguard Worker unsigned int addr = id / 8, bit = 1 << (id % 8);
330*49cdfc7eSAndroid Build Coastguard Worker
331*49cdfc7eSAndroid Build Coastguard Worker if (id >= SVM_INTERCEPT_MAX)
332*49cdfc7eSAndroid Build Coastguard Worker tst_brk(TBROK, "Invalid SVM intercept ID");
333*49cdfc7eSAndroid Build Coastguard Worker
334*49cdfc7eSAndroid Build Coastguard Worker if (state)
335*49cdfc7eSAndroid Build Coastguard Worker vmcb->intercepts[addr] |= bit;
336*49cdfc7eSAndroid Build Coastguard Worker else
337*49cdfc7eSAndroid Build Coastguard Worker vmcb->intercepts[addr] &= ~bit;
338*49cdfc7eSAndroid Build Coastguard Worker }
339*49cdfc7eSAndroid Build Coastguard Worker
kvm_init_guest_vmcb(struct kvm_vmcb * vmcb,uint32_t asid,uint16_t ss,void * rsp,int (* guest_main)(void))340*49cdfc7eSAndroid Build Coastguard Worker void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss,
341*49cdfc7eSAndroid Build Coastguard Worker void *rsp, int (*guest_main)(void))
342*49cdfc7eSAndroid Build Coastguard Worker {
343*49cdfc7eSAndroid Build Coastguard Worker struct kvm_cregs cregs;
344*49cdfc7eSAndroid Build Coastguard Worker struct kvm_sregs sregs;
345*49cdfc7eSAndroid Build Coastguard Worker
346*49cdfc7eSAndroid Build Coastguard Worker kvm_read_cregs(&cregs);
347*49cdfc7eSAndroid Build Coastguard Worker kvm_read_sregs(&sregs);
348*49cdfc7eSAndroid Build Coastguard Worker
349*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_set_intercept(vmcb, SVM_INTERCEPT_VMRUN, 1);
350*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_set_intercept(vmcb, SVM_INTERCEPT_HLT, 1);
351*49cdfc7eSAndroid Build Coastguard Worker
352*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_copy_gdt_descriptor(&vmcb->es, sregs.es >> 3);
353*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_copy_gdt_descriptor(&vmcb->cs, sregs.cs >> 3);
354*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_copy_gdt_descriptor(&vmcb->ss, ss);
355*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_copy_gdt_descriptor(&vmcb->ds, sregs.ds >> 3);
356*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_copy_gdt_descriptor(&vmcb->fs, sregs.fs >> 3);
357*49cdfc7eSAndroid Build Coastguard Worker kvm_vmcb_copy_gdt_descriptor(&vmcb->gs, sregs.gs >> 3);
358*49cdfc7eSAndroid Build Coastguard Worker vmcb->gdtr.base = (uintptr_t)kvm_gdt;
359*49cdfc7eSAndroid Build Coastguard Worker vmcb->gdtr.limit = (KVM_GDT_SIZE*sizeof(struct segment_descriptor)) - 1;
360*49cdfc7eSAndroid Build Coastguard Worker vmcb->idtr.base = (uintptr_t)kvm_idt;
361*49cdfc7eSAndroid Build Coastguard Worker vmcb->idtr.limit = (X86_INTR_COUNT*sizeof(struct intr_descriptor)) - 1;
362*49cdfc7eSAndroid Build Coastguard Worker
363*49cdfc7eSAndroid Build Coastguard Worker vmcb->guest_asid = asid;
364*49cdfc7eSAndroid Build Coastguard Worker vmcb->efer = kvm_rdmsr(MSR_EFER);
365*49cdfc7eSAndroid Build Coastguard Worker vmcb->cr0 = cregs.cr0;
366*49cdfc7eSAndroid Build Coastguard Worker vmcb->cr3 = cregs.cr3;
367*49cdfc7eSAndroid Build Coastguard Worker vmcb->cr4 = cregs.cr4;
368*49cdfc7eSAndroid Build Coastguard Worker vmcb->rip = (uintptr_t)kvm_svm_guest_entry;
369*49cdfc7eSAndroid Build Coastguard Worker vmcb->rax = (uintptr_t)guest_main;
370*49cdfc7eSAndroid Build Coastguard Worker vmcb->rsp = (uintptr_t)rsp;
371*49cdfc7eSAndroid Build Coastguard Worker vmcb->rflags = 0x200; /* Interrupts enabled */
372*49cdfc7eSAndroid Build Coastguard Worker }
373*49cdfc7eSAndroid Build Coastguard Worker
kvm_create_svm_vcpu(int (* guest_main)(void),int alloc_stack)374*49cdfc7eSAndroid Build Coastguard Worker struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void),
375*49cdfc7eSAndroid Build Coastguard Worker int alloc_stack)
376*49cdfc7eSAndroid Build Coastguard Worker {
377*49cdfc7eSAndroid Build Coastguard Worker uint16_t ss = 0;
378*49cdfc7eSAndroid Build Coastguard Worker char *stack = NULL;
379*49cdfc7eSAndroid Build Coastguard Worker struct kvm_vmcb *vmcb;
380*49cdfc7eSAndroid Build Coastguard Worker struct kvm_svm_vcpu *ret;
381*49cdfc7eSAndroid Build Coastguard Worker
382*49cdfc7eSAndroid Build Coastguard Worker vmcb = kvm_alloc_vmcb();
383*49cdfc7eSAndroid Build Coastguard Worker
384*49cdfc7eSAndroid Build Coastguard Worker if (alloc_stack) {
385*49cdfc7eSAndroid Build Coastguard Worker stack = tst_heap_alloc_aligned(2 * PAGESIZE, PAGESIZE);
386*49cdfc7eSAndroid Build Coastguard Worker ss = kvm_create_stack_descriptor(kvm_gdt, KVM_GDT_SIZE, stack);
387*49cdfc7eSAndroid Build Coastguard Worker stack += 2 * PAGESIZE;
388*49cdfc7eSAndroid Build Coastguard Worker }
389*49cdfc7eSAndroid Build Coastguard Worker
390*49cdfc7eSAndroid Build Coastguard Worker kvm_init_guest_vmcb(vmcb, 1, ss, stack, guest_main);
391*49cdfc7eSAndroid Build Coastguard Worker ret = tst_heap_alloc(sizeof(struct kvm_svm_vcpu));
392*49cdfc7eSAndroid Build Coastguard Worker memset(ret, 0, sizeof(struct kvm_svm_vcpu));
393*49cdfc7eSAndroid Build Coastguard Worker ret->vmcb = vmcb;
394*49cdfc7eSAndroid Build Coastguard Worker return ret;
395*49cdfc7eSAndroid Build Coastguard Worker }
396*49cdfc7eSAndroid Build Coastguard Worker
kvm_svm_vmload(struct kvm_vmcb * buf)397*49cdfc7eSAndroid Build Coastguard Worker void kvm_svm_vmload(struct kvm_vmcb *buf)
398*49cdfc7eSAndroid Build Coastguard Worker {
399*49cdfc7eSAndroid Build Coastguard Worker asm (
400*49cdfc7eSAndroid Build Coastguard Worker "vmload %0\n"
401*49cdfc7eSAndroid Build Coastguard Worker :
402*49cdfc7eSAndroid Build Coastguard Worker : "a" (buf)
403*49cdfc7eSAndroid Build Coastguard Worker );
404*49cdfc7eSAndroid Build Coastguard Worker }
405*49cdfc7eSAndroid Build Coastguard Worker
kvm_svm_vmsave(struct kvm_vmcb * buf)406*49cdfc7eSAndroid Build Coastguard Worker void kvm_svm_vmsave(struct kvm_vmcb *buf)
407*49cdfc7eSAndroid Build Coastguard Worker {
408*49cdfc7eSAndroid Build Coastguard Worker asm (
409*49cdfc7eSAndroid Build Coastguard Worker "vmsave %0\n"
410*49cdfc7eSAndroid Build Coastguard Worker :
411*49cdfc7eSAndroid Build Coastguard Worker : "a" (buf)
412*49cdfc7eSAndroid Build Coastguard Worker );
413*49cdfc7eSAndroid Build Coastguard Worker }
414