boot2.c revision 219960
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 219960 2011-03-24 15:09:36Z 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]; 136219225Snyanstatic const char *kname = NULL; 137218946Snyanstatic uint32_t opts; 138201342Snyanstatic int comspeed = SIOSPD; 139201342Snyanstatic struct bootinfo bootinfo; 140219960Snyanstatic 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 int drvread(void *, unsigned); 150201342Snyanstatic int keyhit(unsigned); 151201342Snyanstatic int xputc(int); 152201342Snyanstatic int xgetc(int); 153201342Snyanstatic int getc(int); 154201342Snyan 155201342Snyanstatic void memcpy(void *, const void *, int); 156201342Snyanstatic void 157201342Snyanmemcpy(void *dst, const void *src, int len) 158201342Snyan{ 159201342Snyan const char *s = src; 160201342Snyan char *d = dst; 161201342Snyan 162201342Snyan while (len--) 163201342Snyan *d++ = *s++; 164201342Snyan} 165201342Snyan 166201342Snyanstatic inline int 167201342Snyanstrcmp(const char *s1, const char *s2) 168201342Snyan{ 169201342Snyan for (; *s1 == *s2 && *s1; s1++, s2++); 170201342Snyan return (unsigned char)*s1 - (unsigned char)*s2; 171201342Snyan} 172201342Snyan 173201342Snyan#define UFS_SMALL_CGBASE 174201342Snyan#include "ufsread.c" 175201342Snyan 176201342Snyanstatic inline int 177201342Snyanxfsread(ino_t inode, void *buf, size_t nbyte) 178201342Snyan{ 179201342Snyan if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 180201342Snyan printf("Invalid %s\n", "format"); 181201342Snyan return -1; 182201342Snyan } 183201342Snyan return 0; 184201342Snyan} 185201342Snyan 186201342Snyanstatic inline void 187201342Snyangetstr(void) 188201342Snyan{ 189201342Snyan char *s; 190201342Snyan int c; 191201342Snyan 192201342Snyan s = cmd; 193201342Snyan for (;;) { 194201342Snyan switch (c = xgetc(0)) { 195201342Snyan case 0: 196201342Snyan break; 197201342Snyan case '\177': 198201342Snyan case '\b': 199201342Snyan if (s > cmd) { 200201342Snyan s--; 201201342Snyan printf("\b \b"); 202201342Snyan } 203201342Snyan break; 204201342Snyan case '\n': 205201342Snyan case '\r': 206201342Snyan *s = 0; 207201342Snyan return; 208201342Snyan default: 209201342Snyan if (s - cmd < sizeof(cmd) - 1) 210201342Snyan *s++ = c; 211201342Snyan putchar(c); 212201342Snyan } 213201342Snyan } 214201342Snyan} 215201342Snyan 216201342Snyanstatic inline void 217201342Snyanputc(int c) 218201342Snyan{ 219201342Snyan 220201342Snyan v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 221201342Snyan v86.addr = PUTCORG; /* call to putc in boot1 */ 222201342Snyan v86.eax = c; 223201342Snyan v86int(); 224201342Snyan v86.ctl = V86_FLAGS; 225201342Snyan} 226201342Snyan 227201342Snyanstatic inline int 228201342Snyanis_scsi_hd(void) 229201342Snyan{ 230201342Snyan 231201342Snyan if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01) 232201342Snyan return 1; 233201342Snyan 234201342Snyan return 0; 235201342Snyan} 236201342Snyan 237201342Snyanstatic inline void 238201342Snyanfix_sector_size(void) 239201342Snyan{ 240201342Snyan u_char *p; 241201342Snyan 242201342Snyan p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */ 243201342Snyan 244201342Snyan if ((p[0] & 0x1f) == 7) { /* SCSI MO */ 245201342Snyan if (!(p[3] & 0x30)) { /* 256B / sector */ 246201342Snyan p[3] |= 0x10; /* forced set 512B / sector */ 247201342Snyan p[3 + 0xa1000] |= 0x10; 248201342Snyan } 249201342Snyan } 250201342Snyan} 251201342Snyan 252201342Snyanstatic inline uint32_t 253201342Snyanget_diskinfo(void) 254201342Snyan{ 255201342Snyan 256201342Snyan if (dsk.disk == 0x30) { /* 1440KB FD */ 257201342Snyan /* 80 cylinders, 2 heads, 18 sectors */ 258201342Snyan return (80 << 16) | (2 << 8) | 18; 259201342Snyan } else if (dsk.disk == 0x90) { /* 1200KB FD */ 260201342Snyan /* 80 cylinders, 2 heads, 15 sectors */ 261201342Snyan return (80 << 16) | (2 << 8) | 15; 262201342Snyan } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */ 263201342Snyan v86.addr = 0x1b; 264201342Snyan v86.eax = 0x8400 | dsk.daua; 265201342Snyan v86int(); 266201342Snyan return (v86.ecx << 16) | v86.edx; 267201342Snyan } 268201342Snyan 269201342Snyan /* SCSI MO or CD */ 270201342Snyan fix_sector_size(); /* SCSI MO */ 271201342Snyan 272201342Snyan /* other SCSI devices */ 273201342Snyan return (65535 << 16) | (8 << 8) | 32; 274201342Snyan} 275201342Snyan 276201342Snyanstatic void 277201342Snyanset_dsk(void) 278201342Snyan{ 279201342Snyan uint32_t di; 280201342Snyan 281201342Snyan di = get_diskinfo(); 282201342Snyan 283201342Snyan dsk.head = (di >> 8) & 0xff; 284201342Snyan dsk.sec = di & 0xff; 285201342Snyan dsk.start = 0; 286201342Snyan} 287201342Snyan 288201342Snyan#ifdef GET_BIOSGEOM 289201342Snyanstatic uint32_t 290201342Snyanbd_getbigeom(int bunit) 291201342Snyan{ 292201342Snyan int hds = 0; 293201342Snyan int unit = 0x80; /* IDE HDD */ 294201342Snyan u_int addr = 0x55d; 295201342Snyan 296201342Snyan while (unit < 0xa7) { 297201342Snyan if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) 298201342Snyan if (hds++ == bunit) 299201342Snyan break; 300201342Snyan 301201342Snyan if (unit >= 0xA0) { 302201342Snyan int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F; 303201342Snyan 304201342Snyan if (media == 7 && hds++ == bunit) /* SCSI MO */ 305201342Snyan return(0xFFFE0820); /* C:65535 H:8 S:32 */ 306201342Snyan } 307201342Snyan if (++unit == 0x84) { 308201342Snyan unit = 0xA0; /* SCSI HDD */ 309201342Snyan addr = 0x482; 310201342Snyan } 311201342Snyan } 312201342Snyan if (unit == 0xa7) 313201342Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 314201342Snyan v86.addr = 0x1b; 315201342Snyan v86.eax = 0x8400 | unit; 316201342Snyan v86int(); 317201342Snyan if (v86.efl & 0x1) 318201342Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 319201342Snyan return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); 320201342Snyan} 321201342Snyan#endif 322201342Snyan 323201342Snyanstatic int 324201342Snyancheck_slice(void) 325201342Snyan{ 326201342Snyan struct pc98_partition *dp; 327201342Snyan char *sec; 328201342Snyan unsigned i, cyl; 329201342Snyan 330201342Snyan sec = dmadat->secbuf; 331201342Snyan cyl = *(uint16_t *)PTOV(ARGS); 332201342Snyan set_dsk(); 333201342Snyan 334201342Snyan if (dsk.type == TYPE_FD) 335201342Snyan return (WHOLE_DISK_SLICE); 336201342Snyan if (drvread(sec, DOSBBSECTOR + 1)) 337201342Snyan return (WHOLE_DISK_SLICE); /* Read error */ 338201342Snyan dp = (void *)(sec + DOSPARTOFF); 339201342Snyan for (i = 0; i < NDOSPART; i++) { 340201342Snyan if (dp[i].dp_mid == DOSMID_386BSD) { 341201342Snyan if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl) 342201342Snyan return (BASE_SLICE + i); 343201342Snyan } 344201342Snyan } 345201342Snyan 346201342Snyan return (WHOLE_DISK_SLICE); 347201342Snyan} 348201342Snyan 349201342Snyanint 350201342Snyanmain(void) 351201342Snyan{ 352201342Snyan#ifdef GET_BIOSGEOM 353201342Snyan int i; 354201342Snyan#endif 355218737Snyan uint8_t autoboot; 356201342Snyan ino_t ino; 357201342Snyan 358201342Snyan dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 359201342Snyan v86.ctl = V86_FLAGS; 360201342Snyan v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 361201342Snyan dsk.daua = *(uint8_t *)PTOV(0x584); 362201342Snyan dsk.disk = dsk.daua & DRV_DISK; 363201342Snyan dsk.unit = dsk.daua & DRV_UNIT; 364201342Snyan if (dsk.disk == 0x80) 365201342Snyan dsk.type = TYPE_AD; 366201342Snyan else if (dsk.disk == 0xa0) 367201342Snyan dsk.type = TYPE_DA; 368201342Snyan else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ 369201342Snyan dsk.type = TYPE_FD; 370201342Snyan dsk.slice = check_slice(); 371201342Snyan#ifdef GET_BIOSGEOM 372201342Snyan for (i = 0; i < N_BIOS_GEOM; i++) 373201342Snyan bootinfo.bi_bios_geom[i] = bd_getbigeom(i); 374201342Snyan#endif 375201342Snyan bootinfo.bi_version = BOOTINFO_VERSION; 376201342Snyan bootinfo.bi_size = sizeof(bootinfo); 377201342Snyan 378201342Snyan /* Process configuration file */ 379201342Snyan 380201342Snyan autoboot = 1; 381201342Snyan 382201342Snyan if ((ino = lookup(PATH_CONFIG))) 383201342Snyan fsread(ino, cmd, sizeof(cmd)); 384201342Snyan 385201342Snyan if (*cmd) { 386201342Snyan memcpy(cmddup, cmd, sizeof(cmd)); 387201342Snyan if (parse()) 388201342Snyan autoboot = 0; 389201342Snyan if (!OPT_CHECK(RBX_QUIET)) 390201342Snyan printf("%s: %s", PATH_CONFIG, cmddup); 391201342Snyan /* Do not process this command twice */ 392201342Snyan *cmd = 0; 393201342Snyan } 394201342Snyan 395201342Snyan /* 396201342Snyan * Try to exec stage 3 boot loader. If interrupted by a keypress, 397201342Snyan * or in case of failure, try to load a kernel directly instead. 398201342Snyan */ 399201342Snyan 400219225Snyan if (autoboot && !kname) { 401219225Snyan kname = PATH_BOOT3; 402201342Snyan if (!keyhit(3*SECOND)) { 403201342Snyan load(); 404219225Snyan kname = PATH_KERNEL; 405201342Snyan } 406201342Snyan } 407201342Snyan 408201342Snyan /* Present the user with the boot2 prompt. */ 409201342Snyan 410201342Snyan for (;;) { 411201342Snyan if (!autoboot || !OPT_CHECK(RBX_QUIET)) 412201342Snyan printf("\nFreeBSD/pc98 boot\n" 413201342Snyan "Default: %u:%s(%u,%c)%s\n" 414201342Snyan "boot: ", 415201342Snyan dsk.unit, dev_nm[dsk.type], dsk.unit, 416201342Snyan 'a' + dsk.part, kname); 417201342Snyan if (ioctrl & IO_SERIAL) 418201342Snyan sio_flush(); 419219225Snyan if (!autoboot || keyhit(3*SECOND)) 420201342Snyan getstr(); 421201342Snyan else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 422201342Snyan putchar('\n'); 423201342Snyan autoboot = 0; 424201342Snyan if (parse()) 425201342Snyan putchar('\a'); 426201342Snyan else 427201342Snyan load(); 428201342Snyan } 429201342Snyan} 430201342Snyan 431201342Snyan/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 432201342Snyanvoid 433201342Snyanexit(int x) 434201342Snyan{ 435201342Snyan} 436201342Snyan 437201342Snyanstatic void 438201342Snyanload(void) 439201342Snyan{ 440201342Snyan union { 441201342Snyan struct exec ex; 442201342Snyan Elf32_Ehdr eh; 443201342Snyan } hdr; 444201342Snyan static Elf32_Phdr ep[2]; 445201342Snyan static Elf32_Shdr es[2]; 446201342Snyan caddr_t p; 447201342Snyan ino_t ino; 448219960Snyan uint32_t addr; 449218737Snyan int i, j; 450201342Snyan 451201342Snyan if (!(ino = lookup(kname))) { 452201342Snyan if (!ls) 453201342Snyan printf("No %s\n", kname); 454201342Snyan return; 455201342Snyan } 456201342Snyan if (xfsread(ino, &hdr, sizeof(hdr))) 457201342Snyan return; 458219960Snyan 459219960Snyan if (N_GETMAGIC(hdr.ex) == ZMAGIC) { 460201342Snyan addr = hdr.ex.a_entry & 0xffffff; 461201342Snyan p = PTOV(addr); 462201342Snyan fs_off = PAGE_SIZE; 463201342Snyan if (xfsread(ino, p, hdr.ex.a_text)) 464201342Snyan return; 465201342Snyan p += roundup2(hdr.ex.a_text, PAGE_SIZE); 466201342Snyan if (xfsread(ino, p, hdr.ex.a_data)) 467201342Snyan return; 468219960Snyan } else if (IS_ELF(hdr.eh)) { 469201342Snyan fs_off = hdr.eh.e_phoff; 470201342Snyan for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 471201342Snyan if (xfsread(ino, ep + j, sizeof(ep[0]))) 472201342Snyan return; 473201342Snyan if (ep[j].p_type == PT_LOAD) 474201342Snyan j++; 475201342Snyan } 476201342Snyan for (i = 0; i < 2; i++) { 477201342Snyan p = PTOV(ep[i].p_paddr & 0xffffff); 478201342Snyan fs_off = ep[i].p_offset; 479201342Snyan if (xfsread(ino, p, ep[i].p_filesz)) 480201342Snyan return; 481201342Snyan } 482201342Snyan p += roundup2(ep[1].p_memsz, PAGE_SIZE); 483201342Snyan bootinfo.bi_symtab = VTOP(p); 484201342Snyan if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 485201342Snyan fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 486201342Snyan (hdr.eh.e_shstrndx + 1); 487201342Snyan if (xfsread(ino, &es, sizeof(es))) 488201342Snyan return; 489201342Snyan for (i = 0; i < 2; i++) { 490214257Snyan *(Elf32_Word *)p = es[i].sh_size; 491201342Snyan p += sizeof(es[i].sh_size); 492201342Snyan fs_off = es[i].sh_offset; 493201342Snyan if (xfsread(ino, p, es[i].sh_size)) 494201342Snyan return; 495201342Snyan p += es[i].sh_size; 496201342Snyan } 497201342Snyan } 498201342Snyan addr = hdr.eh.e_entry & 0xffffff; 499218842Snyan bootinfo.bi_esymtab = VTOP(p); 500219960Snyan } else { 501219960Snyan printf("Invalid %s\n", "format"); 502219960Snyan return; 503201342Snyan } 504219960Snyan 505201342Snyan bootinfo.bi_kernelname = VTOP(kname); 506201342Snyan bootinfo.bi_bios_dev = dsk.daua; 507201342Snyan __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 508201342Snyan MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 509201342Snyan 0, 0, 0, VTOP(&bootinfo)); 510201342Snyan} 511201342Snyan 512201342Snyanstatic int 513201342Snyanparse() 514201342Snyan{ 515201342Snyan char *arg = cmd; 516201342Snyan char *ep, *p, *q; 517201342Snyan const char *cp; 518201342Snyan unsigned int drv; 519201342Snyan int c, i, j; 520201342Snyan 521201342Snyan while ((c = *arg++)) { 522201342Snyan if (c == ' ' || c == '\t' || c == '\n') 523201342Snyan continue; 524201342Snyan for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 525201342Snyan ep = p; 526201342Snyan if (*p) 527201342Snyan *p++ = 0; 528201342Snyan if (c == '-') { 529201342Snyan while ((c = *arg++)) { 530201342Snyan if (c == 'P') { 531201342Snyan if (*(uint8_t *)PTOV(0x481) & 0x48) { 532201342Snyan cp = "yes"; 533201342Snyan } else { 534201342Snyan opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 535201342Snyan cp = "no"; 536201342Snyan } 537201342Snyan printf("Keyboard: %s\n", cp); 538201342Snyan continue; 539201342Snyan } else if (c == 'S') { 540201342Snyan j = 0; 541201342Snyan while ((unsigned int)(i = *arg++ - '0') <= 9) 542201342Snyan j = j * 10 + i; 543201342Snyan if (j > 0 && i == -'0') { 544201342Snyan comspeed = j; 545201342Snyan break; 546201342Snyan } 547201342Snyan /* Fall through to error below ('S' not in optstr[]). */ 548201342Snyan } 549201342Snyan for (i = 0; c != optstr[i]; i++) 550201342Snyan if (i == NOPT - 1) 551201342Snyan return -1; 552201342Snyan opts ^= OPT_SET(flags[i]); 553201342Snyan } 554201342Snyan ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 555201342Snyan OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 556201342Snyan if (ioctrl & IO_SERIAL) 557201342Snyan sio_init(115200 / comspeed); 558201342Snyan } else { 559201342Snyan for (q = arg--; *q && *q != '('; q++); 560201342Snyan if (*q) { 561201342Snyan drv = -1; 562201342Snyan if (arg[1] == ':') { 563201342Snyan drv = *arg - '0'; 564201342Snyan if (drv > 9) 565201342Snyan return (-1); 566201342Snyan arg += 2; 567201342Snyan } 568201342Snyan if (q - arg != 2) 569201342Snyan return -1; 570201342Snyan for (i = 0; arg[0] != dev_nm[i][0] || 571201342Snyan arg[1] != dev_nm[i][1]; i++) 572201342Snyan if (i == NDEV - 1) 573201342Snyan return -1; 574201342Snyan dsk.type = i; 575201342Snyan arg += 3; 576201342Snyan dsk.unit = *arg - '0'; 577201342Snyan if (arg[1] != ',' || dsk.unit > 9) 578201342Snyan return -1; 579201342Snyan arg += 2; 580201342Snyan dsk.slice = WHOLE_DISK_SLICE; 581201342Snyan if (arg[1] == ',') { 582201342Snyan dsk.slice = *arg - '0' + 1; 583201342Snyan if (dsk.slice > NDOSPART + 1) 584201342Snyan return -1; 585201342Snyan arg += 2; 586201342Snyan } 587201342Snyan if (arg[1] != ')') 588201342Snyan return -1; 589201342Snyan dsk.part = *arg - 'a'; 590201342Snyan if (dsk.part > 7) 591201342Snyan return (-1); 592201342Snyan arg += 2; 593201342Snyan if (drv == -1) 594201342Snyan drv = dsk.unit; 595201342Snyan dsk.disk = dev_daua[dsk.type]; 596201342Snyan dsk.daua = dsk.disk | dsk.unit; 597201342Snyan dsk_meta = 0; 598201342Snyan } 599219225Snyan kname = arg; 600201342Snyan } 601201342Snyan arg = p; 602201342Snyan } 603201342Snyan return 0; 604201342Snyan} 605201342Snyan 606201342Snyanstatic int 607201342Snyandskread(void *buf, unsigned lba, unsigned nblk) 608201342Snyan{ 609201342Snyan struct pc98_partition *dp; 610201342Snyan struct disklabel *d; 611201342Snyan char *sec; 612201342Snyan unsigned sl, i; 613201342Snyan u_char *p; 614201342Snyan 615201342Snyan if (!dsk_meta) { 616201342Snyan sec = dmadat->secbuf; 617201342Snyan set_dsk(); 618201342Snyan if (dsk.type == TYPE_FD) 619201342Snyan goto unsliced; 620201342Snyan if (drvread(sec, DOSBBSECTOR + 1)) 621201342Snyan return -1; 622201342Snyan dp = (void *)(sec + DOSPARTOFF); 623201342Snyan sl = dsk.slice; 624201342Snyan if (sl < BASE_SLICE) { 625201342Snyan for (i = 0; i < NDOSPART; i++) 626201342Snyan if (dp[i].dp_mid == DOSMID_386BSD) { 627201342Snyan sl = BASE_SLICE + i; 628201342Snyan break; 629201342Snyan } 630201342Snyan dsk.slice = sl; 631201342Snyan } 632201342Snyan if (sl != WHOLE_DISK_SLICE) { 633201342Snyan dp += sl - BASE_SLICE; 634201342Snyan if (dp->dp_mid != DOSMID_386BSD) { 635201342Snyan printf("Invalid %s\n", "slice"); 636201342Snyan return -1; 637201342Snyan } 638201342Snyan dsk.start = dp->dp_scyl * dsk.head * dsk.sec + 639201342Snyan dp->dp_shd * dsk.sec + dp->dp_ssect; 640201342Snyan } 641201342Snyan if (drvread(sec, dsk.start + LABELSECTOR)) 642201342Snyan return -1; 643201342Snyan d = (void *)(sec + LABELOFFSET); 644201342Snyan if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 645201342Snyan if (dsk.part != RAW_PART) { 646201342Snyan printf("Invalid %s\n", "label"); 647201342Snyan return -1; 648201342Snyan } 649201342Snyan } else { 650201342Snyan if (dsk.part >= d->d_npartitions || 651201342Snyan !d->d_partitions[dsk.part].p_size) { 652201342Snyan printf("Invalid %s\n", "partition"); 653201342Snyan return -1; 654201342Snyan } 655201342Snyan dsk.start += d->d_partitions[dsk.part].p_offset; 656201342Snyan dsk.start -= d->d_partitions[RAW_PART].p_offset; 657201342Snyan } 658201342Snyan unsliced: ; 659201342Snyan } 660201342Snyan for (p = buf; nblk; p += 512, lba++, nblk--) { 661201342Snyan if ((i = drvread(p, dsk.start + lba))) 662201342Snyan return i; 663201342Snyan } 664201342Snyan return 0; 665201342Snyan} 666201342Snyan 667201342Snyanstatic void 668201342Snyanprintf(const char *fmt,...) 669201342Snyan{ 670201342Snyan va_list ap; 671219960Snyan static char buf[10]; 672201342Snyan char *s; 673201342Snyan unsigned u; 674201342Snyan int c; 675201342Snyan 676201342Snyan va_start(ap, fmt); 677201342Snyan while ((c = *fmt++)) { 678201342Snyan if (c == '%') { 679201342Snyan c = *fmt++; 680201342Snyan switch (c) { 681201342Snyan case 'c': 682201342Snyan putchar(va_arg(ap, int)); 683201342Snyan continue; 684201342Snyan case 's': 685201342Snyan for (s = va_arg(ap, char *); *s; s++) 686201342Snyan putchar(*s); 687201342Snyan continue; 688201342Snyan case 'u': 689201342Snyan u = va_arg(ap, unsigned); 690201342Snyan s = buf; 691201342Snyan do 692201342Snyan *s++ = '0' + u % 10U; 693201342Snyan while (u /= 10U); 694201342Snyan while (--s >= buf) 695201342Snyan putchar(*s); 696201342Snyan continue; 697201342Snyan } 698201342Snyan } 699201342Snyan putchar(c); 700201342Snyan } 701201342Snyan va_end(ap); 702201342Snyan return; 703201342Snyan} 704201342Snyan 705201342Snyanstatic void 706201342Snyanputchar(int c) 707201342Snyan{ 708201342Snyan if (c == '\n') 709201342Snyan xputc('\r'); 710201342Snyan xputc(c); 711201342Snyan} 712201342Snyan 713201342Snyanstatic int 714201342Snyandrvread(void *buf, unsigned lba) 715201342Snyan{ 716201342Snyan static unsigned c = 0x2d5c7c2f; 717201342Snyan unsigned bpc, x, cyl, head, sec; 718201342Snyan 719201342Snyan bpc = dsk.sec * dsk.head; 720201342Snyan cyl = lba / bpc; 721201342Snyan x = lba % bpc; 722201342Snyan head = x / dsk.sec; 723201342Snyan sec = x % dsk.sec; 724201342Snyan 725201342Snyan if (!OPT_CHECK(RBX_QUIET)) 726201342Snyan printf("%c\b", c = c << 8 | c >> 24); 727201342Snyan v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 728201342Snyan v86.addr = READORG; /* call to read in boot1 */ 729201342Snyan v86.ecx = cyl; 730201342Snyan v86.edx = (head << 8) | sec; 731201342Snyan v86.edi = lba; 732201342Snyan v86.ebx = 512; 733201342Snyan v86.es = VTOPSEG(buf); 734201342Snyan v86.ebp = VTOPOFF(buf); 735201342Snyan v86int(); 736201342Snyan v86.ctl = V86_FLAGS; 737201342Snyan if (V86_CY(v86.efl)) { 738201342Snyan printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, 739201342Snyan cyl, head, sec, lba); 740201342Snyan return -1; 741201342Snyan } 742201342Snyan return 0; 743201342Snyan} 744201342Snyan 745201342Snyanstatic inline void 746201342Snyandelay(void) 747201342Snyan{ 748201342Snyan int i; 749201342Snyan 750201342Snyan i = 800; 751201342Snyan do { 752201342Snyan outb(0x5f, 0); /* about 600ns */ 753201342Snyan } while (--i >= 0); 754201342Snyan} 755201342Snyan 756201342Snyanstatic int 757201342Snyankeyhit(unsigned sec) 758201342Snyan{ 759201342Snyan unsigned i; 760201342Snyan 761201342Snyan if (OPT_CHECK(RBX_NOINTR)) 762201342Snyan return 0; 763201342Snyan for (i = 0; i < sec * 1000; i++) { 764201342Snyan if (xgetc(1)) 765201342Snyan return 1; 766201342Snyan delay(); 767201342Snyan } 768201342Snyan return 0; 769201342Snyan} 770201342Snyan 771201342Snyanstatic int 772201342Snyanxputc(int c) 773201342Snyan{ 774201342Snyan if (ioctrl & IO_KEYBOARD) 775201342Snyan putc(c); 776201342Snyan if (ioctrl & IO_SERIAL) 777201342Snyan sio_putc(c); 778201342Snyan return c; 779201342Snyan} 780201342Snyan 781201342Snyanstatic int 782201342Snyanxgetc(int fn) 783201342Snyan{ 784201342Snyan if (OPT_CHECK(RBX_NOINTR)) 785201342Snyan return 0; 786201342Snyan for (;;) { 787201342Snyan if (ioctrl & IO_KEYBOARD && getc(1)) 788201342Snyan return fn ? 1 : getc(0); 789201342Snyan if (ioctrl & IO_SERIAL && sio_ischar()) 790201342Snyan return fn ? 1 : sio_getc(); 791201342Snyan if (fn) 792201342Snyan return 0; 793201342Snyan } 794201342Snyan} 795201342Snyan 796201342Snyanstatic int 797201342Snyangetc(int fn) 798201342Snyan{ 799201342Snyan v86.addr = 0x18; 800201342Snyan v86.eax = fn << 8; 801201342Snyan v86int(); 802201342Snyan if (fn) 803201342Snyan return (v86.ebx >> 8) & 0x01; 804201342Snyan else 805201342Snyan return v86.eax & 0xff; 806201342Snyan} 807