3 * Copyright (C) 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: apic.c,v 1.1 2004/12/03 20:10:44 gvg Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: hal/halx86/apic.c
28 #include <ddk/ntddk.h>
29 #include <internal/i386/ps.h>
37 #include <internal/debug.h>
39 BOOLEAN
VerifyLocalAPIC(VOID
);
40 VOID
APICCalibrateTimer(ULONG CPU
);
42 extern VOID
MpsTimerInterrupt(VOID
);
43 extern VOID
MpsErrorInterrupt(VOID
);
44 extern VOID
MpsSpuriousInterrupt(VOID
);
45 extern VOID
MpsIpiInterrupt(VOID
);
47 extern ULONG APICMode
; /* APIC mode at startup */
48 extern PULONG BIOSBase
; /* Virtual address of BIOS data segment */
49 extern PULONG CommonBase
; /* Virtual address of common area */
50 extern ULONG BootCPU
; /* Bootstrap processor */
51 extern ULONG OnlineCPUs
; /* Bitmask of online CPUs */
53 extern CHAR
*APstart
, *APend
;
54 extern VOID (*APflush
)(VOID
);
56 #define CMOS_READ(address) ({ \
57 WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
58 READ_PORT_UCHAR((PUCHAR)0x71)); \
61 #define CMOS_WRITE(address, value) ({ \
62 WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
63 WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
67 #define COMMON_AREA 0x2000
70 extern CPU_INFO CPUMap
[MAX_CPU
]; /* Map of all CPUs in the system */
72 PULONG APICBase
= (PULONG
)APIC_DEFAULT_BASE
; /* Virtual address of local APIC */
75 ULONG lastregr
[MAX_CPU
];
76 ULONG lastvalr
[MAX_CPU
];
77 ULONG lastregw
[MAX_CPU
];
78 ULONG lastvalw
[MAX_CPU
];
80 ULONG
APICGetMaxLVT(VOID
)
82 ULONG tmp
, ver
, maxlvt
;
84 tmp
= APICRead(APIC_VER
);
85 ver
= GET_APIC_VERSION(tmp
);
86 /* 82489DXs do not report # of LVT entries. */
87 maxlvt
= APIC_INTEGRATED(ver
) ? GET_APIC_MAXLVT(tmp
) : 2;
96 maxlvt
= APICGetMaxLVT();
99 * Careful: we have to set masks only first to deassert
100 * any level-triggered sources.
106 APICWrite(APIC_LVT3
, tmp
| APIC_LVT3_MASKED
);
109 tmp
= APICRead(APIC_LVTT
);
110 APICWrite(APIC_LVTT
, tmp
| APIC_LVT_MASKED
);
112 tmp
= APICRead(APIC_LINT0
);
113 APICWrite(APIC_LINT0
, tmp
| APIC_LVT_MASKED
);
115 tmp
= APICRead(APIC_LINT1
);
116 APICWrite(APIC_LINT1
, tmp
| APIC_LVT_MASKED
);
120 tmp
= APICRead(APIC_LVTPC
);
121 APICWrite(APIC_LVTPC
, tmp
| APIC_LVT_MASKED
);
126 tmp
= APICRead(APIC_LVTTHMR
);
127 APICWrite(APIC_LVTTHMR
, tmp
| APIC_LVT_MASKED
);
131 * Clean APIC state for other OSs:
133 APICWrite(APIC_LVTT
, APIC_LVT_MASKED
);
134 APICWrite(APIC_LINT0
, APIC_LVT_MASKED
);
135 APICWrite(APIC_LINT1
, APIC_LVT_MASKED
);
139 APICWrite(APIC_LVT3
, APIC_LVT3_MASKED
);
144 APICWrite(APIC_LVTPC
, APIC_LVT_MASKED
);
149 APICWrite(APIC_LVTTHMR
, APIC_LVT_MASKED
);
154 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
155 VOID
EnableSMPMode(VOID
)
158 * Do not trust the local APIC being empty at bootup.
162 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
163 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x01);
166 /* Disable symetric I/O mode ie. go to PIC mode */
167 inline VOID
DisableSMPMode(VOID
)
170 * Put the board back into PIC mode (has an effect
171 * only on certain older boards). Note that APIC
172 * interrupts, including IPIs, won't work beyond
173 * this point! The only exception are INIT IPIs.
175 WRITE_PORT_UCHAR((PUCHAR
)0x22, 0x70);
176 WRITE_PORT_UCHAR((PUCHAR
)0x23, 0x00);
183 if (APICGetMaxLVT() > 3)
185 APICWrite(APIC_ESR
, 0);
187 tmp
= APICRead(APIC_ESR
);
188 DbgPrint("ESR %08x\n", tmp
);
192 VOID
APICDisable(VOID
)
199 * Disable APIC (implies clearing of registers for 82489DX!).
201 tmp
= APICRead(APIC_SIVR
);
202 tmp
&= ~APIC_SIVR_ENABLE
;
203 APICWrite(APIC_SIVR
, tmp
);
206 VOID
HaliInitBSP(VOID
)
209 static BOOLEAN BSPInitialized
= FALSE
;
211 /* Only initialize the BSP once */
218 BSPInitialized
= TRUE
;
220 DPRINT("APIC is mapped at 0x%X\n", APICBase
);
222 if (VerifyLocalAPIC())
224 DPRINT("APIC found\n");
228 DPRINT("No APIC found\n");
232 if (APICMode
== amPIC
)
239 /* BIOS data segment */
240 BIOSBase
= (PULONG
)BIOS_AREA
;
242 /* Area for communicating with the APs */
243 CommonBase
= (PULONG
)COMMON_AREA
;
245 /* Copy bootstrap code to common area */
246 memcpy((PVOID
)((ULONG
)CommonBase
+ PAGE_SIZE
),
248 (ULONG
)&APend
- (ULONG
)&APstart
+ 1);
250 /* Set shutdown code */
251 CMOS_WRITE(0xF, 0xA);
253 /* Set warm reset vector */
254 ps
= (PUSHORT
)((ULONG
)BIOSBase
+ 0x467);
255 *ps
= (COMMON_AREA
+ PAGE_SIZE
) & 0xF;
257 ps
= (PUSHORT
)((ULONG
)BIOSBase
+ 0x469);
258 *ps
= (COMMON_AREA
+ PAGE_SIZE
) >> 4;
260 /* Calibrate APIC timer */
261 APICCalibrateTimer(BootCPU
);
264 volatile inline ULONG
_APICRead(ULONG Offset
)
268 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
273 inline VOID
APICWrite(ULONG Offset
,
278 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
283 inline VOID
APICWrite(ULONG Offset
,
287 ULONG CPU
= (_APICRead(APIC_ID
) & APIC_ID_MASK
) >> 24;
289 lastregw
[CPU
] = Offset
;
290 lastvalw
[CPU
] = Value
;
292 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
300 volatile inline ULONG
APICRead(ULONG Offset
)
304 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
308 volatile inline ULONG
APICRead(ULONG Offset
)
311 ULONG CPU
= (_APICRead(APIC_ID
) & APIC_ID_MASK
) >> 24;
313 lastregr
[CPU
] = Offset
;
316 p
= (PULONG
)((ULONG
)APICBase
+ Offset
);
319 return lastvalr
[CPU
];
323 inline VOID
APICSendEOI(VOID
)
326 APICWrite(APIC_EOI
, 0);
329 static VOID
APICDumpBit(ULONG base
)
333 DbgPrint("0123456789abcdef0123456789abcdef\n");
334 for (i
= 0; i
< 8; i
++)
336 v
= APICRead(base
+ i
*0x10);
337 for (j
= 0; j
< 32; j
++)
351 * Dump the contents of the local APIC registers
354 ULONG v
, ver
, maxlvt
;
355 ULONG r1
, r2
, w1
, w2
;
356 ULONG CPU
= ThisCPU();;
365 DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
366 v
= APICRead(APIC_ID
);
367 DbgPrint("... ID : %08x (%01x) ", v
, GET_APIC_ID(v
));
368 v
= APICRead(APIC_VER
);
369 DbgPrint("... VERSION: %08x\n", v
);
370 ver
= GET_APIC_VERSION(v
);
371 maxlvt
= APICGetMaxLVT();
373 v
= APICRead(APIC_TPR
);
374 DbgPrint("... TPR : %08x (%02x)", v
, v
& ~0);
376 if (APIC_INTEGRATED(ver
))
379 v
= APICRead(APIC_APR
);
380 DbgPrint("... APR : %08x (%02x)\n", v
, v
& ~0);
381 v
= APICRead(APIC_PPR
);
382 DbgPrint("... PPR : %08x\n", v
);
385 v
= APICRead(APIC_EOI
);
386 DbgPrint("... EOI : %08x ! ", v
);
387 v
= APICRead(APIC_LDR
);
388 DbgPrint("... LDR : %08x\n", v
);
389 v
= APICRead(APIC_DFR
);
390 DbgPrint("... DFR : %08x ! ", v
);
391 v
= APICRead(APIC_SIVR
);
392 DbgPrint("... SIVR : %08x\n", v
);
396 DbgPrint("... ISR field:\n");
397 APICDumpBit(APIC_ISR
);
398 DbgPrint("... TMR field:\n");
399 APICDumpBit(APIC_TMR
);
400 DbgPrint("... IRR field:\n");
401 APICDumpBit(APIC_IRR
);
404 if (APIC_INTEGRATED(ver
))
409 /* Due to the Pentium erratum 3AP. */
410 APICWrite(APIC_ESR
, 0);
412 v
= APICRead(APIC_ESR
);
413 DbgPrint("... ESR : %08x\n", v
);
416 v
= APICRead(APIC_ICR0
);
417 DbgPrint("... ICR0 : %08x ! ", v
);
418 v
= APICRead(APIC_ICR1
);
419 DbgPrint("... ICR1 : %08x ! ", v
);
421 v
= APICRead(APIC_LVTT
);
422 DbgPrint("... LVTT : %08x\n", v
);
427 v
= APICRead(APIC_LVTPC
);
428 DbgPrint("... LVTPC : %08x ! ", v
);
430 v
= APICRead(APIC_LINT0
);
431 DbgPrint("... LINT0 : %08x ! ", v
);
432 v
= APICRead(APIC_LINT1
);
433 DbgPrint("... LINT1 : %08x\n", v
);
437 v
= APICRead(APIC_LVT3
);
438 DbgPrint("... LVT3 : %08x\n", v
);
441 v
= APICRead(APIC_ICRT
);
442 DbgPrint("... ICRT : %08x ! ", v
);
443 v
= APICRead(APIC_CCRT
);
444 DbgPrint("... CCCT : %08x ! ", v
);
445 v
= APICRead(APIC_TDCR
);
446 DbgPrint("... TDCR : %08x\n", v
);
448 DbgPrint("Last register read (offset): 0x%08X\n", r1
);
449 DbgPrint("Last register read (value): 0x%08X\n", r2
);
450 DbgPrint("Last register written (offset): 0x%08X\n", w1
);
451 DbgPrint("Last register written (value): 0x%08X\n", w2
);
455 BOOLEAN
VerifyLocalAPIC(VOID
)
459 /* The version register is read-only in a real APIC */
460 reg0
= APICRead(APIC_VER
);
461 DPRINT1("Getting VERSION: %x\n", reg0
);
462 APICWrite(APIC_VER
, reg0
^ APIC_VER_MASK
);
463 reg1
= APICRead(APIC_VER
);
464 DPRINT1("Getting VERSION: %x\n", reg1
);
467 * The two version reads above should print the same
468 * numbers. If the second one is different, then we
469 * poke at a non-APIC.
478 * Check if the version looks reasonably.
480 reg1
= GET_APIC_VERSION(reg0
);
481 if (reg1
== 0x00 || reg1
== 0xff)
485 reg1
= APICGetMaxLVT();
486 if (reg1
< 0x02 || reg1
== 0xff)
492 * The ID register is read/write in a real APIC.
494 reg0
= APICRead(APIC_ID
);
495 DPRINT1("Getting ID: %x\n", reg0
);
496 APICWrite(APIC_ID
, reg0
^ APIC_ID_MASK
);
497 reg1
= APICRead(APIC_ID
);
498 DPRINT1("Getting ID: %x\n", reg1
);
499 APICWrite(APIC_ID
, reg0
);
500 if (reg1
!= (reg0
^ APIC_ID_MASK
))
508 VOID
APICSendIPI(ULONG Target
, ULONG Mode
)
512 /* save flags and disable interrupts */
513 Ki386SaveFlags(flags
);
514 Ki386DisableInterrupts();
516 /* Wait up to 100ms for the APIC to become ready */
517 for (i
= 0; i
< 10000; i
++)
519 tmp
= APICRead(APIC_ICR0
);
520 /* Check Delivery Status */
521 if ((tmp
& APIC_ICR0_DS
) == 0)
523 KeStallExecutionProcessor(10);
528 DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
531 /* Setup the APIC to deliver the IPI */
532 DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target
), Target
);
533 APICWrite(APIC_ICR1
, SET_APIC_DEST_FIELD(Target
));
535 if (Target
== APIC_TARGET_SELF
)
537 Mode
|= APIC_ICR0_DESTS_SELF
;
539 else if (Target
== APIC_TARGET_ALL
)
541 Mode
|= APIC_ICR0_DESTS_ALL
;
543 else if (Target
== APIC_TARGET_ALL_BUT_SELF
)
545 Mode
|= APIC_ICR0_DESTS_ALL_BUT_SELF
;
549 Mode
|= APIC_ICR0_DESTS_FIELD
;
552 /* Now, fire off the IPI */
553 APICWrite(APIC_ICR0
, Mode
);
555 /* Wait up to 100ms for the APIC to become ready */
556 for (i
= 0; i
< 10000; i
++)
558 tmp
= APICRead(APIC_ICR0
);
559 /* Check Delivery Status */
560 if ((tmp
& APIC_ICR0_DS
) == 0)
562 KeStallExecutionProcessor(10);
567 DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
569 Ki386RestoreFlags(flags
);
580 DPRINT1("CPU%d:\n", CPU
);
581 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
582 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
583 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
586 * Intel recommends to set DFR, LDR and TPR before enabling
587 * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
588 * document number 292116). So here it goes...
592 * Put the APIC into flat delivery mode.
593 * Must be "all ones" explicitly for 82489DX.
595 APICWrite(APIC_DFR
, 0xFFFFFFFF);
598 * Set up the logical destination ID.
600 tmp
= APICRead(APIC_LDR
);
601 tmp
&= ~APIC_LDR_MASK
;
604 * This works only up to 8 CPU's
606 tmp
|= (1 << (KeGetCurrentProcessorNumber() + 24));
607 APICWrite(APIC_LDR
, tmp
);
610 DPRINT1("CPU%d:\n", CPU
);
611 DPRINT1(" Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID
)));
612 DPRINT1(" Logical APIC id: %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR
)));
613 DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID
), APICRead(APIC_LDR
), APICRead(APIC_DFR
));
614 DPRINT1("%d\n", CPUMap
[CPU
].APICId
);
616 /* Accept only higher interrupts */
617 APICWrite(APIC_TPR
, 0xef);
619 /* Enable local APIC */
620 tmp
= APICRead(APIC_SIVR
);
622 tmp
|= APIC_SIVR_ENABLE
;
625 tmp
&= ~APIC_SIVR_FOCUS
;
627 tmp
|= APIC_SIVR_FOCUS
;
630 /* Set spurious interrupt vector */
631 tmp
|= SPURIOUS_VECTOR
;
632 APICWrite(APIC_SIVR
, tmp
);
637 * set up through-local-APIC on the BP's LINT0. This is not
638 * strictly necessery in pure symmetric-IO mode, but sometimes
639 * we delegate interrupts to the 8259A.
641 tmp
= APICRead(APIC_LINT0
) & APIC_LVT_MASKED
;
642 if (CPU
== BootCPU
&& (APICMode
== amPIC
|| !tmp
))
644 tmp
= APIC_DM_EXTINT
;
645 DPRINT1("enabled ExtINT on CPU#%d\n", CPU
);
649 tmp
= APIC_DM_EXTINT
| APIC_LVT_MASKED
;
650 DPRINT1("masked ExtINT on CPU#%d\n", CPU
);
652 APICWrite(APIC_LINT0
, tmp
);
656 * Only the BSP should see the LINT1 NMI signal, obviously.
664 tmp
= APIC_DM_NMI
| APIC_LVT_MASKED
;
666 if (!APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
669 tmp
|= APIC_LVT_LEVEL_TRIGGER
;
671 APICWrite(APIC_LINT1
, tmp
);
673 if (APIC_INTEGRATED(CPUMap
[CPU
].APICVersion
))
676 if (APICGetMaxLVT() > 3)
678 /* Due to the Pentium erratum 3AP */
679 APICWrite(APIC_ESR
, 0);
682 tmp
= APICRead(APIC_ESR
);
683 DPRINT("ESR value before enabling vector: 0x%X\n", tmp
);
685 /* Enable sending errors */
687 APICWrite(APIC_LVT3
, tmp
);
690 * Spec says clear errors after enabling vector
692 if (APICGetMaxLVT() > 3)
694 APICWrite(APIC_ESR
, 0);
696 tmp
= APICRead(APIC_ESR
);
697 DPRINT("ESR value after enabling vector: 0x%X\n", tmp
);
701 VOID
APICSyncArbIDs(VOID
)
705 /* Wait up to 100ms for the APIC to become ready */
706 for (i
= 0; i
< 10000; i
++)
708 tmp
= APICRead(APIC_ICR0
);
709 /* Check Delivery Status */
710 if ((tmp
& APIC_ICR0_DS
) == 0)
712 KeStallExecutionProcessor(10);
717 DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
720 DPRINT("Synchronizing Arb IDs.\n");
721 APICWrite(APIC_ICR0
, APIC_ICR0_DESTS_ALL
| APIC_ICR0_LEVEL
| APIC_DM_INIT
);
724 VOID
MpsErrorHandler(VOID
)
730 tmp1
= APICRead(APIC_ESR
);
731 APICWrite(APIC_ESR
, 0);
732 tmp2
= APICRead(APIC_ESR
);
733 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
736 * Acknowledge the interrupt
740 /* Here is what the APIC error bits mean:
742 * 1: Receive CS error
743 * 2: Send accept error
744 * 3: Receive accept error
746 * 5: Send illegal vector
747 * 6: Received illegal vector
748 * 7: Illegal register address
750 DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1
, tmp2
);
754 VOID
MpsSpuriousHandler(VOID
)
758 DPRINT1("Spurious interrupt on CPU(%d)\n", ThisCPU());
760 tmp
= APICRead(APIC_ISR
+ ((SPURIOUS_VECTOR
& ~0x1f) >> 1));
761 if (tmp
& (1 << (SPURIOUS_VECTOR
& 0x1f)))
767 /* No need to send EOI here */
772 VOID
MpsIpiHandler(VOID
)
776 HalBeginSystemInterrupt(IPI_VECTOR
,
777 VECTOR2IRQL(IPI_VECTOR
),
779 Ki386EnableInterrupts();
781 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n",
782 __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
785 KiIpiServiceRoutine(NULL
, NULL
);
788 DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber());
791 Ki386DisableInterrupts();
792 HalEndSystemInterrupt(oldIrql
, 0);
796 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
797 PKTRAP_FRAME TrapFrame
)
799 TrapFrame
->Gs
= (USHORT
)IrqTrapFrame
->Gs
;
800 TrapFrame
->Fs
= (USHORT
)IrqTrapFrame
->Fs
;
801 TrapFrame
->Es
= (USHORT
)IrqTrapFrame
->Es
;
802 TrapFrame
->Ds
= (USHORT
)IrqTrapFrame
->Ds
;
803 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
804 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
805 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
806 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
807 TrapFrame
->Esp
= IrqTrapFrame
->Esp
;
808 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
809 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
810 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
811 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
812 TrapFrame
->Cs
= IrqTrapFrame
->Cs
;
813 TrapFrame
->Eflags
= IrqTrapFrame
->Eflags
;
817 MpsTimerHandler(ULONG Vector
, PKIRQ_TRAPFRAME Trapframe
)
820 KTRAP_FRAME KernelTrapFrame
;
823 static ULONG Count
[MAX_CPU
] = {0,};
825 HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR
,
826 VECTOR2IRQL(LOCAL_TIMER_VECTOR
),
828 Ki386EnableInterrupts();
832 if ((Count
[CPU
] % 100) == 0)
834 DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__
, __LINE__
, CPU
, oldIrql
,Trapframe
->Eip
, KeGetCurrentKPCR());
839 MpsIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
840 if (KeGetCurrentProcessorNumber() == 0)
842 KeUpdateSystemTime(&KernelTrapFrame
, oldIrql
);
846 KeUpdateRunTime(&KernelTrapFrame
, oldIrql
);
849 Ki386DisableInterrupts();
850 HalEndSystemInterrupt (oldIrql
, 0);