Path: blob/main/stand/efi/loader/arch/i386/elf64_freebsd.c
34889 views
/*-1* Copyright (c) 1998 Michael Smith <[email protected]>2* Copyright (c) 2014 The FreeBSD Foundation3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#define __ELF_WORD_SIZE 6428#include <sys/param.h>29#include <sys/linker.h>30#include <vm/vm.h>31#include <vm/pmap.h>32#include <machine/elf.h>33#include <machine/pmap_pae.h>34#include <machine/segments.h>3536#include <efi.h>37#include <efilib.h>3839#include "bootstrap.h"4041#include "loader_efi.h"4243static int elf64_exec(struct preloaded_file *amp);44static int elf64_obj_exec(struct preloaded_file *amp);4546static struct file_format amd64_elf = {47.l_load = elf64_loadfile,48.l_exec = elf64_exec49};5051static struct file_format amd64_elf_obj = {52.l_load = elf64_obj_loadfile,53.l_exec = elf64_obj_exec54};5556struct file_format *file_formats[] = {57&amd64_elf,58&amd64_elf_obj,59NULL60};6162/*63* i386's pmap_pae.h doesn't provide this, so64* just typedef our own.65*/66typedef pdpt_entry_t pml4_entry_t;6768static void (*trampoline)(uint32_t stack, void *copy_finish, uint32_t kernend,69uint32_t modulep, uint64_t *pagetable, void *gdtr, uint64_t entry);7071extern void *amd64_tramp;72extern uint32_t amd64_tramp_size;7374/*75* There is an ELF kernel and one or more ELF modules loaded.76* We wish to start executing the kernel image, so make such77* preparations as are required, and do so.78*/79static int80elf64_exec(struct preloaded_file *fp)81{82/*83* segments.h gives us a 32-bit gdtr, but84* we want a 64-bit one, so define our own.85*/86struct {87uint16_t rd_limit;88uint64_t rd_base;89} __packed *gdtr;90EFI_PHYSICAL_ADDRESS ptr;91EFI_ALLOCATE_TYPE type;92EFI_STATUS err;93struct file_metadata *md;94Elf_Ehdr *ehdr;95pml4_entry_t *PT4;96pdpt_entry_t *PT3;97pd_entry_t *PT2;98struct user_segment_descriptor *gdt;99vm_offset_t modulep, kernend, trampstack;100int i;101102switch (copy_staging) {103case COPY_STAGING_ENABLE:104type = AllocateMaxAddress;105break;106case COPY_STAGING_DISABLE:107type = AllocateAnyPages;108break;109case COPY_STAGING_AUTO:110type = fp->f_kernphys_relocatable ?111AllocateAnyPages : AllocateMaxAddress;112break;113}114115if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)116return (EFTYPE);117ehdr = (Elf_Ehdr *)&(md->md_data);118119ptr = G(1);120err = BS->AllocatePages(type, EfiLoaderCode,121EFI_SIZE_TO_PAGES(amd64_tramp_size), &ptr);122if (EFI_ERROR(err)) {123printf("Unable to allocate trampoline\n");124return (ENOMEM);125}126127trampoline = (void *)(uintptr_t)ptr;128bcopy(&amd64_tramp, trampoline, amd64_tramp_size);129130/*131* Allocate enough space for the GDTR + two GDT segments +132* our temporary stack (28 bytes).133*/134#define DATASZ (sizeof(*gdtr) + \135sizeof(struct user_segment_descriptor) * 2 + 28)136137ptr = G(1);138err = BS->AllocatePages(type, EfiLoaderData,139EFI_SIZE_TO_PAGES(DATASZ), &ptr);140if (EFI_ERROR(err)) {141printf("Unable to allocate GDT and stack\n");142BS->FreePages((uintptr_t)trampoline, 1);143return (ENOMEM);144}145146trampstack = ptr + DATASZ;147148#undef DATASZ149150gdt = (void *)(uintptr_t)ptr;151gdt[0] = (struct user_segment_descriptor) { 0 };152gdt[1] = (struct user_segment_descriptor) {153.sd_p = 1, .sd_long = 1, .sd_type = SDT_MEMERC154};155156gdtr = (void *)(uintptr_t)(ptr +157sizeof(struct user_segment_descriptor) * 2);158gdtr->rd_limit = sizeof(struct user_segment_descriptor) * 2 - 1;159gdtr->rd_base = (uintptr_t)gdt;160161if (type == AllocateMaxAddress) {162/* Copy staging enabled */163164ptr = G(1);165err = BS->AllocatePages(AllocateMaxAddress, EfiLoaderData,166EFI_SIZE_TO_PAGES(512 * 3 * sizeof(uint64_t)), &ptr);167if (EFI_ERROR(err)) {168printf("Unable to allocate trampoline page table\n");169BS->FreePages((uintptr_t)trampoline, 1);170BS->FreePages((uintptr_t)gdt, 1);171return (ENOMEM);172}173PT4 = (pml4_entry_t *)(uintptr_t)ptr;174175PT3 = &PT4[512];176PT2 = &PT3[512];177178/*179* This is kinda brutal, but every single 1GB VM180* memory segment points to the same first 1GB of181* physical memory. But it is more than adequate.182*/183for (i = 0; i < 512; i++) {184/*185* Each slot of the L4 pages points to the186* same L3 page.187*/188PT4[i] = (uintptr_t)PT3 | PG_V | PG_RW;189190/*191* Each slot of the L3 pages points to the192* same L2 page.193*/194PT3[i] = (uintptr_t)PT2 | PG_V | PG_RW;195196/*197* The L2 page slots are mapped with 2MB pages for 1GB.198*/199PT2[i] = (i * M(2)) | PG_V | PG_RW | PG_PS;200}201} else {202pdpt_entry_t *PT3_l, *PT3_u;203pd_entry_t *PT2_l0, *PT2_l1, *PT2_l2, *PT2_l3, *PT2_u0, *PT2_u1;204205err = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,206EFI_SIZE_TO_PAGES(512 * 9 * sizeof(uint64_t)), &ptr);207if (EFI_ERROR(err)) {208printf("Unable to allocate trampoline page table\n");209BS->FreePages((uintptr_t)trampoline, 1);210BS->FreePages((uintptr_t)gdt, 1);211return (ENOMEM);212}213PT4 = (pml4_entry_t *)(uintptr_t)ptr;214215PT3_l = &PT4[512];216PT3_u = &PT3_l[512];217PT2_l0 = &PT3_u[512];218PT2_l1 = &PT2_l0[512];219PT2_l2 = &PT2_l1[512];220PT2_l3 = &PT2_l2[512];221PT2_u0 = &PT2_l3[512];222PT2_u1 = &PT2_u0[512];223224/* 1:1 mapping of lower 4G */225PT4[0] = (uintptr_t)PT3_l | PG_V | PG_RW;226PT3_l[0] = (uintptr_t)PT2_l0 | PG_V | PG_RW;227PT3_l[1] = (uintptr_t)PT2_l1 | PG_V | PG_RW;228PT3_l[2] = (uintptr_t)PT2_l2 | PG_V | PG_RW;229PT3_l[3] = (uintptr_t)PT2_l3 | PG_V | PG_RW;230for (i = 0; i < 2048; i++) {231PT2_l0[i] = ((pd_entry_t)i * M(2)) | PG_V | PG_RW | PG_PS;232}233234/* mapping of kernel 2G below top */235PT4[511] = (uintptr_t)PT3_u | PG_V | PG_RW;236PT3_u[511] = (uintptr_t)PT2_u1 | PG_V | PG_RW;237PT3_u[510] = (uintptr_t)PT2_u0 | PG_V | PG_RW;238/* compat mapping of phys @0 */239PT2_u0[0] = PG_PS | PG_V | PG_RW;240/* this maps past staging area */241for (i = 1; i < 1024; i++) {242PT2_u0[i] = (staging + (i - 1) * M(2))243| PG_V | PG_RW | PG_PS;244}245}246247printf(248"staging %#llx (%scopying) tramp %p PT4 %p GDT %p\n"249"Start @ %#llx ...\n", staging,250type == AllocateMaxAddress ? "" : "not ", trampoline, PT4, gdt,251ehdr->e_entry252);253254255/*256* we have to cleanup here because net_cleanup() doesn't work after257* we call ExitBootServices258*/259dev_cleanup();260261efi_time_fini();262err = bi_load(fp->f_args, &modulep, &kernend, true);263if (err != 0) {264efi_time_init();265return (err);266}267268trampoline(trampstack, type == AllocateMaxAddress ? efi_copy_finish :269efi_copy_finish_nop, kernend, modulep, PT4, gdtr, ehdr->e_entry);270271panic("exec returned");272}273274static int275elf64_obj_exec(struct preloaded_file *fp)276{277return (EFTYPE);278}279280281