aboutsummaryrefslogtreecommitdiff
path: root/stand/efi/loader/arch/amd64
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
committerWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
commitca987d4641cdcd7f27e153db17c5bf064934faf5 (patch)
tree6c3860e3ba8949be9528d644fbb7fa88d8bbbb79 /stand/efi/loader/arch/amd64
parent6eac7115560381ce5c9e2939ab3fce82bb9b6a95 (diff)
downloadsrc-ca987d4641cdcd7f27e153db17c5bf064934faf5.tar.gz
src-ca987d4641cdcd7f27e153db17c5bf064934faf5.zip
Move sys/boot to stand. Fix all references to new location
Sponsored by: Netflix
Notes
Notes: svn path=/head/; revision=325834
Diffstat (limited to 'stand/efi/loader/arch/amd64')
-rw-r--r--stand/efi/loader/arch/amd64/Makefile.inc15
-rw-r--r--stand/efi/loader/arch/amd64/amd64_tramp.S64
-rw-r--r--stand/efi/loader/arch/amd64/elf64_freebsd.c208
-rw-r--r--stand/efi/loader/arch/amd64/exc.S165
-rw-r--r--stand/efi/loader/arch/amd64/ldscript.amd6472
-rw-r--r--stand/efi/loader/arch/amd64/start.S76
-rw-r--r--stand/efi/loader/arch/amd64/trap.c408
7 files changed, 1008 insertions, 0 deletions
diff --git a/stand/efi/loader/arch/amd64/Makefile.inc b/stand/efi/loader/arch/amd64/Makefile.inc
new file mode 100644
index 000000000000..b6d824ce57e4
--- /dev/null
+++ b/stand/efi/loader/arch/amd64/Makefile.inc
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+SRCS+= amd64_tramp.S \
+ start.S \
+ elf64_freebsd.c \
+ trap.c \
+ exc.S
+
+.PATH: ${BOOTSRC}/i386/libi386
+SRCS+= nullconsole.c \
+ comconsole.c \
+ spinconsole.c
+
+CFLAGS+= -fPIC -DTERM_EMU
+LDFLAGS+= -Wl,-znocombreloc
diff --git a/stand/efi/loader/arch/amd64/amd64_tramp.S b/stand/efi/loader/arch/amd64/amd64_tramp.S
new file mode 100644
index 000000000000..c102d9243589
--- /dev/null
+++ b/stand/efi/loader/arch/amd64/amd64_tramp.S
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Benno Rice 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$
+ */
+
+#include <machine/asmacros.h>
+
+ .text
+ .globl amd64_tramp
+
+/*
+ * void amd64_tramp(uint64_t stack, void *copy_finish, uint64_t kernend,
+ * uint64_t modulep, uint64_t pagetable, uint64_t entry)
+ */
+amd64_tramp:
+ cli /* Make sure we don't get interrupted. */
+ movq %rdi,%rsp /* Switch to our temporary stack. */
+
+ movq %rdx,%r12 /* Stash the kernel values for later. */
+ movq %rcx,%r13
+ movq %r8,%r14
+ movq %r9,%r15
+
+ callq *%rsi /* Call copy_finish so we're all ready to go. */
+
+ pushq %r12 /* Push kernend. */
+ salq $32,%r13 /* Shift modulep and push it. */
+ pushq %r13
+ pushq %r15 /* Push the entry address. */
+ movq %r14,%cr3 /* Switch page tables. */
+ ret /* "Return" to kernel entry. */
+
+ ALIGN_TEXT
+amd64_tramp_end:
+
+ .data
+ .globl amd64_tramp_size
+amd64_tramp_size:
+ .long amd64_tramp_end-amd64_tramp
diff --git a/stand/efi/loader/arch/amd64/elf64_freebsd.c b/stand/efi/loader/arch/amd64/elf64_freebsd.c
new file mode 100644
index 000000000000..37e9fe1b4b18
--- /dev/null
+++ b/stand/efi/loader/arch/amd64/elf64_freebsd.c
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * 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$");
+
+#define __ELF_WORD_SIZE 64
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/linker.h>
+#include <string.h>
+#include <machine/elf.h>
+#include <stand.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "bootstrap.h"
+
+#include "platform/acfreebsd.h"
+#include "acconfig.h"
+#define ACPI_SYSTEM_XFACE
+#include "actypes.h"
+#include "actbl.h"
+
+#include "loader_efi.h"
+
+static EFI_GUID acpi_guid = ACPI_TABLE_GUID;
+static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID;
+
+extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp);
+
+static int elf64_exec(struct preloaded_file *amp);
+static int elf64_obj_exec(struct preloaded_file *amp);
+
+static struct file_format amd64_elf = {
+ .l_load = elf64_loadfile,
+ .l_exec = elf64_exec,
+};
+static struct file_format amd64_elf_obj = {
+ .l_load = elf64_obj_loadfile,
+ .l_exec = elf64_obj_exec,
+};
+
+struct file_format *file_formats[] = {
+ &amd64_elf,
+ &amd64_elf_obj,
+ NULL
+};
+
+static pml4_entry_t *PT4;
+static pdp_entry_t *PT3;
+static pd_entry_t *PT2;
+
+static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend,
+ uint64_t modulep, pml4_entry_t *pagetable, uint64_t entry);
+
+extern uintptr_t amd64_tramp;
+extern uint32_t amd64_tramp_size;
+
+/*
+ * There is an ELF kernel and one or more ELF modules loaded.
+ * We wish to start executing the kernel image, so make such
+ * preparations as are required, and do so.
+ */
+static int
+elf64_exec(struct preloaded_file *fp)
+{
+ struct file_metadata *md;
+ Elf_Ehdr *ehdr;
+ vm_offset_t modulep, kernend, trampcode, trampstack;
+ int err, i;
+ ACPI_TABLE_RSDP *rsdp;
+ char buf[24];
+ int revision;
+
+ /*
+ * Report the RSDP to the kernel. While this can be found with
+ * a BIOS boot, the RSDP may be elsewhere when booted from UEFI.
+ * The old code used the 'hints' method to communite this to
+ * the kernel. However, while convenient, the 'hints' method
+ * is fragile and does not work when static hints are compiled
+ * into the kernel. Instead, move to setting different tunables
+ * that start with acpi. The old 'hints' can be removed before
+ * we branch for FreeBSD 12.
+ */
+
+ rsdp = efi_get_table(&acpi20_guid);
+ if (rsdp == NULL) {
+ rsdp = efi_get_table(&acpi_guid);
+ }
+ if (rsdp != NULL) {
+ sprintf(buf, "0x%016llx", (unsigned long long)rsdp);
+ setenv("hint.acpi.0.rsdp", buf, 1);
+ setenv("acpi.rsdp", buf, 1);
+ revision = rsdp->Revision;
+ if (revision == 0)
+ revision = 1;
+ sprintf(buf, "%d", revision);
+ setenv("hint.acpi.0.revision", buf, 1);
+ setenv("acpi.revision", buf, 1);
+ strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
+ buf[sizeof(rsdp->OemId)] = '\0';
+ setenv("hint.acpi.0.oem", buf, 1);
+ setenv("acpi.oem", buf, 1);
+ sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress);
+ setenv("hint.acpi.0.rsdt", buf, 1);
+ setenv("acpi.rsdt", buf, 1);
+ if (revision >= 2) {
+ /* XXX extended checksum? */
+ sprintf(buf, "0x%016llx",
+ (unsigned long long)rsdp->XsdtPhysicalAddress);
+ setenv("hint.acpi.0.xsdt", buf, 1);
+ setenv("acpi.xsdt", buf, 1);
+ sprintf(buf, "%d", rsdp->Length);
+ setenv("hint.acpi.0.xsdt_length", buf, 1);
+ setenv("acpi.xsdt_length", buf, 1);
+ }
+ }
+
+ if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
+ return(EFTYPE);
+ ehdr = (Elf_Ehdr *)&(md->md_data);
+
+ trampcode = (vm_offset_t)0x0000000040000000;
+ err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1,
+ (EFI_PHYSICAL_ADDRESS *)&trampcode);
+ bzero((void *)trampcode, EFI_PAGE_SIZE);
+ trampstack = trampcode + EFI_PAGE_SIZE - 8;
+ bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size);
+ trampoline = (void *)trampcode;
+
+ PT4 = (pml4_entry_t *)0x0000000040000000;
+ err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3,
+ (EFI_PHYSICAL_ADDRESS *)&PT4);
+ bzero(PT4, 3 * EFI_PAGE_SIZE);
+
+ PT3 = &PT4[512];
+ PT2 = &PT3[512];
+
+ /*
+ * This is kinda brutal, but every single 1GB VM memory segment points
+ * to the same first 1GB of physical memory. But it is more than
+ * adequate.
+ */
+ for (i = 0; i < 512; i++) {
+ /* Each slot of the L4 pages points to the same L3 page. */
+ PT4[i] = (pml4_entry_t)PT3;
+ PT4[i] |= PG_V | PG_RW | PG_U;
+
+ /* Each slot of the L3 pages points to the same L2 page. */
+ PT3[i] = (pdp_entry_t)PT2;
+ PT3[i] |= PG_V | PG_RW | PG_U;
+
+ /* The L2 page slots are mapped with 2MB pages for 1GB. */
+ PT2[i] = i * (2 * 1024 * 1024);
+ PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
+ }
+
+ printf("Start @ 0x%lx ...\n", ehdr->e_entry);
+
+ efi_time_fini();
+ err = bi_load(fp->f_args, &modulep, &kernend);
+ if (err != 0) {
+ efi_time_init();
+ return(err);
+ }
+
+ dev_cleanup();
+
+ trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4,
+ ehdr->e_entry);
+
+ panic("exec returned");
+}
+
+static int
+elf64_obj_exec(struct preloaded_file *fp)
+{
+
+ return (EFTYPE);
+}
diff --git a/stand/efi/loader/arch/amd64/exc.S b/stand/efi/loader/arch/amd64/exc.S
new file mode 100644
index 000000000000..0035d4a37e20
--- /dev/null
+++ b/stand/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
diff --git a/stand/efi/loader/arch/amd64/ldscript.amd64 b/stand/efi/loader/arch/amd64/ldscript.amd64
new file mode 100644
index 000000000000..874df9b08f9e
--- /dev/null
+++ b/stand/efi/loader/arch/amd64/ldscript.amd64
@@ -0,0 +1,72 @@
+/* $FreeBSD$ */
+OUTPUT_FORMAT("elf64-x86-64-freebsd", "elf64-x86-64-freebsd", "elf64-x86-64-freebsd")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ ImageBase = .;
+ .hash : { *(.hash) } /* this MUST come first! */
+ . = ALIGN(4096);
+ .eh_frame :
+ {
+ *(.eh_frame)
+ }
+ . = ALIGN(4096);
+ .text : {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.plt)
+ } =0xCCCCCCCC
+ . = ALIGN(4096);
+ .data : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ *(.rodata1)
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
+ *(.opd)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.data1)
+ *(.plabel)
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ }
+ . = ALIGN(4096);
+ set_Xcommand_set : {
+ __start_set_Xcommand_set = .;
+ *(set_Xcommand_set)
+ __stop_set_Xcommand_set = .;
+ }
+ set_Xficl_compile_set : {
+ __start_set_Xficl_compile_set = .;
+ *(set_Xficl_compile_set)
+ __stop_set_Xficl_compile_set = .;
+ }
+ . = ALIGN(4096);
+ __gp = .;
+ .sdata : {
+ *(.got.plt .got)
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ *(dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ }
+ . = ALIGN(4096);
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+ .rela.dyn : {
+ *(.rela.data*)
+ *(.rela.got)
+ *(.rela.stab)
+ *(.relaset_*)
+ }
+ . = ALIGN(4096);
+ .reloc : { *(.reloc) }
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+}
diff --git a/stand/efi/loader/arch/amd64/start.S b/stand/efi/loader/arch/amd64/start.S
new file mode 100644
index 000000000000..774ef4fa7901
--- /dev/null
+++ b/stand/efi/loader/arch/amd64/start.S
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm@hpl.hp.com>.
+ * Copyright (C) 2005 Intel Co.
+ * Contributed by Fenghua Yu <fenghua.yu@intel.com>.
+ * All rights reserved.
+ *
+ * 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.
+ * 3. Neither the name of Hewlett-Packard Co. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+/*
+ * crt0-efi-x86_64.S - x86_64 EFI startup code.
+ * $FreeBSD$
+ */
+
+ .text
+ .align 4
+
+ .globl _start
+_start:
+ subq $8, %rsp
+ pushq %rcx
+ pushq %rdx
+
+0:
+ lea ImageBase(%rip), %rdi
+ lea _DYNAMIC(%rip), %rsi
+
+ popq %rcx
+ popq %rdx
+ pushq %rcx
+ pushq %rdx
+ call self_reloc
+
+ popq %rdi
+ popq %rsi
+
+ call efi_main
+ addq $8, %rsp
+
+.exit:
+ ret
+
+ /*
+ * hand-craft a dummy .reloc section so EFI knows it's a relocatable
+ * executable:
+ */
+
+ .data
+ .section .reloc, "a"
+ .long 0
+ .long 10
+ .word 0
diff --git a/stand/efi/loader/arch/amd64/trap.c b/stand/efi/loader/arch/amd64/trap.c
new file mode 100644
index 000000000000..e8cf188cf22f
--- /dev/null
+++ b/stand/efi/loader/arch/amd64/trap.c
@@ -0,0 +1,408 @@
+/*-
+ * 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)
+{
+
+ /*
+ * printf() depends on loader runtime and UEFI firmware health
+ * to produce the console output, in case of exception, the
+ * loader or firmware runtime may fail to support the 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;
+ /*
+ * We reuse uefi selector for the code segment for the exception
+ * handler code, while the reason for the fault might be the
+ * corruption of that gdt entry. On the other hand, allocating
+ * our own descriptor might be not much better, if gdt is corrupted.
+ */
+ loader_idt_e->gd_selector = fw_idt_e->gd_selector;
+ 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);