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.

692 lines
18 KiB

  1. ;
  2. ;
  3. ; Copyright (C) Microsoft Corporation, 1987-89
  4. ;
  5. ; This Module contains Proprietary Information of Microsoft
  6. ; Corporation and should be treated as Confidential.
  7. ;
  8. title emoem.asm - OEM dependent code for 8087
  9. ;--------------------------------------------------------------------
  10. ;
  11. ; OEM customization routines for 8087/80287 coprocessor
  12. ;
  13. ; This module is designed to work with the following
  14. ; Microsoft language releases:
  15. ;
  16. ; Microsoft C 3.00 and later
  17. ; Microsoft FORTRAN 77 3.30 and later
  18. ; Microsoft Pascal 3.30 and later
  19. ;
  20. ; This module supersedes the OEMR7.ASM module used in earlier
  21. ; versions of Microsoft FORTRAN 77 and Pascal. The documentation
  22. ; provided with the FORTRAN and Pascal releases refers to the old
  23. ; OEMR7.ASM module and is only slightly relevant to this module.
  24. ;
  25. ; The following routines need to be written to properly handle the
  26. ; 8087/808287 installation, termination, and interrupt handler
  27. ;
  28. ; __FPINSTALL87 install 8087 interrupt handler
  29. ; __FPTERMINATE87 deinstall 8087 interrupt handler
  30. ; __fpintreset reset OEM hardware if an 8087 interrupt
  31. ;
  32. ; ***** NEW INSTRUCTIONS *****
  33. ;
  34. ; If you want a PC clone version, do nothing. The libraries are
  35. ; setup for working on IBM PC's and clones.
  36. ;
  37. ; These instructions only need to be followed if a non-IBM PC
  38. ; clone version is desired.
  39. ;
  40. ; This module should be assembled with the
  41. ; Microsoft Macro Assembler Version 4.00 or later as follows:
  42. ;
  43. ; masm -DOEM -r emoem.asm;
  44. ;
  45. ; Most hardware handles the 8087/80287 in one of the following
  46. ; three ways -
  47. ;
  48. ; 1. NMI - IBM PC and clones all handle the interrupt this way
  49. ; 2. single 8259
  50. ; 3. master/slave 8259
  51. ;
  52. ; Manufacturer specific initialization is supported for these 3
  53. ; machine configurations either by modifying this file and replacing
  54. ; the existing EMOEM module in the math libraries or by patching
  55. ; the .LIB and .EXE files directly.
  56. ;
  57. ; LIB 87-+EMOEM;
  58. ; LIB EM-+EMOEM;
  59. ;
  60. ;--------------------------------------------------------------------
  61. ifdef OEM
  62. if1
  63. %out OEM version for non-clone support
  64. endif
  65. endif
  66. ;---------------------------------------------------------------------
  67. ; Assembly constants.
  68. ;---------------------------------------------------------------------
  69. NULL_JMP macro
  70. jmp $+2
  71. endm
  72. WASTE_TIME macro count
  73. local WasteLoop
  74. push cx
  75. ifnb <count>
  76. mov cx, count
  77. else
  78. mov cx, 10h
  79. endif
  80. WasteLoop:
  81. push ax
  82. pop ax
  83. loop WasteLoop
  84. pop cx
  85. endm
  86. ; MS-DOS OS calls
  87. OPSYS EQU 21H
  88. SETVECOP EQU 25H
  89. GETVECOP EQU 35H
  90. DOSVERSION EQU 30h
  91. ifndef _NOCTRLC
  92. CTLCVEC EQU 23h
  93. endif ;_NOCTRLC
  94. extrn __WINFLAGS:abs
  95. WF_PMODE equ 1
  96. WF_CPU286 equ 2
  97. WF_CPU386 equ 4
  98. WF_WIN286 equ 10h
  99. WF_WIN386 equ 20h
  100. EMULATOR_DATA segment para public 'FAR_DATA'
  101. assume ds:EMULATOR_DATA
  102. ; User may place data here if DS is setup properly.
  103. ; Recommend keeping the data items in the code segment.
  104. ifdef OEM
  105. extrn aoldIMR:byte ; 1st 8259 original IMR value
  106. extrn boldIMR:byte ; 2nd 8259 original IMR value
  107. endif ;OEM
  108. extrn OldNMIVec:dword ; Old value in 8087 exception interrupt vector
  109. ifndef _NOCTRLC
  110. extrn ctlc:dword ; Old value of Control-C vector (INT 23h)
  111. endif ;_NOCTRLC
  112. EMULATOR_DATA ends
  113. EMULATOR_TEXT segment para public 'CODE'
  114. assume cs:EMULATOR_TEXT
  115. public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
  116. public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
  117. extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
  118. extrn __FPEXCEPTION87P:near
  119. ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
  120. public __FPINSTALLNO87
  121. public __FPTERMINATENO87
  122. endif ;_NO87INSTALL
  123. ifdef OEM
  124. ;***********************************************************************
  125. ;
  126. ; Hardware dependent parameters in the 8087 exception handler.
  127. ;
  128. ; For machines using 2 8259's to handle the 8087 exception, be sure that
  129. ; the slave 8259 is the 1st below and the master is the 2nd.
  130. ;
  131. ; The last 4 fields allow you to enable extra interrupt lines into the
  132. ; 8259s. It should only be necessary to use these fields if the 8087
  133. ; interrupt is being masked out by the 8259 PIC.
  134. ;
  135. ; The ocw2's (EOI commands) can be either non-specific (20H) or
  136. ; specific (6xH where x=0 to 7). If you do not know which interrupt
  137. ; request line on the 8259 the 8087 exception uses, then you should issue
  138. ; the non-specific EOI (20H). Interrupts are off at this point in the
  139. ; interrupt handler so a higher priority interrupt will not be seen.
  140. oeminfo struc
  141. oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
  142. intnum db 2 ; IBM PC clone interrupt number
  143. share db 0 ; nonzero if original vector should be taken
  144. a8259 dw 0 ; 1st 8259 (A0=0) port #
  145. aocw2 db 0 ; 1st 8259 (A0=0) EOI command
  146. b8259 dw 0 ; 2nd 8259 (A0=0) port #
  147. bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
  148. a8259m dw 0 ; 1st 8259 (A0=1) port #
  149. aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
  150. b8259m dw 0 ; 2nd 8259 (A0=1) port #
  151. bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
  152. oeminfo ends
  153. ;-----------------------------------------------------------------------
  154. ; OEM specific 8087 information
  155. ;
  156. ; If the OEM number returned from the DOS version call matches,
  157. ; this information is automatically moved into the oem struc below.
  158. oemtab label byte ; Table of OEM specific values for 8087
  159. ; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
  160. ;TI Professional Computer
  161. TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
  162. db 0 ; end of table
  163. ; Unique pattern that can be searched for with the debugger so that
  164. ; .LIB or .EXE files can be patched with the correct values.
  165. ; If new values are patched into .LIB or .EXE files, care must be
  166. ; taken in insure the values are correct. In particular, words and
  167. ; bytes are intermixed in oeminfo structure. Remember words are
  168. ; stored low byte - high byte in memory on the 8086 family.
  169. db '<<8087>>' ; older versions used '<8087>'
  170. ; Some manufacturer's machines can not be differentiated by the
  171. ; OEM number returned by the MS-DOS version check system call.
  172. ; For these machines it is necessary to replace the line below
  173. oem1 oeminfo <> ; default values for IBM PC & clones
  174. ; with one of the following. If your machine has an 8087 capability
  175. ; and it is not in the list below, you should contact your hardware
  176. ; manufacturer for the necessary information.
  177. ;ACT Apricot
  178. ;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
  179. ;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
  180. ;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
  181. ;---------------------------------------------------------------------
  182. endif ;OEM
  183. page
  184. ;---------------------------------------------------------------------
  185. ;
  186. ; Perform OEM specific initialization of the 8087.
  187. ;
  188. __FPINSTALL87:
  189. push ds ; DS = EMULATOR_DATA
  190. ifdef OEM
  191. push ds
  192. pop es ; CS = DS = ES
  193. mov ah,DOSVERSION
  194. int OPSYS ; bh = OEM#
  195. cld
  196. mov si,offset oemtab ; start of OEM 8087 info table
  197. mov di,offset oem1+1
  198. mov cx,(size oem1)-1
  199. OEMloop:
  200. lodsb ; get OEM#
  201. or al,al
  202. jz OEMdone ; OEM# = 0 - did not find OEM
  203. cmp al,bh ; correct OEM#
  204. je OEMfound
  205. add si,cx ; skip over OEM information
  206. jmp OEMloop
  207. OEMfound:
  208. rep movsb ; move the information
  209. OEMdone: ; done with automatic customization
  210. endif ;OEM
  211. ; Save old interrupt vector.
  212. ; Ask operating system for vector.
  213. ifdef WINDOWS
  214. mov ax, word ptr [OldNMIVec]
  215. or ax, word ptr [OldNMIVec+2]
  216. jnz SetVector
  217. endif ;WINDOWS
  218. ifdef OEM
  219. mov al,[oem1].intnum ; Interrupt vector number.
  220. mov ah,GETVECOP ; Operating system call interrupt.
  221. else
  222. mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
  223. endif ;OEM
  224. int OPSYS ; Call operating system.
  225. mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
  226. mov word ptr [OldNMIVec+2],es
  227. ; Have operating system install interrupt vectors.
  228. SetVector:
  229. push cs ; Move current CS to DS for opsys calls.
  230. pop ds
  231. assume ds:EMULATOR_TEXT
  232. mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
  233. ifdef OEM
  234. mov ah,SETVECOP ; Set interrupt vector code in AH.
  235. mov al,[oem1].intnum ; Set vector number.
  236. else
  237. mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
  238. endif ;OEM
  239. int OPSYS ; Install vector.
  240. mov ax, __WINFLAGS
  241. test ax, WF_PMODE
  242. jz SkipSettingIRQ13
  243. .286p
  244. .287
  245. fsetpm ; set PM just in case Windows didn't.
  246. .8086
  247. .8087
  248. push cs
  249. pop ds ; Move current CS to DS for opsys calls.
  250. assume ds:EMULATOR_TEXT
  251. mov dx, offset __fpIRQ13 ; Load DX with IRQ 13 interrupt handler.
  252. mov ax, SETVECOP shl 8 + 75h ; set interrupt vector 75h
  253. int OPSYS ; Install vector.
  254. SkipSettingIRQ13:
  255. ifndef _NOCTRLC
  256. ; Intercept Control-C vector to guarentee cleanup
  257. mov ax,GETVECOP shl 8 + CTLCVEC
  258. int OPSYS
  259. mov word ptr [ctlc],bx
  260. mov word ptr [ctlc+2],es
  261. mov dx,offset ctlcexit
  262. mov ax,SETVECOP shl 8 + CTLCVEC
  263. int OPSYS
  264. endif ;_NOCTRLC
  265. ifdef OEM
  266. ; set up 8259's so that 8087 interrupts are enabled
  267. mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
  268. or ah,ah ; if 0, don't need to do this
  269. jz installdone ; and only 1 8259
  270. mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
  271. in al,dx ; read old IMR value
  272. mov [aoldIMR],al ; save it to restore at termination
  273. and al,ah ; mask to enable interrupt
  274. jmp short $+2 ; for 286's
  275. out dx,al ; write out new mask value
  276. mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
  277. or ah,ah ; if 0, don't need to do this
  278. jz installdone ;
  279. mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
  280. in al,dx ; read old IMR value
  281. mov [boldIMR],al ; save it to restore at termination
  282. and al,ah ; mask to enable interrupt
  283. jmp short $+2 ; for 286's
  284. out dx,al ; write out new mask value
  285. installdone:
  286. endif ;OEM
  287. assume ds:EMULATOR_DATA
  288. pop ds
  289. ret
  290. page
  291. ; __FPTERMINATE87
  292. ;
  293. ; This routine should do the OEM 8087 cleanup. This routine is called
  294. ; before the program exits.
  295. ;
  296. ; DS = EMULATOR_DATA
  297. __FPTERMINATE87:
  298. push ds
  299. push ax
  300. push dx
  301. ifdef OEM
  302. mov ah,SETVECOP
  303. mov al,[oem1].intnum
  304. else
  305. mov ax,SETVECOP shl 8 + 2
  306. endif ;OEM
  307. lds dx,[OldNMIVec]
  308. int OPSYS
  309. ifdef OEM
  310. ; reset 8259 IMR's to original state
  311. push cs
  312. pop ds ; DS = CS
  313. assume ds:EMULATOR_TEXT
  314. cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
  315. je term2nd8259 ; no - check 2nd 8259
  316. mov al,[aoldIMR] ; get old IMR
  317. mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
  318. out dx,al ; restore IMR
  319. term2nd8259:
  320. cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
  321. je terminatedone ; no
  322. mov al,[boldIMR] ; get old IMR
  323. mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
  324. out dx,al ; restore IMR
  325. terminatedone:
  326. endif ;OEM
  327. pop dx
  328. pop ax
  329. pop ds
  330. assume ds:EMULATOR_DATA
  331. ret
  332. ; Forced cleanup of 8087 exception handling on Control-C
  333. ifndef _NOCTRLC
  334. ctlcexit:
  335. push ax
  336. push dx
  337. push ds
  338. call __FPTERMINATE87 ; forced cleanup of exception handler
  339. lds dx,[ctlc] ; load old control C vector
  340. mov ax,SETVECOP shl 8 + CTLCVEC
  341. int OPSYS
  342. pop ds
  343. pop dx
  344. pop ax
  345. jmp [ctlc] ; go through old vector
  346. endif ;_NOCTRLC
  347. page
  348. ; __fpinterrupt87
  349. ;
  350. ; This is the 8087 exception interrupt routine.
  351. ;
  352. ; All OEM specific interrupt and harware handling should be done in
  353. ; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
  354. ; exception handler) may not return. __FPEXCEPTION87 also turns
  355. ; interrupts back on.
  356. ;
  357. PENDINGBIT= 80h ; Bit in status word for interrupt pending
  358. public __fpIRQ13
  359. __fpIRQ13:
  360. cli
  361. WASTE_TIME 70
  362. push ax
  363. xor al, al
  364. NULL_JMP
  365. out 0f0h, al ; reset busy line.
  366. NULL_JMP
  367. mov al, 65h
  368. NULL_JMP
  369. out 0a0h, al ; EOI slave irq 5
  370. NULL_JMP
  371. mov al, 62h
  372. NULL_JMP
  373. out 20h, al ; EOI master irq 2
  374. NULL_JMP
  375. pop ax
  376. sub sp, 2
  377. push bp
  378. mov bp, sp
  379. fnstsw [bp+2]
  380. WASTE_TIME
  381. push ax
  382. xor al, al
  383. NULL_JMP
  384. out 0f0h, al ; reset busy line.
  385. NULL_JMP
  386. pop ax
  387. pop bp
  388. fnclex ; 486 bug - must wait till after last
  389. ; "out f0" to clear fp exceptions
  390. ; or IGNNE# will be permanently active.
  391. WASTE_TIME
  392. push ax
  393. xor al, al
  394. NULL_JMP
  395. out 0f0h, al ; reset busy line.
  396. NULL_JMP
  397. pop ax
  398. fnclex ; 486 bug - must wait till after last
  399. ; "out f0" to clear fp exceptions
  400. ; or IGNNE# will be permanently active.
  401. WASTE_TIME
  402. push ax
  403. xor al, al
  404. NULL_JMP
  405. out 0f0h, al ; reset busy line.
  406. NULL_JMP
  407. pop ax
  408. ; fnclex ;Now this is safe.
  409. jmp __FPEXCEPTION87P
  410. public __fpinterrupt87
  411. __fpinterrupt87:
  412. assume ds:nothing
  413. nop
  414. push bp
  415. mov bp, sp
  416. sub sp, 2
  417. fnstsw word ptr [bp-2] ; Store out exceptions
  418. push cx ; waste time
  419. mov cx, 3
  420. self:
  421. loop self
  422. pop cx
  423. test byte ptr [bp-2],PENDINGBIT ; Test for 8087 interrupt
  424. mov sp, bp
  425. pop bp
  426. jz not87int ; Not an 8087 interrupt.
  427. ifdef OEM
  428. call __fpintreset ; OEM interrupt reset routine
  429. endif ;OEM
  430. call __FPEXCEPTION87 ; 8087 error handling - may not return
  431. ; this routine turns interrupts back on
  432. ifdef OEM
  433. cmp [oem1].share,0 ; Should we execute the old interrupt routine?
  434. jnz not87int ; if so then do it
  435. ; else return from interrupt
  436. ; If you fall through here to do further hardware resetting, things
  437. ; may not always work because __FPEXCEPTION87 does not always return
  438. ; This only happens when the 8087 handler gets an exception that is
  439. ; a fatal error in the language runtimes. I.e., divide by zero
  440. ; is a fatal error in all the languages, unless the control word has
  441. ; set to mask out divide by zero errors.
  442. endif ;OEM
  443. done8087:
  444. iret
  445. not87int:
  446. sub sp, 4
  447. push bp
  448. mov bp, sp
  449. push ds
  450. push ax
  451. mov ax, EMULATOR_DATA
  452. mov ds, ax
  453. assume ds:EMULATOR_DATA
  454. mov ax, word ptr [OldNMIVec+2] ; segment of OldNMIVec
  455. mov [bp+4], ax
  456. mov ax, word ptr [OldNMIVec] ; offset of OldNMIVec
  457. mov [bp+2], ax
  458. pop ax
  459. pop ds
  460. mov sp, bp
  461. pop bp
  462. retf ; jmp [OldNMIVec]. We should not return.
  463. ifdef OEM
  464. __fpintreset:
  465. push ax
  466. push dx
  467. mov al,[oem1].aocw2 ; Load up EOI instruction.
  468. or al,al ; Is there at least one 8259 to be reset?
  469. jz Reset8259ret ; no
  470. mov dx,[oem1].a8259
  471. out dx,al ; Reset (master) 8259 interrupt controller.
  472. mov al,[oem1].bocw2 ; Load up EOI instruction.
  473. or al,al ; Is there a slave 8259 to be reset?
  474. jz Reset8259ret
  475. mov dx,[oem1].b8259
  476. out dx,al ; Reset slave 8259 interrupt controller.
  477. Reset8259ret:
  478. pop dx
  479. pop ax
  480. ret
  481. endif ;OEM
  482. ifdef _NO87INSTALL
  483. __FPINSTALLNO87:
  484. push bx
  485. push es
  486. push ax
  487. push dx
  488. push ds
  489. mov ax,cs ; Move current CS to DS for opsys calls.
  490. mov ds,ax
  491. assume ds:EMULATOR_TEXT r
  492. ; Save old interrupt vector.
  493. ; Ask operating system for vector.
  494. ifdef OEM
  495. mov al,[oem1].intnum ; Interrupt vector number.
  496. mov ah,GETVECOP ; Operating system call interrupt.
  497. else
  498. mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
  499. endif ;OEM
  500. int OPSYS ; Call operating system.
  501. mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
  502. mov word ptr [OldNMIVec+2],es
  503. ; Have operating system install interrupt vectors.
  504. mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
  505. ifdef OEM
  506. mov ah,SETVECOP ; Set interrupt vector code in AH.
  507. mov al,[oem1].intnum ; Set vector number.
  508. else
  509. mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
  510. endif ;OEM
  511. int OPSYS ; Install vector.
  512. pop ds
  513. assume ds:nothing
  514. pop dx
  515. pop ax
  516. pop es
  517. pop bx
  518. ret
  519. __fpinterruptno87:
  520. jmp [OldNMIVec] ; will use CS: override
  521. __FPTERMINATENO87:
  522. push ds
  523. push ax
  524. push dx
  525. mov ax,cs
  526. mov ds,ax
  527. assume ds:EMULATOR_TEXT
  528. ifdef OEM
  529. mov ah,SETVECOP
  530. mov al,[oem1].intnum
  531. else
  532. mov ax,SETVECOP shl 8 + 2
  533. endif ;OEM
  534. lds dx,[OldNMIVec]
  535. assume ds:nothing
  536. int OPSYS
  537. pop dx
  538. pop ax
  539. pop ds
  540. ret
  541. endif ;_NO87INSTALL
  542. EMULATOR_TEXT ends
  543. end