1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 2014 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/boot/efi/loader/arch/amd64/elf64_freebsd.c 293724 2016-01-12 02:17:39Z smh $ 28 */ 29 30 #define __ELF_WORD_SIZE 64 31 #include <sys/param.h> 32 #include <sys/exec.h> 33 #include <sys/linker.h> 34 #include <string.h> 35 #include <machine/elf.h> 36 #include <stand.h> 37 38 #include <efi.h> 39 #include <efilib.h> 40 41 #include "bootstrap.h" 42 43 #include "acpi.h" 44 45 #include "loader_efi.h" 46 47 static EFI_GUID acpi_guid = ACPI_TABLE_GUID; 48 static EFI_GUID acpi20_guid = EFI_ACPI_TABLE_GUID; 49 50 extern int bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp); 51 52 static int elf64_exec(struct preloaded_file *amp); 53 static int elf64_obj_exec(struct preloaded_file *amp); 54 55 static struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; 56 static struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; 57 58 struct file_format *file_formats[] = { 59 &amd64_elf, 60 &amd64_elf_obj, 61 NULL 62 }; 63 64 #define PG_V 0x001 65 #define PG_RW 0x002 66 #define PG_U 0x004 67 #define PG_PS 0x080 68 69 typedef u_int64_t p4_entry_t; 70 typedef u_int64_t p3_entry_t; 71 typedef u_int64_t p2_entry_t; 72 static p4_entry_t *PT4; 73 static p3_entry_t *PT3; 74 static p2_entry_t *PT2; 75 76 static void (*trampoline)(uint64_t stack, void *copy_finish, uint64_t kernend, 77 uint64_t modulep, p4_entry_t *pagetable, 78 uint64_t entry); 79 80 extern uintptr_t amd64_tramp; 81 extern uint32_t amd64_tramp_size; 82 83 /* 84 * There is an ELF kernel and one or more ELF modules loaded. 85 * We wish to start executing the kernel image, so make such 86 * preparations as are required, and do so. 87 */ 88 static int 89 elf64_exec(struct preloaded_file *fp) 90 { 91 struct file_metadata *md; 92 Elf_Ehdr *ehdr; 93 vm_offset_t modulep, kernend, trampcode, trampstack; 94 int err, i; 95 ACPI_TABLE_RSDP *rsdp; 96 char buf[24]; 97 int revision; 98 99 rsdp = efi_get_table(&acpi20_guid); 100 if (rsdp == NULL) { 101 rsdp = efi_get_table(&acpi_guid); 102 } 103 if (rsdp != NULL) { 104 sprintf(buf, "0x%016llx", (unsigned long long)rsdp); 105 setenv("hint.acpi.0.rsdp", buf, 1); 106 revision = rsdp->Revision; 107 if (revision == 0) 108 revision = 1; 109 sprintf(buf, "%d", revision); 110 setenv("hint.acpi.0.revision", buf, 1); 111 strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId)); 112 buf[sizeof(rsdp->OemId)] = '\0'; 113 setenv("hint.acpi.0.oem", buf, 1); 114 sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress); 115 setenv("hint.acpi.0.rsdt", buf, 1); 116 if (revision >= 2) { 117 /* XXX extended checksum? */ 118 sprintf(buf, "0x%016llx", 119 (unsigned long long)rsdp->XsdtPhysicalAddress); 120 setenv("hint.acpi.0.xsdt", buf, 1); 121 sprintf(buf, "%d", rsdp->Length); 122 setenv("hint.acpi.0.xsdt_length", buf, 1); 123 } 124 } 125 126 if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) 127 return(EFTYPE); 128 ehdr = (Elf_Ehdr *)&(md->md_data); 129 130 trampcode = (vm_offset_t)0x0000000040000000; 131 err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 1, 132 (EFI_PHYSICAL_ADDRESS *)&trampcode); 133 bzero((void *)trampcode, EFI_PAGE_SIZE); 134 trampstack = trampcode + EFI_PAGE_SIZE - 8; 135 bcopy((void *)&amd64_tramp, (void *)trampcode, amd64_tramp_size); 136 trampoline = (void *)trampcode; 137 138 PT4 = (p4_entry_t *)0x0000000040000000; 139 err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData, 3, 140 (EFI_PHYSICAL_ADDRESS *)&PT4); 141 bzero(PT4, 3 * EFI_PAGE_SIZE); 142 143 PT3 = &PT4[512]; 144 PT2 = &PT3[512]; 145 146 /* 147 * This is kinda brutal, but every single 1GB VM memory segment points 148 * to the same first 1GB of physical memory. But it is more than 149 * adequate. 150 */ 151 for (i = 0; i < 512; i++) { 152 /* Each slot of the L4 pages points to the same L3 page. */ 153 PT4[i] = (p4_entry_t)PT3; 154 PT4[i] |= PG_V | PG_RW | PG_U; 155 156 /* Each slot of the L3 pages points to the same L2 page. */ 157 PT3[i] = (p3_entry_t)PT2; 158 PT3[i] |= PG_V | PG_RW | PG_U; 159 160 /* The L2 page slots are mapped with 2MB pages for 1GB. */ 161 PT2[i] = i * (2 * 1024 * 1024); 162 PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; 163 } 164 165 printf("Start @ 0x%lx ...\n", ehdr->e_entry); 166 167 err = bi_load(fp->f_args, &modulep, &kernend); 168 if (err != 0) 169 return(err); 170 171 dev_cleanup(); 172 173 trampoline(trampstack, efi_copy_finish, kernend, modulep, PT4, 174 ehdr->e_entry); 175 176 panic("exec returned"); 177 } 178 179 static int 180 elf64_obj_exec(struct preloaded_file *fp) 181 { 182 return (EFTYPE); 183 } 184