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