diff options
author | dyson <dyson@FreeBSD.org> | 1997-08-09 01:43:15 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1997-08-09 01:43:15 +0000 |
commit | 305573cb2990c5d329d149cef5a3b5533b1e8fd9 (patch) | |
tree | df06304b637358dbe8a006fdb7a6ea5955fee179 /usr.bin/doscmd | |
parent | dede28832bba6a9de7a428ff58df92439bddbc9c (diff) | |
download | FreeBSD-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')
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(®S->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(®S->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(®S->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(®S->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(®S->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(®S->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 *)≻ + 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(®S->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(®S->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"); +} |