summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halmps/i386/mpipi.asm
blob: 5b7ba47d9ee286f6571d46ecac2809c6335fddf9 (plain) (blame)
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