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