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 18 #include <sys/param.h> 19 #include <sys/gpt.h> 20 #include <sys/dirent.h> 21 #include <sys/reboot.h> 22 23 #include <machine/bootinfo.h> 24 #include <machine/elf.h> 25 #include <machine/pc/bios.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 "stand.h" 35 36 #include "bootargs.h" 37 #include "lib.h" 38 #include "rbx.h" 39 #include "drv.h" 40 #include "cons.h" 41 #include "gpt.h" 42 #include "paths.h" 43 44 #define ARGS 0x900 45 #define NOPT 14 46 #define NDEV 3 47 #define MEM_BASE 0x12 48 #define MEM_EXT 0x15 49 50 #define DRV_HARD 0x80 51 #define DRV_MASK 0x7f 52 53 #define TYPE_AD 0 54 #define TYPE_DA 1 55 #define TYPE_MAXHARD TYPE_DA 56 #define TYPE_FD 2 57 58 /* 59 * Fake multiboot header to provide versioning and to pass 60 * partition start LBA. Partition is either GPT partition or 61 * VTOC slice. 62 */ 63 extern const struct multiboot_header mb_header; 64 extern uint64_t start_sector; 65 66 extern uint32_t _end; 67 68 static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 69 static const unsigned char flags[NOPT] = { 70 RBX_DUAL, 71 RBX_SERIAL, 72 RBX_ASKNAME, 73 RBX_CDROM, 74 RBX_CONFIG, 75 RBX_KDB, 76 RBX_GDB, 77 RBX_MUTE, 78 RBX_NOINTR, 79 RBX_PAUSE, 80 RBX_QUIET, 81 RBX_DFLTROOT, 82 RBX_SINGLE, 83 RBX_VERBOSE 84 }; 85 uint32_t opts; 86 87 static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 88 static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 89 90 static struct dsk dsk; 91 static char kname[1024]; 92 static int comspeed = SIOSPD; 93 static struct bootinfo bootinfo; 94 95 static vm_offset_t high_heap_base; 96 static uint32_t bios_basemem, bios_extmem, high_heap_size; 97 98 static struct bios_smap smap; 99 100 /* 101 * The minimum amount of memory to reserve in bios_extmem for the heap. 102 */ 103 #define HEAP_MIN (3 * 1024 * 1024) 104 105 static char *heap_next; 106 static char *heap_end; 107 108 int main(void); 109 110 void exit(int); 111 static void load(void); 112 static int parse_cmds(char *, int *); 113 114 static uint8_t ls; 115 static uint32_t fs_off; 116 117 #include "cd9660read.c" 118 119 static int 120 xfsread(uint64_t inode, void *buf, size_t nbyte) 121 { 122 123 if ((size_t)cd9660_fsread(inode, buf, nbyte) != nbyte) { 124 printf("Invalid %s\n", "format"); 125 return (-1); 126 } 127 return (0); 128 } 129 130 static void 131 bios_getmem(void) 132 { 133 uint64_t size; 134 135 /* Parse system memory map */ 136 v86.ebx = 0; 137 do { 138 v86.ctl = V86_FLAGS; 139 v86.addr = MEM_EXT; /* int 0x15 function 0xe820 */ 140 v86.eax = 0xe820; 141 v86.ecx = sizeof (struct bios_smap); 142 v86.edx = SMAP_SIG; 143 v86.es = VTOPSEG(&smap); 144 v86.edi = VTOPOFF(&smap); 145 v86int(); 146 if ((v86.efl & 1) || (v86.eax != SMAP_SIG)) 147 break; 148 /* look for a low-memory segment that's large enough */ 149 if ((smap.type == SMAP_TYPE_MEMORY) && (smap.base == 0) && 150 (smap.length >= (512 * 1024))) 151 bios_basemem = smap.length; 152 /* look for the first segment in 'extended' memory */ 153 if ((smap.type == SMAP_TYPE_MEMORY) && 154 (smap.base == 0x100000)) { 155 bios_extmem = smap.length; 156 } 157 158 /* 159 * Look for the largest segment in 'extended' memory beyond 160 * 1MB but below 4GB. 161 */ 162 if ((smap.type == SMAP_TYPE_MEMORY) && 163 (smap.base > 0x100000) && (smap.base < 0x100000000ull)) { 164 size = smap.length; 165 166 /* 167 * If this segment crosses the 4GB boundary, 168 * truncate it. 169 */ 170 if (smap.base + size > 0x100000000ull) 171 size = 0x100000000ull - smap.base; 172 173 if (size > high_heap_size) { 174 high_heap_size = size; 175 high_heap_base = smap.base; 176 } 177 } 178 } while (v86.ebx != 0); 179 180 /* Fall back to the old compatibility function for base memory */ 181 if (bios_basemem == 0) { 182 v86.ctl = 0; 183 v86.addr = 0x12; /* int 0x12 */ 184 v86int(); 185 186 bios_basemem = (v86.eax & 0xffff) * 1024; 187 } 188 189 /* 190 * Fall back through several compatibility functions for extended 191 * memory 192 */ 193 if (bios_extmem == 0) { 194 v86.ctl = V86_FLAGS; 195 v86.addr = 0x15; /* int 0x15 function 0xe801 */ 196 v86.eax = 0xe801; 197 v86int(); 198 if (!(v86.efl & 1)) { 199 bios_extmem = ((v86.ecx & 0xffff) + 200 ((v86.edx & 0xffff) * 64)) * 1024; 201 } 202 } 203 if (bios_extmem == 0) { 204 v86.ctl = 0; 205 v86.addr = 0x15; /* int 0x15 function 0x88 */ 206 v86.eax = 0x8800; 207 v86int(); 208 bios_extmem = (v86.eax & 0xffff) * 1024; 209 } 210 211 /* 212 * If we have extended memory and did not find a suitable heap 213 * region in the SMAP, use the last 3MB of 'extended' memory as a 214 * high heap candidate. 215 */ 216 if (bios_extmem >= HEAP_MIN && high_heap_size < HEAP_MIN) { 217 high_heap_size = HEAP_MIN; 218 high_heap_base = bios_extmem + 0x100000 - HEAP_MIN; 219 } 220 } 221 222 int 223 main(void) 224 { 225 char cmd[512], cmdtmp[512]; 226 ssize_t sz; 227 int autoboot, dskupdated; 228 uint64_t ino; 229 230 bios_getmem(); 231 232 if (high_heap_size > 0) { 233 heap_end = PTOV(high_heap_base + high_heap_size); 234 heap_next = PTOV(high_heap_base); 235 } else { 236 heap_next = (char *) 237 (roundup2(__base + (int32_t)&_end, 0x10000) - __base); 238 heap_end = (char *)PTOV(bios_basemem); 239 } 240 setheap(heap_next, heap_end); 241 242 /* Reference start_sector or linker will elliminate it. */ 243 if (start_sector != 0) 244 printf("isoboot: starting...\n"); 245 246 v86.ctl = V86_FLAGS; 247 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 248 dsk.drive = *(uint8_t *)PTOV(ARGS); 249 dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 250 dsk.unit = dsk.drive & DRV_MASK; 251 dsk.part = -1; 252 dsk.start = 0; 253 bootinfo.bi_version = BOOTINFO_VERSION; 254 bootinfo.bi_size = sizeof (bootinfo); 255 bootinfo.bi_basemem = bios_basemem / 1024; 256 bootinfo.bi_extmem = bios_extmem / 1024; 257 bootinfo.bi_memsizes_valid++; 258 bootinfo.bi_bios_dev = dsk.drive; 259 260 autoboot = 1; 261 *cmd = '\0'; 262 263 for (;;) { 264 *kname = '\0'; 265 if ((ino = cd9660_lookup(PATH_CONFIG)) || 266 (ino = cd9660_lookup(PATH_DOTCONFIG))) { 267 sz = cd9660_fsread(ino, cmd, sizeof (cmd) - 1); 268 cmd[(sz < 0) ? 0 : sz] = '\0'; 269 } 270 if (*cmd != '\0') { 271 memcpy(cmdtmp, cmd, sizeof (cmdtmp)); 272 if (parse_cmds(cmdtmp, &dskupdated)) 273 break; 274 if (!OPT_CHECK(RBX_QUIET)) 275 printf("%s: %s", PATH_CONFIG, cmd); 276 *cmd = '\0'; 277 } 278 279 if (autoboot && keyhit(3)) { 280 if (*kname == '\0') { 281 memcpy(kname, PATH_LOADER, 282 sizeof (PATH_LOADER)); 283 } 284 break; 285 } 286 autoboot = 0; 287 288 /* 289 * Try to exec stage 3 boot loader. If interrupted by a 290 * keypress, or in case of failure, try to load a kernel 291 * directly instead. 292 */ 293 if (*kname != '\0') 294 load(); 295 memcpy(kname, PATH_LOADER, sizeof (PATH_LOADER)); 296 load(); 297 break; 298 } 299 300 /* Present the user with the boot2 prompt. */ 301 302 for (;;) { 303 if (!OPT_CHECK(RBX_QUIET)) { 304 printf("\nillumos/x86 boot\n"); 305 if (dsk.part == -1) { 306 printf("Default: %u:%s(%u)%s\n", 307 dsk.drive & DRV_MASK, dev_nm[dsk.type], 308 dsk.unit, kname); 309 } else { 310 printf("Default: %u:%s(%up%u)%s\n", 311 dsk.drive & DRV_MASK, dev_nm[dsk.type], 312 dsk.unit, dsk.part, kname); 313 } 314 printf("boot: "); 315 } 316 if (ioctrl & IO_SERIAL) 317 sio_flush(); 318 *cmd = '\0'; 319 if (keyhit(0)) 320 getstr(cmd, sizeof (cmd)); 321 else if (!OPT_CHECK(RBX_QUIET)) 322 putchar('\n'); 323 if (parse_cmds(cmd, &dskupdated)) { 324 putchar('\a'); 325 continue; 326 } 327 load(); 328 } 329 /* NOTREACHED */ 330 } 331 332 /* Needed so btxld can link us properly; do not remove. */ 333 void 334 exit(int x) 335 { 336 337 __exit(x); 338 } 339 340 static void 341 load(void) 342 { 343 union { 344 struct exec ex; 345 Elf32_Ehdr eh; 346 } hdr; 347 static Elf32_Phdr ep[2]; 348 static Elf32_Shdr es[2]; 349 caddr_t p; 350 uint64_t ino; 351 uint32_t addr, x; 352 int fmt, i, j; 353 354 if (!(ino = cd9660_lookup(kname))) { 355 if (!ls) { 356 printf("%s: No %s on %u:%s(%u", BOOTPROG, 357 kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], 358 dsk.unit); 359 if (dsk.part != -1) 360 printf("p%u", dsk.part); 361 printf(")\n"); 362 } 363 return; 364 } 365 if (xfsread(ino, &hdr, sizeof (hdr))) 366 return; 367 if (N_GETMAGIC(hdr.ex) == ZMAGIC) 368 fmt = 0; 369 else if (IS_ELF(hdr.eh)) 370 fmt = 1; 371 else { 372 printf("Invalid %s\n", "format"); 373 return; 374 } 375 if (fmt == 0) { 376 addr = hdr.ex.a_entry & 0xffffff; 377 p = PTOV(addr); 378 fs_off = PAGE_SIZE; 379 if (xfsread(ino, p, hdr.ex.a_text)) 380 return; 381 p += roundup2(hdr.ex.a_text, PAGE_SIZE); 382 if (xfsread(ino, p, hdr.ex.a_data)) 383 return; 384 p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 385 bootinfo.bi_symtab = VTOP(p); 386 memcpy(p, &hdr.ex.a_syms, sizeof (hdr.ex.a_syms)); 387 p += sizeof (hdr.ex.a_syms); 388 if (hdr.ex.a_syms) { 389 if (xfsread(ino, p, hdr.ex.a_syms)) 390 return; 391 p += hdr.ex.a_syms; 392 if (xfsread(ino, p, sizeof (int))) 393 return; 394 x = *(uint32_t *)p; 395 p += sizeof (int); 396 x -= sizeof (int); 397 if (xfsread(ino, p, x)) 398 return; 399 p += x; 400 } 401 } else { 402 fs_off = hdr.eh.e_phoff; 403 for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 404 if (xfsread(ino, ep + j, sizeof (ep[0]))) 405 return; 406 if (ep[j].p_type == PT_LOAD) 407 j++; 408 } 409 for (i = 0; i < 2; i++) { 410 p = PTOV(ep[i].p_paddr & 0xffffff); 411 fs_off = ep[i].p_offset; 412 if (xfsread(ino, p, ep[i].p_filesz)) 413 return; 414 } 415 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 416 bootinfo.bi_symtab = VTOP(p); 417 if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 418 fs_off = hdr.eh.e_shoff + sizeof (es[0]) * 419 (hdr.eh.e_shstrndx + 1); 420 if (xfsread(ino, &es, sizeof (es))) 421 return; 422 for (i = 0; i < 2; i++) { 423 memcpy(p, &es[i].sh_size, 424 sizeof (es[i].sh_size)); 425 p += sizeof (es[i].sh_size); 426 fs_off = es[i].sh_offset; 427 if (xfsread(ino, p, es[i].sh_size)) 428 return; 429 p += es[i].sh_size; 430 } 431 } 432 addr = hdr.eh.e_entry & 0xffffff; 433 } 434 bootinfo.bi_esymtab = VTOP(p); 435 bootinfo.bi_kernelname = VTOP(kname); 436 bootinfo.bi_bios_dev = dsk.drive; 437 __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 438 MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.unit, 0), 439 KARGS_FLAGS_EXTARG, 0, 0, VTOP(&bootinfo)); 440 } 441 442 static int 443 parse_cmds(char *cmdstr, int *dskupdated) 444 { 445 char *arg; 446 char *ep, *p, *q; 447 const char *cp; 448 unsigned int drv; 449 int c, i, j; 450 451 arg = cmdstr; 452 *dskupdated = 0; 453 while ((c = *arg++)) { 454 if (c == ' ' || c == '\t' || c == '\n') 455 continue; 456 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++) 457 ; 458 ep = p; 459 if (*p) 460 *p++ = 0; 461 if (c == '-') { 462 while ((c = *arg++)) { 463 if (c == 'P') { 464 if (*(uint8_t *)PTOV(0x496) & 0x10) { 465 cp = "yes"; 466 } else { 467 opts |= OPT_SET(RBX_DUAL) | 468 OPT_SET(RBX_SERIAL); 469 cp = "no"; 470 } 471 printf("Keyboard: %s\n", cp); 472 continue; 473 } else if (c == 'S') { 474 j = 0; 475 while ((unsigned int)(i = *arg++ - '0') 476 <= 9) 477 j = j * 10 + i; 478 if (j > 0 && i == -'0') { 479 comspeed = j; 480 break; 481 } 482 /* 483 * Fall through to error below 484 * ('S' not in optstr[]). 485 */ 486 } 487 for (i = 0; c != optstr[i]; i++) 488 if (i == NOPT - 1) 489 return (-1); 490 opts ^= OPT_SET(flags[i]); 491 } 492 ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 493 OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 494 if (ioctrl & IO_SERIAL) { 495 if (sio_init(115200 / comspeed) != 0) 496 ioctrl &= ~IO_SERIAL; 497 } 498 } else { 499 for (q = arg--; *q && *q != '('; q++) 500 ; 501 if (*q) { 502 drv = -1; 503 if (arg[1] == ':') { 504 drv = *arg - '0'; 505 if (drv > 9) 506 return (-1); 507 arg += 2; 508 } 509 if (q - arg != 2) 510 return (-1); 511 for (i = 0; arg[0] != dev_nm[i][0] || 512 arg[1] != dev_nm[i][1]; i++) 513 if (i == NDEV - 1) 514 return (-1); 515 dsk.type = i; 516 arg += 3; 517 dsk.unit = *arg - '0'; 518 if (arg[1] != 'p' || dsk.unit > 9) 519 return (-1); 520 arg += 2; 521 dsk.part = *arg - '0'; 522 if (dsk.part < 1 || dsk.part > 9) 523 return (-1); 524 arg++; 525 if (arg[0] != ')') 526 return (-1); 527 arg++; 528 if (drv == (unsigned)-1) 529 drv = dsk.unit; 530 dsk.drive = (dsk.type <= TYPE_MAXHARD 531 ? DRV_HARD : 0) + drv; 532 *dskupdated = 1; 533 } 534 if ((i = ep - arg)) { 535 if ((size_t)i >= sizeof (kname)) 536 return (-1); 537 memcpy(kname, arg, i + 1); 538 } 539 } 540 arg = p; 541 } 542 return (0); 543 } 544