Leaked source code of windows server 2003
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.

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