1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 1998 Robert Nordier 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms are freely 6ca987d46SWarner Losh * permitted provided that the above copyright notice and this 7ca987d46SWarner Losh * paragraph and the following disclaimer are duplicated in all 8ca987d46SWarner Losh * such forms. 9ca987d46SWarner Losh * 10ca987d46SWarner Losh * This software is provided "AS IS" and without any express or 11ca987d46SWarner Losh * implied warranties, including, without limitation, the implied 12ca987d46SWarner Losh * warranties of merchantability and fitness for a particular 13ca987d46SWarner Losh * purpose. 14ca987d46SWarner Losh */ 15ca987d46SWarner Losh 16ca987d46SWarner Losh #include <sys/cdefs.h> 17ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 18ca987d46SWarner Losh 19ca987d46SWarner Losh #include <sys/param.h> 20ca987d46SWarner Losh #include <sys/gpt.h> 21ca987d46SWarner Losh #include <sys/dirent.h> 22ca987d46SWarner Losh #include <sys/reboot.h> 23ca987d46SWarner Losh 24ca987d46SWarner Losh #include <machine/bootinfo.h> 25ca987d46SWarner Losh #include <machine/elf.h> 26ca987d46SWarner Losh #include <machine/pc/bios.h> 27ca987d46SWarner Losh #include <machine/psl.h> 28ca987d46SWarner Losh 29ca987d46SWarner Losh #include <stdarg.h> 30ca987d46SWarner Losh 31ca987d46SWarner Losh #include <a.out.h> 32ca987d46SWarner Losh 33ca987d46SWarner Losh #include <btxv86.h> 34ca987d46SWarner Losh 3565628439SWarner Losh #include "stand.h" 361227a4f4SWarner Losh 37ca987d46SWarner Losh #include "bootargs.h" 38ca987d46SWarner Losh #include "lib.h" 39ca987d46SWarner Losh #include "rbx.h" 40ca987d46SWarner Losh #include "drv.h" 41ca987d46SWarner Losh #include "cons.h" 42ca987d46SWarner Losh #include "gpt.h" 43ca987d46SWarner Losh #include "paths.h" 44ca987d46SWarner Losh 45ca987d46SWarner Losh #define ARGS 0x900 46ca987d46SWarner Losh #define NOPT 14 47ca987d46SWarner Losh #define NDEV 3 48ca987d46SWarner Losh #define MEM_BASE 0x12 49ca987d46SWarner Losh #define MEM_EXT 0x15 50ca987d46SWarner Losh 51ca987d46SWarner Losh #define DRV_HARD 0x80 52ca987d46SWarner Losh #define DRV_MASK 0x7f 53ca987d46SWarner Losh 54ca987d46SWarner Losh #define TYPE_AD 0 55ca987d46SWarner Losh #define TYPE_DA 1 56ca987d46SWarner Losh #define TYPE_MAXHARD TYPE_DA 57ca987d46SWarner Losh #define TYPE_FD 2 58ca987d46SWarner Losh 59ca987d46SWarner Losh extern uint32_t _end; 60ca987d46SWarner Losh 61ca987d46SWarner Losh static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; 62ca987d46SWarner Losh static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 63ca987d46SWarner Losh static const unsigned char flags[NOPT] = { 64ca987d46SWarner Losh RBX_DUAL, 65ca987d46SWarner Losh RBX_SERIAL, 66ca987d46SWarner Losh RBX_ASKNAME, 67ca987d46SWarner Losh RBX_CDROM, 68ca987d46SWarner Losh RBX_CONFIG, 69ca987d46SWarner Losh RBX_KDB, 70ca987d46SWarner Losh RBX_GDB, 71ca987d46SWarner Losh RBX_MUTE, 72ca987d46SWarner Losh RBX_NOINTR, 73ca987d46SWarner Losh RBX_PAUSE, 74ca987d46SWarner Losh RBX_QUIET, 75ca987d46SWarner Losh RBX_DFLTROOT, 76ca987d46SWarner Losh RBX_SINGLE, 77ca987d46SWarner Losh RBX_VERBOSE 78ca987d46SWarner Losh }; 79ca987d46SWarner Losh uint32_t opts; 80ca987d46SWarner Losh 81ca987d46SWarner Losh static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 82ca987d46SWarner Losh static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 83ca987d46SWarner Losh 84ca987d46SWarner Losh static char kname[1024]; 85ca987d46SWarner Losh static int comspeed = SIOSPD; 86ca987d46SWarner Losh static struct bootinfo bootinfo; 87ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 88ca987d46SWarner Losh static struct geli_boot_args geliargs; 89ca987d46SWarner Losh #endif 90ca987d46SWarner Losh 91ca987d46SWarner Losh static vm_offset_t high_heap_base; 92ca987d46SWarner Losh static uint32_t bios_basemem, bios_extmem, high_heap_size; 93ca987d46SWarner Losh 94ca987d46SWarner Losh static struct bios_smap smap; 95ca987d46SWarner Losh 96ca987d46SWarner Losh /* 97ca987d46SWarner Losh * The minimum amount of memory to reserve in bios_extmem for the heap. 98ca987d46SWarner Losh */ 99ca987d46SWarner Losh #define HEAP_MIN (3 * 1024 * 1024) 100ca987d46SWarner Losh 101ca987d46SWarner Losh static char *heap_next; 102ca987d46SWarner Losh static char *heap_end; 103ca987d46SWarner Losh 104ca987d46SWarner Losh static void load(void); 105ca987d46SWarner Losh static int parse_cmds(char *, int *); 106ca987d46SWarner Losh static int dskread(void *, daddr_t, unsigned); 107ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 108ca987d46SWarner Losh static int vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, 109ca987d46SWarner Losh size_t bytes); 110ca987d46SWarner Losh #endif 111ca987d46SWarner Losh 112ca987d46SWarner Losh #include "ufsread.c" 113ca987d46SWarner Losh #include "gpt.c" 114ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 115c1418270SIan Lepore #include "geliboot.h" 116ca987d46SWarner Losh static char gelipw[GELI_PW_MAXLEN]; 117ca987d46SWarner Losh static struct keybuf *gelibuf; 118ca987d46SWarner Losh #endif 119ca987d46SWarner Losh 120c1418270SIan Lepore struct gptdsk { 121c1418270SIan Lepore struct dsk dsk; 122c1418270SIan Lepore #ifdef LOADER_GELI_SUPPORT 123c1418270SIan Lepore struct geli_dev *gdev; 124c1418270SIan Lepore #endif 125c1418270SIan Lepore }; 126c1418270SIan Lepore 127c1418270SIan Lepore static struct gptdsk gdsk; 128c1418270SIan Lepore 129ca987d46SWarner Losh static inline int 130ca987d46SWarner Losh xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 131ca987d46SWarner Losh { 132ca987d46SWarner Losh 133ca987d46SWarner Losh if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 134ca987d46SWarner Losh printf("Invalid %s\n", "format"); 135ca987d46SWarner Losh return (-1); 136ca987d46SWarner Losh } 137ca987d46SWarner Losh return (0); 138ca987d46SWarner Losh } 139ca987d46SWarner Losh 140ca987d46SWarner Losh static void 141ca987d46SWarner Losh bios_getmem(void) 142ca987d46SWarner Losh { 143ca987d46SWarner Losh uint64_t size; 144ca987d46SWarner Losh 145ca987d46SWarner Losh /* Parse system memory map */ 146ca987d46SWarner Losh v86.ebx = 0; 147ca987d46SWarner Losh do { 148ca987d46SWarner Losh v86.ctl = V86_FLAGS; 149ca987d46SWarner Losh v86.addr = MEM_EXT; /* int 0x15 function 0xe820*/ 150ca987d46SWarner Losh v86.eax = 0xe820; 151ca987d46SWarner Losh v86.ecx = sizeof(struct bios_smap); 152ca987d46SWarner Losh v86.edx = SMAP_SIG; 153ca987d46SWarner Losh v86.es = VTOPSEG(&smap); 154ca987d46SWarner Losh v86.edi = VTOPOFF(&smap); 155ca987d46SWarner Losh v86int(); 156ca987d46SWarner Losh if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) 157ca987d46SWarner Losh break; 158ca987d46SWarner Losh /* look for a low-memory segment that's large enough */ 159ca987d46SWarner Losh if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 160ca987d46SWarner Losh (smap.length >= (512 * 1024))) 161ca987d46SWarner Losh bios_basemem = smap.length; 162ca987d46SWarner Losh /* look for the first segment in 'extended' memory */ 1638e48426cSBenno Rice if ((smap.type == SMAP_TYPE_MEMORY) && 1648e48426cSBenno Rice (smap.base == 0x100000)) { 165ca987d46SWarner Losh bios_extmem = smap.length; 166ca987d46SWarner Losh } 167ca987d46SWarner Losh 168ca987d46SWarner Losh /* 169ca987d46SWarner Losh * Look for the largest segment in 'extended' memory beyond 170ca987d46SWarner Losh * 1MB but below 4GB. 171ca987d46SWarner Losh */ 1728e48426cSBenno Rice if ((smap.type == SMAP_TYPE_MEMORY) && 1738e48426cSBenno Rice (smap.base > 0x100000) && (smap.base < 0x100000000ull)) { 174ca987d46SWarner Losh size = smap.length; 175ca987d46SWarner Losh 176ca987d46SWarner Losh /* 1778e48426cSBenno Rice * If this segment crosses the 4GB boundary, 1788e48426cSBenno Rice * truncate it. 179ca987d46SWarner Losh */ 180ca987d46SWarner Losh if (smap.base + size > 0x100000000ull) 181ca987d46SWarner Losh size = 0x100000000ull - smap.base; 182ca987d46SWarner Losh 183ca987d46SWarner Losh if (size > high_heap_size) { 184ca987d46SWarner Losh high_heap_size = size; 185ca987d46SWarner Losh high_heap_base = smap.base; 186ca987d46SWarner Losh } 187ca987d46SWarner Losh } 188ca987d46SWarner Losh } while (v86.ebx != 0); 189ca987d46SWarner Losh 190ca987d46SWarner Losh /* Fall back to the old compatibility function for base memory */ 191ca987d46SWarner Losh if (bios_basemem == 0) { 192ca987d46SWarner Losh v86.ctl = 0; 193ca987d46SWarner Losh v86.addr = 0x12; /* int 0x12 */ 194ca987d46SWarner Losh v86int(); 195ca987d46SWarner Losh 196ca987d46SWarner Losh bios_basemem = (v86.eax & 0xffff) * 1024; 197ca987d46SWarner Losh } 198ca987d46SWarner Losh 1998e48426cSBenno Rice /* 2008e48426cSBenno Rice * Fall back through several compatibility functions for extended 2018e48426cSBenno Rice * memory 2028e48426cSBenno Rice */ 203ca987d46SWarner Losh if (bios_extmem == 0) { 204ca987d46SWarner Losh v86.ctl = V86_FLAGS; 205ca987d46SWarner Losh v86.addr = 0x15; /* int 0x15 function 0xe801*/ 206ca987d46SWarner Losh v86.eax = 0xe801; 207ca987d46SWarner Losh v86int(); 208ca987d46SWarner Losh if (!(v86.efl & 1)) { 2098e48426cSBenno Rice bios_extmem = ((v86.ecx & 0xffff) + 2108e48426cSBenno Rice ((v86.edx & 0xffff) * 64)) * 1024; 211ca987d46SWarner Losh } 212ca987d46SWarner Losh } 213ca987d46SWarner Losh if (bios_extmem == 0) { 214ca987d46SWarner Losh v86.ctl = 0; 215ca987d46SWarner Losh v86.addr = 0x15; /* int 0x15 function 0x88*/ 216ca987d46SWarner Losh v86.eax = 0x8800; 217ca987d46SWarner Losh v86int(); 218ca987d46SWarner Losh bios_extmem = (v86.eax & 0xffff) * 1024; 219ca987d46SWarner Losh } 220ca987d46SWarner Losh 221ca987d46SWarner Losh /* 222ca987d46SWarner Losh * If we have extended memory and did not find a suitable heap 223ca987d46SWarner Losh * region in the SMAP, use the last 3MB of 'extended' memory as a 224ca987d46SWarner Losh * high heap candidate. 225ca987d46SWarner Losh */ 226ca987d46SWarner Losh if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 227ca987d46SWarner Losh high_heap_size = HEAP_MIN; 228ca987d46SWarner Losh high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; 229ca987d46SWarner Losh } 230ca987d46SWarner Losh } 231ca987d46SWarner Losh 232ca987d46SWarner Losh static int 233ca987d46SWarner Losh gptinit(void) 234ca987d46SWarner Losh { 235ca987d46SWarner Losh 236c1418270SIan Lepore if (gptread(&freebsd_ufs_uuid, &gdsk.dsk, dmadat->secbuf) == -1) { 237ca987d46SWarner Losh printf("%s: unable to load GPT\n", BOOTPROG); 238ca987d46SWarner Losh return (-1); 239ca987d46SWarner Losh } 240c1418270SIan Lepore if (gptfind(&freebsd_ufs_uuid, &gdsk.dsk, gdsk.dsk.part) == -1) { 241ca987d46SWarner Losh printf("%s: no UFS partition was found\n", BOOTPROG); 242ca987d46SWarner Losh return (-1); 243ca987d46SWarner Losh } 244ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 245c1418270SIan Lepore gdsk.gdev = geli_taste(vdev_read, &gdsk.dsk, 246c1418270SIan Lepore (gpttable[curent].ent_lba_end - gpttable[curent].ent_lba_start), 247c1418270SIan Lepore "disk%up%u:", gdsk.dsk.unit, curent + 1); 248c1418270SIan Lepore if (gdsk.gdev != NULL) { 249c1418270SIan Lepore if (geli_havekey(gdsk.gdev) != 0 && 250c1418270SIan Lepore geli_passphrase(gdsk.gdev, gelipw) != 0) { 251ca987d46SWarner Losh printf("%s: unable to decrypt GELI key\n", BOOTPROG); 252ca987d46SWarner Losh return (-1); 253ca987d46SWarner Losh } 254ca987d46SWarner Losh } 255ca987d46SWarner Losh #endif 256ca987d46SWarner Losh 257ca987d46SWarner Losh dsk_meta = 0; 258ca987d46SWarner Losh return (0); 259ca987d46SWarner Losh } 260ca987d46SWarner Losh 2611227a4f4SWarner Losh int main(void); 2621227a4f4SWarner Losh 263ca987d46SWarner Losh int 264ca987d46SWarner Losh main(void) 265ca987d46SWarner Losh { 266ca987d46SWarner Losh char cmd[512], cmdtmp[512]; 267ca987d46SWarner Losh ssize_t sz; 268ca987d46SWarner Losh int autoboot, dskupdated; 269ca987d46SWarner Losh ufs_ino_t ino; 270ca987d46SWarner Losh 271ca987d46SWarner Losh dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 272ca987d46SWarner Losh 273ca987d46SWarner Losh bios_getmem(); 274ca987d46SWarner Losh 275ca987d46SWarner Losh if (high_heap_size > 0) { 276ca987d46SWarner Losh heap_end = PTOV(high_heap_base + high_heap_size); 277ca987d46SWarner Losh heap_next = PTOV(high_heap_base); 278ca987d46SWarner Losh } else { 279ca987d46SWarner Losh heap_next = (char *)dmadat + sizeof(*dmadat); 280ca987d46SWarner Losh heap_end = (char *)PTOV(bios_basemem); 281ca987d46SWarner Losh } 28265628439SWarner Losh setheap(heap_next, heap_end); 283ca987d46SWarner Losh 284ca987d46SWarner Losh v86.ctl = V86_FLAGS; 285ca987d46SWarner Losh v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 286c1418270SIan Lepore gdsk.dsk.drive = *(uint8_t *)PTOV(ARGS); 287c1418270SIan Lepore gdsk.dsk.type = gdsk.dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 288c1418270SIan Lepore gdsk.dsk.unit = gdsk.dsk.drive & DRV_MASK; 289c1418270SIan Lepore gdsk.dsk.part = -1; 290c1418270SIan Lepore gdsk.dsk.start = 0; 291ca987d46SWarner Losh bootinfo.bi_version = BOOTINFO_VERSION; 292ca987d46SWarner Losh bootinfo.bi_size = sizeof(bootinfo); 293ca987d46SWarner Losh bootinfo.bi_basemem = bios_basemem / 1024; 294ca987d46SWarner Losh bootinfo.bi_extmem = bios_extmem / 1024; 295ca987d46SWarner Losh bootinfo.bi_memsizes_valid++; 296c1418270SIan Lepore bootinfo.bi_bios_dev = gdsk.dsk.drive; 297ca987d46SWarner Losh 298ca987d46SWarner Losh /* Process configuration file */ 299ca987d46SWarner Losh 300ca987d46SWarner Losh if (gptinit() != 0) 301ca987d46SWarner Losh return (-1); 302ca987d46SWarner Losh 303ca987d46SWarner Losh autoboot = 1; 304ca987d46SWarner Losh *cmd = '\0'; 305ca987d46SWarner Losh 306ca987d46SWarner Losh for (;;) { 307ca987d46SWarner Losh *kname = '\0'; 308ca987d46SWarner Losh if ((ino = lookup(PATH_CONFIG)) || 309ca987d46SWarner Losh (ino = lookup(PATH_DOTCONFIG))) { 310ca987d46SWarner Losh sz = fsread(ino, cmd, sizeof(cmd) - 1); 311ca987d46SWarner Losh cmd[(sz < 0) ? 0 : sz] = '\0'; 312ca987d46SWarner Losh } 313ca987d46SWarner Losh if (*cmd != '\0') { 314ca987d46SWarner Losh memcpy(cmdtmp, cmd, sizeof(cmdtmp)); 315ca987d46SWarner Losh if (parse_cmds(cmdtmp, &dskupdated)) 316ca987d46SWarner Losh break; 317ca987d46SWarner Losh if (dskupdated && gptinit() != 0) 318ca987d46SWarner Losh break; 319ca987d46SWarner Losh if (!OPT_CHECK(RBX_QUIET)) 320ca987d46SWarner Losh printf("%s: %s", PATH_CONFIG, cmd); 321ca987d46SWarner Losh *cmd = '\0'; 322ca987d46SWarner Losh } 323ca987d46SWarner Losh 324ca987d46SWarner Losh if (autoboot && keyhit(3)) { 325ca987d46SWarner Losh if (*kname == '\0') 326ca987d46SWarner Losh memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); 327ca987d46SWarner Losh break; 328ca987d46SWarner Losh } 329ca987d46SWarner Losh autoboot = 0; 330ca987d46SWarner Losh 331ca987d46SWarner Losh /* 332ca987d46SWarner Losh * Try to exec stage 3 boot loader. If interrupted by a 333ca987d46SWarner Losh * keypress, or in case of failure, try to load a kernel 334ca987d46SWarner Losh * directly instead. 335ca987d46SWarner Losh */ 336ca987d46SWarner Losh if (*kname != '\0') 337ca987d46SWarner Losh load(); 338ca987d46SWarner Losh memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); 339ca987d46SWarner Losh load(); 340ca987d46SWarner Losh memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 341ca987d46SWarner Losh load(); 342c1418270SIan Lepore gptbootfailed(&gdsk.dsk); 343c1418270SIan Lepore if (gptfind(&freebsd_ufs_uuid, &gdsk.dsk, -1) == -1) 344ca987d46SWarner Losh break; 345ca987d46SWarner Losh dsk_meta = 0; 346ca987d46SWarner Losh } 347ca987d46SWarner Losh 348ca987d46SWarner Losh /* Present the user with the boot2 prompt. */ 349ca987d46SWarner Losh 350ca987d46SWarner Losh for (;;) { 351ca987d46SWarner Losh if (!OPT_CHECK(RBX_QUIET)) { 352ca987d46SWarner Losh printf("\nFreeBSD/x86 boot\n" 353ca987d46SWarner Losh "Default: %u:%s(%up%u)%s\n" 354ca987d46SWarner Losh "boot: ", 355c1418270SIan Lepore gdsk.dsk.drive & DRV_MASK, dev_nm[gdsk.dsk.type], 356c1418270SIan Lepore gdsk.dsk.unit, gdsk.dsk.part, kname); 357ca987d46SWarner Losh } 358ca987d46SWarner Losh if (ioctrl & IO_SERIAL) 359ca987d46SWarner Losh sio_flush(); 360ca987d46SWarner Losh *cmd = '\0'; 361ca987d46SWarner Losh if (keyhit(0)) 362ca987d46SWarner Losh getstr(cmd, sizeof(cmd)); 363ca987d46SWarner Losh else if (!OPT_CHECK(RBX_QUIET)) 364ca987d46SWarner Losh putchar('\n'); 365ca987d46SWarner Losh if (parse_cmds(cmd, &dskupdated)) { 366ca987d46SWarner Losh putchar('\a'); 367ca987d46SWarner Losh continue; 368ca987d46SWarner Losh } 369ca987d46SWarner Losh if (dskupdated && gptinit() != 0) 370ca987d46SWarner Losh continue; 371ca987d46SWarner Losh load(); 372ca987d46SWarner Losh } 373ca987d46SWarner Losh /* NOTREACHED */ 374ca987d46SWarner Losh } 375ca987d46SWarner Losh 376ca987d46SWarner Losh /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 377ca987d46SWarner Losh void 378ca987d46SWarner Losh exit(int x) 379ca987d46SWarner Losh { 380288013f5SBenno Rice 38186bb84d5SWarner Losh while (1); 38247940d85SWarner Losh __unreachable(); 383ca987d46SWarner Losh } 384ca987d46SWarner Losh 385ca987d46SWarner Losh static void 386ca987d46SWarner Losh load(void) 387ca987d46SWarner Losh { 388ca987d46SWarner Losh union { 389ca987d46SWarner Losh struct exec ex; 390ca987d46SWarner Losh Elf32_Ehdr eh; 391ca987d46SWarner Losh } hdr; 392ca987d46SWarner Losh static Elf32_Phdr ep[2]; 393ca987d46SWarner Losh static Elf32_Shdr es[2]; 394ca987d46SWarner Losh caddr_t p; 395ca987d46SWarner Losh ufs_ino_t ino; 396ca987d46SWarner Losh uint32_t addr, x; 397ca987d46SWarner Losh int fmt, i, j; 398ca987d46SWarner Losh 399ca987d46SWarner Losh if (!(ino = lookup(kname))) { 400ca987d46SWarner Losh if (!ls) { 401ca987d46SWarner Losh printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, 40294966221SIan Lepore kname, gdsk.dsk.drive & DRV_MASK, 40394966221SIan Lepore dev_nm[gdsk.dsk.type], gdsk.dsk.unit, 40494966221SIan Lepore gdsk.dsk.part); 405ca987d46SWarner Losh } 406ca987d46SWarner Losh return; 407ca987d46SWarner Losh } 408ca987d46SWarner Losh if (xfsread(ino, &hdr, sizeof(hdr))) 409ca987d46SWarner Losh return; 410ca987d46SWarner Losh if (N_GETMAGIC(hdr.ex) == ZMAGIC) 411ca987d46SWarner Losh fmt = 0; 412ca987d46SWarner Losh else if (IS_ELF(hdr.eh)) 413ca987d46SWarner Losh fmt = 1; 414ca987d46SWarner Losh else { 415ca987d46SWarner Losh printf("Invalid %s\n", "format"); 416ca987d46SWarner Losh return; 417ca987d46SWarner Losh } 418ca987d46SWarner Losh if (fmt == 0) { 419ca987d46SWarner Losh addr = hdr.ex.a_entry & 0xffffff; 420ca987d46SWarner Losh p = PTOV(addr); 421ca987d46SWarner Losh fs_off = PAGE_SIZE; 422ca987d46SWarner Losh if (xfsread(ino, p, hdr.ex.a_text)) 423ca987d46SWarner Losh return; 424ca987d46SWarner Losh p += roundup2(hdr.ex.a_text, PAGE_SIZE); 425ca987d46SWarner Losh if (xfsread(ino, p, hdr.ex.a_data)) 426ca987d46SWarner Losh return; 427ca987d46SWarner Losh p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 428ca987d46SWarner Losh bootinfo.bi_symtab = VTOP(p); 429ca987d46SWarner Losh memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 430ca987d46SWarner Losh p += sizeof(hdr.ex.a_syms); 431ca987d46SWarner Losh if (hdr.ex.a_syms) { 432ca987d46SWarner Losh if (xfsread(ino, p, hdr.ex.a_syms)) 433ca987d46SWarner Losh return; 434ca987d46SWarner Losh p += hdr.ex.a_syms; 435ca987d46SWarner Losh if (xfsread(ino, p, sizeof(int))) 436ca987d46SWarner Losh return; 437ca987d46SWarner Losh x = *(uint32_t *)p; 438ca987d46SWarner Losh p += sizeof(int); 439ca987d46SWarner Losh x -= sizeof(int); 440ca987d46SWarner Losh if (xfsread(ino, p, x)) 441ca987d46SWarner Losh return; 442ca987d46SWarner Losh p += x; 443ca987d46SWarner Losh } 444ca987d46SWarner Losh } else { 445ca987d46SWarner Losh fs_off = hdr.eh.e_phoff; 446ca987d46SWarner Losh for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 447ca987d46SWarner Losh if (xfsread(ino, ep + j, sizeof(ep[0]))) 448ca987d46SWarner Losh return; 449ca987d46SWarner Losh if (ep[j].p_type == PT_LOAD) 450ca987d46SWarner Losh j++; 451ca987d46SWarner Losh } 452ca987d46SWarner Losh for (i = 0; i < 2; i++) { 453ca987d46SWarner Losh p = PTOV(ep[i].p_paddr & 0xffffff); 454ca987d46SWarner Losh fs_off = ep[i].p_offset; 455ca987d46SWarner Losh if (xfsread(ino, p, ep[i].p_filesz)) 456ca987d46SWarner Losh return; 457ca987d46SWarner Losh } 458ca987d46SWarner Losh p += roundup2(ep[1].p_memsz, PAGE_SIZE); 459ca987d46SWarner Losh bootinfo.bi_symtab = VTOP(p); 460ca987d46SWarner Losh if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 461ca987d46SWarner Losh fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 462ca987d46SWarner Losh (hdr.eh.e_shstrndx + 1); 463ca987d46SWarner Losh if (xfsread(ino, &es, sizeof(es))) 464ca987d46SWarner Losh return; 465ca987d46SWarner Losh for (i = 0; i < 2; i++) { 4668e48426cSBenno Rice memcpy(p, &es[i].sh_size, 4678e48426cSBenno Rice sizeof(es[i].sh_size)); 468ca987d46SWarner Losh p += sizeof(es[i].sh_size); 469ca987d46SWarner Losh fs_off = es[i].sh_offset; 470ca987d46SWarner Losh if (xfsread(ino, p, es[i].sh_size)) 471ca987d46SWarner Losh return; 472ca987d46SWarner Losh p += es[i].sh_size; 473ca987d46SWarner Losh } 474ca987d46SWarner Losh } 475ca987d46SWarner Losh addr = hdr.eh.e_entry & 0xffffff; 476ca987d46SWarner Losh } 477ca987d46SWarner Losh bootinfo.bi_esymtab = VTOP(p); 478ca987d46SWarner Losh bootinfo.bi_kernelname = VTOP(kname); 479c1418270SIan Lepore bootinfo.bi_bios_dev = gdsk.dsk.drive; 480ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 481ca987d46SWarner Losh geliargs.size = sizeof(geliargs); 482ca987d46SWarner Losh explicit_bzero(gelipw, sizeof(gelipw)); 4838e48426cSBenno Rice gelibuf = malloc(sizeof(struct keybuf) + 4848e48426cSBenno Rice (GELI_MAX_KEYS * sizeof(struct keybuf_ent))); 485c1418270SIan Lepore geli_export_key_buffer(gelibuf); 486ca987d46SWarner Losh geliargs.notapw = '\0'; 487ca987d46SWarner Losh geliargs.keybuf_sentinel = KEYBUF_SENTINEL; 488ca987d46SWarner Losh geliargs.keybuf = gelibuf; 489ca987d46SWarner Losh #endif 490*b92c2c90SIan Lepore /* 491*b92c2c90SIan Lepore * Note that the geliargs struct is passed by value, not by pointer. 492*b92c2c90SIan Lepore * Code in btxldr.S copies the values from the entry stack to a fixed 493*b92c2c90SIan Lepore * location within loader(8) at startup due to the presence of the 494*b92c2c90SIan Lepore * KARGS_FLAGS_EXTARG flag. 495*b92c2c90SIan Lepore */ 496ca987d46SWarner Losh __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 497c1418270SIan Lepore MAKEBOOTDEV(dev_maj[gdsk.dsk.type], gdsk.dsk.part + 1, gdsk.dsk.unit, 0xff), 498ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 4994e6c8e6dSKyle Evans KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo), geliargs 5004e6c8e6dSKyle Evans #else 5014e6c8e6dSKyle Evans 0, 0, 0, VTOP(&bootinfo) 502ca987d46SWarner Losh #endif 503ca987d46SWarner Losh ); 504ca987d46SWarner Losh } 505ca987d46SWarner Losh 506ca987d46SWarner Losh static int 507ca987d46SWarner Losh parse_cmds(char *cmdstr, int *dskupdated) 508ca987d46SWarner Losh { 509288013f5SBenno Rice char *arg; 510ca987d46SWarner Losh char *ep, *p, *q; 511ca987d46SWarner Losh const char *cp; 512ca987d46SWarner Losh unsigned int drv; 513ca987d46SWarner Losh int c, i, j; 514ca987d46SWarner Losh 515288013f5SBenno Rice arg = cmdstr; 516ca987d46SWarner Losh *dskupdated = 0; 517ca987d46SWarner Losh while ((c = *arg++)) { 518ca987d46SWarner Losh if (c == ' ' || c == '\t' || c == '\n') 519ca987d46SWarner Losh continue; 520ca987d46SWarner Losh for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 521ca987d46SWarner Losh ep = p; 522ca987d46SWarner Losh if (*p) 523ca987d46SWarner Losh *p++ = 0; 524ca987d46SWarner Losh if (c == '-') { 525ca987d46SWarner Losh while ((c = *arg++)) { 526ca987d46SWarner Losh if (c == 'P') { 527ca987d46SWarner Losh if (*(uint8_t *)PTOV(0x496) & 0x10) { 528ca987d46SWarner Losh cp = "yes"; 529ca987d46SWarner Losh } else { 5308e48426cSBenno Rice opts |= OPT_SET(RBX_DUAL) | 5318e48426cSBenno Rice OPT_SET(RBX_SERIAL); 532ca987d46SWarner Losh cp = "no"; 533ca987d46SWarner Losh } 534ca987d46SWarner Losh printf("Keyboard: %s\n", cp); 535ca987d46SWarner Losh continue; 536ca987d46SWarner Losh } else if (c == 'S') { 537ca987d46SWarner Losh j = 0; 5388e48426cSBenno Rice while ((unsigned int)(i = *arg++ - '0') 5398e48426cSBenno Rice <= 9) 540ca987d46SWarner Losh j = j * 10 + i; 541ca987d46SWarner Losh if (j > 0 && i == -'0') { 542ca987d46SWarner Losh comspeed = j; 543ca987d46SWarner Losh break; 544ca987d46SWarner Losh } 5458e48426cSBenno Rice /* 5468e48426cSBenno Rice * Fall through to error below 5478e48426cSBenno Rice * ('S' not in optstr[]). 5488e48426cSBenno Rice */ 549ca987d46SWarner Losh } 550ca987d46SWarner Losh for (i = 0; c != optstr[i]; i++) 551ca987d46SWarner Losh if (i == NOPT - 1) 552288013f5SBenno Rice return (-1); 553ca987d46SWarner Losh opts ^= OPT_SET(flags[i]); 554ca987d46SWarner Losh } 555ca987d46SWarner Losh ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 556ca987d46SWarner Losh OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 557ca987d46SWarner Losh if (ioctrl & IO_SERIAL) { 558ca987d46SWarner Losh if (sio_init(115200 / comspeed) != 0) 559ca987d46SWarner Losh ioctrl &= ~IO_SERIAL; 560ca987d46SWarner Losh } 561ca987d46SWarner Losh } else { 562ca987d46SWarner Losh for (q = arg--; *q && *q != '('; q++); 563ca987d46SWarner Losh if (*q) { 564ca987d46SWarner Losh drv = -1; 565ca987d46SWarner Losh if (arg[1] == ':') { 566ca987d46SWarner Losh drv = *arg - '0'; 567ca987d46SWarner Losh if (drv > 9) 568ca987d46SWarner Losh return (-1); 569ca987d46SWarner Losh arg += 2; 570ca987d46SWarner Losh } 571ca987d46SWarner Losh if (q - arg != 2) 572288013f5SBenno Rice return (-1); 573ca987d46SWarner Losh for (i = 0; arg[0] != dev_nm[i][0] || 574ca987d46SWarner Losh arg[1] != dev_nm[i][1]; i++) 575ca987d46SWarner Losh if (i == NDEV - 1) 576288013f5SBenno Rice return (-1); 57752c0ec14SIan Lepore gdsk.dsk.type = i; 578ca987d46SWarner Losh arg += 3; 57952c0ec14SIan Lepore gdsk.dsk.unit = *arg - '0'; 58052c0ec14SIan Lepore if (arg[1] != 'p' || gdsk.dsk.unit > 9) 581288013f5SBenno Rice return (-1); 582ca987d46SWarner Losh arg += 2; 58352c0ec14SIan Lepore gdsk.dsk.part = *arg - '0'; 58452c0ec14SIan Lepore if (gdsk.dsk.part < 1 || gdsk.dsk.part > 9) 585288013f5SBenno Rice return (-1); 586ca987d46SWarner Losh arg++; 587ca987d46SWarner Losh if (arg[0] != ')') 588288013f5SBenno Rice return (-1); 589ca987d46SWarner Losh arg++; 590ca987d46SWarner Losh if (drv == -1) 59152c0ec14SIan Lepore drv = gdsk.dsk.unit; 59252c0ec14SIan Lepore gdsk.dsk.drive = (gdsk.dsk.type <= TYPE_MAXHARD 593ca987d46SWarner Losh ? DRV_HARD : 0) + drv; 594ca987d46SWarner Losh *dskupdated = 1; 595ca987d46SWarner Losh } 596ca987d46SWarner Losh if ((i = ep - arg)) { 597ca987d46SWarner Losh if ((size_t)i >= sizeof(kname)) 598288013f5SBenno Rice return (-1); 599ca987d46SWarner Losh memcpy(kname, arg, i + 1); 600ca987d46SWarner Losh } 601ca987d46SWarner Losh } 602ca987d46SWarner Losh arg = p; 603ca987d46SWarner Losh } 604288013f5SBenno Rice return (0); 605ca987d46SWarner Losh } 606ca987d46SWarner Losh 607ca987d46SWarner Losh static int 608ca987d46SWarner Losh dskread(void *buf, daddr_t lba, unsigned nblk) 609ca987d46SWarner Losh { 610ca987d46SWarner Losh int err; 611ca987d46SWarner Losh 612c1418270SIan Lepore err = drvread(&gdsk.dsk, buf, lba + gdsk.dsk.start, nblk); 613ca987d46SWarner Losh 614ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 615c1418270SIan Lepore if (err == 0 && gdsk.gdev != NULL) { 616ca987d46SWarner Losh /* Decrypt */ 617c1418270SIan Lepore if (geli_read(gdsk.gdev, lba * DEV_BSIZE, buf, 618c1418270SIan Lepore nblk * DEV_BSIZE)) 619ca987d46SWarner Losh return (err); 620ca987d46SWarner Losh } 621ca987d46SWarner Losh #endif 622ca987d46SWarner Losh 623ca987d46SWarner Losh return (err); 624ca987d46SWarner Losh } 625ca987d46SWarner Losh 626ca987d46SWarner Losh #ifdef LOADER_GELI_SUPPORT 627ca987d46SWarner Losh /* 628c1418270SIan Lepore * Read function compatible with the ZFS callback, required to keep the GELI 629c1418270SIan Lepore * implementation the same for both UFS and ZFS. 630ca987d46SWarner Losh */ 631ca987d46SWarner Losh static int 632ca987d46SWarner Losh vdev_read(void *vdev __unused, void *priv, off_t off, void *buf, size_t bytes) 633ca987d46SWarner Losh { 634ca987d46SWarner Losh char *p; 635ca987d46SWarner Losh daddr_t lba; 636ca987d46SWarner Losh unsigned int nb; 637c1418270SIan Lepore struct gptdsk *dskp; 638288013f5SBenno Rice 639c1418270SIan Lepore dskp = (struct gptdsk *)priv; 640ca987d46SWarner Losh 641ca987d46SWarner Losh if ((off & (DEV_BSIZE - 1)) || (bytes & (DEV_BSIZE - 1))) 642ca987d46SWarner Losh return (-1); 643ca987d46SWarner Losh 644ca987d46SWarner Losh p = buf; 645ca987d46SWarner Losh lba = off / DEV_BSIZE; 646c1418270SIan Lepore lba += dskp->dsk.start; 647ca987d46SWarner Losh 648ca987d46SWarner Losh while (bytes > 0) { 649ca987d46SWarner Losh nb = bytes / DEV_BSIZE; 650ca987d46SWarner Losh if (nb > VBLKSIZE / DEV_BSIZE) 651ca987d46SWarner Losh nb = VBLKSIZE / DEV_BSIZE; 652c1418270SIan Lepore if (drvread(&dskp->dsk, dmadat->blkbuf, lba, nb)) 653ca987d46SWarner Losh return (-1); 654ca987d46SWarner Losh memcpy(p, dmadat->blkbuf, nb * DEV_BSIZE); 655ca987d46SWarner Losh p += nb * DEV_BSIZE; 656ca987d46SWarner Losh lba += nb; 657ca987d46SWarner Losh bytes -= nb * DEV_BSIZE; 658ca987d46SWarner Losh } 659ca987d46SWarner Losh 660ca987d46SWarner Losh return (0); 661ca987d46SWarner Losh } 662ca987d46SWarner Losh #endif /* LOADER_GELI_SUPPORT */ 663