home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / CSDPMI3S.ZIP / SRC / CWSDPMI / EXPHDLR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-11  |  45.4 KB  |  1,399 lines

  1. /* Copyright (C) 1995,1996 CW Sandmann (sandmann@clio.rice.edu) 1206 Braelinn, Sugarland, TX 77479
  2. ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  3. **
  4. ** This file is distributed under the terms listed in the document
  5. ** "copying.cws", available from CW Sandmann at the address above.
  6. ** A copy of "copying.cws" should accompany this file; if not, a copy
  7. ** should be available from where this file was obtained.  This file
  8. ** may not be distributed without a verbatim copy of "copying.cws".
  9. **
  10. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  11. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. */
  13. /* PC98 support contributed 6-95 tantan SGL00213@niftyserve.or.jp */
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <dos.h>
  18. #include <string.h>
  19.  
  20. #include "gotypes.h"
  21. #include "gdt.h"
  22. #include "idt.h"
  23. #include "tss.h"
  24. #include "utils.h"
  25. #include "paging.h"
  26. #include "vcpi.h"
  27. #include "dpmisim.h"
  28. #include "dalloc.h"
  29. #include "valloc.h"
  30. #include "control.h"
  31. #include "mswitch.h"
  32. #include "exphdlr.h"
  33.  
  34. /* Notes on HW interrupts (include info on Int 0x1c, 0x23, 0x24 also):
  35.    Since HW interrupts may occur at any time interrupts are disabled, we
  36.    minimize complications by keeping interrupts disabled during all ring 0
  37.    PM code in CWSDPMI and during almost all RM code here too.  Exceptions
  38.    are when we jump to user routines, handle page faults, or handle
  39.    interrupts which may enable interrupts.  An ugly fact is any print
  40.    routines in this code may also enable interrupts while in DOS, so beware.
  41.  
  42.    HW interrupts which occur in PM go to the IDT and by default are handled
  43.    at Ring 0 (the user stack my be invalid, this is a MUST, the ring change
  44.    switches to the Ring 0 stack which is always valid).  The default handling
  45.    is they are reflected to real mode.  If the user has not hooked a HW int,
  46.    we do not reflect RM ints into PM at all.  Life gets complicated when the
  47.    user hooks a HW interrupt.
  48.  
  49.    Once hooked, HW interrupts which occur in PM go to the IDT and jump to
  50.    the irq routines in tables.asm which are ring 0 code on a ring 0 stack.
  51.    That code moves to a locked stack and changes to ring 3, jumping to the
  52.    user routine.  Their IRET will jump to user_interrupt_return in dpmisim.asm
  53.    which emulates an IRET, but at the same ring (changing stacks).
  54.  
  55.    HW interrupts which occur in RM jump to RMCB's which are specially set up
  56.    to call the user's routine (coded as type != 0), then IRET.
  57.  
  58.    Chaining is ugly.  We return the original PM HW interrupt routine on get
  59.    vector calls, modifying the code selector to be ring 3.  This is OK because
  60.    they should be on the locked stack.  The reflection to real mode would cause
  61.    an infinite loop, since it would trigger a RMCB.  So, before installing
  62.    the RMCB we must save the original RM handler and have special code to
  63.    jump to it if and only if a RMCB is hooked (yuk, this is in mswitch).
  64.  
  65.    Int 1c doesn't need a PM ring 0 handler, just the RMCB, and is treated as
  66.    IRQ 16.  Int 1c does need to handle chaining.
  67.  
  68.    Int 23 and Int 24 don't need PM ring 0 handlers, and don't need to handle
  69.    chaining.  But they are non-standard interrupt handling that need to do
  70.    things on the basis of the carry flag/RETF (I23) or AL (I24).  Int 23 is
  71.    restricted to IRET so can be handled in a standard way, but Int 24 requires
  72.    special values to be set up (AX, BP:SI, DI) and a special return with AL=3.
  73.    This is RMCB type 2, handled in a DPMISIM rmcb_task clone (not done).
  74. */
  75.  
  76. #define n_user_excep 15
  77. #define n_user_hwint 18                /* extras for 0x1c,0x23 */
  78.  
  79. static far32 user_exception_handler[n_user_excep];
  80. far32 user_interrupt_handler[n_user_hwint];
  81. far16 saved_interrupt_vector[n_user_hwint];    /* Used by mswitch */
  82. static word8 hw_int_rmcb[n_user_hwint] = {num_rmcb, num_rmcb, num_rmcb, num_rmcb,
  83.   num_rmcb, num_rmcb, num_rmcb, num_rmcb, num_rmcb, num_rmcb, num_rmcb,
  84.   num_rmcb, num_rmcb, num_rmcb, num_rmcb, num_rmcb, num_rmcb, num_rmcb };
  85. dpmisim_rmcb_struct dpmisim_rmcb[num_rmcb];
  86.  
  87. extern far far32 i30x_jump;
  88. extern far far32 i30x_stack;
  89. extern far word8 i30x_sti;
  90. extern void ivec31x(void);
  91. extern char in_rmcb;
  92.  
  93. word32 locked_stack[1024];    /* 4K locked stack */
  94. word8 locked_count = 0;
  95.  
  96. static word8 old_master_lo=0x08;
  97. word8 hard_master_lo=0x08, hard_master_hi=0x0f;
  98. word8 hard_slave_lo=0x70,  hard_slave_hi=0x77;
  99.  
  100. static char cntrls_initted = 0;
  101. static char far * oldvec;
  102.  
  103. static int i_21(void), i_2f(void), i_31(void);
  104.  
  105. #if 0
  106. void segfault(word32 v)
  107. {
  108.   errmsg("Access violation, address = 0x%08lx\n", (v&0xfffffffL));
  109.   do_faulting_finish_message();
  110. }
  111. #endif
  112.  
  113. void static set_controller(int v)
  114. {
  115.   if (mtype == PC98) {
  116.     int oldmask =inportb(0x02);  /* On PC98 8259 port is 0x00,0x02 */
  117.     outportb(0x00, 0x11);
  118.     outportb(0x02, v);
  119.     outportb(0x02, 0x80);
  120.     outportb(0x02, 0x1d);
  121.     outportb(0x02, oldmask);
  122.   } else {
  123.     int oldmask =inportb(0x21);
  124.     outportb(0x20, 0x11);
  125.     outportb(0x21, v);
  126.     outportb(0x21, 4);
  127.     outportb(0x21, 1);
  128.     outportb(0x21, oldmask);
  129.   }
  130. }
  131.  
  132. static int find_empty_pic(void)
  133. {
  134.   static word8 try[] = { 0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xf8, 0x68, 0x78 };
  135.   int i, j;
  136.   for (i=0; i<sizeof(try); i++)
  137.   {
  138.     char far * far * vec = MK_FP(0, try[i]*4);
  139.     oldvec = vec[0];
  140.     for (j=1; j<8; j++)
  141.     {
  142.       if (*(++vec) != oldvec)
  143.         goto not_empty;
  144.     }
  145.     return try[i];
  146.     not_empty:;
  147.   }
  148.   return 0x78;
  149. }
  150.  
  151. /* static word32 saved_interrupt_table[256]; */
  152.  
  153. void init_controllers(void)
  154. {
  155.   if(cntrls_initted) return;
  156.   cntrls_initted = 1;
  157.   { /* Make sure cleaned up in case previous clients did not */
  158.     int i;
  159.     for(i=0; i < n_user_excep; i++)
  160.       user_exception_handler[i].selector = 0;
  161.     for(i=0; i < n_user_hwint; i++)
  162.       user_interrupt_handler[i].selector = 0;
  163.   }
  164.   locked_count = 0;
  165.   in_rmcb = 0;
  166.  
  167. /*  movedata(0, 0, _DS, FP_OFF(saved_interrupt_table), 256*4); */
  168.  
  169.   disable();
  170.  
  171.   if (vcpi_installed) {
  172.     old_master_lo = vcpi_get_pic();
  173.     hard_slave_lo = vcpi_get_secpic();
  174.   }
  175.   /* else set in initialization; don't turn off VCPI after loading CWSDPMI */
  176.  
  177.   if (old_master_lo == 0x08) {
  178.     word16 i,offset;
  179.     word16 far *iptr;
  180.     extern void real_i8(void);
  181.  
  182.     hard_master_lo = find_empty_pic();
  183.     if (vcpi_installed)
  184.       vcpi_set_pics(hard_master_lo, hard_slave_lo);
  185.     set_controller(hard_master_lo);
  186.  
  187. /*    movedata(0, 0x08*4, 0, hard_master_lo*4, 0x08*4); */
  188.     /* Point new controller block to our space, which we redirect to original
  189.        interrupt area.  Allows nested programs which grab interrupts to work */
  190.     iptr = MK_FP(0, hard_master_lo*4);
  191.     offset = FP_OFF(real_i8);
  192.     for(i=0; i<8; i++) {
  193.       *iptr++ = offset;
  194.       *iptr++ = _CS;
  195.       offset += 3;  /* size of int 0x, iret */
  196.     }
  197.   }
  198.   else
  199.     hard_master_lo = old_master_lo;
  200.  
  201.   hard_master_hi = hard_master_lo + 7;
  202.   hard_slave_hi = hard_slave_lo + 7;
  203.  
  204.   enable();
  205. }
  206.  
  207. void uninit_controllers(void)
  208. {
  209.   if(!cntrls_initted) return;
  210.   cntrls_initted = 0;
  211.   disable();
  212.  
  213. /*  movedata(_DS, FP_OFF(saved_interrupt_table), 0, 0, 256*4); */
  214.  
  215.   {
  216.     int i;
  217.     for(i = 0; i < n_user_hwint; i++)
  218.       if(saved_interrupt_vector[i].segment) {
  219.         int j;
  220.         if(i < 8)
  221.           j = hard_master_lo + i;
  222.         else if(i < 16)
  223.           j = hard_slave_lo + i - 8;
  224.         else if(i == 16)
  225.           j = 0x1c;
  226.         else /* if(i == 17) */
  227.           j = 0x23;
  228.         poke(0, j*4, saved_interrupt_vector[i].offset);
  229.         poke(0, j*4+2, saved_interrupt_vector[i].segment);
  230.         dpmisim_rmcb[hw_int_rmcb[i]].cb_sel = 0;
  231.         hw_int_rmcb[i] = num_rmcb;
  232.         saved_interrupt_vector[i].segment = 0;
  233.       }
  234.   }
  235.   if (old_master_lo == 0x08 )
  236.   {
  237.     if (vcpi_installed)
  238.       vcpi_set_pics(0x08, hard_slave_lo);
  239.     set_controller(0x08);
  240.  
  241.     { /* Restore the table entries we scrogged */
  242.     int j;
  243.     char far * far * vec = (char far * far *)((word32)(hard_master_lo << 2));
  244.     for (j=0; j<8; j++)
  245.       *(vec++) = oldvec;
  246.     }
  247.   }
  248.   enable();
  249. }
  250.  
  251. #ifdef RSX
  252. /*
  253.  * try segment translation for valid LDT selectors (Rainer code modified)
  254.  * some clients need this undocumented Windows feature
  255.  */
  256. static word16 sel2segm(word16 sel)
  257. {
  258.   word16 idx = sel/8;
  259.  
  260.   /* test valid LDT selector, in 1Mb area on paragraph boundary */
  261.   if ((sel & 4) && !(ldt[idx].base1 & 0xf0) && !(ldt[idx].base0 & 0xf)
  262.     && !ldt[idx].base2 && LDT_USED(idx))
  263.       return ((ldt[idx].base0 >> 4) + (ldt[idx].base1 << 12));
  264.   return sel;
  265. }
  266. #endif
  267.  
  268. extern int generic_handler(void);
  269.  
  270. /* This routine will send control to the faulting finish cleanup */
  271. static int unsupported_int(void)
  272. {
  273.   return 1;
  274. }
  275.  
  276. /* The user_exception_handler default == 0 is minor deviation from the DPMI
  277.    spec.  The spec says if a user handler isn't set up, it should be handled
  278.    as an interrupt, eventually passed to real mode.  If they set up a PM
  279.    interrupt handler, we will never get here.  If they didn't, passing it
  280.    to real mode is almost certainly the wrong thing to do (hang) regardless
  281.    of what the spec says.  So, if they chain, we GPF on the null selector
  282.    and abort, just with the wrong register display.  I can live with it. */
  283.  
  284. static int user_exception(void)
  285. {
  286.   word16 locked_sp;
  287.   word32 *locked_loc;
  288.   int i = tss_ptr->tss_irqn;
  289. #if run_ring != 0
  290.   if(!(tss_ptr->tss_cs & 3))
  291.     return 1;    /* Don't try to handle ring 0 exceptions */
  292. #endif
  293.   if(locked_count > 5)
  294.     return 1;
  295.   if(tss_ptr == &a_tss && user_exception_handler[i].selector) {
  296.     if(locked_count)
  297.       locked_loc = &locked_stack[0];    /* use bottom; copy later */
  298.     else
  299.       locked_loc = &locked_stack[1016];
  300.     *(locked_loc++) = FP_OFF(user_exception_return);
  301.     *(locked_loc++) = GDT_SEL(g_pcode);    /* our local prot CS */
  302.     *(locked_loc++) = tss_ptr->tss_error;
  303.     *(locked_loc++) = tss_ptr->tss_eip;
  304.     *(locked_loc++) = tss_ptr->tss_cs;
  305.     *(locked_loc++) = tss_ptr->tss_eflags;
  306.     *(locked_loc++) = tss_ptr->tss_esp;
  307.     *locked_loc = tss_ptr->tss_ss;
  308.     if(locked_count) {
  309.       tss_ptr->tss_esp -= 32;
  310.       memput(tss_ptr->tss_ss, tss_ptr->tss_esp, &locked_stack[0], 32);
  311.     } else {
  312.       tss_ptr->tss_ss = GDT_SEL(g_pdata);
  313.       tss_ptr->tss_esp = FP_OFF(&locked_stack[1016]);
  314.     }
  315.     tss_ptr->tss_eip = user_exception_handler[i].offset32;
  316.     tss_ptr->tss_cs = user_exception_handler[i].selector;
  317.     tss_ptr->tss_eflags = 0x3002;    /*Interrupts disabled; clear T, etc */
  318.     locked_count++;
  319.     return 0;
  320.   }
  321.   return 1;
  322. }
  323.  
  324. static int page_in_user(void)
  325. {
  326.   if(in_rmcb)
  327.     return 1;            /* Page fault in interrupted code; save disk! */
  328.   if(page_in())            /* If we can't handle it, give user a shot */
  329.     return user_exception();
  330.   return 0;
  331. }
  332.  
  333. /* The DPMI spec says we should pass all interrupts through "generic_handler".
  334.    In some cases we choose not to do this for interrupts that most likely would
  335.    cause a wedge, like jumping to data.  All of the unsupported_int calls below
  336.    are deviations from the DPMI spec on purpose.  If any complaints, fix it.  */
  337.  
  338. #define U unsupported_int
  339. #define UE user_exception
  340. typedef int (*FUNC)(void);
  341. static FUNC exception_handler_list[] = {
  342.   UE, UE, generic_handler, UE, UE, UE, UE, UE,    /* NMI passed - laptops/green */
  343.   /* 08 */ U,            /* Double fault */
  344.   UE, UE, UE, UE, UE,
  345.   /* 0e */ page_in_user,
  346.   UE,
  347.   /* 10 */ generic_handler,    /* Video Interrupt */
  348.   /* 11 */ generic_handler,    /* Equipment detection */
  349.   /* 12 */ generic_handler,    /* Get memory size (outdated) */
  350.   /* 13 */ generic_handler,    /* Disk services */
  351.   /* 14 */ generic_handler,    /* Serial communication */
  352.   /* 15 */ generic_handler,    /* Lots of strange things */
  353.   /* 16 */ generic_handler,    /* Keyboard */
  354.   /* 17 */ generic_handler,    /* Parallel printer */
  355.   U, U,                /* ROM Basic, Reboot */
  356.   /* 1a */ generic_handler,    /* Get/set system time */
  357.   generic_handler, generic_handler, /* ^Break and User Tic */
  358.   U, U, U, U,            /* Data pointers, "exit" */
  359.   /* 21 */ i_21,        /* DOS Services */
  360.   U, U, U, U, U, U,        /* DOS things which should not be called */
  361.   /* 28 */ generic_handler,     /* DOS idle */
  362.   /* 29 */ generic_handler,    /* DOS Fast I/O */
  363.   generic_handler, generic_handler, /* Network and unused */
  364.   generic_handler, generic_handler, generic_handler,
  365.   /* 2f */ i_2f, U,        /* Multiplex for PM execution */
  366.   /* 31 */ i_31            /* DPMIsim */
  367. };
  368. #undef U
  369. #undef UE
  370. #define NUM_EXCEPTIONS    (sizeof(exception_handler_list)/sizeof(exception_handler_list[0]))
  371.  
  372. int exception_handler(void)
  373. {
  374.   int i;
  375.   i = tss_ptr->tss_irqn;
  376. /*  cprintf("i=%#02x\r\n", i); /* */
  377.   if (i < NUM_EXCEPTIONS)
  378.     return (exception_handler_list[i])();
  379.   else
  380.     return generic_handler();
  381. }
  382.  
  383. static int i_21(void)
  384. {
  385.   word8 ah;
  386.   ah = (word8)((word16)(tss_ptr->tss_eax) >> 8);
  387.   if(ah == 0x4c)
  388.       cleanup((word16)(tss_ptr->tss_eax));
  389.   return generic_handler();
  390. }
  391.  
  392. static int i_2f(void)
  393. {
  394.   if((word16)(tss_ptr->tss_eax) == 0x1686) {
  395.     (word16)(tss_ptr->tss_eax) = 0;
  396.     return 0;
  397.   }
  398.   return generic_handler();
  399. }
  400.  
  401. static int8 hwirq;
  402.  
  403. static int reg2gate(word8 r)
  404. {
  405.   if(r >= 0x08 && r <= 0x0f) {
  406.     hwirq = r - 8;
  407.     r = hwirq + hard_master_lo;
  408.   } else if(r >= hard_slave_lo && r <= hard_slave_hi)
  409.     hwirq = r - hard_slave_lo + 8;
  410.   else if(r == 0x1c)
  411.     hwirq = 16;
  412.   else if(r == 0x23)
  413.     hwirq = 17;
  414.   else
  415.     hwirq = -1;
  416.   return r;
  417. }
  418.  
  419. #if 0
  420.  
  421. #define DESC_BASE(d)  (((((word32)d.base2<<8)|(word32)d.base1)<<16)|(word32)d.base0)
  422.  
  423. static void check_pointer(word16 sel, word32 off)
  424. {
  425.   /* Checking limit ugly (direction, G bit) so skip. */
  426.   int i = sel/8;
  427.   word32 base;
  428.   if(sel&4)
  429.     base = DESC_BASE(ldt[i]);
  430.   else
  431.     base = DESC_BASE(gdt[i]);
  432.   base += off;
  433.   if(base < 0xfffff || page_is_valid(base))    /* 640K area or our area */
  434.     return;
  435.   segfault(off);
  436. }
  437.  
  438. #define CHECK_POINTER(sel,off) check_pointer((word16)sel,off)
  439. #else
  440. #define CHECK_POINTER(sel,off)
  441. #endif
  442.  
  443. #define SET_CARRY (word8)tss_ptr->tss_eflags |= 1
  444. #define EXIT_OK goto i31_exit
  445. #define EXIT_ERROR goto i31_exit_error
  446.  
  447. int alloc_ldt(int ns)
  448. {
  449.   word16 i, j;
  450.  
  451.   for(i=l_free; (i+ns)<=l_num; i++) {
  452.     for(j=0; j<ns && LDT_FREE(i+j); j++);
  453.     if(j>=ns)break;
  454.   }
  455.   if((i+ns)<=l_num){
  456.     for(j=0;j<ns;j++,i++) {
  457.       ldt[i].lim0 = ldt[i].base0 = 0;
  458.       ldt[i].base1 = ldt[i].base2 = 0;
  459.       ldt[i].lim1 = 0x40;        /* 32-bit, byte granularity, used.  */
  460.       ldt[i].stype = 0x92 | SEL_PRV;    /* Present, data, r/w. */
  461.     }
  462.     return i-ns;    /* Allocation succeeded.  */
  463.   }
  464.   SET_CARRY;
  465.   return 0;        /* Allocation not possible.  */
  466. }
  467.  
  468. static word16 sel_to_ldt_index(word16 reg)
  469. {
  470.   word16 sel = reg;
  471.   if(sel & 0x4) {
  472.     sel = sel / 8;
  473.     if(sel < l_num && LDT_USED(sel))
  474.       return sel;
  475.   }
  476.   return 0xffff;
  477. }
  478.  
  479. /* This routine exists to compress code space.  Address calculation is
  480.    expensive; since ebx is used many times, we hardcode it once. */
  481. static word16 sel_to_ldt_index0(void)
  482. {
  483.   return sel_to_ldt_index((word16)tss_ptr->tss_ebx);
  484. }
  485.  
  486. #define ASSIGN_LDT_INDEX(VAR,REG) if((VAR = sel_to_ldt_index0()) == 0xffff) EXIT_ERROR
  487. #define ASSIGN_LDT_INDEX1(VAR,REG) if((VAR = sel_to_ldt_index((word16)tss_ptr->REG)) == 0xffff) EXIT_ERROR
  488.  
  489. static void free_desc(word16 i)
  490. {
  491. /* DPMI 1.0 free descriptor clears any sregs containing value.  Don't bother
  492.    with CS, SS since illegal and will be caught in task switch */
  493.   word16 tval = LDT_SEL(i);
  494.   ldt[i].stype = 0;
  495.   if(tss_ptr->tss_ds == tval) tss_ptr->tss_ds = 0;
  496.   if(tss_ptr->tss_es == tval) tss_ptr->tss_es = 0;
  497.   if(tss_ptr->tss_fs == tval) tss_ptr->tss_fs = 0;
  498.   if(tss_ptr->tss_gs == tval) tss_ptr->tss_gs = 0;
  499. }
  500.  
  501. /* The DPMI 1.0 specification says 32-bit clients only get one descriptor on
  502.    a DOS memory allocation over 64K.  The 0.9 specification does not agree.
  503.    Windows 3.1 (which is 0.9) only allocates a single descriptor.  Go figure.
  504.    Since we are currently 32-bit only, disable to decrease footprint.  Code
  505.    must be enabled to pass rigorous tests; adds 600 bytes to resident size.
  506.    Since Win 3.1 does not support it, I am sure it is not used by anyone.
  507.    It will be needed when 16-bit support is added.  */
  508.  
  509. #ifdef DOSMEM_MULTIPLE
  510. static void set_limits(word16 segm, word16 para, word16 sel0, int sels)
  511. {
  512.   word32 lim,base,limit;
  513.   int first;
  514.  
  515.   base = (word32)segm << 4;
  516.   limit = para ? ((word32)para << 4) - 1L : 0L;
  517.   first = 1;        /* Only set this if 32-bit client */
  518.   while (sels--) {
  519.     if (first || (word16)(limit >> 16) == 0)
  520.       lim = limit;
  521.     else
  522.       lim = 0xffffL;
  523.     ldt[sel0].base0 = (word16)base;
  524.     ldt[sel0].base1 = (word8)(base >> 16);
  525.     ldt[sel0].base2 = 0;
  526.     ldt[sel0].lim0 = (word16)lim;
  527.     ldt[sel0].lim1 = (word8)(lim >> 16);
  528.     /* Resize does not use alloc_ldt, so we must set the type */
  529.     ldt[sel0++].stype = 0x92 | SEL_PRV;  /* Present, data, r/w. */
  530.  
  531.     limit -= 0x10000L;
  532.     base += 0x10000L;
  533.     first = 0;
  534.   }
  535. }
  536. #else
  537.  
  538. static void set_para_limit(word16 i, word16 npara)
  539. {
  540.   word32 limit = npara;
  541.   if(npara)
  542.     limit = (limit << 4) - 1L;
  543.   ldt[i].lim0 = (word16)limit;
  544.   ldt[i].lim1 = limit >> 16;
  545. }
  546. #endif
  547.  
  548. /* Note: mswitch leaves interrupts disabled, so this entire routine runs with
  549.    interrupts disabled.  Debugging note:  printf() statements may re-enable
  550.    interrupts temporarily and cause unexpected behavior, especially with
  551.    HW interrupts or mouse callbacks. */
  552.  
  553. static int i_31(void)
  554. {
  555. /*  mprintf("DPMI request 0x%x 0x%x 0x%x 0x%lx\r\n",(word16)(tss_ptr->tss_eax),
  556.     (word16)(tss_ptr->tss_ebx),(word16)(tss_ptr->tss_ecx),(tss_ptr->tss_edx));   /* */
  557.   (word8)tss_ptr->tss_eflags &= ~1;    /* Clear carry, only set on failure */
  558. #if 0    /* Testing code for 16-bit */
  559.   tss_ptr->tss_edx = (word16)tss_ptr->tss_edx;
  560.   tss_ptr->tss_esi = (word16)tss_ptr->tss_esi;
  561.   tss_ptr->tss_edi = (word16)tss_ptr->tss_edi;
  562. #endif
  563.   switch ((word16)(tss_ptr->tss_eax))
  564.   {
  565.     case 0x0000: /* Allocate LDT descriptors.  */
  566.       {
  567.       word16 i = alloc_ldt((word16)tss_ptr->tss_ecx);
  568.       if (i)
  569.         (word16)tss_ptr->tss_eax = LDT_SEL(i);
  570.       EXIT_OK;
  571.       }
  572.  
  573.     case 0x0001: /* Free LDT descriptor.  */
  574.       {
  575.       word16 i;
  576.       ASSIGN_LDT_INDEX(i, ebx);
  577.       LDT_MARK_FREE(i);
  578.       EXIT_OK;
  579.       }
  580.  
  581.     case 0x0002: /* Segment to descriptor.  */
  582.       {
  583.       word16 i;
  584.       word16 base0 = (word16)tss_ptr->tss_ebx << 4;
  585.       word16 base1 = (word16)tss_ptr->tss_ebx >> 12;
  586.  
  587.       /* Search for same descriptor */
  588.       for(i=l_free; i<l_num; i++)
  589.         if(!ldt[i].lim1 && !ldt[i].base2 && ldt[i].lim0 == 0xffff &&
  590.             LDT_USED(i) && ldt[i].base0 == base0 && ldt[i].base1 == base1) {
  591.           (word16)tss_ptr->tss_eax = LDT_SEL(i);
  592.           EXIT_OK;
  593.         }
  594.  
  595.       i = alloc_ldt(1);
  596.       if(i) {
  597.         (word16)tss_ptr->tss_eax = LDT_SEL(i);
  598.         ldt[i].lim0 = 0xffff;
  599.         ldt[i].base0 = base0;
  600.         ldt[i].base1 = base1;
  601.         ldt[i].lim1 = 0;        /* 16-bit, not 32 */
  602.       }
  603.       EXIT_OK;
  604.       }
  605.  
  606.     case 0x0003: /* Get Selector Increment.  */
  607.       (word16)tss_ptr->tss_eax = 8;
  608.       EXIT_OK;
  609.  
  610.     case 0x0006: /* Get Selector Base Address.  */
  611.       {
  612.       word16 i;
  613.       ASSIGN_LDT_INDEX(i, ebx);
  614.       (word16)tss_ptr->tss_edx = ldt[i].base0;
  615.       (word16)tss_ptr->tss_ecx = ldt[i].base1 | (ldt[i].base2 << 8);
  616.       EXIT_OK;
  617.       }
  618.  
  619.     case 0x0007: /* Set Selector Base Address.  */
  620.       {
  621.       word16 i;
  622.       ASSIGN_LDT_INDEX(i, ebx);
  623.       ldt[i].base0 = (word16)tss_ptr->tss_edx;
  624.       ldt[i].base1 = (word8)tss_ptr->tss_ecx;
  625.       ldt[i].base2 = ((word16)tss_ptr->tss_ecx >> 8) & 0xff;
  626.       EXIT_OK;
  627.       }
  628.  
  629.     case 0x0008: /* Set Selector Limit.  */
  630.       {
  631.       word16 i, j, k;
  632. /*    word32 *show32; show32 = ldt + i; printf("Descriptor(%d,8): 0x%lx 0x%lx\n",i,show32[0],show32[1]); */
  633.       ASSIGN_LDT_INDEX(i, ebx);
  634.       j = (word16)tss_ptr->tss_edx;
  635.       k = (word16)tss_ptr->tss_ecx;
  636.       if(k > 0xf) {
  637.         j = (j >> 12) | (k << 4);
  638.         k = 0x80 | (k >> 12);
  639.       }
  640.       ldt[i].lim0 = j;
  641.       ldt[i].lim1 &= 0x70;
  642.       ldt[i].lim1 |= k;
  643.       EXIT_OK;
  644.       }
  645.  
  646.     case 0x0009: /* Set Selector Access Rights.  */
  647.       {
  648.       word16 i;
  649.       ASSIGN_LDT_INDEX(i, ebx);
  650.       ldt[i].stype = 0x10 | (word8)tss_ptr->tss_ecx;
  651.       ldt[i].lim1 = (0x0f & ldt[i].lim1) | (((word16)tss_ptr->tss_ecx >> 8) & 0xd0);
  652.       EXIT_OK;
  653.       }
  654.  
  655.     case 0x000a: /* Create Code Selector Alias.  */
  656.       {
  657.       word16 i,j;
  658.       ASSIGN_LDT_INDEX(i, ebx);
  659.       j = alloc_ldt(1);
  660.       if(j) {
  661.         (word16)tss_ptr->tss_eax = LDT_SEL(j);
  662.         ldt[j] = ldt[i];
  663.         ldt[j].stype = 2 | (ldt[j].stype & 0xf0);    /* Data, exp-up, wrt */
  664.       }
  665.       EXIT_OK;
  666.       }
  667.  
  668.     case 0x000b: /* Get Descriptor.  */
  669.       {
  670.       word16 i;
  671.       CHECK_POINTER(tss_ptr->tss_es, tss_ptr->tss_edi);
  672.       ASSIGN_LDT_INDEX(i, ebx);
  673.       memput(tss_ptr->tss_es, tss_ptr->tss_edi, &ldt[i], 8);
  674.       EXIT_OK;
  675.       }
  676.  
  677.     case 0x000c: /* Set Descriptor.  */
  678.       {
  679.       word16 i;
  680.       CHECK_POINTER(tss_ptr->tss_es, tss_ptr->tss_edi);
  681.       ASSIGN_LDT_INDEX(i, ebx);
  682.       memget(tss_ptr->tss_es, tss_ptr->tss_edi, &ldt[i], 8);
  683.       ldt[i].stype |= 0x10;        /* Make sure non-system, non-zero */
  684.       EXIT_OK;
  685.       }
  686.  
  687.     case 0x000d: /* Allocate Specific LDT Selector.  */
  688.       {
  689.       word16 j = (word16)tss_ptr->tss_ebx;
  690.       /* Using ASSIGN_LDT_INDEX here doesn't work since the selector is
  691.          supposed to be free, not used, and they may want "0" */
  692.       word16 i = j/8;
  693.       if(i<16 && (j&4) && LDT_FREE(i)) {
  694.         ldt[i].lim0 = ldt[i].base0 = 0;
  695.         ldt[i].base1 = ldt[i].base2 = 0;
  696.         ldt[i].lim1 = 0x40; /* 32-bit, byte granularity, used.  */
  697.         ldt[i].stype = 0x92 | SEL_PRV; /* Present, data, r/w.  */
  698.         EXIT_OK;
  699.       } else
  700.         EXIT_ERROR;
  701.       }
  702.  
  703. #ifdef DOSMEM_MULTIPLE
  704.     case 0x0100: /* Allocate Dos Memory Block with multiple desciptors.  */
  705.       {
  706.       word16 i, sel0, max, rmseg, ax, bx;
  707.       int sels, bad;
  708.  
  709.       rmseg = bad = 0;
  710.       max = (word16)tss_ptr->tss_ebx;
  711.  
  712.       /* First make sure we have the right number of selectors.  */
  713.       sels = max ? ((max - 1) >> 12) + 1 : 1;
  714.       if ((sel0 = alloc_ldt (sels)) == 0) {
  715.         bad = 8;  /* Insufficient memory.  */
  716.         while (sels > 1 && sel0 == 0)
  717.           sel0 = alloc_ldt (--sels);
  718.         if (sel0)
  719.           max = sels << 12;
  720.         else
  721.           max = 0;
  722.       }
  723.  
  724.       /* Now check for available dos memory.  */
  725.       _BX = max;
  726.       _AH = 0x48;
  727.       geninterrupt(0x21);
  728.       ax = _AX;
  729.       bx = _BX;
  730.       if(_FLAGS & 1) {
  731.         bad = ax;
  732.         max = bx;
  733.       } else
  734.         rmseg = ax;
  735.  
  736.       if (bad) {
  737.         (word16)tss_ptr->tss_eax = bad;
  738.         (word16)tss_ptr->tss_ebx = max;
  739.         if (rmseg) {
  740.           _ES = rmseg;
  741.           _AH = 0x49;  /* Release memory.  */
  742.           geninterrupt(0x21);
  743.         }
  744.         if (sel0)
  745.           for (i = 0; i < sels; i++)
  746.             LDT_MARK_FREE (sel0 + i);
  747.         EXIT_ERROR;
  748.       } else {
  749.         (word16)tss_ptr->tss_eax = rmseg;
  750.         (word16)tss_ptr->tss_edx = LDT_SEL(sel0);
  751.         set_limits(rmseg, max, sel0, sels);
  752.         EXIT_OK;
  753.       }
  754.     }
  755. #else
  756.  
  757.     case 0x0100: /* Allocate Dos Memory Block.  */
  758.       {
  759.       word16 i,ax,bx;
  760.       _BX = (word16)tss_ptr->tss_ebx;    /* number of paragr */
  761.       _AH = 0x48;    /* Allocate memory block */
  762.       geninterrupt(0x21);
  763.       ax = _AX;
  764.       bx = _BX;
  765.       (word16)tss_ptr->tss_eax = ax;
  766.       if(_FLAGS & 1) {
  767.         (word16)tss_ptr->tss_ebx = bx;
  768.         EXIT_ERROR;
  769.       } else {
  770.         i = alloc_ldt(1);
  771.         if(i) {
  772.           (word16)tss_ptr->tss_edx = LDT_SEL(i);
  773.           set_para_limit(i, bx);
  774.           ldt[i].base0 = ax << 4;
  775.           ldt[i].base1 = ax >> 12;
  776.         }
  777.       }
  778.       EXIT_OK;
  779.       }
  780. #endif
  781.  
  782.     case 0x0101: /* Free Dos Memory Block.  */
  783.       {
  784.       word16 i,ax;
  785.       ASSIGN_LDT_INDEX1(i, tss_edx);
  786.       _ES = (ldt[i].base0 >> 4) + (ldt[i].base1 << 12);
  787.       _AH = 0x49;        /* Release memory */
  788.       geninterrupt(0x21);
  789.       ax = _AX;
  790.       if(_FLAGS & 1) {
  791.         (word16)tss_ptr->tss_eax = ax;
  792.         EXIT_ERROR;
  793.       }
  794. #ifdef DOSMEM_MULTIPLE
  795.       {
  796.         unsigned sels = ldt[i].lim1 & 0xf;
  797.         if (ldt[i].lim0 > 0 || sels == 0)
  798.           sels++;
  799.         while (sels--)
  800.           LDT_MARK_FREE(i++);
  801.       }
  802. #else
  803.       LDT_MARK_FREE(i);
  804. #endif
  805.       EXIT_OK;
  806.       }
  807.  
  808. #ifdef DOSMEM_MULTIPLE
  809.     case 0x0102: /* Resize Dos Memory Block with multiple descriptors.  */
  810.       {
  811.       word16 i, j, pars, oldpars, ax, bx, carry;
  812.       int oldsels, newsels, maxsels;
  813.  
  814.       ASSIGN_LDT_INDEX1(i, tss_edx);
  815.       pars = (word16)tss_ptr->tss_ebx;
  816.       oldpars = ((ldt[i].lim1 & 0xf) << 12) + (ldt[i].lim0 >> 4)
  817.         + (ldt[i].lim0 > 0);
  818.  
  819.       oldsels = oldpars ? ((oldpars - 1) >> 12) + 1 : 1;
  820.       newsels = pars ? ((pars - 1) >> 12) + 1 : 1;
  821.  
  822.       if (newsels > oldsels) {
  823.         for (j = i + oldsels, maxsels = oldsels;
  824.              maxsels < newsels && LDT_VALID (j) && LDT_FREE (j);
  825.              j++, maxsels++)
  826.           /* Nothing.  */;
  827.         if (maxsels != newsels)
  828.           pars = maxsels << 12;
  829.       } else
  830.         maxsels = newsels;
  831.  
  832.       _ES = (ldt[i].base0 >> 4) + (ldt[i].base1 << 12);
  833.       _BX = pars;
  834.       _AH = 0x4a;  /* Resize memory.  */
  835.       geninterrupt(0x21);
  836.       ax = _AX;
  837.       bx = _BX;
  838.       carry = _FLAGS & 1;
  839.       if (carry || (newsels != maxsels)) {
  840.         if (carry) {
  841.           (word16)tss_ptr->tss_eax = ax;
  842.           (word16)tss_ptr->tss_ebx = bx;
  843.         } else {
  844.           (word16)tss_ptr->tss_eax = 8;  /* Insufficient memory.  */
  845.           (word16)tss_ptr->tss_ebx = pars;
  846.           _BX = oldpars;
  847.           _AH = 0x4a;  /* Resize memory.  */
  848.           geninterrupt(0x21);
  849.         }
  850.         EXIT_ERROR;
  851.       } else {
  852.         set_limits(_ES, pars, i, newsels);
  853.         for (j = i + newsels; newsels < oldsels; j++, newsels++)
  854.           LDT_MARK_FREE (j);
  855.         EXIT_OK;
  856.       }
  857.       }
  858. #else
  859.  
  860.     case 0x0102: /* Resize Dos Memory Block.  */
  861.       {
  862.       word16 i,ax,bx;
  863.       ASSIGN_LDT_INDEX1(i, tss_edx);
  864.       _ES = (ldt[i].base0 >> 4) + (ldt[i].base1 << 12);
  865.       _BX = (word16)tss_ptr->tss_ebx;
  866.       _AH = 0x4a;        /* Resize memory */
  867.       geninterrupt(0x21);
  868.       ax = _AX;
  869.       bx = _BX;
  870.       if(!(_FLAGS & 1)) {
  871.         set_para_limit(i, bx);
  872.         EXIT_OK;
  873.       } else {
  874.         (word16)tss_ptr->tss_eax = ax;
  875.         (word16)tss_ptr->tss_ebx = bx;
  876.         EXIT_ERROR;
  877.       }
  878.       }
  879. #endif
  880.  
  881.     case 0x0200: /* Get Real Mode Interrupt Vector.  */
  882.       {
  883.       word16 i = reg2gate((word8)tss_ptr->tss_ebx);
  884.       (word16)tss_ptr->tss_ecx = peek(0, i*4+2);
  885.       (word16)tss_ptr->tss_edx = peek(0, i*4);
  886.       EXIT_OK;
  887.       }
  888.  
  889.     case 0x0201: /* Set Real Mode Interrupt Vector.  */
  890.       {
  891.       word16 i = reg2gate((word8)tss_ptr->tss_ebx);
  892.       disable();
  893.       poke(0, i*4+2, (word16)tss_ptr->tss_ecx);
  894.       poke(0, i*4, (word16)tss_ptr->tss_edx);
  895. /*      enable();  Should be disabled already and stay that way */
  896.       EXIT_OK;
  897.       }
  898.  
  899.     case 0x0202: /* Get Protected Mode Exception Vector.  */
  900.       {
  901.       word16 i = (word8)tss_ptr->tss_ebx;
  902.       if(i < n_user_excep) {
  903.         (word16)tss_ptr->tss_ecx = user_exception_handler[i].selector;
  904.         tss_ptr->tss_edx = user_exception_handler[i].offset32;
  905.         EXIT_OK;
  906.       } else
  907.         EXIT_ERROR;
  908.       }
  909.  
  910.     case 0x0203: /* Set Protected Mode Exception Vector.  */
  911.       {
  912.       word16 i = (word8)tss_ptr->tss_ebx;
  913.       if(i < n_user_excep) {
  914.         user_exception_handler[i].selector = (word16)tss_ptr->tss_ecx;
  915.         user_exception_handler[i].offset32 = tss_ptr->tss_edx;
  916.         EXIT_OK;
  917.       } else
  918.         EXIT_ERROR;
  919.       }
  920.  
  921.     case 0x0204: /* Get Protected Mode Interrupt Vector.  */
  922.       {
  923.       word16 i = reg2gate((word8)tss_ptr->tss_ebx);
  924.       if(hwirq != -1 && user_interrupt_handler[hwirq].selector) {
  925.         (word16)tss_ptr->tss_ecx = user_interrupt_handler[hwirq].selector;
  926.         tss_ptr->tss_edx = user_interrupt_handler[hwirq].offset32;
  927.         EXIT_OK;
  928.       }
  929.       if(idt[i].selector == g_rcode*8)
  930.         (word16)tss_ptr->tss_ecx = GDT_SEL(g_pcode);    /* Allow chaining */
  931.       else
  932.         (word16)tss_ptr->tss_ecx = idt[i].selector;
  933.       tss_ptr->tss_edx = idt[i].offset0 | ((word32)idt[i].offset1 << 16);
  934.       EXIT_OK;
  935.       }
  936.  
  937.     case 0x0205: /* Set Protected Mode Interrupt Vector.  */
  938.       {
  939.       word16 i = reg2gate((word8)tss_ptr->tss_ebx);
  940. /*      if(hwirq != -1)
  941.       cprintf("205: %x (%x, %d) 0x%x 0x%lx\r\n",(word8)(tss_ptr->tss_ebx),i, hwirq,
  942.          (word16)(tss_ptr->tss_ecx),(tss_ptr->tss_edx));   /* */
  943.       /* Must use ring 0 handler for i < 8 (bug) and hwirq */
  944. /*      if(i < 8) {
  945.         mprintf("Warning: setting PM Int %d not supported\n",i);
  946.         EXIT_ERROR;
  947.       } */
  948.       if(hwirq != -1) {
  949.         word16 iseg, ioff, rmcb_num;
  950.         iseg = peek(0, i*4+2);
  951.         ioff = peek(0, i*4);
  952.         rmcb_num = hw_int_rmcb[hwirq];
  953.         if((word16)(tss_ptr->tss_ecx) == GDT_SEL(g_pcode)) { /* Restore */
  954.           if(iseg == _CS && ioff == (word16)dpmisim_rmcb0 + rmcb_num * ((word16)dpmisim_rmcb1 - (word16)dpmisim_rmcb0)) {
  955.             poke(0, i*4, saved_interrupt_vector[hwirq].offset);
  956.             poke(0, i*4+2, saved_interrupt_vector[hwirq].segment);
  957.             dpmisim_rmcb[rmcb_num].cb_sel = 0;
  958.             rmcb_num = num_rmcb;
  959.             saved_interrupt_vector[hwirq].segment = 0;
  960.           }
  961.         } else { /* Reflect RM HW ints to PM */
  962.           if(rmcb_num == num_rmcb)    /* RMCB not yet allocated */
  963.             for (rmcb_num=0; rmcb_num<num_rmcb; rmcb_num++)
  964.               if (dpmisim_rmcb[rmcb_num].cb_sel == 0)
  965.                 break;
  966.           if (rmcb_num >= num_rmcb)
  967.             EXIT_ERROR;
  968.           dpmisim_rmcb[rmcb_num].cb_address = tss_ptr->tss_edx;
  969.           dpmisim_rmcb[rmcb_num].cb_sel = (word16)tss_ptr->tss_ecx;
  970.           dpmisim_rmcb[rmcb_num].cb_type = 1;
  971.           poke(0, i*4, (word16)dpmisim_rmcb0 + rmcb_num * ((word16)dpmisim_rmcb1 - (word16)dpmisim_rmcb0) );
  972.           poke(0, i*4+2, _CS);
  973.           if(saved_interrupt_vector[hwirq].segment == 0) {
  974.             saved_interrupt_vector[hwirq].segment = iseg;
  975.             saved_interrupt_vector[hwirq].offset = ioff;
  976.           }
  977.         }
  978.         hw_int_rmcb[hwirq] = rmcb_num;
  979. #if run_ring != 0
  980.         if(hwirq < 16) {    /* Only for PM ring 0 wrappers */
  981.           /* Note IDT selector always rcode, offset1 always 0, type always OK */
  982.           if((word16)tss_ptr->tss_ecx == GDT_SEL(g_pcode)) { /* Restore */
  983.             idt[i].offset0 = (word16)tss_ptr->tss_edx;
  984.             user_interrupt_handler[hwirq].selector = 0;
  985.             EXIT_OK;
  986.           } else {
  987.             extern void irq0(void);
  988.             idt[i].offset0 = (int)FP_OFF(irq0) + 4*hwirq; /*debug comment*/
  989.             user_interrupt_handler[hwirq].selector = (word16)tss_ptr->tss_ecx;
  990.             user_interrupt_handler[hwirq].offset32 = tss_ptr->tss_edx;
  991.             EXIT_OK;
  992.           }
  993.         }
  994. #endif
  995.       } else if(i == 7 || i >= hard_master_lo && i <= hard_master_hi)
  996.         EXIT_OK; /* Must ignore it or DOS/4G apps fail */
  997.       idt[i].selector = (word16)(tss_ptr->tss_ecx);
  998.       idt[i].offset0 = (word16)(tss_ptr->tss_edx);
  999.       idt[i].offset1 = (word16)(tss_ptr->tss_edx >> 16);
  1000.       EXIT_OK;
  1001.       }
  1002.  
  1003.     case 0x0300: /* Simulate Real Mode Interrupt.  */
  1004.     case 0x0301: /* Call Real Mode Procedure with Far Return Frame.  */
  1005.     case 0x0302: /* Call Real Mode Procedure with Iret Frame.  */
  1006.       {
  1007.       word16 i;
  1008.       word16 dpmisim_spare_stack[128];    /* Size = 4 x 0.9 spec (bad video bios) */
  1009.       word16 far *fptr;
  1010.  
  1011. #ifndef I31PROT
  1012.       /* The copy of the reg structure to our space is done in ivec31 in
  1013.          tables.asm since this saves an extra round trip mode swap. */
  1014.       CHECK_POINTER(tss_ptr->tss_es, tss_ptr->tss_edi);
  1015.       memget(tss_ptr->tss_es, tss_ptr->tss_edi, dpmisim_regs, 50);
  1016. #endif
  1017.  
  1018.       if (dpmisim_regs[24] == 0) {
  1019.         dpmisim_regs[24] = _SS;
  1020.         dpmisim_regs[23] = (word16)(dpmisim_spare_stack) + sizeof(dpmisim_spare_stack);
  1021.       }
  1022.  
  1023.       fptr = MK_FP(dpmisim_regs[24], dpmisim_regs[23]); /* Stack pointer */
  1024.       if ((word16)tss_ptr->tss_ecx) {
  1025.         fptr -= (word16)tss_ptr->tss_ecx;
  1026.         memget(tss_ptr->tss_ss, tss_ptr->tss_esp, fptr, 2 * (word16)tss_ptr->tss_ecx);
  1027.       }
  1028.  
  1029.       dpmisim_regs[16] &= 0x3ed7;    /* Clear bits we don't allow */
  1030.       dpmisim_regs[16] |= 0x3002;    /* Set bits we require */
  1031.  
  1032.       if ((word8)tss_ptr->tss_eax != 0x01) {
  1033.         fptr--;
  1034.         *fptr = dpmisim_regs[16];       /* fake pushing flags on stack */
  1035.         dpmisim_regs[16] &= 0xfcff;     /* Clear IF and TF for entry */
  1036.       }
  1037.       dpmisim_regs[23] = FP_OFF (fptr);    /* Restore stack pointer */
  1038.  
  1039.       if ((word8)tss_ptr->tss_eax == 0x00)
  1040.       {
  1041.         dpmisim_regs[21] = peek(0, (word8)tss_ptr->tss_ebx * 4);
  1042.         dpmisim_regs[22] = peek(0, (word8)tss_ptr->tss_ebx * 4 + 2);
  1043.       }
  1044.  
  1045.       dpmisim();
  1046.  
  1047. #ifndef I31PROT
  1048.       /* Only restore 42 bytes; don't modify CS:IP or SS:SP */
  1049.       /* The copy of the reg structure from our space is done in ivec31 in
  1050.          tables.asm since this saves an extra round trip mode swap. */
  1051.       memput(tss_ptr->tss_es, tss_ptr->tss_edi, dpmisim_regs, 42);
  1052. #else
  1053.       i30x_jump.offset32 = tss_ptr->tss_eip;
  1054.       tss_ptr->tss_eip = (word32)FP_OFF(ivec31x);
  1055.       i30x_jump.selector = tss_ptr->tss_cs;
  1056.       tss_ptr->tss_cs = GDT_SEL(g_pcode);
  1057.       i30x_stack.offset32 = tss_ptr->tss_esp;
  1058.       tss_ptr->tss_esp = (word32)FP_OFF(&locked_stack[16]);    /* temp */
  1059.       i30x_stack.selector = tss_ptr->tss_ss;
  1060.       tss_ptr->tss_ss = GDT_SEL(g_pdata);
  1061.       if((word16)tss_ptr->tss_eflags & 0x200) {    /* Interrupt enabled? */
  1062.         (word16)tss_ptr->tss_eflags &= ~0x200;    /* Clear interrupt */
  1063.         i30x_sti = 0xfb;    /* STI */
  1064.       } else
  1065.         i30x_sti = 0x90;    /* NOP */
  1066. #endif      
  1067.       EXIT_OK;
  1068.       }
  1069.  
  1070.     case 0x0303: /* Allocate Real Mode Call-Back Address */
  1071.       {
  1072.       word16 i;
  1073.       CHECK_POINTER(tss_ptr->tss_es, tss_ptr->tss_edi);
  1074.       CHECK_POINTER(tss_ptr->tss_ds, tss_ptr->tss_esi);
  1075.       for (i=0; i<num_rmcb; i++)
  1076.         if (dpmisim_rmcb[i].cb_sel == 0)
  1077.           break;
  1078.       if (i == num_rmcb)
  1079.         EXIT_ERROR;
  1080.       dpmisim_rmcb[i].cb_address = tss_ptr->tss_esi;
  1081.       dpmisim_rmcb[i].cb_sel = tss_ptr->tss_ds;
  1082.       dpmisim_rmcb[i].cb_type = 0;
  1083.       dpmisim_rmcb[i].reg_ptr = tss_ptr->tss_edi;
  1084.       dpmisim_rmcb[i].reg_sel = tss_ptr->tss_es;
  1085.       (word16)tss_ptr->tss_ecx = _CS;
  1086.       (word16)tss_ptr->tss_edx = (word16)dpmisim_rmcb0 + i * ((word16)dpmisim_rmcb1 - (word16)dpmisim_rmcb0);
  1087.       EXIT_OK;
  1088.       }
  1089.  
  1090.     case 0x0304: /* Free Real Mode Call-Back Address */
  1091.       {
  1092.       word16 i;
  1093.       if ((word16)tss_ptr->tss_ecx == _CS)
  1094.         for (i=0; i<num_rmcb; i++)
  1095.           if ((word16)tss_ptr->tss_edx == (word16)dpmisim_rmcb0 + i * ((word16)dpmisim_rmcb1 - (word16)dpmisim_rmcb0))
  1096.           {
  1097.             dpmisim_rmcb[i].cb_sel = 0;
  1098.             EXIT_OK;
  1099.           }
  1100.       EXIT_ERROR;
  1101.       }
  1102.  
  1103.     case 0x0305: /* Get State Save/Restore Adresses.  */
  1104.       (word16)tss_ptr->tss_eax = 0;
  1105.       (word16)tss_ptr->tss_ebx = _CS;
  1106.       (word16)tss_ptr->tss_ecx = (word16)savestate_real;
  1107.       (word16)tss_ptr->tss_esi = GDT_SEL(g_pcode);
  1108.       tss_ptr->tss_edi = (word16)savestate_prot;
  1109.       EXIT_OK;
  1110.  
  1111.     case 0x0306: /* Get Raw Mode Switch Addresses.  */
  1112.       (word16)tss_ptr->tss_ebx = _CS;
  1113.       (word16)tss_ptr->tss_ecx = (word16)do_raw_switch_ret;
  1114.       (word16)tss_ptr->tss_esi = g_ctss*8;
  1115.       tss_ptr->tss_edi = 0; /* doesn't matter, above is a task */
  1116.       EXIT_OK;
  1117.  
  1118.     case 0x0400: /* Get Version.  */
  1119.       (word16)tss_ptr->tss_eax = 0x005a;
  1120.       (word16)tss_ptr->tss_ebx = 5; /* Cheat, pretend always V86 mode (bit 1) */
  1121.       (word8)tss_ptr->tss_ecx = cpu_family;
  1122.       (word16)tss_ptr->tss_edx = (old_master_lo << 8) | hard_slave_lo;
  1123.       EXIT_OK;
  1124.  
  1125.     case 0x0500: /* Get Free Memory Information.  */
  1126.       {
  1127.       word32 tmp_buffer[12];
  1128.       CHECK_POINTER(tss_ptr->tss_es, tss_ptr->tss_edi);
  1129.       memset(tmp_buffer, 0xff, sizeof(tmp_buffer));
  1130.       tmp_buffer[4] = tmp_buffer[6] = valloc_max_size();
  1131.       tmp_buffer[2] = tmp_buffer[5] = valloc_max_size() - valloc_used();
  1132.       tmp_buffer[8] = dalloc_max_size();
  1133. /*      tmp_buffer[1] = tmp_buffer[2] + tmp_buffer[8] - dalloc_used(); */
  1134.       tmp_buffer[1] = tmp_buffer[8] - reserved + valloc_max_size();
  1135.       tmp_buffer[0] = tmp_buffer[1] << 12;
  1136.       memput(tss_ptr->tss_es, tss_ptr->tss_edi, tmp_buffer, sizeof(tmp_buffer));
  1137.       EXIT_OK;
  1138.       }
  1139.  
  1140.     case 0x0501: /* Allocate Memory Block.  */
  1141.       {
  1142.       word32 rsize,newbase;
  1143.       AREAS *area = firstarea;
  1144.       AREAS **lasta = &firstarea;
  1145.       newbase = 0x0fffffff;
  1146.       while(area) {
  1147.         newbase = area->last_addr;
  1148.         lasta = &area->next;
  1149.         area = area->next;
  1150.       }
  1151.       if(!(area = malloc(sizeof(AREAS))))
  1152.         EXIT_ERROR;
  1153. #ifdef OLDWAY
  1154.       newbase |= 0x0fffffff;    /* Leave room for resize */
  1155. #endif
  1156.       rsize = (((word16)tss_ptr->tss_ecx + 0xfffL) & ~0xfffL) + (tss_ptr->tss_ebx << 16);
  1157.       if(cant_ask_for(rsize)) {
  1158.         free(area);
  1159.         EXIT_ERROR;
  1160.       }
  1161.       *lasta = area;
  1162.       area->first_addr = ++newbase;
  1163.       area->last_addr = area->first_addr + rsize - 1;
  1164.       area->next = NULL;
  1165. #if run_ring == 0
  1166.       lock_memory(area->first_addr, rsize, 0);
  1167. #endif
  1168.       (word16)tss_ptr->tss_edi =
  1169.       (word16)tss_ptr->tss_ecx = (word16)area->first_addr;
  1170.       (word16)tss_ptr->tss_esi =
  1171.       (word16)tss_ptr->tss_ebx = area->first_addr >> 16;
  1172.       EXIT_OK;
  1173.       }
  1174.  
  1175.     case 0x0502: /* Free Memory Block.  */
  1176.       if(free_memory_area((word16)tss_ptr->tss_edi + (tss_ptr->tss_esi << 16)))
  1177.         EXIT_OK;
  1178.       else
  1179.         EXIT_ERROR;
  1180.  
  1181.     case 0x0503: /* Resize Memory Block.  */
  1182.       {
  1183.       AREAS *area = firstarea;
  1184.       AREAS **lasta = &firstarea;
  1185.       word32 vaddr = (word16)tss_ptr->tss_edi + (tss_ptr->tss_esi << 16);
  1186.       while(area) {
  1187.         if(vaddr == area->first_addr) {
  1188.           word32 rsize,asize;
  1189.           rsize = (((word16)tss_ptr->tss_ecx + 0xfffL) & ~0xfffL) + (tss_ptr->tss_ebx << 16);
  1190.           asize = rsize-(area->last_addr-area->first_addr+1);
  1191.           if(cant_ask_for(asize))
  1192.             EXIT_ERROR;
  1193.           area->last_addr += asize;
  1194.           if(area->next && area->last_addr >= (area->next)->first_addr) {
  1195.             /* Resize needs to move the zone - groan */
  1196.             word32 newbase;
  1197.             *lasta = area->next;    /* Remove from chain */
  1198.             while((*lasta)->next)
  1199.               lasta = &((*lasta)->next);
  1200.             (*lasta)->next = area;
  1201.             newbase = (*lasta)->last_addr;
  1202.             move_pt(area->first_addr,area->last_addr-asize,++newbase);
  1203.             area->first_addr = newbase;
  1204.             area->last_addr = area->first_addr + rsize - 1;
  1205.             area->next = NULL;
  1206.             (word16)tss_ptr->tss_edi = (word16)area->first_addr;
  1207.             (word16)tss_ptr->tss_esi = area->first_addr >> 16;
  1208.           }
  1209. #if run_ring == 0
  1210.           lock_memory(area->last_addr+1-asize, asize, 0);
  1211. #endif
  1212.           (word16)tss_ptr->tss_ecx = (word16)tss_ptr->tss_edi;
  1213.           (word16)tss_ptr->tss_ebx = (word16)tss_ptr->tss_esi;
  1214.           EXIT_OK;
  1215.         }
  1216.         lasta = &area->next;
  1217.         area = area->next;
  1218.       }
  1219.       EXIT_ERROR;
  1220.       }
  1221.  
  1222.     case 0x0506: /* V1.0 Get Page Attributes.  */
  1223.     case 0x0507: /* V1.0 Set Page Attributes.  */
  1224.       {
  1225.       AREAS *area = firstarea;
  1226.       word32 start = tss_ptr->tss_esi;
  1227.       while(area) {
  1228.         if(start == area->first_addr) {
  1229.           start += tss_ptr->tss_ebx;
  1230.           (word16)start &= ~0xfff;            /* Page align */
  1231.           page_attributes((word8)tss_ptr->tss_eax == 7, start,
  1232.             (word16)tss_ptr->tss_ecx);    /* ES:EDX known by routine */
  1233.           EXIT_OK;
  1234.         }
  1235.         area = area->next;
  1236.       }
  1237.       (word16)tss_ptr->tss_eax = 0x8023;    /* Bad handle */
  1238.       EXIT_ERROR;
  1239.       }
  1240.  
  1241.     case 0x0508: /* V1.0 Map Device in Memory Block.  */
  1242.     case 0x0509: /* V1.0 Map Conventional Memory in Memory Block.  */
  1243.       {
  1244.       AREAS *area = firstarea;
  1245.       word32 start = tss_ptr->tss_esi;
  1246.       while(area) {
  1247.         if(start == area->first_addr) {
  1248.           word32 size = tss_ptr->tss_ecx << 12;
  1249.           start += tss_ptr->tss_ebx;
  1250.           if(((word16)start & 0xfff) ||
  1251.              ((word16)tss_ptr->tss_edx & 0xfff) ||
  1252.              (start + size - 1 > area->last_addr)) {
  1253.               (word16)tss_ptr->tss_eax = 0x8025;    /* Invalid address */
  1254.               EXIT_ERROR;
  1255.            }
  1256.           physical_map(tss_ptr->tss_edx,size,start);    /* maps to "start" */
  1257.           EXIT_OK;
  1258.         }
  1259.         area = area->next;
  1260.       }
  1261.       (word16)tss_ptr->tss_eax = 0x8023;    /* Bad handle */
  1262.       EXIT_ERROR;
  1263.       }
  1264.  
  1265.     case 0x0600: /* Lock Linear Region.  */
  1266.     case 0x0601: /* Unlock Linear Region.  */
  1267.     {
  1268.       word32 vaddr, size;
  1269.       vaddr = (word16)tss_ptr->tss_ecx + (tss_ptr->tss_ebx << 16);
  1270.       size = (word16)tss_ptr->tss_edi + (tss_ptr->tss_esi << 16);
  1271.       /* bugs here - our lock/unlock does not keep lock count */
  1272.       if (vaddr < 0x10000000L)
  1273.         EXIT_ERROR;
  1274.       if(lock_memory(vaddr,size,(word8)tss_ptr->tss_eax))
  1275.         EXIT_ERROR;
  1276.       EXIT_OK;
  1277.     }
  1278.  
  1279.     case 0x0602: /* Mark Real Mode Region as Pageable.  */
  1280.     case 0x0603: /* Relock Real Mode Region.  */
  1281.       EXIT_OK;        /* We don't page real mode region so return success */
  1282.  
  1283.     case 0x0604: /* Get Page Size.  */
  1284.       (word16)tss_ptr->tss_ebx = 0;
  1285.       (word16)tss_ptr->tss_ecx = 4096;
  1286.       EXIT_OK;
  1287.  
  1288.     case 0x0702: /* Mark Page as Demand Paging Candidate.  */
  1289.       EXIT_OK;        /* We choose to ignore hints and return success */
  1290.  
  1291.     case 0x0703: /* Discard Page Contents.  */
  1292.     {
  1293.       word32 firsta, lasta;
  1294.       firsta = (word16)tss_ptr->tss_ecx + (tss_ptr->tss_ebx << 16);
  1295.       lasta = firsta + (word16)tss_ptr->tss_edi + (tss_ptr->tss_esi << 16);
  1296.       firsta += 0xfffL;
  1297.       (word16)firsta &= ~0xfff;        /* Round up - partial pages not discared */
  1298.       if (firsta < 0x10000000L)
  1299.         EXIT_ERROR;
  1300.       (word16)lasta &= ~0xfff;        /* Round down */
  1301.       free_memory(firsta,lasta);
  1302.       EXIT_OK;
  1303.     }
  1304.  
  1305.     case 0x0800: /* Physical Address Mapping.  */
  1306.     {
  1307.       word32 phys, vaddr, size;
  1308.       size = (word16)tss_ptr->tss_edi + (tss_ptr->tss_esi << 16);
  1309.       vaddr = phys = (word16)tss_ptr->tss_ecx + (tss_ptr->tss_ebx << 16);
  1310.       if((word8)(vaddr >> 28) == 1)    /* Conflict with our default mapping */
  1311.         vaddr += 0x10000000;
  1312.       physical_map(phys,size,vaddr);  /* Does 1:1 mapping, we return BX:CX */
  1313.       EXIT_OK;
  1314.     }
  1315.  
  1316.     case 0x0900: /* Get and Disable Virtual Interrupt State.  */
  1317.     case 0x0901: /* Get and Enable Virtual Interrupt State.  */
  1318.     case 0x0902: /* Get Virtual Interrupt State.  */
  1319.       if((word16)tss_ptr->tss_eflags & 0x200) {
  1320.         if((word8)tss_ptr->tss_eax == 0)
  1321.           (word16)tss_ptr->tss_eflags &= ~0x200;
  1322.         (word8)tss_ptr->tss_eax = 1;
  1323.       } else {
  1324.         if((word8)tss_ptr->tss_eax == 1)
  1325.           (word16)tss_ptr->tss_eflags |= 0x200;
  1326.         (word8)tss_ptr->tss_eax = 0;
  1327.       }
  1328.       EXIT_OK;
  1329.  
  1330. #if 0
  1331.     case 0x0A00: /* Get Vendor Specific API Entry Point.  */
  1332. #endif
  1333.  
  1334.     case 0x0B00: /* Set Debug Watchpoint.  */
  1335.       {
  1336.       int enabled = (int)dr[7];
  1337.       word16 i;
  1338.       for(i=0;i<4;i++)
  1339.         if(! (enabled >> (i*2))&3 ) {
  1340.           unsigned mask;
  1341.           dr[i] = (tss_ptr->tss_ebx << 16) | (word16)tss_ptr->tss_ecx;
  1342.           (word16)dr[7] |= (3 << (i*2));
  1343.           mask = ((word16)tss_ptr->tss_edx >> 8) & 3;   /* dh = type */
  1344.           if(mask == 2) mask++;         /* Change dpmi 0,1,2 to 0,1,3 */
  1345.           mask |= (((word16)tss_ptr->tss_edx-1) << 2) & 0x0c; /* dl = size */
  1346.           dr[7] |= (word32)mask << (i*4 + 16);
  1347.           (word16)tss_ptr->tss_ebx = i;
  1348.           EXIT_OK;
  1349.         }
  1350.       EXIT_ERROR;        /* None available */
  1351.       }
  1352.     case 0x0B01: /* Clear Debug Watchpoint.  */
  1353.       {
  1354.       word16 i = (word16)tss_ptr->tss_ebx & 3;
  1355.       (word16)dr[6] &= ~(1 << i);
  1356.       (word16)dr[7] &= ~(3 << (i*2));
  1357.       dr[7] &= ~(15L << (i*4+16));
  1358.       EXIT_OK;
  1359.       }
  1360.     case 0x0B02: /* Get State of Debug Watchpoint.  */
  1361.       {
  1362.       word16 i = (word16)tss_ptr->tss_ebx & 3;
  1363.       (word16)tss_ptr->tss_eax = (word16)dr[6] >> i;
  1364.       EXIT_OK;
  1365.       }
  1366.     case 0x0B03: /* Reset Debug Watchpoint.  */
  1367.       {
  1368.       word16 i = (word16)tss_ptr->tss_ebx & 3;
  1369.       (word16)dr[6] &= ~(1 << i);
  1370.       EXIT_OK;
  1371.       }
  1372.  
  1373. #if 0
  1374.     case 0x0E00: /* DPMI 1.0: Get Coprocessor Status.  */
  1375. #endif
  1376.     case 0x0E01: /* DPMI 1.0: Set Coprocessor Emulation.  */
  1377.       /* Ignore MP bit, since clearing it can cause problems.  We don't
  1378.          actually set the EM bit here, since a task swap will set TS and
  1379.          cause the same effect (by not using our custom TS clear handler). */
  1380.       if((word8)tss_ptr->tss_ebx & 2) {        /* Client supplies emulation */
  1381.         idt[7].offset0 = (int)FP_OFF(ivec0) + 7*((int)ivec1-(int)ivec0);
  1382.       } else {
  1383.         idt[7].offset0 = (int)ivec7;        /* To handle TS bit set faults */
  1384.       }
  1385.       EXIT_OK;
  1386.  
  1387. #ifdef DIAGNOSE
  1388.     default: /* Mark As Unsupported.  */
  1389.       errmsg("DPMI request 0x%x unsupported\n",(word16)(tss_ptr->tss_eax));
  1390. /*      EXIT_ERROR; */
  1391. #endif
  1392.   }
  1393.  
  1394. i31_exit_error:
  1395.   SET_CARRY;
  1396. i31_exit:
  1397.   return 0;
  1398. }
  1399.