1*4a5d661aSToomas Soome /*- 2*4a5d661aSToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3*4a5d661aSToomas Soome * All rights reserved. 4*4a5d661aSToomas Soome * 5*4a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 6*4a5d661aSToomas Soome * modification, are permitted provided that the following conditions 7*4a5d661aSToomas Soome * are met: 8*4a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 9*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 10*4a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 11*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 12*4a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 13*4a5d661aSToomas Soome * 14*4a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*4a5d661aSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*4a5d661aSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*4a5d661aSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*4a5d661aSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*4a5d661aSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*4a5d661aSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*4a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*4a5d661aSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*4a5d661aSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*4a5d661aSToomas Soome * SUCH DAMAGE. 25*4a5d661aSToomas Soome */ 26*4a5d661aSToomas Soome 27*4a5d661aSToomas Soome #include <sys/cdefs.h> 28*4a5d661aSToomas Soome __FBSDID("$FreeBSD$"); 29*4a5d661aSToomas Soome 30*4a5d661aSToomas Soome #include <stand.h> 31*4a5d661aSToomas Soome #include <sys/param.h> 32*4a5d661aSToomas Soome #include <sys/reboot.h> 33*4a5d661aSToomas Soome #include <sys/linker.h> 34*4a5d661aSToomas Soome #include <machine/bootinfo.h> 35*4a5d661aSToomas Soome #include "bootstrap.h" 36*4a5d661aSToomas Soome #include "libi386.h" 37*4a5d661aSToomas Soome #include "btxv86.h" 38*4a5d661aSToomas Soome 39*4a5d661aSToomas Soome static struct bootinfo bi; 40*4a5d661aSToomas Soome 41*4a5d661aSToomas Soome /* 42*4a5d661aSToomas Soome * Copy module-related data into the load area, where it can be 43*4a5d661aSToomas Soome * used as a directory for loaded modules. 44*4a5d661aSToomas Soome * 45*4a5d661aSToomas Soome * Module data is presented in a self-describing format. Each datum 46*4a5d661aSToomas Soome * is preceded by a 32-bit identifier and a 32-bit size field. 47*4a5d661aSToomas Soome * 48*4a5d661aSToomas Soome * Currently, the following data are saved: 49*4a5d661aSToomas Soome * 50*4a5d661aSToomas Soome * MOD_NAME (variable) module name (string) 51*4a5d661aSToomas Soome * MOD_TYPE (variable) module type (string) 52*4a5d661aSToomas Soome * MOD_ARGS (variable) module parameters (string) 53*4a5d661aSToomas Soome * MOD_ADDR sizeof(vm_offset_t) module load address 54*4a5d661aSToomas Soome * MOD_SIZE sizeof(size_t) module size 55*4a5d661aSToomas Soome * MOD_METADATA (variable) type-specific metadata 56*4a5d661aSToomas Soome */ 57*4a5d661aSToomas Soome #define COPY32(v, a, c) { \ 58*4a5d661aSToomas Soome u_int32_t x = (v); \ 59*4a5d661aSToomas Soome if (c) \ 60*4a5d661aSToomas Soome i386_copyin(&x, a, sizeof(x)); \ 61*4a5d661aSToomas Soome a += sizeof(x); \ 62*4a5d661aSToomas Soome } 63*4a5d661aSToomas Soome 64*4a5d661aSToomas Soome #define MOD_STR(t, a, s, c) { \ 65*4a5d661aSToomas Soome COPY32(t, a, c); \ 66*4a5d661aSToomas Soome COPY32(strlen(s) + 1, a, c); \ 67*4a5d661aSToomas Soome if (c) \ 68*4a5d661aSToomas Soome i386_copyin(s, a, strlen(s) + 1); \ 69*4a5d661aSToomas Soome a += roundup(strlen(s) + 1, sizeof(u_long));\ 70*4a5d661aSToomas Soome } 71*4a5d661aSToomas Soome 72*4a5d661aSToomas Soome #define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) 73*4a5d661aSToomas Soome #define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) 74*4a5d661aSToomas Soome #define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) 75*4a5d661aSToomas Soome 76*4a5d661aSToomas Soome #define MOD_VAR(t, a, s, c) { \ 77*4a5d661aSToomas Soome COPY32(t, a, c); \ 78*4a5d661aSToomas Soome COPY32(sizeof(s), a, c); \ 79*4a5d661aSToomas Soome if (c) \ 80*4a5d661aSToomas Soome i386_copyin(&s, a, sizeof(s)); \ 81*4a5d661aSToomas Soome a += roundup(sizeof(s), sizeof(u_long)); \ 82*4a5d661aSToomas Soome } 83*4a5d661aSToomas Soome 84*4a5d661aSToomas Soome #define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) 85*4a5d661aSToomas Soome #define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) 86*4a5d661aSToomas Soome 87*4a5d661aSToomas Soome #define MOD_METADATA(a, mm, c) { \ 88*4a5d661aSToomas Soome COPY32(MODINFO_METADATA | mm->md_type, a, c); \ 89*4a5d661aSToomas Soome COPY32(mm->md_size, a, c); \ 90*4a5d661aSToomas Soome if (c) \ 91*4a5d661aSToomas Soome i386_copyin(mm->md_data, a, mm->md_size); \ 92*4a5d661aSToomas Soome a += roundup(mm->md_size, sizeof(u_long));\ 93*4a5d661aSToomas Soome } 94*4a5d661aSToomas Soome 95*4a5d661aSToomas Soome #define MOD_END(a, c) { \ 96*4a5d661aSToomas Soome COPY32(MODINFO_END, a, c); \ 97*4a5d661aSToomas Soome COPY32(0, a, c); \ 98*4a5d661aSToomas Soome } 99*4a5d661aSToomas Soome 100*4a5d661aSToomas Soome static vm_offset_t 101*4a5d661aSToomas Soome bi_copymodules32(vm_offset_t addr) 102*4a5d661aSToomas Soome { 103*4a5d661aSToomas Soome struct preloaded_file *fp; 104*4a5d661aSToomas Soome struct file_metadata *md; 105*4a5d661aSToomas Soome int c; 106*4a5d661aSToomas Soome 107*4a5d661aSToomas Soome c = addr != 0; 108*4a5d661aSToomas Soome /* start with the first module on the list, should be the kernel */ 109*4a5d661aSToomas Soome for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { 110*4a5d661aSToomas Soome 111*4a5d661aSToomas Soome MOD_NAME(addr, fp->f_name, c); /* this field must come first */ 112*4a5d661aSToomas Soome MOD_TYPE(addr, fp->f_type, c); 113*4a5d661aSToomas Soome if (fp->f_args) 114*4a5d661aSToomas Soome MOD_ARGS(addr, fp->f_args, c); 115*4a5d661aSToomas Soome MOD_ADDR(addr, fp->f_addr, c); 116*4a5d661aSToomas Soome MOD_SIZE(addr, fp->f_size, c); 117*4a5d661aSToomas Soome for (md = fp->f_metadata; md != NULL; md = md->md_next) 118*4a5d661aSToomas Soome if (!(md->md_type & MODINFOMD_NOCOPY)) 119*4a5d661aSToomas Soome MOD_METADATA(addr, md, c); 120*4a5d661aSToomas Soome } 121*4a5d661aSToomas Soome MOD_END(addr, c); 122*4a5d661aSToomas Soome return(addr); 123*4a5d661aSToomas Soome } 124*4a5d661aSToomas Soome 125*4a5d661aSToomas Soome /* 126*4a5d661aSToomas Soome * Load the information expected by an i386 kernel. 127*4a5d661aSToomas Soome * 128*4a5d661aSToomas Soome * - The 'boothowto' argument is constructed 129*4a5d661aSToomas Soome * - The 'bootdev' argument is constructed 130*4a5d661aSToomas Soome * - The 'bootinfo' struct is constructed, and copied into the kernel space. 131*4a5d661aSToomas Soome * - The kernel environment is copied into kernel space. 132*4a5d661aSToomas Soome * - Module metadata are formatted and placed in kernel space. 133*4a5d661aSToomas Soome */ 134*4a5d661aSToomas Soome int 135*4a5d661aSToomas Soome bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) 136*4a5d661aSToomas Soome { 137*4a5d661aSToomas Soome struct preloaded_file *xp, *kfp; 138*4a5d661aSToomas Soome struct i386_devdesc *rootdev; 139*4a5d661aSToomas Soome struct file_metadata *md; 140*4a5d661aSToomas Soome vm_offset_t addr; 141*4a5d661aSToomas Soome vm_offset_t kernend; 142*4a5d661aSToomas Soome vm_offset_t envp; 143*4a5d661aSToomas Soome vm_offset_t size; 144*4a5d661aSToomas Soome vm_offset_t ssym, esym; 145*4a5d661aSToomas Soome char *rootdevname; 146*4a5d661aSToomas Soome int bootdevnr, i, howto; 147*4a5d661aSToomas Soome char *kernelname; 148*4a5d661aSToomas Soome const char *kernelpath; 149*4a5d661aSToomas Soome 150*4a5d661aSToomas Soome howto = bi_getboothowto(args); 151*4a5d661aSToomas Soome 152*4a5d661aSToomas Soome /* 153*4a5d661aSToomas Soome * Allow the environment variable 'rootdev' to override the supplied device 154*4a5d661aSToomas Soome * This should perhaps go to MI code and/or have $rootdev tested/set by 155*4a5d661aSToomas Soome * MI code before launching the kernel. 156*4a5d661aSToomas Soome */ 157*4a5d661aSToomas Soome rootdevname = getenv("rootdev"); 158*4a5d661aSToomas Soome i386_getdev((void **)(&rootdev), rootdevname, NULL); 159*4a5d661aSToomas Soome if (rootdev == NULL) { /* bad $rootdev/$currdev */ 160*4a5d661aSToomas Soome printf("can't determine root device\n"); 161*4a5d661aSToomas Soome return(EINVAL); 162*4a5d661aSToomas Soome } 163*4a5d661aSToomas Soome 164*4a5d661aSToomas Soome /* Try reading the /etc/fstab file to select the root device */ 165*4a5d661aSToomas Soome getrootmount(i386_fmtdev((void *)rootdev)); 166*4a5d661aSToomas Soome 167*4a5d661aSToomas Soome /* Do legacy rootdev guessing */ 168*4a5d661aSToomas Soome 169*4a5d661aSToomas Soome /* XXX - use a default bootdev of 0. Is this ok??? */ 170*4a5d661aSToomas Soome bootdevnr = 0; 171*4a5d661aSToomas Soome 172*4a5d661aSToomas Soome switch(rootdev->d_type) { 173*4a5d661aSToomas Soome case DEVT_CD: 174*4a5d661aSToomas Soome /* Pass in BIOS device number. */ 175*4a5d661aSToomas Soome bi.bi_bios_dev = bc_unit2bios(rootdev->d_unit); 176*4a5d661aSToomas Soome bootdevnr = bc_getdev(rootdev); 177*4a5d661aSToomas Soome break; 178*4a5d661aSToomas Soome 179*4a5d661aSToomas Soome case DEVT_DISK: 180*4a5d661aSToomas Soome /* pass in the BIOS device number of the current disk */ 181*4a5d661aSToomas Soome bi.bi_bios_dev = bd_unit2bios(rootdev->d_unit); 182*4a5d661aSToomas Soome bootdevnr = bd_getdev(rootdev); 183*4a5d661aSToomas Soome break; 184*4a5d661aSToomas Soome 185*4a5d661aSToomas Soome case DEVT_NET: 186*4a5d661aSToomas Soome case DEVT_ZFS: 187*4a5d661aSToomas Soome break; 188*4a5d661aSToomas Soome 189*4a5d661aSToomas Soome default: 190*4a5d661aSToomas Soome printf("WARNING - don't know how to boot from device type %d\n", rootdev->d_type); 191*4a5d661aSToomas Soome } 192*4a5d661aSToomas Soome if (bootdevnr == -1) { 193*4a5d661aSToomas Soome printf("root device %s invalid\n", i386_fmtdev(rootdev)); 194*4a5d661aSToomas Soome return (EINVAL); 195*4a5d661aSToomas Soome } 196*4a5d661aSToomas Soome free(rootdev); 197*4a5d661aSToomas Soome 198*4a5d661aSToomas Soome /* find the last module in the chain */ 199*4a5d661aSToomas Soome addr = 0; 200*4a5d661aSToomas Soome for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { 201*4a5d661aSToomas Soome if (addr < (xp->f_addr + xp->f_size)) 202*4a5d661aSToomas Soome addr = xp->f_addr + xp->f_size; 203*4a5d661aSToomas Soome } 204*4a5d661aSToomas Soome /* pad to a page boundary */ 205*4a5d661aSToomas Soome addr = roundup(addr, PAGE_SIZE); 206*4a5d661aSToomas Soome 207*4a5d661aSToomas Soome /* copy our environment */ 208*4a5d661aSToomas Soome envp = addr; 209*4a5d661aSToomas Soome addr = bi_copyenv(addr); 210*4a5d661aSToomas Soome 211*4a5d661aSToomas Soome /* pad to a page boundary */ 212*4a5d661aSToomas Soome addr = roundup(addr, PAGE_SIZE); 213*4a5d661aSToomas Soome 214*4a5d661aSToomas Soome kfp = file_findfile(NULL, "elf kernel"); 215*4a5d661aSToomas Soome if (kfp == NULL) 216*4a5d661aSToomas Soome kfp = file_findfile(NULL, "elf32 kernel"); 217*4a5d661aSToomas Soome if (kfp == NULL) 218*4a5d661aSToomas Soome panic("can't find kernel file"); 219*4a5d661aSToomas Soome kernend = 0; /* fill it in later */ 220*4a5d661aSToomas Soome file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); 221*4a5d661aSToomas Soome file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); 222*4a5d661aSToomas Soome file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); 223*4a5d661aSToomas Soome bios_addsmapdata(kfp); 224*4a5d661aSToomas Soome 225*4a5d661aSToomas Soome /* Figure out the size and location of the metadata */ 226*4a5d661aSToomas Soome *modulep = addr; 227*4a5d661aSToomas Soome size = bi_copymodules32(0); 228*4a5d661aSToomas Soome kernend = roundup(addr + size, PAGE_SIZE); 229*4a5d661aSToomas Soome *kernendp = kernend; 230*4a5d661aSToomas Soome 231*4a5d661aSToomas Soome /* patch MODINFOMD_KERNEND */ 232*4a5d661aSToomas Soome md = file_findmetadata(kfp, MODINFOMD_KERNEND); 233*4a5d661aSToomas Soome bcopy(&kernend, md->md_data, sizeof kernend); 234*4a5d661aSToomas Soome 235*4a5d661aSToomas Soome /* copy module list and metadata */ 236*4a5d661aSToomas Soome (void)bi_copymodules32(addr); 237*4a5d661aSToomas Soome 238*4a5d661aSToomas Soome ssym = esym = 0; 239*4a5d661aSToomas Soome md = file_findmetadata(kfp, MODINFOMD_SSYM); 240*4a5d661aSToomas Soome if (md != NULL) 241*4a5d661aSToomas Soome ssym = *((vm_offset_t *)&(md->md_data)); 242*4a5d661aSToomas Soome md = file_findmetadata(kfp, MODINFOMD_ESYM); 243*4a5d661aSToomas Soome if (md != NULL) 244*4a5d661aSToomas Soome esym = *((vm_offset_t *)&(md->md_data)); 245*4a5d661aSToomas Soome if (ssym == 0 || esym == 0) 246*4a5d661aSToomas Soome ssym = esym = 0; /* sanity */ 247*4a5d661aSToomas Soome 248*4a5d661aSToomas Soome /* legacy bootinfo structure */ 249*4a5d661aSToomas Soome kernelname = getenv("kernelname"); 250*4a5d661aSToomas Soome i386_getdev(NULL, kernelname, &kernelpath); 251*4a5d661aSToomas Soome bi.bi_version = BOOTINFO_VERSION; 252*4a5d661aSToomas Soome bi.bi_kernelname = 0; /* XXX char * -> kernel name */ 253*4a5d661aSToomas Soome bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ 254*4a5d661aSToomas Soome bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ 255*4a5d661aSToomas Soome for (i = 0; i < N_BIOS_GEOM; i++) 256*4a5d661aSToomas Soome bi.bi_bios_geom[i] = bd_getbigeom(i); 257*4a5d661aSToomas Soome bi.bi_size = sizeof(bi); 258*4a5d661aSToomas Soome bi.bi_memsizes_valid = 1; 259*4a5d661aSToomas Soome bi.bi_basemem = bios_basemem / 1024; 260*4a5d661aSToomas Soome bi.bi_extmem = bios_extmem / 1024; 261*4a5d661aSToomas Soome bi.bi_envp = envp; 262*4a5d661aSToomas Soome bi.bi_modulep = *modulep; 263*4a5d661aSToomas Soome bi.bi_kernend = kernend; 264*4a5d661aSToomas Soome bi.bi_kernelname = VTOP(kernelpath); 265*4a5d661aSToomas Soome bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ 266*4a5d661aSToomas Soome bi.bi_esymtab = esym; 267*4a5d661aSToomas Soome 268*4a5d661aSToomas Soome /* legacy boot arguments */ 269*4a5d661aSToomas Soome *howtop = howto | RB_BOOTINFO; 270*4a5d661aSToomas Soome *bootdevp = bootdevnr; 271*4a5d661aSToomas Soome *bip = VTOP(&bi); 272*4a5d661aSToomas Soome 273*4a5d661aSToomas Soome return(0); 274*4a5d661aSToomas Soome } 275