aboutsummaryrefslogtreecommitdiff
path: root/testcases/kernel/kvm/include/kvm_x86.h
blob: bc36c0e0fa13f97747b46d19a85514de942d333e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2021 SUSE LLC <mdoucha@suse.cz>
 *
 * x86-specific KVM helper functions and structures
 */

#ifndef KVM_X86_H_
#define KVM_X86_H_

#include "kvm_test.h"

#define PAGESIZE 0x1000
#define KVM_GDT_SIZE 32

/* Interrupts */
#define X86_INTR_COUNT 256

#define INTR_ZERODIV 0
#define INTR_DEBUG 1
#define INTR_NMI 2
#define INTR_BREAKPOINT 3
#define INTR_OVERFLOW 4
#define INTR_BOUND_RANGE_EXC 5
#define INTR_BAD_OPCODE 6
#define INTR_DEVICE_ERROR 7
#define INTR_DOUBLE_FAULT 8
#define INTR_INVALID_TSS 10
#define INTR_SEGFAULT 11
#define INTR_STACK_FAULT 12
#define INTR_GPF 13
#define INTR_PAGE_FAULT 14
#define INTR_FPU_ERROR 16
#define INTR_ALIGNMENT_ERROR 17
#define INTR_MACHINE_CHECK 18
#define INTR_SIMD_ERROR 19
#define INTR_VIRT_ERROR 20
#define INTR_CPE 21
#define INTR_HV_INJECTION 28
#define INTR_VMM_COMM 29
#define INTR_SECURITY_ERROR 30


/* Segment descriptor flags */
#define SEGTYPE_LDT 0x02
#define SEGTYPE_TSS 0x09
#define SEGTYPE_TSS_BUSY 0x0b
#define SEGTYPE_CALL_GATE 0x0c
#define SEGTYPE_INTR_GATE 0x0e
#define SEGTYPE_TRAP_GATE 0x0f
#define SEGTYPE_RODATA 0x10
#define SEGTYPE_RWDATA 0x12
#define SEGTYPE_STACK 0x16
#define SEGTYPE_CODE 0x1a
#define SEGTYPE_MASK 0x1f

#define SEGFLAG_NSYSTEM 0x10
#define SEGFLAG_PRESENT 0x80
#define SEGFLAG_CODE64 0x200
#define SEGFLAG_32BIT 0x400
#define SEGFLAG_PAGE_LIMIT 0x800


/* CPUID constants */
#define CPUID_GET_INPUT_RANGE 0x80000000
#define CPUID_GET_EXT_FEATURES 0x80000001
#define CPUID_GET_SVM_FEATURES 0x8000000a


/* Model-specific CPU register constants */
#define MSR_EFER 0xc0000080
#define MSR_VM_CR 0xc0010114
#define MSR_VM_HSAVE_PA 0xc0010117

#define EFER_SCE (1 << 0)	/* SYSCALL/SYSRET instructions enabled */
#define EFER_LME (1 << 8)	/* CPU is running in 64bit mode */
#define EFER_LMA (1 << 10)	/* CPU uses 64bit memory paging (read-only) */
#define EFER_NXE (1 << 11)	/* Execute disable bit active */
#define EFER_SVME (1 << 12)	/* AMD SVM instructions enabled */

#define VM_CR_DPD (1 << 0)
#define VM_CR_R_INIT (1 << 1)
#define VM_CR_DIS_A20M (1 << 2)
#define VM_CR_LOCK (1 << 3)
#define VM_CR_SVMDIS (1 << 4)

/* Control register constants */
#define CR4_VME (1 << 0)
#define CR4_PVI (1 << 1)
#define CR4_TSD (1 << 2)
#define CR4_DE (1 << 3)
#define CR4_PSE (1 << 4)
#define CR4_PAE (1 << 5)
#define CR4_MCE (1 << 6)
#define CR4_PGE (1 << 7)
#define CR4_PCE (1 << 8)
#define CR4_OSFXSR (1 << 9)
#define CR4_OSXMMEXCPT (1 << 10)
#define CR4_UMIP (1 << 11)
#define CR4_LA57 (1 << 12)
#define CR4_VMXE (1 << 13)
#define CR4_SMXE (1 << 14)
#define CR4_FSGSBASE (1 << 16)
#define CR4_PCIDE (1 << 17)
#define CR4_OSXSAVE (1 << 18)
#define CR4_KL (1 << 19)
#define CR4_SMEP (1 << 20)
#define CR4_SMAP (1 << 21)
#define CR4_PKE (1 << 22)
#define CR4_CET (1 << 23)
#define CR4_PKS (1 << 24)

struct intr_descriptor {
	uint16_t offset_lo;
	uint16_t selector;
	uint8_t ist;
	uint8_t flags;
#if defined(__x86_64__)
	uint64_t offset_hi; /* top 16 bits must be set to 0 */
	uint16_t padding;
#else /* defined(__x86_64__) */
	uint16_t offset_hi;
#endif /* defined(__x86_64__) */
} __attribute__((__packed__));

struct segment_descriptor {
	unsigned int limit_lo : 16;
	unsigned int baseaddr_lo : 24;
	unsigned int flags_lo : 8;
	unsigned int limit_hi : 4;
	unsigned int flags_hi : 4;
	unsigned int baseaddr_hi : 8;
} __attribute__((__packed__));

struct segment_descriptor64 {
	unsigned int limit_lo : 16;
	unsigned int baseaddr_lo : 24;
	unsigned int flags_lo : 8;
	unsigned int limit_hi : 4;
	unsigned int flags_hi : 4;
	uint64_t baseaddr_hi : 40;
	uint32_t reserved;
} __attribute__((__packed__));

struct page_table_entry_pae {
	unsigned int present: 1;
	unsigned int writable: 1;
	unsigned int user_access: 1;
	unsigned int write_through: 1;
	unsigned int disable_cache: 1;
	unsigned int accessed: 1;
	unsigned int dirty: 1;
	unsigned int page_type: 1;
	unsigned int global: 1;
	unsigned int padding: 3;
	uint64_t address: 40;
	unsigned int padding2: 7;
	unsigned int prot_key: 4;
	unsigned int noexec: 1;
} __attribute__((__packed__));

struct kvm_cpuid {
	unsigned int eax, ebx, ecx, edx;
};

struct kvm_cregs {
	unsigned long cr0, cr2, cr3, cr4;
};

struct kvm_sregs {
	uint16_t cs, ds, es, fs, gs, ss;
};

struct kvm_regs64 {
	uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp;
	uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
};

extern struct page_table_entry_pae kvm_pagetable[];
extern struct intr_descriptor kvm_idt[X86_INTR_COUNT];
extern struct segment_descriptor kvm_gdt[KVM_GDT_SIZE];

/* Page table helper functions */
uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry);

/* Segment descriptor table functions */
void kvm_set_segment_descriptor(struct segment_descriptor *dst,
	uint64_t baseaddr, uint32_t limit, unsigned int flags);
void kvm_parse_segment_descriptor(struct segment_descriptor *src,
	uint64_t *baseaddr, uint32_t *limit, unsigned int *flags);
int kvm_find_free_descriptor(const struct segment_descriptor *table,
	size_t size);
unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table,
	size_t tabsize, void *stack_base);

/* Functions for querying CPU info and status */
void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf);
void kvm_read_cregs(struct kvm_cregs *buf);
void kvm_read_sregs(struct kvm_sregs *buf);
uint64_t kvm_rdmsr(unsigned int msr);
void kvm_wrmsr(unsigned int msr, uint64_t value);

/* Low-level interrupt handlers, DO NOT call directly */
void kvm_handle_bad_exception(void);
void kvm_handle_zerodiv(void);
void kvm_handle_debug(void);
void kvm_handle_nmi(void);
void kvm_handle_breakpoint(void);
void kvm_handle_overflow(void);
void kvm_handle_bound_range_exc(void);
void kvm_handle_bad_opcode(void);
void kvm_handle_device_error(void);
void kvm_handle_double_fault(void);
void kvm_handle_invalid_tss(void);
void kvm_handle_segfault(void);
void kvm_handle_stack_fault(void);
void kvm_handle_gpf(void);
void kvm_handle_page_fault(void);
void kvm_handle_fpu_error(void);
void kvm_handle_alignment_error(void);
void kvm_handle_machine_check(void);
void kvm_handle_simd_error(void);
void kvm_handle_virt_error(void);
void kvm_handle_cpe(void);
void kvm_handle_hv_injection(void);
void kvm_handle_vmm_comm(void);
void kvm_handle_security_error(void);

#endif /* KVM_X86_H_ */