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.

705 lines
17 KiB

  1. ;++
  2. ;
  3. ; Copyright (c) 1991 Microsoft Corporation
  4. ;
  5. ; Module Name:
  6. ;
  7. ; xxbiosa.asm
  8. ;
  9. ; Abstract:
  10. ;
  11. ; This implements the necessary code to put the processor into
  12. ; V86 mode, make a BIOS call, and return safely to protected mode.
  13. ;
  14. ; Author:
  15. ;
  16. ; John Vert (jvert) 29-Oct-1991
  17. ;
  18. ; Environment:
  19. ;
  20. ; Kernel mode
  21. ;
  22. ; Notes:
  23. ;
  24. ; This module is intended for use in panic situations, such as a bugcheck.
  25. ; As a result, we cannot rely on the integrity of the system so we must
  26. ; handle everything ourselves. Notably, we must map our own memory by
  27. ; adding our own page tables and PTEs.
  28. ;
  29. ; We also cannot call KeBugCheck when we notice something has gone wrong.
  30. ;
  31. ; Revision History:
  32. ;
  33. ;--
  34. .386p
  35. .xlist
  36. include hal386.inc
  37. include callconv.inc ; calling convention macros
  38. include i386\kimacro.inc
  39. .list
  40. extrn _DbgPrint:proc
  41. EXTRNP _DbgBreakPoint,0,IMPORT
  42. EXTRNP Kei386EoiHelper,0,IMPORT
  43. public _HalpRealModeStart
  44. public _HalpRealModeEnd
  45. ;
  46. ; 32-bit override
  47. ;
  48. OVERRIDE equ 66h
  49. ;
  50. ; Reginfo structure
  51. ;
  52. RegInfo struc
  53. RiSegSs dd 0
  54. RiEsp dd 0
  55. RiEFlags dd 0
  56. RiSegCs dd 0
  57. RiEip dd 0
  58. RiTrapFrame dd 0
  59. RiCsLimit dd 0
  60. RiCsBase dd 0
  61. RiCsFlags dd 0
  62. RiSsLimit dd 0
  63. RiSsBase dd 0
  64. RiSsFlags dd 0
  65. RiPrefixFlags dd 0
  66. RegInfo ends
  67. REGINFOSIZE EQU 52
  68. INT_NN_OPCODE EQU 0CDH
  69. page ,132
  70. _DATA SEGMENT DWORD PUBLIC 'DATA'
  71. ;
  72. ; In order to return to the calling function after we've trapped out of
  73. ; V86 mode, we save our ESP value here.
  74. ;
  75. HalpSavedEsp dd 0
  76. _DATA ENDS
  77. _TEXT SEGMENT DWORD PUBLIC 'CODE'
  78. ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
  79. if DBG
  80. page ,132
  81. subttl "Processing Exception occurred in ABIOS code"
  82. ;++
  83. ; VOID
  84. ; KiAbiosException (
  85. ; VOID
  86. ; )
  87. ;
  88. ; Routine Description:
  89. ;
  90. ; This routine is called after an exception being detected
  91. ; in ABIOS ROM code. The system will switch 16 stack to 32 bit
  92. ; stack and bugcheck.
  93. ;
  94. ; N.B. In fact this routine is simply used to resolve a reference
  95. ; to KiAbiosException routine in the Kimacro.inc ENTER_TRAP
  96. ; macro.
  97. ;
  98. ;
  99. ; Arguments:
  100. ;
  101. ; None.
  102. ;
  103. ; Return value:
  104. ;
  105. ; system stopped.
  106. ;
  107. ;--
  108. public _KiAbiosException
  109. _KiAbiosException proc
  110. _Ki16BitStackException:
  111. ret
  112. _KiAbiosException endp
  113. endif
  114. ;++
  115. ; ULONG
  116. ; HalpBorrowTss (
  117. ; VOID
  118. ; )
  119. ;
  120. ; Routine Description:
  121. ;
  122. ; This routine checks if the current TSS has IO MAP space.
  123. ; if yes, it simply returns. Otherwise, it switches to use
  124. ; the regular TSS.
  125. ;
  126. ; Arguments:
  127. ;
  128. ; None.
  129. ;
  130. ; Return value:
  131. ;
  132. ; Return original TSS selector if the regular Tss is borrowed by us.
  133. ;
  134. ;--
  135. cPublicProc _HalpBorrowTss, 0
  136. cPublicFpo 0, 0
  137. xor eax, eax
  138. str ax
  139. mov edx, PCR[PcGdt]
  140. add edx, eax ; (edx)->Gdt Entry of current
  141. ; TSS
  142. xor ecx, ecx
  143. mov cl, [edx].KgdtLimitHi
  144. shl ecx, 16
  145. mov cx, [edx].KgdtLimitLow ; (ecx) = TSS limit
  146. cmp ecx, 2000H ; Is Io map space available?
  147. ja short Hbt99 ; if a, yes, return
  148. sub edx, eax ; (edx)->GDT table
  149. mov ch, [edx+KGDT_TSS+KgdtBaseHi]
  150. mov cl, [edx+KGDT_TSS+KgdtBaseMid]
  151. shl ecx, 16
  152. mov cx, [edx+KGDT_TSS+KgdtBaseLow]
  153. mov PCR[PcTss], ecx
  154. mov ecx, KGDT_TSS ; switch to use regular TSS
  155. mov byte ptr [edx+KGDT_TSS+5], 089h ; 32bit, dpl=0, present, TSS32,
  156. ; not busy.
  157. ltr cx
  158. stdRET _HalpBorrowTss ; (eax) = Original TSS sel
  159. Hbt99:
  160. xor eax, eax ; No TSS swapped
  161. stdRET _HalpBorrowTss
  162. stdENDP _HalpBorrowTss
  163. ;++
  164. ; VOID
  165. ; HalpReturnTss (
  166. ; ULONG TssSelector
  167. ; )
  168. ;
  169. ; Routine Description:
  170. ;
  171. ; This routine switches the current TSS from regular TSS back to
  172. ; the panic TSS (NMI TSS or Double fault TSS).
  173. ;
  174. ; Arguments:
  175. ;
  176. ; TssSelector - the TSS selector to return to.
  177. ;
  178. ; Return value:
  179. ;
  180. ; None.
  181. ;
  182. ;--
  183. cPublicProc _HalpReturnTss, 1
  184. cPublicFpo 1, 0
  185. mov edx, PCR[PcGdt] ; (edx)-> Gdt table
  186. mov eax, [esp + 4]
  187. and eax, 0FFFFh ; (eax)= New TSS sel
  188. add edx, eax ; (edx)->Gdt Entry of new TSS
  189. mov ch, [edx+KgdtBaseHi]
  190. mov cl, [edx+KgdtBaseMid]
  191. shl ecx, 16
  192. mov cx, [edx+KgdtBaseLow]
  193. mov PCR[PcTss], ecx
  194. mov byte ptr [edx+5], 089h ; 32bit, dpl=0, present, TSS32,
  195. ltr ax
  196. stdRET _HalpReturnTss ; return and clear stack
  197. stdENDP _HalpReturnTss
  198. ;++
  199. ;
  200. ; VOID
  201. ; HalpBiosCall
  202. ; VOID
  203. ; )
  204. ;
  205. ; Routine Description:
  206. ;
  207. ; This routine completes the transition to real mode, calls BIOS, and
  208. ; returns to protected mode.
  209. ;
  210. ; Arguments:
  211. ;
  212. ; None.
  213. ;
  214. ; Return Value:
  215. ;
  216. ; None.
  217. ;
  218. ;--
  219. ;;ALIGN 4096
  220. cPublicProc _HalpBiosCall ,0
  221. push ebp
  222. mov ebp, esp
  223. pushfd
  224. push edi
  225. push esi
  226. push ebx
  227. push ds
  228. push es
  229. push fs
  230. push gs
  231. push offset FLAT:HbcProtMode ; address where we will start
  232. ; protected mode again once
  233. ; V86 has completed.
  234. mov HalpSavedEsp, esp
  235. mov eax, cr0 ; make sure alignment
  236. and eax, not CR0_AM ; checks are disabled
  237. mov cr0, eax
  238. ;
  239. ; Create space for the V86 trap frame and update the ESP0 value in the TSS
  240. ; to use this space. We will set this up just below our current stack pointer.
  241. ; The stuff we push on the stack after we set ESP0 is irrelevant once we
  242. ; make it to V86 mode, so it's ok to blast it.
  243. ;
  244. mov esi, fs:PcTss ; (esi) -> TSS
  245. mov eax, esp
  246. sub eax, NPX_FRAME_LENGTH ; skip FP save area
  247. mov [esi]+TssEsp0, eax
  248. push dword ptr 0h ; V86 GS
  249. push dword ptr 0h ; V86 FS
  250. push dword ptr 0h ; V86 DS
  251. push dword ptr 0h ; V86 ES
  252. push dword ptr 2000h ; V86 SS
  253. ;
  254. ; We calculate the V86 sp by adding the difference between the linear address
  255. ; of the V86 ip (HbcReal) and the linear address of the V86 sp (HbcV86Stack)
  256. ; to the offset of the V86 ip (HbcReal & 0xfff).
  257. ;
  258. mov eax, offset FLAT:HbcV86Stack-4
  259. sub eax, offset FLAT:HbcReal
  260. mov edx, offset HbcReal
  261. and edx, 0fffh
  262. add eax, edx
  263. push eax ; V86 esp
  264. pushfd
  265. or dword ptr [esp], EFLAGS_V86_MASK; V86 eflags
  266. or [esp], 03000h ; Give IOPL3
  267. push dword ptr 2000h ; V86 CS
  268. mov eax, offset HbcReal
  269. and eax, 0fffh
  270. push edx ; V86-mode EIP is offset
  271. ; into CS.
  272. iretd
  273. _HalpRealModeStart label byte
  274. HbcReal:
  275. db OVERRIDE ; make mov 32-bits
  276. mov eax, 12h ; 640x480x16 colors
  277. int 10h
  278. db 0c4h, 0c4h ; BOP to indicate V86 mode is done.
  279. ;
  280. ; V86-mode stack
  281. ;
  282. align 4
  283. db 2048 dup(0)
  284. HbcV86Stack:
  285. _HalpRealModeEnd label byte
  286. HbcProtMode:
  287. ;
  288. ; We are back from V86 mode, so restore everything we saved and we are done.
  289. ;
  290. pop gs
  291. pop fs
  292. pop es
  293. pop ds
  294. pop ebx
  295. pop esi
  296. pop edi
  297. popfd
  298. pop ebp
  299. stdRET _HalpBiosCall
  300. public _HalpBiosCallEnd
  301. _HalpBiosCallEnd label byte
  302. _HalpBiosCall endp
  303. subttl "HAL General Protection Fault"
  304. ;++
  305. ;
  306. ; Routine Description:
  307. ;
  308. ; Handle General protection fault.
  309. ;
  310. ; This fault handler is used by the HAL for V86 mode faults only.
  311. ; It should NEVER be used except when running in V86 mode. The HAL
  312. ; replaces the general-purpose KiTrap0D handler entry in the IDT with
  313. ; this routine. This allows us to emulate V86-mode instructions which
  314. ; cause a fault. After we return from V86 mode, we can restore the
  315. ; KiTrap0D handler in the IDT.
  316. ;
  317. ; Arguments:
  318. ;
  319. ; At entry, the saved CS:EIP point to the faulting instruction
  320. ; Error code (whose value depends on detected condition) is provided.
  321. ;
  322. ; Return value:
  323. ;
  324. ; None
  325. ;
  326. ;--
  327. ASSUME DS:FLAT, SS:NOTHING, ES:FLAT
  328. ENTER_DR_ASSIST Htd_a, Htd_t, NoAbiosAssist
  329. cPublicProc _HalpTrap0D ,0
  330. ENTER_TRAP Htd_a, Htd_t
  331. ;
  332. ; Did the trap occur in V86 mode? If not, something is completely messed up.
  333. ;
  334. test dword ptr [ebp]+TsEFlags,00020000H
  335. jnz Ht0d10
  336. ;
  337. ; The trap was not from V86 mode, so something is very wrong. We cannot
  338. ; BugCheck, since we are probably already in a BugCheck. So just stop.
  339. ;
  340. if DBG
  341. _TEXT segment
  342. MsgBadHalTrap db 'HAL: Trap0D while not in V86 mode',0ah,0dh,0
  343. _TEXT ends
  344. push offset FLAT:MsgBadHalTrap
  345. call _DbgPrint
  346. add esp,4
  347. stdCall _DbgBreakPoint
  348. endif
  349. ;
  350. ; We can't bugcheck, so just commit suicide. Maybe we should reboot?
  351. ;
  352. jmp $
  353. Ht0d10:
  354. stdCall HalpDispatchV86Opcode
  355. SPURIOUS_INTERRUPT_EXIT
  356. stdENDP _HalpTrap0d
  357. subttl "HAL Invalid Opcode Fault"
  358. ;++
  359. ;
  360. ; Routine Description:
  361. ;
  362. ; Handle invalid opcode fault
  363. ;
  364. ; This fault handler is used by the HAL to indicate when V86 mode
  365. ; execution is finished. The V86 code attempts to execute an invalid
  366. ; instruction (BOP) when it is done, and that brings us here.
  367. ; This routine just removes the trap frame from the stack and does
  368. ; a RET. Note that this assumes that ESP0 in the TSS has been set
  369. ; up to point to the top of the stack that we want to be running on
  370. ; when the V86 call has completed.
  371. ;
  372. ; This should NEVER be used except when running in V86 mode. The HAL
  373. ; replaces the general-purpose KiTrap06 handler entry in the IDT with
  374. ; this routine. It also sets up ESP0 in the TSS appropriately. After
  375. ; the V86 call has completed, it restores these to their previous values.
  376. ;
  377. ; Arguments:
  378. ;
  379. ; At entry, the saved CS:EIP point to the faulting instruction
  380. ; Error code (whose value depends on detected condition) is provided.
  381. ;
  382. ; Return value:
  383. ;
  384. ; None
  385. ;
  386. ;--
  387. ASSUME DS:FLAT, SS:NOTHING, ES:FLAT
  388. cPublicProc _HalpTrap06 ,0
  389. mov eax,KGDT_R3_DATA OR RPL_MASK
  390. mov ds,ax
  391. mov es,ax
  392. mov esp, HalpSavedEsp
  393. ret
  394. stdENDP _HalpTrap06
  395. subttl "Instruction Emulation Dispatcher"
  396. ;++
  397. ;
  398. ; Routine Description:
  399. ;
  400. ; This routine dispatches to the opcode specific emulation routine,
  401. ; based on the first byte of the opcode. Two byte opcodes, and prefixes
  402. ; result in another level of dispatching, from the handling routine.
  403. ;
  404. ; This code blatantly stolen from ke\i386\instemul.asm
  405. ;
  406. ; Arguments:
  407. ;
  408. ; ebp = pointer to trap frame
  409. ;
  410. ; Returns:
  411. ;
  412. ; Nothing
  413. ;
  414. cPublicProc HalpDispatchV86Opcode ,0
  415. RI equ [ebp - REGINFOSIZE]
  416. push ebp
  417. mov ebp,esp
  418. sub esp,REGINFOSIZE
  419. push esi
  420. push edi
  421. ; Initialize RegInfo
  422. mov esi,[ebp]
  423. mov RI.RiTrapFrame,esi
  424. movzx eax,word ptr [esi].TsHardwareSegSs
  425. mov RI.RiSegSs,eax
  426. mov eax,[esi].TsHardwareEsp
  427. mov RI.RiEsp,eax
  428. mov eax,[esi].TsEFlags
  429. mov RI.RiEFlags,eax
  430. movzx eax,word ptr [esi].TsSegCs
  431. mov RI.RiSegCs,eax
  432. mov eax,[esi].TsEip
  433. mov RI.RiEip,eax
  434. xor eax,eax
  435. mov RI.RiPrefixFlags,eax
  436. lea esi,RI
  437. ;
  438. ; Convert CS to a linear address
  439. ;
  440. mov eax,[esi].RiSegCs
  441. shl eax,4
  442. mov [esi].RiCsBase,eax
  443. mov [esi].RiCsLimit,0FFFFh
  444. mov [esi].RiCsFlags,0
  445. mov edi,RI.RiEip
  446. cmp edi,RI.RiCsLimit
  447. ja doerr
  448. add edi,RI.RiCsBase
  449. mov dl, [edi] ; get faulting opcode
  450. cmp dl, INT_NN_OPCODE
  451. je short @f
  452. stdCall HalpOpcodeInvalid
  453. jmp short doerr
  454. @@:
  455. stdCall HalpOpcodeINTnn
  456. test eax,0FFFFh
  457. jz do20
  458. mov edi,RI.RiTrapFrame
  459. mov eax,RI.RiEip ; advance eip
  460. mov [edi].TsEip,eax
  461. mov eax,1
  462. do20: pop edi
  463. pop esi
  464. mov esp,ebp
  465. pop ebp
  466. ret
  467. doerr: xor eax,eax
  468. jmp do20
  469. stdENDP HalpDispatchV86Opcode
  470. page ,132
  471. subttl "Invalid Opcode Handler"
  472. ;++
  473. ;
  474. ; Routine Description:
  475. ;
  476. ; This routine handles invalid opcodes. It prints the invalid
  477. ; opcode message, and breaks into the kernel debugger.
  478. ;
  479. ; Arguments:
  480. ;
  481. ; esi = address of reg info
  482. ; edx = opcode
  483. ;
  484. ; Returns:
  485. ;
  486. ; nothing
  487. ;
  488. _TEXT segment
  489. HalpMsgInvalidOpcode db 'HAL: An invalid V86 opcode was encountered at '
  490. db 'address %x:%x',0ah, 0dh, 0
  491. _TEXT ends
  492. cPublicProc HalpOpcodeInvalid ,0
  493. push [esi].RiEip
  494. push [esi].RiSegCs
  495. push offset FLAT:HalpMsgInvalidOpcode
  496. call _DbgPrint ; display invalid opcode message
  497. add esp,12
  498. int 3
  499. xor eax,eax
  500. stdRET HalpOpcodeInvalid
  501. stdENDP HalpOpcodeInvalid
  502. subttl "INTnn Opcode Handler"
  503. ;++
  504. ;
  505. ; Routine Description:
  506. ;
  507. ; This routine emulates an INTnn opcode. It retrieves the handler
  508. ; from the IVT, pushes the current cs:ip and flags on the stack,
  509. ; and dispatches to the handler.
  510. ;
  511. ; Arguments:
  512. ;
  513. ; esi = address of reg info
  514. ; edx = opcode
  515. ;
  516. ; Returns:
  517. ;
  518. ; Current CS:IP on user stack
  519. ; RiCs:RiEip -> handler from IVT
  520. ;
  521. cPublicProc HalpOpcodeINTnn ,0
  522. push ebp
  523. push edi
  524. push ebx
  525. ;
  526. ; Convert SS to linear address
  527. ;
  528. mov eax,[esi].RiSegSs
  529. shl eax,4
  530. mov [esi].RiSsBase,eax
  531. mov [esi].RiSsLimit,0FFFFh
  532. mov [esi].RiSsFlags,0
  533. inc [esi].RiEip ; point to int #
  534. mov edi,[esi].RiEip
  535. cmp edi,[esi].RiCsLimit
  536. ja oinerr
  537. add edi,[esi].RiCsBase
  538. movzx ecx,byte ptr [edi] ; get int #
  539. inc [esi].RiEip ; inc past end of instruction
  540. stdCall HalpPushInt
  541. test eax,0FFFFh
  542. jz oin20 ; error!
  543. ;
  544. ; Note: Some sort of check for BOP should go here, or in push int.
  545. ;
  546. mov ebp,[esi].RiTrapFrame
  547. mov eax,[esi].RiSegSs
  548. mov [ebp].TsHardwareSegSs,eax
  549. mov eax,[esi].RiEsp
  550. mov [ebp].TsHardwareEsp,eax
  551. mov eax,[esi].RiSegCs
  552. mov [ebp].TsSegCs,eax
  553. mov eax,[esi].RiEFlags
  554. mov [ebp].TsEFlags,eax
  555. mov eax,1
  556. oin20: pop ebx
  557. pop edi
  558. pop ebp
  559. stdRET HalpOpcodeINTnn
  560. oinerr: xor eax,eax
  561. jmp oin20
  562. stdENDP HalpOpcodeINTnn
  563. page ,132
  564. subttl "Push Interrupt frame on user stack"
  565. ;++
  566. ;
  567. ; Routine Description:
  568. ;
  569. ; This routine pushes an interrupt frame on the user stack
  570. ;
  571. ; Arguments:
  572. ;
  573. ; ecx = interrupt #
  574. ; esi = address of reg info
  575. ; Returns:
  576. ;
  577. ; interrupt frame pushed on stack
  578. ; reg info updated
  579. ;
  580. cPublicProc HalpPushInt ,0
  581. push ebx
  582. mov edx,[esi].RiEsp
  583. mov ebx,[esi].RiSsBase
  584. and edx,0FFFFh ; only use a 16 bit sp
  585. sub dx,2
  586. mov ax,word ptr [esi].RiEFlags
  587. mov [ebx+edx],ax ; push flags
  588. sub dx,2
  589. mov ax,word ptr [esi].RiSegCs
  590. mov [ebx+edx],ax ; push cs
  591. sub dx,2
  592. mov ax,word ptr [esi].RiEip
  593. mov [ebx+edx],ax ; push ip
  594. mov eax,[ecx*4] ; get new cs:ip value
  595. push eax
  596. movzx eax,ax
  597. mov [esi].RiEip,eax
  598. pop eax
  599. shr eax,16
  600. mov [esi].RiSegCs,eax
  601. mov word ptr [esi].RiEsp,dx
  602. ;
  603. ; Convert CS to a linear address
  604. ;
  605. mov eax,[esi].RiSegCs
  606. shl eax,4
  607. mov [esi].RiCsBase,eax
  608. mov [esi].RiCsLimit,0FFFFh
  609. mov [esi].RiCsFlags,0
  610. mov eax,1 ; success
  611. pi80: pop ebx
  612. stdRET HalpPushInt
  613. stdENDP HalpPushInt
  614. _TEXT ends
  615. end