summaryrefslogtreecommitdiffstats
path: root/usr.bin/doscmd
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1997-08-09 01:43:15 +0000
committerdyson <dyson@FreeBSD.org>1997-08-09 01:43:15 +0000
commit305573cb2990c5d329d149cef5a3b5533b1e8fd9 (patch)
treedf06304b637358dbe8a006fdb7a6ea5955fee179 /usr.bin/doscmd
parentdede28832bba6a9de7a428ff58df92439bddbc9c (diff)
downloadFreeBSD-src-305573cb2990c5d329d149cef5a3b5533b1e8fd9.zip
FreeBSD-src-305573cb2990c5d329d149cef5a3b5533b1e8fd9.tar.gz
Add our doscmd to the tree. This is a result of work from BSDI, and
a group of dos emulator developers. Submitted by: Jonathan Lemon <jlemon@americantv.com> Obtained from: BSDI
Diffstat (limited to 'usr.bin/doscmd')
-rw-r--r--usr.bin/doscmd/AsyncIO.c342
-rw-r--r--usr.bin/doscmd/AsyncIO.h50
-rw-r--r--usr.bin/doscmd/PROBLEMS21
-rw-r--r--usr.bin/doscmd/ParseBuffer.c89
-rw-r--r--usr.bin/doscmd/README37
-rw-r--r--usr.bin/doscmd/README.booting_dos89
-rw-r--r--usr.bin/doscmd/bios.c329
-rw-r--r--usr.bin/doscmd/callback.c120
-rw-r--r--usr.bin/doscmd/callback.h13
-rw-r--r--usr.bin/doscmd/cmos.c291
-rw-r--r--usr.bin/doscmd/com.h167
-rw-r--r--usr.bin/doscmd/config.c265
-rw-r--r--usr.bin/doscmd/cpu.c70
-rw-r--r--usr.bin/doscmd/crt0.c43
-rw-r--r--usr.bin/doscmd/cwd.c970
-rw-r--r--usr.bin/doscmd/cwd.h109
-rw-r--r--usr.bin/doscmd/debug.c193
-rw-r--r--usr.bin/doscmd/disktab.c100
-rw-r--r--usr.bin/doscmd/dispatch.h110
-rw-r--r--usr.bin/doscmd/dos.c2508
-rw-r--r--usr.bin/doscmd/dos.h402
-rw-r--r--usr.bin/doscmd/doscmd.c892
-rw-r--r--usr.bin/doscmd/doscmd.h272
-rw-r--r--usr.bin/doscmd/doscmd_loader.c98
-rw-r--r--usr.bin/doscmd/exe.c423
-rw-r--r--usr.bin/doscmd/font.h407
-rw-r--r--usr.bin/doscmd/i386-pinsn.c1814
-rw-r--r--usr.bin/doscmd/instbsdi.c55
-rw-r--r--usr.bin/doscmd/int.c139
-rw-r--r--usr.bin/doscmd/int10.c277
-rw-r--r--usr.bin/doscmd/int13.c873
-rw-r--r--usr.bin/doscmd/int14.c510
-rw-r--r--usr.bin/doscmd/int16.c140
-rw-r--r--usr.bin/doscmd/int17.c191
-rw-r--r--usr.bin/doscmd/int1a.c110
-rw-r--r--usr.bin/doscmd/int2f.c167
-rw-r--r--usr.bin/doscmd/intff.c805
-rw-r--r--usr.bin/doscmd/mem.c325
-rw-r--r--usr.bin/doscmd/mouse.c300
-rw-r--r--usr.bin/doscmd/mouse.h68
-rw-r--r--usr.bin/doscmd/net.c34
-rw-r--r--usr.bin/doscmd/port.c405
-rw-r--r--usr.bin/doscmd/register.h222
-rw-r--r--usr.bin/doscmd/setver.c79
-rw-r--r--usr.bin/doscmd/signal.c114
-rw-r--r--usr.bin/doscmd/timer.c50
-rw-r--r--usr.bin/doscmd/trace.c249
-rw-r--r--usr.bin/doscmd/trap.c612
-rw-r--r--usr.bin/doscmd/trap.h83
-rw-r--r--usr.bin/doscmd/tty.c2193
-rw-r--r--usr.bin/doscmd/video.h154
-rw-r--r--usr.bin/doscmd/vparams.h322
-rw-r--r--usr.bin/doscmd/xms.c65
53 files changed, 18766 insertions, 0 deletions
diff --git a/usr.bin/doscmd/AsyncIO.c b/usr.bin/doscmd/AsyncIO.c
new file mode 100644
index 0000000..2e2d8cd
--- /dev/null
+++ b/usr.bin/doscmd/AsyncIO.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI AsyncIO.c,v 2.2 1996/04/08 19:32:10 bostic Exp
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+#include <limits.h>
+#include "doscmd.h"
+
+#define FD_ISZERO(p) ((p)->fds_bits[0] == 0)
+
+/*
+ * Set or Clear the Async nature of an FD
+ */
+
+#define SETASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag | FASYNC)
+#define CLRASYNC(fd) fcntl(fd, F_SETFL, handlers[fd].flag & ~FASYNC)
+
+/*
+ * Request that ``func'' be called everytime data is available on ``fd''
+ */
+
+static fd_set fdset = { 0 }; /* File Descriptors to select on */
+
+typedef struct {
+ void (*func)(void *, REGISTERS);
+ /* Function to call when data arrives */
+ void (*failure)(void *); /* Function to call on failure */
+ void *arg; /* Argument to above functions */
+ int lockcnt; /* Nested level of lock */
+ fd_set members; /* Set of FD's to disable on SIGIO */
+ int flag; /* The flag from F_GETFL (we own it) */
+} Async;
+
+static Async handlers[OPEN_MAX];
+
+static void HandleIO (struct sigframe *sf);
+
+static int in_handler = 0;
+
+void
+_RegisterIO(fd, func, arg, failure)
+int fd;
+void (*func)();
+void *arg;
+void (*failure)();
+{
+ static int firsttime = 1;
+ Async *as;
+
+ if (fd < 0 || fd > OPEN_MAX) {
+printf("%d: Invalid FD\n", fd);
+ return;
+ }
+
+ as = &handlers[fd];
+
+ if ((as->flag = fcntl(fd, F_GETFL, 0)) == -1) {
+ if (func) {
+/*@*/ perror("get fcntl");
+/*@*/ abort();
+ return;
+ }
+ }
+
+ if (firsttime) {
+ struct sigaction sa;
+
+ firsttime = 0;
+ setsignal(SIGIO, HandleIO);
+ }
+
+ if (handlers[fd].func = func) {
+ as->lockcnt = 0;
+ as->arg = arg;
+ as->failure = failure;
+
+ FD_SET(fd, &fdset);
+ FD_ZERO(&handlers[fd].members);
+ FD_SET(fd, &handlers[fd].members);
+ if (fcntl(fd, F_SETOWN, getpid()) < 0) {
+/*@*/ perror("SETOWN");
+ }
+ SETASYNC(fd);
+ } else {
+ as->arg = 0;
+ as->failure = 0;
+ as->lockcnt = 0;
+
+ CLRASYNC(fd);
+ FD_CLR(fd, &fdset);
+ }
+}
+
+static void
+CleanIO()
+{
+ int x;
+ static struct timeval tv = { 0 };
+
+ /*
+ * For every file des in fd_set, we check to see if it
+ * causes a fault on select(). If so, we unregister it
+ * for the user.
+ */
+ for (x = 0; x < OPEN_MAX; ++x) {
+ fd_set set;
+
+ if (!FD_ISSET(x, &fdset))
+ continue;
+
+ FD_ZERO(&set);
+ FD_SET(x, &set);
+ errno = 0;
+ if (select(FD_SETSIZE, &set, 0, 0, &tv) < 0 &&
+ errno == EBADF) {
+ void (*f)();
+ void *a;
+printf("Closed file descriptor %d\n", x);
+
+ f = handlers[x].failure;
+ a = handlers[x].arg;
+ handlers[x].failure = 0;
+ handlers[x].func = 0;
+ handlers[x].arg = 0;
+ handlers[x].lockcnt = 0;
+ FD_CLR(x, &fdset);
+ if (f)
+ (*f)(a);
+ }
+ }
+}
+
+static void
+HandleIO(struct sigframe *sf)
+{
+ ++in_handler;
+
+ for (;;) {
+ static struct timeval tv = { 0 };
+ fd_set readset;
+ int x;
+ int fd;
+
+ readset = fdset;
+ if ((x = select(FD_SETSIZE, &readset, 0, 0, &tv)) < 0) {
+ /*
+ * If we failed becuase of a BADFiledes, go find
+ * which one(s), fail them out and then try a
+ * new select to see if any of the good ones are
+ * okay.
+ */
+ if (errno == EBADF) {
+ CleanIO();
+ if (FD_ISZERO(&fdset))
+ break;
+ continue;
+ }
+ perror("select");
+ break;
+ }
+
+ /*
+ * If we run out of fds to look at, break out of the loop
+ * and exit the handler.
+ */
+ if (!x)
+ break;
+
+ /*
+ * If there is at least 1 fd saying it has something for
+ * us, then loop through the sets looking for those
+ * bits, stopping when we have handleed the number it has
+ * asked for.
+ */
+ for (fd = 0; x && fd < OPEN_MAX; ++fd) {
+ Async *as;
+
+ if (!FD_ISSET(fd, &readset)) {
+ continue;
+ }
+ --x;
+
+ /*
+ * Is suppose it is possible that one of the previous
+ * io requests changed the fdset.
+ * We do know that SIGIO is turned off right now,
+ * so it is safe to checkit.
+ */
+ if (!FD_ISSET(fd, &fdset)) {
+ continue;
+ }
+ as = &handlers[fd];
+
+ /*
+ * as in above, maybe someone locked us...
+ * we are in dangerous water now if we are
+ * multi-tasked
+ */
+ if (as->lockcnt) {
+/*@*/ fprintf(stderr, "Selected IO on locked %d\n",fd);
+ continue;
+ }
+ /*
+ * Okay, now if there exists a handler, we should
+ * call it. We must turn back on SIGIO if there
+ * are possibly other people waiting for it.
+ */
+ if (as->func) {
+ int afd;
+ Async *aas;
+
+ /*
+ * STEP 1: Lock out all "members"
+ */
+ aas = handlers;
+if (0)
+ for (afd = 0; afd < OPEN_MAX; ++afd, ++aas) {
+ if (FD_ISSET(afd, &as->members)) {
+ if (aas->func) {
+ if (as->lockcnt++ == 0) {
+ FD_CLR(afd, &fdset);
+ CLRASYNC(afd);
+ }
+
+ }
+ }
+ }
+
+ /*
+ * STEP 2: Renable SIGIO so other FDs can
+ * use a hit.
+ _UnblockIO();
+ */
+
+ /*
+ * STEP 3: Call the handler
+ */
+ (*handlers[fd].func)(handlers[fd].arg, &sf->sf_sc);
+
+ /*
+ * STEP 4: Just turn SIGIO off. No check.
+ _BlockIO();
+ */
+
+ /*
+ * STEP 5: Unlock all "members"
+ */
+ aas = handlers;
+if (0)
+ for (afd = 0; afd < OPEN_MAX; ++afd, ++aas) {
+ if (FD_ISSET(afd, &as->members)) {
+ if (aas->func) {
+ if (--as->lockcnt == 0) {
+ FD_SET(afd, &fdset);
+ SETASYNC(afd);
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * Otherwise deregister this guy.
+ */
+ _RegisterIO(fd, 0, 0, 0);
+ }
+ }
+ /*
+ * If we did not process all the fd's, then we should
+ * break out of the probable infinite loop.
+ */
+ if (x) {
+ break;
+ }
+ }
+
+ --in_handler;
+}
+
+static int stackp = 0;
+
+void
+_BlockIO()
+{
+ sigset_t set;
+
+ if (stackp >= 64) {
+ fprintf(stderr, "Signal stack count too deep\n");
+ abort();
+ }
+ if (stackp++ == 0) {
+ sigaddset(&set, SIGIO);
+ sigprocmask(SIG_BLOCK, &set, 0);
+ }
+}
+
+void
+_UnblockIO()
+{
+ sigset_t set;
+
+ if (stackp <= 0) {
+ fprintf(stderr, "Negative signal stack count\n");
+ abort();
+ }
+ if (--stackp == 0) {
+ sigaddset(&set, SIGIO);
+ sigprocmask(SIG_UNBLOCK, &set, 0);
+ }
+}
diff --git a/usr.bin/doscmd/AsyncIO.h b/usr.bin/doscmd/AsyncIO.h
new file mode 100644
index 0000000..b5bc9a7
--- /dev/null
+++ b/usr.bin/doscmd/AsyncIO.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI AsyncIO.h,v 2.2 1996/04/08 19:32:12 bostic Exp
+ */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+void _RegisterIO(int, void (*)(void *), void *, void (*)());
+void _AssociateIO(int, int);
+void _DeAssociateIO(int, int);
+void _LockIO(int);
+int _UnlockIO(int);
+int _LevelIO(int);
+int _DetachIO(int);
+int _EndIO(int, int);
+void _BlockIO(void);
+void _UnblockIO(void);
+#if defined(__cplusplus)
+}
+#endif
+
+#define _Un_RegisterIO(x) _RegisterIO((x), (void (*))0, (void *)0, (void (*))0)
diff --git a/usr.bin/doscmd/PROBLEMS b/usr.bin/doscmd/PROBLEMS
new file mode 100644
index 0000000..ba40611
--- /dev/null
+++ b/usr.bin/doscmd/PROBLEMS
@@ -0,0 +1,21 @@
+trailing \ missing in tempname (affects PKZIP)
+
+FCB find routines don't store the state correctly (affects DIR, NUSQ, GET)
+support for non-extended FCBs is broken (affects LAR)
+wrong device attributes reported after redirection (affects GZIP)
+REP IN/OUT not implemented
+find_next may not close fd
+tty modes wrong when running in terminal session
+devices not really implemented
+
+keyboard queue not fully implemented (affects VSAFE)
+several ioctl request not implemented (affects PKZOOM)
+no font file
+int 0x28 not implemented
+timer chip not implemented
+country info needs localization
+
+specific programs:
+charc crashes with a segment overrun
+sqwez gets a fault while exiting
+jrc outputs its banner again on exit, and sometimes complains about aa.aaa
diff --git a/usr.bin/doscmd/ParseBuffer.c b/usr.bin/doscmd/ParseBuffer.c
new file mode 100644
index 0000000..88c4771
--- /dev/null
+++ b/usr.bin/doscmd/ParseBuffer.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI ParseBuffer.c,v 2.2 1996/04/08 19:32:15 bostic Exp
+ *
+ * $Id: ParseBuffer.c,v 1.2 1996/09/22 05:52:53 miff Exp $
+ */
+
+#include <stdlib.h>
+
+int
+ParseBuffer(obuf, av, mac)
+char *obuf;
+char **av;
+int mac;
+{
+ static char *_buf;
+ char *buf;
+ static int buflen = 0;
+ int len;
+
+ register char *b = buf;
+ register char *p;
+ register char **a;
+ register char **e;
+
+ len = strlen(obuf) + 1;
+ if (len > buflen) {
+ if (buflen)
+ free(_buf);
+ buflen = (len + 1023) & ~1023;
+ _buf = malloc(buflen);
+ }
+ buf = _buf;
+ strcpy(buf, obuf);
+
+ a = av;
+ e = &av[mac];
+
+ while (*buf) {
+ while (*buf == ' ' || *buf == '\t' || *buf == '\n')
+ ++buf;
+ if (*buf) {
+ p = b = buf;
+
+ *a++ = buf;
+ if (a == e) {
+ a[-1] = (char *)0;
+ return(mac - 1);
+ }
+
+ while (*p && !(*p == ' ' || *p == '\t' || *p == '\n')) {
+ *b++ = *p++ & 0177;
+ }
+ if (*p)
+ ++p;
+ *b = 0;
+ buf = p;
+ }
+ }
+ *a = (char *)0;
+ return(a - av);
+}
diff --git a/usr.bin/doscmd/README b/usr.bin/doscmd/README
new file mode 100644
index 0000000..a15078c
--- /dev/null
+++ b/usr.bin/doscmd/README
@@ -0,0 +1,37 @@
+/* BSDI README,v 2.2 1996/04/08 19:32:16 bostic Exp*/
+
+This is the merged doscmd/rundos project. Please read the man
+page for help on configuring doscmd.
+
+Things known not to work:
+ * No mouse support (yet)
+ * No xms/ems support (yet)
+ * No raw VGA support (yet)
+ * Printer support (yet)
+ * COM ports (being worked on)
+ * redirected file system only supported for DOS 4.0 and above
+ (3.3 will be supported in a future version)
+ * Graphics in an X window (not planned to work)
+
+Even with this, I think it is actually a much better product. There have
+been problems reported with the ibmpc font and the distributed X server.
+If you have that problem, try setting
+
+ X11_FONT=fixed
+
+in your .doscmdrc. Be aware that graphics characters will not print correctly
+if you do this.
+
+You will need to patch your kernel. Diffs are provided against the CD-ROM.
+Please let me know if there are a problem with them (I am running a pre 1.1
+kernel now).
+
+It is possible there are some problems in the floppy code due to the fact
+that I am not set up to test under 1.0 at this point. I will be in a few
+days I hope.
+
+Please send all bug reports to prb@BSDI.COM.
+
+ -Paul Borman
+ prb@BSDI.COM
+ Jan 4 1994
diff --git a/usr.bin/doscmd/README.booting_dos b/usr.bin/doscmd/README.booting_dos
new file mode 100644
index 0000000..6172442
--- /dev/null
+++ b/usr.bin/doscmd/README.booting_dos
@@ -0,0 +1,89 @@
+/* BSDI README.booting_dos,v 2.2 1996/04/08 19:32:18 bostic Exp*/
+
+To install DOS on a pseudo hard disk under doscmd:
+
+ 1) Create a .doscmdrc with at least the following:
+
+ assign A: /dev/rfd0_1440_3.5 1440
+ assign A: /dev/rfd0_720_3.5 720
+ assign hard boot_drive 80 2 2
+
+ You may need to adjust the raw files for the A: drive to match
+ your system. This example will cause the HD drive to be tried
+ first and the DD drive second.
+
+ Note that you should only use raw devices or files at this point,
+ do not use a cooked device! (Well, it would probably be okay
+ for a hard disk, but certainly not the floppy)
+
+ boot_drive should be the file name of where you want your bootable
+ image to be. The three numbers which follow "80 2 2" say that the
+ drive will have 80 cylinders, 2 heads and 2 sectors per track.
+ This is the smallest drive possible which still can have MS DOS
+ 5.0 installed on it along with a config.sys and autoexec.bat file.
+
+ You might want to create a larger boot drive.
+
+ The file boot_drive must exist, so use the command touch to create
+ it.
+
+ 2) Insert a floppy disk into the A: drive which is bootable to MS-DOS
+ and has the commands fdisk, format and sys on it. You should also
+ copy the file instbsdi.exe onto the floppy by either mounting it
+ with the msdos file system type or by using mtools.
+
+ (i.e. mwrite instbsdi.exe a:)
+
+ 3) run doscmd.
+
+ 4) At the > prompt type "fdisk"
+
+ 5) Select "Create DOS partition or Logical Drive"
+
+ 6) Select "Create Primary DOS Partition"
+
+ 7) Tell it how big to make it (I say use the whole drive.
+ It is pretty tiny after all.)
+
+ 8) Get out of FDISK by hitting <ESC> a few times.
+
+ 9) doscmd will now abort (will try and fix this in a future version)
+
+ 10) start up doscmd again, leaving the floppy in the drive.
+
+ 11) At the > prompt, type "format c:" and follow the instructions.
+
+ 12) At the > prompt type "sys c:"
+
+ 13) Get out of doscmd.
+
+ 14) Either remove the floppy from the drive or add the line
+
+ boot C:
+
+ to your .doscmdrc
+
+ 15) You should now be running DOS off of your new disk. You will
+ probably want both config.sys and an autoexec.bat file. To
+ start with, you can say:
+
+ > copy con: config.sys
+ LASTDRIVE=Z
+ ^Z
+ > copy con: autoexec.bat
+ @echo off
+ instbsdi.exe
+ ^Z
+
+
+ 16) Quit doscmd.
+
+ 17) You know have a bootable pseudo disk which will automatically call
+ the magic "instbsdi" program, which installs BSDI disks. To use
+ them add lines to your .doscmdrc such as:
+
+ assign D: /usr/dos
+ assign P: -ro /usr/prb
+
+ Not ethat you will not always be able to access every file due to
+ naming problems.
diff --git a/usr.bin/doscmd/bios.c b/usr.bin/doscmd/bios.c
new file mode 100644
index 0000000..ea4090e
--- /dev/null
+++ b/usr.bin/doscmd/bios.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI bios.c,v 2.3 1996/04/08 19:32:19 bostic Exp
+ *
+ * $Id: bios.c,v 1.4 1996/09/22 15:42:47 miff Exp $
+ */
+
+#include "doscmd.h"
+#include "mouse.h"
+#include "com.h"
+
+#define BIOS_copyright 0xfe000
+#define BIOS_reset 0xfe05b
+#define BIOS_nmi 0xfe2c3
+#define BIOS_hdisk_table 0xfe401
+#define BIOS_boot 0xfe6f2
+#define BIOS_comm_table 0xfe729
+#define BIOS_comm_io 0xfe739
+#define BIOS_keyboard_io 0xfe82e
+#define BIOS_keyboard_isr 0xfe987
+#define BIOS_fdisk_io 0xfec59
+#define BIOS_fdisk_isr 0xfef57
+#define BIOS_disk_parms 0xfefc7
+#define BIOS_printer_io 0xfefd2
+#define BIOS_video_io 0xff065
+#define BIOS_video_parms 0xff0a4
+#define BIOS_mem_size 0xff841
+#define BIOS_equipment 0xff84d
+#define BIOS_cassette_io 0xff859
+#define BIOS_video_font 0xffa6e
+#define BIOS_time_of_day 0xffe6e
+#define BIOS_timer_int 0xffea5
+#define BIOS_vector 0xffef3
+#define BIOS_dummy_iret 0xfff53
+#define BIOS_print_screen 0xfff54
+#define BIOS_hard_reset 0xffff0
+#define BIOS_date_stamp 0xffff5
+#define BIOS_hardware_id 0xffffe
+
+static u_char video_parms[] = {
+ 0x38, 40, 0x2d, 10, 0x1f, 6, 0x19, 0x1c, 2, 7, 6, 7, 0, 0, 0, 0,
+ 0x71, 80, 0x5a, 10, 0x1f, 6, 0x19, 0x1c, 2, 7, 6, 7, 0, 0, 0, 0,
+ 0x38, 40, 0x2d, 10, 0x7f, 6, 0x64, 0x70, 2, 1, 6, 7, 0, 0, 0, 0,
+ 0x61, 80, 0x52, 15, 0x19, 6, 0x19, 0x19, 2, 13, 11, 12, 0, 0, 0, 0,
+};
+
+static u_char disk_params[] = {
+ 0xdf, 2, 0x25, 2, 0x0f, 0x1b, 0xff, 0x54, 0xf6, 0x0f, 8,
+};
+
+static u_short comm_table[] = {
+ 1047, 768, 384, 192, 96, 48, 24, 12,
+};
+
+/* exports */
+
+int nfloppies = 0;
+int ndisks = 0;
+int nserial = 0;
+int nparallel = 0;
+unsigned long rom_config;
+
+/*
+** BIOS equipment list
+*/
+static void
+int11(regcontext_t *REGS)
+{
+ R_AX =
+ (nfloppies ? 1:0) | /* do we have any floppydisks? */
+ (0x2 << 4) | /* 80x25 colour */
+ ((nfloppies-1) << 6) | /* how many floppies? */
+ (nserial << 9) | /* serial ports? */
+ (nparallel << 14); /* parallel ports? */
+}
+
+/*
+** get installed memory
+*/
+static void
+int12(regcontext_t *REGS)
+{
+ R_AX = 640;
+}
+
+/*
+** assorted oddments
+*/
+static void
+int15(regcontext_t *REGS)
+{
+ int cond;
+ int count;
+
+ R_FLAGS &= ~PSL_C;
+
+ switch (R_AH) {
+ case 0x00: /* Get Cassette Status */
+ R_AH = 0x86;
+ R_FLAGS |= PSL_C; /* We don't support a cassette */
+ break;
+
+ case 0x04: /* Set ABIOS table */
+ R_FLAGS |= PSL_C; /* We don't support it */
+ break;
+
+ case 0x4f:
+ /*
+ * XXX - Check scan code in GET8L(sc->sc_eax).
+ */
+ break;
+ case 0x88:
+ R_AX = 0; /* memory past 1M */
+ break;
+ case 0xc0: /* get configuration */
+ debug (D_TRAPS|0x15, "Get configuration\n", R_DX);
+ N_PUTVEC(R_ES, R_BX, rom_config);
+ R_AH = 0;
+ break;
+ case 0xc1: /* get extended BIOS data area */
+ R_FLAGS |= PSL_C;
+ break;
+ case 0xc2: /* Pointing device */
+ R_FLAGS |= PSL_C;
+ R_AH = 5; /* No pointer */
+ break;
+ default:
+ unknown_int2(0x15, R_AX, REGS);
+ break;
+ }
+}
+
+
+extern void int16(regcontext_t *REGS);
+extern void int17(regcontext_t *REGS);
+extern void int1a(regcontext_t *REGS);
+
+void
+bios_init(void)
+{
+ int i, j, k;
+ u_char *jtab;
+ struct timeval tv;
+ struct timezone tz;
+ struct tm tm;
+ u_long vec;
+
+ if (1 || !raw_kbd) {
+ strcpy((char *)BIOS_copyright,
+ "Copyright (C) 1993 Krystal Technologies/BSDI");
+
+ *(u_short *)BIOS_reset = 0xffcd;
+ *(u_short *)BIOS_nmi = 0xffcd;
+ *(u_short *)BIOS_boot = 0xffcd;
+ *(u_short *)BIOS_comm_io = 0xffcd;
+ *(u_short *)BIOS_keyboard_io = 0xffcd;
+ *(u_short *)BIOS_keyboard_isr = 0xffcd;
+ *(u_short *)BIOS_fdisk_io = 0xffcd;
+ *(u_short *)BIOS_fdisk_isr = 0xffcd;
+ *(u_short *)BIOS_printer_io = 0xffcd;
+ *(u_short *)BIOS_video_io = 0xffcd;
+ *(u_short *)BIOS_cassette_io = 0xffcd;
+ *(u_short *)BIOS_time_of_day = 0xffcd;
+ *(u_short *)BIOS_timer_int = 0xffcd;
+ *(u_short *)BIOS_dummy_iret = 0xffcd;
+ *(u_short *)BIOS_print_screen = 0xffcd;
+ *(u_short *)BIOS_hard_reset = 0xffcd;
+ *(u_short *)BIOS_mem_size = 0xffcd;
+ *(u_short *)BIOS_equipment = 0xffcd;
+ *(u_short *)BIOS_vector = 0xffcd;
+ *(u_char *)0xffff2 = 0xcf; /* IRET */
+
+ /*
+ *memcpy((u_char *)BIOS_video_parms, video_parms, sizeof(video_parms));
+ */
+ memcpy((u_char *)BIOS_disk_parms, disk_params, sizeof(disk_params));
+ memcpy((u_char *)BIOS_comm_table, comm_table, sizeof(comm_table));
+
+ *(u_short *)BIOS_video_font = 0xffcd;
+
+ jtab = (u_char *)BIOS_date_stamp;
+ *jtab++ = '1';
+ *jtab++ = '0';
+ *jtab++ = '/';
+ *jtab++ = '3';
+ *jtab++ = '1';
+ *jtab++ = '/';
+ *jtab++ = '9';
+ *jtab++ = '3';
+
+#if 0
+ *(u_char *)BIOS_hardware_id = 0xfe; /* Identify as a PC/XT */
+ *(u_char *)BIOS_hardware_id = 0xff; /* Identify as a PC */
+#endif
+ *(u_char *)BIOS_hardware_id = 0xfc; /* Identify as a PC/AT */
+ }
+
+ /*
+ * Interrupt revectors F000:0000 - F000:03ff
+ */
+ for (i = 0, j = 0, k = 0; i < 0x100; ++i) {
+ if ((i >= 0x60 && i < 0x68) ||
+ (i >= 0x78 && i < 0xe2))
+ continue;
+ if ((i >= 0x00 && i < 0x2f) ||
+ (i >= 0x30 && i < 0xfe)) {
+ ivec[i] = 0xF0300000L | (k * 1);
+ jtab = (u_char *)VECPTR(ivec[i]);
+ *jtab++ = 0xf4; /* HLT */
+ ++k;
+ } else {
+ ivec[i] = 0xF0000000L | (j * 6);
+ jtab = (u_char *)VECPTR(ivec[i]);
+ *jtab++ = 0xcd; /* INT i */
+ *jtab++ = i;
+ *jtab++ = 0xca; /* RETF 2 */
+ *jtab++ = 2;
+ *jtab++ = 0;
+ ++j;
+ }
+ }
+
+ /*
+ * Misc variables from F000:0400 - F000:0fff
+ */
+ rom_config = 0xF0000400;
+ jtab = (u_char *)VECPTR(rom_config);
+ *jtab++ = 20; /* length of entry */
+ *jtab++ = 0;
+ *jtab++ = *(u_char *)BIOS_hardware_id;
+ *jtab++ = 0x00; /* Sub model */
+ *jtab++ = 0x01; /* Bios Rev Enhanced kbd w/3.5" floppy */
+ *jtab++ = 0x20; /* real time clock present */
+ *jtab++ = 0; /* Reserved */
+ *jtab++ = 0;
+ *jtab++ = 0;
+ *jtab++ = 0;
+ strcpy((char *)jtab, "BSDI BIOS");
+ *jtab += 10;
+
+ InDOS = jtab++;
+ *InDOS = 0;
+
+ mouse_area = jtab;
+ jtab += 0x10;
+
+ *(u_short *)&BIOSDATA[0x10] =
+ (1 << 0) | /* Diskette avail for boot */
+ (1 << 1) | /* Math co-processor */
+ (nmice << 2) | /* No pointing device */
+ (2 << 4) | /* Initial video (80 x 25 C) */
+ (nfloppies - 1 << 6) | /* Number of floppies - 1 */
+ (nserial << 9) | /* Number of serial devices */
+ (nparallel << 14); /* Number of parallel devices */
+
+
+ *(u_short *)&BIOSDATA[0x13] = 640; /* Amount of memory */
+ BIOSDATA[0x75] = ndisks; /* number of fixed disks */
+
+ BIOSDATA[0x8F] = 0;
+ if (nfloppies >= 1) {
+ BIOSDATA[0x8F] |= 0x04;
+ BIOSDATA[0x90] = 0x40;
+ }
+ if (nfloppies >= 2) {
+ BIOSDATA[0x8F] |= 0x40;
+ BIOSDATA[0x91] = 0x40;
+ }
+
+ gettimeofday(&tv, &tz);
+ tm = *localtime(&tv.tv_sec);
+ *(u_long *)&BIOSDATA[0x6c] =
+ (((tm.tm_hour * 60 + tm.tm_min) * 60) + tm.tm_sec) * 182 / 10;
+
+ vec = insert_softint_trampoline();
+ ivec[0x11] = vec;
+ register_callback(vec, int11, "int 11");
+
+ vec = insert_softint_trampoline();
+ ivec[0x12] = vec;
+ register_callback(vec, int12, "int 12");
+
+ vec = insert_softint_trampoline();
+ ivec[0x14] = vec;
+ register_callback(vec, int14, "int 14");
+
+ vec = insert_softint_trampoline();
+ ivec[0x15] = vec;
+ register_callback(vec, int15, "int 15");
+
+ vec = insert_softint_trampoline();
+ ivec[0x16] = vec;
+ register_callback(vec, int16, "int 16");
+
+ vec = insert_softint_trampoline();
+ ivec[0x17] = vec;
+ register_callback(vec, int17, "int 17");
+
+ vec = insert_softint_trampoline();
+ ivec[0x1a] = vec;
+ register_callback(vec, int1a, "int 1a");
+}
diff --git a/usr.bin/doscmd/callback.c b/usr.bin/doscmd/callback.c
new file mode 100644
index 0000000..4b333ec
--- /dev/null
+++ b/usr.bin/doscmd/callback.c
@@ -0,0 +1,120 @@
+/* No copyright?!
+**
+** $Id: callback.c,v 1.3 1996/09/24 00:02:25 miff Exp $
+*/
+
+
+#include <sys/queue.h>
+#include "doscmd.h"
+
+/*
+** Callbacks are used for chaining interrupt handlers
+** off interrupt vectors
+*/
+
+struct callback {
+ LIST_ENTRY(callback) chain;
+ u_long vec;
+ callback_t func;
+ char *name;
+};
+
+LIST_HEAD(cbhead , callback) cbhead[127];
+
+#define CBHASH(x) (((x) * 17) % 127)
+
+/*
+** Register (func) as a handler for (vec)
+*/
+void
+register_callback(u_long vec, callback_t func, char *name)
+{
+ struct cbhead *head;
+ struct callback *elm;
+
+ elm = malloc(sizeof(struct callback));
+ elm->vec = vec;
+ elm->func = func;
+ elm->name = name;
+
+ head = &cbhead[CBHASH(vec)];
+ LIST_INSERT_HEAD(head, elm, chain);
+}
+
+/*
+** Find a handler for (vec)
+*/
+callback_t
+find_callback(u_long vec)
+{
+ struct cbhead *head;
+ struct callback *elm;
+
+ head = &cbhead[CBHASH(vec)];
+ for (elm = head->lh_first; elm; elm = elm->chain.le_next)
+ if (elm->vec == vec)
+ break;
+ if (elm) {
+ debug(D_TRAPS2, "callback %s\n", elm->name);
+ return (elm->func);
+ } else
+ return ((callback_t)0);
+}
+
+u_long trampoline_rover = 0xF1000000;
+
+/*
+ * Interrupts are disabled on an INTn call, so we must restore interrupts
+ * before via STI returning. IRET is not used here because 1) some DOS
+ * calls want to return status via the FLAGS register, and 2) external
+ * routines which hook INTn calls do not always put a FLAGS image on the
+ * stack which re-enables interrupts.
+ */
+u_char softint_trampoline[] = {
+ 0xf4, /* HLT */
+ 0xfb, /* STI */
+ 0xca, /* RETF 2 */
+ 2,
+ 0,
+};
+u_char hardint_trampoline[] = {
+ 0xf4, /* HLT */
+ 0xcf, /* IRET */
+};
+u_char null_trampoline[] = {
+ 0xcf, /* IRET */
+};
+
+u_long
+insert_generic_trampoline(size_t len, u_char *p)
+{
+ u_char *q;
+ u_long where;
+
+ where = trampoline_rover;
+ q = (u_char *)VECPTR(where);
+ memcpy(q, p, len);
+ trampoline_rover += len;
+ return (where);
+}
+
+u_long
+insert_softint_trampoline(void)
+{
+ return (insert_generic_trampoline(
+ sizeof(softint_trampoline), softint_trampoline));
+}
+
+u_long
+insert_hardint_trampoline(void)
+{
+ return (insert_generic_trampoline(
+ sizeof(hardint_trampoline), hardint_trampoline));
+}
+
+u_long
+insert_null_trampoline(void)
+{
+ return (insert_generic_trampoline(
+ sizeof(null_trampoline), null_trampoline));
+}
diff --git a/usr.bin/doscmd/callback.h b/usr.bin/doscmd/callback.h
new file mode 100644
index 0000000..f81127e
--- /dev/null
+++ b/usr.bin/doscmd/callback.h
@@ -0,0 +1,13 @@
+/*
+** No copyright?!
+**
+** $Id: callback.h,v 1.4 1996/09/22 15:42:48 miff Exp $
+*/
+typedef void (*callback_t)(regcontext_t *REGS);
+
+extern void register_callback(u_long vec, callback_t func, char *name);
+extern callback_t find_callback(u_long vec);
+extern u_long insert_generic_trampoline(size_t len, u_char *p);
+extern u_long insert_softint_trampoline(void);
+extern u_long insert_hardint_trampoline(void);
+extern u_long insert_null_trampoline(void);
diff --git a/usr.bin/doscmd/cmos.c b/usr.bin/doscmd/cmos.c
new file mode 100644
index 0000000..115cbc7
--- /dev/null
+++ b/usr.bin/doscmd/cmos.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI cmos.c,v 2.3 1996/04/08 19:32:20 bostic Exp
+ *
+ * $Id: cmos.c,v 1.2 1996/09/18 16:12:24 miff Exp $
+ */
+
+#include "doscmd.h"
+
+#define ALARM_ON ((unsigned char) 0x20)
+#define FAST_TIMER ((unsigned char) 0x40)
+#define SEC_SIZE 1
+#define MIN_SIZE 60
+#define HOUR_SIZE (MIN_SIZE * 60)
+#define DAY_SIZE (HOUR_SIZE * 24)
+#define YEAR_DAY 365
+
+#define SEC_MS 1000000
+#define FAST_TICK_BSD 0x3D00
+
+#define Jan 31
+#define Feb 28
+#define Mar 31
+#define Apr 30
+#define May 31
+#define Jun 30
+#define Jul 31
+#define Aug 31
+#define Sep 31
+#define Oct 31
+#define Nov 30
+#define Dec 31
+
+static unsigned char cmos_last_port_70 = 0;
+static unsigned char cmos_data[0x40] = {
+ 0x00, /* 0x00 Current Second */
+ 0x00, /* 0x01 Alarm Second */
+ 0x00, /* 0x02 Current minute */
+ 0x00, /* 0x03 Alarm minute */
+ 0x00, /* 0x04 Current hour */
+ 0x00, /* 0x05 Alarm hour */
+ 0x00, /* 0x06 Current week day */
+ 0x00, /* 0x07 Current day */
+ 0x00, /* 0x08 Current month */
+ 0x00, /* 0x09 Current year */
+ 0x26, /* 0x0A Status register A */
+ 0x02, /* 0x0B Status register B */
+ 0x00, /* 0x0C Status register C */
+ 0x80, /* 0x0D Status register D */
+ 0x00, /* 0x0E Diagnostic status */
+ 0x00, /* 0x0F Shutdown Code */
+ 0x00, /* 0x10 Drive types (1 FDHD disk) */
+ 0x00, /* 0x11 Fixed disk 0 type */
+ 0x00, /* 0x12 Fixed disk 1 type */
+ 0x00,
+ 0x00, /* Installed equipment */
+};
+
+int day_in_year [12] = {
+ 0, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov
+};
+
+/* consumed by dos.c */
+time_t delta_clock = 0;
+
+/* locals */
+static int fast_delta_uclock;
+static struct timeval fast_clock;
+static int fast_tick;
+
+static struct timeval glob_clock;
+static int cmos_alarm_time = 0;
+static int cmos_alarm_daytime = 0;
+
+static inline int
+day_in_mon_year (mon, year)
+{
+ return day_in_year[mon] + (mon > 2 && (year % 4 == 0));
+}
+
+static inline int
+to_BCD (int n)
+{
+ n &= 0xFF;
+ return n%10 + ((n/10)<<4);
+}
+
+static inline int
+from_BCD (int n)
+{
+ n &= 0xFF;
+ return (n & 0xF) + (n >> 4) * 10;
+}
+
+/*
+** inb() from clock ports.
+**
+** 0x70 is scratchpad/register select
+** 0x71 is data
+*/
+static unsigned char
+cmos_inb(int portnum)
+{
+ unsigned char ret_val;
+ int cmos_reg;
+ struct timezone tz;
+ struct tm tm;
+ time_t now;
+
+ switch (portnum) {
+ case 0x70:
+ ret_val = cmos_last_port_70;
+ break;
+ case 0x71:
+ cmos_reg = cmos_last_port_70 & 0x3f;
+ if (cmos_reg < 0xa) {
+ gettimeofday(&glob_clock, &tz);
+ now = glob_clock.tv_sec + delta_clock;
+ tm = *localtime(&now);
+ }
+ switch (cmos_reg) {
+ case 0:
+ ret_val = to_BCD(tm.tm_sec);
+ break;
+ case 2:
+ ret_val = to_BCD(tm.tm_min);
+ break;
+ case 4:
+ ret_val = to_BCD(tm.tm_hour);
+ break;
+ case 6:
+ ret_val = to_BCD(tm.tm_wday);
+ break;
+ case 7:
+ ret_val = to_BCD(tm.tm_mday);
+ break;
+ case 8:
+ ret_val = to_BCD(tm.tm_mon + 1);
+ break;
+ case 9:
+ ret_val = to_BCD((tm.tm_year + 1900) % 100);
+ break;
+ default:
+ ret_val = cmos_data[cmos_reg];
+ break;
+ }
+ break;
+ }
+ return (ret_val);
+}
+
+static void
+cmos_outb(int portnum, unsigned char byte)
+{
+ int cmos_reg;
+ int year;
+ int time00;
+ struct timezone tz;
+ struct tm tm;
+ time_t now;
+
+ switch (portnum) {
+ case 0x70:
+ cmos_last_port_70 = byte;
+ break;
+ case 0x71:
+ cmos_reg = cmos_last_port_70 & 0x3f;
+ if (cmos_reg < 0xa) {
+ gettimeofday(&glob_clock, &tz);
+ now = glob_clock.tv_sec + delta_clock;
+ tm = *localtime(&now);
+ }
+ switch (cmos_reg) {
+ case 0:
+ delta_clock += SEC_SIZE * (from_BCD(byte) - tm.tm_sec);
+ break;
+ case 1:
+ cmos_alarm_daytime +=
+ SEC_SIZE * (from_BCD(byte) - from_BCD(cmos_data[1]));
+ break;
+ case 2:
+ delta_clock += MIN_SIZE * (from_BCD(byte) - tm.tm_min);
+ break;
+ case 3:
+ cmos_alarm_daytime +=
+ MIN_SIZE * (from_BCD(byte) - from_BCD(cmos_data[3]));
+ break;
+ case 4:
+ delta_clock += HOUR_SIZE * (from_BCD(byte) - tm.tm_hour);
+ break;
+ case 5:
+ cmos_alarm_daytime +=
+ HOUR_SIZE * (from_BCD(byte) - from_BCD(cmos_data[5]));
+ break;
+ case 7:
+ delta_clock += DAY_SIZE * (from_BCD(byte) - tm.tm_mday);
+ break;
+ case 8:
+ delta_clock += DAY_SIZE *
+ (day_in_mon_year(from_BCD(byte), tm.tm_year) -
+ day_in_mon_year(tm.tm_mon + 1, tm.tm_year));
+ break;
+ case 9:
+ year = from_BCD(byte);
+ delta_clock += DAY_SIZE * (YEAR_DAY * (year - tm.tm_year)
+ + (year/4 - tm.tm_year/4));
+ break;
+ case 0xB:
+ cmos_data[0xc] = byte;
+ if (byte & ALARM_ON) {
+ debug(D_ALWAYS, "Alarm turned on\n");
+ time00 = glob_clock.tv_sec + delta_clock -
+ (tm.tm_sec + MIN_SIZE * tm.tm_min
+ + HOUR_SIZE * tm.tm_hour);
+ cmos_alarm_time = time00 + cmos_alarm_daytime;
+ if (cmos_alarm_time < (glob_clock.tv_sec + delta_clock))
+ cmos_alarm_time += DAY_SIZE;
+ }
+ if (byte & FAST_TIMER) {
+ debug(D_ALWAYS, "Fast timer turned on\n");
+ fast_clock = glob_clock;
+ fast_tick = 0;
+ }
+ break;
+ }
+ cmos_data[cmos_reg] = byte;
+ break;
+ }
+}
+
+
+void
+cmos_init(void)
+{
+ int numflops = 0;
+ int checksum = 0;
+ int i;
+
+ cmos_data[0x0e] = 0;
+
+ numflops = nfloppies;
+ cmos_data[0x10] = (search_floppy(0) << 4) | search_floppy(1);
+
+ if (numflops) /* floppy drives present + numflops */
+ cmos_data[0x14] = ((numflops - 1) << 6) | 1;
+
+ cmos_data[0x15] = 0x80; /* base memory 640k */
+ cmos_data[0x16] = 0x2;
+ for (i=0x10; i<=0x2d; i++)
+ checksum += cmos_data[i];
+ cmos_data[0x2e] = checksum >>8; /* High byte */
+ cmos_data[0x2f] = checksum & 0xFF; /* Low byte */
+
+ cmos_data[0x32] = 0x19; /* Century in BCD ; temporary */
+
+ for (i = 1; i < 12; i++){
+ day_in_year[i] += day_in_year[i-1];
+ }
+
+ define_input_port_handler(0x70, cmos_inb);
+ define_input_port_handler(0x71, cmos_inb);
+ define_output_port_handler(0x70, cmos_outb);
+ define_output_port_handler(0x71, cmos_outb);
+}
diff --git a/usr.bin/doscmd/com.h b/usr.bin/doscmd/com.h
new file mode 100644
index 0000000..c2857e2
--- /dev/null
+++ b/usr.bin/doscmd/com.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI com.h,v 2.2 1996/04/08 19:32:21 bostic Exp
+ *
+ * $Id: com.h,v 1.3 1996/09/22 15:42:48 miff Exp $
+ */
+
+/* com.h for doscmd int14.c */
+
+#define BUFSIZE 1024
+
+/* NS16550A register definitions */
+
+/* interrupt enable register */
+
+#define IE_NOP 0xF0 /* not used */
+#define IE_MODEM_STAT 0x08 /* modem status int. */
+#define IE_LINE_STAT 0x04 /* receiver-line status int. */
+#define IE_TRANS_HLD 0x02 /* transmitter holding register empty int. */
+#define IE_RCV_DATA 0x01 /* received data available int. */
+
+/* interrupt identification register */
+
+#define II_FIFOS_EN 0xC0 /* if FIFOs are enabled */
+#define II_NOP 0x38 /* not used */
+#define II_INT_ID 0x06 /* mask: bits see below */
+#define II_PEND_INT 0x01 /* 1=no interrupt pending */
+
+/* bit masks for II_INT_ID */
+
+#define II_LINE_STAT 0x06
+#define II_RCV_DATA 0x04
+#define II_TRANS_HLD 0x02
+#define II_MODEM_STAT 0x00
+
+/* FIFO control reg */
+
+#define FC_FIFO_EN 0x01
+
+/* line control register */
+
+#define LC_DIV_ACC 0x80 /* divisor latch access bit */
+#define LC_BRK_CTRL 0x40 /* set break control */
+#define LC_S_PAR 0x20 /* stick parity */
+#define LC_EVEN_P 0x10 /* even parity select */
+#define LC_PAR_E 0x08 /* parity enable */
+#define LC_STOP_B 0x04 /* number of stop bits (0 - 1 bit) */
+#define LC_W_LEN 0x03 /* unsigned short length (00 - 5, 01 - 6 etc.) */
+
+/* line status register */
+
+#define LS_NOP 0x80 /* not used */
+#define LS_X_SHFT_E 0x40 /* 0=data transfer, 1=transmitter idle */
+#define LS_X_HOLD_E 0x20 /* 0=ready, 1=transferring character */
+#define LS_BREAK 0x10 /* break received */
+#define LS_FRM_ERR 0x08 /* framing error */
+#define LS_PAR_ERR 0x04 /* parity error */
+#define LS_OVRN_ERR 0x02 /* overrun error */
+#define LS_RCV_DATA_RD 0x01 /* data received */
+
+/* modem status register */
+
+#define MS_DCD 0x80 /* Data Carrier Detect in */
+#define MS_RI 0x40 /* Ring Indicator in */
+#define MS_DSR 0x20 /* Data Set Ready in */
+#define MS_CTS 0x10 /* Clear To Send in */
+#define MS_DELTA_DCD 0x08 /* Data Carrier Detect changed state */
+#define MS_DELTA_RI 0x04 /* Ring Indicator changed state */
+#define MS_DELTA_DSR 0x02 /* Data Set Ready changed state */
+#define MS_DELTA_CTS 0x01 /* Clear To Send changed state */
+
+/* data structure definitions */
+
+#define N_OF_COM_REGS 8
+
+struct com_data_struct {
+ int fd; /* BSD/386 file descriptor */
+ char *path; /* BSD/386 pathname */
+ int addr; /* ISA I/O address */
+ unsigned char irq; /* ISA IRQ */
+ unsigned char flags; /* some general software flags */
+
+ struct queue *com_queue; /* XXX DEBUG obsolete MCL? */
+
+ unsigned char div_latch[2]; /* mirror of 16550 R0':R1' read/write */
+ unsigned char last_char_read; /* mirror of 16550 R0 read only */
+ unsigned char int_enable; /* mirror of 16550 R1 read/write */
+ unsigned char int_id; /* mirror of 16550 R2 read only */
+ unsigned char fifo_ctrl; /* mirror of 16550 R2 write only */
+ unsigned char line_ctrl; /* mirror of 16550 R3 read/write */
+ unsigned char modem_ctrl; /* mirror of 16550 R4 read/write */
+ unsigned char line_stat; /* mirror of 16550 R5 read/write */
+ unsigned char modem_stat; /* mirror of 16550 R6 read/write */
+ unsigned char uart_spare; /* mirror of 16550 R7 read/write */
+};
+
+/* DOS definitions -- parameters */
+
+#define BITRATE_110 0x00
+#define BITRATE_150 0x20
+#define BITRATE_300 0x40
+#define BITRATE_600 0x60
+#define BITRATE_1200 0x80
+#define BITRATE_2400 0xA0
+#define BITRATE_4800 0xC0
+#define BITRATE_9600 0xE0
+#define PARITY_NONE 0x00
+#define PARITY_ODD 0x08
+#define PARITY_EVEN 0x18
+#define STOPBIT_1 0x00
+#define STOPBIT_2 0x04
+#define TXLEN_7BITS 0x02
+#define TXLEN_8BITS 0x03
+
+/* DOS definitions -- return codes */
+
+#define LS_SW_TIME_OUT LS_NOP /* return value used by DOS */
+
+/* miscellaneous definitions */
+
+#define DIV_LATCH_LOW 0
+#define DIV_LATCH_HIGH 1
+
+#define DIV_LATCH_LOW_WRITTEN 0x01
+#define DIV_LATCH_HIGH_WRITTEN 0x02
+#define DIV_LATCH_BOTH_WRITTEN 0x03
+
+/* variable declarations */
+
+extern int errno;
+
+/* routine declarations */
+
+extern void int14(regcontext_t *REGS);
+extern void com_set_line(struct com_data_struct *, unsigned char, unsigned char);
+extern void init_com(int, char *, int, unsigned char);
+extern u_char com_port_in(int);
+extern void com_port_out(int, unsigned char);
+
+/* end of file com.h */
diff --git a/usr.bin/doscmd/config.c b/usr.bin/doscmd/config.c
new file mode 100644
index 0000000..c6463d8
--- /dev/null
+++ b/usr.bin/doscmd/config.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI config.c,v 2.2 1996/04/08 19:32:22 bostic Exp
+ *
+ * $Id: config.c,v 1.2 1996/09/18 16:12:24 miff Exp $
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "doscmd.h"
+
+/*
+** doscmdrc parser
+*/
+int
+read_config(FILE *fp)
+{
+ char *buffer;
+ char _buffer[1024];
+ char *_av[16];
+ char **av;
+ int ac;
+ int bootdrive = -1;
+
+ while (buffer = fgets(_buffer, sizeof(_buffer), fp)) {
+ char *comment = strchr(buffer, '#');
+ char *equal;
+
+ if (comment)
+ *comment = 0;
+
+ while (isspace(*buffer))
+ ++buffer;
+ if (!*buffer)
+ continue;
+
+ /*
+ * Strip <CR><LF>
+ */
+ comment = buffer;
+ while (*comment && *comment != '\n' && *comment != '\r')
+ ++comment;
+ *comment = 0;
+
+ /*
+ * Check to see if this is to go in the environment
+ */
+ equal = buffer;
+ while (*equal && *equal != '=' && !isspace(*equal))
+ ++equal;
+
+ if (*equal == '=') {
+ if (strncmp(buffer, "MS_VERSION=", 11) == 0)
+ setver(0, strtol(equal + 1, 0, 0));
+ else if (strncmp(buffer, "X11_FONT=", 9) == 0)
+ xfont = strdup(equal + 1);
+ else
+ put_dosenv(buffer);
+ continue;
+ }
+
+ ac = ParseBuffer(buffer, av = _av, 16);
+
+ if (ac == 0)
+ continue;
+ if (!strcasecmp(av[0], "assign")) {
+ int drive = -1;
+ int printer;
+ int ro = 0;
+
+ if (ac < 2) {
+ fprintf(stderr, "Usage: assign device ...\n");
+ quit(1);
+ }
+ if (av[2] && !strcasecmp(av[2], "-ro")) {
+ av[2] = av[1];
+ av[1] = av[0];
+ ++av;
+ --ac;
+ ro = 1;
+ }
+ if (!strncasecmp(av[1], "lpt", 3)) {
+ if (av[1][3] < '1' || av[1][3] > '4'
+ || av[1][4] != ':' || ac < 3) {
+ fprintf(stderr, "Usage: assign lptn: [direct] lpr-name [ time-out]\n");
+ quit(1);
+ }
+ printer = av[1][3] - '1';
+ if (strchr(av[2], '/')) {
+ printer_direct(printer);
+ printer_spool(printer, av[2]);
+ } else if (!strcasecmp(av[2], "direct")) {
+ printer_direct(printer);
+ printer_spool(printer, 0);
+ } else {
+ printer_spool(printer, av[2]);
+ if (ac == 4)
+ printer_timeout(printer, av[3]);
+ }
+ } else if (!strncasecmp(av[1], "flop", 4)) {
+ if (ac != 4) {
+ fprintf(stderr, "Usage: assign flop [-ro] file type\n");
+ quit(1);
+ }
+
+ if (isdigit(av[1][4])) {
+ drive = atoi(&av[1][4]) - 1;
+ } else if (islower(av[1][4]) && av[1][5] == ':' && !av[1][6]) {
+ drive = av[1][4] - 'a';
+ } else if (isupper(av[1][4]) && av[1][5] == ':' && !av[1][6]) {
+ drive = av[1][4] - 'A';
+ }
+init_soft:
+ drive = init_floppy(drive, atoi(av[3]), av[2]);
+ if (ro)
+ make_readonly(drive);
+ } else if (!strncasecmp(av[1], "hard", 4)) {
+ int cyl, head, sec;
+
+ if (isdigit(av[1][4])) {
+ drive = atoi(&av[1][4]) + 1;
+ } else if (islower(av[1][4]) && av[1][5] == ':' && !av[1][6]) {
+ drive = av[1][4] - 'a';
+ } else if (isupper(av[1][4]) && av[1][5] == ':' && !av[1][6]) {
+ drive = av[1][4] - 'A';
+ }
+
+init_hard:
+ switch (ac) {
+ default:
+ fprintf(stderr, "Usage: assign [A-Z]: [-ro] directory\n"
+ " assign hard [-ro] file type [boot_sector]\n"
+ " assign hard [-ro] file cylinders heads sectors/track [boot_sector]\n");
+ quit(1);
+ case 5:
+ case 4:
+ if (!map_type(atoi(av[3]), &cyl, &head, &sec)) {
+ fprintf(stderr, "%s: invalid type\n", av[3]);
+ quit(1);
+ }
+ drive = init_hdisk(drive, cyl, head, sec, av[2], av[4]);
+ if (ro)
+ make_readonly(drive);
+ break;
+ case 7:
+ case 6:
+ drive = init_hdisk(drive, atoi(av[3]), atoi(av[4]), atoi(av[5]),
+ av[2], av[6]);
+ if (ro)
+ make_readonly(drive);
+ break;
+ }
+ } else if (av[1][1] == ':') {
+ if (av[1][2] || !isalpha(av[1][0])) {
+ fprintf(stderr, "Usage: assign [A-Z]: ...\n");
+ quit(1);
+ }
+ if (isupper(av[1][0]))
+ drive = av[1][0] - 'A';
+ else
+ drive = av[1][0] - 'a';
+
+ if (ac == 3) {
+ init_path(drive, (u_char *)av[2], 0);
+ if (ro)
+ dos_makereadonly(drive);
+ } else if (drive < 2)
+ goto init_soft;
+ else
+ goto init_hard;
+ } else if (!strncasecmp(av[1], "com", 3)) {
+ int port;
+ int addr;
+ unsigned char irq;
+ int i;
+
+ if ((ac != 5) || (!isdigit(av[1][3]))) {
+ fprintf(stderr, "Usage: assign com[1-4] path addr irq\n");
+ quit(1);
+ }
+ port = atoi(&av[1][3]) - 1;
+ if ((port < 0) || (port > (N_COMS_MAX - 1))) {
+ fprintf(stderr, "Usage: assign com[1-4] path addr irq\n");
+ quit(1);
+ }
+ errno = 0;
+ addr = (int)strtol(av[3], '\0', 0);
+ /* XXX DEBUG ISA-specific */
+ if ((errno != 0) || (addr > MAXPORT)) {
+ fprintf(stderr, "Usage: assign com[1-4] path addr irq\n");
+ quit(1);
+ }
+ errno = 0;
+ irq = (unsigned char)strtol(av[4], '\0', 0);
+ /* XXX DEBUG ISA-specific */
+ if ((errno != 0) || (irq < 1) || (irq > 15)) {
+ fprintf(stderr, "Usage: assign com[1-4] path addr irq\n");
+ quit(1);
+ }
+ init_com(port, av[2], addr, irq);
+ } else {
+ fprintf(stderr, "Usage: assign flop ...\n");
+ fprintf(stderr, " assign hard ...\n");
+ fprintf(stderr, " assign [A-Z]: ...\n");
+ fprintf(stderr, " assign comX ...\n");
+ quit(1);
+ }
+ } else if (!strcasecmp(av[0], "boot")) {
+ if (ac != 2 || av[1][2] || !isalpha(av[1][0])) {
+ fprintf(stderr, "Usage: boot [A: | C:]\n");
+ quit(1);
+ }
+ if (isupper(av[1][0]))
+ bootdrive = av[1][0] - 'A';
+ else
+ bootdrive = av[1][0] - 'a';
+ if (bootdrive != 0 && bootdrive != 2) {
+ fprintf(stderr, "Boot drive must be either A: or C:\n");
+ quit(1);
+ }
+ } else if (!strcasecmp(av[0], "setver")) {
+ int v;
+ if (ac != 3 || !(v = strtol(av[2], 0, 0))) {
+ fprintf(stderr, "Usage: setver command version\n");
+ quit(1);
+ }
+ setver(av[1], v);
+ } else {
+ fprintf(stderr, "%s: invalid command\n", av[0]);
+ quit(1);
+ }
+ }
+ fclose(fp);
+ return(bootdrive);
+}
diff --git a/usr.bin/doscmd/cpu.c b/usr.bin/doscmd/cpu.c
new file mode 100644
index 0000000..bad8725
--- /dev/null
+++ b/usr.bin/doscmd/cpu.c
@@ -0,0 +1,70 @@
+/*
+** No copyright ?!
+**
+** $Id: cpu.c,v 1.5 1996/09/25 11:05:54 miff Exp $
+*/
+#include "doscmd.h"
+
+/*
+** Hardware /0 interrupt
+*/
+void
+int00(regcontext_t *REGS)
+{
+ debug(D_ALWAYS, "Divide by 0 in DOS program!\n");
+ exit(1);
+}
+
+void
+int01(regcontext_t *REGS)
+{
+ debug(D_ALWAYS, "INT 1 with no handler! (single-step/debug)\n");
+}
+
+void
+int03(regcontext_t *REGS)
+{
+ debug(D_ALWAYS, "INT 3 with no handler! (breakpoint)\n");
+}
+
+void
+int0d(regcontext_t *REGS)
+{
+ debug(D_ALWAYS, "IRQ5 with no handler!\n");
+}
+
+void
+cpu_init(void)
+{
+ u_long vec;
+
+ vec = insert_hardint_trampoline();
+ ivec[0x00] = vec;
+ register_callback(vec, int00, "int 00");
+
+ vec = insert_softint_trampoline();
+ ivec[0x01] = vec;
+ register_callback(vec, int01, "int 01");
+
+ vec = insert_softint_trampoline();
+ ivec[0x03] = vec;
+ register_callback(vec, int03, "int 03");
+
+ vec = insert_hardint_trampoline();
+ ivec[0x0d] = vec;
+ register_callback(vec, int0d, "int 0d");
+
+ vec = insert_null_trampoline();
+ ivec[0x34] = vec; /* floating point emulator */
+ ivec[0x35] = vec; /* floating point emulator */
+ ivec[0x36] = vec; /* floating point emulator */
+ ivec[0x37] = vec; /* floating point emulator */
+ ivec[0x38] = vec; /* floating point emulator */
+ ivec[0x39] = vec; /* floating point emulator */
+ ivec[0x3a] = vec; /* floating point emulator */
+ ivec[0x3b] = vec; /* floating point emulator */
+ ivec[0x3c] = vec; /* floating point emulator */
+ ivec[0x3d] = vec; /* floating point emulator */
+ ivec[0x3e] = vec; /* floating point emulator */
+ ivec[0x3f] = vec; /* floating point emulator */
+}
diff --git a/usr.bin/doscmd/crt0.c b/usr.bin/doscmd/crt0.c
new file mode 100644
index 0000000..9b3779b
--- /dev/null
+++ b/usr.bin/doscmd/crt0.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI crt0.c,v 2.2 1996/04/08 19:32:24 bostic Exp
+ *
+ * $Id: crt0.c,v 1.2 1996/09/18 16:12:25 miff Exp $
+ */
+
+char **environ;
+char *__progname;
+
+start(int argc, char **argv, char **env)
+{
+ environ = env;
+ __progname = *argv;
+ quit(main(argc, argv, environ));
+}
diff --git a/usr.bin/doscmd/cwd.c b/usr.bin/doscmd/cwd.c
new file mode 100644
index 0000000..df27ff2
--- /dev/null
+++ b/usr.bin/doscmd/cwd.c
@@ -0,0 +1,970 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI cwd.c,v 2.2 1996/04/08 19:32:25 bostic Exp
+ *
+ * $Id: cwd.c,v 1.6 1996/09/23 09:59:23 miff Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "doscmd.h"
+
+#define D_REDIR 0x0080000 /* XXX - ack */
+#define D_TRAPS3 0x0200000
+
+typedef struct {
+ u_char *path;
+ u_char *cwd;
+ int len;
+ int maxlen;
+ int read_only:1;
+} Path_t;
+
+typedef struct Name_t {
+ u_char *real;
+ struct Name_t *next;
+ u_char name[9];
+ u_char ext[4];
+} Name_t;
+
+
+#define MAX_DRIVE 26
+
+static Path_t paths[MAX_DRIVE] = { 0, };
+static Name_t *names;
+
+extern int diskdrive;
+
+/*
+ * Initialize the drive to be based at 'base' in the BSD filesystem
+ */
+void
+init_path(int drive, u_char *base, u_char *dir)
+{
+ Path_t *d;
+
+ if (drive < 0 || drive >= MAX_DRIVE)
+ return;
+
+ debug(D_TRAPS3, "init_path(%d, %s, %s)\n", drive, base, dir);
+
+ d = &paths[drive];
+
+ if (d->path)
+ free(d->path);
+
+ if ((d->path = ustrdup(base)) == NULL)
+ fatal("strdup in init_path for %c:%s: %s", drive + 'A', base,
+ strerror(errno));
+
+ if (d->maxlen < 2) {
+ d->maxlen = 128;
+ if ((d->cwd = (u_char *)malloc(d->maxlen)) == NULL)
+ fatal("malloc in init_path for %c:%s: %s", drive + 'A', base,
+ strerror(errno));
+ }
+
+ d->cwd[0] = '\\';
+ d->cwd[1] = 0;
+ d->len = 1;
+ if (dir) {
+ if (ustrncmp(base, dir, ustrlen(base)) == 0)
+ dir += ustrlen(base);
+ while (*dir == '/')
+ ++dir;
+
+ while (*dir) {
+ u_char dosname[15];
+ u_char realname[256];
+ u_char *r = realname;;
+
+ while ((*r = *dir) && *dir++ != '/') {
+ ++r;
+ }
+ *r = 0;
+ while (*dir == '/')
+ ++dir;
+
+ dosname[0] = drive + 'A';
+ dosname[1] = ':';
+ real_to_dos(realname, &dosname[2]);
+
+ if (dos_setcwd(dosname)) {
+ fprintf(stderr, "Failed to CD to directory %s in %s\n",
+ dosname, d->cwd);
+ }
+ }
+ }
+}
+
+/*
+ * Mark this drive as read only
+ */
+void
+dos_makereadonly(int drive)
+{
+
+ if (drive < 0 || drive >= MAX_DRIVE)
+ return;
+ paths[drive].read_only = 1;
+}
+
+/*
+ * Return read-only status of drive
+ */
+int
+dos_readonly(int drive)
+{
+
+ if (drive < 0 || drive >= MAX_DRIVE)
+ return (0);
+ debug(D_REDIR, "dos_readonly(%d) -> %d\n", drive, paths[drive].read_only);
+ return (paths[drive].read_only);
+}
+
+/*
+ * Return DOS's idea of the CWD for drive
+ * Return 0 if the drive specified is not mapped (or bad)
+ */
+u_char *
+dos_getcwd(int drive)
+{
+
+ if (drive < 0 || drive >= MAX_DRIVE)
+ return (0);
+ debug(D_REDIR, "dos_getcwd(%d) -> %s\n", drive, paths[drive].cwd);
+ return (paths[drive].cwd);
+}
+
+/*
+ * Return DOS's idea of the CWD for drive
+ * Return 0 if the drive specified is not mapped (or bad)
+ */
+u_char *
+dos_getpath(int drive)
+{
+
+ if (drive < 0 || drive >= MAX_DRIVE)
+ return (0);
+ debug(D_REDIR, "dos_getpath(%d) -> %s\n", drive, paths[drive].path);
+ return (paths[drive].path);
+}
+
+/*
+ * Fix up a DOS path name. Strip out all '.' and '..' entries, turn
+ * '/' into '\\' and convert all lowercase to uppercase.
+ * Returns 0 on success or DOS errno
+ */
+int
+dos_makepath(u_char *where, u_char *newpath)
+{
+ int drive;
+ u_char **dirs;
+ u_char *np;
+ Path_t *d;
+ u_char tmppath[1024];
+
+ if (where[0] != '\0' && where[1] == ':') {
+ drive = *where - 'A';
+ *newpath++ = *where++;
+ *newpath++ = *where++;
+ } else {
+ drive = diskdrive;
+ *newpath++ = diskdrive + 'A';
+ *newpath++ = ':';
+ }
+
+ if (drive < 0 || drive >= MAX_DRIVE) {
+ debug(D_REDIR,"drive %c invalid\n",drive + 'A');
+ return (DISK_DRIVE_INVALID);
+ }
+
+ d = &paths[drive];
+ if (d->cwd == NULL) {
+ debug(D_REDIR,"no cwd for drive %c\n",drive + 'A');
+ return (DISK_DRIVE_INVALID);
+ }
+
+ debug(D_REDIR, "dos_makepath(%d, %s)\n", drive, where);
+
+ np = newpath;
+ if (*where != '\\' && *where != '/') {
+ ustrcpy(tmppath, d->cwd);
+ if (d->cwd[1])
+ ustrcat(tmppath, (u_char *)"/");
+ ustrcat(tmppath, where);
+ } else {
+ ustrcpy(tmppath, where);
+ }
+
+ dirs = get_entries(tmppath);
+ if (dirs == NULL)
+ return (PATH_NOT_FOUND);
+
+ np = newpath;
+ while (*dirs) {
+ u_char *dir = *dirs++;
+ if (*dir == '/' || *dir == '\\') {
+ np = newpath + 1;
+ newpath[0] = '\\';
+ } else if (dir[0] == '.' && dir[1] == 0) {
+ ;
+ } else if (dir[0] == '.' && dir[1] == '.' && dir[2] == '\0') {
+ while (np[-1] != '/' && np[-1] != '\\')
+ --np;
+ if (np - 1 > newpath)
+ --np;
+ } else {
+ if (np[-1] != '\\')
+ *np++ = '\\';
+ while (*np = *dir++)
+ ++np;
+ }
+ }
+ *np = 0;
+
+ return (0);
+}
+
+/*
+ * Set DOS's idea of the CWD for drive to be where.
+ * Returns DOS errno on failuer.
+ */
+int
+dos_setcwd(u_char *where)
+{
+ u_char newpath[1024];
+ u_char realpath[1024];
+ int drive;
+ struct stat sb;
+ Path_t *d;
+ int error;
+
+ debug(D_REDIR, "dos_setcwd(%s)\n", where);
+
+ error = dos_makepath(where, newpath);
+ if (error)
+ return (error);
+
+ error = dos_to_real_path(newpath, realpath, &drive);
+ if (error)
+ return (error);
+
+ if (ustat(realpath, &sb) < 0 || !S_ISDIR(sb.st_mode))
+ return (PATH_NOT_FOUND);
+ if (uaccess(realpath, R_OK | X_OK))
+ return (PATH_NOT_FOUND);
+
+ d = &paths[drive];
+ d->len = ustrlen(newpath + 2);
+
+ if (d->len + 1 > d->maxlen) {
+ free(d->cwd);
+ d->maxlen = d->len + 1 + 32;
+ d->cwd = (u_char *)malloc(d->maxlen);
+ if (d->cwd == NULL)
+ fatal("malloc in dos_setcwd for %c:%s: %s",
+ drive + 'A', newpath, strerror(errno));
+ }
+ ustrcpy(d->cwd, newpath + 2);
+ return (0);
+}
+
+/*
+ * Given a DOS path dospath and a drive, convert it to a BSD pathname
+ * and store the result in realpath.
+ * Return DOS errno on failure.
+ */
+int
+dos_to_real_path(u_char *dospath, u_char *realpath, int *drivep)
+{
+ Path_t *d;
+ u_char newpath[1024];
+ u_char *rp;
+ int error;
+ u_char **dirs;
+ u_char *dir;
+ int drive;
+
+ debug(D_REDIR, "dos_to_real_path(%s)\n", dospath);
+
+ if (dospath[0] != '\0' && dospath[1] == ':') {
+ drive = *dospath - 'A';
+ dospath++;
+ dospath++;
+ } else {
+ drive = diskdrive;
+ }
+
+ d = &paths[drive];
+ if (d->cwd == NULL)
+ return (DISK_DRIVE_INVALID);
+
+ ustrcpy(realpath, d->path);
+
+ rp = realpath;
+ while (*rp)
+ ++rp;
+
+ ustrcpy(newpath, dospath);
+
+ dirs = get_entries(newpath);
+ if (dirs == NULL)
+ return (PATH_NOT_FOUND);
+
+ /*
+ * Skip the leading /
+ * There are no . or .. entries to worry about either
+ */
+
+ while (dir = *++dirs) {
+ *rp++ = '/';
+ dos_to_real(dir, rp);
+ while (*rp)
+ ++rp;
+ }
+
+ *drivep = drive;
+ return (0);
+}
+
+/*
+ * Provide a few istype() style functions.
+ * isvalid: True if the character is a valid DOS filename character
+ * isdot: True if '.'
+ * isslash: True if '/' or '\'
+ *
+ * 0 - invalid
+ * 1 - okay
+ * 2 - *
+ * 3 - dot
+ * 4 - slash
+ * 5 - colon
+ * 6 - ?
+ * 7 - lowercase
+ */
+u_char cattr[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */
+ 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 1, 3, 4, /* 0x20 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 0, 0, 0, 0, 6, /* 0x30 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 4, 0, 1, 1, /* 0x50 */
+ 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, /* 0x60 */
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 0, 1, 1, 0, /* 0x70 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+inline
+isvalid(unsigned c)
+{
+ return (cattr[c & 0xff] == 1);
+}
+
+inline
+isdot(unsigned c)
+{
+ return (cattr[c & 0xff] == 3);
+}
+
+inline
+isslash(unsigned c)
+{
+ return (cattr[c & 0xff] == 4);
+}
+
+/*
+ * Given a real component, compute the DOS component.
+ */
+void
+real_to_dos(u_char *real, u_char *dos)
+{
+ Name_t *n;
+ Name_t *nn;
+ u_char *p;
+ u_char nm[9], ex[4];
+ int ncnt, ecnt;
+ int echar = '0';
+ int nchar = '0';
+
+ if (real[0] == '.' && (real[1] == '\0'
+ || (real[1] == '.' && real[2] == '\0'))) {
+ sprintf((char *)dos, "%.8s", real);
+ return;
+ }
+
+ n = names;
+ while (n) {
+ if (ustrcmp(real, n->real) == 0) {
+ if (n->ext[0])
+ sprintf((char *)dos, "%.8s.%.3s", n->name, n->ext);
+ else
+ sprintf((char *)dos, "%.8s", n->name);
+ return;
+ }
+ n = n->next;
+ }
+
+ p = real;
+ ncnt = ecnt = 0;
+ while (isvalid(*p) && ncnt < 8) {
+ nm[ncnt] = *p;
+ ++ncnt;
+ ++p;
+ }
+ if (isdot(*p)) {
+ ++p;
+ while (isvalid(*p) && ecnt < 3) {
+ ex[ecnt] = *p;
+ ++ecnt;
+ ++p;
+ }
+ }
+ nm[ncnt] = '\0';
+ ex[ecnt] = '\0';
+
+ if (!*p && ncnt <= 8 && ecnt <= 3) {
+ n = names;
+ while (n) {
+ if (ustrncmp(n->name, nm, 8) == 0 && ustrncmp(n->ext, ex, 3) == 0) {
+ break;
+ }
+ n = n->next;
+ }
+ if (n == 0) {
+ ustrcpy(dos, real);
+ return;
+ }
+ }
+
+ n = (Name_t *)malloc(sizeof(Name_t));
+
+ if (!n)
+ fatal("malloc in real_to_dos: %s\n", strerror(errno));
+
+ n->real = ustrdup(real);
+
+ if (!n->real)
+ fatal("strdup in real_to_dos: %s\n", strerror(errno));
+
+ p = real;
+ ncnt = ecnt = 0;
+ while (*p && ncnt < 8) {
+ if (isvalid(*p))
+ n->name[ncnt] = *p;
+ else if (islower(*p))
+ n->name[ncnt] = toupper(*p);
+ else if (isdot(*p))
+ break;
+ else
+ n->name[ncnt] = (*p |= 0x80);
+ ++ncnt;
+ ++p;
+ }
+ if (isdot(*p)) {
+ ++p;
+ while (*p && ecnt < 3) {
+ if (isvalid(*p))
+ n->ext[ecnt] = *p;
+ else if (islower(*p))
+ n->ext[ecnt] = toupper(*p);
+#if 0
+ else if (isdot(*p))
+ ERROR
+#endif
+ else
+ n->ext[ecnt] = (*p |= 0x80);
+ ++ecnt;
+ ++p;
+ }
+ }
+ n->name[ncnt] = '\0';
+ n->ext[ecnt] = '\0';
+
+ for (;;) {
+ nn = names;
+ while (nn) {
+ if (ustrncmp(n->name, nn->name, 8) == 0 &&
+ ustrncmp(n->ext, nn->ext, 3) == 0) {
+ break;
+ }
+ nn = nn->next;
+ }
+ if (!nn)
+ break;
+ /*
+ * Dang, this name was already in the cache.
+ * Let's munge it a little and try again.
+ */
+ if (ecnt < 3) {
+ n->ext[ecnt] = echar;
+ if (echar == '9') {
+ echar = 'A';
+ } else if (echar == 'Z') {
+ ++ecnt;
+ echar = '0';
+ } else {
+ ++echar;
+ }
+ } else if (ncnt < 8) {
+ n->name[ncnt] = nchar;
+ if (nchar == '9') {
+ nchar = 'A';
+ } else if (nchar == 'Z') {
+ ++ncnt;
+ nchar = '0';
+ } else {
+ ++nchar;
+ }
+ } else if (n->ext[2] < 'Z')
+ n->ext[2]++;
+ else if (n->ext[1] < 'Z')
+ n->ext[1]++;
+ else if (n->ext[0] < 'Z')
+ n->ext[0]++;
+ else if (n->name[7] < 'Z')
+ n->name[7]++;
+ else if (n->name[6] < 'Z')
+ n->name[6]++;
+ else if (n->name[5] < 'Z')
+ n->name[5]++;
+ else if (n->name[4] < 'Z')
+ n->name[4]++;
+ else if (n->name[3] < 'Z')
+ n->name[3]++;
+ else if (n->name[2] < 'Z')
+ n->name[2]++;
+ else if (n->name[1] < 'Z')
+ n->name[1]++;
+ else if (n->name[0] < 'Z')
+ n->name[0]++;
+ else
+ break;
+ }
+
+ if (n->ext[0])
+ sprintf((char *)dos, "%.8s.%.3s", n->name, n->ext);
+ else
+ sprintf((char *)dos, "%.8s", n->name);
+ n->next = names;
+ names = n;
+}
+
+
+/*
+ * Given a DOS component, compute the REAL component.
+ */
+void
+dos_to_real(u_char *dos, u_char *real)
+{
+ int ncnt = 0;
+ int ecnt = 0;
+ u_char name[8];
+ u_char ext[3];
+ Name_t *n = names;
+
+ while (ncnt < 8 && (isvalid(*dos) || islower(*dos))) {
+ name[ncnt++] = islower(*dos) ? toupper(*dos) : *dos;
+ ++dos;
+ }
+ if (ncnt < 8)
+ name[ncnt] = 0;
+
+ if (isdot(*dos)) {
+ while (ecnt < 3 && (isvalid(*++dos) || islower(*dos))) {
+ ext[ecnt++] = islower(*dos) ? toupper(*dos) : *dos;
+ }
+ }
+ if (ecnt < 3)
+ ext[ecnt] = 0;
+
+ while (n) {
+ if (!ustrncmp(name, n->name, 8) && !ustrncmp(ext, n->ext, 3)) {
+ ustrcpy(real, n->real);
+ return;
+ }
+ n = n->next;
+ }
+
+ if (ext[0])
+ sprintf((char *)real, "%-.8s.%-.3s", name, ext);
+ else
+ sprintf((char *)real, "%-.8s", name);
+
+ while (*real) {
+ if (isupper(*real))
+ *real = tolower(*real);
+ ++real;
+ }
+}
+
+/*
+ * convert a path into an argv[] like vector of components.
+ * If the path starts with a '/' or '\' then the first entry
+ * will be "/" or "\". This is the only case in which a "/"
+ * or "\" may appear in an entry.
+ * Also convert all lowercase to uppercase.
+ * The data returned is in a static area, so a second call will
+ * erase the data of the first.
+ */
+u_char **
+get_entries(u_char *path)
+{
+ static u_char *entries[128]; /* Maximum depth... */
+ static u_char mypath[1024];
+ u_char **e = entries;
+ u_char *p = mypath;
+
+ ustrncpy(mypath+1, path, 1022);
+ p = mypath+1;
+ mypath[1023] = 0;
+ if (path[0] == '/' || path[0] == '\\') {
+ mypath[0] = path[0];
+ *e++ = mypath;
+ *p++ = 0;
+ }
+ while (*p && e < entries + 127) {
+ while (*p && (*p == '/' || *p == '\\')) {
+ ++p;
+ }
+
+ if (!*p)
+ break;
+ *e++ = p;
+ while (*p && (*p != '/' && *p != '\\')) {
+ if (islower(*p))
+ *p = tolower(*p);
+ ++p;
+ }
+ /*
+ * skip over the '/' or '\'
+ */
+ if (*p)
+ *p++ = 0;
+ }
+ *e = 0;
+ return (entries);
+}
+
+/*
+ * Return file system statistics for drive.
+ * Return the DOS errno on failure.
+ */
+get_space(int drive, fsstat_t *fs)
+{
+ Path_t *d;
+ struct statfs *buf;
+ int nfs;
+ int i;
+ struct statfs *me = 0;
+
+ if (drive < 0 || drive >= MAX_DRIVE)
+ return (DISK_DRIVE_INVALID);
+
+ d = &paths[drive];
+
+ if (!d->path)
+ return (DISK_DRIVE_INVALID);
+
+ nfs = getfsstat(0, 0, MNT_WAIT);
+
+ buf = (struct statfs *)malloc(sizeof(struct statfs) * nfs);
+ if (buf == NULL) {
+ perror("get_space");
+ return (DISK_DRIVE_INVALID);
+ }
+ nfs = getfsstat(buf, sizeof(struct statfs) * nfs, MNT_WAIT);
+
+ for (i = 0; i < nfs; ++i) {
+ if (strncmp(buf[i].f_mntonname, (char *)d->path, strlen(buf[i].f_mntonname)))
+ continue;
+ if (me && strlen(me->f_mntonname) > strlen(buf[i].f_mntonname))
+ continue;
+ me = buf + i;
+ }
+ if (!me) {
+ free(buf);
+ return (3);
+ }
+ fs->bytes_sector = 512;
+ fs->sectors_cluster = me->f_bsize / fs->bytes_sector;
+ fs->total_clusters = me->f_blocks / fs->sectors_cluster;
+ while (fs->total_clusters > 0xFFFF) {
+ fs->sectors_cluster *= 2;
+ fs->total_clusters = me->f_blocks / fs->sectors_cluster;
+ }
+ fs->avail_clusters = me->f_bavail / fs->sectors_cluster;
+ free(buf);
+ return (0);
+}
+
+#if 0
+DIR *dp = 0;
+u_char searchdir[1024];
+u_char *searchend;
+#endif
+
+/*
+ * Convert a dos filename into normal form (8.3 format, space padded)
+ */
+void
+to_dos_fcb(u_char *p, u_char *expr)
+{
+ int i;
+
+ if (expr[0] == '.') {
+ p[0] = '.';
+ if (expr[1] == '\0') {
+ for (i = 1; i < 11; i++)
+ p[i] = ' ';
+ return;
+ }
+ if (expr[1] == '.') {
+ p[1] = '.';
+ if (expr[2] == '\0') {
+ for (i = 2; i < 11; i++)
+ p[i] = ' ';
+ return;
+ }
+ }
+ }
+
+ for (i = 8; i > 0; i--) {
+ switch (*expr) {
+ case '\0':
+ case '.':
+ for (; i > 0; i--)
+ *p++ = ' ';
+ break;
+ case '*':
+ for (; i > 0; i--)
+ *p++ = '?';
+ break;
+ default:
+ if (islower(*expr)) {
+ *p++ = toupper(*expr++);
+ break;
+ }
+ case '?':
+ *p++ = *expr++;
+ break;
+ }
+ }
+
+ while (*expr != '\0' && *expr != '.')
+ ++expr;
+ if (*expr)
+ ++expr;
+
+ for (i = 3; i > 0; i--) {
+ switch (*expr) {
+ case '\0':
+ case '.':
+ for (; i > 0; i--)
+ *p++ = ' ';
+ break;
+ case '*':
+ for (; i > 0; i--)
+ *p++ = '?';
+ break;
+ default:
+ if (islower(*expr)) {
+ *p++ = toupper(*expr++);
+ break;
+ }
+ case '?':
+ *p++ = *expr++;
+ break;
+ }
+ }
+}
+
+/*
+** DOS can't handle multiple concurrent searches, and if we leave the
+** search instance in the DTA we get screwed as soon as someone starts lots
+** of searches without finishing them properly.
+** We allocate a single search structure, and recycle it if find_first()
+** is called before a search ends.
+*/
+static search_t dir_search = {dp : NULL};
+
+/*
+ * Find the first file on drive which matches the path with the given
+ * attributes attr.
+ * If found, the result is placed in dir (32 bytes).
+ * The DTA is populated as required by DOS, but the state area is ignored.
+ * Returns DOS errno on failure.
+ */
+find_first(u_char *path, int attr, dosdir_t *dir, find_block_t *dta)
+{
+ u_char newpath[1024], realpath[1024];
+ u_char *expr, *slash;
+ int drive;
+ int error;
+ search_t *search = &dir_search;
+
+ debug(D_REDIR, "find_first(%s, %x, %x)\n", path, attr, dta);
+
+ error = dos_makepath(path, newpath);
+ if (error)
+ return (error);
+
+ expr = newpath;
+ slash = 0;
+ while (*expr != '\0') {
+ if (*expr == '\\' || *expr == '/')
+ slash = expr;
+ expr++;
+ }
+ *slash++ = '\0';
+
+ error = dos_to_real_path(newpath, realpath, &drive);
+ if (error)
+ return (error);
+
+ if (attr == VOLUME_LABEL) /* never find a volume label */
+ return (NO_MORE_FILES);
+
+ if (search->dp) /* stale search? */
+ closedir(search->dp);
+
+ search->dp = opendir(realpath);
+ if (search->dp == NULL)
+ return (PATH_NOT_FOUND);
+
+ ustrcpy(search->searchdir, realpath);
+ search->searchend = search->searchdir;
+ while (*search->searchend)
+ ++search->searchend;
+ *search->searchend++ = '/';
+
+ search->dp->dd_fd = squirrel_fd(search->dp->dd_fd);
+
+ dta->drive = drive | 0x80;
+ to_dos_fcb(dta->pattern, slash);
+ dta->flag = attr;
+
+ return (find_next(dir, dta));
+}
+
+/*
+ * Continue on where find_first left off.
+ * The results will be placed in dir.
+ * DTA state area is ignored.
+ */
+int
+find_next(dosdir_t *dir, find_block_t *dta)
+{
+ search_t *search = &dir_search;
+ struct dirent *d;
+ struct stat sb;
+ u_char name[16];
+
+ if (!search->dp)
+ return (NO_MORE_FILES);
+
+#if 0
+ debug(D_REDIR, "find_next()\n");
+#endif
+
+ while (d = readdir(search->dp)) {
+ real_to_dos((u_char *)d->d_name, name);
+ to_dos_fcb(dir->name, name);
+#if 0
+printf("find_next: |%-11.11s| |%-11.11s| |%s| |%s|\n", dta->pattern, dir->name, d->d_name, name);
+#endif
+ if (dos_match(dta->pattern, dir->name) == 0)
+ continue;
+
+ ustrcpy(search->searchend, (u_char *)d->d_name);
+ if (ustat(search->searchdir, &sb) < 0)
+ continue;
+#if 0
+printf("find_next: %x\n", sb.st_mode);
+#endif
+ if (S_ISDIR(sb.st_mode)) {
+ if (!(dta->flag & DIRECTORY)) {
+ continue;
+ }
+ }
+ dir->attr = (S_ISDIR(sb.st_mode) ? DIRECTORY : 0) |
+ (uaccess(search->searchdir, W_OK) < 0 ? READ_ONLY_FILE : 0);
+ encode_dos_file_time(sb.st_mtime, &dir->date, &dir->time);
+ dir->start = 1;
+ dir->size = sb.st_size;
+#if 0
+printf("find_next: found %s\n",name);
+#endif
+ return (0);
+ }
+ closedir(search->dp);
+ search->dp = NULL;
+ return (NO_MORE_FILES);
+}
+
+/*
+ * perfrom hokey DOS pattern matching. pattern may contain the wild cards
+ * '*' and '?' only. Follow the DOS convention that '?*', '*?' and '**' all
+ * are the same as '*'. Also, allow '?' to match the blank padding in a
+ * name (hence, ???? matchs all of "a", "ab", "abc" and "abcd" but not "abcde")
+ * Return 1 if a match is found, 0 if not.
+ *
+ * XXX This appears to be severely busted! (no * handling - normal?)
+ */
+int
+dos_match(u_char *pattern, u_char *string)
+{
+ int i;
+
+ /*
+ * Check the base part first
+ */
+ for (i = 11; i > 0; i--) {
+ if (*pattern != '?' && *string != *pattern)
+ return (0);
+ pattern++, string++;
+ }
+ return (1);
+}
diff --git a/usr.bin/doscmd/cwd.h b/usr.bin/doscmd/cwd.h
new file mode 100644
index 0000000..323512f
--- /dev/null
+++ b/usr.bin/doscmd/cwd.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI cwd.h,v 2.2 1996/04/08 19:32:26 bostic Exp
+ *
+ * $Id: cwd.h,v 1.3 1996/09/23 09:59:23 miff Exp $
+ */
+
+static inline u_char *
+ustrcpy(u_char *s1, u_char *s2)
+{
+ return((u_char *)strcpy((char *)s1, (char *)s2));
+}
+
+static inline u_char *
+ustrcat(u_char *s1, u_char *s2)
+{
+ return((u_char *)strcat((char *)s1, (char *)s2));
+}
+
+static inline u_char *
+ustrncpy(u_char *s1, u_char *s2, unsigned n)
+{
+ return((u_char *)strncpy((char *)s1, (char *)s2, n));
+}
+
+static inline int
+ustrcmp(u_char *s1, u_char *s2)
+{
+ return(strcmp((char *)s1, (char *)s2));
+}
+
+static inline int
+ustrncmp(u_char *s1, u_char *s2, unsigned n)
+{
+ return(strncmp((char *)s1, (char *)s2, n));
+}
+
+static inline int
+ustrlen(u_char *s)
+{
+ return(strlen((char *)s));
+}
+
+static inline u_char *
+ustrrchr(u_char *s, u_char c)
+{
+ return((u_char *)strrchr((char *)s, c));
+}
+
+static inline u_char *
+ustrdup(u_char *s)
+{
+ return((u_char *)strdup((char *)s));
+}
+
+static inline int
+ustat(u_char *s, struct stat *sb)
+{
+ return(stat((char *)s, sb));
+}
+
+static inline int
+uaccess(u_char *s, int mode)
+{
+ return(access((char *)s, mode));
+}
+
+extern void init_path(int drive, u_char *base, u_char *where);
+extern void dos_makereadonly(int drive);
+extern int dos_readonly(int drive);
+extern u_char *dos_getcwd(int drive);
+extern u_char *dos_getpath(int drive);
+extern int dos_makepath(u_char *where, u_char *newpath);
+extern int dos_setcwd(u_char *where);
+extern int dos_to_real_path(u_char *dospath, u_char *realpath, int *);
+extern void real_to_dos(u_char *real, u_char *dos);
+extern void dos_to_real(u_char *dos, u_char *real);
+extern u_char **get_entries(u_char *path);
+extern int get_space(int drive, fsstat_t *fs);
+extern int find_first(u_char *path, int attr,
+ dosdir_t *dir, find_block_t *dta);
+extern int find_next(dosdir_t *dir, find_block_t *dta);
diff --git a/usr.bin/doscmd/debug.c b/usr.bin/doscmd/debug.c
new file mode 100644
index 0000000..e736f8d
--- /dev/null
+++ b/usr.bin/doscmd/debug.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1996
+ * Michael Smith, All rights reserved.
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: BSDI doscmd.c,v 2.3 1996/04/08 19:32:30 bostic Exp
+ *
+ * $Id: debug.c,v 1.5 1996/09/25 00:03:43 miff Exp $
+ */
+
+
+#include <stdarg.h>
+
+#include "doscmd.h"
+
+/* debug output goes here */
+FILE *debugf = stderr;
+
+/* see doscmd.h for flag names */
+int debug_flags = D_ALWAYS;
+
+/* include register dumps when reporting unknown interrupts */
+int vflag = 0;
+
+/* interrupts to trace */
+#define BPW (sizeof(u_long) << 3)
+u_long debug_ints[256/BPW];
+
+/* Debug flag manipulation */
+void
+debug_set(int x)
+{
+ x &= 0xff;
+ debug_ints[x/BPW] |= 1 << (x & (BPW - 1));
+}
+
+void
+debug_unset(int x)
+{
+ x &= 0xff;
+ debug_ints[x/BPW] &= ~(1 << (x & (BPW - 1)));
+}
+
+u_long
+debug_isset(int x)
+{
+ x &= 0xff;
+ return(debug_ints[x/BPW] & (1 << (x & (BPW - 1))));
+}
+
+
+/*
+** Emit a debugging message if (flags) matches the current
+** debugging mode.
+*/
+void
+debug (int flags, char *fmt, ...)
+{
+ va_list args;
+
+ if (flags & (debug_flags & ~0xff)) {
+ if ((debug_flags & 0xff) == 0
+ && (flags & (D_ITRAPS|D_TRAPS))
+ && !debug_isset(flags & 0xff))
+ return;
+ va_start (args, fmt);
+ vfprintf (debugf, fmt, args);
+ va_end (args);
+ }
+}
+
+/*
+** Emit a terminal error message and exit
+*/
+void
+fatal (char *fmt, ...)
+{
+ va_list args;
+
+ dead = 1;
+
+ if (xmode) {
+ char buf[1024];
+ char buf2[1024];
+ char *m;
+
+ va_start (args, fmt);
+ vfprintf (debugf, fmt, args);
+ vsprintf (buf, fmt, args);
+ va_end (args);
+
+ tty_move(23, 0);
+ for (m = buf; *m; ++m)
+ tty_write(*m, 0x0400);
+
+ tty_move(24, 0);
+ for (m = "(PRESS <CTRL-ALT> ANY MOUSE BUTTON TO exit)"; *m; ++m)
+ tty_write(*m, 0x0900);
+ tty_move(-1, -1);
+ for (;;)
+ tty_pause();
+ }
+
+ va_start (args, fmt);
+ fprintf (debugf, "doscmd: fatal error ");
+ vfprintf (debugf, fmt, args);
+ va_end (args);
+ quit (1);
+}
+
+/*
+** Emit a register dump (usually when dying)
+*/
+void
+dump_regs(regcontext_t *REGS)
+{
+ u_char *addr;
+ int i;
+ char buf[100];
+
+ debug (D_ALWAYS, "\n");
+ debug (D_ALWAYS, "ax=%04x bx=%04x cx=%04x dx=%04x\n", R_AX, R_BX, R_CX, R_DX);
+ debug (D_ALWAYS, "si=%04x di=%04x sp=%04x bp=%04x\n", R_SI, R_DI, R_SP, R_BP);
+ debug (D_ALWAYS, "cs=%04x ss=%04x ds=%04x es=%04x\n", R_CS, R_SS, R_DS, R_ES);
+ debug (D_ALWAYS, "ip=%x eflags=%x\n", R_IP, R_EFLAGS);
+
+ addr = (u_char *)N_GETPTR(R_CS, R_IP);
+
+ for (i = 0; i < 16; i++)
+ debug (D_ALWAYS, "%02x ", addr[i]);
+ debug (D_ALWAYS, "\n");
+
+ addr = (char *)N_GETPTR(R_CS, R_IP);
+ i386dis(R_CS, R_IP, addr, buf, 0);
+
+ debug (D_ALWAYS, "%s\n", buf);
+}
+
+/*
+** Unknown interrupt error messages
+*/
+void
+unknown_int2(int maj, int min, regcontext_t *REGS)
+{
+ if (vflag) dump_regs(REGS);
+ printf("Unknown interrupt %02x function %02x\n", maj, min);
+ R_FLAGS |= PSL_C;
+}
+
+void
+unknown_int3(int maj, int min, int sub, regcontext_t *REGS)
+{
+ if (vflag) dump_regs(REGS);
+ printf("Unknown interrupt %02x function %02x subfunction %02x\n",
+ maj, min, sub);
+ R_FLAGS |= PSL_C;
+}
+
+void
+unknown_int4(int maj, int min, int sub, int ss, regcontext_t *REGS)
+{
+ if (vflag) dump_regs(REGS);
+ printf("Unknown interrupt %02x function %02x subfunction %02x %02x\n",
+ maj, min, sub, ss);
+ R_FLAGS |= PSL_C;
+}
+
diff --git a/usr.bin/doscmd/disktab.c b/usr.bin/doscmd/disktab.c
new file mode 100644
index 0000000..a9b0861
--- /dev/null
+++ b/usr.bin/doscmd/disktab.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI disktab.c,v 2.2 1996/04/08 19:32:27 bostic Exp
+ */
+
+/* XXX goaway (requires change to config.c) */
+
+static struct {
+ int cylinders;
+ int heads;
+ int sectors;
+} disk_table[] = {
+ { 306, 4, 17 }, /* type 01 10M */
+ { 615, 4, 17 }, /* type 02 20M */
+ { 615, 6, 17 }, /* type 03 30M */
+ { 940, 8, 17 }, /* type 04 62M */
+ { 940, 6, 17 }, /* type 05 46M */
+ { 615, 4, 17 }, /* type 06 20M */
+ { 462, 8, 17 }, /* type 07 30M */
+ { 733, 5, 17 }, /* type 08 30M */
+ { 900, 15, 17 }, /* type 09 112M */
+ { 820, 3, 17 }, /* type 10 20M */
+ { 855, 5, 17 }, /* type 11 35M */
+ { 855, 7, 17 }, /* type 12 49M */
+ { 306, 8, 17 }, /* type 13 20M */
+ { 733, 7, 17 }, /* type 14 42M */
+ { 976, 15, 17 }, /* type 15 121M */
+ { 612, 4, 17 }, /* type 16 20M */
+ { 977, 5, 17 }, /* type 17 40M */
+ { 977, 7, 17 }, /* type 18 56M */
+ { 1024, 7, 17 }, /* type 19 59M */
+ { 733, 5, 17 }, /* type 20 30M */
+ { 733, 7, 17 }, /* type 21 42M */
+ { 733, 5, 17 }, /* type 22 30M */
+ { 306, 4, 17 }, /* type 23 10M */
+ { 925, 7, 17 }, /* type 24 53M */
+ { 925, 9, 17 }, /* type 25 69M */
+ { 754, 7, 17 }, /* type 26 43M */
+ { 754, 11, 17 }, /* type 27 68M */
+ { 699, 7, 17 }, /* type 28 40M */
+ { 823, 10, 17 }, /* type 29 68M */
+ { 918, 7, 17 }, /* type 30 53M */
+ { 1024, 11, 17 }, /* type 31 93M */
+ { 1024, 15, 17 }, /* type 32 127M */
+ { 1024, 5, 17 }, /* type 33 42M */
+ { 612, 2, 17 }, /* type 34 10M */
+ { 1024, 9, 17 }, /* type 35 76M */
+ { 1024, 8, 17 }, /* type 36 68M */
+ { 615, 8, 17 }, /* type 37 40M */
+ { 987, 3, 17 }, /* type 38 24M */
+ { 987, 7, 17 }, /* type 39 57M */
+ { 820, 6, 17 }, /* type 40 40M */
+ { 977, 5, 17 }, /* type 41 40M */
+ { 981, 5, 17 }, /* type 42 40M */
+ { 830, 7, 17 }, /* type 43 48M */
+ { 830, 10, 17 }, /* type 44 68M */
+ { 917, 15, 17 }, /* type 45 114M */
+ { 1224, 15, 17 }, /* type 46 152M */
+};
+
+static int ntypes = sizeof(disk_table)/sizeof(disk_table[0]);
+
+int
+map_type(int type, int *cyl, int *head, int *sec)
+{
+ --type;
+ if (type < 0 || type >= ntypes)
+ return(0);
+ *cyl = disk_table[type].cylinders;
+ *head = disk_table[type].heads;
+ *sec = disk_table[type].sectors;
+ return(1);
+}
diff --git a/usr.bin/doscmd/dispatch.h b/usr.bin/doscmd/dispatch.h
new file mode 100644
index 0000000..59620f1
--- /dev/null
+++ b/usr.bin/doscmd/dispatch.h
@@ -0,0 +1,110 @@
+/*
+** Copyright (c) 1996
+** Michael Smith. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+**
+** $Id: dispatch.h,v 1.3 1996/09/22 05:52:56 miff Exp $
+*/
+
+/*
+** Interrupt dispatcher assistants.
+*/
+
+
+/*
+** Declare a static, initialised array of these, with one
+** entry per function/subfunction.
+**
+** The last element should be a dummy with a 'func' of -1
+*/
+struct intfunc_table
+{
+ int func; /* interrupt function number */
+ int subfunc; /* subfunction number */
+ int (* handler)(regcontext_t *REGS);/* handling function */
+ const char *desc; /* textual description */
+};
+#define IFT_NOSUBFUNC -1
+
+
+/*
+** Declare a static array of 256 integers to use as a fast lookup
+** into the table of handlers.
+**
+** Call this function to initialise the lookup. Note that the table
+** must be arranged with all handlers for a given function together, and
+** that the handler listed with IFT_NOSUBFUNC should be last.
+*/
+static inline void
+intfunc_init(struct intfunc_table table[], int index[])
+{
+ int hn;
+
+ for (hn = 0; hn < 256; hn++) /* initialise all no-handler state */
+ index[hn] = -1; /* default to no handler */
+
+ for (hn = 0; table[hn].func >= 0; hn++) /* walk list of handlers and add references */
+ if (index[table[hn].func] == -1 ) /* reference first handler */
+ index[table[hn].func] = hn;
+}
+
+/*
+** Call this to get an index matching the function/subfunction
+** described by (sc), or -1 if none exist
+*/
+static inline int
+intfunc_find(struct intfunc_table table[], int index[], int func, int subfunc)
+{
+ int ent = index[func]; /* look for handler */
+
+ while ((ent >= 0) && /* scan entries for function */
+ (table[ent].func == func)) {
+
+ if ((table[ent].subfunc == IFT_NOSUBFUNC) || /* handles all */
+ (table[ent].subfunc == subfunc)) { /* handles this one */
+ return(ent);
+ }
+ ent++;
+ }
+ return(-1);
+}
+
+/*
+** A slower lookup for a set of function handlers, but one that requires
+** no initialisation calls.
+** Again, handlers with IFT_NOSUBFUNC should be listed after any with
+** specific subfunction values.
+*/
+static inline int
+intfunc_search(struct intfunc_table table[], int func, int subfunc)
+{
+ int ent;
+
+ for (ent = 0; table[ent].func >= 0; ent++)
+ if ((table[ent].func == func) && /* matches required function */
+ ((table[ent].subfunc == IFT_NOSUBFUNC) || table[ent].subfunc == subfunc))
+ return(ent);
+ return(-1);
+}
+
+
diff --git a/usr.bin/doscmd/dos.c b/usr.bin/doscmd/dos.c
new file mode 100644
index 0000000..918afde
--- /dev/null
+++ b/usr.bin/doscmd/dos.c
@@ -0,0 +1,2508 @@
+/*
+ * Copyright (c) 1996
+ * Michael Smith. All rights reserved.
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int21.c,v 2.2 1996/04/08 19:32:51 bostic Exp
+ *
+ * $Id: dos.c,v 1.8 1996/09/23 09:59:24 miff Exp $
+ */
+
+#include "doscmd.h"
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <time.h>
+#include <glob.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stddef.h>
+
+#include "dispatch.h"
+
+static u_long upcase_vector;
+
+/* Country Info */
+struct {
+ ushort ciDateFormat;
+ char ciCurrency[5];
+ char ciThousands[2];
+ char ciDecimal[2];
+ char ciDateSep[2];
+ char ciTimeSep[2];
+ char ciCurrencyFormat;
+ char ciCurrencyPlaces;
+ char ciTimeFormat;
+ ushort ciCaseMapOffset;
+ ushort ciCaseMapSegment;
+ char ciDataSep[2];
+#if 0
+ char ciReserved[10];
+#endif
+} countryinfo = {
+ 0, "$", ",", ".", "-", ":", 0, 2, 0, 0xffff, 0xffff, "?"
+};
+
+/* DOS File Control Block */
+struct fcb {
+ u_char fcbMagic;
+ u_char fcbResoived[5];
+ u_char fcbAttribute;
+ u_char fcbDriveID;
+ u_char fcbFileName[8];
+ u_char fcbExtent[3];
+ u_short fcbCurBlockNo;
+ u_short fcbRecSize;
+ u_long fcbFileSize;
+ u_short fcbFileDate;
+ u_short fcbFileTime;
+ int fcbReserved;
+ int fcb_fd; /* hide UNIX FD here */
+ u_char fcbCurRecNo;
+ u_long fcbRandomRecNo;
+}/* __attribute__((__packed__))*/;
+
+/* exports */
+void encode_dos_file_time (time_t, u_short *, u_short *);
+int diskdrive = 2; /* C: */
+char *InDOS;
+unsigned long disk_transfer_addr;
+
+/* locals */
+static int ctrl_c_flag = 0;
+static int return_status = 0;
+static int doserrno = 0;
+static int memory_strategy = 0; /* first fit (we ignore this) */
+
+
+static u_char upc_table[0x80] = {
+ 0x80, 0x9a, 'E', 'A', 0x8e, 'A', 0x8f, 0x80,
+ 'E', 'E', 'E', 'I', 'I', 'I', 0x8e, 0x8f,
+ 0x90, 0x92, 0x92, 'O', 0x99, 'O', 'U', 'U',
+ 'Y', 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 'A', 'I', 'O', 'U', 0xa5, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+};
+
+
+/******************************************************************************
+** utility functions
+*/
+
+static u_char
+upcase(u_char c)
+{
+
+ if (islower(c))
+ return (toupper(c));
+ else if (c >= 0x80)
+ return (upc_table[c - 0x80]);
+ else
+ return (c);
+}
+
+static void
+upcase_entry(regcontext_t *REGS)
+{
+ u_char c;
+
+ R_AL = upcase(R_AL);
+}
+
+
+/*
+** Handle the DOS drive info/free space/etc. calls.
+*/
+static int
+int21_free(regcontext_t *REGS)
+{
+ fsstat_t fs;
+ struct statfs fsstat;
+ char fspath[PATH_MAX];
+ int junk;
+ int spc,fclus,bps,nclus;
+ long nsec;
+ int error;
+ int dd_save;
+ int drive;
+
+ /* work out drive */
+ switch (R_AH) {
+ case 0x1c:
+ case 0x36:
+ drive = R_DL;
+ if (drive)
+ break;
+ /* FALLTHROUGH */
+ case 0x1b:
+ drive = diskdrive;
+ break;
+ default:
+ fatal("int21_free called on unknown function %x\n",R_AH);
+ }
+
+ error = get_space(drive, &fs);
+ if (error)
+ return(error);
+
+ R_AL = fs.sectors_cluster; /* sectors per cluster */
+ R_CX = fs.bytes_sector; /* bytes per sector */
+ R_DX = fs.total_clusters; /* total clusters */
+
+ switch (R_AH) {
+ case 0x1b:
+ case 0x1c:
+ BIOSDATA[0xb4] = 0xf0; /* "reserved" area, "other media" FAT ID */
+ R_DX = 0x40; /* BIOS data area */
+ R_BX = 0xb4;
+ break;
+
+ case 0x36:
+ R_BX = fs.avail_clusters; /* number of available clusters */
+ break;
+ }
+ return(0);
+}
+
+static void
+pack_name(u_char *p, u_char *q)
+{
+ int i;
+
+ for (i = 8; i > 0 && *p != ' '; i--)
+ *q++ = *p++;
+ p += i;
+ if (*p != ' ') {
+ *q++ = '.';
+ for (i = 3; i > 0 && *p != ' '; i--)
+ *q++ = *p++;
+ p += i;
+ }
+ *q = '\0';
+}
+
+static void
+dosdir_to_dta(dosdir_t *dosdir, find_block_t *dta)
+{
+ u_char *p, *q;
+
+ dta->attr = dosdir->attr;
+ dta->time = dosdir->time;
+ dta->date = dosdir->date;
+ dta->size = dosdir->size;
+ pack_name(dosdir->name, dta->name);
+}
+
+/* exported */
+void
+encode_dos_file_time(time_t t, u_short *dosdatep, u_short *dostimep)
+{
+ struct tm tm;
+
+ tm = *localtime(&t);
+ *dostimep = (tm.tm_hour << 11) |
+ (tm.tm_min << 5) |
+ ((tm.tm_sec / 2) << 0);
+ *dosdatep = ((tm.tm_year - 80) << 9) |
+ ((tm.tm_mon + 1) << 5) |
+ (tm.tm_mday << 0);
+}
+
+time_t
+decode_dos_file_time(u_short dosdate, u_short dostime)
+{
+ struct tm tm;
+ time_t then;
+
+ tm.tm_hour = (dostime >> 11) & 0x1f;
+ tm.tm_min = (dostime >> 5) & 0x3f;
+ tm.tm_sec = ((dostime >> 0) & 0x1f) * 2;
+ tm.tm_year = ((dosdate >> 9) & 0x7f) + 80;
+ tm.tm_mon = ((dosdate >> 5) & 0x0f) - 1;
+ tm.tm_mday = (dosdate >> 0) & 0x1f;
+ /* tm_wday and tm_yday are ignored. */
+ tm.tm_isdst = 0;
+ /* tm_gmtoff is ignored. */
+ then = mktime(&tm);
+ return (then);
+}
+
+int
+translate_filename(u_char *dname, u_char *uname, int *drivep)
+{
+ u_char newpath[1024];
+ int error;
+
+ if (!strcasecmp(dname, "con")) {
+ *drivep = -1;
+ strcpy(uname, "/dev/tty");
+ return (0);
+ }
+
+ error = dos_makepath(dname, newpath);
+ if (error)
+ return (error);
+
+ error = dos_to_real_path(newpath, uname, drivep);
+ if (error)
+ return (error);
+
+ return (0);
+}
+
+static u_char magic[0x7e] = {
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+
+ 0x08, 0x0f, 0x06, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x04, 0x04, 0x0f, 0x0e, 0x06,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0f,
+
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x06, 0x06, 0x06, 0x0f, 0x0f,
+
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x04, 0x0f,
+};
+
+#define isvalid(x) ((magic[x] & 0x01) != 0)
+#define issep(x) ((magic[x] & 0x02) == 0)
+#define iswhite(x) ((magic[x] & 0x04) == 0)
+
+static char *
+skipwhite(char *p)
+{
+ while (iswhite(*p))
+ ++p;
+ return (p);
+}
+
+#define get_drive_letter(x) ((x) - 0x40)
+
+int
+parse_filename(int flag, char *str, char *fcb, int *nb)
+{
+ char *p;
+ int ret = 0;
+ int i;
+
+ p = str;
+
+ p = skipwhite(p);
+ if (flag & 1) {
+ if (issep(*p)) {
+ ++p;
+ p = skipwhite(p);
+ }
+ }
+
+ if (isvalid(*p) && p[1] == ':') {
+ *fcb++ = get_drive_letter(upcase(*p));
+ p += 2;
+ } else if (flag & 2) {
+ fcb++;
+ } else {
+ *fcb++ = 0; /* default drive */
+ }
+
+ i = 8;
+ if (isvalid(*p)) {
+ for (;;) {
+ if (!isvalid(*p)) {
+ for (; i > 0; i--)
+ *fcb++ = ' ';
+ break;
+ }
+ if (i > 0) {
+ switch (*p) {
+ case '*':
+ ret = 1;
+ for (; i > 0; i--)
+ *fcb++ = '?';
+ break;
+ case '?':
+ ret = 1;
+ default:
+ *fcb++ = upcase(*p);
+ i--;
+ break;
+ }
+ }
+ ++p;
+ }
+ } else if (flag & 4) {
+ fcb += i;
+ } else {
+ for (; i > 0; i--)
+ *fcb++ = ' ';
+ }
+
+ i = 3;
+ if (*p == '.') {
+ ++p;
+ for (;;) {
+ if (!isvalid(*p)) {
+ for (; i > 0; i--)
+ *fcb++ = ' ';
+ break;
+ }
+ if (i > 0) {
+ switch (*p) {
+ case '*':
+ ret = 1;
+ for (; i > 0; i--)
+ *fcb++ = '?';
+ break;
+ case '?':
+ ret = 1;
+ default:
+ *fcb++ = upcase(*p);
+ i--;
+ break;
+ }
+ }
+ ++p;
+ }
+ } else if (flag & 8) {
+ fcb += i;
+ } else {
+ for (; i > 0; i--)
+ *fcb++ = ' ';
+ }
+
+ for (i = 4; i > 0; i--)
+ *fcb++ = 0; /* filler */
+
+ *nb = p - str;
+ return (ret);
+}
+
+/******************************************************************************
+** int21 functions
+*/
+
+/*
+** 21:00
+**
+** terminate
+*/
+static int
+int21_00(regcontext_t *REGS)
+{
+ done(REGS,0);
+}
+
+/*
+** 21:01
+**
+** read character with echo
+*/
+static int
+int21_01(regcontext_t *REGS)
+{
+ int n;
+
+ if ((n = tty_read(&REGS->sc, TTYF_BLOCKALL)) >= 0)
+ R_AL = n;
+ return(0);
+}
+
+/*
+** 21:02
+**
+** write char to stdout
+*/
+static int
+int21_02(regcontext_t *REGS)
+{
+ tty_write(R_DL, TTYF_REDIRECT);
+ return(0);
+}
+
+/*
+** 21:06
+**
+** direct console I/O
+**
+** (dl) is output char unless 0xff, when we read instead
+*/
+static int
+int21_06(regcontext_t *REGS)
+{
+ int n;
+
+ /* XXX - should be able to read a file */
+ if (R_DL == 0xff) {
+ n = tty_read(&REGS->sc, TTYF_ECHO|TTYF_REDIRECT);
+ if (n < 0) {
+ R_FLAGS |= PSL_Z; /* nothing available */
+ R_AL = 0;
+ } else {
+ R_AL = n; /* got character */
+ R_FLAGS &= ~PSL_Z;
+ }
+ } else {
+ /* write and return char in %al */
+ tty_write(R_DL, TTYF_REDIRECT);
+ R_AL = R_DL;
+ }
+ return(0);
+}
+
+/*
+** 21:07
+**
+** direct console input with no echo
+*/
+static int
+int21_07(regcontext_t *REGS)
+{
+ R_AL = tty_read(&REGS->sc, TTYF_BLOCK|TTYF_REDIRECT) & 0xff;
+ return(0);
+}
+
+/*
+** 21:08
+**
+** character input with no echo
+*/
+static int
+int21_08(regcontext_t *REGS)
+{
+ int n;
+
+ if ((n = tty_read(&REGS->sc, TTYF_BLOCK|TTYF_CTRL|TTYF_REDIRECT)) >= 0)
+ R_AL = n;
+ return(0);
+}
+
+/*
+** 21:09
+**
+** write string to standard out.
+**
+** We're a little paranoid here; if the string is very long, truncate it.
+*/
+static int
+int21_09(regcontext_t *REGS)
+{
+ char *addr;
+ int len;
+
+ /* pointer to string */
+ addr = (char *)N_GETPTR(R_DS, R_DX);
+
+ /* walk string looking for terminator or overlength */
+ for (len = 0; len < 10000; len++, addr++) {
+ if (*addr == '$')
+ break;
+ tty_write(*addr, TTYF_REDIRECT);
+ }
+ R_AL = 0x24;
+ return(0);
+}
+
+/*
+** 21:0a
+**
+** buffered input
+*/
+static int
+int21_0a(regcontext_t *REGS)
+{
+ unsigned char *addr;
+ int nbytes,avail;
+ int n;
+
+ /* pointer to buffer */
+ addr = (unsigned char *)N_GETPTR(R_DS, R_DL);
+
+ /* capacity of buffer */
+ avail = addr[0];
+ if (avail == 0) /* no space */
+ return(0);
+ nbytes = 0; /* read nothing yet */
+
+ /* read loop */
+ while (1) {
+ n = tty_read(&REGS->sc, TTYF_BLOCK|TTYF_CTRL|TTYF_REDIRECT);
+ if (n < 0) /* end of input */
+ n = '\r'; /* make like CR */
+
+ switch (n) {
+ case '\r': /* done */
+ addr[1] = nbytes;
+ addr[nbytes+2] = '\r';
+ addr[nbytes+3] = '\0'; /* XXX is this necessary? */
+ return (0);
+ case '\n': /* ignore */
+ case '\0':
+ break;
+ case '\b': /* backspace */
+ if (nbytes > 0) {
+ --nbytes;
+ tty_write('\b', TTYF_REDIRECT);
+ if (addr[nbytes+2] < ' ')
+ tty_write('\b', TTYF_REDIRECT);
+ }
+ break;
+ default:
+ if (nbytes >= (avail-2)) { /* buffer full */
+ tty_write('\007', TTYF_REDIRECT);
+ } else { /* add to end */
+ addr[(nbytes++) +2] = n;
+ if (n != '\t' && n < ' ') {
+ tty_write('^', TTYF_REDIRECT);
+ tty_write(n + '@', TTYF_REDIRECT);
+ } else
+ tty_write(n, TTYF_REDIRECT);
+ }
+ break;
+ }
+ }
+}
+
+/*
+** 21:0b
+**
+** get stdin status
+**
+** This is a favorite for camping on, so we do some poll-counting
+** here as well.
+*/
+static int
+int21_0b(regcontext_t *REGS)
+{
+ int n;
+
+ /* XXX this is pretty bogus, actually */
+ if (!xmode) {
+ R_AL = 0xff; /* no X mode, always claim data available */
+ return(0);
+ }
+ /* XXX tty_peek is broken */
+ n = tty_peek(&REGS->sc, poll_cnt ? 0 : TTYF_POLL) ? 0xff : 0;
+ if (n < 0) /* control-break */
+ return (0);
+ R_AL = n; /* will be 0 or 0xff */
+ if (poll_cnt)
+ --poll_cnt;
+ return(0);
+}
+
+/*
+** 21:0c
+**
+** flush stdin and read using other function
+*/
+static int
+int21_0c(regcontext_t *REGS)
+{
+ if (xmode) /* XXX should always flush! */
+ tty_flush();
+
+ switch(R_AL) { /* which subfunction? */
+ case 0x01:
+ return(int21_01(REGS));
+ case 0x06:
+ return(int21_06(REGS));
+ case 0x07:
+ return(int21_07(REGS));
+ case 0x08:
+ return(int21_08(REGS));
+ case 0x0a:
+ return(int21_0a(REGS));
+ }
+ return(0);
+}
+
+/*
+** 21:0e
+**
+** select default drive
+*/
+static int
+int21_0e(regcontext_t *REGS)
+{
+ diskdrive = R_DL; /* XXX rangecheck? */
+ R_AL = ndisks + 2; /* report actual limit */
+ return(0);
+}
+
+/*
+** 21:19
+**
+** get default drive
+*/
+static int
+int21_19(regcontext_t *REGS)
+{
+ R_AL = diskdrive;
+ return(0);
+}
+
+/*
+** 21:1a
+**
+** set DTA
+*/
+static int
+int21_1a(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "set dta to %x:%x\n", R_DS, R_DX);
+ disk_transfer_addr = N_GETVEC(R_DS, R_DX);
+ return(0);
+}
+
+/*
+** 21:25
+**
+** set interrupt vector
+*/
+static int
+int21_25(regcontext_t *REGS)
+{
+ debug(D_MEMORY, "%02x -> %04x:%04x\n", R_AL, R_DS, R_DX);
+ ivec[R_AL] = N_GETVEC(R_DS, R_DX);
+ return(0);
+}
+
+/*
+** 21:26
+**
+** Create PSP
+*/
+static int
+int21_26(regcontext_t *REGS)
+{
+ unsigned char *addr;
+
+ /* address of new PSP */
+ addr = (unsigned char *)MAKEPTR(R_DX, 0);
+
+ /* copy this process' PSP - XXX needs some work 8( */
+ memcpy (addr, dosmem, 256);
+ return(0);
+}
+
+/*
+** 21:2a
+**
+** Get date
+*/
+static int
+int21_2a(regcontext_t *REGS)
+{
+ struct timeval tv;
+ struct timezone tz;
+ struct tm tm;
+ time_t now;
+
+ gettimeofday(&tv, &tz); /* get time and apply DOS offset */
+ now = tv.tv_sec + delta_clock;
+
+ tm = *localtime(&now); /* deconstruct and timezoneify */
+ R_CX = tm.tm_year + 1900;
+ R_DH = tm.tm_mon + 1;
+ R_DL = tm.tm_mday;
+ R_AL = tm.tm_wday;
+ return(0);
+}
+
+/*
+** 21:2b
+**
+** set date
+*/
+static int
+int21_2b(regcontext_t *REGS)
+{
+ struct timeval tv;
+ struct timezone tz;
+ struct tm tm;
+ time_t now;
+
+ gettimeofday(&tv, &tz); /* get time and apply DOS offset */
+ now = tv.tv_sec + delta_clock;
+ tm = *localtime(&now);
+
+ tm.tm_year = R_CX - 1900;
+ tm.tm_mon = R_DH - 1;
+ tm.tm_mday = R_DL;
+ tm.tm_wday = R_AL;
+
+ now = mktime(&tm);
+ if (now == -1)
+ return (DATA_INVALID);
+
+ delta_clock = now - tv.tv_sec; /* compute new offset? */
+ R_AL = 0;
+ return(0);
+}
+
+/*
+** 21:2c
+**
+** Get time
+*/
+static int
+int21_2c(regcontext_t *REGS)
+{
+ struct timeval tv;
+ struct timezone tz;
+ struct tm tm;
+ time_t now;
+
+ gettimeofday(&tv, &tz);
+ now = tv.tv_sec + delta_clock;
+ tm = *localtime(&now);
+
+ R_CH = tm.tm_hour;
+ R_CL = tm.tm_min;
+ R_DH = tm.tm_sec;
+ R_DL = tv.tv_usec / 10000;
+ return(0);
+}
+
+/*
+** 21:2d
+**
+** Set time
+*/
+static int
+int21_2d(regcontext_t *REGS)
+{
+ struct timeval tv;
+ struct timezone tz;
+ struct tm tm;
+ time_t now;
+
+ gettimeofday(&tv, &tz);
+ now = tv.tv_sec + delta_clock;
+ tm = *localtime(&now);
+
+ tm.tm_hour = R_CH;
+ tm.tm_min = R_CL;
+ tm.tm_sec = R_DH;
+ tv.tv_usec = R_DL * 10000;
+
+ now = mktime(&tm);
+ if (now == -1)
+ return (DATA_INVALID);
+
+ delta_clock = now - tv.tv_sec;
+ R_AL = 0;
+ return(0);
+}
+
+/*
+** 21:2f
+**
+** get DTA
+*/
+static int
+int21_2f(regcontext_t *REGS)
+{
+ N_PUTVEC(R_ES, R_BX, disk_transfer_addr);
+ debug(D_FILE_OPS, "get dta at %x:%x\n", R_ES, R_BX);
+ return(0);
+}
+
+/*
+** 21:30
+**
+** get DOS version number.
+**
+** XXX begging for a rewrite
+*/
+static int
+int21_30(regcontext_t *REGS)
+{
+ int v;
+
+ char *cmd = (char *)MAKEPTR(get_env(), 0);
+
+ /*
+ * retch. I think this skips the environment and looks for the name
+ * of the current command.
+ */
+ do {
+ while (*cmd)
+ ++cmd;
+ } while (*++cmd);
+ ++cmd;
+ cmd += *(short *)cmd + 1;
+ while (cmd[-1] && cmd[-1] != '\\' && cmd[-1] != ':')
+ --cmd;
+
+ /* get the version we're pretending to be for this sucker */
+ v = getver(cmd);
+ R_AL = (v / 100) & 0xff;
+ R_AH = v % 100;
+ return(0);
+}
+
+/*
+** 21:33:05
+**
+** Get boot drive
+*/
+static int
+int21_33_5(regcontext_t *REGS)
+{
+ R_DL = 3; /* always booted from C */
+ return(0);
+}
+
+/*
+** 21:33:06
+**
+** get true DOS version
+*/
+static int
+int21_33_6(regcontext_t *REGS)
+{
+ int v;
+
+ v = getver(NULL);
+ R_BL = (v / 100) & 0xff;
+ R_BH = v % 100;
+ R_DH = 0;
+ R_DL = 0;
+ return(0);
+}
+
+/*
+** 21:33
+**
+** extended break checking
+*/
+static int
+int21_33(regcontext_t *REGS)
+{
+ int ftemp;
+
+ switch (R_AL) {
+ case 0x00:
+ R_DL = ctrl_c_flag;
+ break;
+ case 0x01:
+ ctrl_c_flag = R_DL;
+ break;
+ case 0x02:
+ ftemp = ctrl_c_flag;
+ ctrl_c_flag = R_DL;
+ R_DL = ftemp;
+ break;
+
+ default:
+ unknown_int3(0x21, 0x33, R_AL, REGS);
+ return(FUNC_NUM_IVALID);
+ }
+ return(0);
+}
+
+/*
+** 21:34
+**
+** Get address of InDos flag
+**
+** XXX check interrupt list WRT location of critical error flag too.
+*/
+static int
+int21_34(regcontext_t *REGS)
+{
+ N_PUTVEC(R_ES, R_BX, (u_long)InDOS);
+ return(0);
+}
+
+/*
+** 21:35
+**
+** get interrupt vector
+*/
+static int
+int21_35(regcontext_t *REGS)
+{
+ N_PUTVEC(R_ES, R_BX, ivec[R_AL]);
+ debug(D_MEMORY, "%02x <- %04x:%04x\n", R_AL, R_ES, R_BX);
+ return(0);
+}
+
+/*
+** 21:37
+**
+** switch character manipulation
+**
+*/
+static int
+int21_37(regcontext_t *REGS)
+{
+ switch (R_AL) {
+ case 0: /* get switch character */
+ R_DL = '/';
+ break;
+
+ case 1: /* set switch character (normally /) */
+ /* ignored by most versions of DOS */
+ break;
+ default:
+ unknown_int3(0x21, 0x37, R_AL, REGS);
+ return (FUNC_NUM_IVALID);
+ }
+ return(0);
+
+}
+
+/*
+** 21:38
+**
+** country code information
+**
+** XXX internat guru?
+*/
+static int
+int21_38(regcontext_t *REGS)
+{
+ char *addr;
+
+ if (R_DX == 0xffff) {
+ debug(D_HALF, "warning: set country code ignored");
+ return(0);
+ }
+ addr = (char *)N_GETPTR(R_DS, R_DX);
+ N_PUTVEC(countryinfo.ciCaseMapSegment, countryinfo.ciCaseMapOffset,
+ upcase_vector);
+ memcpy(addr, &countryinfo, sizeof(countryinfo));
+ return(0);
+}
+
+/*
+** 21:39
+** 21:3a
+** 21:41
+** 21:56
+**
+** mkdir, rmdir, unlink, rename
+*/
+static int
+int21_dirfn(regcontext_t *REGS)
+{
+ int error;
+ char fname[PATH_MAX],tname[PATH_MAX];
+ int drive;
+
+ error = translate_filename((u_char *)N_GETPTR(R_DS, R_DX), fname, &drive);
+ if (error)
+ return (error);
+
+ if (dos_readonly(drive))
+ return (WRITE_PROT_DISK);
+
+ switch(R_AH) {
+ case 0x39:
+ debug(D_FILE_OPS, "mkdir(%s)\n", fname);
+ error = mkdir(fname, 0777);
+ break;
+ case 0x3a:
+ debug(D_FILE_OPS, "rmdir(%s)\n", fname);
+ error = rmdir(fname);
+ break;
+ case 0x41:
+ debug(D_FILE_OPS, "unlink(%s)\n", fname);
+ error = unlink(fname);
+ break;
+ case 0x56: /* rename - some extra work */
+ error = translate_filename((u_char *)GETPTR(R_ES, R_DI), tname, &drive);
+ if (error)
+ return (error);
+
+ debug(D_FILE_OPS, "rename(%s, %s)\n", fname, tname);
+ error = rename(fname, tname);
+ break;
+
+ default:
+ fatal("call to int21_dirfn for unknown function %x\n",R_AH);
+ }
+ if (error < 0) {
+ switch (errno) {
+ case ENOTDIR:
+ case ENOENT:
+ return (PATH_NOT_FOUND);
+ case EXDEV:
+ return (NOT_SAME_DEV);
+ default:
+ return (ACCESS_DENIED);
+ }
+ }
+ return(0);
+}
+
+/*
+** 21:3b
+**
+** chdir
+*/
+static int
+int21_3b(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "chdir(%s)\n",(u_char *)N_GETPTR(R_DS, R_DX));
+ return(dos_setcwd((u_char *)N_GETPTR(R_DS, R_DX)));
+}
+
+/*
+** 21:3c
+** 21:5b
+** 21:6c
+**
+** open, creat, creat new, multipurpose creat
+*/
+static int
+int21_open(regcontext_t *REGS)
+{
+ int error;
+ char fname[PATH_MAX];
+ struct stat sb;
+ int mode,action,status;
+ char *pname;
+ int drive;
+ int fd;
+
+ switch(R_AH) {
+ case 0x3c: /* creat */
+ pname = (char *)N_GETPTR(R_DS, R_DX);
+ action = 0x12; /* create/truncate regardless */
+ mode = O_RDWR;
+ debug(D_FILE_OPS, "creat");
+ break;
+
+ case 0x3d: /* open */
+ pname = (char *)N_GETPTR(R_DS, R_DX);
+ action = 0x01; /* fail if not exist, open if exists */
+ switch (R_AL & 3) {
+ case 0:
+ mode = O_RDONLY;
+ break;
+ case 1:
+ mode = O_WRONLY;
+ break;
+ case 2:
+ mode = O_RDWR;
+ break;
+ default:
+ return (FUNC_NUM_IVALID);
+ }
+ debug(D_FILE_OPS, "open");
+ break;
+
+ case 0x5b: /* creat new */
+ pname = (char *)N_GETPTR(R_DS, R_DL);
+ action = 0x10; /* create if not exist, fail if exists */
+ mode = O_RDWR;
+ debug(D_FILE_OPS, "creat_new");
+ break;
+
+ case 0x6c: /* multipurpose */
+ pname = (char *)N_GETPTR(R_DS, R_SI);
+ action = R_DX;
+ switch (R_BL & 3) {
+ case 0:
+ mode = O_RDONLY;
+ break;
+ case 1:
+ mode = O_WRONLY;
+ break;
+ case 2:
+ mode = O_RDWR;
+ break;
+ default:
+ return (FUNC_NUM_IVALID);
+ }
+ debug(D_FILE_OPS, "mopen");
+ break;
+
+ default:
+ fatal("called int21_creat for unknown function %x\n",R_AH);
+ }
+ if (action & 0x02) /* replace/open mode */
+ mode |= O_TRUNC;
+
+ /* consider proposed name */
+ error = translate_filename(pname, fname, &drive);
+ if (error)
+ return (error);
+
+ debug(D_FILE_OPS, "(%s)\n", fname);
+
+ if (dos_readonly(drive) && (mode != O_RDONLY))
+ return (WRITE_PROT_DISK);
+
+ if (ustat(fname, &sb) < 0) { /* file does not exist */
+ if (action & 0x10) { /* create? */
+ sb.st_ino = 0;
+ mode |= O_CREAT; /* have to create as we go */
+ status = 0x02; /* file created */
+ } else {
+ return(FILE_NOT_FOUND);
+ }
+ } else {
+ if (S_ISDIR(sb.st_mode))
+ return(ACCESS_DENIED);
+ if (action & 0x03) { /* exists, work with it */
+ if (action & 0x02) {
+ if (!S_ISREG(sb.st_mode)) { /* only allowed for files */
+ debug(D_FILE_OPS,"attempt to truncate non-regular file\n");
+ return(ACCESS_DENIED);
+ }
+ status = 0x03; /* we're going to truncate it */
+ } else {
+ status = 0x01; /* just open it */
+ }
+ } else {
+ return(FILE_ALREADY_EXISTS); /* exists, fail */
+ }
+ }
+
+ if ((fd = open(fname, mode, from_dos_attr(R_CX))) < 0) {
+ debug(D_FILE_OPS,"failed to open %s : %s\n",fname,strerror(errno));
+ return (ACCESS_DENIED);
+ }
+
+ if (R_AH == 0x6c) /* need to return status too */
+ R_CX = status;
+ R_AX = fd; /* return fd */
+ return(0);
+}
+
+/*
+** 21:3e
+**
+** close
+*/
+static int
+int21_3e(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "close(%d)\n", R_BX);
+
+ if (R_BX == fileno(debugf)) {
+ printf("attempt to close debugging fd\n");
+ return (HANDLE_INVALID);
+ }
+
+ if (close(R_BX) < 0)
+ return (HANDLE_INVALID);
+ return(0);
+}
+
+/*
+** 21:3f
+**
+** read
+*/
+static int
+int21_3f(regcontext_t *REGS)
+{
+ int fd;
+ char *addr;
+ int nbytes,n;
+ int avail;
+
+ addr = (char *)N_GETPTR(R_DS, R_DX);
+
+ debug(D_FILE_OPS, "read(%d, %d)\n", R_BX, R_CX);
+
+ if (R_BX == 0) {
+ if (redirect0) {
+ n = read (R_BX, addr, R_CX);
+ } else {
+ n = 0;
+ while (n < R_CX) {
+ avail = tty_read(REGS, TTYF_BLOCK|TTYF_CTRL|TTYF_ECHONL);
+ if (avail < 0)
+ return (0);
+ if ((addr[n++] = avail) == '\r')
+ break;
+ }
+ }
+ } else {
+ n = read (R_BX, addr, R_CX);
+ }
+ if (n < 0)
+ return (READ_FAULT);
+
+ R_AX = n;
+ return(0);
+}
+
+/*
+** 21:40
+**
+** write
+*/
+static int
+int21_40(regcontext_t *REGS)
+{
+ char *addr;
+ int nbytes,n;
+
+ addr = (char *)N_GETPTR(R_DS, R_DX);
+ nbytes = R_CX;
+
+ debug(D_FILE_OPS, "write(%d, %d)\n", R_BX, nbytes);
+
+ switch (R_BX) {
+ case 0:
+ if (redirect0) {
+ n = write (R_BX, addr, nbytes);
+ break;
+ }
+ n = nbytes;
+ while (nbytes-- > 0)
+ tty_write(*addr++, -1);
+ break;
+ case 1:
+ if (redirect1) {
+ n = write (R_BX, addr, nbytes);
+ break;
+ }
+ n = nbytes;
+ while (nbytes-- > 0)
+ tty_write(*addr++, -1);
+ break;
+ case 2:
+ if (redirect2) {
+ n = write (R_BX, addr, nbytes);
+ break;
+ }
+ n = nbytes;
+ while (nbytes-- > 0)
+ tty_write(*addr++, -1);
+ break;
+ default:
+ n = write (R_BX, addr, nbytes);
+ break;
+ }
+ if (n < 0)
+ return (WRITE_FAULT);
+
+ R_AX = n;
+ return(0);
+}
+
+/*
+** 21:42
+**
+** seek
+*/
+static int
+int21_42(regcontext_t *REGS)
+{
+ int whence;
+ off_t offset;
+
+ offset = ((off_t)R_CX << 16) + R_DX;
+ switch (R_AL) {
+ case 0:
+ whence = SEEK_SET;
+ break;
+ case 1:
+ whence = SEEK_CUR;
+ break;
+ case 2:
+ whence = SEEK_END;
+ break;
+ default:
+ return (FUNC_NUM_IVALID);
+ }
+
+ debug(D_FILE_OPS, "seek(%d, 0x%qx, %d)\n", R_BX, offset, whence);
+
+ if ((offset = lseek(R_BX, offset, whence)) < 0) {
+ if (errno == EBADF)
+ return (HANDLE_INVALID);
+ else
+ return (SEEK_ERROR);
+ }
+
+ R_DX = (offset >> 16) & 0xffff;
+ R_AX = offset & 0xffff;
+ return(0);
+}
+
+/*
+** 21:43
+**
+** get/set attributes
+*/
+static int
+int21_43(regcontext_t *REGS)
+{
+ int error;
+ char fname[PATH_MAX];
+ struct stat sb;
+ int mode;
+ int drive;
+
+ error = translate_filename((u_char *)N_GETPTR(R_DS, R_DX), fname, &drive);
+ if (error)
+ return (error);
+
+ debug(D_FILE_OPS, "get/set attributes: %s, cx=%x, al=%d\n",
+ fname, R_CX, R_AL);
+
+ if (stat(fname, &sb) < 0) {
+ debug(D_FILE_OPS, "stat failed for %s\n", fname);
+ return (FILE_NOT_FOUND);
+ }
+
+ switch (R_AL) {
+ case 0: /* get attributes */
+ mode = 0;
+ if (dos_readonly(drive) || access(fname, W_OK))
+ mode |= 0x01;
+ if (S_ISDIR(sb.st_mode))
+ mode |= 0x10;
+ R_CX = mode;
+ break;
+
+ case 1: /* set attributes - XXX ignored */
+ if (R_CX & 0x18)
+ return (ACCESS_DENIED);
+ break;
+
+ default:
+ return (FUNC_NUM_IVALID);
+ }
+ return(0);
+}
+
+/*
+** 21:44:0
+**
+** ioctl - get device info
+**
+** XXX it would be nice to detect EOF.
+*/
+static int
+int21_44_0(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "ioctl get %d\n", R_BX);
+
+ switch (R_BX) {
+ case 0:
+ R_DX = 0x80 | 0x01; /* is device, is standard output */
+ break;
+ case 1:
+ R_DX = 0x80 | 0x02; /* is device, is standard input */
+ break;
+ case 2:
+ R_DX = 0x80; /* is device */
+ break;
+ default:
+ if (isatty (R_BX))
+ R_DX = 0x80; /* is a device */
+ else
+ R_DX = 0; /* is a file */
+ break;
+ }
+ return(0);
+}
+
+/*
+** 21:44:01
+**
+** ioctl - set device info
+*/
+static int
+int21_44_1(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "ioctl set device info %d flags %x (ignored)\n",
+ R_BX, R_DX);
+ return(0);
+}
+
+/*
+** 21:44:8
+**
+** test for removable block device
+*/
+static int
+int21_44_8(regcontext_t *REGS)
+{
+ R_AX = 1; /* fixed */
+ return(0);
+}
+
+/*
+** 21:44:0
+**
+** test for remote device (disallow direct I/O)
+*/
+static int
+int21_44_9(regcontext_t *REGS)
+{
+ R_DX = 0x1200; /* disk is remote, direct I/O not allowed */
+}
+
+/*
+** 21:45
+**
+** dup
+*/
+static int
+int21_45(regcontext_t *REGS)
+{
+ int nfd;
+
+ debug(D_FILE_OPS, "dup(%d)\n", R_BX);
+
+ if ((nfd = dup(R_BX)) < 0) {
+ if (errno == EBADF)
+ return (HANDLE_INVALID);
+ else
+ return (TOO_MANY_OPEN_FILES);
+ }
+ R_AX = nfd;
+ return(0);
+}
+
+/*
+** 21:46
+**
+** dup2
+*/
+static int
+int21_46(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "dup2(%d, %d)\n", R_BX, R_CX);
+
+ if (dup2(R_BX, R_CX) < 0) {
+ if (errno == EMFILE)
+ return (TOO_MANY_OPEN_FILES);
+ else
+ return (HANDLE_INVALID);
+ }
+ return(0);
+}
+
+/*
+** 21:47
+**
+** getcwd
+*/
+static int
+int21_47(regcontext_t *REGS)
+{
+ int n,nbytes;
+ char *p,*addr;
+
+ n = R_DL;
+ if (!n--)
+ n = diskdrive;
+
+ p = (char *)dos_getcwd(n) + 1;
+ addr = (char *)N_GETPTR(R_DS, R_SI);
+
+ nbytes = strlen(p);
+ if (nbytes > 63)
+ nbytes = 63;
+
+ memcpy(addr, p, nbytes);
+ addr[nbytes] = 0;
+ return(0);
+}
+
+/*
+** 21:48
+**
+** allocate memory
+*/
+static int
+int21_48(regcontext_t *REGS)
+{
+ int memseg,avail;
+
+ memseg = mem_alloc(R_BX, pspseg, &avail);
+
+ if (memseg == 0L) {
+ R_BX = avail;
+ return (INSUF_MEM);
+ }
+
+ R_AX = memseg;
+ return(0);
+}
+
+/*
+** 21:49
+**
+** free memory
+*/
+static int
+int21_49(regcontext_t *REGS)
+{
+ if (mem_adjust(R_ES, 0, NULL) < 0)
+ return (MEM_BLK_ADDR_IVALID);
+ return(0);
+}
+
+/*
+** 21:4a
+**
+** resize memory block
+*/
+static int
+int21_4a(regcontext_t *REGS)
+{
+ int n,avail;
+
+ if ((n = mem_adjust(R_ES, R_BX, &avail)) < 0) {
+ R_BX = avail;
+ if (n == -1)
+ return (INSUF_MEM);
+ else
+ return (MEM_BLK_ADDR_IVALID);
+ }
+ return(0);
+}
+
+/*
+** 21:4b
+**
+** exec
+**
+** XXX verify!
+*/
+static int
+int21_4b(regcontext_t *REGS)
+{
+ int fd;
+ char *fname[PATH_MAX];
+ u_short *param;
+
+ debug(D_EXEC, "exec(%s)\n",(u_char *)N_GETPTR(R_DS, R_DX));
+
+ if ((fd = open_prog((u_char *)N_GETPTR(R_DS, R_DX))) < 0) {
+ debug(D_EXEC, "%s: command not found\n", fname);
+ return (FILE_NOT_FOUND);
+ }
+
+ /* child */
+ param = (u_short *)N_GETPTR(R_ES, R_BX);
+
+ switch (R_AL) {
+ case 0x00: /* load and execute */
+ exec_command(REGS, 1, fd, cmdname, param);
+ close(fd);
+ break;
+
+ case 0x01: /* just load */
+ exec_command(REGS, 0, fd, cmdname, param);
+ close(fd);
+ break;
+
+ case 0x03: /* load overlay */
+ load_overlay(fd, param[0], param[1]);
+ close(fd);
+ break;
+
+ default:
+ unknown_int3(0x21, 0x4b, R_AL, REGS);
+ return (FUNC_NUM_IVALID);
+ }
+ return(0);
+}
+
+/*
+** 21:4c
+**
+** return with code
+*/
+static int
+int21_4c(regcontext_t *REGS)
+{
+ return_status = R_AL;
+ done(REGS, R_AL);
+}
+
+/*
+** 21:4d
+**
+** get return code of child
+*/
+static int
+int21_4d(regcontext_t *REGS)
+{
+ R_AX = return_status;
+ return(0);
+}
+
+/*
+** 21:4e
+** 21:4f
+**
+** find first, find next
+*/
+static int
+int21_find(regcontext_t *REGS)
+{
+ find_block_t *dta;
+ dosdir_t dosdir;
+ int error;
+
+ dta = (find_block_t *)VECPTR(disk_transfer_addr);
+
+ switch (R_AH) {
+ case 0x4e: /* find first */
+ error = find_first((u_char *)N_GETPTR(R_DS, R_DX), R_CX, &dosdir, dta);
+ break;
+ case 0x4f:
+ error = find_next(&dosdir, dta);
+ break;
+ default:
+ fatal("called int21_find for unknown function %x\n",R_AH);
+ }
+ if (!error) {
+ dosdir_to_dta(&dosdir, dta);
+ R_AX = 0;
+ }
+ return(error);
+}
+
+/*
+** 21:50
+**
+** set PSP
+*/
+static int
+int21_50(regcontext_t *REGS)
+{
+ pspseg = R_BX;
+ return(0);
+}
+
+/*
+** 21:57:00
+**
+** get mtime for handle
+*/
+static int
+int21_57_0(regcontext_t *REGS)
+{
+ struct stat sb;
+ u_short date,time;
+
+ if (fstat(R_BX, &sb) < 0)
+ return (HANDLE_INVALID);
+ encode_dos_file_time(sb.st_mtime, &date, &time);
+ R_CX = time;
+ R_DX = date;
+ return(0);
+}
+
+/*
+** 21:57:01
+**
+** set mtime for handle
+*/
+static int
+int21_57_1(regcontext_t *REGS)
+{
+#ifdef __NetBSD__ /* XXX need futimes() */
+ struct stat sb;
+ struct timeval tv[2];
+ u_short date, time;
+
+ time = R_CX;
+ date = R_DX;
+ tv[0].tv_sec = tv[1].tv_sec = decode_dos_file_time(date, time);
+ tv[0].tv_usec = tv[1].tv_usec = 0;
+ if (futimes(R_BX, tv) < 0)
+ return (HANDLE_INVALID);
+ break;
+#endif
+ return(0);
+}
+
+/*
+** 21:58
+**
+** get/set memory strategy
+** get/set UMB link state
+*/
+static int
+int21_58(regcontext_t *REGS)
+{
+ switch (R_AL) {
+ case 0x00: /* get memory strategy */
+ R_AX = memory_strategy;
+ break;
+ case 0x01: /* set memory strategy */
+ memory_strategy = R_BL;
+ if (memory_strategy > 2) /* higher make no sense without UMBs */
+ memory_strategy = 2;
+ break;
+ case 0x02: /* get UMB link state */
+ R_AL = 0; /* UMBs not in link chain */
+ break;
+ default: /* includes set, which is invalid */
+ unknown_int3(0x21, 0x58, R_AL, REGS);
+ return (FUNC_NUM_IVALID);
+ }
+ return(0);
+}
+
+/*
+** 21:59
+**
+** get extended error information
+*/
+static int
+int21_59(regcontext_t *REGS)
+{
+ R_AX = doserrno;
+ switch (doserrno) {
+ case 1:
+ case 6:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 15:
+ R_BH = 7; /* application error */
+ break;
+
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ R_BH = 8; /* not found */
+ break;
+
+ case 7:
+ case 8:
+ R_BH = 1; /* out of resource */
+ break;
+
+ default:
+ R_BH = 12; /* already exists */
+ break;
+ }
+ R_BL = 6; /* always ignore! */
+ R_CH = 1; /* unknown/inappropriate */
+ return(0);
+}
+
+/*
+** 21:5a
+**
+** create temporary file
+*/
+static int
+int21_5a(regcontext_t *REGS)
+{
+ char fname[PATH_MAX];
+ char *pname;
+ int error;
+ int n;
+ int drive;
+ int fd;
+
+ /* get and check proposed path */
+ pname = (char *)N_GETPTR(R_DS, R_DX);
+ error = translate_filename(pname, fname, &drive);
+ if (error)
+ return (error);
+
+ debug(D_FILE_OPS, "tempname(%s)\n", fname);
+
+ if (dos_readonly(drive))
+ return (WRITE_PROT_DISK);
+
+ n = strlen(fname);
+ strcat(fname,"__dostmp.XXX");
+ fd = mkstemp(fname);
+ if (fd < 0)
+ return (ACCESS_DENIED);
+
+ strcat(pname, fname + n); /* give back the full name */
+ R_AX = fd;
+ return(0);
+}
+
+/*
+** 21:60
+**
+** canonicalise name
+*/
+static int
+int21_60(regcontext_t *REGS)
+{
+ return(dos_makepath((char *)GETPTR(R_DS, R_SI),
+ (char *)GETPTR(R_ES, R_DI)));
+}
+
+/*
+** 21:62
+**
+** get current PSP
+*/
+static int
+int21_62(regcontext_t *REGS)
+{
+ R_BX = pspseg;
+}
+
+/*
+** 21:65:23
+**
+** determine yes/no
+** (mostly for humour value 8)
+*/
+static int
+int21_65_23(regcontext_t *REGS)
+{
+ switch (R_DL) {
+ case 'n': /* no, nein, non, nyet */
+ case 'N':
+ R_AX = 0;
+ break;
+ case 'y': /* yes */
+ case 'Y':
+ case 'j': /* ja */
+ case 'J':
+ case 'o': /* oui */
+ case 'O':
+ case 'd': /* da */
+ case 'D':
+ R_AX = 1;
+ break;
+ default: /* maybe */
+ R_AX = 2;
+ break;
+ }
+ return(0);
+}
+
+/*
+** 21:68
+** 21:6a
+**
+** fflush/commit file
+*/
+static int
+int21_fflush(regcontext_t *REGS)
+{
+ debug(D_FILE_OPS, "fsync(%d)\n", R_BX);
+
+ if (fsync(R_BX) < 0)
+ return (HANDLE_INVALID);
+ return(0);
+}
+
+/******************************************************************************
+** 21:0f 21:10 21:11 21:12 21:16 21:27 21:28:21:29
+**
+** FCB functions
+*/
+static void
+openfcb(struct fcb *fcbp)
+{
+ struct stat statb;
+
+ fcbp->fcbDriveID = 3; /* drive C */
+ fcbp->fcbCurBlockNo = 0;
+ fcbp->fcbRecSize = 128;
+ if (fstat(fcbp->fcb_fd, &statb) < 0) {
+ debug(D_FILE_OPS, "open not complete with errno %d\n", errno);
+ return;
+ }
+ encode_dos_file_time(statb.st_mtime,
+ &fcbp->fcbFileDate, &fcbp->fcbFileTime);
+ fcbp->fcbFileSize = statb.st_size;
+}
+
+static int
+getfcb_rec(struct fcb *fcbp, int nrec)
+{
+ int n;
+
+ n = fcbp->fcbRandomRecNo;
+ if (fcbp->fcbRecSize >= 64)
+ n &= 0xffffff;
+ fcbp->fcbCurRecNo = n % 128;
+ fcbp->fcbCurBlockNo = n / 128;
+ if (lseek(fcbp->fcb_fd, n * fcbp->fcbRecSize, SEEK_SET) < 0)
+ return (-1);
+ return (nrec * fcbp->fcbRecSize);
+}
+
+
+static int
+setfcb_rec(struct fcb *fcbp, int n)
+{
+ int recs, total;
+
+ total = fcbp->fcbRandomRecNo;
+ if (fcbp->fcbRecSize >= 64)
+ total &= 0xffffff;
+ recs = (n+fcbp->fcbRecSize-1) / fcbp->fcbRecSize;
+ total += recs;
+
+ fcbp->fcbRandomRecNo = total;
+ fcbp->fcbCurRecNo = total % 128;
+ fcbp->fcbCurBlockNo = total / 128;
+}
+
+void
+fcb_to_string(fcbp, buf)
+ struct fcb *fcbp;
+ u_char *buf;
+{
+
+ if (fcbp->fcbDriveID != 0x00) {
+ *buf++ = fcbp->fcbDriveID - 1 + 'A';
+ *buf++ = ':';
+ }
+ pack_name(fcbp->fcbFileName, buf);
+}
+
+
+static int
+int21_fcb(regcontext_t *REGS)
+{
+ char buf[PATH_MAX];
+ char fname[PATH_MAX];
+ struct stat sb;
+ dosdir_t dosdir;
+ struct fcb *fcbp;
+ find_block_t *dta;
+ u_char *addr;
+ int error;
+ int drive;
+ int fd;
+ int nbytes,n;
+
+
+ fcbp = (struct fcb *)GETPTR(R_DS, R_DX);
+
+ switch (R_AH) {
+
+ case 0x0f: /* open file with FCB */
+ fcb_to_string(fcbp, buf);
+ error = translate_filename(buf, fname, &drive);
+ if (error)
+ return (error);
+
+ debug(D_FILE_OPS, "open FCB(%s)\n", fname);
+
+ if (ustat(fname, &sb) < 0)
+ sb.st_ino = 0;
+
+ if (dos_readonly(drive))
+ return (WRITE_PROT_DISK);
+
+ if (sb.st_ino == 0 || S_ISDIR(sb.st_mode))
+ return (FILE_NOT_FOUND);
+
+ if ((fd = open(fname, O_RDWR)) < 0) {
+ if (errno == ENOENT)
+ return (FILE_NOT_FOUND);
+ else
+ return (ACCESS_DENIED);
+ }
+
+ fcbp->fcb_fd = fd;
+ openfcb(fcbp);
+ R_AL = 0;
+ break;
+
+ case 0x10: /* close file with FCB */
+ debug(D_FILE_OPS, "close FCB(%d)\n", fcbp->fcb_fd);
+
+ if (close(fcbp->fcb_fd) < 0)
+ return (HANDLE_INVALID);
+
+ fcbp->fcb_fd = -1;
+ R_AL = 0;
+ break;
+
+ case 0x11: /* find_first with FCB */
+ dta = (find_block_t *)VECPTR(disk_transfer_addr);
+
+ fcb_to_string(fcbp, buf);
+ error = find_first(buf, fcbp->fcbAttribute, &dosdir, dta);
+ if (error)
+ return (error);
+
+ dosdir_to_dta(&dosdir, dta);
+ R_AL = 0;
+ break;
+
+ case 0x12: /* find_next with FCB */
+ dta = (find_block_t *)VECPTR(disk_transfer_addr);
+
+ error = find_next(&dosdir, dta);
+ if (error)
+ return (error);
+
+ dosdir_to_dta(&dosdir, dta);
+ R_AL = 0;
+ break;
+
+ case 0x16: /* create file with FCB */
+ fcb_to_string(fcbp, buf);
+ error = translate_filename(buf, fname, &drive);
+ if (error)
+ return (error);
+
+ debug(D_FILE_OPS, "creat FCB(%s)\n", fname);
+
+ if (ustat(fname, &sb) < 0)
+ sb.st_ino = 0;
+
+ if (dos_readonly(drive))
+ return (WRITE_PROT_DISK);
+
+ if (sb.st_ino && !S_ISREG(sb.st_mode))
+ return (ACCESS_DENIED);
+
+ if ((fd = open(fname, O_CREAT|O_TRUNC|O_RDWR, 0666)) < 0)
+ return (ACCESS_DENIED);
+
+ fcbp->fcb_fd = fd;
+ openfcb(fcbp);
+ R_AL = 0;
+ break;
+
+ case 0x27: /* random block read */
+ addr = (u_char *)VECPTR(disk_transfer_addr);
+ nbytes = getfcb_rec(fcbp, R_CX);
+
+ if (nbytes < 0)
+ return (READ_FAULT);
+ n = read(fcbp->fcb_fd, addr, nbytes);
+ if (n < 0)
+ return (READ_FAULT);
+ R_CX = setfcb_rec(fcbp, n);
+ if (n < nbytes) {
+ nbytes = n % fcbp->fcbRecSize;
+ if (0 == nbytes) {
+ R_AL = 0x01;
+ } else {
+ bzero(addr + n, fcbp->fcbRecSize - nbytes);
+ R_AL = 0x03;
+ }
+ } else {
+ R_AL = 0;
+ }
+ break;
+
+ case 0x28: /* random block write */
+ addr = (u_char *)VECPTR(disk_transfer_addr);
+ nbytes = getfcb_rec(fcbp, R_CX);
+
+ if (nbytes < 0)
+ return (WRITE_FAULT);
+ n = write(fcbp->fcb_fd, addr, nbytes);
+ if (n < 0)
+ return (WRITE_FAULT);
+ R_CX = setfcb_rec(fcbp, n);
+ if (n < nbytes) {
+ R_AL = 0x01;
+ } else {
+ R_AL = 0;
+ }
+ break;
+
+ case 0x29: /* parse filename */
+ debug(D_FILE_OPS,"parse filename: flag=%d, ", R_AL);
+
+ R_AX = parse_filename(R_AL,
+ (char *)N_GETPTR(R_DS, R_SI),
+ (char *)N_GETPTR(R_ES, R_DI),
+ &nbytes);
+ debug(D_FILE_OPS, "%d %s, FCB: %d, %.11s\n",
+ nbytes,
+ N_GETPTR(R_DS, R_SI),
+ *(int *)N_GETPTR(R_ES, R_DI),
+ N_GETPTR(R_ES, R_DI) + 1);
+
+ R_SI += nbytes;
+ break;
+
+ default:
+ fatal("called int21_fcb with unknown function %x\n",R_AH);
+ }
+ return(0);
+}
+
+/*
+** 21:5d
+** 21:5e
+** 21:5f
+**
+** network functions
+** XXX relevant?
+*/
+static int
+int21_net(regcontext_t *REGS)
+{
+ switch(R_AH) {
+ case 0x5d:
+ switch(R_AL) {
+ case 0x06:
+ debug(D_HALF, "Get Swapable Area\n");
+ return (ACCESS_DENIED);
+ case 0x08: /* Set redirected printer mode */
+ debug(D_HALF, "Redirection is %s\n",
+ R_DL ? "seperate jobs" : "combined");
+ break;
+ case 0x09: /* Flush redirected printer output */
+ break;
+ default:
+ unknown_int3(0x21, 0x5d, R_AL, REGS);
+ return (FUNC_NUM_IVALID);
+ }
+ break;
+
+ case 0x5e:
+ case 0x5f:
+ unknown_int2(0x21, R_AH, REGS);
+ return (FUNC_NUM_IVALID);
+ default:
+ fatal("called int21_net with unknown function %x\n",R_AH);
+ }
+ return(0);
+}
+
+/*
+** 21:??
+**
+** Unknown/unsupported
+*/
+static int
+int21_NOFUNC(regcontext_t *REGS)
+{
+ unknown_int2(0x21, R_AH, REGS);
+ return (FUNC_NUM_IVALID);
+}
+
+/*
+** 21:??
+**
+** Null function; no error, no action
+*/
+static int
+int21_NULLFUNC(regcontext_t *REGS)
+{
+ R_AL = 0;
+ return(0);
+}
+
+
+static struct intfunc_table int21_table [] = {
+ { 0x00, IFT_NOSUBFUNC, int21_00, "terminate"},
+ { 0x01, IFT_NOSUBFUNC, int21_01, "read character with echo"},
+ { 0x02, IFT_NOSUBFUNC, int21_02, "write char to stdout"},
+ { 0x03, IFT_NOSUBFUNC, int21_NOFUNC, "read char from stdaux"},
+ { 0x04, IFT_NOSUBFUNC, int21_NOFUNC, "write char to stdaux"},
+ { 0x05, IFT_NOSUBFUNC, int21_NOFUNC, "write char to printer"},
+ { 0x06, IFT_NOSUBFUNC, int21_06, "direct console I/O"},
+ { 0x07, IFT_NOSUBFUNC, int21_07, "direct console in without echo"},
+ { 0x08, IFT_NOSUBFUNC, int21_08, "read character, no echo"},
+ { 0x09, IFT_NOSUBFUNC, int21_09, "write string to standard out"},
+ { 0x0a, IFT_NOSUBFUNC, int21_0a, "buffered input"},
+ { 0x0b, IFT_NOSUBFUNC, int21_0b, "get stdin status"},
+ { 0x0c, IFT_NOSUBFUNC, int21_0c, "flush stdin and read"},
+ { 0x0d, IFT_NOSUBFUNC, int21_NULLFUNC, "disk reset"},
+ { 0x0e, IFT_NOSUBFUNC, int21_0e, "select default drive"},
+ { 0x19, IFT_NOSUBFUNC, int21_19, "get default drive"},
+ { 0x1a, IFT_NOSUBFUNC, int21_1a, "set DTA"},
+ { 0x1b, IFT_NOSUBFUNC, int21_free, "get allocation for default drive"},
+ { 0x1c, IFT_NOSUBFUNC, int21_free, "get allocation for specific drive"},
+ { 0x1f, IFT_NOSUBFUNC, int21_NOFUNC, "get DPB for current drive"},
+ { 0x25, IFT_NOSUBFUNC, int21_25, "set interrupt vector"},
+ { 0x26, IFT_NOSUBFUNC, int21_26, "create new PSP"},
+ { 0x2a, IFT_NOSUBFUNC, int21_2a, "get date"},
+ { 0x2b, IFT_NOSUBFUNC, int21_2b, "set date"},
+ { 0x2c, IFT_NOSUBFUNC, int21_2c, "get time"},
+ { 0x2d, IFT_NOSUBFUNC, int21_2d, "set time"},
+ { 0x2e, IFT_NOSUBFUNC, int21_NULLFUNC, "set verify flag"},
+ { 0x2f, IFT_NOSUBFUNC, int21_2f, "get DTA"},
+ { 0x30, IFT_NOSUBFUNC, int21_30, "get DOS version"},
+ { 0x31, IFT_NOSUBFUNC, int21_NOFUNC, "terminate and stay resident"},
+ { 0x32, IFT_NOSUBFUNC, int21_NOFUNC, "get DPB for specific drive"},
+ { 0x33, 0x05, int21_33_5, "get boot drive"},
+ { 0x33, 0x06, int21_33_6, "get true version number"},
+ { 0x33, IFT_NOSUBFUNC, int21_33, "extended break checking"},
+ { 0x34, IFT_NOSUBFUNC, int21_34, "get address of InDos flag"},
+ { 0x35, IFT_NOSUBFUNC, int21_35, "get interrupt vector"},
+ { 0x36, IFT_NOSUBFUNC, int21_free, "get disk free space"},
+ { 0x37, IFT_NOSUBFUNC, int21_37, "switch character"},
+ { 0x38, IFT_NOSUBFUNC, int21_38, "country code/information"},
+ { 0x39, IFT_NOSUBFUNC, int21_dirfn, "mkdir"},
+ { 0x3a, IFT_NOSUBFUNC, int21_dirfn, "rmdir"},
+ { 0x3b, IFT_NOSUBFUNC, int21_3b, "chdir"},
+ { 0x3c, IFT_NOSUBFUNC, int21_open, "creat"},
+ { 0x3d, IFT_NOSUBFUNC, int21_open, "open"},
+ { 0x3e, IFT_NOSUBFUNC, int21_3e, "close"},
+ { 0x3f, IFT_NOSUBFUNC, int21_3f, "read"},
+ { 0x40, IFT_NOSUBFUNC, int21_40, "write"},
+ { 0x41, IFT_NOSUBFUNC, int21_dirfn, "unlink"},
+ { 0x42, IFT_NOSUBFUNC, int21_42, "lseek"},
+ { 0x43, IFT_NOSUBFUNC, int21_43, "get/set file attributes"},
+ { 0x44, 0x00, int21_44_0, "ioctl(get)"},
+ { 0x44, 0x01, int21_44_1, "ioctl(set)"},
+ { 0x44, 0x08, int21_44_8, "ioctl(test removable)"},
+ { 0x44, 0x09, int21_44_9, "ioctl(test remote)"},
+ { 0x45, IFT_NOSUBFUNC, int21_45, "dup"},
+ { 0x46, IFT_NOSUBFUNC, int21_46, "dup2"},
+ { 0x47, IFT_NOSUBFUNC, int21_47, "getwd"},
+ { 0x48, IFT_NOSUBFUNC, int21_48, "allocate memory"},
+ { 0x49, IFT_NOSUBFUNC, int21_49, "free memory"},
+ { 0x4a, IFT_NOSUBFUNC, int21_4a, "resize memory block"},
+ { 0x4b, IFT_NOSUBFUNC, int21_4b, "exec"},
+ { 0x4c, IFT_NOSUBFUNC, int21_4c, "exit with return code"},
+ { 0x4d, IFT_NOSUBFUNC, int21_4d, "get return code from child"},
+ { 0x4e, IFT_NOSUBFUNC, int21_find, "findfirst"},
+ { 0x4f, IFT_NOSUBFUNC, int21_find, "findnext"},
+ { 0x50, IFT_NOSUBFUNC, int21_50, "set psp"},
+ { 0x50, IFT_NOSUBFUNC, int21_62, "get psp"},
+ { 0x52, IFT_NOSUBFUNC, int21_NOFUNC, "get LoL"},
+ { 0x53, IFT_NOSUBFUNC, int21_NOFUNC, "translate BPB to DPB"},
+ { 0x54, IFT_NOSUBFUNC, int21_NULLFUNC, "get verify flag"},
+ { 0x55, IFT_NOSUBFUNC, int21_NOFUNC, "create PSP"},
+ { 0x56, IFT_NOSUBFUNC, int21_dirfn, "rename"},
+ { 0x57, 0x00, int21_57_0, "get mtime"},
+ { 0x57, 0x01, int21_57_1, "set mtime"},
+ { 0x58, IFT_NOSUBFUNC, int21_58, "get/set memory strategy"},
+ { 0x59, IFT_NOSUBFUNC, int21_59, "get extended error information"},
+ { 0x5a, IFT_NOSUBFUNC, int21_5a, "create temporary file"},
+ { 0x5b, IFT_NOSUBFUNC, int21_open, "create new file"},
+ { 0x5c, IFT_NOSUBFUNC, int21_NOFUNC, "flock"},
+ { 0x5d, IFT_NOSUBFUNC, int21_net, "network functions"},
+ { 0x5e, IFT_NOSUBFUNC, int21_net, "network functions"},
+ { 0x5f, IFT_NOSUBFUNC, int21_net, "network functions"},
+ { 0x60, IFT_NOSUBFUNC, int21_60, "canonicalise name/path"},
+ { 0x61, IFT_NOSUBFUNC, int21_NULLFUNC, "network functions (reserved)"},
+ { 0x62, IFT_NOSUBFUNC, int21_62, "get current PSP"},
+ { 0x63, IFT_NOSUBFUNC, int21_NOFUNC, "get DBCS lead-byte table"},
+ { 0x64, IFT_NOSUBFUNC, int21_NOFUNC, "set device-driver lookahead"},
+ { 0x65, 0x23, int21_65_23, "determine yes/no"},
+ { 0x65, IFT_NOSUBFUNC, int21_NOFUNC, "get extended country information"},
+ { 0x66, IFT_NOSUBFUNC, int21_NOFUNC, "get/set codepage table"},
+ { 0x67, IFT_NOSUBFUNC, int21_NULLFUNC, "set handle count"},
+ { 0x68, IFT_NOSUBFUNC, int21_fflush, "fflush"},
+ { 0x69, IFT_NOSUBFUNC, int21_NOFUNC, "get/set disk serial number"},
+ { 0x6a, IFT_NOSUBFUNC, int21_fflush, "commit file"},
+ { 0x6b, IFT_NOSUBFUNC, int21_NULLFUNC, "IFS ioctl"},
+ { 0x6c, IFT_NOSUBFUNC, int21_open, "extended open/create"},
+
+/* FCB functions */
+ { 0x0f, IFT_NOSUBFUNC, int21_fcb, "open file"},
+ { 0x10, IFT_NOSUBFUNC, int21_fcb, "close file"},
+ { 0x11, IFT_NOSUBFUNC, int21_fcb, "find first"},
+ { 0x12, IFT_NOSUBFUNC, int21_fcb, "find next"},
+ { 0x13, IFT_NOSUBFUNC, int21_NOFUNC, "delete"},
+ { 0x14, IFT_NOSUBFUNC, int21_NOFUNC, "sequential read"},
+ { 0x15, IFT_NOSUBFUNC, int21_NOFUNC, "sequential write"},
+ { 0x16, IFT_NOSUBFUNC, int21_fcb, "create/truncate"},
+ { 0x17, IFT_NOSUBFUNC, int21_NOFUNC, "rename"},
+ { 0x21, IFT_NOSUBFUNC, int21_NOFUNC, "read random"},
+ { 0x22, IFT_NOSUBFUNC, int21_NOFUNC, "write random"},
+ { 0x23, IFT_NOSUBFUNC, int21_NOFUNC, "get file size"},
+ { 0x24, IFT_NOSUBFUNC, int21_NOFUNC, "set random record number"},
+ { 0x27, IFT_NOSUBFUNC, int21_fcb, "random block read"},
+ { 0x28, IFT_NOSUBFUNC, int21_fcb, "random block write"},
+ { 0x29, IFT_NOSUBFUNC, int21_fcb, "parse filename into FCB"},
+
+/* CPM compactability */
+ { 0x18, IFT_NOSUBFUNC, int21_NULLFUNC, "CPM"},
+ { 0x1d, IFT_NOSUBFUNC, int21_NULLFUNC, "CPM"},
+ { 0x1e, IFT_NOSUBFUNC, int21_NULLFUNC, "CPM"},
+ { 0x20, IFT_NOSUBFUNC, int21_NULLFUNC, "CPM"},
+
+ { -1, IFT_NOSUBFUNC, NULL, NULL} /* terminator */
+
+};
+
+static int int21_fastlookup[256];
+
+char *dos_return[] = {
+ "OK",
+ "FUNC_NUM_IVALID",
+ "FILE_NOT_FOUND",
+ "PATH_NOT_FOUND",
+ "TOO_MANY_OPEN_FILES",
+ "ACCESS_DENIED",
+ "HANDLE_INVALID",
+ "MEM_CB_DEST",
+ "INSUF_MEM",
+ "MEM_BLK_ADDR_IVALID",
+ "ENV_INVALID",
+ "FORMAT_INVALID",
+ "ACCESS_CODE_INVALID",
+ "DATA_INVALID",
+ "UNKNOWN_UNIT",
+ "DISK_DRIVE_INVALID",
+ "ATT_REM_CUR_DIR",
+ "NOT_SAME_DEV",
+ "NO_MORE_FILES",
+ "WRITE_PROT_DISK",
+ "UNKNOWN_UNIT_CERR",
+ "DRIVE_NOT_READY",
+ "UNKNOWN_COMMAND",
+ "DATA_ERROR_CRC",
+ "BAD_REQ_STRUCT_LEN",
+ "SEEK_ERROR",
+ "UNKNOWN_MEDIA_TYPE",
+ "SECTOR_NOT_FOUND",
+ "PRINTER_OUT_OF_PAPER",
+ "WRITE_FAULT",
+ "READ_FAULT",
+ "GENERAL_FAILURE"
+};
+
+const int dos_ret_size = (sizeof(dos_return) / sizeof(char *));
+
+/*
+** for want of anywhere better to go
+*/
+static void
+int20(regcontext_t *REGS)
+{
+ /* int 20 = exit(0) */
+ done(REGS, 0);
+}
+
+static void
+int29(regcontext_t *REGS)
+{
+ tty_write(R_AL, TTYF_REDIRECT);
+}
+
+/******************************************************************************
+** entrypoint for MS-DOS functions
+*/
+static void
+int21(regcontext_t *REGS)
+{
+ int error;
+ int index;
+
+ /* look for a handler */
+ index = intfunc_find(int21_table, int21_fastlookup, R_AH, R_AL);
+
+ if (index == -1) { /* no matching functions */
+ unknown_int2(0x21, R_AL, REGS);
+ return;
+ }
+
+ /* call the handler */
+ error = int21_table[index].handler(REGS);
+ debug(D_DOSCALL, "msdos call %02x (%s) returns %d (%s)\n",
+ int21_table[index].func, int21_table[index].desc, error,
+ ((error >= 0) && (error <= dos_ret_size)) ? dos_return[error] : "unknown");
+
+ if (error) {
+ doserrno = error;
+ R_FLAGS |= PSL_C;
+
+ /* XXX is this entirely legitimate? */
+ if (R_AH >= 0x2f)
+ R_AX = error;
+ else
+ R_AX = 0xff;
+ } else {
+ R_FLAGS &= ~PSL_C;
+ }
+ return;
+}
+
+static u_char upcase_trampoline[] = {
+ 0xf4, /* HLT */
+ 0xcb, /* RETF */
+};
+
+/*
+** initialise thyself
+*/
+void
+dos_init(void)
+{
+ u_long vec;
+ int hn;
+
+ /* hook vectors */
+ vec = insert_softint_trampoline();
+ ivec[0x20] = vec;
+ register_callback(vec, int20, "int 20");
+
+ vec = insert_softint_trampoline();
+ ivec[0x21] = vec;
+ register_callback(vec, int21, "int 21");
+
+ vec = insert_softint_trampoline();
+ ivec[0x29] = vec;
+ register_callback(vec, int29, "int 29");
+
+ vec = insert_null_trampoline();
+ ivec[0x28] = vec; /* dos idle */
+ ivec[0x2b] = vec; /* reserved */
+ ivec[0x2c] = vec; /* reserved */
+ ivec[0x2d] = vec; /* reserved */
+
+ upcase_vector = insert_generic_trampoline(
+ sizeof(upcase_trampoline), upcase_trampoline);
+ register_callback(upcase_vector, upcase_entry, "upcase");
+
+ /* build fastlookup index into the monster table of interrupts */
+ intfunc_init(int21_table, int21_fastlookup);
+}
diff --git a/usr.bin/doscmd/dos.h b/usr.bin/doscmd/dos.h
new file mode 100644
index 0000000..030438e
--- /dev/null
+++ b/usr.bin/doscmd/dos.h
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI dos.h,v 2.2 1996/04/08 19:32:28 bostic Exp
+ *
+ * $Id: dos.h,v 1.7 1996/09/23 09:59:24 miff Exp $
+ */
+
+/*
+ * DOS Error codes
+ */
+/* MS-DOS version 2 error codes */
+#define FUNC_NUM_IVALID 0x01
+#define FILE_NOT_FOUND 0x02
+#define PATH_NOT_FOUND 0x03
+#define TOO_MANY_OPEN_FILES 0x04
+#define ACCESS_DENIED 0x05
+#define HANDLE_INVALID 0x06
+#define MEM_CB_DEST 0x07
+#define INSUF_MEM 0x08
+#define MEM_BLK_ADDR_IVALID 0x09
+#define ENV_INVALID 0x0a
+#define FORMAT_INVALID 0x0b
+#define ACCESS_CODE_INVALID 0x0c
+#define DATA_INVALID 0x0d
+#define UNKNOWN_UNIT 0x0e
+#define DISK_DRIVE_INVALID 0x0f
+#define ATT_REM_CUR_DIR 0x10
+#define NOT_SAME_DEV 0x11
+#define NO_MORE_FILES 0x12
+/* mappings to critical-error codes */
+#define WRITE_PROT_DISK 0x13
+#define UNKNOWN_UNIT_CERR 0x14
+#define DRIVE_NOT_READY 0x15
+#define UNKNOWN_COMMAND 0x16
+#define DATA_ERROR_CRC 0x17
+#define BAD_REQ_STRUCT_LEN 0x18
+#define SEEK_ERROR 0x19
+#define UNKNOWN_MEDIA_TYPE 0x1a
+#define SECTOR_NOT_FOUND 0x1b
+#define PRINTER_OUT_OF_PAPER 0x1c
+#define WRITE_FAULT 0x1d
+#define READ_FAULT 0x1e
+#define GENERAL_FAILURE 0x1f
+
+/* MS-DOS version 3 and later extended error codes */
+#define SHARING_VIOLATION 0x20
+#define FILE_LOCK_VIOLATION 0x21
+#define DISK_CHANGE_INVALID 0x22
+#define FCB_UNAVAILABLE 0x23
+#define SHARING_BUF_EXCEEDED 0x24
+
+#define NETWORK_NAME_NOT_FOUND 0x35
+
+#define FILE_ALREADY_EXISTS 0x50
+
+#define DUPLICATE_REDIR 0x55
+
+/*
+ * dos attribute byte flags
+ */
+#define REGULAR_FILE 0x00
+#define READ_ONLY_FILE 0x01
+#define HIDDEN_FILE 0x02
+#define SYSTEM_FILE 0x04
+#define VOLUME_LABEL 0x08
+#define DIRECTORY 0x10
+#define ARCHIVE_NEEDED 0x20
+
+/*
+ * Internal structure used for get_space()
+ */
+typedef struct {
+ long bytes_sector;
+ long sectors_cluster;
+ long total_clusters;
+ long avail_clusters;
+} fsstat_t;
+
+/*
+ * Several DOS structures used by the file redirector
+ */
+
+typedef struct {
+ DIR *dp;
+ u_char *searchend;
+ u_char searchdir[1024];
+} search_t;
+
+/*
+ * This is really the format of the DTA. The file redirector will only
+ * use the first 21 bytes.
+ */
+typedef struct {
+ u_char drive __attribute__ ((packed));
+ u_char pattern[11] __attribute__ ((packed));
+ u_char flag __attribute__ ((packed));
+ u_char reserved1[4] __attribute__ ((packed));
+ search_t *searchptr __attribute__ ((packed));
+ u_char attr __attribute__ ((packed));
+ u_short time __attribute__ ((packed));
+ u_short date __attribute__ ((packed));
+ u_long size __attribute__ ((packed));
+ u_char name[13] __attribute__ ((packed));
+}/* __attribute__((__packed__))*/ find_block_t;
+
+/*
+ * DOS directory entry structure
+ */
+typedef struct {
+ u_char name[8] __attribute__ ((packed));
+ u_char ext[3] __attribute__ ((packed));
+ u_char attr __attribute__ ((packed));
+ u_char reserved[10] __attribute__ ((packed));
+ u_short time __attribute__ ((packed));
+ u_short date __attribute__ ((packed));
+ u_short start __attribute__ ((packed));
+ u_long size __attribute__ ((packed));
+} dosdir_t;
+
+/*
+ * The Current Drive Structure
+ */
+typedef struct {
+ u_char path[0x43] __attribute__ ((packed));
+ u_short flag __attribute__ ((packed));
+ u_short dpb_off __attribute__ ((packed));
+ u_short dpb_seg __attribute__ ((packed));
+ u_short redirector_off __attribute__ ((packed));
+ u_short redirector_seg __attribute__ ((packed));
+ u_char paramter_int21[2] __attribute__ ((packed));
+ u_short offset __attribute__ ((packed));
+ u_char dummy __attribute__ ((packed));
+ u_char ifs_driver[4] __attribute__ ((packed));
+ u_char dummy2[2] __attribute__ ((packed));
+}/* __attribute__((__packed__))*/ CDS;
+
+#define CDS_remote 0x8000
+#define CDS_ready 0x4000
+#define CDS_joined 0x2000
+#define CDS_substed 0x1000
+
+#define CDS_notnet 0x0080
+
+/*
+ * The List of Lists (used to get the CDS and a few other numbers)
+ */
+typedef struct {
+ u_char dummy1[0x16] __attribute__ ((packed));
+ u_short cds_offset __attribute__ ((packed));
+ u_short cds_seg __attribute__ ((packed));
+ u_char dummy2[6] __attribute__ ((packed));
+ u_char numberbdev __attribute__ ((packed));
+ u_char lastdrive __attribute__ ((packed));
+} LOL;
+
+/*
+ * The System File Table
+ */
+typedef struct {
+/*00*/ u_short nfiles __attribute__ ((packed)); /* Number file handles referring to this file */
+/*02*/ u_short open_mode __attribute__ ((packed)); /* Open mode (bit 15 -> by FCB) */
+/*04*/ u_char attribute __attribute__ ((packed));
+/*05*/ u_short info __attribute__ ((packed)); /* 15 -> remote, 14 -> dont set date */
+/*07*/ u_char ddr_dpb[4] __attribute__ ((packed)); /* Device Driver Header/Drive Paramter Block */
+/*0b*/ u_short fd __attribute__ ((packed));
+/*0d*/ u_short time __attribute__ ((packed));
+/*0f*/ u_short date __attribute__ ((packed));
+/*11*/ u_long size __attribute__ ((packed));
+/*15*/ u_long offset __attribute__ ((packed));
+/*19*/ u_short rel_cluster __attribute__ ((packed));
+/*1b*/ u_short abs_cluster __attribute__ ((packed));
+/*1d*/ u_char dir_sector[2] __attribute__ ((packed));
+/*1f*/ u_char dir_entry __attribute__ ((packed));
+/*20*/ u_char name[8] __attribute__ ((packed));
+/*28*/ u_char ext[3] __attribute__ ((packed));
+/*2b*/ u_char sharesft[4] __attribute__ ((packed));
+/*2f*/ u_char sharenet[2] __attribute__ ((packed));
+/*31*/ u_short psp __attribute__ ((packed));
+/*33*/ u_char share_off[2] __attribute__ ((packed));
+/*35*/ u_char local_end[2] __attribute__ ((packed));
+/*37*/ u_char ifd_driver[4] __attribute__ ((packed));
+} /*__attribute__((__packed__))*/ SFT;
+
+/*
+ * Format of PCDOS 4.01 swappable data area
+ * (Sorry, but you need a wide screen to make this look nice)
+ */
+typedef struct {
+ u_char err_crit __attribute__ ((packed)); /* 00h BYTE critical error flag */
+ u_char InDOS __attribute__ ((packed)); /* 01h BYTE InDOS flag (count of active INT 21 calls) */
+ u_char err_drive __attribute__ ((packed)); /* 02h BYTE ??? drive number or FFh */
+ u_char err_locus __attribute__ ((packed)); /* 03h BYTE locus of last error */
+ u_short err_code __attribute__ ((packed)); /* 04h WORD extended error code of last error */
+ u_char err_suggest __attribute__ ((packed)); /* 06h BYTE suggested action for last error */
+ u_char err_class __attribute__ ((packed)); /* 07h BYTE class of last error */
+ u_short err_di __attribute__ ((packed));
+ u_short err_es __attribute__ ((packed)); /* 08h DWORD ES:DI pointer for last error */
+ u_short dta_off __attribute__ ((packed));
+ u_short dta_seg __attribute__ ((packed)); /* 0Ch DWORD current DTA */
+ u_short psp __attribute__ ((packed)); /* 10h WORD current PSP */
+ u_short int_23_sp __attribute__ ((packed)); /* 12h WORD stores SP across an INT 23 */
+ u_short wait_status __attribute__ ((packed)); /* 14h WORD return code from last process termination (zerod after reading with AH=4Dh) */
+ u_char current_drive __attribute__ ((packed)); /* 16h BYTE current drive */
+ u_char break_flag __attribute__ ((packed)); /* 17h BYTE extended break flag */
+ u_char unknown1[2] __attribute__ ((packed)); /* 18h 2 BYTEs ??? */
+ u_short int_21_ax __attribute__ ((packed)); /* 1Ah WORD value of AX on call to INT 21 */
+ u_short net_psp __attribute__ ((packed)); /* 1Ch WORD PSP segment for sharing/network */
+ u_short net_number __attribute__ ((packed)); /* 1Eh WORD network machine number for sharing/network (0000h = us) */
+ u_short first_mem __attribute__ ((packed)); /* 20h WORD first usable memory block found when allocating memory */
+ u_short best_mem __attribute__ ((packed)); /* 22h WORD best usable memory block found when allocating memory */
+ u_short last_mem __attribute__ ((packed)); /* 24h WORD last usable memory block found when allocating memory */
+ u_char unknown[10] __attribute__ ((packed)); /* 26h 2 BYTEs ??? (don't seem to be referenced) */
+ u_char monthday __attribute__ ((packed)); /* 30h BYTE day of month */
+ u_char month __attribute__ ((packed)); /* 31h BYTE month */
+ u_short year __attribute__ ((packed)); /* 32h WORD year - 1980 */
+ u_short days __attribute__ ((packed)); /* 34h WORD number of days since 1-1-1980 */
+ u_char weekday __attribute__ ((packed)); /* 36h BYTE day of week (0 = Sunday) */
+ u_char unknown2[3] __attribute__ ((packed)); /* 37h BYTE ??? */
+ u_char ddr_head[30] __attribute__ ((packed)); /* 38h 30 BYTEs device driver request header */
+ u_short ddre_ip __attribute__ ((packed));
+ u_short ddre_cs __attribute__ ((packed)); /* 58h DWORD pointer to device driver entry point (used in calling driver) */
+ u_char ddr_head2[22] __attribute__ ((packed)); /* 5Ch 22 BYTEs device driver request header */
+ u_char ddr_head3[30] __attribute__ ((packed)); /* 72h 30 BYTEs device driver request header */
+ u_char unknown3[6] __attribute__ ((packed)); /* 90h 6 BYTEs ??? */
+ u_char clock_xfer[6] __attribute__ ((packed)); /* 96h 6 BYTEs CLOCK$ transfer record (see AH=52h) */
+ u_char unknown4[2] __attribute__ ((packed)); /* 9Ch 2 BYTEs ??? */
+ u_char filename1[128] __attribute__ ((packed)); /* 9Eh 128 BYTEs buffer for filename */
+ u_char filename2[128] __attribute__ ((packed)); /* 11Eh 128 BYTEs buffer for filename */
+ u_char findfirst[21] __attribute__ ((packed)); /* 19Eh 21 BYTEs findfirst/findnext search data block (see AH=4Eh) */
+ u_char foundentry[32] __attribute__ ((packed)); /* 1B3h 32 BYTEs directory entry for found file */
+ u_char cds[88] __attribute__ ((packed)); /* 1D3h 88 BYTEs copy of current directory structure for drive being accessed */
+ u_char fcbname[11] __attribute__ ((packed)); /* 22Bh 11 BYTEs ??? FCB-format filename */
+ u_char unknown5 __attribute__ ((packed)); /* 236h BYTE ??? */
+ u_char wildcard[11] __attribute__ ((packed)); /* 237h 11 BYTEs wildcard destination specification for rename (FCB format) */
+ u_char unknown6[11] __attribute__ ((packed)); /* 242h 2 BYTEs ??? */
+ u_char attrmask __attribute__ ((packed)); /* 24Dh BYTE attribute mask for directory search??? */
+ u_char open_mode __attribute__ ((packed)); /* 24Eh BYTE open mode */
+ u_char unknown7[3] __attribute__ ((packed)); /* 24fh BYTE ??? */
+ u_char virtual_dos __attribute__ ((packed)); /* 252h BYTE flag indicating how DOS function was invoked (00h = direct INT 20/INT 21, FFh = server call AX=5D00h) */
+ u_char unknown8[9] __attribute__ ((packed)); /* 253h BYTE ??? */
+ u_char term_type __attribute__ ((packed)); /* 25Ch BYTE type of process termination (00h-03h) */
+ u_char unknown9[3] __attribute__ ((packed)); /* 25Dh BYTE ??? */
+ u_short dpb_off __attribute__ ((packed));
+ u_short dpb_seg __attribute__ ((packed)); /* 260h DWORD pointer to Drive Parameter Block for critical error invocation */
+ u_short int21_sf_off __attribute__ ((packed));
+ u_short int21_sf_seg __attribute__ ((packed)); /* 264h DWORD pointer to stack frame containing user registers on INT 21 */
+ u_short store_sp __attribute__ ((packed)); /* 268h WORD stores SP??? */
+ u_short dosdpb_off __attribute__ ((packed));
+ u_short dosdpb_seg __attribute__ ((packed)); /* 26Ah DWORD pointer to DOS Drive Parameter Block for ??? */
+ u_short disk_buf_seg __attribute__ ((packed)); /* 26Eh WORD segment of disk buffer */
+ u_short unknown10[4] __attribute__ ((packed)); /* 270h WORD ??? */
+ u_char media_id __attribute__ ((packed)); /* 278h BYTE Media ID byte returned by AH=1Bh,1Ch */
+ u_char unknown11 __attribute__ ((packed)); /* 279h BYTE ??? (doesn't seem to be referenced) */
+ u_short unknown12[2] __attribute__ ((packed)); /* 27Ah DWORD pointer to ??? */
+ u_short sft_off __attribute__ ((packed));
+ u_short sft_seg __attribute__ ((packed)); /* 27Eh DWORD pointer to current SFT */
+ u_short cds_off __attribute__ ((packed));
+ u_short cds_seg __attribute__ ((packed)); /* 282h DWORD pointer to current directory structure for drive being accessed */
+ u_short fcb_off __attribute__ ((packed));
+ u_short fcb_seg __attribute__ ((packed)); /* 286h DWORD pointer to caller's FCB */
+ u_short unknown13[2] __attribute__ ((packed)); /* 28Ah WORD ??? */
+ u_short jft_off __attribute__ ((packed));
+ u_short jft_seg __attribute__ ((packed)); /* 28Eh DWORD pointer to a JFT entry in process handle table (see AH=26h) */
+ u_short filename1_off __attribute__ ((packed)); /* 292h WORD offset in DOS CS of first filename argument */
+ u_short filename2_off __attribute__ ((packed)); /* 294h WORD offset in DOS CS of second filename argument */
+ u_short unknown14[12] __attribute__ ((packed)); /* 296h WORD ??? */
+ u_short file_offset_lo __attribute__ ((packed));
+ u_short file_offset_hi __attribute__ ((packed)); /* 2AEh DWORD offset in file??? */
+ u_short unknown15 __attribute__ ((packed)); /* 2B2h WORD ??? */
+ u_short partial_bytes __attribute__ ((packed)); /* 2B4h WORD bytes in partial sector */
+ u_short number_sectors __attribute__ ((packed)); /* 2B6h WORD number of sectors */
+ u_short unknown16[3] __attribute__ ((packed)); /* 2B8h WORD ??? */
+ u_short nbytes_lo __attribute__ ((packed));
+ u_short nbytes_hi __attribute__ ((packed)); /* 2BEh DWORD number of bytes appended to file */
+ u_short qpdb_off __attribute__ ((packed));
+ u_short qpdb_seg __attribute__ ((packed)); /* 2C2h DWORD pointer to ??? disk buffer */
+ u_short asft_off __attribute__ ((packed));
+ u_short asft_seg __attribute__ ((packed)); /* 2C6h DWORD pointer to ??? SFT */
+ u_short int21_bx __attribute__ ((packed)); /* 2CAh WORD used by INT 21 dispatcher to store caller's BX */
+ u_short int21_ds __attribute__ ((packed)); /* 2CCh WORD used by INT 21 dispatcher to store caller's DS */
+ u_short temporary __attribute__ ((packed)); /* 2CEh WORD temporary storage while saving/restoring caller's registers */
+ u_short prevcall_off __attribute__ ((packed));
+ u_short prevcall_seg __attribute__ ((packed)); /* 2D0h DWORD pointer to prev call frame (offset 264h) if INT 21 reentered also switched to for duration of INT 24 */
+ u_char unknown17[9] __attribute__ ((packed)); /* 2D4h WORD ??? */
+ u_short ext_action __attribute__ ((packed)); /* 2DDh WORD multipurpose open action */
+ u_short ext_attr __attribute__ ((packed)); /* 2DFh WORD multipurpose attribute */
+ u_short ext_mode __attribute__ ((packed)); /* 2E1h WORD multipurpose mode */
+ u_char unknown17a[9] __attribute__ ((packed));
+ u_short lol_ds __attribute__ ((packed)); /* 2ECh WORD stores DS during call to [List-of-Lists + 37h] */
+ u_char unknown18[5] __attribute__ ((packed)); /* 2EEh WORD ??? */
+ u_char usernameptr[4] __attribute__ ((packed)); /* 2F3h DWORD pointer to user-supplied filename */
+ u_char unknown19[4] __attribute__ ((packed)); /* 2F7h DWORD pointer to ??? */
+ u_char lol_ss[2] __attribute__ ((packed)); /* 2FBh WORD stores SS during call to [List-of-Lists + 37h] */
+ u_char lol_sp[2] __attribute__ ((packed)); /* 2FDh WORD stores SP during call to [List-of-Lists + 37h] */
+ u_char lol_flag __attribute__ ((packed)); /* 2FFh BYTE flag, nonzero if stack switched in calling [List-of-Lists+37h] */
+ u_char searchdata[21] __attribute__ ((packed)); /* 300h 21 BYTEs FindFirst search data for source file(s) of a rename operation (see AH=4Eh) */
+ u_char renameentry[32] __attribute__ ((packed)); /* 315h 32 BYTEs directory entry for file being renamed */
+ u_char errstack[331] __attribute__ ((packed)); /* 335h 331 BYTEs critical error stack */
+ u_char diskstack[384] __attribute__ ((packed)); /* 480h 384 BYTEs disk stack (functions greater than 0Ch, INT 25, INT 26) */
+ u_char iostack[384] __attribute__ ((packed)); /* 600h 384 BYTEs character I/O stack (functions 01h through 0Ch) */
+ u_char int_21_08_flag __attribute__ ((packed)); /* 780h BYTE flag affecting AH=08h (see AH=64h) */
+ u_char unknown20[11] __attribute__ ((packed)); /* 781h BYTE ??? looks like a drive number */
+} /*__attribute__((__packed__))*/ SDA;
+
+struct exehdr {
+ u_short magic;
+ u_short bytes_on_last_page;
+ u_short size; /* 512 byte blocks */
+ u_short nreloc;
+ u_short hdr_size; /* paragraphs */
+ u_short min_memory; /* paragraphs */
+ u_short max_memory; /* pargraphs */
+ u_short init_ss;
+ u_short init_sp;
+ u_short checksum;
+ u_short init_ip;
+ u_short init_cs;
+ u_short reloc_offset;
+ u_short overlay_num;
+};
+
+struct reloc_entry {
+ u_short off;
+ u_short seg;
+};
+
+
+/*
+** DOS-related shrapnel
+*/
+
+static inline int
+from_dos_attr(int attr)
+{
+ return((attr & READ_ONLY_FILE) ? 0444 : 0666);
+}
+
+static inline int
+to_dos_attr(int mode)
+{
+ int attr;
+
+ attr = (mode & 0200) ? 0:READ_ONLY_FILE;
+ attr |= S_ISDIR(mode) ? DIRECTORY:0;
+ return(attr);
+}
+
+/* prototypes */
+
+extern char *dos_return[]; /* names of DOS return codes */
+extern const int dos_ret_size; /* length of above */
+extern char *InDOS;
+extern int diskdrive; /* current drive */
+unsigned long disk_transfer_addr;
+
+extern void encode_dos_file_time (time_t, u_short *, u_short *);
+extern time_t decode_dos_file_time(u_short dosdate, u_short dostime);
+extern int translate_filename(u_char *dname, u_char *uname, int *drivep);
+extern int parse_filename(int flag, char *str, char *fcb, int *nb);
+extern void dos_init(void);
+
+/* from exe.c */
+extern int pspseg; /* segment # of PSP */
+extern int curpsp;
+
+extern void exec_command(regcontext_t *REGS, int run, int fd, char *cmdname, u_short *param);
+extern void load_overlay(int fd, int start_segment, int reloc_segment);
+extern void load_command(regcontext_t *REGS, int run, int fd, char *cmdname,
+ u_short *param, char **argv, char **envs);
+extern void exec_return(regcontext_t *REGS, int code);
+extern int get_env(void);
+
+/* from setver.c */
+extern void setver(char *cmd, short version);
+extern short getver(char *cmd);
diff --git a/usr.bin/doscmd/doscmd.c b/usr.bin/doscmd/doscmd.c
new file mode 100644
index 0000000..282aeab
--- /dev/null
+++ b/usr.bin/doscmd/doscmd.c
@@ -0,0 +1,892 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI doscmd.c,v 2.3 1996/04/08 19:32:30 bostic Exp
+ *
+ * $Id: doscmd.c,v 1.10 1997/03/18 02:36:55 msmith Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <machine/param.h>
+#include <machine/vmparam.h>
+
+#include <sys/proc.h>
+#include <machine/sysarch.h>
+#include <machine/vm86.h>
+
+#include "doscmd.h"
+
+/* exports */
+int capture_fd = -1;
+int dead = 0;
+int xmode = 0;
+int booting = 0;
+int raw_kbd = 0;
+int timer_disable = 0;
+struct timeval boot_time;
+unsigned long *ivec = (unsigned long *)0;
+
+u_long pending[256]; /* pending interrupts */
+int n_pending;
+
+#ifndef USE_VM86
+#define PRB_V86_FORMAT 0x4242
+
+struct vconnect_area vconnect_area = {
+ 0, /* Interrupt state */
+ PRB_V86_FORMAT, /* Magic number */
+ { 0, }, /* Pass through ints */
+ { 0x00000000, 0x00000000 } /* Magic iret location */
+};
+#endif
+
+/* local prototypes */
+static void setup_boot(regcontext_t *REGS);
+static void setup_command(int argc, char *argv[], regcontext_t *REGS);
+static FILE *find_doscmdrc(void);
+static int do_args(int argc, char *argv[]);
+static void usage(void);
+static int open_name(char *name, char *ext);
+static void init_iomap(void);
+
+/* Local option flags &c. */
+static int zflag = 0;
+
+/* DOS environment emulation */
+static int ecnt = 0;
+static char *envs[256];
+
+/* Search path and command name */
+static char *dos_path = 0;
+char cmdname[256]; /* referenced from dos.c */
+
+/* high memory mapfile */
+static char *memfile = "/tmp/doscmd.XXXXXX";
+
+static struct i386_vm86_args vm86;
+static struct vm86_init_args kargs;
+
+/* lobotomise */
+int
+main(int argc, char **argv)
+{
+#ifndef USE_VM86
+ struct sigcontext sc;
+#else
+ struct vm86_struct vm86s;
+#define sc vm86s.substr.regs.vmsc
+#endif
+ regcontext_t *REGS = (regcontext_t *)&sc;
+ int fd;
+ int i;
+ char buffer[4096];
+ int mfd;
+ FILE *fp;
+
+
+ /* XXX should only be for tty mode */
+ fd = open ("/dev/null", O_RDWR);
+ if (fd != 3)
+ dup2 (fd, 3); /* stdaux */
+ if (fd != 4)
+ dup2 (fd, 4); /* stdprt */
+ if (fd != 3 && fd != 4)
+ close (fd);
+ fd = -1;
+
+ debug_set(0); /* debug any D_TRAPS without intnum */
+
+ /* perform option argument processing */
+ optind = do_args(argc, argv);
+ argc -= optind;
+ argv += optind;
+
+ if (vflag && debugf == stderr) {
+ debugf = stdout;
+ setbuf (stdout, NULL);
+ }
+
+ mfd = mkstemp(memfile);
+
+ if (mfd < 0) {
+ fprintf(stderr, "memfile: %s\n", strerror(errno));
+ fprintf(stderr, "High memory will not be mapped\n");
+ } else {
+ caddr_t add;
+
+ unlink(memfile);
+
+ mfd = squirrel_fd(mfd);
+
+ lseek(mfd, 64 * 1024 - 1, 0);
+ write(mfd, "", 1);
+ add = mmap((caddr_t)0x000000, 64 * 1024,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ mfd, 0);
+ add = mmap((caddr_t)0x100000, 64 * 1024,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ mfd, 0);
+ }
+
+ /* This needs to happen before the executable is loaded */
+ mem_init();
+
+#ifdef USE_VM86
+ memset(&vm86s, 0, sizeof(vm86s));
+#endif
+
+ /*
+ * With no other arguments we will assume we must boot DOS
+ */
+ if (argc <= 0)
+ booting = 1;
+
+#if 1
+ /*
+ * Nominate interrupts to handle here when the kernel is
+ * performing interrupt handling.
+ *
+ * I would like to let INT 2F pass through as well, but I
+ * need to get my hands on INT 2F:11 to do file redirection.
+ */
+ for (i = 0; i <= 0xff; ++i) {
+ switch (i) {
+ case 0x2f:
+ case 0xff:
+#if 1
+ kargs.int_map[i >> 3] |= (1 << (i & 7));
+#ifndef USE_VM86
+ vconnect_area.passthru[i >> 5] &= ~(1 << (i & 0x1f));
+#else
+ vm86s.int_byuser[i >> 3] |= (1 << (i & 0x07));
+#endif
+#endif
+ break;
+ default:
+#if 1
+ kargs.int_map[i >> 3] &= ~(1 << (i & 7));
+#ifndef USE_VM86
+ vconnect_area.passthru[i >> 5] |= (1 << (i & 0x1f));
+#else
+ vm86s.int_byuser[i >> 3] |= (1 << (i & 0x07));
+#endif
+#endif
+ break;
+ }
+ }
+#endif
+ for (i = 0; i < 256; i++)
+ pending[i] = 0;
+ n_pending = 0;
+
+ if (booting) { /* are we booting? */
+ setup_boot(REGS);
+ } else { /* no, load a command */
+ setup_command(argc, argv, REGS);
+ }
+
+ /* install signal handlers */
+ setsignal (SIGFPE, sigfpe); /* */
+ setsignal (SIGALRM, sigalrm); /* */
+ setsignal (SIGILL, sigill); /* */
+ setsignal (SIGTRAP, sigtrap); /* */
+ setsignal (SIGUSR2, sigtrace); /* */
+ setsignal (SIGINFO, sigtrace); /* */
+#ifdef USE_VM86
+ setsignal (SIGURG, sigurg); /* entry from NetBSD vm86 */
+#else
+ setsignal (SIGBUS, sigbus); /* entry from FreeBSD, BSD/OS vm86 */
+#endif
+
+ /* Call init functions */
+ if (raw_kbd)
+ console_init();
+ init_io_port_handlers();
+ bios_init();
+ cpu_init();
+ video_init();
+ if (xmode)
+ mouse_init();
+ video_bios_init();
+ disk_bios_init();
+ cmos_init();
+ xms_init();
+ dos_init();
+ net_init();
+ speaker_init();
+ timer_init();
+ /* iomap_init(); */
+
+ gettimeofday(&boot_time, 0);
+
+ if (zflag) for (;;) pause(); /* spin if requested */
+
+ if (raw_kbd) {
+ /*
+ * If we have a raw keyboard, and hence, video,
+ * sneak in a call to the video BIOS to reinit the
+ * the video display.
+ */
+ u_long video_vector;
+ static u_char video_trampoline[] = {
+ 0x60, /* pusha */
+ 0xB8, 0x03, 0x00, /* mov ax,00003h */
+ 0xCD, 0x10, /* int 010h */
+ 0x61, /* popa */
+ 0xCF, /* iret */
+ };
+
+ video_vector = insert_generic_trampoline(
+ sizeof(video_trampoline), video_trampoline);
+
+ N_PUSH(R_FLAGS, REGS);
+ N_PUSH(R_CS, REGS);
+ N_PUSH(R_IP, REGS);
+ N_PUTVEC(R_CS, R_IP, video_vector);
+ }
+
+ sc.sc_mask = 0;
+ sc.sc_onstack = 0;
+
+ if (tmode)
+ tracetrap(REGS);
+
+#ifndef USE_VM86
+ R_EAX = (booting || raw_kbd) ? (int)&vconnect_area : -1;
+ R_EFLAGS |= PSL_VM | PSL_VIF; /* request VM86 mode */
+
+ vm86.sub_op = VM86_INIT;
+ vm86.sub_args = (char *)&kargs;
+ i = sysarch(I386_VM86, &vm86);
+ printf("Init: %d\n", i);
+
+ sigreturn(&sc);
+ debug(D_ALWAYS,"sigreturn failed : %s\n", strerror(errno));
+#else
+ vm86s.cpu_type = VCPU_586;
+ i386_vm86(&vm86s);
+#endif
+
+ /* shouldn't get here */
+ if (vflag) dump_regs((regcontext_t *)&sc);
+ fatal ("vm86 returned (no kernel support?)\n");
+#undef sc
+}
+
+/*
+** setup_boot
+**
+** Setup to boot DOS
+*/
+static void
+setup_boot(regcontext_t *REGS)
+{
+ FILE *fp; /* doscmdrc handle */
+ int fd; /* don't close this! */
+
+ fp = find_doscmdrc(); /* get doscmdrc */
+ if (!fp) {
+ fprintf(stderr, "You must have a doscmdrc to boot\n");
+ quit(1);
+ }
+
+ booting = read_config(fp); /* where to boot from? */
+ fclose(fp);
+ if (booting < 0) { /* not specified */
+ if ((fd = disk_fd(booting = 0)) < 0) /* try A: */
+ fd = disk_fd(booting = 2); /* try C: */
+ } else {
+ fd = disk_fd(booting); /* do like the man says */
+ }
+
+ if (fd < 0) { /* can we boot it? */
+ fprintf(stderr, "Cannot boot from %c: (can't open)\n",
+ booting + 'A');
+ quit(1);
+ }
+
+ /* read bootblock */
+ if (read(fd, (char *)0x7c00, 512) != 512) {
+ fprintf(stderr, "Short read on boot block from %c:\n",
+ booting + 'A');
+ quit(1);
+ }
+
+ /* initialise registers for entry to bootblock */
+ R_EFLAGS = 0x20202;
+ R_CS = 0x0000;
+ R_IP = 0x7c00;
+ R_SS = 0x9800;
+ R_SP = 0x8000 - 2;
+ R_DS = 0x0000;
+ R_ES = 0x0000;
+
+ R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0;
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+ /*
+ ** init a few other context registers
+ */
+ R_FS = 0x0000;
+ R_GS = 0x0000;
+#endif
+}
+
+/*
+** setup_command
+**
+** Setup to run a single command and emulate DOS
+*/
+static void
+setup_command(int argc, char *argv[], regcontext_t *REGS)
+{
+ FILE *fp;
+ u_short param[7] = {0, 0, 0, 0, 0, 0, 0};
+ char *p;
+ char prog[1024];
+ char buffer[PATH_MAX];
+ int i;
+ int fd;
+
+ fp = find_doscmdrc(); /* dig up a doscmdrc */
+ if (fp) {
+ read_config(fp); /* load config for non-boot mode */
+ fclose(fp);
+ }
+
+ if (argc <= 0) /* need some arguments */
+ usage();
+
+ /* look for a working directory XXX ??? */
+ if (dos_getcwd('C' - 'A') == NULL) {
+
+ /* try to get our current directory, use '/' if desperate */
+ p = getcwd(buffer, sizeof(buffer));
+ if (!p || !*p) p = getenv("PWD");
+ if (!p || !*p) p = "/";
+ init_path('C' - 'A', (u_char *)"/", (u_char *)p);
+
+ /* look for PATH= already set, learn from it if possible */
+ for (i = 0; i < ecnt; ++i) {
+ if (!strncmp(envs[i], "PATH=", 5)) {
+ dos_path = envs[i] + 5;
+ break;
+ }
+ }
+ /* no PATH in DOS environment? put current directory there*/
+ if (i >= ecnt) {
+ static char path[256];
+ sprintf(path, "PATH=C:%s",
+ dos_getcwd('C' - 'A'));
+ put_dosenv(path);
+ dos_path = envs[ecnt-1] + 5;
+ }
+ }
+
+ /* add a COMSPEC if required */
+ for (i = 0; i < ecnt; ++i) {
+ if (!strncmp(envs[i], "COMSPEC=", 8))
+ break;
+ }
+ if (i >= ecnt)
+ put_dosenv("COMSPEC=C:\\COMMAND.COM");
+
+ /* look for PATH already set, learn from it if possible */
+ for (i = 0; i < ecnt; ++i) {
+ if (!strncmp(envs[i], "PATH=", 5)) {
+ dos_path = envs[i] + 5;
+ break;
+ }
+ }
+ /* No PATH, default to c:\ */
+ if (i >= ecnt) {
+ dos_path = envs[ecnt-1] + 5;
+ put_dosenv("PATH=C:\\");
+ }
+
+ /* if no PROMPT, default to 'DOS>' */
+ for (i = 0; i < ecnt; ++i) {
+ if (!strncmp(envs[i], "PROMPT=", 7))
+ break;
+ }
+ if (i >= ecnt)
+ put_dosenv("PROMPT=DOS> ");
+
+ /* terminate environment */
+ envs[ecnt] = 0;
+
+ /* XXX ??? */
+ if (dos_getcwd('R' - 'A') == NULL)
+ init_path('R' - 'A', (u_char *)"/", 0);
+
+ /* get program name */
+ strncpy(prog, *argv++, sizeof(prog) -1);
+ prog[sizeof(prog) -1] = '\0';
+
+ /* try to open program */
+ if ((fd = open_prog(prog)) < 0) {
+ fprintf (stderr, "%s: command not found\n", prog);
+ quit(1);
+ }
+
+ /* load program */
+ load_command(REGS, 1, fd, cmdname, param, argv, envs);
+ close(fd);
+}
+
+/*
+** find_doscmdrc
+**
+** Try to find a doscmdrc file
+*/
+static FILE *
+find_doscmdrc(void)
+{
+ FILE *fp;
+ char buffer[4096];
+ int fd;
+
+ if ((fp = fopen(".doscmdrc", "r")) == NULL) {
+ struct passwd *pwd = getpwuid(geteuid());
+ if (pwd) {
+ sprintf(buffer, "%s/.doscmdrc", pwd->pw_dir);
+ fp = fopen(buffer, "r");
+ }
+ if (!fp) {
+ char *home = getenv("HOME");
+ if (home) {
+ sprintf(buffer, "%s/.doscmdrc", home);
+ fp = fopen(buffer, "r");
+ }
+ }
+ if (!fp)
+ fp = fopen("/etc/doscmdrc", "r");
+ }
+ return(fp);
+}
+
+/*
+** do_args
+**
+** commandline argument processing
+*/
+static int
+do_args(int argc, char *argv[])
+{
+ int i,c,p;
+ FILE *fp;
+ char *col;
+
+ while ((c = getopt (argc, argv, "234Oc:TkCIEMPRLAU:S:HDtzvVxXfbri:o:d:")) != -1) {
+ switch (c) {
+ case 'd':
+ if (fp = fopen(optarg, "w")) {
+ debugf = fp;
+ setbuf (fp, NULL);
+ } else
+ perror(optarg);
+ break;
+ case '2':
+ debug_flags |= D_TRAPS2;
+ break;
+ case '3':
+ debug_flags |= D_TRAPS3;
+ break;
+ case '4':
+ debug_flags |= D_DEBUGIN;
+ break;
+ case 'O':
+ debugf = stdout;
+ setbuf (stdout, NULL);
+ break;
+ case 'c':
+ if ((capture_fd = creat(optarg, 0666)) < 0) {
+ perror(optarg);
+ quit(1);
+ }
+ break;
+ case 'i':
+ i = 1;
+ if (col = strchr(optarg, ':')) {
+ *col++ = 0;
+ i = strtol(col, 0, 0);
+ }
+ p = strtol(optarg, 0, 0);
+
+ while (i-- > 0)
+ define_input_port_handler(p++, inb_traceport);
+ break;
+ case 'o':
+ i = 1;
+ if (col = strchr(optarg, ':')) {
+ *col++ = 0;
+ i = strtol(col, 0, 0);
+ }
+ p = strtol(optarg, 0, 0);
+
+ while (i-- > 0)
+ define_output_port_handler(p++, outb_traceport);
+ break;
+
+ case 'r':
+ raw_kbd = 1;
+ break;
+ case 'I':
+ debug_flags |= D_ITRAPS;
+ for (c = 0; c < 256; ++c)
+ debug_set(c);
+ break;
+ case 'k':
+ kargs.debug = 1;
+ break;
+ case 'T':
+ timer_disable = 1;
+ break;
+ case 'E':
+ debug_flags |= D_EXEC;
+ break;
+ case 'C':
+ debug_flags |= D_DOSCALL;
+ break;
+ case 'M':
+ debug_flags |= D_MEMORY;
+ break;
+ case 'P':
+ debug_flags |= D_PORT;
+ break;
+ case 'R':
+ debug_flags |= D_REDIR;
+ break;
+ case 'L':
+ debug_flags |= D_PRINTER;
+ break;
+ case 'A':
+ debug_flags |= D_TRAPS|D_ITRAPS;
+ for (c = 0; c < 256; ++c)
+ debug_set(c);
+ break;
+ case 'U':
+ debug_unset(strtol(optarg, 0, 0));
+ break;
+ case 'S':
+ debug_flags |= D_TRAPS|D_ITRAPS;
+ debug_set(strtol(optarg, 0, 0));
+ break;
+ case 'H':
+ debug_flags |= D_HALF;
+ break;
+ case 'x':
+#ifdef NO_X
+ fatal("X11 support not compiled in.\n");
+#endif
+ xmode = 1;
+ break;
+ case 't':
+ tmode = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
+ case 'D':
+ debug_flags |= D_DISK | D_FILE_OPS;
+ break;
+ case 'v':
+ debug_flags |= D_TRAPS | D_ITRAPS | D_HALF | 0xff;
+ break;
+ case 'V':
+ vflag = 1;
+ break;
+ case 'b':
+ booting = 1;
+ break;
+ default:
+ usage ();
+ }
+ }
+ return(optind);
+}
+
+/*
+** Very helpful 8(
+*/
+void
+usage (void)
+{
+ fprintf (stderr, "usage: doscmd cmd args...\n");
+ quit (1);
+}
+
+/*
+** look up a DOS command name
+**
+** XXX ordering is wrong!
+*/
+static int
+open_name(char *name, char *ext)
+{
+ int fd;
+ char *p = name + strlen(name);
+ char *q;
+
+ *ext = 0;
+
+ q = strrchr(name, '/');
+ if (q)
+ q++;
+ else
+ q = name;
+
+ if (!strchr(q, '.')) {
+ strcpy(ext, ".exe");
+ strcpy(p, ".exe");
+
+ if ((fd = open (name, O_RDONLY)) >= 0)
+ return (fd);
+
+ strcpy(ext, ".com");
+ strcpy(p, ".com");
+
+ if ((fd = open (name, O_RDONLY)) >= 0)
+ return (fd);
+ } else {
+ if ((fd = open (name, O_RDONLY)) >= 0)
+ return (fd);
+ }
+
+ return (-1);
+}
+
+/*
+** look up a DOS command, search the path as well.
+*/
+int
+open_prog(char *name)
+{
+ int fd;
+ char fullname[1024], tmppath[1024];
+ char *p;
+ char *e;
+ char ext[5];
+ int error;
+ int drive;
+ char *path;
+
+ if (strpbrk(name, ":/\\")) {
+ error = translate_filename(name, fullname, &drive);
+ if (error)
+ return (-1);
+
+ fd = open_name(fullname, ext);
+
+ strcpy(cmdname, name);
+ if (*ext)
+ strcat(cmdname, ext);
+ return (fd);
+ }
+
+ path = dos_path;
+
+ while (*path) {
+ p = path;
+ while (*p && *p != ';')
+ ++p;
+
+ memcpy(tmppath, path, p - path);
+ e = tmppath + (p - path);
+ *e++ = '\\';
+ strcpy(e, name);
+
+ path = *p ? p + 1 : p;
+
+ error = translate_filename(tmppath, fullname, &drive);
+ if (error)
+ continue;
+
+ fd = open_name(fullname, ext);
+
+ if (fd >= 0) {
+ strcpy(cmdname, tmppath);
+ if (*ext)
+ strcat(cmdname, ext);
+ return (fd);
+ }
+ }
+
+ return (-1);
+}
+
+/*
+** append a value to the DOS environment
+*/
+void
+put_dosenv(char *value)
+{
+ if (ecnt < sizeof(envs)/sizeof(envs[0])) {
+ if ((envs[ecnt++] = strdup(value)) == NULL) {
+ perror("put_dosenv");
+ quit(1);
+ }
+ } else {
+ fprintf(stderr, "Environment full, ignoring %s\n", value);
+ }
+}
+
+/*
+** replicate a fd up at the top of the range
+*/
+int
+squirrel_fd(int fd)
+{
+ int sfd = sysconf(_SC_OPEN_MAX);
+ struct stat sb;
+
+ do {
+ errno = 0;
+ fstat(--sfd, &sb);
+ } while (sfd > 0 && errno != EBADF);
+
+ if (errno == EBADF && dup2(fd, sfd) >= 0) {
+ close(fd);
+ return(sfd);
+ }
+ return(fd);
+}
+
+/*
+** Exit-time stuff
+*/
+
+/*
+** Going away time
+**
+** XXX belongs somewhere else perhaps
+*/
+void
+done (regcontext_t *REGS, int val)
+{
+ if (curpsp < 2) {
+ if (xmode) {
+ char *m;
+
+ tty_move(24, 0);
+ for (m = "END OF PROGRAM"; *m; ++m)
+ tty_write(*m, 0x8400);
+
+ for (m = "(PRESS <CTRL-ALT> ANY MOUSE BUTTON TO exit)"; *m; ++m)
+ tty_write(*m, 0x0900);
+ tty_move(-1, -1);
+ for (;;)
+ tty_pause();
+ } else {
+ quit(val);
+ }
+ }
+ exec_return(REGS, val);
+}
+
+typedef struct COQ {
+ void (*func)();
+ void *arg;
+ struct COQ *next;
+} COQ;
+
+COQ *coq = 0;
+
+void
+quit(int status)
+{
+ while (coq) {
+ COQ *c = coq;
+ coq = coq->next;
+ c->func(c->arg);
+ }
+ if (!xmode) /* XXX not for bootmode */
+ puts("\n");
+ exit(status);
+}
+
+void
+call_on_quit(void (*func)(void *), void *arg)
+{
+ COQ *c = (COQ *)malloc(sizeof(COQ));
+ if (!c) {
+ perror("call_on_quit");
+ quit(1);
+ }
+ c->func = func;
+ c->arg = arg;
+ c->next = coq;
+ coq = c;
+}
+
+struct i386_ioperm_args {
+ u_short start;
+ u_short length;
+ char disable;
+};
+
+struct sysarch_args {
+ int op;
+ char *parms;
+};
+
+static void
+iomap_init(void)
+{
+ int i;
+ struct i386_ioperm_args args[] = {
+#if 0
+ { 0x200, 0x200, 1 }, /* 0x200 - 0x400 */
+ { 0x1c80, 2, 1 }, /* 0x1c80 - 0x1c81 */
+ { 0x2c80, 2, 1 }, /* 0x2c80 - 0x2c81 */
+ { 0x3c80, 2, 1 }, /* 0x3c80 - 0x3c81 */
+ { 0x3c4, 2, 1 }, /* 0x3c4 - 0x3c5 */
+ { 0x3c5, 2, 1 }, /* 0x3ce - 0x3cf */
+#else
+ { 0x0, 0xffff, 1 }, /* entire i/o space */
+#endif
+ { 0, 0, 0 }
+ };
+
+ for (i = 0; args[i].length; i++)
+ if (sysarch(I386_SET_IOPERM, &(args[i])) < 0)
+ err(1, "sysarch");
+}
diff --git a/usr.bin/doscmd/doscmd.h b/usr.bin/doscmd/doscmd.h
new file mode 100644
index 0000000..43d2b30
--- /dev/null
+++ b/usr.bin/doscmd/doscmd.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI doscmd.h,v 2.3 1996/04/08 19:32:32 bostic Exp
+ *
+ * $Id: doscmd.h,v 1.9 1996/09/23 09:59:25 miff Exp $
+ */
+
+
+#ifdef __NetBSD__
+#define USE_VM86
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <machine/frame.h>
+#include <machine/psl.h>
+#include <machine/npx.h>
+#ifdef USE_VM86
+#include <machine/vm86.h>
+#endif
+
+#include "register.h"
+#include "dos.h"
+#include "callback.h"
+#include "cwd.h"
+
+
+/*
+** assorted hardware/scope constants
+*/
+
+#define MAX_AVAIL_SEG 0xa000
+
+#define MAXPORT 0x400
+
+#define N_PARALS_MAX 3
+#define N_COMS_MAX 4 /* DOS restriction (sigh) */
+
+struct vconnect_area {
+ int int_state;
+ int magic; /* 0x4242 -> PRB format */
+ u_long passthru[256>>5]; /* bitmap of INTs to handle */
+ u_long magiciret[2]; /* Bounds of "magic" IRET */
+};
+extern struct vconnect_area vconnect_area;
+#define IntState vconnect_area.int_state
+
+
+/* debug.c */
+extern int vflag;
+extern int tmode;
+extern FILE *debugf;
+extern int debug_flags;
+
+/* Lower 8 bits are int number */
+#define D_ALWAYS 0x0000100 /* always emit this message */
+#define D_TRAPS 0x0000200 /* trap-related activity */
+#define D_FILE_OPS 0x0000400 /* file-related activity */
+#define D_MEMORY 0x0000800 /* memory-related activity */
+#define D_HALF 0x0001000 /* for "half-implemented" system calls */
+#define D_FLOAT 0x0002000 /* ??? */
+#define D_DISK 0x0004000 /* disk (not file) operations */
+#define D_TRAPS2 0x0008000
+#define D_PORT 0x0010000 /* port accesses */
+#define D_EXEC 0x0020000
+#define D_ITRAPS 0x0040000
+#define D_REDIR 0x0080000 /* redirector functions */
+#define D_PRINTER 0x0100000
+#define D_TRAPS3 0x0200000
+#define D_DEBUGIN 0x0400000
+#define D_DOSCALL 0x0800000 /* MS-DOS function results */
+
+#define TTYF_ECHO 0x00000001
+#define TTYF_ECHONL 0x00000003
+#define TTYF_CTRL 0x00000004
+#define TTYF_BLOCK 0x00000008
+#define TTYF_POLL 0x00000010
+#define TTYF_REDIRECT 0x00010000 /* Cannot have 0xffff bits set */
+
+#define TTYF_ALL (TTYF_ECHO | TTYF_CTRL | TTYF_REDIRECT)
+#define TTYF_BLOCKALL (TTYF_ECHO | TTYF_CTRL | TTYF_REDIRECT | TTYF_BLOCK)
+
+extern void unknown_int2(int, int, regcontext_t *REGS);
+extern void unknown_int3(int, int, int, regcontext_t *REGS);
+extern void unknown_int4(int, int, int, int, regcontext_t *REGS);
+extern void fatal (char *fmt, ...);
+extern void debug (int flags, char *fmt, ...);
+extern void dump_regs(regcontext_t *REGS);
+extern void debug_set(int x);
+extern void debug_unset(int x);
+extern u_long debug_isset(int x);
+
+/* doscmd.c */
+extern int capture_fd;
+extern int dead;
+extern int xmode;
+extern int booting;
+extern int raw_kbd;
+extern int timer_disable;
+extern char cmdname[];
+extern struct timeval boot_time;
+extern unsigned long *ivec;
+
+extern int open_prog(char *name);
+extern void done(regcontext_t *REGS, int val);
+extern void quit(int);
+extern void call_on_quit(void (*)(void *), void *);
+
+/* signal.c */
+extern struct sigframe *saved_sigframe;
+extern regcontext_t *saved_regcontext;
+extern int saved_valid;
+extern void setsignal(int s, void (*h)(struct sigframe *));
+
+/* cmos.c */
+extern time_t delta_clock;
+
+extern void cmos_init(void);
+
+/* config.c */
+extern int read_config(FILE *fp);
+
+/* tty.c */
+extern char *xfont;
+
+/* setver.c */
+extern void setver(char *, short);
+extern short getver(char *);
+
+/* mem.c */
+extern char *dosmem;
+
+extern void mem_init(void);
+extern int mem_alloc(int size, int owner, int *biggestp);
+extern int mem_adjust(int addr, int size, int *availp);
+extern void mem_free_owner(int owner);
+extern void mem_change_owner(int addr, int owner);
+
+
+/* intff.c */
+extern int int2f_11(regcontext_t *REGS);
+extern void intff(regcontext_t *REGS);
+
+/* trap.c */
+extern void fake_int(regcontext_t *REGS, int);
+extern void sigtrap(struct sigframe *sf);
+extern void sigtrace(struct sigframe *sf);
+extern void sigalrm(struct sigframe *sf);
+extern void sigill(struct sigframe *sf);
+extern void sigfpe(struct sigframe *sf);
+extern void breakpoint(struct sigframe *sf);
+#ifdef USE_VM86
+extern void sigurg(struct sigframe *sf);
+#else
+extern void sigbus(struct sigframe *sf);
+#endif
+
+/* int.c */
+extern void softint(int intnum);
+extern void hardint(int intnum);
+
+extern void delay_interrupt(int intnum, void (*func)(int));
+extern void resume_interrupt(void);
+
+
+/* bios.c */
+#define BIOSDATA ((u_char *)0x400)
+extern unsigned long rom_config;
+extern int nfloppies;
+extern int ndisks;
+extern int nserial;
+extern int nparallel;
+
+extern volatile int poll_cnt;
+extern void wakeup_poll(void);
+extern void reset_poll(void);
+extern void sleep_poll(void);
+
+/* int13.c */
+extern int init_hdisk(int drive, int cyl, int head, int tracksize,
+ char *file, char *boot_sector);
+extern int init_floppy(int drive, int type, char *file);
+extern int disk_fd(int drive);
+extern void make_readonly(int drive);
+extern int search_floppy(int i);
+extern void disk_bios_init(void);
+
+/* int17.c */
+extern void lpt_poll(void);
+extern void printer_direct(int printer);
+extern void printer_spool(int printer, char *print_queue);
+extern void printer_timeout(int printer, char *time_out);
+
+/* xms.c */
+extern int int2f_43(regcontext_t *REGS);
+
+/****************************** dirty below here ******************************/
+
+extern u_long pending[]; /* pending interrupts */
+extern int n_pending;
+
+u_char *VREG;
+
+extern int nmice;
+
+extern int redirect0;
+extern int redirect1;
+extern int redirect2;
+extern int kbd_fd;
+extern int jmp_okay;
+
+
+
+void put_dosenv(char *value);
+
+
+/* TTY subsystem XXX rewrite! */
+int tty_eread(REGISTERS, int, int);
+void tty_write(int, int);
+void tty_rwrite(int, int, int);
+void tty_move(int, int);
+void tty_report(int *, int *);
+void tty_flush();
+void tty_index();
+void tty_pause();
+int tty_peek(REGISTERS, int);
+int tty_state();
+void tty_scroll(int, int, int, int, int, int);
+void tty_rscroll(int, int, int, int, int, int);
+int tty_char(int, int);
+void video_setborder(int);
+
+void outb_traceport(int, unsigned char);
+unsigned char inb_traceport(int);
+
diff --git a/usr.bin/doscmd/doscmd_loader.c b/usr.bin/doscmd/doscmd_loader.c
new file mode 100644
index 0000000..7032bfb
--- /dev/null
+++ b/usr.bin/doscmd/doscmd_loader.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI doscmd_loader.c,v 2.3 1996/04/08 19:32:33 bostic Exp
+ *
+ * $Id: doscmd_loader.c,v 1.2 1996/09/22 05:52:59 miff Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <a.out.h>
+
+/*
+ * reserve space in "low" memory for the interrupt vector table
+ */
+static const char filler[4096] = { 0, };
+
+#define _PATH_DOS_KERNEL_DIR "/usr/libexec/"
+#define _PATH_DOS_KERNEL "doscmd.kernel"
+
+int
+load_kernel(void)
+{
+ FILE *fp;
+ struct exec exec;
+ int start_address;
+
+ if ((fp = fopen(_PATH_DOS_KERNEL, "r")) == NULL &&
+ (fp = fopen("obj/" _PATH_DOS_KERNEL, "r")) == NULL &&
+ (fp = fopen(_PATH_DOS_KERNEL_DIR _PATH_DOS_KERNEL, "r")) == NULL &&
+ (fp = fopen(getenv("DOS_KERNEL"), "r")) == NULL)
+ err(1, "load_kernel");
+
+ if (fread(&exec, sizeof(exec), 1, fp) != 1 || N_GETMAGIC(exec) != OMAGIC)
+ errx(1, "bad kernel file format");
+
+ start_address = exec.a_entry & (~(getpagesize() - 1));
+ if (brk(start_address + exec.a_text + exec.a_data + exec.a_bss) < 0)
+ err(1, "load_kernel");
+ fread((char *)start_address, exec.a_text + exec.a_data, 1, fp);
+ bzero((char *)(start_address + exec.a_text + exec.a_data), exec.a_bss);
+ fclose(fp);
+ return(exec.a_entry);
+}
+
+void
+main(int argc, char **argv, char **environ)
+{
+ void (*entry_point)();
+#ifndef __FreeBSD__
+ int fd = open("/dev/mem", 0);
+#endif
+ setgid(getgid());
+ setuid(getuid());
+
+#ifndef __FreeBSD__
+ if (fd < 0)
+ err(1, "/dev/mem");
+#endif
+
+ entry_point = (void (*)()) load_kernel();
+
+#ifndef __FreeBSD__
+ if (read(fd, 0, 0x500 != 0x500))
+ err(1, "/dev/mem");
+
+ close(fd);
+#endif
+
+ (*entry_point)(argc, argv, environ);
+ errx(1, "return from doscmd kernel???");
+}
diff --git a/usr.bin/doscmd/exe.c b/usr.bin/doscmd/exe.c
new file mode 100644
index 0000000..0314a62
--- /dev/null
+++ b/usr.bin/doscmd/exe.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI exe.c,v 2.2 1996/04/08 19:32:34 bostic Exp
+ * $Id: exe.c,v 1.3 1996/09/22 06:26:01 miff Exp $
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "doscmd.h"
+
+/* exports */
+int pspseg;
+int curpsp = 0;
+
+/* locals */
+static int psp_s[10] = { 0 };
+static int env_s[10];
+static regcontext_t frames[10];
+static char *env_block;
+
+static int
+make_environment (char *cmdname, char **env)
+{
+ int i;
+ int total;
+ int len;
+ int envseg;
+ char *p;
+ char *env_block;
+
+ total = 0;
+ for (i = 0; env[i]; i++) {
+ debug (D_EXEC,"env: %s\n", env[i]);
+ len = strlen (env[i]);
+ if (total + len >= 32 * 1024)
+ break;
+ total += len + 1;
+ }
+
+ total++; /* terminating null */
+ total += 2; /* word count */
+ total += strlen (cmdname) + 1;
+ total += 4; /* some more zeros, just in case */
+
+ if ((envseg = mem_alloc(total/16 + 1, 1, NULL)) == 0)
+ fatal("out of memory for env\n");
+
+ env_block = (char *)MAKEPTR(envseg, 0);
+ memset (env_block, 0, total);
+
+ p = env_block;
+ total = 0;
+ for (i = 0; env[i]; i++) {
+ len = strlen (env[i]);
+ if (total + len >= 32 * 1024)
+ break;
+ total += len + 1;
+ strcpy (p, env[i]);
+ p += strlen (p) + 1;
+ }
+ *p++ = 0;
+ *(short *)p = strlen(cmdname);
+ p += 2;
+ strcpy (p, cmdname);
+ while(*p) {
+ if (*p == '/')
+ *p = '\\';
+ else if (islower(*p))
+ *p = toupper(*p);
+ p++;
+ }
+ *p = '\0';
+ return(envseg);
+}
+
+static void
+load_com(int fd, int start_segment)
+{
+ char *start_addr;
+ int i;
+
+ start_addr = (char *)MAKEPTR(start_segment, 0);
+
+ lseek (fd, 0, 0);
+ i = read (fd, start_addr, 0xff00);
+
+ debug(D_EXEC, "Read %05x into %04x\n",
+ i, start_segment);
+}
+
+static void
+load_exe(int fd, int start_segment, int reloc_segment, struct exehdr *hdr, int text_size)
+{
+ char *start_addr;
+ int reloc_size;
+ struct reloc_entry *reloc_tbl, *rp;
+ u_short *segp;
+ int i;
+
+ start_addr = (char *)MAKEPTR(start_segment, 0);
+
+ lseek (fd, hdr->hdr_size * 16, 0);
+ if (read (fd, start_addr, text_size) != text_size)
+ fatal ("error reading program text\n");
+ debug(D_EXEC, "Read %05x into %04x\n",
+ text_size, start_segment);
+
+ if (hdr->nreloc) {
+ reloc_size = hdr->nreloc * sizeof (struct reloc_entry);
+
+ if ((reloc_tbl = (struct reloc_entry *)malloc (reloc_size)) == NULL)
+ fatal ("out of memory for program\n");
+
+ lseek (fd, hdr->reloc_offset, 0);
+ if (read (fd, reloc_tbl, reloc_size) != reloc_size)
+ fatal ("error reading reloc table\n");
+
+ for (i = 0, rp = reloc_tbl; i < hdr->nreloc; i++, rp++) {
+ segp = (u_short *)MAKEPTR(start_segment + rp->seg, rp->off);
+ *segp += start_segment;
+ }
+ free((char *)reloc_tbl);
+ }
+}
+
+void
+load_command(regcontext_t *REGS, int run, int fd, char *cmdname,
+ u_short *param, char **argv, char **envs)
+{
+ struct exehdr hdr;
+ int min_memory, max_memory;
+ int biggest;
+ int envseg;
+ char *psp;
+ int text_size;
+ int i;
+ int start_segment;
+ int exe_file;
+ char *p;
+ int used, n;
+ char *fcb;
+ int newpsp;
+ u_short init_cs, init_ip, init_ss, init_sp, init_ds, init_es;
+
+ if (envs)
+ envseg = make_environment(cmdname, envs);
+ else
+ envseg = env_s[curpsp];
+
+ /* read exe header */
+ if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
+ fatal ("can't read header\n");
+
+ /* proper header ? */
+ if (hdr.magic == 0x5a4d) {
+ exe_file = 1;
+ text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
+ - hdr.hdr_size * 16;
+ min_memory = hdr.min_memory + (text_size + 15)/16;
+ max_memory = hdr.max_memory + (text_size + 15)/16;
+ } else {
+ exe_file = 0;
+ min_memory = 64 * (1024/16);
+ max_memory = 0xffff;
+ }
+
+ /* alloc mem block */
+ pspseg = mem_alloc(max_memory, 1, &biggest);
+ if (pspseg == 0) {
+ if (biggest < min_memory ||
+ (pspseg = mem_alloc(biggest, 1, NULL)) == 0)
+ fatal("not enough memory: needed %d have %d\n",
+ min_memory, biggest);
+
+ max_memory = biggest;
+ }
+
+ mem_change_owner(pspseg, pspseg);
+ mem_change_owner(envseg, pspseg);
+
+ /* create psp */
+ newpsp = curpsp + 1;
+ psp_s[newpsp] = pspseg;
+ env_s[newpsp] = envseg;
+
+ psp = (char *)MAKEPTR(pspseg, 0);
+ memset(psp, 0, 256);
+
+ psp[0] = 0xcd;
+ psp[1] = 0x20;
+
+ *(u_short *)&psp[2] = pspseg + max_memory;
+
+ /*
+ * this is supposed to be a long call to dos ... try to fake it
+ */
+ psp[5] = 0xcd;
+ psp[6] = 0x99;
+ psp[7] = 0xc3;
+
+ *(u_short *)&psp[0x16] = psp_s[curpsp];
+ psp[0x18] = 1;
+ psp[0x19] = 1;
+ psp[0x1a] = 1;
+ psp[0x1b] = 0;
+ psp[0x1c] = 2;
+ memset(psp + 0x1d, 0xff, 15);
+
+ *(u_short *)&psp[0x2c] = envseg;
+
+ *(u_short *)&psp[0x32] = 20;
+ *(u_long *)&psp[0x34] = MAKEVEC(pspseg, 0x18);
+ *(u_long *)&psp[0x38] = 0xffffffff;
+
+ psp[0x50] = 0xcd;
+ psp[0x51] = 0x98;
+ psp[0x52] = 0xc3;
+
+ p = psp + 0x81;
+ *p = 0;
+ used = 0;
+ for (i = 0; argv[i]; i++) {
+ n = strlen(argv[i]);
+ if (used + 1 + n > 0x7d)
+ break;
+ *p++ = ' ';
+ memcpy(p, argv[i], n);
+ p += n;
+ used += n;
+ }
+
+ psp[0x80] = strlen(psp + 0x81);
+ psp[0x81 + psp[0x80]] = 0x0d;
+ psp[0x82 + psp[0x80]] = 0;
+
+ p = psp + 0x81;
+ parse_filename(0x00, p, psp + 0x5c, &n);
+ p += n;
+ parse_filename(0x00, p, psp + 0x6c, &n);
+
+ if (param[4]) {
+ fcb = (char *)MAKEPTR(param[4], param[3]);
+ memcpy(psp + 0x5c, fcb, 16);
+ }
+ if (param[6]) {
+ fcb = (char *)MAKEPTR(param[6], param[5]);
+ memcpy(psp + 0x6c, fcb, 16);
+ }
+
+#if 0
+ printf("005c:");
+ for (n = 0; n < 16; n++)
+ printf(" %02x", psp[0x5c + n]);
+ printf("\n");
+ printf("006c:");
+ for (n = 0; n < 16; n++)
+ printf(" %02x", psp[0x6c + n]);
+ printf("\n");
+#endif
+
+ disk_transfer_addr = MAKEVEC(pspseg, 0x80);
+
+ start_segment = pspseg + 0x10;
+
+ if (!exe_file) {
+ load_com(fd, start_segment);
+
+ init_cs = pspseg;
+ init_ip = 0x100;
+ init_ss = init_cs;
+ init_sp = 0xfffe;
+ init_ds = init_cs;
+ init_es = init_cs;
+ } else {
+ load_exe(fd, start_segment, start_segment, &hdr, text_size);
+
+ init_cs = hdr.init_cs + start_segment;
+ init_ip = hdr.init_ip;
+ init_ss = hdr.init_ss + start_segment;
+ init_sp = hdr.init_sp;
+ init_ds = pspseg;
+ init_es = init_ds;
+ }
+
+ debug(D_EXEC, "cs:ip = %04x:%04x, ss:sp = %04x:%04x, "
+ "ds = %04x, es = %04x\n",
+ init_cs, init_ip, init_ss, init_sp, init_ds, init_es);
+
+ if (run) {
+ frames[newpsp] = *REGS;
+ curpsp = newpsp;
+
+ R_EFLAGS = 0x20202;
+ R_CS = init_cs;
+ R_IP = init_ip;
+ R_SS = init_ss;
+ R_SP = init_sp;
+ R_DS = init_ds;
+ R_ES = init_es;
+
+ R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0;
+
+ } else {
+ param[7] = init_sp;
+ param[8] = init_ss;
+ param[9] = init_ip;
+ param[10] = init_cs;
+ }
+}
+
+void
+load_overlay(int fd, int start_segment, int reloc_segment)
+{
+ struct exehdr hdr;
+ int text_size;
+ int exe_file;
+
+ /* read exe header */
+ if (read (fd, &hdr, sizeof hdr) != sizeof hdr)
+ fatal ("can't read header\n");
+
+ /* proper header ? */
+ if (hdr.magic == 0x5a4d) {
+ exe_file = 1;
+ text_size = (hdr.size - 1) * 512 + hdr.bytes_on_last_page
+ - hdr.hdr_size * 16;
+ } else {
+ exe_file = 0;
+ }
+
+ if (!exe_file)
+ load_com(fd, start_segment);
+ else
+ load_exe(fd, start_segment, reloc_segment, &hdr, text_size);
+}
+
+static int
+get_psp(void)
+{
+ return(psp_s[curpsp]);
+}
+
+int
+get_env(void)
+{
+ return(env_s[curpsp]);
+}
+
+void
+exec_command(regcontext_t *REGS, int run,
+ int fd, char *cmdname, u_short *param)
+{
+ char *arg;
+ char *env;
+ char *argv[2];
+ char *envs[100];
+
+ env = (char *)MAKEPTR(param[0], 0);
+ arg = (char *)MAKEPTR(param[2], param[1]);
+
+ if (arg) {
+ int nbytes = *arg++;
+ arg[nbytes] = 0;
+ if (!*arg)
+ arg = NULL;
+ }
+ argv[0] = arg;
+ argv[1] = NULL;
+
+ debug (D_EXEC, "exec_command: cmdname = %s\n"
+ "env = 0x0%x, arg = %04x:%04x(%s)\n",
+ cmdname, param[0], param[2], param[1], arg);
+
+ if (env) {
+ int i;
+ for ( i=0; i < 99 && *env; ++i ) {
+ envs[i] = env;
+ env += strlen(env)+1;
+ }
+ envs[i] = NULL;
+ load_command(REGS, run, fd, cmdname, param, argv, envs);
+ } else
+ load_command(REGS, run, fd, cmdname, param, argv, NULL);
+}
+
+void
+exec_return(regcontext_t *REGS, int code)
+{
+ debug(D_EXEC, "Returning from exec\n");
+ mem_free_owner(psp_s[curpsp]);
+ *REGS = frames[curpsp--];
+ R_AX = code;
+ R_FLAGS &= ~PSL_C; /* It must have worked */
+}
diff --git a/usr.bin/doscmd/font.h b/usr.bin/doscmd/font.h
new file mode 100644
index 0000000..dc1478a
--- /dev/null
+++ b/usr.bin/doscmd/font.h
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI font.h,v 2.2 1996/04/08 19:32:35 bostic Exp
+ */
+
+unsigned char ascii_font[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81,
+ 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe,
+ 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7,
+ 0xe7, 0x99, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66,
+ 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66,
+ 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63,
+ 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
+ 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06,
+ 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18,
+ 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b,
+ 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38,
+ 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18,
+ 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe,
+ 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c,
+ 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c,
+ 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc,
+ 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30,
+ 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+ 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c,
+ 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0xc6, 0xc6, 0xce, 0xd6, 0xd6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06,
+ 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c,
+ 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x0e, 0x06, 0x06,
+ 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x60, 0xc0,
+ 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60,
+ 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c,
+ 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
+ 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc,
+ 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+ 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78,
+ 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde,
+ 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x78, 0x6c, 0x66,
+ 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe,
+ 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c,
+ 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c,
+ 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
+ 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c,
+ 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x6c, 0x38, 0x38, 0x6c, 0x6c, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
+ 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x30, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc,
+ 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 0x60,
+ 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0xdc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c,
+ 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0,
+ 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c,
+ 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66,
+ 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
+ 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c,
+ 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xdc, 0x76, 0x62, 0x60, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
+ 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6,
+ 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2,
+ 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc,
+ 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0,
+ 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00,
+ 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc,
+ 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78,
+ 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60,
+ 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xfe,
+ 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
+ 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
+ 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x10, 0x38,
+ 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66,
+ 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
+ 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+ 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x38,
+ 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60,
+ 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e,
+ 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30,
+ 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60,
+ 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
+ 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+ 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30,
+ 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06,
+ 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
+ 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x93, 0x06, 0x0c, 0x1f,
+ 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66,
+ 0xce, 0x9a, 0x3f, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+ 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11,
+ 0x44, 0x11, 0x44, 0x11, 0x44, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0xdd,
+ 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6,
+ 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30,
+ 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18,
+ 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc6, 0xfc,
+ 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xfe, 0x6c, 0x6c, 0x6c,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+ 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8,
+ 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c,
+ 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6,
+ 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb,
+ 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x06, 0x7e, 0xcf, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60,
+ 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00,
+ 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
+ 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
+ 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c,
+ 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x6c, 0x6c,
+ 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x98, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c,
+ 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/usr.bin/doscmd/i386-pinsn.c b/usr.bin/doscmd/i386-pinsn.c
new file mode 100644
index 0000000..53e9e6c
--- /dev/null
+++ b/usr.bin/doscmd/i386-pinsn.c
@@ -0,0 +1,1814 @@
+#ifdef DISASSEMBLER
+
+/* Print i386 instructions for GDB, the GNU debugger.
+ Copyright (C) 1988, 1989 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+GDB is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GDB is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GDB; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu)
+ * July 1988
+ */
+
+/*
+ * The main tables describing the instructions is essentially a copy
+ * of the "Opcode Map" chapter (Appendix A) of the Intel 80386
+ * Programmers Manual. Usually, there is a capital letter, followed
+ * by a small letter. The capital letter tell the addressing mode,
+ * and the small letter tells about the operand size. Refer to
+ * the Intel manual for details.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#define Eb OP_E, b_mode
+#define indirEb OP_indirE, b_mode
+#define Gb OP_G, b_mode
+#define Ev OP_E, v_mode
+#define indirEv OP_indirE, v_mode
+#define Ew OP_E, w_mode
+#define Ma OP_E, v_mode
+#define M OP_E, 0
+#define Mp OP_E, 0 /* ? */
+#define Gv OP_G, v_mode
+#define Gw OP_G, w_mode
+#define Rw OP_rm, w_mode
+#define Rd OP_rm, d_mode
+#define Ib OP_I, b_mode
+#define sIb OP_sI, b_mode /* sign extened byte */
+#define Iv OP_I, v_mode
+#define Iw OP_I, w_mode
+#define Jb OP_J, b_mode
+#define Jv OP_J, v_mode
+#define ONE OP_ONE, 0
+#define Cd OP_C, d_mode
+#define Dd OP_D, d_mode
+#define Td OP_T, d_mode
+
+#define eAX OP_REG, eAX_reg
+#define eBX OP_REG, eBX_reg
+#define eCX OP_REG, eCX_reg
+#define eDX OP_REG, eDX_reg
+#define eSP OP_REG, eSP_reg
+#define eBP OP_REG, eBP_reg
+#define eSI OP_REG, eSI_reg
+#define eDI OP_REG, eDI_reg
+#define AL OP_REG, al_reg
+#define CL OP_REG, cl_reg
+#define DL OP_REG, dl_reg
+#define BL OP_REG, bl_reg
+#define AH OP_REG, ah_reg
+#define CH OP_REG, ch_reg
+#define DH OP_REG, dh_reg
+#define BH OP_REG, bh_reg
+#define AX OP_REG, ax_reg
+#define DX OP_REG, dx_reg
+#define indirDX OP_REG, indir_dx_reg
+
+#define Sw OP_SEG, w_mode
+#define Ap OP_DIR, lptr
+#define Av OP_DIR, v_mode
+#define Ob OP_OFF, b_mode
+#define Ov OP_OFF, v_mode
+#define Xb OP_DSSI, b_mode
+#define Xv OP_DSSI, v_mode
+#define Yb OP_ESDI, b_mode
+#define Yv OP_ESDI, v_mode
+
+#define es OP_REG, es_reg
+#define ss OP_REG, ss_reg
+#define cs OP_REG, cs_reg
+#define ds OP_REG, ds_reg
+#define fs OP_REG, fs_reg
+#define gs OP_REG, gs_reg
+
+int OP_E(), OP_indirE(), OP_G(), OP_I(), OP_sI(), OP_REG();
+int OP_J(), OP_SEG();
+int OP_DIR(), OP_OFF(), OP_DSSI(), OP_ESDI(), OP_ONE(), OP_C();
+int OP_D(), OP_T(), OP_rm();
+
+
+#define b_mode 1
+#define v_mode 2
+#define w_mode 3
+#define d_mode 4
+
+#define es_reg 100
+#define cs_reg 101
+#define ss_reg 102
+#define ds_reg 103
+#define fs_reg 104
+#define gs_reg 105
+#define eAX_reg 107
+#define eCX_reg 108
+#define eDX_reg 109
+#define eBX_reg 110
+#define eSP_reg 111
+#define eBP_reg 112
+#define eSI_reg 113
+#define eDI_reg 114
+
+#define lptr 115
+
+#define al_reg 116
+#define cl_reg 117
+#define dl_reg 118
+#define bl_reg 119
+#define ah_reg 120
+#define ch_reg 121
+#define dh_reg 122
+#define bh_reg 123
+
+#define ax_reg 124
+#define cx_reg 125
+#define dx_reg 126
+#define bx_reg 127
+#define sp_reg 128
+#define bp_reg 129
+#define si_reg 130
+#define di_reg 131
+
+#define indir_dx_reg 150
+
+#define GRP1b NULL, NULL, 0
+#define GRP1S NULL, NULL, 1
+#define GRP1Ss NULL, NULL, 2
+#define GRP2b NULL, NULL, 3
+#define GRP2S NULL, NULL, 4
+#define GRP2b_one NULL, NULL, 5
+#define GRP2S_one NULL, NULL, 6
+#define GRP2b_cl NULL, NULL, 7
+#define GRP2S_cl NULL, NULL, 8
+#define GRP3b NULL, NULL, 9
+#define GRP3S NULL, NULL, 10
+#define GRP4 NULL, NULL, 11
+#define GRP5 NULL, NULL, 12
+#define GRP6 NULL, NULL, 13
+#define GRP7 NULL, NULL, 14
+#define GRP8 NULL, NULL, 15
+
+#define FLOATCODE 50
+#define FLOAT NULL, NULL, FLOATCODE
+
+struct dis386 {
+ char *name;
+ int (*op1)();
+ int bytemode1;
+ int (*op2)();
+ int bytemode2;
+ int (*op3)();
+ int bytemode3;
+};
+
+struct dis386 dis386[] = {
+ /* 00 */
+ { "addb", Eb, Gb },
+ { "addS", Ev, Gv },
+ { "addb", Gb, Eb },
+ { "addS", Gv, Ev },
+ { "addb", AL, Ib },
+ { "addS", eAX, Iv },
+ { "pushl", es },
+ { "popl", es },
+ /* 08 */
+ { "orb", Eb, Gb },
+ { "orS", Ev, Gv },
+ { "orb", Gb, Eb },
+ { "orS", Gv, Ev },
+ { "orb", AL, Ib },
+ { "orS", eAX, Iv },
+ { "pushl", cs },
+ { "(bad)" }, /* 0x0f extended opcode escape */
+ /* 10 */
+ { "adcb", Eb, Gb },
+ { "adcS", Ev, Gv },
+ { "adcb", Gb, Eb },
+ { "adcS", Gv, Ev },
+ { "adcb", AL, Ib },
+ { "adcS", eAX, Iv },
+ { "pushl", ss },
+ { "popl", ss },
+ /* 18 */
+ { "sbbb", Eb, Gb },
+ { "sbbS", Ev, Gv },
+ { "sbbb", Gb, Eb },
+ { "sbbS", Gv, Ev },
+ { "sbbb", AL, Ib },
+ { "sbbS", eAX, Iv },
+ { "pushl", ds },
+ { "popl", ds },
+ /* 20 */
+ { "andb", Eb, Gb },
+ { "andS", Ev, Gv },
+ { "andb", Gb, Eb },
+ { "andS", Gv, Ev },
+ { "andb", AL, Ib },
+ { "andS", eAX, Iv },
+ { "(bad)" }, /* SEG ES prefix */
+ { "daa" },
+ /* 28 */
+ { "subb", Eb, Gb },
+ { "subS", Ev, Gv },
+ { "subb", Gb, Eb },
+ { "subS", Gv, Ev },
+ { "subb", AL, Ib },
+ { "subS", eAX, Iv },
+ { "(bad)" }, /* SEG CS prefix */
+ { "das" },
+ /* 30 */
+ { "xorb", Eb, Gb },
+ { "xorS", Ev, Gv },
+ { "xorb", Gb, Eb },
+ { "xorS", Gv, Ev },
+ { "xorb", AL, Ib },
+ { "xorS", eAX, Iv },
+ { "(bad)" }, /* SEG SS prefix */
+ { "aaa" },
+ /* 38 */
+ { "cmpb", Eb, Gb },
+ { "cmpS", Ev, Gv },
+ { "cmpb", Gb, Eb },
+ { "cmpS", Gv, Ev },
+ { "cmpb", AL, Ib },
+ { "cmpS", eAX, Iv },
+ { "(bad)" }, /* SEG DS prefix */
+ { "aas" },
+ /* 40 */
+ { "incS", eAX },
+ { "incS", eCX },
+ { "incS", eDX },
+ { "incS", eBX },
+ { "incS", eSP },
+ { "incS", eBP },
+ { "incS", eSI },
+ { "incS", eDI },
+ /* 48 */
+ { "decS", eAX },
+ { "decS", eCX },
+ { "decS", eDX },
+ { "decS", eBX },
+ { "decS", eSP },
+ { "decS", eBP },
+ { "decS", eSI },
+ { "decS", eDI },
+ /* 50 */
+ { "pushS", eAX },
+ { "pushS", eCX },
+ { "pushS", eDX },
+ { "pushS", eBX },
+ { "pushS", eSP },
+ { "pushS", eBP },
+ { "pushS", eSI },
+ { "pushS", eDI },
+ /* 58 */
+ { "popS", eAX },
+ { "popS", eCX },
+ { "popS", eDX },
+ { "popS", eBX },
+ { "popS", eSP },
+ { "popS", eBP },
+ { "popS", eSI },
+ { "popS", eDI },
+ /* 60 */
+ { "pusha" },
+ { "popa" },
+ { "boundS", Gv, Ma },
+ { "arpl", Ew, Gw },
+ { "(bad)" }, /* seg fs */
+ { "(bad)" }, /* seg gs */
+ { "(bad)" }, /* op size prefix */
+ { "(bad)" }, /* adr size prefix */
+ /* 68 */
+ { "pushS", Iv }, /* 386 book wrong */
+ { "imulS", Gv, Ev, Iv },
+ { "pushl", sIb }, /* push of byte really pushes 4 bytes */
+ { "imulS", Gv, Ev, Ib },
+ { "insb", Yb, indirDX },
+ { "insS", Yv, indirDX },
+ { "outsb", indirDX, Xb },
+ { "outsS", indirDX, Xv },
+ /* 70 */
+ { "jo", Jb },
+ { "jno", Jb },
+ { "jb", Jb },
+ { "jae", Jb },
+ { "je", Jb },
+ { "jne", Jb },
+ { "jbe", Jb },
+ { "ja", Jb },
+ /* 78 */
+ { "js", Jb },
+ { "jns", Jb },
+ { "jp", Jb },
+ { "jnp", Jb },
+ { "jl", Jb },
+ { "jnl", Jb },
+ { "jle", Jb },
+ { "jg", Jb },
+ /* 80 */
+ { GRP1b },
+ { GRP1S },
+ { "(bad)" },
+ { GRP1Ss },
+ { "testb", Eb, Gb },
+ { "testS", Ev, Gv },
+ { "xchgb", Eb, Gb },
+ { "xchgS", Ev, Gv },
+ /* 88 */
+ { "movb", Eb, Gb },
+ { "movS", Ev, Gv },
+ { "movb", Gb, Eb },
+ { "movS", Gv, Ev },
+ { "movw", Ew, Sw },
+ { "leaS", Gv, M },
+ { "movw", Sw, Ew },
+ { "popS", Ev },
+ /* 90 */
+ { "nop" },
+ { "xchgS", eCX, eAX },
+ { "xchgS", eDX, eAX },
+ { "xchgS", eBX, eAX },
+ { "xchgS", eSP, eAX },
+ { "xchgS", eBP, eAX },
+ { "xchgS", eSI, eAX },
+ { "xchgS", eDI, eAX },
+ /* 98 */
+ { "cwtl" },
+ { "cltd" },
+ { "lcall", Ap },
+ { "(bad)" }, /* fwait */
+ { "pushf" },
+ { "popf" },
+ { "sahf" },
+ { "lahf" },
+ /* a0 */
+ { "movb", AL, Ob },
+ { "movS", eAX, Ov },
+ { "movb", Ob, AL },
+ { "movS", Ov, eAX },
+ { "movsb", Yb, Xb },
+ { "movsS", Yv, Xv },
+ { "cmpsb", Xb, Yb },
+ { "cmpsS", Xv, Yv },
+ /* a8 */
+ { "testb", AL, Ib },
+ { "testS", eAX, Iv },
+ { "stosb", Yb, AL },
+ { "stosS", Yv, eAX },
+ { "lodsb", AL, Xb },
+ { "lodsS", eAX, Xv },
+ { "scasb", AL, Yb },
+ { "scasS", eAX, Yv },
+ /* b0 */
+ { "movb", AL, Ib },
+ { "movb", CL, Ib },
+ { "movb", DL, Ib },
+ { "movb", BL, Ib },
+ { "movb", AH, Ib },
+ { "movb", CH, Ib },
+ { "movb", DH, Ib },
+ { "movb", BH, Ib },
+ /* b8 */
+ { "movS", eAX, Iv },
+ { "movS", eCX, Iv },
+ { "movS", eDX, Iv },
+ { "movS", eBX, Iv },
+ { "movS", eSP, Iv },
+ { "movS", eBP, Iv },
+ { "movS", eSI, Iv },
+ { "movS", eDI, Iv },
+ /* c0 */
+ { GRP2b },
+ { GRP2S },
+ { "ret", Iw },
+ { "ret" },
+ { "lesS", Gv, Mp },
+ { "ldsS", Gv, Mp },
+ { "movb", Eb, Ib },
+ { "movS", Ev, Iv },
+ /* c8 */
+ { "enter", Iw, Ib },
+ { "leave" },
+ { "lret", Iw },
+ { "lret" },
+ { "int3" },
+ { "int", Ib },
+ { "into" },
+ { "iret" },
+ /* d0 */
+ { GRP2b_one },
+ { GRP2S_one },
+ { GRP2b_cl },
+ { GRP2S_cl },
+ { "aam", Ib },
+ { "aad", Ib },
+ { "(bad)" },
+ { "xlat" },
+ /* d8 */
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ { FLOAT },
+ /* e0 */
+ { "loopne", Jb },
+ { "loope", Jb },
+ { "loop", Jb },
+ { "jCcxz", Jb },
+ { "inb", AL, Ib },
+ { "inS", eAX, Ib },
+ { "outb", Ib, AL },
+ { "outS", Ib, eAX },
+ /* e8 */
+ { "call", Av },
+ { "jmp", Jv },
+ { "ljmp", Ap },
+ { "jmp", Jb },
+ { "inb", AL, indirDX },
+ { "inS", eAX, indirDX },
+ { "outb", indirDX, AL },
+ { "outS", indirDX, eAX },
+ /* f0 */
+ { "(bad)" }, /* lock prefix */
+ { "(bad)" },
+ { "(bad)" }, /* repne */
+ { "(bad)" }, /* repz */
+ { "hlt" },
+ { "cmc" },
+ { GRP3b },
+ { GRP3S },
+ /* f8 */
+ { "clc" },
+ { "stc" },
+ { "cli" },
+ { "sti" },
+ { "cld" },
+ { "std" },
+ { GRP4 },
+ { GRP5 },
+};
+
+struct dis386 dis386_twobyte[] = {
+ /* 00 */
+ { GRP6 },
+ { GRP7 },
+ { "larS", Gv, Ew },
+ { "lslS", Gv, Ew },
+ { "(bad)" },
+ { "(bad)" },
+ { "clts" },
+ { "(bad)" },
+ /* 08 */
+ { "invd" }, { "wbinvd" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 10 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 18 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 20 */
+ /* these are all backward in appendix A of the intel book */
+ { "movl", Rd, Cd },
+ { "movl", Rd, Dd },
+ { "movl", Cd, Rd },
+ { "movl", Dd, Rd },
+ { "movl", Rd, Td },
+ { "(bad)" },
+ { "movl", Td, Rd },
+ { "(bad)" },
+ /* 28 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 30 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 38 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 40 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 48 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 50 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 58 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 60 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 68 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 70 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 78 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* 80 */
+ { "jo", Jv },
+ { "jno", Jv },
+ { "jb", Jv },
+ { "jae", Jv },
+ { "je", Jv },
+ { "jne", Jv },
+ { "jbe", Jv },
+ { "ja", Jv },
+ /* 88 */
+ { "js", Jv },
+ { "jns", Jv },
+ { "jp", Jv },
+ { "jnp", Jv },
+ { "jl", Jv },
+ { "jge", Jv },
+ { "jle", Jv },
+ { "jg", Jv },
+ /* 90 */
+ { "seto", Eb },
+ { "setno", Eb },
+ { "setb", Eb },
+ { "setae", Eb },
+ { "sete", Eb },
+ { "setne", Eb },
+ { "setbe", Eb },
+ { "seta", Eb },
+ /* 98 */
+ { "sets", Eb },
+ { "setns", Eb },
+ { "setp", Eb },
+ { "setnp", Eb },
+ { "setl", Eb },
+ { "setge", Eb },
+ { "setle", Eb },
+ { "setg", Eb },
+ /* a0 */
+ { "pushl", fs },
+ { "popl", fs },
+ { "(bad)" },
+ { "btS", Ev, Gv },
+ { "shldS", Ev, Gv, Ib },
+ { "shldS", Ev, Gv, CL },
+ { "(bad)" },
+ { "(bad)" },
+ /* a8 */
+ { "pushl", gs },
+ { "popl", gs },
+ { "(bad)" },
+ { "btsS", Ev, Gv },
+ { "shrdS", Ev, Gv, Ib },
+ { "shrdS", Ev, Gv, CL },
+ { "(bad)" },
+ { "imulS", Gv, Ev },
+ /* b0 */
+ { "(bad)" },
+ { "(bad)" },
+ { "lssS", Gv, Mp }, /* 386 lists only Mp */
+ { "btrS", Ev, Gv },
+ { "lfsS", Gv, Mp }, /* 386 lists only Mp */
+ { "lgsS", Gv, Mp }, /* 386 lists only Mp */
+ { "movzbS", Gv, Eb },
+ { "movzwS", Gv, Ew },
+ /* b8 */
+ { "(bad)" },
+ { "(bad)" },
+ { GRP8 },
+ { "btcS", Ev, Gv },
+ { "bsfS", Gv, Ev },
+ { "bsrS", Gv, Ev },
+ { "movsbS", Gv, Eb },
+ { "movswS", Gv, Ew },
+ /* c0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* c8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* d0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* d8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* e8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f0 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ /* f8 */
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+ { "(bad)" }, { "(bad)" }, { "(bad)" }, { "(bad)" },
+};
+
+static char obuf[100];
+static char *obufp;
+static char scratchbuf[100];
+static unsigned char *start_codep;
+static unsigned char *codep;
+static int mod;
+static int rm;
+static int reg;
+
+static char *names32[]={
+ "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi",
+};
+static char *names16[] = {
+ "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di",
+};
+static char *names8[] = {
+ "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh",
+};
+static char *names_seg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+};
+static char *names16_pairs[] = {
+ "%bx+%si","%bx+%di","%bp+%si","%bp+%di","%si","%di","%bp","%bx",
+};
+
+struct dis386 grps[][8] = {
+ /* GRP1b */
+ {
+ { "addb", Eb, Ib },
+ { "orb", Eb, Ib },
+ { "adcb", Eb, Ib },
+ { "sbbb", Eb, Ib },
+ { "andb", Eb, Ib },
+ { "subb", Eb, Ib },
+ { "xorb", Eb, Ib },
+ { "cmpb", Eb, Ib }
+ },
+ /* GRP1S */
+ {
+ { "addS", Ev, Iv },
+ { "orS", Ev, Iv },
+ { "adcS", Ev, Iv },
+ { "sbbS", Ev, Iv },
+ { "andS", Ev, Iv },
+ { "subS", Ev, Iv },
+ { "xorS", Ev, Iv },
+ { "cmpS", Ev, Iv }
+ },
+ /* GRP1Ss */
+ {
+ { "addS", Ev, sIb },
+ { "orS", Ev, sIb },
+ { "adcS", Ev, sIb },
+ { "sbbS", Ev, sIb },
+ { "andS", Ev, sIb },
+ { "subS", Ev, sIb },
+ { "xorS", Ev, sIb },
+ { "cmpS", Ev, sIb }
+ },
+ /* GRP2b */
+ {
+ { "rolb", Eb, Ib },
+ { "rorb", Eb, Ib },
+ { "rclb", Eb, Ib },
+ { "rcrb", Eb, Ib },
+ { "shlb", Eb, Ib },
+ { "shrb", Eb, Ib },
+ { "(bad)" },
+ { "sarb", Eb, Ib },
+ },
+ /* GRP2S */
+ {
+ { "rolS", Ev, Ib },
+ { "rorS", Ev, Ib },
+ { "rclS", Ev, Ib },
+ { "rcrS", Ev, Ib },
+ { "shlS", Ev, Ib },
+ { "shrS", Ev, Ib },
+ { "(bad)" },
+ { "sarS", Ev, Ib },
+ },
+ /* GRP2b_one */
+ {
+ { "rolb", Eb },
+ { "rorb", Eb },
+ { "rclb", Eb },
+ { "rcrb", Eb },
+ { "shlb", Eb },
+ { "shrb", Eb },
+ { "(bad)" },
+ { "sarb", Eb },
+ },
+ /* GRP2S_one */
+ {
+ { "rolS", Ev },
+ { "rorS", Ev },
+ { "rclS", Ev },
+ { "rcrS", Ev },
+ { "shlS", Ev },
+ { "shrS", Ev },
+ { "(bad)" },
+ { "sarS", Ev },
+ },
+ /* GRP2b_cl */
+ {
+ { "rolb", Eb, CL },
+ { "rorb", Eb, CL },
+ { "rclb", Eb, CL },
+ { "rcrb", Eb, CL },
+ { "shlb", Eb, CL },
+ { "shrb", Eb, CL },
+ { "(bad)" },
+ { "sarb", Eb, CL },
+ },
+ /* GRP2S_cl */
+ {
+ { "rolS", Ev, CL },
+ { "rorS", Ev, CL },
+ { "rclS", Ev, CL },
+ { "rcrS", Ev, CL },
+ { "shlS", Ev, CL },
+ { "shrS", Ev, CL },
+ { "(bad)" },
+ { "sarS", Ev, CL }
+ },
+ /* GRP3b */
+ {
+ { "testb", Eb, Ib },
+ { "(bad)", Eb },
+ { "notb", Eb },
+ { "negb", Eb },
+ { "mulb", AL, Eb },
+ { "imulb", AL, Eb },
+ { "divb", AL, Eb },
+ { "idivb", AL, Eb }
+ },
+ /* GRP3S */
+ {
+ { "testS", Ev, Iv },
+ { "(bad)" },
+ { "notS", Ev },
+ { "negS", Ev },
+ { "mulS", eAX, Ev },
+ { "imulS", eAX, Ev },
+ { "divS", eAX, Ev },
+ { "idivS", eAX, Ev },
+ },
+ /* GRP4 */
+ {
+ { "incb", Eb },
+ { "decb", Eb },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* GRP5 */
+ {
+ { "incS", Ev },
+ { "decS", Ev },
+ { "call", indirEv },
+ { "lcall", indirEv },
+ { "jmp", indirEv },
+ { "ljmp", indirEv },
+ { "pushS", Ev },
+ { "(bad)" },
+ },
+ /* GRP6 */
+ {
+ { "sldt", Ew },
+ { "str", Ew },
+ { "lldt", Ew },
+ { "ltr", Ew },
+ { "verr", Ew },
+ { "verw", Ew },
+ { "(bad)" },
+ { "(bad)" }
+ },
+ /* GRP7 */
+ {
+ { "sgdt", Ew },
+ { "sidt", Ew },
+ { "lgdt", Ew },
+ { "lidt", Ew },
+ { "smsw", Ew },
+ { "(bad)" },
+ { "lmsw", Ew },
+ { "(bad)" },
+ },
+ /* GRP8 */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "btS", Ev, Ib },
+ { "btsS", Ev, Ib },
+ { "btrS", Ev, Ib },
+ { "btcS", Ev, Ib },
+ }
+};
+
+#define PREFIX_REPZ 0x01
+#define PREFIX_REPNZ 0x02
+#define PREFIX_LOCK 0x04
+#define PREFIX_CS 0x08
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADR 0x400
+#define PREFIX_FWAIT 0x800
+
+static int prefixes;
+
+ckprefix ()
+{
+ prefixes = 0;
+ while (1)
+ {
+ switch (*codep)
+ {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ break;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ break;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ break;
+ case 0x2e:
+ prefixes |= PREFIX_CS;
+ break;
+ case 0x36:
+ prefixes |= PREFIX_SS;
+ break;
+ case 0x3e:
+ prefixes |= PREFIX_DS;
+ break;
+ case 0x26:
+ prefixes |= PREFIX_ES;
+ break;
+ case 0x64:
+ prefixes |= PREFIX_FS;
+ break;
+ case 0x65:
+ prefixes |= PREFIX_GS;
+ break;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ break;
+ case 0x67:
+ prefixes |= PREFIX_ADR;
+ break;
+ case 0x9b:
+ prefixes |= PREFIX_FWAIT;
+ break;
+ default:
+ return;
+ }
+ codep++;
+ }
+}
+
+static int dflag;
+static int aflag;
+
+static char op1out[100], op2out[100], op3out[100];
+static unsigned long start_pc;
+
+/*
+ * disassemble the first instruction in 'inbuf'. You have to make
+ * sure all of the bytes of the instruction are filled in.
+ * On the 386's of 1988, the maximum length of an instruction is 15 bytes.
+ * (see topic "Redundant prefixes" in the "Differences from 8086"
+ * section of the "Virtual 8086 Mode" chapter.)
+ * 'pc' should be the address of this instruction, it will
+ * be used to print the target address if this is a relative jump or call
+ * 'outbuf' gets filled in with the disassembled instruction. it should
+ * be long enough to hold the longest disassembled instruction.
+ * 100 bytes is certainly enough, unless symbol printing is added later
+ * The function returns the length of this instruction in bytes.
+ */
+i386dis (ucs, uip, inbuf, outbuf, mode)
+ unsigned short ucs;
+ unsigned short uip;
+ unsigned char *inbuf;
+ char *outbuf;
+{
+ struct dis386 *dp;
+ char *p;
+ int i;
+ int enter_instruction;
+ char *first, *second, *third;
+ int needcomma;
+
+ obuf[0] = 0;
+ op1out[0] = 0;
+ op2out[0] = 0;
+ op3out[0] = 0;
+
+ start_pc = ucs << 16 | uip;
+ start_codep = inbuf;
+ codep = inbuf;
+
+ ckprefix ();
+
+ if (*codep == 0xc8)
+ enter_instruction = 1;
+ else
+ enter_instruction = 0;
+
+ obufp = obuf;
+
+ if (prefixes & PREFIX_REPZ)
+ oappend ("repz ");
+ if (prefixes & PREFIX_REPNZ)
+ oappend ("repnz ");
+ if (prefixes & PREFIX_LOCK)
+ oappend ("lock ");
+
+ if ((prefixes & PREFIX_FWAIT)
+ && ((*codep < 0xd8) || (*codep > 0xdf)))
+ {
+ /* fwait not followed by floating point instruction */
+ oappend ("fwait");
+ strcpy (outbuf, obuf);
+ return (1);
+ }
+
+ /* these would be initialized to 0 if disassembling for 8086 or 286 */
+ /* these would be initialized to 0 if disassembling for 8086 or 286 */
+ if (mode) {
+ dflag = 1;
+ aflag = 1;
+ } else {
+ dflag = 0;
+ aflag = 0;
+ }
+
+ if (prefixes & PREFIX_DATA)
+ dflag ^= 1;
+
+ if (prefixes & PREFIX_ADR)
+ {
+ aflag ^= 1;
+ oappend ("addr16 ");
+ }
+
+ if (*codep == 0x0f)
+ dp = &dis386_twobyte[*++codep];
+ else
+ dp = &dis386[*codep];
+ codep++;
+ mod = (*codep >> 6) & 3;
+ reg = (*codep >> 3) & 7;
+ rm = *codep & 7;
+
+ if (dp->name == NULL && dp->bytemode1 == FLOATCODE)
+ {
+ dofloat ();
+ }
+ else
+ {
+ if (dp->name == NULL)
+ dp = &grps[dp->bytemode1][reg];
+
+ putop (dp->name);
+
+ obufp = op1out;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+
+ obufp = op2out;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+
+ obufp = op3out;
+ if (dp->op3)
+ (*dp->op3)(dp->bytemode3);
+ }
+
+ obufp = obuf + strlen (obuf);
+ for (i = strlen (obuf); i < 6; i++)
+ oappend (" ");
+ oappend (" ");
+
+ /* enter instruction is printed with operands in the
+ * same order as the intel book; everything else
+ * is printed in reverse order
+ */
+ if (enter_instruction)
+ {
+ first = op1out;
+ second = op2out;
+ third = op3out;
+ }
+ else
+ {
+ first = op3out;
+ second = op2out;
+ third = op1out;
+ }
+ needcomma = 0;
+ if (*first)
+ {
+ oappend (first);
+ needcomma = 1;
+ }
+ if (*second)
+ {
+ if (needcomma)
+ oappend (",");
+ oappend (second);
+ needcomma = 1;
+ }
+ if (*third)
+ {
+ if (needcomma)
+ oappend (",");
+ oappend (third);
+ }
+ strcpy (outbuf, obuf);
+ return (codep - inbuf);
+}
+
+char *float_mem[] = {
+ /* d8 */
+ "fadds",
+ "fmuls",
+ "fcoms",
+ "fcomps",
+ "fsubs",
+ "fsubrs",
+ "fdivs",
+ "fdivrs",
+ /* d9 */
+ "flds",
+ "(bad)",
+ "fsts",
+ "fstps",
+ "fldenv",
+ "fldcw",
+ "fNstenv",
+ "fNstcw",
+ /* da */
+ "fiaddl",
+ "fimull",
+ "ficoml",
+ "ficompl",
+ "fisubl",
+ "fisubrl",
+ "fidivl",
+ "fidivrl",
+ /* db */
+ "fildl",
+ "(bad)",
+ "fistl",
+ "fistpl",
+ "(bad)",
+ "fldt",
+ "(bad)",
+ "fstpt",
+ /* dc */
+ "faddl",
+ "fmull",
+ "fcoml",
+ "fcompl",
+ "fsubl",
+ "fsubrl",
+ "fdivl",
+ "fdivrl",
+ /* dd */
+ "fldl",
+ "(bad)",
+ "fstl",
+ "fstpl",
+ "frstor",
+ "(bad)",
+ "fNsave",
+ "fNstsw",
+ /* de */
+ "fiadd",
+ "fimul",
+ "ficom",
+ "ficomp",
+ "fisub",
+ "fisubr",
+ "fidiv",
+ "fidivr",
+ /* df */
+ "fild",
+ "(bad)",
+ "fist",
+ "fistp",
+ "fbld",
+ "fildll",
+ "fbstp",
+ "fistpll",
+};
+
+#define ST OP_ST, 0
+#define STi OP_STi, 0
+int OP_ST(), OP_STi();
+
+#define FGRPd9_2 NULL, NULL, 0
+#define FGRPd9_4 NULL, NULL, 1
+#define FGRPd9_5 NULL, NULL, 2
+#define FGRPd9_6 NULL, NULL, 3
+#define FGRPd9_7 NULL, NULL, 4
+#define FGRPda_5 NULL, NULL, 5
+#define FGRPdb_4 NULL, NULL, 6
+#define FGRPde_3 NULL, NULL, 7
+#define FGRPdf_4 NULL, NULL, 8
+
+struct dis386 float_reg[][8] = {
+ /* d8 */
+ {
+ { "fadd", ST, STi },
+ { "fmul", ST, STi },
+ { "fcom", STi },
+ { "fcomp", STi },
+ { "fsub", ST, STi },
+ { "fsubr", ST, STi },
+ { "fdiv", ST, STi },
+ { "fdivr", ST, STi },
+ },
+ /* d9 */
+ {
+ { "fld", STi },
+ { "fxch", STi },
+ { FGRPd9_2 },
+ { "(bad)" },
+ { FGRPd9_4 },
+ { FGRPd9_5 },
+ { FGRPd9_6 },
+ { FGRPd9_7 },
+ },
+ /* da */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPda_5 },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* db */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdb_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* dc */
+ {
+ { "fadd", STi, ST },
+ { "fmul", STi, ST },
+ { "(bad)" },
+ { "(bad)" },
+ { "fsub", STi, ST },
+ { "fsubr", STi, ST },
+ { "fdiv", STi, ST },
+ { "fdivr", STi, ST },
+ },
+ /* dd */
+ {
+ { "ffree", STi },
+ { "(bad)" },
+ { "fst", STi },
+ { "fstp", STi },
+ { "fucom", STi },
+ { "fucomp", STi },
+ { "(bad)" },
+ { "(bad)" },
+ },
+ /* de */
+ {
+ { "faddp", STi, ST },
+ { "fmulp", STi, ST },
+ { "(bad)" },
+ { FGRPde_3 },
+ { "fsubp", STi, ST },
+ { "fsubrp", STi, ST },
+ { "fdivp", STi, ST },
+ { "fdivrp", STi, ST },
+ },
+ /* df */
+ {
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ { FGRPdf_4 },
+ { "(bad)" },
+ { "(bad)" },
+ { "(bad)" },
+ },
+};
+
+
+char *fgrps[][8] = {
+ /* d9_2 0 */
+ {
+ "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* d9_4 1 */
+ {
+ "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)",
+ },
+
+ /* d9_5 2 */
+ {
+ "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)",
+ },
+
+ /* d9_6 3 */
+ {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp",
+ },
+
+ /* d9_7 4 */
+ {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos",
+ },
+
+ /* da_5 5 */
+ {
+ "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* db_4 6 */
+ {
+ "feni(287 only)","fdisi(287 only)","fNclex","fNinit",
+ "fNsetpm(287 only)","(bad)","(bad)","(bad)",
+ },
+
+ /* de_3 7 */
+ {
+ "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+
+ /* df_4 8 */
+ {
+ "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)",
+ },
+};
+
+
+dofloat ()
+{
+ struct dis386 *dp;
+ unsigned char floatop;
+
+ floatop = codep[-1];
+
+ if (mod != 3)
+ {
+ putop (float_mem[(floatop - 0xd8) * 8 + reg]);
+ obufp = op1out;
+ OP_E (v_mode);
+ return;
+ }
+ codep++;
+
+ dp = &float_reg[floatop - 0xd8][reg];
+ if (dp->name == NULL)
+ {
+ putop (fgrps[dp->bytemode1][rm]);
+ /* instruction fnstsw is only one with strange arg */
+ if (floatop == 0xdf && *codep == 0xe0)
+ strcpy (op1out, "%eax");
+ }
+ else
+ {
+ putop (dp->name);
+ obufp = op1out;
+ if (dp->op1)
+ (*dp->op1)(dp->bytemode1);
+ obufp = op2out;
+ if (dp->op2)
+ (*dp->op2)(dp->bytemode2);
+ }
+}
+
+/* ARGSUSED */
+OP_ST (ignore)
+{
+ oappend ("%st");
+}
+
+/* ARGSUSED */
+OP_STi (ignore)
+{
+ sprintf (scratchbuf, "%%st(%d)", rm);
+ oappend (scratchbuf);
+}
+
+
+/* capital letters in template are macros */
+putop (template)
+ char *template;
+{
+ char *p;
+
+ for (p = template; *p; p++)
+ {
+ switch (*p)
+ {
+ default:
+ *obufp++ = *p;
+ break;
+ case 'C': /* For jcxz/jecxz */
+ if (aflag == 0)
+ *obufp++ = 'e';
+ break;
+ case 'N':
+ if ((prefixes & PREFIX_FWAIT) == 0)
+ *obufp++ = 'n';
+ break;
+ case 'S':
+ /* operand size flag */
+ if (dflag)
+ *obufp++ = 'l';
+ else
+ *obufp++ = 'w';
+ break;
+ }
+ }
+ *obufp = 0;
+}
+
+oappend (s)
+char *s;
+{
+ strcpy (obufp, s);
+ obufp += strlen (s);
+ *obufp = 0;
+}
+
+append_prefix ()
+{
+ if (prefixes & PREFIX_CS)
+ oappend ("%cs:");
+ if (prefixes & PREFIX_DS)
+ oappend ("%ds:");
+ if (prefixes & PREFIX_SS)
+ oappend ("%ss:");
+ if (prefixes & PREFIX_ES)
+ oappend ("%es:");
+ if (prefixes & PREFIX_FS)
+ oappend ("%fs:");
+ if (prefixes & PREFIX_GS)
+ oappend ("%gs:");
+}
+
+OP_indirE (bytemode)
+{
+ oappend ("*");
+ OP_E (bytemode);
+}
+
+OP_E (bytemode)
+{
+ int disp;
+ int havesib;
+ int didoutput = 0;
+ int base;
+ int index;
+ int scale;
+ int havebase;
+
+ /* skip mod/rm byte */
+ codep++;
+
+ havesib = 0;
+ havebase = 0;
+ disp = 0;
+
+ if (mod == 3) {
+ switch (bytemode) {
+ case b_mode:
+ oappend (names8[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[rm]);
+ else
+ oappend (names16[rm]);
+ break;
+ default:
+ oappend ("<bad dis table>");
+ break;
+ }
+ return;
+ }
+
+ append_prefix ();
+
+ if (aflag && rm == 4) {
+ havesib = 1;
+ havebase = 1;
+ scale = (*codep >> 6) & 3;
+ index = (*codep >> 3) & 7;
+ base = *codep & 7;
+ codep++;
+ }
+
+ switch (mod) {
+ case 0:
+ if (aflag) {
+ switch (rm) {
+ case 4:
+ /* implies havesib and havebase */
+ if (base == 5) {
+ havebase = 0;
+ disp = get32 ();
+ }
+ break;
+ case 5:
+ disp = get32 ();
+ break;
+ default:
+ havebase = 1;
+ base = rm;
+ break;
+ }
+ } else {
+ if (rm == 6) {
+ havebase = 0;
+ disp = get16 ();
+ } else {
+ havebase = 1;
+ base = rm;
+ }
+ }
+ break;
+ case 1:
+ disp = *(char *)codep++;
+ if (!aflag || rm != 4) {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ case 2:
+ if (aflag)
+ disp = get32 ();
+ else
+ disp = get16 ();
+ if (!aflag || rm != 4) {
+ havebase = 1;
+ base = rm;
+ }
+ break;
+ }
+
+ if (mod != 0 || (aflag && rm == 5 || (havesib && base == 5))
+ || (!aflag && rm == 6)) {
+ sprintf (scratchbuf, "0x%x", disp);
+ oappend (scratchbuf);
+ }
+
+ if (havebase || havesib) {
+ oappend ("(");
+ if (havebase)
+ oappend (aflag ? names32[base] : names16_pairs[base]);
+ if (havesib) {
+ if (index != 4) {
+ sprintf (scratchbuf, ",%s", names32[index]);
+ oappend (scratchbuf);
+ }
+ sprintf (scratchbuf, ",%d", 1 << scale);
+ oappend (scratchbuf);
+ }
+ oappend (")");
+ }
+}
+
+OP_G (bytemode)
+{
+ switch (bytemode)
+ {
+ case b_mode:
+ oappend (names8[reg]);
+ break;
+ case w_mode:
+ oappend (names16[reg]);
+ break;
+ case d_mode:
+ oappend (names32[reg]);
+ break;
+ case v_mode:
+ if (dflag)
+ oappend (names32[reg]);
+ else
+ oappend (names16[reg]);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+}
+
+get32 ()
+{
+ int x = 0;
+
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ x |= (*codep++ & 0xff) << 16;
+ x |= (*codep++ & 0xff) << 24;
+ return (x);
+}
+
+get16 ()
+{
+ int x = 0;
+
+ x = *codep++ & 0xff;
+ x |= (*codep++ & 0xff) << 8;
+ return (x);
+}
+
+OP_REG (code)
+{
+ char *s;
+
+ switch (code)
+ {
+ case indir_dx_reg: s = "(%dx)"; break;
+ case ax_reg: case cx_reg: case dx_reg: case bx_reg:
+ case sp_reg: case bp_reg: case si_reg: case di_reg:
+ s = names16[code - ax_reg];
+ break;
+ case es_reg: case ss_reg: case cs_reg:
+ case ds_reg: case fs_reg: case gs_reg:
+ s = names_seg[code - es_reg];
+ break;
+ case al_reg: case ah_reg: case cl_reg: case ch_reg:
+ case dl_reg: case dh_reg: case bl_reg: case bh_reg:
+ s = names8[code - al_reg];
+ break;
+ case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg:
+ case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg:
+ if (dflag)
+ s = names32[code - eAX_reg];
+ else
+ s = names16[code - eAX_reg];
+ break;
+ default:
+ s = "<internal disassembler error>";
+ break;
+ }
+ oappend (s);
+}
+
+OP_I (bytemode)
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ op = *codep++ & 0xff;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = get16 ();
+ break;
+ case w_mode:
+ op = get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return;
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+}
+
+OP_sI (bytemode)
+{
+ int op;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ op = *(char *)codep++;
+ break;
+ case v_mode:
+ if (dflag)
+ op = get32 ();
+ else
+ op = (short)get16();
+ break;
+ case w_mode:
+ op = (short)get16 ();
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ return;
+ }
+ sprintf (scratchbuf, "$0x%x", op);
+ oappend (scratchbuf);
+}
+
+OP_J (bytemode)
+{
+ int disp;
+
+ switch (bytemode)
+ {
+ case b_mode:
+ disp = *(char *)codep++;
+ append_pc(start_pc + codep - start_codep + disp);
+ break;
+ case v_mode:
+ if (dflag) {
+ disp = get32 ();
+ append_pc(start_pc + codep - start_codep + disp);
+ } else {
+ disp = (short)get16 ();
+ disp = (((start_pc + codep - start_codep) & 0xffff) + disp) & 0xffff;
+ append_pc((start_pc & 0xffff0000) | disp);
+ }
+ break;
+ default:
+ oappend ("<internal disassembelr error>");
+ return;
+ }
+
+ oappend (scratchbuf);
+}
+
+append_pc(unsigned long pc)
+{
+ sprintf(scratchbuf, "%04x:%04x", pc >> 16, pc & 0xffff);
+}
+
+/* ARGSUSED */
+OP_SEG (dummy)
+{
+ static char *sreg[] = {
+ "%es","%cs","%ss","%ds","%fs","%gs","%?","%?",
+ };
+
+ oappend (sreg[reg]);
+}
+
+OP_DIR (size)
+{
+ int seg, offset;
+
+ switch (size)
+ {
+ case lptr:
+ if (dflag)
+ {
+ offset = get32 ();
+ seg = get16 ();
+ }
+ else
+ {
+ offset = get16 ();
+ seg = get16 ();
+ }
+ sprintf (scratchbuf, "%04x:%04x", seg, offset);
+ oappend (scratchbuf);
+ break;
+ case v_mode:
+ if (aflag)
+ offset = get32 ();
+ else
+ offset = (short)get16 ();
+
+ append_pc(start_pc + codep - start_codep + offset);
+ oappend (scratchbuf);
+ break;
+ default:
+ oappend ("<internal disassembler error>");
+ break;
+ }
+}
+
+/* ARGSUSED */
+OP_OFF (bytemode)
+{
+ int off;
+
+ if (aflag)
+ off = get32 ();
+ else
+ off = get16 ();
+
+ sprintf (scratchbuf, "0x%x", off);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_ESDI (dummy)
+{
+ oappend ("%es:(");
+ oappend (aflag ? "%edi" : "%di");
+ oappend (")");
+}
+
+/* ARGSUSED */
+OP_DSSI (dummy)
+{
+ oappend ("%ds:(");
+ oappend (aflag ? "%esi" : "%si");
+ oappend (")");
+}
+
+/* ARGSUSED */
+OP_ONE (dummy)
+{
+ oappend ("1");
+}
+
+/* ARGSUSED */
+OP_C (dummy)
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%cr%d", reg);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_D (dummy)
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%db%d", reg);
+ oappend (scratchbuf);
+}
+
+/* ARGSUSED */
+OP_T (dummy)
+{
+ codep++; /* skip mod/rm */
+ sprintf (scratchbuf, "%%tr%d", reg);
+ oappend (scratchbuf);
+}
+
+OP_rm (bytemode)
+{
+ switch (bytemode)
+ {
+ case d_mode:
+ oappend (names32[rm]);
+ break;
+ case w_mode:
+ oappend (names16[rm]);
+ break;
+ }
+}
+
+#else
+
+i386dis (pc, inbuf, outbuf, mode)
+ int pc;
+ unsigned char *inbuf;
+ char *outbuf;
+{
+ strcpy (outbuf, "(no disassembler)");
+ return (1);
+}
+
+#endif /* DISASSEMBLER */
diff --git a/usr.bin/doscmd/instbsdi.c b/usr.bin/doscmd/instbsdi.c
new file mode 100644
index 0000000..bfad58b
--- /dev/null
+++ b/usr.bin/doscmd/instbsdi.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI instbsdi.c,v 2.2 1996/04/08 19:32:39 bostic Exp
+ */
+
+#include <dos.h>
+#include <string.h>
+
+main(int ac, char **av)
+{
+ union REGS in, out, tmp;
+ struct SREGS seg, stmp;
+
+ memset(&out, 0, sizeof(out));
+ out.h.ah = 0x52;
+ int86x(0x21, &out, &tmp, &stmp);
+
+ seg.es = stmp.es;
+ in.x.di = tmp.x.bx;
+
+ out.x.ax = 0x5D06;
+ int86x(0x21, &out, &tmp, &stmp);
+
+ seg.ds = stmp.ds;
+ in.x.si = tmp.x.si;
+
+ int86x(0xff, &in, &out, &seg);
+}
diff --git a/usr.bin/doscmd/int.c b/usr.bin/doscmd/int.c
new file mode 100644
index 0000000..2385f56
--- /dev/null
+++ b/usr.bin/doscmd/int.c
@@ -0,0 +1,139 @@
+/*
+** No copyright?!
+**
+** $Id: int.c,v 1.4 1997/03/18 02:36:56 msmith Exp $
+*/
+#include "doscmd.h"
+
+/*
+** Cause a software interrupt to happen immediately after we
+** return to vm86 mode
+*/
+void
+softint(int intnum)
+{
+ regcontext_t *REGS = saved_regcontext;
+ u_long vec = ivec[intnum];
+
+ /*
+ ** if we're dead, or there's no vector or the saved registers are
+ ** invalid
+ */
+ if (dead || !saved_valid || vec == 0)
+ return;
+
+ /*
+ ** if the vector points into the BIOS, or the handler at the other
+ ** end is just an IRET, don't bother.
+ */
+ if ((vec >> 16) == 0xf000 || *(u_char *)VECPTR(vec) == 0xcf)
+ return;
+
+#if 0
+ /*
+ * software interrupts are always taken
+ */
+ if ((R_EFLAGS & PSL_VIF) == 0) {
+ delay_interrupt(intnum, softint);
+ return;
+ }
+#endif
+
+ debug(D_TRAPS|intnum, "Int%x [%04x:%04x]\n",
+ intnum, vec >> 16, vec & 0xffff);
+
+ N_PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
+ N_PUSH(R_CS, REGS);
+ N_PUSH(R_IP, REGS);
+#if 1
+ R_EFLAGS &= ~PSL_VIF; /* XXX disable interrupts? */
+#else
+ R_EFLAGS |= PSL_VIF;
+#endif
+ N_PUTVEC(R_CS, R_IP, vec);
+}
+
+/*
+** Cause a hardware interrupt to happen immediately after
+** we return to vm86 mode
+*/
+void
+hardint(int intnum)
+{
+ regcontext_t *REGS = saved_regcontext;
+ u_long vec = ivec[intnum];
+
+ /*
+ * XXXXX
+ * We should simulate the IRQ mask in the PIC.
+ */
+
+ /*
+ ** if we're dead, or there's no vector, or the saved registers
+ ** are invalid
+ */
+ if (dead || !saved_valid || vec == 0)
+ return;
+
+ /*
+ ** if the vector points into the BIOS, or the handler at the
+ ** other end is just an IRET, don't bother
+ */
+ if ((vec >> 16) == 0xf000 || *(u_char *)VECPTR(vec) == 0xcf)
+ return;
+
+ if ((R_EFLAGS & PSL_VIF) == 0) {
+ delay_interrupt(intnum, hardint);
+ return;
+ }
+
+ debug(D_TRAPS|intnum, "Int%x [%04x:%04x]\n",
+ intnum, vec >> 16, vec & 0xffff);
+
+ N_PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
+ N_PUSH(R_CS, REGS);
+ N_PUSH(R_IP, REGS);
+#if 1
+ R_EFLAGS &= ~PSL_VIF; /* XXX disable interrupts */
+#else
+ R_EFLAGS |= PSL_VIF;
+#endif
+ N_PUTVEC(R_CS, R_IP, vec);
+}
+
+typedef void (*foo_t)(int);
+
+void
+resume_interrupt(void)
+{
+ int i;
+ regcontext_t *REGS = saved_regcontext;
+
+ n_pending--;
+ if (n_pending == 0)
+ R_EFLAGS &= ~PSL_VIP;
+
+ for (i = 0; i < 256; i++) {
+ if (pending[i]) {
+ ((foo_t)(pending[i]))(i);
+ pending[i] = 0;
+ break;
+ }
+ }
+}
+
+
+void
+delay_interrupt(int intnum, void (*func)(int))
+{
+ regcontext_t *REGS = saved_regcontext;
+
+#if 0
+printf("DELAY [%x/%d]\n", intnum, n_pending);
+#endif
+ if (pending[intnum] == 0) {
+ pending[intnum] = (u_long)func;
+ n_pending++;
+ }
+ R_EFLAGS |= PSL_VIP;
+}
diff --git a/usr.bin/doscmd/int10.c b/usr.bin/doscmd/int10.c
new file mode 100644
index 0000000..0f02cbd
--- /dev/null
+++ b/usr.bin/doscmd/int10.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int10.c,v 2.3 1996/04/08 19:32:40 bostic Exp
+ *
+ * $Id: int10.c,v 1.2 1996/09/22 05:53:00 miff Exp $
+ */
+
+#include "doscmd.h"
+#include "mouse.h"
+
+/*
+ * 0040:0060 contains the start and end of the cursor
+ */
+#define curs_end BIOSDATA[0x60]
+#define curs_start BIOSDATA[0x61]
+
+void
+int10(REGISTERS)
+{
+ char *addr;
+ int i, j;
+ int saved_row, saved_col;
+
+ /*
+ * Any call to the video BIOS is enough to reset the poll
+ * count on the keyboard.
+ */
+ reset_poll();
+
+ switch (GET8H(sc->sc_eax)) {
+ case 0x00: /* Set display mode */
+ debug(D_HALF, "Set video mode to %02x\n", GET8L(sc->sc_eax));
+ break;
+ case 0x01: /* Define cursor */
+ curs_start = GET8H(sc->sc_ecx);
+ curs_end = GET8L(sc->sc_ecx);
+ break;
+ case 0x02: /* Position cursor */
+ if (!xmode)
+ goto unsupported;
+ tty_move(GET8H(sc->sc_edx), GET8L(sc->sc_edx));
+ break;
+ case 0x03: /* Read cursor position */
+ if (!xmode)
+ goto unsupported;
+ tty_report(&i, &j);
+ SET8H(sc->sc_edx, i);
+ SET8L(sc->sc_edx, j);
+ SET8H(sc->sc_ecx, curs_start);
+ SET8L(sc->sc_ecx, curs_end);
+ break;
+ case 0x05:
+ debug(D_HALF, "Select current display page %d\n", GET8L(sc->sc_eax));
+ break;
+ case 0x06: /* initialize window/scroll text upward */
+ if (!xmode)
+ goto unsupported;
+ tty_scroll(GET8H(sc->sc_ecx), GET8L(sc->sc_ecx),
+ GET8H(sc->sc_edx), GET8L(sc->sc_edx),
+ GET8L(sc->sc_eax), GET8H(sc->sc_ebx) << 8);
+ break;
+ case 0x07: /* initialize window/scroll text downward */
+ if (!xmode)
+ goto unsupported;
+ tty_rscroll(GET8H(sc->sc_ecx), GET8L(sc->sc_ecx),
+ GET8H(sc->sc_edx), GET8L(sc->sc_edx),
+ GET8L(sc->sc_eax), GET8H(sc->sc_ebx) << 8);
+ break;
+ case 0x08: /* read character/attribute */
+ if (!xmode)
+ goto unsupported;
+ i = tty_char(-1, -1);
+ SET16(sc->sc_eax, i);
+ break;
+ case 0x09: /* write character/attribute */
+ if (!xmode)
+ goto unsupported;
+ tty_rwrite(GET16(sc->sc_ecx), GET8L(sc->sc_eax), GET8L(sc->sc_ebx) << 8);
+ break;
+ case 0x0a: /* write character */
+ if (!xmode)
+ goto unsupported;
+ tty_rwrite(GET16(sc->sc_ecx), GET8L(sc->sc_eax), -1);
+ break;
+ case 0x0b: /* set border color */
+ if (!xmode)
+ goto unsupported;
+ video_setborder(GET8L(sc->sc_ebx));
+ break;
+ case 0x0e: /* write character */
+ tty_write(GET8L(sc->sc_eax), -1);
+ break;
+ case 0x0f: /* get display mode */
+ SET8H(sc->sc_eax, 80); /* number of columns */
+ SET8L(sc->sc_eax, 3); /* color */
+ SET8H(sc->sc_ebx, 0); /* display page */
+ break;
+ case 0x10:
+ switch (GET8L(sc->sc_eax)) {
+ case 0x01:
+ video_setborder(GET8H(sc->sc_ebx) & 0x0f);
+ break;
+ case 0x02: /* Set pallete registers */
+ debug(D_HALF, "INT 10 10:02 Set all palette registers\n");
+ break;
+ case 0x03: /* Enable/Disable blinking mode */
+ video_blink(GET8L(sc->sc_ebx) ? 1 : 0);
+ break;
+ case 0x13:
+ debug(D_HALF,
+ "INT 10 10:13 Select color or DAC (%02x, %02x)\n",
+ GET8L(sc->sc_ebx), GET8H(sc->sc_ebx));
+ break;
+ case 0x1a: /* get video dac color-page state */
+ SET8H(sc->sc_ebx, 0); /* Current page */
+ SET8L(sc->sc_ebx, 0); /* four pages of 64... */
+ break;
+ default:
+ unknown_int3(0x10, 0x10, GET8L(sc->sc_eax), sc);
+ break;
+ }
+ break;
+#if 1
+ case 0x11:
+ switch (GET8L(sc->sc_eax)) {
+ case 0x00: printf("Tried to load user defined font.\n"); break;
+ case 0x01: printf("Tried to load 8x14 font.\n"); break;
+ case 0x02: printf("Tried to load 8x8 font.\n"); break;
+ case 0x03: printf("Tried to activate character set\n"); break;
+ case 0x04: printf("Tried to load 8x16 font.\n"); break;
+ case 0x10: printf("Tried to load and activate user defined font\n"); break;
+ case 0x11: printf("Tried to load and activate 8x14 font.\n"); break;
+ case 0x12: printf("Tried to load and activate 8x8 font.\n"); break;
+ case 0x14: printf("Tried to load and activate 8x16 font.\n"); break;
+ case 0x30:
+ SET16(sc->sc_ecx, 14);
+ SET8L(sc->sc_edx, 24);
+ switch(GET8H(sc->sc_ebx)) {
+ case 0:
+ PUTVEC(sc->sc_es, sc->sc_ebp, ivec[0x1f]);
+ break;
+ case 1:
+ PUTVEC(sc->sc_es, sc->sc_ebp, ivec[0x43]);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ SET16(sc->sc_es, 0);
+ SET16(sc->sc_ebp, 0);
+ debug(D_HALF,
+ "INT 10 11:30 Request font address %02x",
+ GET8H(sc->sc_ebx));
+ break;
+ default:
+ unknown_int4(0x10, 0x11, 0x30, GET8H(sc->sc_ebx), sc);
+ break;
+ }
+ break;
+ default:
+ unknown_int3(0x10, 0x11, GET8L(sc->sc_eax), sc);
+ break;
+ }
+ break;
+#endif
+ case 0x12: /* Load multiple DAC color register */
+ if (!xmode)
+ goto unsupported;
+ switch (GET8L(sc->sc_ebx)) {
+ case 0x10: /* Read EGA/VGA config */
+ SET8H(sc->sc_ebx, 0); /* Color */
+ SET8L(sc->sc_ebx, 0); /* 64K */
+ break;
+ default:
+ unknown_int3(0x10, 0x12, GET8L(sc->sc_ebx), sc);
+ break;
+ }
+ break;
+ case 0x13: /* write character string */
+ if (!xmode)
+ goto unsupported;
+ addr = (char *)GETPTR(sc->sc_es, sc->sc_ebp);
+ switch (GET8L(sc->sc_eax) & 0x03) {
+ case 0:
+ tty_report(&saved_row, &saved_col);
+ tty_move(GET8H(sc->sc_edx), GET8L(sc->sc_edx));
+ for (i = 0; i < GET16(sc->sc_ecx); ++i)
+ tty_write(*addr++, GET8L(sc->sc_ebx) << 8);
+ tty_move(saved_row, saved_col);
+ break;
+ case 1:
+ tty_move(GET8H(sc->sc_edx), GET8L(sc->sc_edx));
+ for (i = 0; i < GET16(sc->sc_ecx); ++i)
+ tty_write(*addr++, GET8L(sc->sc_ebx) << 8);
+ break;
+ case 2:
+ tty_report(&saved_row, &saved_col);
+ tty_move(GET8H(sc->sc_edx), GET8L(sc->sc_edx));
+ for (i = 0; i < GET16(sc->sc_ecx); ++i) {
+ tty_write(addr[0], addr[1]);
+ addr += 2;
+ }
+ tty_move(saved_row, saved_col);
+ break;
+ case 3:
+ tty_move(GET8H(sc->sc_edx), GET8L(sc->sc_edx));
+ for (i = 0; i < GET16(sc->sc_ecx); ++i) {
+ tty_write(addr[0], addr[1]);
+ addr += 2;
+ }
+ break;
+ }
+ break;
+ case 0x1a:
+ if (!xmode)
+ goto unsupported;
+ SET8L(sc->sc_eax, 0x1a); /* I am VGA */
+ SET8L(sc->sc_ebx, 8); /* Color VGA */
+ SET8H(sc->sc_ebx, 0); /* No other card */
+ break;
+
+ case 0x4f: /* get VESA information */
+ SET8H(sc->sc_eax, 0x01); /* no VESA support */
+ break;
+
+ case 0x1b: /* Functionality state information */
+ case 0xef:
+ case 0xfe: /* Get video buffer */
+ break;
+ case 0xfa: /* Interrogate mouse driver */
+ if (xmode)
+ PUTPTR(sc->sc_es, sc->sc_ebx, (long)mouse_area);
+ break;
+ case 0xff: /* Update real screen from video buffer */
+ /* XXX - we should allow secondary buffer here and then
+ update it as the user requests. */
+ break;
+
+ unsupported:
+ if (vflag) dump_regs(sc);
+ fatal ("int10 function 0x%02x:%02x only available in X mode\n",
+ GET8H(sc->sc_eax), GET8L(sc->sc_eax));
+ unknown:
+ default:
+ unknown_int2(0x10, GET8H(sc->sc_eax), sc);
+ break;
+ }
+}
diff --git a/usr.bin/doscmd/int13.c b/usr.bin/doscmd/int13.c
new file mode 100644
index 0000000..088af03
--- /dev/null
+++ b/usr.bin/doscmd/int13.c
@@ -0,0 +1,873 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int13.c,v 2.3 1996/04/08 19:32:43 bostic Exp
+ *
+ * $Id: int13.c,v 1.3 1996/09/22 15:42:53 miff Exp $
+ */
+
+#include "doscmd.h"
+
+#include <sys/ioctl.h>
+
+#define FDCHANGED _IOR('F', 64, int)
+
+#define INT13_ERR_NONE 0x00
+#define INT13_ERR_BAD_COMMAND 0x01
+#define INT13_ERR_BAD_ADDRESS_MARK 0x02
+#define INT13_ERR_WRITE_PROTECT 0x03
+#define INT13_ERR_SECTOR_ID_BAD 0x04
+#define INT13_ERR_RESET_FAILURE 0x05
+#define INT13_ERR_CLL_ACTIVE 0x06
+#define INT13_ERR_ACT_FAILED 0x07
+#define INT13_ERR_DMA_OVERRUN 0x08
+#define INT13_ERR_DMA_BOUNDARY 0x09
+#define INT13_ERR_BAD_TRACK_FLAG 0x0B
+#define INT13_ERR_MEDIA_TYP_UNKNOWN 0x0C
+#define INT13_ERR_CRC 0x10
+#define INT13_ERR_CORRECTED 0x11
+#define INT13_ERR_CTRLR_FAILURE 0x20
+#define INT13_ERR_SEEK 0x40
+#define INT13_ERR_TIME_OUT 0x80
+#define INT13_ERR_NOT_READY 0xAA
+#define INT13_ERR_UNDEFINED 0xBB
+#define INT13_ERR_SENSE_OPERATION 0xFF
+
+typedef struct {
+ u_char bootIndicator;
+ u_char beginHead;
+ u_char beginSector;
+ u_char beginCyl;
+ u_char systemID;
+ u_char endHead;
+ u_char endSector;
+ u_char endCyl;
+ u_long relSector;
+ u_long numSectors;
+} PTAB;
+
+struct diskinfo {
+ int type;
+ int sectors;
+ int cylinders;
+ int sides;
+ int secsize;
+ int fd;
+ char *path;
+ u_long location;
+ u_char *sector0;
+ u_long offset;
+ char *list[4]; /* Up to 4 devices allowed */
+ unsigned multi:2;
+ int read_only:1;
+ int removeable:1;
+ int changed:1; /* Set if we change format */
+};
+
+#define hd_status (*(u_char *)0x474)
+#define fd_status (*(u_char *)0x441)
+
+static inline int
+disize(struct diskinfo *di)
+{
+ return(di->sectors * di->cylinders * di->sides);
+}
+
+static inline int
+cylsize(struct diskinfo *di)
+{
+ return(di->sectors * di->sides);
+}
+
+static u_long ftable = 0xF1000; /* Floppy table */
+static u_long htable = 0xF1020; /* Hard disk table */
+
+static struct diskinfo diskinfo[26] = { 0 };
+
+static struct diskinfo floppyinfo[] = {
+ { 0, 9, 40, 1, 512, -1, 0, 0, }, /* Probably not correct */
+ { 1, 9, 40, 2, 512, -1, 0, 0, },
+ { 2, 9, 80, 2, 512, -1, 0, 0, },
+ { 3, 15, 80, 2, 512, -1, 0, 0, },
+ { 4, 18, 80, 2, 512, -1, 0, 0, },
+ { 6, 36, 80, 2, 512, -1, 0, 0, },
+ { -1, 0, 0, 0, 0, 0, 0, 0, },
+};
+
+static struct diskinfo *
+getdisk(int drive)
+{
+ struct diskinfo *di;
+
+ if (drive >= 2 && drive < 0x80) {
+ return(0);
+ }
+ if (drive >= 0x80) {
+ drive -= 0x80;
+ drive += 2;
+ }
+
+ if (drive > 25 || diskinfo[drive].path == 0) {
+ return(0);
+ }
+ di = &diskinfo[drive];
+ if (di->fd < 0) {
+ if (di->removeable) {
+ di->read_only = 0;
+ if (!(di->path = di->list[di->multi]))
+ di->path = di->list[di->multi = 0];
+ }
+ if ((di->fd = open(di->path, di->read_only ? O_RDONLY
+ : O_RDWR|O_FSYNC)) < 0 &&
+ (di->read_only = 1) &&
+ (di->fd = open(di->path, O_RDONLY)) < 0) {
+ return(0);
+ }
+ di->fd = squirrel_fd(di->fd);
+ }
+ return(di);
+}
+
+int
+disk_fd(int drive)
+{
+ struct diskinfo *di;
+
+ if (drive > 1)
+ drive += 0x80 - 2;
+ di = getdisk(drive);
+ if (!di)
+ return(-1);
+ return(di->fd);
+}
+
+void
+make_readonly(int drive)
+{
+ if (drive < 0 || drive >= 26)
+ return;
+ diskinfo[drive].read_only = 1;
+}
+
+int
+init_hdisk(int drive, int cyl, int head, int tracksize, char *file, char *fake_ptab)
+{
+ struct diskinfo *di;
+ u_long table;
+
+ if (drive < 0) {
+ for (drive = 2; drive < 26; ++drive) {
+ if (diskinfo[drive].path == 0)
+ break;
+ }
+ }
+ if (drive < 2) {
+ fprintf(stderr, "Only floppies may be assigned to A: or B:\n");
+ return(-1);
+ }
+
+ if (drive >= 26) {
+ fprintf(stderr, "Too many disk drives (only 24 allowed)\n");
+ return(-1);
+ }
+
+ di = &diskinfo[drive];
+
+ if (di->path) {
+ fprintf(stderr, "Drive %c: already assigned to %s\n",
+ drive + 'A', di->path);
+ return(-1);
+ }
+ di->fd = -1;
+ di->sectors = tracksize;
+ di->cylinders = cyl;
+ di->sides = head;
+ di->sector0 = 0;
+ di->offset = 0;
+
+ if (fake_ptab) {
+ u_char buf[512];
+ int fd;
+ PTAB *ptab;
+ int clusters;
+
+ if ((fd = open(fake_ptab, 0)) < 0) {
+ perror(fake_ptab);
+ return(-1);
+ }
+ di->sector0 = malloc(512);
+ if (!di->sector0) {
+ perror("malloc in init_hdisk");
+ quit(1);
+ }
+
+ read(fd, di->sector0, 512);
+ close(fd);
+
+ ptab = (PTAB *)(di->sector0 + 0x01BE);
+
+ for (fd = 0; fd < 4; ++fd) {
+ if (*(u_short *)(di->sector0 + 0x1FE) == 0xAA55 &&
+ ptab[fd].numSectors == head * tracksize * cyl &&
+ (ptab[fd].systemID == 1 || ptab[fd].systemID == 4))
+ break;
+ }
+ if (fd < 4) {
+ if (fd)
+ memcpy(ptab, ptab + fd, sizeof(PTAB));
+ memset(ptab + 1, 0, sizeof(PTAB) * 3);
+ di->offset = ptab[fd].relSector;
+ di->cylinders += di->offset / cylsize(di);
+ } else {
+ memset(ptab, 0, sizeof(PTAB) * 4);
+
+ ptab->beginHead = 0;
+ ptab->beginSector = 1; /* this is 1 based */
+ ptab->beginCyl = 1;
+
+ ptab->endHead = head - 1;
+ ptab->endSector = tracksize; /* this is 1 based */
+ ptab->endCyl = cyl & 0xff;
+ ptab->endSector |= (cyl & 0x300) >> 2;
+
+ ptab->relSector = head * tracksize;
+ ptab->numSectors = head * tracksize * cyl;
+
+ *(u_short *)(di->sector0 + 0x1FE) = 0xAA55;
+
+ fd = open(file, 0);
+ if (fd < 0) {
+ perror(file);
+ return(-1);
+ }
+ memset(buf, 0, 512);
+ read(fd, buf, 512);
+ close(fd);
+ if ((clusters = buf[0x0D]) == 0) {
+ if (disize(di) <= 128 * 2048)
+ clusters = 4;
+ else if (disize(di) <= 256 * 2048)
+ clusters = 8;
+ else if (disize(di) <= 8 * 1024 * 2048)
+ clusters = 16;
+ else if (disize(di) <= 16 * 1024 * 2048)
+ clusters = 32;
+ else
+ clusters = 64;
+ }
+ if ((disize(di) / clusters) <= 4096) {
+ ptab->systemID = 0x01;
+ } else {
+ ptab->systemID = 0x04;
+ }
+
+ di->cylinders += 1; /* Extra cylinder for partition table, etc. */
+ }
+ ptab->bootIndicator = 0x80;
+ }
+ di->type = 0xf8;
+ di->path = file;
+ di->secsize = 512;
+ di->path = strdup(file);
+
+ di->location = ((table & 0xf0000) << 12) | (table & 0xffff);
+
+ if (drive == 0) {
+ ivec[0x41] = di->location;
+ } else if (drive == 1) {
+ ivec[0x46] = di->location;
+ }
+
+ table = htable + (drive - 2) * 0x10;
+ *(u_short *)(table+0x00) = di->cylinders-1; /* Cylinders */
+ *(u_char *)(table+0x02) = di->sides; /* Heads */
+ *(u_short *)(table+0x03) = 0; /* 0 */
+ *(u_short *)(table+0x05) = 0xffff; /* write pre-comp */
+ *(u_char *)(table+0x07) = 0; /* ECC Burst length */
+ *(u_char *)(table+0x08) = 0; /* Control Byte */
+ *(u_char *)(table+0x09) = 0; /* standard timeout */
+ *(u_char *)(table+0x0a) = 0; /* formatting timeout */
+ *(u_char *)(table+0x0b) = 0; /* timeout for checking drive */
+ *(u_short *)(table+0x0c) = di->cylinders-1; /* landing zone */
+ *(u_char *)(table+0x0e) = di->sectors; /* sectors/track */
+ *(u_char *)(table+0x0f) = 0;
+
+ if ((drive - 1) >= ndisks)
+ ndisks = drive - 1;
+ return(drive);
+}
+
+static inline
+bps(int size)
+{
+ switch (size) {
+ case 128: return(0);
+ case 256: return(1);
+ case 512: return(2);
+ case 1024: return(3);
+ default:
+ fprintf(stderr, "Invalid sector size: %d\n", size);
+ quit(1);
+ }
+}
+
+int
+init_floppy(int drive, int type, char *file)
+{
+ struct diskinfo *di = floppyinfo;
+ u_long table;
+ struct stat sb;
+
+ while (di->type >= 0 && di->type != type && disize(di)/2 != type)
+ ++di;
+
+ if (!di->type) {
+ fprintf(stderr, "Invalid floppy type: %d\n", type);
+ return(-1);
+ }
+
+ if (drive < 0) {
+ if (diskinfo[0].path == 0) {
+ drive = 0;
+ } else if (diskinfo[1].path == 0) {
+ drive = 1;
+ } else {
+ fprintf(stderr, "Too many floppy drives (only 2 allowed)\n");
+ return(-1);
+ }
+ }
+ if (drive > 1) {
+ fprintf(stderr, "Floppies must be either drive A: or B:\n");
+ return(-1);
+ }
+
+ if (drive >= nfloppies)
+ nfloppies = drive + 1;
+
+ if (diskinfo[drive].path == 0) {
+ diskinfo[drive] = *di;
+ }
+
+ di = &diskinfo[drive];
+
+ if (stat(file, &sb) < 0) {
+ fprintf(stderr, "Drive %c: Could not stat %s\n",
+ drive + 'A', file);
+ return(-1);
+ }
+
+ if (drive < 2 && (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode))) {
+ if (di->path && !di->removeable) {
+ fprintf(stderr, "Drive %c: is not removeable and hence can only have one assignment\n", drive + 'A');
+ return(-1);
+ }
+ di->removeable = 1;
+ } else if (di->removeable) {
+ fprintf(stderr, "Drive %c: already assigned to %s\n",
+ drive + 'A', di->path);
+ return(-1);
+ }
+
+ if (di->removeable) {
+#if 0 /*XXXXX*/
+ if (di->multi == 4) {
+ fprintf(stderr, "Drive %c: already assigned 4 devices\n",
+ drive + 'A');
+ return(-1);
+ }
+#endif
+ di->path = di->list[di->multi++] = strdup(file);
+ } else {
+ if (di->path) {
+ fprintf(stderr, "Drive %c: already assigned to %s\n",
+ drive + 'A', di->path);
+ return(-1);
+ }
+
+ di->path = strdup(file);
+ }
+ di->fd = -1;
+ di->location = ((table & 0xf0000) << 12) | (table & 0xffff);
+ di->sector0 = 0;
+ di->offset = 0;
+
+ ivec[0x1e] = ((ftable & 0xf0000) << 12) | (ftable & 0xffff);
+
+ table = ftable + drive * 0x0a;
+
+ *(u_char *)(table+0x00) = 0xdf; /* First Specify Byte */
+ *(u_char *)(table+0x01) = 0x02; /* Second Specify Byte */
+ *(u_char *)(table+0x02) = 0x25; /* Timer ticks to wait 'til motor OFF */
+ *(u_char *)(table+0x03) = bps(di->secsize); /* Number of bytes/sector */
+ *(u_char *)(table+0x04) = di->sectors; /* Number of sectors/track */
+ *(u_char *)(table+0x05) = 0x1b; /* Gap length, in bytes */
+ *(u_char *)(table+0x06) = 0xff; /* Data length, in bytes */
+ *(u_char *)(table+0x07) = 0x6c; /* Gap length for format */
+ *(u_char *)(table+0x09) = 0xf6; /* Fill byte for formatting */
+ *(u_char *)(table+0x09) = 0x0f; /* Head settle time, in milliseconds */
+ *(u_char *)(table+0x0a) = 0x08; /* Motor startup time, in 1/8 seconds */
+ return(drive);
+}
+
+int
+search_floppy(int i)
+{
+ return(i < nfloppies ? diskinfo[i].type : 0);
+}
+
+static int icnt = 0;
+
+#define seterror(err) { \
+ if (drive & 0x80) \
+ hd_status = err; \
+ else \
+ fd_status = err; \
+ R_AH = err; \
+ R_FLAGS |= PSL_C; \
+}
+
+static int
+trynext(struct diskinfo *di)
+{
+ close(di->fd);
+ di->fd = -1;
+ di->changed = 1;
+#if 0 /*XXXXX*/
+ if (di->multi++ >= 4)
+ return(0);
+#endif
+ if (di->list[di->multi] && (di = getdisk(di - diskinfo))) {
+ di->multi = 0;
+ return(1);
+ }
+ return(0);
+}
+
+static int
+diread(struct diskinfo *di, regcontext_t *REGS,
+ off_t start, char *addr, int sectors)
+{
+ off_t res;
+
+ int drive = di - diskinfo;
+ di->multi = -1;
+
+ if (drive > 1) {
+ drive -= 2;
+ drive |= 0x80;
+ }
+
+again:
+ res = lseek(di->fd, start * di->secsize, 0);
+
+ if (res < 0 && di->removeable && trynext(di))
+ goto again;
+
+ if (res < 0) {
+ seterror(INT13_ERR_SEEK);
+ return(-1);
+ }
+
+ res = read(di->fd, addr, sectors * di->secsize);
+
+ if (res < 0 && di->removeable && trynext(di))
+ goto again;
+
+ if (di->removeable) {
+ if (res < 0) {
+ seterror(INT13_ERR_NOT_READY);
+ return(-1);
+ }
+ return(res / di->secsize);
+ }
+
+ /*
+ * reads always work, if if they don't.
+ * Just pretend any byte not read was actually a 0
+ */
+ if (res < 0)
+ memset(addr, 0, sectors * di->secsize);
+ else if (res < sectors * di->secsize)
+ memset(addr + res, 0, sectors * di->secsize - res);
+
+ return(sectors);
+}
+
+static int
+diwrite(struct diskinfo *di, regcontext_t *REGS,
+ off_t start, char *addr, int sectors)
+{
+ off_t res;
+ int drive = di - diskinfo;
+ di->multi = -1;
+
+ if (drive > 1) {
+ drive -= 2;
+ drive |= 0x80;
+ }
+
+again:
+ res = lseek(di->fd, start * di->secsize, 0);
+
+ if (res < 0 && di->removeable && trynext(di))
+ goto again;
+
+ if (res < 0) {
+ seterror(INT13_ERR_SEEK);
+ return(-1);
+ }
+
+ res = write(di->fd, addr, sectors * di->secsize);
+
+ if (res < 0 && di->removeable && trynext(di))
+ goto again;
+
+ if (di->removeable) {
+ if (res < 0) {
+ seterror(INT13_ERR_NOT_READY);
+ return(-1);
+ }
+ } else if (res < 0) {
+ seterror(INT13_ERR_WRITE_PROTECT);
+ return(-1);
+ }
+ return(res / di->secsize);
+}
+
+static void
+int13(regcontext_t *REGS)
+{
+ char *addr;
+ int sectors;
+ struct diskinfo *di;
+ off_t start;
+ int did;
+
+ int cyl;
+ int sector;
+ int side;
+ int drive;
+
+ reset_poll();
+
+ R_FLAGS &= ~PSL_C;
+
+ drive = R_DL;
+
+ if (R_AX != 0x01) {
+ if (drive & 0x80)
+ hd_status = 0;
+ else
+ fd_status = 0;
+ }
+
+ switch (R_AH) {
+ case 0x00: /* Reset */
+ break;
+ case 0x01: /* Read disk status */
+ if (drive & 0x80)
+ R_AH = hd_status;
+ else
+ R_AH = fd_status;
+ if (R_AH)
+ R_FLAGS |= PSL_C;
+ break;
+ case 0x02: /* Read */
+ R_AH = 0;
+ addr = (char *)N_GETPTR(R_ES, R_BX);
+ sectors = R_AL;
+ side = R_DH;
+ R_AL = 0; /* Start out with nothing read */
+
+ if (drive & 0x80) {
+ cyl = R_CH | ((R_CL & 0xc0) << 2);
+ sector = (R_CL & 0x3f) - 1;
+ } else {
+ sector = R_CL - 1;
+ cyl = R_CH;
+ }
+
+ if ((di = getdisk(drive)) == 0) {
+ debug(D_DISK, "Bad drive: %02x (%d : %d : %d)\n",
+ drive, cyl, side, sector);
+ seterror(INT13_ERR_BAD_COMMAND);
+ break;
+ }
+ start = cyl * di->sectors * di->sides +
+ side * di->sectors +
+ sector;
+
+ if (start >= disize(di)) {
+ debug(D_DISK, "Read past end of disk\n");
+ seterror(INT13_ERR_SEEK);
+ break;
+ }
+ if (sectors + start >= disize(di)) {
+ sectors = disize(di) - start;
+ }
+
+ if (di->sector0) {
+ if (start < di->offset) {
+ R_AL = sectors;
+ if (start == 0) {
+ memcpy(addr, di->sector0, di->secsize);
+ addr += di->secsize;
+ --sectors;
+ }
+ memset(addr, 0, sectors * di->secsize);
+ break;
+ } else {
+ start -= di->offset;
+ }
+ }
+ debug(D_DISK, "%02x: Read %2d sectors from %qd to %04x:%04x\n",
+ drive, sectors, start, R_ES, R_BX);
+
+ if ((did = diread(di, REGS, start, addr, sectors)) >= 0)
+ R_AL = did;
+#if 0
+ callint(0x0d);
+ callint(0x76);
+#endif
+ break;
+
+ case 0x03: /* Write */
+ R_AH = 0;
+ addr = (char *)GETPTR(R_ES, R_BX);
+ sectors = R_AL;
+ side = R_DH;
+ R_AL = 0; /* Start out with nothing written */
+
+ if (drive & 0x80) {
+ cyl = R_CH | ((R_CL & 0xc0) << 2);
+ sector = (R_CL & 0x3f) - 1;
+ } else {
+ sector = R_CL - 1;
+ cyl = R_CH;
+ }
+
+ if ((di = getdisk(drive)) == 0) {
+ debug(D_DISK, "Bad drive: %d (%d : %d : %d)\n",
+ drive, cyl, side, sector);
+ seterror(INT13_ERR_BAD_COMMAND);
+ break;
+ }
+ if (di->read_only) {
+ debug(D_DISK, "%02x: Attempt to write readonly disk\n", drive);
+ seterror(INT13_ERR_WRITE_PROTECT);
+ break;
+ }
+ start = cyl * di->sectors * di->sides +
+ side * di->sectors +
+ sector;
+
+ if (start >= disize(di)) {
+ debug(D_DISK, "Write past end of disk\n");
+ seterror(INT13_ERR_SEEK);
+ break;
+ }
+
+ if (sectors + start >= disize(di))
+ sectors = disize(di) - start;
+
+ if (di->sector0) {
+ if (start < di->offset) {
+ R_AL = sectors;
+ break;
+ } else {
+ start -= di->offset;
+ }
+ }
+
+ debug(D_DISK, "%02x: Write %2d sectors from %qd to %04x:%04x\n",
+ drive, sectors, start, R_ES, R_BX);
+
+ if ((did = diwrite(di, REGS, start, addr, sectors)) >= 0)
+ R_AL = did;
+#if 0
+ callint(0x0d);
+ callint(0x76);
+#endif
+ break;
+
+ case 0x04: /* Verify */
+ R_AH = 0;
+ sectors = R_AL;
+ side = R_DH;
+
+ if (drive & 0x80) {
+ cyl = R_CH | ((R_CL & 0xc0) << 2);
+ sector = (R_CL & 0x3f) - 1;
+ } else {
+ sector = R_CL - 1;
+ cyl = R_CH;
+ }
+
+ if ((di = getdisk(drive)) == 0) {
+ debug(D_DISK, "Bad drive: %d (%d : %d : %d)\n",
+ drive, cyl, side, sector);
+ seterror(INT13_ERR_BAD_COMMAND);
+ break;
+ }
+ start = cyl * di->sectors * di->sides +
+ side * di->sectors +
+ sector;
+
+ if (start >= disize(di)) {
+ debug(D_DISK, "Verify past end of disk\n");
+ seterror(INT13_ERR_SEEK);
+ break;
+ }
+
+ if (sectors + start >= disize(di))
+ sectors = disize(di) - start;
+
+ if (di->sector0) {
+ if (start < di->offset)
+ break;
+ else
+ start -= di->offset;
+ }
+
+ debug(D_DISK, "Verify %2d sectors from %d\n",
+ sectors, start);
+ if (lseek(di->fd, start * di->secsize, 0) < 0) {
+ debug(D_DISK, "Seek error\n");
+ seterror(INT13_ERR_SEEK);
+ break;
+ }
+ while (sectors > 0) {
+ char buf[512];
+ if (read(di->fd, buf, di->secsize) != di->secsize) {
+ debug(D_DISK, "Verify error\n");
+ seterror(0x04);
+ break;
+ }
+ --sectors;
+ }
+#if 0
+ callint(0x0d);
+ callint(0x76);
+#endif
+ break;
+
+ case 0x05: /* Format track */
+ seterror(INT13_ERR_BAD_COMMAND);
+ break;
+
+ case 0x08: /* Status */
+ R_AH = 0;
+
+ if ((di = getdisk(drive)) == 0) {
+ debug(D_DISK, "Bad drive: %d\n", drive);
+ seterror(INT13_ERR_BAD_COMMAND);
+ break;
+ }
+ R_AX = 0;
+
+ R_BX = di->type;
+ if ((drive & 0x80) == 0)
+ N_PUTVEC(R_ES, R_DI, di->location);
+
+ R_CL = di->sectors | ((di->cylinders >> 2) & 0xc0);
+ R_CH = di->cylinders & 0xff;
+ R_DL = (drive & 0x80) ? ndisks : nfloppies;
+ R_DH = di->sides - 1;
+ debug(D_DISK, "%02x: Status requested: sec %d cyl %d side %d drive %d\n",
+ drive, R_CL, R_CH, R_DH, R_DL);
+#if 0
+ callint(0x0d);
+ callint(0x76);
+#endif
+ break;
+
+ case 0x0c: /* Move read/write head */
+ case 0x0d: /* Reset */
+ break;
+
+ case 0x10: /* check for disk ready */
+ R_AH = 0; /* always open for business */
+ break;
+
+ case 0x15:
+ if ((di = getdisk(drive)) == 0) {
+ R_AH = 0;
+ R_FLAGS |= PSL_C;
+ break;
+ }
+
+ if (drive & 0x80) {
+ start = di->sectors * di->cylinders * di->sides;
+ R_CX = start >> 16;
+ R_DX = start;
+ R_AH = 3;
+ } else {
+ R_AH = 1; /* Non-changeable disk */
+ }
+ break;
+
+ case 0x16: /* Media change */
+ R_AH = 0;
+ if ((di = getdisk(drive)) && di->changed) {
+ di->changed = 0;
+ R_AH = 6;
+ }
+ break;
+
+ case 0x17: /* Determine floppy disk format */
+ seterror(INT13_ERR_BAD_COMMAND);
+ break;
+
+ case 0x18: /* Determine disk format */
+ if ((di = getdisk(drive)) == 0) {
+ R_AH = 0;
+ R_FLAGS |= PSL_C;
+ break;
+ }
+ /* XXX incomplete? */
+ break;
+
+ default:
+ unknown_int2(0x13, R_AH, REGS);
+ break;
+ }
+}
+
+void
+disk_bios_init(void)
+{
+ u_long vec;
+
+ vec = insert_softint_trampoline();
+ ivec[0x13] = vec;
+ register_callback(vec, int13, "int 13");
+
+ vec = insert_null_trampoline();
+ ivec[0x76] = vec;
+}
diff --git a/usr.bin/doscmd/int14.c b/usr.bin/doscmd/int14.c
new file mode 100644
index 0000000..602bb80
--- /dev/null
+++ b/usr.bin/doscmd/int14.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley Software
+ * Design, Inc. by Mark Linoman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int14.c,v 2.2 1996/04/08 19:32:45 bostic Exp
+ *
+ * $Id: int14.c,v 1.3 1996/09/22 15:42:53 miff Exp $
+ */
+
+#include "doscmd.h"
+#include <sys/ioctl.h>
+#include <termios.h>
+#include "com.h"
+
+struct com_data_struct com_data[N_COMS_MAX];
+
+struct queue *create_queue() { return(0); }
+int get_char_q() {}
+int queue_not_empty() {}
+int reset_irq_request() {}
+int set_irq_request() {}
+int test_irq_request() {}
+int write_div_latches() {}
+
+void
+int14(regcontext_t *REGS)
+{
+ int reg_num;
+ struct com_data_struct *cdsp;
+ int i;
+ int nbytes;
+ char c;
+
+ debug (D_PORT, "int14: dl = 0x%02X, al = 0x%02X.\n", R_DL, R_AL);
+ if (R_DL >= N_COMS_MAX) {
+ if (vflag)
+ dump_regs(REGS);
+ fatal ("int14: illegal com port COM%d", R_DL + 1);
+ }
+ cdsp = &(com_data[R_DL]);
+
+ switch (R_AH) {
+ case 0x00: /* Initialize Serial Port */
+#if 0 /* hold off: try to defeat stupid DOS defaults */
+ com_set_line(cdsp, R_DL + 1, R_AL);
+ R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
+ R_AL = 0;
+#endif 0
+ break;
+
+ case 0x01: /* Write Character */
+ errno = 0;
+ c = R_AL;
+ nbytes = write(cdsp->fd, &c, 1);
+ debug (D_PORT, "write of 0x%02x to fd %d on '%s' returned %d %s\n",
+ R_AL, cdsp->fd, cdsp->path, nbytes, strerror(errno));
+ if (nbytes == 1) {
+ R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
+ R_AL = 0;
+ } else {
+ debug(D_PORT, "int14: lost output character 0x%02x\n",
+ R_AL);
+ R_AH = LS_SW_TIME_OUT;
+ R_AL = 0;
+ }
+ break;
+
+ case 0x02: /* Read Character */
+ errno = 0;
+ nbytes = read(cdsp->fd, &c, 1);
+ debug (D_PORT, "read of fd %d on '%s' returned %d byte 0x%02x %s\n",
+ cdsp->fd, cdsp->path, nbytes, c,
+ errno ? strerror(errno) : "");
+ if (nbytes == 1) {
+ R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
+ R_AL = c;
+ } else {
+ R_AH = LS_SW_TIME_OUT;
+ R_AL = 0x60;
+ }
+ break;
+
+ case 0x03: /* Status Request */
+ R_AX = (LS_X_SHFT_E | LS_X_HOLD_E) << 8;
+ break;
+
+ case 0x04: /* Extended Initialization */
+ R_AX = (LS_SW_TIME_OUT) << 8;
+ break;
+
+ case 0x05: /* Modem Control Register operations */
+ switch (R_AH) {
+ case 0x00: /* Read Modem Control Register */
+ R_AX = (LS_SW_TIME_OUT) << 8;
+ break;
+
+ case 0x01: /* Write Modem Control Register */
+ R_AX = (LS_SW_TIME_OUT) << 8;
+ break;
+
+ default:
+ unknown_int3(0x14, 0x05, R_AL, REGS);
+ break;
+ }
+ break;
+ default:
+ unknown_int2(0x14, R_AH, REGS);
+ break;
+ }
+}
+
+
+/* called when doscmd initializes a single line */
+void
+com_set_line(struct com_data_struct *cdsp, unsigned char port, unsigned char param)
+{
+ struct termios tty;
+ struct stat stat_buf;
+ int mode = 0; /* read|write */
+ int speed;
+ int reg_num;
+ int ret_val;
+
+ debug (D_PORT, "com_set_line: cdsp = 0x%08X, port = 0x%04x,"
+ "param = 0x%04X.\n", cdsp, port, param);
+ if (cdsp->fd > 0) {
+ debug (D_PORT, "Re-initialize serial port com%d\n", port);
+ (void)close(cdsp->fd);
+ } else {
+ debug (D_PORT, "Initialize serial port com%d\n", port);
+ }
+
+ stat(cdsp->path, &stat_buf);
+ if (!S_ISCHR(stat_buf.st_mode) ||
+ ((cdsp->fd = open(cdsp->path, O_RDWR | O_NONBLOCK, 0666)) == -1)) {
+
+ debug (D_PORT,
+ "Could not initialize serial port com%d on path '%s'\n",
+ port, cdsp->path);
+ return;
+ }
+
+ cdsp->flags = 0x00;
+ cdsp->last_char_read = 0x00;
+#if 0
+ if ((param & PARITY_EVEN) == PARITY_NONE)
+ tty.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF /* | IXANY */;
+ else
+ tty.c_iflag = IGNBRK | IXON | IXOFF /* | IXANY */;
+ tty.c_oflag = 0;
+ tty.c_lflag = 0;
+ tty.c_cc[VTIME] = 0;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cflag = CREAD | CLOCAL | HUPCL;
+ /* MCL WHY CLOCAL ??????; but, gets errno EIO on writes, else */
+ if ((param & TXLEN_8BITS) == TXLEN_8BITS)
+ tty.c_cflag |= CS8;
+ else
+ tty.c_cflag |= CS7;
+ if ((param & STOPBIT_2) == STOPBIT_2)
+ tty.c_cflag |= CSTOPB;
+ switch (param & PARITY_EVEN) {
+ case (PARITY_ODD):
+ tty.c_cflag |= (PARENB | PARODD);
+ break;
+ case (PARITY_EVEN):
+ tty.c_cflag |= PARENB;
+ break;
+ case (PARITY_NONE):
+ default:
+ break;
+ }
+ switch (param & BITRATE_9600) {
+ case (BITRATE_110):
+ speed = B110;
+ break;
+ case (BITRATE_150):
+ speed = B150;
+ break;
+ case (BITRATE_300):
+ speed = B300;
+ break;
+ case (BITRATE_600):
+ speed = B600;
+ break;
+ case (BITRATE_1200):
+ speed = B1200;
+ break;
+ case (BITRATE_2400):
+ speed = B2400;
+ break;
+ case (BITRATE_4800):
+ speed = B4800;
+ break;
+ case (BITRATE_9600):
+ speed = B9600;
+ break;
+ }
+ debug (D_PORT, "com_set_line: going with cflag 0x%X iflag 0x%X speed %d.\n",
+ tty.c_cflag, tty.c_iflag, speed);
+ errno = 0;
+ ret_val = cfsetispeed(&tty, speed);
+ debug (D_PORT, "com_set_line: cfsetispeed returned 0x%X.\n", ret_val);
+ errno = 0;
+ ret_val = cfsetospeed(&tty, speed);
+ debug (D_PORT, "com_set_line: cfsetospeed returned 0x%X.\n", ret_val);
+ errno = 0;
+ ret_val = tcsetattr(cdsp->fd, 0, &tty);
+ debug (D_PORT, "com_set_line: tcsetattr returned 0x%X.\n", ret_val);
+
+ errno = 0;
+ ret_val = fcntl(cdsp->fd, F_SETFL, O_NDELAY);
+ debug (D_PORT, "fcntl of 0x%X, 0x%X to fd %d returned %d errno %d\n",
+ F_SETFL, O_NDELAY, cdsp->fd, ret_val, errno);
+ errno = 0;
+ ret_val = ioctl(cdsp->fd, TIOCFLUSH, &mode);
+ debug (D_PORT, "ioctl of 0x%02x to fd %d on 0x%X returned %d errno %d\n",
+ TIOCFLUSH, cdsp->fd, mode, ret_val, errno);
+#endif
+ for (reg_num = 0; reg_num < N_OF_COM_REGS; reg_num++) {
+ define_input_port_handler(cdsp->addr + reg_num,
+ com_port_in);
+ define_output_port_handler(cdsp->addr + reg_num,
+ com_port_out);
+ }
+ cdsp->com_queue = create_queue(cdsp->irq);
+ debug(D_PORT, "com%d: attached '%s' at addr 0x%04x irq %d\n",
+ port, cdsp->path, cdsp->addr, cdsp->irq);
+}
+
+
+/* called when config.c initializes a single line */
+void
+init_com(int port, char *path, int addr, unsigned char irq)
+{
+ struct com_data_struct *cdsp;
+
+ debug (D_PORT, "init_com: port = 0x%04x, addr = 0x%04X, irq = %d.\n",
+ port, addr, irq);
+ cdsp = &(com_data[port]);
+ cdsp->path = path; /* XXX DEBUG strcpy? */
+ cdsp->addr = addr;
+ cdsp->irq = irq;
+ cdsp->fd = -1;
+ com_set_line(cdsp, port + 1, TXLEN_8BITS | BITRATE_9600);
+}
+
+
+/* called when DOS wants to read directly from a physical port */
+unsigned char
+com_port_in(int port)
+{
+ struct com_data_struct *cdsp;
+ unsigned char rs;
+ unsigned char i;
+ int nbytes;
+
+ /* search for a valid COM ???or MOUSE??? port */
+ for (i = 0; i < N_COMS_MAX; i++) {
+ if (com_data[i].addr == ((unsigned short)port & 0xfff8)) {
+ cdsp = &(com_data[i]);
+ break;
+ }
+ }
+ if (i == N_COMS_MAX) {
+ debug (D_PORT, "com port 0x%04x not found\n", port);
+ return 0xff;
+ }
+
+ switch (port - cdsp->addr) {
+ /* 0x03F8 - (receive buffer) or (divisor latch LO) */
+ case 0:
+ if (cdsp->line_ctrl & LC_DIV_ACC)
+ rs = cdsp->div_latch[DIV_LATCH_LOW];
+ else {
+#if 0
+ if (queue_not_empty(cdsp->com_queue)) {
+ rs = get_char_q(cdsp->com_queue);
+ cdsp->last_char_read = rs;
+ if (queue_not_empty(cdsp->com_queue) &&
+ (cdsp->int_enable & IE_RCV_DATA) != 0) {
+ debug(D_PORT,
+ "com_port_in: setting irq %d because bytes yet to be read.\n",
+ cdsp->irq);
+ set_irq_request(cdsp->irq);
+ }
+ } else
+#else
+ errno = 0;
+ nbytes = read(cdsp->fd, &rs, 1);
+ debug (D_PORT, "read of fd %d on '%s' returned %d byte 0x%02x errno %d\n",
+ cdsp->fd, cdsp->path, nbytes, rs, errno);
+ if (nbytes != 1)
+#endif
+ rs = cdsp->last_char_read;
+ }
+ break;
+
+ /* 0x03F9 - (interrupt enable) or (divisor latch HI) */
+ case 1:
+ if (cdsp->line_ctrl & LC_DIV_ACC)
+ rs = cdsp->div_latch[DIV_LATCH_HIGH];
+ else
+ rs = cdsp->int_enable;
+
+ /* 0x03FA - interrupt identification register */
+ case 2:
+ /* rs = cdsp->int_id; * XXX DEBUG not initialized */
+ rs = 0;
+ if ((queue_not_empty(cdsp->com_queue))
+ && (test_irq_request(cdsp->irq) != 0))
+ rs |= II_PEND_INT | II_RCV_DATA;
+ if ((cdsp->fifo_ctrl & FC_FIFO_EN) == FC_FIFO_EN)
+ rs |= II_FIFOS_EN;
+ break;
+
+ /* 0x03FB - line control register */
+ case 3:
+ rs = cdsp->line_ctrl;
+ break;
+
+ /* 0x03FC - modem control register */
+ case 4:
+ rs = cdsp->modem_ctrl;
+ break;
+
+ /* 0x03FD - line status register */
+ case 5:
+ rs = LS_X_SHFT_E | LS_X_HOLD_E;
+ /* if (queue_not_empty(cdsp->com_queue)) */
+ ioctl(cdsp->fd, FIONREAD, &nbytes);
+ if (nbytes > 0);
+ rs |= LS_RCV_DATA_RD;
+ break;
+
+ /* 0x03FE - modem status register */
+ case 6:
+ rs = cdsp->modem_stat | MS_DCD | MS_DSR | MS_CTS;
+ break;
+
+ /* 0x03FF - spare register */
+ case 7:
+ rs = cdsp->uart_spare;
+ break;
+
+ default:
+ debug(D_PORT, "com_port_in: illegal port index 0x%04x - 0x%04x\n",
+ port, cdsp->addr);
+ break;
+ }
+ return rs;
+}
+
+
+/* called when DOS wants to write directly to a physical port */
+void
+com_port_out(int port, unsigned char val)
+{
+ struct com_data_struct *cdsp;
+ int nbytes;
+ int i;
+
+ /* search for a valid COM ???or MOUSE??? port */
+ for (i = 0; i < N_COMS_MAX; i++) {
+ if (com_data[i].addr == ((unsigned short)port & 0xfff8)) {
+ cdsp = &(com_data[i]);
+ break;
+ }
+ }
+ if (i == N_COMS_MAX) {
+ debug (D_PORT, "com port 0x%04x not found\n", port);
+ return;
+ }
+
+ switch (port - cdsp->addr) {
+ /* 0x03F8 - (transmit buffer) or (divisor latch LO) */
+ case 0:
+ if (cdsp->line_ctrl & LC_DIV_ACC) {
+ cdsp->div_latch[DIV_LATCH_LOW] = val;
+ cdsp->flags |= DIV_LATCH_LOW_WRITTEN;
+ write_div_latches(cdsp);
+ } else {
+ errno = 0;
+ nbytes = write(cdsp->fd, val, 1);
+ debug (D_PORT, "write of 0x%02x to fd %d on '%s' returned %d errno %d\n",
+ val, cdsp->fd, cdsp->path, nbytes, errno);
+ if (nbytes != 1)
+ debug(D_PORT,
+ "int14: lost output character 0x%02x\n",
+ val);
+ }
+ break;
+
+ /* 0x03F9 - (interrupt enable) or (divisor latch HI) */
+ case 1:
+ if (cdsp->line_ctrl & LC_DIV_ACC) {
+ cdsp->div_latch[DIV_LATCH_HIGH] = val;
+ cdsp->flags |= DIV_LATCH_HIGH_WRITTEN;
+ write_div_latches(cdsp);
+ } else {
+ cdsp->int_enable = val;
+ if ((val & IE_RCV_DATA) == 0) {
+ reset_irq_request(cdsp->irq);
+ } else {
+ if (queue_not_empty(cdsp->com_queue)) {
+ set_irq_request(cdsp->irq);
+ }
+ }
+ }
+ break;
+
+ /* 0x03FA - FIFO control register */
+ case 2:
+ cdsp->fifo_ctrl = val;
+ break;
+
+ /* 0x03FB - line control register */
+ case 3:
+ cdsp->line_ctrl = val;
+ break;
+
+ /* 0x03FC - modem control register */
+ case 4:
+ cdsp->modem_ctrl = val;
+ break;
+
+ /* 0x03FD - line status register */
+ case 5:
+ cdsp->line_stat = val;
+ break;
+
+ /* 0x03FE - modem status register */
+ case 6:
+ cdsp->modem_stat = val;
+ break;
+
+ /* 0x03FF - spare register */
+ case 7:
+ cdsp->uart_spare = val;
+ break;
+
+ default:
+ debug(D_PORT, "com_port_out: illegal port index 0x%04x - 0x%04x\n",
+ port, cdsp->addr);
+ break;
+ }
+}
+
+#if 0
+/*
+ * called when BSD has bytes ready (as discovered via select) for DOS
+ */
+static void do_com_input(int fd)
+{
+ struct com_data_struct *cdsp;
+ unsigned char buffer[BUFSIZE];
+ int i, nbytes;
+
+ dp = search_com_device_by_fd(fd);
+ if (dp == NULL)
+ return;
+ do {
+ nbytes = read(cdsp->fd, buffer, BUFSIZE);
+ if (nbytes > 0) {
+ debug(D_PORT, "do_com_input: read %d bytes from fd %d (aka %d): ",
+ nbytes, fd, cdsp->fd);
+ for (i = 0; i < nbytes; i++) {
+ put_char_q(cdsp->com_queue, buffer[i]);
+ if (cdsp->int_enable & IE_RCV_DATA) {
+ debug(D_PORT, "\n");
+ debug(D_PORT, "do_com_input: setting irq %d because %d bytes read.\n",
+ dp->irq, nbytes);
+ debug(D_PORT, "do_com_input: ");
+ set_irq_request(dp->irq);
+ }
+ debug(D_PORT, "%02x ", buffer[i]);
+ }
+ debug(D_PORT, "\n");
+ }
+ } while (nbytes == BUFSIZE);
+}
+#endif 0
diff --git a/usr.bin/doscmd/int16.c b/usr.bin/doscmd/int16.c
new file mode 100644
index 0000000..ccf99cd
--- /dev/null
+++ b/usr.bin/doscmd/int16.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int16.c,v 2.2 1996/04/08 19:32:47 bostic Exp
+ *
+ * $Id: int16.c,v 1.3 1996/09/22 15:42:54 miff Exp $
+ */
+
+#include "doscmd.h"
+
+#define K_NEXT *(u_short *)0x41a
+#define K_FREE *(u_short *)0x41c
+#define KbdEmpty() (K_NEXT == K_FREE)
+
+#define HWM 16
+volatile int poll_cnt = 0;
+
+void
+wakeup_poll(void)
+{
+ if (poll_cnt <= 0)
+ poll_cnt = HWM;
+}
+
+void
+reset_poll(void)
+{
+ poll_cnt = HWM;
+}
+
+void
+sleep_poll(void)
+{
+#if 0
+ printf("sleep_poll: poll_cnt=%d\n", poll_cnt);
+ if (poll_cnt == 14)
+ tmode = 1;
+#endif
+ if (--poll_cnt <= 0) {
+ poll_cnt = 0;
+ while (KbdEmpty() && poll_cnt <= 0) {
+#if 0
+ softint(0x28);
+#endif
+ if (KbdEmpty() && poll_cnt <= 0)
+ tty_pause();
+ }
+ }
+}
+
+void
+int16(regcontext_t *REGS)
+{
+ int c;
+
+ if (!xmode && !raw_kbd) {
+ if (vflag) dump_regs(REGS);
+ fatal ("int16 func 0x%x only supported in X mode\n", R_AH);
+ }
+ switch(R_AH) {
+ case 0x00:
+ case 0x10: /* Get enhanced keystroke */
+ poll_cnt = 16;
+ while (KbdEmpty())
+ tty_pause();
+ R_AX = KbdRead();
+ break;
+
+ case 0x01: /* Get keystroke */
+ case 0x11: /* Get enhanced keystroke */
+ if (!raw_kbd)
+ sleep_poll();
+
+ if (KbdEmpty()) {
+ R_FLAGS |= PSL_Z;
+ break;
+ }
+ R_FLAGS &= ~PSL_Z;
+ R_AX = KbdPeek();
+ break;
+
+ case 0x02:
+ R_AL = tty_state();
+ break;
+
+ case 0x12:
+ R_AH = tty_estate();
+ R_AL = tty_state();
+ break;
+
+ case 0x03: /* Set typematic and delay rate */
+ break;
+
+ case 0x05:
+ KbdWrite(R_CX);
+ break;
+
+ case 0x55:
+ R_AX = 0x43af; /* Empirical value ... */
+ break;
+
+ case 0x92:
+ R_AH = 0x00;
+ break;
+
+ case 0xa2:
+ debug(D_HALF, "122-key keyboard support check\n");
+ break;
+
+ default:
+ unknown_int2(0x16, R_AH, REGS);
+ break;
+ }
+}
diff --git a/usr.bin/doscmd/int17.c b/usr.bin/doscmd/int17.c
new file mode 100644
index 0000000..fc3eb7d
--- /dev/null
+++ b/usr.bin/doscmd/int17.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int17.c,v 2.2 1996/04/08 19:32:48 bostic Exp
+ *
+ * $Id: int17.c,v 1.3 1996/09/22 15:42:56 miff Exp $
+ */
+
+#include "doscmd.h"
+#include <signal.h>
+
+static int lpt_fd[4] = { -1, -1, -1, -1, };
+static FILE *lpt_file[4] = { 0, 0, 0, 0};
+static int direct[4] = { 0, 0, 0, 0};
+static char *queue[4] = { 0, 0, 0, 0};
+static int timeout[4] = { 30, 30, 30, 30 };
+static int last_poll[4] = { 0, 0, 0, 0};
+static int last_count[4] = { 0, 0, 0, 0};
+static int current_count[4] = { 0, 0, 0, 0};
+static int alarm_active[4] = { 0, 0, 0, 0};
+static int alarm_set = 0;
+
+static void open_printer(int printer);
+
+void
+int17(regcontext_t *REGS)
+{
+ char printer_name[20];
+ int fd;
+ int p;
+ u_char c;
+
+ switch (R_AH) {
+
+ case 0x00:
+ reset_poll();
+
+ fd = lpt_fd[R_DX];
+ if (fd == -1) {
+ open_printer(R_DX);
+ fd = lpt_fd[R_DX];
+ }
+ if (fd >= 0) {
+ c = R_AL;
+ write(fd, &c, 1);
+ }
+ R_AH = 0x90; /* printed selected */
+ current_count[R_DX]++;
+ break;
+
+ case 0x01:
+ case 0x02:
+ R_AH = 0x90;
+ break;
+
+ default:
+ unknown_int2(0x17, R_AH, REGS);
+ break;
+ }
+}
+
+void
+lpt_poll(void)
+{
+ int i;
+ int current;
+
+ current = time(0);
+
+ for(i=0; i < 4; i++) {
+ if (lpt_fd[i] < 0)
+ continue;
+
+ if (current - last_poll[i] < timeout[i])
+ continue;
+
+ last_poll[i] = current;
+
+ if (last_count[i] == current_count[i]) {
+ if (direct[i]) {
+ debug(D_PRINTER, "Closing printer %d\n", i);
+ close(lpt_fd[i]);
+ } else {
+ debug(D_PRINTER, "Closing spool printer %d\n", i);
+ pclose(lpt_file[i]);
+ }
+ lpt_fd[i] = -1;
+ lpt_file[i] = 0;
+ }
+
+ last_count[i] = current_count[i];
+ }
+}
+
+
+static void
+open_printer(int printer)
+{
+ char printer_name[80];
+ char command[120];
+ int fd;
+ FILE *file;
+ char *p;
+
+ /*
+ * if printer is direct then open output device.
+ */
+ if (direct[printer]) {
+ if (p = queue[printer]) {
+ if ((fd = open(p, O_WRONLY|O_APPEND|O_CREAT, 0666)) < 0) {
+ perror(p);
+ return;
+ }
+ } else {
+ sprintf(printer_name, "/dev/lp%d", printer);
+ debug(D_PRINTER, "Opening device %s\n", printer_name);
+ if ((fd = open(printer_name, O_WRONLY)) < 0) {
+ perror(printer_name);
+ return;
+ }
+ }
+ lpt_fd[printer] = fd;
+ return;
+ }
+
+ /*
+ * If printer is a spooled device then open pipe to spooled device
+ */
+ if (queue[printer])
+ strcpy(printer_name, queue[printer]);
+ else
+ strcpy(printer_name, "lp");
+
+ sprintf(command, "lpr -P %s", printer_name);
+ debug(D_PRINTER, "opening pipe to %s\n", printer_name);
+
+ if ((file = popen(command, "w")) == 0) {
+ perror(command);
+ return;
+ }
+ lpt_file[printer] = file;
+ lpt_fd[printer] = fileno(file);
+}
+
+void
+printer_direct(int printer)
+{
+ direct[printer] = 1;
+}
+
+void
+printer_spool(int printer, char *print_queue)
+{
+ queue[printer] = print_queue ? strdup(print_queue) : 0;
+}
+
+void
+printer_timeout(int printer, char *time_out)
+{
+ if (atoi(time_out) <= 0) {
+ fprintf(stderr, "Bad timeout value on lpt%d:\n", printer+1);
+ quit(1);
+ }
+ timeout[printer] = atoi(time_out);
+}
diff --git a/usr.bin/doscmd/int1a.c b/usr.bin/doscmd/int1a.c
new file mode 100644
index 0000000..a75dfec
--- /dev/null
+++ b/usr.bin/doscmd/int1a.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int1a.c,v 2.2 1996/04/08 19:32:49 bostic Exp
+ *
+ * $Id: int1a.c,v 1.3 1996/09/22 15:42:56 miff Exp $
+ */
+
+#include "doscmd.h"
+
+static inline int
+to_BCD (int n)
+{
+ n &= 0xFF;
+ return n%10 + ((n/10)<<4);
+}
+
+void
+int1a(regcontext_t *REGS)
+{
+ struct timeval tod;
+ struct timezone zone;
+ struct tm *tm;
+ long value;
+ static long midnight = 0;
+
+ R_FLAGS &= ~PSL_C;
+
+ switch (R_AH) {
+ case 0x00:
+ gettimeofday(&tod, &zone);
+
+ if (midnight == 0) {
+ tm = localtime(&boot_time.tv_sec);
+ midnight = boot_time.tv_sec - (((tm->tm_hour * 60)
+ + tm->tm_min) * 60
+ + tm->tm_sec);
+ }
+
+ R_AL = (tod.tv_sec - midnight) / (24 * 60 * 60);
+
+ if (R_AL) {
+ tm = localtime(&boot_time.tv_sec);
+ midnight = boot_time.tv_sec - (((tm->tm_hour * 60)
+ + tm->tm_min) * 60
+ + tm->tm_sec);
+ }
+
+ tod.tv_sec -= midnight;
+ tod.tv_usec -= boot_time.tv_usec;
+
+ value = (tod.tv_sec * 182 + tod.tv_usec / (1000000L/182)) / 10;
+ R_CX = value >> 16;
+ R_DX = value & 0xffff;
+ break;
+
+ case 0x01: /* set current clock count */
+ tm = localtime(&boot_time.tv_sec);
+ midnight = boot_time.tv_sec - (((tm->tm_hour * 60)
+ + tm->tm_min) * 60 + tm->tm_sec);
+ break;
+
+ case 0x02:
+ gettimeofday(&tod, &zone);
+ tm = localtime(&tod.tv_sec);
+ R_CH = to_BCD(tm->tm_hour);
+ R_CL = to_BCD(tm->tm_min);
+ R_DH = to_BCD(tm->tm_sec);
+ break;
+
+ case 0x04:
+ gettimeofday(&tod, &zone);
+ tm = localtime(&tod.tv_sec);
+ R_CH = to_BCD((tm->tm_year + 1900) / 100);
+ R_CL = to_BCD((tm->tm_year + 1900) % 100);
+ R_DH = to_BCD(tm->tm_mon + 1);
+ R_DL = to_BCD(tm->tm_mday);
+ break;
+
+ default:
+ unknown_int2(0x1a, R_AH, REGS);
+ break;
+ }
+}
diff --git a/usr.bin/doscmd/int2f.c b/usr.bin/doscmd/int2f.c
new file mode 100644
index 0000000..450d4d7
--- /dev/null
+++ b/usr.bin/doscmd/int2f.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int2f.c,v 2.2 1996/04/08 19:32:53 bostic Exp
+ *
+ * $Id: int2f.c,v 1.4 1996/09/22 15:42:56 miff Exp $
+ */
+
+#include "doscmd.h"
+#include "dispatch.h"
+
+/*
+** Multiplex interrupt.
+**
+** subfunctions 0-0x7f reserved for DOS, some are implemented here.
+**
+*/
+
+/*
+** 2f:00 2f:01 2f:02 2f:03
+**
+** Various PRINT.COM functions
+*/
+static int
+int2f_printer(regcontext_t *REGS)
+{
+ debug (D_FILE_OPS, "Called printer function 0x%02x", R_AH);
+ R_AL = FUNC_NUM_IVALID;
+}
+
+/*
+** 2f:12
+**
+** DOS internal functions. Only one we support is 0x2e, and then only to
+** complain about it.
+*/
+static int
+int2f_dosinternal(regcontext_t *REGS)
+{
+ switch (R_AL) {
+ case 0x2e: /* XXX - GET/SET ERROR TABLE ADDRESSES */
+ switch (R_DL) {
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ debug(D_ALWAYS,"DOS program attempted to get internal error table.\n");
+ break;
+
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ debug(D_ALWAYS,"DOS program attempted to set error table.\n");
+ break;
+ }
+
+ default:
+ unknown_int4(0x2f, 0x12, R_AL, R_DL, REGS);
+ break;
+ }
+ R_AL = FUNC_NUM_IVALID;
+ return(0);
+}
+
+/*
+** 2f:16
+**
+** Windows Enhanced Mode functions. Aigh!
+*/
+static int
+int2f_windows(regcontext_t *REGS)
+{
+ switch (R_AL) {
+ case 0x80: /* installation check */
+ tty_pause();
+ R_AL = 0x00;
+ return(0);
+
+ default:
+ unknown_int3(0x2f, 0x16, R_AL, REGS);
+ break;
+ }
+ R_AL = FUNC_NUM_IVALID;
+ return(0);
+}
+
+/*
+** 2f:43
+**
+** XMS interface
+*/
+static int
+int2f_xms(regcontext_t *REGS)
+{
+ switch(R_AL) {
+ case 0: /* installation check */
+ return(0); /* %al = 0 */
+ default:
+ R_AL = FUNC_NUM_IVALID;
+ return(0);
+ }
+}
+
+
+static struct intfunc_table int2f_table[] = {
+
+ { 0x00, IFT_NOSUBFUNC, int2f_printer, "printer"},
+ { 0x01, IFT_NOSUBFUNC, int2f_printer, "printer"},
+ { 0x02, IFT_NOSUBFUNC, int2f_printer, "printer"},
+ { 0x03, IFT_NOSUBFUNC, int2f_printer, "printer"},
+ { 0x12, IFT_NOSUBFUNC, int2f_dosinternal, "DOS internal function"},
+ { 0x16, IFT_NOSUBFUNC, int2f_windows, "Windows detect"},
+ { 0x43, IFT_NOSUBFUNC, int2f_xms, "XMS"},
+ { -1, 0, NULL, NULL}
+};
+
+/*
+** int2f (multiplex) handler.
+**
+** Note that due to the widely varied and inconsistent conventions, handlers
+** called from here are expected to manage their own return values.
+*/
+void
+int2f(regcontext_t *REGS)
+{
+ int index;
+
+ /* look up the handler for the current function */
+ index = intfunc_search(int2f_table, R_AH, R_AL);
+
+ if (index >= 0) { /* respond on multiplex chain */
+ int2f_table[index].handler(REGS);
+ } else {
+ unknown_int2(0x2f, R_AH, REGS);
+ }
+}
+
+
+
diff --git a/usr.bin/doscmd/intff.c b/usr.bin/doscmd/intff.c
new file mode 100644
index 0000000..e27ac0e
--- /dev/null
+++ b/usr.bin/doscmd/intff.c
@@ -0,0 +1,805 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI intff.c,v 2.2 1996/04/08 19:32:56 bostic Exp
+ *
+ * $Id: intff.c,v 1.8 1996/09/23 09:59:25 miff Exp $
+ */
+
+#include "doscmd.h"
+#include <sys/param.h>
+#include <ctype.h>
+
+#include "dispatch.h"
+
+static LOL *lol = 0; /* DOS list-of-lists */
+static SDA *sda = 0; /* DOS swappable data area */
+
+/******************************************************************************
+** redirector functions
+**
+**
+** These are set up on entry to the redirector each time, and are referenced
+** by the functions here.
+*/
+static int r_drive,n_drive = 0;
+static CDS *r_cds;
+static SFT *r_sft;
+
+
+/*
+** 2f:11:0
+**
+** Installation check
+*/
+static int
+int2f11_00(regcontext_t *REGS)
+{
+ R_AL = 0xff;
+ R_AH = 'U'; /* and why not? 8) */
+ return(0);
+}
+
+/*
+** 2f:11:1 2f:11:2 2f:11:3 2f:11:4 2f:11:5 2f:11:11 2f:11:13
+**
+** Directory functions
+*/
+static int
+int2f11_dirfn(regcontext_t *REGS)
+{
+ char fname[PATH_MAX], tname[PATH_MAX];
+ int error;
+
+ error = translate_filename(sda->filename1, fname, &r_drive);
+ if (error)
+ return(error);
+
+ if (dos_readonly(r_drive) && (R_AL != 0x05))
+ return(WRITE_PROT_DISK);
+
+ switch(R_AL) {
+ case 0x01: /* rmdir */
+ case 0x02:
+ debug(D_REDIR,"rmdir(%s)\n",fname);
+ error = rmdir(fname);
+ break;
+ case 0x03: /* mkdir */
+ case 0x04:
+ debug(D_REDIR,"mkdir(%s)\n",fname);
+ error = mkdir(fname,0777);
+ break;
+ case 0x05: /* chdir */
+ debug(D_REDIR,"chdir(%s)\n",fname);
+ /* Note returns DOS error directly */
+ return(dos_setcwd(sda->filename1));
+
+ case 0x11: /* rename */
+ error = translate_filename(sda->filename2, tname, &r_drive);
+ if (!error) {
+ debug(D_REDIR,"rename(%s,%s)\n",fname,tname);
+ error = rename(fname, tname);
+ }
+ break;
+
+ case 0x13: /* unlink */
+ debug(D_REDIR,"unlink(%s)\n",fname);
+ error = unlink(fname);
+ break;
+
+ default:
+ fatal("called int2f11_dirfn on unknown function %x\n",R_AL);
+ }
+
+ if (error < 0) {
+ switch(errno) {
+ case ENOTDIR:
+ case ENOENT:
+ return(PATH_NOT_FOUND);
+ case EXDEV:
+ return(NOT_SAME_DEV);
+ default:
+ return(ACCESS_DENIED);
+ }
+ }
+ return(0);
+}
+
+/*
+** 2f:11:6
+**
+** Close
+*/
+static int
+int2f11_close(regcontext_t *REGS)
+{
+ int fd;
+
+ fd = r_sft->fd;
+ debug(D_REDIR, "close(%d)\n", fd);
+
+ r_sft->nfiles--;
+ if (r_sft->nfiles) {
+ debug(D_REDIR, "not last close\n");
+ return(0);
+ }
+ if (close(fd) < 0)
+ return(HANDLE_INVALID);
+ return(0);
+}
+
+/*
+** 2f:11:8 2f:11:9
+**
+** read/write
+*/
+static int
+int2f11_rdwr(regcontext_t *REGS)
+{
+ int fd;
+ char *addr;
+ int nbytes;
+ int n;
+
+ fd = r_sft->fd;
+ if (lseek(fd, r_sft->offset, SEEK_SET) < 0)
+ return(SEEK_ERROR);
+
+ addr = (char *)MAKEPTR(sda->dta_seg, sda->dta_off);
+ nbytes = R_CX;
+
+ switch(R_AL) {
+ case 0x08: /* read */
+ debug(D_REDIR, "read(%d, %d)\n", fd, nbytes);
+ n = read(fd, addr, nbytes);
+ if (n < 0)
+ return(READ_FAULT);
+ break;
+ case 0x09:
+ debug(D_REDIR, "write(%d, %d)\n", fd, nbytes);
+ n = write(fd, addr, nbytes);
+ if (n < 0)
+ return(WRITE_FAULT);
+ break;
+ default:
+ fatal("called int2f11_rdwr on unknown function %x\n",R_AL);
+ }
+
+ R_CX = n; /* report count */
+ r_sft->offset += n;
+ if (r_sft->offset > r_sft->size)
+ r_sft->size = r_sft->offset;
+ debug(D_REDIR, "offset now %d\n", r_sft->offset);
+ return(0);
+}
+
+/*
+** 2f:11:c
+**
+** Get free space (like 21:36)
+*/
+static int
+int2f11_free(regcontext_t *REGS)
+{
+ fsstat_t fs;
+ int error;
+
+ error = get_space(r_drive, &fs);
+ if (error)
+ return (error);
+ R_AX = fs.sectors_cluster;
+ R_BX = fs.total_clusters;
+ R_CX = fs.bytes_sector;
+ R_DX = fs.avail_clusters;
+ return(0);
+}
+
+/*
+** 2f:11:f
+**
+** get size and mode
+*/
+static int
+int2f11_stat(regcontext_t *REGS)
+{
+ char fname[PATH_MAX];
+ struct stat sb;
+ int error;
+
+ error = translate_filename(sda->filename1, fname, &r_drive);
+ if (error)
+ return(error);
+
+ if (stat(fname, &sb) < 0)
+ return(FILE_NOT_FOUND);
+
+ R_AX = to_dos_attr(sb.st_mode);
+ R_BX = sb.st_size >> 16;
+ R_DI = sb.st_size & 0xffff;
+ return(0);
+}
+
+/*
+** 2f:11:16 2f:11:17 2f:11:18 2f:11:2e
+**
+** Open/create a file, closely resembles int21_open.
+*/
+static int
+int2f11_open(regcontext_t *REGS)
+{
+ char fname[PATH_MAX];
+ struct stat sb;
+ int error;
+ int mode; /* open mode */
+ int attr; /* attributes of created file */
+ int action; /* what to do about file */
+ u_char *p, *e;
+ int i;
+ int omode; /* mode to say we opened in */
+ int status;
+ int fd;
+
+ error = translate_filename(sda->filename1, fname, &r_drive);
+ if (error)
+ return(error);
+
+ /*
+ ** get attributes/access mode off stack : low byte is attribute, high
+ ** byte is (sometimes) used in conjunction with 'action'
+ */
+ attr = *(u_short *)N_GETPTR(R_SS, R_SP) & 0xff;
+
+ /* which style? */
+ switch(R_AL) {
+ case 0x16: /* open */
+ action = 0x01; /* fail if does not exist */
+ switch (sda->open_mode & 3) {
+ case 0:
+ mode = O_RDONLY;
+ break;
+ case 1:
+ mode = O_WRONLY;
+ break;
+ case 2:
+ mode = O_RDWR;
+ break;
+ default:
+ return (FUNC_NUM_IVALID);
+ }
+ omode = sda->open_mode & 0x7f;
+ debug(D_REDIR,"open");
+ break;
+
+ case 0x17: /* creat/creat new */
+ case 0x18: /* creat/creat new (no CDS, but we don't care)*/
+ mode = O_RDWR;
+ omode = 3;
+ if (attr & 0x100) { /* creat new */
+ action = 0x10; /* create if not exist, fail if exists */
+ debug(D_REDIR, "creat_new");
+ } else { /* creat */
+ action = 0x12; /* create and destroy */
+ debug(D_REDIR, "creat");
+ }
+ break;
+
+ case 0x2e: /* multipurpose */
+ attr = sda->ext_attr;
+ action = sda->ext_action;
+ switch (sda->ext_mode & 3) {
+ case 0:
+ mode = O_RDONLY;
+ break;
+ case 1:
+ mode = O_WRONLY;
+ break;
+ case 2:
+ mode = O_RDWR;
+ break;
+ default:
+ return (FUNC_NUM_IVALID);
+ }
+ omode = sda->ext_mode & 0x7f;
+ debug(D_REDIR,"mopen");
+ break;
+
+ default:
+ fatal("called int2f11_open for unknown function %x\n",R_AL);
+ }
+ if (action & 0x02) /* replace/open mode */
+ mode |= O_TRUNC;
+ debug(D_REDIR, "(%s) action 0x%x mode 0x%x attr 0x%x omode 0x%x \n",
+ fname, action, mode, attr, omode);
+
+ if (ustat(fname, &sb) < 0) { /* file does not exist */
+ if ((action & 0x10) || (attr & 0x100)) { /* create it */
+ sb.st_ino = 0;
+ mode |= O_CREAT; /* have to create as we go */
+ status = 0x02; /* file created */
+ } else {
+ return(FILE_NOT_FOUND); /* fail */
+ }
+ } else {
+ if (S_ISDIR(sb.st_mode))
+ return(ACCESS_DENIED);
+ if ((action & 0x03) && !(attr & 0x100)) { /* exists, work with it */
+ if (action & 0x02) {
+ if (!S_ISREG(sb.st_mode)) { /* only allowed for files */
+ debug(D_FILE_OPS,"attempt to truncate non-regular file\n");
+ return(ACCESS_DENIED);
+ }
+ status = 0x03; /* we're going to truncate it */
+ } else {
+ status = 0x01; /* just open it */
+ }
+ } else {
+ return(FILE_ALREADY_EXISTS); /* exists, fail */
+ }
+ }
+
+ if ((fd = open(fname, mode, from_dos_attr(attr))) < 0) {
+ debug(D_FILE_OPS,"failed to open %s : %s\n",fname,strerror(errno));
+ return (ACCESS_DENIED);
+ }
+
+ if (R_AL == 0x2e) /* extended wants status returned */
+ R_CX = status;
+
+ /* black magic to populate the SFT */
+
+ e = p = sda->filename1 + 2; /* parse name */
+ while (*p) {
+ if (*p++ == '\\') /* look for beginning of filename */
+ e = p;
+ }
+
+ for (i = 0; i < 8; ++i) { /* copy name and pad with spaces */
+ if (*e && *e != '.')
+ r_sft->name[i] = *e++;
+ else
+ r_sft->name[i] = ' ';
+ }
+
+ if (*e == '.') /* skip period on short names */
+ ++e;
+
+ for (i = 0; i < 3; ++i) { /* copy extension and pad with spaces */
+ if (*e)
+ r_sft->ext[i] = *e++;
+ else
+ r_sft->ext[i] = ' ';
+ }
+
+ if (ustat(fname, &sb) < 0) /* re-stat to be accurate */
+ return(WRITE_FAULT); /* any better ideas?! */
+
+ r_sft->open_mode = omode; /* file open mode */
+ *(u_long *)r_sft->ddr_dpb = 0; /* no parameter block */
+ r_sft->size = sb.st_size; /* current size */
+ r_sft->fd = fd; /* our fd for it (hidden in starting cluster number) */
+ r_sft->offset = 0; /* current offset is 0 */
+ *(u_short *)r_sft->dir_sector = 0; /* not local file, ignored */
+ r_sft->dir_entry = 0; /* not local file, ignored */
+ r_sft->attribute = attr & 0xff; /* file attributes as requested */
+ r_sft->info = r_drive + 0x8040; /* hide drive number here for later reference */
+ encode_dos_file_time(sb.st_mtime, &r_sft->date, &r_sft->time);
+ debug(D_REDIR,"success, fd %d status %x\n", fd, status);
+ return(0);
+}
+
+/*
+** 2f:11:19 2f:11:1b
+**
+** find first
+*/
+static int
+int2f11_findfirst(regcontext_t *REGS)
+{
+ return(find_first(sda->filename1,sda->attrmask,
+ (dosdir_t *)sda->foundentry,
+ (find_block_t *)sda->findfirst));
+}
+
+/*
+** 2f:11:1c
+**
+** find next
+*/
+static int
+int2f11_findnext(regcontext_t *REGS)
+{
+ return(find_next((dosdir_t *)sda->foundentry,
+ (find_block_t *)sda->findfirst));
+}
+
+/*
+** 2f:11:21
+**
+** lseek
+*/
+static int
+int2f11_lseek(regcontext_t *REGS)
+{
+ int fd;
+ off_t offset;
+
+ fd = r_sft->fd;
+ offset = (R_CX << 16) + R_DX;
+
+ debug(D_REDIR,"lseek(%d, 0x%qx, SEEK_END)\n", fd, offset);
+
+ if ((offset = lseek(fd, offset, SEEK_END)) < 0) {
+ if (errno == EBADF)
+ return(HANDLE_INVALID);
+ else
+ return(SEEK_ERROR);
+ }
+ r_sft->offset = offset; /* update offset in SFT */
+ R_DX = offset >> 16;
+ R_AX = offset;
+ return(0);
+}
+
+/*
+** 2f:11:23
+**
+** qualify filename
+*/
+static int
+int2f11_fnqual(regcontext_t *REGS)
+{
+ char *fname,*tname;
+ int savedrive;
+ int error;
+
+ return(PATH_NOT_FOUND);
+
+ savedrive = diskdrive; /* to get CWD for network drive */
+ diskdrive = n_drive;
+ fname = (char *)N_GETPTR(R_DS, R_SI); /* path pointers */
+ tname = (char *)N_GETPTR(R_ES, R_DI);
+
+ error = dos_makepath(fname, tname);
+ if (error)
+ tname = "(failed)";
+
+ diskdrive = savedrive; /* restore correct drive */
+
+ debug(D_REDIR, "qualify '%s' -> '%s'\n", fname, tname);
+ return(error);
+}
+
+/*
+** 2f:11:??
+**
+** Null function - we know about it but do nothing
+*/
+static int
+int2f11_NULLFUNC(regcontext_t *REGS)
+{
+ return(0);
+}
+
+/*
+** 2f:11:??
+**
+** no function - not handled here (error)
+*/
+static int
+int2f11_NOFUNC(regcontext_t *REGS)
+{
+ return(-1);
+}
+
+struct intfunc_table int2f11_table[] = {
+ { 0x00, IFT_NOSUBFUNC, int2f11_00, "installation check"},
+ { 0x01, IFT_NOSUBFUNC, int2f11_dirfn, "rmdir"},
+ { 0x02, IFT_NOSUBFUNC, int2f11_dirfn, "rmdir"},
+ { 0x03, IFT_NOSUBFUNC, int2f11_dirfn, "mkdir"},
+ { 0x04, IFT_NOSUBFUNC, int2f11_dirfn, "mkdir"},
+ { 0x05, IFT_NOSUBFUNC, int2f11_dirfn, "chdir"},
+ { 0x06, IFT_NOSUBFUNC, int2f11_close, "close"},
+ { 0x07, IFT_NOSUBFUNC, int2f11_NULLFUNC, "commit file"},
+ { 0x08, IFT_NOSUBFUNC, int2f11_rdwr, "read"},
+ { 0x09, IFT_NOSUBFUNC, int2f11_rdwr, "write"},
+ { 0x0a, IFT_NOSUBFUNC, int2f11_NULLFUNC, "lock region"},
+ { 0x0b, IFT_NOSUBFUNC, int2f11_NULLFUNC, "unlock region"},
+ { 0x0c, IFT_NOSUBFUNC, int2f11_free, "free space"},
+ { 0x0e, IFT_NOSUBFUNC, int2f11_NULLFUNC, "chmod"},
+ { 0x0f, IFT_NOSUBFUNC, int2f11_stat, "stat"},
+ { 0x11, IFT_NOSUBFUNC, int2f11_dirfn, "rename"},
+ { 0x13, IFT_NOSUBFUNC, int2f11_dirfn, "unlink"},
+ { 0x16, IFT_NOSUBFUNC, int2f11_open, "open"},
+ { 0x17, IFT_NOSUBFUNC, int2f11_open, "creat"},
+ { 0x18, IFT_NOSUBFUNC, int2f11_open, "creat"},
+ { 0x19, IFT_NOSUBFUNC, int2f11_findfirst, "find first"},
+ { 0x1b, IFT_NOSUBFUNC, int2f11_findfirst, "find first"},
+ { 0x1c, IFT_NOSUBFUNC, int2f11_findnext, "find next"},
+ { 0x1d, IFT_NOSUBFUNC, int2f11_NULLFUNC, "close all (abort)"},
+ { 0x1e, IFT_NOSUBFUNC, int2f11_NULLFUNC, "do redirection"},
+ { 0x1f, IFT_NOSUBFUNC, int2f11_NULLFUNC, "printer setup"},
+ { 0x20, IFT_NOSUBFUNC, int2f11_NULLFUNC, "flush all buffers"},
+ { 0x21, IFT_NOSUBFUNC, int2f11_lseek, "lseek"},
+ { 0x22, IFT_NOSUBFUNC, int2f11_NULLFUNC, "process terminated"},
+ { 0x23, IFT_NOSUBFUNC, int2f11_fnqual, "qualify filename"},
+ { 0x24, IFT_NOSUBFUNC, int2f11_NOFUNC, "turn off printer"},
+ { 0x25, IFT_NOSUBFUNC, int2f11_NOFUNC, "printer mode"},
+ { 0x2d, IFT_NOSUBFUNC, int2f11_NOFUNC, "extended attributes"},
+ { 0x2e, IFT_NOSUBFUNC, int2f11_open, "extended open/create"},
+ { -1, 0, NULL, NULL}
+};
+
+static int int2f11_fastlookup[256];
+
+/******************************************************************************
+** 2f:11
+**
+** The DOS redirector interface.
+*/
+
+/*
+** Verify that the drive being referenced is one we are handling, and
+** establish some state for upcoming functions.
+**
+** Returns 1 if we should handle this request.
+**
+** XXX this is rather inefficient, but much easier to read than the previous
+** incarnation 8(
+*/
+static int
+int2f11_validate(regcontext_t *REGS)
+{
+ int func = R_AL;
+ char *path = NULL;
+ int doit = 0;
+
+ /* defaults may help trap problems */
+ r_cds = NULL;
+ r_sft = NULL;
+ r_drive = -1;
+
+ /* some functions we accept regardless */
+ switch (func) {
+ case 0x00: /* installation check */
+ case 0x23: /* qualify path */
+ case 0x1c: /* XXX really only valid if a search already started... */
+ return(1);
+ }
+
+ /* Where's the CDS? */
+ switch(func) {
+ case 0x01: /* referenced by the SDA */
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x0e:
+ case 0x0f:
+ case 0x11:
+ case 0x13:
+ case 0x17:
+ case 0x1b:
+ r_cds = (CDS *)MAKEPTR(sda->cds_seg, sda->cds_off);
+ break;
+
+ case 0x0c: /* in es:di */
+ case 0x1c:
+ r_cds = (CDS *)N_GETPTR(R_ES, R_DI);
+ break;
+ }
+
+ /* Where's the SFT? */
+ switch(func) {
+ case 0x06: /* in es:di */
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x21:
+ case 0x2d:
+ case 0x2e:
+ r_sft = (SFT *)N_GETPTR(R_ES, R_DI);
+ break;
+ }
+
+ /* What drive? */
+ switch(func) {
+ case 0x01: /* get drive from fully-qualified path in SDA */
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x0c:
+ case 0x0e:
+ case 0x0f:
+ case 0x11:
+ case 0x13:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1b:
+ case 0x2e:
+ path = sda->filename1;
+ break;
+
+ case 0x06: /* get drive from SFT (we put it here when file was opened) */
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x21:
+ case 0x2d:
+ r_drive = r_sft->info & 0x1f;
+ break;
+ }
+
+ if (path) { /* we have a path and need to determine the drive it refers to */
+
+ if (path[1] != ':') { /* must be fully qualified; we cannot handle this */
+ debug(D_REDIR,"attempt to work non-absolute path %s\n",path);
+ return(0);
+ }
+
+ /* translate letter to drive number */
+ r_drive = toupper(path[0]) - 'A';
+ } else {
+ path = "(no path)";
+ }
+
+ /* do we handle this drive? */
+ if (dos_getcwd(r_drive)) {
+ n_drive = r_drive; /* XXX GROSTIC HACK ALERT */
+ doit = 1;
+ }
+
+ debug(D_REDIR,"%s -> drive %c func %x (%sus)\n",
+ path, 'A'+r_drive, func, doit?"":"not ");
+
+ /* so do we deal with this one? */
+ return(doit);
+}
+
+
+int
+int2f_11(regcontext_t *REGS)
+{
+ int index;
+ int error;
+ char *fname;
+
+
+ if (!sda) { /* not initialised yet */
+ error = FUNC_NUM_IVALID;
+ } else {
+
+ index = intfunc_find(int2f11_table, int2f11_fastlookup, R_AL, 0);
+ if (index == -1) {
+ debug(D_ALWAYS,"no handler for int2f:11:%x\n", R_AL);
+ return(0);
+ }
+ reset_poll();
+
+
+ if (!int2f11_validate(REGS)) { /* determine whether we handle this request */
+ error = -1; /* not handled by us */
+ } else {
+ debug(D_REDIR, "REDIR: %02x (%s)\n",
+ int2f11_table[index].func, int2f11_table[index].desc);
+ /* call the handler */
+ error = int2f11_table[index].handler(REGS);
+ if (error != -1)
+ debug(D_REDIR, "REDIR: returns %d (%s)\n",
+ error, ((error >= 0) && (error <= dos_ret_size)) ? dos_return[error] : "unknown");
+ }
+ }
+
+ if (error == -1)
+ return (0);
+ if (error) {
+ R_AX = error;
+ R_FLAGS |= PSL_C;
+ } else
+ R_FLAGS &= ~PSL_C;
+ return (1);
+}
+
+/******************************************************************************
+** intff handler.
+**
+** intff is the (secret, proprietary, internal, evil) call to
+** initialise the redirector.
+*/
+static void
+install_drive(int drive, u_char *path)
+{
+ CDS *cds;
+
+ /* check that DOS considers this a valid drive */
+ if (drive < 0 || drive >= lol->lastdrive) {
+ debug(D_REDIR, "Drive %c beyond limit of %c)\n",
+ drive + 'A', lol->lastdrive - 1 + 'A');
+ return;
+ }
+
+ /* get the CDS for this drive */
+ cds = (CDS *)MAKEPTR(lol->cds_seg, lol->cds_offset);
+ cds += drive;
+
+#if 0 /* XXX looks OK to me - mjs */
+ if (cds->flag & (CDS_remote | CDS_ready)) {
+ debug(D_REDIR, "Drive %c already installed\n", drive + 'A');
+ return;
+ }
+#endif
+
+ debug(D_REDIR, "Installing %c: as %s\n", drive + 'A', path);
+
+ cds->flag |= CDS_remote | CDS_ready | CDS_notnet;
+ cds->path[0] = drive + 'A';
+ cds->path[1] = ':';
+ cds->path[2] = '\\';
+ cds->path[3] = '\0';
+ cds->offset = 2; /* offset of \ in current path field */
+}
+
+static void
+init_drives(void)
+{
+ int drive;
+ u_char *path;
+
+ /* for all possible drives */
+ for (drive = 0; drive < 26; ++drive) {
+ if (path = dos_getpath(drive)) /* assigned to a path? */
+ install_drive(drive, path); /* make it visible to DOS */
+ }
+}
+
+void
+intff(regcontext_t *REGS)
+{
+
+ if (lol && sda) { /* already been called? */
+ debug(D_REDIR, "redirector duplicate install ignored\n");
+ return;
+ }
+ lol = (LOL *)N_GETPTR(R_ES, R_DI); /* where DOS keeps its goodies */
+ sda = (SDA *)N_GETPTR(R_DS, R_SI);
+
+ init_drives();
+
+ /* initialise dispatcher */
+ intfunc_init(int2f11_table, int2f11_fastlookup);
+}
diff --git a/usr.bin/doscmd/mem.c b/usr.bin/doscmd/mem.c
new file mode 100644
index 0000000..025d86e
--- /dev/null
+++ b/usr.bin/doscmd/mem.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI mem.c,v 2.2 1996/04/08 19:32:57 bostic Exp
+ *
+ * $Id: mem.c,v 1.4 1996/09/22 15:42:57 miff Exp $
+ */
+
+#include <stdio.h>
+#include "doscmd.h"
+
+#define Mark(x) (*(char *) (x))
+#define Owner(x) (*(u_short *) ((char *)(x)+1))
+#define Size(x) (*(u_short *) ((char *)(x)+3))
+#define Next(x) ((char *)(x) + (Size(x)+1)*16)
+
+/* exports */
+char *dosmem;
+
+/* locals */
+static int dosmem_size;
+
+static char *next_p = (char *)0;
+static char *end_p = (char *)0xB0000L;
+
+static char *
+core_alloc(int *size)
+{
+ char *ret;
+ if (*size) {
+ if (*size & 0xfff) {
+ *size = (*size & ~0xfff) + 0x1000;
+ }
+ } else {
+ *size = end_p - next_p;
+ }
+
+ if (next_p + *size > end_p) {
+ return NULL;
+ }
+
+ ret = next_p;
+ next_p += *size;
+ return ret;
+}
+
+void
+mem_free_owner(int owner)
+{
+ char *mp;
+
+ debug(D_MEMORY, " : freeow(%04x)\n", owner);
+
+ for (mp = dosmem; ; mp = Next(mp)) {
+ if (Owner(mp) == owner)
+ Owner(mp) = 0;
+
+ if (Mark(mp) != 'M')
+ break;
+ }
+}
+
+static void
+mem_print(void)
+{
+ char *mp;
+
+ for (mp = dosmem; ; mp = Next(mp)) {
+ debug(D_ALWAYS, "%05x: mark %c owner %04x size %04x\n",
+ mp, Mark(mp), Owner(mp), Size(mp));
+
+ if (Mark(mp) != 'M')
+ break;
+ }
+}
+
+void
+mem_change_owner(int addr, int owner)
+{
+ char *mp;
+
+ debug(D_MEMORY, "%04x: owner (%04x)\n", addr, owner);
+ addr <<= 4;
+
+ for (mp = dosmem; ; mp = Next(mp)) {
+ if ((int)(mp + 16) == addr)
+ goto found;
+
+ if (Mark(mp) != 'M')
+ break;
+ }
+
+ debug(D_ALWAYS, "%05x: illegal block in change owner\n", addr);
+ mem_print();
+ return;
+
+found:
+ Owner(mp) = owner;
+}
+
+void
+mem_init(void)
+{
+ int base, avail_memory;
+
+ base = 0x600;
+ core_alloc(&base);
+
+ avail_memory = MAX_AVAIL_SEG * 16 - base;
+ dosmem = core_alloc(&avail_memory);
+
+ if (!dosmem || dosmem != (char *)base)
+ fatal("internal memory error\n");
+
+ dosmem_size = avail_memory / 16;
+
+ debug(D_MEMORY, "dosmem = 0x%x base = 0x%x avail = 0x%x (%dK)\n",
+ dosmem, base, dosmem_size, avail_memory / 1024);
+
+ Mark(dosmem) = 'Z';
+ Owner(dosmem) = 0;
+ Size(dosmem) = dosmem_size - 1;
+}
+
+static void
+mem_unsplit(char *mp, int size)
+{
+ char *nmp;
+
+ while (Mark(mp) == 'M' && Size(mp) < size) {
+ nmp = Next(mp);
+
+ if (Owner(nmp) != 0)
+ break;
+
+ Size(mp) += Size(nmp) + 1;
+ Mark(mp) = Mark(nmp);
+ }
+}
+
+static void
+mem_split(char *mp, int size)
+{
+ char *nmp;
+ int rest;
+
+ rest = Size(mp) - size;
+ Size(mp) = size;
+ nmp = Next(mp);
+ Mark(nmp) = Mark(mp);
+ Mark(mp) = 'M';
+ Owner(nmp) = 0;
+ Size(nmp) = rest - 1;
+}
+
+int
+mem_alloc(int size, int owner, int *biggestp)
+{
+ char *mp;
+ int biggest;
+
+ biggest = 0;
+ for (mp = dosmem; ; mp = Next(mp)) {
+ if (Owner(mp) == 0) {
+ if (Size(mp) < size)
+ mem_unsplit(mp, size);
+ if (Size(mp) >= size)
+ goto got;
+
+ if (Size(mp) > biggest)
+ biggest = Size(mp);
+ }
+
+ if (Mark(mp) != 'M')
+ break;
+ }
+
+ debug(D_MEMORY, "%04x: alloc(%04x, owner %04x) failed -> %d\n",
+ 0, size, owner, biggest);
+
+ if (biggestp)
+ *biggestp = biggest;
+ return 0;
+
+got:
+ if (Size(mp) > size)
+ mem_split(mp, size);
+ Owner(mp) = owner;
+ debug(D_MEMORY, "%04x: alloc(%04x, owner %04x)\n",
+ (int)mp/16 + 1, size, owner);
+
+ if (biggestp)
+ *biggestp = size;
+ return (int)mp/16 + 1;
+}
+
+int
+mem_adjust(int addr, int size, int *availp)
+{
+ char *mp;
+ int delta, nxtsiz;
+
+ debug(D_MEMORY, "%04x: adjust(%05x)\n", addr, size);
+ addr <<= 4;
+
+ for (mp = dosmem; ; mp = Next(mp)) {
+ if ((int)(mp + 16) == addr)
+ goto found;
+
+ if (Mark(mp) != 'M')
+ break;
+ }
+
+ debug(D_ALWAYS, "%05x: illegal block in adjust\n", addr);
+ mem_print();
+ return -2;
+
+found:
+ if (Size(mp) < size)
+ mem_unsplit(mp, size);
+ if (Size(mp) >= size)
+ goto got;
+
+ debug(D_MEMORY, "%04x: adjust(%04x) failed -> %d\n",
+ (int)mp/16 + 1, size, Size(mp));
+
+ if (availp)
+ *availp = Size(mp);
+ return -1;
+
+got:
+ if (Size(mp) > size)
+ mem_split(mp, size);
+ debug(D_MEMORY, "%04x: adjust(%04x)\n",
+ (int)mp/16 + 1, size);
+
+ if (availp)
+ *availp = size;
+ return 0;
+}
+
+
+
+#ifdef MEM_TEST
+mem_check ()
+{
+ struct mem_block *mp;
+ for (mp = mem_blocks.next; mp != &mem_blocks; mp = mp->next) {
+ if (mp->addr + mp->size != mp->next->addr)
+ break;
+ if (mp->inuse && mp->size == 0)
+ return (-1);
+ }
+
+ if (mp->next != &mem_blocks)
+ return (-1);
+ return (0);
+}
+
+char *blocks[10];
+
+main ()
+{
+ int i;
+ int n;
+ int newsize;
+
+ mem_init (0, 300);
+
+ for (i = 0; i < 100000; i++) {
+ n = random () % 10;
+
+ if (blocks[n]) {
+ newsize = random () % 20;
+ if ((newsize & 1) == 0)
+ newsize = 0;
+
+ if (0)
+ printf ("adjust %d %x %d\n",
+ n, blocks[n], newsize);
+ mem_adjust (blocks[n], newsize, NULL);
+ if (newsize == 0)
+ blocks[n] = NULL;
+ } else {
+ while ((newsize = random () % 20) == 0)
+ ;
+ if (0)
+ printf ("alloc %d %d\n", n, newsize);
+ blocks[n] = mem_alloc (newsize, NULL);
+ }
+ if (mem_check () < 0) {
+ printf ("==== %d\n", i);
+ mem_print ();
+ }
+ }
+
+ mem_print ();
+}
+#endif /* MEM_TEST */
diff --git a/usr.bin/doscmd/mouse.c b/usr.bin/doscmd/mouse.c
new file mode 100644
index 0000000..8593667
--- /dev/null
+++ b/usr.bin/doscmd/mouse.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI int33.c,v 2.2 1996/04/08 19:32:54 bostic Exp
+ *
+ * $Id: mouse.c,v 1.3 1996/09/22 15:42:58 miff Exp $
+ */
+
+#include "doscmd.h"
+#include "mouse.h"
+
+mouse_t mouse_status;
+u_char *mouse_area = 0;
+int nmice = 0;
+
+static void
+mouse_probe(void)
+{
+}
+
+void
+int33(regcontext_t *REGS)
+{
+ u_long vec;
+ u_short mask;
+ void *addr;
+ int i;
+
+ if (!nmice) {
+ R_FLAGS |= PSL_C; /* We don't support a mouse */
+ return;
+ }
+
+ printf("Mouse: %02x\n", R_AX);
+ switch (R_AX) {
+ case 0x00: /* Reset Mouse */
+ printf("Installing mouse driver\n");
+ R_AX = 0xffff; /* Mouse installed */
+ R_BX = 2; /* Number of mouse buttons */
+ memset(&mouse_status, 0, sizeof(mouse_status));
+ mouse_status.installed = 1;
+ mouse_status.hardcursor = 1;
+ mouse_status.end = 16;
+ mouse_status.hmickey = 8;
+ mouse_status.vmickey = 16;
+ mouse_status.doubling = 100;
+ mouse_status.init = -1;
+ mouse_status.range.w = 8 * 80;
+ mouse_status.range.h = 16 * 25;
+ break;
+
+ case 0x01: /* Display Mouse Cursor */
+ if ((mouse_status.init += 1) == 0) {
+ mouse_status.show = 1;
+ }
+ break;
+
+ case 0x02: /* Hide Mouse Cursor */
+ if (mouse_status.init == 0)
+ mouse_status.show = 0;
+ mouse_status.init -= 1;
+ break;
+
+ case 0x03: /* Get cursor position/button status */
+ mouse_probe();
+ R_CX = mouse_status.x;
+ R_DX = mouse_status.y;
+ R_BX = mouse_status.buttons;
+ break;
+
+ case 0x04: /* Move mouse cursor */
+ /* mouse_move(GET16(sc->sc_ecx), GET16(sc->sc_edx)); */
+ break;
+
+ case 0x05: /* Determine number of times mouse button was active */
+ i = R_BX & 3;
+ if (i == 3)
+ i = 1;
+
+ R_BX = mouse_status.downs[i];
+ mouse_status.downs[i] = 0;
+ R_AX = mouse_status.buttons;
+ R_CX = mouse_status.x; /* Not quite right */
+ R_DX = mouse_status.y; /* Not quite right */
+ break;
+
+ case 0x06: /* Determine number of times mouse button was relsd */
+ i = R_DX & 3;
+ if (i == 3)
+ i = 1;
+
+ R_BX = mouse_status.ups[i];
+ mouse_status.ups[i] = 0;
+ R_AX = mouse_status.buttons;
+ R_CX = mouse_status.x; /* Not quite right */
+ R_DX = mouse_status.y; /* Not quite right */
+ break;
+
+ case 0x07: /* Set min/max horizontal cursor position */
+ mouse_status.range.x = R_CX;
+ mouse_status.range.w = R_DX - R_CX;
+ break;
+
+ case 0x08: /* Set min/max vertical cursor position */
+ mouse_status.range.y = R_CX;
+ mouse_status.range.h = R_DX - R_CX;
+
+ case 0x09: /* Set graphics cursor block */
+ /* BX,CX is hot spot, ES:DX is data. */
+ break;
+
+ case 0x0a: /* Set Text Cursor */
+ mouse_status.hardcursor = R_BX ? 1 : 0;
+ mouse_status.start = R_CX;
+ mouse_status.end = R_CX; /* XXX is this right ? */
+ break;
+
+ case 0x0b: /* Read Mouse Motion Counters */
+ mouse_probe();
+ R_CX = mouse_status.x - mouse_status.lastx;
+ R_DX = mouse_status.y - mouse_status.lasty;
+ mouse_status.lastx - mouse_status.x;
+ mouse_status.lasty - mouse_status.y;
+ break;
+
+ case 0x0c: /* Set event handler */
+ mouse_status.mask = R_CX;
+ mouse_status.handler = N_GETVEC(R_ES, R_DX);
+ break;
+
+ case 0x0d: /* Enable light pen */
+ case 0x0e: /* Disable light pen */
+ break;
+
+ case 0x0f: /* Set cursor speed */
+ mouse_status.hmickey = R_CX;
+ mouse_status.vmickey = R_DX;
+ break;
+
+ case 0x10: /* Exclusive area */
+ mouse_status.exclude.x = R_CX;
+ mouse_status.exclude.y = R_DX;
+ mouse_status.exclude.w = R_SI - R_CX;
+ mouse_status.exclude.h = R_DI - R_DX;
+ break;
+
+ case 0x13: /* Set maximum for mouse speed doubling */
+ break;
+ case 0x14: /* Exchange event handlers */
+ mask = mouse_status.mask;
+ vec = mouse_status.handler;
+
+ mouse_status.mask = R_CX;
+ mouse_status.handler = GETVEC(R_ES, R_DX);
+ R_CX = mask;
+ N_PUTVEC(R_ES, R_DX, vec);
+ break;
+
+ case 0x15: /* Determine mouse status buffer size */
+ R_BX = sizeof(mouse_status);
+ break;
+
+ case 0x16: /* Store mouse buffer */
+ memcpy((char *)N_GETPTR(R_ES, R_DX), &mouse_status,
+ sizeof(mouse_status));
+ break;
+
+ case 0x17: /* Restore mouse buffer */
+ memcpy(&mouse_status, (char *)N_GETPTR(R_ES, R_DX),
+ sizeof(mouse_status));
+ break;
+
+ case 0x18: /* Install alternate handler */
+ mask = R_CX & 0xff;
+ if ((R_CX & 0xe0) == 0x00 ||
+ mask == mouse_status.altmask[0] ||
+ mask == mouse_status.altmask[1] ||
+ mask == mouse_status.altmask[2] ||
+ (mouse_status.altmask[i = 0] &&
+ mouse_status.altmask[i = 1] &&
+ mouse_status.altmask[i = 2])) {
+ R_AX = 0xffff;
+ break;
+ }
+ mouse_status.altmask[i] = R_CX;
+ mouse_status.althandler[i] = N_GETVEC(R_ES, R_DX);
+ break;
+
+ case 0x19: /* Determine address of alternate event handler */
+ mask = R_CX & 0xff;
+ if (mask == mouse_status.altmask[0])
+ vec = mouse_status.althandler[0];
+ else if (mask == mouse_status.altmask[1])
+ vec = mouse_status.althandler[1];
+ else if (mask == mouse_status.altmask[2])
+ vec = mouse_status.althandler[2];
+ else
+ R_CX = 0;
+ N_PUTVEC(R_ES, R_DX, vec);
+ break;
+
+ case 0x1a: /* set mouse sensitivity */
+ mouse_status.hmickey = R_BX;
+ mouse_status.vmickey = R_CX;
+ mouse_status.doubling = R_DX;
+ break;
+
+ case 0x1b: /* set mouse sensitivity */
+ R_BX = mouse_status.hmickey;
+ R_CX = mouse_status.vmickey;
+ R_DX = mouse_status.doubling;
+ break;
+
+ case 0x1c: /* set mouse hardware rate */
+ case 0x1d: /* set display page */
+ break;
+
+ case 0x1e: /* get display page */
+ R_BX = 0; /* Always on display page 0 */
+ break;
+
+ case 0x1f: /* Disable mouse driver */
+ if (mouse_status.installed) {
+ N_PUTVEC(R_ES, R_DX, mouse_status.handler);
+ mouse_status.installed = 0;
+ } else {
+ R_AX = 0xffff;
+ }
+ break;
+
+ case 0x20: /* Enable mouse driver */
+ mouse_status.installed = 1;
+ break;
+
+ case 0x21: /* Reset mouse driver */
+ if (mouse_status.installed) {
+ mouse_status.show = 0;
+ mouse_status.handler = 0;
+ mouse_status.mask = 0;
+ mouse_status.cursor = 0;
+ } else {
+ R_AX = 0xffff;
+ }
+ break;
+
+ case 0x22: /* Specified language for mouse messages */
+ break;
+
+ case 0x23: /* Get language number */
+ R_BX = 0; /* Always return english */
+ break;
+
+ case 0x24: /* Get mouse type */
+ R_CX = 0x0400; /* PS/2 style mouse */
+ R_BX = 0x0600 + 24; /* Version 6.24 */
+ break;
+
+ default:
+ R_FLAGS |= PSL_C;
+ break;
+ }
+}
+
+void
+mouse_init(void)
+{
+ u_long vec;
+
+ vec = insert_softint_trampoline();
+ ivec[0x33] = vec;
+ register_callback(vec, int33, "int 33");
+
+ mouse_area[1] = 24;
+}
diff --git a/usr.bin/doscmd/mouse.h b/usr.bin/doscmd/mouse.h
new file mode 100644
index 0000000..e819c50
--- /dev/null
+++ b/usr.bin/doscmd/mouse.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI mouse.h,v 2.2 1996/04/08 19:32:58 bostic Exp
+ *
+ * $Id: mouse.h,v 1.3 1996/09/22 15:42:58 miff Exp $
+ */
+
+typedef struct {
+ u_short hardcursor:1;
+ u_short installed:1;
+ u_short cursor:1;
+ u_short show:1;
+ u_short buttons:3;
+
+ u_short init;
+ u_short start;
+ u_short end;
+ u_short hmickey;
+ u_short vmickey;
+ u_short doubling;
+ u_long handler;
+ u_short mask;
+ u_long althandler[3];
+ u_short altmask[3];
+ struct {
+ u_short x;
+ u_short y;
+ u_short w;
+ u_short h;
+ } range, exclude;
+ u_short x;
+ u_short y;
+ u_short lastx;
+ u_short lasty;
+
+ u_short downs[3];
+ u_short ups[3];
+} mouse_t;
+
+extern mouse_t mouse_status;
+extern u_char *mouse_area;
diff --git a/usr.bin/doscmd/net.c b/usr.bin/doscmd/net.c
new file mode 100644
index 0000000..464113f
--- /dev/null
+++ b/usr.bin/doscmd/net.c
@@ -0,0 +1,34 @@
+/*
+** No copyright!
+**
+** $Id: net.c,v 1.3 1996/09/22 15:42:58 miff Exp $
+**
+** NetBIOS etc. hooks.
+*/
+#include "doscmd.h"
+
+static void
+int2a(regcontext_t *REGS)
+{
+ unknown_int2(0x2a, R_AH, REGS);
+}
+
+static void
+int5c(regcontext_t *REGS)
+{
+ unknown_int2(0x5c, R_AH, REGS);
+}
+
+void
+net_init(void)
+{
+ u_long vec;
+
+ vec = insert_softint_trampoline();
+ ivec[0x2a] = vec;
+ register_callback(vec, int2a, "int 2a");
+
+ vec = insert_softint_trampoline();
+ ivec[0x5c] = vec;
+ register_callback(vec, int5c, "int 5c");
+}
diff --git a/usr.bin/doscmd/port.c b/usr.bin/doscmd/port.c
new file mode 100644
index 0000000..7bcc539
--- /dev/null
+++ b/usr.bin/doscmd/port.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI port.c,v 2.2 1996/04/08 19:33:03 bostic Exp
+ *
+ * $Id: port.c,v 1.2 1996/09/22 05:53:08 miff Exp $
+ */
+
+#include "doscmd.h"
+
+#define MINPORT 0x000
+#define MAXPORT_MASK (MAXPORT - 1)
+
+#include <sys/ioctl.h>
+#include <machine/sysarch.h>
+static int consfd = -1;
+
+#define in(port) \
+({ \
+ register int _inb_result; \
+\
+ asm volatile ("xorl %%eax,%%eax; inb %%dx,%%al" : \
+ "=a" (_inb_result) : "d" (port)); \
+ _inb_result; \
+})
+
+#define out(port, data) \
+ asm volatile ("outb %%al,%%dx" : : "a" (data), "d" (port))
+
+FILE *iolog = 0;
+u_long ioports[MAXPORT/32];
+#ifdef __FreeBSD__
+static void
+iomap(int port, int cnt)
+{
+ fatal("iomap not supported");
+}
+
+static void
+iounmap(int port, int cnt)
+{
+ fatal("iomap not supported");
+}
+
+#else
+static void
+iomap(int port, int cnt)
+{
+
+ if (port + cnt >= MAXPORT) {
+ errno = ERANGE;
+ goto bad;
+ }
+ while (cnt--) {
+ ioports[port/32] |= (1 << (port%32));
+ port++;
+ }
+ if (i386_set_ioperm(ioports) < 0) {
+ bad:
+ perror("iomap");
+ quit(1);
+ }
+}
+
+static void
+iounmap(int port, int cnt)
+{
+
+ if (port + cnt >= MAXPORT) {
+ errno = ERANGE;
+ goto bad;
+ }
+ while (cnt--) {
+ ioports[port/32] &= ~(1 << (port%32));
+ port++;
+ }
+ if (i386_set_ioperm(ioports) < 0) {
+ bad:
+ perror("iounmap");
+ quit(1);
+ }
+}
+#endif
+void
+outb_traceport(int port, unsigned char byte)
+{
+/*
+ if (!iolog && !(iolog = fopen("/tmp/iolog", "a")))
+ iolog = stderr;
+
+ fprintf(iolog, "0x%03X -> %02X\n", port, byte);
+ */
+
+ iomap(port, 1);
+ out(port, byte);
+ iounmap(port, 1);
+}
+
+unsigned char
+inb_traceport(int port)
+{
+ unsigned char byte;
+
+/*
+ if (!iolog && !(iolog = fopen("/tmp/iolog", "a")))
+ iolog = stderr;
+ */
+
+ iomap(port, 1);
+ byte = in(port);
+ iounmap(port, 1);
+
+/*
+ fprintf(iolog, "0x%03X <- %02X\n", port, byte);
+ fflush(iolog);
+ */
+ return(byte);
+}
+
+/*
+ * Fake input/output ports
+ */
+
+static void
+outb_nullport(int port, unsigned char byte)
+{
+/*
+ debug(D_PORT, "outb_nullport called for port 0x%03X = 0x%02X.\n",
+ port, byte);
+ */
+}
+
+static unsigned char
+inb_nullport(int port)
+{
+/*
+ debug(D_PORT, "inb_nullport called for port 0x%03X.\n", port);
+ */
+ return(0xff);
+}
+
+/*
+ * configuration table for ports' emulators
+ */
+
+struct portsw {
+ unsigned char (*p_inb)(int port);
+ void (*p_outb)(int port, unsigned char byte);
+} portsw[MAXPORT];
+
+void
+init_io_port_handlers(void)
+{
+ int i;
+
+ for (i = 0; i < MAXPORT; i++) {
+ if (portsw[i].p_inb == 0)
+ portsw[i].p_inb = inb_nullport;
+ if (portsw[i].p_outb == 0)
+ portsw[i].p_outb = outb_nullport;
+ }
+
+}
+
+void
+define_input_port_handler(int port, unsigned char (*p_inb)(int port))
+{
+ if ((port >= MINPORT) && (port < MAXPORT)) {
+ portsw[port].p_inb = p_inb;
+ } else
+ fprintf (stderr, "attempt to handle invalid port 0x%04x", port);
+}
+
+void
+define_output_port_handler(int port, void (*p_outb)(int port, unsigned char byte))
+{
+ if ((port >= MINPORT) && (port < MAXPORT)) {
+ portsw[port].p_outb = p_outb;
+ } else
+ fprintf (stderr, "attempt to handle invalid port 0x%04x", port);
+}
+
+
+void
+inb(regcontext_t *REGS, int port)
+{
+ unsigned char (*in_handler)(int);
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ in_handler = portsw[port].p_inb;
+ else
+ in_handler = inb_nullport;
+ R_AL = (*in_handler)(port);
+ debug(D_PORT, "IN on port %02x -> %02x\n", port, R_AL);
+}
+
+void
+insb(regcontext_t *REGS, int port)
+{
+ unsigned char (*in_handler)(int);
+ unsigned char data;
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ in_handler = portsw[port].p_inb;
+ else
+ in_handler = inb_nullport;
+ data = (*in_handler)(port);
+ *(u_char *)N_GETPTR(R_ES, R_DI) = data;
+ debug(D_PORT, "INS on port %02x -> %02x\n", port, data);
+
+ if (R_FLAGS & PSL_D)
+ R_DI--;
+ else
+ R_DI++;
+}
+
+void
+inx(regcontext_t *REGS, int port)
+{
+ unsigned char (*in_handler)(int);
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ in_handler = portsw[port].p_inb;
+ else
+ in_handler = inb_nullport;
+ R_AL = (*in_handler)(port);
+ if ((port >= MINPORT) && (port < MAXPORT))
+ in_handler = portsw[port + 1].p_inb;
+ else
+ in_handler = inb_nullport;
+ R_AH = (*in_handler)(port + 1);
+ debug(D_PORT, "IN on port %02x -> %04x\n", port, R_AX);
+}
+
+void
+insx(regcontext_t *REGS, int port)
+{
+ unsigned char (*in_handler)(int);
+ unsigned char data;
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ in_handler = portsw[port].p_inb;
+ else
+ in_handler = inb_nullport;
+ data = (*in_handler)(port);
+ *(u_char *)N_GETPTR(R_ES, R_DI) = data;
+ debug(D_PORT, "INS on port %02x -> %02x\n", port, data);
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ in_handler = portsw[port + 1].p_inb;
+ else
+ in_handler = inb_nullport;
+ data = (*in_handler)(port + 1);
+ ((u_char *)N_GETPTR(R_ES, R_DI))[1] = data;
+ debug(D_PORT, "INS on port %02x -> %02x\n", port, data);
+
+ if (R_FLAGS & PSL_D)
+ R_DI -= 2;
+ else
+ R_DI += 2;
+}
+
+void
+outb(regcontext_t *REGS, int port)
+{
+ void (*out_handler)(int, unsigned char);
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ out_handler = portsw[port].p_outb;
+ else
+ out_handler = outb_nullport;
+ (*out_handler)(port, R_AL);
+ debug(D_PORT, "OUT on port %02x <- %02x\n", port, R_AL);
+/*
+ if (port == 0x3bc && R_AL == 0x55)
+ tmode = 1;
+*/
+}
+
+void
+outx(regcontext_t *REGS, int port)
+{
+ void (*out_handler)(int, unsigned char);
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ out_handler = portsw[port].p_outb;
+ else
+ out_handler = outb_nullport;
+ (*out_handler)(port, R_AL);
+ debug(D_PORT, "OUT on port %02x <- %02x\n", port, R_AL);
+ if ((port >= MINPORT) && (port < MAXPORT))
+ out_handler = portsw[port + 1].p_outb;
+ else
+ out_handler = outb_nullport;
+ (*out_handler)(port + 1, R_AH);
+ debug(D_PORT, "OUT on port %02x <- %02x\n", port + 1, R_AH);
+}
+
+void
+outsb(regcontext_t *REGS, int port)
+{
+ void (*out_handler)(int, unsigned char);
+ unsigned char value;
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ out_handler = portsw[port].p_outb;
+ else
+ out_handler = outb_nullport;
+ value = *(u_char *)N_GETPTR(R_ES, R_DI);
+ debug(D_PORT, "OUT on port %02x <- %02x\n", port, value);
+ (*out_handler)(port, value);
+
+ if (R_FLAGS & PSL_D)
+ R_DI--;
+ else
+ R_DI++;
+}
+
+void
+outsx(regcontext_t *REGS, int port)
+{
+ void (*out_handler)(int, unsigned char);
+ unsigned char value;
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ out_handler = portsw[port].p_outb;
+ else
+ out_handler = outb_nullport;
+ value = *(u_char *)N_GETPTR(R_ES, R_DI);
+ debug(D_PORT, "OUT on port %02x <- %02x\n", port, value);
+ (*out_handler)(port, value);
+
+ if ((port >= MINPORT) && (port < MAXPORT))
+ out_handler = portsw[port + 1].p_outb;
+ else
+ out_handler = outb_nullport;
+ value = ((u_char *)N_GETPTR(R_ES, R_DI))[1];
+ debug(D_PORT, "OUT on port %02x <- %02x\n", port+1, value);
+ (*out_handler)(port + 1, value);
+
+ if (R_FLAGS & PSL_D)
+ R_DI -= 2;
+ else
+ R_DI += 2;
+}
+
+unsigned char port_61 = 0x10;
+int sound_on = 1;
+int sound_freq = 1000;
+
+void
+outb_speaker(int port, unsigned char byte)
+{
+#if 0 /*XXXXX*/
+ if (raw_kbd) {
+ if ((port_61 & 3) != 3) {
+ if ((byte & 3) == 3 && /* prtim[2].gate && */ sound_on)
+ ioctl(kbd_fd, PCCONIOCSTARTBEEP, &sound_freq);
+ } else if ((byte & 3) != 3)
+ ioctl(kbd_fd, PCCONIOCSTOPBEEP);
+ }
+#endif
+ port_61 = byte;
+}
+
+unsigned char
+inb_speaker(int port)
+{
+/* port_61 = (port_61 + 1) & 0xff; */
+ return(port_61);
+}
+
+void
+speaker_init()
+{
+ define_input_port_handler(0x61, inb_speaker);
+ define_output_port_handler(0x61, outb_speaker);
+
+}
diff --git a/usr.bin/doscmd/register.h b/usr.bin/doscmd/register.h
new file mode 100644
index 0000000..1b6cecc
--- /dev/null
+++ b/usr.bin/doscmd/register.h
@@ -0,0 +1,222 @@
+/*
+** Copyright (c) 1996
+** Michael Smith. All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY Michael Smith ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL Michael Smith BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+**
+** $Id: register.h,v 1.4 1997/03/18 02:36:56 msmith Exp $
+*/
+
+/******************************************************************************
+** Abstractions to hide register access methods across different platforms.
+**
+*/
+
+#define NEW_REGISTERS
+
+#ifndef _MACHINE_VM86_H_
+
+/* standard register representation */
+typedef union
+{
+ u_long r_ex;
+ struct
+ {
+ u_short r_x;
+ u_short :16;
+ } r_w;
+ struct
+ {
+ u_char r_l;
+ u_char r_h;
+ u_short :16;
+ } r_b;
+} reg86_t;
+
+#endif
+
+#ifdef __FreeBSD__
+
+/* layout must match definition of struct sigcontext in <machine/signal.h> */
+
+typedef struct
+{
+ int pad[2];
+ reg86_t esp;
+ reg86_t ebp;
+ reg86_t isp;
+ reg86_t eip;
+ reg86_t efl;
+ reg86_t es;
+ reg86_t ds;
+ reg86_t cs;
+ reg86_t ss;
+ reg86_t edi;
+ reg86_t esi;
+ reg86_t ebx;
+ reg86_t edx;
+ reg86_t ecx;
+ reg86_t eax;
+ reg86_t gs;
+ reg86_t fs;
+} registers_t;
+
+typedef union
+{
+ struct sigcontext sc;
+ registers_t r;
+} regcontext_t;
+
+/*
+** passed around as a reference to the registers. This must be in
+** scope for the following register macros to work.
+*/
+
+/* register shorthands */
+#define R_ESP (REGS->r.esp.r_ex)
+#define R_SP (REGS->r.esp.r_w.r_x)
+#define R_EBP (REGS->r.ebp.r_ex)
+#define R_BP (REGS->r.ebp.r_w.r_x)
+#define R_ISP (REGS->r.isp.r_ex)
+#define R_EIP (REGS->r.eip.r_ex)
+#define R_IP (REGS->r.eip.r_w.r_x)
+#define R_EFLAGS (REGS->r.efl.r_ex)
+#define R_FLAGS (REGS->r.efl.r_w.r_x)
+#define R_EES (REGS->r.es.r_ex)
+#define R_ES (REGS->r.es.r_w.r_x)
+#define R_EDS (REGS->r.ds.r_ex)
+#define R_DS (REGS->r.ds.r_w.r_x)
+#define R_ECS (REGS->r.cs.r_ex)
+#define R_CS (REGS->r.cs.r_w.r_x)
+#define R_ESS (REGS->r.ss.r_ex)
+#define R_SS (REGS->r.ss.r_w.r_x)
+#define R_EDI (REGS->r.edi.r_ex)
+#define R_DI (REGS->r.edi.r_w.r_x)
+#define R_ESI (REGS->r.esi.r_ex)
+#define R_SI (REGS->r.esi.r_w.r_x)
+#define R_EBX (REGS->r.ebx.r_ex)
+#define R_BX (REGS->r.ebx.r_w.r_x)
+#define R_BL (REGS->r.ebx.r_b.r_l)
+#define R_BH (REGS->r.ebx.r_b.r_h)
+#define R_EDX (REGS->r.edx.r_ex)
+#define R_DX (REGS->r.edx.r_w.r_x)
+#define R_DL (REGS->r.edx.r_b.r_l)
+#define R_DH (REGS->r.edx.r_b.r_h)
+#define R_ECX (REGS->r.ecx.r_ex)
+#define R_CX (REGS->r.ecx.r_w.r_x)
+#define R_CL (REGS->r.ecx.r_b.r_l)
+#define R_CH (REGS->r.ecx.r_b.r_h)
+#define R_EAX (REGS->r.eax.r_ex)
+#define R_AX (REGS->r.eax.r_w.r_x)
+#define R_AL (REGS->r.eax.r_b.r_l)
+#define R_AH (REGS->r.eax.r_b.r_h)
+#define R_EGS (REGS->r.gs.r_ex)
+#define R_GS (REGS->r.gs.r_w.r_x)
+#define R_EFS (REGS->r.fs.r_ex)
+#define R_FS (REGS->r.fs.r_w.r_x)
+
+#endif
+
+#ifdef __bsdi__
+#endif
+
+#ifdef __NetBSD__
+#endif
+
+/*
+** register manipulation macros
+*/
+
+#define N_PUTVEC(s, o, x) ((s) = ((x) >> 16), (o) = (x) & 0xffff)
+#define MAKEVEC(s, o) (((s) << 16) + (o)) /* XXX these two should be combined */
+#define N_GETVEC(s, o) (((s) << 16) + (o))
+
+#define N_PUTPTR(s, o, x) (((s) = ((x) & 0xf0000) >> 4), (o) = (x) & 0xffff)
+#define MAKEPTR(s, o) (((s) << 4) + (o)) /* XXX these two should be combined */
+#define N_GETPTR(s, o) (((s) << 4) + (o))
+
+#define VECPTR(x) MAKEPTR((x) >> 16, (x) & 0xffff)
+
+#if 0
+#define N_REGISTERS regcontext_t *_regcontext
+#define N_REGS _regcontex
+#endif
+
+inline static void
+N_PUSH(u_short x, regcontext_t *REGS)
+{
+ R_SP -= 2;
+ *(u_short *)N_GETPTR(R_SS, R_SP) = (x);
+}
+
+inline static u_short
+N_POP(regcontext_t *REGS)
+{
+ u_short x;
+
+ x = *(u_short *)N_GETPTR(R_SS, R_SP);
+ R_SP += 2;
+ return(x);
+}
+
+# ifndef PSL_ALLCC /* Grr, FreeBSD doesn't have this */
+# define PSL_ALLCC (PSL_C|PSL_PF|PSL_AF|PSL_Z|PSL_N)
+# endif
+
+/******************************************************************************
+** older stuff below here
+*/
+
+#define REGISTERS struct sigcontext *sc
+
+#define GET16(x) (x & 0xffff)
+#define GET8L(x) (x & 0xff)
+#define GET8H(x) ((x >> 8) & 0xff)
+#define SET16(x, y) (x = (x & ~0xffff) | (y & 0xffff))
+#define SET8L(x, y) (x = (x & ~0xff) | (y & 0xff))
+#define SET8H(x, y) (x = (x & ~0xff00) | ((y & 0xff) << 8))
+
+#define PUTVEC(s, o, x) (SET16(s, x >> 16), SET16(o, x))
+#define GETVEC(s, o) MAKEVEC(GET16(s), GET16(o))
+
+#define PUTPTR(s, o, x) (SET16(s, (x & 0xf0000) >> 4), SET16(o, x))
+#define GETPTR(s, o) MAKEPTR(GET16(s), GET16(o))
+
+#define VECPTR(x) MAKEPTR((x) >> 16, (x) & 0xffff)
+
+inline static void
+PUSH(u_short x, struct sigcontext *sc)
+{
+ SET16(sc->sc_esp, GET16(sc->sc_esp) - 2);
+ *(u_short *)GETPTR(sc->sc_ss, sc->sc_esp) = x;
+}
+
+inline static u_short
+POP(struct sigcontext *sc)
+{
+ u_short x;
+
+ x = *(u_short *)GETPTR(sc->sc_ss, sc->sc_esp);
+ SET16(sc->sc_esp, GET16(sc->sc_esp) + 2);
+ return (x);
+}
+
diff --git a/usr.bin/doscmd/setver.c b/usr.bin/doscmd/setver.c
new file mode 100644
index 0000000..2ae3518
--- /dev/null
+++ b/usr.bin/doscmd/setver.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI setver.c,v 2.2 1996/04/08 19:33:04 bostic Exp
+ *
+ * $Id: setver.c,v 1.2 1996/09/22 05:53:09 miff Exp $
+ */
+
+#include "doscmd.h"
+
+#if 1 /*XXXXX*/
+int ms_version = 622;
+#else
+int ms_version = 410;
+#endif
+
+typedef struct setver_t {
+ short version;
+ char command[14];
+ struct setver_t *next;
+} setver_t;
+
+static setver_t *setver_root;
+
+void
+setver(char *cmd, short version)
+{
+ if (cmd) {
+ setver_t *s = (setver_t *)malloc(sizeof(setver_t));
+
+ strncpy(s->command, cmd, 14);
+ s->version = version;
+ s->next = setver_root;
+ setver_root = s;
+ } else {
+ ms_version = version;
+ }
+}
+
+short
+getver(char *cmd)
+{
+ if (cmd) {
+ setver_t *s = setver_root;
+
+ while (s) {
+ if (strncasecmp(cmd, s->command, 14) == 0)
+ return(s->version);
+ s = s->next;
+ }
+ }
+ return(ms_version);
+}
diff --git a/usr.bin/doscmd/signal.c b/usr.bin/doscmd/signal.c
new file mode 100644
index 0000000..434f00f
--- /dev/null
+++ b/usr.bin/doscmd/signal.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI signal.c,v 2.2 1996/04/08 19:33:06 bostic Exp
+ *
+ * $Id: signal.c,v 1.5 1997/03/18 02:36:56 msmith Exp $
+ */
+
+#include "doscmd.h"
+
+static void (*handler[NSIG])(struct sigframe *);
+static char signal_stack[16 * 1024];
+#define PSS(w) { char s; printf(w " @ %08x\n", (signal_stack + sizeof signal_stack) - &s); }
+
+struct sigframe *saved_sigframe;
+regcontext_t *saved_regcontext;
+int saved_valid = 0;
+
+static void
+sanity_check(struct sigframe *sf)
+{
+#if 0
+ static sigset_t oset;
+ int i;
+
+ for (i = 1; i < 32; ++i) {
+ if (sigismember(&sf->sf_sc.sc_mask, i) != sigismember(&oset, i))
+ fprintf(debugf, "Signal %s %s being blocked\n",
+ sys_signame[i],
+ sigismember(&sf->sf_sc.sc_mask, i) ? "now" : "no longer");
+ }
+ oset = sf->sf_sc.sc_mask;
+#endif
+
+ if (dead)
+ fatal("attempting to return to vm86 while dead");
+}
+
+#if defined(__FreeBSD__) || defined(USE_VM86)
+static void
+generichandler(struct sigframe sf)
+{
+ if (sf.sf_sc.sc_efl & PSL_VM) {
+ saved_sigframe = &sf;
+ saved_regcontext = (regcontext_t *)&(sf.sf_sc);
+ saved_valid = 1;
+ if (handler[sf.sf_signum])
+ (*handler[sf.sf_signum])(&sf);
+ saved_valid = 0;
+ sanity_check(&sf);
+ } else {
+ if (handler[sf.sf_signum])
+ (*handler[sf.sf_signum])(&sf);
+ }
+}
+#else
+#error BSD/OS sigframe/trapframe kernel interface not currently supported.
+#endif
+
+void
+setsignal(int s, void (*h)(struct sigframe *))
+{
+ static int first = 1;
+ struct sigaction sa;
+ sigset_t set;
+
+ if (first) {
+ struct sigaltstack sstack;
+
+ sstack.ss_sp = signal_stack;
+ sstack.ss_size = sizeof signal_stack;
+ sstack.ss_flags = 0;
+ sigaltstack (&sstack, NULL);
+ first = 0;
+ }
+
+ if (s >= 0 && s < NSIG) {
+ handler[s] = h;
+
+ sa.sa_handler = (__sighandler_t *)generichandler;
+ sa.sa_mask = sigmask(SIGIO) | sigmask(SIGALRM);
+ sa.sa_flags = SA_ONSTACK;
+ sigaction(s, &sa, NULL);
+
+ sigaddset(&set, s);
+ sigprocmask(SIG_UNBLOCK, &set, 0);
+ }
+}
diff --git a/usr.bin/doscmd/timer.c b/usr.bin/doscmd/timer.c
new file mode 100644
index 0000000..afaa69f
--- /dev/null
+++ b/usr.bin/doscmd/timer.c
@@ -0,0 +1,50 @@
+/*
+** No copyright?!
+**
+** $Id: timer.c,v 1.3 1996/09/22 15:42:59 miff Exp $
+*/
+#include "doscmd.h"
+
+static void
+int08(regcontext_t *REGS)
+{
+ softint(0x1c);
+}
+
+static void
+int1c(regcontext_t *REGS)
+{
+}
+
+unsigned char timer;
+
+static u_char
+inb_timer(int port)
+{
+ return (--timer);
+}
+
+void
+timer_init(void)
+{
+ u_long vec;
+ struct itimerval itv;
+
+ vec = insert_hardint_trampoline();
+ ivec[0x08] = vec;
+ register_callback(vec, int08, "int 08");
+
+ vec = insert_softint_trampoline();
+ ivec[0x1c] = vec;
+ register_callback(vec, int1c, "int 1c");
+
+ define_input_port_handler(0x42, inb_timer);
+ define_input_port_handler(0x40, inb_timer);
+
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 54925; /* 1193182/65536 times per second */
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 54925; /* 1193182/65536 times per second */
+ if (! timer_disable)
+ setitimer(ITIMER_REAL, &itv, 0);
+}
diff --git a/usr.bin/doscmd/trace.c b/usr.bin/doscmd/trace.c
new file mode 100644
index 0000000..65a6ae3
--- /dev/null
+++ b/usr.bin/doscmd/trace.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI trace.c,v 2.2 1996/04/08 19:33:07 bostic Exp
+ *
+ * $Id: trace.c,v 1.3 1996/09/25 00:03:44 miff Exp $
+ */
+
+#include "doscmd.h"
+#include "trap.h"
+
+extern FILE *debugf;
+int tmode = 0;
+
+static u_short *saddr;
+static u_char *iaddr, ibyte;
+
+/* locals */
+static void printtrace(regcontext_t *REGS, char *buf);
+
+
+/*
+ * Before exiting to VM86 mode:
+ * 1) Always set the trap flag.
+ * 2) If this is a POPF or IRET instruction, set the trap flag in the saved
+ * flag state on the stack.
+ * On enterint from VM86 mode:
+ * 1) Restore the trap flag from our saved flag state.
+ * 2) If we just finished a POPF or IRET unstruction, patch the saved flag
+ * state on the stack.
+ */
+
+int tracetype;
+
+int
+resettrace(regcontext_t *REGS)
+{
+ if ((R_EFLAGS & PSL_VM) == 0) /* invalid unless handling a vm86 process */
+ return (0);
+
+/* XXX */ return 1;
+
+ switch (tracetype) {
+ case 1:
+ R_EFLAGS &= ~PSL_T;
+ tracetype = 0;
+ return (1);
+
+ case 2:
+ if ((u_char *)MAKEPTR(R_CS, R_IP - 1) == iaddr)
+ R_IP --;
+ *iaddr = ibyte;
+ tracetype = 0;
+ return (1);
+
+ case 3:
+ case 4:
+ R_EFLAGS &= ~PSL_T;
+ *saddr &= ~PSL_T;
+ tracetype = 0;
+ return (1);
+ }
+ return (0);
+}
+
+void
+tracetrap(regcontext_t *REGS)
+{
+ u_char *addr;
+ int n;
+ char buf[100];
+
+ if ((R_EFLAGS & PSL_VM) == 0)
+ return;
+
+ addr = (u_char *)N_GETPTR(R_CS, R_IP);
+
+ n = i386dis(R_CS, R_IP, addr, buf, 0);
+ printtrace(REGS, buf);
+
+/* XXX */
+ R_EFLAGS |= PSL_T;
+ return;
+/* XXX */
+
+
+ switch (addr[0]) {
+ case REPNZ:
+ case REPZ:
+ tracetype = 2;
+ iaddr = (u_char *)MAKEPTR(R_CS, R_IP + n);
+ break;
+ case PUSHF:
+ tracetype = 4;
+ saddr = (u_short *)MAKEPTR(R_SS, R_SP - 2);
+ break;
+ case POPF:
+ tracetype = 3;
+ saddr = (u_short *)MAKEPTR(R_SS, R_SP + 0);
+ break;
+ case IRET:
+ tracetype = 3;
+ saddr = (u_short *)MAKEPTR(R_SS, R_SP + 4);
+#if 0
+ printf("IRET: %04x %04x %04x\n",
+ ((u_short *)N_GETPTR(R_SS, R_SP))[0],
+ ((u_short *)N_GETPTR(R_SS, R_SP))[1],
+ ((u_short *)N_GETPTR(R_SS, R_SP))[2]);
+#endif
+ break;
+ case OPSIZ:
+ switch (addr[1]) {
+ case PUSHF:
+ tracetype = 4;
+ saddr = (u_short *)MAKEPTR(R_SS, R_SP - 4);
+ break;
+ case POPF:
+ tracetype = 3;
+ saddr = (u_short *)MAKEPTR(R_SS, R_SP + 0);
+ break;
+ case IRET:
+ tracetype = 3;
+ saddr = (u_short *)MAKEPTR(R_SS, R_SP + 8);
+ break;
+ default:
+ tracetype = 1;
+ break;
+ }
+ default:
+ tracetype = 1;
+ break;
+ }
+
+ switch (tracetype) {
+ case 1:
+ case 4:
+ if (R_EFLAGS & PSL_T)
+ tracetype = 0;
+ else
+ R_EFLAGS |= PSL_T;
+ break;
+ case 2:
+ if (*iaddr == TRACETRAP)
+ tracetype = 0;
+ else {
+ ibyte = *iaddr;
+ *iaddr = TRACETRAP;
+ }
+ break;
+ case 3:
+ R_EFLAGS |= PSL_T;
+ if (*saddr & PSL_T)
+ tracetype = 0;
+ else
+ *saddr |= PSL_T;
+ break;
+ }
+}
+
+inline
+showstate(long flags, long flag, char f)
+{
+ putc((flags & flag) ? f : ' ', debugf);
+}
+
+static void
+printtrace(regcontext_t *REGS, char *buf)
+{
+
+ static int first = 1;
+ u_char *addr = (u_char *)N_GETPTR(R_CS, R_IP);
+ char *bigfmt = "%04x:%04x "
+#if BIG_DEBUG
+ "%02x %02x %02x %02x %02x %02x "
+#endif
+ "%-30s "
+ "%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x ";
+
+ if (first) {
+ fprintf(debugf, "%4s:%4s "
+#if BIG_DEBUG
+ ".. .. .. .. .. .. "
+#endif
+ "%-30s "
+ "%4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n",
+ "CS", "IP", "instruction",
+ "AX", "BX", "CX", "DX",
+ "DI", "SI", "SP", "BP",
+ "SS", "DS", "ES");
+ first = 0;
+ }
+
+ fprintf(debugf, bigfmt,
+ R_CS, R_IP,
+#if BIG_DEBUG
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
+#endif
+ buf,
+ R_AX, R_BX, R_CX, R_DX, R_DI, R_SI, R_SP, R_BP, R_SS, R_DS, R_ES);
+#if 0
+ fprintf(debugf, "%04x %04x %04x %04x ",
+ ((u_short *)VECPTR(0x0D760FCA-14))[0],
+ ((u_short *)VECPTR(0x0D760FCA-14))[1],
+ ((u_short *)VECPTR(0x0D760F7A+8))[0],
+ ((u_short *)VECPTR(0x0D760F7A+8))[1]);
+#endif
+ showstate(R_EFLAGS, PSL_C, 'C');
+ showstate(R_EFLAGS, PSL_PF, 'P');
+ showstate(R_EFLAGS, PSL_AF, 'c');
+ showstate(R_EFLAGS, PSL_Z, 'Z');
+ showstate(R_EFLAGS, PSL_N, 'N');
+ showstate(R_EFLAGS, PSL_T, 'T');
+ showstate(R_EFLAGS, PSL_I, 'I');
+ showstate(R_EFLAGS, PSL_D, 'D');
+ showstate(R_EFLAGS, PSL_V, 'V');
+ showstate(R_EFLAGS, PSL_NT, 'n');
+ showstate(R_EFLAGS, PSL_RF, 'r');
+ showstate(R_EFLAGS, PSL_VM, 'v');
+ showstate(R_EFLAGS, PSL_AC, 'a');
+ showstate(R_EFLAGS, PSL_VIF, 'i');
+ showstate(R_EFLAGS, PSL_VIP, 'p');
+ putc('\n', debugf);
+}
diff --git a/usr.bin/doscmd/trap.c b/usr.bin/doscmd/trap.c
new file mode 100644
index 0000000..7f11368
--- /dev/null
+++ b/usr.bin/doscmd/trap.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI trap.c,v 2.3 1996/04/08 19:33:08 bostic Exp
+ *
+ * $Id: trap.c,v 1.10 1996/10/02 00:31:43 miff Exp $
+ */
+
+#include "doscmd.h"
+#include "trap.h"
+
+/*
+** When the emulator is very busy, it's often common for
+** SIGALRM to be missed, leading to missed screen updates.
+**
+** We update this counter every time a DOS interrupt is processed and
+** if it hits a certain threshold, force an update.
+**
+** When updates occur, the counter is zeroed.
+*/
+static int update_counter = 0;
+#define BUSY_UPDATES 2000
+
+/*
+** handle interrupts passed to us by the kernel
+*/
+void
+fake_int(regcontext_t *REGS, int intnum)
+{
+ if (R_CS == 0xF000 || (ivec[intnum] >> 16) == 0xF000) {
+ if (R_CS != 0xF000)
+ intnum = ((u_char *)VECPTR(ivec[intnum]))[1];
+ debug (D_ITRAPS|intnum, "int %02x:%02x %04x:%04x/%08x\n",
+ intnum, R_AH, R_CS, R_IP, ivec[intnum]);
+ switch (intnum) {
+ case 0x2f: /* multiplex interrupt */
+ int2f(&REGS->sc);
+ break;
+ case 0xff: /* doscmd special */
+ intff(REGS);
+ break;
+ default: /* should not get here */
+ if (vflag) dump_regs(REGS);
+ fatal("no interrupt set up for 0x%02x\n", intnum);
+ }
+ debug (D_ITRAPS|intnum, "\n");
+ return;
+ }
+
+user_int:
+ debug (D_TRAPS|intnum, "INT %02x:%02x [%04x:%04x] %04x %04x %04x %04x from %04x:%04x\n",
+ intnum, R_AH, ivec[intnum] >> 16, ivec[intnum] & 0xffff,
+ R_AX, R_BX, R_CX, R_DX, R_CS, R_IP);
+
+#if 0
+ if ((intnum == 0x13) && (*(u_char *)VECPTR(ivec[intnum]) != 0xf4)) {
+#if 1
+ char *addr; /*= (char *)VECPTR(ivec[intnum]);*/
+ int i, l, j;
+ char buf[100];
+
+ R_CS = 0x2c7;
+ R_IP = 0x14f9;
+ addr = (char *)N_GETPTR(R_CS, R_IP);
+
+ printf("\n");
+ for (i = 0; i < 100; i++) {
+ l = i386dis(R_CS, R_IP, addr, buf, 0);
+ printf("%04x:%04x %s\t;",R_CS,R_IP,buf);
+ for (j = 0; j < l; j++)
+ printf(" %02x", (u_char)addr[j]);
+ printf("\n");
+ R_IP += l;
+ addr += l;
+ }
+ exit (0);
+#else
+ tmode = 1;
+#endif
+ }
+#endif
+
+ if (intnum == 0)
+ dump_regs(REGS);
+
+ if (ivec[intnum] == 0) { /* uninitialised interrupt? */
+ if (vflag) dump_regs(REGS);
+ fatal("Call to uninitialised interrupt 0x%02x\n", intnum);
+ }
+
+ /*
+ * This is really ugly, but when DOS boots, it seems to loop
+ * for a while on INT 16:11 INT 21:3E INT 2A:82
+ * INT 21:3E is a close(), which seems like something one would
+ * not sit on for ever, so we will allow it to reset our POLL count.
+ */
+ if (intnum == 0x21 && R_AX == 0x3E)
+ reset_poll();
+
+ /* stack for and call the interrupt in vm86 space */
+ N_PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
+ N_PUSH(R_CS, REGS);
+ N_PUSH(R_IP, REGS);
+ R_EFLAGS &= ~PSL_VIF; /* disable interrupts */
+ N_PUTVEC(R_CS, R_IP, ivec[intnum]);
+}
+
+/* make this read a little more intuitively */
+#define ipadvance(c,n) SET16(c->sc_eip, GET16(c->sc_eip) + n) /* move %ip along */
+
+#ifdef USE_VM86
+/* entry from NetBSD-style vm86 */
+void
+sigurg(struct sigframe *sf)
+{
+#define sc (&sf->sf_sc)
+ int intnum;
+ u_char *addr;
+ int rep;
+ int port;
+ callback_t func;
+
+#if 0
+ printf("ivec08 = %08x\n", ivec[0x08]);
+#endif
+
+ if (tmode)
+ resettrace(sc);
+
+ switch (VM86_TYPE(sf->sf_code)) {
+ case VM86_INTx:
+ intnum = VM86_ARG(sf->sf_code);
+ switch (intnum) {
+ case 0x2f:
+ switch (GET8H(sc->sc_eax)) {
+ case 0x11:
+ debug (D_TRAPS|0x2f, "INT 2F:%04x\n", GET16(sc->sc_eax));
+ if (int2f_11(sc)) {
+ /* Skip over int 2f:11 */
+ goto out;
+ }
+ break;
+ case 0x43:
+ debug (D_TRAPS|0x2f, "INT 2F:%04x\n", GET16(sc->sc_eax));
+ if (int2f_43(sc)) {
+ /* Skip over int 2f:43 */
+ goto out;
+ }
+ break;
+ }
+ break;
+ }
+ fake_int(sc, intnum);
+ break;
+ case VM86_UNKNOWN:
+ /*XXXXX failed vector also gets here without IP adjust*/
+
+ addr = (u_char *)GETPTR(sc->sc_cs, sc->sc_eip);
+ rep = 1;
+
+ debug (D_TRAPS2, "%04x:%04x [%02x]", GET16(sc->sc_cs), GET16(sc->sc_eip), addr[0]);
+ switch (addr[0]) {
+ case TRACETRAP:
+ ipadvance(sc,1);
+ fake_int(sc, 3);
+ break;
+ case INd:
+ port = addr[1];
+ ipadvance(sc,2);
+ inb(sc, port);
+ break;
+ case OUTd:
+ port = addr[1];
+ ipadvance(sc,2);
+ outb(sc, port);
+ break;
+ case INdX:
+ port = addr[1];
+ ipadvance(sc,2);
+ inx(sc, port);
+ break;
+ case OUTdX:
+ port = addr[1];
+ ipadvance(sc,2);
+ outx(sc, port);
+ break;
+ case IN:
+ ipadvance(sc,1);
+ inb(sc, GET16(sc->sc_edx));
+ break;
+ case INX:
+ ipadvance(sc,1);
+ inx(sc, GET16(sc->sc_edx));
+ break;
+ case OUT:
+ ipadvance(sc,1);
+ outb(sc, GET16(sc->sc_edx));
+ break;
+ case OUTX:
+ ipadvance(sc,1);
+ outx(sc, GET16(sc->sc_edx));
+ break;
+ case OUTSB:
+ ipadvance(sc,1);
+ while (rep-- > 0)
+ outsb(sc, GET16(sc->sc_edx));
+ break;
+ case OUTSW:
+ ipadvance(sc,1);
+ while (rep-- > 0)
+ outsx(sc, GET16(sc->sc_edx));
+ break;
+ case INSB:
+ ipadvance(sc,1);
+ while (rep-- > 0)
+ insb(sc, GET16(sc->sc_edx));
+ break;
+ case INSW:
+ ipadvance(sc,1);
+ while (rep-- > 0)
+ insx(sc, GET16(sc->sc_edx));
+ break;
+ case LOCK:
+ debug(D_TRAPS2, "lock\n");
+ ipadvance(sc,1);
+ break;
+ case HLT: /* BIOS entry points populated with HLT */
+ func = find_callback(GETVEC(sc->sc_cs, sc->sc_eip));
+ if (func) {
+ ipadvance(sc,);
+ SET16(sc->sc_eip, GET16(sc->sc_eip) + 1);
+ func(sc);
+ break;
+ }
+ default:
+ dump_regs(sc);
+ fatal("unsupported instruction\n");
+ }
+ break;
+ default:
+ dump_regs(sc);
+ printf("code = %04x\n", sf->sf_code);
+ fatal("unrecognized vm86 trap\n");
+ }
+
+out:
+ if (tmode)
+ tracetrap(sc);
+#undef sc
+#undef ipadvance
+}
+
+#else /* USE_VM86 */
+
+/* entry from FreeBSD, BSD/OS vm86 */
+void
+sigbus(struct sigframe *sf)
+{
+ u_char *addr;
+ int tempflags,okflags;
+ int intnum;
+ int port;
+ callback_t func;
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ if (!(R_EFLAGS && PSL_VM))
+ fatal("SIGBUS in the emulator\n");
+
+ if (sf->sf_code != 0) {
+ fatal("SIGBUS code %d, trapno: %d, err: %d\n",
+ sf->sf_code, sf->sf_sc.sc_trapno, sf->sf_sc.sc_err);
+ }
+
+ addr = (u_char *)GETPTR(R_CS, R_IP);
+
+ if (tmode)
+ resettrace(REGS);
+
+ if ((R_EFLAGS & (PSL_VIP | PSL_VIF)) == (PSL_VIP | PSL_VIF)) {
+ if (n_pending < 1) {
+ fatal("Pending interrupts out of sync\n");
+ exit(1);
+ }
+ resume_interrupt();
+ goto out;
+ }
+/* printf("%p\n", addr); fflush(stdout); */
+ debug (D_TRAPS2, "%04x:%04x [%02x %02x %02x] ", R_CS, R_IP, (int)addr[0], (int)addr[1], (int)addr[2]);
+#if 0
+ if ((int)addr[0] == 0x67) {
+ int i;
+ printf("HERE\n"); fflush(stdout);
+ printf("addr: %p\n", REGS); fflush(stdout);
+ for (i = 0; i < 21 * 4; i++) {
+ printf("%d: %x\n", i, ((u_char *)REGS)[i]);
+ fflush(stdout);
+ }
+ printf("Trapno, error: %p %p\n", REGS->sc.sc_trapno, REGS->sc.sc_err);
+ fflush(stdout);
+ dump_regs(REGS);
+ }
+#endif
+
+ switch (addr[0]) { /* what was that again dear? */
+
+ case CLI:
+ debug (D_TRAPS2, "cli\n");
+ R_IP++;
+ R_EFLAGS &= ~PSL_VIP;
+ break;
+
+ case STI:
+ debug (D_TRAPS2, "sti\n");
+ R_IP++;
+ R_EFLAGS |= PSL_VIP;
+#if 0
+ if (update_counter++ > BUSY_UPDATES)
+ sigalrm(sf);
+#endif
+ break;
+
+ case PUSHF:
+ debug (D_TRAPS2, "pushf <- 0x%x\n", R_EFLAGS);
+ R_IP++;
+ N_PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
+ break;
+
+ case IRET:
+ R_IP = N_POP(REGS); /* get new cs:ip off the stack */
+ R_CS = N_POP(REGS);
+ debug (D_TRAPS2, "iret to %04x:%04x ", R_CS, R_IP);
+ /* FALLTHROUGH */ /* 'safe' flag pop operation */
+
+ case POPF:
+/* XXX */
+ fatal("popf/iret in emulator");
+
+ if (addr[0] == POPF)
+ R_IP++;
+
+ tempflags = N_POP(REGS); /* get flags from stack */
+ okflags = (PSL_ALLCC | PSL_T | PSL_D | PSL_V); /* flags we consider OK */
+ R_FLAGS = ((R_FLAGS & ~okflags) | /* keep state of non-OK flags */
+ (tempflags & okflags)); /* pop state of OK flags */
+
+ IntState = tempflags & PSL_I; /* restore pseudo PSL_I flag */
+ debug(D_TRAPS2, "popf -> 0x%x\n", R_EFLAGS);
+ break;
+
+ case TRACETRAP:
+ debug(D_TRAPS2, "ttrap\n");
+ R_IP++;
+ fake_int(REGS, 3);
+ break;
+
+ case INTn:
+ intnum = addr[1];
+ R_IP += 2; /* nobody else will do it for us */
+ switch (intnum) {
+ case 0x2f:
+ switch (R_AH) { /* function number */
+ case 0x11:
+ debug (D_TRAPS|0x2f, "INT 2F:%04x\n", R_AX);
+ if (int2f_11(REGS)) {
+ /* Skip over int 2f:11 */
+ goto out;
+ }
+ break;
+ case 0x43:
+ debug (D_TRAPS|0x2f, "INT 2F:%04x\n", R_AX);
+ if (int2f_43(REGS)) {
+ /* Skip over int 2f:43 */
+ goto out;
+ }
+ break;
+ }
+ break;
+ }
+ fake_int(REGS, intnum);
+ break;
+
+ case INd: /* XXX implement in/out */
+ R_IP += 2;
+ port = addr[1];
+ inb(REGS, port);
+ break;
+ case IN:
+ R_IP++;
+ inb(REGS,R_DX);
+ break;
+ case INX:
+ R_IP++;
+ inx(REGS,R_DX);
+ break;
+ case INdX:
+ R_IP += 2;
+ port = addr[1];
+ inx(REGS, port);
+ break;
+ case INSB:
+ R_IP++;
+ printf("(missed) INSB <- 0x%02x\n",R_DX);
+ break;
+ case INSW:
+ R_IP++;
+ printf("(missed) INSW <- 0x%02x\n",R_DX);
+ break;
+
+ case OUTd:
+ R_IP += 2;
+ port = addr[1];
+ outb(REGS, port);
+ break;
+ case OUTdX:
+ R_IP += 2;
+ port = addr[1];
+ outx(REGS, port);
+ break;
+ case OUT:
+ R_IP++;
+ outb(REGS, R_DX);
+ break;
+ case OUTX:
+ R_IP++;
+ outx(REGS, R_DX);
+ break;
+ case OUTSB:
+ R_IP++;
+ printf("(missed) OUTSB -> 0x%02x\n",R_DX);
+ break;
+ case OUTSW:
+ R_IP++;
+ printf("(missed) OUTSW -> 0x%02x\n",R_DX);
+/* tmode = 1; */
+ break;
+
+ case LOCK:
+ debug(D_TRAPS2, "lock\n");
+ R_IP++;
+ break;
+
+ case HLT: /* BIOS entry points populated with HLT */
+ func = find_callback(N_GETVEC(R_CS, R_IP));
+ if (func) {
+ R_IP++; /* pass HLT opcode */
+ func(REGS);
+/* dump_regs(REGS); */
+#if 0
+ update_counter += 5;
+ if (update_counter > BUSY_UPDATES)
+ sigalrm(sf);
+#endif
+ break;
+ }
+/* if (R_EFLAGS & PSL_VIF) { */
+ R_IP++;
+ tty_pause();
+ goto out;
+/* } */
+ /* FALLTHRU */
+
+ default:
+ dump_regs(REGS);
+ fatal("unsupported instruction\n");
+ }
+
+out:
+ if (tmode)
+ tracetrap(REGS);
+}
+#endif /* USE_VM86 */
+
+void
+sigtrace(struct sigframe *sf)
+{
+ int x;
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ if (R_EFLAGS & PSL_VM) {
+ debug(D_ALWAYS, "Currently in DOS\n");
+ dump_regs(REGS);
+ for (x = 0; x < 16; ++x)
+ debug(D_ALWAYS, " %02x", *(unsigned char *)x);
+ putc('\n', debugf);
+ } else {
+ debug(D_ALWAYS, "Currently in the emulator\n");
+ sigalrm(sf);
+ }
+}
+
+void
+sigtrap(struct sigframe *sf)
+{
+ int intnum;
+ int trapno;
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ if ((R_EFLAGS & PSL_VM) == 0) {
+ dump_regs(REGS);
+ fatal("%04x:%08x Sigtrap in protected mode\n", R_CS, R_IP);
+ }
+
+ if (tmode)
+ if (resettrace(REGS))
+ goto doh;
+
+#ifdef __FreeBSD__
+ trapno = sf->sf_code; /* XXX GROSTIC HACK ALERT */
+#else
+ trapno = sc->sc_trapno;
+#endif
+ if (trapno == T_BPTFLT)
+ intnum = 3;
+ else
+ intnum = 1;
+
+ N_PUSH((R_FLAGS & ~PSL_I) | (R_EFLAGS & PSL_VIF ? PSL_I : 0), REGS);
+ N_PUSH(R_CS, REGS);
+ N_PUSH(R_IP, REGS);
+ R_FLAGS &= ~PSL_T;
+ N_PUTVEC(R_CS, R_IP, ivec[intnum]);
+
+doh:
+ if (tmode)
+ tracetrap(REGS);
+}
+
+void
+breakpoint(struct sigframe *sf)
+{
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ if (R_EFLAGS & PSL_VM)
+ printf("doscmd ");
+ printf("breakpoint: %04x\n", *(u_short *)0x8e64);
+
+ __asm__ volatile("mov 0, %eax");
+ __asm__ volatile(".byte 0x0f"); /* MOV DR6,EAX */
+ __asm__ volatile(".byte 0x21");
+ __asm__ volatile(".byte 0x1b");
+}
+
+/*
+** periodic updates
+*/
+void
+sigalrm(struct sigframe *sf)
+{
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ if (tmode)
+ resettrace(REGS);
+
+/* debug(D_ALWAYS,"tick %d", update_counter); */
+ update_counter = 0; /* remember we've updated */
+ video_update(&REGS->sc);
+ hardint(0x08);
+/* debug(D_ALWAYS,"\n"); */
+
+ if (tmode)
+ tracetrap(REGS);
+}
+
+void
+sigill(struct sigframe *sf)
+{
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ fprintf(stderr, "Signal %d from DOS program\n", sf->sf_signum);
+ dump_regs(REGS);
+ fatal("%04x:%04x Illegal instruction\n", R_CS, R_IP);
+
+}
+
+void
+sigfpe(struct sigframe *sf)
+{
+ regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
+
+ if (R_EFLAGS & PSL_VM) {
+ fake_int(REGS, 0); /* call handler XXX rather bogus, eh? */
+ return;
+ }
+ dump_regs(REGS);
+ fatal("%04x:%04x Floating point fault in emulator.\n", R_CS, R_IP);
+}
diff --git a/usr.bin/doscmd/trap.h b/usr.bin/doscmd/trap.h
new file mode 100644
index 0000000..2aa4e9d
--- /dev/null
+++ b/usr.bin/doscmd/trap.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI trap.h,v 2.2 1996/04/08 19:33:09 bostic Exp
+ *
+ * $Id: trap.h,v 1.2 1996/09/22 05:53:11 miff Exp $
+ */
+
+#define CLI 0xfa
+#define STI 0xfb
+#define PUSHF 0x9c
+#define POPF 0x9d
+#define INTn 0xcd
+#define TRACETRAP 0xcc
+#define IRET 0xcf
+#define LOCK 0xf0
+#define HLT 0xf4
+
+#define OPSIZ 0x66
+#define REPNZ 0xf2
+#define REPZ 0xf3
+
+#define INd 0xe4
+#define INdX 0xe5
+#define OUTd 0xe6
+#define OUTdX 0xe7
+
+#define IN 0xec
+#define INX 0xed
+#define OUT 0xee
+#define OUTX 0xef
+
+#define INSB 0x6c
+#define INSW 0x6d
+#define OUTSB 0x6e
+#define OUTSW 0x6f
+
+#define IOFS 0x64
+#define IOGS 0x65
+
+#define TWOBYTE 0x0f
+#define LAR 0x02
+
+#define AC_P 0x8000 /* Present */
+#define AC_P0 0x0000 /* Priv Level 0 */
+#define AC_P1 0x2000 /* Priv Level 1 */
+#define AC_P2 0x4000 /* Priv Level 2 */
+#define AC_P3 0x6000 /* Priv Level 3 */
+#define AC_S 0x1000 /* Memory Segment */
+#define AC_RO 0x0000 /* Read Only */
+#define AC_RW 0x0200 /* Read Write */
+#define AC_RWE 0x0600 /* Read Write Expand Down */
+#define AC_EX 0x0800 /* Execute Only */
+#define AC_EXR 0x0a00 /* Execute Readable */
+#define AC_EXC 0x0c00 /* Execute Only Conforming */
+#define AC_EXRC 0x0e00 /* Execute Readable Conforming */
+#define AC_A 0x0100 /* Accessed */
diff --git a/usr.bin/doscmd/tty.c b/usr.bin/doscmd/tty.c
new file mode 100644
index 0000000..c7b78c0
--- /dev/null
+++ b/usr.bin/doscmd/tty.c
@@ -0,0 +1,2193 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI tty.c,v 2.4 1996/04/08 22:03:27 prb Exp
+ *
+ * $Id: tty.c,v 1.4 1996/09/22 15:43:00 miff Exp $
+ */
+
+#ifndef NO_X
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#endif
+
+#include <stdio.h>
+#include <termios.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#ifdef __FreeBSD__
+# include <machine/console.h>
+#else
+# ifdef __NetBSD__
+# include "machine/pccons.h"
+# else /* BSD/OS */
+# include "/sys/i386/isa/pcconsioctl.h"
+# endif
+#endif
+#include <sys/mman.h>
+#include <ctype.h>
+#include "doscmd.h"
+#include "mouse.h"
+#include "video.h"
+#include "font.h"
+
+static struct termios save = { 0 };
+static struct termios raw = { 0 };
+static int flags = 0;
+static int mode = -1;
+#define vmem ((u_short *)0xB8000)
+static int blink = 1;
+int flipdelete = 1; /* Flip meaning of delete and backspace */
+extern int capture_fd;
+static u_short break_code = 0x00;
+static u_short scan_code = 0x00;
+
+#ifndef NO_X
+static Display *dpy = 0;
+static Window win;
+static XFontStruct *font;
+static unsigned long black;
+static unsigned long white;
+static unsigned long pixels[16];
+static char *color_names[16] = {
+ "black",
+ "medium blue",
+ "olive drab",
+ "turquoise3",
+ "red1",
+ "maroon",
+ "goldenrod4",
+ "gray80",
+ "gray50",
+ "sky blue",
+ "spring green",
+ "PaleTurquoise2",
+ "pink",
+ "violet red",
+ "yellow1",
+ "white",
+};
+
+static int FW, FH, FD;
+static GC gc;
+static GC cgc;
+static int xfd;
+#endif
+
+int kbd_fd = -1;
+int kbd_read = 0;
+static int vattr = 0x0700;
+
+static int width = 80;
+static int height = 25;
+static struct termios tty_cook, tty_raw;
+
+typedef struct TextLine {
+ u_short *data;
+ u_char max_length; /* Not used, but here for future use */
+ u_char changed:1;
+} TextLine;
+static TextLine *lines;
+
+/*
+ * 0040:0050 is a list of 16 bytes, 2 for each page, which contains
+ * the column and row of each page
+ */
+#define row BIOSDATA[0x51]
+#define col BIOSDATA[0x50]
+
+u_char *VREG;
+
+inline SetVREGCur()
+{
+ int cp = row * width + col;
+ VREG[MVC_CurHigh] = cp >> 8;
+ VREG[MVC_CurLow] = cp & 0xff;
+}
+
+/*
+ * 0040:0060 contains the start and end of the cursor
+ */
+#define curs_end BIOSDATA[0x60]
+#define curs_start BIOSDATA[0x61]
+
+#define video_pate BISODATA[0x62]
+
+#define IBMFONT "vga" /* font supplied */
+
+char *xfont = 0;
+
+void video_async_event();
+void debug_event();
+int video_event();
+void tty_cooked();
+void video_update();
+unsigned char video_inb(int);
+unsigned char inb_port60(int);
+void video_outb(int, unsigned char);
+void kbd_event(int fd, REGISTERS);
+u_short read_raw_kbd(int fd, u_short *code);
+
+#define PEEKSZ 16
+
+#define K_NEXT *(u_short *)0x41a
+#define K_FREE *(u_short *)0x41c
+#define K_BUFSTARTP *(u_short *)0x480
+#define K_BUFENDP *(u_short *)0x482
+#define K_BUFSTART ((u_short *)(0x400 + *(u_short *)0x480))
+#define K_BUFEND ((u_short *)(0x400 + *(u_short *)0x482))
+
+#define K1_STATUS BIOSDATA[0x17]
+#define K1_RSHIFT 0x01
+#define K1_LSHIFT 0x02
+#define K1_SHIFT 0x03
+#define K1_CTRL 0x04
+#define K1_ALT 0x08
+#define K1_SLOCK 0x10 /* Active */
+#define K1_NLOCK 0x20 /* Active */
+#define K1_CLOCK 0x40 /* Active */
+#define K1_INSERT 0x80 /* Active */
+
+#define K2_STATUS BIOSDATA[0x18]
+#define K2_LCTRL 0x01
+#define K2_LALT 0x02
+#define K2_SYSREQ 0x04
+#define K2_PAUSE 0x08
+#define K2_SLOCK 0x10 /* Actually held down */
+#define K2_NLOCK 0x20 /* Actually held down */
+#define K2_CLOCK 0x40 /* Actually held down */
+#define K2_INSERT 0x80 /* Actually held down */
+
+#define K3_STATUS BIOSDATA[0x96]
+#define K3_E1 0x01 /* Last code read was e1 */
+#define K3_E2 0x02 /* Last code read was e2 */
+#define K3_RCTRL 0x04
+#define K3_RALT 0x08
+#define K3_ENHANCED 0x10
+#define K3_FORCENLOCK 0x20
+#define K3_TWOBYTE 0x40 /* last code was first of 2 */
+#define K3_READID 0x80 /* read ID in progress */
+
+#define K4_STATUS BIOSDATA[0x97]
+#define K4_SLOCK_LED 0x01
+#define K4_NLOCK_LED 0x02
+#define K4_CLOCK_LED 0x04
+#define K4_ACK 0x10 /* ACK recieved from keyboard */
+#define K4_RESEND 0x20 /* RESEND recieved from keyboard */
+#define K4_LED 0x40 /* LED update in progress */
+#define K4_ERROR 0x80
+
+struct VideoSavePointerTable {
+ u_short video_parameter_tabel[2];
+ u_short parameter_dynamic_save_area[2]; /* Not used */
+ u_short alphanumeric_character_set_override[2]; /* Not used */
+ u_short graphics_character_set_override[2]; /* Not used */
+ u_short secondary_save_pointer_table[2]; /* Not used */
+ u_short mbz[4];
+};
+
+struct SecondaryVideoSavePointerTable {
+ u_short length;
+ u_short display_combination_code_table[2];
+ u_short alphanumeric_character_set_override[2]; /* Not used */
+ u_short user_palette_profile_table[2]; /* Not used */
+ u_short mbz[6];
+};
+
+int KbdEmpty();
+void KbdWrite(u_short code);
+void KbdRepl(u_short code);
+u_short KbdRead();
+u_short KbdPeek();
+
+int redirect0;
+int redirect1;
+int redirect2;
+
+static void
+Failure()
+{
+ fprintf(stderr, "X Connection shutdown\n");
+ quit(1);
+}
+
+struct VideoSavePointerTable *vsp;
+struct SecondaryVideoSavePointerTable *svsp;
+
+#include "vparams.h"
+
+static void
+console_denit(void *arg)
+{
+ int fd = *(int *)arg;
+
+#ifdef __FreeBSD__
+ if (ioctl(fd, KDSKBMODE, K_XLATE))
+ perror("KDSKBMODE/K_XLATE");
+#else
+# ifdef __NetBSD__
+ if (ioctl(fd, CONSOLE_X_MODE_OFF, 0))
+ perror("CONSOLE_X_MODE_OFF");
+# else /* BSD/OS */
+ if (ioctl(fd, PCCONIOCCOOK, 0))
+ perror("PCCONIOCCOOK");
+# endif
+#endif
+ if (tcsetattr(fd, TCSANOW, &tty_cook))
+ perror("tcsetattr");
+}
+
+void
+_kbd_event(int fd, REGISTERS)
+{
+ printf("_kbd_event: fd=%d\n", fd);
+ kbd_read = 1;
+}
+
+void
+console_init()
+{
+ int fd;
+ caddr_t addr;
+
+ if ((fd = open("/dev/vga", 2)) < 0) {
+ perror("/dev/vga");
+ quit(1);
+ }
+ addr = mmap((caddr_t)0xA0000, 5 * 64 * 1024,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ fd, 0);
+ if (addr != (caddr_t)0xA0000) {
+ perror("mmap");
+ quit(1);
+ }
+
+#if 0
+ addr = mmap((caddr_t)0x100000 - 0x1000, 0x1000,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ fd, 0);
+ if (addr != (caddr_t)(0x100000 - 0x1000)) {
+ perror("mmap");
+ quit(1);
+ }
+#endif
+
+ if ((fd = open("/dev/console", 2)) < 0) {
+ perror("/dev/console");
+ quit(1);
+ }
+
+ fd = squirrel_fd(fd);
+ kbd_fd = fd;
+
+#ifdef __FreeBSD__
+ if (ioctl(fd, KDSKBMODE, K_RAW)) {
+ perror("KDSKBMODE/K_RAW");
+ quit(1);
+ }
+#else
+# ifdef __NetBSD__
+ if (ioctl(fd, CONSOLE_X_MODE_ON, 0)) {
+ perror("CONSOLE_X_MODE_ON");
+ quit(1);
+ }
+# else /* BSD/OS */
+ if (ioctl(fd, PCCONIOCRAW, 0)) {
+ perror("PCCONIOCRAW");
+ quit(1);
+ }
+# endif
+#endif
+
+ call_on_quit(console_denit, &kbd_fd);
+
+ if (fcntl(fd, F_SETFL, O_NDELAY|O_ASYNC) < 0) {
+ perror("fcntl");
+ quit(1);
+ }
+ if (tcgetattr(fd, &tty_cook)) {
+ perror("tcgetattr");
+ quit(1);
+ }
+ tty_raw = tty_cook;
+ cfmakeraw(&tty_raw);
+ if (tcsetattr(fd, TCSANOW, &tty_raw)) {
+ perror("tcsetattr");
+ quit(1);
+ }
+
+#if 0
+ _RegisterIO(0, debug_event, 0, Failure);
+ _RegisterIO(fd, kbd_event, fd, Failure);
+#endif
+ _RegisterIO(fd, _kbd_event, fd, Failure);
+}
+
+void
+video_setborder(int color)
+{
+#ifndef NO_X
+ _BlockIO();
+ XSetWindowBackground(dpy, win, pixels[color & 0xf]);
+ _UnblockIO();
+#endif
+}
+void
+video_blink(int mode)
+{
+ blink = mode;
+}
+
+static int show = 1;
+
+setgc(u_short attr)
+{
+#ifndef NO_X
+ XGCValues v;
+ if (blink && !show && (attr & 0x8000))
+ v.foreground = pixels[(attr >> 12) & 0x07];
+ else
+ v.foreground = pixels[(attr >> 8) & 0x0f];
+
+ v.background = pixels[(attr >> 12) & (blink ? 0x07 : 0x0f)];
+#if 0
+ if (v.foreground == v.background) {
+ v.foreground = pixels[15];
+ v.background = pixels[0];
+ }
+#endif
+ XChangeGC(dpy, gc, GCForeground|GCBackground, &v);
+#endif
+}
+
+void
+video_update(REGISTERS)
+{
+#ifndef NO_X
+ static int or = -1;
+ static int oc = -1;
+
+ static int icnt = 4;
+
+ static char buf[256];
+ int r, c;
+ int attr = vmem[0] & 0xff00;
+ XGCValues v;
+
+ if (kbd_read)
+ kbd_event(kbd_fd, sc);
+
+ if (--icnt == 0) {
+
+ icnt = 4;
+
+ lpt_poll(); /* Handle timeout on lpt code */
+
+ if (xmode) {
+ wakeup_poll(); /* Wake up anyone waiting on kbd poll */
+
+ show ^= 1;
+
+ setgc(attr);
+
+ for (r = 0; r < height; ++r) {
+ int cc = 0;
+
+ if (!lines[r].changed) {
+ if ((r == or || r == row) && (or != row || oc != col))
+ lines[r].changed = 1;
+ else {
+ for (c = 0; c < width; ++c) {
+ if (lines[r].data[c] != vmem[r * width + c]) {
+ lines[r].changed = 1;
+ break;
+ }
+ if (blink && lines[r].data[c] & 0x8000) {
+ lines[r].changed = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!lines[r].changed)
+ continue;
+
+ reset_poll();
+ lines[r].changed = 0;
+ memcpy(lines[r].data,
+ &vmem[r * width], sizeof(u_short) * width);
+
+ for (c = 0; c < width; ++c) {
+ int cv = vmem[r * width + c];
+ if ((cv & 0xff00) != attr) {
+ if (cc < c)
+ XDrawImageString(dpy, win, gc,
+ 2 + cc * FW,
+ 2 + (r + 1) * FH,
+ buf + cc, c - cc);
+ cc = c;
+ attr = cv & 0xff00;
+ setgc(attr);
+ }
+ buf[c] = (cv & 0xff) ? cv & 0xff : ' ';
+ }
+ if (cc < c) {
+ XDrawImageString(dpy, win, gc,
+ 2 + cc * FW,
+ 2 + (r + 1) * FH,
+ buf + cc, c - cc);
+ }
+ }
+ or = row;
+ oc = col;
+
+ if (curs_start <= curs_end && curs_end <= FH &&
+ show && row < height && col < width) {
+ int start, end;
+
+ attr = vmem[row * width + col] & 0xff00;
+ v.foreground = pixels[(attr >> 8) & 0x0f] ^
+ pixels[(attr >> 12) & (blink ? 0x07 : 0x0f)];
+ if (v.foreground) {
+ v.function = GXxor;
+ } else {
+ v.foreground = pixels[7];
+ v.function = GXcopy;
+ }
+ XChangeGC(dpy, cgc, GCForeground | GCFunction, &v);
+ start = curs_start * FH / 8;
+ end = curs_end * FH / 8;
+ XFillRectangle(dpy, win, cgc,
+ 2 + col * FW,
+ 2 + row * FH + start + FD,
+ FW, end + 1 - start);
+ }
+
+ if (mouse_status.installed && mouse_status.show) {
+ c = mouse_status.x / mouse_status.hmickey;
+ r = mouse_status.y / mouse_status.vmickey;
+
+ lines[r].changed = 1;
+ attr = vmem[r * width + c] & 0xff00;
+ v.foreground = pixels[(attr >> 8) & 0x0f] ^
+ pixels[(attr >> 12) & 0x0f];
+ if (v.foreground) {
+ v.function = GXxor;
+ } else {
+ v.foreground = pixels[7];
+ v.function = GXcopy;
+ }
+ XChangeGC(dpy, cgc, GCForeground | GCFunction, &v);
+ XFillRectangle(dpy, win, cgc,
+ 2 + c * FW,
+ 2 + r * FH + 2,
+ FW, FH);
+ }
+
+ XFlush(dpy);
+ }
+ }
+
+ if (!booting) {
+ *(u_long *)&BIOSDATA[0x6c] += 1; /* Timer ticks since midnight... */
+ while (*(u_long *)&BIOSDATA[0x6c] >= 24*60*6*182) {
+ *(u_long *)&BIOSDATA[0x6c] -= 24*60*6*182;
+ BIOSDATA[0x70]++; /* BIOSDATA[0x70] # times past mn */
+ }
+ }
+#endif
+}
+
+static u_short Ascii2Scan[] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0x000e, 0x000f, 0xffff, 0xffff, 0xffff, 0x001c, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0xffff, 0x0001, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0x0039, 0x0102, 0x0128, 0x0104, 0x0105, 0x0106, 0x0108, 0x0028,
+ 0x010a, 0x010b, 0x0109, 0x010d, 0x0033, 0x000c, 0x0034, 0x0035,
+ 0x000b, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+ 0x0009, 0x000a, 0x0127, 0x0027, 0x0133, 0x000d, 0x0134, 0x0135,
+ 0x0103, 0x011e, 0x0130, 0x012e, 0x0120, 0x0112, 0x0121, 0x0122,
+ 0x0123, 0x0117, 0x0124, 0x0125, 0x0126, 0x0132, 0x0131, 0x0118,
+ 0x0119, 0x0110, 0x0113, 0x011f, 0x0114, 0x0116, 0x012f, 0x0111,
+ 0x012d, 0x0115, 0x012c, 0x001a, 0x002b, 0x001b, 0x0107, 0x010c,
+ 0x0029, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022,
+ 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, 0x0032, 0x0031, 0x0018,
+ 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011,
+ 0x002d, 0x0015, 0x002c, 0x011a, 0x012b, 0x011b, 0x0129, 0xffff,
+};
+
+struct {
+ u_short base;
+ u_short shift;
+ u_short ctrl;
+ u_short alt;
+} ScanCodes[] = {
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 0 */
+ { 0x011b, 0x011b, 0x011b, 0xffff }, /* key 1 - Escape key */
+ { 0x0231, 0x0221, 0xffff, 0x7800 }, /* key 2 - '1' */
+ { 0x0332, 0x0340, 0x0300, 0x7900 }, /* key 3 - '2' - special handling */
+ { 0x0433, 0x0423, 0xffff, 0x7a00 }, /* key 4 - '3' */
+ { 0x0534, 0x0524, 0xffff, 0x7b00 }, /* key 5 - '4' */
+ { 0x0635, 0x0625, 0xffff, 0x7c00 }, /* key 6 - '5' */
+ { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* key 7 - '6' */
+ { 0x0837, 0x0826, 0xffff, 0x7e00 }, /* key 8 - '7' */
+ { 0x0938, 0x092a, 0xffff, 0x7f00 }, /* key 9 - '8' */
+ { 0x0a39, 0x0a28, 0xffff, 0x8000 }, /* key 10 - '9' */
+ { 0x0b30, 0x0b29, 0xffff, 0x8100 }, /* key 11 - '0' */
+ { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* key 12 - '-' */
+ { 0x0d3d, 0x0d2b, 0xffff, 0x8300 }, /* key 13 - '=' */
+ { 0x0e08, 0x0e08, 0x0e7f, 0xffff }, /* key 14 - backspace */
+ { 0x0f09, 0xffff, 0xffff, 0xffff }, /* key 15 - tab */
+ { 0x1071, 0x1051, 0x1011, 0x1000 }, /* key 16 - 'Q' */
+ { 0x1177, 0x1157, 0x1117, 0x1100 }, /* key 17 - 'W' */
+ { 0x1265, 0x1245, 0x1205, 0x1200 }, /* key 18 - 'E' */
+ { 0x1372, 0x1352, 0x1312, 0x1300 }, /* key 19 - 'R' */
+ { 0x1474, 0x1454, 0x1414, 0x1400 }, /* key 20 - 'T' */
+ { 0x1579, 0x1559, 0x1519, 0x1500 }, /* key 21 - 'Y' */
+ { 0x1675, 0x1655, 0x1615, 0x1600 }, /* key 22 - 'U' */
+ { 0x1769, 0x1749, 0x1709, 0x1700 }, /* key 23 - 'I' */
+ { 0x186f, 0x184f, 0x180f, 0x1800 }, /* key 24 - 'O' */
+ { 0x1970, 0x1950, 0x1910, 0x1900 }, /* key 25 - 'P' */
+ { 0x1a5b, 0x1a7b, 0x1a1b, 0xffff }, /* key 26 - '[' */
+ { 0x1b5d, 0x1b7d, 0x1b1d, 0xffff }, /* key 27 - ']' */
+ { 0x1c0d, 0x1c0d, 0x1c0a, 0xffff }, /* key 28 - CR */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 29 - control */
+ { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* key 30 - 'A' */
+ { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* key 31 - 'S' */
+ { 0x2064, 0x2044, 0x2004, 0x2000 }, /* key 32 - 'D' */
+ { 0x2166, 0x2146, 0x2106, 0x2100 }, /* key 33 - 'F' */
+ { 0x2267, 0x2247, 0x2207, 0x2200 }, /* key 34 - 'G' */
+ { 0x2368, 0x2348, 0x2308, 0x2300 }, /* key 35 - 'H' */
+ { 0x246a, 0x244a, 0x240a, 0x2400 }, /* key 36 - 'J' */
+ { 0x256b, 0x254b, 0x250b, 0x2500 }, /* key 37 - 'K' */
+ { 0x266c, 0x264c, 0x260c, 0x2600 }, /* key 38 - 'L' */
+ { 0x273b, 0x273a, 0xffff, 0xffff }, /* key 39 - ';' */
+ { 0x2827, 0x2822, 0xffff, 0xffff }, /* key 40 - ''' */
+ { 0x2960, 0x297e, 0xffff, 0xffff }, /* key 41 - '`' */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 42 - left shift */
+ { 0x2b5c, 0x2b7c, 0x2b1c, 0xffff }, /* key 43 - '' */
+ { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* key 44 - 'Z' */
+ { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* key 45 - 'X' */
+ { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* key 46 - 'C' */
+ { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* key 47 - 'V' */
+ { 0x3062, 0x3042, 0x3002, 0x3000 }, /* key 48 - 'B' */
+ { 0x316e, 0x314e, 0x310e, 0x3100 }, /* key 49 - 'N' */
+ { 0x326d, 0x324d, 0x320d, 0x3200 }, /* key 50 - 'M' */
+ { 0x332c, 0x333c, 0xffff, 0xffff }, /* key 51 - ',' */
+ { 0x342e, 0x343e, 0xffff, 0xffff }, /* key 52 - '.' */
+ { 0x352f, 0x353f, 0xffff, 0xffff }, /* key 53 - '/' */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 54 - right shift - */
+ { 0x372a, 0xffff, 0x3772, 0xffff }, /* key 55 - prt-scr - */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 56 - Alt - */
+ { 0x3920, 0x3920, 0x3920, 0x3920 }, /* key 57 - space bar */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 58 - caps-lock - */
+ { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* key 59 - F1 */
+ { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* key 60 - F2 */
+ { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* key 61 - F3 */
+ { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* key 62 - F4 */
+ { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* key 63 - F5 */
+ { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* key 64 - F6 */
+ { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* key 65 - F7 */
+ { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* key 66 - F8 */
+ { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* key 67 - F9 */
+ { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* key 68 - F10 */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 69 - num-lock - */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 70 - scroll-lock - */
+ { 0x4700, 0x4737, 0x7700, 0xffff }, /* key 71 - home */
+ { 0x4800, 0x4838, 0xffff, 0xffff }, /* key 72 - cursor up */
+ { 0x4900, 0x4939, 0x8400, 0xffff }, /* key 73 - page up */
+ { 0x2d00, 0x4a2d, 0xffff, 0xffff }, /* key 74 - minus sign */
+ { 0x4b00, 0x4b34, 0x7300, 0xffff }, /* key 75 - cursor left */
+ { 0xffff, 0x4c35, 0xffff, 0xffff }, /* key 76 - center key */
+ { 0x4d00, 0x4d36, 0x7400, 0xffff }, /* key 77 - cursor right */
+ { 0x2b00, 0x4e2b, 0xffff, 0xffff }, /* key 78 - plus sign */
+ { 0x4f00, 0x4f31, 0x7500, 0xffff }, /* key 79 - end */
+ { 0x5000, 0x5032, 0xffff, 0xffff }, /* key 80 - cursor down */
+ { 0x5100, 0x5133, 0x7600, 0xffff }, /* key 81 - page down */
+ { 0x5200, 0x5230, 0xffff, 0xffff }, /* key 82 - insert */
+ { 0x5300, 0x532e, 0xffff, 0xffff }, /* key 83 - delete */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 84 - sys key */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 85 */
+ { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 86 */
+ { 0x8500, 0x5787, 0x8900, 0x8b00 }, /* key 87 - F11 */
+ { 0x8600, 0x5888, 0x8a00, 0x8c00 }, /* key 88 - F12 */
+};
+
+void
+debug_event(int fd, REGISTERS)
+{
+ static char ibuf[1024];
+ static char icnt = 0;
+ static u_short ds = 0;
+ static u_short di = 0;
+ static u_short cnt = 16 * 8;
+ char *ep;
+
+ int r;
+
+ r = read(0, ibuf + icnt, sizeof(ibuf) - icnt);
+ if (r <= 0)
+ return;
+
+ icnt += r;
+
+ ibuf[icnt] = 0;
+ while (ep = strchr(ibuf, '\n')) {
+ int ac;
+ char *_av[16];
+ char **av;
+
+ *ep++ = 0;
+ ac = ParseBuffer(ibuf, av = _av, 16);
+
+ if (ac > 0) {
+ if (!strcasecmp(av[0], "dump")) {
+ if (ac > 1) {
+ char *c;
+ if (c = strchr(av[1], ':')) {
+ ds = strtol(av[1], 0, 16);
+ di = strtol(c+1, 0, 16);
+ } else
+ di = strtol(av[1], 0, 16);
+ }
+ if (ac > 2)
+ cnt = strtol(av[2], 0, 0);
+ cnt = (cnt + 0xf) & ~0xf;
+ if (cnt == 0)
+ cnt = 0x10;
+ di &= ~0xf;
+
+ for (r = 0; r < cnt; r += 0x10, di = (di + 0x10) & 0xffff) {
+ int i;
+ u_char *ap = (u_char *)(((u_long)ds << 4) + di);
+
+ printf("%04x:%04x:", ds, di);
+ for (i = 0; i < 8; ++i)
+ printf(" %02x", ap[i]);
+ printf(" ");
+ for (i = 8; i < 16; ++i)
+ printf(" %02x", ap[i]);
+ printf(": ");
+ for (i = 0; i < 8; ++i)
+ printf("%c",(ap[i] < ' ' || ap[i] > '~') ? '.' : ap[i]);
+ printf(" ");
+ for (i = 8; i < 16; ++i)
+ printf("%c",(ap[i] < ' ' || ap[i] > '~') ? '.' : ap[i]);
+ printf("\n");
+ }
+ } else if (!strcasecmp(av[0], "dis")) {
+ int r;
+ u_char *ap = (u_char *)(((u_long)ds << 4) + di);
+
+ if (ac > 1) {
+ char *c;
+ if (c = strchr(av[1], ':')) {
+ ds = strtol(av[1], 0, 16);
+ di = strtol(c+1, 0, 16);
+ } else
+ di = strtol(av[1], 0, 16);
+ }
+ if (ac > 2)
+ cnt = strtol(av[2], 0, 0);
+
+ for (r = 0; r < cnt; ++r) {
+ char buf[16];
+ int c = i386dis(ds, di, ap, buf, 0);
+ printf("%04x:%04x %s\n", ds, di, buf);
+ di += c;
+ ap += c;
+ }
+ } else if (!strcasecmp(av[0], "regs")) {
+ dump_regs(sc);
+ } else if (!strcasecmp(av[0], "force")) {
+ char *p = av[1];
+
+ while (p = *++av) {
+ while (*p) {
+ if (*p >= ' ' && *p <= '~')
+ KbdWrite(ScanCodes[Ascii2Scan[*p] & 0xff].base);
+ ++p;
+ }
+ }
+ KbdWrite(ScanCodes[28].base);
+ } else if (!strcasecmp(av[0], "bell")) {
+#ifndef NO_X
+ XBell(dpy, 0);
+ XFlush(dpy);
+#endif
+ } else {
+ fprintf(stderr, "%s: unknown command\n", av[0]);
+ }
+ }
+
+ if (ep < ibuf + icnt) {
+ char *f = ep;
+ char *t = ibuf;
+ icnt -= ep - ibuf;
+ while (icnt--)
+ *t++ = *f++;
+ } else
+ icnt = 0;
+ ibuf[icnt] = 0;
+ }
+}
+
+unsigned char
+inb_port60(int port)
+{
+ int r = break_code;
+ break_code = 0;
+ scan_code = 0xffff;
+ return(r);
+}
+
+void
+kbd_event(int fd, REGISTERS)
+{
+ kbd_read = 0;
+
+ printf("kbd_event: fd=%d\n", fd);
+ if ((break_code = read_raw_kbd(fd, &scan_code)) != 0xffff)
+ hardint(0x09);
+}
+
+void
+int09(REGISTERS)
+{
+ if (raw_kbd) {
+ if (scan_code != 0xffff) {
+ KbdWrite(scan_code);
+ break_code = 0;
+ scan_code = 0xffff;
+#if 0
+ kbd_event(kbd_fd, sc);
+#endif
+ }
+ }
+}
+
+u_short
+read_raw_kbd(int fd, u_short *code)
+{
+ unsigned char c;
+ unsigned char oldled = K4_STATUS & 0x7;
+
+ *code = 0xffff;
+
+ if (read(fd, &c, 1) == 1) {
+ if (c == 0xe0) {
+ K3_STATUS |= K3_TWOBYTE;
+ return(c);
+ }
+ switch (c) {
+ case 29: /* Control */
+ K1_STATUS |= K1_CTRL;
+ if (K3_STATUS & K3_TWOBYTE)
+ K3_STATUS |= K3_RCTRL;
+ else
+ K2_STATUS |= K2_LCTRL;
+ break;
+ case 29 | 0x80: /* Control */
+ K1_STATUS &= ~K1_CTRL;
+ if (K3_STATUS & K3_TWOBYTE)
+ K3_STATUS &= ~K3_RCTRL;
+ else
+ K2_STATUS &= ~K2_LCTRL;
+ break;
+
+ case 42: /* left shift */
+ K1_STATUS |= K1_LSHIFT;
+ break;
+ case 42 | 0x80: /* left shift */
+ K1_STATUS &= ~K1_LSHIFT;
+ break;
+
+ case 54: /* right shift */
+ K1_STATUS |= K1_RSHIFT;
+ break;
+ case 54 | 0x80: /* right shift */
+ K1_STATUS &= ~K1_RSHIFT;
+ break;
+
+ case 56: /* Alt */
+ K1_STATUS |= K1_ALT;
+ if (K3_STATUS & K3_TWOBYTE)
+ K3_STATUS |= K3_RALT;
+ else
+ K2_STATUS |= K2_LALT;
+ break;
+ case 56 | 0x80: /* Alt */
+ K1_STATUS &= ~K1_ALT;
+ if (K3_STATUS & K3_TWOBYTE)
+ K3_STATUS &= ~K3_RALT;
+ else
+ K2_STATUS &= ~K2_LALT;
+ break;
+
+ case 58: /* caps-lock */
+ K1_STATUS ^= K1_CLOCK;
+ if (K1_STATUS & K1_CLOCK)
+ K4_STATUS |= K4_CLOCK_LED;
+ else
+ K4_STATUS &= ~K4_CLOCK_LED;
+ K2_STATUS |= K2_CLOCK;
+ break;
+ case 58 | 0x80: /* caps-lock */
+ K2_STATUS &= ~K2_CLOCK;
+ break;
+
+ case 69: /* num-lock */
+ K1_STATUS ^= K1_NLOCK;
+ if (K1_STATUS & K1_NLOCK)
+ K4_STATUS |= K4_NLOCK_LED;
+ else
+ K4_STATUS &= ~K4_NLOCK_LED;
+ K2_STATUS |= K2_NLOCK;
+ break;
+ case 69 | 0x80: /* num-lock */
+ K2_STATUS &= ~K2_NLOCK;
+ break;
+
+ case 70: /* scroll-lock */
+ K1_STATUS ^= K1_SLOCK;
+ if (K1_STATUS & K1_SLOCK)
+ K4_STATUS |= K4_SLOCK_LED;
+ else
+ K4_STATUS &= ~K4_SLOCK_LED;
+ K2_STATUS |= K2_SLOCK;
+ break;
+ case 70 | 0x80: /* scroll-lock */
+ K2_STATUS &= ~K2_SLOCK;
+ break;
+
+ case 82: /* insert */
+ K1_STATUS ^= K1_INSERT;
+ K2_STATUS |= K2_INSERT;
+ break;
+ case 82 | 0x80: /* insert */
+ K2_STATUS &= ~K2_INSERT;
+ break;
+
+ }
+
+#if 0 /*XXXXX*/
+ if ((K4_STATUS & 0x07) != oldled) {
+ oldled = K4_STATUS & 0x07;
+ ioctl (fd, PCCONIOCSETLED, &oldled);
+ }
+#endif
+
+ if (c == 83 && (K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL))
+ quit(0);
+
+ if (c < 89) {
+ u_short scode;
+
+ if (K1_STATUS & K1_ALT) {
+ scode = ScanCodes[c].alt;
+ } else if (K1_STATUS & K1_CTRL) {
+ scode = ScanCodes[c].ctrl;
+ } else if (K1_STATUS & K1_SHIFT) {
+ scode = ScanCodes[c].shift;
+ } else {
+ scode = ScanCodes[c].base;
+ if (K1_STATUS & K1_CLOCK) {
+ if (islower(scode & 0xff)) {
+ scode = (scode & 0xff00) | toupper(scode & 0xff);
+ }
+ }
+ if ((K1_STATUS & K1_NLOCK) && (K3_STATUS & K3_TWOBYTE) == 0) {
+ switch (c) {
+ case 71: /* home */
+ case 72: /* cursor up */
+ case 73: /* page up */
+ case 75: /* cursor left */
+ case 76: /* center key */
+ case 77: /* cursor right */
+ case 79: /* end */
+ case 80: /* cursor down */
+ case 81: /* page down */
+ case 82: /* insert */
+ case 83: /* delete */
+ scode = ScanCodes[c].shift;
+ break;
+ }
+ }
+ }
+ *code = scode;
+ }
+ K3_STATUS &= ~K3_TWOBYTE;
+ if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
+ switch (c) {
+ case 0x13: /* R */
+ kill(getpid(), SIGALRM); /* force redraw */
+printf("FORCED REDRAW\n");
+ return(0xffff);
+ case 0x14: /* T */
+ tmode ^= 1;
+ if (!tmode)
+ resettrace(&saved_sigframe->sf_sc);
+ return(0xffff);
+ case 0x53: /* DEL */
+ quit(0);
+ }
+ }
+ return(c);
+ } else {
+ return(0xffff);
+ }
+}
+
+void
+video_async_event(int fd, regcontext_t *REGS)
+{
+#ifndef NO_X
+ int int09 = 0;
+
+ for (;;) {
+ int x;
+ fd_set fdset;
+ XEvent ev;
+ static struct timeval tv = { 0 };
+
+ /*
+ * Handle any events just sitting around...
+ */
+ XFlush(dpy);
+ while (QLength(dpy) > 0) {
+ XNextEvent(dpy, &ev);
+ int09 |= video_event(&ev);
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
+
+ x = select(FD_SETSIZE, &fdset, 0, 0, &tv);
+
+ switch (x) {
+ case -1:
+ /*
+ * Errno might be wrong, so we just select again.
+ * This could cause a problem is something really
+ * was wrong with select....
+ */
+ perror("select");
+ return;
+ case 0:
+ XFlush(dpy);
+ if (int09)
+ hardint(0x09);
+ return;
+ default:
+ if (FD_ISSET(fd, &fdset)) {
+ do {
+ XNextEvent(dpy, &ev);
+ int09 |= video_event(&ev);
+ } while (QLength(dpy));
+ }
+ break;
+ }
+ }
+#endif
+}
+
+void
+kbd_async_event(int fd, REGISTERS)
+{
+ unsigned char c;
+
+ unsigned char oldled = K4_STATUS & 0x7;
+
+ while (read(fd, &c, 1) == 1) {
+ switch (c) {
+ case 29: /* Control */
+ K1_STATUS |= K1_CTRL;
+ K2_STATUS |= K2_LCTRL;
+ break;
+ case 29 | 0x80: /* Control */
+ K1_STATUS &= ~K1_CTRL;
+ K2_STATUS &= ~K2_LCTRL;
+ break;
+
+ case 42: /* left shift */
+ K1_STATUS |= K1_LSHIFT;
+ break;
+ case 42 | 0x80: /* left shift */
+ K1_STATUS &= ~K1_LSHIFT;
+ break;
+
+ case 54: /* right shift */
+ K1_STATUS |= K1_RSHIFT;
+ break;
+ case 54 | 0x80: /* right shift */
+ K1_STATUS &= ~K1_RSHIFT;
+ break;
+
+ case 56: /* Alt */
+ K1_STATUS |= K1_ALT;
+ K2_STATUS |= K2_LALT;
+ break;
+ case 56 | 0x80: /* Alt */
+ K1_STATUS &= ~K1_ALT;
+ K2_STATUS &= ~K2_LALT;
+ break;
+
+ case 58: /* caps-lock */
+ if (K1_STATUS ^= K1_CLOCK)
+ K4_STATUS &= ~K4_CLOCK_LED;
+ else
+ K4_STATUS |= K4_CLOCK_LED;
+ K2_STATUS |= K2_CLOCK;
+ break;
+ case 58 | 0x80: /* caps-lock */
+ K2_STATUS &= ~K2_CLOCK;
+ break;
+
+ case 69: /* num-lock */
+ if (K1_STATUS ^= K1_CLOCK)
+ K4_STATUS &= ~K4_NLOCK_LED;
+ else
+ K4_STATUS |= K4_NLOCK_LED;
+ K2_STATUS |= K2_NLOCK;
+ break;
+ case 69 | 0x80: /* num-lock */
+ K2_STATUS &= ~K2_NLOCK;
+ break;
+
+ case 70: /* scroll-lock */
+ if (K1_STATUS ^= K1_SLOCK)
+ K4_STATUS &= ~K4_SLOCK_LED;
+ else
+ K4_STATUS |= K4_SLOCK_LED;
+ K2_STATUS |= K2_SLOCK;
+ break;
+ case 70 | 0x80: /* scroll-lock */
+ K2_STATUS &= ~K2_SLOCK;
+ break;
+
+ case 82: /* insert */
+ K1_STATUS ^= K1_INSERT;
+ K2_STATUS |= K2_INSERT;
+ break;
+ case 82 | 0x80: /* insert */
+ K2_STATUS &= ~K2_INSERT;
+ break;
+
+ }
+
+ }
+
+#if 0 /*XXXXX*/
+ if ((K4_STATUS & 0x07) != oldled) {
+ oldled = K4_STATUS & 0x07;
+ ioctl (fd, PCCONIOCSETLED, &oldled);
+ }
+#endif
+}
+
+#ifndef NO_X
+int
+video_event(XEvent *ev)
+{
+ switch (ev->type) {
+ case MotionNotify: {
+ XMotionEvent *me = (XMotionEvent *)ev;
+ me->x -= 2;
+ me->y -= 2;
+
+ mouse_status.x = (me->x < mouse_status.range.x)
+ ? mouse_status.range.x
+ : (me->x > mouse_status.range.w)
+ ? mouse_status.range.w : me->x;
+ mouse_status.y = (me->y < mouse_status.range.y)
+ ? mouse_status.range.y
+ : (me->y > mouse_status.range.h)
+ ? mouse_status.range.h : me->y;
+ break;
+ }
+ case ButtonRelease: {
+ XButtonEvent *be = (XButtonEvent *)ev;
+ be->x -= 2;
+ be->y -= 2;
+
+ if (be->button < 3)
+ mouse_status.ups[be->button]++;
+
+ mouse_status.x = (be->x < mouse_status.range.x)
+ ? mouse_status.range.x
+ : (be->x > mouse_status.range.w)
+ ? mouse_status.range.w : be->x;
+ mouse_status.y = (be->y < mouse_status.range.y)
+ ? mouse_status.range.y
+ : (be->y > mouse_status.range.h)
+ ? mouse_status.range.h : be->y;
+ break;
+ }
+ case ButtonPress: {
+ XButtonEvent *be = (XButtonEvent *)ev;
+ be->x -= 2;
+ be->y -= 2;
+
+ if (be->button < 3)
+ mouse_status.downs[be->button]++;
+
+ mouse_status.x = (be->x < mouse_status.range.x)
+ ? mouse_status.range.x
+ : (be->x > mouse_status.range.w)
+ ? mouse_status.range.w : be->x;
+ mouse_status.y = (be->y < mouse_status.range.y)
+ ? mouse_status.range.y
+ : (be->y > mouse_status.range.h)
+ ? mouse_status.range.h : be->y;
+
+ if ((K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
+ quit(0);
+ }
+ break;
+ }
+ case NoExpose:
+ break;
+ case GraphicsExpose:
+ case Expose: {
+ int r;
+ for (r = 0; r < height; ++r)
+ lines[r].changed = 1;
+ break;
+ }
+ case KeyRelease: {
+ static char buf[128];
+ KeySym ks;
+ int n;
+
+ break_code |= 0x80;
+
+ if (!(ev->xkey.state & ShiftMask)) {
+ K1_STATUS &= ~K1_LSHIFT;
+ K1_STATUS &= ~K1_RSHIFT;
+ }
+ if (!(ev->xkey.state & ControlMask)) {
+ K1_STATUS &= ~K1_CTRL;
+ K2_STATUS &= ~K2_LCTRL;
+ K3_STATUS &= ~K3_RCTRL;
+ }
+ if (!(ev->xkey.state & Mod1Mask)) {
+ K1_STATUS &= ~K1_ALT;
+ K2_STATUS &= ~K2_LALT;
+ K3_STATUS &= ~K3_RALT;
+ }
+ if (!(ev->xkey.state & LockMask)) {
+ K2_STATUS &= ~K2_CLOCK;
+ }
+
+ XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0);
+ switch (ks) {
+ case XK_Shift_L:
+ K1_STATUS &= ~K1_LSHIFT;
+ break;
+ case XK_Shift_R:
+ K1_STATUS &= ~K1_RSHIFT;
+ break;
+ case XK_Control_L:
+ K1_STATUS &= ~K1_CTRL;
+ K2_STATUS &= ~K2_LCTRL;
+ break;
+ case XK_Control_R:
+ K1_STATUS &= ~K1_CTRL;
+ K3_STATUS &= ~K3_RCTRL;
+ break;
+ case XK_Alt_L:
+ K1_STATUS &= ~K1_ALT;
+ K2_STATUS &= ~K2_LALT;
+ break;
+ case XK_Alt_R:
+ K1_STATUS &= ~K1_ALT;
+ K3_STATUS &= ~K3_RALT;
+ break;
+ case XK_Scroll_Lock:
+ K2_STATUS &= ~K2_SLOCK;
+ break;
+ case XK_Num_Lock:
+ K2_STATUS &= ~K2_NLOCK;
+ break;
+ case XK_Caps_Lock:
+ K2_STATUS &= ~K2_CLOCK;
+ break;
+ case XK_Insert:
+ K2_STATUS &= ~K2_INSERT;
+ break;
+ }
+ return(1);
+ }
+ case KeyPress: {
+ static char buf[128];
+ KeySym ks;
+ int n;
+ int nlock = 0;
+ u_short scan = 0xffff;
+
+ if (!(ev->xkey.state & ShiftMask)) {
+ K1_STATUS &= ~K1_LSHIFT;
+ K1_STATUS &= ~K1_RSHIFT;
+ }
+ if (!(ev->xkey.state & ControlMask)) {
+ K1_STATUS &= ~K1_CTRL;
+ K2_STATUS &= ~K2_LCTRL;
+ K3_STATUS &= ~K3_RCTRL;
+ }
+ if (!(ev->xkey.state & Mod1Mask)) {
+ K1_STATUS &= ~K1_ALT;
+ K2_STATUS &= ~K2_LALT;
+ K3_STATUS &= ~K3_RALT;
+ }
+ if (!(ev->xkey.state & LockMask)) {
+ K2_STATUS &= ~K2_CLOCK;
+ }
+
+ n = XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0);
+
+ switch (ks) {
+ case XK_Shift_L:
+ K1_STATUS |= K1_LSHIFT;
+ break;
+ case XK_Shift_R:
+ K1_STATUS |= K1_RSHIFT;
+ break;
+ case XK_Control_L:
+ K1_STATUS |= K1_CTRL;
+ K2_STATUS |= K2_LCTRL;
+ break;
+ case XK_Control_R:
+ K1_STATUS |= K1_CTRL;
+ K3_STATUS |= K3_RCTRL;
+ break;
+ case XK_Alt_L:
+ K1_STATUS |= K1_ALT;
+ K2_STATUS |= K2_LALT;
+ break;
+ case XK_Alt_R:
+ K1_STATUS |= K1_ALT;
+ K3_STATUS |= K3_RALT;
+ break;
+ case XK_Scroll_Lock:
+ K1_STATUS ^= K1_SLOCK;
+ K2_STATUS |= K2_SLOCK;
+ break;
+ case XK_Num_Lock:
+ K1_STATUS ^= K1_NLOCK;
+ K2_STATUS |= K2_NLOCK;
+ break;
+ case XK_Caps_Lock:
+ K1_STATUS ^= K1_CLOCK;
+ K2_STATUS |= K2_CLOCK;
+ break;
+ case XK_Insert:
+ K1_STATUS ^= K1_INSERT;
+ K2_STATUS |= K2_INSERT;
+ scan = 82;
+ goto docode;
+
+ case XK_Escape:
+ scan = 1;
+ goto docode;
+
+ case XK_Tab:
+ scan = 15;
+ goto docode;
+
+ case XK_Return:
+ case XK_KP_Enter:
+ scan = 28;
+ goto docode;
+
+ case XK_Print:
+ scan = 55;
+ goto docode;
+
+ case XK_F1:
+ case XK_F2:
+ case XK_F3:
+ case XK_F4:
+ case XK_F5:
+ case XK_F6:
+ case XK_F7:
+ case XK_F8:
+ case XK_F9:
+ case XK_F10:
+ scan = ks - XK_F1 + 59;
+ goto docode;
+
+ case XK_KP_7:
+ nlock = 1;
+ case XK_Home:
+ scan = 71;
+ goto docode;
+ case XK_KP_8:
+ nlock = 1;
+ case XK_Up:
+ scan = 72;
+ goto docode;
+ case XK_KP_9:
+ nlock = 1;
+ case XK_Prior:
+ scan = 73;
+ goto docode;
+ case XK_KP_Subtract:
+ scan = 74;
+ goto docode;
+ case XK_KP_4:
+ nlock = 1;
+ case XK_Left:
+ scan = 75;
+ goto docode;
+ case XK_KP_5:
+ nlock = 1;
+ case XK_Begin:
+ scan = 76;
+ goto docode;
+ case XK_KP_6:
+ nlock = 1;
+ case XK_Right:
+ scan = 77;
+ goto docode;
+ case XK_KP_Add:
+ scan = 78;
+ goto docode;
+ case XK_KP_1:
+ nlock = 1;
+ case XK_End:
+ scan = 79;
+ goto docode;
+ case XK_KP_2:
+ nlock = 1;
+ case XK_Down:
+ scan = 80;
+ goto docode;
+ case XK_KP_3:
+ nlock = 1;
+ case XK_Next:
+ scan = 81;
+ goto docode;
+ case XK_KP_0:
+ nlock = 1;
+ /* case XK_Insert: This is above */
+ scan = 82;
+ goto docode;
+
+ case XK_KP_Decimal:
+ nlock = 1;
+ scan = 83;
+ goto docode;
+
+ case XK_Delete:
+ scan = flipdelete ? 14 : 83;
+ goto docode;
+
+ case XK_BackSpace:
+ scan = flipdelete ? 83 : 14;
+ goto docode;
+
+ case XK_F11:
+ scan = 87;
+ goto docode;
+ case XK_F12:
+ scan = 88;
+ goto docode;
+
+
+ case XK_KP_Divide:
+ scan = Ascii2Scan['/'];
+ goto docode;
+
+ case XK_KP_Multiply:
+ scan = Ascii2Scan['*'];
+ goto docode;
+
+ default:
+ if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
+ if (ks == 'T' || ks == 't') {
+ tmode ^= 1;
+ if (!tmode)
+ resettrace(&saved_sigframe->sf_sc);
+ break;
+ }
+ if (ks == 'R' || ks == 'r') {
+ kill(getpid(), SIGALRM); /* redraw */
+ break;
+ }
+ }
+ if (ks < ' ' || ks > '~')
+ break;
+ scan = Ascii2Scan[ks];
+ docode:
+ if (nlock)
+ scan |= 0x100;
+
+ if ((scan & ~0x100) > 88) {
+ scan = 0xffff;
+ break;
+ }
+
+ if ((K1_STATUS & K1_SHIFT) || (scan & 0x100)) {
+ scan = ScanCodes[scan & 0xff].shift;
+ } else if (K1_STATUS & K1_CTRL) {
+ scan = ScanCodes[scan & 0xff].ctrl;
+ } else if (K1_STATUS & K1_ALT) {
+ scan = ScanCodes[scan & 0xff].alt;
+ } else
+ scan = ScanCodes[scan & 0xff].base;
+
+ break;
+ }
+ if (scan != 0xffff) {
+ break_code = scan >> 8;
+ KbdWrite(scan);
+ }
+ return(1);
+ }
+ default:
+ break;
+ }
+ return(0);
+}
+#endif
+
+#define R03D4 BIOSDATA[0x65]
+static u_char R03BA = 0;
+static u_char R03DA = 0;
+
+unsigned char
+video_inb(int port)
+{
+ switch(port) {
+ case CGA_Status:
+ R03DA += 1; /* Just cylce throught the values */
+ return(R03DA &= 0x0f);
+ case 0x03c2: /* Misc */
+ case 0x03cc: /* Misc */
+ return(0xc3);
+ case CVC_Data:
+ if (R03D4 < 0x10) {
+ return(VREG[R03D4]);
+ }
+ break;
+ }
+}
+
+void
+video_outb(int port, unsigned char value)
+{
+ int cp;
+
+ switch(port) {
+ case 0x03cc:
+ case 0x03c2:
+ if ((value & 0x1) == 0) /* Trying to request monochrome */
+ break;
+ return;
+ case CGA_Control:
+ if (value & 0x22) /* Trying to select graphics */
+ break;
+ return;
+ case CVC_Address:
+ R03D4 = value & 0x1f;
+ return;
+ case CVC_Data:
+ if (R03D4 > 0x0f)
+ break;
+ VREG[R03D4] = value;
+ switch (R03D4) {
+ case MVC_CurHigh:
+ cp = row * width + col;
+ cp &= 0xff;
+ cp |= (value << 8) & 0xff00;
+ row = cp / width;
+ col = cp % width;
+ break;
+ case MVC_CurLow:
+ cp = row * width + col;
+ cp &= 0xff00;
+ cp |= value & 0xff;
+ row = cp / width;
+ col = cp % width;
+ break;
+ }
+ return;
+ }
+}
+
+void
+tty_move(int r, int c)
+{
+ row = r;
+ col = c;
+ SetVREGCur();
+}
+
+void
+tty_report(int *r, int *c)
+{
+ *r = row;
+ *c = col;
+}
+
+void
+tty_flush()
+{
+ K_NEXT = K_FREE = 0;
+}
+
+void
+tty_index()
+{
+ int i;
+
+ if (row > (height - 1))
+ row = 0;
+ else if (++row >= height) {
+ row = height - 1;
+ memcpy(vmem, &vmem[width], 2 * width * (height - 1));
+ for (i = 0; i < width; ++i)
+ vmem[(height - 1) * width + i] = vattr | ' ';
+ }
+ SetVREGCur();
+}
+
+void
+tty_write(int c, int attr)
+{
+ if (attr == TTYF_REDIRECT) {
+ if (redirect1) {
+ char tc = c;
+ write(1, &c, 1);
+ return;
+ }
+ attr = -1;
+ }
+ if (capture_fd >= 0) {
+ char cc = c;
+ write(capture_fd, &cc, 1);
+ }
+ c &= 0xff;
+ switch (c) {
+ case 0x07:
+ if (xmode) {
+#ifndef NO_X
+ XBell(dpy, 0);
+#endif
+ } else
+ write(1, "\007", 1);
+ break;
+ case 0x08:
+ if (row > (height - 1) || col > width)
+ break;
+ if (col > 0)
+ --col;
+ vmem[row * width + col] &= 0xff00;
+ break;
+ case '\t':
+ if (row > (height - 1))
+ row = 0;
+ col = (col + 8) & ~0x07;
+ if (col > width) {
+ col = 0;
+ tty_index();
+ }
+ break;
+ case '\r':
+ col = 0;
+ break;
+ case '\n':
+ tty_index();
+ break;
+ default:
+ if (col >= width) {
+ col = 0;
+ tty_index();
+ }
+ if (row > (height - 1))
+ row = 0;
+ if (attr >= 0)
+ vmem[row * width + col] = attr & 0xff00;
+ else
+ vmem[row * width + col] &= 0xff00;
+ vmem[row * width + col++] |= c;
+ break;
+ }
+ SetVREGCur();
+}
+
+void
+tty_rwrite(int n, int c, int attr)
+{
+ u_char srow, scol;
+ c &= 0xff;
+
+ srow = row;
+ scol = col;
+ while (n--) {
+ if (col >= width) {
+ col = 0;
+ tty_index();
+ }
+ if (row > (height - 1))
+ row = 0;
+ if (attr >= 0)
+ vmem[row * width + col] = attr & 0xff00;
+ else
+ vmem[row * width + col] &= 0xff00;
+ vmem[row * width + col++] |= c;
+ }
+ row = srow;
+ col = scol;
+ SetVREGCur();
+}
+
+void
+tty_pause()
+{
+ sigset_t set;
+
+ sigprocmask(0, 0, &set);
+ sigdelset(&set, SIGIO);
+ sigdelset(&set, SIGALRM);
+ sigsuspend(&set);
+}
+
+static int nextchar = 0;
+
+int
+tty_read(REGISTERS, int flag)
+{
+ int r;
+
+ if (r = nextchar) {
+ nextchar = 0;
+ return(r & 0xff);
+ }
+
+ if ((flag & TTYF_REDIRECT) && redirect0) {
+ char c;
+ if (read(0, &c, 1) != 1)
+ return(-1);
+ if (c == '\n')
+ c = '\r';
+ return(c);
+ }
+
+ if (KbdEmpty()) {
+ if (flag & TTYF_BLOCK) {
+ while (KbdEmpty())
+ tty_pause();
+ } else {
+ return(-1);
+ }
+ }
+
+ r = KbdRead();
+ if ((r & 0xff) == 0)
+ nextchar = r >> 8;
+ r &= 0xff;
+ if (flag & TTYF_CTRL) {
+ if (r == 3) {
+ /*
+ * XXX - Not quite sure where we should return, maybe not
+ * all the way to the user, but...
+ */
+ if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) {
+ fake_int(sc, 0x23);
+ SET16(sc->sc_eip, GET16(sc->sc_eip) - 2);
+ return(-2);
+ }
+ }
+ }
+ if (flag & TTYF_ECHO) {
+ if ((flag & TTYF_ECHONL) && (r == '\n' || r == '\r')) {
+ tty_write('\r', -1);
+ tty_write('\n', -1);
+ } else
+ tty_write(r, -1);
+ }
+ return(r & 0xff);
+}
+
+int
+tty_peek(REGISTERS, int flag)
+{
+ int c;
+
+ if (c == nextchar)
+ return(nextchar & 0xff);
+
+ if (KbdEmpty()) {
+ if (flag & TTYF_POLL) {
+ sleep_poll();
+ if (KbdEmpty())
+ return(0);
+ } else if (flag & TTYF_BLOCK) {
+ while (KbdEmpty())
+ tty_pause();
+ } else
+ return(0);
+ }
+ c = KbdPeek();
+ if ((c & 0xff) == 3) {
+ /*
+ * XXX - Not quite sure where we should return, maybe not
+ * all the way to the user, but...
+ */
+ if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) {
+ fake_int(sc, 0x23);
+ SET16(sc->sc_eip, GET16(sc->sc_eip) - 2);
+ return(-2);
+ }
+ }
+ return(0xff);
+}
+
+int
+tty_state()
+{
+ return(K1_STATUS);
+}
+
+tty_estate()
+{
+ int state = 0;
+ if (K2_STATUS & K2_SYSREQ)
+ state |= 0x80;
+ if (K2_STATUS & K2_CLOCK)
+ state |= 0x40;
+ if (K2_STATUS & K2_NLOCK)
+ state |= 0x20;
+ if (K2_STATUS & K2_SLOCK)
+ state |= 0x10;
+ if (K3_STATUS & K3_RALT)
+ state |= 0x08;
+ if (K3_STATUS & K3_RCTRL)
+ state |= 0x04;
+ if (K2_STATUS & K2_LALT)
+ state |= 0x02;
+ if (K2_STATUS & K2_LCTRL)
+ state |= 0x01;
+ return(state);
+}
+
+inline int
+inrange(int a, int n, int x)
+{
+ return(a < n ? n : a > x ? x : a);
+}
+
+void
+tty_scroll(int sr, int sc, int er, int ec, int n, int attr)
+{
+ int i, j;
+
+ sr = inrange(sr, 0, height);
+ er = inrange(er, 0, height);
+ sc = inrange(sc, 0, width);
+ ec = inrange(ec, 0, width);
+ if (sr > er || sc > ec)
+ return;
+ ++er;
+ ++ec;
+
+ attr &= 0xff00;
+ attr |= ' ';
+
+ if (n > 0 && n < er - sr) {
+ for (j = sr; j < er - n; ) {
+ memcpy(&vmem[j * width + sc],
+ &vmem[(j + n) * width + sc],
+ sizeof(vmem[0]) * (ec - sc));
+ ++j;
+ }
+ } else
+ n = er - sr;
+ for (j = er - n; j < er; ) {
+ for (i = sc; i < ec; ++i)
+ vmem[j * width + i] = attr;
+ ++j;
+ }
+}
+
+void
+tty_rscroll(int sr, int sc, int er, int ec, int n, int attr)
+{
+ int i, j;
+
+ sr = inrange(sr, 0, height);
+ er = inrange(er, 0, height);
+ sc = inrange(sc, 0, width);
+ ec = inrange(ec, 0, width);
+ if (sr > er || sc > ec)
+ return;
+ ++er;
+ ++ec;
+
+ attr &= 0xff00;
+ attr |= ' ';
+
+ if (n > 0 && n < er - sr) {
+ for (j = er; j > sr + n; ) {
+ --j;
+ memcpy(&vmem[j * width + sc],
+ &vmem[(j - n) * width + sc],
+ sizeof(vmem[0]) * (ec - sc));
+ }
+ } else
+ n = er - sr;
+ for (j = sr + n; j > sr; ) {
+ --j;
+ for (i = sc; i < ec; ++i)
+ vmem[j * width + i] = attr;
+ }
+}
+
+int
+tty_char(int r, int c)
+{
+ if (r == -1)
+ r = row;
+ if (c == -1)
+ c = col;
+ r = inrange(r, 0, height);
+ c = inrange(c, 0, width);
+ return(vmem[r * width + c]);
+}
+
+int
+KbdEmpty()
+{
+ return(K_NEXT == K_FREE);
+}
+
+void
+KbdWrite(u_short code)
+{
+ int klen = K_BUFEND - K_BUFSTART;
+ int kf = (K_FREE + 1) % klen;
+ if (kf == K_NEXT) {
+#ifndef NO_X
+ XBell(dpy, 0);
+#endif
+ return;
+ }
+ K_BUFSTART[K_FREE] = code;
+ K_FREE = kf;
+}
+
+void
+KbdRepl(u_short code)
+{
+ K_BUFSTART[K_NEXT] = code;
+}
+
+u_short
+KbdRead()
+{
+ int klen = K_BUFEND - K_BUFSTART;
+ int kf = K_NEXT;
+ K_NEXT = (K_NEXT + 1) % klen;
+ return(K_BUFSTART[kf]);
+}
+
+u_short
+KbdPeek()
+{
+ return(K_BUFSTART[K_NEXT]);
+}
+
+void int10(REGISTERS);
+
+void
+video_init()
+{
+ u_long vec;
+#ifndef NO_X
+ XSizeHints sh;
+ XGCValues gcv;
+ XColor ccd, rgb;
+#endif
+ unsigned long mask;
+ int level;
+ int i, j;
+
+ VREG = (u_char *)malloc(32);
+
+ /*
+ * Define all known I/O port handlers
+ */
+ define_input_port_handler(0x60, inb_port60);
+
+ if (!raw_kbd) {
+ define_input_port_handler(CGA_Status, video_inb);
+ define_input_port_handler(0x03c2, video_inb);
+ define_input_port_handler(0x03cc, video_inb);
+ define_input_port_handler(CVC_Data, video_inb);
+ define_output_port_handler(CGA_Control, video_outb);
+ define_output_port_handler(0x03c2, video_outb);
+ define_output_port_handler(0x03cc, video_outb);
+ define_output_port_handler(CVC_Address, video_outb);
+ define_output_port_handler(CVC_Data, video_outb);
+ }
+
+ redirect0 = isatty(0) == 0 || !xmode ;
+ redirect1 = isatty(1) == 0 || !xmode ;
+ redirect2 = isatty(2) == 0 || !xmode ;
+
+ K_BUFSTARTP = 0x1e; /* Start of keyboard buffer */
+ K_BUFENDP = 0x3e; /* End of keyboard buffer */
+ K_NEXT = K_FREE = 0x00;
+
+ vec = insert_hardint_trampoline();
+ ivec[0x09] = vec;
+ register_callback(vec, int09, "int 09");
+
+ /*
+ * Initialize video memory with black background, white foreground
+ */
+ for (i = 0; i < height * width; ++i)
+ vmem[i] = vattr;
+
+ if (!xmode)
+ return;
+
+#ifndef NO_X
+ if (!(lines = (TextLine *)malloc(sizeof(TextLine) * height))) {
+ fprintf(stderr, "Could not allocate data structure for text lines\n");
+ quit(1);
+ }
+ for (i = 0; i < height; ++i) {
+ lines[i].max_length = width;
+ if (!(lines[i].data = (u_short *)malloc(width * sizeof(u_short)))) {
+ fprintf(stderr,
+ "Could not allocate data structure for text lines\n");
+ quit(1);
+ }
+ lines[i].changed = 1;
+ }
+
+
+ {
+ /*
+ * Arg... I can no longer change X's fd out from under it.
+ * Open up all the available fd's, leave 3 behind for X
+ * to play with, open X and then release all the other fds
+ */
+ int nfds = sysconf(_SC_OPEN_MAX);
+ int *fds = malloc(sizeof(int) * nfds);
+ i = 0;
+ if (fds)
+ for (i = 0; i < nfds && (i == 0 || fds[i-1] < 63); ++i)
+ if ((fds[i] = open("/dev/null", 0)) < 0)
+ break;
+ /*
+ * Leave 3 fds behind for X to play with
+ */
+ if (i > 0) close(fds[--i]);
+ if (i > 0) close(fds[--i]);
+ if (i > 0) close(fds[--i]);
+
+ dpy = XOpenDisplay(NULL);
+
+ while (i > 0)
+ close(fds[--i]);
+ }
+
+ if (dpy == NULL) {
+ fprintf(stderr, "Could not open display ``%s''\n",
+ XDisplayName(NULL));
+ quit(1);
+ }
+ xfd = ConnectionNumber(dpy);
+
+ _RegisterIO(xfd, video_async_event, xfd, Failure);
+ if (debug_flags & D_DEBUGIN)
+ _RegisterIO(0, debug_event, 0, Failure);
+ _BlockIO();
+
+ pixels[0] = BlackPixel(dpy, DefaultScreen(dpy));
+ pixels[15] = WhitePixel(dpy, DefaultScreen(dpy));
+ for (i = 0; i < 15; ++i) {
+ if (XAllocNamedColor(dpy,
+ DefaultColormap(dpy, DefaultScreen(dpy)),
+ color_names[i], &ccd, &rgb)) {
+ pixels[i] = ccd.pixel;
+ } else if (i < 7)
+ pixels[i] = pixels[0];
+ else
+ pixels[i] = pixels[15];
+ }
+
+ if (!xfont)
+ xfont = IBMFONT;
+
+ font = XLoadQueryFont(dpy, xfont);
+
+ if (font == NULL)
+ font = XLoadQueryFont(dpy, IBMFONT);
+
+ if (font == NULL) {
+ fprintf(stderr, "Could not open font ``%s''\n", xfont);
+ quit(1);
+ }
+
+ FW = font->max_bounds.width;
+ FH = font->max_bounds.ascent + font->max_bounds.descent;
+ FD = font->max_bounds.descent;
+
+ curs_start = 6;
+ curs_end = 7;
+
+ sh.width = FW * width + 4;
+ sh.height = FH * height + 4;
+
+ sh.width += 4;
+ sh.height += 4;
+
+ sh.min_width = sh.max_width = sh.width;
+ sh.min_height = sh.max_height = sh.height;
+
+ sh.flags = USSize | PMinSize | PMaxSize | PSize;
+
+ win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
+ sh.width, sh.height, 2, black, black);
+ if (win == NULL) {
+ fprintf(stderr, "Could not create window\n");
+ quit(1);
+ }
+
+ gcv.foreground = white;
+ gcv.background = black;
+ gcv.font = font->fid;
+
+ mask = GCForeground | GCBackground | GCFont;
+
+ gc = XCreateGC(dpy, win, mask, &gcv);
+
+ gcv.foreground = 1;
+ gcv.background = 0;
+ gcv.function = GXxor;
+ cgc = XCreateGC(dpy, win, GCForeground|GCBackground|GCFunction, &gcv);
+
+ XSetNormalHints(dpy, win, &sh);
+ if (raw_kbd) {
+ XSelectInput(dpy, win, ExposureMask | ButtonPressMask
+ | ButtonReleaseMask | PointerMotionMask );
+ } else {
+ XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask |
+ ExposureMask | ButtonPressMask
+ | ButtonReleaseMask | PointerMotionMask );
+ }
+
+ XMapWindow(dpy, win);
+ XFlush(dpy);
+
+ _UnblockIO();
+#endif
+}
+
+void
+video_bios_init()
+{
+ u_char *p;
+ u_long vec;
+
+ if (raw_kbd)
+ return;
+
+ /*
+ * Put the Video Save Pointer table @ C000:0000
+ * Put the Secondary Video Save Pointer table @ C000:0020
+ * Put the Display Combination code table @ C000:0040
+ * Put the Video Parameter table @ C000:1000 - C000:2FFF
+ * Put the default Font @ C000:3000 - C000:3FFF
+ */
+
+ *(u_long *)&BIOSDATA[0xA8] = 0xC0000000; /* 0040:00A8 points to us */
+
+ vsp = (struct VideoSavePointerTable *)0xC0000L;
+ memset(vsp, 0, sizeof(struct VideoSavePointerTable));
+ svsp = (struct SecondaryVideoSavePointerTable *)0xC0020L;
+
+ vsp->video_parameter_tabel[0] = 0x1000;
+ vsp->video_parameter_tabel[1] = 0xC000;
+
+ vsp->secondary_save_pointer_table[0] = 0x0020;
+ vsp->secondary_save_pointer_table[1] = 0xC000;
+
+ svsp->display_combination_code_table[0] = 0x0040;
+ svsp->display_combination_code_table[1] = 0xC000;
+
+ p = (u_char *)0xC0040;
+ *p++ = 2; /* Only support 2 combinations currently */
+ *p++ = 1; /* Version # */
+ *p++ = 8; /* We wont use more than type 8 */
+ *p++ = 0; /* Resereved */
+ *p++ = 0; *p++ = 0; /* No Display No Display */
+ *p++ = 0; *p++ = 8; /* No Display VGA Color */
+
+ memcpy((void *)0xC1000, videoparams, sizeof(videoparams));
+
+ ivec[0x1d] = 0xC0001000L; /* Video Parameter Table */
+ ivec[0x1e] = 0xC0003000L;
+ ivec[0x42] = ivec[0x10]; /* Copy of video interrupt */
+ memcpy((void *)0xC3000L, ascii_font, sizeof(ascii_font));
+
+ BIOSDATA[0x49] = 3; /* Video Mode */
+ *(u_short *)&BIOSDATA[0x4a] = 80; /* Columns on Screen */
+ *(u_short *)&BIOSDATA[0x4c] = 0; /* Page */
+ *(u_short *)&BIOSDATA[0x4e] = 0; /* Offset into video memory */
+ *(u_short *)&BIOSDATA[0x63] = 0x03d4; /* controller base reg */
+ BIOSDATA[0x84] = 24; /* Rows on screen */
+ *(u_short *)&BIOSDATA[0x85] = 16; /* font height */
+ BIOSDATA[0x87] = 0; /* video ram etc. */
+ BIOSDATA[0x88] = 0xf9; /* video switches */
+ BIOSDATA[0x89] = 0x11; /* video stats */
+ BIOSDATA[0x8a] = 1; /* Index into DCC table */
+ BIOSDATA[0x96] = 0x10;
+ K1_STATUS = 0;
+ K2_STATUS = 0;
+ K3_STATUS = 0;
+ K4_STATUS = 0;
+
+ vec = insert_softint_trampoline();
+ ivec[0x10] = vec;
+ register_callback(vec, int10, "int 10");
+}
diff --git a/usr.bin/doscmd/video.h b/usr.bin/doscmd/video.h
new file mode 100644
index 0000000..2ddded1
--- /dev/null
+++ b/usr.bin/doscmd/video.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI video.h,v 2.2 1996/04/08 19:33:12 bostic Exp
+ *
+ * $Id: video.h,v 1.2 1996/09/22 05:53:12 miff Exp $
+ */
+
+/*
+ * Motorola 6845 Video Controller registers
+ *
+ * They are read by
+ * OUT port,code
+ * IN port+1,res
+ *
+ * They are written by
+ * OUT port,code
+ * OUT port+1,value
+ */
+#define MVC_TotHorzChar 0x00 /* Total Horizontal Character */
+#define MVC_DispHorzChar 0x01 /* Display Horizontal Character */
+#define MVC_HorzSyncChar 0x02 /* Horizontal sync signal after ...char */
+#define MVC_HorzSyncDur 0x03 /* Duration of horizontal sync signal in char */
+#define MVC_TotVertChar 0x04 /* Total Vertical Character */
+#define MVC_AdjVertChar 0x05 /* Adjust Veritcal Character */
+#define MVC_DispVertChar 0x06 /* Display Vertical Charcter */
+#define MVC_VertSyncChar 0x07 /* Vertical sync signal after .. char */
+#define MVC_InterlaceMode 0x08 /* Interlace Mode */
+#define MVC_ScanLines 0x09 /* Number of scan lines per screen line */
+#define MVC_CurStartLine 0x0a /* Starting line of screen cursor */
+#define MVC_CurEndLine 0x0b /* Ending line of screen cursor */
+
+#define MVC_CurHigh 0x0e /* High byte of cursor position */
+#define MVC_CurLow 0x0f /* High byte of cursor position */
+
+/*
+ * Additional MDA register
+ */
+#define MDA_StartDispPageLo 0x0c /* Starting address of displayed screen page (lo byte) */
+#define MDA_StartDispPageHi 0x0d /* Starting address of displayed screen page (hi byte) */
+#define MDA_BlinkCurAddrHi 0x0e /* Character address of blinking screen cursor (hi byte) */
+#define MDA_BlinkCurAddrLo 0x0f /* Character address of blinking screen cursor (lo byte) */
+#define MDA_LightPenHi 0x10 /* Light Pen Position (hi byte) */
+#define MDA_LightPenLo 0x11 /* Light Pen Position (lo byte) */
+
+#define MDA_Control 0x03b8 /* MDA Control Register Port */
+#define MVC_Address 0x03b4 /* MVC Address Register */
+#define MVC_Data 0x03b5 /* MVC Data Register */
+#define MDA_VideoSeg 0xb800 /* Segmet address of video ram */
+
+#define CGA_Control 0x03d8 /* CGA Control Register Port */
+#define CGA_Status 0x03da /* CGA Control Register Port */
+#define CVC_Address 0x03d4 /* CVC Address Register */
+#define CVC_Data 0x03d5 /* CVC Data Register */
+
+#define CGA_Black 0x0
+#define CGA_Blue 0x1
+#define CGA_Green 0x2
+#define CGA_Cyan 0x3
+#define CGA_Red 0x4
+#define CGA_Magenta 0x5
+#define CGA_Brown 0x6
+#define CGA_LightGray 0x7
+#define CGA_DarkGray 0x8
+#define CGA_LightBlue 0x9
+#define CGA_LightGreen 0xa
+#define CGA_LightCyan 0xb
+#define CGA_LightRed 0xc
+#define CGA_LightMagenta 0xd
+#define CGA_Yellow 0xe
+#define CGA_White 0xf
+
+#define VGA_Segment 0xa000 /* Starting Segment of VGA Memory */
+#define V_int 0x10 /* interrupt for dealing with screen */
+#define V_mode 0 /* code for setting new screen mode */
+#define V_curtype 1 /* code for setting new cursor type */
+#define V_setcur 2 /* code for addressing cursor */
+#define V_readcur 3 /* code for reading cursor location */
+#define V_readlp 4 /* code for reading light pen position */
+#define V_setpage 5 /* code to select active page */
+#define V_scrollup 6 /* code to scroll screen up */
+#define V_scrolldn 7 /* code to scroll screen nown */
+#define V_readch 8 /* code to read a character from screen */
+#define V_writeach 9 /* code to write char and attributes */
+#define V_writech 10 /* code to write character only */
+#define V_setpal 11 /* code to set new setpal or border */
+#define V_wdot 12 /* code to write a dot */
+#define V_rdot 13 /* code to read a dot */
+#define V_wtty 14 /* code to write as if teletype */
+#define V_state 15 /* code to find current screen status */
+
+#define VM_40x25 0x00
+#define VM_80x25 0x02
+#define VM_320x200x4 0x04
+#define VM_640x200x2 0x06
+#define VM_80x25mono 0x07
+#define VM_320x200x16 0x0d
+#define VM_640x200x16 0x0e
+#define VM_640x350mono 0x0f
+#define VM_640x350x16 0x10
+#define VM_640x480x2 0x11
+#define VM_640x480x16 0x12
+#define VM_320x200x256 0x13
+#define VM_80x30 0x50
+#define VM_80x43 0x51
+#define VM_80x60 0x52
+#define VM_132x25 0x53
+#define VM_132x30 0x54
+#define VM_132x43 0x55
+#define VM_132x60 0x56
+#define VM_132x25h 0x57
+#define VM_132x30h 0x58
+#define VM_132x43h 0x59
+#define VM_132x60h 0x5a
+#define VM_800x600x16 0x5b
+#define VM_640x400x256 0x5c
+#define VM_640x480x256 0x5d
+#define VM_800x600x256 0x5e
+#define VM_1024x768x16 0x5f
+#define VM_1024x768x4 0x60
+#define VM_768x1024x16 0x61
+#define VM_1024x768x256 0x62
+
+#define VM_VGA VM_640x480x256
+#define VM_EVGA VM_800x600x256
+#define VM_SVGAportrait VM_768x1024x16
+#define VM_SVGA16 VM_1024x768x16
+#define VM_SVGA256 VM_1024x768x256
diff --git a/usr.bin/doscmd/vparams.h b/usr.bin/doscmd/vparams.h
new file mode 100644
index 0000000..59aee81
--- /dev/null
+++ b/usr.bin/doscmd/vparams.h
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI vparams.h,v 2.2 1996/04/08 19:33:13 bostic Exp
+ */
+
+unsigned char videoparams[][64] = {
+ { 0x28, 0x18, 0x08, 0x00, 0x08, 0x09, 0x03, 0x00,
+ 0x02, 0x63, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0,
+ 0xbf, 0x1f, 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x28, 0x18, 0x08, 0x00, 0x08, 0x09, 0x03, 0x00,
+ 0x02, 0x63, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0,
+ 0xbf, 0x1f, 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x08, 0x00, 0x10, 0x01, 0x03, 0x00,
+ 0x02, 0x63, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x08, 0x00, 0x10, 0x01, 0x03, 0x00,
+ 0x02, 0x63, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x28, 0x18, 0x08, 0x00, 0x40, 0x09, 0x03, 0x00,
+ 0x02, 0x63, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80,
+ 0xbf, 0x1f, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96,
+ 0xb9, 0xa2, 0xff, 0x00, 0x13, 0x15, 0x17, 0x02,
+ 0x04, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x01, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, 0xff,
+ },
+ { 0x28, 0x18, 0x08, 0x00, 0x40, 0x09, 0x03, 0x00,
+ 0x02, 0x63, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80,
+ 0xbf, 0x1f, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96,
+ 0xb9, 0xa2, 0xff, 0x00, 0x13, 0x15, 0x17, 0x02,
+ 0x04, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x01, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x08, 0x00, 0x40, 0x01, 0x01, 0x00,
+ 0x06, 0x63, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96,
+ 0xb9, 0xc2, 0xff, 0x00, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x17, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x03, 0xa6, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63,
+ 0xba, 0xa3, 0xff, 0x00, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x10, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x0e, 0x00, 0x0f, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x10, 0x00, 0x10, 0x01, 0x03, 0x00,
+ 0x02, 0x62, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x10, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x0a, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0xff,
+ },
+ { 0x28, 0x18, 0x10, 0x00, 0x08, 0x09, 0x03, 0x00,
+ 0x02, 0x63, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x10, 0x00, 0x10, 0x01, 0x03, 0x00,
+ 0x02, 0x63, 0x60, 0x4f, 0x50, 0x82, 0x56, 0x82,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0f, 0x00,
+ 0x06, 0x62, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
+ 0xb9, 0xe3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x08, 0x05, 0x0f, 0xff,
+ },
+ { 0x50, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0f, 0x00,
+ 0x06, 0x63, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
+ 0xb9, 0xe3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x08, 0x05, 0x0f, 0xff,
+ },
+ { 0x28, 0x18, 0x08, 0x00, 0x20, 0x09, 0x0f, 0x00,
+ 0x06, 0x63, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80,
+ 0xbf, 0x1f, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96,
+ 0xb9, 0xe3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff,
+ },
+ { 0x50, 0x18, 0x08, 0x00, 0x40, 0x01, 0x0f, 0x00,
+ 0x06, 0x63, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96,
+ 0xb9, 0xe3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x80, 0x01, 0x0f, 0x00,
+ 0x06, 0xa2, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63,
+ 0xba, 0xe3, 0xff, 0x00, 0x08, 0x00, 0x00, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x80, 0x01, 0x0f, 0x00,
+ 0x06, 0xa3, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63,
+ 0xba, 0xe3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x80, 0x01, 0x0f, 0x00,
+ 0x06, 0xa2, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63,
+ 0xba, 0xe3, 0xff, 0x00, 0x08, 0x00, 0x00, 0x18,
+ 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x0b, 0x00, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x80, 0x01, 0x0f, 0x00,
+ 0x06, 0xa3, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63,
+ 0xba, 0xe3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff,
+ },
+ { 0x28, 0x18, 0x0e, 0x00, 0x08, 0x09, 0x03, 0x00,
+ 0x02, 0xa3, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0,
+ 0xbf, 0x1f, 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63,
+ 0xba, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x28, 0x18, 0x0e, 0x00, 0x08, 0x09, 0x03, 0x00,
+ 0x02, 0xa3, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0,
+ 0xbf, 0x1f, 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63,
+ 0xba, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x10, 0x01, 0x03, 0x00,
+ 0x02, 0xa3, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63,
+ 0xba, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x0e, 0x00, 0x10, 0x01, 0x03, 0x00,
+ 0x02, 0xa3, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00,
+ 0x00, 0x00, 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63,
+ 0xba, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x28, 0x18, 0x10, 0x00, 0x08, 0x08, 0x03, 0x00,
+ 0x02, 0x67, 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x10, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x02, 0x67, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x50, 0x18, 0x10, 0x00, 0x10, 0x00, 0x03, 0x00,
+ 0x02, 0x66, 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x10, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x0e, 0x00, 0x0f, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0xff,
+ },
+ { 0x50, 0x1d, 0x10, 0x00, 0xa0, 0x01, 0x0f, 0x00,
+ 0x06, 0xe3, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0x0b, 0x3e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7,
+ 0x04, 0xc3, 0xff, 0x00, 0x3f, 0x3f, 0x3f, 0x3f,
+ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
+ 0x3f, 0x3f, 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0xff,
+ },
+ { 0x50, 0x1d, 0x10, 0x00, 0xa0, 0x01, 0x0f, 0x00,
+ 0x06, 0xe3, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0x0b, 0x3e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7,
+ 0x04, 0xe3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x01, 0x00, 0x0f, 0x00, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff,
+ },
+ { 0x28, 0x18, 0x08, 0x00, 0x20, 0x01, 0x0f, 0x00,
+ 0x0e, 0x63, 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80,
+ 0xbf, 0x1f, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x41, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff,
+ },
+ { 0x50, 0x1d, 0x10, 0x00, 0x20, 0x01, 0x03, 0x00,
+ 0x02, 0xe3, 0x5f, 0x4f, 0x50, 0x82, 0x57, 0x82,
+ 0x08, 0x3e, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xea, 0x8f, 0xdf, 0x28, 0x00, 0xe7,
+ 0x04, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+ { 0x84, 0x18, 0x10, 0x00, 0x20, 0x01, 0x03, 0x00,
+ 0x42, 0x62, 0x9b, 0x83, 0x86, 0x9e, 0x8a, 0x1b,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x42, 0x0f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x08, 0x08, 0x08, 0x08,
+ 0x08, 0x08, 0x08, 0x10, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x0a, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0xff,
+ },
+ { 0x84, 0x18, 0x10, 0x00, 0x20, 0x01, 0x03, 0x00,
+ 0x42, 0x63, 0x9b, 0x83, 0x86, 0x9e, 0x8a, 0x1b,
+ 0xbf, 0x1f, 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x8e, 0x8f, 0x42, 0x0f, 0x96,
+ 0xb9, 0xa3, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 0x3c,
+ 0x3d, 0x3e, 0x3f, 0x08, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
+ },
+};
diff --git a/usr.bin/doscmd/xms.c b/usr.bin/doscmd/xms.c
new file mode 100644
index 0000000..c1524de
--- /dev/null
+++ b/usr.bin/doscmd/xms.c
@@ -0,0 +1,65 @@
+/*
+** No copyright?!
+**
+** $Id: xms.c,v 1.3 1996/09/22 15:43:01 miff Exp $
+*/
+#include "doscmd.h"
+
+u_long xms_vector;
+
+int
+int2f_43(regcontext_t *REGS)
+{
+
+ switch (R_AL) {
+ case 0x00: /* installation check */
+ R_AL = 0x80;
+ break;
+
+ case 0x10: /* get handler address */
+ N_PUTVEC(R_ES, R_BX, xms_vector);
+ break;
+
+ default:
+ return (0);
+ }
+ return (1);
+}
+
+/*
+** XXX DANGER WILL ROBINSON!
+*/
+static void
+xms_entry(regcontext_t *REGS)
+{
+ switch (R_AH) {
+ case 0x00: /* get version number */
+ R_AX = 0x0300; /* 3.0 */
+ R_BX = 0x0001; /* internal revision 0.1 */
+ R_DX = 0x0001; /* HMA exists */
+ break;
+
+ default:
+ debug(D_ALWAYS, "XMS %02x\n", R_AH);
+ R_AX = 0;
+ break;
+ }
+}
+
+static u_char xms_trampoline[] = {
+ 0xeb, /* JMP 5 */
+ 0x03,
+ 0x90, /* NOP */
+ 0x90, /* NOP */
+ 0x90, /* NOP */
+ 0xf4, /* HLT */
+ 0xcb, /* RETF */
+};
+
+void
+xms_init(void)
+{
+ xms_vector = insert_generic_trampoline(
+ sizeof(xms_trampoline), xms_trampoline);
+ register_callback(xms_vector + 5, xms_entry, "xms");
+}
OpenPOWER on IntegriCloud