c03b24b2d8
Move the relocated boot1 and arg transfer space from 0x600/0x800 to 0x700/0x900. In theory this should make no difference, apart from the fact that Buslogic controllers happen to use a few bytes at 0x600 for some sort of scratch space for it's int 0x13 hook (!!!), causing the machine to crash badly when the boot2 code makes it's callbacks into boot1 for disk IO. Submitted by: Robert Nordier <rnordier@freebsd.org>
812 lines
16 KiB
C
812 lines
16 KiB
C
/*
|
|
* Copyright (c) 1998 Robert Nordier
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are freely
|
|
* permitted provided that the above copyright notice and this
|
|
* paragraph and the following disclaimer are duplicated in all
|
|
* such forms.
|
|
*
|
|
* This software is provided "AS IS" and without any express or
|
|
* implied warranties, including, without limitation, the implied
|
|
* warranties of merchantability and fitness for a particular
|
|
* purpose.
|
|
*/
|
|
|
|
/*
|
|
* $Id: boot2.c,v 1.16 1998/11/08 18:37:28 rnordier Exp $
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/reboot.h>
|
|
#include <sys/diskslice.h>
|
|
#include <sys/disklabel.h>
|
|
#include <sys/dirent.h>
|
|
#include <machine/bootinfo.h>
|
|
|
|
#include <ufs/ffs/fs.h>
|
|
#include <ufs/ufs/dinode.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <a.out.h>
|
|
#include <elf.h>
|
|
|
|
#include <btxv86.h>
|
|
|
|
#include "lib.h"
|
|
|
|
#define RBX_ASKNAME 0x0 /* -a */
|
|
#define RBX_SINGLE 0x1 /* -s */
|
|
#define RBX_DFLTROOT 0x5 /* -r */
|
|
#define RBX_KDB 0x6 /* -d */
|
|
#define RBX_CONFIG 0xa /* -c */
|
|
#define RBX_VERBOSE 0xb /* -v */
|
|
#define RBX_SERIAL 0xc /* -h */
|
|
#define RBX_CDROM 0xd /* -C */
|
|
#define RBX_GDB 0xf /* -g */
|
|
#define RBX_DUAL 0x1d /* -D */
|
|
#define RBX_PROBEKBD 0x1e /* -P */
|
|
|
|
#define RBX_MASK 0xffff
|
|
|
|
#define PATH_CONFIG "/boot.config"
|
|
#define PATH_BOOT3 "/boot/loader"
|
|
#define PATH_KERNEL "/kernel"
|
|
#define PATH_HELP "boot.help"
|
|
|
|
#define ARGS 0x900
|
|
#define NOPT 11
|
|
#define BSIZEMAX 8192
|
|
#define NDEV 5
|
|
#define MEM_BASE 0x12
|
|
#define MEM_EXT 0x15
|
|
#define V86_CY(x) ((x) & 1)
|
|
#define V86_ZR(x) ((x) & 0x40)
|
|
|
|
#define DRV_HARD 0x80
|
|
#define DRV_MASK 0x7f
|
|
|
|
#define MAJ_WD 0
|
|
#define MAJ_WFD 1
|
|
#define MAJ_FD 2
|
|
#define MAJ_DA 4
|
|
|
|
extern uint32_t _end;
|
|
|
|
static const char optstr[NOPT] = "DhaCcdgPrsv";
|
|
static const unsigned char flags[NOPT] = {
|
|
RBX_DUAL,
|
|
RBX_SERIAL,
|
|
RBX_ASKNAME,
|
|
RBX_CDROM,
|
|
RBX_CONFIG,
|
|
RBX_KDB,
|
|
RBX_GDB,
|
|
RBX_PROBEKBD,
|
|
RBX_DFLTROOT,
|
|
RBX_SINGLE,
|
|
RBX_VERBOSE
|
|
};
|
|
|
|
static const char *const dev_nm[] = {"wd", " ", "fd", " ", "da"};
|
|
|
|
static struct dsk {
|
|
unsigned drive;
|
|
unsigned type;
|
|
unsigned unit;
|
|
unsigned slice;
|
|
unsigned part;
|
|
unsigned start;
|
|
int init;
|
|
int meta;
|
|
} dsk;
|
|
static char cmd[512];
|
|
static char kname[1024];
|
|
static char help[2048];
|
|
static uint32_t opts;
|
|
static struct bootinfo bootinfo;
|
|
static int ls;
|
|
static uint32_t fs_off;
|
|
static uint8_t ioctrl = 0x1;
|
|
|
|
void exit(int);
|
|
static void load(const char *);
|
|
static int parse(char *);
|
|
static void readfile(const char *, void *, size_t);
|
|
static ino_t lookup(const char *);
|
|
static int fsfind(const char *, ino_t *);
|
|
static int xfsread(ino_t, void *, size_t);
|
|
static ssize_t fsread(ino_t, void *, size_t);
|
|
static int dskread(void *, unsigned, unsigned);
|
|
static int printf(const char *,...);
|
|
static void getstr(char *, int);
|
|
static int putchar(int);
|
|
static int getchar(void);
|
|
static void *memcpy(void *, const void *, size_t);
|
|
static int strcmp(const char *, const char *);
|
|
static void *malloc(size_t);
|
|
static uint32_t memsize(int);
|
|
static uint32_t drvinfo(int);
|
|
static int drvread(void *, unsigned, unsigned);
|
|
static int keyhit(unsigned);
|
|
static int xputc(int);
|
|
static int xgetc(int);
|
|
static void putc(int);
|
|
static int getc(int);
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
int autoboot, helpon, i;
|
|
|
|
v86.ctl = V86_FLAGS;
|
|
dsk.drive = *(uint8_t *)PTOV(ARGS);
|
|
dsk.type = dsk.drive & DRV_HARD ? MAJ_WD : MAJ_FD;
|
|
dsk.unit = dsk.drive & DRV_MASK;
|
|
dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
|
|
bootinfo.bi_version = BOOTINFO_VERSION;
|
|
bootinfo.bi_size = sizeof(bootinfo);
|
|
bootinfo.bi_basemem = memsize(MEM_BASE);
|
|
bootinfo.bi_extmem = memsize(MEM_EXT);
|
|
bootinfo.bi_memsizes_valid++;
|
|
for (i = 0; i < N_BIOS_GEOM; i++)
|
|
bootinfo.bi_bios_geom[i] = drvinfo(i);
|
|
autoboot = 2;
|
|
helpon = 1;
|
|
readfile(PATH_HELP, help, sizeof(help));
|
|
readfile(PATH_CONFIG, cmd, sizeof(cmd));
|
|
if (*cmd) {
|
|
printf("%s: %s", PATH_CONFIG, cmd);
|
|
if (parse(cmd))
|
|
autoboot = 0;
|
|
*cmd = 0;
|
|
}
|
|
if (autoboot && !*kname) {
|
|
if (autoboot == 2) {
|
|
memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3));
|
|
if (!keyhit(0x37)) {
|
|
load(kname);
|
|
autoboot = 1;
|
|
}
|
|
}
|
|
if (autoboot == 1)
|
|
memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL));
|
|
}
|
|
for (;;) {
|
|
printf(" \n>> FreeBSD/i386 BOOT\n"
|
|
"Default: %u:%s(%u,%c)%s\n"
|
|
"%s"
|
|
"boot: ",
|
|
dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
|
|
'a' + dsk.part, kname, helpon ? help : "");
|
|
if (ioctrl & 0x2)
|
|
sio_flush();
|
|
if (!autoboot || keyhit(0x5a))
|
|
getstr(cmd, sizeof(cmd));
|
|
else
|
|
putchar('\n');
|
|
autoboot = helpon = 0;
|
|
if (parse(cmd))
|
|
helpon = 1;
|
|
else
|
|
load(kname);
|
|
}
|
|
}
|
|
|
|
void
|
|
exit(int x)
|
|
{
|
|
}
|
|
|
|
static void
|
|
load(const char *fname)
|
|
{
|
|
union {
|
|
struct exec ex;
|
|
Elf32_Ehdr eh;
|
|
} hdr;
|
|
Elf32_Phdr ep[2];
|
|
Elf32_Shdr es[2];
|
|
caddr_t p;
|
|
ino_t ino;
|
|
uint32_t addr, x;
|
|
int fmt, i, j;
|
|
|
|
if (!(ino = lookup(fname))) {
|
|
if (!ls)
|
|
printf("No %s\n", fname);
|
|
return;
|
|
}
|
|
if (xfsread(ino, &hdr, sizeof(hdr)))
|
|
return;
|
|
if (N_GETMAGIC(hdr.ex) == ZMAGIC)
|
|
fmt = 0;
|
|
else if (IS_ELF(hdr.eh))
|
|
fmt = 1;
|
|
else {
|
|
printf("Invalid %s\n", "format");
|
|
return;
|
|
}
|
|
if (fmt == 0) {
|
|
addr = hdr.ex.a_entry & 0xffffff;
|
|
p = PTOV(addr);
|
|
fs_off = PAGE_SIZE;
|
|
if (xfsread(ino, p, hdr.ex.a_text))
|
|
return;
|
|
p += roundup2(hdr.ex.a_text, PAGE_SIZE);
|
|
if (xfsread(ino, p, hdr.ex.a_data))
|
|
return;
|
|
p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE);
|
|
bootinfo.bi_symtab = VTOP(p);
|
|
memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms));
|
|
p += sizeof(hdr.ex.a_syms);
|
|
if (hdr.ex.a_syms) {
|
|
if (xfsread(ino, p, hdr.ex.a_syms))
|
|
return;
|
|
p += hdr.ex.a_syms;
|
|
if (xfsread(ino, p, sizeof(int)))
|
|
return;
|
|
x = *(uint32_t *)p;
|
|
p += sizeof(int);
|
|
x -= sizeof(int);
|
|
if (xfsread(ino, p, x))
|
|
return;
|
|
p += x;
|
|
}
|
|
} else {
|
|
fs_off = hdr.eh.e_phoff;
|
|
for (j = i = 0; i < hdr.eh.e_phoff && j < 2; i++) {
|
|
if (xfsread(ino, ep + j, sizeof(ep[0])))
|
|
return;
|
|
if (ep[j].p_type == PT_LOAD)
|
|
j++;
|
|
}
|
|
for (i = 0; i < 2; i++) {
|
|
p = PTOV(ep[i].p_paddr & 0xffffff);
|
|
fs_off = ep[i].p_offset;
|
|
if (xfsread(ino, p, ep[i].p_filesz))
|
|
return;
|
|
}
|
|
p += roundup2(ep[1].p_memsz, PAGE_SIZE);
|
|
bootinfo.bi_symtab = VTOP(p);
|
|
if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
|
|
fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
|
|
(hdr.eh.e_shstrndx + 1);
|
|
if (xfsread(ino, &es, sizeof(es)))
|
|
return;
|
|
for (i = 0; i < 2; i++) {
|
|
memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
|
|
p += sizeof(es[i].sh_size);
|
|
fs_off = es[i].sh_offset;
|
|
if (xfsread(ino, p, es[i].sh_size))
|
|
return;
|
|
p += es[i].sh_size;
|
|
}
|
|
}
|
|
addr = hdr.eh.e_entry & 0xffffff;
|
|
}
|
|
bootinfo.bi_esymtab = VTOP(p);
|
|
bootinfo.bi_kernelname = VTOP(fname);
|
|
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
|
|
MAKEBOOTDEV(dsk.type, 0, dsk.slice, dsk.unit, dsk.part),
|
|
0, 0, 0, VTOP(&bootinfo));
|
|
}
|
|
|
|
static int
|
|
parse(char *arg)
|
|
{
|
|
char *p, *q;
|
|
int drv, c, i;
|
|
|
|
while ((c = *arg++)) {
|
|
if (c == ' ')
|
|
continue;
|
|
for (p = arg; *p && *p != '\n' && *p != ' '; p++);
|
|
if (*p)
|
|
*p++ = 0;
|
|
if (c == '-') {
|
|
while ((c = *arg++)) {
|
|
for (i = 0; c != optstr[i]; i++)
|
|
if (i == NOPT - 1)
|
|
return -1;
|
|
opts ^= 1 << flags[i];
|
|
}
|
|
if (opts & 1 << RBX_PROBEKBD) {
|
|
i = *(uint8_t *)PTOV(0x496) & 0x10;
|
|
printf("Keyboard: %s\n", i ? "yes" : "no");
|
|
if (!i)
|
|
opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL;
|
|
opts &= ~(1 << RBX_PROBEKBD);
|
|
}
|
|
ioctrl = opts & 1 << RBX_DUAL ? 0x3 :
|
|
opts & 1 << RBX_SERIAL ? 0x2 : 0x1;
|
|
if (ioctrl & 0x2)
|
|
sio_init();
|
|
} else {
|
|
for (q = arg--; *q && *q != '('; q++);
|
|
if (*q) {
|
|
drv = -1;
|
|
if (arg[1] == ':') {
|
|
if (*arg < '0' || *arg > '9')
|
|
return -1;
|
|
drv = *arg - '0';
|
|
arg += 2;
|
|
}
|
|
if (q - arg != 2)
|
|
return -1;
|
|
for (i = 0; arg[0] != dev_nm[i][0] ||
|
|
arg[1] != dev_nm[i][1]; i++)
|
|
if (i == NDEV - 1)
|
|
return -1;
|
|
dsk.type = i;
|
|
arg += 3;
|
|
if (arg[1] != ',' || *arg < '0' || *arg > '9')
|
|
return -1;
|
|
dsk.unit = *arg - '0';
|
|
arg += 2;
|
|
dsk.slice = WHOLE_DISK_SLICE;
|
|
if (arg[1] == ',') {
|
|
if (*arg < '0' || *arg > '0' + NDOSPART)
|
|
return -1;
|
|
if ((dsk.slice = *arg - '0'))
|
|
dsk.slice++;
|
|
arg += 2;
|
|
}
|
|
if (arg[1] != ')' || *arg < 'a' || *arg > 'p')
|
|
return -1;
|
|
dsk.part = *arg - 'a';
|
|
arg += 2;
|
|
if (drv == -1)
|
|
drv = dsk.unit;
|
|
dsk.drive = (dsk.type == MAJ_WD ||
|
|
dsk.type == MAJ_DA ? DRV_HARD : 0) + drv;
|
|
dsk.meta = 0;
|
|
fsread(0, NULL, 0);
|
|
}
|
|
if ((i = p - arg - !*(p - 1))) {
|
|
if (i >= sizeof(kname))
|
|
return -1;
|
|
memcpy(kname, arg, i + 1);
|
|
}
|
|
}
|
|
arg = p;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
readfile(const char *fname, void *buf, size_t size)
|
|
{
|
|
ino_t ino;
|
|
|
|
if ((ino = lookup(fname)))
|
|
fsread(ino, buf, size);
|
|
}
|
|
|
|
static ino_t
|
|
lookup(const char *path)
|
|
{
|
|
char name[MAXNAMLEN + 1];
|
|
const char *s;
|
|
ino_t ino;
|
|
ssize_t n;
|
|
int dt;
|
|
|
|
ino = ROOTINO;
|
|
dt = DT_DIR;
|
|
for (;;) {
|
|
if (*path == '/')
|
|
path++;
|
|
if (!*path)
|
|
break;
|
|
for (s = path; *s && *s != '/'; s++);
|
|
if ((n = s - path) > MAXNAMLEN)
|
|
return 0;
|
|
ls = *path == '?' && n == 1 && !*s;
|
|
memcpy(name, path, n);
|
|
name[n] = 0;
|
|
if ((dt = fsfind(name, &ino)) <= 0)
|
|
break;
|
|
path = s;
|
|
}
|
|
return dt == DT_REG ? ino : 0;
|
|
}
|
|
|
|
static int
|
|
fsfind(const char *name, ino_t * ino)
|
|
{
|
|
char buf[DEV_BSIZE];
|
|
struct dirent *d;
|
|
char *s;
|
|
ssize_t n;
|
|
|
|
fs_off = 0;
|
|
while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
|
|
for (s = buf; s < buf + DEV_BSIZE;) {
|
|
d = (void *)s;
|
|
if (ls)
|
|
printf("%s ", d->d_name);
|
|
else if (!strcmp(name, d->d_name)) {
|
|
*ino = d->d_fileno;
|
|
return d->d_type;
|
|
}
|
|
s += d->d_reclen;
|
|
}
|
|
if (n != -1 && ls)
|
|
putchar('\n');
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
xfsread(ino_t inode, void *buf, size_t nbyte)
|
|
{
|
|
if (fsread(inode, buf, nbyte) != nbyte) {
|
|
printf("Invalid %s\n", "format");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t
|
|
fsread(ino_t inode, void *buf, size_t nbyte)
|
|
{
|
|
static struct fs fs;
|
|
static struct dinode din;
|
|
static char *blkbuf;
|
|
static ufs_daddr_t *indbuf;
|
|
static ino_t inomap;
|
|
static ufs_daddr_t blkmap, indmap;
|
|
static unsigned fsblks;
|
|
char *s;
|
|
ufs_daddr_t lbn, addr;
|
|
size_t n, nb, off;
|
|
|
|
if (!dsk.meta) {
|
|
if (!blkbuf)
|
|
blkbuf = malloc(BSIZEMAX);
|
|
inomap = 0;
|
|
if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
|
|
return -1;
|
|
memcpy(&fs, blkbuf, sizeof(fs));
|
|
if (fs.fs_magic != FS_MAGIC) {
|
|
printf("Not ufs\n");
|
|
return -1;
|
|
}
|
|
fsblks = fs.fs_bsize >> DEV_BSHIFT;
|
|
dsk.meta++;
|
|
}
|
|
if (!inode)
|
|
return 0;
|
|
if (inomap != inode) {
|
|
if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
|
|
fsblks))
|
|
return -1;
|
|
din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
|
|
inomap = inode;
|
|
fs_off = 0;
|
|
blkmap = indmap = 0;
|
|
}
|
|
s = buf;
|
|
if (nbyte > (n = din.di_size - fs_off))
|
|
nbyte = n;
|
|
nb = nbyte;
|
|
while (nb) {
|
|
lbn = lblkno(&fs, fs_off);
|
|
if (lbn < NDADDR)
|
|
addr = din.di_db[lbn];
|
|
else {
|
|
if (indmap != din.di_ib[0]) {
|
|
if (!indbuf)
|
|
indbuf = malloc(BSIZEMAX);
|
|
if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
|
|
fsblks))
|
|
return -1;
|
|
indmap = din.di_ib[0];
|
|
}
|
|
addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
|
|
}
|
|
n = dblksize(&fs, &din, lbn);
|
|
if (blkmap != addr) {
|
|
if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT))
|
|
return -1;
|
|
blkmap = addr;
|
|
}
|
|
off = blkoff(&fs, fs_off);
|
|
n -= off;
|
|
if (n > nb)
|
|
n = nb;
|
|
memcpy(s, blkbuf + off, n);
|
|
s += n;
|
|
fs_off += n;
|
|
nb -= n;
|
|
}
|
|
return nbyte;
|
|
}
|
|
|
|
static int
|
|
dskread(void *buf, unsigned lba, unsigned nblk)
|
|
{
|
|
static char *sec;
|
|
struct dos_partition *dp;
|
|
struct disklabel *d;
|
|
unsigned sl, i;
|
|
|
|
if (!dsk.meta) {
|
|
if (!sec)
|
|
sec = malloc(DEV_BSIZE);
|
|
dsk.start = 0;
|
|
if (drvread(sec, DOSBBSECTOR, 1))
|
|
return -1;
|
|
dp = (void *)(sec + DOSPARTOFF);
|
|
sl = dsk.slice;
|
|
if (sl < BASE_SLICE) {
|
|
for (i = 0; i < NDOSPART; i++)
|
|
if (dp[i].dp_typ == DOSPTYP_386BSD &&
|
|
(dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
|
|
sl = BASE_SLICE + i;
|
|
if (dp[i].dp_flag & 0x80 ||
|
|
dsk.slice == COMPATIBILITY_SLICE)
|
|
break;
|
|
}
|
|
if (dsk.slice == WHOLE_DISK_SLICE)
|
|
dsk.slice = sl;
|
|
}
|
|
if (sl != WHOLE_DISK_SLICE) {
|
|
if (sl != COMPATIBILITY_SLICE)
|
|
dp += sl - BASE_SLICE;
|
|
if (dp->dp_typ != DOSPTYP_386BSD) {
|
|
printf("Invalid %s\n", "slice");
|
|
return -1;
|
|
}
|
|
dsk.start = dp->dp_start;
|
|
}
|
|
if (drvread(sec, dsk.start + LABELSECTOR, 1))
|
|
return -1;
|
|
d = (void *)(sec + LABELOFFSET);
|
|
if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
|
|
if (dsk.part != RAW_PART) {
|
|
printf("Invalid %s\n", "label");
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (!dsk.init) {
|
|
if (d->d_type == DTYPE_SCSI)
|
|
dsk.type = MAJ_DA;
|
|
dsk.init++;
|
|
}
|
|
if (dsk.part >= d->d_npartitions) {
|
|
printf("Invalid %s\n", "partition");
|
|
return -1;
|
|
}
|
|
dsk.start = d->d_partitions[dsk.part].p_offset;
|
|
}
|
|
}
|
|
return drvread(buf, dsk.start + lba, nblk);
|
|
}
|
|
|
|
static int
|
|
printf(const char *fmt,...)
|
|
{
|
|
static const char digits[16] = "0123456789abcdef";
|
|
va_list ap;
|
|
char buf[10];
|
|
char *s;
|
|
unsigned r, u;
|
|
int c;
|
|
|
|
va_start(ap, fmt);
|
|
while ((c = *fmt++)) {
|
|
if (c == '%') {
|
|
c = *fmt++;
|
|
switch (c) {
|
|
case 'c':
|
|
putchar(va_arg(ap, int));
|
|
continue;
|
|
case 's':
|
|
for (s = va_arg(ap, char *); *s; s++)
|
|
putchar(*s);
|
|
continue;
|
|
case 'u':
|
|
case 'x':
|
|
r = c == 'u' ? 10U : 16U;
|
|
u = va_arg(ap, unsigned);
|
|
s = buf;
|
|
do
|
|
*s++ = digits[u % r];
|
|
while (u /= r);
|
|
while (--s >= buf)
|
|
putchar(*s);
|
|
continue;
|
|
}
|
|
}
|
|
putchar(c);
|
|
}
|
|
va_end(ap);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
getstr(char *str, int size)
|
|
{
|
|
char *s;
|
|
int c;
|
|
|
|
s = str;
|
|
do {
|
|
switch (c = getchar()) {
|
|
case 0:
|
|
break;
|
|
case '\b':
|
|
if (s > str) {
|
|
s--;
|
|
putchar(c);
|
|
putchar(' ');
|
|
} else
|
|
c = 0;
|
|
break;
|
|
case '\n':
|
|
*s = 0;
|
|
break;
|
|
default:
|
|
if (s - str < size - 1)
|
|
*s++ = c;
|
|
}
|
|
if (c)
|
|
putchar(c);
|
|
} while (c != '\n');
|
|
}
|
|
|
|
static int
|
|
putchar(int c)
|
|
{
|
|
if (c == '\n')
|
|
xputc('\r');
|
|
return xputc(c);
|
|
}
|
|
|
|
static int
|
|
getchar(void)
|
|
{
|
|
int c;
|
|
|
|
c = xgetc(0);
|
|
if (c == '\r')
|
|
c = '\n';
|
|
return c;
|
|
}
|
|
|
|
static void *
|
|
memcpy(void *dst, const void *src, size_t size)
|
|
{
|
|
const char *s;
|
|
char *d;
|
|
|
|
for (d = dst, s = src; size; size--)
|
|
*d++ = *s++;
|
|
return dst;
|
|
}
|
|
|
|
static int
|
|
strcmp(const char *s1, const char *s2)
|
|
{
|
|
for (; *s1 == *s2 && *s1; s1++, s2++);
|
|
return (u_char)*s1 - (u_char)*s2;
|
|
}
|
|
|
|
static void *
|
|
malloc(size_t size)
|
|
{
|
|
static uint32_t next;
|
|
void *p;
|
|
|
|
if (!next)
|
|
next = roundup2(__base + _end, 0x10000) - __base;
|
|
p = (void *)next;
|
|
next += size;
|
|
return p;
|
|
}
|
|
|
|
static uint32_t
|
|
memsize(int type)
|
|
{
|
|
v86.addr = type;
|
|
v86.eax = 0x8800;
|
|
v86int();
|
|
return v86.eax;
|
|
}
|
|
|
|
static uint32_t
|
|
drvinfo(int drive)
|
|
{
|
|
v86.addr = 0x13;
|
|
v86.eax = 0x800;
|
|
v86.edx = DRV_HARD + drive;
|
|
v86int();
|
|
if (V86_CY(v86.efl))
|
|
return 0x4f010f;
|
|
return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) |
|
|
(v86.edx & 0xff00) | (v86.ecx & 0x3f);
|
|
}
|
|
|
|
static int
|
|
drvread(void *buf, unsigned lba, unsigned nblk)
|
|
{
|
|
static unsigned c = 0x2d5c7c2f;
|
|
|
|
printf("%c\b", c = c << 8 | c >> 24);
|
|
v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
|
|
v86.addr = 0x704; /* call to xread in boot1 */
|
|
v86.es = VTOPSEG(buf);
|
|
v86.eax = lba;
|
|
v86.ebx = VTOPOFF(buf);
|
|
v86.ecx = lba >> 16;
|
|
v86.edx = nblk << 8 | dsk.drive;
|
|
v86int();
|
|
v86.ctl = V86_FLAGS;
|
|
if (V86_CY(v86.efl)) {
|
|
printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff,
|
|
lba);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
keyhit(unsigned ticks)
|
|
{
|
|
uint32_t t0, t1;
|
|
|
|
t0 = 0;
|
|
for (;;) {
|
|
if (xgetc(1))
|
|
return 1;
|
|
t1 = *(uint32_t *)PTOV(0x46c);
|
|
if (!t0)
|
|
t0 = t1;
|
|
if (t1 < t0 || t1 >= t0 + ticks)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int
|
|
xputc(int c)
|
|
{
|
|
if (ioctrl & 0x1)
|
|
putc(c);
|
|
if (ioctrl & 0x2)
|
|
sio_putc(c);
|
|
return c;
|
|
}
|
|
|
|
static int
|
|
xgetc(int fn)
|
|
{
|
|
for (;;) {
|
|
if (ioctrl & 0x1 && getc(1))
|
|
return fn ? 1 : getc(0);
|
|
if (ioctrl & 0x2 && sio_ischar())
|
|
return fn ? 1 : sio_getc();
|
|
if (fn)
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
putc(int c)
|
|
{
|
|
v86.addr = 0x10;
|
|
v86.eax = 0xe00 | (c & 0xff);
|
|
v86.ebx = 0x7;
|
|
v86int();
|
|
}
|
|
|
|
static int
|
|
getc(int fn)
|
|
{
|
|
v86.addr = 0x16;
|
|
v86.eax = fn << 8;
|
|
v86int();
|
|
return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl);
|
|
}
|