gptboot.c revision 295835
1/*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are freely 6 * permitted provided that the above copyright notice and this 7 * paragraph and the following disclaimer are duplicated in all 8 * such forms. 9 * 10 * This software is provided "AS IS" and without any express or 11 * implied warranties, including, without limitation, the implied 12 * warranties of merchantability and fitness for a particular 13 * purpose. 14 */ 15 16#include <sys/cdefs.h> 17__FBSDID("$FreeBSD: stable/10/sys/boot/i386/gptboot/gptboot.c 295835 2016-02-20 10:56:46Z smh $"); 18 19#include <sys/param.h> 20#include <sys/gpt.h> 21#include <sys/dirent.h> 22#include <sys/reboot.h> 23 24#include <machine/bootinfo.h> 25#include <machine/elf.h> 26#include <machine/psl.h> 27 28#include <stdarg.h> 29 30#include <a.out.h> 31 32#include <btxv86.h> 33 34#include "lib.h" 35#include "rbx.h" 36#include "drv.h" 37#include "util.h" 38#include "cons.h" 39#include "gpt.h" 40#include "paths.h" 41 42#define ARGS 0x900 43#define NOPT 14 44#define NDEV 3 45#define MEM_BASE 0x12 46#define MEM_EXT 0x15 47 48#define DRV_HARD 0x80 49#define DRV_MASK 0x7f 50 51#define TYPE_AD 0 52#define TYPE_DA 1 53#define TYPE_MAXHARD TYPE_DA 54#define TYPE_FD 2 55 56extern uint32_t _end; 57 58static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; 59static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 60static const unsigned char flags[NOPT] = { 61 RBX_DUAL, 62 RBX_SERIAL, 63 RBX_ASKNAME, 64 RBX_CDROM, 65 RBX_CONFIG, 66 RBX_KDB, 67 RBX_GDB, 68 RBX_MUTE, 69 RBX_NOINTR, 70 RBX_PAUSE, 71 RBX_QUIET, 72 RBX_DFLTROOT, 73 RBX_SINGLE, 74 RBX_VERBOSE 75}; 76uint32_t opts; 77 78static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 79static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 80 81static struct dsk dsk; 82static char kname[1024]; 83static int comspeed = SIOSPD; 84static struct bootinfo bootinfo; 85 86void exit(int); 87static void load(void); 88static int parse(char *, int *); 89static int dskread(void *, daddr_t, unsigned); 90static uint32_t memsize(void); 91 92#include "ufsread.c" 93 94static inline int 95xfsread(ufs_ino_t inode, void *buf, size_t nbyte) 96{ 97 98 if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 99 printf("Invalid %s\n", "format"); 100 return (-1); 101 } 102 return (0); 103} 104 105static inline uint32_t 106memsize(void) 107{ 108 109 v86.addr = MEM_EXT; 110 v86.eax = 0x8800; 111 v86int(); 112 return (v86.eax); 113} 114 115static int 116gptinit(void) 117{ 118 119 if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) { 120 printf("%s: unable to load GPT\n", BOOTPROG); 121 return (-1); 122 } 123 if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) { 124 printf("%s: no UFS partition was found\n", BOOTPROG); 125 return (-1); 126 } 127 dsk_meta = 0; 128 return (0); 129} 130 131int 132main(void) 133{ 134 char cmd[512], cmdtmp[512]; 135 ssize_t sz; 136 int autoboot, dskupdated; 137 ufs_ino_t ino; 138 139 dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 140 v86.ctl = V86_FLAGS; 141 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 142 dsk.drive = *(uint8_t *)PTOV(ARGS); 143 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 144 dsk.unit = dsk.drive & DRV_MASK; 145 dsk.part = -1; 146 dsk.start = 0; 147 bootinfo.bi_version = BOOTINFO_VERSION; 148 bootinfo.bi_size = sizeof(bootinfo); 149 bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 150 bootinfo.bi_extmem = memsize(); 151 bootinfo.bi_memsizes_valid++; 152 153 /* Process configuration file */ 154 155 if (gptinit() != 0) 156 return (-1); 157 158 autoboot = 1; 159 *cmd = '\0'; 160 161 for (;;) { 162 *kname = '\0'; 163 if ((ino = lookup(PATH_CONFIG)) || 164 (ino = lookup(PATH_DOTCONFIG))) { 165 sz = fsread(ino, cmd, sizeof(cmd) - 1); 166 cmd[(sz < 0) ? 0 : sz] = '\0'; 167 } 168 if (*cmd != '\0') { 169 memcpy(cmdtmp, cmd, sizeof(cmdtmp)); 170 if (parse(cmdtmp, &dskupdated)) 171 break; 172 if (dskupdated && gptinit() != 0) 173 break; 174 if (!OPT_CHECK(RBX_QUIET)) 175 printf("%s: %s", PATH_CONFIG, cmd); 176 *cmd = '\0'; 177 } 178 179 if (autoboot && keyhit(3)) { 180 if (*kname == '\0') 181 memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); 182 break; 183 } 184 autoboot = 0; 185 186 /* 187 * Try to exec stage 3 boot loader. If interrupted by a 188 * keypress, or in case of failure, try to load a kernel 189 * directly instead. 190 */ 191 if (*kname != '\0') 192 load(); 193 memcpy(kname, PATH_LOADER, sizeof(PATH_LOADER)); 194 load(); 195 memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 196 load(); 197 gptbootfailed(&dsk); 198 if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1) 199 break; 200 dsk_meta = 0; 201 } 202 203 /* Present the user with the boot2 prompt. */ 204 205 for (;;) { 206 if (!OPT_CHECK(RBX_QUIET)) { 207 printf("\nFreeBSD/x86 boot\n" 208 "Default: %u:%s(%up%u)%s\n" 209 "boot: ", 210 dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 211 dsk.part, kname); 212 } 213 if (ioctrl & IO_SERIAL) 214 sio_flush(); 215 *cmd = '\0'; 216 if (keyhit(0)) 217 getstr(cmd, sizeof(cmd)); 218 else if (!OPT_CHECK(RBX_QUIET)) 219 putchar('\n'); 220 if (parse(cmd, &dskupdated)) { 221 putchar('\a'); 222 continue; 223 } 224 if (dskupdated && gptinit() != 0) 225 continue; 226 load(); 227 } 228 /* NOTREACHED */ 229} 230 231/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 232void 233exit(int x) 234{ 235} 236 237static void 238load(void) 239{ 240 union { 241 struct exec ex; 242 Elf32_Ehdr eh; 243 } hdr; 244 static Elf32_Phdr ep[2]; 245 static Elf32_Shdr es[2]; 246 caddr_t p; 247 ufs_ino_t ino; 248 uint32_t addr, x; 249 int fmt, i, j; 250 251 if (!(ino = lookup(kname))) { 252 if (!ls) { 253 printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, 254 kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 255 dsk.part); 256 } 257 return; 258 } 259 if (xfsread(ino, &hdr, sizeof(hdr))) 260 return; 261 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 262 fmt = 0; 263 else if (IS_ELF(hdr.eh)) 264 fmt = 1; 265 else { 266 printf("Invalid %s\n", "format"); 267 return; 268 } 269 if (fmt == 0) { 270 addr = hdr.ex.a_entry & 0xffffff; 271 p = PTOV(addr); 272 fs_off = PAGE_SIZE; 273 if (xfsread(ino, p, hdr.ex.a_text)) 274 return; 275 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 276 if (xfsread(ino, p, hdr.ex.a_data)) 277 return; 278 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 279 bootinfo.bi_symtab = VTOP(p); 280 memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 281 p += sizeof(hdr.ex.a_syms); 282 if (hdr.ex.a_syms) { 283 if (xfsread(ino, p, hdr.ex.a_syms)) 284 return; 285 p += hdr.ex.a_syms; 286 if (xfsread(ino, p, sizeof(int))) 287 return; 288 x = *(uint32_t *)p; 289 p += sizeof(int); 290 x -= sizeof(int); 291 if (xfsread(ino, p, x)) 292 return; 293 p += x; 294 } 295 } else { 296 fs_off = hdr.eh.e_phoff; 297 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 298 if (xfsread(ino, ep + j, sizeof(ep[0]))) 299 return; 300 if (ep[j].p_type == PT_LOAD) 301 j++; 302 } 303 for (i = 0; i < 2; i++) { 304 p = PTOV(ep[i].p_paddr & 0xffffff); 305 fs_off = ep[i].p_offset; 306 if (xfsread(ino, p, ep[i].p_filesz)) 307 return; 308 } 309 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 310 bootinfo.bi_symtab = VTOP(p); 311 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 312 fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 313 (hdr.eh.e_shstrndx + 1); 314 if (xfsread(ino, &es, sizeof(es))) 315 return; 316 for (i = 0; i < 2; i++) { 317 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 318 p += sizeof(es[i].sh_size); 319 fs_off = es[i].sh_offset; 320 if (xfsread(ino, p, es[i].sh_size)) 321 return; 322 p += es[i].sh_size; 323 } 324 } 325 addr = hdr.eh.e_entry & 0xffffff; 326 } 327 bootinfo.bi_esymtab = VTOP(p); 328 bootinfo.bi_kernelname = VTOP(kname); 329 bootinfo.bi_bios_dev = dsk.drive; 330 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 331 MAKEBOOTDEV(dev_maj[dsk.type], dsk.part + 1, dsk.unit, 0xff), 332 0, 0, 0, VTOP(&bootinfo)); 333} 334 335static int 336parse(char *cmdstr, int *dskupdated) 337{ 338 char *arg = cmdstr; 339 char *ep, *p, *q; 340 const char *cp; 341 unsigned int drv; 342 int c, i, j; 343 344 *dskupdated = 0; 345 while ((c = *arg++)) { 346 if (c == ' ' || c == '\t' || c == '\n') 347 continue; 348 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 349 ep = p; 350 if (*p) 351 *p++ = 0; 352 if (c == '-') { 353 while ((c = *arg++)) { 354 if (c == 'P') { 355 if (*(uint8_t *)PTOV(0x496) & 0x10) { 356 cp = "yes"; 357 } else { 358 opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 359 cp = "no"; 360 } 361 printf("Keyboard: %s\n", cp); 362 continue; 363 } else if (c == 'S') { 364 j = 0; 365 while ((unsigned int)(i = *arg++ - '0') <= 9) 366 j = j * 10 + i; 367 if (j > 0 && i == -'0') { 368 comspeed = j; 369 break; 370 } 371 /* Fall through to error below ('S' not in optstr[]). */ 372 } 373 for (i = 0; c != optstr[i]; i++) 374 if (i == NOPT - 1) 375 return -1; 376 opts ^= OPT_SET(flags[i]); 377 } 378 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 379 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 380 if (ioctrl & IO_SERIAL) { 381 if (sio_init(115200 / comspeed) != 0) 382 ioctrl &= ~IO_SERIAL; 383 } 384 } else { 385 for (q = arg--; *q && *q != '('; q++); 386 if (*q) { 387 drv = -1; 388 if (arg[1] == ':') { 389 drv = *arg - '0'; 390 if (drv > 9) 391 return (-1); 392 arg += 2; 393 } 394 if (q - arg != 2) 395 return -1; 396 for (i = 0; arg[0] != dev_nm[i][0] || 397 arg[1] != dev_nm[i][1]; i++) 398 if (i == NDEV - 1) 399 return -1; 400 dsk.type = i; 401 arg += 3; 402 dsk.unit = *arg - '0'; 403 if (arg[1] != 'p' || dsk.unit > 9) 404 return -1; 405 arg += 2; 406 dsk.part = *arg - '0'; 407 if (dsk.part < 1 || dsk.part > 9) 408 return -1; 409 arg++; 410 if (arg[0] != ')') 411 return -1; 412 arg++; 413 if (drv == -1) 414 drv = dsk.unit; 415 dsk.drive = (dsk.type <= TYPE_MAXHARD 416 ? DRV_HARD : 0) + drv; 417 *dskupdated = 1; 418 } 419 if ((i = ep - arg)) { 420 if ((size_t)i >= sizeof(kname)) 421 return -1; 422 memcpy(kname, arg, i + 1); 423 } 424 } 425 arg = p; 426 } 427 return 0; 428} 429 430static int 431dskread(void *buf, daddr_t lba, unsigned nblk) 432{ 433 434 return drvread(&dsk, buf, lba + dsk.start, nblk); 435} 436