1119482Sobrien/*- 240269Srnordier * Copyright (c) 1998 Robert Nordier 340269Srnordier * All rights reserved. 440269Srnordier * 540269Srnordier * Redistribution and use in source and binary forms are freely 640269Srnordier * permitted provided that the above copyright notice and this 740269Srnordier * paragraph and the following disclaimer are duplicated in all 840269Srnordier * such forms. 940269Srnordier * 1040269Srnordier * This software is provided "AS IS" and without any express or 1140269Srnordier * implied warranties, including, without limitation, the implied 1240269Srnordier * warranties of merchantability and fitness for a particular 1340269Srnordier * purpose. 1440269Srnordier */ 1540269Srnordier 16119482Sobrien#include <sys/cdefs.h> 17119482Sobrien__FBSDID("$FreeBSD: stable/11/stand/i386/boot2/boot2.c 332130 2018-04-06 18:55:02Z kevans $"); 1840269Srnordier 1940269Srnordier#include <sys/param.h> 2040269Srnordier#include <sys/disklabel.h> 21104272Sphk#include <sys/diskmbr.h> 2240269Srnordier#include <sys/dirent.h> 23122463Sbde#include <sys/reboot.h> 24122463Sbde 2540269Srnordier#include <machine/bootinfo.h> 2676224Sobrien#include <machine/elf.h> 2740269Srnordier 2840269Srnordier#include <stdarg.h> 2940269Srnordier 3040269Srnordier#include <a.out.h> 3140269Srnordier 3240269Srnordier#include <btxv86.h> 3340269Srnordier 3480751Sjhb#include "boot2.h" 3540404Srnordier#include "lib.h" 36294765Simp#include "paths.h" 37294766Simp#include "rbx.h" 3840404Srnordier 39268475Simp/* Define to 0 to omit serial support */ 40268475Simp#ifndef SERIAL 41268475Simp#define SERIAL 1 42268475Simp#endif 43268475Simp 4494411Spb#define IO_KEYBOARD 1 4594411Spb#define IO_SERIAL 2 4694411Spb 47268475Simp#if SERIAL 48268475Simp#define DO_KBD (ioctrl & IO_KEYBOARD) 49268475Simp#define DO_SIO (ioctrl & IO_SERIAL) 50268475Simp#else 51268475Simp#define DO_KBD (1) 52268475Simp#define DO_SIO (0) 53268475Simp#endif 54268475Simp 5594411Spb#define SECOND 18 /* Circa that many ticks in a second. */ 5694411Spb 5742478Speter#define ARGS 0x900 58163707Sru#define NOPT 14 59108000Simp#define NDEV 3 6040269Srnordier#define MEM_BASE 0x12 6140269Srnordier#define MEM_EXT 0x15 6240269Srnordier 6340307Srnordier#define DRV_HARD 0x80 6440307Srnordier#define DRV_MASK 0x7f 6540307Srnordier 6657090Sru#define TYPE_AD 0 67108000Simp#define TYPE_DA 1 6898542Smckusick#define TYPE_MAXHARD TYPE_DA 69108000Simp#define TYPE_FD 2 7040307Srnordier 7140269Srnordierextern uint32_t _end; 7240269Srnordier 73163707Srustatic const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 7440269Srnordierstatic const unsigned char flags[NOPT] = { 75332130Skevans RBX_DUAL, 76332130Skevans RBX_SERIAL, 77332130Skevans RBX_ASKNAME, 78332130Skevans RBX_CDROM, 79332130Skevans RBX_CONFIG, 80332130Skevans RBX_KDB, 81332130Skevans RBX_GDB, 82332130Skevans RBX_MUTE, 83332130Skevans RBX_NOINTR, 84332130Skevans RBX_PAUSE, 85332130Skevans RBX_QUIET, 86332130Skevans RBX_DFLTROOT, 87332130Skevans RBX_SINGLE, 88332130Skevans RBX_VERBOSE 8940269Srnordier}; 9040269Srnordier 91108000Simpstatic const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; 92108000Simpstatic const unsigned char dev_maj[NDEV] = {30, 4, 2}; 9340269Srnordier 9440269Srnordierstatic struct dsk { 95332130Skevans unsigned drive; 96332130Skevans unsigned type; 97332130Skevans unsigned unit; 98332130Skevans uint8_t slice; 99332130Skevans uint8_t part; 100332130Skevans unsigned start; 101332130Skevans int init; 10240269Srnordier} dsk; 103232570Sjhbstatic char cmd[512], cmddup[512], knamebuf[1024]; 104236405Sjhbstatic const char *kname; 105294766Simpuint32_t opts; 106268475Simpstatic struct bootinfo bootinfo; 107268475Simp#if SERIAL 108149212Siedowsestatic int comspeed = SIOSPD; 109219452Srdivackystatic uint8_t ioctrl = IO_KEYBOARD; 110268475Simp#endif 11140269Srnordier 112284878Sdelphijint main(void); 11340269Srnordiervoid exit(int); 114108000Simpstatic void load(void); 115108000Simpstatic int parse(void); 11640269Srnordierstatic int dskread(void *, unsigned, unsigned); 117104679Sphkstatic void printf(const char *,...); 118104679Sphkstatic void putchar(int); 11940269Srnordierstatic int drvread(void *, unsigned, unsigned); 12040269Srnordierstatic int keyhit(unsigned); 12140404Srnordierstatic int xputc(int); 12240404Srnordierstatic int xgetc(int); 123220389Srdivackystatic inline int getc(int); 12440269Srnordier 125132864Skanstatic void memcpy(void *, const void *, int); 126126891Strhodesstatic void 127132864Skanmemcpy(void *dst, const void *src, int len) 128126891Strhodes{ 129332130Skevans const char *s; 130332130Skevans char *d; 131132864Skan 132332130Skevans s = src; 133332130Skevans d = dst; 134332130Skevans 135332130Skevans while (len--) 136332130Skevans *d++ = *s++; 137126891Strhodes} 13862665Sjhb 13962665Sjhbstatic inline int 14062665Sjhbstrcmp(const char *s1, const char *s2) 14162665Sjhb{ 142332130Skevans 143332130Skevans for (; *s1 == *s2 && *s1; s1++, s2++); 144332130Skevans return ((unsigned char)*s1 - (unsigned char)*s2); 14562665Sjhb} 14662665Sjhb 147173040Sjhb#define UFS_SMALL_CGBASE 14897860Sphk#include "ufsread.c" 14962665Sjhb 150329099Skevansstatic int 151235988Sglebxfsread(ufs_ino_t inode, void *buf, size_t nbyte) 15262665Sjhb{ 153332130Skevans 154332130Skevans if ((size_t)fsread(inode, buf, nbyte) != nbyte) { 155332130Skevans printf("Invalid %s\n", "format"); 156332130Skevans return (-1); 157332130Skevans } 158332130Skevans return (0); 15962665Sjhb} 16062665Sjhb 16162665Sjhbstatic inline void 162108000Simpgetstr(void) 16362665Sjhb{ 164332130Skevans char *s; 165332130Skevans int c; 16662665Sjhb 167332130Skevans s = cmd; 168332130Skevans for (;;) { 169332130Skevans switch (c = xgetc(0)) { 170332130Skevans case 0: 171332130Skevans break; 172332130Skevans case '\177': 173332130Skevans case '\b': 174332130Skevans if (s > cmd) { 175332130Skevans s--; 176332130Skevans printf("\b \b"); 177332130Skevans } 178332130Skevans break; 179332130Skevans case '\n': 180332130Skevans case '\r': 181332130Skevans *s = 0; 182332130Skevans return; 183332130Skevans default: 184332130Skevans if (s - cmd < sizeof(cmd) - 1) 185332130Skevans *s++ = c; 186332130Skevans putchar(c); 187332130Skevans } 18862665Sjhb } 18962665Sjhb} 19062665Sjhb 19162665Sjhbstatic inline void 19262665Sjhbputc(int c) 19362665Sjhb{ 194332130Skevans 195332130Skevans v86.addr = 0x10; 196332130Skevans v86.eax = 0xe00 | (c & 0xff); 197332130Skevans v86.ebx = 0x7; 198332130Skevans v86int(); 19962665Sjhb} 20062665Sjhb 20140269Srnordierint 20240269Srnordiermain(void) 20340269Srnordier{ 204332130Skevans uint8_t autoboot; 205332130Skevans ufs_ino_t ino; 206332130Skevans size_t nbyte; 20740269Srnordier 208332130Skevans dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); 209332130Skevans v86.ctl = V86_FLAGS; 210332130Skevans v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 211332130Skevans dsk.drive = *(uint8_t *)PTOV(ARGS); 212332130Skevans dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; 213332130Skevans dsk.unit = dsk.drive & DRV_MASK; 214332130Skevans dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; 215332130Skevans bootinfo.bi_version = BOOTINFO_VERSION; 216332130Skevans bootinfo.bi_size = sizeof(bootinfo); 21794411Spb 218332130Skevans /* Process configuration file */ 21994411Spb 220332130Skevans autoboot = 1; 22198542Smckusick 222332130Skevans if ((ino = lookup(PATH_CONFIG)) || 223332130Skevans (ino = lookup(PATH_DOTCONFIG))) { 224332130Skevans nbyte = fsread(ino, cmd, sizeof(cmd) - 1); 225332130Skevans cmd[nbyte] = '\0'; 226332130Skevans } 22798542Smckusick 228332130Skevans if (*cmd) { 229332130Skevans memcpy(cmddup, cmd, sizeof(cmd)); 230332130Skevans if (parse()) 231332130Skevans autoboot = 0; 232332130Skevans if (!OPT_CHECK(RBX_QUIET)) 233332130Skevans printf("%s: %s", PATH_CONFIG, cmddup); 234332130Skevans /* Do not process this command twice */ 235332130Skevans *cmd = 0; 236332130Skevans } 23794411Spb 238332130Skevans /* 239332130Skevans * Try to exec stage 3 boot loader. If interrupted by a keypress, 240332130Skevans * or in case of failure, try to load a kernel directly instead. 241332130Skevans */ 24294411Spb 243332130Skevans if (!kname) { 244332130Skevans kname = PATH_LOADER; 245332130Skevans if (autoboot && !keyhit(3*SECOND)) { 246332130Skevans load(); 247332130Skevans kname = PATH_KERNEL; 248332130Skevans } 24940269Srnordier } 25094411Spb 251332130Skevans /* Present the user with the boot2 prompt. */ 25294411Spb 253332130Skevans for (;;) { 254332130Skevans if (!autoboot || !OPT_CHECK(RBX_QUIET)) 255332130Skevans printf("\nFreeBSD/x86 boot\n" 256332130Skevans "Default: %u:%s(%u,%c)%s\n" 257332130Skevans "boot: ", 258332130Skevans dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, 259332130Skevans 'a' + dsk.part, kname); 260332130Skevans if (DO_SIO) 261332130Skevans sio_flush(); 262332130Skevans if (!autoboot || keyhit(3*SECOND)) 263332130Skevans getstr(); 264332130Skevans else if (!autoboot || !OPT_CHECK(RBX_QUIET)) 265332130Skevans putchar('\n'); 266332130Skevans autoboot = 0; 267332130Skevans if (parse()) 268332130Skevans putchar('\a'); 269332130Skevans else 270332130Skevans load(); 271332130Skevans } 27240269Srnordier} 27340269Srnordier 27462665Sjhb/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 27540269Srnordiervoid 27640269Srnordierexit(int x) 27740269Srnordier{ 278332130Skevans 27940269Srnordier} 28040269Srnordier 28140269Srnordierstatic void 282108000Simpload(void) 28340269Srnordier{ 284332130Skevans union { 285332130Skevans struct exec ex; 286332130Skevans Elf32_Ehdr eh; 287332130Skevans } hdr; 288332130Skevans static Elf32_Phdr ep[2]; 289332130Skevans static Elf32_Shdr es[2]; 290332130Skevans caddr_t p; 291332130Skevans ufs_ino_t ino; 292332130Skevans uint32_t addr; 293332130Skevans int k; 294332130Skevans uint8_t i, j; 29540269Srnordier 296332130Skevans if (!(ino = lookup(kname))) { 297332130Skevans if (!ls) 298332130Skevans printf("No %s\n", kname); 29940269Srnordier return; 30040269Srnordier } 301332130Skevans if (xfsread(ino, &hdr, sizeof(hdr))) 30240269Srnordier return; 303332130Skevans 304332130Skevans if (N_GETMAGIC(hdr.ex) == ZMAGIC) { 305332130Skevans addr = hdr.ex.a_entry & 0xffffff; 306332130Skevans p = PTOV(addr); 307332130Skevans fs_off = PAGE_SIZE; 308332130Skevans if (xfsread(ino, p, hdr.ex.a_text)) 309332130Skevans return; 310332130Skevans p += roundup2(hdr.ex.a_text, PAGE_SIZE); 311332130Skevans if (xfsread(ino, p, hdr.ex.a_data)) 312332130Skevans return; 313332130Skevans } else if (IS_ELF(hdr.eh)) { 314332130Skevans fs_off = hdr.eh.e_phoff; 315332130Skevans for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) { 316332130Skevans if (xfsread(ino, ep + j, sizeof(ep[0]))) 317332130Skevans return; 318332130Skevans if (ep[j].p_type == PT_LOAD) 319332130Skevans j++; 320332130Skevans } 321332130Skevans for (i = 0; i < 2; i++) { 322332130Skevans p = PTOV(ep[i].p_paddr & 0xffffff); 323332130Skevans fs_off = ep[i].p_offset; 324332130Skevans if (xfsread(ino, p, ep[i].p_filesz)) 325332130Skevans return; 326332130Skevans } 327332130Skevans p += roundup2(ep[1].p_memsz, PAGE_SIZE); 328332130Skevans bootinfo.bi_symtab = VTOP(p); 329332130Skevans if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 330332130Skevans fs_off = hdr.eh.e_shoff + sizeof(es[0]) * 331332130Skevans (hdr.eh.e_shstrndx + 1); 332332130Skevans if (xfsread(ino, &es, sizeof(es))) 333332130Skevans return; 334332130Skevans for (i = 0; i < 2; i++) { 335332130Skevans *(Elf32_Word *)p = es[i].sh_size; 336332130Skevans p += sizeof(es[i].sh_size); 337332130Skevans fs_off = es[i].sh_offset; 338332130Skevans if (xfsread(ino, p, es[i].sh_size)) 339332130Skevans return; 340332130Skevans p += es[i].sh_size; 341332130Skevans } 342332130Skevans } 343332130Skevans addr = hdr.eh.e_entry & 0xffffff; 344332130Skevans bootinfo.bi_esymtab = VTOP(p); 345332130Skevans } else { 346332130Skevans printf("Invalid %s\n", "format"); 34740269Srnordier return; 34840269Srnordier } 349219452Srdivacky 350332130Skevans bootinfo.bi_kernelname = VTOP(kname); 351332130Skevans bootinfo.bi_bios_dev = dsk.drive; 352332130Skevans __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 353332130Skevans MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part), 354332130Skevans 0, 0, 0, VTOP(&bootinfo)); 35540269Srnordier} 35640269Srnordier 35740269Srnordierstatic int 358108000Simpparse() 35940269Srnordier{ 360332130Skevans char *arg, *ep, *p, *q; 361332130Skevans const char *cp; 362332130Skevans unsigned int drv; 363332130Skevans int c, i, j; 364332130Skevans size_t k; 36540269Srnordier 366332130Skevans arg = cmd; 367332130Skevans 368332130Skevans while ((c = *arg++)) { 369332130Skevans if (c == ' ' || c == '\t' || c == '\n') 370332130Skevans continue; 371332130Skevans for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 372332130Skevans ep = p; 373332130Skevans if (*p) 374332130Skevans *p++ = 0; 375332130Skevans if (c == '-') { 376332130Skevans while ((c = *arg++)) { 377332130Skevans if (c == 'P') { 378332130Skevans if (*(uint8_t *)PTOV(0x496) & 0x10) { 379332130Skevans cp = "yes"; 380332130Skevans } else { 381332130Skevans opts |= OPT_SET(RBX_DUAL) | 382332130Skevans OPT_SET(RBX_SERIAL); 383332130Skevans cp = "no"; 384332130Skevans } 385332130Skevans printf("Keyboard: %s\n", cp); 386332130Skevans continue; 387268475Simp#if SERIAL 388332130Skevans } else if (c == 'S') { 389332130Skevans j = 0; 390332130Skevans while ((u_int)(i = *arg++ - '0') <= 9) 391332130Skevans j = j * 10 + i; 392332130Skevans if (j > 0 && i == -'0') { 393332130Skevans comspeed = j; 394332130Skevans break; 395332130Skevans } 396332130Skevans /* 397332130Skevans * Fall through to error below 398332130Skevans * ('S' not in optstr[]). 399332130Skevans */ 400268475Simp#endif 401332130Skevans } 402332130Skevans for (i = 0; c != optstr[i]; i++) 403332130Skevans if (i == NOPT - 1) 404332130Skevans return (-1); 405332130Skevans opts ^= OPT_SET(flags[i]); 406332130Skevans } 407268475Simp#if SERIAL 408332130Skevans ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 409332130Skevans OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 410332130Skevans if (DO_SIO) { 411332130Skevans if (sio_init(115200 / comspeed) != 0) 412332130Skevans ioctrl &= ~IO_SERIAL; 413332130Skevans } 414268475Simp#endif 415332130Skevans } else { 416332130Skevans for (q = arg--; *q && *q != '('; q++); 417332130Skevans if (*q) { 418332130Skevans drv = -1; 419332130Skevans if (arg[1] == ':') { 420332130Skevans drv = *arg - '0'; 421332130Skevans if (drv > 9) 422332130Skevans return (-1); 423332130Skevans arg += 2; 424332130Skevans } 425332130Skevans if (q - arg != 2) 426332130Skevans return (-1); 427332130Skevans for (i = 0; arg[0] != dev_nm[i][0] || 428332130Skevans arg[1] != dev_nm[i][1]; i++) 429332130Skevans if (i == NDEV - 1) 430332130Skevans return (-1); 431332130Skevans dsk.type = i; 432332130Skevans arg += 3; 433332130Skevans dsk.unit = *arg - '0'; 434332130Skevans if (arg[1] != ',' || dsk.unit > 9) 435332130Skevans return (-1); 436332130Skevans arg += 2; 437332130Skevans dsk.slice = WHOLE_DISK_SLICE; 438332130Skevans if (arg[1] == ',') { 439332130Skevans dsk.slice = *arg - '0' + 1; 440332130Skevans if (dsk.slice > NDOSPART + 1) 441332130Skevans return (-1); 442332130Skevans arg += 2; 443332130Skevans } 444332130Skevans if (arg[1] != ')') 445332130Skevans return (-1); 446332130Skevans dsk.part = *arg - 'a'; 447332130Skevans if (dsk.part > 7) 448332130Skevans return (-1); 449332130Skevans arg += 2; 450332130Skevans if (drv == -1) 451332130Skevans drv = dsk.unit; 452332130Skevans dsk.drive = (dsk.type <= TYPE_MAXHARD 453332130Skevans ? DRV_HARD : 0) + drv; 454332130Skevans dsk_meta = 0; 455332130Skevans } 456332130Skevans k = ep - arg; 457332130Skevans if (k > 0) { 458332130Skevans if (k >= sizeof(knamebuf)) 459332130Skevans return (-1); 460332130Skevans memcpy(knamebuf, arg, k + 1); 461332130Skevans kname = knamebuf; 462332130Skevans } 46340269Srnordier } 464332130Skevans arg = p; 46540269Srnordier } 466332130Skevans return (0); 46740269Srnordier} 46840269Srnordier 46940269Srnordierstatic int 47040269Srnordierdskread(void *buf, unsigned lba, unsigned nblk) 47140269Srnordier{ 472332130Skevans struct dos_partition *dp; 473332130Skevans struct disklabel *d; 474332130Skevans char *sec; 475332130Skevans unsigned i; 476332130Skevans uint8_t sl; 477332130Skevans const char *reason; 47840269Srnordier 479332130Skevans if (!dsk_meta) { 480332130Skevans sec = dmadat->secbuf; 481332130Skevans dsk.start = 0; 482332130Skevans if (drvread(sec, DOSBBSECTOR, 1)) 483332130Skevans return (-1); 484332130Skevans dp = (void *)(sec + DOSPARTOFF); 485332130Skevans sl = dsk.slice; 486332130Skevans if (sl < BASE_SLICE) { 487332130Skevans for (i = 0; i < NDOSPART; i++) 488332130Skevans if (dp[i].dp_typ == DOSPTYP_386BSD && 489332130Skevans (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { 490332130Skevans sl = BASE_SLICE + i; 491332130Skevans if (dp[i].dp_flag & 0x80 || 492332130Skevans dsk.slice == COMPATIBILITY_SLICE) 493332130Skevans break; 494332130Skevans } 495332130Skevans if (dsk.slice == WHOLE_DISK_SLICE) 496332130Skevans dsk.slice = sl; 49740314Srnordier } 498332130Skevans if (sl != WHOLE_DISK_SLICE) { 499332130Skevans if (sl != COMPATIBILITY_SLICE) 500332130Skevans dp += sl - BASE_SLICE; 501332130Skevans if (dp->dp_typ != DOSPTYP_386BSD) { 502332130Skevans reason = "slice"; 503332130Skevans goto error; 504332130Skevans } 505332130Skevans dsk.start = dp->dp_start; 506332130Skevans } 507332130Skevans if (drvread(sec, dsk.start + LABELSECTOR, 1)) 508332130Skevans return (-1); 509332130Skevans d = (void *)(sec + LABELOFFSET); 510332130Skevans if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { 511332130Skevans if (dsk.part != RAW_PART) { 512332130Skevans reason = "label"; 513332130Skevans goto error; 514332130Skevans } 515332130Skevans } else { 516332130Skevans if (!dsk.init) { 517332130Skevans if (d->d_type == DTYPE_SCSI) 518332130Skevans dsk.type = TYPE_DA; 519332130Skevans dsk.init++; 520332130Skevans } 521332130Skevans if (dsk.part >= d->d_npartitions || 522332130Skevans !d->d_partitions[dsk.part].p_size) { 523332130Skevans reason = "partition"; 524332130Skevans goto error; 525332130Skevans } 526332130Skevans dsk.start += d->d_partitions[dsk.part].p_offset; 527332130Skevans dsk.start -= d->d_partitions[RAW_PART].p_offset; 528332130Skevans } 52940314Srnordier } 530332130Skevans return (drvread(buf, dsk.start + lba, nblk)); 531275237Srdivackyerror: 532332130Skevans printf("Invalid %s\n", reason); 533332130Skevans return (-1); 53440269Srnordier} 53540269Srnordier 536104679Sphkstatic void 53740269Srnordierprintf(const char *fmt,...) 53840269Srnordier{ 539332130Skevans va_list ap; 540332130Skevans static char buf[10]; 541332130Skevans char *s; 542332130Skevans unsigned u; 543332130Skevans int c; 54440269Srnordier 545332130Skevans va_start(ap, fmt); 546332130Skevans while ((c = *fmt++)) { 547332130Skevans if (c == '%') { 548332130Skevans c = *fmt++; 549332130Skevans switch (c) { 550332130Skevans case 'c': 551332130Skevans putchar(va_arg(ap, int)); 552332130Skevans continue; 553332130Skevans case 's': 554332130Skevans for (s = va_arg(ap, char *); *s; s++) 555332130Skevans putchar(*s); 556332130Skevans continue; 557332130Skevans case 'u': 558332130Skevans u = va_arg(ap, unsigned); 559332130Skevans s = buf; 560332130Skevans do 561332130Skevans *s++ = '0' + u % 10U; 562332130Skevans while (u /= 10U); 563332130Skevans while (--s >= buf) 564332130Skevans putchar(*s); 565332130Skevans continue; 566332130Skevans } 567332130Skevans } 568332130Skevans putchar(c); 56940269Srnordier } 570332130Skevans va_end(ap); 571332130Skevans return; 57240269Srnordier} 57340269Srnordier 574104679Sphkstatic void 57540269Srnordierputchar(int c) 57640269Srnordier{ 577332130Skevans 578332130Skevans if (c == '\n') 579332130Skevans xputc('\r'); 580332130Skevans xputc(c); 58140269Srnordier} 58240269Srnordier 58340269Srnordierstatic int 58440269Srnordierdrvread(void *buf, unsigned lba, unsigned nblk) 58540269Srnordier{ 586332130Skevans static unsigned c = 0x2d5c7c2f; 58740323Srnordier 588332130Skevans if (!OPT_CHECK(RBX_QUIET)) { 589332130Skevans xputc(c = c << 8 | c >> 24); 590332130Skevans xputc('\b'); 591332130Skevans } 592332130Skevans v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; 593332130Skevans v86.addr = XREADORG; /* call to xread in boot1 */ 594332130Skevans v86.es = VTOPSEG(buf); 595332130Skevans v86.eax = lba; 596332130Skevans v86.ebx = VTOPOFF(buf); 597332130Skevans v86.ecx = lba >> 16; 598332130Skevans v86.edx = nblk << 8 | dsk.drive; 599332130Skevans v86int(); 600332130Skevans v86.ctl = V86_FLAGS; 601332130Skevans if (V86_CY(v86.efl)) { 602332130Skevans printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); 603332130Skevans return (-1); 604332130Skevans } 605332130Skevans return (0); 60640269Srnordier} 60740269Srnordier 60840269Srnordierstatic int 60940269Srnordierkeyhit(unsigned ticks) 61040269Srnordier{ 611332130Skevans uint32_t t0, t1; 61240269Srnordier 613332130Skevans if (OPT_CHECK(RBX_NOINTR)) 614332130Skevans return (0); 615332130Skevans t0 = 0; 616332130Skevans for (;;) { 617332130Skevans if (xgetc(1)) 618332130Skevans return (1); 619332130Skevans t1 = *(uint32_t *)PTOV(0x46c); 620332130Skevans if (!t0) 621332130Skevans t0 = t1; 622332130Skevans if ((uint32_t)(t1 - t0) >= ticks) 623332130Skevans return (0); 624332130Skevans } 62540269Srnordier} 62640269Srnordier 62740269Srnordierstatic int 62840404Srnordierxputc(int c) 62940269Srnordier{ 630332130Skevans 631332130Skevans if (DO_KBD) 632332130Skevans putc(c); 633332130Skevans if (DO_SIO) 634332130Skevans sio_putc(c); 635332130Skevans return (c); 63640404Srnordier} 63740404Srnordier 63840404Srnordierstatic int 639220392Srdivackygetc(int fn) 640220392Srdivacky{ 641332130Skevans 642332130Skevans v86.addr = 0x16; 643332130Skevans v86.eax = fn << 8; 644332130Skevans v86int(); 645332130Skevans return (fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl)); 646220392Srdivacky} 647220392Srdivacky 648220392Srdivackystatic int 64940404Srnordierxgetc(int fn) 65040404Srnordier{ 651332130Skevans 652332130Skevans if (OPT_CHECK(RBX_NOINTR)) 653332130Skevans return (0); 654332130Skevans for (;;) { 655332130Skevans if (DO_KBD && getc(1)) 656332130Skevans return (fn ? 1 : getc(0)); 657332130Skevans if (DO_SIO && sio_ischar()) 658332130Skevans return (fn ? 1 : sio_getc()); 659332130Skevans if (fn) 660332130Skevans return (0); 661332130Skevans } 66240404Srnordier} 663