1223695Sdfr/*- 2223695Sdfr * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3223695Sdfr * All rights reserved. 4223695Sdfr * 5223695Sdfr * Redistribution and use in source and binary forms, with or without 6223695Sdfr * modification, are permitted provided that the following conditions 7223695Sdfr * are met: 8223695Sdfr * 1. Redistributions of source code must retain the above copyright 9223695Sdfr * notice, this list of conditions and the following disclaimer. 10223695Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11223695Sdfr * notice, this list of conditions and the following disclaimer in the 12223695Sdfr * documentation and/or other materials provided with the distribution. 13223695Sdfr * 14223695Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15223695Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16223695Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17223695Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18223695Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19223695Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20223695Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21223695Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22223695Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23223695Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24223695Sdfr * SUCH DAMAGE. 25223695Sdfr */ 26223695Sdfr 27223695Sdfr#include <sys/cdefs.h> 28223695Sdfr__FBSDID("$FreeBSD$"); 29223695Sdfr 30223695Sdfr#define __ELF_WORD_SIZE 64 31223695Sdfr#include <sys/param.h> 32223695Sdfr#include <sys/exec.h> 33223695Sdfr#include <sys/linker.h> 34223695Sdfr#include <string.h> 35223695Sdfr#include <i386/include/bootinfo.h> 36223695Sdfr#include <machine/elf.h> 37223695Sdfr#include <stand.h> 38223695Sdfr 39223695Sdfr#include "bootstrap.h" 40223695Sdfr#include "libuserboot.h" 41223695Sdfr 42223695Sdfrstatic int elf64_exec(struct preloaded_file *amp); 43223695Sdfrstatic int elf64_obj_exec(struct preloaded_file *amp); 44223695Sdfr 45223695Sdfrstruct file_format amd64_elf = { elf64_loadfile, elf64_exec }; 46223695Sdfrstruct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; 47223695Sdfr 48223695Sdfr#define MSR_EFER 0xc0000080 49223695Sdfr#define EFER_LME 0x00000100 50223695Sdfr#define EFER_LMA 0x00000400 /* Long mode active (R) */ 51223695Sdfr#define CR4_PAE 0x00000020 52223695Sdfr#define CR4_VMXE (1UL << 13) 53223695Sdfr#define CR4_PSE 0x00000010 54223695Sdfr#define CR0_PG 0x80000000 55223695Sdfr#define CR0_PE 0x00000001 /* Protected mode Enable */ 56223695Sdfr#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ 57223695Sdfr 58223695Sdfr#define PG_V 0x001 59223695Sdfr#define PG_RW 0x002 60223695Sdfr#define PG_U 0x004 61223695Sdfr#define PG_PS 0x080 62223695Sdfr 63223695Sdfrtypedef u_int64_t p4_entry_t; 64223695Sdfrtypedef u_int64_t p3_entry_t; 65223695Sdfrtypedef u_int64_t p2_entry_t; 66223695Sdfr 67223695Sdfr#define GUEST_NULL_SEL 0 68223695Sdfr#define GUEST_CODE_SEL 1 69223695Sdfr#define GUEST_DATA_SEL 2 70223695Sdfr#define GUEST_GDTR_LIMIT (3 * 8 - 1) 71223695Sdfr 72223695Sdfrstatic void 73223695Sdfrsetup_freebsd_gdt(uint64_t *gdtr) 74223695Sdfr{ 75223695Sdfr gdtr[GUEST_NULL_SEL] = 0; 76223695Sdfr gdtr[GUEST_CODE_SEL] = 0x0020980000000000; 77223695Sdfr gdtr[GUEST_DATA_SEL] = 0x0000900000000000; 78223695Sdfr} 79223695Sdfr 80223695Sdfr/* 81223695Sdfr * There is an ELF kernel and one or more ELF modules loaded. 82223695Sdfr * We wish to start executing the kernel image, so make such 83223695Sdfr * preparations as are required, and do so. 84223695Sdfr */ 85223695Sdfrstatic int 86223695Sdfrelf64_exec(struct preloaded_file *fp) 87223695Sdfr{ 88223695Sdfr struct file_metadata *md; 89223695Sdfr Elf_Ehdr *ehdr; 90223695Sdfr vm_offset_t modulep, kernend; 91223695Sdfr int err; 92223695Sdfr int i; 93223695Sdfr uint32_t stack[1024]; 94223695Sdfr p4_entry_t PT4[512]; 95223695Sdfr p3_entry_t PT3[512]; 96223695Sdfr p2_entry_t PT2[512]; 97223695Sdfr uint64_t gdtr[3]; 98223695Sdfr 99223695Sdfr if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) 100223695Sdfr return(EFTYPE); 101223695Sdfr ehdr = (Elf_Ehdr *)&(md->md_data); 102223695Sdfr 103223695Sdfr err = bi_load64(fp->f_args, &modulep, &kernend); 104223695Sdfr if (err != 0) 105223695Sdfr return(err); 106223695Sdfr 107223695Sdfr bzero(PT4, PAGE_SIZE); 108223695Sdfr bzero(PT3, PAGE_SIZE); 109223695Sdfr bzero(PT2, PAGE_SIZE); 110223695Sdfr 111223695Sdfr /* 112223695Sdfr * Build a scratch stack at physical 0x1000, page tables: 113223695Sdfr * PT4 at 0x2000, 114223695Sdfr * PT3 at 0x3000, 115223695Sdfr * PT2 at 0x4000, 116223695Sdfr * gdtr at 0x5000, 117223695Sdfr */ 118223695Sdfr 119223695Sdfr /* 120223695Sdfr * This is kinda brutal, but every single 1GB VM memory segment 121223695Sdfr * points to the same first 1GB of physical memory. But it is 122223695Sdfr * more than adequate. 123223695Sdfr */ 124223695Sdfr for (i = 0; i < 512; i++) { 125223695Sdfr /* Each slot of the level 4 pages points to the same level 3 page */ 126223695Sdfr PT4[i] = (p4_entry_t) 0x3000; 127223695Sdfr PT4[i] |= PG_V | PG_RW | PG_U; 128223695Sdfr 129223695Sdfr /* Each slot of the level 3 pages points to the same level 2 page */ 130223695Sdfr PT3[i] = (p3_entry_t) 0x4000; 131223695Sdfr PT3[i] |= PG_V | PG_RW | PG_U; 132223695Sdfr 133223695Sdfr /* The level 2 page slots are mapped with 2MB pages for 1GB. */ 134223695Sdfr PT2[i] = i * (2 * 1024 * 1024); 135223695Sdfr PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; 136223695Sdfr } 137223695Sdfr 138223695Sdfr#ifdef DEBUG 139223695Sdfr printf("Start @ %#llx ...\n", ehdr->e_entry); 140223695Sdfr#endif 141223695Sdfr 142223695Sdfr dev_cleanup(); 143223695Sdfr 144223695Sdfr stack[0] = 0; /* return address */; 145223695Sdfr stack[1] = modulep; 146223695Sdfr stack[2] = kernend; 147223695Sdfr CALLBACK(copyin, stack, 0x1000, sizeof(stack)); 148223695Sdfr CALLBACK(copyin, PT4, 0x2000, sizeof(PT4)); 149223695Sdfr CALLBACK(copyin, PT3, 0x3000, sizeof(PT3)); 150223695Sdfr CALLBACK(copyin, PT2, 0x4000, sizeof(PT2)); 151223695Sdfr CALLBACK(setreg, 4, 0x1000); 152223695Sdfr 153223695Sdfr CALLBACK(setmsr, MSR_EFER, EFER_LMA | EFER_LME); 154223695Sdfr CALLBACK(setcr, 4, CR4_PAE | CR4_VMXE); 155223695Sdfr CALLBACK(setcr, 3, 0x2000); 156223695Sdfr CALLBACK(setcr, 0, CR0_PG | CR0_PE | CR0_NE); 157223695Sdfr 158223695Sdfr setup_freebsd_gdt(gdtr); 159223695Sdfr CALLBACK(copyin, gdtr, 0x5000, sizeof(gdtr)); 160223695Sdfr CALLBACK(setgdt, 0x5000, sizeof(gdtr)); 161223695Sdfr 162223695Sdfr CALLBACK(exec, ehdr->e_entry); 163223695Sdfr 164223695Sdfr panic("exec returned"); 165223695Sdfr} 166223695Sdfr 167223695Sdfrstatic int 168223695Sdfrelf64_obj_exec(struct preloaded_file *fp) 169223695Sdfr{ 170223695Sdfr 171223695Sdfr return (EFTYPE); 172223695Sdfr} 173