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