gptboot.c revision 151367
1106266Sjulian/*- 2106266Sjulian * Copyright (c) 1998 Robert Nordier 3139823Simp * All rights reserved. 4139823Simp * 5139823Simp * Redistribution and use in source and binary forms are freely 6144674Sglebius * permitted provided that the above copyright notice and this 7106266Sjulian * paragraph and the following disclaimer are duplicated in all 8106266Sjulian * such forms. 9106266Sjulian * 10106266Sjulian * This software is provided "AS IS" and without any express or 11106266Sjulian * implied warranties, including, without limitation, the implied 12106319Sjulian * warranties of merchantability and fitness for a particular 13106266Sjulian * purpose. 14106319Sjulian */ 15106319Sjulian 16106266Sjulian#include <sys/cdefs.h> 17106319Sjulian__FBSDID("$FreeBSD: head/sys/boot/i386/gptboot/gptboot.c 151367 2005-10-16 01:55:35Z sobomax $"); 18106319Sjulian 19106266Sjulian#include <sys/param.h> 20106266Sjulian#include <sys/disklabel.h> 21106266Sjulian#include <sys/diskmbr.h> 22106319Sjulian#include <sys/dirent.h> 23106319Sjulian#include <sys/reboot.h> 24106319Sjulian 25106266Sjulian#include <machine/bootinfo.h> 26106266Sjulian#include <machine/elf.h> 27106266Sjulian 28106266Sjulian#include <stdarg.h> 29106266Sjulian 30106319Sjulian#include <a.out.h> 31106266Sjulian 32106266Sjulian#include <btxv86.h> 33106266Sjulian 34106266Sjulian#include "boot2.h" 35106266Sjulian#include "lib.h" 36106266Sjulian 37106266Sjulian#define IO_KEYBOARD 1 38106266Sjulian#define IO_SERIAL 2 39106266Sjulian 40106266Sjulian#define SECOND 18 /* Circa that many ticks in a second. */ 41125077Sharti 42125077Sharti#define RBX_ASKNAME 0x0 /* -a */ 43125077Sharti#define RBX_SINGLE 0x1 /* -s */ 44106266Sjulian/* 0x2 is reserved for log2(RB_NOSYNC). */ 45106266Sjulian/* 0x3 is reserved for log2(RB_HALT). */ 46143387Sbmilekic/* 0x4 is reserved for log2(RB_INITNAME). */ 47143387Sbmilekic#define RBX_DFLTROOT 0x5 /* -r */ 48143387Sbmilekic#define RBX_KDB 0x6 /* -d */ 49143387Sbmilekic/* 0x7 is reserved for log2(RB_RDONLY). */ 50106266Sjulian/* 0x8 is reserved for log2(RB_DUMP). */ 51106266Sjulian/* 0x9 is reserved for log2(RB_MINIROOT). */ 52106266Sjulian#define RBX_CONFIG 0xa /* -c */ 53106266Sjulian#define RBX_VERBOSE 0xb /* -v */ 54106266Sjulian#define RBX_SERIAL 0xc /* -h */ 55106266Sjulian#define RBX_CDROM 0xd /* -C */ 56143387Sbmilekic/* 0xe is reserved for log2(RB_POWEROFF). */ 57106266Sjulian#define RBX_GDB 0xf /* -g */ 58106266Sjulian#define RBX_MUTE 0x10 /* -m */ 59106266Sjulian/* 0x11 is reserved for log2(RB_SELFTEST). */ 60106266Sjulian/* 0x12 is reserved for boot programs. */ 61106266Sjulian/* 0x13 is reserved for boot programs. */ 62106266Sjulian#define RBX_PAUSE 0x14 /* -p */ 63106266Sjulian/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 64106266Sjulian#define RBX_DUAL 0x1d /* -D */ 65106266Sjulian/* 0x1f is reserved for log2(RB_BOOTINFO). */ 66106266Sjulian/* group of internal options below */ 67106266Sjulian#define RBX_NOINTR 0x20 /* -n */ 68144674Sglebius#define RBX_QUIET 0x21 /* -q */ 69106266Sjulian 70106266Sjulian/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ 71106266Sjulian#define RBX_MASK 0xffffffff 72106266Sjulian 73106266Sjulian#define PATH_CONFIG "/boot.config" 74106266Sjulian#define PATH_BOOT3 "/boot/loader" 75106266Sjulian#define PATH_KERNEL "/boot/kernel/kernel" 76106266Sjulian 77106266Sjulian#define ARGS 0x900 78106266Sjulian#define NOPT 12 79106266Sjulian#define NDEV 3 80106266Sjulian#define MEM_BASE 0x12 81106266Sjulian#define MEM_EXT 0x15 82106266Sjulian#define V86_CY(x) ((x) & 1) 83144674Sglebius#define V86_ZR(x) ((x) & 0x40) 84144674Sglebius 85106266Sjulian#define DRV_HARD 0x80 86106319Sjulian#define DRV_MASK 0x7f 87106266Sjulian 88137138Sglebius#define TYPE_AD 0 89144674Sglebius#define TYPE_DA 1 90144674Sglebius#define TYPE_MAXHARD TYPE_DA 91106266Sjulian#define TYPE_FD 2 92106266Sjulian 93106266Sjulian#define OPT_CHECK(opt) ((opts >> (opt)) & 0x1) 94106266Sjulian 95106266Sjulianextern uint32_t _end; 96106266Sjulian 97106266Sjulianstatic const char optstr[NOPT] = "DhaCgmnpqrsv"; /* Also 'P', 'S' */ 98106266Sjulianstatic const unsigned char flags[NOPT] = { 99106266Sjulian RBX_DUAL, 100106266Sjulian RBX_SERIAL, 101106266Sjulian RBX_ASKNAME, 102144674Sglebius RBX_CDROM, 103106266Sjulian RBX_GDB, 104106266Sjulian RBX_MUTE, 105106266Sjulian RBX_NOINTR, 106106266Sjulian RBX_PAUSE, 107125243Sharti RBX_QUIET, 108106266Sjulian RBX_DFLTROOT, 109144674Sglebius RBX_SINGLE, 110106266Sjulian RBX_VERBOSE 111106266Sjulian}; 112144674Sglebius 113106266Sjulianstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 114106266Sjulianstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 115125077Sharti 116106266Sjulianstatic struct dsk { 117106266Sjulian unsigned drive; 118106266Sjulian unsigned type; 119106266Sjulian unsigned unit; 120106266Sjulian unsigned slice; 121106266Sjulian unsigned part; 122106266Sjulian unsigned start; 123106266Sjulian int init; 124106266Sjulian} dsk; 125106266Sjulianstatic char cmd[512]; 126106266Sjulianstatic char kname[1024]; 127106266Sjulianstatic uint64_t opts; 128106266Sjulianstatic int comspeed = SIOSPD; 129106266Sjulianstatic struct bootinfo bootinfo; 130106266Sjulianstatic uint8_t ioctrl = IO_KEYBOARD; 131106266Sjulian 132106266Sjulianvoid exit(int); 133106266Sjulianstatic void load(void); 134106266Sjulianstatic int parse(void); 135106266Sjulianstatic int xfsread(ino_t, void *, size_t); 136106266Sjulianstatic int dskread(void *, unsigned, unsigned); 137106266Sjulianstatic void printf(const char *,...); 138106266Sjulianstatic void putchar(int); 139106266Sjulianstatic uint32_t memsize(void); 140106266Sjulianstatic int drvread(void *, unsigned, unsigned); 141106266Sjulianstatic int keyhit(unsigned); 142106266Sjulianstatic int xputc(int); 143106266Sjulianstatic int xgetc(int); 144106266Sjulianstatic int getc(int); 145106266Sjulian 146106266Sjulianstatic void memcpy(void *, const void *, int); 147106266Sjulianstatic void 148106266Sjulianmemcpy(void *dst, const void *src, int len) 149106266Sjulian{ 150106266Sjulian const char *s = src; 151106266Sjulian char *d = dst; 152106266Sjulian 153106266Sjulian while (len--) 154106266Sjulian *d++ = *s++; 155106266Sjulian} 156106266Sjulian 157106266Sjulianstatic inline int 158106266Sjulianstrcmp(const char *s1, const char *s2) 159106266Sjulian{ 160106266Sjulian for (; *s1 == *s2 && *s1; s1++, s2++); 161106266Sjulian return (unsigned char)*s1 - (unsigned char)*s2; 162106266Sjulian} 163106266Sjulian 164106266Sjulian#include "ufsread.c" 165106266Sjulian 166106266Sjulianstatic inline int 167106266Sjulianxfsread(ino_t inode, void *buf, size_t nbyte) 168106266Sjulian{ 169106266Sjulian if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 170106266Sjulian printf("Invalid %s\n", "format"); 171106266Sjulian return -1; 172106266Sjulian } 173106266Sjulian return 0; 174106266Sjulian} 175106266Sjulian 176106266Sjulianstatic inline uint32_t 177125033Shartimemsize(void) 178125033Sharti{ 179144674Sglebius v86.addr = MEM_EXT; 180144674Sglebius v86.eax = 0x8800; 181144674Sglebius v86int(); 182125033Sharti return v86.eax; 183125033Sharti} 184153690Sglebius 185153690Sglebiusstatic inline void 186153690Sglebiusgetstr(void) 187153690Sglebius{ 188153690Sglebius char *s; 189153690Sglebius int c; 190153690Sglebius 191106266Sjulian s = cmd; 192106266Sjulian for (;;) { 193106266Sjulian switch (c = xgetc(0)) { 194106266Sjulian case 0: 195106266Sjulian break; 196129823Sjulian case '\177': 197129823Sjulian case '\b': 198129823Sjulian if (s > cmd) { 199129823Sjulian s--; 200129823Sjulian printf("\b \b"); 201129823Sjulian } 202144674Sglebius break; 203129823Sjulian case '\n': 204129823Sjulian case '\r': 205129823Sjulian *s = 0; 206106266Sjulian return; 207106266Sjulian default: 208106266Sjulian if (s - cmd < sizeof(cmd) - 1) 209144674Sglebius *s++ = c; 210125032Sharti putchar(c); 211106266Sjulian } 212106266Sjulian } 213106266Sjulian} 214106266Sjulian 215106321Sjulianstatic inline void 216106266Sjulianputc(int c) 217106266Sjulian{ 218106266Sjulian v86.addr = 0x10; 219125030Sharti v86.eax = 0xe00 | (c & 0xff); 220106266Sjulian v86.ebx = 0x7; 221106266Sjulian v86int(); 222106266Sjulian} 223106321Sjulian 224106321Sjulianint 225106266Sjulianmain(void) 226137138Sglebius{ 227137138Sglebius int autoboot; 228106266Sjulian ino_t ino; 229106266Sjulian 230106266Sjulian dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 231106266Sjulian v86.ctl = V86_FLAGS; 232106266Sjulian dsk.drive = *(uint8_t *)PTOV(ARGS); 233106266Sjulian dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 234106266Sjulian dsk.unit = dsk.drive & DRV_MASK; 235106266Sjulian dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 236106266Sjulian bootinfo.bi_version = BOOTINFO_VERSION; 237144674Sglebius bootinfo.bi_size = sizeof(bootinfo); 238106266Sjulian bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 239106266Sjulian bootinfo.bi_extmem = memsize(); 240144674Sglebius bootinfo.bi_memsizes_valid++; 241106266Sjulian 242144674Sglebius /* Process configuration file */ 243106266Sjulian 244106266Sjulian autoboot = 1; 245106266Sjulian 246106266Sjulian if ((ino = lookup(PATH_CONFIG))) 247144674Sglebius fsread(ino, cmd, sizeof(cmd)); 248106266Sjulian 249106266Sjulian if (*cmd) { 250106266Sjulian if (parse()) 251106266Sjulian autoboot = 0; 252144674Sglebius if (!OPT_CHECK(RBX_QUIET)) 253144674Sglebius printf("%s: %s", PATH_CONFIG, cmd); 254144674Sglebius /* Do not process this command twice */ 255144674Sglebius *cmd = 0; 256144674Sglebius } 257144674Sglebius 258144674Sglebius /* 259144674Sglebius * Try to exec stage 3 boot loader. If interrupted by a keypress, 260144674Sglebius * or in case of failure, try to load a kernel directly instead. 261144674Sglebius */ 262144674Sglebius 263144674Sglebius if (autoboot && !*kname) { 264144674Sglebius memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 265144674Sglebius if (!keyhit(3*SECOND)) { 266144674Sglebius load(); 267144674Sglebius memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 268144674Sglebius } 269144674Sglebius } 270144674Sglebius 271144674Sglebius /* Present the user with the boot2 prompt. */ 272144674Sglebius 273144674Sglebius for (;;) { 274144674Sglebius if (!autoboot || !OPT_CHECK(RBX_QUIET)) 275144674Sglebius printf("\nFreeBSD/i386 boot\n" 276144674Sglebius "Default: %u:%s(%u,%c)%s\n" 277144674Sglebius "boot: ", 278144674Sglebius dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 279144674Sglebius 'a' + dsk.part, kname); 280144674Sglebius if (ioctrl & IO_SERIAL) 281144674Sglebius sio_flush(); 282144674Sglebius if (!autoboot || keyhit(5*SECOND)) 283106266Sjulian getstr(); 284106266Sjulian else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 285106266Sjulian putchar('\n'); 286106321Sjulian autoboot = 0; 287106266Sjulian if (parse()) 288144674Sglebius putchar('\a'); 289144674Sglebius else 290106266Sjulian load(); 291106266Sjulian } 292106321Sjulian} 293144674Sglebius 294106266Sjulian/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 295106266Sjulianvoid 296106435Sjulianexit(int x) 297106435Sjulian{ 298106435Sjulian} 299106435Sjulian 300106266Sjulianstatic void 301106266Sjulianload(void) 302106266Sjulian{ 303106266Sjulian static union { 304106266Sjulian struct exec ex; 305106266Sjulian Elf32_Ehdr eh; 306106266Sjulian } hdr; 307106266Sjulian static Elf32_Phdr ep[2]; 308106266Sjulian static Elf32_Shdr es[2]; 309106266Sjulian caddr_t p; 310106266Sjulian ino_t ino; 311106266Sjulian uint32_t addr, x; 312106266Sjulian int fmt, i, j; 313106266Sjulian 314106266Sjulian if (!(ino = lookup(kname))) { 315106319Sjulian if (!ls) 316106321Sjulian printf("No %s\n", kname); 317106266Sjulian return; 318106319Sjulian } 319106266Sjulian if (xfsread(ino, &hdr, sizeof(hdr))) 320106319Sjulian return; 321106266Sjulian if (N_GETMAGIC(hdr.ex) == ZMAGIC) 322106319Sjulian fmt = 0; 323106266Sjulian else if (IS_ELF(hdr.eh)) 324106266Sjulian fmt = 1; 325106266Sjulian else { 326106266Sjulian printf("Invalid %s\n", "format"); 327106266Sjulian return; 328106266Sjulian } 329106266Sjulian if (fmt == 0) { 330106266Sjulian addr = hdr.ex.a_entry; 331144674Sglebius p = PTOV(addr); 332144674Sglebius fs_off = PAGE_SIZE; 333144674Sglebius if (xfsread(ino, p, hdr.ex.a_text)) 334106266Sjulian return; 335106266Sjulian p += roundup2(hdr.ex.a_text, PAGE_SIZE); 336106266Sjulian if (xfsread(ino, p, hdr.ex.a_data)) 337125033Sharti return; 338144674Sglebius p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 339144674Sglebius bootinfo.bi_symtab = VTOP(p); 340144674Sglebius memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 341144674Sglebius p += sizeof(hdr.ex.a_syms); 342144674Sglebius if (hdr.ex.a_syms) { 343125033Sharti if (xfsread(ino, p, hdr.ex.a_syms)) 344106266Sjulian return; 345106266Sjulian p += hdr.ex.a_syms; 346106266Sjulian if (xfsread(ino, p, sizeof(int))) 347106266Sjulian return; 348106266Sjulian x = *(uint32_t *)p; 349106266Sjulian p += sizeof(int); 350144674Sglebius x -= sizeof(int); 351144674Sglebius if (xfsread(ino, p, x)) 352144674Sglebius return; 353144674Sglebius p += x; 354144674Sglebius } 355144674Sglebius } else { 356144674Sglebius fs_off = hdr.eh.e_phoff; 357144674Sglebius for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 358144674Sglebius if (xfsread(ino, ep + j, sizeof(ep[0]))) 359144674Sglebius return; 360144674Sglebius if (ep[j].p_type == PT_LOAD) 361144674Sglebius j++; 362153690Sglebius } 363153690Sglebius for (i = 0; i < 2; i++) { 364153690Sglebius p = PTOV(ep[i].p_paddr); 365153690Sglebius fs_off = ep[i].p_offset; 366153690Sglebius if (xfsread(ino, p, ep[i].p_filesz)) 367153690Sglebius return; 368153690Sglebius } 369153690Sglebius p += roundup2(ep[1].p_memsz, PAGE_SIZE); 370153690Sglebius bootinfo.bi_symtab = VTOP(p); 371153690Sglebius if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 372153690Sglebius fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 373153690Sglebius (hdr.eh.e_shstrndx + 1); 374153690Sglebius if (xfsread(ino, &es, sizeof(es))) 375153690Sglebius return; 376153690Sglebius for (i = 0; i < 2; i++) { 377106266Sjulian memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 378106266Sjulian p += sizeof(es[i].sh_size); 379106266Sjulian fs_off = es[i].sh_offset; 380106266Sjulian if (xfsread(ino, p, es[i].sh_size)) 381106266Sjulian return; 382106435Sjulian p += es[i].sh_size; 383106435Sjulian } 384106435Sjulian } 385106435Sjulian addr = hdr.eh.e_entry; 386106435Sjulian } 387106435Sjulian bootinfo.bi_esymtab = VTOP(p); 388144674Sglebius bootinfo.bi_kernelname = VTOP(kname); 389144674Sglebius bootinfo.bi_bios_dev = dsk.drive; 390144674Sglebius __exec((caddr_t)addr, RB_BOOTINFO | (uint32_t)(opts & RBX_MASK), 391144674Sglebius MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), 392144674Sglebius 0, 0, 0, VTOP(&bootinfo)); 393144674Sglebius} 394144674Sglebius 395144674Sglebiusstatic int 396144674Sglebiusparse() 397144674Sglebius{ 398106435Sjulian char *arg = cmd; 399106435Sjulian char *ep, *p, *q; 400144674Sglebius const char *cp; 401106435Sjulian unsigned int drv; 402106435Sjulian int c, i, j; 403106435Sjulian 404106435Sjulian while ((c = *arg++)) { 405106266Sjulian if (c == ' ' || c == '\t' || c == '\n') 406106266Sjulian continue; 407106266Sjulian for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 408106266Sjulian ep = p; 409106266Sjulian if (*p) 410106266Sjulian *p++ = 0; 411144674Sglebius if (c == '-') { 412106321Sjulian while ((c = *arg++)) { 413144674Sglebius if (c == 'P') { 414106321Sjulian if (*(uint8_t *)PTOV(0x496) & 0x10) { 415106266Sjulian cp = "yes"; 416106266Sjulian } else { 417106266Sjulian opts |= (uint64_t)1 << RBX_DUAL | (uint64_t)1 << RBX_SERIAL; 418106266Sjulian cp = "no"; 419106266Sjulian } 420106266Sjulian printf("Keyboard: %s\n", cp); 421106266Sjulian continue; 422106266Sjulian } else if (c == 'S') { 423106266Sjulian j = 0; 424106266Sjulian while ((unsigned int)(i = *arg++ - '0') <= 9) 425106321Sjulian j = j * 10 + i; 426106266Sjulian if (j > 0 && i == -'0') { 427144674Sglebius comspeed = j; 428144674Sglebius break; 429106266Sjulian } 430106266Sjulian /* Fall through to error below ('S' not in optstr[]). */ 431106321Sjulian } 432106321Sjulian for (i = 0; c != optstr[i]; i++) 433106266Sjulian if (i == NOPT - 1) 434106266Sjulian return -1; 435144674Sglebius opts ^= (uint64_t)1 << flags[i]; 436106266Sjulian } 437106321Sjulian ioctrl = opts & (uint64_t)1 << RBX_DUAL ? (IO_SERIAL|IO_KEYBOARD) : 438106266Sjulian opts & (uint64_t)1 << RBX_SERIAL ? IO_SERIAL : IO_KEYBOARD; 439106266Sjulian if (ioctrl & IO_SERIAL) 440144674Sglebius sio_init(115200 / comspeed); 441106266Sjulian } else { 442144674Sglebius for (q = arg--; *q && *q != '('; q++); 443106266Sjulian if (*q) { 444125031Sharti drv = -1; 445106266Sjulian if (arg[1] == ':') { 446106266Sjulian drv = *arg - '0'; 447106266Sjulian if (drv > 9) 448106266Sjulian return (-1); 449106266Sjulian arg += 2; 450106266Sjulian } 451106266Sjulian if (q - arg != 2) 452106266Sjulian return -1; 453106266Sjulian for (i = 0; arg[0] != dev_nm[i][0] || 454106266Sjulian arg[1] != dev_nm[i][1]; i++) 455106266Sjulian if (i == NDEV - 1) 456144674Sglebius return -1; 457106266Sjulian dsk.type = i; 458106266Sjulian arg += 3; 459106266Sjulian dsk.unit = *arg - '0'; 460106321Sjulian if (arg[1] != ',' || dsk.unit > 9) 461106321Sjulian return -1; 462125077Sharti arg += 2; 463144674Sglebius dsk.slice = WHOLE_DISK_SLICE; 464106266Sjulian if (arg[1] == ',') { 465106266Sjulian dsk.slice = *arg - '0' + 1; 466106266Sjulian if (dsk.slice > NDOSPART) 467106266Sjulian return -1; 468106266Sjulian arg += 2; 469106266Sjulian } 470106266Sjulian if (arg[1] != ')') 471106266Sjulian return -1; 472106266Sjulian dsk.part = *arg - 'a'; 473106319Sjulian if (dsk.part > 7) 474106266Sjulian return (-1); 475106321Sjulian arg += 2; 476125077Sharti if (drv == -1) 477144674Sglebius drv = dsk.unit; 478106321Sjulian dsk.drive = (dsk.type <= TYPE_MAXHARD 479106266Sjulian ? DRV_HARD : 0) + drv; 480106266Sjulian dsk_meta = 0; 481106266Sjulian } 482106266Sjulian if ((i = ep - arg)) { 483106435Sjulian if ((size_t)i >= sizeof(kname)) 484106435Sjulian return -1; 485106435Sjulian memcpy(kname, arg, i + 1); 486106435Sjulian } 487144674Sglebius } 488106435Sjulian arg = p; 489106435Sjulian } 490106435Sjulian return 0; 491106266Sjulian} 492144674Sglebius 493106266Sjulianstatic int 494106266Sjuliandskread(void *buf, unsigned lba, unsigned nblk) 495125077Sharti{ 496106266Sjulian struct dos_partition *dp; 497106266Sjulian struct disklabel *d; 498106266Sjulian char *sec; 499106266Sjulian unsigned sl, i; 500106266Sjulian 501106266Sjulian if (!dsk_meta) { 502106266Sjulian sec = dmadat->secbuf; 503106266Sjulian dsk.start = 0; 504106266Sjulian if (drvread(sec, DOSBBSECTOR, 1)) 505106266Sjulian return -1; 506106266Sjulian dp = (void *)(sec + DOSPARTOFF); 507125077Sharti sl = dsk.slice; 508106266Sjulian if (sl < BASE_SLICE) { 509106319Sjulian for (i = 0; i < NDOSPART; i++) 510106266Sjulian if (dp[i].dp_typ == DOSPTYP_386BSD && 511106266Sjulian (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 512106266Sjulian sl = BASE_SLICE + i; 513106266Sjulian if (dp[i].dp_flag & 0x80 || 514106266Sjulian dsk.slice == COMPATIBILITY_SLICE) 515106266Sjulian break; 516106266Sjulian } 517106266Sjulian if (dsk.slice == WHOLE_DISK_SLICE) 518106266Sjulian dsk.slice = sl; 519106266Sjulian } 520106266Sjulian if (sl != WHOLE_DISK_SLICE) { 521144674Sglebius if (sl != COMPATIBILITY_SLICE) 522106266Sjulian dp += sl - BASE_SLICE; 523106266Sjulian if (dp->dp_typ != DOSPTYP_386BSD) { 524106266Sjulian printf("Invalid %s\n", "slice"); 525106266Sjulian return -1; 526106266Sjulian } 527144674Sglebius dsk.start = dp->dp_start; 528106266Sjulian } 529106266Sjulian if (drvread(sec, dsk.start + LABELSECTOR, 1)) 530106266Sjulian return -1; 531144674Sglebius d = (void *)(sec + LABELOFFSET); 532144674Sglebius if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 533106266Sjulian if (dsk.part != RAW_PART) { 534106266Sjulian printf("Invalid %s\n", "label"); 535106266Sjulian return -1; 536106266Sjulian } 537106266Sjulian } else { 538106266Sjulian if (!dsk.init) { 539106266Sjulian if (d->d_type == DTYPE_SCSI) 540106266Sjulian dsk.type = TYPE_DA; 541106266Sjulian dsk.init++; 542106266Sjulian } 543106266Sjulian if (dsk.part >= d->d_npartitions || 544106266Sjulian !d->d_partitions[dsk.part].p_size) { 545125031Sharti printf("Invalid %s\n", "partition"); 546106266Sjulian return -1; 547106266Sjulian } 548106266Sjulian dsk.start += d->d_partitions[dsk.part].p_offset; 549106266Sjulian dsk.start -= d->d_partitions[RAW_PART].p_offset; 550106266Sjulian } 551106266Sjulian } 552106266Sjulian return drvread(buf, dsk.start + lba, nblk); 553106266Sjulian} 554106266Sjulian 555106266Sjulianstatic void 556144674Sglebiusprintf(const char *fmt,...) 557144674Sglebius{ 558106266Sjulian va_list ap; 559144674Sglebius char buf[10]; 560144674Sglebius char *s; 561144674Sglebius unsigned u; 562144674Sglebius int c; 563144674Sglebius 564144674Sglebius va_start(ap, fmt); 565144674Sglebius while ((c = *fmt++)) { 566144674Sglebius if (c == '%') { 567144674Sglebius c = *fmt++; 568144674Sglebius switch (c) { 569144674Sglebius case 'c': 570144674Sglebius putchar(va_arg(ap, int)); 571144674Sglebius continue; 572144674Sglebius case 's': 573153690Sglebius for (s = va_arg(ap, char *); *s; s++) 574144674Sglebius putchar(*s); 575144674Sglebius continue; 576144674Sglebius case 'u': 577144674Sglebius u = va_arg(ap, unsigned); 578106266Sjulian s = buf; 579106266Sjulian do 580106266Sjulian *s++ = '0' + u % 10U; 581106266Sjulian while (u /= 10U); 582106266Sjulian while (--s >= buf) 583106266Sjulian putchar(*s); 584144674Sglebius continue; 585106266Sjulian } 586144674Sglebius } 587144674Sglebius putchar(c); 588144674Sglebius } 589144674Sglebius va_end(ap); 590144674Sglebius return; 591106266Sjulian} 592106266Sjulian 593106266Sjulianstatic void 594106266Sjulianputchar(int c) 595106266Sjulian{ 596106266Sjulian if (c == '\n') 597106266Sjulian xputc('\r'); 598106266Sjulian xputc(c); 599125243Sharti} 600106266Sjulian 601125243Shartistatic int 602106266Sjuliandrvread(void *buf, unsigned lba, unsigned nblk) 603106266Sjulian{ 604106266Sjulian static unsigned c = 0x2d5c7c2f; 605125077Sharti 606106266Sjulian if (!OPT_CHECK(RBX_QUIET)) 607144674Sglebius printf("%c\b", c = c << 8 | c >> 24); 608106321Sjulian v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 609106266Sjulian v86.addr = XREADORG; /* call to xread in boot1 */ 610106266Sjulian v86.es = VTOPSEG(buf); 611106266Sjulian v86.eax = lba; 612106266Sjulian v86.ebx = VTOPOFF(buf); 613125033Sharti v86.ecx = lba >> 16; 614141745Sru v86.edx = nblk << 8 | dsk.drive; 615125033Sharti v86int(); 616125033Sharti v86.ctl = V86_FLAGS; 617125033Sharti if (V86_CY(v86.efl)) { 618125033Sharti printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 619153690Sglebius return -1; 620153690Sglebius } 621153690Sglebius return 0; 622153690Sglebius} 623153690Sglebius 624153690Sglebiusstatic int 625153690Sglebiuskeyhit(unsigned ticks) 626153690Sglebius{ 627153690Sglebius uint32_t t0, t1; 628153690Sglebius 629153690Sglebius if (OPT_CHECK(RBX_NOINTR)) 630153690Sglebius return 0; 631153690Sglebius t0 = 0; 632153690Sglebius for (;;) { 633153690Sglebius if (xgetc(1)) 634106266Sjulian return 1; 635125243Sharti t1 = *(uint32_t *)PTOV(0x46c); 636106266Sjulian if (!t0) 637125243Sharti t0 = t1; 638138268Sglebius if (t1 < t0 || t1 >= t0 + ticks) 639137136Sglebius return 0; 640106266Sjulian } 641106266Sjulian} 642106266Sjulian 643106266Sjulianstatic int 644106266Sjulianxputc(int c) 645106266Sjulian{ 646106266Sjulian if (ioctrl & IO_KEYBOARD) 647106266Sjulian putc(c); 648106266Sjulian if (ioctrl & IO_SERIAL) 649106266Sjulian sio_putc(c); 650106266Sjulian return c; 651106266Sjulian} 652106266Sjulian 653125077Shartistatic int 654106321Sjulianxgetc(int fn) 655125077Sharti{ 656106266Sjulian if (OPT_CHECK(RBX_NOINTR)) 657144674Sglebius return 0; 658106266Sjulian for (;;) { 659106266Sjulian if (ioctrl & IO_KEYBOARD && getc(1)) 660106266Sjulian return fn ? 1 : getc(0); 661106266Sjulian if (ioctrl & IO_SERIAL && sio_ischar()) 662106266Sjulian return fn ? 1 : sio_getc(); 663125031Sharti if (fn) 664106266Sjulian return 0; 665106266Sjulian } 666106266Sjulian} 667106266Sjulian 668111119Simpstatic int 669106266Sjuliangetc(int fn) 670125031Sharti{ 671106266Sjulian v86.addr = 0x16; 672106266Sjulian v86.eax = fn << 8; 673106266Sjulian v86int(); 674106266Sjulian return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); 675144674Sglebius} 676125031Sharti