aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/mk/src.opts.mk4
-rw-r--r--stand/kboot/arch/amd64/Makefile.inc8
-rw-r--r--stand/kboot/arch/amd64/amd64_tramp.S76
-rw-r--r--stand/kboot/arch/amd64/conf.c104
-rw-r--r--stand/kboot/arch/amd64/elf64_freebsd.c345
-rw-r--r--stand/kboot/arch/amd64/host_syscall.S29
-rw-r--r--stand/kboot/arch/amd64/ldscript.amd6472
-rw-r--r--stand/kboot/arch/amd64/multiboot2.h1
-rw-r--r--stand/kboot/arch/amd64/syscall_nr.h15
9 files changed, 652 insertions, 2 deletions
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index c580b9aafc0e..a7e414fd0432 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -301,8 +301,8 @@ BROKEN_OPTIONS+=EFI
.if ${__T:Mpowerpc*} == ""
BROKEN_OPTIONS+=LOADER_OFW
.endif
-# KBOOT is only for powerpc64 (powerpc64le broken)
-.if ${__T} != "powerpc64"
+# KBOOT is only for powerpc64 (powerpc64le broken) and kinda for amd64
+.if ${__T} != "powerpc64" && ${__T} != "amd64"
BROKEN_OPTIONS+=LOADER_KBOOT
.endif
# UBOOT is only for arm, and big-endian powerpc
diff --git a/stand/kboot/arch/amd64/Makefile.inc b/stand/kboot/arch/amd64/Makefile.inc
new file mode 100644
index 000000000000..fb954e798599
--- /dev/null
+++ b/stand/kboot/arch/amd64/Makefile.inc
@@ -0,0 +1,8 @@
+SRCS+= conf.c host_syscall.S amd64_tramp.S elf64_freebsd.c
+
+CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include
+# load address. set in linker script
+RELOC?= 0x0
+CFLAGS+= -DRELOC=${RELOC}
+
+LDFLAGS= -nostdlib -static -T ${.CURDIR}/arch/${MACHINE_ARCH}/ldscript.amd64
diff --git a/stand/kboot/arch/amd64/amd64_tramp.S b/stand/kboot/arch/amd64/amd64_tramp.S
new file mode 100644
index 000000000000..877705407f92
--- /dev/null
+++ b/stand/kboot/arch/amd64/amd64_tramp.S
@@ -0,0 +1,76 @@
+/*-
+ * 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>
+
+#define ASM_FILE
+#include "multiboot2.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:
+
+/* void multiboot2_exec(uint64_t entry, uint64_t multiboot_info, uint64_t stack) */
+ .globl multiboot2_exec
+multiboot2_exec:
+ movq %rdx,%rsp
+ pushq %rdi
+ movq %rsi,%rbx
+ movq $MULTIBOOT2_BOOTLOADER_MAGIC,%rax
+ ret
+
+ .data
+ .globl amd64_tramp_size
+amd64_tramp_size:
+ .long amd64_tramp_end-amd64_tramp
diff --git a/stand/kboot/arch/amd64/conf.c b/stand/kboot/arch/amd64/conf.c
new file mode 100644
index 000000000000..b840d008a347
--- /dev/null
+++ b/stand/kboot/arch/amd64/conf.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (C) 1999 Michael Smith <msmith@freebsd.org>
+ * 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$");
+
+#include <stand.h>
+#include "bootstrap.h"
+
+#if defined(LOADER_NET_SUPPORT)
+#include "dev_net.h"
+#endif
+
+extern struct devsw hostdisk;
+
+/*
+ * We could use linker sets for some or all of these, but
+ * then we would have to control what ended up linked into
+ * the bootstrap. So it's easier to conditionalise things
+ * here.
+ *
+ * XXX rename these arrays to be consistent and less namespace-hostile
+ */
+
+/* Exported for libsa */
+struct devsw *devsw[] = {
+#if defined(LOADER_DISK_SUPPORT) || defined(LOADER_CD9660_SUPPORT)
+ &hostdisk,
+#endif
+#if defined(LOADER_NET_SUPPORT)
+ &netdev,
+#endif
+ NULL
+};
+
+struct fs_ops *file_system[] = {
+#if defined(LOADER_UFS_SUPPORT)
+ &ufs_fsops,
+#endif
+#if defined(LOADER_CD9660_SUPPORT)
+ &cd9660_fsops,
+#endif
+#if defined(LOADER_EXT2FS_SUPPORT)
+ &ext2fs_fsops,
+#endif
+#if defined(LOADER_NFS_SUPPORT)
+ &nfs_fsops,
+#endif
+#if defined(LOADER_TFTP_SUPPORT)
+ &tftp_fsops,
+#endif
+#if defined(LOADER_GZIP_SUPPORT)
+ &gzipfs_fsops,
+#endif
+#if defined(LOADER_BZIP2_SUPPORT)
+ &bzipfs_fsops,
+#endif
+ &dosfs_fsops,
+ NULL
+};
+
+extern struct netif_driver kbootnet;
+
+struct netif_driver *netif_drivers[] = {
+#if 0 /* XXX */
+#if defined(LOADER_NET_SUPPORT)
+ &kbootnet,
+#endif
+#endif
+ NULL,
+};
+
+/*
+ * Consoles
+ */
+extern struct console hostconsole;
+
+struct console *consoles[] = {
+ &hostconsole,
+ NULL
+};
diff --git a/stand/kboot/arch/amd64/elf64_freebsd.c b/stand/kboot/arch/amd64/elf64_freebsd.c
new file mode 100644
index 000000000000..a45a0db32e44
--- /dev/null
+++ b/stand/kboot/arch/amd64/elf64_freebsd.c
@@ -0,0 +1,345 @@
+/*-
+ * 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>
+
+#ifdef EFI
+#include <efi.h>
+#include <efilib.h>
+#endif
+
+#include "bootstrap.h"
+
+#include "platform/acfreebsd.h"
+#include "acconfig.h"
+#define ACPI_SYSTEM_XFACE
+#include "actypes.h"
+#include "actbl.h"
+
+#ifdef EFI
+#include "loader_efi.h"
+#endif
+
+#ifdef EFI
+static EFI_GUID acpi_guid = ACPI_TABLE_GUID;
+static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID;
+#endif
+
+#ifdef EFI
+#define LOADER_PAGE_SIZE EFI_PAGE_SIZE
+#else
+#define LOADER_PAGE_SIZE 8192
+#endif
+
+extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp,
+ bool exit_bs);
+
+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,
+};
+
+#if 0
+extern struct file_format multiboot2;
+extern struct file_format multiboot2_obj;
+#endif
+
+struct file_format *file_formats[] = {
+#if 0
+ &multiboot2,
+ &multiboot2_obj,
+#endif
+ &amd64_elf,
+ &amd64_elf_obj,
+ NULL
+};
+
+#ifdef EFI
+static pml4_entry_t *PT4;
+static pdp_entry_t *PT3;
+static pdp_entry_t *PT3_l, *PT3_u;
+static pd_entry_t *PT2;
+static pd_entry_t *PT2_l0, *PT2_l1, *PT2_l2, *PT2_l3, *PT2_u0, *PT2_u1;
+
+extern EFI_PHYSICAL_ADDRESS staging;
+
+static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend,
+ uint64_t modulep, pml4_entry_t *pagetable, uint64_t entry);
+#endif
+
+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)
+{
+#ifdef EFI
+ 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;
+ bool copy_auto;
+
+#ifdef EFI
+ copy_auto = copy_staging == COPY_STAGING_AUTO;
+ if (copy_auto)
+ copy_staging = fp->f_kernphys_relocatable ?
+ COPY_STAGING_DISABLE : COPY_STAGING_ENABLE;
+#else
+ copy_auto = COPY_STAGING_DISABLE; /* XXX */
+#endif
+
+ /*
+ * 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.
+ */
+
+#ifdef EFI
+ rsdp = efi_get_table(&acpi20_guid);
+ if (rsdp == NULL) {
+ rsdp = efi_get_table(&acpi_guid);
+ }
+#else
+ rsdp = NULL;
+#warning "write me"
+#endif
+ 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 = copy_staging == COPY_STAGING_ENABLE ?
+ (vm_offset_t)0x0000000040000000 /* 1G */ :
+ (vm_offset_t)0x0000000100000000; /* 4G */;
+#ifdef EFI
+ err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1,
+ (EFI_PHYSICAL_ADDRESS *)&trampcode);
+ if (EFI_ERROR(err)) {
+ printf("Unable to allocate trampoline\n");
+ if (copy_auto)
+ copy_staging = COPY_STAGING_AUTO;
+ return (ENOMEM);
+ }
+#else
+#warning "Write me"
+#endif
+ bzero((void *)trampcode, LOADER_PAGE_SIZE);
+ trampstack = trampcode + LOADER_PAGE_SIZE - 8;
+ bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size);
+ trampoline = (void *)trampcode;
+
+ if (copy_staging == COPY_STAGING_ENABLE) {
+ PT4 = (pml4_entry_t *)0x0000000040000000;
+#ifdef EFI
+ err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3,
+ (EFI_PHYSICAL_ADDRESS *)&PT4);
+ if (EFI_ERROR(err)) {
+ printf("Unable to allocate trampoline page table\n");
+ BS->FreePages(trampcode, 1);
+ if (copy_auto)
+ copy_staging = COPY_STAGING_AUTO;
+ return (ENOMEM);
+ }
+#else
+#warning "Write me"
+#endif
+ bzero(PT4, 3 * LOADER_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 < NPTEPG; 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;
+
+ /*
+ * Each slot of the L3 pages points to the
+ * same L2 page.
+ */
+ PT3[i] = (pdp_entry_t)PT2;
+ PT3[i] |= PG_V | PG_RW;
+
+ /*
+ * The L2 page slots are mapped with 2MB pages for 1GB.
+ */
+ PT2[i] = (pd_entry_t)i * (2 * 1024 * 1024);
+ PT2[i] |= PG_V | PG_RW | PG_PS;
+ }
+ } else {
+ PT4 = (pml4_entry_t *)0x0000000100000000; /* 4G */
+#ifdef EFI
+ err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 9,
+ (EFI_PHYSICAL_ADDRESS *)&PT4);
+ if (EFI_ERROR(err)) {
+ printf("Unable to allocate trampoline page table\n");
+ BS->FreePages(trampcode, 9);
+ if (copy_auto)
+ copy_staging = COPY_STAGING_AUTO;
+ return (ENOMEM);
+ }
+#else
+#warning "Write me"
+#endif
+
+ bzero(PT4, 9 * LOADER_PAGE_SIZE);
+
+ PT3_l = &PT4[NPML4EPG * 1];
+ PT3_u = &PT4[NPML4EPG * 2];
+ PT2_l0 = &PT4[NPML4EPG * 3];
+ PT2_l1 = &PT4[NPML4EPG * 4];
+ PT2_l2 = &PT4[NPML4EPG * 5];
+ PT2_l3 = &PT4[NPML4EPG * 6];
+ PT2_u0 = &PT4[NPML4EPG * 7];
+ PT2_u1 = &PT4[NPML4EPG * 8];
+
+ /* 1:1 mapping of lower 4G */
+ PT4[0] = (pml4_entry_t)PT3_l | PG_V | PG_RW;
+ PT3_l[0] = (pdp_entry_t)PT2_l0 | PG_V | PG_RW;
+ PT3_l[1] = (pdp_entry_t)PT2_l1 | PG_V | PG_RW;
+ PT3_l[2] = (pdp_entry_t)PT2_l2 | PG_V | PG_RW;
+ PT3_l[3] = (pdp_entry_t)PT2_l3 | PG_V | PG_RW;
+ for (i = 0; i < 4 * NPDEPG; i++) {
+ PT2_l0[i] = ((pd_entry_t)i << PDRSHIFT) | PG_V |
+ PG_RW | PG_PS;
+ }
+
+ /* mapping of kernel 2G below top */
+ PT4[NPML4EPG - 1] = (pml4_entry_t)PT3_u | PG_V | PG_RW;
+ PT3_u[NPDPEPG - 2] = (pdp_entry_t)PT2_u0 | PG_V | PG_RW;
+ PT3_u[NPDPEPG - 1] = (pdp_entry_t)PT2_u1 | PG_V | PG_RW;
+ /* compat mapping of phys @0 */
+ PT2_u0[0] = PG_PS | PG_V | PG_RW;
+ /* this maps past staging area */
+ for (i = 1; i < 2 * NPDEPG; i++) {
+ PT2_u0[i] = ((pd_entry_t)staging +
+ ((pd_entry_t)i - 1) * NBPDR) |
+ PG_V | PG_RW | PG_PS;
+ }
+ }
+
+ printf("staging %#lx (%scopying) tramp %p PT4 %p\n",
+ staging, copy_staging == COPY_STAGING_ENABLE ? "" : "not ",
+ trampoline, PT4);
+ printf("Start @ 0x%lx ...\n", ehdr->e_entry);
+
+#ifdef EFI
+ efi_time_fini();
+#endif
+ err = bi_load(fp->f_args, &modulep, &kernend, true);
+ if (err != 0) {
+#ifdef EFI
+ efi_time_init();
+#endif
+ if (copy_auto)
+ copy_staging = COPY_STAGING_AUTO;
+ return (err);
+ }
+
+ dev_cleanup();
+
+ trampoline(trampstack, copy_staging == COPY_STAGING_ENABLE ?
+ efi_copy_finish : efi_copy_finish_nop, kernend, modulep,
+ PT4, ehdr->e_entry);
+#endif
+
+ panic("exec returned");
+}
+
+static int
+elf64_obj_exec(struct preloaded_file *fp)
+{
+
+ return (EFTYPE);
+}
diff --git a/stand/kboot/arch/amd64/host_syscall.S b/stand/kboot/arch/amd64/host_syscall.S
new file mode 100644
index 000000000000..5bf0fca0cec1
--- /dev/null
+++ b/stand/kboot/arch/amd64/host_syscall.S
@@ -0,0 +1,29 @@
+#include <machine/asm.h>
+
+/*
+ * Emulate the Linux system call interface. The system call number is set in
+ * %rax, and %rdi, %rsi, %rdx, %r10, %r8, %r9 have the 6 system call
+ * arguments. errno is returned as a negative value, but we use it more as a
+ * flag something went wrong rather than using its value.
+ *
+ * Note: For system calls, we use %r10 instead of %rcx for the 4th argument.
+ * See section A.2.1 for the Linux calling conventions of the ABI spec
+ * https://web.archive.org/web/20160801075146/http://www.x86-64.org/documentation/abi.pdf
+ * In addition to the below, %r11 and %rcx are destroyed, negative
+ * values are ERRNO for %rax between -1 and -4095 otherwise the system
+ * call is successful. Unlike other Unix systems, carry isn't used to
+ * signal an error in the system call. We expose the raw system call
+ * result, rather than do the POSIX converion to -1 and setting errno.
+ */
+ENTRY(host_syscall)
+ movq %rdi, %rax /* SYS_ number in %rax */
+ movq %rsi, %rdi /* arg2 -> 1 */
+ movq %rdx, %rsi /* arg3 -> 2 */
+ movq %rcx, %rdx /* arg4 -> 3 */
+ movq %r8, %r10 /* arg5 -> 4 */
+ movq %r9, %r8 /* arg6 -> 5 */
+ movq 8(%rsp),%r9 /* arg7 -> 6 from stack. */
+ syscall
+ ret
+/* Note: We're exposing the raw return value to the caller */
+END(host_syscall)
diff --git a/stand/kboot/arch/amd64/ldscript.amd64 b/stand/kboot/arch/amd64/ldscript.amd64
new file mode 100644
index 000000000000..bbfe47cd4ef5
--- /dev/null
+++ b/stand/kboot/arch/amd64/ldscript.amd64
@@ -0,0 +1,72 @@
+/* $FreeBSD$ */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x401000;
+ 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/kboot/arch/amd64/multiboot2.h b/stand/kboot/arch/amd64/multiboot2.h
new file mode 100644
index 000000000000..bf673da66c2c
--- /dev/null
+++ b/stand/kboot/arch/amd64/multiboot2.h
@@ -0,0 +1 @@
+#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
diff --git a/stand/kboot/arch/amd64/syscall_nr.h b/stand/kboot/arch/amd64/syscall_nr.h
new file mode 100644
index 000000000000..193368364bf3
--- /dev/null
+++ b/stand/kboot/arch/amd64/syscall_nr.h
@@ -0,0 +1,15 @@
+#define SYS_read 0
+#define SYS_write 1
+#define SYS_open 2
+#define SYS_close 3
+#define SYS_gettimeofday 96
+#define SYS_reboot 169
+#define SYS_mmap 9
+#define SYS_uname 63
+#define SYS_lseek 8
+#define SYS_getdents 78
+#define SYS_select 23
+#define __NR_kexec_load 246
+
+#define KEXEC_ARCH_X86_64 62
+#define KEXEC_ARCH KEXEC_ARCH_X86_64