Hello.

I needed to run some commercial DOS-based multitasking
environment recently, which doesn't work under dosbox.
It implements the memory context switching by the use of
EMS. dosemu doesn't support this, but it was easy to implement,
so the patch is attached.
There is still a problem with this patch that I'd like to address
to make sure the multitasker will work reliably.
It defeats the meaning of IS_GENERIC_LOWMEM_ADDR().
In the patch I just removed it entirely to make things a go,
otherwise the multitasker just crashes here and there, but
my concern is that it will crash sooner or later again, because,
with the 0-based conv memory, dosemu will attempt to write
to zero page.
I can see the following solutions to this:
1. Make IS_GENERIC_LOWMEM_ADDR() end at 0x40000,
rather than at 0xa0000. This will work because in my patch
I made it so the addresses below 0x40000 are never mappable,
but who knows if some other multitasker will require also this.
2. Introduce the lowmem_alias maintained by mapping.c.
Actually, when I introduced lowmem_base, the intention was
only to provide it to the different "mappers", like EMS/HMA/DPMI.
Only much later someone started to use it as an alias for zero-page,
but maybe this should not have been done.
3. Make a fully functional dosaddr_to_unixaddr(), not just
a quick hack it currently is. It should use the proper reverse-mapping
maintained by mapping.c, instead of relying on a "map_char".

I think the most "correct" approach is 3, while the simplest is 1.
I personally wouldn't go for 2, but the changelog suggests that
2 was attempted at times already.
Then, if this is fixed, I think all the uses of LOWMEM() should
be killed, except those intended initially: for the use by the mappers.
No one, except "mappers", should use LOWMEM(). Fortunately,
the uses of LOWMEM() are already very few in the code.

I cannot understand what lowmemp() does. It seems to take the
dos pointer, but, for the "side-mapped" areas, it returns that
pointer directly, both without adjusting it to mem_base, and
without looking up the mapping source. How does this work?

My patch also touches dosdebug: that's a hack too, but
otherwise dosdebug just randomly exits for me. What's the
use of searching for 1 in the read buffer?

Also, there seems to be the e_invalidate() calls spread around
the code. I haven't added them to my patch because I don't
think its the right thing to do, but again, this may introduce
the instability. We already have the macros to access the DOS
memory, so why was it necessary to litter with the e_invalidate()
calls, forcing everyone to include "cpu-emu.h"?

But the good thing is that the aforementioned multitasker
works under (patched) dosemu even on x86_64. I am surprised
with how mature the CPU emulator is; it was barely usable
the last time I looked. :) I think KVM also has the CPU emulator
builtin. Was this considered as the speedup?
Index: etc/dosemu.conf
===================================================================
--- etc/dosemu.conf     (revision 2065)
+++ etc/dosemu.conf     (working copy)
@@ -137,15 +137,27 @@
 # give you the additional 64K of UMB space, but as a side-effect
 # it will also disable the protected mode DOS API translator,
 # making many protected-mode apps to crash.
-# Default: 2048
+# Default: 8192
 
-# $_ems = (2048)
+# $_ems = (8192)
 
 # DOS segment where the EMS frame is put.
 # Default: 0xe400
 
 # $_ems_frame = (0xe400)
 
+# the amount of EMS-mappable pages in UMA.
+# Possible values: 0 to 12
+# Default: 4
+
+# $_ems_uma_pages = (4)
+
+# the amount of EMS-mappable pages in conventional memory.
+# Possible values: 0 to 24
+# Default: 24
+
+# $_ems_conv_pages = (24)
+
 # DPMI memory size in Kbytes; default: 0x5000
 
 # $_dpmi = (0x5000)
Index: etc/global.conf
===================================================================
--- etc/global.conf     (revision 2065)
+++ etc/global.conf     (working copy)
@@ -154,7 +154,8 @@
     checkuservar $_debug, $_trace_ports,
       $_features, $_mapping, $_hogthreshold, $_cli_timeout, $_pic_watchdog,
       $_timemode,
-      $_mathco, $_cpu, $_cpu_emu, $_rdtsc, $_cpuspeed, $_xms, $_ems, 
$_ems_frame,
+      $_mathco, $_cpu, $_cpu_emu, $_rdtsc, $_cpuspeed, $_xms, $_ems,
+      $_ems_frame, $_ems_uma_pages, $_ems_conv_pages,
       $_ext_mem, $_dpmi, $_dpmi_base, $_ignore_djgpp_null_derefs, $_emusys,
       $_emuini, $_dosmem, $_full_file_locks, $_lfn_support
     checkuservar
@@ -224,7 +225,16 @@
   endif
   xms 0
   $_pm_dos_api = $_ems;                # disabling EMS disables also the 
translator
-  if ($_ems || ($_dpmi && $_pm_dos_api)) ems { ems_size $_ems ems_frame 
$_ems_frame } else ems off endif
+  if ($_ems || ($_dpmi && $_pm_dos_api))
+    ems {
+          ems_size $_ems
+          ems_frame $_ems_frame
+          ems_uma_pages $_ems_uma_pages
+          ems_conv_pages $_ems_conv_pages
+        }
+  else
+    ems off
+  endif
   dpmi $_dpmi
   dpmi_base $_dpmi_base
   pm_dos_api $_pm_dos_api
Index: src/dosext/misc/emm.c
===================================================================
--- src/dosext/misc/emm.c       (revision 2065)
+++ src/dosext/misc/emm.c       (working copy)
@@ -40,8 +40,8 @@
  * In contrast to some of the comments (Yes, _I_ know the adage about that...)
  * we appear to be supporting EMS 4.0, not 3.2.  The following EMS 4.0
  * functions are not supported (yet): 0x4f (partial page map functions),
- * 0x55 (map pages and jump), and 0x56 (map pages and call).  OS handle
- * support is missing, and raw page size is 16k (instead of 4k).  Other than
+ * 0x55 (map pages and jump), and 0x56 (map pages and call),
+ * and raw page size is 16k (instead of 4k).  Other than
  * that, EMS 4.0 support appears complete.
  *
  * /REMARK
@@ -134,13 +134,6 @@
 #define GET_ARRAY              0
 #define GET_RAW_PAGECOUNT      1
 
-#if 0
-#define        EMM_BASE_ADDRESS 0xd0000
-#define        EMM_SEGMENT      0xd000
-#else
-/* now defined in emu.h */
-#endif
-
 /* Support EMM version 3.2 */
 #define EMM_VERS       0x40    /* was 0x32 */
 
@@ -168,27 +161,26 @@
 
 #define EMM_TOTAL      MAX_EMM
 
-static int handle_total, emm_allocated;
+static int handle_total, emm_allocated, phys_pages, saved_phys_pages;
+static u_short cnv_start_seg;
+static u_short cnv_pages_start;
 
 static struct emm_record {
-  int handle;
-  int logical_page;
+  u_short handle;
+  u_short logical_page;
+  u_short phys_seg;
 } emm_map[EMM_MAX_PHYS];
 
 static struct handle_record {
   u_char active;
   int numpages;
   void *object;
-  size_t objsize;
   char name[9];
-  int saved_mappings_handle[EMM_MAX_PHYS];
-  int saved_mappings_logical[EMM_MAX_PHYS];
+  u_short saved_mappings_handle[EMM_MAX_SAVED_PHYS];
+  u_short saved_mappings_logical[EMM_MAX_SAVED_PHYS];
 } handle_info[MAX_HANDLES];
 
 #define OS_HANDLE      0
-#define OS_PORT                (256*1024)
-#define OS_SIZE                (640*1024 - OS_PORT)
-#define OS_PAGES       (OS_SIZE / (16*1024))
 
 /* For OS use of EMM */
 static u_char  os_inuse=0;
@@ -228,7 +220,7 @@
      (unsigned)WORD(state->eax))); }
 
 #define PHYS_PAGE_SEGADDR(i) \
-  (EMM_SEGMENT + (0x400 * (i)))
+  (emm_map[i].phys_seg)
 
 #define PHYS_PAGE_ADDR(i) \
   (PHYS_PAGE_SEGADDR(i) << 4)
@@ -314,8 +306,7 @@
   return addr;
 }
 
-static int
-allocate_handle(int pages_needed)
+int emm_allocate_handle(int pages_needed)
 {
   int i, j;
   void *obj;
@@ -348,7 +339,7 @@
       CLEAR_HANDLE_NAME(handle_info[i].name);
       handle_total++;
       emm_allocated += pages_needed;
-      for (j = 0; j < EMM_MAX_PHYS; j++) {
+      for (j = 0; j < saved_phys_pages; j++) {
        handle_info[i].saved_mappings_logical[j] = NULL_PAGE;
       }
       handle_info[i].active = 1;
@@ -359,15 +350,14 @@
   return (EMM_ERROR);
 }
 
-static boolean_t
-deallocate_handle(int handle)
+boolean_t emm_deallocate_handle(int handle)
 {
   int numpages, i;
   void *object;
 
   if ((handle < 0) || (handle >= MAX_HANDLES))
     return (FALSE);
-  for (i = 0; i < EMM_MAX_PHYS; i++) {
+  for (i = 0; i < phys_pages; i++) {
     if (emm_map[i].handle == handle) {
       unmap_page(i);
       emm_map[i].handle = NULL_HANDLE;
@@ -406,13 +396,6 @@
        PROT_READ | PROT_WRITE | PROT_EXEC, base);
 }
 
-void emm_unmap_all()
-{
-  if (!config.ems_size)
-    return;
-  _do_unmap_page(EMM_BASE_ADDRESS, EMS_FRAME_SIZE);
-}
-
 static boolean_t
 __map_page(int physical_page)
 {
@@ -420,7 +403,7 @@
   caddr_t logical;
   unsigned int base;
 
-  if ((physical_page < 0) || (physical_page >= EMM_MAX_PHYS))
+  if ((physical_page < 0) || (physical_page >= phys_pages))
     return (FALSE);
   handle=emm_map[physical_page].handle;
   if (handle == NULL_HANDLE)
@@ -429,7 +412,7 @@
   E_printf("EMS: map()ing physical page 0x%01x, handle=%d, logical page 
0x%x\n", 
            physical_page,handle,emm_map[physical_page].logical_page);
 
-  base = EMM_BASE_ADDRESS + (physical_page * EMM_PAGE_SIZE);
+  base = PHYS_PAGE_ADDR(physical_page);
   logical = handle_info[handle].object + emm_map[physical_page].logical_page * 
EMM_PAGE_SIZE;
 
   _do_map_page(base, logical, EMM_PAGE_SIZE);
@@ -442,7 +425,7 @@
   int handle;
   unsigned int base;
 
-  if ((physical_page < 0) || (physical_page >= EMM_MAX_PHYS))
+  if ((physical_page < 0) || (physical_page >= phys_pages))
     return (FALSE);
   handle=emm_map[physical_page].handle;
   if (handle == NULL_HANDLE)
@@ -451,10 +434,10 @@
   E_printf("EMS: unmap()ing physical page 0x%01x, handle=%d, logical page 
0x%x\n", 
            physical_page,handle,emm_map[physical_page].logical_page);
 
-  base = EMM_BASE_ADDRESS + (physical_page * EMM_PAGE_SIZE);
+  base = PHYS_PAGE_ADDR(physical_page);
 
   _do_unmap_page(base, EMM_PAGE_SIZE);
-       
+
   return (TRUE);
 }
 
@@ -481,14 +464,14 @@
 
 static boolean_t
 map_page(int handle, int physical_page, int logical_page)
-{ 
+{
   unsigned int base;
   caddr_t logical;
 
   E_printf("EMS: map_page(handle=%d, phy_page=%d, log_page=%d), prev 
handle=%d\n", 
            handle, physical_page, logical_page, emm_map[physical_page].handle);
 
-  if ((physical_page < 0) || (physical_page >= EMM_MAX_PHYS))
+  if ((physical_page < 0) || (physical_page >= phys_pages))
     return (FALSE);
 
   if (handle == NULL_HANDLE) 
@@ -496,16 +479,15 @@
   if (handle_info[handle].numpages <= logical_page)
     return (FALSE);
 
-#ifdef SYNC_ALOT
-  sync();
-#endif
-
+#if 0
+/* no need to unmap before mapping */
   if (emm_map[physical_page].handle != NULL_HANDLE)
     unmap_page(physical_page);
+#endif
 
-  base = EMM_BASE_ADDRESS + (physical_page * EMM_PAGE_SIZE);
+  base = PHYS_PAGE_ADDR(physical_page);
   logical = handle_info[handle].object + logical_page * EMM_PAGE_SIZE;
-   
+
   _do_map_page(base, logical, EMM_PAGE_SIZE);
 
   emm_map[physical_page].handle = handle;
@@ -528,12 +510,11 @@
   return (handle_info[handle].numpages);
 }
 
-static int
-save_handle_state(int handle)
+int emm_save_handle_state(int handle)
 {
   int i;
 
-  for (i = 0; i < EMM_MAX_PHYS; i++) {
+  for (i = 0; i < saved_phys_pages; i++) {
     if (emm_map[i].handle != NULL_HANDLE) {
       handle_info[handle].saved_mappings_logical[i] =
        emm_map[i].logical_page;
@@ -547,12 +528,11 @@
   return 0;
 }
 
-static int
-restore_handle_state(int handle)
+int emm_restore_handle_state(int handle)
 {
   int i;
 
-  for (i = 0; i < EMM_MAX_PHYS; i++) {
+  for (i = 0; i < saved_phys_pages; i++) {
     int saved_mapping;
     int saved_mapping_handle;
 
@@ -571,7 +551,7 @@
 }
 
 static int
-do_map_unmap(state_t * state, int handle, int physical_page, int logical_page)
+do_map_unmap(int handle, int physical_page, int logical_page)
 {
 
   CHECK_OS_HANDLE(handle);
@@ -580,15 +560,13 @@
       (handle_info[handle].active == 0)) {
     E_printf("Invalid Handle handle=%x, active=%d\n",
             handle, handle_info[handle].active);
-    SETHIGH(&(state->eax), EMM_INV_HAN);
-    return (UNCHANGED);
+    return EMM_INV_HAN;
   }
 
-  if ((physical_page < 0) || (physical_page >= EMM_MAX_PHYS)) {
-    SETHIGH(&(state->eax), EMM_ILL_PHYS);
+  if ((physical_page < 0) || (physical_page >= phys_pages)) {
     E_printf("Invalid Physical Page physical_page=%x\n",
             physical_page);
-    return (UNCHANGED);
+    return EMM_ILL_PHYS;
   }
 
   if (logical_page == 0xffff) {
@@ -597,29 +575,29 @@
   }
   else {
     if (logical_page >= handle_info[handle].numpages) {
-      SETHIGH(&(state->eax), EMM_LOG_OUT_RAN);
       E_printf("Logical page too high logical_page=%d, numpages=%d\n",
               logical_page, handle_info[handle].numpages);
-      return (UNCHANGED);
+      return EMM_LOG_OUT_RAN;
     }
 
     E_printf("EMS: do_map_unmap is mapping\n");
     map_page(handle, physical_page, logical_page);
   }
-  SETHIGH(&(state->eax), EMM_NO_ERR);
-  return (TRUE);
+  return EMM_NO_ERR;
 }
 
 static inline int
 SEG_TO_PHYS(int segaddr)
 {
+  int i;
   E_printf("SEG_TO_PHYS: segment: %x\n", segaddr);
 
-  segaddr-=EMM_SEGMENT;
-  if ((segaddr<0) || (segaddr >= EMM_MAX_PHYS*EMM_PAGE_SIZE/16) || ((segaddr & 
0x3ff) != 0))
-     return -1;
-  else
-     return (segaddr)/(EMM_PAGE_SIZE/16);
+  for (i = 0; i < phys_pages; i++) {
+    if (segaddr >= emm_map[i].phys_seg && segaddr < emm_map[i].phys_seg +
+       EMM_PAGE_SIZE/16)
+      return i;
+  }
+  return -1;
 }
 
 /* EMS 4.0 functions start here */
@@ -631,10 +609,25 @@
   SETHIGH(&(state->eax), EMM_NO_ERR);
 }
 
+int emm_map_unmap_multi(const u_short *array, int handle, int map_len)
+{
+  char ret = EMM_NO_ERR;
+  int i, phys, log;
+  for (i = 0; i < map_len; i++) {
+    log = array[i * 2];
+    phys = array[i * 2 + 1];
+    Kdebug0((dbg_fd, "loop: 0x%x 0x%x \n", log, phys));
+    ret = do_map_unmap(handle, phys, log);
+    if (ret != EMM_NO_ERR)
+      break;
+  }
+  return ret;
+}
+
 static void
 map_unmap_multiple(state_t * state)
 {
-
+  char ret;
   Kdebug0((dbg_fd, "map_unmap_multiple %d called\n",
           (int) LOW(state->eax)));
 
@@ -642,20 +635,14 @@
   case MULT_LOGPHYS:{          /* 0 */
       int handle = WORD(state->edx);
       int map_len = WORD(state->ecx);
-      int i = 0, phys, log;
       u_short *array = (u_short *) Addr(state, ds, esi);
 
       Kdebug0((dbg_fd, "...using mult_logphys method, "
               "handle %d, map_len %d, array @ %p\n",
               handle, map_len, array));
 
-      for (i = 0; i < map_len; i++) {
-       log = *(u_short *) array++;
-       phys = *(u_short *) array++;
-
-       Kdebug0((dbg_fd, "loop: 0x%x 0x%x \n", log, phys));
-       do_map_unmap(state, handle, phys, log);
-      }
+      ret = emm_map_unmap_multi(array, handle, map_len);
+      SETHIGH(&(state->eax), ret);
       break;
     }
 
@@ -664,14 +651,15 @@
       int map_len = WORD(state->ecx);
       int i = 0, phys, log, seg;
       u_short *array = (u_short *) Addr(state, ds, esi);
+      u_short *array2 = malloc(PAGE_MAP_SIZE(map_len));
 
       Kdebug0((dbg_fd, "...using mult_logseg method, "
               "handle %d, map_len %d, array @ %p\n",
               handle, map_len, array));
 
       for (i = 0; i < map_len; i++) {
-       log = *(u_short *) array;
-       seg = *(u_short *) (array + 1);
+       log = array[i * 2];
+       seg = array[i * 2 + 1];
 
        phys = SEG_TO_PHYS(seg);
 
@@ -679,17 +667,19 @@
                 log, seg, phys));
 
        if (phys == -1) {
+         free(array2);
          SETHIGH(&(state->eax), EMM_ILL_PHYS);
          return;
        }
        else {
-         do_map_unmap(state, handle, phys, log);
-         SETHIGH(&(state->eax), EMM_NO_ERR);
+         array2[i * 2] = log;
+         array2[i * 2 + 1] = phys;
        }
-       array++;
-       array++;
       }
 
+      ret = emm_map_unmap_multi(array2, handle, map_len);
+      SETHIGH(&(state->eax), ret);
+      free(array2);
       break;
     }
 
@@ -738,7 +728,7 @@
 
   /* Make sure extended pages have correct data */
 
-  for (i = 0; i < EMM_MAX_PHYS; i++)
+  for (i = 0; i < phys_pages; i++)
      if (emm_map[i].handle == handle)
         reunmap_page(i);
 
@@ -791,13 +781,13 @@
       }
     }
   }
-  
+
   Kdebug0((dbg_fd, "reallocate_pages handle %d num %d called object=%p\n",
           handle, newcount, obj));
 
   /* remove pages no longer in range, remap others */
 
-  for (i = 0; i < EMM_MAX_PHYS; i++) {
+  for (i = 0; i < phys_pages; i++) {
     if (emm_map[i].handle == handle) {
        /*
         * NOTE: In case of the above critical case (newcount==0)
@@ -1160,7 +1150,7 @@
 
       Kdebug0((dbg_fd, "GET_MPA addr %p called\n", ptr));
 
-      for (i = 0; i < EMM_MAX_PHYS; i++) {
+      for (i = 0; i < phys_pages; i++) {
        *ptr = PHYS_PAGE_SEGADDR(i);
        ptr++;
        *ptr = i;
@@ -1170,14 +1160,14 @@
       }
 
       SETHIGH(&(state->eax), EMM_NO_ERR);
-      SETWORD(&(state->ecx), EMM_MAX_PHYS);
+      SETWORD(&(state->ecx), phys_pages);
       return (TRUE);
     }
 
   case GET_MPA_ENTRY_COUNT:
     Kdebug0((dbg_fd, "GET_MPA_ENTRY_COUNT called\n"));
     SETHIGH(&(state->eax), EMM_NO_ERR);
-    SETWORD(&(state->ecx), EMM_MAX_PHYS);
+    SETWORD(&(state->ecx), phys_pages);
     return (TRUE);
 
   default:
@@ -1195,16 +1185,11 @@
       case GET_ARRAY:{
         u_short *ptr = (u_short *) Addr(state, es, edi);
 
-        *ptr = (16 * 1024) / 16;
-        ptr++;                 /* raw page size in paragraphs, 4K */
-        *ptr = 0;
-        ptr++;                 /* # of alternate register sets */
-        *ptr = PAGE_MAP_SIZE;
-        ptr++;                 /* size of context save area */
-        *ptr = 0;
-        ptr++;                 /* no DMA channels */
-        *ptr = 0;
-        ptr++;                 /* DMA channel operation */
+        *ptr++ = (16 * 1024) / 16;     /* raw page size in paragraphs 
(16Bytes), 16K */
+        *ptr++ = 0;            /* # of alternate register sets */
+        *ptr++ = PAGE_MAP_SIZE(phys_pages);    /* size of context save area */
+        *ptr++ = 0;            /* no DMA channels */
+        *ptr++ = 0;            /* DMA channel operation */
 
         Kdebug1((dbg_fd, "bios_emm: Get Hardware Info\n"));
         SETHIGH(&(state->eax), EMM_NO_ERR);
@@ -1232,7 +1217,7 @@
     Kdebug1((dbg_fd, "bios_emm: Get Hardware Info/Raw Pages - Denied\n"));
     SETHIGH(&(state->eax), 0xa4);
     return(TRUE);
-  }    
+  }
 }
 
 static int
@@ -1244,7 +1229,7 @@
   Kdebug1((dbg_fd, "bios_emm: Get Handle and Standard Allocate pages = 0x%x\n",
           pages_needed));
 
-  if ((handle = allocate_handle(pages_needed)) == EMM_ERROR) {
+  if ((handle = emm_allocate_handle(pages_needed)) == EMM_ERROR) {
     SETHIGH(&(state->eax), emm_error);
     return (UNCHANGED);
   }
@@ -1256,23 +1241,23 @@
   return 0;
 }
 
-void emm_get_map_registers(char *ptr)
+static void emm_get_map_registers(char *ptr)
 {
   u_short *buf = (u_short *)ptr;
   int i;
   if (!config.ems_size)
     return;
 
-  for (i = 0; i < EMM_MAX_PHYS; i++) {
+  for (i = 0; i < phys_pages; i++) {
     buf[i * 2] = emm_map[i].handle;
     buf[i * 2 + 1] = emm_map[i].logical_page;
-    Kdebug1((dbg_fd, "phy %d h %x lp %x\n",
+    Kdebug1((dbg_fd, "phy %d h %x lp %d\n",
             i, emm_map[i].handle,
             emm_map[i].logical_page));
   }
 }
 
-void emm_set_map_registers(char *ptr)
+static void emm_set_map_registers(char *ptr)
 {
   u_short *buf = (u_short *)ptr;
   int i;
@@ -1281,7 +1266,7 @@
   if (!config.ems_size)
     return;
 
-  for (i = 0; i < EMM_MAX_PHYS; i++) {
+  for (i = 0; i < phys_pages; i++) {
     handle = buf[i * 2];
     if (handle == OS_HANDLE)
       E_printf("EMS: trying to use OS handle in ALT_SET_REGISTERS\n");
@@ -1292,7 +1277,7 @@
     else
       unmap_page(i);
 
-    Kdebug1((dbg_fd, "phy %d h %x lp %x\n",
+    Kdebug1((dbg_fd, "phy %d h %x lp %d\n",
            i, handle, logical_page));
   }
 }
@@ -1329,9 +1314,10 @@
        return;
       }
     case 2:
-      Kdebug1((dbg_fd, "bios_emm: Get Alternate Map Save Array Size = 
0x%zx\n", PAGE_MAP_SIZE));
+      Kdebug1((dbg_fd, "bios_emm: Get Alternate Map Save Array Size = 0x%zx\n",
+          PAGE_MAP_SIZE(phys_pages)));
       SETHIGH(&(state->eax), EMM_NO_ERR);
-      SETWORD(&(state->edx), PAGE_MAP_SIZE);
+      SETWORD(&(state->edx), PAGE_MAP_SIZE(phys_pages));
       return;
     case 3:                    /* Allocate Alternate Register */
       SETHIGH(&(state->eax), EMM_NO_ERR);
@@ -1409,7 +1395,7 @@
   }
   return;
 }
-     
+
 static void
 os_set_function(state_t * state)
 {
@@ -1526,7 +1512,7 @@
        return (UNCHANGED);
       }
 
-      if ((handle = allocate_handle(pages_needed)) == EMM_ERROR) {
+      if ((handle = emm_allocate_handle(pages_needed)) == EMM_ERROR) {
        SETHIGH(&(state->eax), emm_error);
        return (UNCHANGED);
       }
@@ -1542,8 +1528,10 @@
       int physical_page = LOW(state->eax);
       int logical_page = WORD(state->ebx);
       int handle = WORD(state->edx);
+      char ret;
 
-      do_map_unmap(state, handle, physical_page, logical_page);
+      ret = do_map_unmap(handle, physical_page, logical_page);
+      SETHIGH(&(state->eax), ret);
       break;
     }
   case DEALLOCATE_HANDLE:{     /* 0x45 */
@@ -1562,7 +1550,7 @@
        return (UNCHANGED);
       }
 
-      deallocate_handle(handle);
+      emm_deallocate_handle(handle);
       SETHIGH(&(state->eax), EMM_NO_ERR);
       break;
     }
@@ -1588,7 +1576,7 @@
        return (UNCHANGED);
       }
 
-      save_handle_state(handle);
+      emm_save_handle_state(handle);
       SETHIGH(&(state->eax), EMM_NO_ERR);
       break;
     }
@@ -1607,7 +1595,7 @@
        return (UNCHANGED);
       }
 
-      restore_handle_state(handle);
+      emm_restore_handle_state(handle);
       SETHIGH(&(state->eax), EMM_NO_ERR);
       break;
     }
@@ -1707,7 +1695,7 @@
          Kdebug1((dbg_fd, "bios_emm: Get size for page map\n"));
 
          SETHIGH(&(state->eax), EMM_NO_ERR);
-         SETLOW(&(state->eax), PAGE_MAP_SIZE);
+         SETLOW(&(state->eax), PAGE_MAP_SIZE(phys_pages));
          return (UNCHANGED);
        }
       default:{
@@ -1785,12 +1773,12 @@
     break;
 
   case ALTERNATE_MAP_REGISTER: /* 0x5B */
-      alternate_map_register(state); 
-    break;     
+      alternate_map_register(state);
+    break;
 
   case OS_SET_FUNCTION: /* 0x5D */
       os_set_function(state); 
-    break;     
+    break;
 
 /* This seems to be used by DV.
            case 0xde:
@@ -1801,6 +1789,7 @@
 */
 
   default:{
+      mhp_intercept("\nUnsupported EMM function\n\n", "+9E");
       Kdebug1((dbg_fd,
         "bios_emm: EMM function NOT supported 0x%04x\n",
         (unsigned) WORD(state->eax)));
@@ -1829,14 +1818,17 @@
     handle_info[sh_base].active = 0;
   }
 
-  /* should set up OS handle here */
-  handle_info[OS_HANDLE].numpages = 0;
-  handle_info[OS_HANDLE].object = 0;
-  handle_info[OS_HANDLE].objsize = 0;
+  /* set up OS handle here */
+  handle_info[OS_HANDLE].numpages = config.ems_cnv_pages;
+  handle_info[OS_HANDLE].object = LOWMEM(cnv_start_seg << 4);
   handle_info[OS_HANDLE].active = 1;
-  for (j = 0; j < EMM_MAX_PHYS; j++) {
+  for (j = 0; j < saved_phys_pages; j++) {
     handle_info[OS_HANDLE].saved_mappings_logical[j] = NULL_PAGE;
   }
+  for (sh_base = 0; sh_base < config.ems_cnv_pages; sh_base++) {
+    emm_map[sh_base + cnv_pages_start].handle = OS_HANDLE;
+    emm_map[sh_base + cnv_pages_start].logical_page = sh_base;
+  }
 
   handle_total = 1;
   SET_HANDLE_NAME(handle_info[OS_HANDLE].name, "SYSTEM  ");
@@ -1847,21 +1839,53 @@
   int sh_base;
   for (sh_base = 1; sh_base < MAX_HANDLES; sh_base++) {
     if (handle_info[sh_base].active)
-      deallocate_handle(sh_base);
+      emm_deallocate_handle(sh_base);
   }
   ems_reset2();
 }
 
 void ems_init(void)
 {
+  int i, j;
   if (!config.ems_size && !config.pm_dos_api)
     return;
 
+  if (config.ems_uma_pages > EMM_UMA_MAX_PHYS) {
+    error("config.ems_uma_pages is too large\n");
+    config.exitearly = 1;
+    return;
+  }
+  if (config.ems_uma_pages < 4 && config.pm_dos_api) {
+    error("config.ems_uma_pages is too small, DPMI must be disabled\n");
+    config.exitearly = 1;
+    return;
+  }
+  if (config.ems_cnv_pages > EMM_CNV_MAX_PHYS) {
+    error("config.ems_cnv_pages is too large\n");
+    config.exitearly = 1;
+    return;
+  }
+
   open_mapping(MAPPING_EMS);
   E_printf("EMS: initializing memory\n");
 
   memcheck_addtype('E', "EMS page frame");
-  memcheck_reserve('E', EMM_BASE_ADDRESS, EMM_MAX_PHYS * EMM_PAGE_SIZE);
+  /* set up standard EMS frame in UMA */
+  for (i = 0; i < config.ems_uma_pages; i++) {
+    emm_map[i].phys_seg = EMM_SEGMENT + 0x400 * i;
+    memcheck_reserve('E', PHYS_PAGE_ADDR(i), EMM_PAGE_SIZE);
+  }
+  saved_phys_pages = (i < EMM_MAX_SAVED_PHYS ? i : EMM_MAX_SAVED_PHYS);
+  /* now in conventional mem */
+  cnv_start_seg = 0xa000 - 0x400 * config.ems_cnv_pages;
+  cnv_pages_start = i;
+  E_printf("EMS: Using %i pages in conventional memory, starting from 0x%x\n",
+       config.ems_cnv_pages, cnv_start_seg);
+  for (j = 0; j < config.ems_cnv_pages; j++, i++) {
+    emm_map[i].phys_seg = cnv_start_seg + 0x400 * j;
+  }
+  phys_pages = i;
+  E_printf("EMS: initialized %i pages\n", phys_pages);
 
   ems_reset2();
 }
Index: src/dosext/dpmi/msdos.c
===================================================================
--- src/dosext/dpmi/msdos.c     (revision 2065)
+++ src/dosext/dpmi/msdos.c     (working copy)
@@ -39,6 +39,7 @@
 #endif
 
 #define TRANS_BUFFER_SEG EMM_SEGMENT
+#define MSDOS_EMS_PAGES 4
 #define EXEC_SEG (MSDOS_CLIENT.lowmem_seg + EXEC_Para_ADD)
 
 #define DTA_over_1MB (GetSegmentBase(MSDOS_CLIENT.user_dta_sel) + 
MSDOS_CLIENT.user_dta_off)
@@ -69,11 +70,13 @@
        D_printf("DPMI: env segment %#x converted to descriptor %#x\n",
                envp, CURRENT_ENV_SEL);
     }
+    MSDOS_CLIENT.ems_handle = emm_allocate_handle(MSDOS_EMS_PAGES);
     D_printf("MSDOS: init, %i\n", msdos_client_num);
 }
 
 void msdos_done(void)
 {
+  emm_deallocate_handle(MSDOS_CLIENT.ems_handle);
   if (CURRENT_ENV_SEL)
       WRITE_ENV_SEL(GetSegmentBase(CURRENT_ENV_SEL) >> 4);
     msdos_client_num--;
@@ -135,18 +138,21 @@
 
 static void prepare_ems_frame(void)
 {
+    static const u_short ems_map_simple[MSDOS_EMS_PAGES * 2] =
+       { 0, 0, 1, 1, 2, 2, 3, 3 };
     if (MSDOS_CLIENT.ems_frame_mapped)
        return;
     MSDOS_CLIENT.ems_frame_mapped = 1;
-    emm_get_map_registers(MSDOS_CLIENT.ems_map_buffer);
-    emm_unmap_all();
+    emm_save_handle_state(MSDOS_CLIENT.ems_handle);
+    emm_map_unmap_multi(ems_map_simple, MSDOS_CLIENT.ems_handle,
+       MSDOS_EMS_PAGES);
 }
 
 static void restore_ems_frame(void)
 {
     if (!MSDOS_CLIENT.ems_frame_mapped)
        return;
-    emm_set_map_registers(MSDOS_CLIENT.ems_map_buffer);
+    emm_restore_handle_state(MSDOS_CLIENT.ems_handle);
     MSDOS_CLIENT.ems_frame_mapped = 0;
 }
 
Index: src/dosext/dpmi/msdos.h
===================================================================
--- src/dosext/dpmi/msdos.h     (revision 2065)
+++ src/dosext/dpmi/msdos.h     (working copy)
@@ -34,8 +34,7 @@
   unsigned short user_psp_sel;
   unsigned short current_psp;
   unsigned short lowmem_seg;
-  char ems_map_buffer[PAGE_MAP_SIZE];
-  int ems_frame_mapped;
+  int ems_handle, ems_frame_mapped;
   dpmi_pm_block mem_map[MSDOS_MAX_MEM_ALLOCS];
 };
 
Index: src/emu.c
===================================================================
--- src/emu.c   (revision 2065)
+++ src/emu.c   (working copy)
@@ -453,8 +453,10 @@
        loopstep_run_vm86();
     }
 
-    sync();
-    fprintf(stderr, "Not a good day to die!!!!!\n");
+    if (fatalerr) {
+      sync();
+      fprintf(stderr, "Not a good day to die!!!!!\n");
+    }
     leavedos(99);
     return 0;  /* just to make gcc happy */
 }
Index: src/base/init/parser.y.in
===================================================================
--- src/base/init/parser.y.in   (revision 2065)
+++ src/base/init/parser.y.in   (working copy)
@@ -246,7 +246,8 @@
 %token MATHCO CPU CPUSPEED RDTSC BOOTA BOOTB BOOTC
 %token L_XMS L_DPMI DPMI_BASE PM_DOS_API NO_NULL_CHECKS 
 %token PORTS DISK DOSMEM EXT_MEM
-%token L_EMS L_UMB EMS_SIZE EMS_FRAME TTYLOCKS L_SOUND L_SND_OSS L_JOYSTICK 
FULL_FILE_LOCKS
+%token L_EMS L_UMB EMS_SIZE EMS_FRAME EMS_UMA_PAGES EMS_CONV_PAGES
+%token TTYLOCKS L_SOUND L_SND_OSS L_JOYSTICK FULL_FILE_LOCKS
 %token DEXE ALLOWDISK FORCEXDOS XDOSONLY
 %token ABORT WARN
 %token BOOTDISK L_FLOPPY EMUSYS EMUINI L_X
@@ -1602,6 +1603,14 @@
                     config.ems_frame = $2 & 0xfc00;
                     c_printf("CONF: EMS-frame = 0x%04x\n", config.ems_frame);
                   }
+               | EMS_UMA_PAGES expression
+                  {
+                    config.ems_uma_pages = $2;
+                  }
+               | EMS_CONV_PAGES expression
+                  {
+                    config.ems_cnv_pages = $2;
+                  }
                | STRING
                    { yyerror("unrecognized ems command '%s'", $1);
                      free($1); }
Index: src/base/init/lexer.l.in
===================================================================
--- src/base/init/lexer.l.in    (revision 2065)
+++ src/base/init/lexer.l.in    (working copy)
@@ -403,6 +403,8 @@
        /* ems values */
 ems_size               RETURN(EMS_SIZE);
 ems_frame              RETURN(EMS_FRAME);
+ems_uma_pages          RETURN(EMS_UMA_PAGES);
+ems_conv_pages         RETURN(EMS_CONV_PAGES);
 
        /* speaker values */
 
Index: src/base/init/memcheck.c
===================================================================
--- src/base/init/memcheck.c    (revision 2065)
+++ src/base/init/memcheck.c    (working copy)
@@ -206,17 +206,17 @@
     return &mem_base[addr];
   map_char = mem_map[addr/GRAN_SIZE];
   /* Not EMS, Hardware, or Video */
-  if (map_char == 'E' || map_char == 'h' || map_char == 'v')
+//  if (map_char == 'E' || map_char == 'h' || map_char == 'v')
     return &mem_base[addr];    // FIXTHIS !
-  return LOWMEM(addr);
+//  return LOWMEM(addr);
 }
 
 void *lowmemp(const void *ptr)
 {
   unsigned char map_char;
   uintptr_t addr = (unsigned char *)ptr - mem_base;
-  if (IS_GENERIC_LOWMEM_ADDR(addr))
-    return LOWMEM(addr);
+//  if (IS_GENERIC_LOWMEM_ADDR(addr))
+//    return LOWMEM(addr);
   if (addr >= MEM_SIZE)
     return (void *)ptr;
   map_char = mem_map[addr/GRAN_SIZE];
Index: src/arch/linux/debugger/dosdebug.c
===================================================================
--- src/arch/linux/debugger/dosdebug.c  (revision 2065)
+++ src/arch/linux/debugger/dosdebug.c  (working copy)
@@ -190,7 +190,7 @@
   if (n >0) {
     if ((p=strchr(buf,1))!=NULL) n=p-buf;
     write(1, buf, n);
-    if (p!=NULL) exit(0);
+//    if (p!=NULL) exit(0);
   }
   if (n == 0)
     exit(1);
Index: src/include/memory.h
===================================================================
--- src/include/memory.h        (revision 2065)
+++ src/include/memory.h        (working copy)
@@ -99,7 +99,6 @@
 #define EMS_OFF                0x0000
 #define EMS_ADD                ((EMS_SEG << 4) + EMS_OFF)
 
-#define EMM_BASE_ADDRESS        (SEGOFF2LINEAR(config.ems_frame, 0))
 #define EMM_SEGMENT             (config.ems_frame)
 
 #define INT16_SEG      ROMBIOSSEG
@@ -263,16 +262,9 @@
 #define LOWMEM_READ_DWORD(addr)                UNIX_READ_DWORD(LOWMEM(addr))
 #define LOWMEM_WRITE_DWORD(addr, val)  UNIX_WRITE_DWORD(LOWMEM(addr), val)
 
-/* generic lowmem addresses are the ones below 1Mb, that are
- * not in the EMS frame, hardware or video memory. We can _safely_
- * add lowmem_base to those. */
-#define IS_GENERIC_LOWMEM_ADDR(addr) \
-       ((addr) <= 0x9fffc || ((addr) >= 0xf4000 && (addr) <= 0xffffc))
-
 static inline void *LINEAR2UNIX(unsigned int addr)
 {
-       return IS_GENERIC_LOWMEM_ADDR(addr) ? LOWMEM(addr) :
-         dosaddr_to_unixaddr(addr);
+       return dosaddr_to_unixaddr(addr);
 }
 
 #define READ_BYTE(addr)                UNIX_READ_BYTE(LINEAR2UNIX(addr))
Index: src/include/emm.h
===================================================================
--- src/include/emm.h   (revision 2065)
+++ src/include/emm.h   (working copy)
@@ -11,22 +11,29 @@
 #define DOSEMU_EMS_DRIVER_VERSION 3
 
 #define        MAX_HANDLES     255     /* must fit in a byte */
-#define EMS_FRAME_SIZE (EMM_MAX_PHYS * EMM_PAGE_SIZE)
 /* this is in EMS pages, which MAX_EMS (defined in Makefile) is in K */
 #define MAX_EMM                (config.ems_size >> 4)
 #ifndef PAGE_SIZE
 #define PAGE_SIZE      4096
 #endif
 #define        EMM_PAGE_SIZE   (16*1024)
-#define EMM_MAX_PHYS   4
-#define NULL_HANDLE    -1
+#define EMM_UMA_MAX_PHYS 12
+#define EMM_UMA_STD_PHYS 4
+#define EMM_CNV_MAX_PHYS 24
+#define EMM_MAX_PHYS   (EMM_UMA_MAX_PHYS + EMM_CNV_MAX_PHYS)
+#define EMM_MAX_SAVED_PHYS EMM_UMA_STD_PHYS
+#define NULL_HANDLE    0xffff
 #define        NULL_PAGE       0xffff
-#define PAGE_MAP_SIZE          (sizeof(u_short) * 2 * EMM_MAX_PHYS)
+#define PAGE_MAP_SIZE(np)      (sizeof(u_short) * 2 * (np))
 
 #ifndef __ASSEMBLER__
-void emm_get_map_registers(char *ptr);
-void emm_set_map_registers(char *ptr);
-void emm_unmap_all(void);
+/* export a few EMS functions to DPMI so it doesn't have to call interrupt */
+int emm_allocate_handle(int pages_needed);
+boolean_t emm_deallocate_handle(int handle);
+int emm_save_handle_state(int handle);
+int emm_restore_handle_state(int handle);
+int emm_map_unmap_multi(const u_short *array, int handle, int map_len);
+/* end of DPMI/EMS API */
 
 void ems_init(void);
 void ems_reset(void);
Index: src/include/emu.h
===================================================================
--- src/include/emu.h   (revision 2065)
+++ src/include/emu.h   (working copy)
@@ -268,6 +268,7 @@
 
        int mem_size, ext_mem, xms_size, ems_size, max_umb;
        unsigned int ems_frame;
+       int ems_uma_pages, ems_cnv_pages;
        int dpmi, pm_dos_api, no_null_checks;
        unsigned long dpmi_base;
 
------------------------------------------------------------------------------
For Developers, A Lot Can Happen In A Second.
Boundary is the first to Know...and Tell You.
Monitor Your Applications in Ultra-Fine Resolution. Try it FREE!
http://p.sf.net/sfu/Boundary-d2dvs2
_______________________________________________
Dosemu-devel mailing list
Dosemu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dosemu-devel

Reply via email to