1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2021 SUSE LLC <mdoucha@suse.cz>
4 *
5 * x86-specific KVM helper functions
6 */
7
8 #include "kvm_x86.h"
9
10 struct kvm_interrupt_frame {
11 uintptr_t eip, cs, eflags, esp, ss;
12 };
13
14 const char *tst_interrupt_names[INTERRUPT_COUNT] = {
15 "Division by zero",
16 "Debug interrupt",
17 "Non-maskable interrupt",
18 "Breakpoint",
19 "Arithmetic overflow",
20 "Bound range exception",
21 "Illegal instruction error",
22 "Device not available error",
23 "Double fault",
24 NULL,
25 "Invalid TSS error",
26 "Segment not present error",
27 "Stack segment fault",
28 "General protection fault",
29 "Page fault",
30 NULL,
31 "Floating point exception",
32 "Alignment error",
33 "Machine check exception",
34 "SIMD floating point exception",
35 "Virtualization exception",
36 "Control protection exception",
37 NULL,
38 NULL,
39 NULL,
40 NULL,
41 NULL,
42 NULL,
43 "Hypervisor injection exception",
44 "VMM communication exception",
45 "Security exception",
46 NULL
47 };
48
49 static uintptr_t intr_handlers[] = {
50 (uintptr_t)kvm_handle_zerodiv,
51 (uintptr_t)kvm_handle_debug,
52 (uintptr_t)kvm_handle_nmi,
53 (uintptr_t)kvm_handle_breakpoint,
54 (uintptr_t)kvm_handle_overflow,
55 (uintptr_t)kvm_handle_bound_range_exc,
56 (uintptr_t)kvm_handle_bad_opcode,
57 (uintptr_t)kvm_handle_device_error,
58 (uintptr_t)kvm_handle_double_fault,
59 (uintptr_t)kvm_handle_bad_exception,
60 (uintptr_t)kvm_handle_invalid_tss,
61 (uintptr_t)kvm_handle_segfault,
62 (uintptr_t)kvm_handle_stack_fault,
63 (uintptr_t)kvm_handle_gpf,
64 (uintptr_t)kvm_handle_page_fault,
65 (uintptr_t)kvm_handle_bad_exception,
66 (uintptr_t)kvm_handle_fpu_error,
67 (uintptr_t)kvm_handle_alignment_error,
68 (uintptr_t)kvm_handle_machine_check,
69 (uintptr_t)kvm_handle_simd_error,
70 (uintptr_t)kvm_handle_virt_error,
71 (uintptr_t)kvm_handle_cpe,
72 (uintptr_t)kvm_handle_bad_exception,
73 (uintptr_t)kvm_handle_bad_exception,
74 (uintptr_t)kvm_handle_bad_exception,
75 (uintptr_t)kvm_handle_bad_exception,
76 (uintptr_t)kvm_handle_bad_exception,
77 (uintptr_t)kvm_handle_bad_exception,
78 (uintptr_t)kvm_handle_hv_injection,
79 (uintptr_t)kvm_handle_vmm_comm,
80 (uintptr_t)kvm_handle_security_error,
81 (uintptr_t)kvm_handle_bad_exception,
82 0
83 };
84
kvm_set_intr_handler(unsigned int id,uintptr_t func)85 static void kvm_set_intr_handler(unsigned int id, uintptr_t func)
86 {
87 memset(kvm_idt + id, 0, sizeof(kvm_idt[0]));
88 kvm_idt[id].offset_lo = func & 0xffff;
89 kvm_idt[id].offset_hi = func >> 16;
90 kvm_idt[id].selector = 8;
91 kvm_idt[id].flags = 0x8f; /* type = 0xf, P = 1 */
92 }
93
kvm_init_interrupts(void)94 void kvm_init_interrupts(void)
95 {
96 int i;
97
98 for (i = 0; intr_handlers[i]; i++)
99 kvm_set_intr_handler(i, intr_handlers[i]);
100
101 for (; i < X86_INTR_COUNT; i++)
102 kvm_set_intr_handler(i, (uintptr_t)kvm_handle_bad_exception);
103 }
104
kvm_get_page_address_pae(const struct page_table_entry_pae * entry)105 uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry)
106 {
107 if (!entry->present)
108 return 0;
109
110 return entry->address << 12;
111 }
112
kvm_get_cpuid(unsigned int eax,unsigned int ecx,struct kvm_cpuid * buf)113 void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf)
114 {
115 asm (
116 "cpuid\n"
117 : "=a" (buf->eax), "=b" (buf->ebx), "=c" (buf->ecx),
118 "=d" (buf->edx)
119 : "0" (eax), "2" (ecx)
120 );
121 }
122
kvm_rdmsr(unsigned int msr)123 uint64_t kvm_rdmsr(unsigned int msr)
124 {
125 unsigned int ret_lo, ret_hi;
126
127 asm (
128 "rdmsr\n"
129 : "=a" (ret_lo), "=d" (ret_hi)
130 : "c" (msr)
131 );
132
133 return (((uint64_t)ret_hi) << 32) | ret_lo;
134 }
135
kvm_wrmsr(unsigned int msr,uint64_t value)136 void kvm_wrmsr(unsigned int msr, uint64_t value)
137 {
138 uint32_t val_lo = value & 0xffffffff, val_hi = value >> 32;
139
140 asm (
141 "wrmsr\n"
142 :
143 : "a" (val_lo), "d" (val_hi), "c" (msr)
144 );
145 }
146
kvm_get_interrupt_ip(const struct kvm_interrupt_frame * ifrm)147 uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm)
148 {
149 return ifrm->eip;
150 }
151