summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjlemon <jlemon@FreeBSD.org>1997-09-30 22:04:06 +0000
committerjlemon <jlemon@FreeBSD.org>1997-09-30 22:04:06 +0000
commitd41bb2bc87f29068e4d03f319a4989911f2cd73c (patch)
tree648a56a6242ed5ba9d08e736053edb3c7c0a6194
parent0f45f2fb69fa51d32a49bcda72f6de056fdf4b0a (diff)
downloadFreeBSD-src-d41bb2bc87f29068e4d03f319a4989911f2cd73c.zip
FreeBSD-src-d41bb2bc87f29068e4d03f319a4989911f2cd73c.tar.gz
Add support for EMS emulation to doscmd. This requires changing the
interface for callbacks to doscmd from DOS, obsoleting the instbsdi redirector. (redir.com replaces it) A temporary hack is in place so the instbsdi program will (hopefully) work in the short term. Submitted by: Helmut F. Wirth <hfwirth@ping.at>
-rw-r--r--usr.bin/doscmd/Makefile22
-rw-r--r--usr.bin/doscmd/Makefile.dos47
-rw-r--r--usr.bin/doscmd/README.booting_dos20
-rw-r--r--usr.bin/doscmd/doscmd.119
-rw-r--r--usr.bin/doscmd/doscmd.c7
-rw-r--r--usr.bin/doscmd/doscmd.h11
-rw-r--r--usr.bin/doscmd/ems.c1696
-rw-r--r--usr.bin/doscmd/ems.h313
-rw-r--r--usr.bin/doscmd/emsdriv.S261
-rw-r--r--usr.bin/doscmd/emsdriv.sys.uu11
-rw-r--r--usr.bin/doscmd/emuint.c111
-rw-r--r--usr.bin/doscmd/emuint.h50
-rw-r--r--usr.bin/doscmd/instbsdi.c55
-rw-r--r--usr.bin/doscmd/instbsdi.exe.uu172
-rw-r--r--usr.bin/doscmd/intff.c10
-rw-r--r--usr.bin/doscmd/redir.S122
-rw-r--r--usr.bin/doscmd/redir.com.uu6
-rw-r--r--usr.bin/doscmd/trap.c9
-rw-r--r--usr.bin/doscmd/xms.c116
19 files changed, 2757 insertions, 301 deletions
diff --git a/usr.bin/doscmd/Makefile b/usr.bin/doscmd/Makefile
index c8754e7..1c35787 100644
--- a/usr.bin/doscmd/Makefile
+++ b/usr.bin/doscmd/Makefile
@@ -5,11 +5,12 @@
PROG= doscmd
MAN1= doscmd.1
SRCS= AsyncIO.c ParseBuffer.c bios.c callback.c cpu.c dos.c cmos.c config.c \
- cwd.c debug.c disktab.c doscmd.c exe.c i386-pinsn.c int.c int10.c \
- int13.c int14.c int16.c int17.c int1a.c int2f.c intff.c mem.c mouse.c \
- net.c port.c setver.c signal.c timer.c trace.c trap.c tty.c xms.c
+ cwd.c debug.c disktab.c doscmd.c ems.c emuint.c exe.c i386-pinsn.c \
+ int.c int10.c int13.c int14.c int16.c int17.c int1a.c int2f.c intff.c \
+ mem.c mouse.c net.c port.c setver.c signal.c timer.c trace.c trap.c \
+ tty.c xms.c
-CLEANFILES= doscmd.kernel crt0.o doscmd_loader.o instbsdi.exe
+CLEANFILES= doscmd.kernel crt0.o doscmd_loader.o redir.com emsdriv.sys
BINGRP= kmem
EXEGRP= bin
@@ -31,13 +32,18 @@ afterinstall:
install ${COPY} -o ${BINOWN} -g ${EXEGRP} -m ${EXEMODE} \
doscmd.kernel ${DESTDIR}/usr/libexec/doscmd.kernel
install -c -o ${BINOWN} -g ${EXEGRP} -m ${EXEMODE} \
- instbsdi.exe ${DESTDIR}/usr/libdata/doscmd/
+ redir.com ${DESTDIR}/usr/libdata/doscmd/
+ install -c -o ${BINOWN} -g ${EXEGRP} -m ${EXEMODE} \
+ emsdriv.sys ${DESTDIR}/usr/libdata/doscmd/
-doscmd: doscmd.kernel ${LIBCRT0} doscmd_loader.o instbsdi.exe
+doscmd: doscmd.kernel ${LIBCRT0} doscmd_loader.o redir.com emsdriv.sys
ld -e start -dc -dp -o doscmd /usr/lib/crt0.o doscmd_loader.o -lgcc -lc
-instbsdi.exe: instbsdi.exe.uu
- uudecode ${.CURDIR}/instbsdi.exe.uu
+redir.com: redir.com.uu
+ uudecode ${.CURDIR}/redir.com.uu
+
+emsdriv.sys: emsdriv.sys.uu
+ uudecode ${.CURDIR}/emsdriv.sys.uu
.include <bsd.prog.mk>
diff --git a/usr.bin/doscmd/Makefile.dos b/usr.bin/doscmd/Makefile.dos
new file mode 100644
index 0000000..5951bee
--- /dev/null
+++ b/usr.bin/doscmd/Makefile.dos
@@ -0,0 +1,47 @@
+# Special makefile for the as86/ld86 tools
+#
+# This is used only to make the dos tools. It is not used in the normal
+# build process, except one of the *.S files is changed. The ready to
+# use tools are included as uuencoded files.
+# To use this makefile you must have Bruce Evans bcc package installed
+#
+
+AS86 = as86
+LD86 = ld86
+
+OBJS = redir.o emsdriv.o
+DOSPROG = redir.com emsdriv.sys
+DOSDIST = redir.com.uu emsdriv.sys.uu
+
+all: ${DOSPROG} ${DOSDIST}
+
+redir.com: redir.o
+ $(LD86) -T 0 -s -o ${.PREFIX}.tmp ${.ALLSRC}
+ dd if=${.PREFIX}.tmp of=${.TARGET} bs=1 skip=288
+ rm -f ${.PREFIX}.tmp
+
+emsdriv.sys: emsdriv.o
+ $(LD86) -T 0 -s -o ${.PREFIX}.tmp ${.ALLSRC}
+ dd if=${.PREFIX}.tmp of=${.TARGET} bs=1 skip=32
+ rm -f ${.PREFIX}.tmp
+
+redir.com.uu: redir.com
+ uuencode redir.com redir.com > redir.com.uu
+
+emsdriv.sys.uu: emsdriv.sys
+ uuencode emsdriv.sys emsdriv.sys > emsdriv.sys.uu
+
+clean:
+ rm -f ${DOSPROG} ${OBJS}
+
+allclean:
+ rm -f ${DOSPROG} ${DOSDIST} ${OBJS}
+
+
+# Rule for as86
+.S.o:
+ $(AS86) -0 -o ${.TARGET} ${.IMPSRC}
+
+
+
+
diff --git a/usr.bin/doscmd/README.booting_dos b/usr.bin/doscmd/README.booting_dos
index 6172442..3f0098b 100644
--- a/usr.bin/doscmd/README.booting_dos
+++ b/usr.bin/doscmd/README.booting_dos
@@ -29,10 +29,10 @@ To install DOS on a pseudo hard disk under doscmd:
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
+ copy the file redir.com onto the floppy by either mounting it
with the msdos file system type or by using mtools.
- (i.e. mwrite instbsdi.exe a:)
+ (i.e. mwrite redir.com a:)
3) run doscmd.
@@ -72,18 +72,26 @@ To install DOS on a pseudo hard disk under doscmd:
^Z
> copy con: autoexec.bat
@echo off
- instbsdi.exe
+ redir.com
^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
+ 17) You now have a bootable pseudo disk which will automatically call
+ the magic "redir" program, which installs FreeBSD 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
+ Note that you will not always be able to access every file due to
naming problems.
+
+ 18) To use the new EMS memory you need to copy the file emsdriv.sys
+ to your DOS boot disk (disk image) in the same way you copied
+ redir.com. The use it in your "config.sys" from DOS:
+ device=C:\emsdriv.sys
+ where C: is your boot drive (supply the correct letter, if needed)
+ and emsdriv.sys is the driver. You could load it high. It should
+ report "Doscmd EMS 4.0 driver installed".
diff --git a/usr.bin/doscmd/doscmd.1 b/usr.bin/doscmd/doscmd.1
index c1e1ba3..76e4e31 100644
--- a/usr.bin/doscmd/doscmd.1
+++ b/usr.bin/doscmd/doscmd.1
@@ -37,7 +37,7 @@
.Nd run a subset of real-mode DOS programs
.Sh SYNOPSIS
.Nm doscmd
-.Fl 23AbDEfHIMOPRrtVvxz
+.Fl 23AbDEfHIMOPRrtVvXxYz
.Fl c Ar file
.Fl d Ar file
.Fl i Ar port Ns Xo
@@ -263,6 +263,11 @@ can be used with or without
.\"
.\"
.\"
+.It Fl Y
+Enable debugging of the EMS operations.
+.\"
+.\"
+.\"
.It Fl z
Cause
.Nm doscmd
@@ -315,7 +320,7 @@ to be assigned as the specified drive. If the
.Fl ro
flag is specified, it is a read only file system.
These assignments will not take place when booting DOS until the
-.Pa /usr/dos/instbsdi.exe
+.Pa /usr/libdata/doscmd/redir.com
binary is run.
.\"
.\"
@@ -622,10 +627,10 @@ must exist, so use the command touch to create it.
.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
+copy the file redir.com onto the floppy by either mounting it
with the msdos file system type or by using mtools
(e.g.,
-.Li mwrite instbsdi.exe a: ).
+.Li mwrite redir.com a: ).
.It 3
run doscmd.
.It 4
@@ -672,7 +677,7 @@ LASTDRIVE=Z
^Z
> copy con: autoexec.bat
@echo off
-instbsdi.exe
+redir.com
^Z
.Ed
.It 15
@@ -680,8 +685,8 @@ Quit doscmd.
.It 16
You know have a bootable pseudo disk which will automatically call
the magic
-.Li instbsdi
-program, which installs BSD/OS disks. To use
+.Li redir
+program, which installs FreeBSD disks. To use
them add lines to your .doscmdrc such as:
.Bd -literal -offset indent
assign D: /usr/dos
diff --git a/usr.bin/doscmd/doscmd.c b/usr.bin/doscmd/doscmd.c
index 295b6a4..2bfa3cf 100644
--- a/usr.bin/doscmd/doscmd.c
+++ b/usr.bin/doscmd/doscmd.c
@@ -29,7 +29,7 @@
*
* BSDI doscmd.c,v 2.3 1996/04/08 19:32:30 bostic Exp
*
- * $Id: doscmd.c,v 1.1 1997/08/09 01:42:41 dyson Exp $
+ * $Id: doscmd.c,v 1.2 1997/08/15 23:41:23 jlemon Exp $
*/
#include <sys/types.h>
@@ -489,7 +489,7 @@ do_args(int argc, char *argv[])
FILE *fp;
char *col;
- while ((c = getopt (argc, argv, "234Oc:TkCIEMPRLAU:S:HDtzvVxXfbri:o:d:")) != -1) {
+ while ((c = getopt (argc, argv, "234Oc:TkCIEMPRLAU:S:HDtzvVxXYfbri:o:d:")) != -1) {
switch (c) {
case 'd':
if (fp = fopen(optarg, "w")) {
@@ -572,6 +572,9 @@ do_args(int argc, char *argv[])
case 'X':
debug_flags |= D_XMS;
break;
+ case 'Y':
+ debug_flags |= D_EMS;
+ break;
case 'L':
debug_flags |= D_PRINTER;
break;
diff --git a/usr.bin/doscmd/doscmd.h b/usr.bin/doscmd/doscmd.h
index 27aa07f..9d420d9 100644
--- a/usr.bin/doscmd/doscmd.h
+++ b/usr.bin/doscmd/doscmd.h
@@ -29,7 +29,7 @@
*
* BSDI doscmd.h,v 2.3 1996/04/08 19:32:32 bostic Exp
*
- * $Id: doscmd.h,v 1.1 1997/08/09 01:43:09 dyson Exp $
+ * $Id: doscmd.h,v 1.2 1997/08/15 23:41:24 jlemon Exp $
*/
@@ -107,6 +107,7 @@ extern int debug_flags;
#define D_DEBUGIN 0x0400000
#define D_DOSCALL 0x0800000 /* MS-DOS function results */
#define D_XMS 0x1000000 /* XMS calls */
+#define D_EMS 0x2000000 /* EMS calls */
#define TTYF_ECHO 0x00000001
#define TTYF_ECHONL 0x00000003
@@ -179,6 +180,9 @@ extern void mem_change_owner(int addr, int owner);
extern int int2f_11(regcontext_t *REGS);
extern void intff(regcontext_t *REGS);
+/* emuint.c */
+extern void emuint(regcontext_t *REGS);
+
/* trap.c */
extern void fake_int(regcontext_t *REGS, int);
extern void sigtrap(struct sigframe *sf);
@@ -235,6 +239,11 @@ extern void get_raw_extmemory_info(regcontext_t *REGS);
extern void initHMA(void);
extern u_long xms_maxsize;
+/* ems.c */
+extern int ems_init();
+extern void ems_entry(regcontext_t *REGS);
+extern u_long ems_frame_addr;
+
/****************************** dirty below here ******************************/
extern u_long pending[]; /* pending interrupts */
diff --git a/usr.bin/doscmd/ems.c b/usr.bin/doscmd/ems.c
new file mode 100644
index 0000000..25b68db
--- /dev/null
+++ b/usr.bin/doscmd/ems.c
@@ -0,0 +1,1696 @@
+/*-
+ * Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
+ * 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 immediately at the beginning of the file, witout modification,
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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$
+ */
+
+/*
+ * EMS memory emulation
+ *
+ * To emulate Expanded Memory we use a DOS driver (emsdriv.sys) which
+ * routes calls to int 0x67 to this emulator routine. The main entry point
+ * is ems_entry(..). The emulator needs to be initialized before the first
+ * call. The first step of the initialization is done during program startup
+ * the second part is done during DOS boot, from a call of the DOS driver.
+ * The DOS driver is neccessary because DOS programs look for it to
+ * determine if EMS is available.
+ *
+ * To emulate a configurable amount of EMS memory we use a file created
+ * at startup with the size of the configured EMS memory. This file is
+ * mapped into the EMS window like any DOS memory manager would do, using
+ * mmap calls.
+ *
+ * The emulation follows the LIM EMS 4.0 standard. Not all functions of it
+ * are implemented yet. The "alter page map and jump" and "alter page map
+ * and call" functions are not implemented, because they are rather hard to
+ * do. (It would mean a call to the emulator executes a routine in EMS
+ * memory and returns to the emulator, the emulator switches the page map
+ * and then returns to the DOS program.) LINUX does not emulate this
+ * functions and I think they were very rarely used by DOS applications.
+ *
+ * Credits: To the writers of LINUX dosemu, I looked at their code
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "doscmd.h"
+#include "ems.h"
+
+/* Will be configurable */
+u_long ems_max_size = EMS_MAXSIZE * 1024;
+u_long ems_frame_addr = EMS_FRAME_ADDR;
+
+/*
+ * Method for EMS: Allocate a mapfile with the size of EMS memory
+ * and map the needed part into the page frame
+ */
+
+#define EMS_MAP_PATH "/var/tmp/" /* Use a big file system */
+#define EMS_MAP_FILE "doscmd.XXXXXX"
+static int mapfile_fd = -1;
+
+/* Pages are always 16 kB in size. The page frame is 64 kB, there are
+ * 4 positions (0..3) for a page to map in. The pages are numbered from 0 to
+ * the highest 16 kB page in the mapfile, depending on the EMS size
+ */
+
+EMS_mapping_context ems_mapping_context;
+
+/* Handle and page management (see ems.h) */
+
+/* The handle array. If the pointer is NULL, the handle is unallocated */
+static EMS_handle *ems_handle[EMS_NUM_HANDLES];
+static u_long ems_alloc_handles;
+/* The active handle, if any */
+static short active_handle;
+
+/* The page array. It is malloced at runtime, depending on the total
+ * allocation size
+ */
+
+static EMS_page *ems_page = NULL;
+static u_long ems_total_pages;
+static u_long ems_alloc_pages;
+static u_long ems_free_pages;
+
+/* Local structure used for region copy and move operations */
+
+struct copydesc {
+#define SRC_EMS 1
+#define DST_EMS 2
+ short copytype; /* Type of source and destination memory */
+ EMS_addr src_addr; /* Combined pointer for source */
+ EMS_addr dst_addr; /* Combined pointer for destination */
+ u_long rest_len; /* Lenght to copy */
+};
+
+
+/* Local prototypes */
+static int init_mapfile();
+static void map_page(u_long pagenum, u_char position, short handle,
+ int unmaponly);
+static EMS_handle *get_new_handle(long npages);
+static void context_to_handle(short handle);
+static long find_next_free_handle();
+static short lookup_handle(Hname *hp);
+static void allocate_pages_to_handle(u_short handle, long npages);
+static void allocate_handle(short handle, long npages);
+static void reallocate_pages_to_handle(u_short handle, long npages);
+static void free_handle(short handle);
+static void free_pages_of_handle(short handle);
+static void restore_context(EMS_mapping_context *emc);
+static void save_context_to_dos(EMScontext *emp);
+static int check_saved_context(EMScontext *emp);
+static void *get_valid_pointer(u_short seg, u_short offs, u_long size);
+static u_long move_ems_to_conv(short handle, u_short src_seg,
+ u_short src_offset, u_long dst_addr, u_long length);
+static u_long move_conv_to_ems(u_long src_addr, u_short dst_handle,
+ u_short dst_seg, u_short dst_offset, u_long length);
+static u_long move_ems_to_ems(u_short src_hande, u_short src_seg,
+ u_short src_offset, u_short dst_handle,
+ u_short dst_seg, u_short dst_offset, u_long length);
+
+
+/*
+ * EMS initialization routine: Return 1, if successful, return 0 if
+ * init problem or EMS disabled
+ */
+
+int
+ems_init()
+{
+ int i;
+
+ if (ems_max_size == 0)
+ return 0;
+ if (init_mapfile() == 0)
+ return 0;
+ /* Sanity */
+ bzero((void *)(&ems_handle[0]), sizeof(ems_handle));
+ ems_total_pages = ems_max_size / EMS_PAGESIZE;
+ ems_alloc_pages = 0;
+ ems_free_pages = ems_total_pages;
+ ems_alloc_handles = 0;
+ active_handle = 0;
+ /* Malloc the page array */
+ ems_page = (EMS_page *)malloc(sizeof(EMS_page) * ems_total_pages);
+ if (ems_page == NULL) {
+ debug(D_ALWAYS, "Could not malloc page array, EMS disabled\n");
+ ems_frame_addr = 0;
+ ems_max_size = 0;
+ ems_total_pages = 0;
+ return 0;
+ }
+ for (i = 0; i < ems_total_pages; i++) {
+ ems_page[i].handle = 0;
+ ems_page[i].status = EMS_FREE;
+ }
+ debug(D_EMS, "EMS: Emulation init OK.\n");
+ return 1;
+}
+
+
+/* Main entry point */
+
+void
+ems_entry(regcontext_t *REGS)
+{
+ /*
+ * If EMS is not enabled, the DOS ems.exe module should not have
+ * been loaded. If it is loaded anyway, report software malfunction
+ */
+ if (ems_max_size == 0) {
+ R_AH = EMS_SW_MALFUNC;
+ debug(D_EMS, "EMS emulation not enabled\n");
+ return;
+ }
+
+ switch (R_AH)
+ {
+ case GET_MANAGER_STATUS:
+ debug(D_EMS, "EMS: Get manager status\n");
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case GET_PAGE_FRAME_SEGMENT:
+ debug(D_EMS, "EMS: Get page frame segment\n");
+ R_BX = ems_frame_addr >> 4;
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case GET_PAGE_COUNTS:
+ R_BX = ems_total_pages - ems_alloc_pages;
+ R_DX = ems_total_pages;
+ debug(D_EMS, "EMS: Get page count: Returned total=%d, free=%d\n",
+ R_DX, R_BX);
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case GET_HANDLE_AND_ALLOCATE:
+ {
+ u_short npages;
+ short handle;
+
+ npages = R_BX;
+ debug(D_EMS, "EMS: Get handle and allocate %d pages: ", npages);
+
+ /* Enough handles? */
+ if ((handle = find_next_free_handle()) < 0) {
+ debug(D_EMS,"Return error:No handles\n");
+ R_AH = EMS_OUT_OF_HANDLES;
+ break;
+ }
+ /* Enough memory for this request ? */
+ if (npages > ems_free_pages) {
+ debug(D_EMS,"Return error:Request too big\n");
+ R_AH = EMS_OUT_OF_LOG;
+ break;
+ }
+ if (npages > ems_total_pages) {
+ debug(D_EMS,"Return error:Request too big\n");
+ R_AH = EMS_OUT_OF_PHYS;
+ break;
+ }
+ /* Not allowed to allocate zero pages with this function */
+ if (npages == 0) {
+ debug(D_EMS,"Return error:Cannot allocate 0 pages\n");
+ R_AH = EMS_ZERO_PAGES;
+ break;
+ }
+ /* Allocate the handle */
+ allocate_handle(handle, npages);
+
+ /* Allocate the pages */
+ allocate_pages_to_handle(handle, npages);
+ R_DX = handle;
+ R_AH = EMS_SUCCESS;
+ debug(D_EMS,"Return success:Handle = %d\n", handle);
+ break;
+ }
+
+ case MAP_UNMAP:
+ {
+ u_char position;
+ u_short hpagenum, spagenum;
+ short handle;
+
+ debug(D_EMS, "EMS: Map/Unmap handle=%d, pos=%d, pagenum=%d ",
+ R_DX, R_AL, R_BX);
+ handle = R_DX;
+ position = R_AL;
+ if (position > 3) {
+ debug(D_EMS, "invalid position\n");
+ R_AH = EMS_ILL_PHYS;
+ break;
+ }
+ hpagenum = R_BX;
+ /* This succeeds without a valid handle ! */
+ if (hpagenum == 0xffff) {
+ /* Unmap only */
+ map_page(0, position, handle, 1);
+ debug(D_EMS, "(unmap only) success\n");
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ if (handle > 255 || handle == 0 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ debug(D_EMS, "invalid handle\n");
+ break;
+ }
+ if (hpagenum >= ems_handle[handle]->npages) {
+ R_AH = EMS_LOGPAGE_TOOBIG;
+ debug(D_EMS, "invalid pagenumber\n");
+ break;
+ }
+ spagenum = ems_handle[handle]->pagenum[hpagenum];
+ map_page(spagenum, position, handle, 0);
+ debug(D_EMS, "success\n");
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ case DEALLOCATE_HANDLE:
+ {
+ short handle;
+
+ /* Handle valid ? */
+ handle = R_DX;
+ debug(D_EMS, "EMS: Deallocate handle %d\n", handle);
+ if (handle > 255 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ break;
+ }
+ /* Mapping context saved ? */
+ if (ems_handle[handle]->mcontext != NULL) {
+ R_AH = EMS_SAVED_MAP;
+ break;
+ }
+
+ free_pages_of_handle(handle);
+ free_handle(handle);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ case GET_EMM_VERSION:
+ debug(D_EMS, "EMS: Get version\n");
+ R_AL = EMS_VERSION;
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case SAVE_PAGE_MAP:
+ {
+ short handle;
+
+ debug(D_EMS, "EMS: Save page map\n");
+ handle = R_DX;
+ if (handle > 255 || handle == 0 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ break;
+ }
+ if (ems_handle[handle]->mcontext != NULL) {
+ /* There is already a context saved */
+ if (memcmp((void *)ems_handle[handle]->mcontext,
+ (void *)&ems_mapping_context,
+ sizeof(EMS_mapping_context)) == 0)
+ R_AH = EMS_ALREADY_SAVED;
+ else
+ R_AH = EMS_NO_ROOM_TO_SAVE;
+ break;
+ }
+ context_to_handle(handle);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ case RESTORE_PAGE_MAP:
+ {
+ short handle;
+
+ debug(D_EMS, "EMS: Restore page map\n");
+ handle = R_DX;
+ if (handle > 255 || handle == 0 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ break;
+ }
+ if (ems_handle[handle]->mcontext == NULL) {
+ R_AH = EMS_NO_SAVED_CONTEXT;
+ break;
+ }
+ restore_context(ems_handle[handle]->mcontext);
+ free((void *)ems_handle[handle]->mcontext);
+ ems_handle[handle]->mcontext = NULL;
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ case RESERVED_1:
+ case RESERVED_2:
+ debug(D_ALWAYS, "Reserved function called: %02x\n", R_AH);
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+
+ case GET_HANDLE_COUNT:
+ debug(D_EMS, "EMS: Get handle count\n");
+ R_BX = ems_alloc_handles + 1;
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case GET_PAGES_OWNED:
+ {
+ short handle;
+
+ debug(D_EMS, "EMS: Get pages owned\n");
+ /* Handle valid ? */
+ handle = R_DX;
+ if (handle > 255 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ break;
+ }
+ if (handle == 0)
+ R_BX = 0;
+ else
+ R_BX = ems_handle[handle]->npages;
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ case GET_PAGES_FOR_ALL:
+ {
+ EMShandlepage *ehp;
+ int safecount;
+ int i;
+
+ debug(D_EMS, "EMS: Get pages for all\n");
+ /* Get the address passed from DOS app */
+ ehp = (EMShandlepage *)get_valid_pointer(R_ES, R_DI,
+ sizeof(EMShandlepage) * ems_alloc_handles);
+ if (ehp == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+
+ R_BX = ems_alloc_handles;
+ safecount = 0;
+ for (i = 0; i < 255; i++) {
+ if (ems_handle[i] != NULL) {
+ if (safecount > (ems_alloc_handles+1))
+ fatal("EMS: ems_alloc_handles is wrong, cannot continue\n");
+ ehp->handle = i;
+ ehp->npages = ems_handle[i]->npages;
+ ehp++;
+ safecount++;
+ }
+ }
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ case PAGE_MAP:
+ /* This function is a nuisance. It was invented to save time and
+ * memory, but in our case it is useless. We have to support it
+ * but we use the same save memory as for the page map function.
+ * It uses only 20 bytes anyway. We store/restore the entire mapping
+ */
+ case PAGE_MAP_PARTIAL:
+ {
+ u_long addr;
+ int subfunction;
+ EMScontext *src, *dest;
+
+ debug(D_EMS, "EMS: Page map ");
+ subfunction = R_AL;
+ if (R_AH == PAGE_MAP_PARTIAL) {
+ debug(D_EMS, "partial ");
+ /* Page map partial has slightly different subfunctions
+ * GET_SET does not exist and is GET_SIZE in this case
+ */
+ if (subfunction == GET_SET)
+ subfunction = GET_SIZE;
+ }
+ switch (subfunction)
+ {
+ case GET:
+ {
+ debug(D_EMS, "get\n");
+ /* Get the address passed from DOS app */
+ dest = (EMScontext *)get_valid_pointer(R_ES, R_DI,
+ sizeof(EMScontext));
+ if (dest == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ save_context_to_dos(dest);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ case SET:
+ {
+ debug(D_EMS, "set\n");
+ src = (EMScontext *)get_valid_pointer(R_DS, R_SI,
+ sizeof(EMScontext));
+ if (src == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ if (check_saved_context(src) == 0) {
+ R_AH = EMS_SAVED_CONTEXT_BAD;
+ break;
+ }
+ restore_context(&src->ems_saved_context);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ case GET_SET:
+ {
+ debug(D_EMS, "get/set\n");
+ dest = (EMScontext *)get_valid_pointer(R_ES, R_DI,
+ sizeof(EMScontext));
+ if (dest == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ save_context_to_dos(dest);
+ src = (EMScontext *)get_valid_pointer(R_DS, R_SI,
+ sizeof(EMScontext));
+ if (src == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ if (check_saved_context(src) == 0) {
+ R_AH = EMS_SAVED_CONTEXT_BAD;
+ break;
+ }
+ restore_context(&src->ems_saved_context);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ case GET_SIZE:
+ debug(D_EMS, "get size\n");
+ R_AL = (sizeof(EMScontext) + 1) & 0xfe;
+ R_AH = EMS_SUCCESS;
+ break;
+ default:
+ debug(D_EMS, "invalid subfunction\n");
+ R_AH = EMS_INVALID_SUB;
+ break;
+ }
+ break;
+ }
+
+ case MAP_UNMAP_MULTI_HANDLE:
+ {
+ u_char position;
+ u_short hpagenum, spagenum;
+ short handle;
+ EMSmapunmap *mp;
+ int n_entry, i;
+
+
+ debug(D_EMS, "EMS: Map/Unmap multiple ");
+
+ if ((n_entry = R_CX) > 3) {
+ R_AH = EMS_ILL_PHYS;
+ }
+
+ /* This is valid according to the LIM EMS 4.0 spec */
+ if (n_entry == 0) {
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ handle = R_DX;
+ if (handle > 255 || handle == 0 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ break;
+ }
+
+ mp = (EMSmapunmap *)get_valid_pointer(R_DS, R_SI,
+ sizeof(EMSmapunmap) * n_entry);
+ if (mp == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+
+ R_AH = EMS_SUCCESS;
+ /* Walk through the table and map/unmap */
+ for (i = 0; i < n_entry; i++) {
+ hpagenum = mp->log;
+ /* Method is in R_AL */
+ if (R_AL == 0) {
+ debug(D_EMS, "phys page method\n");
+ if (mp->phys <= 3) {
+ position = mp->phys;
+ } else {
+ R_AH = EMS_ILL_PHYS;
+ break;
+ }
+ } else if (R_AL == 1) {
+ /* Compute position from segment address */
+ u_short p_seg;
+
+ debug(D_EMS, "segment method\n");
+ p_seg = mp->phys;
+ p_seg -= ems_frame_addr;
+ p_seg /= EMS_PAGESIZE;
+ if (p_seg <= 3) {
+ position = p_seg;
+ } else {
+ R_AH = EMS_ILL_PHYS;
+ break;
+ }
+ } else {
+ debug(D_EMS, "invalid subfunction\n");
+ R_AH = EMS_INVALID_SUB;
+ break;
+ }
+
+ mp++;
+ if (hpagenum == 0xffff) {
+ /* Unmap only */
+ map_page(0, position, handle, 1);
+ continue;
+ }
+ if (hpagenum >= ems_handle[handle]->npages) {
+ R_AH = EMS_LOGPAGE_TOOBIG;
+ break;
+ }
+ spagenum = ems_handle[handle]->pagenum[hpagenum];
+ map_page(spagenum, position, handle, 0);
+ }
+ break;
+ }
+
+ case REALLOC_PAGES:
+ {
+ short handle;
+ u_long newpages;
+
+ debug(D_EMS, "EMS: Realloc pages ");
+
+ handle = R_DX;
+ if (handle > 255 || handle == 0 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ debug(D_EMS, "invalid handle\n");
+ break;
+ }
+ newpages = R_BX;
+ debug(D_EMS, "changed from %d to %d pages\n",
+ ems_handle[handle]->npages, newpages);
+
+ /* Case 1: Realloc to zero pages */
+ if (newpages == 0) {
+ free_pages_of_handle(handle);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ /* Case 2: New allocation is equal to allocated number */
+ if (newpages == ems_handle[handle]->npages) {
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ /* Case 3: Reallocate to bigger and smaller sizes */
+ if (newpages > ems_handle[handle]->npages) {
+ if (newpages > ems_free_pages) {
+ R_AH = EMS_OUT_OF_LOG;
+ break;
+ }
+ if (newpages > ems_total_pages) {
+ R_AH = EMS_OUT_OF_PHYS;
+ break;
+ }
+ }
+ reallocate_pages_to_handle(handle, newpages);
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ /* We do not support nonvolatile pages */
+ case HANDLE_ATTRIBUTES:
+ debug(D_EMS, "Handle attributes called\n");
+ switch (R_AL) {
+ case GET:
+ case SET:
+ R_AH = EMS_FEAT_NOSUP;
+ break;
+ case HANDLE_CAPABILITY:
+ R_AL = 0; /* Volatile only */
+ R_AH = EMS_SUCCESS;
+ break;
+ default:
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+ }
+ break;
+
+ case HANDLE_NAME:
+ {
+ short handle;
+ Hname *hp;
+
+ handle = R_DX;
+ if (handle > 255 || handle == 0 || ems_handle[handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ debug(D_EMS, "invalid handle\n");
+ break;
+ }
+ switch (R_AL) {
+ case GET:
+ if ((hp = (Hname *)get_valid_pointer(R_ES, R_DI, 8))
+ == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ *hp = ems_handle[handle]->hname;
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case SET:
+ if ((hp = (Hname *)get_valid_pointer(R_DS, R_SI, 8))
+ == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ /* If the handle name is not 0, it may not exist */
+ if ((hp->ul_hn[0] | hp->ul_hn[1]) != 0) {
+ if (lookup_handle(hp) == 0) {
+ ems_handle[handle]->hname = *hp;
+ R_AH = EMS_SUCCESS;
+ } else {
+ R_AH = EMS_NAME_EXISTS;
+ break;
+ }
+ } else {
+ /* Name is deleted (set to zeros) */
+ ems_handle[handle]->hname = *hp;
+ R_AH = EMS_SUCCESS;
+ }
+ break;
+
+ default:
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+ }
+ break;
+ }
+
+ case HANDLE_DIRECTORY:
+ {
+ int i;
+ EMShandledir *hdp;
+ Hname *hp;
+ short handle;
+
+ switch(R_AL) {
+ case GET:
+ hdp = (EMShandledir *)get_valid_pointer(R_ES, R_DI,
+ sizeof(EMShandledir) * ems_alloc_handles);
+ if (hdp == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ for (i = 0; i < EMS_NUM_HANDLES; i++) {
+ if (ems_handle[i] != NULL) {
+ hdp->log = i;
+ hdp->name = ems_handle[i]->hname;
+ }
+ }
+ R_AH = EMS_SUCCESS;
+ break;
+
+ case HANDLE_SEARCH:
+ hp = (Hname *)get_valid_pointer(R_DS, R_SI, 8);
+ if (hp == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ /* Cannot search for NULL handle name */
+ if ((hp->ul_hn[0] | hp->ul_hn[1]) != 0) {
+ R_AH = EMS_NAME_EXISTS;
+ break;
+ }
+ if ((handle = lookup_handle(hp)) == 0) {
+ R_AH = EMS_HNAME_NOT_FOUND;
+ } else {
+ R_DX = handle;
+ R_AH = EMS_SUCCESS;
+ }
+ break;
+
+ case GET_TOTAL_HANDLES:
+ R_AH = EMS_SUCCESS;
+ R_BX = EMS_NUM_HANDLES; /* Includes OS handle */
+ break;
+
+ default:
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+ }
+ break;
+ }
+
+
+ /* I do not know if we need this. LINUX emulation leaves it out
+ * so I leave it out too for now.
+ */
+ case ALTER_PAGEMAP_JUMP:
+ debug(D_ALWAYS, "Alter pagemap and jump used!\n");
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+ case ALTER_PAGEMAP_CALL:
+ debug(D_ALWAYS, "Alter pagemap and call used!\n");
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+
+
+ case MOVE_MEMORY_REGION:
+ {
+ EMSmovemem *emvp;
+ u_long src_addr, dst_addr;
+ u_short src_handle, dst_handle;
+
+ if (R_AL == EXCHANGE)
+ debug(D_EMS, "EMS: Exchange memory region ");
+ else
+ debug(D_EMS, "EMS: Move memory region ");
+
+ emvp = (EMSmovemem *)get_valid_pointer(R_DS, R_SI,
+ sizeof(EMSmovemem));
+ if (emvp == NULL) {
+ debug(D_EMS, "Invalid structure pointer\n");
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ /* Zero length is not an error */
+ if (emvp->length == 0) {
+ debug(D_EMS, "Zero length\n");
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ /* Some checks */
+ if (emvp->src_type == EMS_MOVE_CONV) {
+ /* Conventional memory source */
+ src_addr = N_GETPTR(emvp->src_seg, emvp->src_offset);
+ /* May not exceed conventional memory */
+ if ((src_addr + emvp->length) > 640 * 1024) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ } else {
+ /* Check the handle */
+ src_handle = emvp->src_handle;
+ if (src_handle > 255 || src_handle == 0 ||
+ ems_handle[src_handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ debug(D_EMS, "invalid source handle\n");
+ break;
+ }
+ /* Offset may not exceed page size */
+ if (emvp->src_offset >= (16 * 1024)) {
+ R_AH = EMS_PAGEOFFSET;
+ debug(D_EMS, "source page offset too big\n");
+ break;
+ }
+ }
+
+ if (emvp->dst_type == EMS_MOVE_CONV) {
+ /* Conventional memory source */
+ dst_addr = N_GETPTR(emvp->dst_seg, emvp->dst_offset);
+ /* May not exceed conventional memory */
+ if ((dst_addr + emvp->length) > 640 * 1024) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ } else {
+ /* Check the handle */
+ dst_handle = emvp->dst_handle;
+ if (dst_handle > 255 || dst_handle == 0 ||
+ ems_handle[dst_handle] == NULL) {
+ R_AH = EMS_INV_HANDLE;
+ debug(D_EMS, "invalid destination handle\n");
+ break;
+ }
+ /* Offset may not exceed page size */
+ if (emvp->dst_offset >= (16 * 1024)) {
+ R_AH = EMS_PAGEOFFSET;
+ debug(D_EMS, "destination page offset too big\n");
+ break;
+ }
+ }
+
+ if (R_AL == MOVE) {
+ /* If it is conventional memory only, do it */
+ if (emvp->src_type == EMS_MOVE_CONV &&
+ emvp->dst_type == EMS_MOVE_CONV) {
+ memmove((void *)dst_addr, (void *)src_addr,
+ (size_t) emvp->length);
+ debug(D_EMS, "conventional to conventional memory done\n");
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ if (emvp->src_type == EMS_MOVE_EMS &&
+ emvp->dst_type == EMS_MOVE_CONV)
+ R_AH = move_ems_to_conv(src_handle, emvp->src_seg,
+ emvp->src_offset, dst_addr, emvp->length);
+ else if (emvp->src_type == EMS_MOVE_CONV &&
+ emvp->dst_type == EMS_MOVE_EMS)
+ R_AH = move_conv_to_ems(src_addr, dst_handle,
+ emvp->dst_seg, emvp->dst_offset, emvp->length);
+ else
+ R_AH = move_ems_to_ems(src_handle, emvp->src_seg,
+ emvp->src_offset, dst_handle, emvp->dst_seg,
+ emvp->dst_offset, emvp->length);
+ debug(D_EMS, " done\n");
+ break;
+ } else {
+ /* exchange memory region */
+
+ /* We need a scratch area for the exchange */
+ void *buffer;
+ if ((buffer = malloc(emvp->length)) == NULL)
+ fatal("EMS: Could not malloc scratch area for exchange");
+
+ /* If it is conventional memory only, do it */
+ if (emvp->src_type == EMS_MOVE_CONV &&
+ emvp->dst_type == EMS_MOVE_CONV) {
+ /* destination -> buffer */
+ memmove(buffer, (void *)dst_addr, (size_t) emvp->length);
+ /* Source -> destination */
+ memmove((void *)dst_addr, (void *)src_addr,
+ (size_t) emvp->length);
+ /* Buffer -> source */
+ memmove((void *)src_addr, buffer, (size_t) emvp->length);
+ free(buffer);
+ debug(D_EMS, "conventional to conventional memory done\n");
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+
+ /* Exchange EMS with conventional */
+ if (emvp->src_type == EMS_MOVE_EMS &&
+ emvp->dst_type == EMS_MOVE_CONV) {
+ /* Destination -> buffer */
+ memmove(buffer, (void *)dst_addr, (size_t) emvp->length);
+ /* Source -> destination */
+ R_AH = move_ems_to_conv(src_handle, emvp->src_seg,
+ emvp->src_offset, dst_addr, emvp->length);
+ if (R_AH != EMS_SUCCESS) {
+ free(buffer);
+ break;
+ }
+ /* Buffer -> source */
+ R_AH = move_conv_to_ems((u_long)buffer, src_handle,
+ emvp->src_seg, emvp->src_offset, emvp->length);
+
+ /* Exchange conventional with EMS */
+ } else if (emvp->src_type == EMS_MOVE_CONV &&
+ emvp->dst_type == EMS_MOVE_EMS) {
+ /* Destination -> buffer */
+ R_AH = move_ems_to_conv(dst_handle, emvp->dst_seg,
+ emvp->dst_offset, (u_long)buffer, emvp->length);
+ if (R_AH != EMS_SUCCESS) {
+ free(buffer);
+ break;
+ }
+ /* Source -> destination */
+ R_AH = move_conv_to_ems((u_long)buffer, dst_handle,
+ emvp->dst_seg, emvp->dst_offset, emvp->length);
+ /* Buffer -> source */
+ memmove(buffer, (void *)src_addr, (size_t) emvp->length);
+
+ /* Exchange EMS with EMS */
+ } else {
+ /* Destination -> buffer */
+ R_AH = move_ems_to_conv(dst_handle, emvp->dst_seg,
+ emvp->dst_offset, (u_long)buffer, emvp->length);
+ if (R_AH != EMS_SUCCESS) {
+ free(buffer);
+ break;
+ }
+ /* Source -> destination */
+ R_AH = move_ems_to_ems(src_handle, emvp->src_seg,
+ emvp->src_offset, dst_handle, emvp->dst_seg,
+ emvp->dst_offset, emvp->length);
+ if (R_AH != EMS_SUCCESS) {
+ free(buffer);
+ break;
+ }
+ /* Buffer -> source */
+ R_AH = move_conv_to_ems((u_long)buffer, src_handle,
+ emvp->src_seg, emvp->src_offset, emvp->length);
+ }
+ free(buffer);
+ }
+ debug(D_EMS, " done\n");
+ break;
+ }
+
+ case GET_MAPPABLE_PHYS_ADDR:
+ {
+ switch (R_AL) {
+ case GET_ARRAY:
+ {
+ EMSaddrarray *eadp;
+ int i;
+ u_short seg;
+
+ eadp = (EMSaddrarray *)get_valid_pointer(R_ES, R_DI,
+ sizeof(EMSaddrarray) * 4);
+ if (eadp == NULL) {
+ R_AH = EMS_SW_MALFUNC;
+ break;
+ }
+ for (i = 0, seg = (ems_frame_addr >> 4); i < 4; i++) {
+ eadp->segm = seg;
+ eadp->phys = i;
+ eadp++;
+ seg += 1024;
+ }
+ R_AH = EMS_SUCCESS;
+ break;
+ }
+ case GET_ARRAY_ENTRIES:
+ /* There are always 4 positions, 4*16kB = 64kB */
+ R_CX = 4;
+ R_AH = EMS_SUCCESS;
+ break;
+ default:
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+ }
+ break;
+ }
+
+ /* This is an OS function in the LIM EMS 4.0 standard: It is
+ * usable only by an OS and its use can be disabled for all other
+ * programs. I think we do not need to support it. It is not
+ * implemented and it reports "disabled" to any caller.
+ */
+ case GET_HW_CONFIGURATION:
+ R_AH = EMS_FUNCTION_DISABLED;
+ break;
+
+ /* This function is a little different, it was defined with
+ * LIM EMS 4.0: It is allowed to allocate zero pages and raw
+ * page size (i.e. page size != 16kB) is supported. We have
+ * only 16kB pages, so the second difference does not matter.
+ */
+ case ALLOCATE_PAGES:
+ {
+ u_short npages;
+ short handle;
+
+ npages = R_BX;
+ debug(D_EMS, "EMS: Get handle and allocate %d pages: ", npages);
+
+ /* Enough handles? */
+ if ((handle = find_next_free_handle()) < 0) {
+ debug(D_EMS,"Return error:No handles\n");
+ R_AH = EMS_OUT_OF_HANDLES;
+ break;
+ }
+ /* Enough memory for this request ? */
+ if (npages > ems_free_pages) {
+ debug(D_EMS,"Return error:Request too big\n");
+ R_AH = EMS_OUT_OF_LOG;
+ break;
+ }
+ if (npages > ems_total_pages) {
+ debug(D_EMS,"Return error:Request too big\n");
+ R_AH = EMS_OUT_OF_PHYS;
+ break;
+ }
+
+ /* Allocate the handle */
+ allocate_handle(handle, npages);
+
+ /* Allocate the pages */
+ allocate_pages_to_handle(handle, npages);
+ R_DX = handle;
+ R_AH = EMS_SUCCESS;
+ debug(D_EMS,"Return success:Handle = %d\n", handle);
+ break;
+ }
+
+ /* This is an OS function in the LIM EMS 4.0 standard: It is
+ * usable only by an OS and its use can be disabled for all other
+ * programs. I think we do not need to support it. It is not
+ * implemented and it reports "disabled" to any caller.
+ */
+ case ALTERNATE_MAP_REGISTER:
+ R_AH = EMS_FUNCTION_DISABLED;
+ break;
+
+ /* We cannot support that ! */
+ case PREPARE_WARMBOOT:
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+
+ case OS_FUNCTION_SET:
+ R_AH = EMS_FUNCTION_DISABLED;
+ break;
+
+unknown:
+ default:
+ debug(D_ALWAYS, "EMS: Unknown function called: %02x\n", R_AH);
+ R_AH = EMS_FUNC_NOSUP;
+ break;
+ }
+}
+
+/* Initialize the EMS memory: Return 1 on success, 0 on failure */
+
+static int
+init_mapfile()
+{
+ char path[256];
+ int mfd;
+
+ /* Sanity */
+ if (ems_max_size == 0)
+ return;
+ strcpy(path, EMS_MAP_PATH);
+ strcat(path, EMS_MAP_FILE);
+
+ mfd = mkstemp(path);
+
+ if (mfd < 0) {
+ debug(D_ALWAYS, "Could not create EMS mapfile, ");
+ goto fail;
+ }
+ unlink(path);
+ mapfile_fd = squirrel_fd(mfd);
+
+ if (lseek(mapfile_fd, (off_t)(ems_max_size - 1), 0) < 0) {
+ debug(D_ALWAYS, "Could not seek into EMS mapfile, ");
+ goto fail;
+ }
+ if (write(mapfile_fd, "", 1) < 0) {
+ debug(D_ALWAYS, "Could not write to EMS mapfile, ");
+ goto fail;
+ }
+ /* Unmap the entire page frame */
+ if (munmap((caddr_t)ems_frame_addr, 64 * 1024) < 0) {
+ debug(D_ALWAYS, "Could not unmap EMS page frame, ");
+ goto fail;
+ }
+ /* DOS programs will access the page frame without allocating
+ * pages first. Microsoft diagnose MSD.EXE does this, for example
+ * We need to have memory here to avoid segmentation violation
+ */
+ if (mmap((caddr_t)ems_frame_addr, 64 * 1024,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ -1, 0) < 0) {
+ debug(D_ALWAYS, "Could not map EMS page frame, ");
+ goto fail;
+ }
+ bzero((void *)&ems_mapping_context, sizeof(EMS_mapping_context));
+ return (1);
+
+fail:
+ debug(D_ALWAYS, "EMS disabled\n");
+ ems_max_size = 0;
+ ems_frame_addr = 0;
+ return (0);
+}
+
+/* Map/Unmap pages into one of four positions in the frame segment */
+
+static void
+map_page(u_long pagenum, u_char position, short handle, int unmaponly)
+{
+ caddr_t map_addr;
+ size_t len;
+ off_t file_offs;
+
+ if (position > 3)
+ fatal("EMS: Internal error: Mapping position\n");
+
+ map_addr = (caddr_t)(ems_frame_addr + (1024 * 16 * (u_long)position));
+ len = 1024 * 16;
+ file_offs = (off_t)(pagenum * 16 * 1024);
+
+ if (ems_mapping_context.pos_mapped[position]) {
+ if (munmap(map_addr, len) < 0) {
+ fatal("EMS unmapping error: %s\nCannot recover\n",
+ strerror(errno));
+ }
+ ems_page[ems_mapping_context.pos_pagenum[position]].status
+ &= ~EMS_MAPPED;
+ ems_mapping_context.pos_mapped[position] = 0;
+ ems_mapping_context.handle[position] = 0;
+ }
+ if (unmaponly) {
+ /* DOS programs will access the page frame without allocating
+ * pages first. Microsoft diagnose MSD.EXE does this, for example
+ * We need to have memory here to avoid segmentation violation
+ */
+ if (mmap((caddr_t)ems_frame_addr, 64 * 1024,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ -1, 0) < 0)
+ fatal("Could not map EMS page frame during unmap only\n");
+ return;
+ }
+ if (mmap(map_addr, len,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED,
+ mapfile_fd, file_offs) < 0) {
+ fatal("EMS mapping error: %s\nCannot recover\n", strerror(errno));
+ }
+ ems_mapping_context.pos_mapped[position] = 1;
+ ems_mapping_context.pos_pagenum[position] = pagenum;
+ ems_mapping_context.handle[position] = handle;
+ ems_page[pagenum].status |= EMS_MAPPED;
+}
+
+/* Get a pointer from VM86 app, check it and return it. This returns NULL
+ * if the pointer is not valid. We can check only for very limited
+ * criteria: The pointer and the area defined by size may not point to
+ * memory over 1MB and it may not may to addresses under 1kB, because there
+ * is the VM86 interrupt table.
+ */
+static void
+*get_valid_pointer(u_short seg, u_short offs, u_long size)
+{
+ u_long addr;
+ addr = N_GETPTR(seg, offs);
+ /* Check bounds */
+ if ((addr + size) >= (1024 * 1024) || addr < 1024)
+ return NULL;
+ else
+ return (void *)addr;
+}
+
+/* Malloc a new handle */
+static EMS_handle
+*get_new_handle(long npages)
+{
+ EMS_handle *ehp;
+ size_t dynsize = sizeof(EMS_handle) + sizeof(short) * npages;
+
+ if ((ehp = calloc(1, dynsize)) == NULL)
+ fatal("Cannot malloc EMS handle, cannot continue\n");
+ return ehp;
+}
+
+/* Allocate a mapping context to a handle */
+static void
+context_to_handle(short handle)
+{
+ EMS_mapping_context *emc;
+
+ if (ems_handle[handle] == NULL)
+ fatal("EMS context_to_handle called with invalid handle\n");
+ if ((emc = calloc(1, sizeof(EMS_mapping_context))) == NULL)
+ fatal("EMS Cannot malloc mapping context, cannot continue\n");
+ ems_handle[handle]->mcontext = emc;
+ memmove((void *)emc, (void *)&ems_mapping_context,
+ sizeof(EMS_mapping_context));
+}
+
+/* Find the next free handle, returns -1 if there are no more handles */
+static long
+find_next_free_handle()
+{
+ int i;
+
+ if (ems_alloc_handles >= 255)
+ return (-1);
+ /* handle 0 is OS handle */
+ for (i = 1; i < EMS_NUM_HANDLES; i++) {
+ if (ems_handle[i] == NULL)
+ return (i);
+ }
+ fatal("EMS handle count garbled, should not happen\n");
+}
+
+/* Look for a named handle, returns 0 if not found, else handle */
+static short
+lookup_handle(Hname *hp)
+{
+ int i;
+
+ for (i = 1; i < EMS_NUM_HANDLES; i++) {
+ if (ems_handle[i] != NULL) {
+ if (hp->ul_hn[0] == ems_handle[i]->hname.ul_hn[0] &&
+ hp->ul_hn[1] == ems_handle[i]->hname.ul_hn[1])
+ return (i);
+ }
+ }
+ return (0);
+}
+
+/* Malloc a new handle struct and put into array at index handle */
+static void
+allocate_handle(short handle, long npages)
+{
+ if (ems_handle[handle] != NULL)
+ fatal("EMS allocate_handle, handle was not free\n");
+ ems_handle[handle] = get_new_handle(npages);
+ ems_alloc_handles++;
+}
+
+/* Free a handle, return its memory. Call this *after* freeing the
+ * allocated pages !
+ */
+static void
+free_handle(short handle)
+{
+ if (ems_handle[handle] == NULL)
+ fatal("EMS free_handle, handle was free\n");
+ if (ems_handle[handle]->mcontext != NULL)
+ free((void *)ems_handle[handle]->mcontext);
+ free((void *)ems_handle[handle]);
+ ems_handle[handle] = NULL;
+ ems_alloc_handles--;
+}
+
+
+/* Allocates npages to handle. Call this routine only after you have
+ * ensured there are enough free pages *and* the new handle is in place
+ * in the handle array !
+ */
+static void
+allocate_pages_to_handle(u_short handle, long npages)
+{
+ int syspagenum;
+ int pages_to_alloc = npages;
+ int allocpagenum = 0;
+
+ /* sanity */
+ if (handle > 255 || ems_handle[handle] == NULL)
+ fatal("EMS allocate_pages_to_handle called with invalid handle\n");
+
+ ems_handle[handle]->npages = npages;
+ for (syspagenum = 0; syspagenum < ems_total_pages; syspagenum++) {
+ if (ems_page[syspagenum].status == EMS_FREE) {
+ ems_page[syspagenum].handle = handle;
+ ems_page[syspagenum].status = EMS_ALLOCED;
+ ems_handle[handle]->pagenum[allocpagenum] = syspagenum;
+ allocpagenum++;
+ pages_to_alloc--;
+ if (pages_to_alloc == 0)
+ break;
+ }
+ }
+ if (pages_to_alloc > 0)
+ fatal("EMS allocate_pages_to_handle found not enough free pages\n");
+ ems_alloc_pages += npages;
+ ems_free_pages -= npages;
+}
+
+/* Reallocates npages to handle. Call this routine only after you have
+ * ensured there are enough free pages *and* the new handle is in place
+ * in the handle array !
+ */
+static void
+reallocate_pages_to_handle(u_short handle, long npages)
+{
+ int syspagenum;
+ int pages_to_alloc;
+ int allocpagenum;
+ long delta;
+ size_t dynsize;
+ EMS_handle *emp;
+
+ /* sanity */
+ if (handle > 255 || ems_handle[handle] == NULL)
+ fatal("EMS allocate_pages_to_handle called with invalid handle\n");
+
+ delta = npages - ems_handle[handle]->npages;
+ if (delta > 0) {
+ /* Grow array size and allocation */
+
+ emp = ems_handle[handle];
+ dynsize = sizeof(EMS_handle) + sizeof(short) * npages;
+
+ /* First step: Make room in the handle pagenum array */
+ if ((emp = (EMS_handle *)realloc((void *)emp, dynsize)) == NULL)
+ fatal("Cannot malloc EMS handle, cannot continue\n");
+ ems_handle[handle] = emp;
+
+ /* Second step: Add pages to the handle */
+ pages_to_alloc = delta;
+ allocpagenum = ems_handle[handle]->npages;
+ ems_handle[handle]->npages = npages;
+ for (syspagenum = 0; syspagenum < ems_total_pages; syspagenum++) {
+ if (ems_page[syspagenum].status == EMS_FREE) {
+ ems_page[syspagenum].handle = handle;
+ ems_page[syspagenum].status = EMS_ALLOCED;
+ ems_handle[handle]->pagenum[allocpagenum] = syspagenum;
+ allocpagenum++;
+ pages_to_alloc--;
+ if (pages_to_alloc == 0)
+ break;
+ }
+ }
+ if (pages_to_alloc > 0)
+ fatal("EMS allocate_pages_to_handle found not enough free pages\n");
+
+ } else {
+ /* Shrink array size and allocation */
+
+ /* First step: Deallocate all pages from new size to old size */
+ for (allocpagenum = npages;
+ allocpagenum < ems_handle[handle]->npages;
+ allocpagenum++) {
+ syspagenum = ems_handle[handle]->pagenum[allocpagenum];
+
+ /* sanity */
+ if (syspagenum > ems_total_pages)
+ fatal("EMS free_pages_of_handle found invalid page number\n");
+ if (!(ems_page[syspagenum].status & EMS_ALLOCED))
+ fatal("EMS free_pages_of_handle tried to free page already free\n");
+ ems_page[syspagenum].handle = 0;
+ ems_page[syspagenum].status = EMS_FREE;
+ }
+
+ /* Second step: Shrink the dynamic array of the handle */
+ dynsize = sizeof(EMS_handle) + sizeof(short) * npages;
+ emp = ems_handle[handle];
+ if ((emp = (EMS_handle *)realloc((void *)emp, dynsize)) == NULL)
+ fatal("Cannot realloc EMS handle, cannot continue\n");
+ ems_handle[handle] = emp;
+ ems_handle[handle]->npages = npages;
+ }
+ ems_alloc_pages += delta;
+ ems_free_pages -= delta;
+}
+
+/* Free all pages belonging to a handle, handle must be valid */
+static void
+free_pages_of_handle(short handle)
+{
+ int allocpagenum;
+ int syspagenum;
+ int npages;
+
+ /* sanity */
+
+ if (handle > 255 || ems_handle[handle] == NULL)
+ fatal("EMS free_pages_of_handle called with invalid handle\n");
+
+ if ((npages = ems_handle[handle]->npages) == 0)
+ return;
+
+ for (allocpagenum = 0; allocpagenum < npages; allocpagenum++) {
+ syspagenum = ems_handle[handle]->pagenum[allocpagenum];
+ /* sanity */
+ if (syspagenum > ems_total_pages)
+ fatal("EMS free_pages_of_handle found invalid page number\n");
+ if (!(ems_page[syspagenum].status & EMS_ALLOCED))
+ fatal("EMS free_pages_of_handle tried to free page already free\n");
+ ems_page[syspagenum].handle = 0;
+ ems_page[syspagenum].status = EMS_FREE;
+ }
+ ems_alloc_pages -= npages;
+ ems_free_pages += npages;
+}
+
+/* Restore a saved mapping context, overwrites current mapping context */
+static void
+restore_context(EMS_mapping_context *emc)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ ems_mapping_context.handle[i] = emc->handle[i];
+ if (emc->pos_mapped[i] != 0 &&
+ ems_mapping_context.pos_pagenum[i] != emc->pos_pagenum[i]) {
+ map_page(emc->pos_pagenum[i], (u_char) i, emc->handle[i], 0);
+ } else {
+ ems_mapping_context.pos_mapped[i] = 0;
+ }
+ }
+}
+
+/* Prepare a special context save block for DOS and save it to
+ * VM86 memory
+ */
+static void
+save_context_to_dos(EMScontext *emp)
+{
+ int i, end;
+ EMScontext context;
+ u_short *sp;
+ u_short sum;
+
+ context.ems_saved_context = ems_mapping_context;
+ context.magic = EMS_SAVEMAGIC;
+ context.checksum = 0;
+ sp = (u_short *)&context;
+ end = sizeof(EMScontext) / sizeof(short);
+ /* Generate checksum */
+ for (i = 0, sum = 0; i < end; i++) {
+ sum += *sp++;
+ sum &= 0xffff;
+ }
+ context.checksum = 0x10000L - sum;
+ /* Save it to VM86 memory */
+ *emp = context;
+}
+
+/* Check a context returned from VM86 app for validity, return 0, if
+ * not valid, else return 1
+ */
+static int
+check_saved_context(EMScontext *emp)
+{
+ int i, end;
+ u_short *sp;
+ u_short sum;
+
+ if (emp->magic != EMS_SAVEMAGIC)
+ return 0;
+
+ sp = (u_short *)emp;
+ end = sizeof(EMScontext) / sizeof(short);
+ /* Generate checksum */
+ for (i = 0, sum = 0; i < end; i++) {
+ sum += *sp++;
+ sum &= 0xffff;
+ }
+ if (sum != 0)
+ return 0;
+ else
+ return 1;
+}
+
+/* Helper routine for the move routines below: Check if length bytes
+ * can be moved from/to handle pages (i.e are there enough pages)
+ */
+static int
+check_alloc_pages(u_short handle, u_short firstpage, u_short offset,
+ u_long length)
+{
+ u_long nbytes;
+
+ if (firstpage > ems_handle[handle]->npages)
+ return (0);
+ nbytes = (ems_handle[handle]->npages - firstpage) * EMS_PAGESIZE - offset;
+ return (ems_handle[handle]->npages >= nbytes);
+}
+
+/* Copy a block of memory up to the next 16kB boundary in the source
+ * to the destination in upward direction (i.e. with ascending addresses)
+ * XXX Could be an inline function.
+ */
+static void
+copy_block_up(struct copydesc *cdp)
+{
+ size_t size;
+ void *srcp;
+ void *dstp;
+
+ /* If source or both memory types are EMS, source determines the
+ * block lenght, else destination determines the block lenght
+ */
+ if (cdp->copytype & SRC_EMS)
+ size = EMS_PAGESIZE - cdp->EMS_OFFS(src_addr);
+ else
+ size = EMS_PAGESIZE - cdp->EMS_OFFS(dst_addr);
+
+ if (size > cdp->rest_len)
+ size = cdp->rest_len;
+
+ /* If src is EMS memory, it is mapped into position 0 */
+ if (cdp->copytype & SRC_EMS)
+ srcp = (void *)(ems_frame_addr + cdp->EMS_OFFS(src_addr));
+ else
+ srcp = (void *)(cdp->EMS_PTR(src_addr));
+
+ /* If dest is EMS memory, it is mapped into position 1,2 */
+ if (cdp->copytype & DST_EMS)
+ dstp = (void *)(ems_frame_addr + EMS_PAGESIZE +
+ cdp->EMS_OFFS(dst_addr));
+ else
+ dstp = (void *)(cdp->EMS_PTR(dst_addr));
+
+ /* Move this block */
+ memmove(dstp, srcp, size);
+
+ /* Update the copy descriptor: This updates the address of both
+ * conventional and EMS memory
+ */
+ cdp->EMS_PTR(src_addr) += size;
+ cdp->EMS_PTR(dst_addr) += size;
+
+ cdp->rest_len -= size;
+}
+
+
+/* Move EMS memory starting with handle page src_seg and offset src_offset
+ * to conventional memory dst_addr for length bytes
+ * dst_addr is checked, handle is valid
+ */
+static u_long
+move_ems_to_conv(short src_handle, u_short src_seg,
+ u_short src_offset, u_long dst_addr, u_long length)
+{
+ EMS_mapping_context ems_saved_context;
+ EMS_handle *ehp;
+ int pageindx = src_seg;
+ struct copydesc cd;
+
+ if (check_alloc_pages(src_handle, src_seg, src_offset, length) == 0)
+ return EMS_MOVE_OVERFLOW;
+
+ ehp = ems_handle[src_handle];
+
+ /* Prepare the move: Save the mapping context */
+ ems_saved_context = ems_mapping_context;
+
+ /* Setup the copy descriptor struct */
+
+ cd.copytype = SRC_EMS;
+ cd.EMS_PAGE(src_addr) = ehp->pagenum[pageindx];
+ cd.EMS_OFFS(src_addr) = src_offset;
+ cd.EMS_PTR(dst_addr) = dst_addr;
+ cd.rest_len = length;
+
+ do {
+ /* Map for the first block copy, source is mapped to position zero */
+ map_page(cd.EMS_PAGE(src_addr), 0, src_handle, 0);
+ copy_block_up(&cd);
+ } while(cd.rest_len > 0);
+
+ /* Restore the original mapping */
+ restore_context(&ems_saved_context);
+ return EMS_SUCCESS;
+}
+
+/* Move conventional memory starting with src_addr
+ * to EMS memory starting with handle page src_seg and offset src_offset
+ * for length bytes
+ * dst_addr is checked, handle is valid
+ */
+static u_long
+move_conv_to_ems(u_long src_addr, u_short dst_handle, u_short dst_seg,
+ u_short dst_offset, u_long length)
+{
+ EMS_mapping_context ems_saved_context;
+ EMS_handle *ehp;
+ int pageindx = dst_seg;
+ struct copydesc cd;
+
+ if (check_alloc_pages(dst_handle, dst_seg, dst_offset, length) == 0)
+ return EMS_MOVE_OVERFLOW;
+
+ ehp = ems_handle[dst_handle];
+
+ /* Prepare the move: Save the mapping context */
+ ems_saved_context = ems_mapping_context;
+
+ /* Setup the copy descriptor struct */
+
+ cd.copytype = DST_EMS;
+ cd.EMS_PAGE(dst_addr) = ehp->pagenum[pageindx];
+ cd.EMS_OFFS(dst_addr) = dst_offset;
+ cd.EMS_PTR(src_addr) = src_addr;
+ cd.rest_len = length;
+
+ do {
+ map_page(cd.EMS_PAGE(dst_addr), 1, dst_handle, 0);
+ copy_block_up(&cd);
+ } while(cd.rest_len > 0);
+
+ /* Restore the original mapping */
+ restore_context(&ems_saved_context);
+ return EMS_SUCCESS;
+}
+
+static u_long
+move_ems_to_ems(u_short src_handle, u_short src_seg, u_short src_offset,
+ u_short dst_handle, u_short dst_seg, u_short dst_offset,
+ u_long length)
+{
+ EMS_mapping_context ems_saved_context;
+ EMS_handle *src_hp, *dst_hp;
+ struct copydesc cd;
+
+ if (check_alloc_pages(src_handle, src_seg, src_offset, length) == 0)
+ return EMS_MOVE_OVERFLOW;
+ if (check_alloc_pages(dst_handle, dst_seg, dst_offset, length) == 0)
+ return EMS_MOVE_OVERFLOW;
+
+ src_hp = ems_handle[src_handle];
+ dst_hp = ems_handle[dst_handle];
+
+ /* Prepare the move: Save the mapping context */
+ ems_saved_context = ems_mapping_context;
+
+ /* Setup the copy descriptor struct */
+
+ cd.copytype = SRC_EMS | DST_EMS;
+ cd.EMS_PAGE(src_addr) = src_hp->pagenum[src_seg];
+ cd.EMS_OFFS(src_addr) = src_offset;
+ cd.EMS_PAGE(dst_addr) = dst_hp->pagenum[dst_seg];
+ cd.EMS_OFFS(dst_addr) = dst_offset;
+ cd.rest_len = length;
+
+ /* Copy */
+ do {
+ map_page(cd.EMS_PAGE(src_addr), 0, src_handle, 0);
+ map_page(cd.EMS_PAGE(dst_addr), 1, dst_handle, 0);
+ /* If there are more pages, map the next destination page to
+ * position 2. This removes a compare between source and dest
+ * offsets.
+ */
+ if (cd.EMS_PAGE(dst_addr) < dst_hp->npages)
+ map_page((cd.EMS_PAGE(dst_addr) + 1), 2, dst_handle, 0);
+ copy_block_up(&cd);
+ } while(cd.rest_len > 0);
+
+ /* Restore the original mapping */
+ restore_context(&ems_saved_context);
+ return EMS_SUCCESS;
+}
diff --git a/usr.bin/doscmd/ems.h b/usr.bin/doscmd/ems.h
new file mode 100644
index 0000000..866a551
--- /dev/null
+++ b/usr.bin/doscmd/ems.h
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
+ * 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 immediately at the beginning of the file, witout modification,
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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$
+ */
+
+#ifndef EMS_H
+#define EMS_H
+
+/* Header for ems.c, the EMS emulation */
+
+/* Global definitions, some of them will be configurable in the future */
+
+#define EMS_NUM_HANDLES 256 /* Includes OS handle 0 */
+#define EMS_MAXSIZE 1024 /* In kbytes */
+#define EMS_MAX_PHYS 4 /* Frame is 64kB */
+#define EMS_FRAME_ADDR 0xe0000
+#define EMS_VERSION 0x40 /* Version 4.0 */
+#define EMS_PAGESIZE (16 *1024) /* page size in bytes */
+#define EMS_SAVEMAGIC 0xAFFE /* magic number */
+
+/* These are the LIM EMS 3.0 calls */
+#define GET_MANAGER_STATUS 0x40
+#define GET_PAGE_FRAME_SEGMENT 0x41
+#define GET_PAGE_COUNTS 0x42
+#define GET_HANDLE_AND_ALLOCATE 0x43
+#define MAP_UNMAP 0x44
+#define DEALLOCATE_HANDLE 0x45
+#define GET_EMM_VERSION 0x46
+#define SAVE_PAGE_MAP 0x47
+#define RESTORE_PAGE_MAP 0x48
+#define RESERVED_1 0x49
+#define RESERVED_2 0x4a
+#define GET_HANDLE_COUNT 0x4b
+#define GET_PAGES_OWNED 0x4c
+#define GET_PAGES_FOR_ALL 0x4d
+
+/* LIM EMS 4.0 calls */
+/* Global subfunctions for the LIM EMS 4.0 calls */
+#define GET 0x0
+#define SET 0x1
+/* Modes for Map/Unmap and AlterandCall/AlterAndJump */
+#define PHYS_ADDR 0x0
+#define SEG_ADDR 0x0
+
+/* Page map functions */
+#define PAGE_MAP 0x4e
+#define PAGE_MAP_PARTIAL 0x4f
+/* Page map subfunctions */
+#define GET_SET 0x2
+#define GET_SIZE 0x3
+
+#define MAP_UNMAP_MULTI_HANDLE 0x50
+
+#define REALLOC_PAGES 0x51
+
+#define HANDLE_ATTRIBUTES 0x52
+/* Subfunctions */
+#define HANDLE_CAPABILITY 0x2
+
+#define HANDLE_NAME 0x53
+
+#define HANDLE_DIRECTORY 0x54
+#define HANDLE_SEARCH 0x1
+#define GET_TOTAL_HANDLES 0x2
+
+#define ALTER_PAGEMAP_JUMP 0x55
+#define ALTER_PAGEMAP_CALL 0x56
+/* Subfunction for call */
+#define GET_STACK_SIZE 0x2
+
+#define MOVE_MEMORY_REGION 0x57
+/* Subfunctions */
+#define MOVE 0x0
+#define EXCHANGE 0x1
+
+#define GET_MAPPABLE_PHYS_ADDR 0x58
+/* Subfunctions */
+#define GET_ARRAY 0x0
+#define GET_ARRAY_ENTRIES 0x1
+
+#define GET_HW_CONFIGURATION 0x59
+/* Subfunctions */
+#define GET_HW_ARRAY 0x0
+#define GET_RAW_PAGE_COUNT 0x1
+
+#define ALLOCATE_PAGES 0x5a
+/* Subfunctions */
+#define ALLOC_STANDARD 0x0
+#define ALLOC_RAW 0x1
+
+#define ALTERNATE_MAP_REGISTER 0x5b
+/* Subfunctions */
+#define GET_SAVE_ARRAY_SIZE 0x2
+#define ALLOCATE_REGISTER_SET 0x3
+#define DEALLOCATE_REGISTER_SET 0x4
+#define ALLOCATE_DMA 0x5
+#define ENABLE_DMA 0x6
+#define DISABLE_DMA 0x7
+#define DEALLOCATE_DMA 0x8
+
+#define PREPARE_WARMBOOT 0x5c
+
+#define OS_FUNCTION_SET 0x5d
+/* Subfunctions */
+#define ENABLE 0x0
+#define DISABLE 0x1
+#define RETURN_KEY 0x2
+
+/* End of call definitions */
+
+/* EMS errors */
+
+#define EMS_SUCCESS 0x0
+#define EMS_SW_MALFUNC 0x80
+#define EMS_HW_MALFUNC 0x81
+#define EMS_INV_HANDLE 0x83
+#define EMS_FUNC_NOSUP 0x84
+#define EMS_OUT_OF_HANDLES 0x85
+#define EMS_SAVED_MAP 0x86
+#define EMS_OUT_OF_PHYS 0x87
+#define EMS_OUT_OF_LOG 0x88
+#define EMS_ZERO_PAGES 0x89
+#define EMS_LOGPAGE_TOOBIG 0x8a
+#define EMS_ILL_PHYS 0x8b
+#define EMS_NO_ROOM_TO_SAVE 0x8c
+#define EMS_ALREADY_SAVED 0x8d
+#define EMS_NO_SAVED_CONTEXT 0x8e
+#define EMS_INVALID_SUB 0x8f
+#define EMS_INVALID_ATTR 0x90
+#define EMS_FEAT_NOSUP 0x91
+#define EMS_MOVE_OVERLAP1 0x92
+#define EMS_MOVE_OVERFLOW 0x93
+#define EMS_PAGEOFFSET 0x95
+#define EMS_MOVE_OVERLAP2 0x97
+#define EMS_HNAME_NOT_FOUND 0xa0
+#define EMS_NAME_EXISTS 0xa1
+#define EMS_SAVED_CONTEXT_BAD 0xa3
+#define EMS_FUNCTION_DISABLED 0xa4
+
+/*
+ * EMS handles: The handle contains at its end an array of pointers to
+ * its allocated pages. The array is of size npages. Handle structs are
+ * malloced at runtime.
+ * Page numbering: Every page is 16kB, always. The pages are numbered
+ * from 0 to highest page, depending on total EMS memory. Every handle
+ * has pages allocated and this pages too are numbered from 0 to highest
+ * page allocated. This are *not* the same numbers, because there may be
+ * holes in the allocation.
+ * Page numbers are unsigned short, which will give us 65536 * 16 kB (1GB)
+ * pages to handle at maximum. This should be enough for the next years.
+ */
+
+typedef struct {
+ short handle[4]; /* Handle for each mapping */
+ u_char pos_mapped[4]; /* Boolean value, 1 if something is mapped */
+ u_char pos_pagenum[4]; /* Page number currently mapped into position */
+} EMS_mapping_context;
+
+
+/* This union is for copying operations of the handle name only */
+typedef union {
+ u_char uc_hn[8];
+ u_long ul_hn[2];
+} Hname;
+
+typedef struct {
+ Hname hname;
+ u_long npages;
+ /* The mapping context for save/restore page map */
+ EMS_mapping_context *mcontext;
+ /* The pagenum here is the number in the system page array. The
+ * logical page number connected with this handle is the index into
+ * this array.
+ */
+ u_short pagenum[0];
+ /* Will grow here, depending on allocation */
+} EMS_handle;
+
+/*
+ * The connection between every page in the system and the handles is
+ * maintained by an array of these structs. The array is indexed by the
+ * page numbers.
+ */
+
+typedef struct {
+ short handle; /* The handle this page belongs to */
+#define EMS_FREE 0
+#define EMS_ALLOCED 1
+#define EMS_MAPPED 2
+ u_short status; /* room for misc information */
+} EMS_page;
+
+/*
+ * The combined pointer into EMS memory: offs is the offset into an EMS
+ * page, page is the page index inside the region allocated to a handle.
+ * This depends on EMS_PAGESIZE.
+ * This is used for copy and move operations.
+ */
+
+typedef struct {
+ u_long offs:14;
+ u_long page:18;
+} EMS_combi;
+
+typedef union {
+ u_long ua_addr; /* Conventional address pointer */
+ EMS_combi ua_emsaddr; /* EMS address pointer */
+} EMS_addr;
+
+#define EMS_OFFS(u) u.ua_emsaddr.offs
+#define EMS_PAGE(u) u.ua_emsaddr.page
+#define EMS_PTR(u) u.ua_addr
+
+/*
+ * EMS info structure, only used to pass information to and from
+ * DOS
+ */
+
+typedef struct {
+ u_short handle __attribute__ ((packed)); /* handle */
+ u_short npages __attribute__ ((packed)); /* pages allocated */
+} EMShandlepage;
+
+/*
+ * EMS map/unmap multiple, only used to pass information to and from
+ * DOS
+ */
+
+typedef struct {
+ u_short log __attribute__ ((packed)); /* logical page number */
+ u_short phys __attribute__ ((packed)); /* physical page (position) or
+ segment address inside frame */
+} EMSmapunmap;
+
+/*
+ * EMS handle directory, only used to pass information to and from
+ * DOS
+ */
+
+typedef struct {
+ u_short log __attribute__ ((packed)); /* logical page number */
+ Hname name __attribute__ ((packed)); /* Handle name */
+
+} EMShandledir;
+
+/*
+ * Structure for get/set page map: This structure is used to save and
+ * restore the page map from DOS memory. A program can get the mapping
+ * context and later set (restore) it. To avoid errors we add a magic
+ * number and a checksum.
+ */
+
+typedef struct {
+ u_short magic; /* Magic number */
+ u_short checksum; /* Checksum over entire structure */
+ EMS_mapping_context ems_saved_context;
+} EMScontext;
+
+/*
+ * EMS physical address array, only used to pass information to and from
+ * DOS
+ */
+
+typedef struct {
+ u_short segm __attribute__ ((packed)); /* segment address inside frame */
+ u_short phys __attribute__ ((packed)); /* physical page (position) */
+} EMSaddrarray;
+
+/*
+ * EMS move memory call structure, only used to pass information to and from
+ * DOS
+ */
+
+typedef struct {
+ u_long length __attribute__ ((packed)); /* length of region */
+#define EMS_MOVE_CONV 0
+#define EMS_MOVE_EMS 1
+ u_char src_type __attribute__ ((packed)); /* source type (0,1) */
+ u_short src_handle __attribute__ ((packed)); /* source handle */
+ u_short src_offset __attribute__ ((packed)); /* source offset */
+ u_short src_seg __attribute__ ((packed)); /* source type */
+ u_char dst_type __attribute__ ((packed)); /* destination type (0,1) */
+ u_short dst_handle __attribute__ ((packed)); /* destination handle */
+ u_short dst_offset __attribute__ ((packed)); /* destination offset */
+ u_short dst_seg __attribute__ ((packed)); /* destination type */
+} EMSmovemem;
+
+#endif /* EMS_H */
diff --git a/usr.bin/doscmd/emsdriv.S b/usr.bin/doscmd/emsdriv.S
new file mode 100644
index 0000000..ffa2c98
--- /dev/null
+++ b/usr.bin/doscmd/emsdriv.S
@@ -0,0 +1,261 @@
+! Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
+! 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 immediately at the beginning of the file, witout modification,
+! 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. The name of the author may not be used to endorse or promote products
+! derived from this software without specific prior written permission.
+!
+! THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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$
+
+
+!
+! This driver is needed for Expanded Memory emulation (EMS). A driver
+! is needed here, because EMS drivers are installed as DOS devices
+! with the name "EMMXXXX0" and programs look for such a device while
+! checking the existence of EMS.
+! The driver is installed by CONFIG.SYS, it has no options. It uses
+! the emulator callback interrupt 0xff to initialize the EMS subsystem.
+! If EMS is not configured or if there is an error inside the emulator
+! the driver reports failure and does not install itself.
+! If all works, the driver changes the interrupt vector for int 0x67 to
+! point at itself. The resident part of the drivers simlpy routes calls
+! to int 0x67 to the correct subfunction of the emulator callback interrupt.
+
+use16
+
+.text
+.bss
+.data
+.align 0
+
+ .org 0
+
+NumFunc = 15
+
+! Emulator interrupt entry
+EmulatorINT = 0xFF
+
+! Emulator EMS callback function
+EMU_EMS = 0x2
+EMU_EMS_CTL = 0
+EMU_EMS_CALL = 1
+
+! DOS print message
+DOSMesg = 0x9
+
+cr = 0xd
+lf = 0xa
+eom = '$' ! DOS end of string
+
+EMSintnum = 0x67
+Intoffset = (EMSintnum * 4)
+
+.globl _main
+_main:
+
+driverhead:
+ .long -1 ! link to next device driver
+ .word 0xC000 ! attribute word for driver
+ .word Strategy ! ptr to strategy routine
+ .word Interrupt ! ptr to interrupt service routine
+ .ascii "EMMXXXX0" ! logical device name
+
+reqhead:
+ .long 0
+
+vectordone:
+ .word 0 ! != 0 , if vector installed
+
+FuncTable:
+ .word InitDrv ! initialize driver
+ .word Noop ! media Check
+ .word Noop ! build BPB
+ .word Noop ! Ioctl
+ .word Noop ! read
+ .word Noop ! non destructive read
+ .word Noop ! input status
+ .word Noop ! flush input
+ .word Noop ! write
+ .word Noop ! write with verify
+ .word Noop ! output status
+ .word Noop ! flush output
+ .word Noop ! ioctl output
+ .word Noop ! open device
+ .word Noop ! close device
+ .word Noop ! removeable media check
+
+Strategy:
+ seg cs
+ mov [reqhead], bx
+ seg cs
+ mov [reqhead+2],es
+ retf
+
+Interrupt:
+ push ax
+ push bx
+ push cx
+ push dx
+ push ds
+ push es
+ push di
+ push si
+ push bp
+
+ push cs
+ pop ds
+
+ les di,[reqhead] ! load pointer to request header
+
+ seg es
+ movb bl,[di+2]
+ xorb bh,bh
+ cmp bx, #NumFunc
+ jle dointr
+ call errorhandler
+ jmp intrend
+
+dointr:
+ shl bx,#1
+ call [bx+FuncTable]
+ les di,[reqhead] ! load pointer to request header
+
+intrend:
+ or ax,#0x100 ! done bit
+ seg es
+ mov [di+3],ax
+
+ pop bp
+ pop si
+ pop di
+ pop es
+ pop ds
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ retf
+
+errorhandler:
+ mov ax,#0x8003 ! report error to caller
+ ret
+
+
+! This is done for all functions except init. It supports the different
+! methods for an EMS installation check described in the LIM EMS 4.0 spec
+Noop:
+ call installvector
+ xor ax,ax
+ ret
+
+! The interrupt vector installed for int 0x67 points to this routine
+intr67:
+ push ax ! Save original AX
+ mov ah, #EMU_EMS ! Emuint function
+ mov al, #EMU_EMS_CALL ! Emuint subfunction
+ int EmulatorINT ! Call emulator for EMS
+ iret
+
+installvector:
+ push cs
+ pop ds ! load DS to use local data
+ mov ax,[vectordone]
+ cmp ax,#0
+ jne isinstalled ! already installed
+
+ push di ! save request header pointer
+ push es
+
+ mov ax, #0 ! write the new interrupt vector
+ mov es, ax
+ mov di, #Intoffset
+ seg es
+ mov [di], #intr67
+ seg es
+ mov [di+2], cs
+
+ pop es
+ pop di
+
+ mov ax,#1
+ mov [vectordone],ax
+
+isinstalled:
+ ret
+
+InitDrv:
+ push cs
+ pop ds
+ push ax
+ mov ah, #EMU_EMS ! Emuint function
+ mov al, #EMU_EMS_CTL ! Emuint subfunction
+ int EmulatorINT
+ cmp ax,#0 ! check if successful
+ je Fail
+
+ call installvector
+
+ push cs
+ pop ds
+
+ mov ah, #DOSMesg
+ mov dx, #Success
+ int 0x21
+
+ seg es
+ mov [di+14], #InitDrv ! address break for driver
+ seg es
+ mov [di+16], cs
+
+ xor ax,ax
+ ret
+
+Fail:
+ push cs
+ pop ds
+ mov ah, #DOSMesg
+ mov dx, #Failure
+ int 0x21
+
+ seg es
+ movb [di+13],#0
+ seg es
+ mov [di+20],cs
+ seg es
+ mov [di+14],#0 ! address break == 0, no driver
+ seg es
+ mov [di+16],cs
+ ret
+
+
+Success:
+ .ascii "Doscmd EMS 4.0 driver installed"
+ .byte cr,lf,eom
+
+Failure:
+ .byte cr,lf,lf
+ .ascii "EMS emulation is disabled"
+ .byte cr,lf
+ .ascii "Driver not installed"
+ .byte cr,lf,lf,eom
+
+ end
diff --git a/usr.bin/doscmd/emsdriv.sys.uu b/usr.bin/doscmd/emsdriv.sys.uu
new file mode 100644
index 0000000..fae517e
--- /dev/null
+++ b/usr.bin/doscmd/emsdriv.sys.uu
@@ -0,0 +1,11 @@
+begin 644 emsdriv.sys
+M_____P#`.`!#`$5-35A86%@P````````M`"``(``@`"``(``@`"``(``@`"`
+M`(``@`"``(``@``NB1X2`"Z,!A0`RU!345(>!E=650X?Q#X2`":*70(P_X/[
+M#WX%Z!P`ZPG1X_]7&,0^$@`-``$FB44#75Y?!Q]:65M8R[@#@,/H"P`QP,-0
+MM`*P`<W_SPX?H18`/0``=1M7!K@``([`OYP!)L<%A@`FC$T"!U^X`0"C%@##
+M#A]0M`*P`,W_/0``=!GHR?\.'[0)NO@`S2$FQT4.M``FC$T0,<###A^T";H:
+M`<TA)L9%#0`FC$T4)L=%#@``)HQ-$,-$;W-C;60@14U3(#0N,"!D<FEV97(@
+M:6YS=&%L;&5D#0HD#0H*14U3(&5M=6QA=&EO;B!I<R!D:7-A8FQE9`T*1')I
+5=F5R(&YO="!I;G-T86QL960-"@HD
+`
+end
diff --git a/usr.bin/doscmd/emuint.c b/usr.bin/doscmd/emuint.c
new file mode 100644
index 0000000..1b2bfdd7
--- /dev/null
+++ b/usr.bin/doscmd/emuint.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
+ * 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 immediately at the beginning of the file, witout modification,
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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$
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include "doscmd.h"
+#include "emuint.h"
+
+/* The central entry point for the emulator interrupt. This is used by
+ * different special programs to call the emulator from VM86 space.
+ * Look at emuint.h for definitions and a list of the currently defined
+ * subfunctions.
+ * To call emuint from VM86 space do:
+ * push ax Save original ax value (*must be done* !)
+ * mov ah, funcnum Emuint function number to ah
+ * mov al, subfunc Subfunction number, optional, depening on func
+ * int 0xff
+ * ..
+ * ..
+ * Emuint saves the function and subfunction numbers internally, then
+ * pops ax off the stack and calls the function handler with the original
+ * value in ax.
+ */
+void
+emuint(regcontext_t *REGS)
+{
+ u_short func, subfunc;
+
+ /* Remove function number from stack */
+ func = R_AH;
+ subfunc = R_AL;
+
+ R_AX = N_POP(REGS);
+
+ /* Call the function handler, subfunction is ignored, if unused */
+ switch (func)
+ {
+ /* The redirector call */
+ case EMU_REDIR:
+ intff(REGS);
+ break;
+
+ /* EMS call, used by emsdriv.sys */
+ case EMU_EMS:
+ {
+ switch (subfunc)
+ {
+ case EMU_EMS_CTL:
+ R_AX = (u_short)ems_init();
+ break;
+
+ case EMU_EMS_CALL:
+ ems_entry(REGS);
+ break;
+
+ default:
+ debug(D_ALWAYS, "Undefined subfunction for EMS call\n");
+ break;
+ }
+ break;
+ }
+
+ default:
+ debug(D_ALWAYS, "Emulator interrupt called with undefined function %02x\n", func);
+
+ /*
+ * XXX
+ * temporary backwards compatability with instbsdi.exe
+ * remove after a while.
+ */
+ fprintf(stderr, "***\n*** WARNING - unknown emuint function\n");
+ fprintf(stderr, "*** Continuing; assuming instbsdi redirector.\n");
+ fprintf(stderr, "*** Please install the new redirector");
+ fprintf(stderr, " `redir.com' as soon as possible.\n");
+ fprintf(stderr, "*** This compatability hack is not permanent.\n");
+ fprintf(stderr, "***\n");
+ N_PUSH(R_AX, REGS);
+ R_BX = R_ES;
+ R_DX = R_DI;
+ R_DI = R_DS;
+ intff(REGS);
+ break;
+ }
+}
diff --git a/usr.bin/doscmd/emuint.h b/usr.bin/doscmd/emuint.h
new file mode 100644
index 0000000..d90b60e
--- /dev/null
+++ b/usr.bin/doscmd/emuint.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
+ * 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 immediately at the beginning of the file, witout modification,
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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$
+ */
+
+
+/*
+ * The emulator helper interrupt:
+ *
+ * Interrupt 0xFF is used by some emulator functions. It is a portal into
+ * the emulator and cannot be used by ordinary DOS applications directly
+ * The interrupt 0xFF is called by helper functions under DOS (such as
+ * the redirector interfcae and the EMS emulation).
+ * There are functions and subfunctions defined. (See emuint.c for details)
+ */
+
+/* The redirector interface (formerly instbsdi.exe) */
+#define EMU_REDIR 0x1 /* Function for redirector interface */
+/* No subfunctions defined */
+
+/* Expanded memory (EMS) driver callback */
+#define EMU_EMS 0x2 /* Function for EMS driver control */
+/* subfunctions for EMS */
+#define EMU_EMS_CTL 0x0 /* Control function, used during init */
+#define EMU_EMS_CALL 0x1 /* Callback, calls are routed via this */
diff --git a/usr.bin/doscmd/instbsdi.c b/usr.bin/doscmd/instbsdi.c
deleted file mode 100644
index bfad58b..0000000
--- a/usr.bin/doscmd/instbsdi.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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/instbsdi.exe.uu b/usr.bin/doscmd/instbsdi.exe.uu
deleted file mode 100644
index e775c06..0000000
--- a/usr.bin/doscmd/instbsdi.exe.uu
+++ /dev/null
@@ -1,172 +0,0 @@
-begin 644 instbsdi.exe
-M35JK``8`!``@`($`__^+```(.VR.````'@````$`"@!P`)D````C`0``G@!P
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````58OLN#H`Z+T"N`X`
-M4"O`4(U&SE#H80:#Q`;&1L]2C4;J4(U&\E"-1LY0N"$`4.BS!8/$"(M&ZHE&
-MQHM&](E&YL=&S@9=C4;J4(U&\E"-1LY0N"$`4.B,!8/$"(M&\(E&S(M&^HE&
-MY(U&QE"-1LY0C4;<4+C_`%#H:@6+Y5W#M##-(3P"<P+-(+]L`(LV`@`K]X'^
-M`!!R`[X`$/J.UX'$[@'[<Q`6'^CW`3/`4.AV!+C_3,TA@^3^-HDF2``VB29$
-M`(O&L033X$@VHT(``_>)-@(`C,,KWO?;M$K-(3:,'KD`%@?\O^P!N?`!*\\S
-MP/.J%A_H.P`6'^B2`^@!`C/M_S;:`/\VV`#_-M8`Z/+^4.CB`+AL`([8N`,`
-M-L<&1@`$`E#H>P'H_0.X_P!0_Q9&`+0PS2&CNP"X`#7-(8D>IP",!JD`#A^X
-M`"6Z(@'-(18?BPX(`>,NC@:Y`":+-BP`Q08*`8S:,]LV_QX&`7,%%A_I30$V
-MQ08.`8S:NP,`-O\>!@$6'XX&N0`FBPXL`.,VCL$S_R:`/0!T++D,`+Z:`/.F
-M=`NY_W\SP/*N=1GKY08>!Q^+][_"`*R8D:S^P'0!2*KB]Q8?NP0`@*?"`+^X
-M`$3-(7(*]L*`=`6`C\(`0$MYY[X2`;\2`>BB`+X2`;\2`>B*`,-5B^R^[`&_
-M[`'H?0"^$@&_$@'H=`#K`U6+[+X2`;\2`>AF`+X2`;\2`>AL`.BY``O`=`N#
-M?@0`=07'1@3_`+D/`+L%`/:'P@`!=`2T/LTA0^+RZ`<`BT8$M$S-(8L."`'C
-M![L"`/\>!@$>Q1:G`+@`)<TA'X`^Y```=`T>H.4`Q1;F`+0ES2$?PSOW<PI/
-M3XL-X_;_T>ORPSOW<PZ#[P2+!0M%`G3R_QWK[L,`58OLN/P`4.A[`H,^Z@``
-M=`3_%NH`N/\`4.AI`HOE7<.X`@#I6_Y9B]PKV'(*.Q[L`'($B^/_X3/`Z47^
-M5C/VN4(`,N3\K#+@XON`]%5T#>BN_[@!`%#H+`*X`0!>PX\&[@"Z`@`X%KL`
-M="F.!KD`)HX&+`",!MX`,\"9N0"`,__RKJYU^T='B3[<`+G___*N]]&+T;\!
-M`+Z!`(X>N0"L/"!T^SP)=/<\#71O"L!T:T=.K#P@=.@\"73D/`UT7`K`=%@\
-M(G0D/%QT`T+KY#/)0:P\7'3Z/")T!`/1Z].+P='I$]&H`77*ZP%.K#P-="L*
-MP'0G/")TNCQ<=`-"Z^PSR4&L/%QT^CPB=`0#T>O;B\'1Z1/1J`%UTNN7%A^)
-M/M8``]='T><#UX#B_BOBB\2CV`"+V`/[%@<VB3]#0\4VW`"LJ@K`=?J^@0`V
-MCAZY`.L#,\"JK#P@=/L\"73W/`UU`^E_``K`=0/K>9`VB3]#0TZL/"!TVSP)
-M=-<\#71B"L!T7CPB="<\7'0#JNOD,\E!K#Q<=/H\(G0&L%SSJNO1L%S1Z?.J
-M<P:P(JKKQ4ZL/`UT+@K`="H\(G2W/%QT`ZKK[#/)0:P\7'3Z/")T!K!<\ZKK
-MV;!<T>GSJG.6L"*JZ\TSP*H6'\<'``#_)NX`58OL58X>N0`SR8O!B^F+^4F+
-M-BP`"_9T$([&)H`^````=`;RKD6N=?I%ET`D_HO]T>4#Q18?5[\)`.B%`%^+
-MSXO]`_B)+MH`'@>.WC/V2>,3@3P[0W0%B7X`146LJ@K`=?KB[8E.`!8?78OE
-M7<-5B^Q65QX'BU8$OAH!K3O"=!!`EG0,ES/`N?__\JZ+]^OKEE]>B^5=P@(`
-M58OL5_]V!.C+_PO`=!22B_HSP+G___*N]]%)NP(`M$#-(5^+Y5W"`@"+T`,&
-M2`!R-3D&0@!S)04/`%#1V+$#T^B,V8L>N0`KRP/!CL.+V+1*S2%8<A`D\$BC
-M0@"5BRY(``$62`##B\?ID?MR$S/`B^5=PW/X4.@8`%B+Y5W#<P?H#@"X__^9
-MB^5=PS+DZ`$`PZ*^``KD=2.`/KL``W(-/")S#3P@<@6P!>L'D#P3=@*P$[OP
-M`->8H[,`PXK$Z_=5B^Q65QZ#[`K&1O3-BT8$B$;U/"5T"CPF=`;&1O;+ZPS&
-M1OC+QD;W1,9&]D2,5O*-1O2)1O"+?@:+!8M=`HM-!(M5!HMU"/]U"HM^"HX%
-MCET&7U7_7O!=_%<>%A^+?@J,!8]%!HM^"(D%B5T"B4T$B54&B74(CT4*<@0S
-M]NL(Z$K_O@$`BP6)=0R#Q`H?7UZ+Y5W#58OLB]>,V([`BWX$B]^+3@CC%8I&
-M!HK@]\<!`'0"JDG1Z?.K$\GSJHOZDUW#`````````````````````````$U3
-M(%)U;BU4:6UE($QI8G)A<GD@+2!#;W!Y<FEG:'0@*&,I(#$Y.#@L($UI8W)O
-M<V]F="!#;W)P$0``````&P(``&P`````````````````````````````````
-M````````````````````````````````````````````````````````````
-M`````````$@`.T-?1DE,15])3D9/````````````````````````````````
-M```4`(&!@0$!````````````````````````````X`!L`$,`````````````
-M`/`"````%@("&`T)#`P,!P@6%O\2#1("_P``````````````````/#Q.35-'
-M/CX``%(V,#`P#0HM('-T86-K(&]V97)F;&]W#0H``P!2-C`P,PT*+2!I;G1E
-M9V5R(&1I=FED92!B>2`P#0H`"0!2-C`P.0T*+2!N;W0@96YO=6=H('-P86-E
-M(&9O<B!E;G9I<F]N;65N=`T*`/P`#0H`_P!R=6XM=&EM92!E<G)O<B```@!2
-M-C`P,@T*+2!F;&]A=&EN9R!P;VEN="!N;W0@;&]A9&5D#0H``0!2-C`P,0T*
-M+2!N=6QL('!O:6YT97(@87-S:6=N;65N=`T*`/___XD$BU[\N``"B4<"B40"
-MQ@<!@$P&`K@!`%Z+Y5W#58OL@^P"5H-^!`!T6X%^!C@!=`>!?@9``75VBUX&
-MBD<'F%#H_@V#Q`(+P'1DBT8&+3`!L0/3^(O(T>`#P='@!=`!B4;^_W8&Z$L`
-M@\0"BU[^Q@<`QT<"``"+7@:+\RO`B02)1P3K*I"+7@:!?P2@`W0'@7\$H`=U
-M&(I'!YA0Z*,-@\0""\!T"?]V!N@(`(/$`EZ+Y5W#58OL@^P$5U:+=@0K_XI$
-M!B0#/`)U1O9$!@AU&8O>@>LP`;$#T_N+P]'C`]C1X_:'T`$!=">+!"M$!(E&
-M_`O`?AM0_W0$BD0'F%#H8PF#Q`8[1OQT!X!,!B"___^+1`2)!,=$`@``B\=>
-M7XOE7<-5B^RX9`'H(?E75HMV!HV&GOZCC`.+1@BC?`.+1@2C<`/'!H8#``#'
-M!H0#``#I?`*`/"5T`^E8`L<&B`,!`"O`HW@#HW0#HX(#HW8#HX`#HWX#HW(#
-MHVX#HWH#QP:2`R``@'P!,'4\1L<&D@,P`.LS@#PK=0W_!G@#QP9^`P``ZR*0
-M@#P@=0V#/G@#`'45_P9^`^L/_P9N`^L)@#PM=='_!GH#1HH$F%#H]0>#Q`(+
-MP'7H5KB.`U#H9@>#Q`2+\(,^C@,`?0S_!GH#H8X#]]BCC@.`/"YU(_\&@`-&
-M5KB(`U#H/`>#Q`2+\(,^B`,`?0K'!H@#`0#_#H`#B@28/48`=#(]3@!T-3UH
-M`'0@/6P`=0;'!G8#`@"#/G8#`'4%@#Q,=0%&@#P`=1OIB`''!G8#`0#KX\<&
-M=@,0`.O;QP9V`P@`Z].*!)B)AIS^/44`=`H]1P!T!3U8`'4)_P9T`X.&G/X@
-MBX:<_BUC`#T5`'8#Z10!`\"3+O^GE@R+'GP#BQ^AA`.)!X,&?`,"Z6D!D/\&
-M@@/'!FX#``"X"@!0Z'\!@\0"Z5$!D+@(`.OPD/\&<@/_!G0#@SZ``P!U"<<&
-MB@,!`.L'D,<&B@,``/\&@`/'!H@#!`"#/G8#"'4#Z8@`*\"C=@.)1OPY!HX#
-M=">AC@.)1OR#/GH#`'0)QP:.`P``ZQ*0@RZ.`P6AC@,+P'T"*\"CC@.#!GP#
-M`K@0`%#H_P"#Q`*X.@!0Z,\#@\0"@W[\`'0B@SYZ`P!T%8M&_"T%`*..`PO`
-M?0(KP*..`^L'D,<&C@,``(,N?`,$N!``4.B^`(/$`ND?_[@0`.DO_RO`4.CB
-M`>DJ_Y"X`0#K\Y#_MIS^Z+D"Z1G_@SYV`P!T`XO&3HO^1X`]`'0%@#TE=?6+
-MQRO&4!Y6Z.T#@\0&B_>`/`!T`^E\_8,^A`,`=5F+'G`#]D<&('1/N/__ZTU"
-M#%X+2`Q(#$@,4@Q>"U(,4@Q2#%(,1@MR"W@+4@Q2##@,4@Q:"U(,4@PR#(,^
-MA@,`=!.#/H0#`'40BQYP`_9'!B!UM^L$1NN9D*&$`UY?B^5=PY!5B^R#[!A7
-M5H-^!`IT!/\&@@.#/G8#`G0'@SYV`Q!U%HL>?`.+!XM7`HE&_(E6_H,&?`,$
-MZRJ#/H(#`'01BQY\`XL'B4;\QT;^``#K#I"+'GP#BP>9B4;\B5;^@P9\`P*#
-M/FX#`'0-BT;\"T;^=`6+1@3K`BO`HY`#BS:,`X,^@@,`=2J#?OX`?22#?@0*
-M=1?&!"U&BT;\BU;^]]B#T@#WVHE&_(E6_L=&^`$`ZP7'1O@``(U&Z(OX_W8$
-M5_]V_O]V_.@S"8/$"(,^@`,`="%7Z`D)@\0"BPZ(`RO(B4[TZP60Q@0P1HO!
-M20O`?_6)3O2+#G0#B@6(!`O)=`<\87P#@"P@1D>`??\`=>F#/H(#`'44H7@#
-M"P9^`W0+@W[X`'4%N`$`ZP(KP%#HL@*#Q`)>7XOE7<.058OL@^P05U:#?@0`
-M=!2^`0"A?`.)1OB,7OJ#!GP#`NF1`(,^=@,0=1>+'GP#BP>+5P*)1OB)5OJ#
-M!GP#!.L5D(L>?`.+!XE&_(E&^(Q>^H,&?`,"@SYV`Q!U#8M&^`M&^G44N$H"
-MZPF#?OP`=0FX40*)1OB,7OJ+1OB+5OJ)1O*)5O0K]CDV@`-T'(L.B`/K#I#$
-M7O+_1O(F@#\`=!5&.\Y^$.OMD$;$7O+_1O(F@#\`=?.+/HX#*_Z#/GH#`'4'
-M5^@>`8/$`E;_=OK_=OCH;P&#Q`:#/GH#`'0'5^@#`8/$`EY?B^5=PU6+[(/L
-M!*%\`XE&_H-^!&=T!H-^!$=U!+`!ZP(JP(A&_(,^@`,`=0;'!H@#!@"`?OP`
-M=`V#/H@#`'4&QP:(`P$`_S9T`_\VB`/_=@3_-HP#_W;^_Q9T`H/$"H!^_`!T
-M$H,^;@,`=0O_-HP#_Q9V`H/$`H,^;@,`=!*#/H@#`'4+_S:,`_\6>@*#Q`*#
-M!GP#",<&D`,``*%X`PL&?@-T$_]V_O\6?`*#Q`(+P'0%N`$`ZP(KP%#H"`&+
-MY5W#58OL5H,^A@,`=2^+'G`#_T\">`Z*1@2+-_\'B`0JY.L+D%/_=@3HE?:#
-MQ`1`=0?_!H8#ZP60_P:$`UY=PY!5B^R#[`)75H,^A@,`=4F+=@0+]GY"ZQ7_
-M-G`#_S:2`^A=]H/$!$!U!/\&A@.+QDX+P'X6BQYP`_]/`GC;H)(#BS__!X@%
-M*N3KW(,^A@,`=0>+1@0!!H0#7E^+Y5W#58OL@^P"5U:+=@B#/H8#`'50ZQS_
-M-G`#Q%X$)HH'F%#H__6#Q`1`=03_!H8#_T8$B\9."\!T'8L><`/_3P)XU,1>
-M!":*!XL><`.+/_\'B`4JY.O2@SZ&`P!U!XM&"`$&A`->7XOE7<-5B^R#[`I7
-M5HLVC`,KP(E&_(E&^H,^D@,P=1@Y!H`#=!(Y!G(#=`8Y!HH#=0;'!I(#(`"+
-M/HX#5NC#!8/$`HE&^"OX*WX$@SYZ`P!U&(`\+743@SZ2`S!U#*R84.B=_H/$
-M`O].^(,^D@,P=`L+_WX'@SYZ`P!T&8-^!`!T!O]&^NA?`(,^D`,`=`;_1OSH
-M:@"#/GH#`'4F5^B?_H/$`H-^!`!T"8-^^@!U`^@U`(,^D`,`=`F#?OP`=0/H
-M/0#_=O@>5NC3_H/$!H,^>@,`=`W'!I(#(`!7Z&'^@\0"7E^+Y5W#@SYX`P!T
-M!;@K`.L#N"``4.@'_H/$`L.0N#``4.C[_8/$`H,^D`,0=1>#/G0#`'0&N%@`
-MZP20N'@`4.C=_8/$`L.058OL@^P$5U:+=@;'1OX!`(`\*G4/BQY\`XL_@P9\
-M`P)&ZTB0@#PM=0;'1O[__T8K_X`\,'PU@#PY?S`Y/H`#=0N`/#!U!L<&D@,P
-M`(H$F(O/T>'1X0//T>$#R(/I,(OY1H`\,'P%@#PY?N&+1O[W[XOXBUX$B3^+
-MQEY?B^5=PY!5B^R#[`)6OE@"BDX$ZP*01H`\`'0*.@QU]K@!`.L#D"O`7HOE
-M7<.058OL@^P$BUX$.Q[J`'(%N``)ZRKW1@@`@'1(@WX*`'0:,\F+T;@!0LTA
-M<DOW1@H"`'4.`T8&$U8(>2BX`!;YZS:)5OZ)1OR+T;@"0LTA`T8&$U8(>0V+
-M3OZ+5ORX`$+-(>O8BU8&BTX(BD8*M$+-(7(%@*?L`/WIQ?)5B^R#[`B+7@0[
-M'NH`<@>X``GYZ:_R]H?L`"!T"[@"0C/)B]'-(7+K]H?L`(!T;HM6!AX',\")
-M1OZ)1OS\5U:+^HORB6;XBTX(XU2P"O*N=4KHU``]J`!V2(/L`HO<N@`"/2@"
-M<P.Z@``KXHO4B_H6!XM."*P\"G0,._MT&:KB].@C`.MAL`T[^W4#Z!@`JK`*
-M_T;\Z^/H#0#KXEY?ZU7K13/`Z9WM4%-1B\\KRN,0BUX$M$#-(7(-`4;^"\!T
-M!EE;6(OZPX/$"',$M`GK'O:'[`!`=`N+7@:`/QIU`_CK#/FX`!SK!HM&_BM&
-M_(MF^%Y?Z='QBTX("\EU!8O!Z<7QBU8&M$#-(7,$M`GKY`O`=>#VA^P`0'0*
-MB]J`/QIU`_CKS_FX`!SKR5FA%@$[Q',&*\3WV/_A,\#K^E6+[(M>!`O;=`2`
-M3_X!B^5=PU6+[%97NUX"@S\`=2D>![@%`.AS`74%,\"9ZR1`)/ZC7@*C8`*6
-MQP0!`(/&!,=$_O[_B39D`HM.!(S8CL#H"0!?7HOE7</IS@!!=/J`X?Z#^>YS
-M\HMW`ORMB_ZH`71"2#O!<Q6+T`/PK:@!=#0#P@4"`(OWB43^Z^:+_G0,`_F)
-M3/XKP4B)!>L%`_G^3/Z+QHS:C-$[T70%)HP>;`*)?P+#)L8&<@("/?[_="6+
-M_@/PK:@!=/*+_D@[P7.]B]`#\*VH`73B`\(%`@"+]XE$_NOFBT<("\!T!([8
-MZQ0F_@YR`G01C-B,USO'=`4FCAYH`HLWZ[R+=P8SP.AJ`#O&=`TD`4!`F.A>
-M`'0-_DW^Z!P`=`663D[KF8S8C-$[P70$)J-L`HL'B4<",\"9PU&+1?ZH`70#
-M*\A)04&Z_W\F.Q9N`G8$T>IU]8O!`\9R%0/"<@WWTB/"*\;H#`!U"/?2T>IU
-MY3/`6<-24>@=`'085XO^B_`#\L=$_O[_B7<&B]8KUTJ)5?Y865K#4U`STAY2
-M4E"X`0!0!A_H#P"#Q`B#^O\?6EMT`@O2PP!5B^Q65P:#?@@`=3B_<@"+5@:+
-M1@1(=0?H4P!R)^M(BS;"`$AT$3OW=`V+1`*)1@Q6Z#H`7G,P@\8$@?["`',$
-M"])U!KC__YGK'8O:@\,/T=NQ`]/KM$C-(7+IDHD$B50"B3;"`#/`!U]>B^5=
-MPXM.#(OW.4P"=`R#Q@2!_L(`=?+YZS^+V@,<<CF+TX[!._=U!CD>;`!S)H/#
-M#]';T>O1Z]'K._=U"0/9H>,`*]B.P+1*S2%R#3OW=02)%FP`DH<$B]'#58OL
-MB]>,V([`BWX$,\"Y___RKO?129&+^EW#`%6+[%97LP#IY@!5B^R+7@0['NH`
-M?1&#^P!\#/:'[`!`=`6X`0#K`C/`B^5=PP!5B^Q65QZ#[`K&1O3-BT8$B$;U
-M/"5T"CPF=`;&1O;+ZPS&1OC+QD;W1,9&]D2,5O*-1O2)1O"+?@:+!8M=`HM-
-M!(M5!HMU"/]U"HM^"HX%CET&7U7_7O!=_%<>%A^+?@J,!8]%!HM^"(D%B5T"
-MB4T$B54&B74(CT4*<@0S]NL(Z$[NO@$`BP6)=0R#Q`H?7UZ+Y5W#58OLB]>,
-MV([`BWX$B]^+3@CC%8I&!HK@]\<!`'0"JDG1Z?.K$\GSJHOZDUW#`(M."HM&
-M!(M6!HM^"%<>!_R3"L!T$X/Y"G4."])Y"K`MJO?;@](`]]J+]Y(ST@O`=`+W
-M\9/W\9*'TP0P/#EV`@0GJHO""\-UXH@%3ZR&!8A$_XU$`3O'<O)87UZ+Y5W#
-M``````````````````````````````!-4R!2=6XM5&EM92!,:6)R87)Y("T@
-M0V]P>7)I9VAT("AC*2`Q.3@X+"!-:6-R;W-O9G0@0V]R<!$`3$],(&ES(&%T
-M("4P-'@Z)3`T>`H`4T1!(&ES(&%T("4P-'@Z)3`T>`H``````#L"``"$`0``
-M````````````````````````````````````````````````````````````
-M``````````````````````````````````````!R`#M#7T9)3$5?24Y&3P``
-M````````````````````````````````%`"!@8$!`0``````````````````
-M``````````H!A`%#``````````````"@"@```!8"`A@-"0P,#`<(%A;_$@T2
-M`O\``*`%``"@!0$``````````@$````````"`@```````(0#`````````@0`
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M```````````````````````````````````````!```"````````````````
-M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````````````````
-M``````````````````#(`2AN=6QL*0`H;G5L;"D`*RT@(P``````````````
-M```````````@`````/`"\`+P`O`"\`(``````````````````````````!0&
-M/#Q.35-'/CX``%(V,#`P#0HM('-T86-K(&]V97)F;&]W#0H``P!2-C`P,PT*
-M+2!I;G1E9V5R(&1I=FED92!B>2`P#0H`"0!2-C`P.0T*+2!N;W0@96YO=6=H
-M('-P86-E(&9O<B!E;G9I<F]N;65N=`T*`/P`#0H`_P!R=6XM=&EM92!E<G)O
-M<B```@!2-C`P,@T*+2!F;&]A=&EN9R!P;VEN="!N;W0@;&]A9&5D#0H``0!2
-E-C`P,0T*+2!N=6QL('!O:6YT97(@87-S:6=N;65N=`T*`/___V5D
-`
-end
diff --git a/usr.bin/doscmd/intff.c b/usr.bin/doscmd/intff.c
index e27ac0e..0633246 100644
--- a/usr.bin/doscmd/intff.c
+++ b/usr.bin/doscmd/intff.c
@@ -29,7 +29,7 @@
*
* 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 $
+ * $Id: intff.c,v 1.1 1997/08/09 01:42:51 dyson Exp $
*/
#include "doscmd.h"
@@ -787,17 +787,17 @@ init_drives(void)
}
}
+
void
intff(regcontext_t *REGS)
{
- if (lol && sda) { /* already been called? */
+ 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);
-
+ lol = (LOL *)N_GETPTR(R_BX, R_DX); /* where DOS keeps its goodies */
+ sda = (SDA *)N_GETPTR(R_DI, R_SI);
init_drives();
/* initialise dispatcher */
diff --git a/usr.bin/doscmd/redir.S b/usr.bin/doscmd/redir.S
new file mode 100644
index 0000000..4cb4e2e
--- /dev/null
+++ b/usr.bin/doscmd/redir.S
@@ -0,0 +1,122 @@
+! Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
+! 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 immediately at the beginning of the file, witout modification,
+! 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. The name of the author may not be used to endorse or promote products
+! derived from this software without specific prior written permission.
+!
+! THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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$
+
+
+!
+! This is the new redirector program, it replaces instbsdi.exe
+! The program fetches some pointers from DOS and reports them back to
+! the emulator via the emulator interrupt 0xff. It does not stay resident.
+
+use16
+
+.text
+.bss
+.data
+.align 0
+
+! Emulator interrupt entry
+EmulatorINT = 0xFF
+! Emulator redirector function
+EmulatorRED = 0x1
+
+! DOS interrupt
+DOSInt = 0x21
+
+! DOS get list of lists call, returns pointer to system vars in ES:BX
+DOSGetList = 0x52
+
+! DOS get swappable area, returns DOS swappable area in DS:SI
+DOSGetSwapD = 0x5D06
+
+! DOS terminate program with return code
+DOSExit = 0x4C
+
+! DOS print message
+DOSMesg = 0x9
+
+cr = 0xd
+lf = 0xa
+eom = '$' ! DOS end of string
+
+ .org 0x100
+
+.globl _main
+_main:
+
+ mov ah, #DOSGetList
+ int DOSInt
+ jc Fail
+ mov [_list], bx
+ mov ax, es
+ mov [_list+2], ax
+ push ds
+ mov ax, #DOSGetSwapD
+ int DOSInt
+ mov ax, ds
+ pop ds
+ jc Fail
+ mov [_swap], si
+ mov [_swap+2], ax
+ push ax
+ mov ah, #EmulatorRED
+ mov dx, [_list]
+ mov bx, [_list+2]
+ mov si, [_swap]
+ mov di, [_swap+2]
+ int EmulatorINT
+ xor al, al ! return 0
+ jmp Exit
+Fail:
+ mov ah, #DOSMesg
+ mov dx, #ErrorMessage
+ int DOSInt
+ mov al, #1 ! return 1
+Exit:
+ mov ah, #DOSExit
+ int DOSInt
+!
+! Should never get to this point
+!
+ nop
+ nop
+ hlt
+
+! The two pointers are found using the DOS calls
+! and passed to the redirector interface via int FF
+! The two pointers are passed in BX:DX (list) and DI:SI (swap)
+
+.align 2
+
+_list: .word 0
+ .word 0
+_swap: .word 0
+ .word 0
+
+ErrorMessage:
+ .ascii "Error installing redirector interface"
+ .byte cr,lf,eom, 0
diff --git a/usr.bin/doscmd/redir.com.uu b/usr.bin/doscmd/redir.com.uu
new file mode 100644
index 0000000..0bdf492
--- /dev/null
+++ b/usr.bin/doscmd/redir.com.uu
@@ -0,0 +1,6 @@
+begin 644 redir.com
+MM%+-(7(TB1Y*`8S`HTP!'K@&7<TAC-@?<B")-DX!HU`!4+0!BQ9*`8L>3`&+
+M-DX!BSY0`<W_,,#K";0)NE(!S2&P`;1,S2&0D/0``````````$5R<F]R(&EN
+B<W1A;&QI;F<@<F5D:7)E8W1O<B!I;G1E<F9A8V4-"B0`````
+`
+end
diff --git a/usr.bin/doscmd/trap.c b/usr.bin/doscmd/trap.c
index 7f11368..a3d5af0 100644
--- a/usr.bin/doscmd/trap.c
+++ b/usr.bin/doscmd/trap.c
@@ -29,7 +29,7 @@
*
* 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 $
+ * $Id: trap.c,v 1.1 1997/08/09 01:42:58 dyson Exp $
*/
#include "doscmd.h"
@@ -63,7 +63,7 @@ fake_int(regcontext_t *REGS, int intnum)
int2f(&REGS->sc);
break;
case 0xff: /* doscmd special */
- intff(REGS);
+ emuint(REGS);
break;
default: /* should not get here */
if (vflag) dump_regs(REGS);
@@ -581,7 +581,7 @@ sigalrm(struct sigframe *sf)
update_counter = 0; /* remember we've updated */
video_update(&REGS->sc);
hardint(0x08);
-/* debug(D_ALWAYS,"\n"); */
+/* debug(D_ALWAYS,"\n"); */
if (tmode)
tracetrap(REGS);
@@ -604,6 +604,9 @@ sigfpe(struct sigframe *sf)
regcontext_t *REGS = (regcontext_t *)(&sf->sf_sc);
if (R_EFLAGS & PSL_VM) {
+ dump_regs(REGS);
+ debug(D_ALWAYS, "DOS program caused floating point fault\n");
+/*XXX Look into that !! */
fake_int(REGS, 0); /* call handler XXX rather bogus, eh? */
return;
}
diff --git a/usr.bin/doscmd/xms.c b/usr.bin/doscmd/xms.c
index f9df109..81ba91b 100644
--- a/usr.bin/doscmd/xms.c
+++ b/usr.bin/doscmd/xms.c
@@ -25,7 +25,7 @@
* (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$
+ * $Id: xms.c,v 1.2 1997/08/15 23:41:25 jlemon Exp $
*/
/*
@@ -111,7 +111,10 @@ xms_init(void)
add_block(&UMB_freelist, create_block(0xd0000, 64*1024));
/*XXX check for EMS emulation, when it is done! */
/* 0xE0000 to 0xEffff */
- add_block(&UMB_freelist, create_block(0xe0000, 64*1024));
+
+/* This is used as window for EMS, will be configurable ! */
+/* add_block(&UMB_freelist, create_block(0xe0000, 64*1024)); */
+
merge_blocks();
xms_vector = insert_generic_trampoline(
@@ -142,8 +145,7 @@ add_block(UMB_block **listp, UMB_block *blk)
if (*listp == NULL) {
*listp = blk;
blk->next = NULL;
- }
- else {
+ } else {
/* Insert at the start */
bp = obp = *listp;
if (blk->addr < bp->addr) {
@@ -156,8 +158,7 @@ add_block(UMB_block **listp, UMB_block *blk)
if (blk->addr > bp->addr) {
obp = bp;
continue;
- }
- else {
+ } else {
obp->next = blk;
blk->next = bp;
return;
@@ -228,10 +229,10 @@ merge_blocks()
bp->size += mergebp->size;
bp->next = mergebp->next;
free(mergebp);
- }
- else
+ } else {
/* Goto next block */
bp = bp->next;
+ }
} while (bp != NULL);
}
@@ -485,13 +486,19 @@ static void
xms_entry(regcontext_t *REGS)
{
- if (R_AH != 0) {
- if (HMA_a20 < 0) { /* This feature is disabled */
- R_AX = 0x0;
- R_BL = XMS_HMA_NOT_MANAGED;
- return;
- }
+ if (R_AH != 0)
vec_grabbed = 1;
+
+ /* If the HMA feature is disabled these calls are "not managed" */
+ if (HMA_a20 < 0) {
+ if (R_AH == XMS_ALLOCATE_HIGH_MEMORY || R_AH == XMS_FREE_HIGH_MEMORY ||
+ R_AH == XMS_GLOBAL_ENABLE_A20 || R_AH == XMS_GLOBAL_DISABLE_A20 ||
+ R_AH == XMS_LOCAL_ENABLE_A20 || R_AH == XMS_LOCAL_DISABLE_A20 ||
+ R_AH == XMS_QUERY_A20) {
+ R_AX = 0x0;
+ R_BL = XMS_HMA_NOT_MANAGED;
+ return;
+ }
}
switch (R_AH) {
@@ -513,8 +520,7 @@ xms_entry(regcontext_t *REGS)
if (HMA_allocated) {
R_AX = 0x0;
R_BL = XMS_HMA_ALREADY_USED;
- }
- else {
+ } else {
HMA_allocated = 1;
R_AX = 0x1;
R_BL = XMS_SUCCESS;
@@ -527,8 +533,7 @@ xms_entry(regcontext_t *REGS)
HMA_allocated = 0;
R_AX = 0x1;
R_BL = XMS_SUCCESS;
- }
- else {
+ } else {
R_AX = 0x0;
R_BL = XMS_HMA_NOT_ALLOCATED;
}
@@ -588,8 +593,19 @@ xms_entry(regcontext_t *REGS)
break;
case XMS_QUERY_FREE_EXTENDED_MEMORY:
- R_AX = R_DX = xms_free_mem / 1024;
- R_BL = XMS_SUCCESS;
+ /* DOS MEM.EXE chokes, if the HMA is enabled and the reported
+ * free space includes the HMA. So we subtract 64kB from the
+ * space reported, if the HMA is enabled.
+ */
+ if (HMA_a20 < 0)
+ R_EAX = R_EDX = xms_free_mem / 1024;
+ else
+ R_EAX = R_EDX = (xms_free_mem / 1024) - 64;
+
+ if (xms_free_mem == 0)
+ R_BL = XMS_FULL;
+ else
+ R_BL = XMS_SUCCESS;
debug(D_XMS, "XMS: Query free EMM: Returned %dkB\n", R_AX);
break;
@@ -626,10 +642,10 @@ xms_entry(regcontext_t *REGS)
* but with no memory attached ? XMS specs are unclear on
* that point. Linux implementation does it this way.
*/
- if (req_siz == 0)
+ if (req_siz == 0) {
/* This handle is reserved, but has size 0 and no address */
xms_hand[hindx].addr = XMS_NULL_ALLOC;
- else {
+ } else {
if ((mem = malloc(req_siz)) == NULL)
fatal("XMS: Cannot malloc !");
xms_hand[hindx].addr = (u_long)mem;
@@ -663,13 +679,13 @@ xms_entry(regcontext_t *REGS)
R_AX = 0x0;
R_BL = XMS_INVALID_HANDLE;
debug(D_XMS, " Invalid handle\n");
- }
- else if (xms_hand[hindx].num_locks > 0) {
+
+ } else if (xms_hand[hindx].num_locks > 0) {
R_AX = 0x0;
R_BL = XMS_BLOCK_IS_LOCKED;
debug(D_XMS, " Is locked\n");
- }
- else {
+
+ } else {
if (xms_hand[hindx].addr != XMS_NULL_ALLOC) {
free((void *)xms_hand[hindx].addr);
xms_free_mem += xms_hand[hindx].size;
@@ -724,7 +740,7 @@ xms_entry(regcontext_t *REGS)
srcoffs = eptr->src_offset;
dstoffs = eptr->dst_offset;
n = eptr->nbytes;
- /* Lenght must be even, see XMS spec */
+ /* Length must be even, see XMS spec */
if (n & 1) {
R_AX = 0x0;
R_BL = XMS_INVALID_LENGTH;
@@ -746,8 +762,7 @@ xms_entry(regcontext_t *REGS)
break;
}
srcptr += srcoffs;
- }
- else {
+ } else {
srcptr = VECPTR(srcoffs);
/* Sanity check: Don't allow srcptr pointing to
* emulator data above 1M
@@ -775,8 +790,7 @@ xms_entry(regcontext_t *REGS)
break;
}
dstptr += dstoffs;
- }
- else {
+ } else {
dstptr = VECPTR(dstoffs);
/* Sanity check: Don't allow dstptr pointing to
* emulator data above 1M
@@ -863,7 +877,7 @@ xms_entry(regcontext_t *REGS)
{
int hnum,hindx;
- debug(D_XMS, "XMS: Get handle information: DX=%04x\n, R_DX");
+ debug(D_XMS, "XMS: Get handle information: DX=%04x\n", R_DX);
hnum = R_DX;
if (hnum > NUM_HANDLES || hnum == 0) {
R_AX = 0x0;
@@ -933,8 +947,7 @@ xms_entry(regcontext_t *REGS)
fatal("XMS: Cannot malloc !");
xms_hand[hindx].addr = (u_long)mem;
xms_hand[hindx].size = req_siz;
- }
- else {
+ } else {
if ((mem = realloc((void *)xms_hand[hindx].addr,req_siz))
== NULL)
fatal("XMS: Cannot realloc !");
@@ -978,13 +991,13 @@ xms_entry(regcontext_t *REGS)
R_AX = 0x0;
R_BL = XMS_NO_UMBS_AVAILABLE;
R_DX = 0x0;
- }
- else if (bp->size < req_siz) {
+
+ } else if (bp->size < req_siz) {
R_AX = 0x0;
R_BL = XMS_REQUESTED_UMB_TOO_BIG;
R_DX = bp->size / 16;
- }
- else {
+
+ } else {
UMB_block *newbp;
/* Found a block large enough. Split it into the size
* we need, rest remains on the free list. New block
@@ -1011,8 +1024,7 @@ xms_entry(regcontext_t *REGS)
if ((blk = find_allocated_block(req_addr)) == NULL) {
R_AX = 0x0;
R_BL = XMS_INVALID_UMB_SEGMENT;
- }
- else {
+ } else {
/* Move the block from the alloc list to the free list
* and try to do garbage collection
*/
@@ -1037,6 +1049,27 @@ xms_entry(regcontext_t *REGS)
R_BL = XMS_NOT_IMPLEMENTED;
break;
+ /* Some test programs use this call */
+ case XMS_QUERY_FREE_EXTENDED_MEMORY_LARGE:
+ /* DOS MEM.EXE chokes, if the HMA is enabled and the reported
+ * free space includes the HMA. So we subtract 64kB from the
+ * space reported, if the HMA is enabled.
+ */
+ if (HMA_a20 < 0)
+ R_EAX = R_EDX = xms_free_mem / 1024;
+ else
+ R_EAX = R_EDX = (xms_free_mem / 1024) - 64;
+ /* ECX should return the highest address of any memory block
+ * We return 1MB + size of extended memory
+ */
+ R_ECX = 1024 * 1024 + xms_maxsize -1;
+ if (xms_free_mem == 0)
+ R_BL = XMS_FULL;
+ else
+ R_BL = XMS_SUCCESS;
+ debug(D_XMS, "XMS: Query free EMM(large): Returned %dkB\n", R_AX);
+ break;
+
/* These are the same as the above functions, but they use 32 bit
* registers (i.e. EDX instead of DX). This is for allocations of
* more than 64MB. I think this will hardly be used in the emulator
@@ -1044,10 +1077,9 @@ xms_entry(regcontext_t *REGS)
* spec. If something breaks because they are not here, I can implement
* them
*/
- case XMS_QUERY_FREE_EXTENDED_MEMORY_LARGE:
case XMS_ALLOCATE_EXTENDED_MEMORY_LARGE:
case XMS_FREE_EXTENDED_MEMORY_LARGE:
- debug(D_XMS, "XMS: 8x function called, not implemented\n");
+ debug(D_XMS, "XMS: %02x function called, not implemented\n", R_AH);
R_AX = 0x0;
R_BL = XMS_NOT_IMPLEMENTED;
break;
OpenPOWER on IntegriCloud