boot2.c revision 218842
1201342Snyan/*- 2201342Snyan * Copyright (c) 2008-2009 TAKAHASHI Yoshihiro 3201342Snyan * Copyright (c) 1998 Robert Nordier 4201342Snyan * All rights reserved. 5201342Snyan * 6201342Snyan * Redistribution and use in source and binary forms are freely 7201342Snyan * permitted provided that the above copyright notice and this 8201342Snyan * paragraph and the following disclaimer are duplicated in all 9201342Snyan * such forms. 10201342Snyan * 11201342Snyan * This software is provided "AS IS" and without any express or 12201342Snyan * implied warranties, including, without limitation, the implied 13201342Snyan * warranties of merchantability and fitness for a particular 14201342Snyan * purpose. 15201342Snyan */ 16201342Snyan 17201342Snyan#include <sys/cdefs.h> 18201342Snyan__FBSDID("$FreeBSD: head/sys/boot/pc98/boot2/boot2.c 218842 2011-02-19 10:32:12Z nyan $"); 19201342Snyan 20201342Snyan#include <sys/param.h> 21201342Snyan#include <sys/disklabel.h> 22201342Snyan#include <sys/diskpc98.h> 23201342Snyan#include <sys/dirent.h> 24201342Snyan#include <sys/reboot.h> 25201342Snyan 26201342Snyan#include <machine/bootinfo.h> 27201342Snyan#include <machine/cpufunc.h> 28201342Snyan#include <machine/elf.h> 29201342Snyan#include <machine/psl.h> 30201342Snyan 31201342Snyan#include <stdarg.h> 32201342Snyan 33201342Snyan#include <a.out.h> 34201342Snyan 35201342Snyan#include <btxv86.h> 36201342Snyan 37201342Snyan#include "boot2.h" 38201342Snyan#include "lib.h" 39201342Snyan 40201342Snyan#define IO_KEYBOARD 1 41201342Snyan#define IO_SERIAL 2 42201342Snyan 43201342Snyan#define SECOND 1 /* Circa that many ticks in a second. */ 44201342Snyan 45201342Snyan#define RBX_ASKNAME 0x0 /* -a */ 46201342Snyan#define RBX_SINGLE 0x1 /* -s */ 47201342Snyan/* 0x2 is reserved for log2(RB_NOSYNC). */ 48201342Snyan/* 0x3 is reserved for log2(RB_HALT). */ 49201342Snyan/* 0x4 is reserved for log2(RB_INITNAME). */ 50201342Snyan#define RBX_DFLTROOT 0x5 /* -r */ 51201342Snyan#define RBX_KDB 0x6 /* -d */ 52201342Snyan/* 0x7 is reserved for log2(RB_RDONLY). */ 53201342Snyan/* 0x8 is reserved for log2(RB_DUMP). */ 54201342Snyan/* 0x9 is reserved for log2(RB_MINIROOT). */ 55201342Snyan#define RBX_CONFIG 0xa /* -c */ 56201342Snyan#define RBX_VERBOSE 0xb /* -v */ 57201342Snyan#define RBX_SERIAL 0xc /* -h */ 58201342Snyan#define RBX_CDROM 0xd /* -C */ 59201342Snyan/* 0xe is reserved for log2(RB_POWEROFF). */ 60201342Snyan#define RBX_GDB 0xf /* -g */ 61201342Snyan#define RBX_MUTE 0x10 /* -m */ 62201342Snyan/* 0x11 is reserved for log2(RB_SELFTEST). */ 63201342Snyan/* 0x12 is reserved for boot programs. */ 64201342Snyan/* 0x13 is reserved for boot programs. */ 65201342Snyan#define RBX_PAUSE 0x14 /* -p */ 66201342Snyan#define RBX_QUIET 0x15 /* -q */ 67201342Snyan#define RBX_NOINTR 0x1c /* -n */ 68201342Snyan/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ 69201342Snyan#define RBX_DUAL 0x1d /* -D */ 70201342Snyan/* 0x1f is reserved for log2(RB_BOOTINFO). */ 71201342Snyan 72201342Snyan/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ 73201342Snyan#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ 74201342Snyan OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ 75201342Snyan OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ 76201342Snyan OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ 77201342Snyan OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ 78201342Snyan OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) 79201342Snyan 80201342Snyan#define PATH_CONFIG "/boot.config" 81201342Snyan#define PATH_BOOT3 "/boot/loader" 82201342Snyan#define PATH_KERNEL "/boot/kernel/kernel" 83201342Snyan 84201342Snyan#define ARGS 0x900 85201342Snyan#define NOPT 14 86201342Snyan#define NDEV 3 87201342Snyan#define V86_CY(x) ((x) & PSL_C) 88201342Snyan#define V86_ZR(x) ((x) & PSL_Z) 89201342Snyan 90201342Snyan#define DRV_DISK 0xf0 91201342Snyan#define DRV_UNIT 0x0f 92201342Snyan 93201342Snyan#define TYPE_AD 0 94201342Snyan#define TYPE_DA 1 95201342Snyan#define TYPE_FD 2 96201342Snyan 97201342Snyan#define OPT_SET(opt) (1 << (opt)) 98201342Snyan#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) 99201342Snyan 100201342Snyanextern uint32_t _end; 101201342Snyan 102201342Snyanstatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 103201342Snyanstatic const unsigned char flags[NOPT] = { 104201342Snyan RBX_DUAL, 105201342Snyan RBX_SERIAL, 106201342Snyan RBX_ASKNAME, 107201342Snyan RBX_CDROM, 108201342Snyan RBX_CONFIG, 109201342Snyan RBX_KDB, 110201342Snyan RBX_GDB, 111201342Snyan RBX_MUTE, 112201342Snyan RBX_NOINTR, 113201342Snyan RBX_PAUSE, 114201342Snyan RBX_QUIET, 115201342Snyan RBX_DFLTROOT, 116201342Snyan RBX_SINGLE, 117201342Snyan RBX_VERBOSE 118201342Snyan}; 119201342Snyan 120201342Snyanstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 121201342Snyanstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 122201342Snyanstatic const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90}; 123201342Snyan 124201342Snyanstatic struct dsk { 125201342Snyan unsigned daua; 126201342Snyan unsigned type; 127201342Snyan unsigned disk; 128201342Snyan unsigned unit; 129201342Snyan unsigned head; 130201342Snyan unsigned sec; 131201342Snyan unsigned slice; 132201342Snyan unsigned part; 133201342Snyan unsigned start; 134201342Snyan} dsk; 135201342Snyanstatic char cmd[512], cmddup[512]; 136201342Snyanstatic char kname[1024]; 137218737Snyanstatic uint16_t opts; 138201342Snyanstatic int comspeed = SIOSPD; 139201342Snyanstatic struct bootinfo bootinfo; 140201342Snyanstatic uint8_t ioctrl = IO_KEYBOARD; 141201342Snyan 142201342Snyanvoid exit(int); 143201342Snyanstatic void load(void); 144201342Snyanstatic int parse(void); 145201342Snyanstatic int xfsread(ino_t, void *, size_t); 146201342Snyanstatic int dskread(void *, unsigned, unsigned); 147201342Snyanstatic void printf(const char *,...); 148201342Snyanstatic void putchar(int); 149201342Snyanstatic uint32_t memsize(void); 150201342Snyanstatic int drvread(void *, unsigned); 151201342Snyanstatic int keyhit(unsigned); 152201342Snyanstatic int xputc(int); 153201342Snyanstatic int xgetc(int); 154201342Snyanstatic int getc(int); 155201342Snyan 156201342Snyanstatic void memcpy(void *, const void *, int); 157201342Snyanstatic void 158201342Snyanmemcpy(void *dst, const void *src, int len) 159201342Snyan{ 160201342Snyan const char *s = src; 161201342Snyan char *d = dst; 162201342Snyan 163201342Snyan while (len--) 164201342Snyan *d++ = *s++; 165201342Snyan} 166201342Snyan 167201342Snyanstatic inline int 168201342Snyanstrcmp(const char *s1, const char *s2) 169201342Snyan{ 170201342Snyan for (; *s1 == *s2 && *s1; s1++, s2++); 171201342Snyan return (unsigned char)*s1 - (unsigned char)*s2; 172201342Snyan} 173201342Snyan 174201342Snyan#define UFS_SMALL_CGBASE 175201342Snyan#include "ufsread.c" 176201342Snyan 177201342Snyanstatic inline int 178201342Snyanxfsread(ino_t inode, void *buf, size_t nbyte) 179201342Snyan{ 180201342Snyan if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 181201342Snyan printf("Invalid %s\n", "format"); 182201342Snyan return -1; 183201342Snyan } 184201342Snyan return 0; 185201342Snyan} 186201342Snyan 187201342Snyanstatic inline uint32_t 188201342Snyanmemsize(void) 189201342Snyan{ 190212098Sdim return (*(u_char *)PTOV(0x401) * 128 * 1024 + 191212098Sdim *(uint16_t *)PTOV(0x594) * 1024 * 1024); 192201342Snyan} 193201342Snyan 194201342Snyanstatic inline void 195201342Snyangetstr(void) 196201342Snyan{ 197201342Snyan char *s; 198201342Snyan int c; 199201342Snyan 200201342Snyan s = cmd; 201201342Snyan for (;;) { 202201342Snyan switch (c = xgetc(0)) { 203201342Snyan case 0: 204201342Snyan break; 205201342Snyan case '\177': 206201342Snyan case '\b': 207201342Snyan if (s > cmd) { 208201342Snyan s--; 209201342Snyan printf("\b \b"); 210201342Snyan } 211201342Snyan break; 212201342Snyan case '\n': 213201342Snyan case '\r': 214201342Snyan *s = 0; 215201342Snyan return; 216201342Snyan default: 217201342Snyan if (s - cmd < sizeof(cmd) - 1) 218201342Snyan *s++ = c; 219201342Snyan putchar(c); 220201342Snyan } 221201342Snyan } 222201342Snyan} 223201342Snyan 224201342Snyanstatic inline void 225201342Snyanputc(int c) 226201342Snyan{ 227201342Snyan 228201342Snyan v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 229201342Snyan v86.addr = PUTCORG; /* call to putc in boot1 */ 230201342Snyan v86.eax = c; 231201342Snyan v86int(); 232201342Snyan v86.ctl = V86_FLAGS; 233201342Snyan} 234201342Snyan 235201342Snyanstatic inline int 236201342Snyanis_scsi_hd(void) 237201342Snyan{ 238201342Snyan 239201342Snyan if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01) 240201342Snyan return 1; 241201342Snyan 242201342Snyan return 0; 243201342Snyan} 244201342Snyan 245201342Snyanstatic inline void 246201342Snyanfix_sector_size(void) 247201342Snyan{ 248201342Snyan u_char *p; 249201342Snyan 250201342Snyan p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */ 251201342Snyan 252201342Snyan if ((p[0] & 0x1f) == 7) { /* SCSI MO */ 253201342Snyan if (!(p[3] & 0x30)) { /* 256B / sector */ 254201342Snyan p[3] |= 0x10; /* forced set 512B / sector */ 255201342Snyan p[3 + 0xa1000] |= 0x10; 256201342Snyan } 257201342Snyan } 258201342Snyan} 259201342Snyan 260201342Snyanstatic inline uint32_t 261201342Snyanget_diskinfo(void) 262201342Snyan{ 263201342Snyan 264201342Snyan if (dsk.disk == 0x30) { /* 1440KB FD */ 265201342Snyan /* 80 cylinders, 2 heads, 18 sectors */ 266201342Snyan return (80 << 16) | (2 << 8) | 18; 267201342Snyan } else if (dsk.disk == 0x90) { /* 1200KB FD */ 268201342Snyan /* 80 cylinders, 2 heads, 15 sectors */ 269201342Snyan return (80 << 16) | (2 << 8) | 15; 270201342Snyan } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */ 271201342Snyan v86.addr = 0x1b; 272201342Snyan v86.eax = 0x8400 | dsk.daua; 273201342Snyan v86int(); 274201342Snyan return (v86.ecx << 16) | v86.edx; 275201342Snyan } 276201342Snyan 277201342Snyan /* SCSI MO or CD */ 278201342Snyan fix_sector_size(); /* SCSI MO */ 279201342Snyan 280201342Snyan /* other SCSI devices */ 281201342Snyan return (65535 << 16) | (8 << 8) | 32; 282201342Snyan} 283201342Snyan 284201342Snyanstatic void 285201342Snyanset_dsk(void) 286201342Snyan{ 287201342Snyan uint32_t di; 288201342Snyan 289201342Snyan di = get_diskinfo(); 290201342Snyan 291201342Snyan dsk.head = (di >> 8) & 0xff; 292201342Snyan dsk.sec = di & 0xff; 293201342Snyan dsk.start = 0; 294201342Snyan} 295201342Snyan 296201342Snyan#ifdef GET_BIOSGEOM 297201342Snyanstatic uint32_t 298201342Snyanbd_getbigeom(int bunit) 299201342Snyan{ 300201342Snyan int hds = 0; 301201342Snyan int unit = 0x80; /* IDE HDD */ 302201342Snyan u_int addr = 0x55d; 303201342Snyan 304201342Snyan while (unit < 0xa7) { 305201342Snyan if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) 306201342Snyan if (hds++ == bunit) 307201342Snyan break; 308201342Snyan 309201342Snyan if (unit >= 0xA0) { 310201342Snyan int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F; 311201342Snyan 312201342Snyan if (media == 7 && hds++ == bunit) /* SCSI MO */ 313201342Snyan return(0xFFFE0820); /* C:65535 H:8 S:32 */ 314201342Snyan } 315201342Snyan if (++unit == 0x84) { 316201342Snyan unit = 0xA0; /* SCSI HDD */ 317201342Snyan addr = 0x482; 318201342Snyan } 319201342Snyan } 320201342Snyan if (unit == 0xa7) 321201342Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 322201342Snyan v86.addr = 0x1b; 323201342Snyan v86.eax = 0x8400 | unit; 324201342Snyan v86int(); 325201342Snyan if (v86.efl & 0x1) 326201342Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 327201342Snyan return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); 328201342Snyan} 329201342Snyan#endif 330201342Snyan 331201342Snyanstatic int 332201342Snyancheck_slice(void) 333201342Snyan{ 334201342Snyan struct pc98_partition *dp; 335201342Snyan char *sec; 336201342Snyan unsigned i, cyl; 337201342Snyan 338201342Snyan sec = dmadat->secbuf; 339201342Snyan cyl = *(uint16_t *)PTOV(ARGS); 340201342Snyan set_dsk(); 341201342Snyan 342201342Snyan if (dsk.type == TYPE_FD) 343201342Snyan return (WHOLE_DISK_SLICE); 344201342Snyan if (drvread(sec, DOSBBSECTOR + 1)) 345201342Snyan return (WHOLE_DISK_SLICE); /* Read error */ 346201342Snyan dp = (void *)(sec + DOSPARTOFF); 347201342Snyan for (i = 0; i < NDOSPART; i++) { 348201342Snyan if (dp[i].dp_mid == DOSMID_386BSD) { 349201342Snyan if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl) 350201342Snyan return (BASE_SLICE + i); 351201342Snyan } 352201342Snyan } 353201342Snyan 354201342Snyan return (WHOLE_DISK_SLICE); 355201342Snyan} 356201342Snyan 357201342Snyanint 358201342Snyanmain(void) 359201342Snyan{ 360201342Snyan#ifdef GET_BIOSGEOM 361201342Snyan int i; 362201342Snyan#endif 363218737Snyan uint8_t autoboot; 364201342Snyan ino_t ino; 365201342Snyan 366201342Snyan dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 367201342Snyan v86.ctl = V86_FLAGS; 368201342Snyan v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 369201342Snyan dsk.daua = *(uint8_t *)PTOV(0x584); 370201342Snyan dsk.disk = dsk.daua & DRV_DISK; 371201342Snyan dsk.unit = dsk.daua & DRV_UNIT; 372201342Snyan if (dsk.disk == 0x80) 373201342Snyan dsk.type = TYPE_AD; 374201342Snyan else if (dsk.disk == 0xa0) 375201342Snyan dsk.type = TYPE_DA; 376201342Snyan else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ 377201342Snyan dsk.type = TYPE_FD; 378201342Snyan dsk.slice = check_slice(); 379201342Snyan#ifdef GET_BIOSGEOM 380201342Snyan for (i = 0; i < N_BIOS_GEOM; i++) 381201342Snyan bootinfo.bi_bios_geom[i] = bd_getbigeom(i); 382201342Snyan#endif 383201342Snyan bootinfo.bi_version = BOOTINFO_VERSION; 384201342Snyan bootinfo.bi_size = sizeof(bootinfo); 385201342Snyan bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ 386201342Snyan bootinfo.bi_extmem = memsize(); 387201342Snyan bootinfo.bi_memsizes_valid++; 388201342Snyan 389201342Snyan /* Process configuration file */ 390201342Snyan 391201342Snyan autoboot = 1; 392201342Snyan 393201342Snyan if ((ino = lookup(PATH_CONFIG))) 394201342Snyan fsread(ino, cmd, sizeof(cmd)); 395201342Snyan 396201342Snyan if (*cmd) { 397201342Snyan memcpy(cmddup, cmd, sizeof(cmd)); 398201342Snyan if (parse()) 399201342Snyan autoboot = 0; 400201342Snyan if (!OPT_CHECK(RBX_QUIET)) 401201342Snyan printf("%s: %s", PATH_CONFIG, cmddup); 402201342Snyan /* Do not process this command twice */ 403201342Snyan *cmd = 0; 404201342Snyan } 405201342Snyan 406201342Snyan /* 407201342Snyan * Try to exec stage 3 boot loader. If interrupted by a keypress, 408201342Snyan * or in case of failure, try to load a kernel directly instead. 409201342Snyan */ 410201342Snyan 411201342Snyan if (autoboot && !*kname) { 412201342Snyan memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); 413201342Snyan if (!keyhit(3*SECOND)) { 414201342Snyan load(); 415201342Snyan memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); 416201342Snyan } 417201342Snyan } 418201342Snyan 419201342Snyan /* Present the user with the boot2 prompt. */ 420201342Snyan 421201342Snyan for (;;) { 422201342Snyan if (!autoboot || !OPT_CHECK(RBX_QUIET)) 423201342Snyan printf("\nFreeBSD/pc98 boot\n" 424201342Snyan "Default: %u:%s(%u,%c)%s\n" 425201342Snyan "boot: ", 426201342Snyan dsk.unit, dev_nm[dsk.type], dsk.unit, 427201342Snyan 'a' + dsk.part, kname); 428201342Snyan if (ioctrl & IO_SERIAL) 429201342Snyan sio_flush(); 430201342Snyan if (!autoboot || keyhit(5*SECOND)) 431201342Snyan getstr(); 432201342Snyan else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 433201342Snyan putchar('\n'); 434201342Snyan autoboot = 0; 435201342Snyan if (parse()) 436201342Snyan putchar('\a'); 437201342Snyan else 438201342Snyan load(); 439201342Snyan } 440201342Snyan} 441201342Snyan 442201342Snyan/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 443201342Snyanvoid 444201342Snyanexit(int x) 445201342Snyan{ 446201342Snyan} 447201342Snyan 448201342Snyanstatic void 449201342Snyanload(void) 450201342Snyan{ 451201342Snyan union { 452201342Snyan struct exec ex; 453201342Snyan Elf32_Ehdr eh; 454201342Snyan } hdr; 455201342Snyan static Elf32_Phdr ep[2]; 456201342Snyan static Elf32_Shdr es[2]; 457201342Snyan caddr_t p; 458201342Snyan ino_t ino; 459201342Snyan uint32_t addr, x; 460218737Snyan int i, j; 461218737Snyan uint8_t fmt; 462201342Snyan 463201342Snyan if (!(ino = lookup(kname))) { 464201342Snyan if (!ls) 465201342Snyan printf("No %s\n", kname); 466201342Snyan return; 467201342Snyan } 468201342Snyan if (xfsread(ino, &hdr, sizeof(hdr))) 469201342Snyan return; 470201342Snyan if (N_GETMAGIC(hdr.ex) == ZMAGIC) 471201342Snyan fmt = 0; 472201342Snyan else if (IS_ELF(hdr.eh)) 473201342Snyan fmt = 1; 474201342Snyan else { 475201342Snyan printf("Invalid %s\n", "format"); 476201342Snyan return; 477201342Snyan } 478201342Snyan if (fmt == 0) { 479201342Snyan addr = hdr.ex.a_entry & 0xffffff; 480201342Snyan p = PTOV(addr); 481201342Snyan fs_off = PAGE_SIZE; 482201342Snyan if (xfsread(ino, p, hdr.ex.a_text)) 483201342Snyan return; 484201342Snyan p += roundup2(hdr.ex.a_text, PAGE_SIZE); 485201342Snyan if (xfsread(ino, p, hdr.ex.a_data)) 486201342Snyan return; 487201342Snyan } else { 488201342Snyan fs_off = hdr.eh.e_phoff; 489201342Snyan for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 490201342Snyan if (xfsread(ino, ep + j, sizeof(ep[0]))) 491201342Snyan return; 492201342Snyan if (ep[j].p_type == PT_LOAD) 493201342Snyan j++; 494201342Snyan } 495201342Snyan for (i = 0; i < 2; i++) { 496201342Snyan p = PTOV(ep[i].p_paddr & 0xffffff); 497201342Snyan fs_off = ep[i].p_offset; 498201342Snyan if (xfsread(ino, p, ep[i].p_filesz)) 499201342Snyan return; 500201342Snyan } 501201342Snyan p += roundup2(ep[1].p_memsz, PAGE_SIZE); 502201342Snyan bootinfo.bi_symtab = VTOP(p); 503201342Snyan if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 504201342Snyan fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 505201342Snyan (hdr.eh.e_shstrndx + 1); 506201342Snyan if (xfsread(ino, &es, sizeof(es))) 507201342Snyan return; 508201342Snyan for (i = 0; i < 2; i++) { 509214257Snyan *(Elf32_Word *)p = es[i].sh_size; 510201342Snyan p += sizeof(es[i].sh_size); 511201342Snyan fs_off = es[i].sh_offset; 512201342Snyan if (xfsread(ino, p, es[i].sh_size)) 513201342Snyan return; 514201342Snyan p += es[i].sh_size; 515201342Snyan } 516201342Snyan } 517201342Snyan addr = hdr.eh.e_entry & 0xffffff; 518218842Snyan bootinfo.bi_esymtab = VTOP(p); 519201342Snyan } 520201342Snyan bootinfo.bi_kernelname = VTOP(kname); 521201342Snyan bootinfo.bi_bios_dev = dsk.daua; 522201342Snyan __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 523201342Snyan MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 524201342Snyan 0, 0, 0, VTOP(&bootinfo)); 525201342Snyan} 526201342Snyan 527201342Snyanstatic int 528201342Snyanparse() 529201342Snyan{ 530201342Snyan char *arg = cmd; 531201342Snyan char *ep, *p, *q; 532201342Snyan const char *cp; 533201342Snyan unsigned int drv; 534201342Snyan int c, i, j; 535201342Snyan 536201342Snyan while ((c = *arg++)) { 537201342Snyan if (c == ' ' || c == '\t' || c == '\n') 538201342Snyan continue; 539201342Snyan for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 540201342Snyan ep = p; 541201342Snyan if (*p) 542201342Snyan *p++ = 0; 543201342Snyan if (c == '-') { 544201342Snyan while ((c = *arg++)) { 545201342Snyan if (c == 'P') { 546201342Snyan if (*(uint8_t *)PTOV(0x481) & 0x48) { 547201342Snyan cp = "yes"; 548201342Snyan } else { 549201342Snyan opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 550201342Snyan cp = "no"; 551201342Snyan } 552201342Snyan printf("Keyboard: %s\n", cp); 553201342Snyan continue; 554201342Snyan } else if (c == 'S') { 555201342Snyan j = 0; 556201342Snyan while ((unsigned int)(i = *arg++ - '0') <= 9) 557201342Snyan j = j * 10 + i; 558201342Snyan if (j > 0 && i == -'0') { 559201342Snyan comspeed = j; 560201342Snyan break; 561201342Snyan } 562201342Snyan /* Fall through to error below ('S' not in optstr[]). */ 563201342Snyan } 564201342Snyan for (i = 0; c != optstr[i]; i++) 565201342Snyan if (i == NOPT - 1) 566201342Snyan return -1; 567201342Snyan opts ^= OPT_SET(flags[i]); 568201342Snyan } 569201342Snyan ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 570201342Snyan OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 571201342Snyan if (ioctrl & IO_SERIAL) 572201342Snyan sio_init(115200 / comspeed); 573201342Snyan } else { 574201342Snyan for (q = arg--; *q && *q != '('; q++); 575201342Snyan if (*q) { 576201342Snyan drv = -1; 577201342Snyan if (arg[1] == ':') { 578201342Snyan drv = *arg - '0'; 579201342Snyan if (drv > 9) 580201342Snyan return (-1); 581201342Snyan arg += 2; 582201342Snyan } 583201342Snyan if (q - arg != 2) 584201342Snyan return -1; 585201342Snyan for (i = 0; arg[0] != dev_nm[i][0] || 586201342Snyan arg[1] != dev_nm[i][1]; i++) 587201342Snyan if (i == NDEV - 1) 588201342Snyan return -1; 589201342Snyan dsk.type = i; 590201342Snyan arg += 3; 591201342Snyan dsk.unit = *arg - '0'; 592201342Snyan if (arg[1] != ',' || dsk.unit > 9) 593201342Snyan return -1; 594201342Snyan arg += 2; 595201342Snyan dsk.slice = WHOLE_DISK_SLICE; 596201342Snyan if (arg[1] == ',') { 597201342Snyan dsk.slice = *arg - '0' + 1; 598201342Snyan if (dsk.slice > NDOSPART + 1) 599201342Snyan return -1; 600201342Snyan arg += 2; 601201342Snyan } 602201342Snyan if (arg[1] != ')') 603201342Snyan return -1; 604201342Snyan dsk.part = *arg - 'a'; 605201342Snyan if (dsk.part > 7) 606201342Snyan return (-1); 607201342Snyan arg += 2; 608201342Snyan if (drv == -1) 609201342Snyan drv = dsk.unit; 610201342Snyan dsk.disk = dev_daua[dsk.type]; 611201342Snyan dsk.daua = dsk.disk | dsk.unit; 612201342Snyan dsk_meta = 0; 613201342Snyan } 614201342Snyan if ((i = ep - arg)) { 615201342Snyan if ((size_t)i >= sizeof(kname)) 616201342Snyan return -1; 617201342Snyan memcpy(kname, arg, i + 1); 618201342Snyan } 619201342Snyan } 620201342Snyan arg = p; 621201342Snyan } 622201342Snyan return 0; 623201342Snyan} 624201342Snyan 625201342Snyanstatic int 626201342Snyandskread(void *buf, unsigned lba, unsigned nblk) 627201342Snyan{ 628201342Snyan struct pc98_partition *dp; 629201342Snyan struct disklabel *d; 630201342Snyan char *sec; 631201342Snyan unsigned sl, i; 632201342Snyan u_char *p; 633201342Snyan 634201342Snyan if (!dsk_meta) { 635201342Snyan sec = dmadat->secbuf; 636201342Snyan set_dsk(); 637201342Snyan if (dsk.type == TYPE_FD) 638201342Snyan goto unsliced; 639201342Snyan if (drvread(sec, DOSBBSECTOR + 1)) 640201342Snyan return -1; 641201342Snyan dp = (void *)(sec + DOSPARTOFF); 642201342Snyan sl = dsk.slice; 643201342Snyan if (sl < BASE_SLICE) { 644201342Snyan for (i = 0; i < NDOSPART; i++) 645201342Snyan if (dp[i].dp_mid == DOSMID_386BSD) { 646201342Snyan sl = BASE_SLICE + i; 647201342Snyan break; 648201342Snyan } 649201342Snyan dsk.slice = sl; 650201342Snyan } 651201342Snyan if (sl != WHOLE_DISK_SLICE) { 652201342Snyan dp += sl - BASE_SLICE; 653201342Snyan if (dp->dp_mid != DOSMID_386BSD) { 654201342Snyan printf("Invalid %s\n", "slice"); 655201342Snyan return -1; 656201342Snyan } 657201342Snyan dsk.start = dp->dp_scyl * dsk.head * dsk.sec + 658201342Snyan dp->dp_shd * dsk.sec + dp->dp_ssect; 659201342Snyan } 660201342Snyan if (drvread(sec, dsk.start + LABELSECTOR)) 661201342Snyan return -1; 662201342Snyan d = (void *)(sec + LABELOFFSET); 663201342Snyan if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 664201342Snyan if (dsk.part != RAW_PART) { 665201342Snyan printf("Invalid %s\n", "label"); 666201342Snyan return -1; 667201342Snyan } 668201342Snyan } else { 669201342Snyan if (dsk.part >= d->d_npartitions || 670201342Snyan !d->d_partitions[dsk.part].p_size) { 671201342Snyan printf("Invalid %s\n", "partition"); 672201342Snyan return -1; 673201342Snyan } 674201342Snyan dsk.start += d->d_partitions[dsk.part].p_offset; 675201342Snyan dsk.start -= d->d_partitions[RAW_PART].p_offset; 676201342Snyan } 677201342Snyan unsliced: ; 678201342Snyan } 679201342Snyan for (p = buf; nblk; p += 512, lba++, nblk--) { 680201342Snyan if ((i = drvread(p, dsk.start + lba))) 681201342Snyan return i; 682201342Snyan } 683201342Snyan return 0; 684201342Snyan} 685201342Snyan 686201342Snyanstatic void 687201342Snyanprintf(const char *fmt,...) 688201342Snyan{ 689201342Snyan va_list ap; 690201342Snyan char buf[10]; 691201342Snyan char *s; 692201342Snyan unsigned u; 693201342Snyan int c; 694201342Snyan 695201342Snyan va_start(ap, fmt); 696201342Snyan while ((c = *fmt++)) { 697201342Snyan if (c == '%') { 698201342Snyan c = *fmt++; 699201342Snyan switch (c) { 700201342Snyan case 'c': 701201342Snyan putchar(va_arg(ap, int)); 702201342Snyan continue; 703201342Snyan case 's': 704201342Snyan for (s = va_arg(ap, char *); *s; s++) 705201342Snyan putchar(*s); 706201342Snyan continue; 707201342Snyan case 'u': 708201342Snyan u = va_arg(ap, unsigned); 709201342Snyan s = buf; 710201342Snyan do 711201342Snyan *s++ = '0' + u % 10U; 712201342Snyan while (u /= 10U); 713201342Snyan while (--s >= buf) 714201342Snyan putchar(*s); 715201342Snyan continue; 716201342Snyan } 717201342Snyan } 718201342Snyan putchar(c); 719201342Snyan } 720201342Snyan va_end(ap); 721201342Snyan return; 722201342Snyan} 723201342Snyan 724201342Snyanstatic void 725201342Snyanputchar(int c) 726201342Snyan{ 727201342Snyan if (c == '\n') 728201342Snyan xputc('\r'); 729201342Snyan xputc(c); 730201342Snyan} 731201342Snyan 732201342Snyanstatic int 733201342Snyandrvread(void *buf, unsigned lba) 734201342Snyan{ 735201342Snyan static unsigned c = 0x2d5c7c2f; 736201342Snyan unsigned bpc, x, cyl, head, sec; 737201342Snyan 738201342Snyan bpc = dsk.sec * dsk.head; 739201342Snyan cyl = lba / bpc; 740201342Snyan x = lba % bpc; 741201342Snyan head = x / dsk.sec; 742201342Snyan sec = x % dsk.sec; 743201342Snyan 744201342Snyan if (!OPT_CHECK(RBX_QUIET)) 745201342Snyan printf("%c\b", c = c << 8 | c >> 24); 746201342Snyan v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 747201342Snyan v86.addr = READORG; /* call to read in boot1 */ 748201342Snyan v86.ecx = cyl; 749201342Snyan v86.edx = (head << 8) | sec; 750201342Snyan v86.edi = lba; 751201342Snyan v86.ebx = 512; 752201342Snyan v86.es = VTOPSEG(buf); 753201342Snyan v86.ebp = VTOPOFF(buf); 754201342Snyan v86int(); 755201342Snyan v86.ctl = V86_FLAGS; 756201342Snyan if (V86_CY(v86.efl)) { 757201342Snyan printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, 758201342Snyan cyl, head, sec, lba); 759201342Snyan return -1; 760201342Snyan } 761201342Snyan return 0; 762201342Snyan} 763201342Snyan 764201342Snyanstatic inline void 765201342Snyandelay(void) 766201342Snyan{ 767201342Snyan int i; 768201342Snyan 769201342Snyan i = 800; 770201342Snyan do { 771201342Snyan outb(0x5f, 0); /* about 600ns */ 772201342Snyan } while (--i >= 0); 773201342Snyan} 774201342Snyan 775201342Snyanstatic int 776201342Snyankeyhit(unsigned sec) 777201342Snyan{ 778201342Snyan unsigned i; 779201342Snyan 780201342Snyan if (OPT_CHECK(RBX_NOINTR)) 781201342Snyan return 0; 782201342Snyan for (i = 0; i < sec * 1000; i++) { 783201342Snyan if (xgetc(1)) 784201342Snyan return 1; 785201342Snyan delay(); 786201342Snyan } 787201342Snyan return 0; 788201342Snyan} 789201342Snyan 790201342Snyanstatic int 791201342Snyanxputc(int c) 792201342Snyan{ 793201342Snyan if (ioctrl & IO_KEYBOARD) 794201342Snyan putc(c); 795201342Snyan if (ioctrl & IO_SERIAL) 796201342Snyan sio_putc(c); 797201342Snyan return c; 798201342Snyan} 799201342Snyan 800201342Snyanstatic int 801201342Snyanxgetc(int fn) 802201342Snyan{ 803201342Snyan if (OPT_CHECK(RBX_NOINTR)) 804201342Snyan return 0; 805201342Snyan for (;;) { 806201342Snyan if (ioctrl & IO_KEYBOARD && getc(1)) 807201342Snyan return fn ? 1 : getc(0); 808201342Snyan if (ioctrl & IO_SERIAL && sio_ischar()) 809201342Snyan return fn ? 1 : sio_getc(); 810201342Snyan if (fn) 811201342Snyan return 0; 812201342Snyan } 813201342Snyan} 814201342Snyan 815201342Snyanstatic int 816201342Snyangetc(int fn) 817201342Snyan{ 818201342Snyan v86.addr = 0x18; 819201342Snyan v86.eax = fn << 8; 820201342Snyan v86int(); 821201342Snyan if (fn) 822201342Snyan return (v86.ebx >> 8) & 0x01; 823201342Snyan else 824201342Snyan return v86.eax & 0xff; 825201342Snyan} 826