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.

570 lines
15 KiB

  1. ;
  2. ;
  3. ; Copyright (C) Microsoft Corporation, 1987
  4. ;
  5. ; This Module contains Proprietary Information of Microsoft
  6. ; Corporation and should be treated as Confidential.
  7. ;
  8. ;
  9. page ,132
  10. title emoem.asm - OEM dependent code for 8087
  11. ;--------------------------------------------------------------------
  12. ;
  13. ; OEM customization routines for 8087/80287 coprocessor
  14. ;
  15. ; This module is designed to work with the following
  16. ; Microsoft language releases:
  17. ;
  18. ; Microsoft Quick BASIC 4.0 and later
  19. ; Microsoft Quick BASIC (KANJI) 4.0 and later
  20. ; Microsoft BASCOM 3.0
  21. ; Microsoft BASCOMK 3.0
  22. ; Microsoft BASCOM/2
  23. ; Microsoft BASCOMK/2
  24. ;
  25. ; This module supersedes the OEMR7.ASM module used in earlier
  26. ; versions of Microsoft FORTRAN 77 and Pascal. The documentation
  27. ; provided with the FORTRAN and Pascal releases refers to the old
  28. ; OEMR7.ASM module and is only slightly relevant to this module.
  29. ;
  30. ; The following routines need to be written to properly handle the
  31. ; 8087/808287 installation, termination, and interrupt handler
  32. ;
  33. ; __FPINSTALL87 install 8087 interrupt handler
  34. ; __FPTERMINATE87 deinstall 8087 interrupt handler
  35. ; __fpintreset reset OEM hardware if an 8087 interrupt
  36. ;
  37. ; ***** NEW INSTRUCTIONS *****
  38. ;
  39. ; If you want a PC clone version, do nothing. The libraries are
  40. ; setup for working on IBM PC's and clones.
  41. ;
  42. ; This instructions only need to be followed if a non-IBM PC
  43. ; clone version is desired.
  44. ;
  45. ; This module should be assembled with the
  46. ; Microsoft Macro Assembler Version 4.00 or later as follows:
  47. ;
  48. ; masm -DOEM -r emoem.asm;
  49. ;
  50. ; For QuickBASIC, assemble as follows:
  51. ;
  52. ; masm -D_QB -DOEM -r emoem.asm;
  53. ;
  54. ; Most hardware handles the 8087/80287 in one of the following
  55. ; three ways -
  56. ;
  57. ; 1. NMI - IBM PC and clones all handle the interrupt this way
  58. ; 2. single 8259
  59. ; 3. master/slave 8259
  60. ;
  61. ; Manufacturer specific initialization is supported for these 3
  62. ; machine configurations either by modifying this file and replacing
  63. ; the existing EMOEM module in the math libraries or by patching
  64. ; the .LIB and .EXE files directly.
  65. ;
  66. ; LIB 87-+EMOEM;
  67. ; LIB EM-+EMOEM;
  68. ;
  69. ;--------------------------------------------------------------------
  70. ifdef OEM
  71. if1
  72. %out OEM version for non-clone support
  73. endif
  74. endif
  75. ifndef _QB
  76. _HOOK_CTRLC=1
  77. endif
  78. ifdef _HOOK_CTRLC
  79. if1
  80. %out Non-QB version. Hooks Ctrl-C. Hooks INT 75h.
  81. endif
  82. else
  83. if1
  84. %out QB version. Doesn't hook Ctrl-C. Hooks INT 75h.
  85. endif
  86. endif
  87. ;---------------------------------------------------------------------
  88. ; Assembly constants.
  89. ;---------------------------------------------------------------------
  90. ; MS-DOS OS calls
  91. OPSYS EQU 21H
  92. SETVECOP EQU 25H
  93. GETVECOP EQU 35H
  94. DOSVERSION EQU 30h
  95. ifdef _HOOK_CTRLC
  96. CTLCVEC EQU 23h
  97. endif ;_HOOK_CTRLC
  98. EMULATOR_DATA segment public 'FAR_DATA'
  99. assume ds:EMULATOR_DATA
  100. ; User may place data here if DS is setup properly.
  101. ; Recommend keeping the data items in the code segment.
  102. EMULATOR_DATA ends
  103. EMULATOR_TEXT segment public 'CODE'
  104. assume cs:EMULATOR_TEXT
  105. public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
  106. public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
  107. extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
  108. ifdef OEM
  109. ;***********************************************************************
  110. ;
  111. ; Hardware dependent parameters in the 8087 exception handler.
  112. ;
  113. ; For machines using 2 8259's to handle the 8087 exception, be sure that
  114. ; the slave 8259 is the 1st below and the master is the 2nd.
  115. ;
  116. ; The last 4 fields allow you to enable extra interrupt lines into the
  117. ; 8259s. It should only be necessary to use these fields if the 8087
  118. ; interrupt is being masked out by the 8259 PIC.
  119. ;
  120. ; The ocw2's (EOI commands) can be either non-specific (20H) or
  121. ; specific (6xH where x=0 to 7). If you do not know which interrupt
  122. ; request line on the 8259 the 8087 exception uses, then you should issue
  123. ; the non-specific EOI (20H). Interrupts are off at this point in the
  124. ; interrupt handler so a higher priority interrupt will not be seen.
  125. oeminfo struc
  126. oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
  127. intnum db 2 ; IBM PC clone interrupt number
  128. share db 0 ; nonzero if original vector should be taken
  129. a8259 dw 0 ; 1st 8259 (A0=0) port #
  130. aocw2 db 0 ; 1st 8259 (A0=0) EOI command
  131. b8259 dw 0 ; 2nd 8259 (A0=0) port #
  132. bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
  133. a8259m dw 0 ; 1st 8259 (A0=1) port #
  134. aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
  135. b8259m dw 0 ; 2nd 8259 (A0=1) port #
  136. bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
  137. oeminfo ends
  138. ;-----------------------------------------------------------------------
  139. ; OEM specific 8087 information
  140. ;
  141. ; If the OEM number returned from the DOS version call matches,
  142. ; this information is automatically moved into the oem struc below.
  143. oemtab label byte ; Table of OEM specific values for 8087
  144. ; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
  145. ;TI Professional Computer
  146. TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
  147. db 0 ; end of table
  148. ; Unique pattern that can be searched for with the debugger so that
  149. ; .LIB or .EXE files can be patched with the correct values.
  150. ; If new values are patched into .LIB or .EXE files, care must be
  151. ; taken in insure the values are correct. In particular, words and
  152. ; bytes are intermixed in oeminfo structure. Remember words are
  153. ; stored low byte - high byte in memory on the 8086 family.
  154. db '<<8087>>' ; older versions used '<8087>'
  155. ; Some manufacturer's machines can not be differentiated by the
  156. ; OEM number returned by the MS-DOS version check system call.
  157. ; For these machines it is necessary to replace the line below
  158. oem1 oeminfo <> ; default values for IBM PC & clones
  159. ; with one of the following. If your machine has an 8087 capability
  160. ; and it is not in the list below, you should contact your hardware
  161. ; manufacturer for the necessary information.
  162. ;ACT Apricot
  163. ;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
  164. ;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
  165. ;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
  166. ;---------------------------------------------------------------------
  167. aoldIMR db 0 ; 1st 8259 original IMR value
  168. boldIMR db 0 ; 2nd 8259 original IMR value
  169. endif ;OEM
  170. statwd dw 0 ; Temporary for status word
  171. oldvec dd 0 ; Old value in 8087 exception interrupt vector
  172. ifdef _HOOK_CTRLC
  173. ctlc dd 0 ; Old value of Control-C vector (INT 23h)
  174. endif ;_HOOK_CTRLC
  175. ifndef OEM
  176. oldvec75 dd 0 ; Old value INT 75H interrupt vector
  177. INT75FLAGS DW 0 ; flags at INT 75 time
  178. INT75CS DW 0 ; CS at INT 75 time
  179. INT75IP DW 0 ; IP at INT 75 time
  180. INT75VEC DW OFFSET FPREALINT2 ; place INT 75 IRETs to
  181. endif ;OEM
  182. page
  183. ;---------------------------------------------------------------------
  184. ;
  185. ; Perform OEM specific initialization of the 8087.
  186. ;
  187. __FPINSTALL87:
  188. push ds ; DS = EMULATOR_DATA
  189. push cs ; Move current CS to DS for opsys calls.
  190. pop ds
  191. assume ds:EMULATOR_TEXT
  192. ifdef OEM
  193. push ds
  194. pop es ; CS = DS = ES
  195. mov ah,DOSVERSION
  196. int OPSYS ; bh = OEM#
  197. cld
  198. mov si,offset oemtab ; start of OEM 8087 info table
  199. mov di,offset oem1+1
  200. mov cx,(size oem1)-1
  201. OEMloop:
  202. lodsb ; get OEM#
  203. or al,al
  204. jz OEMdone ; OEM# = 0 - did not find OEM
  205. cmp al,bh ; correct OEM#
  206. je OEMfound
  207. add si,cx ; skip over OEM information
  208. jmp OEMloop
  209. OEMfound:
  210. rep movsb ; move the information
  211. OEMdone: ; done with automatic customization
  212. endif ;OEM
  213. ; Save old interrupt vector.
  214. ; Ask operating system for vector.
  215. ifdef OEM
  216. mov al,[oem1].intnum ; Interrupt vector number.
  217. mov ah,GETVECOP ; Operating system call interrupt.
  218. int OPSYS ; Call operating system.
  219. mov word ptr [oldvec],bx ; Squirrel away old vector.
  220. mov word ptr [oldvec+2],es
  221. else
  222. mov ax,GETVECOP shl 8 + 75H ; get interrupt vector 75H
  223. int OPSYS ; Call operating system.
  224. mov word ptr [oldvec75],bx ; Squirrel away old vector.
  225. mov word ptr [oldvec75+2],es;
  226. mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
  227. int OPSYS ; Call operating system.
  228. mov word ptr [oldvec],bx ; Squirrel away old vector.
  229. mov word ptr [oldvec+2],es
  230. endif ;OEM
  231. ; Have operating system install interrupt vectors.
  232. ifdef OEM
  233. mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
  234. mov ah,SETVECOP ; Set interrupt vector code in AH.
  235. mov al,[oem1].intnum ; Set vector number.
  236. int OPSYS ; Install vector.
  237. else
  238. mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
  239. mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
  240. int OPSYS ; Install vector.
  241. mov dx,offset __fpinterrupt75 ; Load DX with 8087 interrupt handler.
  242. mov ax,SETVECOP shl 8 + 75H ; set interrupt vector 75
  243. int OPSYS ; Install vector.
  244. endif ;OEM
  245. ; Intercept Control-C vector to guarentee cleanup
  246. ifdef _HOOK_CTRLC ;
  247. mov ax,GETVECOP shl 8 + CTLCVEC
  248. int OPSYS
  249. mov word ptr [ctlc],bx
  250. mov word ptr [ctlc+2],es
  251. mov dx,offset ctlcexit
  252. mov ax,SETVECOP shl 8 + CTLCVEC
  253. int OPSYS
  254. endif ;_HOOK_CTRLC
  255. ifdef OEM
  256. ; set up 8259's so that 8087 interrupts are enabled
  257. mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
  258. or ah,ah ; if 0, don't need to do this
  259. jz installdone ; and only 1 8259
  260. mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
  261. in al,dx ; read old IMR value
  262. mov [aoldIMR],al ; save it to restore at termination
  263. and al,ah ; mask to enable interrupt
  264. jmp short $+2 ; for 286's
  265. out dx,al ; write out new mask value
  266. mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
  267. or ah,ah ; if 0, don't need to do this
  268. jz installdone ;
  269. mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
  270. in al,dx ; read old IMR value
  271. mov [boldIMR],al ; save it to restore at termination
  272. and al,ah ; mask to enable interrupt
  273. jmp short $+2 ; for 286's
  274. out dx,al ; write out new mask value
  275. installdone:
  276. endif ;OEM
  277. assume ds:EMULATOR_DATA
  278. pop ds
  279. ret
  280. page
  281. ; __FPTERMINATE87
  282. ;
  283. ; This routine should do the OEM 8087 cleanup. This routine is called
  284. ; before the program exits.
  285. ;
  286. ; DS = EMULATOR_DATA
  287. __FPTERMINATE87:
  288. push ds
  289. push ax
  290. push dx
  291. ifdef OEM
  292. mov ah,SETVECOP
  293. mov al,[oem1].intnum
  294. lds dx,[oldvec]
  295. int OPSYS
  296. else
  297. mov ax,SETVECOP shl 8 + 2
  298. lds dx,[oldvec]
  299. int OPSYS
  300. mov ax,SETVECOP shl 8 + 75H ; restore int 75
  301. lds dx,[oldvec75] ;
  302. int OPSYS ;
  303. endif ;OEM
  304. ifdef OEM
  305. ; reset 8259 IMR's to original state
  306. push cs
  307. pop ds ; DS = CS
  308. assume ds:EMULATOR_TEXT
  309. cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
  310. je term2nd8259 ; no - check 2nd 8259
  311. mov al,[aoldIMR] ; get old IMR
  312. mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
  313. out dx,al ; restore IMR
  314. term2nd8259:
  315. cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
  316. je terminatedone ; no
  317. mov al,[boldIMR] ; get old IMR
  318. mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
  319. out dx,al ; restore IMR
  320. terminatedone:
  321. endif ;OEM
  322. pop dx
  323. pop ax
  324. pop ds
  325. assume ds:EMULATOR_DATA
  326. ret
  327. ifdef _HOOK_CTRLC
  328. ; Forced cleanup of 8087 exception handling on Control-C
  329. ctlcexit:
  330. push ax
  331. push dx
  332. push ds
  333. call __FPTERMINATE87 ; forced cleanup of exception handler
  334. lds dx,[ctlc] ; load old control C vector
  335. mov ax,SETVECOP shl 8 + CTLCVEC
  336. int OPSYS
  337. pop ds
  338. pop dx
  339. pop ax
  340. jmp [ctlc] ; go through old vector
  341. endif ;_HOOK_CTRLC
  342. page
  343. ;
  344. ; __fpinterrupt75
  345. ;
  346. ; This is the "real" 80x87 interrupt routine for AT's and clones.
  347. ; Entire routine added [2].
  348. ;
  349. ; We hook INT 75 in order to work around a DOS nuance that otherwise causes the
  350. ; exception handler to get executed with the wrong stack segment.
  351. ;
  352. ; In PC's, a math exception is a simple INT 2, which since we hook, we recieve
  353. ; unobstructed. On AT's, an INT 75H is generated, which is normally trapped by
  354. ; the BIOS, which performs some hardware magic, and then executes an INT 2
  355. ; instruction to simulate the PC's behaviour. Hooking INT 2 alone is sufficient
  356. ; to handle these two cases.
  357. ;
  358. ; In MS-DOS (and PC-DOS) versions 3.2x, a stack swapping scheme is employed in
  359. ; which the DOS actually allocates a new SS:SP before executing the interrupt
  360. ; handler. If we do not hook INT 75H, then it gets a new SS:SP, and executes
  361. ; the INT 2 with that stack, and we cannot look back on the stack for our
  362. ; context, nor can we really know anything about the stack at the time of the
  363. ; exception.
  364. ;
  365. ; The process used to over come this problem is, essentially, to allow the
  366. ; INT 75H to execute, including it's embedded INT 2, but to do nothing in that
  367. ; INT 2. We fake the INT 75H return, though, such that it returns to us, (with
  368. ; the right stack to boot), and we can continue to process the exception.
  369. ;
  370. ; The steps invoved:
  371. ;
  372. ; 1) Hook BOTH INT 2 and INT 75H
  373. ;
  374. ; 2) On an INT 75, save the CS, IP and FLAGS of the return address, and REPLACE
  375. ; THEM with values that will cause the INT 75H's IRET to return step 5,
  376. ; below.
  377. ;
  378. ; 3) Just jump to the previous INT 75H handler.
  379. ;
  380. ; 4) On the subsequent INT 2, IF there is a CS as saved in step 1, then do
  381. ; nothing. Just IRET. If there is not saved CS, then we have a plain old
  382. ; INT 2 (running on an XT, most likely), and we just go to step 6.
  383. ;
  384. ; 5) On return from the INT 75H, we have the SS:SP at the time of the
  385. ; exception. Just push the previously saved FLAGS, CS and IP of the
  386. ; exception, clear the saved CS, and fall into....
  387. ;
  388. ; 6) A normal INT 2 handler.
  389. ;
  390. ifndef OEM ;
  391. __fpinterrupt75:
  392. ASSUME DS:NOTHING
  393. POP CS:[INT75IP] ;Squirel away exception address
  394. POP CS:[INT75CS]
  395. POP CS:[INT75FLAGS]
  396. PUSHF ;Set up INT 75 to return to our code
  397. PUSH CS
  398. PUSH CS:[INT75VEC]
  399. JMP [oldvec75] ;And execute original INT 75H
  400. endif ; ifndef OEM
  401. ;
  402. ; __fpinterrupt87
  403. ;
  404. ; This is the 8087 exception interrupt routine.
  405. ;
  406. ; All OEM specific interrupt and harware handling should be done in
  407. ; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
  408. ; exception handler) may not return. __FPEXCEPTION87 also turns
  409. ; interrupts back on.
  410. ;
  411. PENDINGBIT= 80h ; Bit in status word for interrupt pending
  412. __fpinterrupt87:
  413. assume ds:nothing
  414. nop
  415. fnstsw [statwd] ; Store out exceptions
  416. ifndef OEM ;
  417. TEST CS:[INT75CS],-1 ; has INT 75 ocurred?
  418. JZ FPWASINT2 ; jump if not
  419. IRET ; just return to original INT 75 handler
  420. FPREALINT2: ; INT 75 IRETs here
  421. PUSH CS:[INT75FLAGS] ; fake up original exception
  422. PUSH CS:[INT75CS] ;
  423. PUSH CS:[INT75IP] ;
  424. MOV CS:[INT75CS],0 ; and clear the INT75 occurred flag.
  425. FPWASINT2: ;
  426. endif ; ifndef OEM
  427. push cx ; waste time
  428. mov cx,3
  429. self:
  430. loop self
  431. pop cx
  432. test byte ptr [statwd],PENDINGBIT ; Test for 8087 interrupt
  433. jz not87int ; Not an 8087 interrupt.
  434. ifdef OEM
  435. call __fpintreset ; OEM interrupt reset routine
  436. endif ;OEM
  437. call __FPEXCEPTION87 ; 8087 error handling - may not return
  438. ; this routine turns interrupts back on
  439. ifdef OEM
  440. cmp [oem1].share,0 ; Should we execute the old interrupt routine?
  441. jz done8087 ; if not then return
  442. ; If you fall through here to do further hardware resetting, things
  443. ; may not always work because __FPEXCEPTION87 does not always return
  444. ; This only happens when the 8087 handler gets an exception that is
  445. ; a fatal error in the language runtimes. I.e., divide by zero
  446. ; is a fatal error in all the languages, unless the control word has
  447. ; set to mask out divide by zero errors.
  448. else ;
  449. iret ;
  450. endif ;OEM
  451. not87int:
  452. jmp [oldvec] ; We should never return from here.
  453. ifdef OEM
  454. done8087:
  455. iret
  456. __fpintreset:
  457. push ax
  458. push dx
  459. mov al,[oem1].aocw2 ; Load up EOI instruction.
  460. or al,al ; Is there at least one 8259 to be reset?
  461. jz Reset8259ret ; no
  462. mov dx,[oem1].a8259
  463. out dx,al ; Reset (master) 8259 interrupt controller.
  464. mov al,[oem1].bocw2 ; Load up EOI instruction.
  465. or al,al ; Is there a slave 8259 to be reset?
  466. jz Reset8259ret
  467. mov dx,[oem1].b8259
  468. out dx,al ; Reset slave 8259 interrupt controller.
  469. Reset8259ret:
  470. pop dx
  471. pop ax
  472. ret
  473. endif ;OEM
  474. EMULATOR_TEXT ends
  475. end