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