1 /*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <stand.h> 31 #include <sys/param.h> 32 #include <sys/reboot.h> 33 #include <sys/linker.h> 34 #include <i386/include/bootinfo.h> 35 36 #include "bootstrap.h" 37 #include "modinfo.h" 38 #include "libuserboot.h" 39 40 #ifdef LOADER_GELI_SUPPORT 41 #include "geliboot.h" 42 #endif 43 44 static struct bootinfo bi; 45 46 /* 47 * Load the information expected by an i386 kernel. 48 * 49 * - The 'boothowto' argument is constructed 50 * - The 'bootdev' argument is constructed 51 * - The 'bootinfo' struct is constructed, and copied into the kernel space. 52 * - The kernel environment is copied into kernel space. 53 * - Module metadata are formatted and placed in kernel space. 54 */ 55 int 56 bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) 57 { 58 struct preloaded_file *xp, *kfp; 59 struct devdesc *rootdev; 60 struct file_metadata *md; 61 vm_offset_t addr; 62 vm_offset_t kernend; 63 vm_offset_t envp; 64 vm_offset_t size; 65 vm_offset_t ssym, esym; 66 char *rootdevname; 67 int bootdevnr, howto; 68 char *kernelname; 69 const char *kernelpath; 70 uint64_t lowmem, highmem; 71 72 howto = bi_getboothowto(args); 73 74 /* 75 * Allow the environment variable 'rootdev' to override the supplied device 76 * This should perhaps go to MI code and/or have $rootdev tested/set by 77 * MI code before launching the kernel. 78 */ 79 rootdevname = getenv("rootdev"); 80 userboot_getdev((void **)(&rootdev), rootdevname, NULL); 81 if (rootdev == NULL) { /* bad $rootdev/$currdev */ 82 printf("can't determine root device\n"); 83 return(EINVAL); 84 } 85 86 /* Try reading the /etc/fstab file to select the root device */ 87 getrootmount(devformat(rootdev)); 88 89 bootdevnr = 0; 90 #if 0 91 if (bootdevnr == -1) { 92 printf("root device %s invalid\n", devformat(rootdev)); 93 return (EINVAL); 94 } 95 #endif 96 free(rootdev); 97 98 /* find the last module in the chain */ 99 addr = 0; 100 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 101 if (addr < (xp->f_addr + xp->f_size)) 102 addr = xp->f_addr + xp->f_size; 103 } 104 /* pad to a page boundary */ 105 addr = roundup(addr, PAGE_SIZE); 106 107 /* copy our environment */ 108 envp = addr; 109 addr = md_copyenv(addr); 110 111 /* pad to a page boundary */ 112 addr = roundup(addr, PAGE_SIZE); 113 114 kfp = file_findfile(NULL, "elf kernel"); 115 if (kfp == NULL) 116 kfp = file_findfile(NULL, "elf32 kernel"); 117 if (kfp == NULL) 118 panic("can't find kernel file"); 119 kernend = 0; /* fill it in later */ 120 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 121 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 122 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 123 bios_addsmapdata(kfp); 124 #ifdef LOADER_GELI_SUPPORT 125 geli_export_key_metadata(kfp); 126 #endif 127 128 /* Figure out the size and location of the metadata */ 129 *modulep = addr; 130 size = md_copymodules(0, false); 131 kernend = roundup(addr + size, PAGE_SIZE); 132 *kernendp = kernend; 133 134 /* patch MODINFOMD_KERNEND */ 135 md = file_findmetadata(kfp, MODINFOMD_KERNEND); 136 bcopy(&kernend, md->md_data, sizeof kernend); 137 138 /* copy module list and metadata */ 139 (void)md_copymodules(addr, false); 140 141 ssym = esym = 0; 142 md = file_findmetadata(kfp, MODINFOMD_SSYM); 143 if (md != NULL) 144 ssym = *((vm_offset_t *)&(md->md_data)); 145 md = file_findmetadata(kfp, MODINFOMD_ESYM); 146 if (md != NULL) 147 esym = *((vm_offset_t *)&(md->md_data)); 148 if (ssym == 0 || esym == 0) 149 ssym = esym = 0; /* sanity */ 150 151 /* legacy bootinfo structure */ 152 kernelname = getenv("kernelname"); 153 userboot_getdev(NULL, kernelname, &kernelpath); 154 bi.bi_version = BOOTINFO_VERSION; 155 bi.bi_size = sizeof(bi); 156 CALLBACK(getmem, &lowmem, &highmem); 157 bi.bi_memsizes_valid = 1; 158 bi.bi_basemem = 640; 159 bi.bi_extmem = (lowmem - 0x100000) / 1024; 160 bi.bi_envp = envp; 161 bi.bi_modulep = *modulep; 162 bi.bi_kernend = kernend; 163 bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ 164 bi.bi_esymtab = esym; 165 166 /* 167 * Copy the legacy bootinfo and kernel name to the guest at 0x2000 168 */ 169 bi.bi_kernelname = 0x2000 + sizeof(bi); 170 CALLBACK(copyin, &bi, 0x2000, sizeof(bi)); 171 CALLBACK(copyin, kernelname, 0x2000 + sizeof(bi), strlen(kernelname) + 1); 172 173 /* legacy boot arguments */ 174 *howtop = howto | RB_BOOTINFO; 175 *bootdevp = bootdevnr; 176 *bip = 0x2000; 177 178 return(0); 179 } 180