Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1560 lines
45 KiB

  1. PAGE ,132
  2. TITLE DXUTIL.ASM -- Dos Extender Miscellaneous Routines
  3. ; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
  4. ;****************************************************************
  5. ;* *
  6. ;* DXUTIL.ASM - Dos Extender Miscellaneous *
  7. ;* *
  8. ;****************************************************************
  9. ;* *
  10. ;* Module Description: *
  11. ;* *
  12. ;* This module contains miscellaneous routines for the Dos *
  13. ;* Extender. *
  14. ;* *
  15. ;****************************************************************
  16. ;* Revision History: *
  17. ;* *
  18. ;* 08/08/90 earleh DOSX and client privilege ring determined *
  19. ;* by equate in pmdefs.inc *
  20. ;* 04/09/90 jimmat If 286 with 287, put 287 into pMode too. *
  21. ;* 08/20/89 jimmat Removed local A20 code since HIMEM 2.07 *
  22. ;* works properly across processor resets *
  23. ;* 07/28/89 jimmat Added A20 check/set routines, added *
  24. ;* SelOff2SegOff & Lma2SegOff routines. *
  25. ;* 06/19/89 jimmat Set direction flag before REP MOVS *
  26. ;* 05/25/89 jimmat Added GetSegmentAccess routine *
  27. ;* 03/30/89 jimmat Set IOPL = 3 when entering protect mode *
  28. ;* 03/16/89 jimmat Added more debug sanity checks *
  29. ;* 03/15/89 jimmat Minor changes to run child in ring 1 *
  30. ;* 03/13/89 jimmat Added support for LDT & TSS *
  31. ;* 02/10/89 (GeneA): changed Dos Extender from small model to *
  32. ;* medium model. Also added MoveMemBlock function. *
  33. ;* 01/25/89 (GeneA): changed initialization of real mode code *
  34. ;* segment address in EnterRealMode. caused by adding *
  35. ;* new method of relocationg dos extender for PM operation *
  36. ;* 12/13/88 (GeneA): moved EnterProtectedMode and EnterReal- *
  37. ;* Mode here from dxinit.asm *
  38. ;* 09/16/88 (GeneA): created by extracting code from the *
  39. ;* SST debugger modules DOSXTND.ASM, VIRTMD.ASM, *
  40. ;* VRTUTIL.ASM, and INTERRPT.ASM *
  41. ;* 18-Dec-1992 sudeepb Changed cli/sti to faster FCLI/FSTI *
  42. ;* 24-Jan-1992 v-simonf Added WOW callout when INT 8 hooked *
  43. ;* *
  44. ;****************************************************************
  45. .286p
  46. .287
  47. ; -------------------------------------------------------
  48. ; INCLUDE FILE DEFINITIONS
  49. ; -------------------------------------------------------
  50. ; .sall
  51. ; .xlist
  52. include segdefs.inc
  53. include gendefs.inc
  54. include pmdefs.inc
  55. include dpmi.inc
  56. include intmac.inc
  57. .list
  58. ; -------------------------------------------------------
  59. ; GENERAL SYMBOL DEFINITIONS
  60. ; -------------------------------------------------------
  61. SHUT_DOWN = 8Fh ;address in CMOS ram of the shutdown code
  62. CMOS_ADDR = 70h ;i/o address of the cmos ram address register
  63. CMOS_DATA = 71h ;i/o address of the cmos ram data register
  64. DMAServiceSegment equ 040h ;40:7B bit 5 indicates DMA services
  65. DMAServiceByte equ 07Bh ; are currently required
  66. DMAServiceBit equ 020h
  67. ; -------------------------------------------------------
  68. ; EXTERNAL SYMBOL DEFINITIONS
  69. ; -------------------------------------------------------
  70. ; -------------------------------------------------------
  71. ; DATA SEGMENT DEFINITIONS
  72. ; -------------------------------------------------------
  73. DXDATA segment
  74. extrn segGDT:WORD
  75. extrn segIDT:WORD
  76. extrn selGDT:WORD
  77. extrn selIDT:WORD
  78. extrn selGDTFree:WORD
  79. extrn bpGDT:FWORD
  80. extrn bpIDT:FWORD
  81. extrn bpRmIVT:FWORD
  82. extrn rgbXfrBuf1:BYTE
  83. extrn PMFaultVector:DWORD
  84. extrn lpfnXMSFunc:DWORD
  85. extrn pbReflStack:WORD
  86. bIntMask db 0
  87. bpBogusIDT df 0 ;This is loaded into the IDT register to
  88. ; force a bogus IDT to be defined. When we
  89. ; then do an interrupt a triple fault will
  90. ; occur forcing the processor to reset. This
  91. ; is when doing a mode switch to real mode.
  92. IDTSaveArea dw 3 DUP (?) ;save area for IDT during mode switch
  93. public A20EnableCount
  94. A20EnableCount dw 0
  95. ShutDownSP dw 0 ;stack pointer during 286 reset
  96. public f286_287
  97. f286_287 db 0 ;NZ if this is a 286 with 287 coprocessor
  98. if DEBUG ;------------------------------------------------------------
  99. extrn fTraceA20:WORD
  100. extrn fTraceMode:WORD
  101. public fA20
  102. fA20 db 0
  103. endif ;DEBUG --------------------------------------------------------
  104. selPmodeFS dw 0
  105. selPmodeGS dw 0
  106. public HighestSel
  107. HighestSel dw 0
  108. ifndef WOW_x86
  109. public IretBopTable
  110. IretBopTable label byte
  111. irp x,<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>
  112. db 0c4h, 0c4h, 05dh, x
  113. endm
  114. else
  115. public FastBop
  116. FastBop df 0
  117. IretBopTable label byte
  118. irp x,<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>
  119. db 02eh, 066h, 0FFh, 01eh, 00h, 00h, 05dh, x
  120. endm
  121. NullSel dd 0
  122. dd 0
  123. endif
  124. extrn DpmiFlags:WORD
  125. DXDATA ends
  126. ; -------------------------------------------------------
  127. ; CODE SEGMENT VARIABLES
  128. ; -------------------------------------------------------
  129. DXCODE segment
  130. extrn segDXData:WORD
  131. extrn segDXCode:WORD
  132. extrn selDgroup:WORD
  133. DXCODE ends
  134. DXPMCODE segment
  135. extrn selDgroupPM:WORD
  136. DXPMCODE ends
  137. ; -------------------------------------------------------
  138. subttl Real/Protected Mode Switch Routines
  139. page
  140. ; -------------------------------------------------------
  141. DXCODE segment
  142. assume cs:DXCODE
  143. ; -------------------------------------------------------
  144. ; REAL/PROTECTED MODE SWITCH ROUTINES
  145. ; -------------------------------------------------------
  146. ;
  147. ; EnterProtectedMode -- This routine will switch the processor
  148. ; into protected mode. It will return with the processor
  149. ; in protected mode and all of the segment registers loaded
  150. ; with the selectors for the protected mode segments.
  151. ; (CS with the selector for DXCODE and DS,ES,SS with the
  152. ; selector for DXDATA)
  153. ; It will also switch mode dependent memory variables.
  154. ; It assumes that InitGlobalDscrTable and InitIntrDscrTable
  155. ; have been called to set up the descriptor tables appropriately.
  156. ;
  157. ; Note: Except for a very brief time in this routine and in
  158. ; EnterRealMode, the DOS Extender runs in the same ring along
  159. ; with it's child app. This has the benefit of eliminating
  160. ; ring transitions on hardware and software interrupts.
  161. ; It also makes it possible for the child to hook their
  162. ; own interrupt routine into the IDT.
  163. ;
  164. ; Input: none
  165. ; Output: none
  166. ; Errors: none
  167. ; Uses: AX, DS, ES, SS, CS modified, all others preserved
  168. ;
  169. ; NOTE: This routine turns interrupts of and does not turn them
  170. ; back on.
  171. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  172. public EnterProtectedMode
  173. EnterProtectedMode proc near
  174. FCLI
  175. ; Update the mode dependent variables.
  176. mov ax,SEL_DXDATA or STD_RING
  177. mov selDgroup,ax
  178. ; Set the DMA services required bit for pMode users.
  179. mov ax,DMAServiceSegment
  180. mov es,ax
  181. or byte ptr es:[DMAServiceByte],DMAServiceBit
  182. ; 'local enable' the A20 line via HIMEM before switching to pMode.
  183. ; This is more complicated than you might think. Some real mode code
  184. ; (like old versions of SMARTDRV.SYS) may diddle with A20 on their own.
  185. ; These programs may not want us to change A20 on them. RMIntrReflector
  186. ; may do a XMS 'local enable' to turn A20 back on for one of these pgms.
  187. ; Also, on a 386 where we actually do the mode switch, we try to leave
  188. ; A20 enabled so as to not waste time diddling for nothing. The
  189. ; A20EnabledCount variable tracks if we've 'local enabled' A20 or not.
  190. ; Since we can't really trust real mode to leave A20 alone, we double
  191. ; check that it's really really on when we think it should be.
  192. push bx ;save bx around XMS calls
  193. cmp A20EnableCount,0 ;should A20 already be enabled?
  194. jz enpm10 ; no, (normal 4 286) just go enable it
  195. xmssvc 7 ; yes, is it really enabled?
  196. or ax,ax
  197. jnz enpm15 ; yes, we be done!
  198. if DEBUG ;------------------------------------------------------------
  199. or fA20,1 ; somebody done us wrong
  200. endif ;---------------------------------------------------------------
  201. xmssvc 6 ;keep enable/disable calls balanced
  202. dec A20EnableCount
  203. enpm10:
  204. xmssvc 5 ;local enable A20
  205. inc A20EnableCount
  206. if DEBUG ;------------------------------------------------------------
  207. or ax,ax
  208. jnz @f
  209. or fA20,2 ;enable failed!
  210. @@:
  211. cmp fTraceA20,0
  212. jz @f
  213. xmssvc 7 ;in debug mode, make double sure
  214. or ax,ax ; A20 was enabled. Slows things
  215. jnz @f ; down, but it's better to know.
  216. or fA20,2
  217. @@:
  218. endif ;DEBUG --------------------------------------------------------
  219. enpm15: pop bx
  220. ifndef WOW_x86
  221. DPMIBOP SetAltRegs
  222. ; Make sure that the nested task flag is clear
  223. pushf
  224. pop ax
  225. and ax,NOT 4000h
  226. push ax
  227. npopf
  228. ; Make sure that we have the appropriate descriptor tables in effect,
  229. ; and switch the machine into protected mode
  230. enpr20: smsw ax ;get current machine state
  231. or ax,1 ;set the protected mode bit
  232. lgdt bpGDT
  233. lidt bpIDT
  234. lmsw ax ;and away we go
  235. ; Flush the instruction queue and load the code segment selector
  236. ; by doing a far jump.
  237. db 0EAh ;jump far opcode
  238. dw offset enpm40 ;offset of far pointer
  239. dw SEL_DXCODE0 ;selector part of PM far pointer (ring 0)
  240. ; Load the other segment registers with valid selectors (not under VCPI)
  241. enpm40: mov ax,SEL_DXDATA0 ;stack has gotta be ring 0 also
  242. mov ss,ax
  243. ; Load the LDT register and the Task Register
  244. mov ax,SEL_LDT
  245. lldt ax ;load the LDT register
  246. mov ax,SEL_DXDATA or STD_RING
  247. mov ds,ax ;ds to our DGROUP
  248. mov ax,SEL_GDT
  249. mov es,ax ;es to GDT
  250. push si ;make sure busy bit is off
  251. mov si,SEL_TSS ; in the TSS descriptor
  252. mov es:[si].arbSegAccess,STD_TSS ; before trying to load it
  253. ltr si ;now load the task register
  254. pop si
  255. else
  256. .386p
  257. push ebp
  258. mov ebp,esp
  259. push SEL_DXCODE or STD_RING ; new cs
  260. push 0 ; high half eip
  261. push offset epmwow ; new eip
  262. push SEL_DXDATA or STD_RING ; new ss
  263. push ebp
  264. push SEL_DXDATA or STD_RING ; new ds
  265. DPMIBOP DPMISwitchToProtectedMode
  266. epmwow:
  267. pop ebp
  268. .286p
  269. endif
  270. push ds ;point es to DGROUP
  271. pop es
  272. ; If this is a 286 machine with a 287 math coprocessor, put the coprocessor
  273. ; into protected mode also.
  274. cmp f286_287,0 ;286 and 287?
  275. jz @f
  276. ifndef NEC_98
  277. xor al,al ; yup, clear co-processor busy line
  278. out 0F0h,al
  279. endif ;!NEC_98
  280. fsetpm ; and put it in pMode
  281. @@:
  282. ; We're currently running in ring 0. Setup an interlevel iret frame
  283. ; to switch to our normal ring, and also force IOPL=3. I spent 1+ day
  284. ; debugging on a 286 system (with no debugger!) because the 286 seemed
  285. ; switch into protected mode with IOPL=0, and once we got to an outer
  286. ; ring, we would fault on things like CLI instructions.
  287. enpmSwitchRing:
  288. ifndef WOW_x86
  289. mov ax,sp ;still points to return address
  290. push SEL_DXDATA or STD_RING ;new ss
  291. push ax ;new sp
  292. pushf
  293. pop ax
  294. or ah,30h
  295. push ax ;new flags, with IOPL=3
  296. push SEL_DXCODE or STD_RING ;new cs
  297. push offset DXCODE:epm_ret ;new ip
  298. iret
  299. endif
  300. ; When we get here, we are now in an outer ring.
  301. epm_ret:
  302. .386
  303. mov ax, selPmodeFS
  304. mov fs, ax
  305. mov ax, selPmodeGS
  306. mov gs, ax
  307. .286p
  308. ret ;near return to caller in pMode
  309. EnterProtectedMode endp
  310. ; -------------------------------------------------------
  311. ; EnterRealMode -- This routine will switch the processor
  312. ; from protected mode back into real mode. It will also
  313. ; reset the various mode dependent variables to their
  314. ; real mode values and load the segment registers with
  315. ; the real mode segment addresses.
  316. ;
  317. ; Input: none
  318. ; Output: none
  319. ; Errors: none
  320. ; Uses: AX, DS, ES, SS, CS modified
  321. ;
  322. ; NOTE: This routine must be called with the stack segment set
  323. ; to the Dos Extender data segment, as it resets the stack
  324. ; segment register to the Dos Extender real mode data segment
  325. ; but does not modify the stack pointer.
  326. ; NOTE: This routine turns interrupts off and and does not turn
  327. ; them back on.
  328. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  329. public EnterRealMode
  330. EnterRealMode proc near
  331. .386
  332. mov ax,fs
  333. mov selPmodeFS, ax
  334. mov ax,gs
  335. mov selPmodeGS, ax
  336. .286p
  337. FCLI
  338. mov es,selDgroup
  339. push SegDxCode
  340. push offset DXCODE:enrmwow
  341. push SegDxData
  342. push sp
  343. push SegDxData
  344. .386p
  345. DPMIBOP DPMISwitchToRealMode
  346. .286p
  347. enrmwow: add sp,6 ; remove rest of parameters
  348. push ds
  349. pop es ; es not set by mode switch
  350. enrm70:
  351. push es ;clear DMA services required
  352. mov ax,DMAServiceSegment ; bit for real mode
  353. mov es,ax
  354. and byte ptr es:[DMAServiceByte],not DMAServiceBit
  355. pop es
  356. mov ax,segDXData
  357. mov selDgroup,ax
  358. ret
  359. EnterRealMode endp
  360. ; -------------------------------------------------------
  361. public RmUnsimulateProc
  362. RmUnsimulateProc proc far
  363. BOP BOP_UNSIMULATE
  364. RmUnsimulateProc endp
  365. ; -------------------------------------------------------
  366. DXCODE ends
  367. DXPMCODE segment
  368. assume cs:DXPMCODE
  369. public PmUnsimulateProc
  370. PmUnsimulateProc proc far
  371. BOP BOP_UNSIMULATE
  372. PmUnsimulateProc endp
  373. ; -------------------------------------------------------
  374. ; RAW MODE SWITCH ROUTINES
  375. ; -------------------------------------------------------
  376. ; ------------------------------------------------------
  377. ; PmRawModeSwitch -- This routine performs a raw mode switch from
  378. ; protected mode to real mode. NOTE: applications will JUMP at this
  379. ; routine
  380. ;
  381. ; Input: ax - new DS
  382. ; cx - new ES
  383. ; dx - new SS
  384. ; bx - new sp
  385. ; si - new CS
  386. ; di - new ip
  387. ; Output: DS, ES, SS, sp, CS, ip contain new values
  388. ; Errors: none
  389. ; Uses:
  390. ;
  391. ;
  392. ;
  393. assume ds:nothing, ss:nothing, es:nothing
  394. public PmRawModeSwitch
  395. PmRawModeSwitch proc far
  396. push ss
  397. pop ds
  398. push bx
  399. .386p
  400. mov bx,ss
  401. movzx ebx,bx
  402. lar ebx,ebx
  403. test ebx,(AB_BIG SHL 8)
  404. mov ebx,esp
  405. jnz prms10
  406. movzx ebx,bx
  407. prms10:
  408. .286p
  409. ; Switch to dosx stack (since switch to real mode will do that to us anyway
  410. ; NOTE: no-one can call EnterIntHandler or ExitIntHandler until we switch to
  411. ; the user's new stack. If they do, they will use the area we stored
  412. ; the parameters for this call for a stack frame
  413. rpushf
  414. FCLI
  415. push SEL_DXDATA OR STD_RING
  416. pop ss
  417. assume ss:DGROUP
  418. .386p
  419. movzx esp,word ptr pbReflStack
  420. .286p
  421. ; Save user registers
  422. push dx ; ss
  423. .386p
  424. push word ptr [ebx]
  425. push word ptr [ebx - 2]; flags pushed before cli
  426. .286p
  427. push si ; cs
  428. push di ; ip
  429. push ax ; ds
  430. push cx ; es
  431. ; switch modes
  432. mov ax,SEL_DXDATA OR STD_RING
  433. mov ds,ax
  434. SwitchToRealMode
  435. ; set the registers, switch stacks, and return to the user
  436. pop es
  437. pop ds
  438. pop ax ; ip
  439. pop bx ; cs
  440. pop cx ; flags
  441. pop si ; sp
  442. pop ss
  443. assume ss:nothing
  444. mov sp,si
  445. push cx
  446. popf
  447. push bx
  448. push ax
  449. ret
  450. PmRawModeSwitch endp
  451. ; NOTE: this is now the DXCODE segment, NOT the DXPMCODE segment (courtesy
  452. ; of SwitchToRealMode
  453. ; ------------------------------------------------------
  454. ; RmRawModeSwitch -- This routine performs a raw mode switch from
  455. ; protected mode to real mode. NOTE: applications will JUMP at this
  456. ; routine
  457. ;
  458. ; Input: ax - new DS
  459. ; cx - new ES
  460. ; dx - new SS
  461. ; bx - new sp
  462. ; si - new CS
  463. ; di - new ip
  464. ; Output: DS, ES, SS, sp, CS, ip contain new values
  465. ; Errors: none
  466. ; Uses:
  467. ;
  468. ;
  469. ;
  470. assume ds:nothing, ss:nothing, es:nothing
  471. public RmRawModeSwitch
  472. RmRawModeSwitch proc far
  473. push ss
  474. pop ds
  475. push bx
  476. mov bx,sp
  477. ; Switch to dosx stack (since switch to real mode will do that to us anyway
  478. ; NOTE: no-one can call EnterIntHandler or ExitIntHandler until we switch to
  479. ; the user's new stack. If they do, they will use the area we stored
  480. ; the parameters for this call for a stack frame
  481. pushf
  482. FCLI
  483. push segDxData
  484. pop ss
  485. assume ss:DGROUP
  486. mov sp,pbReflStack
  487. ; Save user registers
  488. push dx ; ss
  489. push word ptr [bx] ; sp
  490. push word ptr [bx - 2] ; flags from before cli
  491. push si ; cs
  492. push di ; ip
  493. push ax ; ds
  494. push cx ; es
  495. ; switch modes
  496. mov ax,segDxData
  497. mov ds,ax
  498. SwitchToProtectedMode
  499. ; set the registers, switch stacks, and return to the user
  500. pop es
  501. pop ds
  502. .386p
  503. test DpmiFlags,DPMI_32BIT
  504. jnz rrms10
  505. xor eax,eax ; clear high 16 bits
  506. xor edi,edi ; clear high 16 bits
  507. .286p
  508. rrms10: pop di ; ip
  509. pop ax ; cs
  510. pop cx ; flags from before cli
  511. pop bx ; sp
  512. assume ss:nothing
  513. pop ss
  514. .386p
  515. mov esp,ebx
  516. .286p
  517. push cx
  518. rpopf
  519. .386p
  520. push eax
  521. push edi
  522. db 066h
  523. retf
  524. .286p
  525. RmRawModeSwitch endp
  526. DXPMCODE ENDS
  527. DXCODE SEGMENT
  528. ; -------------------------------------------------------
  529. ; STATE SAVE/RESTORE ROUTINES
  530. ; -------------------------------------------------------
  531. ; -------------------------------------------------------
  532. ; RmSaveRestoreState -- This routine exists as a placeholder. It
  533. ; is not currently necessary to perform any state saving/restoring
  534. ; for raw mode switch. The DPMI spec states that the user can call
  535. ; this routine with no adverse effect.
  536. ;
  537. ; Input: none
  538. ; Output: none
  539. ; Errors: none
  540. ; Uses: none
  541. ;
  542. assume ds:nothing, ss:nothing, es:nothing
  543. public RmSaveRestoreState
  544. RmSaveRestoreState proc far
  545. ret
  546. RmSaveRestoreState endp
  547. DXCODE ends
  548. ; -------------------------------------------------------
  549. DXPMCODE segment
  550. assume cs:DXPMCODE
  551. ; -------------------------------------------------------
  552. ; RmSaveRestoreState -- This routine exists as a placeholder. It
  553. ; is not currently necessary to perform any state saving/restoring
  554. ; for raw mode switch. The DPMI spec states that the user can call
  555. ; this routine with no adverse effect.
  556. ;
  557. ; Input: none
  558. ; Output: none
  559. ; Errors: none
  560. ; Uses: none
  561. ;
  562. assume ds:DGROUP, ss:nothing, es:nothing
  563. public PmSaveRestoreState
  564. PmSaveRestoreState proc far
  565. push ax
  566. push ds
  567. mov ax, SEL_DXDATA or STD_RING
  568. mov ds, ax
  569. test DpmiFlags,DPMI_32BIT
  570. pop ds
  571. pop ax
  572. jnz short @f ; 32-bit return
  573. ret
  574. @@:
  575. db 66h
  576. ret
  577. PmSaveRestoreState endp
  578. ifdef NEC_98
  579. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  580. public IncInBios
  581. public DecInBios
  582. ;
  583. ; IncInBios / DecInBios
  584. ;
  585. ; IN_BIOS Inc/Dec SubRoutine
  586. ;
  587. IncInBios proc near
  588. push ax
  589. push es
  590. mov ax, 0040h
  591. mov es, ax
  592. test byte ptr es:[0], 20h
  593. jz @f
  594. inc byte ptr es:[056h]
  595. @@:
  596. pop es
  597. pop ax
  598. ret
  599. IncInBios endp
  600. DecInBios proc near
  601. push ax
  602. push es
  603. mov ax, 0040h
  604. mov es, ax
  605. test byte ptr es:[0], 20h
  606. jz @f
  607. dec byte ptr es:[056h]
  608. @@:
  609. pop es
  610. pop ax
  611. ret
  612. DecInBios endp
  613. endif ;NEC_98
  614. ; -------------------------------------------------------
  615. ; GTPARA -- This routine will return the real mode paragraph
  616. ; address of the specified protected mode memory segment.
  617. ;
  618. ; Input: SI - selector of the segment
  619. ; Output: returns ZR true if segment is in lower 1MB range
  620. ; AX - real mode paragraph address
  621. ; returns ZR false if segment is in extended memory
  622. ; Errors: returns CY true if selector isn't valid
  623. ; Uses: AX modified, all else preserved
  624. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  625. public gtpara
  626. gtpara:
  627. push cx
  628. push es
  629. push si
  630. push bx
  631. mov bx,selGDT ;selector for the GDT segment
  632. mov es,bx
  633. lsl bx,bx
  634. and bx,SELECTOR_INDEX
  635. and si,SELECTOR_INDEX
  636. cmp si,bx ;check the given selector against
  637. ; the GDT segment limit
  638. pop bx
  639. jc gtpr20
  640. ; The given selector is beyond the end of the GDT, so return error.
  641. or sp,sp
  642. stc
  643. Debug_Out "gtpara: invalid selector (#si)"
  644. jmp short gtpr90
  645. ; The selector specified is inside the range of defined descriptors in
  646. ; the GDT. Get the address from the descriptor.
  647. gtpr20: mov cl,es:[si].adrBaseHigh
  648. test cl,0F0h
  649. jnz gtpr90
  650. shl cl,4
  651. mov ax,es:[si].adrBaseLow
  652. if DEBUG ;------------------------------------------------------------
  653. test al,0Fh
  654. jz @f
  655. Debug_Out "gtpara: segment not on para boundry, sel #si at #cl#ax"
  656. @@:
  657. endif ;DEBUG --------------------------------------------------------
  658. shr ax,4
  659. or ah,cl
  660. cmp ax,ax
  661. ;
  662. gtpr90:
  663. pop si
  664. pop es
  665. pop cx
  666. ret
  667. ; -------------------------------------------------------
  668. ; SelOff2SegOff -- This routine will return will translate a
  669. ; protected mode selector:offset address to the corresponding
  670. ; real mode segment:offset address.
  671. ;
  672. ; Input: AX - PM selector
  673. ; DX - PM offset
  674. ; Output: if Z set:
  675. ; AX - RM segment
  676. ; DX - RM offset
  677. ; if NZ set, address is not in conventional memory, and
  678. ; cannot be translated
  679. ;
  680. ; Errors: none
  681. ; Uses: AX, DX; all else preserved
  682. ;
  683. ; Note: This routine is very similar to gtpara, and could replace it!
  684. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  685. public SelOff2SegOff
  686. SelOff2SegOff proc near
  687. push bx
  688. push cx
  689. push dx
  690. call GetSegmentAddress ;bx:dx = lma of segment
  691. pop cx ;cx = offset
  692. test bl,0f0h ;above 1 Meg line?
  693. jnz @f ; yes, cut out now
  694. add dx,cx
  695. adc bx,0 ;bx:dx = lma of segment:offset
  696. call Lma2SegOff ;bx:dx = seg:off
  697. mov ax,bx ;dx:ax = seg:off
  698. cmp ax,ax ;under 1 Meg, set Z flag
  699. @@:
  700. pop cx
  701. pop bx
  702. ret
  703. SelOff2SegOff endp
  704. ; ------------------------------------------------------
  705. ; Lma2SegOff -- This routine converts a linear memory address
  706. ; in BX:DX to a normalized SEG:OFF in BX:DX.
  707. ;
  708. ; Input: BX:DX = lma
  709. ; Output: BX:DX = normalized SEG:OFF
  710. ; Uses: none
  711. public Lma2SegOff
  712. Lma2SegOff proc near
  713. push dx
  714. shl bx,12
  715. shr dx,4
  716. or bx,dx
  717. pop dx
  718. and dx,0fh
  719. ret
  720. Lma2SegOff endp
  721. ; -------------------------------------------------------
  722. ; GetSegmentAddress -- This routine will return with
  723. ; the linear address of the specified segment.
  724. ;
  725. ; Input: AX - segment selector
  726. ; Output: DX - low word of segment address
  727. ; BX - high word of segment address
  728. ; Errors: none
  729. ; Uses: BX, DX, all else preserved
  730. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  731. public GetSegmentAddress
  732. GetSegmentAddress:
  733. push es
  734. push di
  735. mov es,selGDT
  736. mov di,ax
  737. and di,SELECTOR_INDEX
  738. mov dx,es:[di].adrBaseLow
  739. mov bl,es:[di].adrBaseHigh
  740. mov bh,es:[di].adrbBaseHi386
  741. pop di
  742. pop es
  743. ret
  744. ; -------------------------------------------------------
  745. ; SetSegmentAddress -- This routine will modify the
  746. ; segment base address of the specified segment.
  747. ;
  748. ; Input: AX - segment selector
  749. ; Output: DX - low word of segment address
  750. ; BX - high word of segment address
  751. ; Errors: None
  752. ; Uses: All registers preserved
  753. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  754. public SetSegmentAddress
  755. SetSegmentAddress:
  756. push si
  757. push es
  758. mov es,selGDT
  759. mov si,ax
  760. and si,SELECTOR_INDEX
  761. mov es:[si].adrBaseLow,dx
  762. mov es:[si].adrBaseHigh,bl
  763. mov es:[si].adrbBaseHi386,bh
  764. push ax
  765. push bx
  766. push cx
  767. mov ax,si
  768. mov cx,1
  769. mov bx,si
  770. .386p
  771. FBOP BOP_DPMI,<SetDescriptorTableEntries>,FastBop
  772. .286p
  773. pop cx
  774. pop bx
  775. pop ax
  776. pop es
  777. pop si
  778. ret
  779. ; -------------------------------------------------------
  780. ; NSetSegmentAccess -- This routine will modify the
  781. ; access rights byte of a specified segment.
  782. ;
  783. ; Input: Selector - segment selector
  784. ; Access - Access rights byte value
  785. ; Output: none
  786. ; Errors: Carry set, AX = error code
  787. ; Uses: All registers preserved
  788. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  789. cProc NSetSegmentAccess,<PUBLIC,NEAR>,<es,si>
  790. parmW Selector
  791. parmW Access
  792. cBegin
  793. mov es,selGDT
  794. mov si,Selector
  795. and si,SELECTOR_INDEX
  796. mov ax,Access
  797. mov es:[si].arbSegAccess,al ; Set access byte.
  798. and ah,0F0h ; Mask off reserved bits.
  799. and es:[si].cbLimitHi386,0fh ; Clear old extended bits.
  800. or es:[si].cbLimitHi386,ah ; Set new extended bits.
  801. IFDEF WOW_x86
  802. push ax
  803. push bx
  804. push cx
  805. mov ax,si
  806. mov cx,1
  807. mov bx,si
  808. .386p
  809. FBOP BOP_DPMI,<SetDescriptorTableEntries>,FastBop
  810. .286p
  811. pop cx
  812. pop bx
  813. pop ax
  814. ENDIF
  815. cEnd
  816. ; -------------------------------------------------------
  817. ; ParaToLDTSelector -- This routine will convert a segment
  818. ; address relative to the start of the exe file into the
  819. ; corresponding selector for the segment. It searches the
  820. ; LDT to see if a segment is already defined at that address.
  821. ; If so, its selector is returned. If not, a new segment
  822. ; descriptor will be defined.
  823. ;
  824. ; Note: The LDT and GDT are currently one and the same.
  825. ;
  826. ; Input: AX - paragraph aaddress of real mode segment
  827. ; BX - access rights byte for the segment
  828. ; Output: AX - selector for the segment
  829. ; Errors: returns CY set if unable to define a new segment
  830. ; Uses: AX, all other registers preserved
  831. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  832. public ParaToLDTSelector
  833. ParaToLDTSelector proc near
  834. push bx
  835. push cx
  836. push dx
  837. ; Convert the paragraph address to a linear address and see if there
  838. ; is a segment defined at that address.
  839. mov dx,ax
  840. call FindLowSelector
  841. jnc @f ;if so, we don't need to make one
  842. ; This segment isn't defined, so we need to create a descriptor for it.
  843. mov ax,dx
  844. call MakeLowSegment
  845. if DEBUG ;------------------------------------------------------------
  846. jnc ptos80
  847. Debug_Out "ParaToLDTSelector: can't make selector!"
  848. ptos80:
  849. endif ;DEBUG --------------------------------------------------------
  850. jc ptos90
  851. @@: or al,SELECTOR_TI or STD_RING ;look like LDT selector
  852. ; All done
  853. ptos90: pop dx
  854. pop cx
  855. pop bx
  856. ret
  857. ParaToLDTSelector endp
  858. public FarParaToLDTSelector
  859. FarParaToLDTSelector proc far
  860. call ParaToLDTSelector
  861. ret
  862. FarParaToLDTSelector endp
  863. ; -------------------------------------------------------
  864. page
  865. ; -------------------------------------------------------
  866. ; DESCRIPTOR TABLE MANIPULATION ROUTINES
  867. ; -------------------------------------------------------
  868. ; -------------------------------------------------------
  869. ; AllocateSelector -- This function will obtain the
  870. ; next free descriptor in the global descriptor table.
  871. ; The descriptors in the GDT are stored on a linked list
  872. ; of free descriptors. The cbLimit field of the descriptor
  873. ; is used as the link to the next element of the list. In
  874. ; addition, free descriptors have the access rights byte
  875. ; set to 0.
  876. ;
  877. ; Note: The function InitGlobalDscrTable must have been
  878. ; called before calling this function.
  879. ;
  880. ; Input: none
  881. ; Output: AX - selector if one is available
  882. ; Errors: CY clear if successful, AX=0 and CY set if not free selectors
  883. ; Uses: AX, all else preserved
  884. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  885. public AllocateSelector
  886. AllocateSelector proc near
  887. ; Get the next free descriptor on the list.
  888. push cx
  889. mov cx, 1 ; # of selectors needed
  890. mov ax, 0
  891. push ds
  892. FBOP BOP_DPMI,Int31Call,FastBop
  893. pop cx
  894. ret
  895. AllocateSelector endp
  896. ; -------------------------------------------------------
  897. ; FreeSelector -- This routine will mark the segment
  898. ; descriptor for the specified selector as free. This
  899. ; is used to release a temporary selector when no longer
  900. ; needed. The descriptor is marked as free by setting the
  901. ; access rights byte to 0 and placing it on the free list.
  902. ;
  903. ; Note: This routine can only be called in protected mode.
  904. ;
  905. ; Input: AX - selector to free
  906. ; Output: none
  907. ; Errors: CY clear if no error, set if selector is invalid
  908. ; Uses: AX used, all other registers preserved
  909. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  910. public FreeSelector
  911. FreeSelector proc near
  912. push bx
  913. mov bx,ax
  914. mov ax,1
  915. push ds
  916. FBOP BOP_DPMI,Int31Call,FastBop
  917. pop bx
  918. ret
  919. FreeSelector endp
  920. ; -------------------------------------------------------
  921. ; FindLowSelector -- This function will search the global
  922. ; descriptor table for a descriptor matching the given
  923. ; address.
  924. ;
  925. ; Input: AX - real mode paragraph to search for
  926. ; BX - access rights byte for the segment
  927. ; Output: AX - selector corresponding to input paragraph address
  928. ; Errors: returns CY set if specified descriptor not found
  929. ; Uses: AX, all else preserved
  930. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  931. public FindLowSelector
  932. FindLowSelector:
  933. push bx
  934. push dx
  935. ;
  936. mov dx,ax
  937. push bx
  938. call ParaToLinear
  939. pop ax
  940. mov bh,al
  941. call FindSelector
  942. ;
  943. pop dx
  944. pop bx
  945. ret
  946. ; -------------------------------------------------------
  947. ; FindSelector -- This function will search the global
  948. ; descriptor table for a segment descriptor matching
  949. ; the specified linear byte address.
  950. ;
  951. ; Note that this routine cannot be used to find
  952. ; selectors pointing to addresses above 16 Megabytes.
  953. ; This is not really a problem, since the routine
  954. ; is used to find selectors in real mode DOS land
  955. ; most of the time.
  956. ;
  957. ; Input: DX - low word of linear byte address
  958. ; BL - high byte of linear address
  959. ; BH - access rights byte for the segment
  960. ; Output: AX - selector of corresponding segment
  961. ; Errors: returns CY set if specified descriptor not found
  962. ; Uses: AX used, all other registers preserved
  963. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  964. public FindSelector
  965. FindSelector proc near
  966. push si
  967. push di
  968. push es
  969. push cx
  970. ; Get segment limit of the GDT to use as a limit on the search.
  971. lsl di,selGDT
  972. mov es,selGDT
  973. ; Look for a descriptor matching the address in BL:AX
  974. mov si,SEL_USER ;search starting here
  975. if 0
  976. fnds20: cmp es:[si].arbSegAccess,0
  977. else
  978. fnds20: cmp word ptr es:[si].arbSegAccess,0
  979. endif
  980. jz fnds28 ;skip if unused descriptor
  981. cmp bl,es:[si].adrBaseHigh
  982. jnz fnds28
  983. cmp dx,es:[si].adrBaseLow
  984. jnz fnds28
  985. if 0
  986. cmp es:[si].cbLimit,0
  987. jz fnds28 ;skip if dscr has 0 limit
  988. else
  989. cmp es:[si].cbLimit,0ffffh
  990. jnz fnds28 ;skip unless dscr has 64k limit
  991. endif
  992. mov cl,bh
  993. xor cl,es:[si].arbSegAccess
  994. and cl,NOT AB_ACCESSED
  995. jz fnds90
  996. fnds28: add si,8 ;bump to next descriptor
  997. jc fnds80
  998. cmp si,di ;check against end of GDT
  999. jc fnds20 ;if still less, continue on.
  1000. ; Hit the end of the GDT and didn't find one. So return error.
  1001. fnds80: stc
  1002. jmp short fnds99
  1003. ; We found it, so return the selector
  1004. fnds90: mov ax,si
  1005. fnds99: pop cx
  1006. pop es
  1007. pop di
  1008. pop si
  1009. ret
  1010. FindSelector endp
  1011. ; -------------------------------------------------------
  1012. ; DupSegmentDscr -- This function will duplicate the specified
  1013. ; segment descriptor into the specified destination descriptor. The
  1014. ; end result is a second segment descriptor pointing to the same place
  1015. ; in memory as the first.
  1016. ;
  1017. ; Input: AX - selector of segment descriptor to duplicate
  1018. ; BX - selector of the segment descriptor to receive duplicate
  1019. ; Output: none
  1020. ; Errors: none
  1021. ; Uses: All registers preserved. Modifies the segment
  1022. ; descriptor for the specified segment. If this selector happens
  1023. ; to be in a segment register when this routine is called, that
  1024. ; segment register may end up pointing to the new location.
  1025. assume ds:DGROUP,es:NOTHING
  1026. public DupSegmentDscr
  1027. DupSegmentDscr proc near
  1028. push cx
  1029. push si
  1030. push di
  1031. push ds
  1032. push es
  1033. mov si,ax
  1034. mov di,bx
  1035. and si,SELECTOR_INDEX
  1036. and di,SELECTOR_INDEX
  1037. mov es,selGDT
  1038. mov ds,selGDT
  1039. assume ds:NOTHING
  1040. mov cx,4
  1041. cld
  1042. rep movs word ptr [di],word ptr [si]
  1043. pop es
  1044. pop ds
  1045. pop di
  1046. pop si
  1047. pop cx
  1048. ret
  1049. DupSegmentDscr endp
  1050. IFDEF ROM
  1051. ; -------------------------------------------------------
  1052. DXPMCODE ends
  1053. ; -------------------------------------------------------
  1054. DXCODE segment
  1055. assume cs:DXCODE
  1056. ENDIF
  1057. ; -------------------------------------------------------
  1058. ; NSetSegmentDscr -- This function will initialize the
  1059. ; specified descriptor table entry with the specified data.
  1060. ;
  1061. ; This function can be called in real mode or protected mode.
  1062. ;
  1063. ; Input:
  1064. ; Param1 - WORD segment selector
  1065. ; Param2 - DWORD 32-bit segment base address
  1066. ; Param3 - DWORD 32-bit segment limit
  1067. ; param4 - WORD segment access/type
  1068. ; Output: returns selector for the segment
  1069. ; Errors: none
  1070. ; Uses: Flags
  1071. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1072. cProc NSetSegmentDscr,<PUBLIC,FAR>,<es,di,ax,bx>
  1073. parmW Selector
  1074. parmD Base
  1075. parmD Limit
  1076. parmW Access
  1077. cBegin
  1078. mov es,selGDT
  1079. mov di,Selector
  1080. and di,SELECTOR_INDEX
  1081. mov ax,off_Base ; Set segment base
  1082. mov es:[di].adrBaseLow,ax
  1083. mov ax,seg_Base
  1084. mov es:[di].adrBaseHigh,al
  1085. mov es:[di].adrbBaseHi386,ah
  1086. mov ax,word ptr Access
  1087. and ax,070ffh ; clear 'G' bit and
  1088. ; extended limit bits
  1089. mov word ptr es:[di].arbSegAccess,ax
  1090. ; set access
  1091. mov ax,seg_Limit
  1092. mov bx,off_Limit ; AX:BX = segment limit
  1093. test ax,0fff0h ; big?
  1094. jz ssd_0 ; No
  1095. shr bx,12d ; Yes, make it page granular.
  1096. shl ax,4d
  1097. or bx,ax
  1098. mov ax,seg_Limit
  1099. shr ax,12d
  1100. or al,080h ; set 'G' bit
  1101. ssd_0:
  1102. or es:[di].cbLimitHi386,al ; set high limit
  1103. mov es:[di].cbLimit,bx ; set low limit
  1104. push ax
  1105. push bx
  1106. push cx
  1107. mov ax,di
  1108. mov cx,1
  1109. mov bx,di
  1110. .386p
  1111. FBOP BOP_DPMI,<SetDescriptorTableEntries>,FastBop
  1112. .286p
  1113. pop cx
  1114. pop bx
  1115. pop ax
  1116. cEnd
  1117. ifndef WOW_x86
  1118. ; -------------------------------------------------------
  1119. ; NSetGDTSegmentDscr -- This function will initialize the
  1120. ; specified descriptor table entry with the specified data.
  1121. ;
  1122. ; This function can be called in real mode or protected mode.
  1123. ;
  1124. ; Input:
  1125. ; Param1 - WORD segment selector
  1126. ; Param2 - DWORD 32-bit segment base address
  1127. ; Param3 - DWORD 32-bit segment limit
  1128. ; param4 - WORD segment access/type
  1129. ; Output: returns selector for the segment
  1130. ; Errors: none
  1131. ; Uses: Flags
  1132. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1133. cProc NSetGDTSegmentDscr,<PUBLIC,FAR>,<es,di,ax,bx>
  1134. parmW Selector
  1135. parmD Base
  1136. parmD Limit
  1137. parmW Access
  1138. cBegin
  1139. mov ax,SEL_GDT
  1140. mov es,ax
  1141. mov di,Selector
  1142. and di,SELECTOR_INDEX
  1143. mov ax,off_Base ; Set segment base
  1144. mov es:[di].adrBaseLow,ax
  1145. mov ax,seg_Base
  1146. mov es:[di].adrBaseHigh,al
  1147. mov es:[di].adrbBaseHi386,ah
  1148. mov ax,word ptr Access
  1149. and ax,070ffh ; clear 'G' bit and
  1150. ; extended limit bits
  1151. mov word ptr es:[di].arbSegAccess,ax
  1152. ; set access
  1153. mov ax,seg_Limit
  1154. mov bx,off_Limit ; AX:BX = segment limit
  1155. test ax,0fff0h ; big?
  1156. jz @f ; No
  1157. shr bx,12d ; Yes, make it page granular.
  1158. shl ax,4d
  1159. or bx,ax
  1160. mov ax,seg_Limit
  1161. shr ax,12d
  1162. or al,080h ; set 'G' bit
  1163. @@:
  1164. or es:[di].cbLimitHi386,al ; set high limit
  1165. mov es:[di].cbLimit,bx ; set low limit
  1166. cEnd
  1167. endif ; WOW_x86
  1168. IFDEF ROM
  1169. ; -------------------------------------------------------
  1170. DXCODE ends
  1171. ; -------------------------------------------------------
  1172. DXPMCODE segment
  1173. assume cs:DXPMCODE
  1174. ENDIF
  1175. ; -------------------------------------------------------
  1176. ; MakeLowSegment -- This function will create a segment
  1177. ; descriptor for the specified low memory paragraph address.
  1178. ; The segment length will be set to 64k. The difference
  1179. ; between this and MakeScratchSelector is that this function
  1180. ; allocates a new segment descriptor in the user area of
  1181. ; the global descriptor table, thus creating a more or less
  1182. ; permanent selector. MakeScratchSelector always uses the
  1183. ; same descriptor location in the descriptor table, thus
  1184. ; creating a very temporary selector.
  1185. ;
  1186. ; Input: AX - paragraph address in low memory
  1187. ; BX - access rights word for the segment
  1188. ; Output: AX - selector to use to access the memory
  1189. ; Errors: returns CY clear if no error, CY set if unable to
  1190. ; allocate a segment descriptor
  1191. ; Uses: AX used, all else preserved
  1192. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1193. public MakeLowSegment
  1194. MakeLowSegment proc near
  1195. ; We need to allocate a segment descriptor, convert the paragraph address
  1196. ; to a linear byte address, and then initialize the allocated segment
  1197. ; descriptor.
  1198. push dx
  1199. push cx
  1200. mov cx,bx
  1201. mov dx,ax ;paragraph address to DX
  1202. call AllocateSelector ;get a segment descriptor to use
  1203. jc mksl90 ;get out if error
  1204. call ParaToLinear
  1205. cCall NSetSegmentDscr,<ax,bx,dx,0,0FFFFh,cx>
  1206. clc
  1207. mksl90:
  1208. pop cx
  1209. pop dx
  1210. ret
  1211. MakeLowSegment endp
  1212. ; -------------------------------------------------------
  1213. ; ParaToLinear
  1214. ;
  1215. ; This function will convert a paragraph address in the lower
  1216. ; megabyte of memory space into a linear address for use in
  1217. ; a descriptor table.
  1218. ;
  1219. ; Input: DX - paragraph address
  1220. ; Output: DX - lower word of linear address
  1221. ; BX - high word of linear address
  1222. ; Errors: none
  1223. ; Uses: DX, BL used, all else preserved
  1224. assume ds:NOTHING,es:NOTHING,ss:NOTHING
  1225. public ParaToLinear
  1226. ParaToLinear proc near
  1227. mov bl,dh
  1228. shr bl,4
  1229. shl dx,4
  1230. xor bh,bh
  1231. ret
  1232. ParaToLinear endp
  1233. ; -------------------------------------------------------
  1234. ; RZCall -- Utility routine to call a Ring
  1235. ; Zero procedure. Stack parameter is the NEAR
  1236. ; address of the routine in the DXPMCODE segment to
  1237. ; call. The called routine must be declared FAR
  1238. ; and take no stack parameters.
  1239. ;
  1240. ; USES: Whatever Ring 0 routine uses
  1241. ; +Flags
  1242. ; RETURNS: Whatever Ring 0 routine returns
  1243. ;
  1244. ; NOTE: Assumes that interrupts must be disabled
  1245. ; for the Ring 0 routine.
  1246. ;
  1247. ; History:
  1248. ; 12-Feb-1991 -- ERH wrote it!!!
  1249. ; -------------------------------------------------------
  1250. My_Call_Gate dd (SEL_SCR0 or STD_TBL_RING) shl 10h
  1251. public RZCall
  1252. RZCall proc near
  1253. pushf
  1254. FCLI
  1255. push bp
  1256. mov bp,sp
  1257. cCall NSetSegmentDscr,<SEL_SCR0,0,SEL_EH,0,[bp+6],STD_CALL>
  1258. pop bp
  1259. call dword ptr My_Call_Gate
  1260. cCall NSetSegmentDscr,<SEL_SCR0,0,0,0,-1,STD_DATA>
  1261. npopf
  1262. retn 2
  1263. RZCall endp
  1264. ; -------------------------------------------------------
  1265. ; -------------------------------------------------------
  1266. DXPMCODE ends
  1267. ;
  1268. ;****************************************************************
  1269. end