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