"Fossies" - the Fresh Open Source Software Archive

Member "dosemu-1.4.0/src/dosext/dpmi/msdos.c" (4 May 2007, 44434 Bytes) of package /linux/misc/old/dosemu-1.4.0.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "msdos.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * (C) Copyright 1992, ..., 2007 the "DOSEMU-Development-Team".
    3  *
    4  * for details see file COPYING.DOSEMU in the DOSEMU distribution
    5  */
    6 
    7 /*  MS-DOS API translator for DOSEMU\'s DPMI Server
    8  *
    9  * DANG_BEGIN_MODULE msdos.c
   10  *
   11  * REMARK
   12  * MS-DOS API translator allows DPMI programs to call DOS service directly
   13  * in protected mode.
   14  *
   15  * /REMARK
   16  * DANG_END_MODULE
   17  *
   18  * First Attempted by Dong Liu,  dliu@rice.njit.edu
   19  *
   20  */
   21 
   22 #include <stdlib.h>
   23 #include <string.h>
   24 
   25 #include "emu.h"
   26 #include "emu-ldt.h"
   27 #include "int.h"
   28 #include "bios.h"
   29 #include "emm.h"
   30 #include "dpmi.h"
   31 #include "dpmisel.h"
   32 #include "msdos.h"
   33 #include "vgaemu.h"
   34 #include "utilities.h"
   35 
   36 #define SUPPORT_DOSEMU_HELPERS 1
   37 #if SUPPORT_DOSEMU_HELPERS
   38 #include "doshelpers.h"
   39 #endif
   40 
   41 #define TRANS_BUFFER_SEG EMM_SEGMENT
   42 #define EXEC_SEG (MSDOS_CLIENT.lowmem_seg + EXEC_Para_ADD)
   43 
   44 #define DTA_over_1MB (void*)(GetSegmentBaseAddress(MSDOS_CLIENT.user_dta_sel) + MSDOS_CLIENT.user_dta_off)
   45 #define DTA_under_1MB SEG2LINEAR(MSDOS_CLIENT.lowmem_seg + DTA_Para_ADD)
   46 
   47 #define MAX_DOS_PATH 260
   48 
   49 #define D_16_32(reg)        (MSDOS_CLIENT.is_32 ? reg : reg & 0xffff)
   50 #define MSDOS_CLIENT (msdos_client[msdos_client_num - 1])
   51 #define CURRENT_ENV_SEL ((u_short)READ_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0x2c)))
   52 #define WRITE_ENV_SEL(sel) (WRITE_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0x2c), sel))
   53 
   54 static int msdos_client_num = 0;
   55 static struct msdos_struct msdos_client[DPMI_MAX_CLIENTS];
   56 
   57 void msdos_init(int is_32, unsigned short mseg, unsigned short psp)
   58 {
   59     unsigned short envp;
   60     msdos_client_num++;
   61     memset(&MSDOS_CLIENT, 0, sizeof(struct msdos_struct));
   62     MSDOS_CLIENT.is_32 = is_32;
   63     MSDOS_CLIENT.lowmem_seg = mseg;
   64     MSDOS_CLIENT.current_psp = psp;
   65     /* convert environment pointer to a descriptor */
   66     envp = READ_WORD((psp<<4)+0x2c);
   67     if (envp) {
   68     WRITE_ENV_SEL(ConvertSegmentToDescriptor(envp));
   69     D_printf("DPMI: env segment %#x converted to descriptor %#x\n",
   70         envp, CURRENT_ENV_SEL);
   71     }
   72     D_printf("MSDOS: init, %i\n", msdos_client_num);
   73 }
   74 
   75 void msdos_done(void)
   76 {
   77   if (CURRENT_ENV_SEL)
   78       WRITE_ENV_SEL(GetSegmentBaseAddress(CURRENT_ENV_SEL) >> 4);
   79     msdos_client_num--;
   80     D_printf("MSDOS: done, %i\n", msdos_client_num);
   81 }
   82 
   83 int msdos_get_lowmem_size(void)
   84 {
   85     return DTA_Para_SIZE + EXEC_Para_SIZE;
   86 }
   87 
   88 static void *msdos_malloc(unsigned long size)
   89 {
   90   int i;
   91   dpmi_pm_block block = DPMImalloc(size);
   92   if (!block.size)
   93     return NULL;
   94   for (i = 0; i < MSDOS_MAX_MEM_ALLOCS; i++) {
   95     if (MSDOS_CLIENT.mem_map[i].size == 0) {
   96       MSDOS_CLIENT.mem_map[i] = block;
   97       break;
   98     }
   99   }
  100   return block.base;
  101 }
  102 
  103 static int msdos_free(void *addr)
  104 {
  105   int i;
  106   for (i = 0; i < MSDOS_MAX_MEM_ALLOCS; i++) {
  107     if (MSDOS_CLIENT.mem_map[i].base == addr) {
  108       DPMIfree(MSDOS_CLIENT.mem_map[i].handle);
  109       MSDOS_CLIENT.mem_map[i].size = 0;
  110       return 0;
  111     }
  112   }
  113   return -1;
  114 }
  115 
  116 static void *msdos_realloc(void *addr, unsigned long new_size)
  117 {
  118   int i;
  119   dpmi_pm_block block;
  120   block.size = 0;
  121   for (i = 0; i < MSDOS_MAX_MEM_ALLOCS; i++) {
  122     if (MSDOS_CLIENT.mem_map[i].base == addr) {
  123       block = MSDOS_CLIENT.mem_map[i];
  124       break;
  125     }
  126   }
  127   if (!block.size)
  128     return NULL;
  129   block = DPMIrealloc(block.handle, new_size);
  130   if (!block.size)
  131     return NULL;
  132   MSDOS_CLIENT.mem_map[i] = block;
  133   return block.base;
  134 }
  135 
  136 static void prepare_ems_frame(void)
  137 {
  138     if (MSDOS_CLIENT.ems_frame_mapped)
  139     return;
  140     MSDOS_CLIENT.ems_frame_mapped = 1;
  141     emm_get_map_registers(MSDOS_CLIENT.ems_map_buffer);
  142     emm_unmap_all();
  143 }
  144 
  145 static void restore_ems_frame(void)
  146 {
  147     if (!MSDOS_CLIENT.ems_frame_mapped)
  148     return;
  149     emm_set_map_registers(MSDOS_CLIENT.ems_map_buffer);
  150     MSDOS_CLIENT.ems_frame_mapped = 0;
  151 }
  152 
  153 static int need_copy_dseg(struct sigcontext_struct *scp, int intr)
  154 {
  155     switch (intr) {
  156     case 0x21:
  157         switch (_HI(ax)) {
  158         case 0x0a:      /* buffered keyboard input */
  159         case 0x5a:      /* mktemp */
  160         case 0x69:
  161             return 1;
  162         case 0x44:      /* IOCTL */
  163             switch (_LO(ax)) {
  164             case 0x02 ... 0x05:
  165             case 0x0c: case 0x0d:
  166                 return 1;
  167             }
  168             break;
  169         case 0x5d:      /* Critical Error Information  */
  170             return (_LO(ax) != 0x06 && _LO(ax) != 0x0b);
  171         case 0x5e:
  172             return (_LO(ax) != 0x03);
  173         }
  174         break;
  175     case 0x25:          /* Absolute Disk Read */
  176     case 0x26:          /* Absolute Disk write */
  177         return 1;
  178     }
  179 
  180     return 0;
  181 }
  182 
  183 static int need_copy_eseg(struct sigcontext_struct *scp, int intr)
  184 {
  185     switch (intr) {
  186     case 0x10:          /* video */
  187         switch (_HI(ax)) {
  188         case 0x10:      /* Set/Get Palette Registers (EGA/VGA) */
  189             switch(_LO(ax)) {
  190             case 0x2:       /* set all palette registers and border */
  191             case 0x09:      /* ead palette registers and border (PS/2) */
  192             case 0x12:      /* set block of DAC color registers */
  193             case 0x17:      /* read block of DAC color registers */
  194                 return 1;
  195             }
  196             break;
  197         case 0x11:      /* Character Generator Routine (EGA/VGA) */
  198             switch (_LO(ax)) {
  199             case 0x0:       /* user character load */
  200             case 0x10:      /* user specified character definition table */
  201             case 0x20: case 0x21:
  202                 return 1;
  203             }
  204             break;
  205         case 0x13:      /* Write String */
  206         case 0x15:      /*  Return Physical Display Parms */
  207         case 0x1b:
  208             return 1;
  209         case 0x1c:
  210             if (_LO(ax) == 1 || _LO(ax) == 2)
  211             return 1;
  212             break;
  213     }
  214     break;
  215     case 0x21:
  216         switch (_HI(ax)) {
  217         case 0x57:      /* Get/Set File Date and Time Using Handle */
  218             if ((_LO(ax) == 0) || (_LO(ax) == 1)) {
  219             return 0;
  220             }
  221             return 1;
  222         case 0x5e:
  223             return (_LO(ax) == 0x03);
  224         }
  225         break;
  226     case 0x33:
  227         switch (_HI(ax)) {
  228         case 0x16:      /* save state */
  229         case 0x17:      /* restore */
  230             return 1;
  231         }
  232         break;
  233 #if SUPPORT_DOSEMU_HELPERS
  234     case DOS_HELPER_INT:            /* dosemu helpers */
  235         switch (_LO(ax)) {
  236         case DOS_HELPER_PRINT_STRING:       /* print string to dosemu log */
  237             return 1;
  238         }
  239         break;
  240 #endif
  241     }
  242 
  243     return 0;
  244 }
  245 
  246 /* DOS selector is a selector whose base address is less than 0xffff0 */
  247 /* and para. aligned.                                                 */
  248 static int in_dos_space(unsigned short sel, unsigned long off)
  249 {
  250     unsigned long base = GetSegmentBaseAddress(sel);
  251 
  252     if (base + off > 0x10ffef) {    /* ffff:ffff for DOS high */
  253       D_printf("MSDOS: base address %#lx of sel %#x > DOS limit\n", base, sel);
  254       return 0;
  255     } else
  256     if (base & 0xf) {
  257       D_printf("MSDOS: base address %#lx of sel %#x not para. aligned.\n", base, sel);
  258       return 0;
  259     } else
  260       return 1;
  261 }
  262 
  263 static void old_dos_terminate(struct sigcontext_struct *scp, int i)
  264 {
  265     unsigned short psp_seg_sel, parent_psp = 0;
  266     unsigned short psp_sig;
  267 
  268     D_printf("MSDOS: old_dos_terminate, int=%#x\n", i);
  269 
  270     REG(cs)  = MSDOS_CLIENT.current_psp;
  271     REG(eip) = 0x100;
  272 
  273 #if 0
  274     _eip = READ_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0xa));
  275     _cs = ConvertSegmentToCodeDescriptor(
  276       READ_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0xa+2)));
  277 #endif
  278 
  279     /* put our return address there */
  280     WRITE_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0xa),
  281          DPMI_OFF + HLT_OFF(DPMI_return_from_dosint) + i);
  282     WRITE_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0xa+2), DPMI_SEG);
  283 
  284     psp_seg_sel = READ_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0x16));
  285     /* try segment */
  286     psp_sig = READ_WORD(SEG2LINEAR(psp_seg_sel));
  287     if (psp_sig != 0x20CD) {
  288     /* now try selector */
  289     unsigned long addr;
  290     D_printf("MSDOS: Trying PSP sel=%#x, V=%i, d=%i, l=%#lx\n",
  291         psp_seg_sel, ValidAndUsedSelector(psp_seg_sel),
  292         in_dos_space(psp_seg_sel, 0), GetSegmentLimit(psp_seg_sel));
  293     if (ValidAndUsedSelector(psp_seg_sel) && in_dos_space(psp_seg_sel, 0) &&
  294         GetSegmentLimit(psp_seg_sel) >= 0xff) {
  295         addr = GetSegmentBaseAddress(psp_seg_sel);
  296         psp_sig = READ_WORD(addr);
  297         D_printf("MSDOS: Trying PSP sel=%#x, addr=%#lx\n", psp_seg_sel, addr);
  298         if (!(addr & 0x0f) && psp_sig == 0x20CD) {
  299         /* found selector */
  300         parent_psp = addr >> 4;
  301             D_printf("MSDOS: parent PSP sel=%#x, seg=%#x\n",
  302             psp_seg_sel, parent_psp);
  303         }
  304     }
  305     } else {
  306     /* found segment */
  307     parent_psp = psp_seg_sel;
  308     }
  309     if (!parent_psp) {
  310     /* no PSP found, use current as the last resort */
  311     D_printf("MSDOS: using current PSP as parent!\n");
  312     parent_psp = MSDOS_CLIENT.current_psp;
  313     }
  314 
  315     D_printf("MSDOS: parent PSP seg=%#x\n", parent_psp);
  316     if (parent_psp != psp_seg_sel)
  317     WRITE_WORD(SEGOFF2LINEAR(MSDOS_CLIENT.current_psp, 0x16), parent_psp);
  318     /* And update our PSP pointer */
  319     MSDOS_CLIENT.current_psp = parent_psp;
  320 }
  321 
  322 /*
  323  * DANG_BEGIN_FUNCTION msdos_pre_extender
  324  *
  325  * This function is called before a protected mode client goes to real
  326  * mode for DOS service. All protected mode selector is changed to
  327  * real mode segment register. And if client\'s data buffer is above 1MB,
  328  * necessary buffer copying is performed. This function returns 1 if
  329  * it does not need to go to real mode, otherwise returns 0.
  330  *
  331  * DANG_END_FUNCTION
  332  */
  333 
  334 int msdos_pre_extender(struct sigcontext_struct *scp, int intr)
  335 {
  336     D_printf("MSDOS: pre_extender: int 0x%x, ax=0x%x\n", intr, _LWORD(eax));
  337     if (MSDOS_CLIENT.user_dta_sel && intr == 0x21) {
  338     switch (_HI(ax)) {  /* functions use DTA */
  339     case 0x11: case 0x12:   /* find first/next using FCB */
  340     case 0x4e: case 0x4f:   /* find first/next */
  341         MEMCPY_DOS2DOS(DTA_under_1MB, DTA_over_1MB, 0x80);
  342         break;
  343     }
  344     }
  345 
  346     /* only consider DOS and some BIOS services */
  347     switch (intr) {
  348     case 0x41:          /* win debug */
  349     return MSDOS_DONE;
  350 
  351     case 0x15:          /* misc */
  352     switch (_HI(ax)) {
  353       case 0xc2:
  354         D_printf("MSDOS: PS2MOUSE function 0x%x\n", _LO(ax));
  355         switch (_LO(ax)) {
  356           case 0x07:        /* set handler addr */
  357         if ( _es && D_16_32(_ebx) ) {
  358           D_printf("MSDOS: PS2MOUSE: set handler addr 0x%x:0x%x\n",
  359             _es, D_16_32(_ebx));
  360           MSDOS_CLIENT.PS2mouseCallBack.selector = _es;
  361           MSDOS_CLIENT.PS2mouseCallBack.offset = D_16_32(_ebx); 
  362           REG(es) = DPMI_SEG;
  363           REG(ebx) = DPMI_OFF + HLT_OFF(MSDOS_PS2_mouse_callback);
  364         } else {
  365           D_printf("MSDOS: PS2MOUSE: reset handler addr\n");
  366           REG(es) = 0;
  367           REG(ebx) = 0;
  368         }
  369         return 0;
  370           default:
  371         return 0;
  372         }
  373         break;
  374       default:
  375         return 0;
  376     }
  377     case 0x20:          /* DOS terminate */
  378     old_dos_terminate(scp, intr);
  379     return 0;
  380     case 0x21:
  381     switch (_HI(ax)) {
  382         /* first see if we don\'t need to go to real mode */
  383     case 0x25: {        /* set vector */
  384           INTDESC desc;
  385           desc.selector = _ds;
  386           desc.offset = D_16_32(_edx);
  387           dpmi_set_interrupt_vector(_LO(ax), desc);
  388           D_printf("MSDOS: int 21,ax=0x%04x, ds=0x%04x. dx=0x%04x\n",
  389              _LWORD(eax), _ds, _LWORD(edx));
  390         }
  391         return MSDOS_DONE;
  392     case 0x35: {    /* Get Interrupt Vector */
  393           INTDESC desc = dpmi_get_interrupt_vector(_LO(ax));
  394           _es = desc.selector;
  395           _ebx = desc.offset;
  396           D_printf("MSDOS: int 21,ax=0x%04x, es=0x%04x. bx=0x%04x\n",
  397              _LWORD(eax), _es, _LWORD(ebx));
  398         }
  399         return MSDOS_DONE;
  400     case 0x48:      /* allocate memory */
  401         {
  402         unsigned long size = _LWORD(ebx) << 4;
  403         void *addr = msdos_malloc(size);
  404         if (!addr) {
  405             unsigned int meminfo[12];
  406             GetFreeMemoryInformation(meminfo);
  407             _eflags |= CF;
  408             _LWORD(ebx) = meminfo[0] >> 4;
  409             _LWORD(eax) = 0x08;
  410         } else {
  411             unsigned short sel = AllocateDescriptors(1);
  412             SetSegmentBaseAddress(sel, (unsigned long)addr);
  413             SetSegmentLimit(sel, size - 1);
  414             _LWORD(eax) = sel;
  415             _eflags &= ~CF;
  416         }
  417         return MSDOS_DONE;
  418         }
  419     case 0x49:      /* free memory */
  420         {
  421         if (msdos_free((void *)GetSegmentBaseAddress(_es)) == -1) {
  422             _eflags |= CF;
  423         } else {
  424             _eflags &= ~CF;
  425             FreeDescriptor(_es);
  426             FreeSegRegs(scp, _es);
  427         }
  428         return MSDOS_DONE;
  429         }
  430     case 0x4a:      /* reallocate memory */
  431         {
  432         unsigned long new_size = _LWORD(ebx) << 4;
  433         void *addr = msdos_realloc((void *)GetSegmentBaseAddress(_es), new_size);
  434         if (!addr) {
  435             unsigned int meminfo[12];
  436             GetFreeMemoryInformation(meminfo);
  437             _eflags |= CF;
  438             _LWORD(ebx) = meminfo[0] >> 4;
  439             _LWORD(eax) = 0x08;
  440         } else {
  441             SetSegmentBaseAddress(_es, (unsigned long)addr);
  442             SetSegmentLimit(_es, new_size - 1);
  443             _eflags &= ~CF;
  444         }
  445         return MSDOS_DONE;
  446         }
  447     case 0x01 ... 0x08: /* These are dos functions which */
  448     case 0x0b ... 0x0e: /* are not required memory copy, */
  449     case 0x19:      /* and segment register translation. */
  450     case 0x2a ... 0x2e:
  451     case 0x30 ... 0x34:
  452     case 0x36: case 0x37:
  453     case 0x3e:
  454     case 0x42:
  455     case 0x45: case 0x46:
  456     case 0x4d:
  457     case 0x4f:      /* find next */
  458     case 0x54:
  459     case 0x58: case 0x59:
  460     case 0x5c:      /* lock */
  461     case 0x66 ... 0x68: 
  462     case 0xF8:      /* OEM SET vector */
  463         return 0;
  464     case 0x00:      /* DOS terminate */
  465         old_dos_terminate(scp, intr);
  466         LWORD(eax) = 0x4c00;
  467         return 0;
  468     case 0x09:      /* Print String */
  469         {
  470         int i;
  471         char *s, *d;
  472         prepare_ems_frame();
  473         REG(ds) = TRANS_BUFFER_SEG;
  474         REG(edx) = 0;
  475         d = SEG2LINEAR(REG(ds));
  476         s = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx);
  477         for(i=0; i<0xffff; i++, d++, s++) {
  478             *d = *s;
  479             if( *s == '$')
  480             break;
  481         }
  482         }
  483         return 0;
  484     case 0x1a:      /* set DTA */
  485       {
  486         unsigned long off = D_16_32(_edx);
  487         if ( !in_dos_space(_ds, off)) {
  488         MSDOS_CLIENT.user_dta_sel = _ds;
  489         MSDOS_CLIENT.user_dta_off = off;
  490         REG(ds) = MSDOS_CLIENT.lowmem_seg+DTA_Para_ADD;
  491         REG(edx)=0;
  492                 MEMCPY_DOS2DOS(DTA_under_1MB, DTA_over_1MB, 0x80);
  493         } else {
  494                 REG(ds) = GetSegmentBaseAddress(_ds) >> 4;
  495                 MSDOS_CLIENT.user_dta_sel = 0;
  496             }
  497       }
  498       return 0;
  499             
  500     /* FCB functions */     
  501     case 0x0f: case 0x10:   /* These are not supported by */
  502     case 0x14: case 0x15:   /* dosx.exe, according to Ralf Brown */
  503     case 0x21 ... 0x24:
  504     case 0x27: case 0x28:
  505         error("MS-DOS: Unsupported function 0x%x\n", _HI(ax));
  506         _HI(ax) = 0xff;
  507         return MSDOS_DONE;
  508     case 0x11: case 0x12:   /* find first/next using FCB */
  509     case 0x13:      /* Delete using FCB */
  510     case 0x16:      /* Create usring FCB */
  511     case 0x17:      /* rename using FCB */
  512         prepare_ems_frame();
  513         REG(ds) = TRANS_BUFFER_SEG;
  514         REG(edx) = 0;
  515         MEMCPY_DOS2DOS(SEG_ADR((void *), ds, dx),
  516             (void *)GetSegmentBaseAddress(_ds) + D_16_32(_edx),
  517             0x50);
  518         return 0;
  519     case 0x29:      /* Parse a file name for FCB */
  520         {
  521         unsigned short seg = TRANS_BUFFER_SEG;
  522         prepare_ems_frame();
  523         REG(ds) = seg;
  524         REG(esi) = 0;
  525         MEMCPY_DOS2DOS(SEG_ADR((void *), ds, si),
  526                 (void *)GetSegmentBaseAddress(_ds) + D_16_32(_esi),
  527                 0x100);
  528         seg += 0x10;
  529         REG(es) = seg;
  530         REG(edi) = 0;
  531         MEMCPY_DOS2DOS(SEG_ADR((void *), es, di),
  532                 (void *)GetSegmentBaseAddress(_es) + D_16_32(_edi),
  533                 0x50);
  534         }
  535         return 0;
  536     case 0x47:      /* GET CWD */
  537         prepare_ems_frame();
  538         REG(ds) = TRANS_BUFFER_SEG;
  539         REG(esi) = 0;
  540         return 0;
  541     case 0x4b:      /* EXEC */
  542       {
  543         /* we must copy all data from higher 1MB to lower 1MB */
  544         unsigned short segment = EXEC_SEG;
  545         char *p;
  546         unsigned short sel,off;
  547 
  548         D_printf("BCC: call dos exec\n");
  549         /* must copy command line */
  550         REG(ds) = segment;
  551         REG(edx) = 0;
  552         p = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx);
  553         snprintf((char *)SEG2LINEAR(REG(ds)), MAX_DOS_PATH, "%s", p);
  554         segment += (MAX_DOS_PATH + 0x0f) >> 4;
  555 
  556         /* must copy parameter block */
  557         REG(es) = segment;
  558         REG(ebx) = 0;
  559         MEMCPY_DOS2DOS(SEG_ADR((void *), es, bx),
  560            (void *)GetSegmentBaseAddress(_es) + D_16_32(_ebx), 0x20);
  561         segment += 2;
  562 #if 0
  563         /* now the envrionment segment */
  564         sel = READ_WORD(SEG_ADR((unsigned short *), es, bx));
  565         WRITE_WORD(SEG_ADR((unsigned short *), es, bx), segment);
  566         MEMCPY_DOS2DOS((void *)SEG2LINEAR(segment),           /* 4K envr. */
  567         (void *)GetSegmentBaseAddress(sel),
  568         0x1000);
  569         segment += 0x100;
  570 #else
  571         WRITE_WORD(SEG_ADR((unsigned short *), es, bx), 0);
  572 #endif
  573         /* now the tail of the command line */
  574             off = READ_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+2));
  575         sel = READ_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+4));
  576         WRITE_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+4), segment);
  577         WRITE_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+2), 0);
  578         MEMCPY_DOS2DOS((void *)SEG2LINEAR(segment),
  579         (void *)GetSegmentBaseAddress(sel) + off,
  580         0x80);
  581         segment += 8;
  582 
  583         /* set the FCB pointers to something reasonable */
  584         WRITE_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+6), 0);
  585         WRITE_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+8), segment);
  586         WRITE_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+0xA), 0);
  587         WRITE_WORD(SEGOFF2LINEAR(REG(es), LWORD(ebx)+0xC), segment);
  588         MEMSET_DOS(SEG2LINEAR(segment), 0, 0x30);
  589         segment += 3;
  590 
  591         /* then the enviroment seg */
  592         if (CURRENT_ENV_SEL)
  593         WRITE_ENV_SEL(GetSegmentBaseAddress(CURRENT_ENV_SEL) >> 4);
  594 
  595         if (segment != EXEC_SEG + EXEC_Para_SIZE)
  596         error("DPMI: exec: seg=%#x (%#x), size=%#x\n",
  597             segment, segment - EXEC_SEG, EXEC_Para_SIZE);
  598         if (MSDOS_CLIENT.ems_frame_mapped)
  599         error("DPMI: exec: EMS frame should not be mapped here\n");
  600       }
  601       return 0;
  602 
  603     case 0x50:      /* set PSP */
  604         if ( !in_dos_space(_LWORD(ebx), 0)) {
  605         MSDOS_CLIENT.user_psp_sel = _LWORD(ebx);
  606         LWORD(ebx) = MSDOS_CLIENT.current_psp;
  607         MEMCPY_DOS2DOS((void *)SEG2LINEAR(LWORD(ebx)), 
  608             (void *)GetSegmentBaseAddress(_LWORD(ebx)), 0x100);
  609         D_printf("MSDOS: PSP moved from %p to %p\n",
  610             (char *)GetSegmentBaseAddress(_LWORD(ebx)),
  611             (void *)SEG2LINEAR(LWORD(ebx)));
  612         } else {
  613         REG(ebx) = GetSegmentBaseAddress(_LWORD(ebx)) >> 4;
  614         MSDOS_CLIENT.user_psp_sel = 0;
  615         }
  616         MSDOS_CLIENT.current_psp = LWORD(ebx);
  617         return 0;
  618 
  619     case 0x26:      /* create PSP */
  620         prepare_ems_frame();
  621         REG(edx) = TRANS_BUFFER_SEG;
  622         return 0;
  623 
  624     case 0x55:      /* create & set PSP */
  625         if ( !in_dos_space(_LWORD(edx), 0)) {
  626         MSDOS_CLIENT.user_psp_sel = _LWORD(edx);
  627         LWORD(edx) = MSDOS_CLIENT.current_psp;
  628         } else {
  629         REG(edx) = GetSegmentBaseAddress(_LWORD(edx)) >> 4;
  630         MSDOS_CLIENT.current_psp = LWORD(edx);
  631         MSDOS_CLIENT.user_psp_sel = 0;
  632         }
  633         return 0;
  634 
  635     case 0x39:      /* mkdir */
  636     case 0x3a:      /* rmdir */
  637     case 0x3b:      /* chdir */
  638     case 0x3c:      /* creat */
  639     case 0x3d:      /* Dos OPEN */
  640     case 0x41:      /* unlink */
  641     case 0x43:      /* change attr */
  642     case 0x4e:      /* find first */
  643     case 0x5b:      /* Create */
  644         if ((_HI(ax) == 0x4e) && (_ecx & 0x8))
  645         D_printf("MSDOS: MS-DOS try to find volume label\n");
  646         {
  647         char *src, *dst;
  648         prepare_ems_frame();
  649         REG(ds) = TRANS_BUFFER_SEG;
  650         REG(edx) = 0;
  651         src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx);
  652         dst = SEG_ADR((char *), ds, dx);
  653         D_printf("MSDOS: passing ASCIIZ > 1MB to dos %p\n", dst);
  654         D_printf("%p: '%s'\n", src, src);
  655                 snprintf(dst, MAX_DOS_PATH, "%s", src);
  656         }
  657         return 0;
  658     case 0x38:
  659         if (_LWORD(edx) != 0xffff) { /* get country info */
  660         prepare_ems_frame();
  661         REG(ds) = TRANS_BUFFER_SEG;
  662         REG(edx) = 0;
  663         }
  664         break;
  665     case 0x3f:      /* dos read */
  666         set_io_buffer((char*)GetSegmentBaseAddress(_ds) + D_16_32(_edx),
  667         D_16_32(_ecx));
  668         prepare_ems_frame();
  669         REG(ds) = TRANS_BUFFER_SEG;
  670         REG(edx) = 0;
  671         REG(ecx) = D_16_32(_ecx);
  672         fake_call_to(DOS_LONG_READ_SEG, DOS_LONG_READ_OFF);
  673         return MSDOS_ALT_ENT;
  674     case 0x40:      /* DOS Write */
  675         set_io_buffer((char*)GetSegmentBaseAddress(_ds) + D_16_32(_edx),
  676         D_16_32(_ecx));
  677         prepare_ems_frame();
  678         REG(ds) = TRANS_BUFFER_SEG;
  679         REG(edx) = 0;
  680         REG(ecx) = D_16_32(_ecx);
  681         fake_call_to(DOS_LONG_WRITE_SEG, DOS_LONG_WRITE_OFF);
  682         return MSDOS_ALT_ENT;
  683     case 0x53:      /* Generate Drive Parameter Table  */
  684         {
  685         unsigned short seg = TRANS_BUFFER_SEG;
  686         prepare_ems_frame();
  687         REG(ds) = seg;
  688         REG(esi) = 0;
  689         MEMCPY_DOS2DOS(SEG_ADR((void *), ds, si),
  690                 (void *)GetSegmentBaseAddress(_ds) + D_16_32(_esi),
  691                 0x30);
  692         seg += 3;
  693 
  694         REG(es) = seg;
  695         REG(ebp) = 0;
  696         MEMCPY_DOS2DOS(SEG_ADR((void *), es, bp),
  697                 (void *)GetSegmentBaseAddress(_es) + D_16_32(_ebp),
  698                 0x60);
  699         }
  700         return 0;
  701     case 0x56:      /* rename file */
  702         {
  703         unsigned short seg = TRANS_BUFFER_SEG;
  704         prepare_ems_frame();
  705         REG(ds) = seg;
  706         REG(edx) = 0;
  707         snprintf(SEG2LINEAR(REG(ds)), MAX_DOS_PATH, "%s",
  708                  (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx));
  709         seg += 0x20;
  710 
  711         REG(es) = seg;
  712         REG(edi) = 0;
  713         snprintf(SEG2LINEAR(REG(es)), MAX_DOS_PATH, "%s",
  714                  (char *)GetSegmentBaseAddress(_es) + D_16_32(_edi));
  715         }
  716         return 0;
  717     case 0x5f:      /* redirection */
  718         switch (_LO(ax)) {
  719         unsigned short seg;
  720         case 0: case 1:
  721         return 0;
  722         case 2 ... 6:
  723         prepare_ems_frame();
  724         seg = TRANS_BUFFER_SEG;
  725         REG(ds) = seg;
  726         REG(esi) = 0;
  727         MEMCPY_DOS2DOS(SEG_ADR((void *), ds, si),
  728             (void *)GetSegmentBaseAddress(_ds) + D_16_32(_esi),
  729             0x100);
  730         seg += 0x10;
  731         REG(es) = seg;
  732         REG(edi) = 0;
  733         MEMCPY_DOS2DOS(SEG_ADR((void *), es, di),
  734             (void *)GetSegmentBaseAddress(_es) + D_16_32(_edi),
  735             0x100);
  736         return 0;
  737         }
  738     case 0x60:      /* Get Fully Qualified File Name */
  739         {
  740         unsigned short seg = TRANS_BUFFER_SEG;
  741         prepare_ems_frame();
  742         REG(ds) = seg;
  743         REG(esi) = 0;
  744         MEMCPY_DOS2DOS(SEG_ADR((void *), ds, si),
  745             (void *)GetSegmentBaseAddress(_ds) + D_16_32(_esi),
  746             0x100);
  747         seg += 0x10;
  748         REG(es) = seg;
  749         REG(edi) = 0;
  750         return 0;
  751         }
  752     case 0x6c:      /*  Extended Open/Create */
  753         {
  754         char *src, *dst;
  755         prepare_ems_frame();
  756         REG(ds) = TRANS_BUFFER_SEG;
  757         REG(esi) = 0;
  758         src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_esi);
  759         dst = SEG_ADR((char *), ds, si);
  760         D_printf("MSDOS: passing ASCIIZ > 1MB to dos %p\n", dst); 
  761         D_printf("%p: '%s'\n", src, src);
  762         snprintf(dst, MAX_DOS_PATH, "%s", src);
  763         }
  764         return 0;
  765     case 0x65:      /* internationalization */
  766             switch (_LO(ax)) {
  767         case 0:
  768             prepare_ems_frame();
  769             REG(es) = TRANS_BUFFER_SEG;
  770             REG(edi) = 0;
  771             MEMCPY_DOS2DOS(SEG_ADR((void *), es, di),
  772             (void *)GetSegmentBaseAddress(_es) + D_16_32(_edi),
  773             _LWORD(ecx));
  774             break;
  775         case 1 ... 7:
  776             prepare_ems_frame();
  777             REG(es) = TRANS_BUFFER_SEG;
  778             REG(edi) = 0;
  779             break;
  780         case 0x21:
  781         case 0xa1:
  782             prepare_ems_frame();
  783             REG(ds) = TRANS_BUFFER_SEG;
  784             REG(edx) = 0;
  785             MEMCPY_DOS2DOS(SEG_ADR((void *), ds, dx),
  786             (void *)GetSegmentBaseAddress(_ds) + D_16_32(_edx),
  787             _LWORD(ecx));
  788             break;
  789         case 0x22:
  790         case 0xa2:
  791             prepare_ems_frame();
  792             REG(ds) = TRANS_BUFFER_SEG;
  793             REG(edx) = 0;
  794             strcpy(SEG_ADR((void *), ds, dx),
  795             (void *)GetSegmentBaseAddress(_ds) + D_16_32(_edx));
  796             break;
  797         }
  798             return 0;
  799     case 0x71:     /* LFN functions */
  800         {
  801         char *src, *dst;
  802         switch (_LO(ax)) {
  803         case 0x3B: /* change dir */
  804         case 0x41: /* delete file */
  805         case 0x43: /* get file attributes */
  806         prepare_ems_frame();
  807             REG(ds) = TRANS_BUFFER_SEG;
  808             REG(edx) = 0;
  809             src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx);
  810             dst = SEG_ADR((char *), ds, dx);
  811             snprintf(dst, MAX_DOS_PATH, "%s", src);
  812             return 0;
  813         case 0x4E: /* find first file */
  814         prepare_ems_frame();
  815             REG(ds) = TRANS_BUFFER_SEG;
  816             REG(edx) = 0;
  817             REG(es) = TRANS_BUFFER_SEG;
  818             REG(edi) = MAX_DOS_PATH;
  819             src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx);
  820             dst = SEG_ADR((char *), ds, dx);
  821             snprintf(dst, MAX_DOS_PATH, "%s", src);
  822             return 0;
  823         case 0x4F: /* find next file */
  824         prepare_ems_frame();
  825             REG(es) = TRANS_BUFFER_SEG;
  826             REG(edi) = 0;
  827             src = (char *)GetSegmentBaseAddress(_es) + D_16_32(_edi);
  828             dst = SEG_ADR((char *), es, di);
  829             MEMCPY_DOS2DOS(dst, src, 0x13e);
  830             return 0;
  831         case 0x47: /* get cur dir */
  832         prepare_ems_frame();
  833             REG(ds) = TRANS_BUFFER_SEG;
  834             REG(esi) = 0;
  835             return 0;
  836     case 0x60: /* canonicalize filename */
  837         prepare_ems_frame();
  838         REG(ds) = TRANS_BUFFER_SEG;
  839         REG(esi) = 0;
  840         REG(es) = TRANS_BUFFER_SEG;
  841         REG(edi) = MAX_DOS_PATH;
  842         src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_esi);   
  843         dst = SEG_ADR((char *), ds, si);
  844         snprintf(dst, MAX_DOS_PATH, "%s", src);
  845         return 0;
  846         case 0x6c: /* extended open/create */
  847         prepare_ems_frame();
  848             REG(ds) = TRANS_BUFFER_SEG;
  849             REG(esi) = 0;
  850             src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_esi);
  851             dst = SEG_ADR((char *), ds, si);
  852             snprintf(dst, MAX_DOS_PATH, "%s", src);
  853             return 0;
  854         case 0xA0: /* get volume info */
  855         prepare_ems_frame();
  856             REG(ds) = TRANS_BUFFER_SEG;
  857             REG(edx) = 0;
  858             REG(es) = TRANS_BUFFER_SEG;
  859             REG(edi) = MAX_DOS_PATH;
  860             src = (char *)GetSegmentBaseAddress(_ds) + D_16_32(_edx);
  861             dst = SEG_ADR((char *), ds, dx);
  862             snprintf(dst, MAX_DOS_PATH, "%s", src);
  863             return 0;
  864         case 0xA1: /* close find */
  865             return 0;
  866         default: /* all other subfuntions currently not supported */
  867             _eflags |= CF;
  868             _eax = _eax & 0xFFFFFF00;
  869             return 1;
  870         }
  871         }
  872     default:
  873         break;
  874     }
  875     break;
  876     case 0x33:          /* mouse */
  877     switch (_LWORD(eax)) {
  878     case 0x09:      /* Set Mouse Graphics Cursor */
  879         prepare_ems_frame();
  880         REG(es) = TRANS_BUFFER_SEG;
  881         REG(edx) = 0;
  882         MEMCPY_DOS2DOS(SEG_ADR((void *), es, dx),
  883             (void *)GetSegmentBaseAddress(_es) + D_16_32(_edx),
  884             16);
  885         return 0;
  886     case 0x0c:      /* set call back */
  887     case 0x14: {        /* swap call back */
  888         struct pmaddr_s old_callback = MSDOS_CLIENT.mouseCallBack;
  889         MSDOS_CLIENT.mouseCallBack.selector = _es;
  890         MSDOS_CLIENT.mouseCallBack.offset = D_16_32(_edx);
  891         if (_es) {
  892         D_printf("MSDOS: set mouse callback\n");
  893         REG(es) = DPMI_SEG;
  894         REG(edx) = DPMI_OFF + HLT_OFF(MSDOS_mouse_callback);
  895         } else {
  896         D_printf("MSDOS: reset mouse callback\n");
  897         REG(es) = 0;
  898         REG(edx) = 0;
  899         }
  900         if (_LWORD(eax) == 0x14) {
  901         _es = old_callback.selector;
  902         if (MSDOS_CLIENT.is_32)
  903             _edx = old_callback.offset;
  904         else
  905             _LWORD(edx) = old_callback.offset;
  906         }
  907       }
  908       return 0;
  909     }
  910     break;
  911     }
  912 
  913     if (need_copy_dseg(scp, intr)) {
  914     char *src, *dst;
  915     int len;
  916     prepare_ems_frame();
  917     REG(ds) = TRANS_BUFFER_SEG;
  918     src = (char *)GetSegmentBaseAddress(_ds);
  919     dst = SEG2LINEAR(REG(ds));
  920     len = min((int)(GetSegmentLimit(_ds) + 1), 0x10000);
  921     D_printf("MSDOS: whole segment of DS at %p copy to DOS at %p for %#x\n",
  922         src, dst, len);
  923     MEMCPY_DOS2DOS(dst, src, len);
  924     }
  925 
  926     if (need_copy_eseg(scp, intr)) {
  927     char *src, *dst;
  928     int len;
  929     prepare_ems_frame();
  930     REG(es) = TRANS_BUFFER_SEG;
  931     src = (char *)GetSegmentBaseAddress(_es);
  932     dst = SEG2LINEAR(REG(es));
  933     len = min((int)(GetSegmentLimit(_es) + 1), 0x10000);
  934     D_printf("MSDOS: whole segment of ES at %p copy to DOS at %p for %#x\n",
  935         src, dst, len);
  936     MEMCPY_DOS2DOS(dst, src, len);
  937     }
  938     return 0;
  939 }
  940 
  941 /*
  942  * DANG_BEGIN_FUNCTION msdos_post_extender
  943  *
  944  * This function is called after return from real mode DOS service
  945  * All real mode segment registers are changed to protected mode selectors
  946  * And if client\'s data buffer is above 1MB, necessary buffer copying
  947  * is performed.
  948  *
  949  * DANG_END_FUNCTION
  950  */
  951 
  952 int msdos_post_extender(struct sigcontext_struct *scp, int intr)
  953 {
  954     int update_mask = ~0;
  955 #define PRESERVE1(rg) (update_mask &= ~(1 << rg##_INDEX))
  956 #define PRESERVE2(rg1, rg2) (update_mask &= ~((1 << rg1##_INDEX) | (1 << rg2##_INDEX)))
  957 #define SET_REG(rg, val) (PRESERVE1(rg), _##rg = (val))
  958     D_printf("MSDOS: post_extender: int 0x%x ax=0x%04x\n", intr, _LWORD(eax));
  959 
  960     if (MSDOS_CLIENT.user_dta_sel && intr == 0x21 ) {
  961     switch (_HI(ax)) {  /* functions use DTA */
  962     case 0x11: case 0x12:   /* find first/next using FCB */
  963     case 0x4e: case 0x4f:   /* find first/next */
  964         MEMCPY_DOS2DOS(DTA_over_1MB, DTA_under_1MB, 0x80);
  965         break;
  966     }
  967     }
  968 
  969     if (need_copy_dseg(scp, intr)) {
  970     unsigned short my_ds;
  971     char *src, *dst;
  972     int len;
  973     my_ds = TRANS_BUFFER_SEG;
  974     src = SEG2LINEAR(my_ds);
  975     dst = (char *)GetSegmentBaseAddress(_ds);
  976     len = min((int)(GetSegmentLimit(_ds) + 1), 0x10000);
  977     D_printf("MSDOS: DS seg at %p copy back at %p for %#x\n",
  978         src, dst, len);
  979     MEMCPY_DOS2DOS(dst, src, len);
  980     } 
  981 
  982     if (need_copy_eseg(scp, intr)) {
  983     unsigned short my_es;
  984     char *src, *dst;
  985     int len;
  986     my_es = TRANS_BUFFER_SEG;
  987     src = SEG2LINEAR(my_es);
  988     dst = (char *)GetSegmentBaseAddress(_es);
  989     len = min((int)(GetSegmentLimit(_es) + 1), 0x10000);
  990     D_printf("MSDOS: ES seg at %p copy back at %p for %#x\n",
  991         src, dst, len);
  992     MEMCPY_DOS2DOS(dst, src, len);
  993     } 
  994 
  995     switch (intr) {
  996     case 0x10:          /* video */
  997     if (_LWORD(eax) == 0x1130) {
  998         /* get current character generator infor */
  999         SET_REG(es, ConvertSegmentToDescriptor(REG(es)));
 1000     }
 1001     break;
 1002     case 0x15:
 1003     /* we need to save regs at int15 because AH has the return value */
 1004     if (_HI(ax) == 0xc0) { /* Get Configuration */
 1005                 if (REG(eflags)&CF)
 1006                         break;
 1007                 SET_REG(es, ConvertSegmentToDescriptor(REG(es)));
 1008         }
 1009     break;
 1010     case 0x2f:
 1011     switch (_LWORD(eax)) {
 1012         case 0x4310:
 1013                 MSDOS_CLIENT.XMS_call = MK_FARt(REG(es), LWORD(ebx));
 1014                 SET_REG(es, dpmi_sel());
 1015                 SET_REG(ebx, DPMI_SEL_OFF(MSDOS_XMS_call));
 1016         break;
 1017     }
 1018     break;
 1019 
 1020     case 0x21:
 1021     switch (_HI(ax)) {
 1022     case 0x00:      /* psp kill */
 1023         PRESERVE1(eax);
 1024         break;
 1025     case 0x09:      /* print String */
 1026     case 0x1a:      /* set DTA */
 1027         PRESERVE1(edx);
 1028         break;
 1029     case 0x11: case 0x12:   /* findfirst/next using FCB */
 1030     case 0x13:      /* Delete using FCB */
 1031     case 0x16:      /* Create usring FCB */
 1032     case 0x17:      /* rename using FCB */
 1033         PRESERVE1(edx);
 1034         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_ds) + D_16_32(_edx),
 1035             SEG_ADR((void *), ds, dx), 0x50);
 1036         break;
 1037 
 1038     case 0x29:      /* Parse a file name for FCB */
 1039         PRESERVE2(esi, edi);
 1040         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_ds) + D_16_32(_esi),
 1041         /* Warning: SI altered, assume old value = 0, don't touch. */
 1042                 SEG2LINEAR(REG(ds)), 0x100);
 1043         SET_REG(esi, _esi + LWORD(esi));
 1044         MEMCPY_DOS2DOS((void *)(GetSegmentBaseAddress(_es) + D_16_32(_edi)),
 1045                 SEG_ADR((void *), es, di),  0x50);
 1046         break;
 1047 
 1048     case 0x2f:      /* GET DTA */
 1049         if (SEG_ADR((void*), es, bx) == DTA_under_1MB) {
 1050         if (!MSDOS_CLIENT.user_dta_sel)
 1051             error("Selector is not set for the translated DTA\n");
 1052         SET_REG(es, MSDOS_CLIENT.user_dta_sel);
 1053         SET_REG(ebx, MSDOS_CLIENT.user_dta_off);
 1054         } else {
 1055         SET_REG(es, ConvertSegmentToDescriptor(REG(es)));
 1056         /* it is important to copy only the lower word of ebx
 1057          * and make the higher word zero, so do it here instead
 1058          * of relying on dpmi.c */
 1059         SET_REG(ebx, LWORD(ebx));
 1060         }
 1061         break;
 1062 
 1063     case 0x34:      /* Get Address of InDOS Flag */
 1064     case 0x35:      /* GET Vector */
 1065     case 0x52:      /* Get List of List */
 1066         SET_REG(es, ConvertSegmentToDescriptor(REG(es)));
 1067         break;
 1068 
 1069     case 0x39:      /* mkdir */
 1070     case 0x3a:      /* rmdir */
 1071     case 0x3b:      /* chdir */
 1072     case 0x3c:      /* creat */
 1073     case 0x3d:      /* Dos OPEN */
 1074     case 0x41:      /* unlink */
 1075     case 0x43:      /* change attr */
 1076     case 0x4e:      /* find first */
 1077     case 0x5b:      /* Create */
 1078         PRESERVE1(edx);
 1079         break;
 1080 
 1081     case 0x50:      /* Set PSP */
 1082         PRESERVE1(ebx);
 1083         break;
 1084 
 1085     case 0x6c:      /*  Extended Open/Create */
 1086         PRESERVE1(esi);
 1087         break;
 1088         
 1089     case 0x55:      /* create & set PSP */
 1090         PRESERVE1(edx);
 1091         if (!in_dos_space(_LWORD(edx), 0)) {
 1092         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_LWORD(edx)),
 1093             SEG2LINEAR(LWORD(edx)), 0x100);
 1094         }
 1095         break;
 1096 
 1097     case 0x26:      /* create PSP */
 1098         PRESERVE1(edx);
 1099         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_LWORD(edx)),
 1100         (void *)SEG2LINEAR(LWORD(edx)), 0x100);
 1101       break;
 1102 
 1103         case 0x59:      /* Get EXTENDED ERROR INFORMATION */
 1104         if(LWORD(eax) == 0x22) { /* only this code has a pointer */
 1105         SET_REG(es, ConvertSegmentToDescriptor(REG(es)));
 1106         }
 1107         break;
 1108     case 0x38:
 1109         if (_LWORD(edx) != 0xffff) { /* get country info */
 1110         PRESERVE1(edx);
 1111         if (LWORD(eflags) & CF)
 1112             break;
 1113         /* FreeDOS copies only 0x18 bytes */
 1114         MEMCPY_DOS2DOS((void *)(GetSegmentBaseAddress(_ds) +
 1115             D_16_32(_edx)), SEG_ADR((void *), ds, dx), 0x18);
 1116         }
 1117         break;
 1118     case 0x47:      /* get CWD */
 1119         PRESERVE1(esi);
 1120         if (LWORD(eflags) & CF)
 1121         break;
 1122         snprintf((char *)(GetSegmentBaseAddress(_ds) +
 1123             D_16_32(_esi)), 0x40, "%s", 
 1124                 SEG_ADR((char *), ds, si));
 1125         D_printf("MSDOS: CWD: %s\n",(char *)(GetSegmentBaseAddress(_ds) +
 1126             D_16_32(_esi)));
 1127         break;
 1128 #if 0       
 1129     case 0x48:      /* allocate memory */
 1130         if (LWORD(eflags) & CF)
 1131         break;
 1132         SET_REG(eax, ConvertSegmentToDescriptor(LWORD(eax)));
 1133         break;
 1134 #endif      
 1135     case 0x4b:      /* EXEC */
 1136         if (CURRENT_ENV_SEL)
 1137         WRITE_ENV_SEL(ConvertSegmentToDescriptor(CURRENT_ENV_SEL));
 1138         D_printf("DPMI: Return from DOS exec\n");
 1139         break;
 1140     case 0x51:      /* get PSP */
 1141     case 0x62:
 1142         {/* convert environment pointer to a descriptor*/
 1143         unsigned short psp = LWORD(ebx);
 1144         if (psp == MSDOS_CLIENT.current_psp && MSDOS_CLIENT.user_psp_sel) {
 1145             SET_REG(ebx, MSDOS_CLIENT.user_psp_sel);
 1146         } else {
 1147             SET_REG(ebx, ConvertSegmentToDescriptor_lim(psp, 0xff));
 1148         }
 1149         }
 1150         break;
 1151     case 0x53:      /* Generate Drive Parameter Table  */
 1152         PRESERVE2(esi, ebp);
 1153         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_es) + D_16_32(_ebp),
 1154                 SEG_ADR((void *), es, bp),
 1155                 0x60);
 1156         break ;
 1157     case 0x56:      /* rename */
 1158         PRESERVE2(edx, edi);
 1159         break ;
 1160     case 0x5d:
 1161         if (_LO(ax) == 0x06 || _LO(ax) == 0x0b) /* get address of DOS swappable area */
 1162                 /*        -> DS:SI                     */
 1163         SET_REG(ds, ConvertSegmentToDescriptor(REG(ds)));
 1164         break;
 1165     case 0x63:      /* Get Lead Byte Table Address */
 1166         /* _LO(ax)==0 is to test for 6300 on input, LO(ax)==0 for success*/
 1167         if (_LO(ax) == 0 && LO(ax) == 0)
 1168             SET_REG(ds, ConvertSegmentToDescriptor(REG(ds)));
 1169         break;
 1170 
 1171     case 0x3f:
 1172         unset_io_buffer();
 1173         PRESERVE2(edx, ecx);
 1174         break;
 1175     case 0x40:
 1176         unset_io_buffer();
 1177         PRESERVE2(edx, ecx);
 1178         break;
 1179     case 0x5f:      /* redirection */
 1180         switch (_LO(ax)) {
 1181         case 0: case 1:
 1182         break ;
 1183         case 2 ... 6:
 1184         PRESERVE2(esi, edi);
 1185         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_ds)
 1186             + D_16_32(_esi),
 1187             SEG_ADR((void *), ds, si),
 1188             0x100);
 1189         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_es)
 1190             + D_16_32(_edi),
 1191             SEG_ADR((void *), es, di),
 1192             0x100);
 1193         }
 1194         break;
 1195     case 0x60:      /* Canonicalize file name */
 1196         PRESERVE2(esi, edi);
 1197         MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_es)
 1198             + D_16_32(_edi),
 1199             SEG_ADR((void *), es, di),
 1200             0x80);
 1201         break;
 1202     case 0x65:      /* internationalization */
 1203         PRESERVE2(edi, edx);
 1204         if (LWORD(eflags) & CF)
 1205         break;
 1206             switch (_LO(ax)) {
 1207         case 1 ... 7:
 1208             MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_es)
 1209             + D_16_32(_edi),
 1210             SEG_ADR((void *), es, di),
 1211             LWORD(ecx));
 1212             break;
 1213         case 0x21:
 1214         case 0xa1:
 1215             MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_ds)
 1216             + D_16_32(_edx),
 1217             SEG_ADR((void *), ds, dx),
 1218             _LWORD(ecx));
 1219             break;
 1220         case 0x22:
 1221         case 0xa2:
 1222             strcpy((void *)GetSegmentBaseAddress(_ds)
 1223             + D_16_32(_edx),
 1224             SEG_ADR((void *), ds, dx));
 1225             break;
 1226         }
 1227         break;
 1228     case 0x71:      /* LFN functions */
 1229         switch (_LO(ax)) {
 1230         case 0x3B:
 1231         case 0x41:
 1232         case 0x43:
 1233         PRESERVE1(edx);
 1234             break;
 1235         case 0x4E:
 1236         PRESERVE1(edx);
 1237             /* fall thru */
 1238         case 0x4F:
 1239         PRESERVE1(edi);
 1240             if (LWORD(eflags) & CF)
 1241                 break;
 1242             MEMCPY_DOS2DOS((void *)GetSegmentBaseAddress(_es)
 1243                      + D_16_32(_edi),
 1244                      SEG_ADR((void *), es, di),
 1245                         0x13E);
 1246             break;
 1247         case 0x47:
 1248         PRESERVE1(esi);
 1249             if (LWORD(eflags) & CF)
 1250                 break;
 1251         snprintf((char *)(GetSegmentBaseAddress(_ds) +
 1252             D_16_32(_esi)), MAX_DOS_PATH, "%s", 
 1253                 SEG_ADR((char *), ds, si));
 1254             break;
 1255     case 0x60:
 1256         PRESERVE2(esi, edi);
 1257         if (LWORD(eflags) & CF)
 1258         break;
 1259         snprintf((void *)GetSegmentBaseAddress(_es) + 
 1260         D_16_32(_edi), MAX_DOS_PATH, "%s",
 1261         SEG_ADR((char *), es, di));
 1262         break;
 1263         case 0x6c:
 1264         PRESERVE1(esi);
 1265             break;
 1266         case 0xA0:
 1267             PRESERVE2(edx, edi);
 1268             if (LWORD(eflags) & CF)
 1269                 break;
 1270             snprintf((void *)GetSegmentBaseAddress(_es) +
 1271                      D_16_32(_edi), _LWORD(ecx), "%s",
 1272                      SEG_ADR((char *), es, di));
 1273             break;
 1274         };
 1275 
 1276     default:
 1277         break;
 1278     }
 1279     break;
 1280     case 0x25:          /* Absolute Disk Read */
 1281     case 0x26:          /* Absolute Disk Write */
 1282     /* the flags should be pushed to stack */
 1283     if (MSDOS_CLIENT.is_32) {
 1284         _esp -= 4;
 1285         *(uint32_t *)(GetSegmentBaseAddress(_ss) + _esp - 4) =
 1286           REG(eflags);
 1287     } else {
 1288         _esp -= 2;
 1289         *(unsigned short *)(GetSegmentBaseAddress(_ss) +
 1290           _LWORD(esp) - 2) = LWORD(eflags);
 1291     }
 1292     break;
 1293     case 0x33:          /* mouse */
 1294     switch (_LWORD(eax)) {
 1295     case 0x09:      /* Set Mouse Graphics Cursor */
 1296     case 0x14:      /* swap call back */
 1297         PRESERVE1(edx);
 1298         break;
 1299     case 0x19:      /* Get User Alternate Interrupt Address */
 1300         SET_REG(ebx, ConvertSegmentToDescriptor(LWORD(ebx)));
 1301         break;
 1302     default:
 1303         break;
 1304     }
 1305     break;
 1306     }
 1307     restore_ems_frame();
 1308     return update_mask;
 1309 }
 1310 
 1311 int msdos_pre_rm(struct sigcontext_struct *scp)
 1312 {
 1313   unsigned char *lina = SEG_ADR((unsigned char *), cs, ip) - 1;
 1314   unsigned short *ssp = (us *) (GetSegmentBaseAddress(_ss) + D_16_32(_esp));
 1315 
 1316   if (lina == (unsigned char *)(DPMI_ADD + HLT_OFF(MSDOS_mouse_callback))) {
 1317     if (!ValidAndUsedSelector(MSDOS_CLIENT.mouseCallBack.selector)) {
 1318       D_printf("MSDOS: ERROR: mouse callback to unused segment\n");
 1319       return 0;
 1320     }
 1321     D_printf("MSDOS: starting mouse callback\n");
 1322     rm_to_pm_regs(scp, ~0);
 1323     _ds = ConvertSegmentToDescriptor(REG(ds));
 1324     _cs = MSDOS_CLIENT.mouseCallBack.selector;
 1325     _eip = MSDOS_CLIENT.mouseCallBack.offset;
 1326 
 1327     if (MSDOS_CLIENT.is_32) {
 1328     *--ssp = (us) 0;
 1329     *--ssp = dpmi_sel(); 
 1330     ssp -= 2, *((uint32_t *) ssp) =
 1331          DPMI_SEL_OFF(MSDOS_return_from_pm);
 1332     _esp -= 8;
 1333     } else {
 1334     *--ssp = dpmi_sel(); 
 1335     *--ssp = DPMI_SEL_OFF(MSDOS_return_from_pm);
 1336     _LWORD(esp) -= 4;
 1337     }
 1338 
 1339   } else if (lina ==(unsigned char *)(DPMI_ADD +
 1340                       HLT_OFF(MSDOS_PS2_mouse_callback))) {
 1341     unsigned short *rm_ssp;
 1342     if (!ValidAndUsedSelector(MSDOS_CLIENT.PS2mouseCallBack.selector)) {
 1343       D_printf("MSDOS: ERROR: PS2 mouse callback to unused segment\n");
 1344       return 0;
 1345     }
 1346     D_printf("MSDOS: starting PS2 mouse callback\n");
 1347 
 1348     _cs = MSDOS_CLIENT.PS2mouseCallBack.selector;
 1349     _eip = MSDOS_CLIENT.PS2mouseCallBack.offset;
 1350 
 1351     rm_ssp = (unsigned short *)SEGOFF2LINEAR(LWORD(ss), LWORD(esp) + 4 + 8);
 1352 
 1353     if (MSDOS_CLIENT.is_32) {
 1354     *--ssp = (us) 0;
 1355     *--ssp = *--rm_ssp;
 1356     D_printf("data: 0x%x ", *ssp);
 1357     *--ssp = (us) 0;
 1358     *--ssp = *--rm_ssp;
 1359     D_printf("0x%x ", *ssp);
 1360     *--ssp = (us) 0;
 1361     *--ssp = *--rm_ssp;
 1362     D_printf("0x%x ", *ssp);
 1363     *--ssp = (us) 0;
 1364     *--ssp = *--rm_ssp;
 1365     D_printf("0x%x\n", *ssp);
 1366     *--ssp = (us) 0;
 1367     *--ssp = dpmi_sel(); 
 1368     ssp -= 2, *((uint32_t *) ssp) =
 1369          DPMI_SEL_OFF(MSDOS_return_from_pm);
 1370     _esp -= 24;
 1371     } else {
 1372     *--ssp = *--rm_ssp;
 1373     D_printf("data: 0x%x ", *ssp);
 1374     *--ssp = *--rm_ssp;
 1375     D_printf("0x%x ", *ssp);
 1376     *--ssp = *--rm_ssp;
 1377     D_printf("0x%x ", *ssp);
 1378     *--ssp = *--rm_ssp;
 1379     D_printf("0x%x\n", *ssp);
 1380     *--ssp = dpmi_sel(); 
 1381     *--ssp = DPMI_SEL_OFF(MSDOS_return_from_pm);
 1382     _LWORD(esp) -= 12;
 1383     }
 1384   }
 1385   return 1;
 1386 }
 1387 
 1388 void msdos_post_rm(struct sigcontext_struct *scp)
 1389 {
 1390   pm_to_rm_regs(scp, ~0);
 1391 }
 1392 
 1393 int msdos_pre_pm(struct sigcontext_struct *scp)
 1394 {
 1395   if (_eip==1+DPMI_SEL_OFF(MSDOS_XMS_call)) {
 1396     D_printf("MSDOS: XMS call to 0x%x:0x%x\n",
 1397     MSDOS_CLIENT.XMS_call.segment, MSDOS_CLIENT.XMS_call.offset);
 1398     pm_to_rm_regs(scp, ~0);
 1399     REG(cs) = DPMI_SEG;
 1400     REG(eip) = DPMI_OFF + HLT_OFF(MSDOS_return_from_rm);
 1401     fake_call_to(MSDOS_CLIENT.XMS_call.segment, MSDOS_CLIENT.XMS_call.offset);
 1402   } else {
 1403     error("MSDOS: unknown pm call %p\n", _eip);
 1404     return 0;
 1405   }
 1406   return 1;
 1407 }
 1408 
 1409 void msdos_post_pm(struct sigcontext_struct *scp)
 1410 {
 1411   rm_to_pm_regs(scp, ~0);
 1412 }
 1413 
 1414 
 1415 int msdos_fault(struct sigcontext_struct *scp)
 1416 {
 1417     struct sigcontext_struct new_sct;
 1418     int reg;
 1419     unsigned int segment;
 1420     unsigned short desc;
 1421 
 1422     D_printf("MSDOS: msdos_fault, err=%#lx\n",_err);
 1423     if ((_err & 0xffff) == 0) { /*  not a selector error */
 1424     /* Why should we "fix" the NULL dereferences? */
 1425     /* Because the unmodified Win3.1 kernel (not WinOS2) needs this */
 1426     /* Yes, but only when LDT is read-only, and then it doesn't work anyway.
 1427      * So lets disable it again and see if someone else needs this. */
 1428 #if 0
 1429     char fixed = 0;
 1430     unsigned char * csp;
 1431 
 1432     csp = (unsigned char *) SEL_ADR(_cs, _eip);
 1433 
 1434     /* see if client wants to access control registers */
 1435     if (*csp == 0x0f) {
 1436       if (cpu_trap_0f(csp, scp)) return 1;  /* 1=handled */
 1437     }
 1438     
 1439     switch (*csp) {
 1440     case 0x2e:      /* cs: */
 1441         break;      /* do nothing */
 1442     case 0x36:      /* ss: */
 1443         break;      /* do nothing */
 1444     case 0x26:      /* es: */
 1445         if (_es == 0) {
 1446         D_printf("MSDOS: client tries to use use gdt 0 as es\n");
 1447         _es = ConvertSegmentToDescriptor(0);
 1448         fixed = 1;
 1449         }
 1450         break;
 1451     case 0x64:      /* fs: */
 1452         if (_fs == 0) {
 1453         D_printf("MSDOS: client tries to use use gdt 0 as fs\n");
 1454         _fs = ConvertSegmentToDescriptor(0);
 1455         fixed = 1;
 1456         }
 1457         break;
 1458     case 0x65:      /* gs: */
 1459         if (_gs == 0) {
 1460         D_printf("MSDOS: client tries to use use gdt 0 as es\n");
 1461         _gs = ConvertSegmentToDescriptor(0);
 1462         fixed = 1;
 1463         }
 1464         break;
 1465     case 0xf2:      /* REPNE prefix */
 1466     case 0xf3:      /* REP, REPE */
 1467         /* this might be a string insn */
 1468         switch (*(csp+1)) {
 1469         case 0xaa: case 0xab:       /* stos */
 1470         case 0xae: case 0xaf:           /* scas */
 1471         /* only use es */
 1472         if (_es == 0) {
 1473             D_printf("MSDOS: client tries to use use gdt 0 as es\n");
 1474             _es = ConvertSegmentToDescriptor(0);
 1475             fixed = 1;
 1476         }
 1477         break;
 1478         case 0xa4: case 0xa5:       /* movs */
 1479         case 0xa6: case 0xa7:         /* cmps */
 1480         /* use both ds and es */
 1481         if (_es == 0) {
 1482             D_printf("MSDOS: client tries to use use gdt 0 as es\n");
 1483             _es = ConvertSegmentToDescriptor(0);
 1484             fixed = 1;
 1485         }
 1486         if (_ds == 0) {
 1487             D_printf("MSDOS: client tries to use use gdt 0 as ds\n");
 1488             _ds = ConvertSegmentToDescriptor(0);
 1489             fixed = 1;
 1490         }
 1491         break;
 1492         }
 1493         break;
 1494     case 0x3e:      /* ds: */
 1495     default:        /* assume default is using ds, but if the */
 1496                 /* client sets ss to 0, it is totally broken */
 1497         if (_ds == 0) {
 1498         D_printf("MSDOS: client tries to use use gdt 0 as ds\n");
 1499         _ds = ConvertSegmentToDescriptor(0);
 1500         fixed = 1;
 1501         }
 1502         break;
 1503     }
 1504     return fixed;
 1505 #else
 1506     return 0;
 1507 #endif
 1508     }
 1509     
 1510     /* now it is a invalid selector error, try to fix it if it is */
 1511     /* caused by an instruction such as mov Sreg,r/m16            */
 1512 
 1513     copy_context(&new_sct, scp, 0);
 1514     reg = decode_modify_segreg_insn(&new_sct, 1, &segment);
 1515     if (reg == -1)
 1516       return 0;
 1517 
 1518     if (ValidAndUsedSelector(segment)) {
 1519     /*
 1520      * The selector itself is OK, but the descriptor (type) is not.
 1521      * We cannot fix this! So just give up immediately and dont
 1522      * screw up the context.
 1523      */
 1524     D_printf("MSDOS: msdos_fault: Illegal use of selector %#x\n", segment);
 1525     return 0;
 1526     }
 1527 
 1528     D_printf("MSDOS: try mov to a invalid selector 0x%04x\n", segment);
 1529 
 1530 #if 0
 1531     /* only allow using some special GTD\'s */
 1532     if ((segment != 0x0040) && (segment != 0xa000) &&
 1533     (segment != 0xb000) && (segment != 0xb800) &&
 1534     (segment != 0xc000) && (segment != 0xe000) &&
 1535     (segment != 0xf000) && (segment != 0xbf8) &&
 1536     (segment != 0xf800) && (segment != 0xff00))
 1537     return 0;
 1538 #endif    
 1539 
 1540     if (!(desc = (reg != cs_INDEX ? ConvertSegmentToDescriptor_lim(segment, 0xfffff) :
 1541     ConvertSegmentToCodeDescriptor_lim(segment, 0xfffff))))
 1542     return 0;
 1543 
 1544     /* OKay, all the sanity checks passed. Now we go and fix the selector */
 1545     copy_context(scp, &new_sct, 0);
 1546     switch (reg) {
 1547     case es_INDEX:
 1548     _es = desc;
 1549     break;
 1550     case cs_INDEX:
 1551     _cs = desc;
 1552     break;
 1553     case ss_INDEX:
 1554     _ss = desc;
 1555     break;
 1556     case ds_INDEX:
 1557     _ds = desc;
 1558     break;
 1559     case fs_INDEX:
 1560     _fs = desc;
 1561     break;
 1562     case gs_INDEX:
 1563     _gs = desc;
 1564     break;
 1565     }
 1566 
 1567     /* let's hope we fixed the thing, and return */
 1568     return 1;
 1569 }