xref: /aosp_15_r20/external/ltp/testcases/kernel/kvm/lib_x86.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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