home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2MISC / PMODE12S.ZIP / SRC / PMODE / PMODE.ASM < prev    next >
Encoding:
Assembly Source File  |  1997-07-30  |  157.4 KB  |  5,523 lines

  1. ; PMODE v3.07 DPMI/VCPI/XMS/raw protected mode interface kernel.
  2. ; Copyright (c) 1994, Tran (a.k.a. Thomas Pytel).
  3. ;
  4. ; Changed to compile under TASM for DJGPP by m.grimrath@tu-bs.de
  5. ; Assemble case sensitive on all symbols!
  6.  
  7.     P386
  8.     IDEAL
  9.     ASSUME    cs:_TEXT, ds:DGROUP, es:nothing, ss:nothing
  10.     GROUP DGROUP _DATA, _BSS
  11.  
  12. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  13. ; Configuration options
  14. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  15. ; [fold]  [
  16.  
  17. ; Set to one to call exception 7 through a trap gate. An improvement of
  18. ; 10% in execution speed is possible using wmemu387.
  19. ; However, if one of the pics uses ints 0 to 7 (highly unlikely but supported)
  20. ; then an IRQ7 or IRQ15 will probably crash the computer.
  21. ; Also we cannot tell 'int 7' from exception 7.
  22. FAST_FPU_EMU    =    1
  23.  
  24. ; Set to one to let int 24 (critical error) conform to the DPMI spec.
  25. ; Since CWSDPMI doesn't support it, there is usually no need to support
  26. ; it in PMODE/DJ.
  27. SUPPORT_INT_24    =    0
  28.  
  29. ; Set to 1 to have PMODE/DJ extensions to the DPMI standard.
  30. ; So far no extension is available; setting this just wastes memory.
  31. PMODEDJ_EXT    =    0
  32.  
  33. ; Set this to have DPMI 1.0 functions 0e,0f (Get/Set multiple selectors)
  34. ; For DJGPP you can leave it 0; Recommended to set only if you just can't
  35. ; live without it! :-)
  36. MULTI_DESCRIPTORS    =    0
  37.  
  38. ; Setting this pmode will check if the requested DPL of descriptors match
  39. ; the CPL of the client. If not set, pmode will ignore the DPL and replace
  40. ; it with zero.
  41. ; This is only useful if you want pmodetsr to work around a bug in
  42. ; clients, namely zip. For DJGPP, always set this to 1
  43. STRICT_RING_CHECKING    =    1
  44.  
  45. ; Setting this pmode will check each segment limit. In particular, requesting
  46. ; to set a limit >1Mb while the lower 12 bits are != FFF will fail. If it
  47. ; not set, the 12 lower bits are ignored.
  48. ; For DJGPP, you must clear this flag; if not, your program won't run under
  49. ; a clean system.
  50. STRICT_LIMITS        =    0
  51.  
  52. ; How much bytes for physical address mapping. Will be rounded up to the next
  53. ; multiple of 4MB. Be careful! Setting this to high values consumes much
  54. ; conventional memory!
  55. ; Note that you might map more memory than specified here, because mapped
  56. ; memory uses the same pagetables as "normal" memory.
  57. EXTRALINEAR    =    8096*1024
  58.  
  59. RMSTACKLEN    =    0C00h    ; real mode stack length, in bytes
  60. RMONESTACKLEN    =    200h
  61. PMSTACKLEN    =    0C00h    ; protected mode stack length, in bytes
  62. PMONESTACKLEN    =    200h
  63. VCPISTACKLEN    =    100h    ; just for switching
  64. CALLBACKS    =    16    ; number of real mode callbacks
  65. NUM_EXCEPTIONS    =    16    ; # of handled exceptions
  66. ; [fold]  ]
  67.  
  68. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  69. ; Makros
  70. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  71. ; [fold]  [
  72.  
  73. off        EQU    offset
  74. pdseg        EQU    fs    ; take advantage of the 2 additional
  75. coreseg        EQU    gs    ; segment registers!
  76.  
  77. ; Macros to build up standard selectors
  78.     MACRO init_sel        ; Initialize selector
  79. sel_aktcnt    =    0
  80.     ENDM
  81.     MACRO mk_sel selec    ; Add one selectors
  82. selec        =    sel_aktcnt*8
  83. sel_aktcnt    =    sel_aktcnt+1
  84.     ENDM
  85.     MACRO mk_msel selec,num ; Make multiple selectors
  86. selec        =    sel_aktcnt*8
  87. sel_aktcnt    =    sel_aktcnt+num
  88.     ENDM
  89.     MACRO get_num_sel lab    ; returns the current number of selectors
  90. lab    =    sel_aktcnt
  91.     ENDM
  92.  
  93. ; a 32 addressing nop (for a 386 bug)
  94.     MACRO dnop
  95.     DB 67h
  96.     nop
  97.     ENDM
  98.  
  99. ; Makes a linear address from seg:ofs
  100.     MACRO ptr2lin seg,ofs,r1,r2,er1,er2
  101.     mov r1,seg
  102.     movzx er1,r1
  103.     shl er1,4
  104.     mov r2,ofs
  105.     movzx er2,r2
  106.     add er1,er2
  107.     ENDM
  108.  
  109. ; Make a segment from a linear address
  110.     MACRO lin2seg segm,lin,ereg,reg
  111.     IFDIF <lin>,<ereg>
  112.     mov ereg,lin
  113.     ENDIF
  114.     shr ereg,4
  115.     mov segm,reg
  116.     ENDM
  117.  
  118. ; Sets a memory area to zero
  119.     MACRO setmemw seg,ofs,size
  120.     IFDIF <seg>,<es>
  121.     push seg
  122.     pop es
  123.     ENDIF
  124.     IFDIF <ofs>,<di>
  125.     mov di,ofs
  126.     ENDIF
  127.     mov cx,(size) / 2
  128.     sub ax,ax
  129.     cld
  130.     rep stosw
  131.     nop        ; 386 bug
  132.     ENDM
  133.  
  134. ; Copies memory areas with ESI and EDI
  135.     MACRO dmemcpyw sseg,sofs,dseg,dofs,size
  136.     IFDIF <sofs>,<esi>
  137.     mov esi,sofs   ; Put this HERE, or else you can't use esp
  138.     ENDIF
  139.     IFDIF <dofs>,<edi>
  140.     mov edi,dofs   ; as macro argument
  141.     ENDIF
  142.     IFDIF <size>,<ecx>
  143.     mov ecx,(size) / 2
  144.     ENDIF
  145.     push ds es
  146.     IFDIF <dseg>,<es>
  147.     push dseg
  148.     ENDIF
  149.     IFDIF <sseg>,<ds>
  150.     push sseg
  151.     pop ds
  152.     ENDIF
  153.     IFDIF <dseg>,<es>
  154.     pop es
  155.     ENDIF
  156.     cld
  157.     DB 67h        ; To use ECX, ESI and EDI
  158.     rep movsw
  159.     dnop        ; 386 bug
  160.     pop es ds
  161.     ENDM
  162.  
  163. ; Copies memory areas with SI and DI
  164.     MACRO memcpyw sseg,sofs,dseg,dofs,size
  165.     IFDIF <sofs>,<si>
  166.     mov si,sofs   ; Put this HERE, or else you can't use esp
  167.     ENDIF
  168.     IFDIF <dofs>,<di>
  169.     mov di,dofs   ; as macro argument
  170.     ENDIF
  171.     IFDIF <size>,<cx>
  172.     mov cx,(size) / 2
  173.     ENDIF
  174.     push ds es
  175.     IFDIF <dseg>,<es>
  176.     push dseg
  177.     ENDIF
  178.     IFDIF <sseg>,<ds>
  179.     push sseg
  180.     pop ds
  181.     ENDIF
  182.     IFDIF <dseg>,<es>
  183.     pop es
  184.     ENDIF
  185.     cld
  186.     rep movs [WORD PTR es:di],[WORD PTR ds:si]
  187.     pop es ds    ; these pops cover 386 bug
  188.     ENDM
  189.  
  190. ; to save one line of source code
  191.     MACRO copy dst,src,reg
  192.     mov reg,src
  193.     mov dst,reg
  194.     ENDM
  195.  
  196. ; not to write so many lines
  197.     MACRO init_dsc base,sel,limit,rights
  198.     IFDIF <base>,<ax>
  199.     mov ax,base
  200.     ENDIF
  201.     IFDIF <sel>,<bx>
  202.     mov bx,sel
  203.     ENDIF
  204.     IFDIF <limit>,<ecx>
  205.     mov ecx,limit
  206.     ENDIF
  207.     IFDIF <rights>,<dx>
  208.     mov dx,rights
  209.     ENDIF
  210.     call vxr_initsetdsc
  211.     ENDM
  212.  
  213. ; zero extends 16 bit offset to 32, so it can be linked without 32 records
  214.     MACRO do16to32 mnem,p1,p2
  215.     DB 66h    ; 32 bit operand mode
  216.     mnem p1,p2
  217.     DW 0
  218.     ENDM
  219. ; [fold]  ]
  220.  
  221. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  222. ; Constants and structures
  223. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  224. ; [fold]  [
  225.  
  226. ; As you might notice, all structures start with a capital letter
  227. ; When changing the source, please keep this style!
  228.  
  229.     init_sel        ; Global descriptortable
  230.     mk_sel    SELNULL        ; NULL selector
  231.     mk_sel    SELCORE        ; selector of entire memory space
  232.     mk_sel    SELCS        ; Selector for Codesegment
  233.     mk_sel    SELDS        ; Selector for Datasegment
  234.     mk_sel    SELREAL        ; real mode attributes selector
  235.     mk_sel    SELALIASCS    ; to write to CS
  236.     mk_sel    SELPRIVAT    ; to access privat data
  237. IF SUPPORT_INT_24 NE 0
  238.     mk_sel    SELINT24    ; for INT 24h callback
  239. ENDIF
  240.     mk_sel    SELVCPITSS    ; TSS selector for VCPI
  241.     mk_sel    SELVCPI        ; VCPI call code selector
  242.     mk_sel    SELVCPI1
  243.     mk_sel    SELVCPI2    ; reserved for VCPI host
  244.     mk_msel SELTASKS,NUM_EXCEPTIONS
  245.    get_num_sel    SYSSELECTORS    ; number of system-selectors
  246. GDT_NUM_ENTRIES =      128    ; # of entries in the gdt
  247.  
  248. ; A 32bit Task status structure
  249. STRUC Tss
  250. backlink    DW    ?,?
  251. esp0        DD    ?
  252. ss0        DW    ?,?
  253. esp1        DD    ?
  254. ss1        DW    ?,?
  255. esp2        DD    ?
  256. ss2        DW    ?,?
  257. cr3        DD    ?
  258. eip        DD    ?
  259. eflags        DD    ?
  260. eax        DD    ?
  261. ecx        DD    ?
  262. edx        DD    ?
  263. ebx        DD    ?
  264. esp        DD    ?
  265. ebp        DD    ?
  266. esi        DD    ?
  267. edi        DD    ?
  268. es        DW    ?,?
  269. cs        DW    ?,?
  270. ss        DW    ?,?
  271. ds        DW    ?,?
  272. fs        DW    ?,?
  273. gs        DW    ?,?
  274. ldt        DW    ?,?
  275. trap        DW    ?
  276. iomapbase    DW    ?
  277. ENDS
  278.  
  279. ; DPMI register structure
  280. STRUC Dpmi_regs
  281. LABEL edi DWORD
  282. di    DW    ?
  283. di_hi    DW    ?
  284. LABEL esi DWORD
  285. si    DW    ?
  286. si_hi    DW    ?
  287. LABEL ebp DWORD
  288. bp    DW    ?
  289. bp_hi    DW    ?
  290. res    DD    ?
  291. LABEL ebx DWORD
  292. LABEL bx WORD
  293. bl    DB    ?
  294. bh    DB    ?
  295. bx_hi    DW    ?
  296. LABEL edx DWORD
  297. LABEL dx WORD
  298. dl    DB    ?
  299. dh    DB    ?
  300. dx_hi    DW    ?
  301. LABEL ecx DWORD
  302. LABEL cx WORD
  303. cl    DB    ?
  304. ch    DB    ?
  305. cx_hi    DW    ?
  306. LABEL eax DWORD
  307. LABEL ax WORD
  308. al    DB    ?
  309. ah    DB    ?
  310. ax_hi    DW    ?
  311. flags    DW    ?
  312. es    DW    ?
  313. ds    DW    ?
  314. fs    DW    ?
  315. gs    DW    ?
  316. ip    DW    ?
  317. cs    DW    ?
  318. sp    DW    ?
  319. ss    DW    ?
  320. ENDS
  321.  
  322. ; to access a descriptor entry more easily
  323. STRUC Descriptor
  324. limit0_15    DW ?
  325. base0_15    DW ?
  326. base16_23    DB ?
  327. LABEL types WORD
  328. types0        DB ?
  329. types1        DB ?
  330. base24_31    DB ?
  331. ENDS
  332.  
  333. ; Almost the same as a descriptor, but its a gate
  334. STRUC Gate
  335. offset0        DW    ?
  336. sel        DW    ?
  337. reserved    DB    ?
  338. gtype        DB    ?
  339. offset1        DW    ?
  340. ENDS
  341.  
  342. ; for DPMI call memory information
  343. STRUC Dpmi_meminfo
  344. available_memory        DD    ?
  345. available_pages            DD    ?
  346. available_lockable_pages    DD    ?
  347. linear_space            DD    ?
  348. unlocked_pages            DD    ?
  349. available_physical_pages    DD    ?
  350. total_physical_pages        DD    ?
  351. free_linear_space        DD    ?
  352. max_pages_in_paging_file    DD    ?
  353. reserved            DD 3 DUP(?)
  354. ENDS
  355.  
  356. ; also for easy access
  357. STRUC Farptr16        ; A 16 bit far ptr
  358. LABEL    ptr DWORD
  359. offset    DW    ?
  360. sel    DW    ?
  361. ENDS
  362.  
  363. STRUC Farptr32        ; A 32 Bit far ptr
  364. LABEL    ptr FWORD
  365. offset    DD    ?
  366. sel    DW    ?
  367. pad    DW    ?    ; one for align
  368. ENDS
  369.  
  370. STRUC Temp        ; for temporary variables
  371. LABEL    d0 DWORD
  372. LABEL    w0 WORD
  373. b0    DB    ?
  374. b1    DB    ?
  375. LABEL    w1 WORD
  376. b2    DB    ?
  377. b3    DB    ?
  378. ENDS
  379.  
  380. STRUC Callback
  381.     DB 0Fh,0A8h            ; PUSH gs
  382.     DB 0Fh,0A0h            ; PUSH fs
  383.     DB 1Eh                ; PUSH ds
  384.     DB 06h                ; PUSH es
  385.     DB 9Ch                ; PUSHF
  386.     DB 66h,60h            ; PUSHAD instruction
  387.     DB 68h                ; PUSH WORD instruction
  388. ds    DW 0                ; immediate 0 used as free flag
  389.     DB 66h,68h            ; PUSH DWORD instruction
  390. esi    DD 0                ;    immediate data
  391.     DB 0B9h                ; MOV CX,? instruction
  392. es    DW 0                ;    immediate data
  393.     DB 66h,68h            ; PUSH DWORD instruction
  394. edi    DD 0                ;    immediate data
  395.     DB 0EAh                ; JMP FAR PTR ?:? intruction
  396. ptr    Farptr16 ?            ;    immediate data
  397. ENDS
  398.  
  399. ; The data structure for privat data
  400. STRUC Pdata
  401. rmstack        DB RMSTACKLEN DUP(?)
  402. pmstack        DB PMSTACKLEN DUP(?)
  403. vcpistack    DB VCPISTACKLEN DUP(?)
  404. vcpitss        Tss ?
  405. exceptiontasks    Tss NUM_EXCEPTIONS DUP(?)
  406. exceptions    Farptr32 32 DUP(?)
  407. rmint_ptrs    DD 256 DUP(?)
  408. rmint_copy    Farptr16 16 DUP(?)    ; transparent hooking of HW RM Ints
  409. rmint_old    Farptr16 16 DUP(?)
  410. lowint        Farptr32 NUM_EXCEPTIONS DUP(?)
  411.         DB 256 DUP(?)
  412. LABEL exceptionstack WORD
  413. idt        Gate 256 DUP(?)
  414. gdt        Descriptor GDT_NUM_ENTRIES DUP(?)
  415. LABEL after WORD
  416. ENDS
  417. ; if running under VCPI, this is (page aligned) followed by the
  418. ; pagedirectory and the pagetables.
  419.  
  420. ; [fold]  ]
  421.  
  422. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  423. ; DATA
  424. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  425.     SEGMENT _DATA PARA PUBLIC USE16 'DATA'
  426.  
  427. PUBLIC pm_exit                ; user procedure at exit
  428. ; [fold]  [
  429.  
  430. lvcpistruc    DD    ?        ; VCPI switch structure linear address
  431. LABEL vcpi_switch_struct WORD
  432. vcpi_cr3    DD    ?        ; VCPI CR3 value for protected mode
  433. vcpi_gdtaddx    DD    ?        ; linear addx of GDT limit and base
  434. vcpi_idtaddx    DD    ?        ; linear addx of IDT limit and base
  435. vcpi_selldt    DW    0        ; LDT selector for protected mode
  436. vcpi_seltss    DW    SELVCPITSS    ; TSS selector for protected mode
  437. vcpi_eip    DW    off v_rmtopmswpm; destination EIP in protected mode
  438.         DW    0
  439. vcpi_cs        DW    SELCS        ; destination CS in protected mode
  440.  
  441. emspage        DW    -1        ; For some VCPI Managers
  442.  
  443. picbasetab    DB    88h,90h,98h,0A0h,0A8h,0B0h,0B8h,68h,78h,-1
  444.  
  445. initrouttbl    DW    r_init,x_init,v_init,d_init
  446. exitrouttbl    DW    r_exit,x_exit,v_exit ; exit functions. DPMI not needed
  447. pm_exit        DW    ret_only        ; Just a ret
  448.  
  449. int31functbl    DW    0000h, 0001h, 0002h, 0003h, 0006h
  450.         DW    0007h, 0008h, 0009h, 000ah, 000bh
  451.         DW    000ch
  452. IF MULTI_DESCRIPTORS NE 0
  453.         DW    000eh, 000fh
  454. ENDIF
  455.         DW    0100h, 0101h, 0102h
  456.         DW    0200h, 0201h, 0202h, 0203h
  457.         DW    0204h, 0205h
  458.         DW    0300h, 0301h, 0302h, 303h, 304h
  459.         DW    0305h, 0306h
  460.         DW    0400h
  461.         DW    0500h, 0501h, 0502h, 0503h
  462.         DW    0600h, 0601h, 0602h, 0603h, 0604h
  463.         DW    0702h, 0703h
  464.         DW    0800h, 0801h
  465.         DW    0900h, 0901h, 0902h
  466. IF PMODEDJ_EXT EQ 1
  467.         DW    0A00h
  468. ENDIF
  469.         DW    0E00h, 0E01h
  470. INT31FUNCNUM    = ($ - int31functbl) / 2
  471.  
  472. int31routtbl    DW    int310000, int310001, int310002, int310003, int310006
  473.         DW    int310007, int310008, int310009, int31000a, int31000b
  474.         DW    int31000c
  475. IF MULTI_DESCRIPTORS NE 0
  476.         DW    int31000e, int31000f
  477. ENDIF
  478.         DW    int310100, int310101, int310102
  479.         DW    int310200, int310201, int310202, int310203
  480.         DW    int310204, int310205
  481.         DW    int310300, int310301, int310302, int310303, int310304
  482.         DW    int310305, int310306
  483.         DW    int310400
  484.         DW    int310500, int310501, int310502, int310503
  485.         DW    int310600, int310601, int310602, int310603, int310604
  486.         DW    int310702, int310703
  487. int31phystbl    DW    int310800v,int310801v
  488.         DW    int310900, int310901, int310902
  489. IF PMODEDJ_EXT EQ 1
  490.         DW    int310a00
  491. ENDIF
  492.         DW    int310e00, int310e01
  493.  
  494. ; the letters stand for:
  495. ; v - VCPI memory
  496. ; x - XMS memory
  497. ; r - raw memory (INT15/VDISK)
  498. ; n - no memory
  499. int31mvrouttbl    DW    int310500v, int310501v, int310502v, int310503v
  500. int31mxrouttbl    DW    int310500x, int310501x, int310502x, int310503x
  501. int31mrrouttbl    DW    int310500r, int310501r, int310502r, int310503r
  502. int31mnrouttbl    DW    int310500n, int310501n, int310502n, int310503n
  503. INT31MROUTTBL_ENTRIES = ($ - int31mnrouttbl) / 2
  504.  
  505. int31physxrtbl    DW    int310800xr, int310801xr
  506.  
  507. IF PMODEDJ_EXT EQ 1
  508. apitab:
  509. APITAB_SIZE    = $ - apitab
  510. pmodedj_id    DB    'DJGPP',0
  511. PMODEDJ_ID_SIZE = $ - pmodedj_id
  512. ENDIF
  513.         ALIGN 4
  514.  
  515. ; Placed here, coz my TASM had problems putting this in the code
  516. common_callbacks Callback CALLBACKS DUP(<>)
  517.  
  518. rawextmemused    DW    1        ; raw extended memory used in K
  519. rawextmembase    DD    0ffffffffh    ; raw extended memory base
  520. rawextmemtop    DD    0        ; raw extended memory top
  521.  
  522. rmidtlimit    DW    3ffh        ; real mode IDT limit
  523. rmidtbase    DD    0        ; real mode IDT base
  524.  
  525. ; THIS MUST BE THE LAST VAR! padsec will kill any trailing zeros from the
  526. ; exefile, which means variables initialized here 0 have undefined values
  527. ; in them.
  528. ; padsec must do this job because tasm or tlink doesn't get it right. :(
  529.         DW    0abcdh
  530.     ENDS
  531.  
  532.     SEGMENT _BSS PARA PUBLIC USE16 'BSS'
  533. int31mrouttbl    DW INT31MROUTTBL_ENTRIES DUP(?)
  534.  
  535. segmentbases    DW 16*2 DUP(?)        ; segment bases for function 0002h
  536. segmentbases_SIZE = ($ - segmentbases)
  537.  
  538. temp0        Temp    ?        ; temporary variables
  539. temp1        Temp    ?        ;     "        "
  540.  
  541. rmwrapper    Farptr16 8 DUP(?)    ; real mode wrappers to reprogram PIC
  542. xms_call    Farptr16 ?
  543.  
  544. dpmiepmode    Farptr16 ?        ; DPMI protected mode entry
  545.  
  546. vcpiswitchstack Farptr32 ?        ; VCPI temporary mode switch stack
  547. vcpi_service    Farptr32 ?        ; VCPI code pointer
  548.  
  549. gdtlimit    DW    ?        ; GDT limit
  550. gdtbase        DD    ?        ; GDT base
  551. idtlimit    DW    ?        ; IDT limit
  552. idtbase        DD    ?        ; IDT base
  553.  
  554. SetMasterPIC    DW    ?        ; offset of PIC set routine
  555. ResetMasterPIC    DW    ?        ; offset of PIC reset routine
  556. SetA20        DW    ?        ; offset of A20 set routine
  557. ResetA20    DW    ?        ; offset of A20 reset routine
  558.  
  559. pmstackbase    DD    ?        ; bottom of protected mode stack area
  560. pmstacktop    DD    ?        ; top of protected mode stack area
  561. rmstackbase    DW    ?        ; bottom of real mode stack area
  562. rmstacktop    DW    ?        ; top of real mode stack area
  563.  
  564. processortype    DB    ?        ; processor type
  565. pmodetype    DB    ?        ; protected mode type
  566. reprogrampic    DB    ?        ; if first PIC should be reprogrammed
  567. from_us        DB    ?        ; if int call by PMODE
  568. picslaveold    DB    ?        ; old PIC slave base interrupt
  569. picmasterold    DB    ?        ; old PIC master base interrupt
  570. picslavenew    DB    ?        ; New PIC slave base
  571. picmasternew    DB    ?        ; New PIC master base
  572.  
  573. olda20        DB    ?
  574. detectionflags    DB    ?
  575. oldCR0L        DB    ?        ; low byte of CR0
  576. newEM_MP    DB    ?        ; user specified EM and MP
  577. oldint15vector    DD    ?
  578. oldint2fvector    DD    ?
  579.  
  580. pagedir        DD    ?        ; linear address of pagedirectory
  581. pagetablebase    DD    ?        ; base of page table area
  582. pagetabletop    DD    ?        ; top of page table area
  583. pagetablefree    DD    ?        ; base of available page table area
  584. pagetabledelta    DD    ?        ; # of KB for allocates pagetables
  585.  
  586. privatedataseg    DW    ?        ; segment of privat data
  587.  
  588. rmtopmswrout    DW    ?        ; offset of real to protected routine
  589. pmtormswrout    DW    ?        ; offset of protected to real routine
  590. rmstackparmtop    DW    ?        ; for functions 0300h, 0301h, 0302h
  591.         DB 128 DUP(?)        ; little stack at exit
  592. LABEL endstack WORD
  593.         ENDS
  594. ; [fold]  ]
  595.  
  596. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  597. ; DETECT/INIT CODE
  598. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  599.  
  600.     SEGMENT _TEXT PARA PUBLIC USE16 'CODE'
  601.  
  602. PUBLIC pm_info        ; procedure to get info
  603. PUBLIC pm_init        ; switches to protected mode
  604.  
  605. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  606. ; [fold]  [
  607. ; pm_info: Get protected mode info
  608. ; In:
  609. ;   AX =
  610. ;     Bit  0 = 0: Check for DPMI first, else check for VCPI first
  611. ;     Bit  1    : ignored and reserved for pm_init
  612. ;
  613. ;     Bit  8 = 1: forbid raw
  614. ;     Bit  9 = 1: forbid XMS
  615. ;     Bit 10 = 1: forbid VCPI
  616. ;     Bit 11 = 1: forbid DPMI
  617. ;
  618. ; Out:
  619. ;   AX = return code:
  620. ;     0000h = successful
  621. ;     0001h = no 80386+ detected
  622. ;     0002h = system already in protected mode and no VCPI or DPMI found
  623. ;     0003h = no way to switch into protected mode
  624. ;   CF = set on error, if no error:
  625. ;     BX = number of paragraphs needed for protected mode data (may be 0)
  626. ;     CL = processor type:
  627. ;    02h = 80286
  628. ;    03h = 80386
  629. ;    04h = 80486
  630. ;    05h = 80586
  631. ;    06h-FFh = reserved for future use
  632. ;     CH = protected mode type:
  633. ;    00h = raw
  634. ;    01h = XMS
  635. ;    02h = VCPI
  636. ;    03h = DPMI
  637. ;
  638. ; Remark by MG: spaghetticode!
  639. ;
  640. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  641. pm_info:
  642.     push dx si di bp ds es bx cx    ; preserve registers
  643.  
  644.     mov [detectionflags],ah        ; store detection flags
  645.     test al,1            ; check order of DPMI/VCPI detection
  646.     jz short @@infof0
  647.  
  648.     call @@detect_VCPI        ; check for VCPI first
  649.     call @@detect_DPMI        ; check for DPMI second
  650.     jmp short @@infof2        ; neither found, go on to XMS check
  651.  
  652. @@infof0:
  653.     call @@detect_DPMI        ; check for DPMI first
  654.     call @@detect_VCPI        ; check for VCPI second
  655.  
  656. ;-----------------------------------------------------------------------------
  657. @@infof2:
  658.     smsw ax                ; AX = machine status word
  659.     test al,1            ; is system in protected mode?
  660.     mov ax,2            ; error code in case protected mode
  661.     jnz short @@infofail        ; if in protected mode, fail
  662.  
  663.     mov ch,1            ; pmode type XMS
  664.     test [detectionflags],2        ; XMS allowed?
  665.     jnz short @@chkr
  666.     mov ax,4300h            ; check for XMS
  667.     int 2fh
  668.     cmp al,80h            ; XMS present?
  669.     jz short @@w1            ; if so, go on
  670.  
  671. @@chkr: sub ch,ch            ; set type to raw
  672.     test [detectionflags],1        ; raw allowed?
  673.     jz short @@w1            ; if so
  674.  
  675.     mov ax,3            ; else set error code
  676.     jmp short @@infofail        ; and fail
  677.  
  678. @@w1:    sub bx,bx            ; no special memory needed
  679.  
  680. ;-----------------------------------------------------------------------------
  681. @@infof1:
  682.     add bx,(SIZE Pdata+15) / 16    ; Size of privatdata structure
  683.     jmp short @@infook        ; go to done ok
  684.  
  685. ;-----------------------------------------------------------------------------
  686. @@infofail:
  687.     pop cx bx            ; restore BX and CX
  688.     stc                ; carry set, failed
  689.     jmp short @@infodone
  690.  
  691. ;-----------------------------------------------------------------------------
  692. @@infook:
  693.     mov [pmodetype],ch        ; store pmode type
  694.  
  695.     add sp,4            ; skip BX and CX on stack
  696.     xor ax,ax            ; success code, also clear carry flag
  697.     clc                ; Signal success
  698.  
  699. ;-----------------------------------------------------------------------------
  700. @@infodone:
  701.     pop es ds bp di si dx        ; restore other registers
  702.     ret                ; return
  703.  
  704. ;─────────────────────────────────────────────────────────────────────────────
  705. ; [fold]  [
  706. @@detect_DPMI: ; detect a DPMI host
  707.     pop bp                ; pop return address from stack
  708.  
  709.     test [detectionflags],8        ; DPMI allowed?
  710.     jnz short @@detect_DPMIdone    ; if not, quit
  711.  
  712.     sub ax,ax
  713.     mov es,ax
  714.     mov ax,[es:02Fh*4]
  715.     or ax,[es:02Fh*4+2]        ; check if multiplex set
  716.     jz short @@detect_DPMIdone
  717.  
  718.     mov ax,1687h            ; check for DPMI
  719.     int 2fh
  720.  
  721.     or ax,ax            ; DPMI present?
  722.     jnz short @@detect_DPMIdone    ; if no, exit routine
  723.  
  724.     mov ax,3            ; error code in case DPMI not 32bit
  725.     test bl,1            ; is DPMI 32bit?
  726.     jz short @@detect_DPMIdone    ; if not, this DPMI host is no good
  727.  
  728.     mov ax,1            ; error code in case no processor 386+
  729.     cmp cl,3            ; is processor 386+? (redundant)
  730.     jb short @@infofail        ; if no, fail
  731.  
  732.     mov [dpmiepmode.offset],di    ; store DPMI initial mode switch addx
  733.     mov [dpmiepmode.sel],es
  734.  
  735.     mov bx,si            ; BX = number of paragraphs needed
  736.     mov ch,3            ; pmode type is 3 (DPMI)
  737.  
  738.     jmp @@infook            ; go to done ok
  739.  
  740. @@detect_DPMIdone:
  741.     jmp bp                ; return to calling routine
  742. ; [fold]  ]
  743.  
  744. ;─────────────────────────────────────────────────────────────────────────────
  745. ; [fold]  [
  746. @@detect_VCPI: ; detect a VCPI server
  747.     pop bp                ; pop return address from stack
  748.  
  749.     call @@detect_processor        ; get processor type
  750.  
  751.     mov ax,1            ; error code in case no processor 386+
  752.     cmp cl,3            ; is processor 386+?
  753.     jb short @@infofail        ; if no, no VCPI
  754.     mov [processortype],cl        ; store processor type
  755.  
  756.     test [detectionflags],4        ; VCPI allowed?
  757.     jnz @@detect_VCPIdone        ; if not, ignore
  758.  
  759.     xor ax,ax            ; get INT 67h vector
  760.     mov es,ax
  761.     mov ax,[es:67h*4]
  762.     or ax,[es:67h*4+2]        ; is vector NULL
  763.     jz short @@detect_VCPIdone    ; if yes, no VCPI
  764.  
  765.     cmp    [emspage],-1        ; if already EMS Page allocated,
  766.     jnz    short @@no_alloc    ; skip
  767.     mov    ah,40H            ;Get Status
  768.     int    67h
  769.     cmp    ah,0
  770.     jne    short @@no_alloc    ;maybe only EMS turned off
  771.     mov    ah,42H            ;Get Unallocate Page Count
  772.     int    67h
  773.     cmp    ah,0
  774.     jne    short @@no_alloc
  775.     cmp    bx,dx            ;Other Program EMS Page Used?
  776.     jne    short @@no_alloc    ;Used!!
  777.     mov    bx,1
  778.     mov    ah,43H            ;Allocate Pages(1 Page Only),
  779.     int    67h            ;so EMS has to be turned on
  780.     cmp    ah,0
  781.     jne    short @@no_alloc    ;if page alloc failed
  782.     mov    [emspage],dx        ; store EMS page
  783.  
  784. @@no_alloc:
  785.     mov ax,0de00h            ; call VCPI installation check
  786.     int 67h
  787.     or ah,ah            ; AH returned as 0?
  788.     jnz short @@detect_VCPIdone2    ; if no, no VCPI
  789.  
  790.     ; determine here # of max pagetables + pagedir
  791.     mov ax,0DE03h            ; # of free pages
  792.     int 67h
  793.     add edx,1023+1024+(((EXTRALINEAR+4096*1024-1) AND NOT (4096*1024-1)) \
  794.                /(1024*4))    ; align to next pagetable +
  795.     and dx,NOT 1023            ;   first MB + 8 MB extra linear
  796.     shl edx,2            ; # of bytes for page tables
  797.     mov [pagetabledelta],edx    ; store size of pagetables
  798.     shr edx,12-8            ; calc # of paragraphs
  799.     mov bx,dx            ; if highword is not zero, you would
  800.                     ; still have enough mem!
  801.     add bx,(4096+4096) / 16        ; page directory and page align
  802.     mov ch,2            ; pmode type is 2 (VCPI)
  803.  
  804.     jmp @@infof1            ; go to figure other memory needed
  805.  
  806. @@detect_VCPIdone2:
  807.     mov dx,[emspage]
  808.     cmp dx,-1
  809.     jz short @@detect_VCPIdone    ; free allocated EMS page
  810.     mov ah,45h
  811.     int 67h
  812.     mov [emspage],-1        ; reset to 'no emspage allocated'
  813. @@detect_VCPIdone:
  814.     jmp bp                ; return to calling routine
  815. ; [fold]  ]
  816.  
  817. ;─────────────────────────────────────────────────────────────────────────────
  818. ; [fold]  [
  819. @@detect_processor: ; get processor: 286, 386, 486, or 586
  820.     xor cl,cl            ; processor type 0 in case of exit
  821.  
  822.     pushf                ; transfer FLAGS to BX
  823.     pop bx
  824.  
  825.     mov ax,bx            ; try to clear high 4 bits of FLAGS
  826.     and ah,0fh
  827.  
  828.     push ax                ; transfer AX to FLAGS
  829.     popf
  830.     pushf                ; transfer FLAGS back to AX
  831.     pop ax
  832.  
  833.     and ah,0f0h            ; isolate high 4 bits
  834.     cmp ah,0f0h
  835.     je short @@detect_processordone ; if bits are set, CPU is 8086/8
  836.  
  837.     mov cl,2            ; processor type 2 in case of exit
  838.  
  839.     or bh,0f0h            ; try to set high 4 bits of FLAGS
  840.  
  841.     push bx                ; transfer BX to FLAGS
  842.     popf
  843.     pushf                ; transfer FLAGS to AX
  844.     pop ax
  845.  
  846.     and ah,0f0h            ; isolate high 4 bits
  847.     jz short @@detect_processordone ; if bits are not set, CPU is 80286
  848.  
  849.     inc cx                ; processor type 3 in case of exit
  850.  
  851.     push eax ebx edx        ; preserve 32bit registers
  852.  
  853.     pushfd                ; transfer EFLAGS to EBX
  854.     pop ebx
  855.  
  856.     mov eax,ebx            ; try to flip AC bit in EFLAGS
  857.     xor eax,40000h
  858.  
  859.     push eax            ; transfer EAX to EFLAGS
  860.     popfd
  861.     pushfd                ; transfer EFLAGS back to EAX
  862.     pop eax
  863.  
  864.     xor eax,ebx            ; AC bit fliped?
  865.     jz short @@detect_try_cpuid    ; if no, CPU is 386
  866.  
  867.     inc cx                ; processor type 4 in case of exit
  868. @@detect_try_cpuid:
  869.  
  870.     mov eax,ebx            ; try to flip ID bit in EFLAGS
  871.     xor eax,200000h
  872.  
  873.     push eax            ; transfer EAX to EFLAGS
  874.     popfd
  875.     pushfd                ; transfer EFLAGS back to EAX
  876.     pop eax
  877.  
  878.     xor eax,ebx            ; ID bit fliped?
  879.     jz short @@detect_processordone2; if no, return 386 or 486
  880.  
  881. ; Use cpuid instruction if supported
  882. ; cpuid is supported on some new 486, some new Nx586, Pentium, Am5x86,
  883. ; Cyrix 6x86 and all newer processors. I'm not sure about Cyrix 5x86.
  884. ; Nx586 returns 5, Am5x86 returns 4, Cyrix 6x86 returns 6.
  885.     mov eax,0            ; check if CPUID accepts 1 in eax
  886.     db 0fh,0a2h            ; CPUID
  887.     or eax,eax            ; eax for distant future compatibility
  888.     mov cx,5            ; processor type 5 in case of exit
  889.     jz short @@detect_processordone2; cpuid can not be used further
  890.  
  891.     mov eax,1            ; get chip type and supported features
  892.     db 0fh,0a2h            ; CPUID
  893.     and ah,0fh            ; clear type field
  894.     movzx cx,ah            ; return family field.
  895.  
  896. @@detect_processordone2:
  897.     pop edx ebx eax            ; restore 32bit registers
  898.  
  899. @@detect_processordone:
  900.     ret                ; return
  901. ; [fold]  ]
  902.  
  903. ; [fold]  ]
  904.  
  905. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  906. ; [fold]  [
  907. ; pm_init: switch into protected mode
  908. ; In:
  909. ;   AX = Bit  0 = 1 Check for VCPI first
  910. ;     Bit  1 = 1 Reprogram first PIC if possible
  911. ;     Bit  8 = 1 forbid raw
  912. ;     Bit  9 = 1 forbid XMS
  913. ;     Bit 10 = 1 forbid VCPI
  914. ;     Bit 11 = 1 forbid DPMI
  915. ;   ES = real mode segment for protected mode data (ignored if not needed)
  916. ; Out:
  917. ;   AX = return code:
  918. ;     0000h = successful
  919. ;     0001h = no 80386+ detected
  920. ;     0002h = system already in protected mode and no VCPI or DPMI found
  921. ;     0003h = (changed) no way to switch into protected mode
  922. ;     0004h = could not enable A20 gate
  923. ;     0005h = DPMI - could not enter 32bit protected mode
  924. ;   CF = set on error, if no error running in protected mode:
  925. ;     ESP = high word clear
  926. ;     CS = 16bit selector for real mode CS with limit of 64k
  927. ;     SS = selector for real mode SS with limit of 64k
  928. ;     DS = selector for real mode DS with limit of 64k
  929. ;     ES = selector for PSP with limit of 100h
  930. ;     FS = 0 (NULL selector)
  931. ;     GS = 0 (NULL selector)
  932. ;  Rem: DS == SS, if DS == SS on entry
  933. ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
  934. ; [fold]  [
  935. pm_init:
  936.     push ax
  937.     call pm_info
  938.     pop ax
  939.     jnc short @@initf0        ; error?
  940.     ret                ; yup, abort
  941.  
  942. @@initf0:                ; no error, init protected mode
  943.     test ax,2
  944.     setnz [reprogrampic]
  945.  
  946.     push esi edi ebp
  947.     cld
  948.  
  949.     setmemw es,<off 0+Pdata.gdt>,<GDT_NUM_ENTRIES * SIZE Descriptor>
  950.                     ; clear GDT with all 0
  951.     mov [privatedataseg],es        ; save data segment
  952.     movzx bx,[pmodetype]        ; jump to appropriate init code
  953.     add bx,bx
  954.     jmp [bx + initrouttbl]
  955. ; [fold]  ]
  956.  
  957. ;═════════════════════════════════════════════════════════════════════════════
  958. ; [fold]  [
  959. d_init: ; DPMI protected mode init
  960.     mov ax,1            ; enter DPMI protected mode
  961.     call [dpmiepmode.ptr]
  962.     sub bx,bx
  963.     jnc short init_done        ; error? if not, finished here
  964.     mov bx,5            ; error entering protected mode, set
  965.  
  966. ;-----------------------------------------------------------------------------
  967. init_done:                ; return with return code
  968.     mov ax,bx
  969.     pop ebp edi esi
  970.     ret
  971. ; [fold]  ]
  972.  
  973. ;─────────────────────────────────────────────────────────────────────────────
  974. ; This assumes, that the extender runs in 1 Code and 1 Datasegment.
  975. ; (This applies for model tiny, small, compact, and sometimes for tpascal)
  976. ; The original source put here created a codesegment descriptor
  977. ; to return from this procedure. But as pm_init is near-called, there is no
  978. ; need for such a code.
  979. ; [fold]  [
  980. dvxr_init: ; DPMI/VCPI/XMS/raw common init tail
  981.     sub bx,bx            ; error code = 0 (no error)
  982.     mov fs,bx            ; changed, when switching by raw
  983.     mov gs,bx
  984.     clc                ; signal success
  985.     jmp    init_done
  986. ; [fold]  ]
  987.  
  988. ;═════════════════════════════════════════════════════════════════════════════
  989. ; In: ES = segment for host private data buffer
  990. ; [fold]  [
  991. v_init: ; VCPI protected mode init
  992.     mov [SetMasterPIC],off v_setpic
  993.     mov [ResetMasterPIC],off v_resetpic
  994.     mov [SetA20],off v_seta20
  995.     mov [ResetA20],off v_reseta20
  996.  
  997.     mov ax,0de0ah            ; get PIC mappings
  998.     int 67h
  999.     mov [picmasterold],bl
  1000.     mov [picslaveold],cl
  1001.  
  1002.     mov ax,0de07h            ; get CR0
  1003.     int 67h
  1004.     mov [oldCR0L],bl        ; save old state
  1005.     sar bl,1
  1006.     and bl,3            ; keep EM and MP
  1007.     mov [newEM_MP],bl
  1008.  
  1009.     ptr2lin es,<off 0+Pdata.after>,ax,bx,eax,ebx
  1010.     add eax,4095
  1011.     and ax,NOT 4095            ; align data area on page
  1012.     mov [pagedir],eax        ; store
  1013.  
  1014.     add eax,1000h            ; skip pagedir
  1015.     mov [pagetablebase],eax        ; set base of page table area
  1016.     add eax,[pagetabledelta]    ; size of pagetables
  1017.     mov [pagetabletop],eax        ; set top of page table area
  1018.  
  1019.     lin2seg es,[pagedir],eax,ax
  1020.     mov gs,ax            ; GS = segment of page directory
  1021.     mov es,ax            ; ES = segment of page directory
  1022.     add ax,100h
  1023.     mov fs,ax            ; FS = segment of first page table
  1024.  
  1025.     setmemw es,0,2*4096        ; clear page dir and first page table
  1026.     copy es,fs,ax            ; ES = segment of first pagetable
  1027.  
  1028.     push ds
  1029.     mov ds,[privatedataseg]
  1030.     mov si,off SELVCPI+Pdata.gdt    ; descriptors for VCPI host
  1031.     xor di,di            ; get VCPI protected mode interface
  1032.     mov ax,0de01h
  1033.     int 67h
  1034.     pop ds                ; restore old ds
  1035.  
  1036.     movzx eax,di            ; set base of usable page table area
  1037.     add ax,4095
  1038.     and ax,NOT 4095            ; align to next pagetable
  1039.     add eax,[pagetablebase]
  1040.     mov [pagetablefree],eax
  1041.  
  1042.     mov [vcpi_service.sel],SELVCPI    ; store protected mode VCPI call CS
  1043.     mov [vcpi_service.offset],ebx    ; store protected mode VCPI call EIP
  1044.  
  1045.     ; For safety clear reserved bits 9-11
  1046. @@v_initl0:
  1047.     and [byte ptr es:di+1],0f1h
  1048.     sub di,4
  1049.     jnc @@v_initl0
  1050.  
  1051.     ; --------- Link pagetables in pagedirectory ----------
  1052.     mov si,es            ; DX = current page table segment
  1053.     xor ebx,ebx            ; index in page dir, also loop counter
  1054.     mov ebp,[pagetabledelta]
  1055.     shr ebp,12            ; # of pagetables
  1056.     jmp short @@v_initl1f0
  1057.  
  1058. @@v_initl1:
  1059.     xor di,di            ; clear page table
  1060.     mov cx,800h
  1061.     xor ax,ax
  1062.     rep stosw
  1063.     nop        ; 386 bug
  1064.  
  1065. @@v_initl1f0:
  1066.     mov cx,si
  1067.     shr cx,8            ; get page number
  1068.     mov ax,0de06h            ; get physical address
  1069.     int 67h
  1070.     and dh,0f1h            ; For safety clear reserved bits 9-11
  1071.     or dl,7                ; set present, User and R/W bit
  1072.     mov [gs:ebx*4],edx        ; store in page directory
  1073.  
  1074.     add si,100h            ; increment page table segment
  1075.     mov es,si
  1076.  
  1077.     inc bx                ; increment index in page directory
  1078.     cmp bx,bp            ; at end of page tables?
  1079.     jb @@v_initl1            ; if no, loop
  1080.  
  1081. ;-----------------------------------------------------------------------------
  1082.  
  1083.     mov ecx,[pagedir]
  1084.     shr ecx,12
  1085.     mov ax,0de06h
  1086.     int 67h                ; get physical address
  1087.     mov [vcpi_cr3],edx
  1088.     ptr2lin ds,<off gdtlimit>,ax,bx,eax,ebx
  1089.     mov [vcpi_gdtaddx],eax
  1090.     ptr2lin ds,<off idtlimit>,ax,bx,eax,ebx
  1091.     mov [vcpi_idtaddx],eax
  1092.     ptr2lin ds,<off vcpi_switch_struct>,ax,bx,eax,ebx
  1093.     mov [lvcpistruc],eax
  1094.     mov [rmtopmswrout],off v_rmtopmsw
  1095.     mov [pmtormswrout],off v_pmtormsw
  1096.  
  1097.     mov si,off int31mvrouttbl
  1098. ; [fold]  ]
  1099.  
  1100. ;─────────────────────────────────────────────────────────────────────────────
  1101. ; [fold]  [
  1102. vxr_init: ; VCPI/XMS/raw common init tail
  1103.     mov [from_us],0            ; init
  1104.     mov pdseg,[privatedataseg]    ; access private data
  1105.  
  1106.     push ds                ; ES = DS for table copy
  1107.     pop es
  1108.     mov di,off int31mrouttbl
  1109.     mov cx,INT31MROUTTBL_ENTRIES    ; set memory allocation function
  1110.     memcpyw ds,si,es,di,cx        ; copy memory allocation function
  1111.  
  1112.     setmemw ds,<off segmentbases>,segmentbases_SIZE
  1113.  
  1114.     sub edx,edx
  1115.     mov dx,off critical_error    ; Standard exception handler
  1116.     mov si,off 0 + Pdata.exceptions
  1117.     mov ax,32 ;NUM_EXCEPTIONS
  1118. @@lp:    mov [pdseg:si + Farptr32.sel],SELCS
  1119.     mov [pdseg:si + Farptr32.offset],edx
  1120.     mov [pdseg:si + Farptr32.pad],0
  1121.     add si,SIZE Farptr32
  1122.     dec ax
  1123.     jnz @@lp
  1124.     do16to32 mov,ax,<off NMI_exception> ; NMI is passed down to real mode
  1125.     mov [pdseg:off (2*SIZE Farptr32) + Pdata.exceptions],eax
  1126.  
  1127. IF FAST_FPU_EMU EQ 1
  1128.     mov ax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.sel]
  1129.     mov [cs:FPU_emu_vector.sel],ax
  1130.     mov eax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.offset]
  1131.     mov [cs:FPU_emu_vector.offset],eax
  1132. ENDIF
  1133.  
  1134.     copy [picslavenew],[picslaveold],al
  1135.     copy [picmasternew],[picmasterold],al
  1136.     test [reprogrampic],-1        ; reprogram first PIC?
  1137.     jz short @@pice
  1138.     cmp [picmasternew],8        ; default value for first PIC?
  1139.     jnz short @@pice        ; if not, keep hands off!
  1140. @@gopic:mov di,off picbasetab
  1141.     copy es,0,ax            ; ES -> Base of IVT
  1142.     jmp short @@lpde
  1143. @@lpd:    mov eax,[es:edx*4]        ; get first interrupt vector
  1144.     mov cl,7
  1145. @@lpc:    inc dx
  1146.     cmp eax,[es:edx*4]        ; contest the same?
  1147.     jnz short @@lpde        ; if not, try next
  1148.     dec cl                ; Rem: This is faster than 'loop'!
  1149.     jnz @@lpc            ; Compare next
  1150.     sub dx,7            ; yeah, found a place
  1151.     jmp short @@repr
  1152. @@lpde: movzx edx,[BYTE PTR di]
  1153.     inc di
  1154.     cmp dl,-1
  1155.     jnz @@lpd
  1156.  
  1157. @@repr: cmp dl,-1            ; search successful?
  1158.     jz short @@pice            ; if not, everything's the same
  1159.     mov [picmasternew],dl
  1160.  
  1161. @@pice: ptr2lin pdseg,<off 0+Pdata.idt>,ax,bx,eax,ebx
  1162.     mov [idtbase],eax        ; set IDT base address
  1163.     mov [idtlimit],(256 * SIZE Gate)-1
  1164.  
  1165.     mov [rmstackbase],off 0+Pdata.rmstack        ; set top and base of
  1166.     mov [rmstacktop],off RMSTACKLEN + Pdata.rmstack ; real mode stack
  1167.  
  1168.     ; ------------------ Set up IDT -----------------
  1169.     sub di,di
  1170.     mov si,off common_int_handler
  1171.     sub cx,cx
  1172. @@vxr_idt_loop1:
  1173.     mov [pdseg:di + Pdata.idt.offset0],si
  1174.     mov [pdseg:di + Pdata.idt.offset1],0
  1175.     mov [pdseg:di + Pdata.idt.reserved],0
  1176.     mov [pdseg:di + Pdata.idt.sel],SELCS
  1177.     mov [pdseg:di + Pdata.idt.gtype],8Fh    ; trap gate
  1178.     add di,SIZE Gate
  1179.     add si,INT_HANDLER_SIZE
  1180.     inc cx
  1181.     cmp cx,256
  1182.     jne @@vxr_idt_loop1
  1183.  
  1184.     ; ------------------ Set up RM vector pointers --------------
  1185.     sub edi,edi
  1186. @@rm_vector_pointer_loop:
  1187.     mov [pdseg:di + Pdata.rmint_ptrs],edi
  1188.     add di,4
  1189.     cmp di,256*4
  1190.     jne short @@rm_vector_pointer_loop
  1191.  
  1192.     ; --------------- Set up hardware IRQ handlers --------------
  1193.     mov ax,off common_hardirq_handler
  1194.     movzx edx,[privatedataseg]
  1195.     shl edx,4
  1196.     do16to32 add,dx,<off 0+Pdata.rmint_copy>
  1197.  
  1198.     mov cl,16
  1199.     movzx edi,[picmasterold]
  1200.     movzx esi,[picmasternew]
  1201. @@hi1:    cmp cl,8
  1202.     jne short @@www1
  1203.     movzx edi,[picslaveold]
  1204.     movzx esi,[picslavenew]
  1205. @@www1: mov [pdseg:edi*SIZE Gate + Pdata.idt.offset0],ax ; fast HW IRQ handler
  1206.     mov [pdseg:edi*SIZE Gate + Pdata.idt.gtype],8Eh     ; interrupt gate
  1207.     mov [pdseg:esi*SIZE Gate + Pdata.idt.offset0],ax ; fast HW IRQ handler
  1208.     mov [pdseg:esi*SIZE Gate + Pdata.idt.gtype],8Eh     ; interrupt gate
  1209.     mov [pdseg:edi*4     + Pdata.rmint_ptrs],edx ; to transparate hook
  1210.     mov [pdseg:esi*4     + Pdata.rmint_ptrs],edx ; RM IRQ
  1211.     inc si
  1212.     inc di
  1213.     add ax,HARDIRQ_HANDLER_SIZE
  1214.     add edx,SIZE Farptr16
  1215.     dec cl
  1216.     jne short @@hi1
  1217.  
  1218.     ; --------------- Copy RM HW Intvectors ---------------------
  1219.     mov bl,[picmasterold]
  1220.     mov bh,[picslaveold]
  1221.     push ds
  1222.     cld
  1223.     mov di,off 0+Pdata.rmint_copy
  1224.     copy es,pdseg,ax
  1225.     movzx si,bl
  1226.     shl si,2
  1227.     sub ax,ax
  1228.     mov ds,ax
  1229.     mov cx,(8*4)/2
  1230.     rep movsw
  1231.     movzx si,bh        ; NOP not needed
  1232.     shl si,2
  1233.     mov cx,(8*4)/2
  1234.     rep movsw
  1235.     mov si,off 0+Pdata.rmint_copy
  1236.     mov di,off 0+Pdata.rmint_old
  1237.     mov cx,(16*4)/2
  1238.     rep movs [word ptr es:di],[word ptr pdseg:si]
  1239.     pop ds            ; NOP not needed
  1240.  
  1241.     ; --------------- Set up RM wrappers ------------------------
  1242.     mov cl,8
  1243.     mov di,off rmwrapper
  1244.     mov si,off pic_ints
  1245. @@wrlp: mov [di+Farptr16.sel],cs
  1246.     mov [di+Farptr16.offset],si
  1247.     add si,PIC_INT_SIZE
  1248.     add di,SIZE Farptr16
  1249.     dec cl
  1250.     jne short @@wrlp
  1251.     call [SetMasterPIC]        ; set new pic base
  1252.  
  1253.     ; --------------- Set up exception handler tasks ------------
  1254.     sub di,di
  1255.     mov si,SELTASKS
  1256.     sub cx,cx
  1257.     mov bx,off 0 + Pdata.lowint
  1258. @@vxr_idt_loop2:
  1259.     mov ax,[pdseg:di + Pdata.idt.offset1]
  1260.     shl eax,16
  1261.     mov ax,[pdseg:di + Pdata.idt.offset0]
  1262.     mov [pdseg:bx + Farptr32.offset],eax
  1263.     mov ax,[pdseg:di + Pdata.idt.sel]
  1264.     mov [pdseg:bx + Farptr32.sel],ax
  1265.     mov [pdseg:bx + Farptr32.pad],0
  1266.  
  1267.     mov [pdseg:di + Pdata.idt.offset0],0
  1268.     mov [pdseg:di + Pdata.idt.offset1],0
  1269.     mov [pdseg:di + Pdata.idt.reserved],0
  1270.     mov [pdseg:di + Pdata.idt.sel],si
  1271.     mov [pdseg:di + Pdata.idt.gtype],85h    ; set to Task Gate
  1272.  
  1273.     add di,SIZE Gate
  1274.     add si,SIZE Descriptor
  1275.     add bx,SIZE Farptr32
  1276.     inc cx
  1277.     cmp cx,NUM_EXCEPTIONS
  1278.     jne @@vxr_idt_loop2
  1279.  
  1280. IF FAST_FPU_EMU EQ 1
  1281.     ; 'FPU not present' called by trap gate
  1282.     DB 66h
  1283.     mov [WORD PTR pdseg:(7*SIZE Gate) + Pdata.idt.offset0],off FPU_emulation
  1284.     DW 0
  1285.     mov [pdseg:(7*SIZE Gate) + Pdata.idt.reserved],0
  1286.     mov [pdseg:(7*SIZE Gate) + Pdata.idt.sel],SELCS
  1287.     mov [pdseg:(7*SIZE Gate) + Pdata.idt.gtype],8Fh
  1288. ENDIF
  1289.  
  1290.     ; Set up special ints
  1291.     mov [pdseg:8*31h+Pdata.idt.offset0],off int31 ; protected mode INT 31h
  1292.     mov [pdseg:8*21h+Pdata.idt.offset0],off int21 ; protected mode INT 21h
  1293.     mov [pdseg:8*23h+Pdata.idt.offset0],off int23pm ; pm INT 23h
  1294.     mov [pdseg:8*24h+Pdata.idt.offset0],off int24pm ; pm INT 24h
  1295.     mov [pdseg:8*2fh+Pdata.idt.offset0],off int2fpm ; pm INT 2fh
  1296.     ; Set callback for int23
  1297.     do16to32 mov,<[word ptr cs:hardirq_callback+16*HARDIRQ_CALLBACK_SIZE+HARDIRQ_CALLBACK_OFS]>,<off int23pm>
  1298.     mov [word ptr cs:hardirq_callback+16*HARDIRQ_CALLBACK_SIZE \
  1299.          +HARDIRQ_CALLBACK_SEL],SELCS
  1300.  
  1301. ;-----------------------------------------------------------------------------
  1302.  
  1303.     ptr2lin pdseg,<off 0+Pdata.pmstack>,ax,bx,eax,ebx
  1304.     mov [pmstackbase],eax
  1305.     ptr2lin pdseg,<off PMSTACKLEN + Pdata.pmstack>,ax,bx,eax,ebx
  1306.     mov [pmstacktop],eax
  1307.  
  1308. ;-----------------------------------------------------------------------------
  1309.  
  1310.     ptr2lin pdseg,<off 0 + Pdata.gdt>,ax,bx,eax,ebx
  1311.     mov [gdtbase],eax        ; set GDT base address
  1312.     mov [gdtlimit],(GDT_NUM_ENTRIES * SIZE Descriptor) - 1
  1313.  
  1314. ;-----------------------------------------------------------------------------
  1315.  
  1316.     ptr2lin pdseg,<off 0 + Pdata.vcpitss>,ax,bx,eax,ebx
  1317.     mov [pdseg:SELVCPITSS + Pdata.gdt.base0_15],ax
  1318.     shr eax,16
  1319.     mov [pdseg:SELVCPITSS + Pdata.gdt.base16_23],al
  1320.     mov [pdseg:SELVCPITSS + Pdata.gdt.base24_31],ah
  1321.     mov [pdseg:SELVCPITSS + Pdata.gdt.limit0_15],SIZE Tss-1
  1322.     mov [pdseg:SELVCPITSS + Pdata.gdt.types],0089h
  1323.  
  1324.     mov [vcpiswitchstack.offset],off VCPISTACKLEN+Pdata.vcpistack
  1325.     mov [vcpiswitchstack.sel],SELPRIVAT
  1326.  
  1327. ;-----------------------------------------------------------------------------
  1328.  
  1329.     setmemw [privatedataseg],<off 0+Pdata.vcpitss>,<SIZE Tss>
  1330.                     ; clear Switch TSS
  1331.     mov es,[privatedataseg]
  1332.     mov eax,[vcpi_cr3]        ; set CR3 in TSS
  1333.     mov [es:Pdata.vcpitss.cr3],eax
  1334.     mov [es:Pdata.vcpitss.iomapbase],SIZE Tss
  1335.  
  1336. ;-----------------------------------------------------------------------------
  1337.  
  1338.     mov [WORD PTR pdseg:-2+Pdata.exceptionstack],0
  1339.     mov di,off 0 + Pdata.exceptiontasks    ; set up exception tasks
  1340.     sub esi,esi
  1341.     mov si,off common_exception_without_error_handler
  1342.     mov edx,[vcpi_cr3]            ; EDX = page directory
  1343.     sub ecx,ecx
  1344. @@exceptiontaskloop:
  1345.     push cx di
  1346.     setmemw pdseg,di,<SIZE Tss>        ; Clear exception task
  1347.     pop di cx
  1348.  
  1349.     mov [pdseg:di + Tss.ss0],SELPRIVAT
  1350.     mov [pdseg:di + Tss.esp0],off 0+Pdata.exceptionstack
  1351.     mov [pdseg:di + Tss.ss1],SELPRIVAT
  1352.     mov [pdseg:di + Tss.esp1],off 0+Pdata.exceptionstack
  1353.     mov [pdseg:di + Tss.ss2],SELPRIVAT
  1354.     mov [pdseg:di + Tss.esp2],off 0+Pdata.exceptionstack
  1355.     mov [pdseg:di + Tss.ss],SELPRIVAT
  1356.     mov [pdseg:di + Tss.esp],off 0+Pdata.exceptionstack
  1357.  
  1358.     mov [pdseg:di + Tss.cs],SELCS
  1359.     mov [pdseg:di + Tss.eip],esi
  1360.  
  1361.     mov [pdseg:di + Tss.ds],SELPRIVAT    ; es and ds are needed
  1362.     mov [pdseg:di + Tss.es],SELDS
  1363.  
  1364.     mov [pdseg:di + Tss.eflags],0
  1365.  
  1366.     mov [pdseg:di + Tss.cr3],edx
  1367.     mov [pdseg:di + Tss.iomapbase],SIZE Tss
  1368.  
  1369.     mov [pdseg:di + Tss.ebx],ecx        ; store exception number
  1370.  
  1371.     push cx
  1372.     and cl,7
  1373.     mov ah,1
  1374.     shl ah,cl                ; ah is mask for pic
  1375.     pop cx
  1376.  
  1377.     mov al,cl                ; al is high 5 bits of cx used
  1378.     and al,0f8h                ; to compare to pic base
  1379.     mov [pdseg:di + Tss.eax],eax
  1380.     mov [pdseg:di + Tss.edx],off 0 + Pdata.exceptionstack
  1381.  
  1382.     cmp al,8            ; exceptions 8, 9-0eh have error
  1383.     jne short @@go_on        ; and we can skip the checking
  1384.     cmp cl,9
  1385.     je short @@go_on
  1386.     cmp cl,0fh
  1387.     je short @@go_on
  1388.     sub eax,eax
  1389.     mov ax,off common_exception_with_error_handler
  1390.     mov [pdseg:di + Tss.eip],eax
  1391. @@go_on:
  1392.  
  1393.     mov [pdseg:di + Tss.ecx],0    ; to be used as default error code
  1394.  
  1395.     add di,SIZE Tss
  1396.     inc cx
  1397.     cmp cx,NUM_EXCEPTIONS
  1398.     jne @@exceptiontaskloop
  1399.  
  1400. ;-----------------------------------------------------------------------------
  1401.  
  1402.     ptr2lin pdseg,<off 0+Pdata.exceptiontasks>,ax,bx,eax,ebx
  1403.     mov bx,SELTASKS
  1404.     mov ecx,SIZE Tss-1        ; Limit
  1405.     mov dx,1089h            ; waiting Task
  1406.     sub si,si
  1407. @@taskgateloop:
  1408.     push eax dx
  1409.     mov [pdseg:bx + Pdata.gdt.limit0_15],cx ; limit = CX
  1410.     mov [pdseg:bx + Pdata.gdt.base0_15],ax
  1411.     shr eax,16
  1412.     mov [pdseg:bx + Pdata.gdt.base16_23],al
  1413.     mov [pdseg:bx + Pdata.gdt.base24_31],ah
  1414.     mov eax,ecx
  1415.     shr eax,8
  1416.     and dh,0F0h                ; Clear limit16_19
  1417.     or dh,ah                ; Set it
  1418.     mov [pdseg:bx + Pdata.gdt.types],dx    ; access rights = DX
  1419.     add bx,8
  1420.     pop dx eax
  1421.  
  1422.     add eax,SIZE Tss
  1423.     inc si
  1424.     cmp si,NUM_EXCEPTIONS
  1425.     jne @@taskgateloop
  1426.  
  1427. ;-----------------------------------------------------------------------------
  1428.  
  1429.     init_dsc 0,SELCORE,0FFFFFh,0D092h
  1430.  
  1431.     init_dsc cs,SELCS,0FFFFh,109Ah    ; Make selector for CS
  1432.     init_dsc 0,SELREAL,ecx,1092h    ; set real mode attributes descriptor
  1433.     init_dsc cs,SELALIASCS,ecx,5092h; To write to CS in protected mode
  1434.     init_dsc ds,SELDS,ecx,dx    ; Make selector for DS
  1435. IF SUPPORT_INT_24
  1436.     init_dsc ax,SELINT24,ecx,dx    ; Make selector for INT 24 callback
  1437. ENDIF
  1438.     init_dsc pdseg,SELPRIVAT,<SIZE Pdata>,dx
  1439.  
  1440.  
  1441.     mov bx,SIZE Descriptor*SYSSELECTORS ; BX = base of free descriptors
  1442.     push bx                ; store CS selector
  1443.     init_dsc cs,bx,0FFFFh,109Ah    ; make caller cs selector
  1444.     push bx bx            ; store SS and DS selectors
  1445.  
  1446.     init_dsc ss,bx,ecx,5092h    ; set caller SS descriptor
  1447.  
  1448.     mov ax,ds
  1449.     mov si,ss            ; SS = DS?
  1450.     cmp ax,si
  1451.     jz short @@skip            ; if so, they have to be equal!
  1452.     pop ax                ; else set new selector for DS
  1453.     push bx
  1454.     init_dsc ds,bx,ecx,dx
  1455. @@skip:
  1456.     push bx                ; get PSP segment
  1457.     mov ah,51h
  1458.     int 21h
  1459.     mov es,bx            ; set caller environment descriptor
  1460.     mov si,bx
  1461.     pop bx
  1462.  
  1463.     mov ax,[es:2ch]
  1464.     or ax,ax            ; is environment seg 0?
  1465.     jz short @@vxr_initf0        ; if yes, dont convert to descriptor
  1466.     mov [es:2ch],bx            ; store selector value in PSP
  1467.     init_dsc ax,bx,ecx,dx
  1468.  
  1469. @@vxr_initf0:
  1470.     init_dsc si,bx,0FFh,dx        ; set caller PSP descriptor
  1471.  
  1472. ;-----------------------------------------------------------------------------
  1473.  
  1474.     lea ecx,[ebx-8]            ; CX = ES descriptor, just set
  1475.     pop ax                ; AX = DS descriptor, from datasegment
  1476.     pop dx                ; DX = SS descriptor, from stack
  1477.     pop si                ; target CS, from codesegment
  1478.     mov di,off @@vxr_initf2        ; target EIP
  1479.     movzx ebx,sp            ; EBX = SP, current SP - same stack
  1480.     movzx edi,di
  1481.  
  1482.     jmp [rmtopmswrout]        ; jump to mode switch routine
  1483.  
  1484. @@vxr_initf2:
  1485.     copy coreseg,SELCORE,ax
  1486.     copy pdseg,SELDS,ax
  1487.  
  1488.     mov eax,[coreseg:4*2Fh]        ; check if multiplex set
  1489.     mov [pdseg:oldint2fvector],eax
  1490.     or eax,eax
  1491.     jnz short @@ok
  1492.     DB 66h
  1493.     mov [WORD PTR coreseg:4*2Fh],off int2frm ; set multiplex
  1494.     DW _TEXT
  1495. @@ok:
  1496.     DB 66h                    ; set new INT 23h handler
  1497.     mov [WORD PTR coreseg:4*23h],off hardirq_callback+16*HARDIRQ_CALLBACK_SIZE
  1498.     DW _TEXT
  1499.     DB 66h
  1500.     mov [WORD PTR coreseg:4*24h],off int24rm ; set new INT 24h handler
  1501.     DW _TEXT
  1502.     push ds
  1503.     copy ds,SELALIASCS,ax
  1504.     mov bx,off oldint21vector    ; setting direct makes tlink puke
  1505.     mov eax,[coreseg:4*21h]        ; get DOS vector
  1506.     mov [ds:bx],eax            ; save
  1507.     pop ds
  1508.     DB 66h
  1509.     mov [WORD PTR coreseg:4*21h],off dos21rm ; set new DOS vector
  1510.     DW _TEXT
  1511.  
  1512.     mov eax,[coreseg:4*15h]        ; get INT 15h vector
  1513.     mov [pdseg:oldint15vector],eax    ; store INT 15h vector
  1514.  
  1515.     mov esi,[pdseg:rawextmembase]    ; ESI = raw base of extended memory
  1516.     cmp esi,[pdseg:rawextmemtop]    ; is there any raw extended memory?
  1517.     jae dvxr_init            ; if no, go DPMI/VCPI/XMS/raw init
  1518.  
  1519.     DB 66h
  1520.     mov [WORD PTR coreseg:4*15h],off int15 ; MOV [4*15],_TEXT:offset int15
  1521.     DW _TEXT            ; set new INT 15h handler
  1522.  
  1523.     mov edi,[pdseg:rawextmemtop]    ; EDI = raw top of extended memory
  1524.     mov eax,edi            ; EAX = size of extended memory
  1525.     sub eax,esi
  1526.     sub eax,10h            ; subtract memory control block size
  1527.     mov [coreseg:edi-16],eax    ; store size in memory control block
  1528.     xor eax,eax
  1529.     mov [coreseg:edi-12],eax    ; no next memory control block
  1530.     mov [coreseg:edi-8],eax        ; no previous memory control block
  1531.     mov [coreseg:edi-4],al        ; memory block is free
  1532.  
  1533.     jmp dvxr_init            ; go to DPMI/VCPI/XMS/raw init tail
  1534.  
  1535. ;─────────────────────────────────────────────────────────────────────────────
  1536. ; set descriptor for VCPI/XMS/raw init
  1537. ; In
  1538. ;   ax      = real mode segment
  1539. ;   bx      = Selector
  1540. ;   ecx      = limit
  1541. ;   dx      = access rights/type
  1542. ;   pdseg = segment to privat data
  1543. ; Out
  1544. ;   bx+8, trashes eax
  1545. vxr_initsetdsc:
  1546.     push dx
  1547.     movzx eax,ax                ; EAX = base of segment
  1548.     shl eax,4
  1549.     mov [pdseg:bx + Pdata.gdt.limit0_15],cx ; limit = CX
  1550.     mov [pdseg:bx + Pdata.gdt.base0_15],ax
  1551.     shr eax,16
  1552.     mov [pdseg:bx + Pdata.gdt.base16_23],al
  1553.     mov [pdseg:bx + Pdata.gdt.base24_31],ah
  1554.     mov eax,ecx
  1555.     shr eax,8
  1556.     and dh,0F0h                ; Clear limit16_19
  1557.     or dh,ah                ; Set it
  1558.     mov [pdseg:bx + Pdata.gdt.types],dx    ; access rights = DX
  1559.     add bx,8
  1560.     pop dx
  1561.     ret
  1562. ; [fold]  ]
  1563.  
  1564. ;═════════════════════════════════════════════════════════════════════════════
  1565. ; [fold]  [
  1566. x_init: ; XMS protected mode init
  1567.     push es
  1568.     mov ax,4310h            ; get XMS driver address
  1569.     int 2fh
  1570.     mov [xms_call.offset],bx    ; store XMS driver address
  1571.     mov [xms_call.sel],es
  1572.     pop es
  1573.  
  1574.     call x_seta20            ; enable A20
  1575.     mov bx,4            ; error code 0004h in case of error
  1576.     cmp ax,1            ; error enabling A20?
  1577.     jc init_done            ; if yes, exit with error 0004h
  1578.  
  1579.     mov [SetA20],off x_seta20    ; procedure to enable a20 under XMS
  1580.     mov [ResetA20],off x_reseta20    ; resets a20 to startup state
  1581.  
  1582.     mov si,off int31mxrouttbl    ; set XMS memory allocation functions
  1583. ; [fold]  ]
  1584.  
  1585. ;─────────────────────────────────────────────────────────────────────────────
  1586. ; [fold]  [
  1587. xr_init: ; XMS/raw common init tail
  1588.     mov eax,[dword ptr int31physxrtbl] ; copy physical mapping functions
  1589.     mov [dword ptr int31phystbl],eax
  1590.  
  1591.     mov [rmtopmswrout],off xr_rmtopmsw ; set XMS/raw mode switch addresses
  1592.     mov [pmtormswrout],off xr_pmtormsw
  1593.  
  1594.     mov [SetMasterPIC],off xr_setpic ; set XMS/raw PIC program address
  1595.     mov [ResetMasterPIC],off xr_resetpic
  1596.  
  1597.     mov [picmasterold],8        ; assuming standard PIC mappings
  1598.     mov [picslaveold],70h
  1599.  
  1600.     mov ebx,cr0            ; get CR0
  1601.     mov [oldCR0L],bl        ; save old state
  1602.     sar bl,1
  1603.     and bl,3
  1604.     mov [newEM_MP],bl
  1605.  
  1606.     jmp vxr_init            ; go to VCPI/XMS/raw continue init
  1607. ; [fold]  ]
  1608.  
  1609. ;═════════════════════════════════════════════════════════════════════════════
  1610. ; [fold]  [
  1611. r_init: ; raw protected mode init
  1612.     mov [SetA20],off r_seta20    ; procedure to enable a20 under raw
  1613.     mov [ResetA20],off r_reseta20    ; resets a20 to startup state
  1614.  
  1615.     mov ah,88h            ; how much extended memory free
  1616.     int 15h
  1617.  
  1618.     mov si,off int31mnrouttbl    ; SI -> no memory allocation functions
  1619.     or ax,ax            ; if none, done with raw init
  1620.     jz xr_init
  1621.  
  1622.     movzx eax,ax            ; convert AX K to ptr to top of mem
  1623.     shl eax,10
  1624.     add eax,100000h
  1625.     mov [rawextmemtop],eax
  1626.  
  1627.     call r_seta20            ; enable A20
  1628.     mov bx,4
  1629.     jc init_done
  1630.  
  1631.     xor cx,cx            ; ES -> 0 (interrupt vector table)
  1632.     mov es,cx
  1633.     les bx,[dword ptr es:4*19h]    ; ES:BX -> int vector table
  1634.  
  1635.     mov eax,100000h            ; initial free extended memory base
  1636.     cmp [dword ptr es:bx+12h],'SIDV'; VDISK memory allocation?
  1637.     jne short @@r_initf0        ; if present, get base of free mem
  1638.  
  1639.     mov eax,[dword ptr es:bx+2ch]    ; get first free byte of extended mem
  1640.     add eax,0fh            ; align on paragraph
  1641.     and eax,0fffff0h        ; address is only 24bit
  1642.  
  1643. @@r_initf0:
  1644.     dec cx                ; ES -> 0ffffh for ext mem addressing
  1645.     mov es,cx
  1646.  
  1647.     cmp [dword ptr es:13h],'SIDV'   ; VDISK memory allocation?
  1648.     jne short @@r_initf1        ; if present, get base of free mem
  1649.  
  1650.     movzx ebx,[word ptr es:2eh]    ; get first free K of extended memory
  1651.     shl ebx,10            ; adjust K to bytes
  1652.  
  1653.     cmp eax,ebx            ; pick larger of 2 addresses
  1654.     ja short @@r_initf1
  1655.  
  1656.     mov eax,ebx
  1657.  
  1658. @@r_initf1:
  1659.     mov si,off int31mnrouttbl    ; SI -> no memory allocation functions
  1660.     cmp eax,[rawextmemtop]        ; any valid free extended memory
  1661.     jae xr_init            ; if none, done with raw init
  1662.  
  1663.     mov [rawextmembase],eax
  1664.     mov si,off int31mrrouttbl    ; set raw memory allocation functions
  1665.  
  1666.     jmp xr_init            ; go to XMS/raw continue init
  1667. ; [fold]  ]
  1668.  
  1669. ; [fold]  ]
  1670.  
  1671. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1672. ; PROTECTED MODE KERNEL CODE
  1673. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  1674. ; [fold]  [
  1675.  
  1676. ;═════════════════════════════════════════════════════════════════════════════
  1677. ; [fold]  [
  1678. ; VCPI real to protected switch
  1679. v_rmtopmsw:
  1680.     pushf                ; store FLAGS
  1681.     cli
  1682.     push DGROUP
  1683.     pop ds
  1684.     pop [temp0.w0]            ; move FLAGS from stack to temp
  1685.     mov [temp0.w1],ax        ; store AX (protected mode DS)
  1686.     mov [temp1.w0],si        ; store SI (protected mode CS)
  1687.     mov esi,[lvcpistruc]        ; ESI = linear addx of VCPI structure
  1688.     mov ax,0de0ch            ; VCPI switch to protected mode
  1689.     int 67h
  1690. v_rmtopmswpm:
  1691.     mov ax,SELDS
  1692.     mov ds,ax
  1693.     mov es,cx            ; load protected mode es
  1694.     xor eax,eax
  1695.     mov fs,ax            ; load protected mode FS with NULL
  1696.     mov gs,ax            ; load protected mode GS with NULL
  1697.     mov ax,[temp0.w0]
  1698.     and ax,0bfffh            ; clear NT flag
  1699.     push eax
  1700.     popfd
  1701.     mov ss,dx            ; load protected mode SS:ESP
  1702.     mov esp,ebx
  1703.     push [temp1.d0]            ; push cs
  1704.     push edi            ; push eip
  1705.     mov ds,[temp0.w1]        ; caller ds
  1706.     DB 66h
  1707.     retf                ; go to target addx in protected mode
  1708. ; [fold]  ]
  1709.  
  1710. ;═════════════════════════════════════════════════════════════════════════════
  1711. ; [fold]  [
  1712. ; VCPI protected to real switch
  1713. v_pmtormsw:
  1714.     pushf                ; store FLAGS
  1715.     cli
  1716.     push SELCORE
  1717.     pop ds                ; for VCPI server
  1718.     push SELDS
  1719.     pop es
  1720.     pop [es:temp0.w0]        ; store flags
  1721.     mov [es:temp0.w1],ax        ; save AX (real mode DS)
  1722.     lss esp,[es:vcpiswitchstack.ptr] ; set up switchstack
  1723.     sub ax,ax
  1724.     push eax            ; real mode GS
  1725.     push eax            ; real mode FS
  1726.     push DGROUP            ; real mode DS
  1727.     push ecx            ; real mode ES
  1728.     push edx            ; real mode SS
  1729.     push 0 bx            ; real mode ESP
  1730.     push eax            ; reserved
  1731.     DB 66h
  1732.     push _TEXT            ; push dword _TEXT
  1733.     DW 0                ; real mode entry CS
  1734.     DB 66h
  1735.     push off @@v_pmtormswf0        ; push dword value
  1736.     DW 0                ; real mode entry IP
  1737.     mov ax,0de0ch            ; VCPI switch to real mode (V86)
  1738.     call [es:vcpi_service.ptr]
  1739. @@v_pmtormswf0:
  1740.     push [temp0.w0]            ; store old FLAGS
  1741.     mov ds,[temp0.w1]        ; get caller ds
  1742.     push si                ; store target CS in real mode
  1743.     push di                ; store target IP in real mode
  1744.     iret                ; go to target addx in real mode
  1745. ; [fold]  ]
  1746.  
  1747. ;═════════════════════════════════════════════════════════════════════════════
  1748. ; [fold]  [
  1749. ; XMS/raw real to protected switch
  1750. xr_rmtopmsw:
  1751.     pushfd                ; store EFLAGS
  1752.     cli
  1753.     push DGROUP
  1754.     pop ds
  1755.     push [vcpi_seltss]
  1756.     push si                ; save SI
  1757.     lidt [fword ptr idtlimit]    ; load protected mode IDT
  1758.     lgdt [fword ptr gdtlimit]    ; load protected mode GDT
  1759.     mov si,[vcpi_seltss]
  1760.     mov ds,[privatedataseg]
  1761.     mov [ds:si + Pdata.gdt.types],0089h ; Clear busy bit
  1762.     mov esi,cr0            ; switch to protected mode
  1763.     or si,1
  1764.     mov cr0,esi
  1765.     db 0eah                ; JMP FAR PTR SELCODE:$+4
  1766.     dw $+4,SELCS            ;  (clear prefetch que)
  1767.     pop si
  1768.     mov ds,ax            ; load protected mode DS
  1769.     mov es,cx            ; load protected mode ES
  1770.     xor ax,ax
  1771.     mov fs,ax            ; load protected mode FS with NULL
  1772.     mov gs,ax            ; load protected mode GS with NULL
  1773.     lldt ax                ; load protected mode LDT
  1774.     pop ax                ; set up task register
  1775.     ltr ax                ; load protected mode TR
  1776.     clts                ; free coprocessor
  1777.     pop eax
  1778.     mov ss,dx            ; load protected mode SS:ESP
  1779.     mov esp,ebx
  1780.     and ah,0bfh            ; set NT=0 in old EFLAGS
  1781.     push eax            ; set current EFLAGS
  1782.     popfd
  1783.     push esi            ; store protected mode target CS
  1784.     push edi            ; store protected mode target EIP
  1785.     DB 66h
  1786.     retf                ; go to targed addx in protected mode
  1787. ; [fold]  ]
  1788.  
  1789. ;═════════════════════════════════════════════════════════════════════════════
  1790. ; [fold]  [
  1791. ; XMS/raw protected to real switch
  1792. xr_pmtormsw:
  1793.     pushf                ; store FLAGS
  1794.     cli
  1795.     push SELDS
  1796.     pop ds
  1797.     mov [temp0.w0],ax        ; move real mode DS to temp
  1798.     pop [temp0.w1]            ; move FLAGS from stack to temp
  1799.     lidt [fword ptr rmidtlimit]    ; load real mode IDT
  1800.     mov ax,SELREAL            ; load descriptors with real mode seg
  1801.     mov ds,ax            ;  attributes
  1802.     mov es,ax
  1803.     mov fs,ax
  1804.     mov gs,ax
  1805.     mov ss,ax            ; load descriptor with real mode attr
  1806.     movzx esp,bx            ; load real mode SP, high word 0
  1807.     mov eax,cr0            ; switch to real mode
  1808.     and al,0feh
  1809.     mov cr0,eax
  1810.     db 0eah                ; JMP FAR PTR PMODE_TEXT:$+4
  1811.     dw $+4,_TEXT            ;  (clear prefetch que)
  1812.     mov ss,dx            ; load real mode SS
  1813.     mov es,cx            ; load real mode ES
  1814.     xor ax,ax
  1815.     mov fs,ax            ; load real mode FS with NULL
  1816.     mov gs,ax            ; load real mode GS with NULL
  1817.     copy ds,DGROUP,ax        ; datasegment
  1818.     push [temp0.w1]            ; store old FLAGS
  1819.     mov ds,[temp0.w0]        ; load real mode DS
  1820.     push si                ; store real mode target CS
  1821.     push di                ; store real mode target IP
  1822.     iret                ; go to target addx in real mode
  1823. ; [fold]  ]
  1824.  
  1825. ;═════════════════════════════════════════════════════════════════════════════
  1826. ; [fold]  [
  1827. ; General interrupt handler
  1828. common_int_handler:
  1829.     REPT 256
  1830.     DB 0E8h
  1831.     DW @@int_handler - 2 - $    ; call @@int_handler
  1832.     DB 90h                ; align
  1833.     ENDM
  1834. INT_HANDLER_SIZE = ($ - common_int_handler) / 256
  1835. IF INT_HANDLER_SIZE NE 4
  1836. ERR INT_HANDLER_SIZE must be 4! Or change the code (good luck...)
  1837. ENDIF
  1838. @@int_handler:
  1839.     push gs fs ds es
  1840.     pushad                ; store general registers
  1841.     pushf
  1842.     and [WORD PTR esp],NOT 300h    ; Clear IF and TF
  1843.     popf
  1844.     copy ds,SELDS,ax
  1845.     copy pdseg,SELPRIVAT,ax
  1846.     copy coreseg,SELCORE,ax
  1847.  
  1848.     mov dx,[rmstacktop]
  1849.     movzx ebx,dx
  1850.     sub dx,RMONESTACKLEN
  1851.     cmp dx,[rmstackbase]        ; exceeded real mode stack space?
  1852.     jb critical_error        ; if yes, critical error (hang)
  1853.     mov [rmstacktop],dx        ; update for possible reentrancy
  1854.  
  1855.     mov si,[esp+40]            ; get "return" address
  1856.     sub si,3 + off common_int_handler
  1857.     mov esi,[pdseg:si + Pdata.rmint_ptrs] ; get intvector offset pointer
  1858.     sub bx,50            ; space on real mode stack
  1859.     mov ax,[esp+50]            ; get flags
  1860.     and ax,NOT 300h            ; Clear IF and TF (like in real mode)
  1861.     mov [pdseg:bx+32],ax        ; put FLAGS
  1862.     mov [pdseg:bx+42],ax
  1863.     copy [pdseg:bx+34],[coreseg:esi],eax
  1864.     DB 66h
  1865.     mov [word ptr pdseg:bx+38],off @@inte
  1866.     DW _TEXT
  1867.     mov [pdseg:bx+44],esp        ; protected mode stack
  1868.     mov [pdseg:bx+48],ss        ; to return to protected mode
  1869.  
  1870.     dmemcpyw ss,esp,pdseg,ebx,32    ; copy to real mode stack
  1871.  
  1872.     mov dx,[privatedataseg]
  1873.     mov si,_TEXT
  1874.     mov di,off @@intrirqf0
  1875.     jmp [pmtormswrout]        ; switch to real mode
  1876.  
  1877. @@intrirqf0:
  1878.     popad                ; get general registers
  1879.     popf
  1880.     retf                ; jump into rm int
  1881. @@inte: pushf
  1882.     pushad                ; store general registers
  1883.     copy ds,DGROUP,ax
  1884.     movzx ebp,sp
  1885.     mov dx,[bp+38]        ; protected mode SS
  1886.     mov ebx,[bp+34]        ; protected mode ESP
  1887.     mov si,SELCS        ; protected mode CS
  1888.     mov di,off @@intrirqf1
  1889.     movzx edi,di        ; protected mode EIP
  1890.     mov cx,SELPRIVAT    ; protected mode ES
  1891.     mov ax,SELDS        ; protected mode DS
  1892.     jmp [rmtopmswrout]    ; jump back to protected mode
  1893.  
  1894. @@intrirqf1:
  1895.     add [rmstacktop],RMONESTACKLEN        ; adjust realmode stack
  1896.     mov ax,[es:bp+32]            ; get real mode flags
  1897.     and [WORD PTR ss:esp+50],200h        ; Change all except IF
  1898.     and ax,NOT 200h                ; Clear IF
  1899.     or [ss:esp+50],ax            ; set return flags
  1900.     dmemcpyw es,ebp,ss,esp,32        ; copy general registers
  1901.  
  1902.     popad
  1903.     pop es ds fs gs                ; restore all registers
  1904.     add esp,2                ; kill interrupt #
  1905.     iretd
  1906. ; [fold]  ]
  1907.  
  1908. ;═════════════════════════════════════════════════════════════════════════════
  1909. ; [fold]  [
  1910. ; General hardware IRQ handler (faster than above)
  1911. common_hardirq_handler:
  1912. count = 0
  1913.     REPT 16
  1914.     DB 6Ah
  1915.     DB count            ; push offet in rmint_master table
  1916.     jmp short @@hard_handler
  1917. count = count + (SIZE Farptr16)
  1918.     ENDM
  1919. HARDIRQ_HANDLER_SIZE = ($ - common_hardirq_handler) / 16
  1920. @@hard_handler:
  1921.     push 0 ds es fs gs
  1922.     pushad                ; store general registers
  1923.     copy ds,SELDS,ax
  1924.     copy pdseg,SELPRIVAT,ax
  1925.  
  1926.     mov dx,[rmstacktop]
  1927.     movzx ebx,dx
  1928.     sub dx,RMONESTACKLEN
  1929.     cmp dx,[rmstackbase]        ; exceeded real mode stack space?
  1930.     jb critical_error        ; if yes, critical error (hang)
  1931.     mov [rmstacktop],dx        ; update for possible reentrancy
  1932.  
  1933.     mov si,[ss:esp+42]        ; get intvector
  1934.     sub bx,6            ; space on real mode stack
  1935.     DB 66h
  1936.     mov [WORD PTR pdseg:bx],off @@entr
  1937.     DW _TEXT
  1938.     mov [word ptr pdseg:bx+4],0    ; put flags on rm iret frame
  1939.     mov ebp,esp            ; EBP = pm ESP
  1940.     mov dx,[privatedataseg]        ; set dx to real mode ss
  1941.     mov cx,ss            ; ES = pm SS
  1942.     mov di,[pdseg:si+Pdata.rmint_copy.offset] ; offset of rm int
  1943.     mov ax,DGROUP
  1944.     mov si,[pdseg:si+Pdata.rmint_copy.sel]      ; segment of rm int
  1945.     jmp [pmtormswrout]        ; switch to real mode
  1946.  
  1947. ; regs won't change, because this is an hardware int
  1948. @@entr: mov dx,es            ; protected mode SS
  1949.     mov ebx,ebp            ; protected mode ESP
  1950.     mov si,SELCS            ; protected mode CS
  1951.     do16to32 mov,di,<off @@intrirqf1> ; mov edi,off @@intrirqf1
  1952.     mov cx,SELDS            ; protected mode ES
  1953.     mov ax,cx            ; protected mode DS
  1954.     jmp [rmtopmswrout]        ; jump back to protected mode
  1955.  
  1956. @@intrirqf1:
  1957.     add [rmstacktop],RMONESTACKLEN    ; adjust realmode stack
  1958.     popad
  1959.     pop gs fs es ds            ; restore all registers
  1960.     add esp,4            ; kill interrupt #
  1961.     iretd
  1962. ; [fold]  ]
  1963.  
  1964. ;═════════════════════════════════════════════════════════════════════════════
  1965. ; [fold]  [
  1966. ; Hardware IRQ callback. (for simulating v86 mode)
  1967. hardirq_callback:
  1968.     REPT 17                ; used for int23 also
  1969.     DB 68h
  1970.     DW -1                ; push selector of pm int
  1971.     DB 66h,68h
  1972.     DD -1                ; push offset of pm int
  1973.     DB 0E9h
  1974.     DW @@hardirq_callback - 2 - $    ; jump @@hardirq_callback:
  1975.     ENDM
  1976. HARDIRQ_CALLBACK_SIZE = ($ - hardirq_callback) / 16
  1977. HARDIRQ_CALLBACK_SEL  = 1
  1978. HARDIRQ_CALLBACK_OFS  = 5
  1979. @@hardirq_callback:
  1980.     push gs fs ds es        ; cli not needed, because ints are
  1981.     pushad                ; disabled automatically on RM HW Ints
  1982.     copy ds,DGROUP,ax
  1983.     mov bp,ss            ; save real mode stack for later
  1984.     shl ebp,16
  1985.     mov bp,sp
  1986.  
  1987.     xor eax,eax            ; EAX = base address of SS
  1988.     mov ax,ss
  1989.     shl eax,4
  1990.     movzx ebx,sp            ; EBX = stack in prot. mode
  1991.     add ebx,eax
  1992.  
  1993.     mov ax,SELDS            ; DS selector for protected mode
  1994.     mov cx,ax            ; ES selector for protected mode
  1995.     mov dx,SELCORE            ; SS selector
  1996.     mov si,SELCS            ; target protected mode CS:EIP
  1997.     do16to32 mov,di,<off @@callbackf0> ; mov edi,off @@callbackf0
  1998.     jmp [rmtopmswrout]        ; go to protected mode
  1999.  
  2000. @@callbackf0:
  2001.     push ebp            ; save real mode stack
  2002.     pushfd                ; simulate interrupt
  2003.     call [ss:esp+48+Farptr32.ptr]    ; call pm int
  2004.     pop bx                ; BX = real mode SP
  2005.     pop dx                ; DX = real mode SS
  2006.     mov si,_TEXT            ; SI = real mode CS
  2007.     mov di,off @@callbackf2        ; DI = real mode IP
  2008.     jmp [pmtormswrout]        ; switch to real mode
  2009.  
  2010. @@callbackf2:
  2011.     mov bp,sp
  2012.     mov eax,[bp + Dpmi_regs.res]    ; get old highword of esp
  2013.     mov ax,sp
  2014.     mov esp,eax            ; restore old esp
  2015.  
  2016.     popad
  2017.     pop es ds fs gs            ; restore old regvalues
  2018.     add sp,6
  2019.     iret
  2020. ; [fold]  ]
  2021.  
  2022. ;═════════════════════════════════════════════════════════════════════════════
  2023. ; [fold]  [
  2024. ; handler for NMI interrupt.
  2025. NMI_exception:
  2026.     pushfd
  2027.     push large cs
  2028.     push 0
  2029.     call common_int_handler + 2*INT_HANDLER_SIZE
  2030.     DB 66h
  2031.     retf
  2032. ; [fold]  ]
  2033.  
  2034. ;═════════════════════════════════════════════════════════════════════════════
  2035. ; [fold]  [
  2036. ; special handler for emulating the FPU.
  2037. IF FAST_FPU_EMU EQ 1
  2038. EX_SIZE EQU 100        ; bytes to be made available on the user stack
  2039.             ; djgpp v2 requires 92 bytes (exception structure size)
  2040.             ; in the release version, while beta4 needs 0
  2041. FPU_emulation:
  2042.     sub esp,EX_SIZE+6    ; leave required bytes plus slot for ds and edi
  2043.     push ss
  2044.     push esp
  2045.     add [DWORD PTR esp],EX_SIZE+20    ; esp before exception
  2046.     push [DWORD PTR esp+EX_SIZE+20] ; move eflags
  2047.     push [DWORD PTR esp+EX_SIZE+20] ; move cs
  2048.     push [DWORD PTR esp+EX_SIZE+20] ; move eip
  2049.     push eax            ; dummy error code
  2050.     push large cs            ; return segment
  2051.     db 66h
  2052.     push off FPU_emulation_end    ; return address
  2053.     dw 0
  2054.     db 66h, 0EAh            ; jmp far to 32 bit offset
  2055. FPU_emu_vector Farptr32 <0,0,0>
  2056.  
  2057. FPU_emulation_end:
  2058.     add esp,4            ; kill error code
  2059.     mov [esp+18],edi        ; store edi and ds
  2060.     mov [esp+22],ds
  2061.     sub [dword ptr esp+12],12    ; make room for iret frame
  2062.     lds edi,[esp+12]
  2063.     pop [DWORD PTR ds:edi]        ; get EIP
  2064.     pop [DWORD PTR ds:edi+4]    ; get CS
  2065.     pop [DWORD PTR ds:edi+8]    ; get EFLAGS
  2066.     lds edi,[esp+6]            ; restore ds and edi
  2067.     lss esp,[esp]            ; switch to requested stack
  2068.     iretd
  2069. ENDIF
  2070. ; [fold]  ]
  2071.  
  2072. ;═════════════════════════════════════════════════════════════════════════════
  2073. ; [fold]  [
  2074. ; Exception handler code
  2075. ; We get here through a task switch. ds is SELPRIVAT, es is SELDS, bx is
  2076. ; exception number, al is bl & 0f8h, ah is 1<<(bl&7) (both used for user
  2077. ; int identification), dx is Pdata.exceptionstack, ecx is 0.
  2078. ; ints are disabled, for details, see vxr_init
  2079.  
  2080.     ASSUME ds:NOTHING
  2081. common_exception_with_error_handler:
  2082.     push 2
  2083.     popf                ; Clear NT flag, disable ints
  2084.  
  2085.     cmp sp,dx            ; Error code on stack?
  2086.     jz short do_user_int        ; yes, its an exception
  2087.     pop ecx                ; pop error code
  2088.     jmp do_exception
  2089.  
  2090. common_exception_without_error_handler:
  2091.     push 2
  2092.     popf                ; Clear NT flag, disable ints
  2093.  
  2094.     mov dx,020h            ; port for master pic
  2095.     cmp al,[es:picmasternew]
  2096.     je short @@test_hw_int
  2097.     mov dx,0a0h            ; port for slave pic
  2098.     cmp al,[es:picslavenew]
  2099.     jne short @@test_sw_int
  2100.  
  2101. ; This code assumes that the appropriate hardware int is enabled. I may add
  2102. ; code to fix that, but the probability of this causing trouble is extremely
  2103. ; low and only possible in strange configurations.
  2104. @@test_hw_int:
  2105.     mov al,0bh            ; read ISR
  2106.     out dx,al            ; dx is pic port
  2107.     jmp short $+2
  2108.     in al,dx
  2109.     and al,ah            ; mask is already in ah
  2110.     jnz short do_user_int        ; it is an exception
  2111.  
  2112. ; There is a probability of wrong identification here if an exception occurs
  2113. ; after an instruction that ends with the sequence 0cdxxh where xx is the
  2114. ; exception number.
  2115. @@test_sw_int:
  2116.     mov edi,[ds:Pdata.vcpitss.eip]
  2117.     cmp edi,2            ; is it the beginning of the segment
  2118.     jb do_exception            ; so that int instruction doesn't fit?
  2119.     mov ax,[ds:Pdata.vcpitss.cs]
  2120.     mov fs,ax
  2121.     mov ax,[word ptr fs:edi-2]
  2122.     cmp al,0cdh            ; is it an int instruction?
  2123.     jne short do_exception
  2124.     cmp ah,bl            ; is the int number correct?
  2125.     jne short do_exception
  2126.  
  2127. ; Here we serve a hardware or software int if it uses the same vector with an
  2128. ; exception. The registers are restored and we switch to the user task.
  2129. do_user_int:
  2130.     mov di,[es:vcpi_seltss]
  2131.     mov [ds:di + Pdata.gdt.types],0089h
  2132.     ltr di                ; now we are in user task
  2133.     shl bx,3
  2134.     mov [ds:bx + SELTASKS + Pdata.gdt.types],0089h ; clear busy bit
  2135.  
  2136.     mov ss,[ds:Pdata.vcpitss.ss]    ; CPU disables ints for next ins.
  2137.     mov esp,[ds:Pdata.vcpitss.esp]    ; switch to user stack
  2138.  
  2139. ; interrupt frame
  2140.     push [ds:Pdata.vcpitss.eflags]
  2141.     push [DWORD PTR ds:Pdata.vcpitss.cs]
  2142.     push [ds:Pdata.vcpitss.eip]
  2143. ; handler address
  2144.     push [DWORD PTR ds:bx + Pdata.lowint.sel]
  2145.     push [ds:bx + Pdata.lowint.offset]
  2146.  
  2147.     mov eax,[ds:Pdata.vcpitss.eax]
  2148.     mov ecx,[ds:Pdata.vcpitss.ecx]
  2149.     mov edx,[ds:Pdata.vcpitss.edx]
  2150.     mov ebx,[ds:Pdata.vcpitss.ebx]
  2151.     mov ebp,[ds:Pdata.vcpitss.ebp]
  2152.     mov esi,[ds:Pdata.vcpitss.esi]
  2153.     mov edi,[ds:Pdata.vcpitss.edi]
  2154.     mov es,[ds:Pdata.vcpitss.es]
  2155.     mov fs,[ds:Pdata.vcpitss.fs]
  2156.     mov gs,[ds:Pdata.vcpitss.gs]
  2157.     mov ds,[ds:Pdata.vcpitss.ds]
  2158.  
  2159.     clts
  2160.     DB 66h        ; a 32 far return
  2161.     retf
  2162.  
  2163. ; Here we serve an exception. Error code is in ecx.
  2164. do_exception:
  2165.     shl bx,3
  2166.     mov di,[es:vcpi_seltss]
  2167.     mov [ds:di + Pdata.gdt.types],0089h
  2168.     ltr di                ; now we are in user task
  2169.     mov [ds:bx + SELTASKS + Pdata.gdt.types],0089h ; clear busy bit
  2170.  
  2171.     push SELCORE            ; selector for ss
  2172.     mov eax,[es:pmstacktop]
  2173.     push eax            ; top of pmstack
  2174.     sub eax,PMONESTACKLEN        ; set EAX to next stack location
  2175.     mov [es:pmstacktop],eax        ; update ptr for possible reenterancy
  2176.  
  2177.     cmp eax,[es:pmstackbase]    ; exceeded protected mode stack space?
  2178.     jbe critical_error        ; if yes, critical error (hang)
  2179.  
  2180.     lss esp,[esp]
  2181.     push [DWORD PTR ds:Pdata.vcpitss.ss]  ; build up stack like DPMI says
  2182.     push [ds:Pdata.vcpitss.esp]
  2183.     push [ds:Pdata.vcpitss.eflags]
  2184.     push [DWORD PTR ds:Pdata.vcpitss.cs]
  2185.     push [ds:Pdata.vcpitss.eip]
  2186.     push ecx            ; store error code
  2187.     push large SELCS
  2188.     DB 66h
  2189.     push off @@back            ; push return address
  2190.     DW 0
  2191.     push [DWORD PTR ds:bx + Pdata.exceptions.sel] ; push address of
  2192.     push [ds:bx + Pdata.exceptions.offset]    ; handler
  2193.  
  2194.     mov eax,[ds:Pdata.vcpitss.eax]
  2195.     mov ecx,[ds:Pdata.vcpitss.ecx]
  2196.     mov edx,[ds:Pdata.vcpitss.edx]
  2197.     mov ebx,[ds:Pdata.vcpitss.ebx]
  2198.     mov ebp,[ds:Pdata.vcpitss.ebp]
  2199.     mov esi,[ds:Pdata.vcpitss.esi]
  2200.     mov edi,[ds:Pdata.vcpitss.edi]
  2201.     mov es,[ds:Pdata.vcpitss.es]
  2202.     mov fs,[ds:Pdata.vcpitss.fs]
  2203.     mov gs,[ds:Pdata.vcpitss.gs]
  2204.     mov ds,[ds:Pdata.vcpitss.ds]
  2205.  
  2206.     DB 66h        ; a 32 far return
  2207.     retf
  2208.  
  2209. @@back:            ; if come here, jump back to caller
  2210.     sub [DWORD PTR esp+16],18    ; return interrupt frame in user stack
  2211.     push edi
  2212.     push ds
  2213.     mov edi,[esp+22]        ; user esp
  2214.     mov ds,[esp+26]            ; user ss
  2215.     pop [WORD PTR ds:edi]        ; task's DS
  2216.     pop [DWORD PTR ds:edi+2]    ; task's EDI
  2217.     add esp,4            ; Kill error code
  2218.     pop [DWORD PTR ds:edi+6]    ; return eip to user stack
  2219.     pop [DWORD PTR ds:edi+10]    ; return cs to user stack
  2220.     pop [DWORD PTR ds:edi+14]    ; return eflags to user stack
  2221.  
  2222.     lss esp,[esp]            ; switch to user stack
  2223.     push SELDS            ; restore the pmstack from the user
  2224.     pop ds                ; stack in case ints are enabled
  2225.     add [ds:pmstacktop],PMONESTACKLEN
  2226.     pop ds
  2227.     pop edi
  2228.     clts
  2229.     iretd
  2230.  
  2231.     ASSUME ds:DGROUP
  2232. ; [fold]  ]
  2233.  
  2234. ;═════════════════════════════════════════════════════════════════════════════
  2235. ; [fold]  [
  2236. ; callback handler
  2237. ; The callbacks are not 100% DPMI compliant. If the callback code doesn't
  2238. ; update the cs:ip fields of the call structure the callback should be
  2239. ; entered immediately again. We will hang the computer instead, but this
  2240. ; practice shouldn't be a real problem.
  2241. callback:
  2242.     cli
  2243.     cld
  2244.     mov ax,sp
  2245.     add ax,10+32+2+8        ; sp when called
  2246.     push ss ax            ; store for later use
  2247.     copy ds,DGROUP,ax
  2248.  
  2249.     sub [pmstacktop],PMONESTACKLEN
  2250.     mov ebx,[pmstacktop]
  2251.     cmp ebx,[pmstackbase]        ; exceeded protected mode stack space?
  2252.     jbe critical_error        ; if yes, critical error (hang)
  2253.     add ebx,PMONESTACKLEN        ; EBX = top of pmstack
  2254.  
  2255.     xor eax,eax            ; EAX = base address of SS
  2256.     mov ax,ss
  2257.     shl eax,4
  2258.     movzx ebp,sp            ; EBP = current linear SS:SP
  2259.     add ebp,eax
  2260.  
  2261.     mov ax,SELCORE            ; DS selector for protected mode
  2262.     mov dx,ax            ; SS selector = DS selector
  2263.     mov si,SELCS            ; target protected mode CS:EIP
  2264.     do16to32 mov,di,<offset @@callbackf0>
  2265.  
  2266.     jmp [rmtopmswrout]        ; go to protected mode
  2267.  
  2268. @@callbackf0:
  2269.     mov edi,[ebp+4]            ; get register structure
  2270.     lea esi,[ebp+4+10]        ; pointer to saved registers
  2271.     dmemcpyw ds,esi,es,edi,32+2+8    ; copy register to struct
  2272.     sub edi,32+2+8            ; correct edi
  2273.     mov [es:edi+Dpmi_regs.ip],off critical_error
  2274.     mov [es:edi+Dpmi_regs.cs],_TEXT ; in case cs:ip are not updated...
  2275.     mov eax,[ebp]            ; get original ss:sp
  2276.     mov [DWORD PTR es:edi+Dpmi_regs.sp],eax
  2277.  
  2278.     pushfd                ; push flags for IRETD from callback
  2279.     db 66h                ; push 32bit CS for IRETD
  2280.     push cs
  2281.     dw 6866h,@@callbackf1,0        ; push 32bit EIP for IRETD
  2282.  
  2283.     push 0                ; pad stack
  2284.     push [WORD PTR ebp+4+4+4]    ; get callback cs
  2285.     push [DWORD PTR ebp+4+4]    ; get callback eip
  2286.  
  2287.     db 66h                ; 32bit RETF to callback
  2288.     retf
  2289.  
  2290. @@callbackf1:
  2291.     cli
  2292.     push es                ; DS:ESI = register structure
  2293.     pop ds
  2294.     mov esi,edi
  2295.     copy es,SELCORE,ax        ; ES -> 0 (beginning of memory)
  2296.     copy fs,SELDS,ax        ; selector for Datasegment
  2297.     add [fs:pmstacktop],PMONESTACKLEN ; correct stack
  2298.  
  2299.     ptr2lin [ds:esi+Dpmi_regs.ss],[ds:esi+Dpmi_regs.sp],di,ax,edi,eax
  2300.     sub edi,32+2+8+4        ; Space for regs on rm stack + jump
  2301.     dmemcpyw ds,esi,es,edi,32+2+8+4 ; copy regs + jump
  2302.     sub esi,32+2+8+4        ; correct ESI
  2303.  
  2304.     mov bx,[ds:esi+Dpmi_regs.sp]
  2305.     sub bx,32+2+8+4            ; BX = real mode SP
  2306.     mov dx,[ds:esi+Dpmi_regs.ss]    ; DX = real mode SS
  2307.     mov si,_TEXT            ; SI = real mode CS
  2308.     mov di,off @@callbackf2        ; DI = real mode IP
  2309.     jmp [fs:pmtormswrout]        ; switch to real mode
  2310.  
  2311. @@callbackf2:
  2312.     mov bp,sp
  2313.     mov eax,[bp+Dpmi_regs.res]    ; get old highword of esp
  2314.     mov ax,sp
  2315.     mov esp,eax            ; restore old esp
  2316.  
  2317.     popad                ; get callback return general regs
  2318.     popf                ; get callback flags
  2319.     pop es ds fs gs            ; get callback return segment regs
  2320.     retf                ; go to callback return CS:IP
  2321. ; [fold]  ]
  2322.  
  2323. ;═════════════════════════════════════════════════════════════════════════════
  2324. ; [fold]  [
  2325. ; real mode INT 15h handler
  2326. int15:    push ds
  2327.     push DGROUP
  2328.     pop ds
  2329.     cmp ah,88h            ; function 88h?
  2330.     je short @@int15f0        ; if yes, need to process
  2331.  
  2332.     pushf
  2333.     call [oldint15vector]
  2334.     push bp
  2335.     pushf
  2336.     mov bp,sp
  2337.     pop [WORD PTR bp+10]        ; store flags
  2338.     pop bp ds
  2339.     iret
  2340.  
  2341. @@int15f0:
  2342.     pushf                ; call old int 15h handler
  2343.     call [oldint15vector]
  2344.  
  2345.     sub ax,[rawextmemused]        ; adjust AX by extended memory used
  2346.  
  2347.     push bp                ; clear carry flag on stack for IRET
  2348.     mov bp,sp
  2349.     and [byte ptr bp+8],0feh
  2350.     pop bp
  2351.  
  2352.     pop ds
  2353.     iret                ; return with new AX extended memory
  2354. ; [fold]  ]
  2355.  
  2356. ;═════════════════════════════════════════════════════════════════════════════
  2357. ; [fold]  [
  2358. ; Int 21 (shelling out)
  2359. dos21rm:
  2360.     cmp ax,4B00h            ; dos exec call
  2361.     je short @@doit
  2362.     cmp ax,4B03h
  2363.     je short @@doit
  2364.     cmp ax,4B05h
  2365.     je short @@doit
  2366.     jmp short @@exit
  2367.  
  2368. @@doit: push ax gs fs ds es        ; store registers on stack
  2369.     pushad
  2370.     copy ds,DGROUP,ax
  2371.     test [from_us],-1
  2372.     jnz short @@nous        ; int not from us
  2373.  
  2374.     inc [from_us]            ; for reentrancy
  2375.     call [ResetMasterPIC]        ; reset to default
  2376.     call [ResetA20]
  2377.     mov bp,sp
  2378.     mov ax,[bp+46]
  2379.     mov [bp+40],ax
  2380.     popad
  2381.     pop es ds fs gs
  2382.     call [cs:oldint21vector.ptr]    ; call old
  2383.     push gs fs ds es        ; save return
  2384.     pushad
  2385.     pushf
  2386.     copy ds,DGROUP,ax
  2387.     call [SetMasterPIC]
  2388.     call [SetA20]
  2389.     dec [from_us]
  2390.     pop ax                ; get flags
  2391.     mov bp,sp
  2392.     mov [bp+44],ax            ; store for iret
  2393.     popad
  2394.     pop es ds fs gs
  2395.     iret                ; return to caller
  2396.  
  2397. @@nous: popad
  2398.     pop es ds fs gs ax
  2399. @@exit: DB 0EAh                ; jmp far ?:?
  2400. oldint21vector Farptr16 ?
  2401. ; [fold]  ]
  2402.  
  2403. ;═════════════════════════════════════════════════════════════════════════════
  2404. ; [fold]  [
  2405. ; Int 23 (ctrl-c)
  2406. int23pm: iretd        ; default pm handler
  2407. ; [fold]  ]
  2408.  
  2409. ;═════════════════════════════════════════════════════════════════════════════
  2410. ; [fold]  [
  2411. ; Int 24 (critical error)
  2412. IF SUPPORT_INT_24 NE 0
  2413. int24pm: ; default pm handler
  2414.     mov al,3    ; fail is default action. I hope it will never
  2415.     iretd        ; happen that dos aborts on return
  2416. int24rm: ; callbacks to protected mode
  2417.     push gs fs ds es
  2418.     pushad
  2419.     cli
  2420.     copy ds,DGROUP,ax
  2421.     mov bp,ss            ; save real mode stack for later
  2422.     shl ebp,16
  2423.     mov bp,sp
  2424.  
  2425.     xor eax,eax            ; EAX = base address of SS
  2426.     mov ax,ss
  2427.     shl eax,4
  2428.     movzx ebx,sp            ; EBX = stack in prot. mode
  2429.     add ebx,eax
  2430.  
  2431.     mov ax,SELDS            ; DS selector for protected mode
  2432.     mov cx,ax            ; ES selector for protected mode
  2433.     mov dx,SELCORE            ; SS selector
  2434.     mov si,SELCS            ; target protected mode CS:EIP
  2435.     do16to32 mov,di,<off @@callbackf0> ; mov edi,off @@callbackf0
  2436.     jmp [rmtopmswrout]        ; go to protected mode
  2437.  
  2438. @@callbackf0:
  2439.     movzx edx,[esp + Dpmi_regs.bp]
  2440.     shl edx,4
  2441.     mov ecx,edx
  2442.     shr ecx,16
  2443.     mov bx,SELINT24
  2444.     mov ax,0007h
  2445.     int 31h                ; set base of INT 24 selector
  2446.  
  2447.     mov ax,[esp + Dpmi_regs.ax]
  2448.     mov si,[esp + Dpmi_regs.si]
  2449.     mov di,[esp + Dpmi_regs.di]
  2450.     push ebp
  2451.     mov bp,SELINT24
  2452.     int 24h                ; call pm critical error handler
  2453.     pop bx                ; BX = real mode SP
  2454.     pop dx                ; DX = real mode SS
  2455.     mov [esp + Dpmi_regs.al],al    ; store return value
  2456.     mov si,_TEXT            ; SI = real mode CS
  2457.     mov di,off @@callbackf2        ; DI = real mode IP
  2458.     jmp [pmtormswrout]        ; switch to real mode
  2459.  
  2460. @@callbackf2:
  2461.     mov bp,sp
  2462.     mov eax,[bp + Dpmi_regs.res]    ; get old highword of esp
  2463.     mov ax,sp
  2464.     mov esp,eax            ; restore old esp
  2465.  
  2466.     popad                ; get callback return general regs
  2467.     pop es ds fs gs            ; get callback return segment regs
  2468.     iret
  2469. ELSE
  2470. int24pm: ; for safety supply a pm handler
  2471.     mov al,3
  2472.     iretd
  2473. int24rm: ; real mode handler
  2474.     mov al,3    ; fail is default action. I hope it will never
  2475.     iret        ; happen that dos aborts on return
  2476. ENDIF
  2477. ; [fold]  ]
  2478.  
  2479. ;═════════════════════════════════════════════════════════════════════════════
  2480. ; [fold]  [
  2481. ; internal int 2f, ax=1680h, ax=1686h or ax=168ah
  2482. int2fpm:
  2483. IF PMODEDJ_EXT EQ 1
  2484.     cmp ax,168ah
  2485.     je short @@int2f168a
  2486. ENDIF
  2487.     cmp ax,1680h
  2488.     je short @@int2f1680
  2489.     cmp ax,1686h
  2490.     jne common_int_handler+2fh*INT_HANDLER_SIZE ; if no, go to INT 2fh
  2491. @@int2f1686: ; Get CPU Mode
  2492.     xor ax,ax        ; we are runniing in protected mode
  2493.     iretd
  2494. @@int2f1680: ; Release Current Virtual Machine's Time Slice
  2495.     pushfd
  2496.     push large cs
  2497.     push 0
  2498.     call common_int_handler+2fh*INT_HANDLER_SIZE ; pass down to real mode
  2499.     test al,al        ; is it supported?
  2500.     je short @@int2f1680ok    ; yes, we are done.
  2501.     sti            ; give processor a chance to cool down :)
  2502.     hlt            ; wait for int.
  2503.     xor al,al
  2504. @@int2f1680ok:
  2505.     iretd
  2506. IF PMODEDJ_EXT EQ 1
  2507. @@int2f168a: ; Get Vendor-Specific API Entry Point
  2508.     mov ax,0a00h
  2509.     int 31h            ; try the extension
  2510.     mov ax,1600h        ; prepare ax for succesful exit
  2511.     iretd
  2512. ENDIF
  2513. ; [fold]  ]
  2514.  
  2515. ;═════════════════════════════════════════════════════════════════════════════
  2516. ; [fold]  [
  2517. ; real mode INT 2F handler
  2518. int2frm: iret
  2519. ; [fold]  ]
  2520.  
  2521. ;═════════════════════════════════════════════════════════════════════════════
  2522. ; [fold]  [
  2523. ; VCPI/XMS/raw save/restore status (called from real mode)
  2524. vxr_saverestorerm:
  2525.     retf                ; no save/restore needed, 16bit RETF
  2526. ; [fold]  ]
  2527.  
  2528. ;═════════════════════════════════════════════════════════════════════════════
  2529. ; [fold]  [
  2530. ; VCPI/XMS/raw save/restore status (called from protected mode)
  2531. vxr_saverestorepm:
  2532.     db 66h,0cbh            ; no save/restore needed, 32bit RETF
  2533. ; [fold]  ]
  2534.  
  2535. ;═════════════════════════════════════════════════════════════════════════════
  2536. ; [fold]  [
  2537. ; critical error routine
  2538. critical_error:                ; some unrecoverable error
  2539.     cli                ; make sure we are not interrupted
  2540.     in al,61h            ; beep
  2541.     or al,3
  2542.     out 61h,al
  2543.     jmp $                ; now hang
  2544. ; [fold]  ]
  2545.  
  2546. ;═════════════════════════════════════════════════════════════════════════════
  2547. ; [fold]  [
  2548. ; PIC reprogramming
  2549.  
  2550. ;─────────────────────────────────────────────────────────────────────────────
  2551. ; [fold]  [
  2552. ; Resets the master PIC base
  2553. v_resetpic:
  2554.     pushf
  2555.     cli
  2556.     call pic_repr            ; reprogramming allowed?
  2557.     movzx bx,[picmasterold]
  2558.     movzx cx,[picslaveold]
  2559.     mov ax,0DE0Bh            ; VCPI set pic mappings
  2560.     int 67h
  2561.     jmp short xr_ddd
  2562. xr_resetpic:
  2563.     pushf
  2564.     cli
  2565.     call pic_repr            ; reprogramming allowed?
  2566. xr_ddd: mov cl,[picmasterold]        ; set master PIC base to default
  2567.     call Change_PIC
  2568.     movzx di,[picmasternew]        ; Clear entries in the IVT
  2569.     shl di,2
  2570.     setmemw 0,di,8*4
  2571.     popf
  2572.     ret
  2573. ; [fold]  ]
  2574.  
  2575. ;─────────────────────────────────────────────────────────────────────────────
  2576. ; [fold]  [
  2577. ; Sets the master PIC base
  2578. v_setpic:
  2579.     pushf
  2580.     cli
  2581.     call pic_repr            ; reprogramming allowed?
  2582.     movzx bx,[picmasternew]
  2583.     movzx cx,[picslavenew]
  2584.     mov ax,0DE0Bh            ; VCPI set pic mappings
  2585.     int 67h
  2586.     jmp short xr_eee
  2587. xr_setpic:
  2588.     pushf
  2589.     cli
  2590.     call pic_repr            ; reprogramming allowed?
  2591. xr_eee: mov si,off rmwrapper
  2592.     movzx di,[picmasternew]
  2593.     shl di,2
  2594.     sub ax,ax
  2595.     mov es,ax
  2596.     mov cx,(8*4)/2
  2597.     rep movsw            ; copy wrappers
  2598.     mov cl,[picmasternew]        ; NOP not needed
  2599.     call Change_PIC
  2600.     popf
  2601.     ret
  2602. ; [fold]  ]
  2603.  
  2604. ;-----------------------------------------------------------------------------
  2605. ; [fold]  [
  2606. ; Returns to caller, if reprogramming of the master PIC is not allowed.
  2607. pic_repr:
  2608.     pop bx                ; pop return address
  2609.     test [reprogrampic],-1
  2610.     jz short @@oops
  2611.     mov al,[picmasternew]
  2612.     cmp al,[picmasterold]        ; same?
  2613.     jz short @@oops
  2614.     jmp bx                ; repromming allowed, return
  2615. @@oops: popf                ; return to caller
  2616.     ret
  2617. ; [fold]  ]
  2618.  
  2619. ;─────────────────────────────────────────────────────────────────────────────
  2620. ; [fold]  [
  2621. ; Reprograms the first PIC
  2622. ; IN: CL = new master PIC base; Interrupts disabled
  2623. Change_PIC:
  2624.     in    al,21h
  2625.     mov    di,ax            ; save old state
  2626.     call    @@wt
  2627.     mov    al,0FFh
  2628.     out    21h,al            ; disable master ints
  2629.  
  2630.     call    @@wt
  2631.     mov    al,11h
  2632.     out    20h,al
  2633.     call    @@wt
  2634.     mov    al,cl            ; set new base
  2635.     out    21h,al
  2636.     call    @@wt
  2637.     mov    al,4
  2638.     out    21h,al
  2639.     call    @@wt
  2640.     mov    al,1
  2641.     out    21h,al            ; init finished here
  2642.     call    @@wt
  2643.     mov    al,0FFh
  2644.     out    21h,al            ; disable master ints again
  2645.  
  2646.     mov    ax,di
  2647.     out    21h,al            ; restore master ints
  2648.     ret
  2649. @@wt:    in    al,80h            ; a safe ioport
  2650.     ret
  2651. ; [fold]  ]
  2652.  
  2653. ;─────────────────────────────────────────────────────────────────────────────
  2654. ; [fold]  [
  2655. ; Redirection interrupt handlers.
  2656. ; Needed so the Compi (hopefully) doesn't crash in real mode when the master
  2657. ; PIC base is changed.
  2658. pic_ints:
  2659. count = 8
  2660.     REPT 8
  2661.     push eax
  2662.     push bp ds
  2663.     sub bp,bp
  2664.     mov ds,bp
  2665.     mov eax,[ds:count*4]
  2666.     mov bp,sp
  2667.     xchg eax,[ss:bp+4]
  2668.     pop ds bp
  2669.     retf
  2670. count = count +1
  2671.     ENDM
  2672. PIC_INT_SIZE = ($ - pic_ints) / 8
  2673. ; [fold]  ]
  2674.  
  2675. ; [fold]  ]
  2676.  
  2677. ;═════════════════════════════════════════════════════════════════════════════
  2678. ; [fold]  [
  2679. ; A20 control
  2680.  
  2681. ;─────────────────────────────────────────────────────────────────────────────
  2682. ; [fold]  [
  2683. v_seta20: ; Under VCPI A20 is controlled complety by the Memory Manager
  2684. v_reseta20:
  2685. ret_only:
  2686.     ret
  2687. ; [fold]  ]
  2688.  
  2689. ;─────────────────────────────────────────────────────────────────────────────
  2690. ; [fold]  [
  2691. x_seta20: ; XMS set A20
  2692.     mov ah,7
  2693.     call [xms_call.ptr]        ; get current state of A20
  2694.     mov [olda20],al            ; store
  2695.  
  2696.     mov ah,3            ; enable A20
  2697.     call [xms_call.ptr]
  2698.     ret
  2699. ; [fold]  ]
  2700.  
  2701. ;─────────────────────────────────────────────────────────────────────────────
  2702. ; [fold]  [
  2703. x_reseta20: ; XMS reset A20
  2704.     mov ah,[olda20]        ; get old state of A20
  2705.     xor ah,1
  2706.     add ah,3
  2707.     call [xms_call.ptr]    ; set to old state
  2708.     ret
  2709. ; [fold]  ]
  2710.  
  2711. ;─────────────────────────────────────────────────────────────────────────────
  2712. ; [fold]  [
  2713. r_seta20: ; raw set A20
  2714.     clc                ; assume success
  2715.     pushf                ; save intena flag
  2716.     cli
  2717.     call enablea20test        ; get old state
  2718.     mov [olda20],al            ; is A20 already enabled?
  2719.     jz short @@enablea20done    ; if yes, done
  2720.  
  2721.     in al,92h            ; PS/2 A20 enable
  2722.     or al,2
  2723.     jmp short $+2
  2724.     jmp short $+2
  2725.     jmp short $+2
  2726.     out 92h,al
  2727.  
  2728.     call enablea20test        ; is A20 enabled?
  2729.     jz short @@enablea20done    ; if yes, done
  2730.  
  2731.     call enablea20kbwait        ; AT A20 enable
  2732.     jnz short @@enablea20f0
  2733.  
  2734.     mov al,0d1h
  2735.     out 64h,al
  2736.  
  2737.     call enablea20kbwait
  2738.     jnz short @@enablea20f0
  2739.  
  2740.     mov al,0dfh
  2741.     out 60h,al
  2742.  
  2743.     call enablea20kbwait
  2744.  
  2745. @@enablea20f0:                ; wait for A20 to enable
  2746.     mov cx,800h            ; do 800h tries
  2747.  
  2748. @@enablea20l0:
  2749.     call enablea20test        ; is A20 enabled?
  2750.     jz short @@enablea20done    ; if yes, done
  2751.  
  2752.     in al,40h            ; get current tick counter
  2753.     jmp short $+2
  2754.     jmp short $+2
  2755.     jmp short $+2
  2756.     in al,40h
  2757.     mov ah,al
  2758.  
  2759. @@enablea20l1:                ; wait a single tick
  2760.     in al,40h
  2761.     jmp short $+2
  2762.     jmp short $+2
  2763.     jmp short $+2
  2764.     in al,40h
  2765.     cmp al,ah
  2766.     je @@enablea20l1
  2767.  
  2768.     loop @@enablea20l0        ; loop for another try
  2769.  
  2770.     mov bp,sp            ; error, A20 did not enable
  2771.     or [WORD PTR bp],1        ; set carry
  2772.  
  2773. @@enablea20done:
  2774.     popf
  2775.     ret
  2776. ; [fold]  ]
  2777.  
  2778. ;─────────────────────────────────────────────────────────────────────────────
  2779. ; [fold]  [
  2780. r_reseta20: ; raw reset A20 from GO32/CWSDPMI
  2781.     cmp [olda20],0        ; old state of A20
  2782.     jne short @@done    ; if it was set, do not disable
  2783.     pushf            ; save INTENA
  2784.     cli            ; disable ints
  2785.     in al,092h        ; 092h PS/2 & clone system control port "A"
  2786.     and al,not 2        ; this resets the A20 bit in register al
  2787.     jmp short $+2        ; forget the instruction fetch
  2788.     jmp short $+2
  2789.     jmp short $+2
  2790.     out 092h,al        ; set the A20 bit off
  2791.     popf            ; restore INTENA
  2792. @@done: ret
  2793. ; [fold]  ]
  2794.  
  2795. ;-----------------------------------------------------------------------------
  2796. ; [fold]  [
  2797. enablea20kbwait: ; wait for safe to write to 8042
  2798.     xor cx,cx
  2799. @@enablea20kbwaitl0:
  2800.     jmp short $+2
  2801.     jmp short $+2
  2802.     jmp short $+2
  2803.     in al,64h            ; read 8042 status
  2804.     test al,2            ; buffer full?
  2805.     loopnz @@enablea20kbwaitl0    ; if yes, loop
  2806.     ret
  2807. ; [fold]  ]
  2808.  
  2809. ;-----------------------------------------------------------------------------
  2810. ; [fold]  [
  2811. enablea20test: ; test for enabled A20
  2812.     push ds es
  2813.  
  2814.     xor ax,ax            ; set A20 test segments 0 and 0ffffh
  2815.     mov ds,ax
  2816.     dec ax
  2817.     mov es,ax
  2818.  
  2819.     mov al,[ds:0]            ; get byte from 0:0
  2820.     mov ah,al            ; preserve old byte
  2821.     not al                ; modify byte
  2822.     xchg al,[es:10h]        ; put modified byte to 0ffffh:10h
  2823.     xchg bl,[ds:0]            ; force cache flush
  2824.     cmp ah,bl            ; set zero if byte at 0:0 not modified
  2825.     xchg bl,[ds:0]            ; put back old byte and restore bl
  2826.     mov [es:10h],al            ; put back old byte at 0ffffh:10h
  2827.     sete al
  2828.     cbw
  2829.  
  2830.     pop es ds
  2831.     ret                ; return, zero if A20 enabled
  2832. ; [fold]  ]
  2833.  
  2834. ; [fold]  ]
  2835.  
  2836. ;═════════════════════════════════════════════════════════════════════════════
  2837. ; [fold]  [
  2838. ; internal int 21, ah=4C
  2839. int21:    cmp ah,4ch                    ; AH = 4Ch?
  2840.     jne common_int_handler+21h*INT_HANDLER_SIZE    ; if no, go to INT 21h
  2841.  
  2842.     push ax                ; save return value
  2843.     copy ds,SELDS,ax
  2844.     copy es,SELCORE,ax
  2845.     mov eax,[oldint15vector]    ; put back old INT 15h handler
  2846.     mov [es:4*15h],eax
  2847.     mov eax,[oldint2fvector]    ; put back old multiplex
  2848.     mov [es:4*2fh],eax
  2849.     mov eax,[cs:oldint21vector.ptr] ; put back old INT 21h handler
  2850.     mov [es:4*21h],eax
  2851.  
  2852.     mov ebx,cr0            ; restore EM bit
  2853.     and ebx,NOT 4
  2854.     mov al,[oldCR0L]
  2855.     and al,4
  2856.     or bl,al
  2857.     mov cr0,ebx
  2858.  
  2859.     mov ax,[privatedataseg]
  2860.     mov dx,DGROUP
  2861.     sub cx,cx
  2862.     mov bx,off endstack-2
  2863.     pop [WORD PTR bx]        ; put returnvalue on real mode stack
  2864.     mov si,_TEXT
  2865.     mov di,off @@come
  2866.     jmp [pmtormswrout]        ; switch to real mode
  2867.  
  2868. @@come: mov bl,[ss:picmasterold]
  2869.     mov bh,[ss:picslaveold]
  2870.     cld
  2871.     mov si,off 0+Pdata.rmint_old
  2872.     movzx di,bl
  2873.     shl di,2
  2874.     mov cx,(8*4)/2
  2875.     rep movsw
  2876.     nop
  2877.     movzx di,bh
  2878.     shl di,2
  2879.     mov cx,(8*4)/2
  2880.     rep movsw
  2881.     copy ds,DGROUP,ax        ; NOP no needed
  2882.  
  2883.     movzx bx,[pmodetype]
  2884.     add bx,bx
  2885.     call [exitrouttbl+bx]        ; deinit
  2886.  
  2887.     mov es,[privatedataseg]
  2888.     mov ah,49h
  2889.     int 21h                ; free private data
  2890.     call [pm_exit]            ; user defined cleanup routine
  2891.     pop ax
  2892.     int 21h                ; quit
  2893.  
  2894. ;-----------------------------------------------------------------------------
  2895. ; [fold]  [
  2896. ; deinit VCPI
  2897. v_exit: call [ResetMasterPIC]        ; default PIC mappings
  2898.     mov dx,[emspage]        ; emspage allocated?
  2899.     cmp dx,-1
  2900.     jz short @@ok1            ; if not, skip
  2901.     mov ah,45h
  2902.     int 67h                ; free emspage
  2903. @@ok1:    ret
  2904. ; [fold]  ]
  2905.  
  2906. ;-----------------------------------------------------------------------------
  2907. ; [fold]  [
  2908. ; deinit XMS/raw
  2909. x_exit:
  2910. r_exit: call [ResetMasterPIC]        ; default PIC mappings
  2911.     call [ResetA20]            ; default A20 state
  2912.     ret
  2913. ; [fold]  ]
  2914.  
  2915. ; [fold]  ]
  2916.  
  2917. ; [fold]  ]
  2918.  
  2919. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2920. ; INT 31h INTERFACE
  2921. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  2922. ; [fold]  [
  2923.  
  2924. ;═════════════════════════════════════════════════════════════════════════════
  2925. ; [fold]  [
  2926. int31: ; protected mode INT 31h handler
  2927.     cli
  2928.     cld
  2929.     push ds es fs gs        ; push regs needed
  2930.     pushad
  2931.     copy coreseg,SELCORE,ax
  2932.     copy pdseg,SELPRIVAT,ax
  2933.     copy ds,SELDS,ax        ; set up selectors
  2934.     mov ax,[esp+Dpmi_regs.ax]    ; restore ax
  2935.  
  2936.     push bx
  2937.     mov bx,(INT31FUNCNUM - 1) * 2    ; number of functions to check
  2938. @@int31l0:
  2939.     cmp ax,[int31functbl+bx]    ; found function value?
  2940.     jne short @@int31l0c
  2941.  
  2942.     mov bx,[int31routtbl+bx]    ; yes, go to appropriate handler
  2943.     xchg bx,[esp]
  2944.     ret
  2945.  
  2946. @@int31l0c:
  2947.     sub bx,2            ; no, continue loop
  2948.     jnc @@int31l0
  2949.  
  2950.     pop bx                ; no function found
  2951.     jmp short int31fail8001        ; error 8001h
  2952. ; [fold]  ]
  2953.  
  2954. ;-----------------------------------------------------------------------------
  2955. ; [fold]  [
  2956. ; int 31 fail labels
  2957. int31fail8024:                ; INT 31h return fail with error 8024h
  2958.     mov [word ptr esp+28],8024h    ; set AX on stack to 8024h for POPAD
  2959.     jmp short int31fail
  2960.  
  2961. ;-----------------------------------------------------------------------------
  2962. int31fail8023:                ; INT 31h return fail with error 8023h
  2963.     mov [word ptr esp+28],8023h    ; set AX on stack to 8023h for POPAD
  2964.     jmp short int31fail
  2965.  
  2966. ;-----------------------------------------------------------------------------
  2967. int31fail8022:                ; INT 31h return fail with error 8022h
  2968.     mov [word ptr esp+28],8022h    ; set AX on stack to 8022h for POPAD
  2969.     jmp short int31fail
  2970.  
  2971. ;-----------------------------------------------------------------------------
  2972. int31fail8021:                ; INT 31h return fail with error 8021h
  2973.     mov [word ptr esp+28],8021h    ; set AX on stack to 8021h for POPAD
  2974.     jmp short int31fail
  2975.  
  2976. ;-----------------------------------------------------------------------------
  2977. int31fail8016:                ; INT 31h return fail with error 8016h
  2978.     mov [word ptr esp+28],8016h    ; set AX on stack to 8016h for POPAD
  2979.     jmp short int31fail
  2980.  
  2981. ;-----------------------------------------------------------------------------
  2982. int31fail8015:                ; INT 31h return fail with error 8015h
  2983.     mov [word ptr esp+28],8015h    ; set AX on stack to 8015h for POPAD
  2984.     jmp short int31fail
  2985.  
  2986. ;-----------------------------------------------------------------------------
  2987. int31fail8013:                ; INT 31h return fail with error 8013h
  2988.     mov [word ptr esp+28],8013h    ; set AX on stack to 8013h for POPAD
  2989.     jmp short int31fail
  2990.  
  2991. ;-----------------------------------------------------------------------------
  2992. int31fail8012:                ; INT 31h return fail with error 8012h
  2993.     mov [word ptr esp+28],8012h    ; set AX on stack to 8012h for POPAD
  2994.     jmp short int31fail
  2995.  
  2996. ;-----------------------------------------------------------------------------
  2997. int31fail8011:                ; INT 31h return fail with error 8011h
  2998.     mov [word ptr esp+28],8011h    ; set AX on stack to 8011h for POPAD
  2999.     jmp short int31fail
  3000.  
  3001. ;-----------------------------------------------------------------------------
  3002. int31fail8010:                ; INT 31h return fail with error 8010h
  3003.     mov [word ptr esp+28],8010h    ; set AX on stack to 8010h for POPAD
  3004.     jmp short int31fail
  3005.  
  3006. ;-----------------------------------------------------------------------------
  3007. int31fail8003:                ; INT 31h return fail with error 8003h
  3008.     mov [word ptr esp+28],8003h    ; set AX on stack to 8003h for POPAD
  3009.     jmp short int31fail
  3010.  
  3011. ;-----------------------------------------------------------------------------
  3012. int31fail8001:                ; INT 31h return fail with error 8001h
  3013.     mov [word ptr esp+28],8001h    ; set AX on stack to 8001h for POPAD
  3014.     jmp short int31fail
  3015.  
  3016. ;-----------------------------------------------------------------------------
  3017. int31failcx:                ; INT 31h return fail with CX,AX
  3018.     mov [word ptr esp+24],cx    ; put CX onto stack for POPAD
  3019.  
  3020. ;-----------------------------------------------------------------------------
  3021. int31failax:                ; INT 31h return fail with AX
  3022.     mov [word ptr esp+28],ax    ; put AX onto stack for POPAD
  3023.  
  3024. ;-----------------------------------------------------------------------------
  3025. int31fail:                ; INT 31h return fail, pop all regs
  3026.     popad
  3027.     pop gs fs es ds
  3028.  
  3029. ;-----------------------------------------------------------------------------
  3030. int31failnopop:                ; INT 31h return fail with carry set
  3031.     or [byte ptr esp+8],1        ; set carry in EFLAGS on stack
  3032.     iretd
  3033.  
  3034. ;-----------------------------------------------------------------------------
  3035. int31okedx:                ; INT 31h return ok with EDX,CX,AX
  3036.     mov [esp+20],edx        ; put EDX onto stack for POPAD
  3037.     jmp short int31okcx
  3038.  
  3039. ;-----------------------------------------------------------------------------
  3040. int31okdx:                ; INT 31h return ok with DX,CX,AX
  3041.     mov [esp+20],dx            ; put DX onto stack for POPAD
  3042.     jmp short int31okcx
  3043.  
  3044. ;-----------------------------------------------------------------------------
  3045. int31oksinoax:                ; INT 31h return ok SI,DI,BX,CX
  3046.     mov ax,[esp+28]            ; get old value of AX for restore
  3047.  
  3048. ;-----------------------------------------------------------------------------
  3049. int31oksi:                ; INT 31h return ok SI,DI,BX,CX,AX
  3050.     mov [esp+4],si            ; put SI onto stack for POPAD
  3051.     mov [esp],di            ; put DI onto stack for POPAD
  3052.     mov [esp+16],bx            ; put BX onto stack for POPAD
  3053.  
  3054. ;-----------------------------------------------------------------------------
  3055. int31okcx:                ; INT 31h return ok with CX,AX
  3056.     mov [esp+24],cx            ; put CX onto stack for POPAD
  3057.  
  3058. ;-----------------------------------------------------------------------------
  3059. int31okax:                ; INT 31h return ok with AX
  3060.     mov [esp+28],ax            ; put AX onto stack for POPAD
  3061.  
  3062. ;-----------------------------------------------------------------------------
  3063. int31ok:                ; INT 31h return ok, pop all regs
  3064.     popad
  3065.     pop gs fs es ds
  3066.  
  3067. ;-----------------------------------------------------------------------------
  3068. int31oknopop:                ; INT 31h return ok with carry clear
  3069.     and [byte ptr esp+8],0feh    ; clear carry in EFLAGS on stack
  3070.     iretd
  3071. ; [fold]  ]
  3072. ; [fold]  ]
  3073.  
  3074. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3075. ; DESCRIPTOR FUNCTIONS
  3076. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3077. ; [fold]  [
  3078.  
  3079. ;-----------------------------------------------------------------------------
  3080. ; [fold]  [
  3081. int31testsel: ; test for valid selector BX
  3082.     pop bp                ; pop return address
  3083.  
  3084.     movzx ebx,bx
  3085.     mov edi,[gdtbase]
  3086.     cmp bx,[gdtlimit]        ; selector BX out of range?
  3087.     ja int31fail8022        ; if yes, fail with error 8022h
  3088.  
  3089.     test bl,7            ; index in LDT? Or wrong RPL?
  3090.     jnz int31fail8022        ; Only GDT allowed
  3091.     ;and bl,0f8h   mask offset table index and RPL - not needed, its zero
  3092.     test [byte ptr coreseg:6+ebx+edi],10h; is descriptor used?
  3093.     jz int31fail8022        ; if descriptor not used, fail 8022h
  3094.  
  3095.     jmp bp                ; return ok
  3096. ; [fold]  ]
  3097.  
  3098. ;-----------------------------------------------------------------------------
  3099. ; [fold]  [
  3100. int31testaccess: ; test access bits in CX
  3101.     pop bp                ; pop return address
  3102.  
  3103. IF STRICT_RING_CHECKING EQ 0
  3104.     and cl,9Fh
  3105. ENDIF
  3106.     test ch,20h            ; test MUST BE 0 bit in CH
  3107.     jnz int31fail8021        ; if not 0, error 8021h
  3108.  
  3109.     test cl,90h            ; test present and MUST BE 1 bits
  3110.     jz int31fail8021        ; if both 0, error 8021h
  3111.     jpo int31fail8021        ; if unequal, error 8021h
  3112.  
  3113.     test cl,60h            ; test DPL
  3114.     jnz int31fail8021        ; if not 0, error 8021h
  3115.  
  3116.     test cl,8            ; if code, more tests needed
  3117.     jz short @@int31testselok    ; if data, skip code tests
  3118.  
  3119.     test cl,2            ; readable?
  3120.     jz int31fail8021
  3121.     test cl,4            ; non-conform?
  3122.     jnz int31fail8021
  3123.  
  3124. @@int31testselok:
  3125.     jmp bp                ; return ok
  3126. ; [fold]  ]
  3127.  
  3128. ;─────────────────────────────────────────────────────────────────────────────
  3129. ; [fold]  [
  3130. int310000: ; allocate descriptors
  3131.     or cx,cx            ; if CX = 0, error 8021h
  3132.     jz int31fail8021
  3133.  
  3134.     mov edx,[gdtbase]        ; get base of GDT
  3135.     movzx eax,[gdtlimit]        ; EAX = last selector index
  3136.     and al,0f8h
  3137.  
  3138.     mov bx,cx            ; BX = number of selectors to find
  3139. @@int310000l0:
  3140.     test [byte ptr coreseg:edx+eax+6],10h; is descriptor used?
  3141.     jnz short @@int310000l0f0
  3142.  
  3143.     dec bx                ; found free descriptor, dec counter
  3144.     jnz short @@int310000l0f1    ; continue if need to find more
  3145.  
  3146.     mov ebx,eax            ; found all descriptors requested
  3147. @@int310000l1:
  3148.     mov [dword ptr coreseg:edx+ebx],0    ; set entire new descriptor
  3149.     mov [dword ptr coreseg:edx+ebx+4],109200h
  3150.     add bx,8            ; increment selector index
  3151.     dec cx                ; dec counter of descriptors to mark
  3152.     jnz @@int310000l1        ; loop if more to mark
  3153.  
  3154.     jmp int31okax            ; return ok, with AX
  3155.  
  3156. @@int310000l0f0:
  3157.     mov bx,cx            ; reset number of selectors to find
  3158.  
  3159. @@int310000l0f1:
  3160.     sub ax,8            ; dec current selector counter
  3161.     cmp ax,8*SYSSELECTORS        ; more descriptors to go?
  3162.     jae @@int310000l0        ; if yes, loop
  3163.  
  3164.     jmp int31fail8011        ; did not find descriptors
  3165. ; [fold]  ]
  3166.  
  3167. ;─────────────────────────────────────────────────────────────────────────────
  3168. ; [fold]  [
  3169. int310001: ; free descriptor
  3170.     call int31testsel        ; test for valid selector BX
  3171.     mov ax,ss
  3172.     cmp bx,ax            ; free stackselector?
  3173.     jz int31fail8022        ;   never do this!
  3174.     cmp bx,[esp+32+8+4]        ; free codeselector?
  3175.     jz int31fail8022
  3176.  
  3177.     and [byte ptr coreseg:edi+ebx+6],0efh; mark descriptor as free
  3178.     and [byte ptr coreseg:edi+ebx+5],07Fh; clear present bit
  3179.  
  3180.     mov cx,4            ; zero any segregs loaded with BX
  3181.     lea ebp,[esp+32]        ; EBP -> selectors on stack
  3182. @@int310001l0:
  3183.     cmp [word ptr ebp],bx        ; selector = BX?
  3184.     jne short @@int310001l0f0    ; if no, continue loop
  3185.  
  3186.     mov [word ptr ebp],0        ; zero selector on stack
  3187.  
  3188. @@int310001l0f0:
  3189.     add ebp,2            ; increment selector ptr
  3190.     loop @@int310001l0        ; loop
  3191.  
  3192.     jmp int31ok            ; return ok
  3193. ; [fold]  ]
  3194.  
  3195. ;─────────────────────────────────────────────────────────────────────────────
  3196. ; [fold]  [
  3197. int310002: ; segment to selector
  3198.     mov si,off segmentbases        ; check, if segment already mapped
  3199. @@lp1:    mov ax,[si + 0]            ; load selector to ax
  3200.     test ax,ax            ; selector valid?
  3201.     jz short @@skp
  3202.     cmp bx,[si + 2]            ; compare segment values
  3203.     jz int31okax
  3204. @@skp:    add si,4
  3205.     cmp si,off segmentbases + segmentbases_SIZE
  3206.     jb @@lp1
  3207.  
  3208.     mov si,off segmentbases        ; search for a free entry
  3209. @@lp2:    test [word ptr si],-1        ; this field free?
  3210.     jz short @@skp2            ; if so, use it
  3211.     add si,4
  3212.     cmp si,off segmentbases + segmentbases_SIZE
  3213.     jb @@lp2
  3214.     jmp int31fail8010        ; no entry free
  3215.  
  3216. @@skp2: mov [si + 2],bx            ; store segment
  3217.     movzx edi,bx            ; convert to linear address
  3218.     shl edi,4
  3219.     mov cx,1
  3220.     sub ax,ax
  3221.     int 31h                ; allocate selector
  3222.     jc int31failax
  3223.     mov [si + 0],ax            ; store selector
  3224.  
  3225.     mov bx,ax
  3226.     sub cx,cx
  3227.     mov dx,-1
  3228.     mov ax,8
  3229.     int 31h                ; set descriptor limit
  3230.  
  3231.     mov dx,di
  3232.     shr edi,16
  3233.     mov cx,di
  3234.     mov ax,7
  3235.     int 31h                ; set descriptor base - cannot fail
  3236.  
  3237.     mov cx,4092h
  3238.     mov ax,9
  3239.     int 31h                ; set access rights
  3240.  
  3241.     mov ax,bx            ; return selector
  3242.     jmp int31okax
  3243. ; [fold]  ]
  3244.  
  3245. ;─────────────────────────────────────────────────────────────────────────────
  3246. ; [fold]  [
  3247. int310003: ; get selector increment value
  3248.     mov ax,8            ; selector increment value is 8
  3249.     jmp int31okax            ; return ok, with AX
  3250. ; [fold]  ]
  3251.  
  3252. ;─────────────────────────────────────────────────────────────────────────────
  3253. ; [fold]  [
  3254. int310006: ; get segment base address
  3255.     call int31testsel        ; test for valid selector BX
  3256.  
  3257.     mov dx,[word ptr coreseg:edi+ebx+2]  ; low word of 32bit linear addr
  3258.     mov cl,[byte ptr coreseg:edi+ebx+4]  ; high word of 32bit linear addr
  3259.     mov ch,[byte ptr coreseg:edi+ebx+7]
  3260.  
  3261.     jmp int31okdx            ; return ok, with DX, CX, AX
  3262. ; [fold]  ]
  3263.  
  3264. ;─────────────────────────────────────────────────────────────────────────────
  3265. ; [fold]  [
  3266. int310007: ; set segment base address
  3267.     call int31testsel        ; test for valid selector BX
  3268.  
  3269.     mov [word ptr coreseg:edi+ebx+2],dx  ; low word of 32bit linear addr
  3270.     mov [byte ptr coreseg:edi+ebx+4],cl  ; high word of 32bit linear addr
  3271.     mov [byte ptr coreseg:edi+ebx+7],ch
  3272.  
  3273.     jmp int31ok            ; return ok
  3274. ; [fold]  ]
  3275.  
  3276. ;─────────────────────────────────────────────────────────────────────────────
  3277. ; [fold]  [
  3278. int310008: ; set segment limit
  3279.     call int31testsel        ; test for valid selector BX
  3280.  
  3281.     cmp cx,0fh            ; limit greater than 1M?
  3282.     jbe short @@int310008f0
  3283.  
  3284. ; Current DJGPP code doesn't work with limit check, so...
  3285. IF STRICT_LIMITS EQ 1
  3286.        mov ax,dx               ; yup, limit greater than 1M
  3287.        and ax,0fffh
  3288.        cmp ax,0fffh               ; low 12 bits set?
  3289.        jne int31fail8021           ; if no, error 8021h
  3290. ENDIF
  3291.     shrd dx,cx,12            ; DX = low 16 bits of page limit
  3292.     shr cx,12            ; CL = high 4 bits of page limit
  3293.     or cl,80h            ; set granularity bit in CL
  3294.  
  3295. @@int310008f0:
  3296.     mov [word ptr coreseg:edi+ebx],dx    ; put low word of limit
  3297.     and [byte ptr coreseg:edi+ebx+6],70h ; mask off G and high nybble of limit
  3298.     or [byte ptr coreseg:edi+ebx+6],cl   ; put high nybble of limit
  3299.  
  3300.     jmp int31ok            ; return ok
  3301. ; [fold]  ]
  3302.  
  3303. ;─────────────────────────────────────────────────────────────────────────────
  3304. ; [fold]  [
  3305. int310009: ; set descriptor access rights
  3306.     call int31testsel        ; test for valid selector BX
  3307.  
  3308.     call int31testaccess        ; test access bits in CX
  3309.  
  3310.     or ch,10h            ; set AVL bit, descriptor used
  3311.     and ch,0f0h            ; mask off low nybble of CH
  3312.     and [byte ptr coreseg:edi+ebx+6],0fh ; mask off high nybble access rights
  3313.     or [byte ptr coreseg:edi+ebx+6],ch   ; or in high access rights byte
  3314.     mov [byte ptr coreseg:edi+ebx+5],cl  ; put low access rights byte
  3315.  
  3316.     jmp int31ok            ; return ok
  3317. ; [fold]  ]
  3318.  
  3319. ;─────────────────────────────────────────────────────────────────────────────
  3320. ; [fold]  [
  3321. int31000a: ; create alias descriptor
  3322.     call int31testsel        ; test for valid selector BX
  3323.  
  3324.     mov ax,0000h            ; allocate descriptor
  3325.     mov cx,1
  3326.     int 31h
  3327.     jc int31fail8011        ; if failed, descriptor unavailable
  3328.  
  3329.     push ax                ; preserve allocated selector
  3330.  
  3331.     movzx edi,ax            ; EDI = target selector
  3332.     mov esi,[gdtbase]        ; ESI -> GDT
  3333.  
  3334.     copy [coreseg:esi+edi],[coreseg:esi+ebx],eax
  3335.     mov eax,[coreseg:esi+ebx+4]    ; copy descriptor data
  3336.     mov ah,92h
  3337.     mov [coreseg:esi+edi+4],eax
  3338.  
  3339.     pop ax                ; restore allocated selector
  3340.  
  3341.     jmp int31okax            ; return ok, with AX
  3342. ; [fold]  ]
  3343.  
  3344. ;─────────────────────────────────────────────────────────────────────────────
  3345. ; [fold]  [
  3346. int31000b: ; get descriptor
  3347.     call int31testsel        ; test for valid selector BX
  3348.  
  3349.     lea esi,[edi+ebx]        ; ESI -> descriptor in GDT
  3350.     mov edi,[esp]            ; get EDI buffer ptr from stack
  3351.     copy [es:edi+0],[coreseg:esi+0],eax ; copy descriptor
  3352.     copy [es:edi+4],[coreseg:esi+4],eax
  3353.  
  3354.     jmp int31ok            ; return ok
  3355. ; [fold]  ]
  3356.  
  3357. ;─────────────────────────────────────────────────────────────────────────────
  3358. ; [fold]  [
  3359. int31000c: ; set descriptor
  3360.     call int31testsel        ; test for valid selector BX
  3361.  
  3362.     mov esi,[esp]            ; ESI = EDI buffer ptr from stack
  3363.     mov cx,[es:esi+5]        ; get access rights from descriptor
  3364.     call int31testaccess        ; test access bits in CX
  3365.  
  3366.     add edi,ebx            ; adjust EDI to descriptor in GDT
  3367.     copy [coreseg:edi],[es:esi],eax
  3368.     mov eax,[es:esi+4]
  3369.     or eax,100000h            ; set descriptor AVL bit
  3370.     mov [coreseg:edi+4],eax
  3371. IF STRICT_RING_CHECKING EQ 0
  3372.     and [byte ptr coreseg:edi+5],9Fh ; set DPL to 0
  3373. ENDIF
  3374.     jmp int31ok            ; return ok
  3375. ; [fold]  ]
  3376.  
  3377. ;─────────────────────────────────────────────────────────────────────────────
  3378. ; [fold]  [
  3379. int31000e: ; get multiple descriptors
  3380. IF MULTI_DESCRIPTORS NE 0
  3381.     mov ax,000bh            ; function 000bh, get descriptor
  3382.  
  3383. ;-----------------------------------------------------------------------------
  3384. int31000ef:                ; common to funcions 000eh and 000fh
  3385.     or cx,cx            ; if CX = 0, return ok immediately
  3386.     jz int31ok
  3387.  
  3388.     mov dx,cx            ; DX = number of descriptors
  3389.     xor cx,cx            ; CX = successful counter
  3390. @@int31000efl0:
  3391.     mov bx,[es:edi]            ; BX = selector to get
  3392.     add edi,2
  3393.  
  3394.     int 31h                ; get/set descriptor
  3395.     jc int31failcx            ; if error, fail with AX and CX
  3396.  
  3397.     add edi,8            ; increment descriptor ptr
  3398.     inc cx                ; increment successful copy counter
  3399.     dec dx                ; decrement loop counter
  3400.     jnz @@int31000efl0        ; if more descriptors to go, loop
  3401.  
  3402.     jmp int31ok            ; return ok
  3403. ENDIF
  3404. ; [fold]  ]
  3405.  
  3406. ;─────────────────────────────────────────────────────────────────────────────
  3407. ; [fold]  [
  3408. int31000f: ; set multiple descriptors
  3409. IF MULTI_DESCRIPTORS NE 0
  3410.     mov ax,000ch            ; function 000ch, set descriptor
  3411.  
  3412.     jmp int31000ef            ; go to common function
  3413. ENDIF
  3414. ; [fold]  ]
  3415.  
  3416. ; [fold]  ]
  3417.  
  3418. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3419. ; DOS MEMORY FUNCTIONS
  3420. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3421. ; [fold]  [
  3422.  
  3423. ;-----------------------------------------------------------------------------
  3424. ; [fold]  [
  3425. int31010getdosbase:
  3426.     pop bp                ; return address
  3427.  
  3428.     mov si,dx            ; save selector for later use
  3429.     mov bx,si
  3430.     mov ax,6
  3431.     int 31h                ; Get base of selector
  3432.     jc int31failax            ; fail, if selector invalid
  3433.  
  3434.     test dx,0Fh            ; not paragraph aligned?
  3435.     jnz int31failax            ; not a valid segment address
  3436.  
  3437.     shrd dx,cx,4            ; make segment address
  3438.     test cx,0FFF0h            ; above first MB border?
  3439.     jnz int31fail8021        ; if so, fail
  3440.  
  3441.     jmp bp                ; else selector and address ok
  3442. ; [fold]  ]
  3443.  
  3444. ;-----------------------------------------------------------------------------
  3445. ; [fold]  [
  3446. int31010issueint:
  3447.     pop bp
  3448.  
  3449.     mov [esp + Dpmi_regs.es],dx
  3450.     mov [esp + Dpmi_regs.ss],0
  3451.     mov [esp + Dpmi_regs.sp],0    ; no own stack
  3452.     mov edi,esp
  3453.     copy es,ss,ax
  3454.     mov bx,21h            ; dos int, no reset of PICs and A20
  3455.     sub cx,cx            ; no stack params to copy
  3456.     mov ax,300h
  3457.     int 31h                ; make dos interrupt
  3458.     jnc short @@ok
  3459.     add esp,SIZE Dpmi_regs
  3460.     jmp int31failax
  3461. @@ok:    mov cx,[esp + Dpmi_regs.flags]
  3462.     mov ax,[esp + Dpmi_regs.ax]
  3463.     mov bx,[esp + Dpmi_regs.bx]
  3464.     add esp,SIZE Dpmi_regs        ; correct stack
  3465.     test cx,1            ; allocation successful?
  3466.     jz short @@away
  3467.     mov [esp + Dpmi_regs.bx],bx    ; return max. # of paragraphs
  3468.     jmp int31failax
  3469.  
  3470. @@away: jmp bp
  3471. ; [fold]  ]
  3472.  
  3473. ;─────────────────────────────────────────────────────────────────────────────
  3474. ; [fold]  [
  3475. int310100: ; Allocate DOS memory block
  3476.     sub esp,SIZE Dpmi_regs        ; space for real mode registers
  3477.     mov [esp + Dpmi_regs.ax],4800h    ; dos function allocate memory
  3478.     mov [esp + Dpmi_regs.bx],bx    ; # of paragraphs
  3479.     call int31010issueint        ; attempt to allocate memory
  3480.     mov si,ax            ; save segment for later use
  3481.  
  3482.     sub ax,ax            ; Allocate Descriptor
  3483.     mov cx,1            ; 1 is enough for 32bit code
  3484.     int 31h                ; try to get one
  3485.     jc short @@failfree        ; fail, if no descriptor free
  3486.     mov bx,ax            ; BX = DOS mem selector
  3487.  
  3488.     mov cx,4092h            ; data descriptor
  3489.     mov ax,9
  3490.     int 31h                ; set descriptor type
  3491.  
  3492.     movzx ecx,[esp + Dpmi_regs.bx]    ; get size
  3493.     shl ecx,4
  3494.     dec ecx
  3495.     mov dx,cx
  3496.     shr ecx,16
  3497.     mov ax,8
  3498.     int 31h                ; Set descriptor limit
  3499.  
  3500.     mov cx,si            ; CX = highword of linear address
  3501.     mov dx,cx            ; DX = lowword of linear address
  3502.     shr cx,12
  3503.     shl dx,4
  3504.     mov ax,7
  3505.     int 31h                ; set descriptor base
  3506.  
  3507.     mov ax,si            ; initial real mode segment
  3508.     mov [esp + Dpmi_regs.dx],bx    ; store selector
  3509.     jmp int31okax            ; return successful
  3510.  
  3511. @@failfree:
  3512.     sub esp,SIZE Dpmi_regs        ; space for real mode registers
  3513.     mov [esp + Dpmi_regs.ax],4900h    ; dos function free memory
  3514.     mov dx,si            ; segment
  3515.     call int31010issueint        ; free memory
  3516.     jmp int31fail8011        ; and fail
  3517. ; [fold]  ]
  3518.  
  3519. ;─────────────────────────────────────────────────────────────────────────────
  3520. ; [fold]  [
  3521. int310101: ; Free DOS memory block
  3522.     call int31010getdosbase        ; check selector and get segment addr
  3523.  
  3524.     mov bx,si
  3525.     mov ax,1
  3526.     int 31h                ; free associated selector
  3527.  
  3528.     sub esp,SIZE Dpmi_regs        ; space for real mode registers
  3529.     mov [esp + Dpmi_regs.ax],4900h    ; dos function free memory
  3530.     call int31010issueint        ; attempt to free memory
  3531.  
  3532.     jmp int31okax            ; else return no error
  3533. ; [fold]  ]
  3534.  
  3535. ;─────────────────────────────────────────────────────────────────────────────
  3536. ; [fold]  [
  3537. int310102: ; Resize DOS memory block
  3538.     mov di,bx            ; save size for later use
  3539.  
  3540.     call int31010getdosbase        ; check selector and segment addr
  3541.  
  3542.     sub esp,SIZE Dpmi_regs        ; space for real mode registers
  3543.     mov [esp + Dpmi_regs.ax],4A00h    ; dos function resize memory
  3544.     mov [esp + Dpmi_regs.bx],di    ; new size
  3545.     call int31010issueint        ; attempt to resize memory
  3546.  
  3547.     movzx ecx,[esp + Dpmi_regs.bx]    ; get size again
  3548.     shl ecx,4
  3549.     dec ecx
  3550.     mov dx,cx
  3551.     shr cx,16
  3552.     mov bx,[esp + Dpmi_regs.dx]    ; get selector
  3553.     mov ax,8
  3554.     int 31h                ; Set descriptor limit
  3555.  
  3556.     jmp int31okax
  3557. ; [fold]  ]
  3558.  
  3559. ; [fold]  ]
  3560.  
  3561. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3562. ; INTERRUPT FUNCTIONS
  3563. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3564. ; [fold]  [
  3565.  
  3566. ;─────────────────────────────────────────────────────────────────────────────
  3567. ; [fold]  [
  3568. int310200: ; get real mode interrupt vector
  3569.     mov al,bl
  3570.     and al,0F8h            ; In any PIC range?
  3571.  
  3572.     cmp al,[picmasterold]
  3573.     je short @@std
  3574.     cmp al,[picmasternew]        ; In the new range?
  3575.     je int31fail8003        ; system integrity
  3576.  
  3577. @@std:    movzx ebx,bl            ; EBX = BL (interrupt number)
  3578.     mov ebx,[pdseg:ebx*4 + Pdata.rmint_ptrs]
  3579.     mov dx,[coreseg:ebx]        ; load real mode vector offset
  3580.     mov cx,[coreseg:ebx+2]        ; load real mode vector segment
  3581.     jmp int31okdx            ; return ok, with AX, CX, DX
  3582. ; [fold]  ]
  3583.  
  3584. ;─────────────────────────────────────────────────────────────────────────────
  3585. ; [fold]  [
  3586. int310201: ; set real mode interrupt vector
  3587.     movzx ebx,bl            ; EBX = BL (interrupt number)
  3588.     push cx dx
  3589.     pop edx                ; EDX = pointer to RM Int vector
  3590.     mov al,bl
  3591.     and ax,0F8h            ; In any PIC range?
  3592.     mov si,bx
  3593.     and esi,7            ; IRQ #
  3594.     mov bp,si
  3595.  
  3596.     movzx edi,[picmasternew]
  3597.     cmp al,[picmasterold]
  3598.     je short @@pics
  3599.     cmp ax,di            ; In the new range?
  3600.     je int31fail8003        ; system integrity
  3601.  
  3602.     movzx edi,[picslavenew]
  3603.     cmp al,[picslaveold]
  3604.     jne short @@std
  3605.     add si,8
  3606.  
  3607. @@pics: shl si,2
  3608.     mov [pdseg:si + Pdata.rmint_copy.ptr],edx
  3609.     cmp edx,[pdseg:si + Pdata.rmint_old.ptr]
  3610.     jne short @@hook        ; original handler installed?
  3611.  
  3612.     cmp ax,di            ; any difference in old and new?
  3613.     je short @@skp
  3614.     add di,bp
  3615.     imul dx,si,PIC_INT_SIZE
  3616.     shr dx,2
  3617.     add dx,off pic_ints
  3618.     push _TEXT dx
  3619.     pop edx
  3620.     mov [si + rmwrapper.ptr],edx
  3621.     mov [coreseg:edi*SIZE Farptr16 + Farptr16.ptr],edx
  3622.  
  3623. @@skp:    mov ax,204h            ; This will unhook the hidden
  3624.     int 31h                ; callback if not necessary
  3625.     mov ax,205h
  3626.     int 31h
  3627.     jmp int31ok
  3628.  
  3629. @@hook: cmp ax,di
  3630.     je short @@std
  3631.     add di,bp
  3632.     mov [si + rmwrapper.ptr],edx
  3633.     mov [coreseg:edi*SIZE Farptr16 + Farptr16.ptr],edx
  3634.  
  3635. @@std:    mov [coreseg:ebx*4],edx        ; set real mode int vector offset
  3636.     jmp int31ok            ; return ok
  3637. ; [fold]  ]
  3638.  
  3639. ;─────────────────────────────────────────────────────────────────────────────
  3640. ; [fold]  [
  3641. int310202: ; get exception handler
  3642.     cmp bl,31            ; Check exception number
  3643.     ja int31fail8021
  3644.  
  3645.     movzx ebx,bl
  3646.     mov cx,[pdseg:ebx*SIZE Farptr32 + Pdata.exceptions.sel]
  3647.     mov edx,[pdseg:ebx*SIZE Farptr32 + Pdata.exceptions.offset]
  3648.  
  3649.     mov ax,202h            ; no error code
  3650.     jmp int31okedx
  3651. ; [fold]  ]
  3652.  
  3653. ;─────────────────────────────────────────────────────────────────────────────
  3654. ; [fold]  [
  3655. int310203: ; set exception handler
  3656.     cmp bl,31            ; Check exception number
  3657.     ja int31fail8021
  3658.  
  3659.     xchg bx,cx            ; swap int number with int selector
  3660.     call int31testsel        ; test for valid selector BX
  3661.  
  3662.     movzx ecx,cl
  3663.     mov [pdseg:ecx*SIZE Farptr32 + Pdata.exceptions.pad],0
  3664.     mov [pdseg:ecx*SIZE Farptr32 + Pdata.exceptions.sel],bx
  3665.     mov [pdseg:ecx*SIZE Farptr32 + Pdata.exceptions.offset],edx
  3666.  
  3667. IF FAST_FPU_EMU EQ 1
  3668.     copy es,SELALIASCS,ax
  3669.     mov ax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.sel]
  3670.     mov [es:FPU_emu_vector.sel],ax
  3671.     mov eax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.offset]
  3672.     mov [es:FPU_emu_vector.offset],eax
  3673. ENDIF
  3674.     jmp int31ok
  3675. ; [fold]  ]
  3676.  
  3677. ;─────────────────────────────────────────────────────────────────────────────
  3678. ; [fold]  [
  3679. int310204: ; get protected mode interrupt vector
  3680.     movzx ebx,bl            ; EBX = BL (interrupt number)
  3681.     cmp bl,NUM_EXCEPTIONS
  3682.     jae short @@ok3
  3683.     mov cx,[pdseg:ebx*SIZE Farptr32 + Pdata.lowint.sel]
  3684.     mov edx,[pdseg:ebx*SIZE Farptr32 + Pdata.lowint.offset]
  3685.  
  3686.     mov ax,204h
  3687.     jmp int31okedx
  3688.  
  3689. @@ok3:    mov dx,[pdseg:ebx*8+Pdata.idt.offset1]    ; get high word of offset
  3690.     shl edx,16
  3691.     mov dx,[pdseg:ebx*8+Pdata.idt.offset0]    ; get low word of offset
  3692.     mov cx,[pdseg:ebx*8+Pdata.idt.sel]    ; get selector
  3693.  
  3694.     mov ax,204h
  3695.     jmp int31okedx            ; return ok, with AX, CX, EDX
  3696. ; [fold]  ]
  3697.  
  3698. ;─────────────────────────────────────────────────────────────────────────────
  3699. ; [fold]  [
  3700. int310205: ; set protected mode interrupt vector
  3701.     xchg bx,cx            ; swap int number with int selector
  3702.     call int31testsel        ; test for valid selector BX
  3703.  
  3704.     copy es,SELALIASCS,ax
  3705.     movzx ecx,cl            ; ECX = CL (interrupt number)
  3706.  
  3707. ; This code sets the requested int number and if it is a hardware int on the
  3708. ; master pic, then the actual irq int is set as well. The only problem is that
  3709. ; requests to set one of the actual irq's will fail with error 8003h (system
  3710. ; integrity). One possible solution is to reprogram the offending pic in such
  3711. ; a case, but I won't bother for the time being.
  3712.     mov al,cl
  3713.     and al,0f8h
  3714.     cmp al,[picmasterold]
  3715.     jne short @@notmaster
  3716. ; set master pic int
  3717.     mov esi,ecx
  3718.     and si,7
  3719.     call @@hookhidden
  3720.     call @@setint
  3721.     sub cl,[picmasterold]
  3722.     add cl,[picmasternew]
  3723.     jmp short @@soft
  3724.  
  3725. @@notmaster:
  3726.     cmp al,[picslaveold]
  3727.     jne short @@notslave
  3728.  
  3729.     mov esi,ecx
  3730.     and si,7
  3731.     or si,8
  3732.     call @@hookhidden
  3733.     jmp short @@soft
  3734.  
  3735. @@notslave:
  3736.     cmp al,[picmasternew]
  3737.     je int31fail8003
  3738.  
  3739. @@soft: call @@setint
  3740.     cmp cl,23h            ; ctrl-c ?
  3741.     jne int31ok            ; if not, finished
  3742.  
  3743. @@ctrl: mov si,16
  3744.     call @@hookhidden        ; set ctrl-c callback
  3745.     jmp int31ok
  3746.  
  3747. ;-----------------------------------------------------------------------------
  3748. @@hookhidden: ; hooks RM HW
  3749.     imul bp,si,HARDIRQ_CALLBACK_SIZE
  3750.     add bp,off hardirq_callback    ; update pointer in hardirq_callback
  3751.     mov [es:bp+HARDIRQ_CALLBACK_OFS],edx
  3752.     mov [es:bp+HARDIRQ_CALLBACK_SEL],bx
  3753.  
  3754.     cmp bx,SELCS        ; our pm int handler?
  3755.     je short @@remo        ; if so, deinstall our callback
  3756.  
  3757.     mov [coreseg:ecx*SIZE Farptr16 + Farptr16.sel],_TEXT
  3758.     mov [coreseg:ecx*SIZE Farptr16 + Farptr16.offset],bp
  3759.     ret            ; install our 'hidden' rm to pm IRQ callback
  3760.  
  3761. @@remo: mov eax,[pdseg:esi*SIZE Farptr16 + Pdata.rmint_copy.ptr]
  3762.     mov [coreseg:ecx*SIZE Farptr16+Farptr16.ptr],eax
  3763.     ret            ; deinstall 'hidden' IRQ callback
  3764.  
  3765. ;-----------------------------------------------------------------------------
  3766. @@setint:
  3767.     cmp cl,NUM_EXCEPTIONS
  3768.     jae short @@setint1
  3769.     mov [pdseg:ecx*SIZE Farptr32 + Pdata.lowint.pad],0
  3770.     mov [pdseg:ecx*SIZE Farptr32 + Pdata.lowint.sel],bx
  3771.     mov [pdseg:ecx*SIZE Farptr32 + Pdata.lowint.offset],edx
  3772.     ret
  3773. @@setint1:
  3774.     mov [pdseg:ecx*8+Pdata.idt.offset0],dx    ; set low word of offset
  3775.     shld eax,edx,16
  3776.     mov [pdseg:ecx*8+Pdata.idt.offset1],ax    ; set high word of offset
  3777.     mov [pdseg:ecx*8+Pdata.idt.sel],bx    ; set selector
  3778.     ret
  3779. ; [fold]  ]
  3780.  
  3781. ;─────────────────────────────────────────────────────────────────────────────
  3782. ; [fold]  [
  3783. int310900:  ; get and disable interrupt state
  3784.     btc [word ptr esp+48],9        ; test and clear IF bit in EFLAGS
  3785.     setc al                ; set AL = carry (IF flag from EFLAGS)
  3786.  
  3787.     jmp int31okax            ; return ok
  3788. ; [fold]  ]
  3789.  
  3790. ;─────────────────────────────────────────────────────────────────────────────
  3791. ; [fold]  [
  3792. int310901: ; get and enable interrupt state
  3793.     bts [word ptr esp+48],9        ; test and set IF bit in EFLAGS
  3794.     setc al                ; set AL = carry (IF flag from EFLAGS)
  3795.  
  3796.     jmp int31okax            ; return ok
  3797. ; [fold]  ]
  3798.  
  3799. ;─────────────────────────────────────────────────────────────────────────────
  3800. ; [fold]  [
  3801. int310902: ; get interrupt state
  3802.     bt [word ptr esp+48],9        ; just test IF bit in EFLAGS
  3803.     setc al                ; set AL = carry (IF flag from EFLAGS)
  3804.  
  3805.     jmp int31okax            ; return ok
  3806. ; [fold]  ]
  3807.  
  3808. ; [fold]  ]
  3809.  
  3810. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3811. ; REAL/PROTECTED MODE TRANSLATION FUNCTIONS
  3812. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  3813. ; [fold]  [
  3814.  
  3815. ;─────────────────────────────────────────────────────────────────────────────
  3816. ; [fold]  [
  3817. int310300: ; simulate real mode interrupt
  3818.     push cx
  3819.     mov ax,200h
  3820.     int 31h                ; get real mode INT CS:IP
  3821.     mov [es:edi+Dpmi_regs.cs],cx
  3822.     mov [es:edi+Dpmi_regs.ip],dx
  3823.     pop cx
  3824. ; [fold]  ]
  3825.  
  3826. ;─────────────────────────────────────────────────────────────────────────────
  3827. int310301: ; call real mode FAR procedure
  3828.                     ; same start as function 0302h
  3829. ;─────────────────────────────────────────────────────────────────────────────
  3830. int310302: ; call real mode IRET procedure
  3831.  
  3832. ;-----------------------------------------------------------------------------
  3833. ; [fold]  [
  3834. int3103: ; common to 0300h, 0301h, and 0302h
  3835.     movzx ebx,[es:edi+Dpmi_regs.sp] ; EBX = SP from register structure
  3836.     movzx edx,[es:edi+Dpmi_regs.ss] ; EDX = SS from register structure
  3837.  
  3838.     mov ax,bx            ; check if caller provided stack
  3839.     or ax,dx
  3840.     jnz short @@int3103f3        ; if yes, go on to set stack
  3841.  
  3842.     mov dx,[privatedataseg]        ; real mode SS
  3843.     mov bx,[rmstacktop]        ; BX = top of real mode stack
  3844.     mov ax,bx            ; save top of stack
  3845.     sub bx,RMONESTACKLEN        ; adjust BX to next stack location
  3846.  
  3847.     cmp bx,[rmstackbase]        ; exceeded real mode stack space?
  3848.     jb int31fail8012        ; if yes, error 8012h
  3849.  
  3850.     mov [rmstacktop],bx        ; update ptr for possible reenterancy
  3851.     mov bx,ax            ; restore top of stack
  3852.  
  3853. @@int3103f3:
  3854.     shl edx,4            ; convert seg:ofs form to linear
  3855.     mov edi,edx            ; address
  3856.     add edi,ebx            ; EDI = top of real mode stack
  3857.  
  3858.     sub edi,10
  3859.     lea ax,[bx-10]            ; AX = top of stack parms
  3860.     xchg ax,[rmstackparmtop]    ; preserve and set new top of stack
  3861.     push ax                ;  parms for possible reenterancy
  3862.  
  3863.     mov [coreseg:edi+8],cx        ; store # of parameters
  3864.     mov [coreseg:edi+6],ss        ; store SS:ESP on real mode stack
  3865.     mov [coreseg:edi+2],esp        ; ESP when switching to real mode
  3866.     mov [coreseg:edi+0],es        ; store ES on real mode stack
  3867.  
  3868.     movzx ecx,cx
  3869.     lea esi,[esp+ecx*2+2+32+8+12]    ; start of parameters on stack
  3870.     mov ebx,ecx
  3871.     jmp short @@lp1in
  3872. @@lp1:    sub esi,2
  3873.     mov ax,[ss:esi]
  3874.     sub edi,2
  3875.     mov [coreseg:edi],ax        ; copy parameters
  3876. @@lp1in:dec ebx
  3877.     jns @@lp1
  3878.  
  3879.     mov esi,[esp+2+Dpmi_regs.edi]    ; call struct
  3880.     mov ax,[es:esi+Dpmi_regs.flags] ; AX = flags for real mode
  3881.     cmp [esp+2+Dpmi_regs.ax],301h    ; if function 301h, no space for flags
  3882.     jz short @@w1
  3883.     and ah,0fch            ; 0300h or 0302h, clear IF and TF flag
  3884.     mov [es:esi+Dpmi_regs.flags],ax
  3885.     sub edi,2            ; push flags for IRET stack frame
  3886.     mov [coreseg:edi],ax
  3887. @@w1:
  3888.     mov [WORD PTR coreseg:edi-4],off @@int3103f1
  3889.     mov [WORD PTR coreseg:edi-2],_TEXT
  3890.     copy <[DWORD PTR coreseg:edi-8]>,<[DWORD PTR es:esi+Dpmi_regs.ip]>,eax
  3891.  
  3892.     sub edi,8+42
  3893.     dmemcpyw es,esi,coreseg,edi,42    ; copy registers + flags
  3894.     sub edi,42            ; correct edi
  3895.  
  3896.     sub edi,edx
  3897.     mov ax,DGROUP            ; AX  = Real Mode DS
  3898.     movzx ebx,di            ; EBX = Real Mode ESP
  3899.     shr edx,4            ; DX  = Real Mode SS
  3900.     mov si,_TEXT            ; SI  = Real Mode CS
  3901.     mov di,off @@int3103f0        ; DI  = Real Mode IP
  3902.     jmp [pmtormswrout]        ; switch to real mode
  3903.  
  3904. @@int3103f0:                ; real mode INT, FAR, or IRET call
  3905.     popad                ; load regs with call values
  3906.     popf                ; load flags with call value
  3907.     pop es ds fs gs            ; load sregs with call values
  3908.     retf                ; go to call address
  3909.  
  3910. @@int3103f1:
  3911.     push gs fs ds es        ; store registers on stack
  3912.     pushf                ; store flags on stack
  3913.     cli
  3914.     pushad
  3915.     copy ds,DGROUP,ax
  3916.     mov bp,[rmstackparmtop]
  3917.  
  3918.     mov cx,[bp+0]            ; get protected mode ES from stack
  3919.     mov ebx,[bp+2]            ; get protected mode SS:ESP from stack
  3920.     mov dx,[bp+6]
  3921.  
  3922.     mov bp,ss            ; EBP = linear ptr to SS
  3923.     movzx ebp,bp
  3924.     shl ebp,4
  3925.  
  3926.     mov ax,SELDS            ; DS selector value for protected mode
  3927.     mov si,SELCS            ; target CS:EIP in protected mode
  3928.     do16to32 mov,di,<off @@int3103f2>
  3929.     jmp [rmtopmswrout]        ; go back to protected mode
  3930.  
  3931. @@int3103f2:
  3932.     copy coreseg,SELCORE,ax
  3933.     copy pdseg,SELPRIVAT,ax
  3934.  
  3935.     movzx eax,[rmstackparmtop]
  3936.     add ebp,eax            ; EBP = linear address of rm stack
  3937.     pop [rmstackparmtop]
  3938.  
  3939.     movzx eax,[WORD PTR coreseg:ebp+8] ; get paramcount
  3940.     add eax,eax
  3941.     sub ebp,eax
  3942.     lea esi,[ebp-42]
  3943.     mov edi,[esp+Dpmi_regs.edi]    ; get structure offset from stack
  3944.     dmemcpyw coreseg,esi,es,edi,42    ; copy regs and flags
  3945.  
  3946.     cmp [dword ptr es:edi+4],0    ; stack provided by caller?
  3947.     jne int31ok            ; if yes, done now
  3948.  
  3949.     add [rmstacktop],RMONESTACKLEN    ; restore top of real mode stack
  3950.     jmp int31ok            ; return ok
  3951. ; [fold]  ]
  3952.  
  3953. ;─────────────────────────────────────────────────────────────────────────────
  3954. ; [fold]  [
  3955. int310303: ; allocate real mode callback address
  3956.     mov dx,CALLBACKS        ; DX = total number of callbacks
  3957.     mov bx,off common_callbacks    ; BX = base of callbacks
  3958.     jmp short @@in
  3959. @@int310303l0:
  3960.     cmp [bx+Callback.ds],0        ; is this callback free?
  3961.     jz short @@int310303f0        ; if yes, allocate
  3962.  
  3963.     add bx,SIZE Callback        ; increment ptr to callback
  3964. @@in:    dec dx                ; decrement loop counter
  3965.     jns @@int310303l0        ; if more callbacks to check, loop
  3966.  
  3967.     jmp int31fail8015        ; no free callback, error 8015h
  3968.  
  3969. @@int310303f0:
  3970.     mov cx,[esp+38]            ; CX = caller DS from stack
  3971.     mov [bx+Callback.ds],cx        ; store callback parms in callback
  3972.     mov [bx+Callback.esi],esi
  3973.     mov [bx+Callback.es],es
  3974.     mov [bx+Callback.edi],edi
  3975.     mov [bx+Callback.ptr.offset],off callback
  3976.     mov [bx+Callback.ptr.sel],_TEXT
  3977.  
  3978.     mov dx,bx            ; DX = offset of callback
  3979.     mov cx,DGROUP            ; CX = segment of callback
  3980.  
  3981.     jmp int31okdx            ; return ok, with DX, CX, AX
  3982. ; [fold]  ]
  3983.  
  3984. ;─────────────────────────────────────────────────────────────────────────────
  3985. ; [fold]  [
  3986. int310304: ; free real mode callback address
  3987.     cmp cx,DGROUP            ; valid callback segment?
  3988.     jne int31fail8024        ; if no, error 8024h
  3989.  
  3990.     mov bx,dx            ; BX = offset of callback
  3991.  
  3992.     xor ax,ax            ; check if valid offset
  3993.     xchg dx,ax
  3994.     sub ax,off common_callbacks
  3995.     mov cx,SIZE Callback
  3996.     div cx
  3997.  
  3998.     or dx,dx            ; is there a remainder
  3999.     jnz int31fail8024        ; if yes, not valid, error 8024h
  4000.  
  4001.     cmp ax,CALLBACKS        ; callback index out of range?
  4002.     jae int31fail8024        ; if yes, not valid, error 8024h
  4003.  
  4004.     mov [bx+Callback.ds],0        ; set callback free
  4005.  
  4006.     jmp int31ok            ; return ok
  4007. ; [fold]  ]
  4008.  
  4009. ; [fold]  ]
  4010.  
  4011. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4012. ; MISC FUNCTIONS
  4013. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4014. ; [fold]  [
  4015.  
  4016. ;─────────────────────────────────────────────────────────────────────────────
  4017. ; [fold]  [
  4018. int310305: ; get state save/restore addresses
  4019.     add esp,20h            ; adjust stack
  4020.  
  4021.     xor ax,ax            ; size needed is none
  4022.     mov bx,_TEXT            ; real mode seg of same RETF
  4023.     mov cx,off vxr_saverestorerm    ; same offset of 16bit RETF
  4024.     mov si,cs            ; selector of routine is this one
  4025.     DB 66h
  4026.     mov di,off vxr_saverestorepm    ; offset of simple 32bit RETF
  4027.     DW 0
  4028.     pop gs fs es ds            ; restore segment registers
  4029.     jmp int31oknopop        ; return ok, dont pop registers
  4030. ; [fold]  ]
  4031.  
  4032. ;─────────────────────────────────────────────────────────────────────────────
  4033. ; [fold]  [
  4034. int310306: ; get raw mode switch addresses
  4035.     add esp,20h            ; adjust stack
  4036.  
  4037.     mov si,cs            ; selector of pmtorm rout is this one
  4038.     movzx edi,[pmtormswrout]    ; offset in this seg of rout
  4039.     mov bx,_TEXT            ; real mode seg of rmtopm rout
  4040.     mov cx,[rmtopmswrout]        ; offset of rout in real mode
  4041.  
  4042.     pop gs fs es ds            ; restore segment registers
  4043.     jmp int31oknopop        ; return ok, dont pop registers
  4044. ; [fold]  ]
  4045.  
  4046. ;─────────────────────────────────────────────────────────────────────────────
  4047. ; [fold]  [
  4048. int310400: ; get version
  4049.     add esp,20h            ; adjust stack
  4050.  
  4051.     mov ax,90            ; return version 0.90
  4052.     mov bx,3            ; capabilities
  4053.     mov cl,[processortype]        ; processor type
  4054.     mov dl,[picslaveold]        ; master and slave PIC default
  4055.     mov dh,[picmasterold]        ;  values for this PC
  4056.  
  4057.     pop gs fs es ds            ; restore segment registers
  4058.     jmp int31oknopop        ; return ok, dont pop registers
  4059. ; [fold]  ]
  4060.  
  4061. ; [fold]  ]
  4062.  
  4063. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4064. ; LOCK MEMORY FUNCTIONS
  4065. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4066. ; [fold]  [
  4067.  
  4068. ; So far all of these functions only clear the carry
  4069.  
  4070. ;─────────────────────────────────────────────────────────────────────────────
  4071. int310600: ; Lock Linear Region
  4072.     jmp int31ok
  4073.  
  4074. ;─────────────────────────────────────────────────────────────────────────────
  4075. int310601: ; Unlock Linear Region
  4076.     jmp int31ok
  4077.  
  4078. ;─────────────────────────────────────────────────────────────────────────────
  4079. int310602: ; Mark Real Mode Region as Pageable
  4080.     jmp int31ok
  4081.  
  4082. ;─────────────────────────────────────────────────────────────────────────────
  4083. int310603: ; Relock Real Mode Region
  4084.     jmp int31ok
  4085.  
  4086. ;─────────────────────────────────────────────────────────────────────────────
  4087. int310604: ; Get Page Size
  4088.     sub bx,bx
  4089.     mov cx,4096
  4090.     jmp int31oksinoax
  4091.  
  4092. ; [fold]  ]
  4093.  
  4094. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4095. ; DEMAND PAGING PERFORMANCE TUNING SERVICES
  4096. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4097. ; [fold]  [
  4098.  
  4099. ; So far all of these functions only clear the carry
  4100.  
  4101. ;─────────────────────────────────────────────────────────────────────────────
  4102. int310702: ; Mark Page as Demand Paging Candidate
  4103.     jmp int31ok
  4104.  
  4105. ;─────────────────────────────────────────────────────────────────────────────
  4106. int310703: ; Discard Page Contents
  4107.     jmp int31ok
  4108.  
  4109. ; [fold]  ]
  4110.  
  4111. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4112. ; PMODE/DJ EXTENSIONS
  4113. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4114. ; [fold]  [
  4115.  
  4116. IF PMODEDJ_EXT EQ 1
  4117. ;═════════════════════════════════════════════════════════════════════════════
  4118. ; [fold]  [
  4119. int310a00: ; PMODE/DJ DPMI extensions
  4120.     mov ds,[esp + 32 + 6]
  4121.     copy es,SELDS,ax
  4122.     do16to32 mov di,<off pmodedj_id>
  4123.     mov ecx,PMODEDJ_ID_SIZE
  4124.     repe cmps [BYTE PTR ds:esi],[BYTE PTR es:edi]
  4125.     dnop
  4126.     jnz int31fail8001        ; dont wanna talk to us
  4127.     mov [esp + 32 + 4],cs
  4128.     do16to32 mov <[WORD PTR esp + Dpmi_regs.edi]>,<off @@api>
  4129.     jmp int31ok
  4130. ; [fold]  ]
  4131.  
  4132. ;-----------------------------------------------------------------------------
  4133. ; [fold]  [
  4134. @@api: ; extension entry
  4135.     stc
  4136.     DB 66h
  4137.     retf
  4138. ; [fold]  ]
  4139. ENDIF
  4140. ; [fold]  ]
  4141.  
  4142. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4143. ; COPROCESSOR FUNCTIONS
  4144. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4145. ; [fold]  [
  4146.  
  4147. ;─────────────────────────────────────────────────────────────────────────────
  4148. ; [fold]  [
  4149. int310e00: ; get coprocessor status
  4150.     mov al,[processortype]
  4151.     mov bl,[oldCR0L]
  4152.     cmp al,3            ; is it 386?
  4153.     jne short @@ok1
  4154.     test bl,10h            ; ET bit
  4155.     jnz short @@ok1
  4156.     mov al,2            ; is 287
  4157. @@ok1:    shl al,4
  4158.     and bl,6
  4159.     shl bl,1
  4160.     or al,bl
  4161.     or al,[newEM_MP]
  4162.     sub ah,ah
  4163.     jmp int31okax
  4164. ; [fold]  ]
  4165.  
  4166. ;─────────────────────────────────────────────────────────────────────────────
  4167. ; [fold]  [
  4168. int310e01: ; set coprocessor emulation
  4169.     mov eax,cr0
  4170.     and al,0fbh            ; clear bit 3 (EM)
  4171.     and bl,3            ; keep EM and MP bits
  4172.     mov [newEM_MP],bl
  4173.     shl bl,1            ; move to place
  4174.     and bl,4            ; clear MP
  4175.     or al,bl
  4176.     mov cr0,eax
  4177.     jmp int31ok
  4178. ; [fold]  ]
  4179.  
  4180. ; [fold]  ]
  4181.  
  4182. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4183. ; EXTENDED MEMORY FUNCTIONS
  4184. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4185. ; [fold]  (
  4186.  
  4187. ; A potential problems are the memory handles. We must tell extended memory
  4188. ; handles from conventional mem ones. Here the MSB bit of the 32 Bit handle
  4189. ; is used. This "restricts" the available base linear addresses below 2GB.
  4190. ;
  4191. ; This is no problem for XMS and raw, since both can handle only up to
  4192. ; 64 MByte due to system restriction. (size in KB as a 16 Bit value)
  4193. ; Though unlikely, VCPI checks if the linear address is below 2 GB.
  4194.  
  4195. ;-----------------------------------------------------------------------------
  4196. ; [fold]  [
  4197. int310500convertbxcx: ; convert bx:cx (on stack) bytes to bx paragraphs
  4198.     pop bp
  4199.  
  4200.     mov bx,[esp + Dpmi_regs.bx]
  4201.     shl ebx,16
  4202.     mov bx,[esp + Dpmi_regs.cx]    ; get # of requested bytes
  4203.     add ebx,15            ; align on paragraph
  4204.     shr ebx,4            ; convert to paragraphs
  4205.  
  4206.     test ebx,0FFFF0000h        ; more than 1 meg?
  4207.     jnz int31fail8013        ; sorry, that's too much
  4208.     or bx,bx
  4209.     jz int31fail8021        ; can't allocate 0 bytes
  4210.  
  4211.     jmp bp
  4212. ; [fold]  ]
  4213.  
  4214. ;-----------------------------------------------------------------------------
  4215. ; [fold]  [
  4216. int310500doserror: ; convert dos error to DPMI error
  4217.     cmp ax,8022h            ; descriptor invalid?
  4218.     jz int31fail8023        ; convert to invalid handle
  4219.     cmp ax,8            ; not enough free memory?
  4220.     jz int31fail8013        ; yup
  4221.     jnz int31fail8016        ; else return this (but correct?)
  4222. ; [fold]  ]
  4223.  
  4224. ;─────────────────────────────────────────────────────────────────────────────
  4225. ; [fold]  [
  4226. int310500: ; get free memory information
  4227.     call [int31mrouttbl + 0*2]
  4228.     mov edi,eax        ; save free extended memory
  4229.  
  4230.     mov ebx,0000FFFFh
  4231.     mov ax,100h
  4232.     int 31h            ; get free dos memory
  4233.     cmp ax,8
  4234.     jz short @@w1        ; any error other than insufficient memory
  4235.     sub bx,bx        ; is treated as no mem available
  4236. @@w1:    mov eax,ebx
  4237.     shl eax,4        ; convert to bytes
  4238.  
  4239.     cmp eax,edi        ; take larger of both
  4240.     jnc short @@setbuf
  4241.     mov eax,edi        ; take extended memory
  4242.  
  4243. @@setbuf:
  4244.     mov es,[esp+24h]        ; get ES:EDI buffer ptr from stack
  4245.     mov edi,[esp]
  4246.  
  4247.     stos [dword ptr es:edi]        ; store block size in output buffer
  4248.     dnop
  4249.     shr eax,12            ; convert from bytes to pages
  4250.     stos [dword ptr es:edi]        ; store in output buffer max unlock
  4251.     stos [dword ptr es:edi]        ; store in output buffer max locked
  4252.     dnop
  4253.     mov ecx,09h            ; fill rest of buffer with 0ffffffffh
  4254.     mov eax,0ffffffffh
  4255.     rep stos [dword ptr es:edi]
  4256.     dnop
  4257.  
  4258.     jmp int31ok            ; return ok
  4259. ; [fold]  ]
  4260.  
  4261. ;─────────────────────────────────────────────────────────────────────────────
  4262. ; [fold]  [
  4263. int310501: ; allocate memory block
  4264.     pushfd
  4265.     push large cs
  4266.     DB 66h
  4267.     push off @@cont
  4268.     DW 0
  4269.     push ds es fs gs
  4270.     pushad
  4271.     jmp [int31mrouttbl + 1*2]    ; try extended memory first
  4272.  
  4273. @@cont: jc short @@try_dos        ; mem not available, try dos mem
  4274.     add esp,8*4
  4275.     pop gs fs es ds            ; got extended mem, return ok
  4276.     jmp int31oknopop
  4277.  
  4278. @@try_dos:
  4279.     call int310500convertbxcx
  4280.  
  4281.     mov ax,100h
  4282.     int 31h                ; attempt to allocate memory
  4283.     jc int310500doserror        ; convert dos error to DPMI error
  4284.  
  4285.     mov cx,ax
  4286.     mov bx,ax
  4287.     shl cx,4            ; make lo-word of linear address
  4288.     shr bx,12            ; make hi-word of linear address
  4289.  
  4290.     mov si,8000h            ; hi-word of handle, mark as dos
  4291.     mov di,dx            ; lo-word of handle = selector
  4292.  
  4293.     jmp int31oksinoax        ; return ok with BX,CX,SI,DI
  4294. ; [fold]  ]
  4295.  
  4296. ;─────────────────────────────────────────────────────────────────────────────
  4297. ; [fold]  (
  4298. int310502: ; free memory block
  4299.     or si,si            ; dos memory handle?
  4300.     js short @@dos_handle
  4301.     jmp [int31mrouttbl + 2*2]    ; else extended memory
  4302.  
  4303. @@dos_handle:
  4304.     mov dx,di            ; DX = selector of dos memory
  4305.     mov ax,101h            ; free dos memory
  4306.     int 31h
  4307.     jnc int31ok            ; no problem, exit
  4308.     jmp int31fail8023        ; DPMI specs force this error
  4309. ; [fold]  )
  4310.  
  4311. ;─────────────────────────────────────────────────────────────────────────────
  4312. ; [fold]  [
  4313. int310503: ; resize memory block
  4314. ; We make it simple here - extended memory blocks will stay in extended
  4315. ; memory, and dos memory blocks in dos memory.
  4316. ;
  4317. ; A better approach would be to change dynamically between both memory types.
  4318. ; However, DJGPP will never free any memory before exit, and DOS is a single
  4319. ; task system. So if we have to use dos memory as DPMI memory, we can assume
  4320. ; there is no extended memory available. (Remember: PMODE runs only under
  4321. ; plain DOS, in a DOS shell of a different OS PMODE won't be active!)
  4322.     or si,si            ; dos memory handle?
  4323.     js short @@dos_handle
  4324.     jmp [int31mrouttbl + 3*2]    ; else extended memory
  4325.  
  4326. @@dos_handle:
  4327.     call int310500convertbxcx
  4328.  
  4329.     mov dx,di            ; get selector
  4330.     mov ax,102h
  4331.     int 31h                ; attempt to resize memory
  4332.     jc int310500doserror
  4333.  
  4334.     mov bx,di
  4335.     mov ax,006h            ; get address
  4336.     int 31h
  4337.     mov bx,cx
  4338.     mov cx,dx
  4339.     jmp int31oksinoax        ; handle won't change
  4340. ; [fold]  ]
  4341.  
  4342. ; [fold]  )
  4343.  
  4344. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4345. ; VCPI EXTENDED MEMORY FUNCTIONS
  4346. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4347. ; [fold]  [
  4348.  
  4349. ;-----------------------------------------------------------------------------
  4350. ; [fold]  [
  4351. int310500vsiditoesi: ; convert handle SI:DI to ptr ESI
  4352.     pop bp                ; pop return address
  4353.  
  4354.     test di,3            ; is handle (ptr) aligned on dword?
  4355.     jnz int31fail8023        ; if no, error 8023h
  4356.  
  4357.     shl esi,16            ; ESI = SI:DI
  4358.     mov si,di
  4359.  
  4360.     cmp esi,[pagetablefree]        ; handle too low?
  4361.     jb int31fail8023        ; if yes, error 8023h
  4362.  
  4363.     cmp esi,[pagetabletop]        ; handle too high?
  4364.     jae int31fail8023        ; if yes, error 8023h
  4365.  
  4366.     test [byte ptr coreseg:esi+1],2 ; is page first in allocated block?
  4367.     jz int31fail8023        ; if no, error 8023h
  4368.  
  4369.     jmp bp                ; return ok
  4370. ; [fold]  ]
  4371.  
  4372. ;-----------------------------------------------------------------------------
  4373. ; [fold]  [
  4374. int310500vbxcxtoebx: ; convert BX:CX bytes to EBX pages
  4375.     pop bp                ; pop return address
  4376.  
  4377.     shl ebx,16            ; EBX = BX:CX
  4378.     mov bx,cx
  4379.  
  4380.     or ebx,ebx            ; check for invalid value
  4381.     jz int31fail8021        ; if invalid value, error 8021h
  4382.  
  4383.     add ebx,0fffh            ; convert EBX to page count
  4384.     shr ebx,12
  4385.  
  4386.     jmp bp                ; return ok
  4387. ; [fold]  ]
  4388.  
  4389. ;-----------------------------------------------------------------------------
  4390. ; [fold]  [
  4391. int310500vpmalloc: ; allocate physical memory block
  4392.     mov edi,esi            ; EDI = ESI, ptr to linear block start
  4393.     xor ebp,ebp            ; EBP = running allocated page count
  4394.  
  4395. @@int310500vpmallocl0:
  4396.     mov ax,0de04h            ; VCPI allocate a page
  4397.     call [vcpi_service.ptr]
  4398.  
  4399.     or ah,ah            ; got a page?
  4400.     jz short @@int310500vpmallocl0f0; if yes, go on
  4401.  
  4402.     cmp ebp,1            ; allocated any pages?
  4403.     jc short @@int310500vpmallocdone; if no, fail immediately
  4404.  
  4405.     or [byte ptr coreseg:edi-3],4    ; set last allocated page as last
  4406.  
  4407.     call int310500vfree        ; free what was allocated
  4408.  
  4409.     stc                ; carry set, failed
  4410.     jmp short @@int310500vpmallocdone    ; go to done
  4411.  
  4412. @@int310500vpmallocl0f0:
  4413.     and dh,0f0h            ; clear 4 bits of page table entry
  4414.     mov dl,7            ; set page as user/writeable/present
  4415.     mov [coreseg:edi],edx        ; store page in page table
  4416.     add edi,4            ; increment page table ptr
  4417.  
  4418.     inc ebp                ; increment allocated page count
  4419.     cmp ebp,ebx            ; allocated all needed pages?
  4420.     jb @@int310500vpmallocl0    ; if no, loop
  4421.  
  4422.     or [byte ptr coreseg:esi+1],2    ; set first allocated page as first
  4423.     or [byte ptr coreseg:edi-3],4    ; set last allocated page as last
  4424.     clc                ; carry clear, success
  4425.  
  4426. @@int310500vpmallocdone:
  4427.     mov eax,ebp            ; EAX = number of pages allocated
  4428.     ret                ; return
  4429. ; [fold]  ]
  4430.  
  4431. ;-----------------------------------------------------------------------------
  4432. ; [fold]  [
  4433. int310500vlmalloc: ; check for linear memory block
  4434.     mov edi,[pagetablefree]        ; EDI = search ptr in page table
  4435.  
  4436.     mov ecx,[pagetabletop]        ; ECX = count of pages to search
  4437.     sub ecx,edi
  4438.     shr ecx,2
  4439.  
  4440.     xor edx,edx            ; EDX = largest linear block found
  4441.     xor eax,eax            ; EAX = search unit, free entry (0)
  4442.  
  4443.     push ebx            ; preserve EBX, memory requested
  4444.  
  4445. @@int310500vlmallocl0:
  4446.     jecxz short @@int310500vlmallocdone    ; if no more entries, done
  4447.  
  4448.     repne scas [dword ptr es:edi]    ; search for first next free entry
  4449.     dnop
  4450.     jne short @@int310500vlmallocdone    ; if no more free, go on
  4451.  
  4452.     mov ebp,ecx            ; EBP = current count
  4453.     lea ebx,[edi-4]            ; EBX = start of free block
  4454.  
  4455.     repe scas [dword ptr es:edi]    ; search for end of free linear block
  4456.     dnop
  4457.     jne short @@int310500vlmallocl0f0 ; if previous entry not free, go on
  4458.  
  4459.     inc ebp                ; previous entry free, extra one
  4460.  
  4461. @@int310500vlmallocl0f0:
  4462.     sub ebp,ecx            ; EBP = number of free pages in block
  4463.  
  4464.     cmp ebp,edx            ; new block larger than last largest?
  4465.     jb @@int310500vlmallocl0    ; if no, loop
  4466.  
  4467.     mov esi,ebx            ; ESI = ptr to largest block found
  4468.     mov edx,ebp            ; size of new largest block found
  4469.  
  4470.     cmp ebp,[esp]            ; block sufficient for memory request?
  4471.     jb @@int310500vlmallocl0    ; if no, loop
  4472.  
  4473. @@int310500vlmallocdone:
  4474.     pop ebx                ; restore EBX, memory requested
  4475.     ret                ; return
  4476. ; [fold]  ]
  4477.  
  4478. ;-----------------------------------------------------------------------------
  4479. ; [fold]  [
  4480. int310500vmalloc: ; allocate linear+physical mem block
  4481.     call int310500vlmalloc        ; try to allocate linear memory block
  4482.  
  4483.     cmp edx,1            ; found ANY free linear area?
  4484.     jc short @@int310500vmallocfaillinear ; if no, done
  4485.  
  4486.     cmp edx,ebx            ; linear block enough for request?
  4487.     jb short @@int310500vmallocf0    ; if no, go to physical memory check
  4488.  
  4489.     call int310500vpmalloc        ; try to allocate physical mem
  4490.  
  4491.     mov cl,1            ; error is not enough physical memory
  4492.     jmp short @@int310500vmallocdone; go to done
  4493.  
  4494. @@int310500vmallocf0:
  4495.     mov ebx,edx            ; only linear block size physical mem
  4496.  
  4497.     call int310500vpmalloc        ; try to allocate physical memory
  4498.     mov cl,1            ; if failed, physical mem
  4499.     jc short @@int310500vmallocdone ; if failed, done
  4500.  
  4501.     call int310500vfree        ; success, so must free block
  4502.  
  4503.     mov eax,ebx            ; can allocate this much total memory
  4504.     stc                ; carry set, failed
  4505.  
  4506. @@int310500vmallocfaillinear:
  4507.     mov cl,0            ; error is not enough linear memory
  4508.  
  4509. @@int310500vmallocdone:
  4510.     ret                ; return
  4511. ; [fold]  ]
  4512.  
  4513. ;-----------------------------------------------------------------------------
  4514. ; [fold]  [
  4515. int310500vfree: ; free linear+physical memory block
  4516.     mov edi,esi            ; EDI = ESI, ptr to linear block start
  4517.  
  4518. @@int310500vfreel0:
  4519.     xor ecx,ecx            ; new page table entry is free (0)
  4520.     xchg ecx,[coreseg:edi]        ; swap ECX with page table entry
  4521.     add edi,4            ; increment page table ptr
  4522.  
  4523.     mov edx,ecx            ; EDX = page table entry
  4524.     and dx,0f000h            ; mask off low 12 bits
  4525.  
  4526.     mov ax,0de05h            ; VCPI free a page
  4527.     call [vcpi_service.ptr]
  4528.  
  4529.     test ch,4            ; last page of block?
  4530.     jz @@int310500vfreel0        ; if no, loop
  4531.  
  4532.     ret                ; return
  4533. ; [fold]  ]
  4534.  
  4535. ;─────────────────────────────────────────────────────────────────────────────
  4536. ; [fold]  [
  4537. int310500v: ; VCPI get free memory information (near called)
  4538.     push coreseg            ; ES = core for VCPI malloc functions
  4539.     pop es
  4540.  
  4541.     mov ebx,0ffffffffh        ; try to allocate an impossible amount
  4542.     call int310500vmalloc
  4543.     shl eax,12            ; returned EAX is highest possible
  4544.     ret                ; return memory information
  4545. ; [fold]  ]
  4546.  
  4547. ;─────────────────────────────────────────────────────────────────────────────
  4548. ; [fold]  [
  4549. int310501v: ; VCPI allocate memory block
  4550.     push coreseg            ; ES=coreseg for VCPI malloc functions
  4551.     pop es
  4552.  
  4553.     call int310500vbxcxtoebx    ; convert BX:CX bytes to EBX pages
  4554.  
  4555.     call int310500vmalloc        ; try to allocate requested amount
  4556.     jnc short int310501vaddxnhandle ; if successful, go to done
  4557.  
  4558.     or cl,cl            ; error is not enough linear memory?
  4559.     jz int31fail8012        ; if yes, error 8012h
  4560.     jmp int31fail8013        ; error is physical, error 8013h
  4561.  
  4562. int310501vaddxnhandle:
  4563.     or esi,esi
  4564.     jns short @@ok
  4565.     call int310500vfree        ; sorry, need this bit for dos mem
  4566.     jmp int31fail8013
  4567.  
  4568. @@ok:    mov ecx,esi            ; figure address of block from handle
  4569.     sub ecx,[pagetablebase]
  4570.     shl ecx,10
  4571.     shld ebx,ecx,16
  4572.  
  4573.     mov di,si            ; SI:DI = ESI, handle
  4574.     shr esi,16
  4575.  
  4576.     mov eax,[vcpi_cr3]        ; reload CR3 to clear TLB
  4577.     mov cr3,eax
  4578.  
  4579.     jmp int31oksinoax        ; return ok, with SI, DI, BX, CX
  4580. ; [fold]  ]
  4581.  
  4582. ;─────────────────────────────────────────────────────────────────────────────
  4583. ; [fold]  [
  4584. int310502v: ; VCPI free memory block
  4585.     call int310500vsiditoesi    ; convert handle SI:DI to ptr ESI
  4586.  
  4587.     call int310500vfree        ; free memory block
  4588.  
  4589.     mov eax,[vcpi_cr3]        ; reload CR3 to clear TLB
  4590.     mov cr3,eax
  4591.  
  4592.     jmp int31ok            ; return ok
  4593. ; [fold]  ]
  4594.  
  4595. ;─────────────────────────────────────────────────────────────────────────────
  4596. ; [fold]  [
  4597. int310503v: ; VCPI resize memory block
  4598.     push coreseg            ; ES=coreseg for VCPI malloc functions
  4599.     pop es
  4600.  
  4601.     call int310500vbxcxtoebx    ; convert BX:CX bytes to EBX pages
  4602.  
  4603.     call int310500vsiditoesi    ; convert handle SI:DI to ptr ESI
  4604.  
  4605.     mov edi,esi            ; EDI = ESI, ptr to linear block start
  4606.     xor ebp,ebp            ; EBP = running block size in pages
  4607.  
  4608. @@int310503vl0:
  4609.     add edi,4            ; increment page table ptr
  4610.     inc ebp                ; increment block size
  4611.  
  4612.     test [byte ptr coreseg:edi-3],4 ; last page of block?
  4613.     jz @@int310503vl0        ; if no, loop
  4614.  
  4615.     sub ebx,ebp            ; EBX = change in block size
  4616.     jz int310501vaddxnhandle    ; if no change, done
  4617.  
  4618.     jc @@int310503vf0        ; if block made smaller, just free top
  4619.  
  4620.     mov ecx,[pagetabletop]        ; ECX = count of pages to search
  4621.     sub ecx,edi
  4622.     shr ecx,2
  4623.  
  4624.     mov edx,ecx            ; EDX = current count
  4625.     xor eax,eax            ; EAX = search unit, free entry (0)
  4626.  
  4627.     jecxz short @@int310503vf3    ; if no entries above, try below
  4628.  
  4629.     repe scas [dword ptr es:edi]    ; check for free entries above block
  4630.     dnop
  4631.     je short @@int310503vf2        ; if previous entry free, go on
  4632.  
  4633.     dec edx                ; previous entry not free, minus one
  4634.  
  4635. @@int310503vf2:
  4636.     sub edx,ecx            ; EDX = number of free pages in block
  4637.  
  4638.     cmp edx,ebx            ; enough linear memory?
  4639.     jb short @@int310503vf3        ; if no, try below in linear memory
  4640.  
  4641.     push esi            ; preserve start of block
  4642.     lea esi,[esi+ebp*4]        ; ESI -> start of new block for alloc
  4643.  
  4644.     call int310500vpmalloc        ; try to allocate physical memory
  4645.     mov edi,esi            ; EDI -> start of new block
  4646.     pop esi                ; restore start of old block
  4647.     jc int31fail8013        ; if alloc failed, error 8013h
  4648.  
  4649.     and [byte ptr coreseg:edi-3],0fbh ; clear last bit in old block end
  4650.     and [byte ptr coreseg:edi+1],0fdh ; clear first bit in new block start
  4651.  
  4652.     jmp int310501vaddxnhandle    ; go to done
  4653.  
  4654. @@int310503vf3:
  4655.     mov ecx,esi            ; ECX = count of pages to search up
  4656.     sub ecx,[pagetablefree]
  4657.     shr ecx,2
  4658.  
  4659.     or ecx,ecx            ; any linear memory below?
  4660.     jz @@int310503vf1        ; if no, try to allocate
  4661.  
  4662.     push ebp            ; preserve size of original block
  4663.  
  4664.     lea edi,[esi-4]            ; EDI = ESI, ptr to linear block start
  4665.     mov ebp,ecx            ; EBP = current count
  4666.  
  4667.     std                ; search is up
  4668.     repe scas [dword ptr es:edi]    ; check for free entries after block
  4669.     dnop
  4670.     cld
  4671.     je short @@int310503vf4        ; if previous entry free, go on
  4672.  
  4673.     dec ebp                ; previous entry not free, minus one
  4674.  
  4675. @@int310503vf4:
  4676.     sub ebp,ecx            ; EBP = number of free pages in block
  4677.     lea eax,[ebp+edx]        ; free size below + free size above
  4678.  
  4679.     pop ebp                ; restore original block size
  4680.  
  4681.     cmp eax,ebx            ; enough linear memory?
  4682.     jb @@int310503vf1        ; if no, try to allocate
  4683.  
  4684.     push esi            ; preserve original block address
  4685.  
  4686.     sub ebx,edx            ; EBX = number of pages needed below
  4687.     lea eax,[ebx*4]            ; get base of block below
  4688.     sub esi,eax
  4689.  
  4690.     push edx ebp            ; preserve some vars
  4691.     call int310500vpmalloc        ; try to allocate physical memory
  4692.     pop ebp edx            ; restore some vars
  4693.  
  4694.     mov edi,esi            ; EDI -> base of block below
  4695.     pop esi                ; restore base of original block
  4696.     jc int31fail8013        ; if alloc failed, error 8013h
  4697.  
  4698.     or edx,edx            ; any pages needed above?
  4699.     jz short @@int310503vf6        ; if no, go on
  4700.  
  4701.     push esi edi ebp        ; preserve some vars
  4702.  
  4703.     mov ebx,edx            ; EBX = size of block below
  4704.     lea esi,[esi+ebp*4]        ; ESI -> start of block above
  4705.  
  4706.     call int310500vpmalloc        ; try to allocate physical memory
  4707.     pop ebp edi esi            ; restore some vars
  4708.     jnc short @@int310503vf5    ; if allocated ok, go on
  4709.  
  4710.     mov esi,edi            ; ESI -> allocated block below
  4711.     call int310500vfree        ; free allocated block below
  4712.  
  4713.     jmp int31fail8013        ; fail, error 8013h
  4714.  
  4715. @@int310503vf5:
  4716.     and [byte ptr coreseg:esi-3],0fbh ; clear last bit in below block end
  4717.     and [byte ptr coreseg:esi+ebp*4+1],0fdh ; clear first bit in above block start
  4718.  
  4719. @@int310503vf6:
  4720.     and [byte ptr coreseg:edi+1],0fdh    ; clear first bit in below block start
  4721.     and [byte ptr coreseg:esi+ebp*4-3],0fbh ; clear last bit in old block end
  4722.  
  4723.     push edi            ; preserve new block start
  4724.  
  4725.     mov edx,edi            ; EDX = base of move area
  4726.     lea ebx,[esi-4]            ; EBX = current location in move area
  4727.  
  4728. @@int310503vl1:
  4729.     mov edi,ebx            ; set up to shift up a page
  4730.     mov esi,ebx
  4731.     mov ecx,ebp
  4732.  
  4733.     push ds                ; save data selector
  4734.     push coreseg
  4735.     pop ds                ; ds = core selector
  4736.     lods [dword ptr ds:esi]        ; shift old pages a page down in table
  4737.     rep movs [dword ptr es:edi],[dword ptr ds:esi]
  4738.     stos [dword ptr es:edi]
  4739.     dnop        ; 386 bug
  4740.     pop ds                ; ds now data selector again
  4741.  
  4742.     sub ebx,4            ; decrement to next page to shift
  4743.     cmp ebx,edx            ; more pages to shift?
  4744.     jae @@int310503vl1        ; if yes, loop
  4745.  
  4746.     pop esi                ; restore new block start address
  4747.  
  4748.     jmp int310501vaddxnhandle    ; go to done
  4749.  
  4750. @@int310503vf1:
  4751.     add ebx,ebp            ; restore EBX as requested size
  4752.  
  4753.     push esi ebp            ; preserve some vars
  4754.     call int310500vlmalloc        ; check for linear memory block
  4755.     pop ebp edi            ; restore some vars
  4756.  
  4757.     cmp edx,ebx            ; enough linear memory?
  4758.     jb int31fail8012        ; if no, error 8012h
  4759.  
  4760.     sub ebx,ebp            ; EBX = extra pages needed
  4761.     push esi            ; preserve for later copy
  4762.     lea esi,[esi+ebp*4]        ; ESI -> start of extra space needed
  4763.  
  4764.     push edi ebp            ; preserve some vars
  4765.     call int310500vpmalloc        ; try to allocate physical memory
  4766.     pop ecx esi edi            ; restore some vars
  4767.     jc int31fail8013        ; if not enough mem, error 8013h
  4768.  
  4769.     push edi esi ecx        ; preserve, new and old block, size
  4770.  
  4771.     push ds
  4772.     push coreseg
  4773.     pop ds
  4774.     rep movs [dword ptr es:edi],[dword ptr ds:esi]    ; copy old block pages
  4775.     dnop                ; 386 bug
  4776.     pop ds
  4777.  
  4778.     and [byte ptr coreseg:edi-3],0fbh ; clear last bit in old block end
  4779.     and [byte ptr coreseg:edi+1],0fdh ; clear first bit in new block start
  4780.  
  4781.     pop ecx edi            ; restore to clear old block
  4782.  
  4783.     xor eax,eax            ; new page table entry is free (0)
  4784.     rep stos [dword ptr es:edi]    ; clear old page table block
  4785.     dnop        ; 386 bug
  4786.  
  4787.     pop esi                ; restore new block address
  4788.  
  4789.     jmp int310501vaddxnhandle    ; go to done
  4790.  
  4791. @@int310503vf0:
  4792.     sub edi,4            ; decrement page table ptr
  4793.  
  4794.     xor edx,edx            ; new page table entry is free (0)
  4795.     xchg edx,[coreseg:edi]        ; swap EDX with page table entry
  4796.     and dx,0f000h            ; mask off low 12 bits
  4797.  
  4798.     mov ax,0de05h            ; VCPI free a page
  4799.     call [vcpi_service.ptr]
  4800.  
  4801.     inc ebx                ; increment negative change counter
  4802.     jnz @@int310503vf0        ; if more pages to free, loop
  4803.  
  4804.     or [byte ptr coreseg:edi-3],4    ; set next page up as last of block
  4805.  
  4806.     jmp int310501vaddxnhandle    ; go to done
  4807. ; [fold]  ]
  4808.  
  4809. ;─────────────────────────────────────────────────────────────────────────────
  4810. ; [fold]  [
  4811. int310800v: ; VCPI physical address mapping
  4812.     push coreseg
  4813.     pop es
  4814.     shl ebx,16
  4815.     mov bx,cx
  4816.     cmp ebx,100000h            ; below 1st MB?
  4817.     jb int31fail8021        ; DPMI says to fail then
  4818.  
  4819.     mov bx,si
  4820.     shl ebx,16
  4821.     mov bx,di            ; get size
  4822.     or ebx,ebx            ; size 0?
  4823.     jz int31fail8021        ; if invalid value, error 8021h
  4824.  
  4825.     and ecx,0FFFh            ; mask lower 12 bits of phys addr
  4826.     add ebx,ecx            ; add page offset to size
  4827.     jc int31fail8021
  4828.     add ebx,4095
  4829.     jc int31fail8021
  4830.     shr ebx,12            ; get # of pages
  4831.  
  4832.     push ecx            ; save page offset
  4833.     call int310500vlmalloc        ; allocate linear address space
  4834.     pop ebp
  4835.     cmp edx,ebx            ; linear block enough for request?
  4836.     jb int31fail8012        ; if no, fail
  4837.  
  4838. ; fill PTEs will correct values
  4839.     mov edi,esi            ; edi = addr of PTE
  4840.     mov ax,[esp + Dpmi_regs.bx]
  4841.     shl eax,16
  4842.     mov ax,[esp + Dpmi_regs.cx]    ; get physical address
  4843.     and ah,0f0h            ; clear 4 bits of page table entry
  4844.     mov al,17h            ; user/writeable/present/PCD
  4845. @@loop: mov [coreseg:edi],eax        ; set page address
  4846.     add eax,4096            ; next page in real memory
  4847.     add edi,4            ; next PTE
  4848.     dec ebx
  4849.     jne short @@loop
  4850.  
  4851.     or [byte ptr coreseg:esi+1],2    ; set first allocated page as first
  4852.     or [byte ptr coreseg:edi-3],4    ; set last allocated page as last
  4853.  
  4854.     mov ecx,esi            ; figure address of block from handle
  4855.     sub ecx,[pagetablebase]
  4856.     shl ecx,10
  4857.     add ecx,ebp            ; add page offset
  4858.     shld ebx,ecx,16
  4859.  
  4860.     mov eax,[vcpi_cr3]        ; reload CR3 to clear TLB
  4861.     mov cr3,eax
  4862.  
  4863.     mov si,[esp + Dpmi_regs.si]
  4864.     mov di,[esp + Dpmi_regs.di]
  4865.     jmp int31oksinoax
  4866. ; [fold]  ]
  4867.  
  4868. ;─────────────────────────────────────────────────────────────────────────────
  4869. ; [fold]  [
  4870. int310801v: ; VCPI free physical address mapping
  4871.     shl ebx,16
  4872.     mov bx,cx            ; make linear address
  4873.     shr ebx,10
  4874.     and bl,0FCh
  4875.     add ebx,[pagetablebase]        ; EBX = start of PTE
  4876.  
  4877. @@loop: sub eax,eax
  4878.     xchg eax,[coreseg:ebx]        ; mark this PTE as free
  4879.     add ebx,4
  4880.     test ah,4            ; last page?
  4881.     jz short @@loop            ; if not, loop
  4882.  
  4883.     jmp int31ok
  4884. ; [fold]  ]
  4885.  
  4886. ; [fold]  ]
  4887.  
  4888. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4889. ; XMS EXTENDED MEMORY FUNCTIONS
  4890. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  4891. ; [fold]  (
  4892.  
  4893. ;-----------------------------------------------------------------------------
  4894. ; [fold]  [
  4895. int310500xcallxms: ; make a call to real mode XMS driver
  4896.     pop bp                ; pop return address
  4897.     sub esp,32h            ; stack space for register structure
  4898.  
  4899.     mov [esp+1ch],ax        ; put AX in register structure
  4900.     mov [esp+10h],bx        ; put BX in register structure
  4901.     mov [esp+18h],cx        ; put CX in register structure
  4902.     mov [esp+14h],dx        ; put DX in register structure
  4903.  
  4904.     mov [word ptr esp+20h],0    ; zero FLAGS in register structure
  4905.     mov [dword ptr esp+2eh],0    ; zero SS:SP in register structure
  4906.     mov eax,[xms_call.ptr]        ; put XMS driver address in CS:IP in
  4907.     mov [esp+2ah],eax        ;  register structure
  4908.  
  4909.     push ss                ; ES:EDI -> register structure
  4910.     pop es
  4911.     mov edi,esp
  4912.  
  4913.     xor cx,cx            ; copy 0 words as stack parameters
  4914. ;     xor bh,bh             ; doesnt really need to be here
  4915.     mov ax,301h            ; call real mode FAR procedure
  4916.     int 31h
  4917.     jc critical_error        ; if INT 31h failed, hang
  4918.  
  4919.     mov ax,[esp+1ch]        ; get AX from register structure
  4920.     mov bx,[esp+10h]        ; get BX from register structure
  4921.     mov cx,[esp+18h]        ; get CX from register structure
  4922.     mov dx,[esp+14h]        ; get DX from register structure
  4923.     add esp,32h            ; adjust ESP
  4924.  
  4925.     jmp bp                ; return
  4926. ; [fold]  ]
  4927.  
  4928. ;-----------------------------------------------------------------------------
  4929. ; [fold]  [
  4930. int310500xbxcxtodx: ; convert BX:CX bytes to DX K
  4931.     pop bp                ; pop return address
  4932.  
  4933.     mov dx,cx            ; check for invalid value, BX=CX=0
  4934.     or dx,bx
  4935.     jz int31fail8021        ; if invalid value, error 8021h
  4936.  
  4937.     add cx,1023            ; adjust for size in K and align
  4938.     adc bx,0
  4939.  
  4940.     test bh,0fch            ; memory request too high
  4941.     jnz int31fail8013        ; if yes, error 8013h
  4942.  
  4943.     shrd cx,bx,10            ; CX = memory in K
  4944.     mov dx,cx
  4945.  
  4946.     jmp bp                ; return ok
  4947. ; [fold]  ]
  4948.  
  4949. ;-----------------------------------------------------------------------------
  4950. ; [fold]  [
  4951. int310500xerror: ; XMS error, return with DPMI error
  4952.     cmp bl,0a0h            ; out of memory?
  4953.     je int31fail8013        ; if yes, error 8013h
  4954.  
  4955.     cmp bl,0a1h            ; handles exhausted?
  4956.     je int31fail8016        ; if yes, error 8016h
  4957.  
  4958.     cmp bl,0a2h            ; invalid handle?
  4959.     je int31fail8023        ; if yes, error 8023h
  4960.  
  4961.     jmp int31fail8010        ; else, error 8010h
  4962. ; [fold]  ]
  4963.  
  4964. ;─────────────────────────────────────────────────────────────────────────────
  4965. ; [fold]  [
  4966. int310500x: ; XMS get free memory information (near called)
  4967.     mov ah,8            ; get largest free memory block in K
  4968.     call int310500xcallxms
  4969.     movzx eax,ax
  4970.     shl eax,10            ; EAX = free memory in bytes
  4971.     ret                ; return memory information
  4972. ; [fold]  ]
  4973.  
  4974. ;─────────────────────────────────────────────────────────────────────────────
  4975. ; [fold]  [
  4976. int310501x: ; XMS allocate memory block
  4977.     call int310500xbxcxtodx        ; convert BX:CX bytes to DX K
  4978.     mov cx,dx            ; preserve size of block in K
  4979.  
  4980.     mov ah,9            ; allocate DX K of XMS memory
  4981.     call int310500xcallxms
  4982.     or ax,ax            ; error?
  4983.     jz int310500xerror        ; if yes, convert XMS error to DPMI
  4984.  
  4985.     mov si,dx            ; get DPMI handle from XMS handle
  4986.  
  4987. int310501xgotmem:
  4988.     mov ah,0ch            ; lock memory block
  4989.     call int310500xcallxms
  4990.     or ax,ax            ; error?
  4991.     jnz short @@int310501xf0    ; if no, go on
  4992.  
  4993.     push bx                ; yup, preserve error number
  4994.  
  4995.     mov ah,0ah            ; free block causing lock error
  4996.     call int310500xcallxms
  4997.  
  4998.     pop bx                ; restore error number
  4999.     jmp int310500xerror        ; XMS error, return with DPMI error
  5000.  
  5001. @@int310501xf0:
  5002.     mov di,si            ; lo-word of handle = XMS handle
  5003.     sub si,si            ; mark handle as non-dos
  5004.  
  5005.     mov cx,bx            ; XMS linear address to DPMI regs
  5006.     mov bx,dx
  5007.  
  5008.     add cx,0fh            ; align linear address on paragraph
  5009.     adc bx,0
  5010.     and cl,0f0h
  5011.  
  5012.     jmp int31oksinoax        ; return ok, with SI, DI, BX, CX
  5013. ; [fold]  ]
  5014.  
  5015. ;─────────────────────────────────────────────────────────────────────────────
  5016. ; [fold]  [
  5017. int310502x: ; XMS free memory block
  5018.     mov dx,di            ; get XMS handle from DPMI handle
  5019.  
  5020.     mov ah,0dh            ; unlock memory block
  5021.     call int310500xcallxms
  5022.     or ax,ax            ; error?
  5023.     jz int310500xerror        ; if XMS error, return with DPMI error
  5024.  
  5025.     mov ah,0ah            ; free memory block
  5026.     call int310500xcallxms
  5027.     or ax,ax            ; error?
  5028.     jz int310500xerror        ; if yes, convert XMS error to DPMI
  5029.  
  5030.     jmp int31ok            ; return ok
  5031. ; [fold]  ]
  5032.  
  5033. ;─────────────────────────────────────────────────────────────────────────────
  5034. ; [fold]  (
  5035. int310503x: ; XMS resize memory block
  5036.     mov si,di            ; xcallxms clobbers di
  5037.     call int310500xbxcxtodx        ; convert BX:CX bytes to DX K
  5038.     mov cx,dx            ; preserve size of block in K
  5039.     mov dx,si            ; get XMS handle from DPMI handle
  5040.  
  5041.     mov ah,0dh            ; unlock memory block
  5042.     call int310500xcallxms
  5043.     or ax,ax            ; error?
  5044.     jz int310500xerror        ; if XMS error, return with DPMI error
  5045.  
  5046.     mov bx,cx            ; BX = new size in K
  5047.     mov ah,0fh            ; resize memory block
  5048.     call int310500xcallxms
  5049.     mov dx,si            ; get XMS handle again
  5050.     or ax,ax            ; error in resize?
  5051.     jnz int310501xgotmem        ; if no, go to memory block code
  5052.  
  5053.     push bx                ; yup, preserve error number
  5054.  
  5055.     mov ah,0ch            ; lock memory block
  5056.     call int310500xcallxms
  5057.  
  5058.     pop bx                ; restore error number
  5059.     jmp int310500xerror        ; XMS error, return with DPMI error
  5060. ; [fold]  )
  5061.  
  5062. ;─────────────────────────────────────────────────────────────────────────────
  5063. ; [fold]  [
  5064. int310800xr: ; physical address mapping (both XMS and raw)
  5065.     shl ebx,16
  5066.     mov bx,cx
  5067.     cmp ebx,100000h        ; below 1st MB?
  5068.     jb int31fail8021    ; DPMI says to fail then
  5069.  
  5070.     or si,di
  5071.     jz int31fail8021    ; size is zero
  5072.     jmp int31ok        ; physical and linear address is the same
  5073. ; [fold]  ]
  5074.  
  5075. ;─────────────────────────────────────────────────────────────────────────────
  5076. int310801xr: ; free physical address mapping (both XMS and raw)
  5077.     jmp int31ok        ; physical and linear address is the same
  5078.  
  5079. ; [fold]  )
  5080.  
  5081. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  5082. ; RAW EXTENDED MEMORY FUNCTIONS
  5083. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  5084. ; [fold]  [
  5085.  
  5086. ;-----------------------------------------------------------------------------
  5087. ; [fold]  [
  5088. int310500rbxcxtoebx: ; convert BX:CX bytes to EBX bytes
  5089.     pop bp                ; pop return address
  5090.  
  5091.     shl ebx,16            ; EBX = BX:CX
  5092.     mov bx,cx
  5093.  
  5094.     or ebx,ebx            ; check for invalid value
  5095.     jz int31fail8021        ; if invalid value, error 8021h
  5096.  
  5097.     add ebx,0fh            ; align EBX on paragraph
  5098.     and bl,0f0h
  5099.  
  5100.     jmp bp                ; return ok
  5101. ; [fold]  ]
  5102.  
  5103. ;-----------------------------------------------------------------------------
  5104. ; [fold]  [
  5105. int310500rfindmcb: ; find MCB for handle SI:DI
  5106.     pop bp                ; pop return address
  5107.  
  5108.     shl esi,16            ; ESI = handle SI:DI = address of MCB
  5109.     mov si,di
  5110.  
  5111.     mov edi,[rawextmemtop]        ; EDI -> first memory control block
  5112.  
  5113. @@int310500rfindmcbl0:
  5114.     cmp edi,esi            ; found MCB?
  5115.     jne short @@int310500rfindmcbl0f0    ; if no, keep looking
  5116.  
  5117.     cmp [byte ptr coreseg:edi-4],0    ; memory block free?
  5118.     je int31fail8023        ; if yes, error 8023h
  5119.  
  5120.     jmp bp                ; return ok, found MCB
  5121.  
  5122. @@int310500rfindmcbl0f0:
  5123.     mov edi,[coreseg:edi-12]    ; EDI -> next memory control block
  5124.     or edi,edi            ; is there another MCB?
  5125.     jnz @@int310500rfindmcbl0    ; if yes, loop
  5126.  
  5127.     jmp int31fail8023        ; fail, error 8023h
  5128. ; [fold]  ]
  5129.  
  5130. ;-----------------------------------------------------------------------------
  5131. ; [fold]  [
  5132. int310500radjustused: ; adjust INT 15h extended memory used
  5133.     mov eax,[rawextmemtop]        ; EAX -> first memory control block
  5134.  
  5135. @@int310500radjustusedl0:
  5136.     cmp [dword ptr coreseg:eax-12],0    ; last memory control block?
  5137.     jz short @@int310500radjustusedf0    ; if yes, go to set new used K
  5138.  
  5139.     mov eax,[coreseg:eax-12]    ; EAX -> next memory control block
  5140.     jmp @@int310500radjustusedl0    ; loop
  5141.  
  5142. @@int310500radjustusedf0:
  5143.     cmp [byte ptr coreseg:eax-4],0        ; memory block free?
  5144.     je short @@int310500radjustusedf1    ; if no, go on
  5145.  
  5146.     sub eax,[coreseg:eax-16]    ; used, adjust by size of block
  5147.  
  5148. @@int310500radjustusedf1:
  5149.     sub eax,10h            ; adjust by size of MCB
  5150.     and eax,0fffffc00h        ; align on K
  5151.     sub eax,[rawextmemtop]        ; size of extended memory used
  5152.     neg eax
  5153.     shr eax,10            ; convert from bytes to K
  5154.  
  5155.     mov [rawextmemused],ax        ; adjust INT 15h extended memory used
  5156.  
  5157. @@int310500radjustuseddone:
  5158.     ret                ; return
  5159. ; [fold]  ]
  5160.  
  5161. ;-----------------------------------------------------------------------------
  5162. ; [fold]  [
  5163. int310500rlinkmcb: ; link memory blocks at ESI and EDI
  5164.     mov eax,[coreseg:esi-16]    ; combine two block sizes
  5165.     add eax,10h
  5166.     add [coreseg:edi-16],eax    ; add size of next block to this one
  5167.     mov ecx,[coreseg:esi-12]    ; copy next MCB field
  5168.     mov [coreseg:edi-12],ecx
  5169.     jecxz short @@int310500rlinkmcbf0    ; if no next MCB, done
  5170.  
  5171.     mov [coreseg:ecx-8],edi        ; set prev MCB in next MCB to this MCB
  5172.  
  5173. @@int310500rlinkmcbf0:
  5174.     ret                ; return
  5175. ; [fold]  ]
  5176.  
  5177. ;─────────────────────────────────────────────────────────────────────────────
  5178. ; [fold]  [
  5179. int310500r: ; raw get free memory information (near called)
  5180.     mov edi,[rawextmemtop]        ; EDI -> first memory control block
  5181.  
  5182.     xor eax,eax            ; running highest free memory block
  5183. @@int310500rl0:
  5184.     cmp [byte ptr coreseg:edi-4],0    ; is block free?
  5185.     jne short @@int310500rl0f0    ; if no, loop
  5186.  
  5187.     mov ebx,[coreseg:edi-16]    ; EBX = size of block
  5188.     cmp eax,ebx            ; last free block larger?
  5189.     ja short @@int310500rl0f0    ; if yes, loop
  5190.  
  5191.     mov eax,ebx            ; found larger block, new largest
  5192.  
  5193. @@int310500rl0f0:
  5194.     mov edi,[coreseg:edi-12]    ; EDI -> next memory control block
  5195.     or edi,edi            ; is there another MCB?
  5196.     jnz @@int310500rl0        ; if yes, loop
  5197.  
  5198.     ret                ; return memory information
  5199. ; [fold]  ]
  5200.  
  5201. ;─────────────────────────────────────────────────────────────────────────────
  5202. ; [fold]  [
  5203. int310501r: ; raw allocate memory block
  5204.     call int310500rbxcxtoebx    ; convert BX:CX bytes to EBX bytes
  5205.  
  5206.     mov edi,[rawextmemtop]        ; EDI -> first memory control block
  5207.  
  5208. @@int310501rl0:
  5209.     cmp [byte ptr coreseg:edi-4],0    ; is block free?
  5210.     je short @@int310501rl0f2    ; if yes, check block
  5211.  
  5212. @@int310501rl0f0:
  5213.     mov edi,[coreseg:edi-12]    ; EDI -> next memory control block
  5214.     or edi,edi            ; is there another MCB?
  5215.     jnz @@int310501rl0        ; if yes, loop
  5216.  
  5217.     jmp int31fail8013        ; fail, error 8013h
  5218.  
  5219. @@int310501rl0f2:
  5220.     lea ecx,[coreseg:edi-10h]    ; ECX -> possible new MCB
  5221.     sub ecx,ebx
  5222.  
  5223.     mov eax,[coreseg:edi-16]    ; EAX = size of block
  5224.     sub eax,ebx            ; enough free memory in block?
  5225.     jc short @@int310501rl0f0    ; if no, loop
  5226.  
  5227.     jz short @@int310501rl0f1    ; if exactly same size, continue
  5228.  
  5229.     sub eax,10h            ; adjust for size of new created MCB
  5230.     mov [coreseg:ecx-16],eax    ; put size of new block in new MCB
  5231.     mov eax,ecx            ; set next MCB in old MCB as new one
  5232.     xchg [coreseg:edi-12],eax    ; copy next MCB from old to new MCB
  5233.     mov [coreseg:ecx-12],eax
  5234.     or eax,eax            ; is there a next MCB?
  5235.     jz short @@int310501rl0f3    ; if no, go on
  5236.  
  5237.     mov [coreseg:eax-8],ecx        ; set prev MCB in next MCB to new MCB
  5238.  
  5239. @@int310501rl0f3:
  5240.     mov [coreseg:ecx-8],edi        ; set prev MCB in new MCB as old one
  5241.     mov [byte ptr coreseg:ecx-4],0    ; set new MCB as free
  5242.     mov [coreseg:edi-16],ebx    ; set size of allocated block
  5243.  
  5244. @@int310501rl0f1:
  5245.     mov [byte ptr coreseg:edi-4],1    ; set block as allocated
  5246.  
  5247. int310501raddxnhandle:
  5248.     shld ebx,ecx,16            ; BX:CX = ECX, address of block
  5249.     shld esi,edi,16            ; SI:DI = EDI, handle (address of MCB)
  5250.  
  5251.     call int310500radjustused    ; adjust INT 15h extended memory used
  5252.  
  5253.     jmp int31oksinoax        ; return ok, with SI, DI, BX, CX
  5254. ; [fold]  ]
  5255.  
  5256. ;─────────────────────────────────────────────────────────────────────────────
  5257. ; [fold]  [
  5258. int310502r: ; raw free memory block
  5259.     call int310500rfindmcb        ; find MCB for handle SI:DI
  5260.  
  5261.     mov [byte ptr coreseg:edi-4],0    ; set this memory block as free
  5262.  
  5263.     mov esi,[coreseg:edi-12]    ; ESI -> next memory control block
  5264.     or esi,esi            ; is there next MCB?
  5265.     jz short @@int310502rf0        ; if no, go on
  5266.  
  5267.     cmp [byte ptr coreseg:esi-4],0    ; is next memory block free?
  5268.     jne short @@int310502rf0    ; if no, go on
  5269.  
  5270.     call int310500rlinkmcb        ; link two memory blocks
  5271.  
  5272. @@int310502rf0:
  5273.     mov esi,[coreseg:edi-8]        ; ESI -> previous memory control block
  5274.     or esi,esi            ; is there previous MCB?
  5275.     jz short @@int310502rf1        ; if no, go on
  5276.  
  5277.     cmp [byte ptr coreseg:esi-4],0    ; is previous memory block free?
  5278.     jne short @@int310502rf1    ; if no, go on
  5279.  
  5280.     xchg esi,edi            ; change mcb order for function
  5281.     call int310500rlinkmcb        ; link two memory blocks
  5282.  
  5283. @@int310502rf1:
  5284.     call int310500radjustused    ; adjust INT 15h extended memory used
  5285.  
  5286.     jmp int31ok            ; return ok
  5287. ; [fold]  ]
  5288.  
  5289. ;─────────────────────────────────────────────────────────────────────────────
  5290. ; [fold]  [
  5291. int310503r: ; raw resize memory block
  5292.     call int310500rbxcxtoebx    ; convert BX:CX bytes to EBX bytes
  5293.     mov edx,ebx            ; EDX = size of new block
  5294.  
  5295.     call int310500rfindmcb        ; find MCB for handle SI:DI
  5296.  
  5297.     copy ds,SELCORE,ax        ; for easier block copy
  5298.     copy es,ds,ax            ; ES = DS for possible block copy
  5299.  
  5300.     sub ebx,[esi-16]        ; EBX = change in block size
  5301.     jz @@int310503rf0        ; if no change, done
  5302.  
  5303.     jc @@int310503rf1        ; if block made smaller, just free top
  5304.  
  5305.     xor eax,eax            ; running memory counter
  5306.  
  5307.     mov ecx,[esi-12]        ; ECX -> next MCB
  5308.     jecxz short @@int310503rf4    ; if no next MCB, check previous MCB
  5309.  
  5310.     cmp [byte ptr ecx-4],0        ; next MCB free?
  5311.     jne short @@int310503rf4    ; if not, check previous MCB
  5312.  
  5313.     mov eax,[ecx-16]        ; EAX = amount of free memory in block
  5314.     add eax,10h            ;  including memory control block
  5315.  
  5316. @@int310503rf4:
  5317.     mov ecx,[esi-8]            ; ECX -> previous MCB
  5318.     jecxz short @@int310503rf5    ; if no previous MCB, check memory
  5319.  
  5320.     cmp [byte ptr ecx-4],0        ; previous MCB free?
  5321.     jne short @@int310503rf5    ; if not, check memory
  5322.  
  5323.     add eax,[ecx-16]        ; add amount of free memory in block
  5324.     add eax,10h            ;  including memory control block
  5325.  
  5326. @@int310503rf5:
  5327.     cmp eax,ebx            ; enough to resize within area
  5328.     jb @@int310503rf3        ; if no, try to allocate
  5329.  
  5330.     or ecx,ecx            ; is there a previous MCB?
  5331.     jz @@int310503rf6        ; if no, resize to next
  5332.  
  5333.     cmp [byte ptr ecx-4],0        ; previous MCB free?
  5334.     jne short @@int310503rf6    ; if not, resize to next
  5335.  
  5336.     mov ebp,[ecx-16]        ; EBP = size of previous block, try to
  5337.     add ebp,10h            ;  resize within previous block
  5338.  
  5339.     sub ebp,ebx            ; EBP = prev block size - needed size
  5340.     jbe short @@int310503rf7    ; if prev block too small, go on
  5341.  
  5342.     mov edi,ecx            ; EDI -> new MCB for new memory block
  5343.     sub edi,ebp            ;  resize will fit entirely
  5344.  
  5345.     lea eax,[ebp-10h]        ; EAX = new size of free block
  5346.     mov [ecx-16],eax        ; store mew free size in prev MCB
  5347.     mov [edi-16],edx        ; store new size in new MCB
  5348.     mov [ecx-12],edi        ; set next MCB in prev MCB to new MCB
  5349.     mov [edi-8],ecx            ; set prev MCB in new MCB to prev MCB
  5350.     mov [byte ptr edi-4],1        ; set new MCB as used
  5351.  
  5352.     mov ecx,[esi-12]        ; copy next MCB field
  5353.     mov [edi-12],ecx
  5354.     or ecx,ecx            ; is there a next MCB
  5355.     jz @@int310503rf0        ; if no, go to block readjust
  5356.  
  5357.     mov [ecx-8],edi            ; set prev MCB in next MCB to new MCB
  5358.  
  5359.     jmp @@int310503rf0        ; go to block readjust
  5360.  
  5361. @@int310503rf7:
  5362.     mov edi,ecx            ; EDI -> new MCB for new memory block
  5363.  
  5364.     lea eax,[edx+ebp]        ; EAX = size of new block
  5365.     mov [edi-16],eax        ; store mew free size in new MCB
  5366.     mov [byte ptr edi-4],1        ; set new MCB as used
  5367.  
  5368.     mov ecx,[esi-12]        ; copy next MCB field
  5369.     mov [edi-12],ecx
  5370.     jecxz short @@int310503rf8    ; if no next MCB, go on
  5371.  
  5372.     mov [ecx-8],edi            ; set prev MCB in next MCB to new MCB
  5373.  
  5374. @@int310503rf8:
  5375.     add ebp,ebx            ; EBP = size of block just acquired
  5376.     sub ebx,ebp            ; EBX = new size still needed
  5377.     jz @@int310503rf0        ; if no more space needed, done
  5378.  
  5379.     mov esi,edi            ; ESI -> new MCB
  5380.  
  5381. @@int310503rf6:
  5382.     mov edi,[esi-12]        ; EDI -> next MCB
  5383.  
  5384.     mov ecx,[edi-12]        ; copy next MCB field
  5385.     mov [esi-12],ecx
  5386.     jecxz short @@int310503rf9    ; if no next MCB, go on
  5387.  
  5388.     mov [ecx-8],esi            ; set prev MCB in next MCB to this MCB
  5389.  
  5390. @@int310503rf9:
  5391.     mov eax,[edi-16]        ; EAX = size of next memory block
  5392.     add eax,10h
  5393.  
  5394.     sub edi,eax            ; EDI -> start of next memory block
  5395.     sub eax,ebx            ; EAX = amount of free space left
  5396.  
  5397.     mov ecx,[esi-16]        ; ECX = old size of this memory block
  5398.     mov [esi-16],edx        ; store new size in this MCB
  5399.     mov [byte ptr esi-4],1        ; set this MCB as used
  5400.  
  5401.     sub esi,ecx            ; ESI -> start of this memory block
  5402.     sub esi,10h
  5403.  
  5404.     shr ecx,2            ; copy this memory block down in mem
  5405.     rep movs [dword ptr es:edi],[dword ptr ds:esi]
  5406.     dnop
  5407.  
  5408.     add esi,10h            ; adjust ESI to top MCB
  5409.     mov edi,esi            ; EDI -> top MCB
  5410.  
  5411.     mov ebx,eax            ; EBX = negative of space free at top
  5412.     neg ebx
  5413.     jz @@int310503rf0        ; in no space free, go to done
  5414.  
  5415.     jmp short @@int310503rf1    ; set new MCBs for moved block
  5416.  
  5417. @@int310503rf3:
  5418.     mov ebp,edi            ; preserve old block MCB address
  5419.     sub edx,ebx            ; EDX = size of old block
  5420.  
  5421.     mov bx,[esp+16]            ; BX:CX = new block size from stack
  5422.     mov cx,[esp+24]
  5423.     mov ax,501h            ; try to allocate new block
  5424.     int 31h
  5425.     jc int31failax            ; if could not, fail with error AX
  5426.  
  5427.     shrd eax,esi,16            ; EAX -> new block MCB
  5428.     mov ax,di
  5429.  
  5430.     shrd edi,ebx,16            ; EDI -> start of new block
  5431.     mov di,cx
  5432.  
  5433.     lea esi,[ebp-10h]        ; ESI -> start of old block
  5434.     sub esi,edx
  5435.  
  5436.     mov ecx,edx            ; copy memory from old block to new
  5437.     shr ecx,2
  5438.     rep movs [dword ptr es:edi],[dword ptr ds:esi]
  5439.     dnop
  5440.  
  5441.     mov edx,eax            ; EDX -> new block MCB
  5442.  
  5443.     shld esi,ebp,16            ; SI:DI = handle of old block
  5444.     mov di,bp
  5445.     mov ax,0502h            ; free old block
  5446.     int 31h
  5447.  
  5448.     mov edi,edx            ; EDI -> new block MCB for done
  5449.  
  5450.     jmp short @@int310503rf0    ; go to done
  5451.  
  5452. @@int310503rf1:
  5453.     lea edi,[esi+ebx]        ; EDI -> new MCB for new memory block
  5454.  
  5455.     lea eax,[ebx+10h]        ; EAX = size of freed block
  5456.     neg eax
  5457.     mov [esi-16],eax        ; store freed size in old MCB
  5458.     mov [edi-16],edx        ; store new size in new MCB
  5459.  
  5460.     mov ecx,[esi-12]        ; copy next MCB field
  5461.     mov [edi-12],ecx
  5462.     jecxz short @@int310503rf2    ; if no next MCB, go on
  5463.  
  5464.     mov [ecx-8],edi            ; set prev MCB in next MCB to new MCB
  5465.  
  5466. @@int310503rf2:
  5467.     mov [esi-12],edi        ; set next MCB in old MCB as new MCB
  5468.     mov [edi-8],esi            ; set prev MCB in new MCB as old MCB
  5469.     mov [byte ptr edi-4],1        ; set new MCB as used
  5470.     mov [byte ptr esi-4],0        ; set old MCB as free
  5471.  
  5472.     mov ecx,[esi-8]            ; ECX -> prev MCB of old MCB
  5473.     jecxz short @@int310503rf0    ; if no prev MCB, done
  5474.  
  5475.     cmp [byte ptr ecx-4],0        ; is previous MCB free?
  5476.     jne short @@int310503rf0    ; if no, dont link
  5477.  
  5478.     push edi            ; preserve new MCB
  5479.     mov edi,ecx            ; top MCB = prev MCB for link function
  5480.     call int310500rlinkmcb        ; link two memory blocks
  5481.     pop edi                ; restore new MCB
  5482.  
  5483. @@int310503rf0:
  5484.     mov ecx,[edi-16]        ; ECX = base address of new block
  5485.     neg ecx
  5486.     lea ecx,[ecx+edi-10h]
  5487.  
  5488.     push SELDS
  5489.     pop ds                ; restore old DS
  5490.     jmp int310501raddxnhandle    ; return address and handle
  5491. ; [fold]  ]
  5492.  
  5493. ; [fold]  ]
  5494.  
  5495. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  5496. ; "NO MEMORY" EXTENDED MEMORY FUNCTIONS
  5497. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
  5498. ; [fold]  [
  5499.  
  5500. ;─────────────────────────────────────────────────────────────────────────────
  5501. ; [fold]  [
  5502. int310500n: ; no free extended memory present (near called)
  5503.     xor eax,eax            ; 0 bytes available extended memory
  5504.     ret                ; return memory information
  5505. ; [fold]  ]
  5506.  
  5507. ;─────────────────────────────────────────────────────────────────────────────
  5508. ; [fold]  [
  5509. int310501n: ; no allocation of memory
  5510.     jmp int31fail8013
  5511. ; [fold]  ]
  5512.  
  5513. ;─────────────────────────────────────────────────────────────────────────────
  5514. int310502n: ; freeing not possible
  5515. int310503n: ; resizing as well
  5516.     jmp int31fail8023
  5517.  
  5518. ; [fold]  ]
  5519.     ENDS
  5520.     END
  5521.  
  5522. ; [fold]  148
  5523.