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: stable/11/stand/pc98/boot2/boot2.c 333049 2018-04-27 02:39: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 30201342Snyan#include <stdarg.h> 31201342Snyan 32201342Snyan#include <a.out.h> 33201342Snyan 34201342Snyan#include <btxv86.h> 35201342Snyan 36201342Snyan#include "boot2.h" 37201342Snyan#include "lib.h" 38294765Simp#include "paths.h" 39294766Simp#include "rbx.h" 40201342Snyan 41268475Simp/* Define to 0 to omit serial support */ 42268475Simp#ifndef SERIAL 43268475Simp#define SERIAL 0 44268475Simp#endif 45268475Simp 46201342Snyan#define IO_KEYBOARD 1 47201342Snyan#define IO_SERIAL 2 48201342Snyan 49268475Simp#if SERIAL 50268475Simp#define DO_KBD (ioctrl & IO_KEYBOARD) 51268475Simp#define DO_SIO (ioctrl & IO_SERIAL) 52268475Simp#else 53268475Simp#define DO_KBD (1) 54268475Simp#define DO_SIO (0) 55268475Simp#endif 56268475Simp 57201342Snyan#define SECOND 1 /* Circa that many ticks in a second. */ 58201342Snyan 59201342Snyan#define ARGS 0x900 60201342Snyan#define NOPT 14 61201342Snyan#define NDEV 3 62201342Snyan 63201342Snyan#define DRV_DISK 0xf0 64201342Snyan#define DRV_UNIT 0x0f 65201342Snyan 66201342Snyan#define TYPE_AD 0 67201342Snyan#define TYPE_DA 1 68201342Snyan#define TYPE_FD 2 69201342Snyan 70201342Snyanextern uint32_t _end; 71201342Snyan 72201342Snyanstatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 73201342Snyanstatic const unsigned char flags[NOPT] = { 74333049Snyan RBX_DUAL, 75333049Snyan RBX_SERIAL, 76333049Snyan RBX_ASKNAME, 77333049Snyan RBX_CDROM, 78333049Snyan RBX_CONFIG, 79333049Snyan RBX_KDB, 80333049Snyan RBX_GDB, 81333049Snyan RBX_MUTE, 82333049Snyan RBX_NOINTR, 83333049Snyan RBX_PAUSE, 84333049Snyan RBX_QUIET, 85333049Snyan RBX_DFLTROOT, 86333049Snyan RBX_SINGLE, 87333049Snyan RBX_VERBOSE 88201342Snyan}; 89201342Snyan 90201342Snyanstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 91201342Snyanstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 92201342Snyanstatic const unsigned char dev_daua[NDEV] = {0x80, 0xa0, 0x90}; 93201342Snyan 94201342Snyanstatic struct dsk { 95333049Snyan unsigned daua; 96333049Snyan unsigned type; 97333049Snyan unsigned disk; 98333049Snyan unsigned unit; 99333049Snyan unsigned head; 100333049Snyan unsigned sec; 101333049Snyan uint8_t slice; 102333049Snyan uint8_t part; 103333049Snyan unsigned start; 104201342Snyan} dsk; 105232784Snyanstatic char cmd[512], cmddup[512], knamebuf[1024]; 106239063Snyanstatic const char *kname; 107294847Simpuint32_t opts; 108268475Simpstatic struct bootinfo bootinfo; 109268475Simp#if SERIAL 110201342Snyanstatic int comspeed = SIOSPD; 111219960Snyanstatic uint8_t ioctrl = IO_KEYBOARD; 112268475Simp#endif 113201342Snyan 114284885Snyanint main(void); 115201342Snyanvoid exit(int); 116201342Snyanstatic void load(void); 117201342Snyanstatic int parse(void); 118201342Snyanstatic int dskread(void *, unsigned, unsigned); 119201342Snyanstatic void printf(const char *,...); 120201342Snyanstatic void putchar(int); 121201342Snyanstatic int drvread(void *, unsigned); 122201342Snyanstatic int keyhit(unsigned); 123201342Snyanstatic int xputc(int); 124201342Snyanstatic int xgetc(int); 125220685Snyanstatic inline int getc(int); 126201342Snyan 127201342Snyanstatic void memcpy(void *, const void *, int); 128201342Snyanstatic void 129201342Snyanmemcpy(void *dst, const void *src, int len) 130201342Snyan{ 131333049Snyan const char *s = src; 132333049Snyan char *d = dst; 133201342Snyan 134333049Snyan while (len--) 135333049Snyan *d++ = *s++; 136201342Snyan} 137201342Snyan 138201342Snyanstatic inline int 139201342Snyanstrcmp(const char *s1, const char *s2) 140201342Snyan{ 141333049Snyan 142333049Snyan for (; *s1 == *s2 && *s1; s1++, s2++); 143333049Snyan return ((unsigned char)*s1 - (unsigned char)*s2); 144201342Snyan} 145201342Snyan 146201342Snyan#define UFS_SMALL_CGBASE 147201342Snyan#include "ufsread.c" 148201342Snyan 149201342Snyanstatic inline int 150235988Sglebxfsread(ufs_ino_t inode, void *buf, size_t nbyte) 151201342Snyan{ 152333049Snyan 153333049Snyan if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 154333049Snyan printf("Invalid %s\n", "format"); 155333049Snyan return (-1); 156333049Snyan } 157333049Snyan return (0); 158201342Snyan} 159201342Snyan 160201342Snyanstatic inline void 161201342Snyangetstr(void) 162201342Snyan{ 163333049Snyan char *s; 164333049Snyan int c; 165201342Snyan 166333049Snyan s = cmd; 167333049Snyan for (;;) { 168333049Snyan switch (c = xgetc(0)) { 169333049Snyan case 0: 170333049Snyan break; 171333049Snyan case '\177': 172333049Snyan case '\b': 173333049Snyan if (s > cmd) { 174333049Snyan s--; 175333049Snyan printf("\b \b"); 176333049Snyan } 177333049Snyan break; 178333049Snyan case '\n': 179333049Snyan case '\r': 180333049Snyan *s = 0; 181333049Snyan return; 182333049Snyan default: 183333049Snyan if (s - cmd < sizeof(cmd) - 1) 184333049Snyan *s++ = c; 185333049Snyan putchar(c); 186333049Snyan } 187201342Snyan } 188201342Snyan} 189201342Snyan 190201342Snyanstatic inline void 191201342Snyanputc(int c) 192201342Snyan{ 193201342Snyan 194333049Snyan v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 195333049Snyan v86.addr = PUTCORG; /* call to putc in boot1 */ 196333049Snyan v86.eax = c; 197333049Snyan v86int(); 198333049Snyan v86.ctl = V86_FLAGS; 199201342Snyan} 200201342Snyan 201201342Snyanstatic inline int 202201342Snyanis_scsi_hd(void) 203201342Snyan{ 204201342Snyan 205201342Snyan if ((*(u_char *)PTOV(0x482) >> dsk.unit) & 0x01) 206201342Snyan return 1; 207201342Snyan 208201342Snyan return 0; 209201342Snyan} 210201342Snyan 211201342Snyanstatic inline void 212201342Snyanfix_sector_size(void) 213201342Snyan{ 214201342Snyan u_char *p; 215201342Snyan 216201342Snyan p = (u_char *)PTOV(0x460 + dsk.unit * 4); /* SCSI equipment parameter */ 217201342Snyan 218201342Snyan if ((p[0] & 0x1f) == 7) { /* SCSI MO */ 219201342Snyan if (!(p[3] & 0x30)) { /* 256B / sector */ 220201342Snyan p[3] |= 0x10; /* forced set 512B / sector */ 221201342Snyan p[3 + 0xa1000] |= 0x10; 222201342Snyan } 223201342Snyan } 224201342Snyan} 225201342Snyan 226201342Snyanstatic inline uint32_t 227201342Snyanget_diskinfo(void) 228201342Snyan{ 229201342Snyan 230201342Snyan if (dsk.disk == 0x30) { /* 1440KB FD */ 231201342Snyan /* 80 cylinders, 2 heads, 18 sectors */ 232201342Snyan return (80 << 16) | (2 << 8) | 18; 233201342Snyan } else if (dsk.disk == 0x90) { /* 1200KB FD */ 234201342Snyan /* 80 cylinders, 2 heads, 15 sectors */ 235201342Snyan return (80 << 16) | (2 << 8) | 15; 236201342Snyan } else if (dsk.disk == 0x80 || is_scsi_hd()) { /* IDE or SCSI HDD */ 237201342Snyan v86.addr = 0x1b; 238201342Snyan v86.eax = 0x8400 | dsk.daua; 239201342Snyan v86int(); 240201342Snyan return (v86.ecx << 16) | v86.edx; 241201342Snyan } 242201342Snyan 243201342Snyan /* SCSI MO or CD */ 244201342Snyan fix_sector_size(); /* SCSI MO */ 245201342Snyan 246201342Snyan /* other SCSI devices */ 247201342Snyan return (65535 << 16) | (8 << 8) | 32; 248201342Snyan} 249201342Snyan 250201342Snyanstatic void 251201342Snyanset_dsk(void) 252201342Snyan{ 253201342Snyan uint32_t di; 254201342Snyan 255201342Snyan di = get_diskinfo(); 256201342Snyan 257201342Snyan dsk.head = (di >> 8) & 0xff; 258201342Snyan dsk.sec = di & 0xff; 259201342Snyan dsk.start = 0; 260201342Snyan} 261201342Snyan 262201342Snyan#ifdef GET_BIOSGEOM 263201342Snyanstatic uint32_t 264201342Snyanbd_getbigeom(int bunit) 265201342Snyan{ 266201342Snyan int hds = 0; 267201342Snyan int unit = 0x80; /* IDE HDD */ 268201342Snyan u_int addr = 0x55d; 269201342Snyan 270201342Snyan while (unit < 0xa7) { 271201342Snyan if (*(u_char *)PTOV(addr) & (1 << (unit & 0x0f))) 272201342Snyan if (hds++ == bunit) 273201342Snyan break; 274201342Snyan 275201342Snyan if (unit >= 0xA0) { 276201342Snyan int media = ((unsigned *)PTOV(0x460))[unit & 0x0F] & 0x1F; 277201342Snyan 278201342Snyan if (media == 7 && hds++ == bunit) /* SCSI MO */ 279201342Snyan return(0xFFFE0820); /* C:65535 H:8 S:32 */ 280201342Snyan } 281201342Snyan if (++unit == 0x84) { 282201342Snyan unit = 0xA0; /* SCSI HDD */ 283201342Snyan addr = 0x482; 284201342Snyan } 285201342Snyan } 286201342Snyan if (unit == 0xa7) 287201342Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 288201342Snyan v86.addr = 0x1b; 289201342Snyan v86.eax = 0x8400 | unit; 290201342Snyan v86int(); 291292682Sjhb if (V86_CY(v86.efl)) 292201342Snyan return 0x4F020F; /* 1200KB FD C:80 H:2 S:15 */ 293201342Snyan return ((v86.ecx & 0xffff) << 16) | (v86.edx & 0xffff); 294201342Snyan} 295201342Snyan#endif 296201342Snyan 297201342Snyanstatic int 298201342Snyancheck_slice(void) 299201342Snyan{ 300201342Snyan struct pc98_partition *dp; 301201342Snyan char *sec; 302201342Snyan unsigned i, cyl; 303201342Snyan 304201342Snyan sec = dmadat->secbuf; 305201342Snyan cyl = *(uint16_t *)PTOV(ARGS); 306201342Snyan set_dsk(); 307201342Snyan 308201342Snyan if (dsk.type == TYPE_FD) 309201342Snyan return (WHOLE_DISK_SLICE); 310254015Smarcel if (drvread(sec, PC98_BBSECTOR)) 311201342Snyan return (WHOLE_DISK_SLICE); /* Read error */ 312254015Smarcel dp = (void *)(sec + PC98_PARTOFF); 313254015Smarcel for (i = 0; i < PC98_NPARTS; i++) { 314201342Snyan if (dp[i].dp_mid == DOSMID_386BSD) { 315201342Snyan if (dp[i].dp_scyl <= cyl && cyl <= dp[i].dp_ecyl) 316201342Snyan return (BASE_SLICE + i); 317201342Snyan } 318201342Snyan } 319201342Snyan 320201342Snyan return (WHOLE_DISK_SLICE); 321201342Snyan} 322201342Snyan 323201342Snyanint 324201342Snyanmain(void) 325201342Snyan{ 326201342Snyan#ifdef GET_BIOSGEOM 327333049Snyan int i; 328201342Snyan#endif 329333049Snyan uint8_t autoboot; 330333049Snyan ufs_ino_t ino; 331333049Snyan size_t nbyte; 332201342Snyan 333333049Snyan dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 334333049Snyan v86.ctl = V86_FLAGS; 335333049Snyan v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 336333049Snyan dsk.daua = *(uint8_t *)PTOV(0x584); 337333049Snyan dsk.disk = dsk.daua & DRV_DISK; 338333049Snyan dsk.unit = dsk.daua & DRV_UNIT; 339333049Snyan if (dsk.disk == 0x80) 340333049Snyan dsk.type = TYPE_AD; 341333049Snyan else if (dsk.disk == 0xa0) 342333049Snyan dsk.type = TYPE_DA; 343333049Snyan else /* if (dsk.disk == 0x30 || dsk.disk == 0x90) */ 344333049Snyan dsk.type = TYPE_FD; 345333049Snyan dsk.slice = check_slice(); 346201342Snyan#ifdef GET_BIOSGEOM 347333049Snyan for (i = 0; i < N_BIOS_GEOM; i++) 348333049Snyan bootinfo.bi_bios_geom[i] = bd_getbigeom(i); 349201342Snyan#endif 350333049Snyan bootinfo.bi_version = BOOTINFO_VERSION; 351333049Snyan bootinfo.bi_size = sizeof(bootinfo); 352201342Snyan 353333049Snyan /* Process configuration file */ 354201342Snyan 355333049Snyan autoboot = 1; 356201342Snyan 357333049Snyan if ((ino = lookup(PATH_CONFIG)) || 358333049Snyan (ino = lookup(PATH_DOTCONFIG))) { 359333049Snyan nbyte = fsread(ino, cmd, sizeof(cmd) - 1); 360333049Snyan cmd[nbyte] = '\0'; 361333049Snyan } 362201342Snyan 363333049Snyan if (*cmd) { 364333049Snyan memcpy(cmddup, cmd, sizeof(cmd)); 365333049Snyan if (parse()) 366333049Snyan autoboot = 0; 367333049Snyan if (!OPT_CHECK(RBX_QUIET)) 368333049Snyan printf("%s: %s", PATH_CONFIG, cmddup); 369333049Snyan /* Do not process this command twice */ 370333049Snyan *cmd = 0; 371333049Snyan } 372201342Snyan 373333049Snyan /* 374333049Snyan * Try to exec stage 3 boot loader. If interrupted by a keypress, 375333049Snyan * or in case of failure, try to load a kernel directly instead. 376333049Snyan */ 377201342Snyan 378333049Snyan if (!kname) { 379333049Snyan kname = PATH_LOADER; 380333049Snyan if (autoboot && !keyhit(3*SECOND)) { 381333049Snyan load(); 382333049Snyan kname = PATH_KERNEL; 383333049Snyan } 384201342Snyan } 385201342Snyan 386333049Snyan /* Present the user with the boot2 prompt. */ 387201342Snyan 388333049Snyan for (;;) { 389333049Snyan if (!autoboot || !OPT_CHECK(RBX_QUIET)) 390333049Snyan printf("\nFreeBSD/pc98 boot\n" 391333049Snyan "Default: %u:%s(%u,%c)%s\n" 392333049Snyan "boot: ", 393333049Snyan dsk.unit, dev_nm[dsk.type], dsk.unit, 394333049Snyan 'a' + dsk.part, kname); 395333049Snyan if (DO_SIO) 396333049Snyan sio_flush(); 397333049Snyan if (!autoboot || keyhit(3*SECOND)) 398333049Snyan getstr(); 399333049Snyan else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 400333049Snyan putchar('\n'); 401333049Snyan autoboot = 0; 402333049Snyan if (parse()) 403333049Snyan putchar('\a'); 404333049Snyan else 405333049Snyan load(); 406333049Snyan } 407201342Snyan} 408201342Snyan 409201342Snyan/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 410201342Snyanvoid 411201342Snyanexit(int x) 412201342Snyan{ 413333049Snyan 414201342Snyan} 415201342Snyan 416201342Snyanstatic void 417201342Snyanload(void) 418201342Snyan{ 419333049Snyan union { 420333049Snyan struct exec ex; 421333049Snyan Elf32_Ehdr eh; 422333049Snyan } hdr; 423333049Snyan static Elf32_Phdr ep[2]; 424333049Snyan static Elf32_Shdr es[2]; 425333049Snyan caddr_t p; 426333049Snyan ufs_ino_t ino; 427333049Snyan uint32_t addr; 428333049Snyan int k; 429333049Snyan uint8_t i, j; 430201342Snyan 431333049Snyan if (!(ino = lookup(kname))) { 432333049Snyan if (!ls) 433333049Snyan printf("No %s\n", kname); 434201342Snyan return; 435201342Snyan } 436333049Snyan if (xfsread(ino, &hdr, sizeof(hdr))) 437201342Snyan return; 438333049Snyan 439333049Snyan if (N_GETMAGIC(hdr.ex) == ZMAGIC) { 440333049Snyan addr = hdr.ex.a_entry & 0xffffff; 441333049Snyan p = PTOV(addr); 442333049Snyan fs_off = PAGE_SIZE; 443333049Snyan if (xfsread(ino, p, hdr.ex.a_text)) 444333049Snyan return; 445333049Snyan p += roundup2(hdr.ex.a_text, PAGE_SIZE); 446333049Snyan if (xfsread(ino, p, hdr.ex.a_data)) 447333049Snyan return; 448333049Snyan } else if (IS_ELF(hdr.eh)) { 449333049Snyan fs_off = hdr.eh.e_phoff; 450333049Snyan for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { 451333049Snyan if (xfsread(ino, ep + j, sizeof(ep[0]))) 452333049Snyan return; 453333049Snyan if (ep[j].p_type == PT_LOAD) 454333049Snyan j++; 455333049Snyan } 456333049Snyan for (i = 0; i < 2; i++) { 457333049Snyan p = PTOV(ep[i].p_paddr & 0xffffff); 458333049Snyan fs_off = ep[i].p_offset; 459333049Snyan if (xfsread(ino, p, ep[i].p_filesz)) 460333049Snyan return; 461333049Snyan } 462333049Snyan p += roundup2(ep[1].p_memsz, PAGE_SIZE); 463333049Snyan bootinfo.bi_symtab = VTOP(p); 464333049Snyan if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 465333049Snyan fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 466333049Snyan (hdr.eh.e_shstrndx + 1); 467333049Snyan if (xfsread(ino, &es, sizeof(es))) 468333049Snyan return; 469333049Snyan for (i = 0; i < 2; i++) { 470333049Snyan *(Elf32_Word *)p = es[i].sh_size; 471333049Snyan p += sizeof(es[i].sh_size); 472333049Snyan fs_off = es[i].sh_offset; 473333049Snyan if (xfsread(ino, p, es[i].sh_size)) 474333049Snyan return; 475333049Snyan p += es[i].sh_size; 476333049Snyan } 477333049Snyan } 478333049Snyan addr = hdr.eh.e_entry & 0xffffff; 479333049Snyan bootinfo.bi_esymtab = VTOP(p); 480333049Snyan } else { 481333049Snyan printf("Invalid %s\n", "format"); 482201342Snyan return; 483201342Snyan } 484219960Snyan 485333049Snyan bootinfo.bi_kernelname = VTOP(kname); 486333049Snyan bootinfo.bi_bios_dev = dsk.daua; 487333049Snyan __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 488333049Snyan MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 489333049Snyan 0, 0, 0, VTOP(&bootinfo)); 490201342Snyan} 491201342Snyan 492201342Snyanstatic int 493201342Snyanparse() 494201342Snyan{ 495333049Snyan char *arg = cmd; 496333049Snyan char *ep, *p, *q; 497333049Snyan const char *cp; 498333049Snyan unsigned int drv; 499333049Snyan int c, i, j; 500333049Snyan size_t k; 501201342Snyan 502333049Snyan while ((c = *arg++)) { 503333049Snyan if (c == ' ' || c == '\t' || c == '\n') 504333049Snyan continue; 505333049Snyan for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 506333049Snyan ep = p; 507333049Snyan if (*p) 508333049Snyan *p++ = 0; 509333049Snyan if (c == '-') { 510333049Snyan while ((c = *arg++)) { 511333049Snyan if (c == 'P') { 512333049Snyan if (*(uint8_t *)PTOV(0x481) & 0x48) { 513333049Snyan cp = "yes"; 514333049Snyan } else { 515333049Snyan opts |= OPT_SET(RBX_DUAL) | 516333049Snyan OPT_SET(RBX_SERIAL); 517333049Snyan cp = "no"; 518333049Snyan } 519333049Snyan printf("Keyboard: %s\n", cp); 520333049Snyan continue; 521268475Simp#if SERIAL 522333049Snyan } else if (c == 'S') { 523333049Snyan j = 0; 524333049Snyan while ((unsigned int)(i = *arg++ - '0') <= 9) 525333049Snyan j = j * 10 + i; 526333049Snyan if (j > 0 && i == -'0') { 527333049Snyan comspeed = j; 528333049Snyan break; 529333049Snyan } 530333049Snyan /* 531333049Snyan * Fall through to error below 532333049Snyan * ('S' not in optstr[]). 533333049Snyan */ 534268475Simp#endif 535333049Snyan } 536333049Snyan for (i = 0; c != optstr[i]; i++) 537333049Snyan if (i == NOPT - 1) 538333049Snyan return (-1); 539333049Snyan opts ^= OPT_SET(flags[i]); 540333049Snyan } 541268475Simp#if SERIAL 542333049Snyan ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 543333049Snyan OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 544333049Snyan if (DO_SIO) { 545333049Snyan if (sio_init(115200 / comspeed) != 0) 546333049Snyan ioctrl &= ~IO_SERIAL; 547333049Snyan } 548268475Simp#endif 549333049Snyan } else { 550333049Snyan for (q = arg--; *q && *q != '('; q++); 551333049Snyan if (*q) { 552333049Snyan drv = -1; 553333049Snyan if (arg[1] == ':') { 554333049Snyan drv = *arg - '0'; 555333049Snyan if (drv > 9) 556333049Snyan return (-1); 557333049Snyan arg += 2; 558333049Snyan } 559333049Snyan if (q - arg != 2) 560333049Snyan return (-1); 561333049Snyan for (i = 0; arg[0] != dev_nm[i][0] || 562333049Snyan arg[1] != dev_nm[i][1]; i++) 563333049Snyan if (i == NDEV - 1) 564333049Snyan return (-1); 565333049Snyan dsk.type = i; 566333049Snyan arg += 3; 567333049Snyan dsk.unit = *arg - '0'; 568333049Snyan if (arg[1] != ',' || dsk.unit > 9) 569333049Snyan return (-1); 570333049Snyan arg += 2; 571333049Snyan dsk.slice = WHOLE_DISK_SLICE; 572333049Snyan if (arg[1] == ',') { 573333049Snyan dsk.slice = *arg - '0' + 1; 574333049Snyan if (dsk.slice > PC98_NPARTS + 1) 575333049Snyan return (-1); 576333049Snyan arg += 2; 577333049Snyan } 578333049Snyan if (arg[1] != ')') 579333049Snyan return (-1); 580333049Snyan dsk.part = *arg - 'a'; 581333049Snyan if (dsk.part > 7) 582333049Snyan return (-1); 583333049Snyan arg += 2; 584333049Snyan if (drv == -1) 585333049Snyan drv = dsk.unit; 586333049Snyan dsk.disk = dev_daua[dsk.type]; 587333049Snyan dsk.daua = dsk.disk | dsk.unit; 588333049Snyan dsk_meta = 0; 589333049Snyan } 590333049Snyan k = ep - arg; 591333049Snyan if (k > 0) { 592333049Snyan if (k >= sizeof(knamebuf)) 593333049Snyan return (-1); 594333049Snyan memcpy(knamebuf, arg, k + 1); 595333049Snyan kname = knamebuf; 596333049Snyan } 597201342Snyan } 598333049Snyan arg = p; 599201342Snyan } 600333049Snyan return (0); 601201342Snyan} 602201342Snyan 603201342Snyanstatic int 604201342Snyandskread(void *buf, unsigned lba, unsigned nblk) 605201342Snyan{ 606333049Snyan struct pc98_partition *dp; 607333049Snyan struct disklabel *d; 608333049Snyan char *sec; 609333049Snyan unsigned i; 610333049Snyan uint8_t sl; 611333049Snyan u_char *p; 612333049Snyan const char *reason; 613201342Snyan 614333049Snyan if (!dsk_meta) { 615333049Snyan sec = dmadat->secbuf; 616333049Snyan set_dsk(); 617333049Snyan if (dsk.type == TYPE_FD) 618333049Snyan goto unsliced; 619333049Snyan if (drvread(sec, PC98_BBSECTOR)) 620333049Snyan return -1; 621333049Snyan dp = (void *)(sec + PC98_PARTOFF); 622333049Snyan sl = dsk.slice; 623333049Snyan if (sl < BASE_SLICE) { 624333049Snyan for (i = 0; i < PC98_NPARTS; i++) 625333049Snyan if (dp[i].dp_mid == DOSMID_386BSD) { 626333049Snyan sl = BASE_SLICE + i; 627333049Snyan break; 628333049Snyan } 629333049Snyan dsk.slice = sl; 630201342Snyan } 631333049Snyan if (sl != WHOLE_DISK_SLICE) { 632333049Snyan dp += sl - BASE_SLICE; 633333049Snyan if (dp->dp_mid != DOSMID_386BSD) { 634333049Snyan reason = "slice"; 635333049Snyan goto error; 636333049Snyan } 637333049Snyan dsk.start = dp->dp_scyl * dsk.head * dsk.sec + 638333049Snyan dp->dp_shd * dsk.sec + dp->dp_ssect; 639333049Snyan } 640333049Snyan if (drvread(sec, dsk.start + LABELSECTOR)) 641333049Snyan return -1; 642333049Snyan d = (void *)(sec + LABELOFFSET); 643333049Snyan if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 644333049Snyan if (dsk.part != RAW_PART) { 645333049Snyan reason = "label"; 646333049Snyan goto error; 647333049Snyan } 648333049Snyan } else { 649333049Snyan if (dsk.part >= d->d_npartitions || 650333049Snyan !d->d_partitions[dsk.part].p_size) { 651333049Snyan reason = "partition"; 652333049Snyan goto error; 653333049Snyan } 654333049Snyan dsk.start += d->d_partitions[dsk.part].p_offset; 655333049Snyan dsk.start -= d->d_partitions[RAW_PART].p_offset; 656333049Snyan } 657333049Snyan unsliced: ; 658201342Snyan } 659333049Snyan for (p = buf; nblk; p += 512, lba++, nblk--) { 660333049Snyan if ((i = drvread(p, dsk.start + lba))) 661333049Snyan return (i); 662201342Snyan } 663333049Snyan return (0); 664275239Snyanerror: 665333049Snyan printf("Invalid %s\n", reason); 666333049Snyan return (-1); 667201342Snyan} 668201342Snyan 669201342Snyanstatic void 670201342Snyanprintf(const char *fmt,...) 671201342Snyan{ 672333049Snyan va_list ap; 673333049Snyan static char buf[10]; 674333049Snyan char *s; 675333049Snyan unsigned u; 676333049Snyan int c; 677201342Snyan 678333049Snyan va_start(ap, fmt); 679333049Snyan while ((c = *fmt++)) { 680333049Snyan if (c == '%') { 681333049Snyan c = *fmt++; 682333049Snyan switch (c) { 683333049Snyan case 'c': 684333049Snyan putchar(va_arg(ap, int)); 685333049Snyan continue; 686333049Snyan case 's': 687333049Snyan for (s = va_arg(ap, char *); *s; s++) 688333049Snyan putchar(*s); 689333049Snyan continue; 690333049Snyan case 'u': 691333049Snyan u = va_arg(ap, unsigned); 692333049Snyan s = buf; 693333049Snyan do 694333049Snyan *s++ = '0' + u % 10U; 695333049Snyan while (u /= 10U); 696333049Snyan while (--s >= buf) 697333049Snyan putchar(*s); 698333049Snyan continue; 699333049Snyan } 700333049Snyan } 701333049Snyan putchar(c); 702201342Snyan } 703333049Snyan va_end(ap); 704333049Snyan return; 705201342Snyan} 706201342Snyan 707201342Snyanstatic void 708201342Snyanputchar(int c) 709201342Snyan{ 710333049Snyan 711333049Snyan if (c == '\n') 712333049Snyan xputc('\r'); 713333049Snyan xputc(c); 714201342Snyan} 715201342Snyan 716201342Snyanstatic int 717201342Snyandrvread(void *buf, unsigned lba) 718201342Snyan{ 719333049Snyan static unsigned c = 0x2d5c7c2f; 720333049Snyan unsigned bpc, x, cyl, head, sec; 721201342Snyan 722333049Snyan bpc = dsk.sec * dsk.head; 723333049Snyan cyl = lba / bpc; 724333049Snyan x = lba % bpc; 725333049Snyan head = x / dsk.sec; 726333049Snyan sec = x % dsk.sec; 727333049Snyan 728333049Snyan if (!OPT_CHECK(RBX_QUIET)) { 729333049Snyan xputc(c = c << 8 | c >> 24); 730333049Snyan xputc('\b'); 731333049Snyan } 732333049Snyan v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 733333049Snyan v86.addr = READORG; /* call to read in boot1 */ 734333049Snyan v86.ecx = cyl; 735333049Snyan v86.edx = (head << 8) | sec; 736333049Snyan v86.edi = lba; 737333049Snyan v86.ebx = 512; 738333049Snyan v86.es = VTOPSEG(buf); 739333049Snyan v86.ebp = VTOPOFF(buf); 740333049Snyan v86int(); 741333049Snyan v86.ctl = V86_FLAGS; 742333049Snyan if (V86_CY(v86.efl)) { 743333049Snyan printf("error %u c/h/s %u/%u/%u lba %u\n", v86.eax >> 8 & 0xff, 744333049Snyan cyl, head, sec, lba); 745333049Snyan return (-1); 746333049Snyan } 747333049Snyan return (0); 748201342Snyan} 749201342Snyan 750201342Snyanstatic inline void 751201342Snyandelay(void) 752201342Snyan{ 753333049Snyan int i; 754201342Snyan 755333049Snyan i = 800; 756333049Snyan do { 757333049Snyan outb(0x5f, 0); /* about 600ns */ 758333049Snyan } while (--i >= 0); 759201342Snyan} 760201342Snyan 761201342Snyanstatic int 762201342Snyankeyhit(unsigned sec) 763201342Snyan{ 764333049Snyan unsigned i; 765201342Snyan 766333049Snyan if (OPT_CHECK(RBX_NOINTR)) 767333049Snyan return (0); 768333049Snyan for (i = 0; i < sec * 1000; i++) { 769333049Snyan if (xgetc(1)) 770333049Snyan return (1); 771333049Snyan delay(); 772333049Snyan } 773333049Snyan return (0); 774201342Snyan} 775201342Snyan 776201342Snyanstatic int 777201342Snyanxputc(int c) 778201342Snyan{ 779333049Snyan 780333049Snyan if (DO_KBD) 781333049Snyan putc(c); 782333049Snyan if (DO_SIO) 783333049Snyan sio_putc(c); 784333049Snyan return (c); 785201342Snyan} 786201342Snyan 787201342Snyanstatic int 788220685Snyangetc(int fn) 789220685Snyan{ 790333049Snyan 791333049Snyan v86.addr = 0x18; 792333049Snyan v86.eax = fn << 8; 793333049Snyan v86int(); 794333049Snyan if (fn) 795333049Snyan return ((v86.ebx >> 8) & 0x01); 796333049Snyan else 797333049Snyan return (v86.eax & 0xff); 798220685Snyan} 799220685Snyan 800220685Snyanstatic int 801201342Snyanxgetc(int fn) 802201342Snyan{ 803333049Snyan 804333049Snyan if (OPT_CHECK(RBX_NOINTR)) 805333049Snyan return (0); 806333049Snyan for (;;) { 807333049Snyan if (DO_KBD && getc(1)) 808333049Snyan return (fn ? 1 : getc(0)); 809333049Snyan if (DO_SIO && sio_ischar()) 810333049Snyan return (fn ? 1 : sio_getc()); 811333049Snyan if (fn) 812333049Snyan return (0); 813333049Snyan } 814201342Snyan} 815