18eef2ab6SToomas Soome /*
29c8f3233SToomas Soome  * Copyright (c) 2016 The FreeBSD Foundation
39c8f3233SToomas Soome  * All rights reserved.
49c8f3233SToomas Soome  *
59c8f3233SToomas Soome  * This software was developed by Konstantin Belousov under sponsorship
69c8f3233SToomas Soome  * from the FreeBSD Foundation.
79c8f3233SToomas Soome  *
89c8f3233SToomas Soome  * Redistribution and use in source and binary forms, with or without
99c8f3233SToomas Soome  * modification, are permitted provided that the following conditions
109c8f3233SToomas Soome  * are met:
119c8f3233SToomas Soome  * 1. Redistributions of source code must retain the above copyright
129c8f3233SToomas Soome  *    notice, this list of conditions and the following disclaimer.
139c8f3233SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
149c8f3233SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
159c8f3233SToomas Soome  *    documentation and/or other materials provided with the distribution.
169c8f3233SToomas Soome  *
179c8f3233SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
189c8f3233SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199c8f3233SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209c8f3233SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
219c8f3233SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229c8f3233SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239c8f3233SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249c8f3233SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259c8f3233SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269c8f3233SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279c8f3233SToomas Soome  * SUCH DAMAGE.
289c8f3233SToomas Soome  */
299c8f3233SToomas Soome 
309c8f3233SToomas Soome #include <sys/cdefs.h>
319c8f3233SToomas Soome 
329c8f3233SToomas Soome #include <stand.h>
339c8f3233SToomas Soome #include <string.h>
349c8f3233SToomas Soome #include <sys/param.h>
359c8f3233SToomas Soome #include <machine/cpufunc.h>
369c8f3233SToomas Soome #include <machine/psl.h>
379c8f3233SToomas Soome #include <machine/segments.h>
389c8f3233SToomas Soome #include <machine/frame.h>
399c8f3233SToomas Soome #include <machine/tss.h>
409c8f3233SToomas Soome 
419c8f3233SToomas Soome #include <efi.h>
429c8f3233SToomas Soome #include <efilib.h>
439c8f3233SToomas Soome 
449c8f3233SToomas Soome #include "bootstrap.h"
459c8f3233SToomas Soome #include "loader_efi.h"
469c8f3233SToomas Soome 
479c8f3233SToomas Soome #define	NUM_IST	8
489c8f3233SToomas Soome #define	NUM_EXC	32
499c8f3233SToomas Soome 
509c8f3233SToomas Soome /*
519c8f3233SToomas Soome  * This code catches exceptions but forwards hardware interrupts to
529c8f3233SToomas Soome  * handlers installed by firmware.  It differentiates exceptions
539c8f3233SToomas Soome  * vs. interrupts by presence of the error code on the stack, which
549c8f3233SToomas Soome  * causes different stack pointer value on trap handler entry.
559c8f3233SToomas Soome  *
569c8f3233SToomas Soome  * Use kernel layout for the trapframe just to not be original.
579c8f3233SToomas Soome  *
589c8f3233SToomas Soome  * Use free IST slot in existing TSS, or create our own TSS if
599c8f3233SToomas Soome  * firmware did not configured any, to have stack switched to
609c8f3233SToomas Soome  * IST-specified one, e.g. to handle #SS.  If hand-off cannot find
619c8f3233SToomas Soome  * unused IST slot, or create a new descriptor in GDT, we bail out.
629c8f3233SToomas Soome  */
639c8f3233SToomas Soome 
649c8f3233SToomas Soome static struct region_descriptor fw_idt;	/* Descriptor for pristine fw IDT */
65*f334afcfSToomas Soome static struct region_descriptor
66*f334afcfSToomas Soome     loader_idt; /* Descriptor for loader shadow IDT */
679c8f3233SToomas Soome static EFI_PHYSICAL_ADDRESS lidt_pa;	/* Address of loader shadow IDT */
689c8f3233SToomas Soome static EFI_PHYSICAL_ADDRESS tss_pa;	/* Address of TSS */
69*f334afcfSToomas Soome static EFI_PHYSICAL_ADDRESS exc_stack_pa; /* Address of IST stack for loader */
70*f334afcfSToomas Soome EFI_PHYSICAL_ADDRESS
71*f334afcfSToomas Soome     exc_rsp;	/* %rsp value on our IST stack when exception happens */
72*f334afcfSToomas Soome EFI_PHYSICAL_ADDRESS
73*f334afcfSToomas Soome     fw_intr_handlers[NUM_EXC]; /* fw handlers for < 32 IDT vectors */
749c8f3233SToomas Soome static int intercepted[NUM_EXC];
759c8f3233SToomas Soome static int ist;				/* IST for exception handlers */
769c8f3233SToomas Soome static uint32_t tss_fw_seg;		/* Fw TSS segment */
779c8f3233SToomas Soome static uint32_t loader_tss;		/* Loader TSS segment */
789c8f3233SToomas Soome static struct region_descriptor fw_gdt;	/* Descriptor of pristine GDT */
799c8f3233SToomas Soome static EFI_PHYSICAL_ADDRESS loader_gdt_pa; /* Address of loader shadow GDT */
809c8f3233SToomas Soome 
819c8f3233SToomas Soome void report_exc(struct trapframe *tf);
829c8f3233SToomas Soome void
report_exc(struct trapframe * tf)839c8f3233SToomas Soome report_exc(struct trapframe *tf)
849c8f3233SToomas Soome {
859c8f3233SToomas Soome 
869c8f3233SToomas Soome 	/*
879c8f3233SToomas Soome 	 * printf() depends on loader runtime and UEFI firmware health
889c8f3233SToomas Soome 	 * to produce the console output, in case of exception, the
899c8f3233SToomas Soome 	 * loader or firmware runtime may fail to support the printf().
909c8f3233SToomas Soome 	 */
919c8f3233SToomas Soome 	printf("===================================================="
929c8f3233SToomas Soome 	    "============================\n");
939c8f3233SToomas Soome 	printf("Exception %u\n", tf->tf_trapno);
949c8f3233SToomas Soome 	printf("ss 0x%04hx cs 0x%04hx ds 0x%04hx es 0x%04hx fs 0x%04hx "
959c8f3233SToomas Soome 	    "gs 0x%04hx\n",
969c8f3233SToomas Soome 	    (uint16_t)tf->tf_ss, (uint16_t)tf->tf_cs, (uint16_t)tf->tf_ds,
979c8f3233SToomas Soome 	    (uint16_t)tf->tf_es, (uint16_t)tf->tf_fs, (uint16_t)tf->tf_gs);
989c8f3233SToomas Soome 	printf("err 0x%08x rfl 0x%08x addr 0x%016lx\n"
999c8f3233SToomas Soome 	    "rsp 0x%016lx rip 0x%016lx\n",
1009c8f3233SToomas Soome 	    (uint32_t)tf->tf_err, (uint32_t)tf->tf_rflags, tf->tf_addr,
1019c8f3233SToomas Soome 	    tf->tf_rsp, tf->tf_rip);
1029c8f3233SToomas Soome 	printf(
1039c8f3233SToomas Soome 	    "rdi 0x%016lx rsi 0x%016lx rdx 0x%016lx\n"
1049c8f3233SToomas Soome 	    "rcx 0x%016lx r8  0x%016lx r9  0x%016lx\n"
1059c8f3233SToomas Soome 	    "rax 0x%016lx rbx 0x%016lx rbp 0x%016lx\n"
1069c8f3233SToomas Soome 	    "r10 0x%016lx r11 0x%016lx r12 0x%016lx\n"
1079c8f3233SToomas Soome 	    "r13 0x%016lx r14 0x%016lx r15 0x%016lx\n",
1089c8f3233SToomas Soome 	    tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_rcx, tf->tf_r8,
1099c8f3233SToomas Soome 	    tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10,
1109c8f3233SToomas Soome 	    tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15);
1119c8f3233SToomas Soome 	printf("Machine stopped.\n");
1129c8f3233SToomas Soome }
1139c8f3233SToomas Soome 
1149c8f3233SToomas Soome static void
prepare_exception(unsigned idx,uint64_t my_handler,int ist_use_table[static NUM_IST])1159c8f3233SToomas Soome prepare_exception(unsigned idx, uint64_t my_handler,
1169c8f3233SToomas Soome     int ist_use_table[static NUM_IST])
1179c8f3233SToomas Soome {
1189c8f3233SToomas Soome 	struct gate_descriptor *fw_idt_e, *loader_idt_e;
1199c8f3233SToomas Soome 
1209c8f3233SToomas Soome 	fw_idt_e = &((struct gate_descriptor *)fw_idt.rd_base)[idx];
1219c8f3233SToomas Soome 	loader_idt_e = &((struct gate_descriptor *)loader_idt.rd_base)[idx];
1229c8f3233SToomas Soome 	fw_intr_handlers[idx] = fw_idt_e->gd_looffset +
1239c8f3233SToomas Soome 	    (fw_idt_e->gd_hioffset << 16);
1249c8f3233SToomas Soome 	intercepted[idx] = 1;
1259c8f3233SToomas Soome 	ist_use_table[fw_idt_e->gd_ist]++;
1269c8f3233SToomas Soome 	loader_idt_e->gd_looffset = my_handler;
1279c8f3233SToomas Soome 	loader_idt_e->gd_hioffset = my_handler >> 16;
1289c8f3233SToomas Soome 	/*
1299c8f3233SToomas Soome 	 * We reuse uefi selector for the code segment for the exception
1309c8f3233SToomas Soome 	 * handler code, while the reason for the fault might be the
1319c8f3233SToomas Soome 	 * corruption of that gdt entry. On the other hand, allocating
1329c8f3233SToomas Soome 	 * our own descriptor might be not much better, if gdt is corrupted.
1339c8f3233SToomas Soome 	 */
1349c8f3233SToomas Soome 	loader_idt_e->gd_selector = fw_idt_e->gd_selector;
1359c8f3233SToomas Soome 	loader_idt_e->gd_ist = 0;
1369c8f3233SToomas Soome 	loader_idt_e->gd_type = SDT_SYSIGT;
1379c8f3233SToomas Soome 	loader_idt_e->gd_dpl = 0;
1389c8f3233SToomas Soome 	loader_idt_e->gd_p = 1;
1399c8f3233SToomas Soome 	loader_idt_e->gd_xx = 0;
1409c8f3233SToomas Soome 	loader_idt_e->sd_xx1 = 0;
1419c8f3233SToomas Soome }
1429c8f3233SToomas Soome #define	PREPARE_EXCEPTION(N)						\
1439c8f3233SToomas Soome     extern char EXC##N##_handler[];					\
1449c8f3233SToomas Soome     prepare_exception(N, (uintptr_t)EXC##N##_handler, ist_use_table);
1459c8f3233SToomas Soome 
1469c8f3233SToomas Soome static void
free_tables(void)1479c8f3233SToomas Soome free_tables(void)
1489c8f3233SToomas Soome {
1499c8f3233SToomas Soome 
1509c8f3233SToomas Soome 	if (lidt_pa != 0) {
1519c8f3233SToomas Soome 		BS->FreePages(lidt_pa, EFI_SIZE_TO_PAGES(fw_idt.rd_limit));
1529c8f3233SToomas Soome 		lidt_pa = 0;
1539c8f3233SToomas Soome 	}
1549c8f3233SToomas Soome 	if (exc_stack_pa != 0) {
1559c8f3233SToomas Soome 		BS->FreePages(exc_stack_pa, 1);
1569c8f3233SToomas Soome 		exc_stack_pa = 0;
1579c8f3233SToomas Soome 	}
1589c8f3233SToomas Soome 	if (tss_pa != 0 && tss_fw_seg == 0) {
159*f334afcfSToomas Soome 		BS->FreePages(tss_pa,
160*f334afcfSToomas Soome 		    EFI_SIZE_TO_PAGES(sizeof (struct amd64tss)));
1619c8f3233SToomas Soome 		tss_pa = 0;
1629c8f3233SToomas Soome 	}
1639c8f3233SToomas Soome 	if (loader_gdt_pa != 0) {
1649c8f3233SToomas Soome 		BS->FreePages(tss_pa, 2);
1659c8f3233SToomas Soome 		loader_gdt_pa = 0;
1669c8f3233SToomas Soome 	}
1679c8f3233SToomas Soome 	ist = 0;
1689c8f3233SToomas Soome 	loader_tss = 0;
1699c8f3233SToomas Soome }
1709c8f3233SToomas Soome 
1719c8f3233SToomas Soome static int
efi_setup_tss(struct region_descriptor * gdt,uint32_t loader_tss_idx,struct amd64tss ** tss)1729c8f3233SToomas Soome efi_setup_tss(struct region_descriptor *gdt, uint32_t loader_tss_idx,
1739c8f3233SToomas Soome     struct amd64tss **tss)
1749c8f3233SToomas Soome {
1759c8f3233SToomas Soome 	EFI_STATUS status;
1769c8f3233SToomas Soome 	struct system_segment_descriptor *tss_desc;
1779c8f3233SToomas Soome 
1789c8f3233SToomas Soome 	tss_desc = (struct system_segment_descriptor *)(gdt->rd_base +
1799c8f3233SToomas Soome 	    (loader_tss_idx << 3));
1809c8f3233SToomas Soome 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
181*f334afcfSToomas Soome 	    EFI_SIZE_TO_PAGES(sizeof (struct amd64tss)), &tss_pa);
1829c8f3233SToomas Soome 	if (EFI_ERROR(status)) {
1839c8f3233SToomas Soome 		printf("efi_setup_tss: AllocatePages tss error %lu\n",
184*f334afcfSToomas Soome 		    DECODE_ERROR(status));
1859c8f3233SToomas Soome 		return (0);
1869c8f3233SToomas Soome 	}
1879c8f3233SToomas Soome 	*tss = (struct amd64tss *)tss_pa;
188*f334afcfSToomas Soome 	bzero(*tss, sizeof (**tss));
189*f334afcfSToomas Soome 	tss_desc->sd_lolimit = sizeof (struct amd64tss);
1909c8f3233SToomas Soome 	tss_desc->sd_lobase = tss_pa;
1919c8f3233SToomas Soome 	tss_desc->sd_type = SDT_SYSTSS;
1929c8f3233SToomas Soome 	tss_desc->sd_dpl = 0;
1939c8f3233SToomas Soome 	tss_desc->sd_p = 1;
194*f334afcfSToomas Soome 	tss_desc->sd_hilimit = sizeof (struct amd64tss) >> 16;
1959c8f3233SToomas Soome 	tss_desc->sd_gran = 0;
1969c8f3233SToomas Soome 	tss_desc->sd_hibase = tss_pa >> 24;
1979c8f3233SToomas Soome 	tss_desc->sd_xx0 = 0;
1989c8f3233SToomas Soome 	tss_desc->sd_xx1 = 0;
1999c8f3233SToomas Soome 	tss_desc->sd_mbz = 0;
2009c8f3233SToomas Soome 	tss_desc->sd_xx2 = 0;
2019c8f3233SToomas Soome 	return (1);
2029c8f3233SToomas Soome }
2039c8f3233SToomas Soome 
2049c8f3233SToomas Soome static int
efi_redirect_exceptions(void)2059c8f3233SToomas Soome efi_redirect_exceptions(void)
2069c8f3233SToomas Soome {
2079c8f3233SToomas Soome 	int ist_use_table[NUM_IST];
2089c8f3233SToomas Soome 	struct gate_descriptor *loader_idt_e;
2099c8f3233SToomas Soome 	struct system_segment_descriptor *tss_desc, *gdt_desc;
2109c8f3233SToomas Soome 	struct amd64tss *tss;
2119c8f3233SToomas Soome 	struct region_descriptor *gdt_rd, loader_gdt;
2129c8f3233SToomas Soome 	uint32_t i;
2139c8f3233SToomas Soome 	EFI_STATUS status;
2149c8f3233SToomas Soome 	register_t rfl;
2159c8f3233SToomas Soome 
2169c8f3233SToomas Soome 	sidt(&fw_idt);
2179c8f3233SToomas Soome 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
2189c8f3233SToomas Soome 	    EFI_SIZE_TO_PAGES(fw_idt.rd_limit), &lidt_pa);
2199c8f3233SToomas Soome 	if (EFI_ERROR(status)) {
2209c8f3233SToomas Soome 		printf("efi_redirect_exceptions: AllocatePages IDT error %lu\n",
221*f334afcfSToomas Soome 		    DECODE_ERROR(status));
2229c8f3233SToomas Soome 		lidt_pa = 0;
2239c8f3233SToomas Soome 		return (0);
2249c8f3233SToomas Soome 	}
2259c8f3233SToomas Soome 	status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1,
2269c8f3233SToomas Soome 	    &exc_stack_pa);
2279c8f3233SToomas Soome 	if (EFI_ERROR(status)) {
2289c8f3233SToomas Soome 		printf("efi_redirect_exceptions: AllocatePages stk error %lu\n",
229*f334afcfSToomas Soome 		    DECODE_ERROR(status));
2309c8f3233SToomas Soome 		exc_stack_pa = 0;
2319c8f3233SToomas Soome 		free_tables();
2329c8f3233SToomas Soome 		return (0);
2339c8f3233SToomas Soome 	}
2349c8f3233SToomas Soome 	loader_idt.rd_limit = fw_idt.rd_limit;
2359c8f3233SToomas Soome 	bcopy((void *)fw_idt.rd_base, (void *)loader_idt.rd_base,
2369c8f3233SToomas Soome 	    loader_idt.rd_limit);
237*f334afcfSToomas Soome 	bzero(ist_use_table, sizeof (ist_use_table));
238*f334afcfSToomas Soome 	bzero(fw_intr_handlers, sizeof (fw_intr_handlers));
239*f334afcfSToomas Soome 	bzero(intercepted, sizeof (intercepted));
2409c8f3233SToomas Soome 
2419c8f3233SToomas Soome 	sgdt(&fw_gdt);
2429c8f3233SToomas Soome 	tss_fw_seg = read_tr();
2439c8f3233SToomas Soome 	gdt_rd = NULL;
2449c8f3233SToomas Soome 	if (tss_fw_seg == 0) {
245*f334afcfSToomas Soome 		for (i = 2; (i << 3) + sizeof (*gdt_desc) <= fw_gdt.rd_limit;
2469c8f3233SToomas Soome 		    i += 2) {
2479c8f3233SToomas Soome 			gdt_desc = (struct system_segment_descriptor *)(
2489c8f3233SToomas Soome 			    fw_gdt.rd_base + (i << 3));
2499c8f3233SToomas Soome 			if (gdt_desc->sd_type == 0 && gdt_desc->sd_mbz == 0) {
2509c8f3233SToomas Soome 				gdt_rd = &fw_gdt;
2519c8f3233SToomas Soome 				break;
2529c8f3233SToomas Soome 			}
2539c8f3233SToomas Soome 		}
2549c8f3233SToomas Soome 		if (gdt_rd == NULL) {
2559c8f3233SToomas Soome 			if (i >= 8190) {
2569c8f3233SToomas Soome 				printf("efi_redirect_exceptions: all slots "
2579c8f3233SToomas Soome 				    "in gdt are used\n");
2589c8f3233SToomas Soome 				free_tables();
2599c8f3233SToomas Soome 				return (0);
2609c8f3233SToomas Soome 			}
2619c8f3233SToomas Soome 			loader_gdt.rd_limit = roundup2(fw_gdt.rd_limit +
262*f334afcfSToomas Soome 			    sizeof (struct system_segment_descriptor),
263*f334afcfSToomas Soome 			    sizeof (struct system_segment_descriptor)) - 1;
2649c8f3233SToomas Soome 			i = (loader_gdt.rd_limit + 1 -
265*f334afcfSToomas Soome 			    sizeof (struct system_segment_descriptor)) /
266*f334afcfSToomas Soome 			    sizeof (struct system_segment_descriptor) * 2;
2679c8f3233SToomas Soome 			status = BS->AllocatePages(AllocateAnyPages,
2689c8f3233SToomas Soome 			    EfiLoaderData,
2699c8f3233SToomas Soome 			    EFI_SIZE_TO_PAGES(loader_gdt.rd_limit),
2709c8f3233SToomas Soome 			    &loader_gdt_pa);
2719c8f3233SToomas Soome 			if (EFI_ERROR(status)) {
2729c8f3233SToomas Soome 				printf("efi_setup_tss: AllocatePages gdt error "
273*f334afcfSToomas Soome 				    "%lu\n",  DECODE_ERROR(status));
2749c8f3233SToomas Soome 				loader_gdt_pa = 0;
2759c8f3233SToomas Soome 				free_tables();
2769c8f3233SToomas Soome 				return (0);
2779c8f3233SToomas Soome 			}
2789c8f3233SToomas Soome 			loader_gdt.rd_base = loader_gdt_pa;
2799c8f3233SToomas Soome 			bzero((void *)loader_gdt.rd_base, loader_gdt.rd_limit);
2809c8f3233SToomas Soome 			bcopy((void *)fw_gdt.rd_base,
2819c8f3233SToomas Soome 			    (void *)loader_gdt.rd_base, fw_gdt.rd_limit);
2829c8f3233SToomas Soome 			gdt_rd = &loader_gdt;
2839c8f3233SToomas Soome 		}
2849c8f3233SToomas Soome 		loader_tss = i << 3;
2859c8f3233SToomas Soome 		if (!efi_setup_tss(gdt_rd, i, &tss)) {
2869c8f3233SToomas Soome 			tss_pa = 0;
2879c8f3233SToomas Soome 			free_tables();
2889c8f3233SToomas Soome 			return (0);
2899c8f3233SToomas Soome 		}
2909c8f3233SToomas Soome 	} else {
2919c8f3233SToomas Soome 		tss_desc = (struct system_segment_descriptor *)((char *)
2929c8f3233SToomas Soome 		    fw_gdt.rd_base + tss_fw_seg);
2939c8f3233SToomas Soome 		if (tss_desc->sd_type != SDT_SYSTSS &&
2949c8f3233SToomas Soome 		    tss_desc->sd_type != SDT_SYSBSY) {
2959c8f3233SToomas Soome 			printf("LTR points to non-TSS descriptor\n");
2969c8f3233SToomas Soome 			free_tables();
2979c8f3233SToomas Soome 			return (0);
2989c8f3233SToomas Soome 		}
2999c8f3233SToomas Soome 		tss_pa = tss_desc->sd_lobase + (tss_desc->sd_hibase << 16);
3009c8f3233SToomas Soome 		tss = (struct amd64tss *)tss_pa;
3019c8f3233SToomas Soome 		tss_desc->sd_type = SDT_SYSTSS; /* unbusy */
3029c8f3233SToomas Soome 	}
3039c8f3233SToomas Soome 
3049c8f3233SToomas Soome 	PREPARE_EXCEPTION(0);
3059c8f3233SToomas Soome 	PREPARE_EXCEPTION(1);
3069c8f3233SToomas Soome 	PREPARE_EXCEPTION(2);
3079c8f3233SToomas Soome 	PREPARE_EXCEPTION(3);
3089c8f3233SToomas Soome 	PREPARE_EXCEPTION(4);
3099c8f3233SToomas Soome 	PREPARE_EXCEPTION(5);
3109c8f3233SToomas Soome 	PREPARE_EXCEPTION(6);
3119c8f3233SToomas Soome 	PREPARE_EXCEPTION(7);
3129c8f3233SToomas Soome 	PREPARE_EXCEPTION(8);
3139c8f3233SToomas Soome 	PREPARE_EXCEPTION(9);
3149c8f3233SToomas Soome 	PREPARE_EXCEPTION(10);
3159c8f3233SToomas Soome 	PREPARE_EXCEPTION(11);
3169c8f3233SToomas Soome 	PREPARE_EXCEPTION(12);
3179c8f3233SToomas Soome 	PREPARE_EXCEPTION(13);
3189c8f3233SToomas Soome 	PREPARE_EXCEPTION(14);
3199c8f3233SToomas Soome 	PREPARE_EXCEPTION(16);
3209c8f3233SToomas Soome 	PREPARE_EXCEPTION(17);
3219c8f3233SToomas Soome 	PREPARE_EXCEPTION(18);
3229c8f3233SToomas Soome 	PREPARE_EXCEPTION(19);
3239c8f3233SToomas Soome 	PREPARE_EXCEPTION(20);
3249c8f3233SToomas Soome 
3259c8f3233SToomas Soome 	exc_rsp = exc_stack_pa + PAGE_SIZE -
3269c8f3233SToomas Soome 	    (6 /* hw exception frame */ + 3 /* scratch regs */) * 8;
3279c8f3233SToomas Soome 
3289c8f3233SToomas Soome 	/* Find free IST and use it */
3299c8f3233SToomas Soome 	for (ist = 1; ist < NUM_IST; ist++) {
3309c8f3233SToomas Soome 		if (ist_use_table[ist] == 0)
3319c8f3233SToomas Soome 			break;
3329c8f3233SToomas Soome 	}
3339c8f3233SToomas Soome 	if (ist == NUM_IST) {
3349c8f3233SToomas Soome 		printf("efi_redirect_exceptions: all ISTs used\n");
3359c8f3233SToomas Soome 		free_tables();
3369c8f3233SToomas Soome 		lidt_pa = 0;
3379c8f3233SToomas Soome 		return (0);
3389c8f3233SToomas Soome 	}
3399c8f3233SToomas Soome 	for (i = 0; i < NUM_EXC; i++) {
3409c8f3233SToomas Soome 		loader_idt_e = &((struct gate_descriptor *)loader_idt.
3419c8f3233SToomas Soome 		    rd_base)[i];
3429c8f3233SToomas Soome 		if (intercepted[i])
3439c8f3233SToomas Soome 			loader_idt_e->gd_ist = ist;
3449c8f3233SToomas Soome 	}
3459c8f3233SToomas Soome 	(&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE;
3469c8f3233SToomas Soome 
3479c8f3233SToomas Soome 	/* Switch to new IDT */
3489c8f3233SToomas Soome 	rfl = intr_disable();
3499c8f3233SToomas Soome 	if (loader_gdt_pa != 0)
3509c8f3233SToomas Soome 		bare_lgdt(&loader_gdt);
3519c8f3233SToomas Soome 	if (loader_tss != 0)
3529c8f3233SToomas Soome 		ltr(loader_tss);
3539c8f3233SToomas Soome 	lidt(&loader_idt);
3549c8f3233SToomas Soome 	intr_restore(rfl);
3559c8f3233SToomas Soome 	return (1);
3569c8f3233SToomas Soome }
3579c8f3233SToomas Soome 
3589c8f3233SToomas Soome static void
efi_unredirect_exceptions(void)3599c8f3233SToomas Soome efi_unredirect_exceptions(void)
3609c8f3233SToomas Soome {
3619c8f3233SToomas Soome 	register_t rfl;
3629c8f3233SToomas Soome 
3639c8f3233SToomas Soome 	if (lidt_pa == 0)
3649c8f3233SToomas Soome 		return;
3659c8f3233SToomas Soome 
3669c8f3233SToomas Soome 	rfl = intr_disable();
3679c8f3233SToomas Soome 	if (ist != 0)
3689c8f3233SToomas Soome 		(&(((struct amd64tss *)tss_pa)->tss_ist1))[ist - 1] = 0;
3699c8f3233SToomas Soome 	if (loader_gdt_pa != 0)
3709c8f3233SToomas Soome 		bare_lgdt(&fw_gdt);
3719c8f3233SToomas Soome 	if (loader_tss != 0)
3729c8f3233SToomas Soome 		ltr(tss_fw_seg);
3739c8f3233SToomas Soome 	lidt(&fw_idt);
3749c8f3233SToomas Soome 	intr_restore(rfl);
3759c8f3233SToomas Soome 	free_tables();
3769c8f3233SToomas Soome }
3779c8f3233SToomas Soome 
3789c8f3233SToomas Soome static int
command_grab_faults(int argc __unused,char * argv[]__unused)3798eef2ab6SToomas Soome command_grab_faults(int argc __unused, char *argv[] __unused)
3809c8f3233SToomas Soome {
3819c8f3233SToomas Soome 	int res;
3829c8f3233SToomas Soome 
3839c8f3233SToomas Soome 	res = efi_redirect_exceptions();
3849c8f3233SToomas Soome 	if (!res)
3859c8f3233SToomas Soome 		printf("failed\n");
3869c8f3233SToomas Soome 	return (CMD_OK);
3879c8f3233SToomas Soome }
3889c8f3233SToomas Soome COMMAND_SET(grap_faults, "grab_faults", "grab faults", command_grab_faults);
3899c8f3233SToomas Soome 
3909c8f3233SToomas Soome static int
command_ungrab_faults(int argc __unused,char * argv[]__unused)3918eef2ab6SToomas Soome command_ungrab_faults(int argc __unused, char *argv[] __unused)
3929c8f3233SToomas Soome {
3939c8f3233SToomas Soome 
3949c8f3233SToomas Soome 	efi_unredirect_exceptions();
3959c8f3233SToomas Soome 	return (CMD_OK);
3969c8f3233SToomas Soome }
3979c8f3233SToomas Soome COMMAND_SET(ungrab_faults, "ungrab_faults", "ungrab faults",
3989c8f3233SToomas Soome     command_ungrab_faults);
3999c8f3233SToomas Soome 
4009c8f3233SToomas Soome static int
command_fault(int argc __unused,char * argv[]__unused)4018eef2ab6SToomas Soome command_fault(int argc __unused, char *argv[] __unused)
4029c8f3233SToomas Soome {
4039c8f3233SToomas Soome 
4049c8f3233SToomas Soome 	__asm("ud2");
4059c8f3233SToomas Soome 	return (CMD_OK);
4069c8f3233SToomas Soome }
4079c8f3233SToomas Soome COMMAND_SET(fault, "fault", "generate fault", command_fault);
408