home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / CSDPMI3S.ZIP / SRC / CWSDPMI / DPMISIM.ASM < prev    next >
Encoding:
Assembly Source File  |  1996-08-06  |  13.4 KB  |  569 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.     title    dpmisim
  14.     include    segdefs.inc
  15.     include tss.inc
  16.     include gdt.inc
  17.  
  18. ;------------------------------------------------------------------------
  19.  
  20.     start_data16
  21.  
  22.     public    _DPMIsp
  23. _DPMIsp dw    ?
  24. _DPMIss dw    DGROUP
  25.  
  26.     end_data16
  27.  
  28.     start_bss
  29.  
  30.     extrn    _a_tss:tss_s
  31.     extrn    _tss_ptr:word
  32.     extrn    _locked_stack:dword
  33.     extrn    _locked_count:byte
  34.     extrn    _dpmisim_rmcb:dword
  35.  
  36.     public    _dpmisim_regs
  37. _dpmisim_regs    label    dword
  38. ds_edi    dd    ?
  39. ds_esi    dd    ?
  40. ds_ebp    dd    ?
  41. ds_res    dd    ?
  42. ds_ebx    dd    ?
  43. ds_edx    dd    ?
  44. ds_ecx    dd    ?
  45. ds_eax    dd    ?
  46. ds_flg    dw    ?
  47. ds_es    dw    ?
  48. ds_ds    dw    ?
  49. ds_fs    dw    ?
  50. ds_gs    dw    ?
  51. ds_ip    dw    ?
  52. ds_cs    dw    ?
  53. ds_sp    dw    ?
  54. ds_ss    dw    ?
  55.  
  56.     public    _in_rmcb
  57. _in_rmcb    label    byte
  58.     db    ?
  59.  
  60.     end_bss
  61.  
  62. ;------------------------------------------------------------------------
  63.  
  64.     start_code16
  65.  
  66.     extrn    _go_til_stop:near
  67.     extrn    _DPMIstartup:near
  68.     extrn    _cputype:near
  69.     extrn    _main1:near
  70.  
  71. ; CWS note: dpmisim may be called recursively.  This routine can transfer
  72. ; control back to another program which can also request DPMI services.
  73. ; The other routine which is recursive and handles most of the setup is
  74. ; DPMIstartup, which is called to enter protected mode the first time.
  75.  
  76. ds_savesp    dd    ?
  77. ds_tmpds    dw    ?
  78.  
  79.     public    _dpmisim
  80. _dpmisim:
  81.     push    bp
  82.     push    si
  83.     push    di
  84.  
  85.     push    _DPMIsp                ;Save old value for restore
  86.     mov    _DPMIsp,sp            ;Where to start stack next call
  87.  
  88.     call    restore_registers
  89.     lss    sp, dword ptr ds_sp
  90.  
  91.     push    cs
  92.     push    offset dpmisim_return
  93.     push    ds_flg
  94.     push    ds_cs
  95.     push    ds_ip
  96.     mov    ds, ds_ds
  97.     iret    ; actually a far call in disguise, loading flags
  98. dpmisim_return:
  99.  
  100.     call    save_registers            ;Also disables interrupts
  101. ;    mov    ds_sp, sp            ;Not returned
  102.     lss    sp, dword ptr _DPMIsp
  103.  
  104.     pop    _DPMIsp
  105.     
  106.     pop    di
  107.     pop    si
  108.     pop    bp
  109.     cld
  110.     ret
  111.  
  112. restore_registers:
  113.     mov    edi, ds_edi
  114.     mov    esi, ds_esi
  115.     mov    ebp, ds_ebp
  116.     mov    ebx, ds_ebx
  117.     mov    edx, ds_edx
  118.     mov    ecx, ds_ecx
  119.     mov    eax, ds_eax
  120.     mov    es, ds_es
  121.     mov    fs, ds_fs
  122.     mov    gs, ds_gs
  123.     ret
  124.  
  125. save_registers:
  126.     pushf
  127.     cli                    ;Interlock, this is static
  128.     mov    cs:[ds_tmpds], ds
  129.     push    DGROUP
  130.     pop    ds
  131.     pop    ds_flg
  132.  
  133.     mov    ds_edi, edi
  134.     mov    ds_esi, esi
  135.     mov    ds_ebp, ebp
  136.     mov    ds_ebx, ebx
  137.     mov    ds_edx, edx
  138.     mov    ds_ecx, ecx
  139.     mov    ds_eax, eax
  140.     mov    ds_es, es
  141.     mov    ds_fs, fs
  142.     mov    ds_gs, gs
  143.     mov    ds_ss, ss
  144.     
  145.     mov    ax, cs:[ds_tmpds]
  146.     mov    ds_ds, ax
  147.     ret
  148.  
  149. rmcb    macro    n
  150.     push    n
  151.     jmp    short rmcb_common
  152.     endm
  153.  
  154.     public    _dpmisim_rmcb0
  155. _dpmisim_rmcb0:
  156.     rmcb    0
  157.     public    _dpmisim_rmcb1
  158. _dpmisim_rmcb1:
  159.     x=1
  160.     rept 23                ;num_rmcb-1 from dpmisim.h
  161.      rmcb x
  162.      x=x+1
  163.     endm
  164.  
  165. ; We enter from real mode here, and must put registers in ES:EDI real mode
  166. ; call structure, set DS:ESI as pointer to caller's stack (for modification)
  167. ; and set SS:ESP to the 32 bit locked stack
  168.  
  169. ; Needs to be reentrant, and is!  The a_tss values are saved on our stack.
  170. ; _DPMISP is stored by all methods to real mode, just in case we get another
  171. ; callback.  The static structures are only used temporarily and with 
  172. ; interrupts disabled.  Interrupts may be re-enabled during the 
  173. ; user routine, but we shut them back off in the critical exit sections.
  174. ; This is used for HW interrupt reflection into prot mode from real mode.
  175. ; Note, only a single mode switch!
  176.  
  177. rmcb_common:
  178.     call    save_registers            ;Also disables interrupts
  179.     pop    bx            ; rmcb number
  180.     mov    ds_sp,sp
  181.  
  182.     lss    sp,dword ptr _DPMIsp    ; set up our local stack
  183.     sub    sp,300h            ; A HW interrupt may occur anywhere
  184.                     ; I give up trying to find it!
  185.  
  186. ; Save a_tss values on our 16 bit stack while we use it
  187.     cld
  188.     push    ss
  189.     pop    es            ; ES=DS=SS
  190.     sub    sp,64            ; make room to save a_tss info
  191.     mov    si,offset DGROUP:_a_tss.tss_eip
  192.     mov    di,sp
  193.     mov    cx,32
  194.     rep    movsw            ; DS:_a_tss to SS:sp
  195.  
  196. ; Set up 32 bit stack for callback
  197.     cmp    _locked_count,0        ; already on locked stack?
  198.     jne    short already_locked
  199.     mov    _a_tss.tss_ss, g_pdata    ; ss:esp for pointer to temp stack
  200.     lea    ecx,_locked_stack+4096    ; end of locked stack
  201.     and    cl,0fch            ; longword align stack
  202.     mov    _a_tss.tss_esp, ecx
  203.  
  204. already_locked:
  205.     inc    _locked_count
  206.     inc    _in_rmcb
  207.     
  208.     shl    bx,4            ; each element 16 bytes
  209.     mov    eax, _dpmisim_rmcb[bx]    ; cb_address (eip for func)
  210.     mov    cs:rmcboff, eax
  211.     mov    ax, word ptr _dpmisim_rmcb[bx+4]  ; cb_sel (cs for func call)
  212.     mov    cs:rmcbseg, ax
  213.     mov    ax, word ptr _dpmisim_rmcb[bx+6]  ; cb_type
  214.     mov    word ptr _a_tss.tss_eax, ax
  215.  
  216.     or    al,al
  217.     je    short user_call_type
  218.  
  219. ; Internal RMCB type for interrupts
  220.     mov    ax, _a_tss.tss_ss
  221.     mov    _a_tss.tss_es, ax        ; We want regs stored on stack
  222.     sub    _a_tss.tss_esp, 34h        ; Make room, long aligned
  223.     mov    eax, _a_tss.tss_esp
  224.     mov    _a_tss.tss_edi, eax        ; ES:EDI == SS:ESP
  225.     jmp    short type_common
  226.  
  227. user_call_type:
  228.     mov    eax,_dpmisim_rmcb[bx+8]    ; reg_ptr
  229.     mov    _a_tss.tss_edi, eax
  230.     mov    ax, word ptr _dpmisim_rmcb[bx+12]  ; reg_sel
  231.     mov    _a_tss.tss_es, ax
  232. type_common:
  233.     mov    word ptr _a_tss.tss_eflags, 3002h    ; disable interrupts
  234.  
  235.     mov    _a_tss.tss_eip, offset rmcb_task
  236.     mov    _a_tss.tss_cs, g_pcode
  237.  
  238.     mov    _a_tss.tss_ds, g_core    ; ds:esi for pointer to caller stack
  239.     movzx    eax,ds_ss
  240.     shl    eax,4
  241.     movzx    ebx,ds_sp
  242.     add    eax,ebx
  243.     mov    _a_tss.tss_esi, eax
  244.  
  245. ; We take advantage of the fact that some registers are "undefined" in the spec
  246. ; We set FS:EBX to point to dpmisim_regs so we can do the copies in prot mode
  247.  
  248.     mov    _a_tss.tss_fs, g_pdata
  249.     mov    _a_tss.tss_ebx, offset DGROUP:_dpmisim_regs
  250.  
  251.     push    _tss_ptr
  252.     mov    _tss_ptr,offset DGROUP:_a_tss
  253.  
  254.     call    _go_til_stop            ;tss_ptr acts as non-zero arg
  255.     
  256.     pop    _tss_ptr
  257.  
  258. ; Note: go_til_stop leaves interrupts disabled on entry to real mode, so OK!
  259.  
  260.     dec    _in_rmcb
  261.     dec    _locked_count
  262.     push    ds
  263.     pop    es            ; ES=DS=SS
  264.     mov    si,sp
  265.     mov    di,offset DGROUP:_a_tss.tss_eip
  266.     mov    cx,32
  267.     rep    movsw            ; Restore a_tss from stack
  268.  
  269.     call    restore_registers
  270.     lss    sp, dword ptr ds_sp
  271.  
  272.     push    ds_flg
  273.     push    ds_cs
  274.     push    ds_ip
  275.     mov    ds, ds_ds
  276.     iret                ; jmp to wherever the regs said to
  277.  
  278. ; This is a wrapper around their RMCB which copies the regs.  On entry:
  279. ; DS:ESI points to real mode SS:SP         AX     is RMCB type
  280. ; ES:EDI points to PM register structure   FS:EBX points to RM register struct
  281.  
  282. rmcb_task:
  283.     mov    ecx,25            ; Size of reg struct in words
  284.     push    esi
  285.     push    edi
  286.     mov    esi,ebx            ; Copy RM regs to PM
  287.     rep    movs word ptr es:[edi],word ptr fs:[esi]
  288.     pop    edi
  289.     pop    esi
  290.     push    ebx            ; Save for return restore
  291.     push    fs
  292.     push    ds
  293.     push    esi            ; Real stack for us if internal int
  294.     push    eax
  295. ; Now set up the iret frame for their call
  296.     pushfd
  297.     db    66h, 09ah        ; Far call from 16 seg to 32 seg
  298. rmcboff    dd    ?
  299. rmcbseg    dw    ?
  300.  
  301. ; They return via IRET, so flags are correct, interrupts disabled
  302. ; Restore the reg structure es:edi to ss:(stack value)
  303.     pop    eax
  304.     pop    esi
  305.     pop    ds
  306.     or    al,al
  307.     je    short not_internal
  308.     lods    dword ptr [esi]        ; Get CS:IP from real stack in eax
  309.     mov    dword ptr es:[edi+2ah], eax
  310.     lods    word ptr [esi]            ; Get flags
  311.     mov    word ptr es:[edi+20h], ax
  312.     add    word ptr es:[edi+2eh], 6    ; Adjust RM SP
  313.  
  314. not_internal:
  315.     push    es
  316.     pop    ds
  317.     mov    esi,edi            ; ds:esi now = es:edi
  318.     pop    es
  319.     pop    edi            ; es:edi is now reg struct
  320.     mov    ecx,25            ; Size of reg struct in words
  321.     rep    movs word ptr es:[edi],word ptr [esi]
  322.     xor    bx,bx            ; Indicate not valid raw switch (sp=0)
  323.     jmpt    g_ctss            ; Back to real mode
  324.  
  325.     public    _oldint2f
  326. _oldint2f    label    dword
  327.     dw    2 dup (?)
  328.  
  329. _dpmientrysw    label    dword
  330.     dw    dpmientry
  331.     dw    _TEXT
  332.  
  333.     public    _cpu_family
  334. _cpu_family    label    byte
  335.     dw    ?
  336.  
  337.     public    _dpmiint2f
  338. _dpmiint2f:
  339.     cmp    ax,1687h
  340.     jne    short not_us
  341.     mov    cl,cs:_cpu_family
  342.     xor    ax,ax            ;Yes, we are here
  343.     mov    bx,1            ;32 bit programs supported
  344.     mov    dx,5ah            ;0.90 version
  345.     mov    si,6            ;paragraphs needed for tss save
  346.     les    di,cs:_dpmientrysw
  347.     iret
  348. not_us:
  349.     jmp    DWORD PTR cs:_oldint2f
  350.  
  351. dpmientry:                ;far return point cs:ip on stack
  352.     test    al,1            ;Bogus code since we don't do 16 bit
  353.     jnz    short ok_32        ;Bogus code
  354. ;    stc                ;Bogus code - but bcc make doesn't check
  355. ;    retf                ;Bogus code - carry so wedges machine !
  356.     mov    dx,offset bogus_msg    ;Bogus code
  357.     push    cs            ;Bogus code
  358.     pop    ds            ;Bogus code
  359.     mov    ah,9            ;Bogus code
  360.     int    21h            ;Bogus code
  361.     mov    ax,4c01h        ;Bogus code
  362.     int    21h            ;Bogus code
  363. bogus_msg    db "16-bit DPMI unsupported.",13,10,"$"
  364. ok_32:                    ;Bogus code
  365.     push    ds
  366.     push    ebx
  367.     push    es
  368.     pop    ds            ;Real mode segment of DPMI host area
  369.     xor    bx,bx
  370.     pop     [bx].tss_ebx
  371.     pop     [bx].tss_ds
  372.     pop    word ptr [bx].tss_eip    ;saved ip on stack from far call here
  373.     mov    word ptr [bx+2].tss_eip,bx    ;Clear upper word
  374.     pop    [bx].tss_cs        ;saved cs on stack from far call here
  375.     mov    [bx].tss_eax,eax
  376.     mov    [bx].tss_ecx,ecx
  377.     mov    [bx].tss_edx,edx
  378.     mov    word ptr [bx].tss_esp,sp ;stack clean at this point (req short)
  379.     mov    word ptr [bx+2].tss_esp,bx    ;Clear upper word
  380.     mov    [bx].tss_ebp,ebp
  381.     mov    [bx].tss_esi,esi
  382.     mov    [bx].tss_edi,edi
  383. ;    mov    [bx].tss_es,es        ;not used
  384.     mov    [bx].tss_ss,ss
  385.     push    DGROUP            ;setup our DS so we can setup tss
  386.     pop    ds
  387.  
  388. ; Their state is now stored.  Finish switching to our state
  389.     lss    sp,dword ptr _DPMIsp
  390.     cld
  391.     call    _DPMIstartup
  392.     push    0
  393.     call    _go_til_stop            ; never to return
  394.  
  395. ; We enter this routine at user ring in protected mode after the user exception
  396. ; handler has done its far return.  It must restore the EIP/CS/EFLAGS/ESP/SS 
  397. ; from the structure on the stack (possibly modified by the user).
  398.  
  399.     public    _user_exception_return
  400. _user_exception_return:
  401.     add    esp,4                ;Clear error code
  402.  
  403.     public    _user_interrupt_return
  404. _user_interrupt_return:
  405. IF run_ring EQ 0
  406. ; This code moves the EIP/CS/EFLAGS to the specified stack-12, swaps to that 
  407. ; stack, and then does an iretd.  This code doesn't work for HW interrupts 
  408. ; since it touches their stack which may not be present or may be messed up by 
  409. ; the CWS HW int to exception algorithm.  Fix me.
  410.     push    ebp                ;Save for later
  411.     mov    ebp,esp                ;Pointer to our stack
  412.     push    eax                ;Work area
  413.     push    ebx                ;Save for later
  414.     push    ds                ;Save
  415.     lds    ebx,[ebp+16]            ;Info for new SS:ESP
  416.     sub    ebx,16                ;Room for 4 dwords
  417.     mov    [ebp+16],ebx            ;Update ESP for reload
  418.     mov    eax,[ebp]            ;Saved EBP
  419.     mov    [ebx],eax
  420.     mov    eax,[ebp+4]            ;Saved EIP
  421.     mov    [ebx+4],eax
  422.     mov    eax,[ebp+8]            ;Saved CS
  423.     mov    [ebx+8],eax
  424.     mov    eax,[ebp+12]            ;Saved Eflags
  425.     mov    [ebx+12],eax
  426.     push    g_pdata
  427.     pop    ds
  428.     dec    _locked_count            ;we may be leaving locked stack
  429.     pop    ds
  430.     pop    ebx
  431.     pop    eax
  432.     lss    esp,[ebp+16]            ;Info for new SS:ESP
  433.     pop    ebp
  434.     iretd
  435. ELSE
  436.     db    09ah                ;Call intersegment to call gate
  437.     dw    0, g_iret            ;Should point to code below
  438.  
  439. ; We enter here on ring 0 stack with 4 dwords.  We need 5 dwords for the iret
  440. ; structure on the old stack, which (while it is locked) is a ring 3 stack,
  441. ; maybe in the user code space.  Copy the structure here then do the IRET.
  442.  
  443.     public    _ring0_iret
  444. _ring0_iret:
  445.     sub    esp,4                ;More room (we need EFLAGS)
  446.     push    ebp                ;Save for later
  447.     mov    ebp,esp                ;Pointer to our stack
  448.     push    ds
  449.     push    es
  450.     push    esi
  451.     push    edi
  452.     push    ecx
  453.     mov    ecx,5                ;Dword count
  454.     mov    edi,ebp
  455.     add    edi,4                ;Our stack address, adjusted
  456.     push    ss
  457.     pop    es
  458.     lds    esi,[ebp+16]            ;Old ESP:SS
  459.     cld
  460.     rep    movs dword ptr es:[edi],dword ptr ds:[esi]    ;ecx count
  461.     pop    ecx
  462.     pop    edi
  463.     pop    esi
  464.     push    g_pdata
  465.     pop    ds
  466.     dec    _locked_count            ;we may be leaving locked stack
  467.     pop    es
  468.     pop    ds
  469.     pop    ebp
  470.     iretd                    ;Restore SS:ESP, CS:EIP, EFLAGS
  471. ENDIF
  472.  
  473. ; We enter here from protected mode wanting to raw switch to real
  474.     public    _do_raw_switch
  475. _do_raw_switch:
  476.     push    ebp si di
  477.     pushf    
  478.     push    _DPMIsp                ;For nested calls
  479.     xor    ax,ax
  480.     mov    fs,ax
  481.     mov    gs,ax
  482.     mov    _DPMIsp,sp
  483. ;    mov    _DPMIss,ss
  484.     mov    bx,_tss_ptr
  485.     mov    ss,word ptr [bx].tss_edx
  486.     mov    sp,word ptr [bx].tss_ebx    ; high word???
  487.     mov    es,word ptr [bx].tss_ecx
  488.     mov    ebp,[bx].tss_ebp
  489.     push    word ptr [bx].tss_esi        ; CS
  490.     push    word ptr [bx].tss_edi        ; IP
  491.     mov    ds,word ptr [bx].tss_eax
  492.     retf
  493.  
  494. ; We enter here from real mode wanting to switch back to protected
  495.     public    _do_raw_switch_ret
  496. _do_raw_switch_ret:
  497.     push    DGROUP
  498.     pop    ds
  499.     lss    sp,dword ptr _DPMIsp
  500.     push    ebx
  501.     mov    bx,_tss_ptr
  502.     mov    [bx].tss_fs,0
  503.     mov    [bx].tss_gs,0
  504.     mov    [bx].tss_ds,ax
  505.     mov    [bx].tss_es,cx
  506.     mov    [bx].tss_ss,dx
  507.     pop    [bx].tss_esp
  508.     mov    [bx].tss_cs,si
  509.     mov    [bx].tss_eip,edi
  510.     mov    [bx].tss_ebp,ebp
  511.     pop    _DPMIsp
  512.     popf
  513.     pop     di si ebp
  514.     ret
  515.  
  516. ; Since we don't do anything in saving state, same for both modes
  517.     public    _savestate_real
  518. _savestate_real:
  519. ;    push    es
  520. ;    push    0b800h
  521. ;    pop    es
  522. ;    mov    byte ptr es:[0f9ch],'R'
  523. ;    pop    es
  524. ;    retf
  525.     public    _savestate_prot
  526. _savestate_prot:
  527. ;    push    es
  528. ;    push    esi
  529. ;    push    g_core
  530. ;    pop    es
  531. ;    mov    esi,0b8f9eh
  532. ;    mov    byte ptr es:[esi],'P'
  533. ;    pop    esi
  534. ;    pop    es
  535.     retf
  536.  
  537.     public    _int23
  538.     public    _int24
  539. _int24:
  540.     mov    al,3
  541. _int23:
  542.     iret
  543.  
  544. badcpu_msg    db "80386 required.",13,10
  545. badsize equ    $ - badcpu_msg
  546.     public    _main
  547. _main:
  548.     call    _cputype
  549.     mov    cs:_cpu_family,al
  550.     cmp    al,3
  551.     jb    short badcpu
  552.     jmp    _main1
  553. badcpu:
  554.     push    cs
  555.     pop    ds
  556.     mov    dx,offset _TEXT:badcpu_msg
  557.     mov    ah,40h
  558.     mov    bx,2        ;Standard error
  559.     mov    cx,badsize
  560.     int    21h
  561.     mov    ax,4c01h
  562.     int    21h
  563.  
  564.     end_code16
  565.  
  566. ;------------------------------------------------------------------------
  567.  
  568.     end
  569.