Deleted Added
full compact
trap.c (306738) trap.c (329114)
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);