t's a bit embarrasing that some of this was undone until recently, but we now
[reactos.git] / reactos / ntoskrnl / ke / powerpc / ppc_irq.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/irq.c
6 * PURPOSE: IRQ handling
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /*
12 * NOTE: In general the PIC interrupt priority facilities are used to
13 * preserve the NT IRQL semantics, global interrupt disables are only used
14 * to keep the PIC in a consistent state
15 *
16 */
17
18 /* INCLUDES ****************************************************************/
19
20 #include <ntoskrnl.h>
21 #include <ppcmmu/mmu.h>
22
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 KDPC KiExpireTimerDpc;
27 extern ULONG KiMaximumDpcQueueDepth;
28 extern ULONG KiMinimumDpcRate;
29 extern ULONG KiAdjustDpcThreshold;
30 extern ULONG KiIdealDpcRate;
31 extern LONG KiTickOffset;
32 extern ULONG KeMaximumIncrement;
33 extern ULONG KeMinimumIncrement;
34 extern ULONG KeTimeAdjustment;
35
36 extern void PearPCDebug(int ch);
37
38 /* GLOBALS *****************************************************************/
39
40 /* Interrupt handler list */
41
42 #define NR_TRAPS 16
43 #ifdef CONFIG_SMP
44
45 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
46
47 #define BUILD_INTERRUPT_HANDLER(intnum) \
48 VOID INT_NAME2(intnum)(VOID);
49
50 #define D(x,y) \
51 BUILD_INTERRUPT_HANDLER(x##y)
52
53 #define D16(x) \
54 D(x,0) D(x,1) D(x,2) D(x,3) \
55 D(x,4) D(x,5) D(x,6) D(x,7) \
56 D(x,8) D(x,9) D(x,A) D(x,B) \
57 D(x,C) D(x,D) D(x,E) D(x,F)
58
59 D16(3) D16(4) D16(5) D16(6)
60 D16(7) D16(8) D16(9) D16(A)
61 D16(B) D16(C) D16(D) D16(E)
62 D16(F)
63
64 #define L(x,y) \
65 (ULONG)& INT_NAME2(x##y)
66
67 #define L16(x) \
68 L(x,0), L(x,1), L(x,2), L(x,3), \
69 L(x,4), L(x,5), L(x,6), L(x,7), \
70 L(x,8), L(x,9), L(x,A), L(x,B), \
71 L(x,C), L(x,D), L(x,E), L(x,F)
72
73 static ULONG irq_handler[ROUND_UP(NR_TRAPS, 16)] = {
74 L16(3), L16(4), L16(5), L16(6),
75 L16(7), L16(8), L16(9), L16(A),
76 L16(B), L16(C), L16(D), L16(E)
77 };
78
79 #undef L
80 #undef L16
81 #undef D
82 #undef D16
83
84 #else /* CONFIG_SMP */
85
86 void trap_handler_0(void);
87 void trap_handler_1(void);
88 void trap_handler_2(void);
89 void trap_handler_3(void);
90 void trap_handler_4(void);
91 void trap_handler_5(void);
92 void trap_handler_6(void);
93 void trap_handler_7(void);
94 void trap_handler_8(void);
95 void trap_handler_9(void);
96 void trap_handler_10(void);
97 void trap_handler_11(void);
98 void trap_handler_12(void);
99 void trap_handler_13(void);
100 void trap_handler_14(void);
101 void trap_handler_15(void);
102
103 static unsigned int trap_handler[NR_TRAPS] __attribute__((unused)) =
104 {
105 (int)&trap_handler_0,
106 (int)&trap_handler_1,
107 (int)&trap_handler_2,
108 (int)&trap_handler_3,
109 (int)&trap_handler_4,
110 (int)&trap_handler_5,
111 (int)&trap_handler_6,
112 (int)&trap_handler_7,
113 (int)&trap_handler_8,
114 (int)&trap_handler_9,
115 (int)&trap_handler_10,
116 (int)&trap_handler_11,
117 (int)&trap_handler_12,
118 (int)&trap_handler_13,
119 (int)&trap_handler_14,
120 (int)&trap_handler_15,
121 };
122
123 #endif /* CONFIG_SMP */
124
125 /*
126 * PURPOSE: Object describing each isr
127 * NOTE: The data in this table is only modified at passsive level but can
128 * be accessed at any irq level.
129 */
130
131 typedef struct
132 {
133 LIST_ENTRY ListHead;
134 KSPIN_LOCK Lock;
135 ULONG Count;
136 }
137 ISR_TABLE, *PISR_TABLE;
138
139 #ifdef CONFIG_SMP
140 static ISR_TABLE IsrTable[NR_TRAPS][MAXIMUM_PROCESSORS];
141 #else
142 static ISR_TABLE IsrTable[NR_TRAPS][1];
143 #endif
144
145 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
146
147 /* FUNCTIONS ****************************************************************/
148
149 VOID
150 INIT_FUNCTION
151 NTAPI
152 KeInitInterrupts (VOID)
153 {
154 int i, j;
155
156 /*
157 * Setup the IDT entries to point to the interrupt handlers
158 */
159 for (i=0;i<NR_TRAPS;i++)
160 {
161 #ifdef CONFIG_SMP
162 for (j = 0; j < MAXIMUM_PROCESSORS; j++)
163 #else
164 j = 0;
165 #endif
166 {
167 InitializeListHead(&IsrTable[i][j].ListHead);
168 KeInitializeSpinLock(&IsrTable[i][j].Lock);
169 IsrTable[i][j].Count = 0;
170 }
171 }
172 }
173
174 static VOID
175 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
176 PKTRAP_FRAME TrapFrame)
177 {
178 }
179
180 static VOID
181 KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame,
182 PKIRQ_TRAPFRAME IrqTrapFrame)
183 {
184 }
185
186 /*
187 * NOTE: On Windows this function takes exactly one parameter and EBP is
188 * guaranteed to point to KTRAP_FRAME. The function is used only
189 * by HAL, so there's no point in keeping that prototype.
190 *
191 * @implemented
192 */
193 VOID
194 STDCALL
195 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
196 IN KIRQL Irql)
197 {
198 PKPRCB Prcb = KeGetCurrentPrcb();
199 PKTHREAD CurrentThread;
200 PKPROCESS CurrentProcess;
201
202 /* Make sure we don't go further if we're in early boot phase. */
203 if (!(Prcb) || !(Prcb->CurrentThread)) return;
204
205 /* Get the current thread and process */
206 CurrentThread = Prcb->CurrentThread;
207 CurrentProcess = CurrentThread->ApcState.Process;
208
209 /* Check if we came from user mode */
210 if (TrapFrame->PreviousMode != KernelMode)
211 {
212 /* Update user times */
213 CurrentThread->UserTime++;
214 InterlockedIncrement((PLONG)&CurrentProcess->UserTime);
215 Prcb->UserTime++;
216 }
217 else
218 {
219 /* Check IRQ */
220 if (Irql > DISPATCH_LEVEL)
221 {
222 /* This was an interrupt */
223 Prcb->InterruptTime++;
224 }
225 else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
226 {
227 /* This was normal kernel time */
228 CurrentThread->KernelTime++;
229 InterlockedIncrement((PLONG)&CurrentProcess->KernelTime);
230 }
231 else if (Irql == DISPATCH_LEVEL)
232 {
233 /* This was DPC time */
234 Prcb->DpcTime++;
235 }
236
237 /* Update CPU kernel time in all cases */
238 Prcb->KernelTime++;
239 }
240
241 /* Set the last DPC Count and request rate */
242 Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
243 Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
244 Prcb->DpcRequestRate) / 2;
245
246 /* Check if we should request a DPC */
247 if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
248 {
249 /* Request one */
250 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
251
252 /* Update the depth if needed */
253 if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
254 (Prcb->MaximumDpcQueueDepth > 1))
255 {
256 /* Decrease the maximum depth by one */
257 Prcb->MaximumDpcQueueDepth--;
258 }
259 }
260 else
261 {
262 /* Decrease the adjustment threshold */
263 if (!(--Prcb->AdjustDpcThreshold))
264 {
265 /* We've hit 0, reset it */
266 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
267
268 /* Check if we've hit queue maximum */
269 if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
270 {
271 /* Increase maximum by one */
272 Prcb->MaximumDpcQueueDepth++;
273 }
274 }
275 }
276
277 /*
278 * If we're at end of quantum request software interrupt. The rest
279 * is handled in KiDispatchInterrupt.
280 *
281 * NOTE: If one stays at DISPATCH_LEVEL for a long time the DPC routine
282 * which checks for quantum end will not be executed and decrementing
283 * the quantum here can result in overflow. This is not a problem since
284 * we don't care about the quantum value anymore after the QuantumEnd
285 * flag is set.
286 */
287 if ((CurrentThread->Quantum -= 3) <= 0)
288 {
289 Prcb->QuantumEnd = TRUE;
290 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
291 }
292 }
293
294
295 /*
296 * NOTE: On Windows this function takes exactly zero parameters and EBP is
297 * guaranteed to point to KTRAP_FRAME. Also [esp+0] contains an IRQL.
298 * The function is used only by HAL, so there's no point in keeping
299 * that prototype.
300 *
301 * @implemented
302 */
303 VOID
304 STDCALL
305 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
306 IN KIRQL Irql,
307 IN ULONG Increment)
308 {
309 LONG OldOffset;
310 LARGE_INTEGER Time;
311 ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
312
313 /* Update interrupt time */
314 Time.LowPart = SharedUserData->InterruptTime.LowPart;
315 Time.HighPart = SharedUserData->InterruptTime.High1Time;
316 Time.QuadPart += Increment;
317 SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
318 SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
319 SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
320
321 /* Increase the tick offset */
322 KiTickOffset -= Increment;
323 OldOffset = KiTickOffset;
324
325 /* Check if this isn't a tick yet */
326 if (KiTickOffset > 0)
327 {
328 /* Expire timers */
329 KeInsertQueueDpc(&KiExpireTimerDpc, 0, 0);
330 }
331 else
332 {
333 /* Setup time structure for system time */
334 Time.LowPart = SharedUserData->SystemTime.LowPart;
335 Time.HighPart = SharedUserData->SystemTime.High1Time;
336 Time.QuadPart += KeTimeAdjustment;
337 SharedUserData->SystemTime.High2Time = Time.HighPart;
338 SharedUserData->SystemTime.LowPart = Time.LowPart;
339 SharedUserData->SystemTime.High1Time = Time.HighPart;
340
341 /* Setup time structure for tick time */
342 Time.LowPart = KeTickCount.LowPart;
343 Time.HighPart = KeTickCount.High1Time;
344 Time.QuadPart += 1;
345 KeTickCount.High2Time = Time.HighPart;
346 KeTickCount.LowPart = Time.LowPart;
347 KeTickCount.High1Time = Time.HighPart;
348 SharedUserData->TickCount.High2Time = Time.HighPart;
349 SharedUserData->TickCount.LowPart = Time.LowPart;
350 SharedUserData->TickCount.High1Time = Time.HighPart;
351
352 /* Update tick count in shared user data as well */
353 SharedUserData->TickCountLowDeprecated++;
354
355 /* Queue a DPC that will expire timers */
356 KeInsertQueueDpc(&KiExpireTimerDpc, 0, 0);
357 }
358
359 /* Update process and thread times */
360 if (OldOffset <= 0)
361 {
362 /* This was a tick, calculate the next one */
363 KiTickOffset += KeMaximumIncrement;
364 KeUpdateRunTime(TrapFrame, Irql);
365 }
366 }
367
368 VOID STDCALL
369 KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
370 /*
371 * FUNCTION: Calls all the interrupt handlers for a given irq.
372 * ARGUMENTS:
373 * vector - The number of the vector to call handlers for.
374 * old_level - The irql of the processor when the irq took place.
375 * NOTES: Must be called at DIRQL.
376 */
377 {
378 PKINTERRUPT isr;
379 PLIST_ENTRY current;
380 KIRQL oldlvl;
381 PISR_TABLE CurrentIsr;
382
383 DPRINT("I(0x%.08x, 0x%.08x)\n", vector, old_level);
384
385 /*
386 * Iterate the list until one of the isr tells us its device interrupted
387 */
388 CurrentIsr = &IsrTable[vector][(ULONG)KeGetCurrentProcessorNumber()];
389
390 KiAcquireSpinLock(&CurrentIsr->Lock);
391
392 CurrentIsr->Count++;
393 current = CurrentIsr->ListHead.Flink;
394
395 while (current != &CurrentIsr->ListHead)
396 {
397 isr = CONTAINING_RECORD(current,KINTERRUPT,InterruptListEntry);
398 oldlvl = KeAcquireInterruptSpinLock(isr);
399 if (isr->ServiceRoutine(isr, isr->ServiceContext))
400 {
401 KeReleaseInterruptSpinLock(isr, oldlvl);
402 break;
403 }
404 KeReleaseInterruptSpinLock(isr, oldlvl);
405 current = current->Flink;
406 }
407 KiReleaseSpinLock(&CurrentIsr->Lock);
408 }
409
410 VOID
411 KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
412 /*
413 * FUNCTION: Calls the irq specific handler for an irq
414 * ARGUMENTS:
415 * irq = IRQ that has interrupted
416 */
417 {
418 KIRQL old_level;
419 KTRAP_FRAME KernelTrapFrame;
420 PKTHREAD CurrentThread;
421 PKTRAP_FRAME OldTrapFrame=NULL;
422
423 /*
424 * At this point we have interrupts disabled, nothing has been done to
425 * the PIC.
426 */
427
428 KeGetCurrentPrcb()->InterruptCount++;
429
430 /*
431 * Notify the rest of the kernel of the raised irq level. For the
432 * default HAL this will send an EOI to the PIC and alter the IRQL.
433 */
434 if (!HalBeginSystemInterrupt (vector,
435 vector,
436 &old_level))
437 {
438 return;
439 }
440
441
442 /*
443 * Enable interrupts
444 * NOTE: Only higher priority interrupts will get through
445 */
446 _enable();
447
448 #ifndef CONFIG_SMP
449 if (vector == 0)
450 {
451 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
452 KeUpdateSystemTime(&KernelTrapFrame, old_level, 100000);
453 }
454 else
455 #endif
456 {
457 /*
458 * Actually call the ISR.
459 */
460 KiInterruptDispatch2(vector, old_level);
461 }
462
463 /*
464 * End the system interrupt.
465 */
466 _disable();
467
468 if (old_level==PASSIVE_LEVEL)
469 {
470 HalEndSystemInterrupt (APC_LEVEL, 0);
471
472 CurrentThread = KeGetCurrentThread();
473 if (CurrentThread!=NULL && CurrentThread->ApcState.UserApcPending)
474 {
475 if (CurrentThread->TrapFrame == NULL)
476 {
477 OldTrapFrame = CurrentThread->TrapFrame;
478 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
479 CurrentThread->TrapFrame = &KernelTrapFrame;
480 }
481
482 _enable();
483 KiDeliverApc(UserMode, NULL, NULL);
484 _disable();
485
486 ASSERT(KeGetCurrentThread() == CurrentThread);
487 if (CurrentThread->TrapFrame == &KernelTrapFrame)
488 {
489 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame, Trapframe);
490 CurrentThread->TrapFrame = OldTrapFrame;
491 }
492 }
493 KeLowerIrql(PASSIVE_LEVEL);
494 }
495 else
496 {
497 HalEndSystemInterrupt (old_level, 0);
498 }
499
500 }
501
502 static VOID
503 KeDumpIrqList(VOID)
504 {
505 PKINTERRUPT current;
506 PLIST_ENTRY current_entry;
507 LONG i, j;
508 KIRQL oldlvl;
509 BOOLEAN printed;
510
511 for (i=0;i<NR_TRAPS;i++)
512 {
513 printed = FALSE;
514 KeRaiseIrql(i,&oldlvl);
515
516 for (j=0; j < KeNumberProcessors; j++)
517 {
518 KiAcquireSpinLock(&IsrTable[i][j].Lock);
519
520 current_entry = IsrTable[i][j].ListHead.Flink;
521 current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
522 while (current_entry!=&(IsrTable[i][j].ListHead))
523 {
524 if (printed == FALSE)
525 {
526 printed = TRUE;
527 DPRINT("For irq %x:\n",i);
528 }
529 DPRINT(" Isr %x\n",current);
530 current_entry = current_entry->Flink;
531 current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
532 }
533 KiReleaseSpinLock(&IsrTable[i][j].Lock);
534 }
535 KeLowerIrql(oldlvl);
536 }
537 }
538
539 /*
540 * @implemented
541 */
542 BOOLEAN
543 STDCALL
544 KeConnectInterrupt(PKINTERRUPT InterruptObject)
545 {
546 KIRQL oldlvl,synch_oldlvl;
547 PKINTERRUPT ListHead;
548 ULONG Vector;
549 PISR_TABLE CurrentIsr;
550 BOOLEAN Result;
551
552 DPRINT("KeConnectInterrupt()\n");
553
554 Vector = InterruptObject->Vector;
555
556 if (Vector < 0 || Vector >= NR_TRAPS)
557 return FALSE;
558
559 ASSERT (InterruptObject->Number < KeNumberProcessors);
560
561 KeSetSystemAffinityThread(1 << InterruptObject->Number);
562
563 CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number];
564
565 KeRaiseIrql(Vector,&oldlvl);
566 KiAcquireSpinLock(&CurrentIsr->Lock);
567
568 /*
569 * Check if the vector is already in use that we can share it
570 */
571 if (!IsListEmpty(&CurrentIsr->ListHead))
572 {
573 ListHead = CONTAINING_RECORD(CurrentIsr->ListHead.Flink,KINTERRUPT,InterruptListEntry);
574 if (InterruptObject->ShareVector == FALSE || ListHead->ShareVector==FALSE)
575 {
576 KiReleaseSpinLock(&CurrentIsr->Lock);
577 KeLowerIrql(oldlvl);
578 KeRevertToUserAffinityThread();
579 return FALSE;
580 }
581 }
582
583 synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
584
585 DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink);
586
587 Result = HalEnableSystemInterrupt(Vector, InterruptObject->Irql, InterruptObject->Mode);
588 if (Result)
589 {
590 InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry);
591 DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->InterruptListEntry.Blink);
592 }
593
594 InterruptObject->Connected = TRUE;
595 KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
596
597 /*
598 * Release the table spinlock
599 */
600 KiReleaseSpinLock(&CurrentIsr->Lock);
601 KeLowerIrql(oldlvl);
602
603 KeDumpIrqList();
604
605 KeRevertToUserAffinityThread();
606
607 return Result;
608 }
609
610 /*
611 * @implemented
612 *
613 * FUNCTION: Releases a drivers isr
614 * ARGUMENTS:
615 * InterruptObject = isr to release
616 */
617 BOOLEAN
618 STDCALL
619 KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
620 {
621 KIRQL oldlvl,synch_oldlvl;
622 PISR_TABLE CurrentIsr;
623 BOOLEAN State;
624
625 DPRINT1("KeDisconnectInterrupt\n");
626 ASSERT (InterruptObject->Number < KeNumberProcessors);
627
628 /* Set the affinity */
629 KeSetSystemAffinityThread(1 << InterruptObject->Number);
630
631 /* Get the ISR Tabe */
632 CurrentIsr = &IsrTable[InterruptObject->Vector]
633 [(ULONG)InterruptObject->Number];
634
635 /* Raise IRQL to required level and lock table */
636 KeRaiseIrql(InterruptObject->Vector,&oldlvl);
637 KiAcquireSpinLock(&CurrentIsr->Lock);
638
639 /* Check if it's actually connected */
640 if ((State = InterruptObject->Connected))
641 {
642 /* Lock the Interrupt */
643 synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
644
645 /* Remove this one, and check if all are gone */
646 RemoveEntryList(&InterruptObject->InterruptListEntry);
647 if (IsListEmpty(&CurrentIsr->ListHead))
648 {
649 /* Completely Disable the Interrupt */
650 HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql);
651 }
652
653 /* Disconnect it */
654 InterruptObject->Connected = FALSE;
655
656 /* Release the interrupt lock */
657 KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
658 }
659 /* Release the table spinlock */
660 KiReleaseSpinLock(&CurrentIsr->Lock);
661 KeLowerIrql(oldlvl);
662
663 /* Go back to default affinity */
664 KeRevertToUserAffinityThread();
665
666 /* Return Old Interrupt State */
667 return State;
668 }
669
670 /*
671 * @implemented
672 */
673 VOID
674 STDCALL
675 KeInitializeInterrupt(PKINTERRUPT Interrupt,
676 PKSERVICE_ROUTINE ServiceRoutine,
677 PVOID ServiceContext,
678 PKSPIN_LOCK SpinLock,
679 ULONG Vector,
680 KIRQL Irql,
681 KIRQL SynchronizeIrql,
682 KINTERRUPT_MODE InterruptMode,
683 BOOLEAN ShareVector,
684 CHAR ProcessorNumber,
685 BOOLEAN FloatingSave)
686 {
687 /* Set the Interrupt Header */
688 Interrupt->Type = InterruptObject;
689 Interrupt->Size = sizeof(KINTERRUPT);
690
691 /* Check if we got a spinlock */
692 if (SpinLock)
693 {
694 Interrupt->ActualLock = SpinLock;
695 }
696 else
697 {
698 /* This means we'll be usin the built-in one */
699 KeInitializeSpinLock(&Interrupt->SpinLock);
700 Interrupt->ActualLock = &Interrupt->SpinLock;
701 }
702
703 /* Set the other settings */
704 Interrupt->ServiceRoutine = ServiceRoutine;
705 Interrupt->ServiceContext = ServiceContext;
706 Interrupt->Vector = Vector;
707 Interrupt->Irql = Irql;
708 Interrupt->SynchronizeIrql = SynchronizeIrql;
709 Interrupt->Mode = InterruptMode;
710 Interrupt->ShareVector = ShareVector;
711 Interrupt->Number = ProcessorNumber;
712 Interrupt->FloatingSave = FloatingSave;
713
714 /* Disconnect it at first */
715 Interrupt->Connected = FALSE;
716 }
717
718 VOID KePrintInterruptStatistic(VOID)
719 {
720 LONG i, j;
721
722 for (j = 0; j < KeNumberProcessors; j++)
723 {
724 DPRINT1("CPU%d:\n", j);
725 for (i = 0; i < NR_TRAPS; i++)
726 {
727 if (IsrTable[i][j].Count)
728 {
729 DPRINT1(" Irq %x(%d): %d\n", i, i, IsrTable[i][j].Count);
730 }
731 }
732 }
733 }
734
735 BOOLEAN
736 NTAPI
737 KeDisableInterrupts(VOID)
738 {
739 ULONG Flags = 0;
740 BOOLEAN Return;
741
742 Flags = __readmsr();
743 Return = (Flags & 0x8000) ? TRUE: FALSE;
744
745 /* Disable interrupts */
746 _disable();
747 return Return;
748 }
749
750 ULONG
751 NTAPI
752 KdpServiceDispatcher(ULONG Service, PCHAR Buffer, ULONG Length);
753
754 VOID
755 NTAPI
756 KiSystemService(ppc_trap_frame_t *trap_frame)
757 {
758 int i;
759 PKSYSTEM_ROUTINE SystemRoutine;
760
761 switch(trap_frame->gpr[8])
762 {
763 case 0x10000: /* DebugService */
764 for( i = 0; i < trap_frame->gpr[5]; i++ )
765 {
766 PearPCDebug(((PCHAR)trap_frame->gpr[4])[i]);
767 WRITE_PORT_UCHAR((PVOID)0x800003f8, ((PCHAR)trap_frame->gpr[4])[i]);
768 }
769 trap_frame->gpr[3] = KdpServiceDispatcher
770 (trap_frame->gpr[3],
771 (PCHAR)trap_frame->gpr[4],
772 trap_frame->gpr[5]);
773 break;
774 case 0xf0000: /* Thread startup */
775 /* XXX how to use UserThread (gpr[6]) */
776 SystemRoutine = (PKSYSTEM_ROUTINE)trap_frame->gpr[3];
777 SystemRoutine((PKSTART_ROUTINE)trap_frame->gpr[4],
778 (PVOID)trap_frame->gpr[5]);
779 break;
780 }
781 }
782
783 /* EOF */