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