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 and structures
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci#ifndef KVM_X86_H_
9f08c3bdfSopenharmony_ci#define KVM_X86_H_
10f08c3bdfSopenharmony_ci
11f08c3bdfSopenharmony_ci#include "kvm_test.h"
12f08c3bdfSopenharmony_ci
13f08c3bdfSopenharmony_ci#define PAGESIZE 0x1000
14f08c3bdfSopenharmony_ci#define KVM_GDT_SIZE 32
15f08c3bdfSopenharmony_ci
16f08c3bdfSopenharmony_ci/* Interrupts */
17f08c3bdfSopenharmony_ci#define X86_INTR_COUNT 256
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci#define INTR_ZERODIV 0
20f08c3bdfSopenharmony_ci#define INTR_DEBUG 1
21f08c3bdfSopenharmony_ci#define INTR_NMI 2
22f08c3bdfSopenharmony_ci#define INTR_BREAKPOINT 3
23f08c3bdfSopenharmony_ci#define INTR_OVERFLOW 4
24f08c3bdfSopenharmony_ci#define INTR_BOUND_RANGE_EXC 5
25f08c3bdfSopenharmony_ci#define INTR_BAD_OPCODE 6
26f08c3bdfSopenharmony_ci#define INTR_DEVICE_ERROR 7
27f08c3bdfSopenharmony_ci#define INTR_DOUBLE_FAULT 8
28f08c3bdfSopenharmony_ci#define INTR_INVALID_TSS 10
29f08c3bdfSopenharmony_ci#define INTR_SEGFAULT 11
30f08c3bdfSopenharmony_ci#define INTR_STACK_FAULT 12
31f08c3bdfSopenharmony_ci#define INTR_GPF 13
32f08c3bdfSopenharmony_ci#define INTR_PAGE_FAULT 14
33f08c3bdfSopenharmony_ci#define INTR_FPU_ERROR 16
34f08c3bdfSopenharmony_ci#define INTR_ALIGNMENT_ERROR 17
35f08c3bdfSopenharmony_ci#define INTR_MACHINE_CHECK 18
36f08c3bdfSopenharmony_ci#define INTR_SIMD_ERROR 19
37f08c3bdfSopenharmony_ci#define INTR_VIRT_ERROR 20
38f08c3bdfSopenharmony_ci#define INTR_CPE 21
39f08c3bdfSopenharmony_ci#define INTR_HV_INJECTION 28
40f08c3bdfSopenharmony_ci#define INTR_VMM_COMM 29
41f08c3bdfSopenharmony_ci#define INTR_SECURITY_ERROR 30
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci/* Segment descriptor flags */
45f08c3bdfSopenharmony_ci#define SEGTYPE_LDT 0x02
46f08c3bdfSopenharmony_ci#define SEGTYPE_TSS 0x09
47f08c3bdfSopenharmony_ci#define SEGTYPE_TSS_BUSY 0x0b
48f08c3bdfSopenharmony_ci#define SEGTYPE_CALL_GATE 0x0c
49f08c3bdfSopenharmony_ci#define SEGTYPE_INTR_GATE 0x0e
50f08c3bdfSopenharmony_ci#define SEGTYPE_TRAP_GATE 0x0f
51f08c3bdfSopenharmony_ci#define SEGTYPE_RODATA 0x10
52f08c3bdfSopenharmony_ci#define SEGTYPE_RWDATA 0x12
53f08c3bdfSopenharmony_ci#define SEGTYPE_STACK 0x16
54f08c3bdfSopenharmony_ci#define SEGTYPE_CODE 0x1a
55f08c3bdfSopenharmony_ci#define SEGTYPE_MASK 0x1f
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci#define SEGFLAG_NSYSTEM 0x10
58f08c3bdfSopenharmony_ci#define SEGFLAG_PRESENT 0x80
59f08c3bdfSopenharmony_ci#define SEGFLAG_CODE64 0x200
60f08c3bdfSopenharmony_ci#define SEGFLAG_32BIT 0x400
61f08c3bdfSopenharmony_ci#define SEGFLAG_PAGE_LIMIT 0x800
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci/* CPUID constants */
65f08c3bdfSopenharmony_ci#define CPUID_GET_INPUT_RANGE 0x80000000
66f08c3bdfSopenharmony_ci#define CPUID_GET_EXT_FEATURES 0x80000001
67f08c3bdfSopenharmony_ci#define CPUID_GET_SVM_FEATURES 0x8000000a
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci/* Model-specific CPU register constants */
71f08c3bdfSopenharmony_ci#define MSR_EFER 0xc0000080
72f08c3bdfSopenharmony_ci#define MSR_VM_CR 0xc0010114
73f08c3bdfSopenharmony_ci#define MSR_VM_HSAVE_PA 0xc0010117
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci#define EFER_SCE (1 << 0)	/* SYSCALL/SYSRET instructions enabled */
76f08c3bdfSopenharmony_ci#define EFER_LME (1 << 8)	/* CPU is running in 64bit mode */
77f08c3bdfSopenharmony_ci#define EFER_LMA (1 << 10)	/* CPU uses 64bit memory paging (read-only) */
78f08c3bdfSopenharmony_ci#define EFER_NXE (1 << 11)	/* Execute disable bit active */
79f08c3bdfSopenharmony_ci#define EFER_SVME (1 << 12)	/* AMD SVM instructions enabled */
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci#define VM_CR_DPD (1 << 0)
82f08c3bdfSopenharmony_ci#define VM_CR_R_INIT (1 << 1)
83f08c3bdfSopenharmony_ci#define VM_CR_DIS_A20M (1 << 2)
84f08c3bdfSopenharmony_ci#define VM_CR_LOCK (1 << 3)
85f08c3bdfSopenharmony_ci#define VM_CR_SVMDIS (1 << 4)
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci/* Control register constants */
88f08c3bdfSopenharmony_ci#define CR4_VME (1 << 0)
89f08c3bdfSopenharmony_ci#define CR4_PVI (1 << 1)
90f08c3bdfSopenharmony_ci#define CR4_TSD (1 << 2)
91f08c3bdfSopenharmony_ci#define CR4_DE (1 << 3)
92f08c3bdfSopenharmony_ci#define CR4_PSE (1 << 4)
93f08c3bdfSopenharmony_ci#define CR4_PAE (1 << 5)
94f08c3bdfSopenharmony_ci#define CR4_MCE (1 << 6)
95f08c3bdfSopenharmony_ci#define CR4_PGE (1 << 7)
96f08c3bdfSopenharmony_ci#define CR4_PCE (1 << 8)
97f08c3bdfSopenharmony_ci#define CR4_OSFXSR (1 << 9)
98f08c3bdfSopenharmony_ci#define CR4_OSXMMEXCPT (1 << 10)
99f08c3bdfSopenharmony_ci#define CR4_UMIP (1 << 11)
100f08c3bdfSopenharmony_ci#define CR4_LA57 (1 << 12)
101f08c3bdfSopenharmony_ci#define CR4_VMXE (1 << 13)
102f08c3bdfSopenharmony_ci#define CR4_SMXE (1 << 14)
103f08c3bdfSopenharmony_ci#define CR4_FSGSBASE (1 << 16)
104f08c3bdfSopenharmony_ci#define CR4_PCIDE (1 << 17)
105f08c3bdfSopenharmony_ci#define CR4_OSXSAVE (1 << 18)
106f08c3bdfSopenharmony_ci#define CR4_KL (1 << 19)
107f08c3bdfSopenharmony_ci#define CR4_SMEP (1 << 20)
108f08c3bdfSopenharmony_ci#define CR4_SMAP (1 << 21)
109f08c3bdfSopenharmony_ci#define CR4_PKE (1 << 22)
110f08c3bdfSopenharmony_ci#define CR4_CET (1 << 23)
111f08c3bdfSopenharmony_ci#define CR4_PKS (1 << 24)
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_cistruct intr_descriptor {
114f08c3bdfSopenharmony_ci	uint16_t offset_lo;
115f08c3bdfSopenharmony_ci	uint16_t selector;
116f08c3bdfSopenharmony_ci	uint8_t ist;
117f08c3bdfSopenharmony_ci	uint8_t flags;
118f08c3bdfSopenharmony_ci#if defined(__x86_64__)
119f08c3bdfSopenharmony_ci	uint64_t offset_hi; /* top 16 bits must be set to 0 */
120f08c3bdfSopenharmony_ci	uint16_t padding;
121f08c3bdfSopenharmony_ci#else /* defined(__x86_64__) */
122f08c3bdfSopenharmony_ci	uint16_t offset_hi;
123f08c3bdfSopenharmony_ci#endif /* defined(__x86_64__) */
124f08c3bdfSopenharmony_ci} __attribute__((__packed__));
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_cistruct segment_descriptor {
127f08c3bdfSopenharmony_ci	unsigned int limit_lo : 16;
128f08c3bdfSopenharmony_ci	unsigned int baseaddr_lo : 24;
129f08c3bdfSopenharmony_ci	unsigned int flags_lo : 8;
130f08c3bdfSopenharmony_ci	unsigned int limit_hi : 4;
131f08c3bdfSopenharmony_ci	unsigned int flags_hi : 4;
132f08c3bdfSopenharmony_ci	unsigned int baseaddr_hi : 8;
133f08c3bdfSopenharmony_ci} __attribute__((__packed__));
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_cistruct segment_descriptor64 {
136f08c3bdfSopenharmony_ci	unsigned int limit_lo : 16;
137f08c3bdfSopenharmony_ci	unsigned int baseaddr_lo : 24;
138f08c3bdfSopenharmony_ci	unsigned int flags_lo : 8;
139f08c3bdfSopenharmony_ci	unsigned int limit_hi : 4;
140f08c3bdfSopenharmony_ci	unsigned int flags_hi : 4;
141f08c3bdfSopenharmony_ci	uint64_t baseaddr_hi : 40;
142f08c3bdfSopenharmony_ci	uint32_t reserved;
143f08c3bdfSopenharmony_ci} __attribute__((__packed__));
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_cistruct page_table_entry_pae {
146f08c3bdfSopenharmony_ci	unsigned int present: 1;
147f08c3bdfSopenharmony_ci	unsigned int writable: 1;
148f08c3bdfSopenharmony_ci	unsigned int user_access: 1;
149f08c3bdfSopenharmony_ci	unsigned int write_through: 1;
150f08c3bdfSopenharmony_ci	unsigned int disable_cache: 1;
151f08c3bdfSopenharmony_ci	unsigned int accessed: 1;
152f08c3bdfSopenharmony_ci	unsigned int dirty: 1;
153f08c3bdfSopenharmony_ci	unsigned int page_type: 1;
154f08c3bdfSopenharmony_ci	unsigned int global: 1;
155f08c3bdfSopenharmony_ci	unsigned int padding: 3;
156f08c3bdfSopenharmony_ci	uint64_t address: 40;
157f08c3bdfSopenharmony_ci	unsigned int padding2: 7;
158f08c3bdfSopenharmony_ci	unsigned int prot_key: 4;
159f08c3bdfSopenharmony_ci	unsigned int noexec: 1;
160f08c3bdfSopenharmony_ci} __attribute__((__packed__));
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_cistruct kvm_cpuid {
163f08c3bdfSopenharmony_ci	unsigned int eax, ebx, ecx, edx;
164f08c3bdfSopenharmony_ci};
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_cistruct kvm_cregs {
167f08c3bdfSopenharmony_ci	unsigned long cr0, cr2, cr3, cr4;
168f08c3bdfSopenharmony_ci};
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_cistruct kvm_sregs {
171f08c3bdfSopenharmony_ci	uint16_t cs, ds, es, fs, gs, ss;
172f08c3bdfSopenharmony_ci};
173f08c3bdfSopenharmony_ci
174f08c3bdfSopenharmony_cistruct kvm_regs64 {
175f08c3bdfSopenharmony_ci	uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp;
176f08c3bdfSopenharmony_ci	uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
177f08c3bdfSopenharmony_ci};
178f08c3bdfSopenharmony_ci
179f08c3bdfSopenharmony_ciextern struct page_table_entry_pae kvm_pagetable[];
180f08c3bdfSopenharmony_ciextern struct intr_descriptor kvm_idt[X86_INTR_COUNT];
181f08c3bdfSopenharmony_ciextern struct segment_descriptor kvm_gdt[KVM_GDT_SIZE];
182f08c3bdfSopenharmony_ci
183f08c3bdfSopenharmony_ci/* Page table helper functions */
184f08c3bdfSopenharmony_ciuintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry);
185f08c3bdfSopenharmony_ci
186f08c3bdfSopenharmony_ci/* Segment descriptor table functions */
187f08c3bdfSopenharmony_civoid kvm_set_segment_descriptor(struct segment_descriptor *dst,
188f08c3bdfSopenharmony_ci	uint64_t baseaddr, uint32_t limit, unsigned int flags);
189f08c3bdfSopenharmony_civoid kvm_parse_segment_descriptor(struct segment_descriptor *src,
190f08c3bdfSopenharmony_ci	uint64_t *baseaddr, uint32_t *limit, unsigned int *flags);
191f08c3bdfSopenharmony_ciint kvm_find_free_descriptor(const struct segment_descriptor *table,
192f08c3bdfSopenharmony_ci	size_t size);
193f08c3bdfSopenharmony_ciunsigned int kvm_create_stack_descriptor(struct segment_descriptor *table,
194f08c3bdfSopenharmony_ci	size_t tabsize, void *stack_base);
195f08c3bdfSopenharmony_ci
196f08c3bdfSopenharmony_ci/* Functions for querying CPU info and status */
197f08c3bdfSopenharmony_civoid kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf);
198f08c3bdfSopenharmony_civoid kvm_read_cregs(struct kvm_cregs *buf);
199f08c3bdfSopenharmony_civoid kvm_read_sregs(struct kvm_sregs *buf);
200f08c3bdfSopenharmony_ciuint64_t kvm_rdmsr(unsigned int msr);
201f08c3bdfSopenharmony_civoid kvm_wrmsr(unsigned int msr, uint64_t value);
202f08c3bdfSopenharmony_ci
203f08c3bdfSopenharmony_ci/* Low-level interrupt handlers, DO NOT call directly */
204f08c3bdfSopenharmony_civoid kvm_handle_bad_exception(void);
205f08c3bdfSopenharmony_civoid kvm_handle_zerodiv(void);
206f08c3bdfSopenharmony_civoid kvm_handle_debug(void);
207f08c3bdfSopenharmony_civoid kvm_handle_nmi(void);
208f08c3bdfSopenharmony_civoid kvm_handle_breakpoint(void);
209f08c3bdfSopenharmony_civoid kvm_handle_overflow(void);
210f08c3bdfSopenharmony_civoid kvm_handle_bound_range_exc(void);
211f08c3bdfSopenharmony_civoid kvm_handle_bad_opcode(void);
212f08c3bdfSopenharmony_civoid kvm_handle_device_error(void);
213f08c3bdfSopenharmony_civoid kvm_handle_double_fault(void);
214f08c3bdfSopenharmony_civoid kvm_handle_invalid_tss(void);
215f08c3bdfSopenharmony_civoid kvm_handle_segfault(void);
216f08c3bdfSopenharmony_civoid kvm_handle_stack_fault(void);
217f08c3bdfSopenharmony_civoid kvm_handle_gpf(void);
218f08c3bdfSopenharmony_civoid kvm_handle_page_fault(void);
219f08c3bdfSopenharmony_civoid kvm_handle_fpu_error(void);
220f08c3bdfSopenharmony_civoid kvm_handle_alignment_error(void);
221f08c3bdfSopenharmony_civoid kvm_handle_machine_check(void);
222f08c3bdfSopenharmony_civoid kvm_handle_simd_error(void);
223f08c3bdfSopenharmony_civoid kvm_handle_virt_error(void);
224f08c3bdfSopenharmony_civoid kvm_handle_cpe(void);
225f08c3bdfSopenharmony_civoid kvm_handle_hv_injection(void);
226f08c3bdfSopenharmony_civoid kvm_handle_vmm_comm(void);
227f08c3bdfSopenharmony_civoid kvm_handle_security_error(void);
228f08c3bdfSopenharmony_ci
229f08c3bdfSopenharmony_ci#endif /* KVM_X86_H_ */
230