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.

536 lines
13 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. 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. ; MS-DOS OS calls
  70. OPSYS EQU 21H
  71. SETVECOP EQU 25H
  72. GETVECOP EQU 35H
  73. DOSVERSION EQU 30h
  74. ifndef _NOCTRLC
  75. CTLCVEC EQU 23h
  76. endif ;_NOCTRLC
  77. DATA segment word public
  78. assume ds:DATA
  79. ; User may place data here if DS is setup properly.
  80. ; Recommend keeping the data items in the code segment.
  81. DATA ends
  82. CODE segment word public
  83. assume cs:CODE
  84. public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
  85. public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
  86. extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
  87. ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
  88. public __FPINSTALLNO87
  89. public __FPTERMINATENO87
  90. endif ;_NO87INSTALL
  91. ifdef OEM
  92. ;***********************************************************************
  93. ;
  94. ; Hardware dependent parameters in the 8087 exception handler.
  95. ;
  96. ; For machines using 2 8259's to handle the 8087 exception, be sure that
  97. ; the slave 8259 is the 1st below and the master is the 2nd.
  98. ;
  99. ; The last 4 fields allow you to enable extra interrupt lines into the
  100. ; 8259s. It should only be necessary to use these fields if the 8087
  101. ; interrupt is being masked out by the 8259 PIC.
  102. ;
  103. ; The ocw2's (EOI commands) can be either non-specific (20H) or
  104. ; specific (6xH where x=0 to 7). If you do not know which interrupt
  105. ; request line on the 8259 the 8087 exception uses, then you should issue
  106. ; the non-specific EOI (20H). Interrupts are off at this point in the
  107. ; interrupt handler so a higher priority interrupt will not be seen.
  108. oeminfo struc
  109. oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
  110. intnum db 2 ; IBM PC clone interrupt number
  111. share db 0 ; nonzero if original vector should be taken
  112. a8259 dw 0 ; 1st 8259 (A0=0) port #
  113. aocw2 db 0 ; 1st 8259 (A0=0) EOI command
  114. b8259 dw 0 ; 2nd 8259 (A0=0) port #
  115. bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
  116. a8259m dw 0 ; 1st 8259 (A0=1) port #
  117. aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
  118. b8259m dw 0 ; 2nd 8259 (A0=1) port #
  119. bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
  120. oeminfo ends
  121. ;-----------------------------------------------------------------------
  122. ; OEM specific 8087 information
  123. ;
  124. ; If the OEM number returned from the DOS version call matches,
  125. ; this information is automatically moved into the oem struc below.
  126. oemtab label byte ; Table of OEM specific values for 8087
  127. ; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
  128. ;TI Professional Computer
  129. TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
  130. db 0 ; end of table
  131. ; Unique pattern that can be searched for with the debugger so that
  132. ; .LIB or .EXE files can be patched with the correct values.
  133. ; If new values are patched into .LIB or .EXE files, care must be
  134. ; taken in insure the values are correct. In particular, words and
  135. ; bytes are intermixed in oeminfo structure. Remember words are
  136. ; stored low byte - high byte in memory on the 8086 family.
  137. db '<<8087>>' ; older versions used '<8087>'
  138. ; Some manufacturer's machines can not be differentiated by the
  139. ; OEM number returned by the MS-DOS version check system call.
  140. ; For these machines it is necessary to replace the line below
  141. oem1 oeminfo <> ; default values for IBM PC & clones
  142. ; with one of the following. If your machine has an 8087 capability
  143. ; and it is not in the list below, you should contact your hardware
  144. ; manufacturer for the necessary information.
  145. ;ACT Apricot
  146. ;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
  147. ;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
  148. ;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
  149. ;---------------------------------------------------------------------
  150. aoldIMR db 0 ; 1st 8259 original IMR value
  151. boldIMR db 0 ; 2nd 8259 original IMR value
  152. endif ;OEM
  153. statwd dw 0 ; Temporary for status word
  154. oldvec dd 0 ; Old value in 8087 exception interrupt vector
  155. ifndef _NOCTRLC
  156. ctlc dd 0 ; Old value of Control-C vector (INT 23h)
  157. endif ;_NOCTRLC
  158. page
  159. ;---------------------------------------------------------------------
  160. ;
  161. ; Perform OEM specific initialization of the 8087.
  162. ;
  163. __FPINSTALL87:
  164. push ds ; DS = EMULATOR_DATA
  165. push cs ; Move current CS to DS for opsys calls.
  166. pop ds
  167. assume ds:CODE
  168. ifdef OEM
  169. push ds
  170. pop es ; CS = DS = ES
  171. mov ah,DOSVERSION
  172. int OPSYS ; bh = OEM#
  173. cld
  174. mov si,offset oemtab ; start of OEM 8087 info table
  175. mov di,offset oem1+1
  176. mov cx,(size oem1)-1
  177. OEMloop:
  178. lodsb ; get OEM#
  179. or al,al
  180. jz OEMdone ; OEM# = 0 - did not find OEM
  181. cmp al,bh ; correct OEM#
  182. je OEMfound
  183. add si,cx ; skip over OEM information
  184. jmp OEMloop
  185. OEMfound:
  186. rep movsb ; move the information
  187. OEMdone: ; done with automatic customization
  188. endif ;OEM
  189. ; Save old interrupt vector.
  190. ; Ask operating system for vector.
  191. ifdef WINDOWS
  192. mov ax, word ptr [oldvec]
  193. or ax, word ptr [oldvec+2]
  194. jnz SetVector
  195. endif ;WINDOWS
  196. ifdef OEM
  197. mov al,[oem1].intnum ; Interrupt vector number.
  198. mov ah,GETVECOP ; Operating system call interrupt.
  199. else
  200. mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
  201. endif ;OEM
  202. int OPSYS ; Call operating system.
  203. mov word ptr [oldvec],bx ; Squirrel away old vector.
  204. mov word ptr [oldvec+2],es
  205. ; Have operating system install interrupt vectors.
  206. SetVector:
  207. mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
  208. ifdef OEM
  209. mov ah,SETVECOP ; Set interrupt vector code in AH.
  210. mov al,[oem1].intnum ; Set vector number.
  211. else
  212. mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
  213. endif ;OEM
  214. int OPSYS ; Install vector.
  215. ifndef _NOCTRLC
  216. ; Intercept Control-C vector to guarentee cleanup
  217. mov ax,GETVECOP shl 8 + CTLCVEC
  218. int OPSYS
  219. mov word ptr [ctlc],bx
  220. mov word ptr [ctlc+2],es
  221. mov dx,offset ctlcexit
  222. mov ax,SETVECOP shl 8 + CTLCVEC
  223. int OPSYS
  224. endif ;_NOCTRLC
  225. ifdef OEM
  226. ; set up 8259's so that 8087 interrupts are enabled
  227. mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
  228. or ah,ah ; if 0, don't need to do this
  229. jz installdone ; and only 1 8259
  230. mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
  231. in al,dx ; read old IMR value
  232. mov [aoldIMR],al ; save it to restore at termination
  233. and al,ah ; mask to enable interrupt
  234. jmp short $+2 ; for 286's
  235. out dx,al ; write out new mask value
  236. mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
  237. or ah,ah ; if 0, don't need to do this
  238. jz installdone ;
  239. mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
  240. in al,dx ; read old IMR value
  241. mov [boldIMR],al ; save it to restore at termination
  242. and al,ah ; mask to enable interrupt
  243. jmp short $+2 ; for 286's
  244. out dx,al ; write out new mask value
  245. installdone:
  246. endif ;OEM
  247. assume ds:DATA
  248. pop ds
  249. ret
  250. page
  251. ; __FPTERMINATE87
  252. ;
  253. ; This routine should do the OEM 8087 cleanup. This routine is called
  254. ; before the program exits.
  255. ;
  256. ; DS = EMULATOR_DATA
  257. __FPTERMINATE87:
  258. push ds
  259. push ax
  260. push dx
  261. ifdef OEM
  262. mov ah,SETVECOP
  263. mov al,[oem1].intnum
  264. else
  265. mov ax,SETVECOP shl 8 + 2
  266. endif ;OEM
  267. lds dx,[oldvec]
  268. int OPSYS
  269. ifdef OEM
  270. ; reset 8259 IMR's to original state
  271. push cs
  272. pop ds ; DS = CS
  273. assume ds:CODE
  274. cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
  275. je term2nd8259 ; no - check 2nd 8259
  276. mov al,[aoldIMR] ; get old IMR
  277. mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
  278. out dx,al ; restore IMR
  279. term2nd8259:
  280. cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
  281. je terminatedone ; no
  282. mov al,[boldIMR] ; get old IMR
  283. mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
  284. out dx,al ; restore IMR
  285. terminatedone:
  286. endif ;OEM
  287. pop dx
  288. pop ax
  289. pop ds
  290. assume ds:DATA
  291. ret
  292. ; Forced cleanup of 8087 exception handling on Control-C
  293. ifndef _NOCTRLC
  294. ctlcexit:
  295. push ax
  296. push dx
  297. push ds
  298. call __FPTERMINATE87 ; forced cleanup of exception handler
  299. lds dx,[ctlc] ; load old control C vector
  300. mov ax,SETVECOP shl 8 + CTLCVEC
  301. int OPSYS
  302. pop ds
  303. pop dx
  304. pop ax
  305. jmp [ctlc] ; go through old vector
  306. endif ;_NOCTRLC
  307. page
  308. ; __fpinterrupt87
  309. ;
  310. ; This is the 8087 exception interrupt routine.
  311. ;
  312. ; All OEM specific interrupt and harware handling should be done in
  313. ; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
  314. ; exception handler) may not return. __FPEXCEPTION87 also turns
  315. ; interrupts back on.
  316. ;
  317. PENDINGBIT= 80h ; Bit in status word for interrupt pending
  318. __fpinterrupt87:
  319. assume ds:nothing
  320. nop
  321. fnstsw [statwd] ; Store out exceptions
  322. push cx ; waste time
  323. mov cx,3
  324. self:
  325. loop self
  326. pop cx
  327. test byte ptr [statwd],PENDINGBIT ; Test for 8087 interrupt
  328. jz not87int ; Not an 8087 interrupt.
  329. ifdef OEM
  330. call __fpintreset ; OEM interrupt reset routine
  331. endif ;OEM
  332. call __FPEXCEPTION87 ; 8087 error handling - may not return
  333. ; this routine turns interrupts back on
  334. ifdef OEM
  335. cmp [oem1].share,0 ; Should we execute the old interrupt routine?
  336. jnz not87int ; if so then do it
  337. ; else return from interrupt
  338. ; If you fall through here to do further hardware resetting, things
  339. ; may not always work because __FPEXCEPTION87 does not always return
  340. ; This only happens when the 8087 handler gets an exception that is
  341. ; a fatal error in the language runtimes. I.e., divide by zero
  342. ; is a fatal error in all the languages, unless the control word has
  343. ; set to mask out divide by zero errors.
  344. endif ;OEM
  345. done8087:
  346. iret
  347. not87int:
  348. jmp [oldvec] ; We should never return from here.
  349. ifdef OEM
  350. __fpintreset:
  351. push ax
  352. push dx
  353. mov al,[oem1].aocw2 ; Load up EOI instruction.
  354. or al,al ; Is there at least one 8259 to be reset?
  355. jz Reset8259ret ; no
  356. mov dx,[oem1].a8259
  357. out dx,al ; Reset (master) 8259 interrupt controller.
  358. mov al,[oem1].bocw2 ; Load up EOI instruction.
  359. or al,al ; Is there a slave 8259 to be reset?
  360. jz Reset8259ret
  361. mov dx,[oem1].b8259
  362. out dx,al ; Reset slave 8259 interrupt controller.
  363. Reset8259ret:
  364. pop dx
  365. pop ax
  366. ret
  367. endif ;OEM
  368. ifdef _NO87INSTALL
  369. __FPINSTALLNO87:
  370. push bx
  371. push es
  372. push ax
  373. push dx
  374. push ds
  375. mov ax,cs ; Move current CS to DS for opsys calls.
  376. mov ds,ax
  377. assume ds:CODE
  378. ; Save old interrupt vector.
  379. ; Ask operating system for vector.
  380. ifdef OEM
  381. mov al,[oem1].intnum ; Interrupt vector number.
  382. mov ah,GETVECOP ; Operating system call interrupt.
  383. else
  384. mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
  385. endif ;OEM
  386. int OPSYS ; Call operating system.
  387. mov word ptr [oldvec],bx ; Squirrel away old vector.
  388. mov word ptr [oldvec+2],es
  389. ; Have operating system install interrupt vectors.
  390. mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
  391. ifdef OEM
  392. mov ah,SETVECOP ; Set interrupt vector code in AH.
  393. mov al,[oem1].intnum ; Set vector number.
  394. else
  395. mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
  396. endif ;OEM
  397. int OPSYS ; Install vector.
  398. pop ds
  399. assume ds:nothing
  400. pop dx
  401. pop ax
  402. pop es
  403. pop bx
  404. ret
  405. __fpinterruptno87:
  406. jmp [oldvec] ; will use CS: override
  407. __FPTERMINATENO87:
  408. push ds
  409. push ax
  410. push dx
  411. mov ax,cs
  412. mov ds,ax
  413. assume ds:CODE
  414. ifdef OEM
  415. mov ah,SETVECOP
  416. mov al,[oem1].intnum
  417. else
  418. mov ax,SETVECOP shl 8 + 2
  419. endif ;OEM
  420. lds dx,[oldvec]
  421. assume ds:nothing
  422. int OPSYS
  423. pop dx
  424. pop ax
  425. pop ds
  426. ret
  427. endif ;_NO87INSTALL
  428. CODE ends
  429. end