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.

1133 lines
30 KiB

  1. title "Interprocessor Interrupt"
  2. ;++
  3. ;
  4. ;Copyright (c) 1991 Microsoft Corporation
  5. ;Copyright (c) 1992 Intel Corporation
  6. ;All rights reserved
  7. ;
  8. ;INTEL CORPORATION PROPRIETARY INFORMATION
  9. ;
  10. ;This software is supplied to Microsoft under the terms
  11. ;of a license agreement with Intel Corporation and may not be
  12. ;copied nor disclosed except in accordance with the terms
  13. ;of that agreement.
  14. ;
  15. ;
  16. ;Module Name:
  17. ;
  18. ; mpipi.asm
  19. ;
  20. ;Abstract:
  21. ;
  22. ; PC+MP IPI code.
  23. ; Provides the HAL support for Interprocessor Interrupts and Processor
  24. ; initialization for PC+MP Systems
  25. ;
  26. ;Author:
  27. ;
  28. ; Ken Reneris (kenr) 13-Jan-1992
  29. ;
  30. ;Revision History:
  31. ;
  32. ; Ron Mosgrove (Intel) Aug 1993
  33. ; Modified for PC+MP Systems
  34. ;--
  35. .486p
  36. .xlist
  37. ;
  38. ; Normal includes
  39. ;
  40. include hal386.inc
  41. include i386\kimacro.inc
  42. include mac386.inc
  43. include apic.inc
  44. include callconv.inc ; calling convention macros
  45. include ntapic.inc
  46. EXTRNP Kei386EoiHelper,0,IMPORT
  47. EXTRNP _HalBeginSystemInterrupt,3
  48. EXTRNP _HalEndSystemInterrupt,2
  49. EXTRNP _KiIpiServiceRoutine,2,IMPORT
  50. EXTRNP _HalDisplayString,1
  51. EXTRNP HalpAcquireHighLevelLock,1,,FASTCALL
  52. EXTRNP HalpReleaseHighLevelLock,2,,FASTCALL
  53. ifdef ACPI_HAL
  54. EXTRNP _DetectAcpiMP,2
  55. else
  56. EXTRNP _DetectMPS,1
  57. endif
  58. EXTRNP _HalpRegisterKdSupportFunctions,1
  59. EXTRNP _HalpInitializeLocalUnit,0
  60. EXTRNP _HalpResetThisProcessor,0
  61. if DBG OR DEBUGGING
  62. EXTRNP _DbgBreakPoint,0,IMPORT
  63. endif
  64. extrn _HalpDefaultInterruptAffinity:DWORD
  65. extrn _HalpActiveProcessors:DWORD
  66. extrn _HalpGlobal8259Mask:WORD
  67. extrn _HalpStaticIntAffinity:BYTE
  68. extrn _HalpPICINTToVector:BYTE
  69. extrn _rgzBadHal:BYTE
  70. extrn _HalpMaxProcsPerCluster:BYTE
  71. extrn _HalpIntDestMap:BYTE
  72. I386_80387_BUSY_PORT equ 0f0h
  73. SEND_IPI macro IpiCommand
  74. ; Assumption:
  75. ; TargetProcessors KAFFINITY value is in eax at entry
  76. ; IpiCommand is a constant(i.e. an immediate value not in a register)
  77. local HsiGetProcessor, HsiGetNextProcInCluster, HsiDone, HsiSendIpi
  78. local HsiUseClusterMode, HsiExit
  79. cmp _HalpMaxProcsPerCluster, 0
  80. jne HsiUseClusterMode
  81. ; Fewer than 8 processors. Use APIC flat logical mode to send IPI.
  82. shl eax, DESTINATION_SHIFT
  83. pushfd
  84. cli
  85. STALL_WHILE_APIC_BUSY
  86. mov dword ptr APIC[LU_INT_CMD_HIGH], eax
  87. APICFIX edx
  88. mov dword ptr APIC[LU_INT_CMD_LOW], IpiCommand
  89. STALL_WHILE_APIC_BUSY
  90. popfd
  91. jmp HsiExit
  92. ; Use APIC cluster mode to send IPI
  93. HsiUseClusterMode:
  94. pushad
  95. pushfd
  96. mov ch, 0ffh
  97. HsiGetProcessor:
  98. test eax, eax
  99. jz HsiDone
  100. @@:
  101. inc ch
  102. shr eax, 1
  103. jnc @b
  104. ; Found a processor. Get its hardware processor bitmask
  105. xor ebx, ebx ; Avoid partial stall on PentiumPro
  106. mov bl, ch
  107. add ebx, offset _HalpIntDestMap
  108. movzx edx, byte ptr[ebx]
  109. ; Search for other target processors with the same cluster ID
  110. mov edi, eax
  111. mov cl, 0ffh
  112. HsiGetNextProcInCluster:
  113. test edi, edi
  114. jz HsiSendIpi
  115. @@:
  116. inc cl
  117. shr edi, 1
  118. jnc @b
  119. xor ebx, ebx
  120. mov bl, cl
  121. add bl, ch
  122. add ebx, offset _HalpIntDestMap
  123. inc ebx ; Both cl and ch indices are zero based
  124. movzx esi, byte ptr[ebx]
  125. mov ebx, esi
  126. ; Compare cluster ID of new processor with current processor
  127. ; Note that 0 is a valid cluster ID
  128. shr bl, 4
  129. mov bh, dl
  130. shr bh, 4
  131. cmp bl, bh
  132. jne HsiGetNextProcInCluster
  133. ; Found another target processor with the same cluster ID. Or it in.
  134. or edx, esi
  135. ; Remove this new processor from the set of remaining processors
  136. mov esi, 1
  137. shl esi, cl
  138. not esi
  139. and eax, esi
  140. jmp HsiGetNextProcInCluster
  141. HsiSendIpi:
  142. ; (edx) = Target Processor bitmask
  143. shl edx, DESTINATION_SHIFT
  144. cli
  145. STALL_WHILE_APIC_BUSY
  146. mov dword ptr APIC[LU_INT_CMD_HIGH], edx
  147. APICFIX edx
  148. mov dword ptr APIC[LU_INT_CMD_LOW], IpiCommand
  149. STALL_WHILE_APIC_BUSY
  150. jmp HsiGetProcessor
  151. HsiDone:
  152. popfd
  153. popad
  154. HsiExit:
  155. endm ;; SEND_IPI
  156. _DATA SEGMENT DWORD PUBLIC 'DATA'
  157. ALIGN dword
  158. public _HalpProcessorPCR
  159. _HalpProcessorPCR dd MAXIMUM_PROCESSORS dup (?) ; PCR pointer for each processor
  160. ;
  161. ; The following symbols are used by the Local Apic Error handler.
  162. ;
  163. LogApicErrors equ 1
  164. if LogApicErrors
  165. public _HalpLocalApicErrorLock
  166. public _HalpLocalApicErrorCount
  167. public _HalpApicErrorLog
  168. APIC_ERROR_LOG_SIZE equ 128 ; Must be 2^n see usage below
  169. ALIGN dword
  170. _HalpApicErrorLog dw APIC_ERROR_LOG_SIZE dup(0)
  171. _HalpLocalApicErrorLock dd 0
  172. _HalpLocalApicErrorCount dd 0
  173. ;
  174. ; Bit:
  175. ;
  176. ; 0 - Send checksum error
  177. ; 1 - Recieve checksum error
  178. ; 2 - Send accept error
  179. ; 3 - Receive accept error
  180. ; 4 - reserved
  181. ; 5 - Send illegal vector
  182. ; 6 - Receive illegal vector
  183. ; 7 - illegal register address
  184. ; 8-31 - reserved
  185. ;
  186. endif ; LogApicErrors
  187. public HalpBroadcastLock, HalpBroadcastTargets
  188. public HalpBroadcastFunction, HalpBroadcastContext
  189. HalpBroadcastLock dd 0
  190. HalpBroadcastFunction dd 0
  191. HalpBroadcastContext dd 0
  192. HalpBroadcastTargets dd 0
  193. _DATA ends
  194. _TEXT SEGMENT DWORD PUBLIC 'DATA'
  195. ALIGN dword
  196. ;
  197. ; The _PicExtintIntiHandlers and the _PicNopIntiHandlers tables are
  198. ; used by the enable and disable system interrupt routines to determine
  199. ; the EXTINT interrupt handler to install.
  200. ;
  201. public _PicExtintIntiHandlers
  202. _PicExtintIntiHandlers label dword
  203. dd PicInterruptHandlerInti0 ; Inti 0 - PIC 1
  204. dd PicInterruptHandlerInti1 ; Inti 1 - PIC 1
  205. dd PicInterruptHandlerInti2 ; Inti 2 - PIC 1
  206. dd PicInterruptHandlerInti3 ; Inti 3 - PIC 1
  207. dd PicInterruptHandlerInti4 ; Inti 4 - PIC 1
  208. dd PicInterruptHandlerInti5 ; Inti 5 - PIC 1
  209. dd PicInterruptHandlerInti6 ; Inti 6 - PIC 1
  210. dd PicInterruptHandlerInti7 ; Inti 7 - PIC 1
  211. dd PicInterruptHandlerInti8 ; Inti 8 - PIC 2
  212. dd PicInterruptHandlerInti9 ; Inti 9 - PIC 2
  213. dd PicInterruptHandlerIntiA ; Inti 10 - PIC 2
  214. dd PicInterruptHandlerIntiB ; Inti 11 - PIC 2
  215. dd PicInterruptHandlerIntiC ; Inti 12 - PIC 2
  216. dd PicInterruptHandlerIntiD ; Inti 13 - PIC 2
  217. dd PicInterruptHandlerIntiE ; Inti 14 - PIC 2
  218. dd PicInterruptHandlerIntiF ; Inti 15 - PIC 2
  219. public _PicNopIntiHandlers
  220. _PicNopIntiHandlers label dword
  221. dd PicNopHandlerInti0 ; Inti 0 - PIC 1
  222. dd PicNopHandlerInti1 ; Inti 1 - PIC 1
  223. dd PicNopHandlerInti2 ; Inti 2 - PIC 1
  224. dd PicNopHandlerInti3 ; Inti 3 - PIC 1
  225. dd PicNopHandlerInti4 ; Inti 4 - PIC 1
  226. dd PicNopHandlerInti5 ; Inti 5 - PIC 1
  227. dd PicNopHandlerInti6 ; Inti 6 - PIC 1
  228. dd PicNopHandlerInti7 ; Inti 7 - PIC 1
  229. dd CommonPic2NopHandler ; Inti 8 - PIC 2
  230. dd CommonPic2NopHandler ; Inti 9 - PIC 2
  231. dd CommonPic2NopHandler ; Inti 10 - PIC 2
  232. dd CommonPic2NopHandler ; Inti 11 - PIC 2
  233. dd CommonPic2NopHandler ; Inti 12 - PIC 2
  234. dd PicNopHandlerIntiD ; Inti 13 - PIC 2
  235. dd CommonPic2NopHandler ; Inti 14 - PIC 2
  236. dd CommonPic2NopHandler ; Inti 15 - PIC 2
  237. _TEXT ends
  238. page ,132
  239. subttl "Post InterProcessor Interrupt"
  240. _TEXT SEGMENT DWORD PUBLIC 'CODE'
  241. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  242. ;++
  243. ;
  244. ; VOID
  245. ; HalInitializeProcessor(
  246. ; ULONG Number
  247. ; PVOID LoaderBlock
  248. ; );
  249. ;
  250. ;Routine Description:
  251. ;
  252. ; Initialize hal pcr values for current processor (if any)
  253. ; (called shortly after processor reaches kernel, before
  254. ; HalInitSystem if P0)
  255. ;
  256. ; IPI's and KeReadir/LowerIrq's must be available once this function
  257. ; returns. (IPI's are only used once two or more processors are
  258. ; available)
  259. ;
  260. ; . Enable IPI interrupt (makes sense for P1, P2, ...).
  261. ; . Save Processor Number in PCR.
  262. ; . if (P0)
  263. ; . determine if the system is a PC+MP,
  264. ; . if not a PC+MP System Halt;
  265. ; . Enable IPI's on CPU.
  266. ;
  267. ;Arguments:
  268. ;
  269. ; Number - Logical processor number of calling processor
  270. ;
  271. ;Return Value:
  272. ;
  273. ; None.
  274. ;
  275. ;--
  276. cPublicProc _HalInitializeProcessor ,2
  277. mov PCR[PcIDR], 0FFFFFFFFH ; mark all INTs as disabled
  278. movzx eax, byte ptr [esp+4]
  279. mov PCR[PcHal.PcrNumber], al ; Save processor # in PCR
  280. mov ecx, PCR[PcSelfPcr] ; Flat address of this PCR
  281. mov _HalpProcessorPCR[eax*4], ecx ; Save it away
  282. mov dword ptr PCR[PcStallScaleFactor], INITIAL_STALL_COUNT
  283. ;
  284. ; set bit in affinity mask for this active processor
  285. ;
  286. lock bts _HalpActiveProcessors, eax
  287. ;
  288. ; set interrupt affinity to either be most-significant processor or
  289. ; a set of all processors
  290. ;
  291. mov edx, eax
  292. mov eax, _HalpDefaultInterruptAffinity
  293. hip10: cmp _HalpStaticIntAffinity, 1 ; Signle or all?
  294. sbb ecx, ecx ; set mask 0 or -1
  295. and ecx, eax ; include existing set or not
  296. bts ecx, edx ; include self
  297. cmp ecx, eax ; new mask a better choice?
  298. jc short hip20 ; no, done
  299. lock cmpxchg _HalpDefaultInterruptAffinity, ecx ; set new mask
  300. jnz short hip10 ; if it didn't take, do it again
  301. hip20:
  302. ;
  303. ; Most of the following code is only needed on P0
  304. ;
  305. or edx, edx
  306. jnz PnInitCode ; Not P0 skip a lot
  307. ; Run on P0 only
  308. ;
  309. ; Determine if the system we are on is an PC+MP
  310. ;
  311. ; DetectMPS has a parameter we don't currently use. It's a boolean
  312. ; which is set to TRUE if the system we're on is a MP system. Remember,
  313. ; we could have a UP PC+MP system.
  314. ;
  315. ; The DetectMPS routine also allocates Virtual Addresses for all of
  316. ; the APIC's in the system (it needs to access the devices anyway so ...)
  317. ;
  318. sub esp, 4
  319. ifdef ACPI_HAL
  320. mov eax, esp
  321. stdCall _DetectAcpiMP <eax, [esp + 12]> ; Are we running on an ACPI MP
  322. else
  323. stdCall _DetectMPS <esp> ; Are we running on an PC+MP
  324. endif
  325. add esp,4
  326. cmp eax, 0 ; Yes (nonZero) or
  327. je NotPcMp ; No (Zero)
  328. ; stdCall _HalDisplayString, <offset HalSignonString>
  329. ;
  330. ; This next call has nothing to do with processor init.
  331. ; But this is the only function in the HAL that gets
  332. ; called before KdInit.
  333. ;
  334. stdCall _HalpRegisterKdSupportFunctions <[esp + 8]>
  335. mov ax, 0FFFFH ; mask all PIC interrupts
  336. mov _HalpGlobal8259Mask, ax ; save the mask
  337. SET_8259_MASK
  338. ;
  339. ; Other P0 initialization would go here
  340. ;
  341. jmp CommonInitCode
  342. PnInitCode:
  343. ;
  344. ; Pn initialization goes here
  345. ;
  346. CommonInitCode:
  347. stdCall _HalInitApicInterruptHandlers
  348. ;
  349. ; initialize the APIC local unit for this Processor
  350. ;
  351. stdCall _HalpInitializeLocalUnit
  352. stdRET _HalInitializeProcessor
  353. NotPcMp:
  354. stdCall _HalDisplayString, <offset _rgzBadHal>
  355. hlt
  356. stdENDP _HalInitializeProcessor
  357. D_INT032 EQU 8E00h ; access word for 386 ring 0 interrupt gate
  358. ;++
  359. ;
  360. ; VOID
  361. ; HalInitApicInterruptHandlers(
  362. ; );
  363. ;
  364. ;Routine Description:
  365. ;
  366. ; This routine installs the interrupt vector in the IDT for the APIC
  367. ; spurious interrupt.
  368. ;
  369. ;Arguments:
  370. ;
  371. ; None.
  372. ;
  373. ;Return Value:
  374. ;
  375. ; None.
  376. ;
  377. ;--
  378. cPublicProc _HalInitApicInterruptHandlers ,0
  379. enter 8,0 ; setup ebp, reserve 8 bytes of stack
  380. sidt fword ptr [ebp-8] ; get IDT address
  381. mov edx, [ebp-6] ; (edx)->IDT
  382. mov ecx, PIC1_SPURIOUS_VECTOR ; Spurious Vector
  383. mov eax, offset FLAT:PicSpuriousService37
  384. mov word ptr [edx+8*ecx], ax ; Lower half of handler addr
  385. mov word ptr [edx+8*ecx+2], KGDT_R0_CODE ; set up selector
  386. mov word ptr [edx+8*ecx+4], D_INT032 ; 386 interrupt gate
  387. shr eax, 16 ; (ax)=higher half of handler addr
  388. mov word ptr [edx+8*ecx+6], ax
  389. mov ecx, APIC_SPURIOUS_VECTOR ; Apic Spurious Vector
  390. mov eax, offset FLAT:_HalpApicSpuriousService
  391. mov word ptr [edx+8*ecx], ax ; Lower half of handler addr
  392. mov word ptr [edx+8*ecx+2], KGDT_R0_CODE ; set up selector
  393. mov word ptr [edx+8*ecx+4], D_INT032 ; 386 interrupt gate
  394. shr eax, 16 ; (ax)=higher half of handler addr
  395. mov word ptr [edx+8*ecx+6], ax
  396. leave
  397. stdRET _HalInitApicInterruptHandlers
  398. stdENDP _HalInitApicInterruptHandlers
  399. cPublicProc PicSpuriousService37 ,0
  400. iretd
  401. stdENDP PicSpuriousService37
  402. ;++
  403. ;
  404. ; VOID
  405. ; HalpApicRebootService(
  406. ; );
  407. ;
  408. ;Routine Description:
  409. ;
  410. ; This is the ISR that handles Reboot events
  411. ;
  412. ;--
  413. ENTER_DR_ASSIST HReboot_a, HReboot_t
  414. cPublicProc _HalpApicRebootService ,0
  415. ENTER_INTERRUPT_FORCE_STATE HReboot_a, HReboot_t ; (ebp) -> Trap frame
  416. mov eax, APIC_REBOOT_VECTOR
  417. mov ecx, dword ptr APIC[LU_TPR] ; get the old TPR
  418. push ecx ; save it
  419. mov dword ptr APIC[LU_TPR], eax ; set the TPR
  420. APICFIX edx
  421. ;
  422. ; EOI the local APIC, warm reset does not reset the 82489 APIC
  423. ; so if we don't EOI here we'll never see an interrupt after
  424. ; the reboot.
  425. ;
  426. mov dword ptr APIC[LU_EOI], 0 ; send EOI to APIC local unit
  427. stdCall _HalpResetThisProcessor
  428. ;
  429. ; We should never get here, but just in case someone is stepping
  430. ; through this
  431. ;
  432. pop eax
  433. mov dword ptr APIC[LU_TPR], eax ; reset the TPR
  434. APICFIX edx
  435. ;
  436. ; Do interrupt exit processing without EOI
  437. ;
  438. SPURIOUS_INTERRUPT_EXIT
  439. stdENDP _HalpApicRebootService
  440. ;++
  441. ;
  442. ; VOID
  443. ; HalpGenericCallService(
  444. ; );
  445. ;
  446. ; Routine Description:
  447. ; This is the ISR that handles the GenericCall interrupt
  448. ;
  449. ;--
  450. ENTER_DR_ASSIST HGeneric_a, HGeneric_t
  451. cPublicProc _HalpBroadcastCallService ,0
  452. ENTER_INTERRUPT HGeneric_a, HGeneric_t ; (ebp) -> Trap frame
  453. ;
  454. ; (esp) - base of trap frame
  455. ;
  456. ; dismiss interrupt and raise Irql
  457. ;
  458. push APIC_GENERIC_VECTOR
  459. sub esp, 4 ; allocate space to save OldIrql
  460. stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL-1,APIC_GENERIC_VECTOR,esp>
  461. call _HalpPollForBroadcast
  462. INTERRUPT_EXIT ; lower irql to old value, iret
  463. stdENDP _HalpBroadcastCallService
  464. ;++
  465. ;
  466. ; VOID
  467. ; HalpGenericCall(
  468. ; IN VOID (*WorkerFunction)(VOID),
  469. ; IN ULONG Context,
  470. ; IN KAFFINITY TargetProcessors
  471. ; );
  472. ;
  473. ; Routine Description:
  474. ; Causes the WorkerFunction to be called on the specified target
  475. ; processors. The WorkerFunction is called at CLOCK2_LEVEL-1
  476. ; (Must be below IPI_LEVEL in order to prevent system deadlocks).
  477. ;
  478. ; Enviroment:
  479. ; Must be called with interrupts enabled.
  480. ; Must be called with IRQL = CLOCK2_LEVEL-1
  481. ;--
  482. cPublicProc _HalpGenericCall,3
  483. cPublicFpo 3, 0
  484. GENERIC_IPI equ (DELIVER_FIXED OR LOGICAL_DESTINATION OR ICR_USE_DEST_FIELD OR APIC_GENERIC_VECTOR)
  485. @@: call _HalpPollForBroadcast
  486. test HalpBroadcastLock, 1 ; Is broadcast busy?
  487. jnz short @b ; Yes, wait
  488. lock bts HalpBroadcastLock, 0 ; Try to get lock
  489. jc short @b ; didn't get it, loop
  490. hgc30: mov ecx, [esp+4]
  491. mov edx, [esp+8]
  492. mov eax, [esp+12]
  493. mov HalpBroadcastFunction, ecx
  494. mov HalpBroadcastContext, edx
  495. mov HalpBroadcastTargets, eax
  496. or eax, eax ; (eax) = Targets
  497. jz gc90
  498. SEND_IPI GENERIC_IPI
  499. ;
  500. ; Wait for all processors to call broadcast function
  501. ;
  502. @@: call _HalpPollForBroadcast
  503. cmp HalpBroadcastTargets, 0
  504. jnz short @b
  505. gc90: mov HalpBroadcastLock, 0 ; Release BroadcastLock
  506. stdRET _HalpGenericCall
  507. stdENDP _HalpGenericCall
  508. ;++
  509. ;
  510. ; VOID
  511. ; _HalpPollForBroadcast (
  512. ; VOID
  513. ; );
  514. ;
  515. ; Routine Description:
  516. ;
  517. ; IRQL = CLOCK2_LEVEL-1
  518. ;--
  519. cPublicProc _HalpPollForBroadcast, 0
  520. cPublicFpo 0, 0
  521. mov eax, PCR[PcSetMember]
  522. test HalpBroadcastTargets, eax
  523. jz short pb90
  524. mov ecx, HalpBroadcastFunction ; Pickup broadcast function
  525. push HalpBroadcastContext
  526. not eax ; Remove our bit from destionations
  527. lock and HalpBroadcastTargets, eax
  528. call ecx
  529. pb90: stdRET _HalpPollForBroadcast
  530. stdENDP _HalpPollForBroadcast
  531. ;++
  532. ;
  533. ; ULONG
  534. ; FASTCALL
  535. ; HalpWaitForPending (
  536. ; ULONG Count (ecx)
  537. ; PULONG LuICR (edx)
  538. ; );
  539. ;
  540. ; Routine Description:
  541. ;
  542. ; Waits for DELIVERY_PENDING to clear and returns remaining iteration count
  543. ;--
  544. cPublicFastCall HalpWaitForPending, 2
  545. cPublicFpo 0, 0
  546. wfp10: test dword ptr [edx], DELIVERY_PENDING
  547. jz short wfp20
  548. dec ecx
  549. jnz short wfp10
  550. wfp20: mov eax, ecx
  551. fstRet HalpWaitForPending
  552. fstENDP HalpWaitForPending
  553. ;++
  554. ;
  555. ; VOID
  556. ; HalpLocalApicErrorService(
  557. ; );
  558. ;
  559. ;Routine Description:
  560. ;
  561. ; This routine fields Local APIC error Events
  562. ;
  563. ;--
  564. ENTER_DR_ASSIST HApicErr_a, HApicErr_t
  565. cPublicProc _HalpLocalApicErrorService ,0
  566. ;
  567. ; Save machine state in trap frame
  568. ;
  569. ENTER_INTERRUPT HApicErr_a, HApicErr_t ; (ebp) -> Trap frame
  570. if LogApicErrors
  571. lea ecx, _HalpLocalApicErrorLock
  572. fstCall HalpAcquireHighLevelLock
  573. push eax
  574. mov eax, _HalpLocalApicErrorCount
  575. inc _HalpLocalApicErrorCount
  576. lea ecx, _HalpApicErrorLog
  577. and eax, APIC_ERROR_LOG_SIZE-1
  578. shl eax, 1
  579. add ecx, eax
  580. endif ; LogApicErrors
  581. mov dword ptr APIC[LU_EOI], 0 ; local unit EOI
  582. APICFIX eax
  583. ;
  584. ; The Apic EDS (Rev 4.0) says you have to write before you read
  585. ; this doesn't work. The write clears the status bits.
  586. ; But P6 works as according to the EDS!
  587. ;
  588. mov eax, PCR[PcPrcb]
  589. cmp byte ptr [eax].PbCpuType, 6
  590. jc short lae10
  591. mov dword ptr APIC[LU_ERROR_STATUS], 0
  592. lae10:
  593. mov eax, dword ptr APIC[LU_ERROR_STATUS] ; read error status
  594. ; Find out what kind of error it is and update the appropriate count.
  595. if LogApicErrors
  596. ; out 80h, al
  597. mov byte ptr [ecx], al
  598. inc ecx
  599. mov al, byte ptr PCR[PcHal.PcrNumber]
  600. mov byte ptr [ecx], al
  601. lea ecx, _HalpLocalApicErrorLock
  602. pop edx
  603. fstCall HalpReleaseHighLevelLock
  604. endif ; LogApicErrors
  605. SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
  606. stdENDP _HalpLocalApicErrorService
  607. ;++
  608. ;
  609. ; VOID
  610. ; HalRequestIpi(
  611. ; IN ULONG Mask
  612. ; );
  613. ;
  614. ;Routine Description:
  615. ;
  616. ; Requests an interprocessor interrupt
  617. ;
  618. ;Arguments:
  619. ;
  620. ; Mask - Supplies a mask of the processors to be interrupted
  621. ;
  622. ;Return Value:
  623. ;
  624. ; None.
  625. ;
  626. ;--
  627. APIC_IPI equ (DELIVER_FIXED OR LOGICAL_DESTINATION OR ICR_USE_DEST_FIELD OR APIC_IPI_VECTOR)
  628. cPublicProc _HalRequestIpi ,1
  629. cPublicFpo 1, 0
  630. mov eax, [esp+4] ; (eax) = Processor bitmask
  631. SEND_IPI APIC_IPI
  632. stdRET _HalRequestIpi
  633. stdENDP _HalRequestIpi
  634. page ,132
  635. subttl "PC+MP IPI Interrupt Handler"
  636. ;++
  637. ;
  638. ; VOID
  639. ; HalpIpiHandler (
  640. ; );
  641. ;
  642. ; Routine Description:
  643. ;
  644. ; This routine is entered as the result of an interrupt generated by inter
  645. ; processor communication.
  646. ;
  647. ; Arguments:
  648. ;
  649. ; None.
  650. ;
  651. ; Return Value:
  652. ;
  653. ; None.
  654. ;
  655. ;--
  656. ENTER_DR_ASSIST Hipi_a, Hipi_t
  657. cPublicProc _HalpIpiHandler ,0
  658. ;
  659. ; Save machine state in trap frame
  660. ;
  661. ENTER_INTERRUPT Hipi_a, Hipi_t ; (ebp) -> Trap frame
  662. ;
  663. ; Save previous IRQL
  664. ;
  665. push APIC_IPI_VECTOR ; Vector
  666. sub esp, 4 ; space for OldIrql
  667. ;
  668. ; We now dismiss the interprocessor interrupt and call its handler
  669. ;
  670. stdCall _HalBeginSystemInterrupt,<IPI_LEVEL,APIC_IPI_VECTOR,esp>
  671. stdCall _KiIpiServiceRoutine, <ebp,0>
  672. ;
  673. ; Do interrupt exit processing
  674. ;
  675. INTERRUPT_EXIT ; will return to caller
  676. stdENDP _HalpIpiHandler
  677. ;++
  678. ;
  679. ; VOID
  680. ; HalpApicSpuriousService(
  681. ; );
  682. ;
  683. ;Routine Description:
  684. ;
  685. ; A place for spurious interrupts to end up.
  686. ;
  687. ;--
  688. cPublicProc _HalpApicSpuriousService,0
  689. iretd
  690. stdENDP _HalpApicSpuriousService
  691. ;++
  692. ;
  693. ; VOID
  694. ; _PicInterruptHandlerIntiXX(
  695. ; );
  696. ;
  697. ;Routine Description:
  698. ;
  699. ; These handlers receive interrupts from the PIC and reissues them via
  700. ; a vector at the proper priority level. This is used to provide a symetric
  701. ; interrupt distribution on a non symetric system.
  702. ;
  703. ; The PIC interrupts will normally only be received (in the PC+MP Hal) via an
  704. ; interrupt input from on either the IO Unit or the Local unit which has been
  705. ; programed as EXTINT. EXTINT interrupts are received outside of the APIC
  706. ; priority structure (the PIC provides the vector). We use the APIC ICR to
  707. ; generate interrupts to the proper handler at the proper priority.
  708. ;
  709. ; The EXTINT interrupts are directed to a single processor, currently P0.
  710. ; There is no good reason why they can't be directed to another processor.
  711. ;
  712. ; Since one processor must absorb the overhead of redistributing PIC interrupts
  713. ; the interrupt handling on a system using EXTINT interrupts is not symetric.
  714. ;
  715. ;--
  716. ENTER_DR_ASSIST Hcpic_a, Hcpic_t
  717. cPublicProc PicHandler ,0
  718. PicInterruptHandlerInti0:
  719. push 0
  720. jmp short CommonPicHandler
  721. PicInterruptHandlerInti1:
  722. push 1
  723. jmp short CommonPicHandler
  724. PicInterruptHandlerInti2:
  725. push 2
  726. jmp short CommonPicHandler
  727. PicInterruptHandlerInti3:
  728. push 3
  729. jmp short CommonPicHandler
  730. PicInterruptHandlerInti4:
  731. push 4
  732. jmp short CommonPicHandler
  733. PicInterruptHandlerInti5:
  734. push 5
  735. jmp short CommonPicHandler
  736. PicInterruptHandlerInti6:
  737. push 6
  738. jmp short CommonPicHandler
  739. PicInterruptHandlerInti7:
  740. ;
  741. ; Check to see if this is a spurious interrupt
  742. ;
  743. push eax
  744. mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
  745. out PIC1_PORT0, al
  746. IODelay ; delay
  747. in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
  748. test al, 10000000B ; Is In-Service register set?
  749. pop eax
  750. jz short pic7_spurious ;
  751. push 7
  752. jmp short CommonPicHandler
  753. picf_spurious:
  754. mov al, OCW2_SPECIFIC_EOI OR SlavePicInti ; specific eoi to master for pic2 eoi
  755. out PIC1_PORT0, al
  756. pop eax
  757. pic7_spurious:
  758. iretd ; ignore PIC
  759. PicInterruptHandlerInti8:
  760. push 8
  761. jmp short CommonPicHandler
  762. PicInterruptHandlerInti9:
  763. push 9
  764. jmp short CommonPicHandler
  765. PicInterruptHandlerIntiA:
  766. push 10
  767. jmp short CommonPicHandler
  768. PicInterruptHandlerIntiB:
  769. push 11
  770. jmp short CommonPicHandler
  771. PicInterruptHandlerIntiC:
  772. push 12
  773. jmp short CommonPicHandler
  774. PicInterruptHandlerIntiD:
  775. push 13
  776. push eax
  777. xor eax, eax
  778. out I386_80387_BUSY_PORT, al
  779. pop eax
  780. jmp short CommonPicHandler
  781. PicInterruptHandlerIntiE:
  782. push 14
  783. jmp short CommonPicHandler
  784. PicInterruptHandlerIntiF:
  785. push eax
  786. mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
  787. out PIC2_PORT0, al
  788. IODelay ; delay
  789. in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
  790. test al, 10000000B ; Is In-Service register set?
  791. jz short picf_spurious ; Go eoi PIC1 & Ignore PIC2
  792. pop eax
  793. push 15
  794. jmp short CommonPicHandler
  795. CommonPicHandler:
  796. ENTER_INTERRUPT Hcpic_a, Hcpic_t,PassDwordParm ; (ebp) -> Trap frame
  797. ;
  798. ; Need to determine if we have a level interrupt and if so don't EOI it
  799. ; It should be EOI'd by end system interrupt
  800. ;
  801. cmp bl, 8 ; Pic or Slave Pic
  802. jae short cph20
  803. mov al, bl
  804. or al, OCW2_SPECIFIC_EOI ; specific eoi
  805. out PIC1_PORT0, al ; dismiss the interrupt
  806. jmp short cph30
  807. cph20:
  808. mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
  809. out PIC2_PORT0, al
  810. mov al, OCW2_SPECIFIC_EOI OR SlavePicInti ; specific eoi to master for pic2 eoi
  811. out PIC1_PORT0, al ; send irq2 specific eoi to master
  812. cph30:
  813. mov al, _HalpPICINTToVector[ebx] ; Get vector for PIC interrupt
  814. or al, al ; Is vector known?
  815. jz short cph90 ; No, don't dispatch it
  816. ;
  817. ; Now gain exclusive access to the ICR
  818. ;
  819. STALL_WHILE_APIC_BUSY
  820. cmp bl, 8
  821. je short HandleClockInti
  822. ;
  823. ; Write the IPI Command to the Memory Mapped Register
  824. ;
  825. mov dword ptr APIC[LU_INT_CMD_HIGH], DESTINATION_ALL_CPUS
  826. APICFIX edx
  827. mov dword ptr APIC[LU_INT_CMD_LOW], eax
  828. jmp short cph90
  829. HandleClockInti:
  830. ;
  831. ; Write the IPI Command to the Memory Mapped Register
  832. ;
  833. mov dword ptr APIC[LU_INT_CMD_LOW], (DELIVER_FIXED OR ICR_SELF OR APIC_CLOCK_VECTOR)
  834. cph90: APICFIX edx
  835. SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
  836. stdENDP PicHandler
  837. ;++
  838. ;
  839. ; VOID
  840. ; _PicXXNopHandler(
  841. ; );
  842. ;
  843. ;Routine Description:
  844. ;
  845. ; These handlers are designed to be installed on a system to field any PIC
  846. ; interrupts when there are not supposed to be any delivered.
  847. ;
  848. ; In the Debug case this routine increments an error count EOI's the PIC and
  849. ; returns. Normally the increment is not performed.
  850. ;--
  851. cPublicProc PicNopHandler ,0
  852. PicNopHandlerInti0:
  853. push eax ; Save Scratch Registers
  854. mov al, 0
  855. jmp short CommonPic1NopHandler
  856. PicNopHandlerInti1:
  857. push eax ; Save Scratch Registers
  858. mov al, 1
  859. jmp short CommonPic1NopHandler
  860. PicNopHandlerInti2:
  861. push eax ; Save Scratch Registers
  862. mov al, 2
  863. jmp short CommonPic1NopHandler
  864. PicNopHandlerInti3:
  865. push eax ; Save Scratch Registers
  866. mov al, 3
  867. jmp short CommonPic1NopHandler
  868. PicNopHandlerInti4:
  869. push eax ; Save Scratch Registers
  870. mov al, 4
  871. jmp short CommonPic1NopHandler
  872. PicNopHandlerInti5:
  873. push eax ; Save Scratch Registers
  874. mov al, 5
  875. jmp short CommonPic1NopHandler
  876. PicNopHandlerInti6:
  877. push eax ; Save Scratch Registers
  878. mov al, 6
  879. jmp short CommonPic1NopHandler
  880. PicNopHandlerInti7:
  881. push eax ; Save Scratch Registers
  882. mov al, 7
  883. CommonPic1NopHandler:
  884. ;
  885. ; Need to determine if we have a level interrupt and if so don't EOI it
  886. ; It should be EOI'd by end system interrupt
  887. ;
  888. or al, OCW2_SPECIFIC_EOI ; specific eoi
  889. out PIC1_PORT0, al ; dismiss the interrupt
  890. pop eax ; Restore Scratch registers
  891. iretd
  892. PicNopHandlerIntiD:
  893. push eax
  894. xor eax, eax
  895. out I386_80387_BUSY_PORT, al
  896. pop eax
  897. CommonPic2NopHandler:
  898. push eax
  899. ;
  900. ; Need to determine if we have a level interrupt and if so don't EOI it
  901. ; It should be EOI'd by end system interrupt
  902. ;
  903. mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
  904. out PIC2_PORT0, al
  905. mov al, OCW2_SPECIFIC_EOI OR SlavePicInti ; specific eoi to master for pic2 eoi
  906. out PIC1_PORT0, al ; send irq2 specific eoi to master
  907. pop eax
  908. iretd
  909. stdENDP PicNopHandler
  910. _TEXT ENDS
  911. END