Index: projects/uefi/sys/boot/i386/efi/Makefile =================================================================== --- projects/uefi/sys/boot/i386/efi/Makefile (revision 247213) +++ projects/uefi/sys/boot/i386/efi/Makefile (revision 247214) @@ -1,97 +1,98 @@ # $FreeBSD$ NO_MAN= WITHOUT_SSP= BUILDING_EFI= .include PROG= loader.sym INTERNALPROG= # architecture-specific loader code SRCS= main.c exec.c conf.c vers.c reloc.c elf32_freebsd.c elf64_freebsd.c SRCS+= x86_efi_copy.c bootinfo.c bootinfo64.c autoload.c devicename.c efimd.c +SRCS+= amd64_tramp.S .PATH: ${.CURDIR}/${MACHINE_CPUARCH} SRCS+= start.S CFLAGS+= -fPIC CFLAGS+= -I. CFLAGS+= -I${.CURDIR}/../../efi/include CFLAGS+= -I${.CURDIR}/../../efi/include/${MACHINE_CPUARCH} CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include CFLAGS+= -I${.CURDIR}/../../.. .if ${MK_FORTH} != "no" BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH CFLAGS+= -I${.CURDIR}/../../ficl CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH} .if ${MACHINE_CPUARCH} == "amd64" LIBFICL= ${.OBJDIR}/../../ficl64/libficl.a .else LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif .endif # Include bcache code. HAVE_BCACHE= yes # Always add MI sources .PATH: ${.CURDIR}/../../common .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common FILES= loader.efi FILESMODE_loader.efi= ${BINMODE} LDSCRIPT= ${.CURDIR}/ldscript.${MACHINE_CPUARCH} LDFLAGS= -Wl,-T${LDSCRIPT} -Wl,-Bsymbolic -shared -Wl,-znocombreloc ${PROG}: ${LDSCRIPT} CLEANFILES= vers.c loader.efi NEWVERSWHAT= "EFI loader" ${MACHINE_CPUARCH} vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} OBJCOPY?= objcopy OBJDUMP?= objdump .if ${MACHINE_CPUARCH} == "amd64" EFI_TARGET= efi-app-x86_64 .else EFI_TARGET= efi-app-ia32 .endif loader.efi: loader.sym if [ `${OBJDUMP} -t ${.ALLSRC} | fgrep '*UND*' | wc -l` != 0 ]; then \ ${OBJDUMP} -t ${.ALLSRC} | fgrep '*UND*'; \ exit 1; \ fi ${OBJCOPY} -j .text -j .sdata -j .data \ -j .dynamic -j .dynsym -j .rel.dyn \ -j .rela.dyn -j .reloc -j .eh_frame -j set_Xcommand_set \ --target=${EFI_TARGET} ${.ALLSRC} ${.TARGET} LIBEFI= ${.OBJDIR}/../../efi/libefi/libefi.a CFLAGS+= -I${.CURDIR}/../libi386 CFLAGS+= -I${.CURDIR}/../btx/lib CFLAGS+= -I${.CURDIR}/../../common DPADD= ${LIBFICL} ${LIBEFI} ${LIBSTAND} LDADD= ${LIBFICL} ${LIBEFI} ${LIBSTAND} .include .if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine CLEANFILES+= machine machine: ln -sf ${.CURDIR}/../../../amd64/include machine .endif Index: projects/uefi/sys/boot/i386/efi/amd64_tramp.S =================================================================== --- projects/uefi/sys/boot/i386/efi/amd64_tramp.S (nonexistent) +++ projects/uefi/sys/boot/i386/efi/amd64_tramp.S (revision 247214) @@ -0,0 +1,34 @@ +#include + + .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 + + call %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 Index: projects/uefi/sys/boot/i386/efi/elf64_freebsd.c =================================================================== --- projects/uefi/sys/boot/i386/efi/elf64_freebsd.c (revision 247213) +++ projects/uefi/sys/boot/i386/efi/elf64_freebsd.c (revision 247214) @@ -1,185 +1,184 @@ /*- * Copyright (c) 1998 Michael Smith * 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 __FBSDID("$FreeBSD$"); #define __ELF_WORD_SIZE 64 #include #include #include #include #include #include #include #include #include #include "bootstrap.h" #include "../libi386/libi386.h" #include "../btx/lib/btxv86.h" #include "platform/acfreebsd.h" #include "acconfig.h" #define ACPI_SYSTEM_XFACE #include "actypes.h" #include "actbl.h" #include "x86_efi_copy.h" static EFI_GUID acpi_guid = ACPI_TABLE_GUID; static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID; extern int bi_load64(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); struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; #define PG_V 0x001 #define PG_RW 0x002 #define PG_U 0x004 #define PG_PS 0x080 typedef u_int64_t p4_entry_t; typedef u_int64_t p3_entry_t; typedef u_int64_t p2_entry_t; static p4_entry_t *PT4; static p3_entry_t *PT3; static p2_entry_t *PT2; +static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend, + uint64_t modulep, p4_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, pagetable; - uint32_t mp, ke; + vm_offset_t modulep, kernend, trampcode, trampstack; int err, i; ACPI_TABLE_RSDP *rsdp; char buf[24]; int revision; rsdp = efi_get_table(&acpi20_guid); if (rsdp == NULL) { rsdp = efi_get_table(&acpi_guid); } if (rsdp != NULL) { sprintf(buf, "0x%016llx", rsdp); setenv("hint.acpi.0.rsdp", buf, 1); revision = rsdp->Revision; if (revision == 0) revision = 1; sprintf(buf, "%d", revision); setenv("hint.acpi.0.revision", buf, 1); strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); buf[sizeof(rsdp->OemId)] = '\0'; setenv("hint.acpi.0.oem", buf, 1); sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); setenv("hint.acpi.0.rsdt", buf, 1); if (revision >= 2) { /* XXX extended checksum? */ sprintf(buf, "0x%016llx", rsdp->XsdtPhysicalAddress); setenv("hint.acpi.0.xsdt", buf, 1); sprintf(buf, "%d", rsdp->Length); setenv("hint.acpi.0.xsdt_length", buf, 1); } } if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) return(EFTYPE); ehdr = (Elf_Ehdr *)&(md->md_data); - PT4 = (p4_entry_t *)0x00000000fffff000; + 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 = (p4_entry_t *)0x0000000040000000; err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3, (EFI_PHYSICAL_ADDRESS *)&PT4); - bzero(PT4, 3 * PAGE_SIZE); + 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 level 4 pages points to the same level 3 page */ PT4[i] = (p4_entry_t)PT3; PT4[i] |= PG_V | PG_RW | PG_U; /* Each slot of the level 3 pages points to the same level 2 page */ PT3[i] = (p3_entry_t)PT2; PT3[i] |= PG_V | PG_RW | PG_U; /* The level 2 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; } err = bi_load64(fp->f_args, &modulep, &kernend); if (err != 0) return(err); printf("Start @ 0x%lx ...\n", ehdr->e_entry); ldr_enter(fp->f_name); dev_cleanup(); - x86_efi_copy_finish(); - - mp = modulep & 0xffffffff; - ke = kernend & 0xffffffff; - pagetable = (uintptr_t)PT4; - __asm __volatile( - "movl %0, %%eax;" - "pushq %%rax;" - "movl %1, %%eax;" - "salq $32, %%rax;" - "pushq %%rax;" - "movq %2, %%rax;" - "pushq %%rax;" - "movq %3, %%rax;" - "movq %%rax, %%cr3;" - "ret" - :: "r" (ke), "r" (mp), "r" (ehdr->e_entry), "r" (PT4)); + trampoline(trampstack, x86_efi_copy_finish, kernend, modulep, PT4, + ehdr->e_entry); panic("exec returned"); } static int elf64_obj_exec(struct preloaded_file *fp) { return (EFTYPE); } Index: projects/uefi/sys/boot/i386/efi/x86_efi_copy.c =================================================================== --- projects/uefi/sys/boot/i386/efi/x86_efi_copy.c (revision 247213) +++ projects/uefi/sys/boot/i386/efi/x86_efi_copy.c (revision 247214) @@ -1,98 +1,103 @@ /*- * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include -#define STAGE_PAGES 8000 /* 32MB */ +#define STAGE_PAGES 8192 /* 32MB */ EFI_PHYSICAL_ADDRESS staging; int stage_offset_set = 0; ssize_t stage_offset; int x86_efi_copy_init(void) { EFI_STATUS status; status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, STAGE_PAGES, &staging); if (EFI_ERROR(status)) { printf("failed to allocate staging area: %d\n", status & EFI_ERROR_MASK); return (status); } printf("x86_efi_copyinit>>> staging=0x%016x\n", staging); return (0); } ssize_t x86_efi_copyin(const void *src, vm_offset_t dest, const size_t len) { if (!stage_offset_set) { stage_offset = (vm_offset_t)staging - dest; stage_offset_set = 1; } bcopy(src, (void *)(dest + stage_offset), len); return (len); } ssize_t x86_efi_copyout(const vm_offset_t src, void *dest, const size_t len) { bcopy((void *)(src + stage_offset), dest, len); return (len); } ssize_t x86_efi_readin(const int fd, vm_offset_t dest, const size_t len) { return (read(fd, (void *)(dest + stage_offset), len)); } void x86_efi_copy_finish(void) { + uint64_t *src, *dst, *last; - bcopy((void *)staging, (void *)(staging - stage_offset), - STAGE_PAGES * EFI_PAGE_SIZE); + src = (uint64_t *)staging; + dst = (uint64_t *)(staging - stage_offset); + last = (uint64_t *)(staging + STAGE_PAGES * EFI_PAGE_SIZE); + + while (src < last) + *dst++ = *src++; }