Date: Wed, 5 Oct 2016 22:04:23 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r306738 - stable/11/sys/boot/efi/loader/arch/amd64 Message-ID: <201610052204.u95M4Nvn038008@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Wed Oct 5 22:04:22 2016 New Revision: 306738 URL: https://svnweb.freebsd.org/changeset/base/306738 Log: MFC r306090: Simple post-mortem reporter for amd64 loader.efi. Added: stable/11/sys/boot/efi/loader/arch/amd64/exc.S - copied unchanged from r306090, head/sys/boot/efi/loader/arch/amd64/exc.S stable/11/sys/boot/efi/loader/arch/amd64/trap.c - copied unchanged from r306090, head/sys/boot/efi/loader/arch/amd64/trap.c Modified: stable/11/sys/boot/efi/loader/arch/amd64/Makefile.inc Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/boot/efi/loader/arch/amd64/Makefile.inc ============================================================================== --- stable/11/sys/boot/efi/loader/arch/amd64/Makefile.inc Wed Oct 5 22:02:36 2016 (r306737) +++ stable/11/sys/boot/efi/loader/arch/amd64/Makefile.inc Wed Oct 5 22:04:22 2016 (r306738) @@ -3,7 +3,9 @@ SRCS+= amd64_tramp.S \ start.S \ framebuffer.c \ - elf64_freebsd.c + elf64_freebsd.c \ + trap.c \ + exc.S .PATH: ${.CURDIR}/../../i386/libi386 SRCS+= nullconsole.c \ Copied: stable/11/sys/boot/efi/loader/arch/amd64/exc.S (from r306090, head/sys/boot/efi/loader/arch/amd64/exc.S) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/11/sys/boot/efi/loader/arch/amd64/exc.S Wed Oct 5 22:04:22 2016 (r306738, copy of r306090, head/sys/boot/efi/loader/arch/amd64/exc.S) @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + .macro EH N, err=1 + .align 8 + .globl EXC\N\()_handler +EXC\N\()_handler: + .if \err != 1 + pushq $0 + .endif + pushq %rax + pushq %rdx + pushq %rcx + movl $\N,%ecx + jmp all_handlers + .endm + + .text + EH 0,0 + EH 1,0 + EH 2,0 + EH 3,0 + EH 4,0 + EH 5,0 + EH 6,0 + EH 7,0 + EH 8 + EH 9,0 + EH 10 + EH 11 + EH 12 + EH 13 + EH 14 + EH 16,0 + EH 17 + EH 18,0 + EH 19,0 + EH 20,0 + + .globl exc_rsp +all_handlers: + cmpq %rsp,exc_rsp(%rip) + je exception + + /* + * Interrupt, not exception. + * First, copy the hardware interrupt frame to the previous stack. + * Our handler always has private IST stack. + */ + movq (6*8)(%rsp),%rax /* saved %rsp value, AKA old stack */ + subq (5*8),%rax + movq (3*8)(%rsp),%rdx /* copy %rip to old stack */ + movq %rdx,(%rax) + movq (4*8)(%rsp),%rdx /* copy %cs */ + movq %rdx,(1*8)(%rax) + movq (5*8)(%rsp),%rdx /* copy %rflags */ + movq %rdx,(2*8)(%rax) + movq (6*8)(%rsp),%rdx /* copy %rsp */ + movq %rdx,(3*8)(%rax) + movq (7*8)(%rsp),%rdx /* copy %ss */ + movq %rdx,(4*8)(%rax) + + /* + * Now simulate invocation of the original interrupt handler + * with retq. We switch stacks and execute retq from the old + * stack since there is no free registers at the last moment. + */ + subq $16,%rax + leaq fw_intr_handlers(%rip),%rdx + movq (%rdx,%rcx,8),%rdx /* push intr handler address on old stack */ + movq %rdx,8(%rax) + movq (2*8)(%rsp),%rcx /* saved %rax is put on top of old stack */ + movq %rcx,(%rax) + movq (%rsp),%rcx + movq 8(%rsp),%rdx + + movq 32(%rsp),%rsp /* switch to old stack */ + popq %rax + retq + +exception: + /* + * Form the struct trapframe on our IST stack. + * Skip three words, which are currently busy with temporal + * saves. + */ + pushq %r15 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %rbp + pushq %rbx + pushq $0 /* %rax */ + pushq %r9 + pushq %r8 + pushq $0 /* %rcx */ + pushq $0 /* %rdx */ + pushq %rsi + pushq %rdi + + /* + * Move %rax, %rdx, %rcx values into the final location, + * from the three words which were skipped above. + */ + movq 0x88(%rsp),%rax + movq %rax,0x30(%rsp) /* tf_rax */ + movq 0x78(%rsp),%rax + movq %rax,0x18(%rsp) /* tf_rcx */ + movq 0x80(%rsp),%rax + movq %rax,0x10(%rsp) /* tf_rdx */ + + /* + * And fill the three words themself. + */ + movq %cr2,%rax + movq %rax,0x80(%rsp) /* tf_addr */ + movl %ecx,0x78(%rsp) /* tf_trapno */ + movw %ds,0x8e(%rsp) + movw %es,0x8c(%rsp) + movw %fs,0x7c(%rsp) + movw %gs,0x7e(%rsp) + movw $0,0x88(%rsp) /* tf_flags */ + + /* + * Call dump routine. + */ + movq %rsp,%rdi + callq report_exc + + /* + * Hang after reporting. Interrupts are already disabled. + */ +1: + hlt + jmp 1b Copied: stable/11/sys/boot/efi/loader/arch/amd64/trap.c (from r306090, head/sys/boot/efi/loader/arch/amd64/trap.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/11/sys/boot/efi/loader/arch/amd64/trap.c Wed Oct 5 22:04:22 2016 (r306738, copy of r306090, head/sys/boot/efi/loader/arch/amd64/trap.c) @@ -0,0 +1,398 @@ +/*- + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> +#include <string.h> +#include <sys/param.h> +#include <machine/cpufunc.h> +#include <machine/psl.h> +#include <machine/segments.h> +#include <machine/frame.h> +#include <machine/tss.h> + +#include <efi.h> +#include <efilib.h> + +#include "bootstrap.h" +#include "loader_efi.h" + +#define NUM_IST 8 +#define NUM_EXC 32 + +/* + * This code catches exceptions but forwards hardware interrupts to + * handlers installed by firmware. It differentiates exceptions + * vs. interrupts by presence of the error code on the stack, which + * causes different stack pointer value on trap handler entry. + * + * Use kernel layout for the trapframe just to not be original. + * + * Use free IST slot in existing TSS, or create our own TSS if + * firmware did not configured any, to have stack switched to + * IST-specified one, e.g. to handle #SS. If hand-off cannot find + * unused IST slot, or create a new descriptor in GDT, we bail out. + */ + +static struct region_descriptor fw_idt; /* Descriptor for pristine fw IDT */ +static struct region_descriptor loader_idt;/* Descriptor for loader + shadow IDT */ +static EFI_PHYSICAL_ADDRESS lidt_pa; /* Address of loader shadow IDT */ +static EFI_PHYSICAL_ADDRESS tss_pa; /* Address of TSS */ +static EFI_PHYSICAL_ADDRESS exc_stack_pa;/* Address of IST stack for loader */ +EFI_PHYSICAL_ADDRESS exc_rsp; /* %rsp value on our IST stack when + exception happens */ +EFI_PHYSICAL_ADDRESS fw_intr_handlers[NUM_EXC]; /* fw handlers for < 32 IDT + vectors */ +static int intercepted[NUM_EXC]; +static int ist; /* IST for exception handlers */ +static uint32_t tss_fw_seg; /* Fw TSS segment */ +static uint32_t loader_tss; /* Loader TSS segment */ +static struct region_descriptor fw_gdt; /* Descriptor of pristine GDT */ +static EFI_PHYSICAL_ADDRESS loader_gdt_pa; /* Address of loader shadow GDT */ + +void report_exc(struct trapframe *tf); +void +report_exc(struct trapframe *tf) +{ + + /* XXX using printf */ + printf("====================================================" + "============================\n"); + printf("Exception %u\n", tf->tf_trapno); + printf("ss 0x%04hx cs 0x%04hx ds 0x%04hx es 0x%04hx fs 0x%04hx " + "gs 0x%04hx\n", + (uint16_t)tf->tf_ss, (uint16_t)tf->tf_cs, (uint16_t)tf->tf_ds, + (uint16_t)tf->tf_es, (uint16_t)tf->tf_fs, (uint16_t)tf->tf_gs); + printf("err 0x%08x rfl 0x%08x addr 0x%016lx\n" + "rsp 0x%016lx rip 0x%016lx\n", + (uint32_t)tf->tf_err, (uint32_t)tf->tf_rflags, tf->tf_addr, + tf->tf_rsp, tf->tf_rip); + printf( + "rdi 0x%016lx rsi 0x%016lx rdx 0x%016lx\n" + "rcx 0x%016lx r8 0x%016lx r9 0x%016lx\n" + "rax 0x%016lx rbx 0x%016lx rbp 0x%016lx\n" + "r10 0x%016lx r11 0x%016lx r12 0x%016lx\n" + "r13 0x%016lx r14 0x%016lx r15 0x%016lx\n", + tf->tf_rdi, tf->tf_rsi, tf->tf_rdx, tf->tf_rcx, tf->tf_r8, + tf->tf_r9, tf->tf_rax, tf->tf_rbx, tf->tf_rbp, tf->tf_r10, + tf->tf_r11, tf->tf_r12, tf->tf_r13, tf->tf_r14, tf->tf_r15); + printf("Machine stopped.\n"); +} + +static void +prepare_exception(unsigned idx, uint64_t my_handler, + int ist_use_table[static NUM_IST]) +{ + struct gate_descriptor *fw_idt_e, *loader_idt_e; + + fw_idt_e = &((struct gate_descriptor *)fw_idt.rd_base)[idx]; + loader_idt_e = &((struct gate_descriptor *)loader_idt.rd_base)[idx]; + fw_intr_handlers[idx] = fw_idt_e->gd_looffset + + (fw_idt_e->gd_hioffset << 16); + intercepted[idx] = 1; + ist_use_table[fw_idt_e->gd_ist]++; + loader_idt_e->gd_looffset = my_handler; + loader_idt_e->gd_hioffset = my_handler >> 16; + loader_idt_e->gd_selector = fw_idt_e->gd_selector; /* XXX */ + loader_idt_e->gd_ist = 0; + loader_idt_e->gd_type = SDT_SYSIGT; + loader_idt_e->gd_dpl = 0; + loader_idt_e->gd_p = 1; + loader_idt_e->gd_xx = 0; + loader_idt_e->sd_xx1 = 0; +} +#define PREPARE_EXCEPTION(N) \ + extern char EXC##N##_handler[]; \ + prepare_exception(N, (uintptr_t)EXC##N##_handler, ist_use_table); + +static void +free_tables(void) +{ + + if (lidt_pa != 0) { + BS->FreePages(lidt_pa, EFI_SIZE_TO_PAGES(fw_idt.rd_limit)); + lidt_pa = 0; + } + if (exc_stack_pa != 0) { + BS->FreePages(exc_stack_pa, 1); + exc_stack_pa = 0; + } + if (tss_pa != 0 && tss_fw_seg == 0) { + BS->FreePages(tss_pa, EFI_SIZE_TO_PAGES(sizeof(struct + amd64tss))); + tss_pa = 0; + } + if (loader_gdt_pa != 0) { + BS->FreePages(tss_pa, 2); + loader_gdt_pa = 0; + } + ist = 0; + loader_tss = 0; +} + +static int +efi_setup_tss(struct region_descriptor *gdt, uint32_t loader_tss_idx, + struct amd64tss **tss) +{ + EFI_STATUS status; + struct system_segment_descriptor *tss_desc; + + tss_desc = (struct system_segment_descriptor *)(gdt->rd_base + + (loader_tss_idx << 3)); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(sizeof(struct amd64tss)), &tss_pa); + if (EFI_ERROR(status)) { + printf("efi_setup_tss: AllocatePages tss error %lu\n", + EFI_ERROR_CODE(status)); + return (0); + } + *tss = (struct amd64tss *)tss_pa; + bzero(*tss, sizeof(**tss)); + tss_desc->sd_lolimit = sizeof(struct amd64tss); + tss_desc->sd_lobase = tss_pa; + tss_desc->sd_type = SDT_SYSTSS; + tss_desc->sd_dpl = 0; + tss_desc->sd_p = 1; + tss_desc->sd_hilimit = sizeof(struct amd64tss) >> 16; + tss_desc->sd_gran = 0; + tss_desc->sd_hibase = tss_pa >> 24; + tss_desc->sd_xx0 = 0; + tss_desc->sd_xx1 = 0; + tss_desc->sd_mbz = 0; + tss_desc->sd_xx2 = 0; + return (1); +} + +static int +efi_redirect_exceptions(void) +{ + int ist_use_table[NUM_IST]; + struct gate_descriptor *loader_idt_e; + struct system_segment_descriptor *tss_desc, *gdt_desc; + struct amd64tss *tss; + struct region_descriptor *gdt_rd, loader_gdt; + uint32_t i; + EFI_STATUS status; + register_t rfl; + + sidt(&fw_idt); + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(fw_idt.rd_limit), &lidt_pa); + if (EFI_ERROR(status)) { + printf("efi_redirect_exceptions: AllocatePages IDT error %lu\n", + EFI_ERROR_CODE(status)); + lidt_pa = 0; + return (0); + } + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, 1, + &exc_stack_pa); + if (EFI_ERROR(status)) { + printf("efi_redirect_exceptions: AllocatePages stk error %lu\n", + EFI_ERROR_CODE(status)); + exc_stack_pa = 0; + free_tables(); + return (0); + } + loader_idt.rd_limit = fw_idt.rd_limit; + bcopy((void *)fw_idt.rd_base, (void *)loader_idt.rd_base, + loader_idt.rd_limit); + bzero(ist_use_table, sizeof(ist_use_table)); + bzero(fw_intr_handlers, sizeof(fw_intr_handlers)); + bzero(intercepted, sizeof(intercepted)); + + sgdt(&fw_gdt); + tss_fw_seg = read_tr(); + gdt_rd = NULL; + if (tss_fw_seg == 0) { + for (i = 2; (i << 3) + sizeof(*gdt_desc) <= fw_gdt.rd_limit; + i += 2) { + gdt_desc = (struct system_segment_descriptor *)( + fw_gdt.rd_base + (i << 3)); + if (gdt_desc->sd_type == 0 && gdt_desc->sd_mbz == 0) { + gdt_rd = &fw_gdt; + break; + } + } + if (gdt_rd == NULL) { + if (i >= 8190) { + printf("efi_redirect_exceptions: all slots " + "in gdt are used\n"); + free_tables(); + return (0); + } + loader_gdt.rd_limit = roundup2(fw_gdt.rd_limit + + sizeof(struct system_segment_descriptor), + sizeof(struct system_segment_descriptor)) - 1; + i = (loader_gdt.rd_limit + 1 - + sizeof(struct system_segment_descriptor)) / + sizeof(struct system_segment_descriptor) * 2; + status = BS->AllocatePages(AllocateAnyPages, + EfiLoaderData, + EFI_SIZE_TO_PAGES(loader_gdt.rd_limit), + &loader_gdt_pa); + if (EFI_ERROR(status)) { + printf("efi_setup_tss: AllocatePages gdt error " + "%lu\n", EFI_ERROR_CODE(status)); + loader_gdt_pa = 0; + free_tables(); + return (0); + } + loader_gdt.rd_base = loader_gdt_pa; + bzero((void *)loader_gdt.rd_base, loader_gdt.rd_limit); + bcopy((void *)fw_gdt.rd_base, + (void *)loader_gdt.rd_base, fw_gdt.rd_limit); + gdt_rd = &loader_gdt; + } + loader_tss = i << 3; + if (!efi_setup_tss(gdt_rd, i, &tss)) { + tss_pa = 0; + free_tables(); + return (0); + } + } else { + tss_desc = (struct system_segment_descriptor *)((char *) + fw_gdt.rd_base + tss_fw_seg); + if (tss_desc->sd_type != SDT_SYSTSS && + tss_desc->sd_type != SDT_SYSBSY) { + printf("LTR points to non-TSS descriptor\n"); + free_tables(); + return (0); + } + tss_pa = tss_desc->sd_lobase + (tss_desc->sd_hibase << 16); + tss = (struct amd64tss *)tss_pa; + tss_desc->sd_type = SDT_SYSTSS; /* unbusy */ + } + + PREPARE_EXCEPTION(0); + PREPARE_EXCEPTION(1); + PREPARE_EXCEPTION(2); + PREPARE_EXCEPTION(3); + PREPARE_EXCEPTION(4); + PREPARE_EXCEPTION(5); + PREPARE_EXCEPTION(6); + PREPARE_EXCEPTION(7); + PREPARE_EXCEPTION(8); + PREPARE_EXCEPTION(9); + PREPARE_EXCEPTION(10); + PREPARE_EXCEPTION(11); + PREPARE_EXCEPTION(12); + PREPARE_EXCEPTION(13); + PREPARE_EXCEPTION(14); + PREPARE_EXCEPTION(16); + PREPARE_EXCEPTION(17); + PREPARE_EXCEPTION(18); + PREPARE_EXCEPTION(19); + PREPARE_EXCEPTION(20); + + exc_rsp = exc_stack_pa + PAGE_SIZE - + (6 /* hw exception frame */ + 3 /* scratch regs */) * 8; + + /* Find free IST and use it */ + for (ist = 1; ist < NUM_IST; ist++) { + if (ist_use_table[ist] == 0) + break; + } + if (ist == NUM_IST) { + printf("efi_redirect_exceptions: all ISTs used\n"); + free_tables(); + lidt_pa = 0; + return (0); + } + for (i = 0; i < NUM_EXC; i++) { + loader_idt_e = &((struct gate_descriptor *)loader_idt. + rd_base)[i]; + if (intercepted[i]) + loader_idt_e->gd_ist = ist; + } + (&(tss->tss_ist1))[ist - 1] = exc_stack_pa + PAGE_SIZE; + + /* Switch to new IDT */ + rfl = intr_disable(); + if (loader_gdt_pa != 0) + bare_lgdt(&loader_gdt); + if (loader_tss != 0) + ltr(loader_tss); + lidt(&loader_idt); + intr_restore(rfl); + return (1); +} + +static void +efi_unredirect_exceptions(void) +{ + register_t rfl; + + if (lidt_pa == 0) + return; + + rfl = intr_disable(); + if (ist != 0) + (&(((struct amd64tss *)tss_pa)->tss_ist1))[ist - 1] = 0; + if (loader_gdt_pa != 0) + bare_lgdt(&fw_gdt); + if (loader_tss != 0) + ltr(tss_fw_seg); + lidt(&fw_idt); + intr_restore(rfl); + free_tables(); +} + +static int +command_grab_faults(int argc, char *argv[]) +{ + int res; + + res = efi_redirect_exceptions(); + if (!res) + printf("failed\n"); + return (CMD_OK); +} +COMMAND_SET(grap_faults, "grab_faults", "grab faults", command_grab_faults); + +static int +command_ungrab_faults(int argc, char *argv[]) +{ + + efi_unredirect_exceptions(); + return (CMD_OK); +} +COMMAND_SET(ungrab_faults, "ungrab_faults", "ungrab faults", + command_ungrab_faults); + +static int +command_fault(int argc, char *argv[]) +{ + + __asm("ud2"); + return (CMD_OK); +} +COMMAND_SET(fault, "fault", "generate fault", command_fault);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610052204.u95M4Nvn038008>