1 #ifndef _X86_DESC_H_ 2 #define _X86_DESC_H_ 3 4 #include <setjmp.h> 5 6 #ifdef __ASSEMBLY__ 7 #define __ASM_FORM(x, ...) x,## __VA_ARGS__ 8 #else 9 #define __ASM_FORM(x, ...) " " xstr(x,##__VA_ARGS__) " " 10 #endif 11 12 #ifndef __x86_64__ 13 #define __ASM_SEL(a,b) __ASM_FORM(a) 14 #else 15 #define __ASM_SEL(a,b) __ASM_FORM(b) 16 #endif 17 18 void setup_idt(void); 19 void load_idt(void); 20 void setup_alt_stack(void); 21 22 struct ex_regs { 23 unsigned long rax, rcx, rdx, rbx; 24 unsigned long dummy, rbp, rsi, rdi; 25 #ifdef __x86_64__ 26 unsigned long r8, r9, r10, r11; 27 unsigned long r12, r13, r14, r15; 28 #endif 29 unsigned long vector; 30 unsigned long error_code; 31 unsigned long rip; 32 unsigned long cs; 33 unsigned long rflags; 34 #ifdef __x86_64__ 35 unsigned long rsp; 36 unsigned long ss; 37 #endif 38 }; 39 40 typedef void (*handler)(struct ex_regs *regs); 41 42 typedef struct { 43 u16 prev; 44 u16 res1; 45 u32 esp0; 46 u16 ss0; 47 u16 res2; 48 u32 esp1; 49 u16 ss1; 50 u16 res3; 51 u32 esp2; 52 u16 ss2; 53 u16 res4; 54 u32 cr3; 55 u32 eip; 56 u32 eflags; 57 u32 eax, ecx, edx, ebx, esp, ebp, esi, edi; 58 u16 es; 59 u16 res5; 60 u16 cs; 61 u16 res6; 62 u16 ss; 63 u16 res7; 64 u16 ds; 65 u16 res8; 66 u16 fs; 67 u16 res9; 68 u16 gs; 69 u16 res10; 70 u16 ldt; 71 u16 res11; 72 u16 t:1; 73 u16 res12:15; 74 u16 iomap_base; 75 } tss32_t; 76 77 typedef struct __attribute__((packed)) { 78 u32 res1; 79 u64 rsp0; 80 u64 rsp1; 81 u64 rsp2; 82 u64 res2; 83 u64 ist1; 84 u64 ist2; 85 u64 ist3; 86 u64 ist4; 87 u64 ist5; 88 u64 ist6; 89 u64 ist7; 90 u64 res3; 91 u16 res4; 92 u16 iomap_base; 93 } tss64_t; 94 95 #define __ASM_TRY(prefix, catch) \ 96 "movl $0, %%gs:4\n\t" \ 97 ".pushsection .data.ex\n\t" \ 98 __ASM_SEL(.long, .quad) " 1111f, " catch "\n\t" \ 99 ".popsection \n\t" \ 100 prefix "\n\t" \ 101 "1111:" 102 103 #define ASM_TRY(catch) __ASM_TRY("", catch) 104 105 /* Forced emulation prefix, used to invoke the emulator unconditionally. */ 106 #define KVM_FEP "ud2; .byte 'k', 'v', 'm';" 107 #define ASM_TRY_FEP(catch) __ASM_TRY(KVM_FEP, catch) 108 109 static inline bool is_fep_available(void) 110 { 111 /* 112 * Use the non-FEP ASM_TRY() as KVM will inject a #UD on the prefix 113 * itself if forced emulation is not available. 114 */ 115 asm goto(ASM_TRY("%l[fep_unavailable]") 116 KVM_FEP "nop\n\t" 117 ::: "memory" : fep_unavailable); 118 return true; 119 fep_unavailable: 120 return false; 121 } 122 123 /* 124 * selector 32-bit 64-bit 125 * 0x00 NULL descriptor NULL descriptor 126 * 0x08 ring-0 code segment (32-bit) ring-0 code segment (64-bit) 127 * 0x10 ring-0 data segment (32-bit) ring-0 data segment (32/64-bit) 128 * 0x18 ring-0 code segment (P=0) ring-0 code segment (64-bit, P=0) 129 * 0x20 intr_alt_stack TSS ring-0 code segment (32-bit) 130 * 0x28 ring-0 code segment (16-bit) same 131 * 0x30 ring-0 data segment (16-bit) same 132 * 0x38 (0x3b) ring-3 code segment (32-bit) same 133 * 0x40 (0x43) ring-3 data segment (32-bit) ring-3 data segment (32/64-bit) 134 * 0x48 (0x4b) **unused** ring-3 code segment (64-bit) 135 * 0x50-0x78 free to use for test cases same 136 * 0x80-0x870 primary TSS (CPU 0..254) same 137 * 0x878-0x1068 percpu area (CPU 0..254) not used 138 * 139 * Note that the same segment can be used for 32-bit and 64-bit data segments 140 * (the L bit is only defined for code segments) 141 * 142 * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL 143 * and SYSRET instructions. 144 */ 145 146 #define KERNEL_CS 0x08 147 #define KERNEL_DS 0x10 148 #define NP_SEL 0x18 149 #ifdef __x86_64__ 150 #define KERNEL_CS32 0x20 151 #else 152 #define TSS_INTR 0x20 153 #endif 154 #define KERNEL_CS16 0x28 155 #define KERNEL_DS16 0x30 156 #define USER_CS32 0x3b 157 #define USER_DS 0x43 158 #ifdef __x86_64__ 159 #define USER_CS64 0x4b 160 #endif 161 162 /* Synonyms */ 163 #define KERNEL_DS32 KERNEL_DS 164 #define USER_DS32 USER_DS 165 166 #ifdef __x86_64__ 167 #define KERNEL_CS64 KERNEL_CS 168 #define USER_CS USER_CS64 169 #define KERNEL_DS64 KERNEL_DS 170 #define USER_DS64 USER_DS 171 #else 172 #define KERNEL_CS32 KERNEL_CS 173 #define USER_CS USER_CS32 174 #endif 175 176 #define FIRST_SPARE_SEL 0x50 177 #define TSS_MAIN 0x80 178 179 typedef struct { 180 unsigned short offset0; 181 unsigned short selector; 182 unsigned short ist : 3; 183 unsigned short : 5; 184 unsigned short type : 4; 185 unsigned short : 1; 186 unsigned short dpl : 2; 187 unsigned short p : 1; 188 unsigned short offset1; 189 #ifdef __x86_64__ 190 unsigned offset2; 191 unsigned reserved; 192 #endif 193 } idt_entry_t; 194 195 typedef struct { 196 uint16_t limit1; 197 uint16_t base1; 198 uint8_t base2; 199 union { 200 uint16_t type_limit_flags; /* Type and limit flags */ 201 struct { 202 uint16_t type:4; 203 uint16_t s:1; 204 uint16_t dpl:2; 205 uint16_t p:1; 206 uint16_t limit2:4; 207 uint16_t avl:1; 208 uint16_t l:1; 209 uint16_t db:1; 210 uint16_t g:1; 211 } __attribute__((__packed__)); 212 } __attribute__((__packed__)); 213 uint8_t base3; 214 } __attribute__((__packed__)) gdt_entry_t; 215 216 #ifdef __x86_64__ 217 struct system_desc64 { 218 gdt_entry_t common; 219 uint32_t base4; 220 uint32_t zero; 221 } __attribute__((__packed__)); 222 #endif 223 224 #define DESC_BUSY 2 225 226 extern idt_entry_t boot_idt[256]; 227 228 #ifndef __x86_64__ 229 extern tss32_t tss[]; 230 extern tss32_t tss_intr; 231 void set_gdt_task_gate(u16 tss_sel, u16 sel); 232 void set_idt_task_gate(int vec, u16 sel); 233 void set_intr_task_gate(int vec, void *fn); 234 void setup_tss32(void); 235 #else 236 extern tss64_t tss[]; 237 #endif 238 extern gdt_entry_t gdt[]; 239 240 unsigned exception_vector(void); 241 unsigned exception_error_code(void); 242 bool exception_rflags_rf(void); 243 void set_desc_entry(idt_entry_t *e, size_t e_sz, void *addr, 244 u16 sel, u16 type, u16 dpl); 245 void set_idt_entry(int vec, void *addr, int dpl); 246 void set_idt_sel(int vec, u16 sel); 247 void set_idt_dpl(int vec, u16 dpl); 248 void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 access, u8 gran); 249 void load_gdt_tss(size_t tss_offset); 250 void set_intr_alt_stack(int e, void *fn); 251 void print_current_tss_info(void); 252 handler handle_exception(u8 v, handler fn); 253 void unhandled_exception(struct ex_regs *regs, bool cpu); 254 const char* exception_mnemonic(int vector); 255 256 bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data), 257 void *data); 258 void __set_exception_jmpbuf(jmp_buf *addr); 259 #define set_exception_jmpbuf(jmpbuf) \ 260 (setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0)) 261 262 static inline void *get_idt_addr(idt_entry_t *entry) 263 { 264 uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16); 265 #ifdef __x86_64__ 266 addr |= (u64)entry->offset2 << 32; 267 #endif 268 return (void *)addr; 269 } 270 271 extern gdt_entry_t *get_tss_descr(void); 272 extern unsigned long get_gdt_entry_base(gdt_entry_t *entry); 273 extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry); 274 275 #endif 276