- NtUserWaitForInputIdle: Call EngGetTickCount, removing duplicated code
[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 <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 NTAPI
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 NTAPI
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 /* Queue a DPC that will expire timers */
353 KeInsertQueueDpc(&KiExpireTimerDpc, 0, 0);
354 }
355
356 /* Update process and thread times */
357 if (OldOffset <= 0)
358 {
359 /* This was a tick, calculate the next one */
360 KiTickOffset += KeMaximumIncrement;
361 KeUpdateRunTime(TrapFrame, Irql);
362 }
363 }
364
365 VOID NTAPI
366 KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
367 /*
368 * FUNCTION: Calls all the interrupt handlers for a given irq.
369 * ARGUMENTS:
370 * vector - The number of the vector to call handlers for.
371 * old_level - The irql of the processor when the irq took place.
372 * NOTES: Must be called at DIRQL.
373 */
374 {
375 PKINTERRUPT isr;
376 PLIST_ENTRY current;
377 KIRQL oldlvl;
378 PISR_TABLE CurrentIsr;
379
380 DPRINT("I(0x%.08x, 0x%.08x)\n", vector, old_level);
381
382 /*
383 * Iterate the list until one of the isr tells us its device interrupted
384 */
385 CurrentIsr = &IsrTable[vector][(ULONG)KeGetCurrentProcessorNumber()];
386
387 KiAcquireSpinLock(&CurrentIsr->Lock);
388
389 CurrentIsr->Count++;
390 current = CurrentIsr->ListHead.Flink;
391
392 while (current != &CurrentIsr->ListHead)
393 {
394 isr = CONTAINING_RECORD(current,KINTERRUPT,InterruptListEntry);
395 oldlvl = KeAcquireInterruptSpinLock(isr);
396 if (isr->ServiceRoutine(isr, isr->ServiceContext))
397 {
398 KeReleaseInterruptSpinLock(isr, oldlvl);
399 break;
400 }
401 KeReleaseInterruptSpinLock(isr, oldlvl);
402 current = current->Flink;
403 }
404 KiReleaseSpinLock(&CurrentIsr->Lock);
405 }
406
407 VOID
408 KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
409 /*
410 * FUNCTION: Calls the irq specific handler for an irq
411 * ARGUMENTS:
412 * irq = IRQ that has interrupted
413 */
414 {
415 KIRQL old_level;
416 KTRAP_FRAME KernelTrapFrame;
417 PKTHREAD CurrentThread;
418 PKTRAP_FRAME OldTrapFrame=NULL;
419
420 /*
421 * At this point we have interrupts disabled, nothing has been done to
422 * the PIC.
423 */
424
425 KeGetCurrentPrcb()->InterruptCount++;
426
427 /*
428 * Notify the rest of the kernel of the raised irq level. For the
429 * default HAL this will send an EOI to the PIC and alter the IRQL.
430 */
431 if (!HalBeginSystemInterrupt (vector,
432 vector,
433 &old_level))
434 {
435 return;
436 }
437
438
439 /*
440 * Enable interrupts
441 * NOTE: Only higher priority interrupts will get through
442 */
443 _enable();
444
445 #ifndef CONFIG_SMP
446 if (vector == 0)
447 {
448 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
449 KeUpdateSystemTime(&KernelTrapFrame, old_level, 100000);
450 }
451 else
452 #endif
453 {
454 /*
455 * Actually call the ISR.
456 */
457 KiInterruptDispatch2(vector, old_level);
458 }
459
460 /*
461 * End the system interrupt.
462 */
463 _disable();
464
465 if (old_level==PASSIVE_LEVEL)
466 {
467 HalEndSystemInterrupt (APC_LEVEL, 0);
468
469 CurrentThread = KeGetCurrentThread();
470 if (CurrentThread!=NULL && CurrentThread->ApcState.UserApcPending)
471 {
472 if (CurrentThread->TrapFrame == NULL)
473 {
474 OldTrapFrame = CurrentThread->TrapFrame;
475 KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
476 CurrentThread->TrapFrame = &KernelTrapFrame;
477 }
478
479 _enable();
480 KiDeliverApc(UserMode, NULL, NULL);
481 _disable();
482
483 ASSERT(KeGetCurrentThread() == CurrentThread);
484 if (CurrentThread->TrapFrame == &KernelTrapFrame)
485 {
486 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame, Trapframe);
487 CurrentThread->TrapFrame = OldTrapFrame;
488 }
489 }
490 KeLowerIrql(PASSIVE_LEVEL);
491 }
492 else
493 {
494 HalEndSystemInterrupt (old_level, 0);
495 }
496
497 }
498
499 static VOID
500 KeDumpIrqList(VOID)
501 {
502 PKINTERRUPT current;
503 PLIST_ENTRY current_entry;
504 LONG i, j;
505 KIRQL oldlvl;
506 BOOLEAN printed;
507
508 for (i=0;i<NR_TRAPS;i++)
509 {
510 printed = FALSE;
511 KeRaiseIrql(i,&oldlvl);
512
513 for (j=0; j < KeNumberProcessors; j++)
514 {
515 KiAcquireSpinLock(&IsrTable[i][j].Lock);
516
517 current_entry = IsrTable[i][j].ListHead.Flink;
518 current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
519 while (current_entry!=&(IsrTable[i][j].ListHead))
520 {
521 if (printed == FALSE)
522 {
523 printed = TRUE;
524 DPRINT("For irq %x:\n",i);
525 }
526 DPRINT(" Isr %x\n",current);
527 current_entry = current_entry->Flink;
528 current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
529 }
530 KiReleaseSpinLock(&IsrTable[i][j].Lock);
531 }
532 KeLowerIrql(oldlvl);
533 }
534 }
535
536 /*
537 * @implemented
538 */
539 BOOLEAN
540 NTAPI
541 KeConnectInterrupt(PKINTERRUPT InterruptObject)
542 {
543 KIRQL oldlvl,synch_oldlvl;
544 PKINTERRUPT ListHead;
545 ULONG Vector;
546 PISR_TABLE CurrentIsr;
547 BOOLEAN Result;
548
549 DPRINT("KeConnectInterrupt()\n");
550
551 Vector = InterruptObject->Vector;
552
553 if (Vector < 0 || Vector >= NR_TRAPS)
554 return FALSE;
555
556 ASSERT (InterruptObject->Number < KeNumberProcessors);
557
558 KeSetSystemAffinityThread(1 << InterruptObject->Number);
559
560 CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number];
561
562 KeRaiseIrql(Vector,&oldlvl);
563 KiAcquireSpinLock(&CurrentIsr->Lock);
564
565 /*
566 * Check if the vector is already in use that we can share it
567 */
568 if (!IsListEmpty(&CurrentIsr->ListHead))
569 {
570 ListHead = CONTAINING_RECORD(CurrentIsr->ListHead.Flink,KINTERRUPT,InterruptListEntry);
571 if (InterruptObject->ShareVector == FALSE || ListHead->ShareVector==FALSE)
572 {
573 KiReleaseSpinLock(&CurrentIsr->Lock);
574 KeLowerIrql(oldlvl);
575 KeRevertToUserAffinityThread();
576 return FALSE;
577 }
578 }
579
580 synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
581
582 DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink);
583
584 Result = HalEnableSystemInterrupt(Vector, InterruptObject->Irql, InterruptObject->Mode);
585 if (Result)
586 {
587 InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry);
588 DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->InterruptListEntry.Blink);
589 }
590
591 InterruptObject->Connected = TRUE;
592 KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
593
594 /*
595 * Release the table spinlock
596 */
597 KiReleaseSpinLock(&CurrentIsr->Lock);
598 KeLowerIrql(oldlvl);
599
600 KeDumpIrqList();
601
602 KeRevertToUserAffinityThread();
603
604 return Result;
605 }
606
607 /*
608 * @implemented
609 *
610 * FUNCTION: Releases a drivers isr
611 * ARGUMENTS:
612 * InterruptObject = isr to release
613 */
614 BOOLEAN
615 NTAPI
616 KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
617 {
618 KIRQL oldlvl,synch_oldlvl;
619 PISR_TABLE CurrentIsr;
620 BOOLEAN State;
621
622 DPRINT1("KeDisconnectInterrupt\n");
623 ASSERT (InterruptObject->Number < KeNumberProcessors);
624
625 /* Set the affinity */
626 KeSetSystemAffinityThread(1 << InterruptObject->Number);
627
628 /* Get the ISR Tabe */
629 CurrentIsr = &IsrTable[InterruptObject->Vector]
630 [(ULONG)InterruptObject->Number];
631
632 /* Raise IRQL to required level and lock table */
633 KeRaiseIrql(InterruptObject->Vector,&oldlvl);
634 KiAcquireSpinLock(&CurrentIsr->Lock);
635
636 /* Check if it's actually connected */
637 if ((State = InterruptObject->Connected))
638 {
639 /* Lock the Interrupt */
640 synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
641
642 /* Remove this one, and check if all are gone */
643 RemoveEntryList(&InterruptObject->InterruptListEntry);
644 if (IsListEmpty(&CurrentIsr->ListHead))
645 {
646 /* Completely Disable the Interrupt */
647 HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql);
648 }
649
650 /* Disconnect it */
651 InterruptObject->Connected = FALSE;
652
653 /* Release the interrupt lock */
654 KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
655 }
656 /* Release the table spinlock */
657 KiReleaseSpinLock(&CurrentIsr->Lock);
658 KeLowerIrql(oldlvl);
659
660 /* Go back to default affinity */
661 KeRevertToUserAffinityThread();
662
663 /* Return Old Interrupt State */
664 return State;
665 }
666
667 /*
668 * @implemented
669 */
670 VOID
671 NTAPI
672 KeInitializeInterrupt(PKINTERRUPT Interrupt,
673 PKSERVICE_ROUTINE ServiceRoutine,
674 PVOID ServiceContext,
675 PKSPIN_LOCK SpinLock,
676 ULONG Vector,
677 KIRQL Irql,
678 KIRQL SynchronizeIrql,
679 KINTERRUPT_MODE InterruptMode,
680 BOOLEAN ShareVector,
681 CHAR ProcessorNumber,
682 BOOLEAN FloatingSave)
683 {
684 /* Set the Interrupt Header */
685 Interrupt->Type = InterruptObject;
686 Interrupt->Size = sizeof(KINTERRUPT);
687
688 /* Check if we got a spinlock */
689 if (SpinLock)
690 {
691 Interrupt->ActualLock = SpinLock;
692 }
693 else
694 {
695 /* This means we'll be usin the built-in one */
696 KeInitializeSpinLock(&Interrupt->SpinLock);
697 Interrupt->ActualLock = &Interrupt->SpinLock;
698 }
699
700 /* Set the other settings */
701 Interrupt->ServiceRoutine = ServiceRoutine;
702 Interrupt->ServiceContext = ServiceContext;
703 Interrupt->Vector = Vector;
704 Interrupt->Irql = Irql;
705 Interrupt->SynchronizeIrql = SynchronizeIrql;
706 Interrupt->Mode = InterruptMode;
707 Interrupt->ShareVector = ShareVector;
708 Interrupt->Number = ProcessorNumber;
709 Interrupt->FloatingSave = FloatingSave;
710
711 /* Disconnect it at first */
712 Interrupt->Connected = FALSE;
713 }
714
715 VOID KePrintInterruptStatistic(VOID)
716 {
717 LONG i, j;
718
719 for (j = 0; j < KeNumberProcessors; j++)
720 {
721 DPRINT1("CPU%d:\n", j);
722 for (i = 0; i < NR_TRAPS; i++)
723 {
724 if (IsrTable[i][j].Count)
725 {
726 DPRINT1(" Irq %x(%d): %d\n", i, i, IsrTable[i][j].Count);
727 }
728 }
729 }
730 }
731
732 BOOLEAN
733 NTAPI
734 KeDisableInterrupts(VOID)
735 {
736 ULONG Flags = 0;
737 BOOLEAN Return;
738
739 Flags = __readmsr();
740 Return = (Flags & 0x8000) ? TRUE: FALSE;
741
742 /* Disable interrupts */
743 _disable();
744 return Return;
745 }
746
747 ULONG
748 NTAPI
749 KdpServiceDispatcher(ULONG Service, PCHAR Buffer, ULONG Length);
750
751 typedef ULONG (*PSYSCALL_FUN)
752 (ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG);
753
754 VOID
755 NTAPI
756 KiSystemService(ppc_trap_frame_t *trap_frame)
757 {
758 int i;
759 PKSYSTEM_ROUTINE SystemRoutine;
760 PSYSCALL_FUN SyscallFunction;
761
762 switch(trap_frame->gpr[0])
763 {
764 case 0x10000: /* DebugService */
765 for( i = 0; i < trap_frame->gpr[5]; i++ )
766 {
767 PearPCDebug(((PCHAR)trap_frame->gpr[4])[i]);
768 WRITE_PORT_UCHAR((PVOID)0x800003f8, ((PCHAR)trap_frame->gpr[4])[i]);
769 }
770 trap_frame->gpr[3] = KdpServiceDispatcher
771 (trap_frame->gpr[3],
772 (PCHAR)trap_frame->gpr[4],
773 trap_frame->gpr[5]);
774 break;
775 case 0xf0000: /* Thread startup */
776 /* XXX how to use UserThread (gpr[6]) */
777 SystemRoutine = (PKSYSTEM_ROUTINE)trap_frame->gpr[3];
778 SystemRoutine((PKSTART_ROUTINE)trap_frame->gpr[4],
779 (PVOID)trap_frame->gpr[5]);
780 break;
781
782 /* Handle a normal system call */
783 default:
784 SyscallFunction =
785 ((PSYSCALL_FUN*)KeServiceDescriptorTable
786 [trap_frame->gpr[0] >> 12].Base)[trap_frame->gpr[0] & 0xfff];
787 trap_frame->gpr[3] = SyscallFunction
788 (trap_frame->gpr[3],
789 trap_frame->gpr[4],
790 trap_frame->gpr[5],
791 trap_frame->gpr[6],
792 trap_frame->gpr[7],
793 trap_frame->gpr[8],
794 trap_frame->gpr[9],
795 trap_frame->gpr[10],
796 trap_frame->gpr[11],
797 trap_frame->gpr[12]);
798 break;
799 }
800 }
801
802 /* EOF */