home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / asm_programming / DOS32.ASM < prev    next >
Assembly Source File  |  1993-10-17  |  48KB  |  1,710 lines

  1. COMMENT $
  2.  
  3.                       DOS32           Version 1.2
  4.  
  5.            A  32 bit MSDOS extender for assembly programmers
  6.  
  7.                            supporting
  8.  
  9.               Dos Protected Mode Interrupt Specification
  10.                   and
  11.        System BIOS extended memory copy service (INT 15h AH = 87h)
  12.        for without DPMI.
  13.  
  14.     Unlike Version 1.0 this uses the only one protected mode segment.
  15.        i.e Does not have a seperate code ,data and stack descriptor
  16.         base addresses.  A much better way to program
  17.  
  18.    Written by Adam Seychell     SEP-1993
  19.  
  20.    email   s921880@minyos.xx.rmit.oz.au
  21.  
  22.  
  23.  
  24. $
  25. .SEQ
  26. .386p           ; Enable "REAL"  CPU instuctions.
  27.  
  28. V86_stack_size     equ 200h    ; Size of stack for V86 interrupt calls
  29.  
  30. PIC_Base    equ 80h        ; Base interrupt address for the 8259s
  31.  
  32.  
  33.  
  34.  
  35. ;
  36. ; Format of a 386DX TSS (Task State Segment)
  37. ;
  38. TSS    struc
  39. tss_prev    dw    0    ,0        ; back link to previous TSS
  40. tss_esp0    dd    0            ; Priv. 0 ESP
  41. tss_ss0        dw    0            ; Priv. 0 SS
  42.         dw    0            ; unused
  43. tss_esp1    dd    0            ; Priv. 1 ESP
  44. tss_ss1        dw    0            ; Priv. 1 SS
  45.         dw    0            ; unused
  46. tss_esp2    dd    0            ; Priv. 2 ESP
  47. tss_ss2        dw    0            ; Priv. 2 SS
  48.         dw    0            ; unused
  49. tss_cr3        dd    0            ; PDBR
  50. tss_eip        dd    0
  51. tss_eflags    dd    0
  52. tss_eax        dd    0
  53. tss_ecx        dd    0
  54. tss_edx        dd    0
  55. tss_ebx        dd    0
  56. tss_esp        dd    0
  57. tss_ebp        dd    0
  58. tss_esi        dd    0
  59. tss_edi        dd    0
  60. tss_es        dw    0,0
  61. tss_cs        dw    0,0
  62. tss_ss        dw    0,0
  63. tss_ds        dw    0,0
  64. tss_fs        dw    0,0
  65. tss_gs        dw    0,0
  66. tss_ldt        dw    0,0
  67. tss_t        dw    0        ; if bit 0 set, exception on tsk switch
  68. tss_iobase    dw    068h        ; points to beg. of I/O permissions map
  69. tss_iomap    db    2000h dup (0)    ; I/O permissions bit map
  70. tss_ioend    db    11111111b    ; I/O map trailer
  71. TSS_ENDS    equ    $ - TSS
  72. tss ends
  73.  
  74.  
  75.  
  76.  
  77. Data_sruct    struc
  78. C_EDI        dd 0
  79. C_ESI        dd 0
  80. C_EBP        dd 0
  81. C_resrved    dd 0
  82. C_EBX        dd 0
  83. C_EDX        dd 0
  84. C_ECX        dd 0
  85. C_EAX        dd 0
  86. C_FLAGS        dw 0
  87. C_ES        dw 0
  88. C_DS        dw 0
  89. C_FS        dw 0
  90. C_GS        dw 0
  91. C_IP        dw 0
  92. C_CS        dw 0
  93. C_SP        dw 0
  94. C_SS        dw 0
  95. ends
  96.  
  97.  
  98. DOS_CODE    SEGMENT PUBLIC 'CODE' USE16
  99. assume CS:DOS_CODE , DS:DOS_CODE , FS:CODE32
  100.  
  101. s_ACCESS record d_P:1,d_DPL:2,s_S:1,d_TYPE:4
  102. s_INFO   record d_G:1,d_D:1,d_nul:1,d_avl:1,d_lim:4
  103.  
  104. align 8
  105. GDT        dd 0,0          ; First descriptor is always NULL.
  106.  
  107. ;    Data DESCRIPTOR for a FLAT memory model
  108. Flat_Data_Desc    dw 0ffffh             ; Limit[15..0]
  109.         db 0,0,0            ; Base[23..0]
  110.          s_ACCESS <1,00b,1,0010b>    ; P,DPL,1,type[E=0,ED,W,A ]
  111.         s_INFO <1,1,0,0,0fh>        ; G,B,0,avl,Limit[19..16]
  112.             db 0                ; Base[31..24]
  113.  
  114. ;    Code DESCRIPTOR for a FLAT memory model
  115. Flat_CODE32_Desc dw 0ffffh             ; Limit[15..0]
  116.          db 0,0,0            ; Base[23..0]
  117.          s_ACCESS <1,00,1,1010b>    ; P,DPL,1,type[E=1,C,R,A ]
  118.          s_INFO <1,1,0,0,0fh>        ; G,D,0,avl,Limit[19..16]
  119.          db 0                ; Base[31..24]
  120.  
  121. ;    Data DESCRIPTOR for the free extented memory block
  122. XMS_Desc    dw 0000h             ; Limit[15..0]
  123.         db 00,00,10h            ; Base[23..0]
  124.          s_ACCESS <1,00b,1,0010b>    ; P,DPL,1,type[E=0,ED,W,A ]
  125.         s_INFO <1,1,0,0,00h>        ; G,B,0,avl,Limit[19..16]
  126.             db 0                ; Base[31..24]
  127.  
  128. ;    Data DESCRIPTOR with base = start of free base memory
  129. BASE_Desc    dw 0ffffh             ; Limit[15..0]
  130.         db ?,?,?            ; Base[23..0]
  131.          s_ACCESS <1,00,1,0010b>        ; P,DPL,1,type[E=0,ED,W,A ]
  132.         s_INFO <0,1,0,0,0fh>        ; G,B,0,avl,Limit[19..16]
  133.             db 0                ; Base[31..24]
  134.  
  135. ;    Data DESCRIPTOR     with base = 0A0000h
  136. Video_Desc    dw 0ffffh             ; Limit[15..0]
  137.         db 00,00,0Ah            ; Base[23..0]
  138.          s_ACCESS <1,00,1,0010b>        ; P,DPL,1,type[E=0,ED,W,A ]
  139.         s_INFO <0,1,0,0,01h>        ; G,B,0,avl,Limit[19..16]
  140.             db 0                ; Base[31..24]
  141.  
  142.  
  143. ;    16bit data and code DESCRIPTORS for real mode ( DOS )
  144. DOS_Code_Desc    dw 0ffffh            ; Limit[15..0]
  145.         db ?,?,?            ; Base[23..0]
  146.          s_ACCESS <1,00,1,1010b>        ; P,DPL,1,type[E=1,C,R,A ]
  147.         s_INFO <0,0,0,0,00h>        ; G,D,0,avl,Limit[19..16]
  148.             db 0                ; Base[31..24]
  149.  
  150. Dos_Data_Desc    dw 0ffffh             ; Limit[15..0]
  151.         db ?,?,?            ; Base[23..0]
  152.          s_ACCESS <1,00,1,0010b>        ; P,DPL,1,type[E=0,ED,W,A ]
  153.         s_INFO <0,0,0,0,0h>        ; G,B,0,avl,Limit[19..16]
  154.             db 0                ; Base[31..24]
  155.  
  156.  
  157. ;    Data PSP Descr   with base = PSP , limit = 100h
  158. PSP_desc    dw 0ffh                 ; Limit[15..0]
  159.         db 00,00,00h            ; Base[23..0]
  160.          s_ACCESS <1,00,1,0010b>        ; P,DPL,1,type[E=0,ED,W,A ]
  161.         s_INFO <0,0,0,0,00h>        ; G,B,0,avl,Limit[19..16]
  162.             db 0                ; Base[31..24]
  163.  
  164.  
  165. ;    Data Descr for program ENVIRONMENT
  166. ENVIRONMENT_desc    dw 0ffh                 ; Limit[15..0]
  167.             db 00,00,00h            ; Base[23..0]
  168.              s_ACCESS <1,00,1,0010b>        ; P,DPL,1,type[E=0,ED,W,A ]
  169.             s_INFO <0,0,0,0,0h>        ; G,B,0,avl,Limit[19..16]
  170.                 db 0                ; Base[31..24]
  171.  
  172. ;    DATA and CODE  DESCRIPTORS for your dos extender
  173.  
  174. CODE32_Desc    dw 0ffffh            ; Limit[15..0]
  175.         db ?,?,?            ; Base[23..0]
  176.          s_ACCESS <1,00,1,1010b>        ; P,DPL,1,type[E=1,C,R,A ]
  177.         s_INFO <0,1,0,0,0fh>        ; G,D,0,avl,Limit[19..16]
  178.             db 0                ; Base[31..24]
  179.  
  180.  
  181. Data_Desc    dw 0ffffh             ; Limit[15..0]
  182.         db ?,?,?            ; Base[23..0]
  183.          s_ACCESS <1,00b,1,0010b>    ; P,DPL,1,type[E=0,ED,W,A ]
  184.         s_INFO <0,1,0,0,0fh>        ; G,B,0,avl,Limit[19..16]
  185.             db 0                ; Base[31..24]
  186.  
  187.  
  188. MyMain_TSS_Desc    dw TSS_ends            ; Limit[15..0]
  189.         db ?,?,?            ; Base[23..0]
  190.         s_ACCESS <1,00,0,09h>        ; P,DPL,0,(type  = avalible 386 TSS )
  191.         s_INFO <0,0,0,0,00h>        ; G,0,0,0,Limit[19..16]
  192.         db 0                ; Base[31..24]
  193.  
  194.  
  195. GDT_ends    equ    $ - GDT
  196.  
  197.  
  198. ;======== ERROR MESSAGES FOR PROGRAM TERMINATION IN NON-DPMI ===============
  199. unknown_int_exit_mesg db 'Exited from Unhandled protected mode interrupt',10,13,36
  200. _V86_illigal_err db 10,13,' Invalid Instuction in V86 mode ',10,13,36
  201. _exit_errror    db 10,10,' PROGRAM TERMINATED ',10,13,7,36
  202. e_0 db '0  Divide error',10,13,36
  203. e_1 db '1  Debug exception',10,13,36
  204. e_2 db '2  Non-Maskable interrupt',10,13,36
  205. e_3 db '3  Breakpoint',10,13,36
  206. e_4 db '4  Overflow',10,13,36
  207. e_5 db '5  Range Exceeded',10,13,36
  208. e_6 db '6  Invalid opcode',10,13,36
  209. e_7 db '7  No math unit avalible',10,13,36
  210. e_8 db '8  Reserved',10,13,36
  211. e_9 db '9  Reserved',10,13,36
  212. e_10 db '10  Invalid TSS',10,13,36
  213. e_11 db '11 Segment Not Present',10,13,36
  214. e_12 db '12  Stack exception',10,13,36
  215. e_13 db '13 General Protection Exception',10,13,36
  216. e_14 db '14  Page fault',10,13,36
  217. e_15 db '14  Reserved',10,13,36
  218.  
  219. DOS_IDT_value    dw 03ffh,0,0,0
  220.  
  221. DPMI_entry    dw 0,0
  222. xms_usage_tmp    dd 0
  223. _tmpL_xms_base    dw 0
  224. _tmpH_xms_base    dw 0
  225. xms_driver    dd 0
  226. XMS_handle    dw 0,0
  227. oirqMask    db 0,0
  228. DPMI_Selector    dw 0
  229. PIC1_Base    db 0
  230. PIC2_Base    db 0
  231.  
  232. ;----------------------------------------------------------------------------
  233. ;─────────────────────  INTERNALY USED ROUTINES ───────────────────────────────────
  234. ;----------------------------------------------------------------------------
  235.  
  236. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  237. Exit_Error:    mov ah,9    ; Prints error mesage and terminates
  238.         int 21h
  239.         call free_XMS_memory
  240.         mov ah,4ch
  241.         int 21h
  242.  
  243. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  244. free_XMS_memory proc near
  245.             cmp [xms_driver],0
  246.             jz No_xms_driver
  247.  
  248.  
  249.                 ; UNLOCK THE ALLOCATED EXTENDED MEMORY BLOCK
  250.         mov    ah,0Dh
  251.                 mov    dx,[XMS_handle]
  252.                 call    [XMS_Driver]
  253.  
  254.         ; FREE ALLOCATED BLOCK
  255.                 MOV    AH,0Ah
  256.         mov    dx,[XMS_handle]
  257.                 call    [xms_driver]
  258. No_xms_driver:    RET
  259.  
  260. free_XMS_memory    endp
  261. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  262. ;─────────────────────────────────────────────────────────────────────────────
  263.             ; Set new IRQ vector numbers
  264. set_8259intvec  proc    ; Set IRQ vectors 0..7 to bl
  265.             ; and  IRQ vectors 8..15 to bh
  266.  
  267.         CLI              ;∙·∙·∙·∙·∙·∙·  set first 8259A PIC  ∙·∙·∙·∙·∙·∙·
  268.  
  269.         mov al,00010001b    ;ICW1
  270.         out 20h,al          ;icw4 is needed
  271.         call Delay8259
  272.         mov al,bl       ;ICW2
  273.         out 21h,al      ;( Set PIC 1 Base interrupt number )
  274.         call Delay8259
  275.         mov al,4h       ;ICW3
  276.         out 21h,al
  277.         call Delay8259
  278.         mov al,1h       ;ICW4
  279.         out 21h,al
  280.         call Delay8259  ;∙·∙·∙·∙·∙·∙·  set second 8259A PIC  ∙·∙·∙·∙·∙·∙·
  281.         mov al,00010001b    ;ICW1
  282.         out 0a0h,al     ;icw4 is needed
  283.         call Delay8259
  284.         mov al,bh       ;ICW2
  285.         out 0a1h,al     ;( Set PIC 2 Base interrupt number )
  286.         call Delay8259
  287.         mov al,00000010b    ;ICW3
  288.         out 0a1h,al
  289.         call Delay8259
  290.         mov al,0000001b     ;ICW4
  291.         out 0a1h,al
  292.         call Delay8259
  293.         ret
  294.  
  295. delay8259:  mov ax,1000h
  296.     @3del:  dec ax
  297.             jnz @3del
  298.             ret
  299. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  300. ;─────────────────────────────────────────────────────────────────────────────
  301. endp
  302.  
  303.  
  304.  
  305. Go_REAL_MODE proc near
  306.  
  307. ;─────────────────────────────────────────────────────────────────────────────
  308. ; Entry point to exit protected mode and restore hardware configeration.
  309. ; Then exits back to MSDOS. ( only for non-DPMI )
  310. ;─────────────────────────────────────────────────────────────────────────────
  311.     cli
  312.  
  313.     mov al,00110100b    ; SLOW DOWN TIMER FOR POOR OLD DOS
  314.     out 43h,al
  315.         XOR AL,AL
  316.     out 40h,al
  317.     out 40h,al
  318.  
  319. ; Exit protected mode and return to DOS
  320.  
  321. ; Load Data registers with 8086 SEGMENTs (Fields  B=0 and D=0 of descriptors)
  322.         mov    ax,DOS_Data_Desc - GDT
  323.         mov    ss,ax
  324.         mov    es,ax
  325.         mov    ds,ax
  326.         mov    fs,ax
  327.         mov    gs,ax
  328.  
  329.         lidt    qword ptr DOS_IDT_value        ; Set IDT to how DOS want's it
  330.  
  331. ; Exit protecded mode
  332.         mov    eax,CR0
  333.         and    al,NOT 1        ;Clear PE bit
  334.         mov    CR0,eax
  335.  
  336.         db 0eah
  337.         dw  To_MSDOS , Dos_CODE        ; reload CS:IP with real mode values
  338.  
  339. To_MSDOS:        ;-- remap IRQ int vectors ---
  340.         mov    bl,008h
  341.             mov    bh,070h
  342.         call    set_8259intvec
  343.  
  344.  
  345. assume ds:dos_code
  346.         mov ax,dos_code
  347.         mov ds,ax
  348.         mov ax,V86_STACK    ; Set up a bit of stack just to exit
  349.         mov ss,ax
  350.         mov esp,100h
  351.  
  352.         mov al,oirqMask         ; return origonal values of the IRQ mask bits
  353.         out 21h,al
  354.         mov al,oirqMask+1
  355.         out 0A1h,al
  356.  
  357.  
  358.         mov al,20h              ; Send PIC acknoledge
  359.         out 20h,al
  360.         out 0a0h,al
  361.  
  362.         in al,60h        ; do a keyboard read to get out of buffer
  363.                                 ; just in case program exits without so
  364.         cmp    ebp,'ERRA'
  365.         jnz normal_terminate
  366.             ; Print error message if need to
  367.                 push    dx
  368.                 mov    ax,3    ; Want to exit in text mode
  369.                 int    10h
  370.                 pop    dx
  371.                 mov    ah,9
  372.                 int    21h
  373.                 mov    dx,offset _exit_errror
  374.                 int    21h
  375.  
  376. normal_terminate:
  377.  
  378.     call free_XMS_memory        ; deallocated XMS
  379.  
  380. Exit_To_MSDOS:
  381.      mov    ax,4C00h        ; Finaly get back to MSDOS in real mode.
  382.         int    21h
  383. assume ds:dos_code
  384.  
  385. endp
  386.  
  387. ;---------------- finished exiting routine -------------------------
  388.  
  389. align 16
  390. NON_DPMI_initalize_start:  
  391.  
  392.  
  393. GDTR_value    dw    GDT_ends - 1
  394.         dd   offset GDT
  395. IDTR_value    dq 0000000007ffh
  396.  
  397. Label InterruptGATE_a dword
  398.           dw offset exception        ; Offset[15..0]
  399.     dw CODE32_Desc - GDT        ; Selector
  400. Label InterruptGATE_b dword
  401.         db 00000000b            ; 0,0,0,WordCnt[4..0]
  402.      s_ACCESS <1,00b,0,0Eh>        ; P,DPL,0,type = 386 interrupt Gate
  403.            dw 0                ; Offset[31..16]
  404.  
  405.  
  406. ;═════════════════ INITALIZATION ERROR MESSAGES ════════════════════════════
  407. _inV86_err db '  Unable to enter protected mode because another protected mode ',10,13
  408. db 'application is operating and does not support Dos Protected Mode Interface',10,13
  409. db 'specifiaction.',10,13,10
  410. db ' Disable the protected mode sofware and try again.',10,13,36
  411. mesg_TimeOut8042 db 'Time out error in the keyboard controller (8042) failing to ',10,13
  412. db ' respond on enabling the A20 gate.',10,13
  413. all_DPMI_err    db 'Encountered DPMI error: ',36
  414. pmiERr        db 'Switching to protecded mode.',10,13,36
  415. No_Mem_err    db 'Not Enough Base memory.  6000 bytes needed.',10,13,36
  416. erralc_mesg    db 'Can''t allocate descriptors.',10,13,36
  417. errset_mesg    db 'Can''t Set descriptors.',10,13,36
  418. dpmi_aloc_err    db 'Can''t allocate extended memory.',10,13,36
  419. dpmi_lock_err    db 'Unable to lock allocated memory.',10,13,36
  420. dpmi_free_err    db 'Unable to get free memory information.',10,13,36
  421. mesgA20_err     db 'ERROR:  Physical A20 gate test failed.',10,13,36
  422. xms_mesgA20_err    db 'ERROR:  XMS enabling the A20 gate.',10,13,36
  423. ;xms_vers_err    db 'Need XMS v3.0 or greater.',10,13,36
  424. xms_alloc_Err    db 'Can''t allocate XMS memory.',10,13,36
  425. xms_lock_err    db 'Can''t lock allocated XMS memory.',10,13,36
  426. wrongCPU_mseg    db ' CPU was found but sorry to say, a 386 or higher needed',10,13,36
  427. got_286_mesg    db '80286$'
  428. got_8086_mesg    db '8086$'
  429. CALL_DATA    Data_sruct <>
  430.  
  431.  
  432.     .8086
  433.  
  434. ;=========================================================================
  435. ;                    START  OF  THE  DOS  EXTENDER
  436. ;=========================================================================
  437. DosStart proc
  438.     mov    ax,DOS_CODE
  439.         mov    ds,ax
  440.  
  441. ;========= make sure we running on a 386 or higher =============
  442.  
  443. ;
  444. ;  Bits 12-15 are always set on the 8086
  445. ;
  446.  
  447.         pushf               ; save flags 
  448.         pop    bx            ; into BX
  449.         mov    ax,0fffh        ;clear bits 12-15
  450.         and    ax,bx
  451.         push    ax                      ; put new flags value onto stack
  452.         popf
  453.         pushf
  454.         pop    ax
  455.         and    ax,0f000h
  456.         cmp    ax,0f000h               ; if ax = 0f000h then it's a 8086
  457.         mov    dx,offset got_8086_mesg
  458.         jz Not_a_386
  459.  
  460. ;
  461. ;  Bits 12-15 are always clear on the 80286
  462. ;
  463.     or    bx,0f000h          ; try setting bits 12-15
  464.         push    bx
  465.         popf
  466.         pushf
  467.         pop    ax
  468.         and    ax,0f000h
  469.         mov    dx,offset got_286_mesg
  470.         jnz Have_a_386_and_above
  471.  
  472. Not_a_386:
  473.         mov    ah,9
  474.         int    21H
  475.         mov    dx,offset wrongCPU_mseg
  476.     jmp exit_error
  477.  
  478. .386p
  479.  
  480. Have_a_386_and_above:
  481.  
  482.         mov    ax,CODE32
  483.         mov    fs,ax
  484.         mov    fs:[psp_segment],ES        ; store psp_segment
  485.  
  486.  
  487.  
  488. ; DOS loads from bottom to top, thus the end location of this program
  489. ; up to 9ffffh is free memory.)
  490.  
  491. ; Get end of program address segment from the stack segment addrress
  492.     mov    bx,SP
  493.     shr    bx,4
  494.     inc     bx
  495.     mov    ax,SS
  496.     add    bx,ax
  497.     mov    FS:Base_Segment,bx    ; store this ending address
  498.  
  499.  
  500.  
  501. ; SET GLOBAL DISCRIPTOR TABLE BASE ADDRESSES
  502.  
  503.  
  504.     ; ===== Set the 32bit CODE & DATA descriptor base address ==========
  505.     mov eax,CODE32
  506.         shl eax,4
  507.         mov word ptr [CODE32_desc +2 ],ax
  508.         mov word ptr [DATA_desc +2   ],ax
  509.         shr eax,16
  510.         mov byte ptr [CODE32_desc +4 ],al
  511.         mov byte ptr [DATA_desc + 4  ],al
  512.  
  513.     ; ===== Set the DOS CODE & DATA descriptor base address ==========
  514.     mov eax,DOS_CODE
  515.         shl eax,4
  516.         mov word ptr [DOS_CODE_desc +2 ],ax
  517.         mov word ptr [DOS_DATA_desc +2   ],ax
  518.         shr eax,16
  519.         mov byte ptr [DOS_CODE_desc +4 ],al
  520.         mov byte ptr [DOS_DATA_desc + 4  ],al
  521.  
  522.     ; ===== Set the program segment prefix base address ==========
  523.         xor eax,eax
  524.     mov ax,fs:[psp_segment]
  525.         shl eax,4
  526.         mov word ptr [PSP_desc  +2 ],ax
  527.         shr eax,16
  528.         mov byte ptr [PSP_desc+ 4 ],al
  529.  
  530.     ; ===== Set the PROGRAM  ENVIRONMENT  base address ==========
  531.         xor eax,eax
  532.         mov ax,es:[2Ch]
  533.         shl eax,4
  534.         mov word ptr [ENVIRONMENT_desc  +2 ],ax
  535.         shr eax,16
  536.         mov byte ptr [ENVIRONMENT_desc+ 4 ],al
  537.  
  538.  
  539. ;------------------------- A 2 0     G A T E -------------------------------
  540. ;                        ENABLE THE A20 GATE
  541. ; If a XMS Driver is installed then use the Driver to enable the A20
  542. ; If it's done directly (with 8042) ,the XMS Driver will not have
  543. ; track of the A20 state and usualy ends up hanging the system.
  544. ;
  545. ;-----------------------------------------------------------------------------
  546.  
  547.         ; Look for XMS driver installation
  548.         mov ax,4300h
  549.         int 2fh
  550.         cmp al,80h
  551.         jnz No_XMS
  552.                              ; ELSE A XMS Driver is installed
  553.               push ES
  554.               mov  ax,4310h       ; get Driver entry point
  555.               int  2fh
  556.                mov  word ptr xms_Driver,bx
  557.                mov  word ptr xms_Driver+2,es
  558.                POP ES
  559.  
  560.         ; LOCAL ENABLE A20 GATE
  561.         mov  ah,05h
  562.                call xms_Driver
  563.                cmp ax,1
  564.                Jz A20_Controlled            ; OK to go protecded mode
  565.         mov dx,offset xms_mesgA20_err
  566.                 jmp Exit_Error
  567.  
  568.  
  569. ;-- Waiting procedures for enabling the A20 directly --
  570. Wait_until_status_bit0_is_1 proc
  571. st0_clear:  
  572.     xor cx,cx
  573.     in al,64h
  574.     test al,1
  575.     jnz st0_set
  576.     loop st0_clear
  577.     jmp A20_8042_timeout
  578. st0_set: ret
  579. endp
  580.  
  581. wait_until_status_bit1_is_0 proc
  582. st1set:    xor cx,cx
  583.     in al,64h
  584.     test al,2
  585.     jz st1_clear
  586.     loop st1set
  587.     jmp A20_8042_timeout
  588. st1_clear: ret
  589. endp
  590. ;----- jumps here if a time out error in enableing the A20 line ---
  591. A20_8042_timeout:
  592.         mov dx,offset mesg_TimeOut8042
  593.                 jmp Exit_Error
  594.  
  595.  
  596.  
  597. No_XMS:   ;------- Jumps here if no XMS driver is installed ---------------
  598.  
  599.  
  600. ;--- Must enable A20 directly through the 8042 ( keyboard controller)----
  601. ;     It does this by setting bit 1 of the 8042's output port wich is
  602. ;     inaccessable to the CPU Bus.
  603.  
  604.     cli
  605.     call wait_until_status_bit1_is_0
  606.     mov al,0adh                     ;send disable keyboard command
  607.     out 64h,al                ; viar 8042
  608.  
  609.     call wait_until_status_bit1_is_0
  610.     mov al,0d0h                      ;Send read 8042 output port  cmd
  611.     out 64h,al
  612.  
  613.     call wait_until_status_bit0_is_1
  614.     in al,60h                     ; read the output port and save it
  615.     push ax
  616.  
  617.     call wait_until_status_bit1_is_0
  618.     mov al,0d1h                      ; write output port cmd
  619.     out 64h,al
  620.  
  621.     call wait_until_status_bit1_is_0
  622.     pop ax                           ; write data to the output port
  623.     or al,2
  624. ;    and al,not 2
  625.     out 60h,al                       ; seting bit 1 > enables A20
  626.  
  627.     call wait_until_status_bit1_is_0
  628.      mov al,0aeh                      ;enable keyboard again
  629.     out 64h,al
  630.  
  631.     call wait_until_status_bit1_is_0    ; wait a bit more
  632.  
  633. ; Don't really know if need to wait so many times
  634.  
  635.  
  636. ;----- check if A20 really is enabled -------------
  637.     mov ax,0FFFFh
  638.     mov es,ax
  639.         mov ax,0
  640.         mov gs,ax
  641.     mov bl,gs:[0]       ;Compare location 00000000 to 100000h
  642.         cmp es:[10h],bl     ; Check if the same
  643.         jnz A20_enabled        ; if not equal then A20 *MUST* be on.
  644.  
  645.     not byte ptr es:[10h]        ; Cange byte at adreess 100000h.
  646.         mov bl,es:[10h]                   ; And compare again
  647.         mov al,gs:[00]
  648.     not byte ptr es:[10h]        ; Put back value
  649.         cmp al,bl              ; Now see if the same
  650.         jnz A20_enabled
  651.  
  652.  
  653.             ;--- EXIT on A20 error ----
  654.                 mov dx , offset mesgA20_err
  655.                 jmp Exit_Error    ; print error mesg and exit
  656.  
  657.  
  658. ; --- A20 is deffently enabled ---
  659. A20_enabled:
  660.  
  661.  
  662. A20_Controlled:    ; The A20 line should be enabled at this point
  663.  
  664.  
  665. ;-------------------------- A20 ACTIVE ------------------------------------
  666. ;-----------------------------------------------------------------------------
  667.  
  668. align 4
  669. init_P_mode_Stack:
  670.  
  671. ;════════════════════════════════════════════════════════════════════════
  672. ;══════════════════ SEE IF NEED TO USE DPMI OR NOT  ═════════════════════
  673. ;════════════════════════════════════════════════════════════════════════
  674.  
  675. ;     USE  DPMI TO ENTER  PROTECTED  MODE
  676.  
  677.  ; Obtain the Real Mode (acually V86) to Protected Mode Switch Entry Point
  678.         mov    ax,1687h
  679.         int    2Fh
  680.         and    ax,ax
  681.         jnz   No_DPMI                   ; ax = 0 if DPMI is installed
  682.     mov [DPMI_entry],di        ; save entry point
  683.     mov [DPMI_entry+2],es
  684.  
  685.         mov    fs:[Base_Segment],SS
  686.  
  687.         mov    ax,DOS_CODE       ;set Tempery Protected Mode stack area
  688.         mov    ss,ax
  689.         mov    sp,offset init_P_mode_Stack
  690.  
  691.  
  692.     ; Use memory for the DPMI OS private data area
  693.         mov    es,fs:[Base_Segment]
  694.      add    fs:Base_Segment,si
  695.         cmp    fs:Base_Segment,09900h    ; See if enough base memory
  696.      mov dx,offset No_Mem_err
  697.         jae Exit_Error
  698.  
  699.      call Allocate_Base        ; Set descriptor base to here
  700.  
  701.     mov    eax,fs:[xms_usage]
  702.     mov    xms_usage_tmp,eax
  703.  
  704.         mov    gs,fs:[psp_segment]         ;Save environment pointer
  705.         push    word ptr gs:[2Ch]
  706.  
  707.  
  708.         ;  Call the V86 To Protected Mode Switch Entry Point
  709.         mov    ax,1        ; use 32 DPMI ( big stack )
  710.         call    dword ptr [DPMI_entry]
  711.     mov     dx,offset pmiERr
  712.         Jc Exit_Error
  713.  
  714.  
  715.     ;************** NOW IN DPMI PROTECTED MODE ******************
  716.                ; as a 16 bit but want 32 bit
  717.  
  718.         push ds        ; load ES to data segment
  719.         pop es
  720.  
  721.         cmp    xms_usage_tmp,0
  722.         jz No_DPMI_MEMORY
  723.  
  724.         ; Get Free memory info
  725.         mov    ax,0500h
  726.         mov     edi,offset Call_data
  727.         int    31h
  728.         mov    word ptr Call_data.c_edx,offset dpmi_free_err
  729.     jc    print_error
  730.  
  731.         mov    eax,dword ptr Call_data+00h    ; first get total avalible.
  732.  
  733.         mov    ebx,dword ptr Call_data+08h    ; get lockable size (pages)
  734.         cmp    ebx,-1              ; if 0ffffffffh then has invalid info
  735.         jz _lesslck        
  736.         shl    ebx,12            ; convert limit  pages into Bytes
  737.  
  738.     cmp    eax,ebx        ; get the lowest of the two
  739.         jb _lesslck
  740.     mov    eax,ebx
  741. _lesslck:
  742.     ; Only Allocate memory defined in xms_usage
  743.         cmp    eax,xms_usage_tmp
  744.         jbe LvDmpiSize
  745.         mov    eax,xms_usage_tmp
  746. LvDmpiSize:    mov    xms_usage_tmp,eax
  747.  
  748.     mov    ebx,eax
  749.         shr    ebx,12
  750.         dec    ebx
  751.         mov     word ptr [XMS_desc+0],bx    ; Set xms descriptor Limit
  752.     shr    ebx,16
  753.         and    bl,0fh
  754.         or     byte ptr [XMS_desc+6],bl
  755.  
  756.         ; Allocate memory Block
  757.         mov    cx,ax            ; Olny allocate the Lockable memory
  758.         shr    eax,16
  759.         mov    bx,ax
  760.         mov    ax,0501h
  761.         int    31h
  762.         mov    word ptr Call_data.c_edx,offset dpmi_aloc_err
  763.     jc    print_error
  764.                     ; Returns BX:CX with the linear address
  765.     mov    word ptr [XMS_Desc+2],cx    ; Set Desciptor base
  766.     mov    byte ptr [XMS_Desc+4],bl
  767.         mov    byte ptr [XMS_desc+7],bh
  768.         mov    _tmpL_xms_base,CX        ; store base address
  769.         mov    _tmpH_xms_base,BX
  770.  
  771. No_DPMI_MEMORY:
  772. ; Set DPL for all descriptors to CPL
  773.         mov si,offset GDT+8 + 5
  774. setDPL:
  775.     or    byte ptr [si],01100000b
  776.         add    si,8
  777.         cmp    si, 11*8 +5
  778.         jbe setDPL
  779.  
  780. ; Allocate 11 descriptors
  781.     mov    AX,0000h
  782.     mov    CX,11
  783.         int    31h
  784.         mov    word ptr Call_data.c_edx,offset erralc_mesg
  785.         jc    print_error
  786.  
  787.  
  788.        mov    DPMI_Selector,ax
  789.  
  790.  
  791.     ;---- Set Descriptors -----
  792.     xor    esi,esi
  793. set_Descr:
  794.         mov    ax,000Ch               ; Set Descriptor
  795.         mov    bx,DPMI_Selector
  796.         push    bx
  797.         mov    edi,offset GDT +8
  798.         mov    edx,esi         
  799.         shl    edx,3
  800.         add    edi,edx
  801.         int    31h
  802.         mov    word ptr Call_data.c_edx,offset errset_mesg
  803.     jc    print_error
  804.  
  805.         mov    ax,0003h        ; Get Next Selector incremental value
  806.         int    31h
  807.         add    DPMI_Selector,ax
  808.         inc    esi
  809.     cmp    esi,11        ; must set 11 descriptors
  810.         jb set_Descr
  811.  
  812.  
  813.         pop DS        ; Pop all the selector values that were pushed.
  814.  
  815. ASSUME  DS:CODE32
  816.         MOV DATA_sel,DS
  817.  
  818.     POP  CODE32_sel
  819.         POP  ENVIRONMENT_sel
  820.     POP  PSP_sel
  821.     POP  DOS_DATA_sel
  822.     POP  DOS_CODE_sel
  823.     POP  VIDEO_sel
  824.     POP  BASE_sel
  825.     POP  XMS_sel
  826.     POP  FLAT_CODE32_sel
  827.     POP  FLAT_DATA_sel
  828.  
  829.         mov    es,[PSP_Sel]        ; Restore environment pointer
  830.         pop    word ptr es:[02Ch]
  831.  
  832.  
  833.  
  834.  
  835.  
  836.         mov es,DOS_data_sel
  837. ASSUME    ES:DOS_CODE
  838.  
  839.  
  840.     mov    eax,ES:xms_usage_tmp
  841.     mov    xms_usage,eax          ; return store the acual amout allocted
  842.  
  843.     mov    eax,dword ptr ES:_tmpL_xms_base
  844.     mov    xms_base,eax        ; store the base address
  845.  
  846.  
  847.         ; Get the base interrupt values of the PIC's
  848.         mov    ax,0400h
  849.         int    31h
  850.         mov    ES:PIC1_base,dh
  851.         mov    ES:PIC2_base,dl
  852.  
  853.         cli
  854.  
  855.         mov ax,0205h
  856.         mov cx,CODE32_sel
  857.  
  858.         ; set int vector
  859. setdmpiInts macro in
  860.         mov edx,offset irq&in
  861.         int 31h
  862.         inc bl
  863. endm
  864.  
  865.         mov bl,es:PIC1_base
  866.     setdmpiInts 0
  867. x=0
  868. rept 8
  869. ;    setdmpiInts %x
  870. x=x+1
  871. endm
  872.         mov bl,es:PIC2_base
  873. x=8
  874. rept 8
  875. ;    setdmpiInts %x
  876. x=x+1
  877. endm
  878.  
  879.     mov    edx,offset DPMI_EmulateRealInterupt
  880.         mov    bl,20h
  881.         int    31h
  882.  
  883.         mov es:DPMI_entry,offset Start32
  884.         mov ax,CODE32_sel
  885.         mov es:DPMI_entry+2,ax
  886.  
  887.  
  888.     ;-----  Jump to 32bit mode through CODE 32 descriptor -----
  889.         jmp dword ptr es:DPMI_entry
  890.  
  891.  
  892. ASSUME DS:DOS_CODE
  893.  
  894. print_error:
  895.         push    Call_data.c_edx
  896.         mov    Call_data.c_edx,offset all_DPMI_err
  897.         call print
  898.         pop    Call_data.c_edx
  899.         call print
  900. dpmi_exit:
  901.         mov ah,4ch
  902.         int 21h
  903.  
  904. print proc  near
  905.         mov    Call_data.c_eax,0900h
  906.         mov    Call_data.c_DS,DOS_CODE
  907.         mov    ax,0300h        ; sim real int
  908.         mov    bl,21h
  909.         mov     bh,0
  910.         mov    edi,offset call_data
  911.         xor    cx,cx
  912.     int    31h
  913.     ret
  914. endp
  915. ;==================================================
  916. ;    FINISHED SETTING PROTECTED MODE FOR DPMI
  917. ;===================================================
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924. No_DPMI:
  925. ;════════════════════════════════════════════════════════════════════════════
  926. ; Jups here if the operating system dos not support DPMI.
  927. ; Must enter protected mode directly.
  928. ;
  929. ;════════════════════════════════════════════════════════════════════════════
  930. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  931.  
  932.     ; See if in V86 mode Because if so we can't go any further
  933.  
  934.         smsw ax                ; Not allowed to use,  MOV EAX,CR0
  935.         test al,1
  936.          mov dx,offset _inV86_err
  937.          jnz Exit_Error
  938.  
  939.        ;    See if enough base memory for TSS, IDT that get build below.
  940. ;        cmp fs:Base_Segment,09A00h
  941. ;        ja no_mem
  942.  
  943.     cmp xms_driver,00       ; Can't use XMS sevices if got no XMS dirver.
  944.         jz No_XMS_MEMORY
  945.  
  946. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  947. ; Use the XMS services to allocate extended memoey
  948.             cmp    fs:xms_usage,0    ; if no memory is requested then
  949.             jz Extended_mem_set    ; don't bother allocating memory
  950.  
  951.                ; Must have XMS V3.0 to work
  952. ;               mov    ah,00        ; Get XMS Version number
  953. ;               call    XMS_Driver
  954. ;               cmp    ah,3
  955. ;              mov dx,offset xms_vers_err
  956. ;              jnae Exit_Error
  957.  
  958.  
  959.                  ; QUERY FREE EXTENDED MEMORY
  960.                MOV    AH,08h
  961.                call    XMS_Driver         ; returns eax with KB free
  962.                and    eax,0ffffh
  963.                and    al,0FCh        ; want page granular
  964.                shl    eax,10            ; put KB -> bytes
  965.  
  966.             ;Only Allocate memory defined in xms_usage
  967.                 cmp    eax,fs:xms_usage
  968.                 jbe LvXmsSize
  969.         mov    eax,fs:xms_usage
  970. LvXmsSize:    mov    fs:xms_usage,eax
  971.  
  972.                 mov    edx,eax
  973.                 shr    edx,10
  974.                and    dl,0FCh            ; want page granular
  975.  
  976.                 call    set_xms_limit        ; set limit to eax
  977.  
  978.                 ; ALLOCATE ANY EXTENDED MEMORY BLOCK ( size in eDX )
  979.          mov    ah,09h
  980.                 call    XMS_Driver
  981.                 cmp ax,1
  982.                 jz xms_alloc_OK
  983.          mov dx,offset xms_alloc_err
  984.                  jmp Exit_Error
  985. xms_alloc_OK:
  986.             mov    XMS_handle,dx        ; Save XMS block handle
  987.  
  988.  
  989.                 ; LOCK THE ALLOCATED EXTENDED MEMORY BLOCK
  990.         mov    ah,0ch
  991.                 call    XMS_Driver
  992.                 cmp ax,1
  993.                 jz XMS_locked_OK
  994.          mov dx,offset xms_lock_err
  995.                 jmp Exit_Error
  996. XMS_locked_OK:
  997.  
  998.           ; DX:BX has "PHYSICAL"  address.
  999.  
  1000.             mov    word ptr [XMS_Desc+2],bx    ;set xms descriptor
  1001.         mov    byte ptr [XMS_Desc+4],dl    ; Base.
  1002.         mov    byte ptr [XMS_Desc+7],dh
  1003.         mov    word ptr fs:xms_base,BX        ; set base of block
  1004.         mov    word ptr fs:xms_base+2,DX
  1005.  
  1006.         jmp Extended_mem_set
  1007.  
  1008.  
  1009. No_XMS_MEMORY:
  1010. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1011. ; ALLOCATE EVERY SINGLE BYTE OF EXTENDED MEMORY IF NO XMS DRIVER IS INSTALLED
  1012.  
  1013.             ; GET EXTENDED MEMORY SIZE FROM CMOS RAM -
  1014.                 mov al,24   ; get MSB
  1015.         out 70h,al
  1016.                 in  al,71h
  1017.                 shl ax,8
  1018.                 mov al,23   ; get LSB
  1019.         out 70h,al
  1020.                 in  al,71h
  1021.  
  1022.                 and    eax,0ffffh
  1023.                 shl    eax,10             ; Kbytes -> bytes
  1024.                mov    fs:xms_usage,eax
  1025.                 call    set_xms_limit        ; set limit to eax
  1026.         mov    fs:xms_base,100000h    ;Always start block at 1MB
  1027. Extended_mem_set:
  1028. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1029.  
  1030. ; Extended memory is allocated at this point
  1031.  
  1032.     CLI
  1033.         in al,21h
  1034.         mov oirqMask,al
  1035.         in al,0a1h
  1036.         mov oirqMask+1,al
  1037.  
  1038.         ;-- remap IRQ int vectors ---
  1039.     mov    bl,Pic_Base
  1040.         mov    bh,Pic_Base+8
  1041.     call    set_8259intvec
  1042.  
  1043.        mov al,oirqMask
  1044.        out 21h,al
  1045.        mov al,oirqMask+1
  1046.        out 0A1h,al
  1047.  
  1048.  
  1049. ;    THE INTERRUPT DESCRIPTOR TABLE
  1050.  
  1051. ; Use memory for the Interrupt Descriptor Table and the TSS
  1052.  
  1053.         mov    ax,fs:Base_Segment        ; Set IDT Reg base
  1054.         mov    es,ax
  1055.         and    eax,0ffffh
  1056.         shl    eax,4
  1057.         mov    dword ptr IDTR_value+2,eax
  1058.         mov    fs:[IDT_base],eax
  1059.  
  1060.         xor    eax,eax            ; Clear all the new memory
  1061.         xor    edi,edi
  1062.         mov    ecx,(8*256 +TSS_Ends+16)/4
  1063.     cld
  1064.         rep    stosd
  1065.  
  1066.  
  1067.         ;--- Build the Interrupt Descriptor Table ---
  1068.     mov    eax,InterruptGATE_a
  1069.     mov    edx,InterruptGATE_B
  1070.         xor    cl,cl
  1071.         xor    si,si
  1072. @MakeIDT:
  1073.     mov    es:[si],eax        ; Put into memory
  1074.     mov    es:[si+4],edx        ; Put into memory
  1075.         add    si,8
  1076.     dec    cl
  1077.     jnz @MakeIDT
  1078.  
  1079.  
  1080.         ;---- Set interrupt vector 31h  ------
  1081.         mov    word ptr es:[31h*8],offset MyDPMI_services
  1082.  
  1083.         ;---- Set interrupt vector 21h  ------
  1084.     mov    word ptr es:[21h*8],offset Go_REAL_MODE
  1085.     mov    word ptr es:[21h*8+2], Dos_Code_desc - GDT
  1086.  
  1087.     ; ---- Set the 16 hardware and 16 exception interrupt handlers  --------
  1088. setexecp macro n
  1089.     mov    word ptr es:[n*8],offset _386exception_&n
  1090.            mov    word ptr es:[(Pic_Base+n)*8],offset firstIRQ&n
  1091. endm
  1092. x=0
  1093. rept 16
  1094. setexecp %x
  1095. x=x+1
  1096. endm    
  1097.  
  1098.     ; ---- Set general protection exception handler interrupt --------
  1099.     mov    word ptr es:[13*8],offset General_Exeption_Handler
  1100.  
  1101.     ; ---- Set real mode interrupt emulation handler interrupt --------
  1102.     mov    word ptr es:[20h*8],offset My_EmulateRealInterupt
  1103.  
  1104.  
  1105.     ;-- Build the Task State Segment  --
  1106.     add    fs:Base_Segment,80h
  1107.         mov    es,fs:Base_Segment
  1108.  
  1109.  
  1110.         xor eax,eax    ; Get TSS base address
  1111.         mov ax,es
  1112.         shl eax,4
  1113.                                         
  1114.         mov fs:tss_Level0ESP,eax        ;Save address of level0 ESP TSS field
  1115.         add fs:tss_Level0ESP,offset tss_esp0    ;Need to use it latter
  1116.  
  1117.     mov    MyMain_TSS_Desc+2,ax    ; Load Base address of TSS descriptor
  1118.         shr    eax,16
  1119.     mov    byte ptr MyMain_TSS_Desc+4,al
  1120.  
  1121.  
  1122.  
  1123. ;Load important TSS fields
  1124. ;
  1125. ;    NOTE: The level0 stack field is set when real mode interrupt emulation 
  1126. ;    is called
  1127.     mov    es:tss_iobase, 068h
  1128.     mov    es:tss_ioend,11111111b
  1129.  
  1130. ; TSS is now built . Time to set the base descriptor base address just
  1131. ; after the TSS and IDT are located.
  1132.  
  1133.     add    fs:Base_Segment,(TSS_Ends+15)/16    ;add to Base_Segment
  1134.     call    Allocate_Base
  1135.  
  1136.     CLI        ; Can't have interrupts anymore
  1137.  
  1138. ;    Load the Interrupt descriptor table register
  1139.             lidt    qword ptr IDTR_value
  1140.  
  1141. ;    Load the Global descriptor table register
  1142.         mov EAX,DOS_CODE
  1143.                 shl EAX,4
  1144.                 add dword ptr  GDTR_value+2 , EAX
  1145.                 lgdt qword ptr GDTR_value
  1146.  
  1147. ; Enter Protected Mode
  1148.     mov    eax,CR0
  1149.     or    al,1            ; Set PE bit of CR0
  1150.     mov    CR0,eax
  1151.  
  1152.  
  1153.         db 0EAh            ; Jump to 32bit mode through CODE 32 descr
  1154.         dw offset Setup_Pmode , CODE32_Desc - GDT
  1155. ;--------------------------------------------------------------------------
  1156. ;         END OF PROTECTED MODE INITALIZATION
  1157. ;--------------------------------------------------------------------------
  1158.  
  1159. ;----------------------------------------------------------------------------
  1160. ;─────────────────────  INTERNAL ROUTINES ───────────────────────────────────
  1161. ;----------------------------------------------------------------------------
  1162. assume ds:dos_code
  1163. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1164. set_xms_limit proc
  1165.                     ; Set the xms descriptor limit.
  1166.             shr    eax,12
  1167.             dec    eax
  1168.         mov    word ptr [XMS_Desc+0],ax    ; set limit [0..15]
  1169.         shr    eax,16
  1170.             or     byte ptr [XMS_desc+6],al        ; limit [16..19]
  1171.         ret
  1172. endp
  1173.  
  1174.  
  1175. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1176. Allocate_Base    proc
  1177.         mov    ax,fs:Base_Segment    ; Set BASE data descriptor to this
  1178.         and    eax,0ffffh
  1179.         shl    eax,4
  1180.         mov    word ptr [Base_Desc +2 ],ax
  1181.         shr    eax,16
  1182.         mov    byte ptr [Base_Desc +4 ],al
  1183.     ret
  1184. ENDP
  1185. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191. dosstart endp
  1192. DOS_CODE ENDS
  1193.  
  1194.  
  1195. CODE32    SEGMENT PARA PUBLIC  USE32
  1196. assume    DS:CODE32 , CS:CODE32 , ES:CODE32    ; Flat memory model segment
  1197.  
  1198. align 4
  1199.     CODE32_sel    dw CODE32_desc        - gdt
  1200. public    CODE32_sel
  1201.     DATA_sel    dw data_desc        - gdt
  1202. public    DATA_sel
  1203.     VIDEO_sel    dw video_desc        - gdt
  1204. public    VIDEO_sel
  1205.     FLAT_DATA_sel    dw FLAT_DATA_desc    - gdt
  1206. public    FLAT_DATA_sel
  1207.     FLAT_CODE32_sel    dw FLAT_CODE32_desc    - gdt
  1208. public    FLAT_CODE32_sel
  1209.     XMS_sel        dw XMS_desc        - gdt
  1210. public    XMS_sel
  1211.     BASE_sel    dw BASE_desc        - gdt
  1212. public    BASE_sel
  1213.     PSP_sel        dw PSP_desc        - gdt
  1214. public    PSP_sel
  1215.     ENVIRONMENT_sel    dw ENVIRONMENT_desc    - gdt
  1216. public    ENVIRONMENT_sel
  1217.  
  1218. align 4
  1219.     Real_GS        dd 0
  1220. public    Real_GS
  1221.     Real_FS        dd 0
  1222. public    Real_FS
  1223.     Real_DS        dd 0
  1224. public    Real_DS
  1225.     Real_ES        dd 0
  1226. public    Real_ES
  1227.     Real_SS        dd V86_Stack        ; Setup initial V86 stack
  1228. public    Real_SS
  1229.     Real_SP    dd V86_stack_size
  1230. public    Real_SP
  1231.  
  1232.  
  1233.  
  1234.  
  1235. global    xms_usage    :dword
  1236. global    xms_base    :dword
  1237. global    Base_Segment    :word
  1238. global    PSP_segment    :word
  1239.  
  1240. global  START32    :near
  1241. global    IRQ0    :near
  1242. global    IRQ1    :near
  1243. global    IRQ2    :near
  1244. global    IRQ3    :near
  1245. global    IRQ4    :near
  1246. global    IRQ5    :near
  1247. global    IRQ6    :near
  1248. global    IRQ7    :near
  1249. global    IRQ8    :near
  1250. global    IRQ9     :near
  1251. global    IRQ10    :near
  1252. global    IRQ11    :near
  1253. global    IRQ12    :near
  1254. global    IRQ13    :near
  1255. global    IRQ14    :near
  1256. global    IRQ15    :near
  1257.  
  1258.  
  1259.  
  1260. align 4
  1261. tss_Level0ESP    dd 0
  1262. V86_Lv0_ESPSave    dd 10h dup (0)     ; TSS level 0 ESP save for V86 calls.
  1263. V86_Lv0_SSSave    dw 10h dup (0)     ; TSS level 0 SS save for V86 calls.
  1264. IDT_base    dd 0
  1265. _tmp0_        dd 0
  1266. _tmp1_        dd 0
  1267. _tmp2_        dd 0
  1268. tmp_Real_Flags    dw 0
  1269. V86_irq_Count    db 0
  1270.  
  1271. DOS_CODE_sel    dw DOS_CODE_Desc - GDT
  1272. DOS_DATA_sel    dw DOS_DATA_Desc - GDT
  1273.  
  1274.  
  1275. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1276. Setup_Pmode:           ; first 32bit protected mode point
  1277.        ;!! MUST LOAD SEGMENT REGISTERS VALID SELECTORS !!
  1278.         mov     ax,cs:[Data_SEL]
  1279.     mov    es,ax
  1280.     mov    fs,ax
  1281.     mov    gs,ax
  1282.     mov    ds,ax
  1283.  
  1284.         mov    ax,MyMain_TSS_Desc - GDT    ; Set TR to any valid TSS
  1285.         ltr    ax
  1286.  
  1287.     mov    ss,[flat_data_sel]     ; Setup initial Protected mode stack
  1288.     mov    esp,seg init_P_mode_Stack
  1289.         shl    esp,4
  1290.     add    esp,offset init_P_mode_Stack
  1291.  
  1292.     db 0eah            ; jump to start of main program
  1293.         dd offset start32 , CODE32_desc - gdt
  1294.  
  1295. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1296. ;************** EXCEPTION HANDLERS ... *********************
  1297. Exception:
  1298.         mov    ax,DATA_desc - gdt
  1299.     mov    ds,ax
  1300.     mov    es,Flat_data_sel
  1301.     mov    ss,DATA_sel
  1302.     mov    fs,FLAT_data_sel
  1303.     mov    gs,FLAT_data_sel
  1304.     mov    esp,100h
  1305.         mov    dx,offset unknown_int_exit_mesg
  1306.         mov    ebp,'ERRA'        ; Exit with error code
  1307.         int    21h
  1308.  
  1309. getexeec macro n
  1310. _386exception_&n&:
  1311.     mov dx,offset e_&n
  1312.         jmp All_exceptions
  1313. endm
  1314. x=0
  1315. rept 16
  1316. getexeec %x
  1317. x=x+1
  1318. endm
  1319.  
  1320. ;═══════════════════════════════════════════════════════════════════════════
  1321. All_exceptions:
  1322. ;    jmp _Pmode_exit_error
  1323.  
  1324. ;∙·∙·∙·∙·∙·∙·∙·∙∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1325. _Pmode_exit_error:
  1326.         cli
  1327.     mov    ss,CS:[DATA_SEL]        ; set up some stack to exit
  1328.     mov    esp,offset CODE32_end_of + 100h
  1329.     mov    ebp,'ERRA'
  1330.         int    21h            ; Exit with error
  1331.  
  1332. set1STirqm macro nt
  1333. local not_v86_irq_
  1334. firstIRQ&nt:
  1335.        push offset irq&nt
  1336.         jmp check_HardwareINT
  1337. endm
  1338.  
  1339. x = 0
  1340. rept 16
  1341.         set1STirqm %x
  1342. x=x+1
  1343. endm
  1344.  
  1345. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1346. ;═══════════════════════════════════════════════════════════════════════════
  1347. check_HardwareINT proc near
  1348.         test dword ptr [esp+3*4],020000h
  1349.         jz not_v86_irq                         ; jump if IRQ was from P.mode
  1350.  
  1351.         push    eax                            ; IRQ was from V86 mode.
  1352.      mov    ds,cs:DATA_sel
  1353.         mov    eax,[esp+5*4]         ; Put new V86 stack pointer
  1354.         mov    [Real_SP],eax
  1355.         mov    eax,[esp+6*4]        ; Put new V86 stack segment
  1356.         mov    [real_SS],eax          ; we Don't care about  ES,DS,FS & GS
  1357.         pop    eax
  1358.  
  1359.  
  1360.         mov    fs,[esp+10*4]        ; return segment reg selectors
  1361.         mov    ds,[esp+11*4]        ; as they were before entering V86
  1362.         mov    gs,[esp+12*4]
  1363.         mov    es,[esp+13*4]
  1364. not_v86_irq:
  1365.     ret                ; Go to IRQ handler
  1366. endp
  1367.  
  1368.  
  1369.  
  1370. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1371. ;═══════════════════════════════════════════════════════════════════════════
  1372. ;------- The General Exception Handler ( Int 13 ) ---------------
  1373. ;═══════════════════════════════════════════════════════════════════════════
  1374. General_Exeption_Handler:
  1375.  
  1376.         test dword ptr [esp+4*3],0020000h    ;    Test VM bit
  1377.     jnz V86_Monitor
  1378.         mov dx,offset e_13    ; if exception from p.mode then terminate.
  1379.         jmp All_Exceptions
  1380.  
  1381.  
  1382.  
  1383.      ;*****************************************
  1384. ;*********  Virtual 8086 exception handler *********
  1385.      ;*****************************************
  1386. V86_Monitor proc
  1387.         add    esp,4    ; delete the undocumented pushed error code ??
  1388.         pushad
  1389.     mov    fs,CS:Flat_DATA_SEL
  1390.  
  1391.      ;;; Find what instruction caused the exception ;;;;
  1392.     movzx ebx,word ptr [esp+36]    ; Get CS from stack
  1393.     shl ebx,4
  1394.     add ebx,[esp+32]        ; Get EIP form stack
  1395.     inc dword ptr [esp+32]
  1396.     mov dl,fs:[ebx]            ; Get opcode
  1397.     mov al,3
  1398.     cmp dl,0cch            ; see if INT 3 Breakpoint
  1399.     je short DO_v86int        ; if so do it's int
  1400.         mov al,4
  1401.     cmp dl,0ceh            ; See if INTO
  1402.     je short Do_v86int        ; if so do it's int
  1403.     cmp dl,0cdh            ; see if INT n
  1404.     jne V86exc            ; if not then exception
  1405.     inc dword ptr [esp+32]        ; It must be a INT n instruction
  1406.     mov al,fs:[ebx+1]        ; get INT n number
  1407.  
  1408.     cmp al,0FFh            ; If int 0ffh and Then
  1409.     jz Exit_V86            ; return to main Program
  1410.  
  1411.         cmp al,15h
  1412.         jnz NoXmsToCopy
  1413.  
  1414.     cmp byte ptr ss:[esp+7*4+1],87h        ; Detect if v86 application
  1415.         jz Emulate_XMS_COPY            ; wants to copy extended mem
  1416.                                                 ; i.e ah = 87h
  1417.  
  1418. NoXmsToCopy:
  1419.  
  1420. public DO_v86int
  1421.  
  1422.  ;****; Emulate V86 interrupt ;****;
  1423. DO_v86int:                ; Do interrupt "AL" for V86 task
  1424.     movzx ebx,al
  1425.     shl ebx,2            ; Get 8086 Int Vector
  1426.         movzx edx,word ptr [esp+(8+4)*4]    ; Get SS stored on stack
  1427.         shl edx,4
  1428.         sub word ptr [esp+(8+3)*4],6        ; Sub ESP stored on stack by 6
  1429.         add edx,[esp+(8+3)*4]        ; edx = Phyical Address of V86 stack
  1430.     mov ax,[esp+(8+2)*4]    ;Put FLAGS from Prev.0 Stack to V86 stack
  1431.     mov fs:[edx+4],ax
  1432.     mov ax,[esp+(8+1)*4]        ;Put CS from Prev.0 Stack to V86 stack
  1433.     mov fs:[edx+2],ax
  1434.     mov ax,[esp+(8+0)*4]        ;Put IP from Prev.0 Stack to V86 stack
  1435.     mov fs:[edx],ax
  1436.     mov eax,fs:[ebx]        ; Get real mode int vector (CS:IP)
  1437.     mov [esp+(8+0)*4],ax        ; Store it on prev. 0 Stack
  1438.     shr eax,16
  1439.     mov [esp+(8+1)*4],ax
  1440. ret86:    and word ptr [esp+(8+2)*4],0fcffh ; Clear DF & IF flags on prev. 0 Stack
  1441.         popad
  1442.         iretd                           ; Return to V86 mode
  1443.  
  1444. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1445. ; Stop emulating V86 mode interrupts and return to main program.
  1446.   ; Jumps here when v86 code causes an exception from the Int 0FFh instuction
  1447. Exit_V86:
  1448.     mov    DS,CS:DATA_SEL        ; Need to use data segment
  1449.  
  1450.         popad
  1451.         mov    [_tmp0_],eax
  1452.         mov    [_tmp1_],ebx
  1453.         mov    [_tmp2_],ecx
  1454.                            ; Pop off all the stuff pushed from V86 exception.
  1455.         add    esp,8            ; ignore EIP & CS
  1456.         pop    eax            ; Get Efplags
  1457.         and    eax,NOT 23000h        ; Clear VM bit
  1458.         mov    [esp+13*4],eax        ; Put onto stack
  1459.         pop    [Real_SP]
  1460.         pop    [Real_SS]
  1461.      pop    [Real_ES]
  1462.     pop    [Real_DS]
  1463.     pop    [Real_FS]
  1464.     pop    [Real_GS]
  1465.  
  1466.  
  1467. ;Must return the TSS Level 0 ESP to the previous V86 call's Level 0 ESP value.
  1468.         dec    V86_irq_Count
  1469.         movzx    eax,V86_irq_Count
  1470.         sub    al,1
  1471.         jl   jH98_V86        ; Only do it if a V86 call inside a call.
  1472.           mov    bx,[V86_Lv0_SSSave +EAX*2]     ; Get previous TSS Lv0 SS
  1473.           mov    eax,[V86_Lv0_ESPSave+EAX*4]     ; Get previous TSS Lv0 ESP
  1474.           mov    ecx,[tss_Level0ESP]             ; Get address of TSS Lv0 ESP
  1475.           mov    fs:[ecx],eax                 ; Load ESP.
  1476.           mov    fs:[ecx+4],bx                 ; Load SS.
  1477. jH98_V86:
  1478.  
  1479.         mov    eax,[_tmp0_]        ;Return temperaly saved registers
  1480.         mov    ebx,[_tmp1_]
  1481.         mov    ecx,[_tmp2_]
  1482.  
  1483.     pop     fs ds         ; pop seg reg from the entering V86
  1484.     pop    gs es        ; call; see  My_EmulateRealInterupt proc
  1485.  
  1486.         iretd            ; Return to main program and continue.
  1487.  
  1488.  
  1489. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1490. ;═══════════════════════════════════════════════════════════════════════════
  1491. ; Emulate the SYSTEM BIOS - COPY EXTENDED MEMORY Srevice for V86 application
  1492. ; INT 15  & AH = 87h
  1493. ;═══════════════════════════════════════════════════════════════════════════
  1494.  
  1495. Emulate_XMS_COPY:        ; A20 gate always seems to be on ?
  1496.  
  1497.  
  1498.     mov    ecx,[esp+(6)*4]    ; Get Number of words to copy
  1499.         and    ecx,0ffffh
  1500.     cmp    cx,8000h
  1501.         ja _error_1587
  1502.     shr    ecx,1
  1503.  
  1504.             ; CALCULATE THE LOCATION OF THE GDT.
  1505.         xor    eax,eax
  1506.         mov    ax,[esp+(8+5)*4]        ; Get ES
  1507.         shl    eax,4
  1508.         movzx    ebx,word ptr [esp+(1)*4]    ; Get SI
  1509.         add     eax,ebx                ;EAX has location of GDT
  1510.  
  1511.         mov     esi,fs:[eax+7h+10h]
  1512.         shl     esi,24
  1513.         mov    edx,fs:[eax+2h+10h]    ; Get 32bit Source address
  1514.         and    edx,0ffffffh
  1515.         add     esi,edx
  1516.  
  1517.         mov     edi,fs:[eax+7h+18h]
  1518.         shl     edi,24
  1519.         mov    edx,fs:[eax+2h+18h]    ; Get 32bit Destination address
  1520.         and    edx,0ffffffh
  1521.         add     edi,edx
  1522.  
  1523.     push fs
  1524.         pop es
  1525.     cld
  1526.         rep    movs dword ptr es:[edi],es:[esi]    ; do the transfer
  1527.  
  1528.         mov    byte ptr [esp+(7*4)+1],00        ;return AH = 0
  1529.  
  1530.     and    byte ptr [esp+(8+2)*4],NOT 01    ; Clear Carry  flag on prev. 0 Stack
  1531.  
  1532.         jmp ret86
  1533.  
  1534. _error_1587:
  1535.     or byte ptr [esp+(8+2)*4],01    ; Set Carry  flag on prev. 0 Stack
  1536.         mov    byte ptr [esp+(7*4)+1],03        ;return AH
  1537.     jmp ret86
  1538. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1539.  
  1540.  
  1541. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1542. ;═══════════════════════════════════════════════════════════════════════════
  1543. V86exc:
  1544.         mov    dx,offset _V86_illigal_err
  1545.         jmp    _Pmode_exit_error
  1546.  
  1547. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1548.  
  1549. ;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
  1550.  
  1551.  
  1552. endp
  1553.  
  1554.  
  1555.  
  1556. ;**********************************
  1557. MyDPMI_services:;*********************
  1558. ;**********************************
  1559.         cmp    ax,0205h
  1560.         jz SetPmodeintVector
  1561.         cmp    ax,0204h
  1562.         jz GetPmodeintVector
  1563.         cmp    ax,0400h
  1564.         jz GetVersion
  1565.             iretd
  1566.  
  1567. SetPmodeintVector:
  1568.            push edi ebx fs ds
  1569.        mov  ax,data_desc - gdt
  1570.            mov  ds,ax
  1571.            mov fs,[flat_DATA_sel]
  1572.            movzx ebx,bl
  1573.            mov edi,ebx
  1574.            sub    edi,Pic_Base    ; No allowed to set the hardware int vectors
  1575.            cmp    edi,15
  1576.            jbe Set_irq_vec
  1577.        mov    edi,[idt_base]
  1578.            mov    fs:[ebx*8+edi],dx    ; offset 0..15
  1579.            SHR    EDX,16
  1580.            mov    fs:[ebx*8+edi+6],dx    ; offset 16..32
  1581.            mov    fs:[ebx*8+edi+2],cx    ; Code Selector
  1582.        pop ds fs ebx edi
  1583.          iretd
  1584.  
  1585. GetPmodeintVector:
  1586.            push edi ebx fs ds
  1587.        mov  ax,data_desc - gdt
  1588.            mov  ds,ax
  1589.            mov fs,[flat_DATA_sel]
  1590.            movzx ebx,bl
  1591.            shl    ebx,3
  1592.            add    ebx,[idt_base]
  1593.        mov    edi,[idt_base]
  1594.            mov    dx,fs:[ebx+6]        ; Get offset 16..32
  1595.            SHL    EDX,16
  1596.            mov    dx,fs:[ebx]        ; Get offset 0..15
  1597.            mov    cx,fs:[ebx+2]        ; Get Code Selector
  1598. ivec22:       pop ds fs ebx edi
  1599.        iretd
  1600.  
  1601. Set_irq_vec:
  1602.     stc
  1603.     jmp ivec22
  1604.  
  1605.  
  1606. GetVersion:    ; Emulate DPMI service Get Version
  1607.         ; only need to emulate the returned values of PIC bases
  1608.     mov dh,PIC_base
  1609.     mov dl,PIC_base+8
  1610.     iretd
  1611.  
  1612. ;═══════════════════════════════════════════════════════════════════════════
  1613. ;        PROCEDURES TO EMULATE REAL MODE INTERRUPT
  1614. ;                FOR BOTH  DPMI  AND  MY  VERSIONS
  1615. ;═══════════════════════════════════════════════════════════════════════════
  1616. DPMI_EmulateRealInterupt proc far
  1617.         push    ES  DS          ; save used seg registers
  1618.         mov    DS, CS:[data_sel]        ; Load DS data seg regs.
  1619.     push    ax      ; Push a 2 bytes to keep stack dword aligned for speed.
  1620.     push    0    ; Push the real mode SS:SP. If zero, DPMI set it up.
  1621.     push    0               ; ignore CS:IP not used by DPMI
  1622.     push    word ptr [Real_GS]
  1623.     push    word ptr [Real_FS]
  1624.     push    word ptr [Real_DS]
  1625.         push    word ptr [Real_ES]
  1626.         push    word ptr [esp+4*6+2]    ; get the flag register from INT 20h
  1627.         pushad
  1628.     mov    edi,esp
  1629.         push    ss
  1630.         pop    es
  1631.         mov    ax,0300h
  1632.         mov    bl,[esp+4*18]    ; get the V86 int number that was pushed
  1633.         xor    ecx,ecx
  1634.         xor    bh,bh
  1635.         int    31h                 ; Use the DPMI service
  1636.         popad
  1637.         pop    word ptr [esp+14+6*4]        ; return eflags
  1638.         pop    word ptr [Real_ES]
  1639.         pop    word ptr [Real_DS]
  1640.         pop    word ptr [Real_FS]
  1641.         pop    word ptr [Real_GS]
  1642.         add    esp,10                    ; Ignore CS:IP ,SS:SP and 2 bytes.
  1643.         pop    DS  ES            ; Restore used seg registers.
  1644.         iretd                         ; Return from INT 20h
  1645. ENDP
  1646.  
  1647.  
  1648. ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
  1649. My_EmulateRealInterupt proc far
  1650.     push    es gs ds fs        ; save segment registers.
  1651.  
  1652.         mov    ds,cs:[data_sel]        ; Load seg regs.
  1653.     mov    fs,[flat_data_sel]
  1654.  
  1655.     mov    _tmp0_,eax        ; temperly save  eax.
  1656.  
  1657.         mov    eax,[esp+4*6]        ; Get flags from stack.
  1658.         mov     [tmp_Real_Flags],ax    ; Temperaly saved them.
  1659.  
  1660.     mov    eax,[tss_Level0esp]    ; Set Level 0 stack to current SS:ESP
  1661.         mov    fs:[eax],esp
  1662.         mov    fs:[eax+4],SS
  1663.  
  1664.         movzx    eax,V86_irq_Count             ; Save the TSS LV0 Stack
  1665.         mov    [V86_Lv0_ESPSave+EAX*4], ESP
  1666.         mov    [V86_Lv0_SSSave+EAX*2], SS
  1667.     inc    V86_irq_Count
  1668.  
  1669.         pushfd                ; Clear Nested Task, ( bit 14 )
  1670.         pop eax                ; If set then the 386 will
  1671.         and ah,10111101b        ; use the back link field in the TSS
  1672.         push eax            ; to switch tasks. A no no.
  1673.         popfd
  1674.  
  1675.  
  1676.         mov al,[esp+4*7]        ; Get the V86 interrupt number
  1677.     mov byte ptr [ V86Int_instuction+1],AL    ; put it
  1678.  
  1679.     push    [Real_GS]            ; GS
  1680.     push    [Real_FS]            ; FS
  1681.     push    [Real_DS]            ; DS
  1682.     push    [Real_ES]            ; ES
  1683.     push    [Real_SS]            ; SS
  1684.     push    [Real_SP]            ; ESP
  1685.     mov    eax,00023000h            ; IOPL = 3 , VM = 1
  1686.         or    ax,[tmp_Real_Flags]
  1687.     push    eax                ; EFLAGS
  1688.     mov    eax,seg TASK0_V86
  1689.     push    eax                ; CS
  1690.     mov    eax,offset TASK0_V86
  1691.     push    eax                ; EIP
  1692.         mov    eax,_tmp0_            ; Return origonal EAX value
  1693.     IRETD                ; Enter V86 mode !!!!!
  1694. endp
  1695. ;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
  1696.  
  1697. TASK0_V86:
  1698.  
  1699. V86Int_instuction:    int 000h
  1700.             int 0ffh    ; Tell V86 exception handler to exit.
  1701. CODE32_end_of:
  1702. CODE32 ENDS
  1703.  
  1704. V86_STACK    SEGMENT public stack 'stack' USE16
  1705. db    V86_stack_size dup (?)
  1706. V86_STACK    ENDS
  1707.  
  1708.  
  1709. END   DosStart
  1710.