• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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