1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 2016 The FreeBSD Foundation 3ca987d46SWarner Losh * 4ca987d46SWarner Losh * This software was developed by Konstantin Belousov under sponsorship 5ca987d46SWarner Losh * from the FreeBSD Foundation. 6ca987d46SWarner Losh * 7ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 8ca987d46SWarner Losh * modification, are permitted provided that the following conditions 9ca987d46SWarner Losh * are met: 10ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 12ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 13ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 14ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 15ca987d46SWarner Losh * 16ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26ca987d46SWarner Losh * SUCH DAMAGE. 27ca987d46SWarner Losh */ 28ca987d46SWarner Losh 29ca987d46SWarner Losh #include <sys/cdefs.h> 30ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 31ca987d46SWarner Losh 32ca987d46SWarner Losh #include <stand.h> 33ca987d46SWarner Losh #include <string.h> 34ca987d46SWarner Losh #include <sys/param.h> 35ca987d46SWarner Losh #include <machine/cpufunc.h> 36ca987d46SWarner Losh #include <machine/psl.h> 37ca987d46SWarner Losh #include <machine/segments.h> 38ca987d46SWarner Losh #include <machine/frame.h> 39ca987d46SWarner Losh #include <machine/tss.h> 40ca987d46SWarner Losh 41ca987d46SWarner Losh #include <efi.h> 42ca987d46SWarner Losh #include <efilib.h> 43ca987d46SWarner Losh 44ca987d46SWarner Losh #include "bootstrap.h" 45ca987d46SWarner Losh #include "loader_efi.h" 46ca987d46SWarner Losh 47ca987d46SWarner Losh #define NUM_IST 8 48ca987d46SWarner Losh #define NUM_EXC 32 49ca987d46SWarner Losh 50ca987d46SWarner Losh /* 51ca987d46SWarner Losh * This code catches exceptions but forwards hardware interrupts to 52ca987d46SWarner Losh * handlers installed by firmware. It differentiates exceptions 53ca987d46SWarner Losh * vs. interrupts by presence of the error code on the stack, which 54ca987d46SWarner Losh * causes different stack pointer value on trap handler entry. 55ca987d46SWarner Losh * 56ca987d46SWarner Losh * Use kernel layout for the trapframe just to not be original. 57ca987d46SWarner Losh * 58ca987d46SWarner Losh * Use free IST slot in existing TSS, or create our own TSS if 59ca987d46SWarner Losh * firmware did not configured any, to have stack switched to 60ca987d46SWarner Losh * IST-specified one, e.g. to handle #SS. If hand-off cannot find 61ca987d46SWarner Losh * unused IST slot, or create a new descriptor in GDT, we bail out. 62ca987d46SWarner Losh */ 63ca987d46SWarner Losh 64ca987d46SWarner Losh static struct region_descriptor fw_idt; /* Descriptor for pristine fw IDT */ 65ca987d46SWarner Losh static struct region_descriptor loader_idt;/* Descriptor for loader 66ca987d46SWarner Losh shadow IDT */ 67ca987d46SWarner Losh static EFI_PHYSICAL_ADDRESS lidt_pa; /* Address of loader shadow IDT */ 68ca987d46SWarner Losh static EFI_PHYSICAL_ADDRESS tss_pa; /* Address of TSS */ 69ca987d46SWarner Losh static EFI_PHYSICAL_ADDRESS exc_stack_pa;/* Address of IST stack for loader */ 70ca987d46SWarner Losh EFI_PHYSICAL_ADDRESS exc_rsp; /* %rsp value on our IST stack when 71ca987d46SWarner Losh exception happens */ 72ca987d46SWarner Losh EFI_PHYSICAL_ADDRESS fw_intr_handlers[NUM_EXC]; /* fw handlers for < 32 IDT 73ca987d46SWarner Losh vectors */ 74ca987d46SWarner Losh static int intercepted[NUM_EXC]; 75ca987d46SWarner Losh static int ist; /* IST for exception handlers */ 76ca987d46SWarner Losh static uint32_t tss_fw_seg; /* Fw TSS segment */ 77ca987d46SWarner Losh static uint32_t loader_tss; /* Loader TSS segment */ 78ca987d46SWarner Losh static struct region_descriptor fw_gdt; /* Descriptor of pristine GDT */ 79ca987d46SWarner Losh static EFI_PHYSICAL_ADDRESS loader_gdt_pa; /* Address of loader shadow GDT */ 80ca987d46SWarner Losh 81*f4ca0fdbSToomas Soome struct frame { 82*f4ca0fdbSToomas Soome struct frame *fr_savfp; 83*f4ca0fdbSToomas Soome uintptr_t fr_savpc; 84*f4ca0fdbSToomas Soome }; 85*f4ca0fdbSToomas Soome 86ca987d46SWarner Losh void report_exc(struct trapframe *tf); 87ca987d46SWarner Losh void 88ca987d46SWarner Losh report_exc(struct trapframe *tf) 89ca987d46SWarner Losh { 90*f4ca0fdbSToomas Soome struct frame *fp; 91*f4ca0fdbSToomas Soome uintptr_t pc, base; 92*f4ca0fdbSToomas Soome char buf[80]; 93*f4ca0fdbSToomas Soome int ret; 94ca987d46SWarner Losh 95*f4ca0fdbSToomas Soome base = (uintptr_t)boot_img->ImageBase; 96ca987d46SWarner Losh /* 97ca987d46SWarner Losh * printf() depends on loader runtime and UEFI firmware health 98ca987d46SWarner Losh * to produce the console output, in case of exception, the 99ca987d46SWarner Losh * loader or firmware runtime may fail to support the printf(). 100ca987d46SWarner Losh */ 101ca987d46SWarner Losh printf("====================================================" 102ca987d46SWarner Losh "============================\n"); 103ca987d46SWarner Losh printf("Exception %u\n", tf->tf_trapno); 104ca987d46SWarner Losh printf("ss 0x%04hx cs 0x%04hx ds 0x%04hx es 0x%04hx fs 0x%04hx " 105ca987d46SWarner Losh "gs 0x%04hx\n", 106ca987d46SWarner Losh (uint16_t)tf->tf_ss, (uint16_t)tf->tf_cs, (uint16_t)tf->tf_ds, 107ca987d46SWarner Losh (uint16_t)tf->tf_es, (uint16_t)tf->tf_fs, (uint16_t)tf->tf_gs); 108ca987d46SWarner Losh printf("err 0x%08x rfl 0x%08x addr 0x%016lx\n" 109ca987d46SWarner Losh "rsp 0x%016lx rip 0x%016lx\n", 110ca987d46SWarner Losh (uint32_t)tf->tf_err, (uint32_t)tf->tf_rflags, tf->tf_addr, 111ca987d46SWarner Losh tf->tf_rsp, tf->tf_rip); 112ca987d46SWarner Losh printf( 113ca987d46SWarner Losh "rdi 0x%016lx rsi 0x%016lx rdx 0x%016lx\n" 114ca987d46SWarner Losh "rcx 0x%016lx r8 0x%016lx r9 0x%016lx\n" 115ca987d46SWarner Losh "rax 0x%016lx rbx 0x%016lx rbp 0x%016lx\n" 116ca987d46SWarner Losh "r10 0x%016lx r11 0x%016lx r12 0x%016lx\n" 117ca987d46SWarner Losh "r13 0x%016lx r14 0x%016lx r15 0x%016lx\n", 118ca987d46SWarner Losh tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_rcx, tf->tf_r8, 119ca987d46SWarner Losh tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10, 120ca987d46SWarner Losh tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); 121*f4ca0fdbSToomas Soome 122*f4ca0fdbSToomas Soome fp = (struct frame *)tf->tf_rbp; 123*f4ca0fdbSToomas Soome pc = tf->tf_rip; 124*f4ca0fdbSToomas Soome 125*f4ca0fdbSToomas Soome printf("Stack trace:\n"); 126*f4ca0fdbSToomas Soome pager_open(); 127*f4ca0fdbSToomas Soome while (fp != NULL || pc != 0) { 128*f4ca0fdbSToomas Soome char *source = "PC"; 129*f4ca0fdbSToomas Soome 130*f4ca0fdbSToomas Soome if (pc >= base && pc < base + boot_img->ImageSize) { 131*f4ca0fdbSToomas Soome pc -= base; 132*f4ca0fdbSToomas Soome source = "loader PC"; 133*f4ca0fdbSToomas Soome } 134*f4ca0fdbSToomas Soome (void) snprintf(buf, sizeof (buf), "FP %016lx: %s 0x%016lx\n", 135*f4ca0fdbSToomas Soome (uintptr_t)fp, source, pc); 136*f4ca0fdbSToomas Soome if (pager_output(buf)) 137*f4ca0fdbSToomas Soome break; 138*f4ca0fdbSToomas Soome 139*f4ca0fdbSToomas Soome if (fp != NULL) 140*f4ca0fdbSToomas Soome fp = fp->fr_savfp; 141*f4ca0fdbSToomas Soome 142*f4ca0fdbSToomas Soome if (fp != NULL) 143*f4ca0fdbSToomas Soome pc = fp->fr_savpc; 144*f4ca0fdbSToomas Soome else 145*f4ca0fdbSToomas Soome pc = 0; 146*f4ca0fdbSToomas Soome } 147*f4ca0fdbSToomas Soome pager_close(); 148ca987d46SWarner Losh printf("Machine stopped.\n"); 149ca987d46SWarner Losh } 150ca987d46SWarner Losh 151ca987d46SWarner Losh static void 152ca987d46SWarner Losh prepare_exception(unsigned idx, uint64_t my_handler, 153ca987d46SWarner Losh int ist_use_table[static NUM_IST]) 154ca987d46SWarner Losh { 155ca987d46SWarner Losh struct gate_descriptor *fw_idt_e, *loader_idt_e; 156ca987d46SWarner Losh 157ca987d46SWarner Losh fw_idt_e = &((struct gate_descriptor *)fw_idt.rd_base)[idx]; 158ca987d46SWarner Losh loader_idt_e = &((struct gate_descriptor *)loader_idt.rd_base)[idx]; 159ca987d46SWarner Losh fw_intr_handlers[idx] = fw_idt_e->gd_looffset + 160ca987d46SWarner Losh (fw_idt_e->gd_hioffset << 16); 161ca987d46SWarner Losh intercepted[idx] = 1; 162ca987d46SWarner Losh ist_use_table[fw_idt_e->gd_ist]++; 163ca987d46SWarner Losh loader_idt_e->gd_looffset = my_handler; 164ca987d46SWarner Losh loader_idt_e->gd_hioffset = my_handler >> 16; 165ca987d46SWarner Losh /* 166ca987d46SWarner Losh * We reuse uefi selector for the code segment for the exception 167ca987d46SWarner Losh * handler code, while the reason for the fault might be the 168ca987d46SWarner Losh * corruption of that gdt entry. On the other hand, allocating 169ca987d46SWarner Losh * our own descriptor might be not much better, if gdt is corrupted. 170ca987d46SWarner Losh */ 171ca987d46SWarner Losh loader_idt_e->gd_selector = fw_idt_e->gd_selector; 172ca987d46SWarner Losh loader_idt_e->gd_ist = 0; 173ca987d46SWarner Losh loader_idt_e->gd_type = SDT_SYSIGT; 174ca987d46SWarner Losh loader_idt_e->gd_dpl = 0; 175ca987d46SWarner Losh loader_idt_e->gd_p = 1; 176ca987d46SWarner Losh loader_idt_e->gd_xx = 0; 177ca987d46SWarner Losh loader_idt_e->sd_xx1 = 0; 178ca987d46SWarner Losh } 179ca987d46SWarner Losh #define PREPARE_EXCEPTION(N) \ 180ca987d46SWarner Losh extern char EXC##N##_handler[]; \ 181ca987d46SWarner Losh prepare_exception(N, (uintptr_t)EXC##N##_handler, ist_use_table); 182ca987d46SWarner Losh 183ca987d46SWarner Losh static void 184ca987d46SWarner Losh free_tables(void) 185ca987d46SWarner Losh { 186ca987d46SWarner Losh 187ca987d46SWarner Losh if (lidt_pa != 0) { 188ca987d46SWarner Losh BS->FreePages(lidt_pa, EFI_SIZE_TO_PAGES(fw_idt.rd_limit)); 189ca987d46SWarner Losh lidt_pa = 0; 190ca987d46SWarner Losh } 191ca987d46SWarner Losh if (exc_stack_pa != 0) { 192ca987d46SWarner Losh BS->FreePages(exc_stack_pa, 1); 193ca987d46SWarner Losh exc_stack_pa = 0; 194ca987d46SWarner Losh } 195ca987d46SWarner Losh if (tss_pa != 0 && tss_fw_seg == 0) { 196ca987d46SWarner Losh BS->FreePages(tss_pa, EFI_SIZE_TO_PAGES(sizeof(struct 197ca987d46SWarner Losh amd64tss))); 198ca987d46SWarner Losh tss_pa = 0; 199ca987d46SWarner Losh } 200ca987d46SWarner Losh if (loader_gdt_pa != 0) { 201ca987d46SWarner Losh BS->FreePages(tss_pa, 2); 202ca987d46SWarner Losh loader_gdt_pa = 0; 203ca987d46SWarner Losh } 204ca987d46SWarner Losh ist = 0; 205ca987d46SWarner Losh loader_tss = 0; 206ca987d46SWarner Losh } 207ca987d46SWarner Losh 208ca987d46SWarner Losh static int 209ca987d46SWarner Losh efi_setup_tss(struct region_descriptor *gdt, uint32_t loader_tss_idx, 210ca987d46SWarner Losh struct amd64tss **tss) 211ca987d46SWarner Losh { 212ca987d46SWarner Losh EFI_STATUS status; 213ca987d46SWarner Losh struct system_segment_descriptor *tss_desc; 214ca987d46SWarner Losh 215ca987d46SWarner Losh tss_desc = (struct system_segment_descriptor *)(gdt->rd_base + 216ca987d46SWarner Losh (loader_tss_idx << 3)); 217ca987d46SWarner Losh status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 218ca987d46SWarner Losh EFI_SIZE_TO_PAGES(sizeof(struct amd64tss)), &tss_pa); 219ca987d46SWarner Losh if (EFI_ERROR(status)) { 220ca987d46SWarner Losh printf("efi_setup_tss: AllocatePages tss error %lu\n", 221ca987d46SWarner Losh EFI_ERROR_CODE(status)); 222ca987d46SWarner Losh return (0); 223ca987d46SWarner Losh } 224ca987d46SWarner Losh *tss = (struct amd64tss *)tss_pa; 225ca987d46SWarner Losh bzero(*tss, sizeof(**tss)); 226ca987d46SWarner Losh tss_desc->sd_lolimit = sizeof(struct amd64tss); 227ca987d46SWarner Losh tss_desc->sd_lobase = tss_pa; 228ca987d46SWarner Losh tss_desc->sd_type = SDT_SYSTSS; 229ca987d46SWarner Losh tss_desc->sd_dpl = 0; 230ca987d46SWarner Losh tss_desc->sd_p = 1; 231ca987d46SWarner Losh tss_desc->sd_hilimit = sizeof(struct amd64tss) >> 16; 232ca987d46SWarner Losh tss_desc->sd_gran = 0; 233ca987d46SWarner Losh tss_desc->sd_hibase = tss_pa >> 24; 234ca987d46SWarner Losh tss_desc->sd_xx0 = 0; 235ca987d46SWarner Losh tss_desc->sd_xx1 = 0; 236ca987d46SWarner Losh tss_desc->sd_mbz = 0; 237ca987d46SWarner Losh tss_desc->sd_xx2 = 0; 238ca987d46SWarner Losh return (1); 239ca987d46SWarner Losh } 240ca987d46SWarner Losh 241ca987d46SWarner Losh static int 242ca987d46SWarner Losh efi_redirect_exceptions(void) 243ca987d46SWarner Losh { 244ca987d46SWarner Losh int ist_use_table[NUM_IST]; 245ca987d46SWarner Losh struct gate_descriptor *loader_idt_e; 246ca987d46SWarner Losh struct system_segment_descriptor *tss_desc, *gdt_desc; 247ca987d46SWarner Losh struct amd64tss *tss; 248ca987d46SWarner Losh struct region_descriptor *gdt_rd, loader_gdt; 249ca987d46SWarner Losh uint32_t i; 250ca987d46SWarner Losh EFI_STATUS status; 251ca987d46SWarner Losh register_t rfl; 252ca987d46SWarner Losh 253ca987d46SWarner Losh sidt(&fw_idt); 254ca987d46SWarner Losh status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 255ca987d46SWarner Losh EFI_SIZE_TO_PAGES(fw_idt.rd_limit), &lidt_pa); 256ca987d46SWarner Losh if (EFI_ERROR(status)) { 257ca987d46SWarner Losh printf("efi_redirect_exceptions: AllocatePages IDT error %lu\n", 258ca987d46SWarner Losh EFI_ERROR_CODE(status)); 259ca987d46SWarner Losh lidt_pa = 0; 260ca987d46SWarner Losh return (0); 261ca987d46SWarner Losh } 262ca987d46SWarner Losh status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, 263ca987d46SWarner Losh &exc_stack_pa); 264ca987d46SWarner Losh if (EFI_ERROR(status)) { 265ca987d46SWarner Losh printf("efi_redirect_exceptions: AllocatePages stk error %lu\n", 266ca987d46SWarner Losh EFI_ERROR_CODE(status)); 267ca987d46SWarner Losh exc_stack_pa = 0; 268ca987d46SWarner Losh free_tables(); 269ca987d46SWarner Losh return (0); 270ca987d46SWarner Losh } 271ca987d46SWarner Losh loader_idt.rd_limit = fw_idt.rd_limit; 272ca987d46SWarner Losh bcopy((void *)fw_idt.rd_base, (void *)loader_idt.rd_base, 273ca987d46SWarner Losh loader_idt.rd_limit); 274ca987d46SWarner Losh bzero(ist_use_table, sizeof(ist_use_table)); 275ca987d46SWarner Losh bzero(fw_intr_handlers, sizeof(fw_intr_handlers)); 276ca987d46SWarner Losh bzero(intercepted, sizeof(intercepted)); 277ca987d46SWarner Losh 278ca987d46SWarner Losh sgdt(&fw_gdt); 279ca987d46SWarner Losh tss_fw_seg = read_tr(); 280ca987d46SWarner Losh gdt_rd = NULL; 281ca987d46SWarner Losh if (tss_fw_seg == 0) { 282ca987d46SWarner Losh for (i = 2; (i << 3) + sizeof(*gdt_desc) <= fw_gdt.rd_limit; 283ca987d46SWarner Losh i += 2) { 284ca987d46SWarner Losh gdt_desc = (struct system_segment_descriptor *)( 285ca987d46SWarner Losh fw_gdt.rd_base + (i << 3)); 286ca987d46SWarner Losh if (gdt_desc->sd_type == 0 && gdt_desc->sd_mbz == 0) { 287ca987d46SWarner Losh gdt_rd = &fw_gdt; 288ca987d46SWarner Losh break; 289ca987d46SWarner Losh } 290ca987d46SWarner Losh } 291ca987d46SWarner Losh if (gdt_rd == NULL) { 292ca987d46SWarner Losh if (i >= 8190) { 293ca987d46SWarner Losh printf("efi_redirect_exceptions: all slots " 294ca987d46SWarner Losh "in gdt are used\n"); 295ca987d46SWarner Losh free_tables(); 296ca987d46SWarner Losh return (0); 297ca987d46SWarner Losh } 298ca987d46SWarner Losh loader_gdt.rd_limit = roundup2(fw_gdt.rd_limit + 299ca987d46SWarner Losh sizeof(struct system_segment_descriptor), 300ca987d46SWarner Losh sizeof(struct system_segment_descriptor)) - 1; 301ca987d46SWarner Losh i = (loader_gdt.rd_limit + 1 - 302ca987d46SWarner Losh sizeof(struct system_segment_descriptor)) / 303ca987d46SWarner Losh sizeof(struct system_segment_descriptor) * 2; 304ca987d46SWarner Losh status = BS->AllocatePages(AllocateAnyPages, 305ca987d46SWarner Losh EfiLoaderData, 306ca987d46SWarner Losh EFI_SIZE_TO_PAGES(loader_gdt.rd_limit), 307ca987d46SWarner Losh &loader_gdt_pa); 308ca987d46SWarner Losh if (EFI_ERROR(status)) { 309ca987d46SWarner Losh printf("efi_setup_tss: AllocatePages gdt error " 310ca987d46SWarner Losh "%lu\n", EFI_ERROR_CODE(status)); 311ca987d46SWarner Losh loader_gdt_pa = 0; 312ca987d46SWarner Losh free_tables(); 313ca987d46SWarner Losh return (0); 314ca987d46SWarner Losh } 315ca987d46SWarner Losh loader_gdt.rd_base = loader_gdt_pa; 316ca987d46SWarner Losh bzero((void *)loader_gdt.rd_base, loader_gdt.rd_limit); 317ca987d46SWarner Losh bcopy((void *)fw_gdt.rd_base, 318ca987d46SWarner Losh (void *)loader_gdt.rd_base, fw_gdt.rd_limit); 319ca987d46SWarner Losh gdt_rd = &loader_gdt; 320ca987d46SWarner Losh } 321ca987d46SWarner Losh loader_tss = i << 3; 322ca987d46SWarner Losh if (!efi_setup_tss(gdt_rd, i, &tss)) { 323ca987d46SWarner Losh tss_pa = 0; 324ca987d46SWarner Losh free_tables(); 325ca987d46SWarner Losh return (0); 326ca987d46SWarner Losh } 327ca987d46SWarner Losh } else { 328ca987d46SWarner Losh tss_desc = (struct system_segment_descriptor *)((char *) 329ca987d46SWarner Losh fw_gdt.rd_base + tss_fw_seg); 330ca987d46SWarner Losh if (tss_desc->sd_type != SDT_SYSTSS && 331ca987d46SWarner Losh tss_desc->sd_type != SDT_SYSBSY) { 332ca987d46SWarner Losh printf("LTR points to non-TSS descriptor\n"); 333ca987d46SWarner Losh free_tables(); 334ca987d46SWarner Losh return (0); 335ca987d46SWarner Losh } 336ca987d46SWarner Losh tss_pa = tss_desc->sd_lobase + (tss_desc->sd_hibase << 16); 337ca987d46SWarner Losh tss = (struct amd64tss *)tss_pa; 338ca987d46SWarner Losh tss_desc->sd_type = SDT_SYSTSS; /* unbusy */ 339ca987d46SWarner Losh } 340ca987d46SWarner Losh 341ca987d46SWarner Losh PREPARE_EXCEPTION(0); 342ca987d46SWarner Losh PREPARE_EXCEPTION(1); 343ca987d46SWarner Losh PREPARE_EXCEPTION(2); 344ca987d46SWarner Losh PREPARE_EXCEPTION(3); 345ca987d46SWarner Losh PREPARE_EXCEPTION(4); 346ca987d46SWarner Losh PREPARE_EXCEPTION(5); 347ca987d46SWarner Losh PREPARE_EXCEPTION(6); 348ca987d46SWarner Losh PREPARE_EXCEPTION(7); 349ca987d46SWarner Losh PREPARE_EXCEPTION(8); 350ca987d46SWarner Losh PREPARE_EXCEPTION(9); 351ca987d46SWarner Losh PREPARE_EXCEPTION(10); 352ca987d46SWarner Losh PREPARE_EXCEPTION(11); 353ca987d46SWarner Losh PREPARE_EXCEPTION(12); 354ca987d46SWarner Losh PREPARE_EXCEPTION(13); 355ca987d46SWarner Losh PREPARE_EXCEPTION(14); 356ca987d46SWarner Losh PREPARE_EXCEPTION(16); 357ca987d46SWarner Losh PREPARE_EXCEPTION(17); 358ca987d46SWarner Losh PREPARE_EXCEPTION(18); 359ca987d46SWarner Losh PREPARE_EXCEPTION(19); 360ca987d46SWarner Losh PREPARE_EXCEPTION(20); 361ca987d46SWarner Losh 362ca987d46SWarner Losh exc_rsp = exc_stack_pa + PAGE_SIZE - 363ca987d46SWarner Losh (6 /* hw exception frame */ + 3 /* scratch regs */) * 8; 364ca987d46SWarner Losh 365ca987d46SWarner Losh /* Find free IST and use it */ 366ca987d46SWarner Losh for (ist = 1; ist < NUM_IST; ist++) { 367ca987d46SWarner Losh if (ist_use_table[ist] == 0) 368ca987d46SWarner Losh break; 369ca987d46SWarner Losh } 370ca987d46SWarner Losh if (ist == NUM_IST) { 371ca987d46SWarner Losh printf("efi_redirect_exceptions: all ISTs used\n"); 372ca987d46SWarner Losh free_tables(); 373ca987d46SWarner Losh lidt_pa = 0; 374ca987d46SWarner Losh return (0); 375ca987d46SWarner Losh } 376ca987d46SWarner Losh for (i = 0; i < NUM_EXC; i++) { 377ca987d46SWarner Losh loader_idt_e = &((struct gate_descriptor *)loader_idt. 378ca987d46SWarner Losh rd_base)[i]; 379ca987d46SWarner Losh if (intercepted[i]) 380ca987d46SWarner Losh loader_idt_e->gd_ist = ist; 381ca987d46SWarner Losh } 382ca987d46SWarner Losh (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE; 383ca987d46SWarner Losh 384ca987d46SWarner Losh /* Switch to new IDT */ 385ca987d46SWarner Losh rfl = intr_disable(); 386ca987d46SWarner Losh if (loader_gdt_pa != 0) 387ca987d46SWarner Losh bare_lgdt(&loader_gdt); 388ca987d46SWarner Losh if (loader_tss != 0) 389ca987d46SWarner Losh ltr(loader_tss); 390ca987d46SWarner Losh lidt(&loader_idt); 391ca987d46SWarner Losh intr_restore(rfl); 392ca987d46SWarner Losh return (1); 393ca987d46SWarner Losh } 394ca987d46SWarner Losh 395ca987d46SWarner Losh static void 396ca987d46SWarner Losh efi_unredirect_exceptions(void) 397ca987d46SWarner Losh { 398ca987d46SWarner Losh register_t rfl; 399ca987d46SWarner Losh 400ca987d46SWarner Losh if (lidt_pa == 0) 401ca987d46SWarner Losh return; 402ca987d46SWarner Losh 403ca987d46SWarner Losh rfl = intr_disable(); 404ca987d46SWarner Losh if (ist != 0) 405ca987d46SWarner Losh (&(((struct amd64tss *)tss_pa)->tss_ist1))[ist - 1] = 0; 406ca987d46SWarner Losh if (loader_gdt_pa != 0) 407ca987d46SWarner Losh bare_lgdt(&fw_gdt); 408ca987d46SWarner Losh if (loader_tss != 0) 409ca987d46SWarner Losh ltr(tss_fw_seg); 410ca987d46SWarner Losh lidt(&fw_idt); 411ca987d46SWarner Losh intr_restore(rfl); 412ca987d46SWarner Losh free_tables(); 413ca987d46SWarner Losh } 414ca987d46SWarner Losh 415ca987d46SWarner Losh static int 416ca987d46SWarner Losh command_grab_faults(int argc, char *argv[]) 417ca987d46SWarner Losh { 418ca987d46SWarner Losh int res; 419ca987d46SWarner Losh 420ca987d46SWarner Losh res = efi_redirect_exceptions(); 421ca987d46SWarner Losh if (!res) 422ca987d46SWarner Losh printf("failed\n"); 423ca987d46SWarner Losh return (CMD_OK); 424ca987d46SWarner Losh } 425ca987d46SWarner Losh COMMAND_SET(grap_faults, "grab_faults", "grab faults", command_grab_faults); 426ca987d46SWarner Losh 427ca987d46SWarner Losh static int 428ca987d46SWarner Losh command_ungrab_faults(int argc, char *argv[]) 429ca987d46SWarner Losh { 430ca987d46SWarner Losh 431ca987d46SWarner Losh efi_unredirect_exceptions(); 432ca987d46SWarner Losh return (CMD_OK); 433ca987d46SWarner Losh } 434ca987d46SWarner Losh COMMAND_SET(ungrab_faults, "ungrab_faults", "ungrab faults", 435ca987d46SWarner Losh command_ungrab_faults); 436ca987d46SWarner Losh 437ca987d46SWarner Losh static int 438ca987d46SWarner Losh command_fault(int argc, char *argv[]) 439ca987d46SWarner Losh { 440ca987d46SWarner Losh 441ca987d46SWarner Losh __asm("ud2"); 442ca987d46SWarner Losh return (CMD_OK); 443ca987d46SWarner Losh } 444ca987d46SWarner Losh COMMAND_SET(fault, "fault", "generate fault", command_fault); 445