- Rewrite the low-level trap/exception/system call code from the ground up:

- Do not corrupt the stack anymore
  - Use a consistent trap frame layout (enable OldIrql and PreviousMode, and set the 0xBADB0D00 debug mark)
  - Use slower but more correct trap prolog/epilog code for now.
  - Generalize all prolog/epilog code into macros just like on x86. As a result, traps are now 6 lines of code.
- Rewrite the system call interface from the ground up:
  - System calls didn't actually work: a debug print made the stack layout magical enough so that they didn't normally crush, but only slowly ate the stack.
  - Copying arguments from caller to system call was, as the comment on the original code so aptly put it, "total shit".
  - Due to ABI concerns, and to provide an actual template on how you're -supposed- to implement something like system calls on RISC processors, we now use
    a model similar to BSD, but about ten times better (with that much less code too). We'll document it later on the RosPSG Wiki.
  - This code probably contains some of the most vile-yet-elegant macro magic ever written for such low-level code as system call dispatching. 
- The result of all this is that we're at the same place as before (RamdiskAddDevice needs to be implemented by the Ramdisk guys) but with a sane low-level
  backend that isn't slowly eating away the stack, corrupting data, and basically working through random chance.
- Move timebase code from stubs.c to its own file, time.c.
- Silence multiple debug prints and fix a corrupted debug print in KiSystemStartup.


svn path=/trunk/; revision=34366
This commit is contained in:
ReactOS Portable Systems Group 2008-07-08 09:11:44 +00:00
parent 8249e5ced9
commit b513c98fb2
12 changed files with 846 additions and 782 deletions

View file

@ -759,7 +759,6 @@ HalRequestSoftwareInterrupt(IN KIRQL Request)
//
// Force a software interrupt
//
DPRINT1("[SOFTINT]: %d\n", Request);
WRITE_REGISTER_ULONG(VIC_SOFT_INT, 1 << Request);
}
@ -768,9 +767,8 @@ FASTCALL
HalClearSoftwareInterrupt(IN KIRQL Request)
{
//
// Force a software interrupt
// Clear a software interrupt
//
DPRINT1("[SOFTINTC] %d\n", Request);
WRITE_REGISTER_ULONG(VIC_SOFT_INT_CLEAR, 1 << Request);
}

View file

@ -59,13 +59,11 @@ Author:
//
typedef struct _KTRAP_FRAME
{
ULONG OldIrql;
// UCHAR PreviousMode;
// ULONG Fpscr;
// ULONG FpExc;
// ULONG S[33];
// ULONG FpExtra[8];
ULONG Spsr;
// ULONG FpExtra[8];
ULONG DbgArgMark;
ULONG R0;
ULONG R1;
ULONG R2;
@ -84,6 +82,9 @@ typedef struct _KTRAP_FRAME
ULONG SvcSp;
ULONG SvcLr;
ULONG Pc;
ULONG Spsr;
ULONG OldIrql;
ULONG PreviousMode;
} KTRAP_FRAME, *PKTRAP_FRAME;
#ifndef NTOS_MODE_USER

View file

@ -42,8 +42,27 @@
/*
* Trap Frame offsets
*/
.equ TrR0, 0x00
.equ TrapFrameLength, 0x144
.equ TrDbgArgMark, 0x00
.equ TrR0, 0x04
.equ TrR1, 0x08
.equ TrR2, 0x0C
.equ TrR3, 0x10
.equ TrR4, 0x14
.equ TrR5, 0x18
.equ TrR6, 0x1C
.equ TrR7, 0x20
.equ TrR8, 0x24
.equ TrR9, 0x28
.equ TrR10, 0x2C
.equ TrR11, 0x30
.equ TrR12, 0x34
.equ TrUserSp, 0x38
.equ TrUserLr, 0x3C
.equ TrSvcSp, 0x40
.equ TrSvcLr, 0x44
.equ TrPc, 0x48
.equ TrSpsr, 0x4C
.equ TrapFrameLength, (22 * 0x04)
/*
* PCR

View file

@ -19,3 +19,171 @@
end_&Name:
.endfunc
.endm
.macro TRAP_PROLOG Abort
//
// Fixup lr
//
.if \Abort
sub lr, lr, #8
.else
sub lr, lr, #4
.endif
//
// Save the bottom 4 registers
//
stmdb sp, {r0-r3}
//
// Save the abort lr, sp, spsr, cpsr
//
mov r0, lr
mov r1, sp
mrs r2, cpsr
mrs r3, spsr
//
// Switch to SVC mode
//
bic r2, r2, #CPSR_MODES
orr r2, r2, #CPSR_SVC_MODE
msr cpsr_c, r2
//
// Save the SVC sp before we modify it
//
mov r2, sp
//
// Make space for the trap frame
//
sub sp, sp, #TrapFrameLength
//
// Save abt32 state
//
str r0, [sp, #TrPc]
str lr, [sp, #TrSvcLr]
str r2, [sp, #TrSvcSp]
//
// Restore the saved SPSR
//
msr spsr_all, r3
//
// Restore our 4 registers
//
ldmdb r1, {r0-r3}
//
// Build trap frame
// FIXME: Change to stmdb later
//
str r0, [sp, #TrR0]
str r1, [sp, #TrR1]
str r2, [sp, #TrR2]
str r3, [sp, #TrR3]
str r4, [sp, #TrR4]
str r5, [sp, #TrR5]
str r6, [sp, #TrR6]
str r7, [sp, #TrR7]
str r8, [sp, #TrR8]
str r9, [sp, #TrR9]
str r10, [sp, #TrR10]
str r11, [sp, #TrR11]
str r12, [sp, #TrR12]
mov r12, sp
add r12, r12, #TrUserSp
stm r12, {sp, lr}^
mrs r0, spsr_all
str r0, [sp, #TrSpsr]
ldr r0, =0xBADB0D00
str r0, [sp, #TrDbgArgMark]
.endm
.macro SYSCALL_PROLOG
//
// Make space for the trap frame
//
sub sp, sp, #TrapFrameLength
//
// Build trap frame
// FIXME: Change to stmdb later
//
str r0, [sp, #TrR0]
str r1, [sp, #TrR1]
str r2, [sp, #TrR2]
str r3, [sp, #TrR3]
str r4, [sp, #TrR4]
str r5, [sp, #TrR5]
str r6, [sp, #TrR6]
str r7, [sp, #TrR7]
str r8, [sp, #TrR8]
str r9, [sp, #TrR9]
str r10, [sp, #TrR10]
str r11, [sp, #TrR11]
str r12, [sp, #TrR12]
mov r12, sp
add r12, r12, #TrUserSp
stm r12, {sp, lr}^
str sp, [sp, #TrSvcSp]
str lr, [sp, #TrPc]
mrs r0, spsr_all
str r0, [sp, #TrSpsr]
ldr r0, =0xBADB0D00
str r0, [sp, #TrDbgArgMark]
.endm
.macro TRAP_EPILOG SystemCall
//
// ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00)
//
ldr r0, [sp, #TrDbgArgMark]
ldr r1, =0xBADB0D00
cmp r0, r1
bne 1f
//
// Get the SPSR and restore it
//
ldr r0, [sp, #TrSpsr]
msr spsr_all, r0
//
// Restore the registers
// FIXME: Use LDMIA later
//
mov r0, sp
add r0, r0, #TrUserSp
ldm r0, {sp, lr}^
ldr r0, [sp, #TrR0]
ldr r1, [sp, #TrR1]
ldr r2, [sp, #TrR2]
ldr r3, [sp, #TrR3]
ldr r4, [sp, #TrR4]
ldr r5, [sp, #TrR5]
ldr r6, [sp, #TrR6]
ldr r7, [sp, #TrR7]
ldr r8, [sp, #TrR8]
ldr r9, [sp, #TrR9]
ldr r10, [sp, #TrR10]
ldr r11, [sp, #TrR11]
ldr r12, [sp, #TrR12]
//
// Restore program execution state
//
.if \SystemCall
ldr lr, [sp, #TrPc]
add sp, sp, #TrapFrameLength
movs pc, lr
.else
add sp, sp, #TrSvcSp
ldmia sp, {sp, lr, pc}^
.endif
1:
b .
.endm

View file

@ -0,0 +1,104 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/arm/ke_i.h
* PURPOSE: Implements macro-generated system call portable wrappers
* PROGRAMMERS: ReactOS Portable Systems Group
*/
//
// First, cleanup after any previous invocation
//
#undef _1
#undef _2
#undef _3
#undef _4
#undef _5
#undef _6
#undef _7
#undef _8
#undef _9
#undef a
#undef b
#undef c
#undef d
#undef e
#undef f
#undef _10
#undef _11
#undef SYSCALL
//
// Are we building the typedef prototypes?
//
#ifdef PROTO
//
// Then, each parameter is actually a prototype argument
//
#define _1 PVOID
#define _2 PVOID
#define _3 PVOID
#define _4 PVOID
#define _5 PVOID
#define _6 PVOID
#define _7 PVOID
#define _8 PVOID
#define _9 PVOID
#define a PVOID
#define b PVOID
#define c PVOID
#define d PVOID
#define e PVOID
#define f PVOID
#define _10 PVOID
#define _11 PVOID
//
// And we generate the typedef
//
#define SYSCALL(x, y) typedef NTSTATUS (*PKI_SYSCALL_##x##PARAM)y;
//
// Cleanup for next run
//
#undef PROTO
#else
//
// Each parameter is actually an argument for the system call
//
#define _1 g[0x00]
#define _2 g[0x01]
#define _3 g[0x02]
#define _4 g[0x03]
#define _5 g[0x04]
#define _6 g[0x05]
#define _7 g[0x06]
#define _8 g[0x07]
#define _9 g[0x08]
#define a g[0x09]
#define b g[0x0A]
#define c g[0x0B]
#define d g[0x0C]
#define e g[0x0D]
#define f g[0x0E]
#define _10 g[0x0F]
#define _11 g[0x10]
//
// And we generate the actual system call
//
#define SYSCALL(x, y) \
NTSTATUS \
KiSyscall##x##Param( \
IN PVOID p, \
IN PVOID *g \
) \
{ \
return ((PKI_SYSCALL_##x##PARAM)p)y; \
}
//
// Cleanup for next run
//
#undef FUNC
#endif

View file

@ -80,7 +80,7 @@ KiInitializeKernel(IN PKPROCESS InitProcess,
PKPCR Pcr;
ULONG i;
DPRINT1("[INIT] Process: %p Thread: %p Stack: %p PRCB: %p Number: %d LoaderBlock: %p\n",
__FUNCTION__, InitProcess, InitThread, IdleStack, Prcb, Number, LoaderBlock);
InitProcess, InitThread, IdleStack, Prcb, Number, LoaderBlock);
//
// Initialize the platform

View file

@ -9,284 +9,3 @@ ULONG KeProcessorArchitecture;
ULONG KeProcessorLevel;
ULONG KeProcessorRevision;
ULONG KeFeatureBits;
extern LONG KiTickOffset;
extern ULONG KeTimeAdjustment;
ULONG
KiComputeTimerTableIndex(IN LONGLONG DueTime)
{
ULONG Hand;
DPRINT1("DueTime: %I64x Max: %lx\n", DueTime, KeMaximumIncrement);
//
// Compute the timer table index
//
Hand = (DueTime / KeMaximumIncrement);
DPRINT1("HAND: %lx\n", Hand);
Hand %= TIMER_TABLE_SIZE;
DPRINT1("HAND: %lx\n", Hand);
return Hand;
}
VOID
NTAPI
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql,
IN ULONG Increment)
{
PKPRCB Prcb = KeGetPcr()->Prcb;
ULARGE_INTEGER SystemTime, InterruptTime;
ULONG Hand;
//
// Do nothing if this tick is being skipped
//
if (Prcb->SkipTick)
{
//
// Handle it next time
//
Prcb->SkipTick = FALSE;
return;
}
//
// Add the increment time to the shared data
//
InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
InterruptTime.QuadPart += Increment;
SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
//
// Update tick count
//
KiTickOffset -= Increment;
//
// Check for incomplete tick
//
if (KiTickOffset <= 0)
{
//
// Update the system time
//
SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
SystemTime.QuadPart += KeTimeAdjustment;
SharedUserData->SystemTime.High1Time = SystemTime.HighPart;
SharedUserData->SystemTime.LowPart = SystemTime.LowPart;
SharedUserData->SystemTime.High2Time = SystemTime.HighPart;
//
// Update the tick count
//
SystemTime.HighPart = KeTickCount.High1Time;
SystemTime.LowPart = KeTickCount.LowPart;
SystemTime.QuadPart += 1;
KeTickCount.High1Time = SystemTime.HighPart;
KeTickCount.LowPart = SystemTime.LowPart;
KeTickCount.High2Time = SystemTime.HighPart;
//
// Update it in the shared user data
//
SharedUserData->TickCount.High1Time = SystemTime.HighPart;
SharedUserData->TickCount.LowPart = SystemTime.LowPart;
SharedUserData->TickCount.High2Time = SystemTime.HighPart;
}
//
// Check for timer expiration
//
Hand = KeTickCount.LowPart % TIMER_TABLE_SIZE;
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
{
//
// Timer has expired!
//
DPRINT1("hand: %d\n", Hand);
DPRINT1("Interrupt time: %I64x\n", InterruptTime.QuadPart);
DPRINT1("TIMER EXPIRATION: %I64x!!!\n", KiTimerTableListHead[Hand].Time.QuadPart);
while (TRUE);
}
//
// Check if we should request a debugger break
//
if (KdDebuggerEnabled)
{
//
// Check if we should break
//
if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
}
//
// Check if this was a full tick
//
if (KiTickOffset <= 0)
{
//
// Updare the tick offset
//
KiTickOffset += KeMaximumIncrement;
//
// Update system runtime
//
KeUpdateRunTime(TrapFrame, CLOCK2_LEVEL);
}
else
{
//
// Increase interrupt count and exit
//
Prcb->InterruptCount++;
}
}
VOID
NTAPI
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql)
{
PKTHREAD Thread = KeGetCurrentThread();
PKPROCESS Process = Thread->ApcState.Process;
PKPRCB Prcb = KeGetCurrentPrcb();
//
// Do nothing if this tick is being skipped
//
if (Prcb->SkipTick)
{
//
// Handle it next time
//
Prcb->SkipTick = FALSE;
return;
}
//
// Increase interrupt count
//
Prcb->InterruptCount++;
//
// Check if we came from user mode
//
if (0) //(TrapFrame->PreviousMode != KernelMode)
{
//
// Increase process user time
//
InterlockedIncrement((PLONG)&Process->UserTime);
Prcb->UserTime++;
Thread->UserTime++;
}
else
{
//
// See if we were in an ISR
//
if (TrapFrame->OldIrql > DISPATCH_LEVEL)
{
//
// Handle that
//
Prcb->InterruptTime++;
}
else if ((TrapFrame->OldIrql < DISPATCH_LEVEL) ||
!(Prcb->DpcRoutineActive))
{
//
// Handle being in kernel mode
//
Thread->KernelTime++;
InterlockedIncrement((PLONG)&Process->KernelTime);
}
else
{
//
// Handle being in a DPC
//
Prcb->DpcTime++;
//
// FIXME: Handle DPC checks
//
}
}
//
// Update DPC rates
//
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
Prcb->DpcRequestRate) >> 1;
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
//
// Check if the queue is large enough
//
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
{
//
// Request a DPC
//
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
//
// Fix the maximum queue depth
//
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
(Prcb->MaximumDpcQueueDepth > 1))
{
//
// Make it smaller
//
Prcb->MaximumDpcQueueDepth--;
}
}
else
{
//
// Check if we've reached the adjustment limit
//
if (!(--Prcb->AdjustDpcThreshold))
{
//
// Reset it, and check the queue maximum
//
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
{
//
// Increase it
//
Prcb->MaximumDpcQueueDepth++;
}
}
}
//
// Decrement the thread quantum
//
Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
//
// Check if the time expired
//
if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
{
//
// Schedule a quantum end
//
Prcb->QuantumEnd = 1;
//HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}

View file

@ -0,0 +1,295 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/arm/time.c
* PURPOSE: Implements timebase functionality on ARM processors
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
LONG KiTickOffset;
ULONG KeTimeAdjustment;
/* FUNCTIONS ******************************************************************/
ULONG
KiComputeTimerTableIndex(IN LONGLONG DueTime)
{
ULONG Hand;
//
// Compute the timer table index
//
Hand = (DueTime / KeMaximumIncrement);
Hand %= TIMER_TABLE_SIZE;
return Hand;
}
VOID
NTAPI
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql,
IN ULONG Increment)
{
PKPRCB Prcb = KeGetPcr()->Prcb;
ULARGE_INTEGER SystemTime, InterruptTime;
ULONG Hand;
//
// Do nothing if this tick is being skipped
//
if (Prcb->SkipTick)
{
//
// Handle it next time
//
Prcb->SkipTick = FALSE;
return;
}
//
// Add the increment time to the shared data
//
InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
InterruptTime.QuadPart += Increment;
SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
//
// Update tick count
//
KiTickOffset -= Increment;
//
// Check for incomplete tick
//
if (KiTickOffset <= 0)
{
//
// Update the system time
//
SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
SystemTime.QuadPart += KeTimeAdjustment;
SharedUserData->SystemTime.High1Time = SystemTime.HighPart;
SharedUserData->SystemTime.LowPart = SystemTime.LowPart;
SharedUserData->SystemTime.High2Time = SystemTime.HighPart;
//
// Update the tick count
//
SystemTime.HighPart = KeTickCount.High1Time;
SystemTime.LowPart = KeTickCount.LowPart;
SystemTime.QuadPart += 1;
KeTickCount.High1Time = SystemTime.HighPart;
KeTickCount.LowPart = SystemTime.LowPart;
KeTickCount.High2Time = SystemTime.HighPart;
//
// Update it in the shared user data
//
SharedUserData->TickCount.High1Time = SystemTime.HighPart;
SharedUserData->TickCount.LowPart = SystemTime.LowPart;
SharedUserData->TickCount.High2Time = SystemTime.HighPart;
}
//
// Check for timer expiration
//
Hand = KeTickCount.LowPart % TIMER_TABLE_SIZE;
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
{
//
// Timer has expired!
//
DPRINT1("hand: %d\n", Hand);
DPRINT1("Interrupt time: %I64x\n", InterruptTime.QuadPart);
DPRINT1("TIMER EXPIRATION: %I64x!!!\n",
KiTimerTableListHead[Hand].Time.QuadPart);
while (TRUE);
}
//
// Check if we should request a debugger break
//
if (KdDebuggerEnabled)
{
//
// Check if we should break
//
if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
}
//
// Check if this was a full tick
//
if (KiTickOffset <= 0)
{
//
// Updare the tick offset
//
KiTickOffset += KeMaximumIncrement;
//
// Update system runtime
//
KeUpdateRunTime(TrapFrame, CLOCK2_LEVEL);
}
else
{
//
// Increase interrupt count and exit
//
Prcb->InterruptCount++;
}
}
VOID
NTAPI
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql)
{
PKTHREAD Thread = KeGetCurrentThread();
PKPROCESS Process = Thread->ApcState.Process;
PKPRCB Prcb = KeGetCurrentPrcb();
//
// Do nothing if this tick is being skipped
//
if (Prcb->SkipTick)
{
//
// Handle it next time
//
Prcb->SkipTick = FALSE;
return;
}
//
// Increase interrupt count
//
Prcb->InterruptCount++;
//
// Check if we came from user mode
//
if (0) //(TrapFrame->PreviousMode != KernelMode)
{
//
// Increase process user time
//
InterlockedIncrement((PLONG)&Process->UserTime);
Prcb->UserTime++;
Thread->UserTime++;
}
else
{
//
// See if we were in an ISR
//
if (TrapFrame->OldIrql > DISPATCH_LEVEL)
{
//
// Handle that
//
Prcb->InterruptTime++;
}
else if ((TrapFrame->OldIrql < DISPATCH_LEVEL) ||
!(Prcb->DpcRoutineActive))
{
//
// Handle being in kernel mode
//
Thread->KernelTime++;
InterlockedIncrement((PLONG)&Process->KernelTime);
}
else
{
//
// Handle being in a DPC
//
Prcb->DpcTime++;
//
// FIXME: Handle DPC checks
//
}
}
//
// Update DPC rates
//
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
Prcb->DpcRequestRate) >> 1;
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
//
// Check if the queue is large enough
//
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
{
//
// Request a DPC
//
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
//
// Fix the maximum queue depth
//
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
(Prcb->MaximumDpcQueueDepth > 1))
{
//
// Make it smaller
//
Prcb->MaximumDpcQueueDepth--;
}
}
else
{
//
// Check if we've reached the adjustment limit
//
if (!(--Prcb->AdjustDpcThreshold))
{
//
// Reset it, and check the queue maximum
//
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
{
//
// Increase it
//
Prcb->MaximumDpcQueueDepth++;
}
}
}
//
// Decrement the thread quantum
//
Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
//
// Check if the time expired
//
if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
{
//
// Schedule a quantum end
//
Prcb->QuantumEnd = 1;
//HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}

View file

@ -7,7 +7,7 @@
*/
.title "ARM Trap Dispatching and Handling"
.include "ntoskrnl/include/internal/arm/kxarm.h"
#include "ntoskrnl/include/internal/arm/kxarm.h"
.include "ntoskrnl/include/internal/arm/ksarm.h"
.global KiArmVectorTable
@ -28,7 +28,7 @@
_KiReservedJump: .word KiReservedException
_KiInterruptJump: .word KiInterruptException
_KiFastInterruptJump: .word KiFastInterruptException
TEXTAREA
NESTED_ENTRY KiUndefinedInstructionException
PROLOG_END KiUndefinedInstructionException
@ -42,76 +42,25 @@
NESTED_ENTRY KiSoftwareInterruptException
PROLOG_END KiSoftwareInterruptException
//
// Save the current lr
//
str lr, [sp, #-4]!
//
// Save the SVC lr and sp
//
str lr, [sp, #-4]!
str sp, [sp, #-4]!
//
// Make space for trap frame
// Handle trap entry
//
sub sp, sp, #(4*15)
//
// Save user-mode registers
//
stmia sp, {r0-r12}
add r0, sp, #(4*13)
stmia r0, {r13-r14}^
mov r0, r0
//
// Save SPSR
//
mrs r0, spsr_all
str r0, [sp, #-4]!
//
// Make space for IRQL
//
sub sp, sp, #4
SYSCALL_PROLOG
//
// Call the C handler
//
adr lr, 1f
mov r0, sp
bl KiSoftwareInterruptHandler
//
// Skip IRQL
//
add sp, sp, #(4)
ldr pc, =KiSoftwareInterruptHandler
1:
//
// Get the SPSR and restore it
//
ldr r0, [sp], #4
msr spsr_all, r0
// Handle trap exit
//
TRAP_EPILOG 1 // FromSystemCall
//
// Restore the registers
//
ldmia sp, {r0-r14}^
mov r0, r0
//
// Advance in the trap frame
//
add sp, sp, #(4*17)
//
// Restore program execution state
//
ldr lr, [sp], #4
movs pc, lr
b .
ENTRY_END KiSoftwareInterruptException
NESTED_ENTRY KiPrefetchAbortException
@ -128,233 +77,47 @@
PROLOG_END KiDataAbortException
//
// Fixup lr
// Handle trap entry
//
sub lr, lr, #8
TRAP_PROLOG 1 // FromAbort
//
// Save the bottom 4 registers
//
stmdb sp, {r0-r3}
//
// Save the abort lr, sp, spsr, cpsr
//
mov r0, lr
mov r1, sp
mrs r2, cpsr
mrs r3, spsr
//
// Switch to SVC mode
//
bic r2, r2, #CPSR_MODES
orr r2, r2, #CPSR_SVC_MODE
msr cpsr_c, r2
//
// Save the SVC sp before we modify it
//
mov r2, sp
//
// Save the abort lr
//
str r0, [sp, #-4]!
//
// Save the SVC lr and sp
//
str lr, [sp, #-4]!
str r2, [sp, #-4]!
//
// Restore the saved SPSR
//
msr spsr_all, r3
//
// Restore our 4 registers
//
ldmdb r1, {r0-r3}
//
// Make space for the trap frame
//
sub sp, sp, #(4*15) // TrapFrameLength
//
// Save user-mode registers
//
stmia sp, {r0-r12}
add r0, sp, #(4*13)
stmia r0, {r13-r14}^
mov r0, r0
//
// Save SPSR
//
mrs r0, spsr_all
str r0, [sp, #-4]!
//
// Make space for IRQL
//
sub sp, sp, #4
//
// Call the C handler
//
adr lr, AbortExit
adr lr, 1f
mov r0, sp
ldr pc, =KiDataAbortHandler
AbortExit:
1:
//
// Handle trap exit
//
TRAP_EPILOG 0 // NotFromSystemCall
//
// Skip IRQL
//
add sp, sp, #(4)
//
// Get the SPSR and restore it
//
ldr r0, [sp], #4
msr spsr_all, r0
//
// Restore the registers
//
ldmia sp, {r0-r14}^
mov r0, r0
//
// Advance in the trap frame
//
add sp, sp, #(4*15)
//
// Restore program execution state
//
ldmia sp, {sp, lr, pc}^
b .
ENTRY_END KiDataAbortException
NESTED_ENTRY KiInterruptException
PROLOG_END KiInterruptException
//
// Handle trap entry
//
TRAP_PROLOG 0 // NotFromAbort
//
// Fixup lr
//
sub lr, lr, #4
//
// Save the bottom 4 registers
//
stmdb sp, {r0-r3}
//
// Save the IRQ lr, sp, spsr, cpsr
//
mov r0, lr
mov r1, sp
mrs r2, cpsr
mrs r3, spsr
//
// Switch to SVC mode
//
bic r2, r2, #CPSR_MODES
orr r2, r2, #CPSR_SVC_MODE
msr cpsr_c, r2
//
// Save the SVC sp before we modify it
//
mov r2, sp
//
// Save the IRQ lr
//
str r0, [sp, #-4]!
//
// Save the SVC lr and sp
//
str lr, [sp, #-4]!
str r2, [sp, #-4]!
//
// Restore the saved SPSR
//
msr spsr_all, r3
//
// Restore our 4 registers
//
ldmdb r1, {r0-r3}
//
// Make space for the trap frame
//
sub sp, sp, #(4*15) // TrapFrameLength
//
// Save user-mode registers
//
stmia sp, {r0-r12}
add r0, sp, #(4*13)
stmia r0, {r13-r14}^
mov r0, r0
//
// Save SPSR
//
mrs r0, spsr_all
str r0, [sp, #-4]!
//
// Make space for IRQL
//
sub sp, sp, #4
//
// Call the C handler
//
adr lr, IntExit
adr lr, 1f
mov r0, sp
mov r1, #0
ldr pc, =KiInterruptHandler
IntExit:
1:
//
// Skip IRQL
//
add sp, sp, #(4)
//
// Get the SPSR and restore it
//
ldr r0, [sp], #4
msr spsr_all, r0
// Handle trap exit
//
TRAP_EPILOG 0 // NotFromSystemCall
//
// Restore the registers
//
ldmia sp, {r0-r14}^
mov r0, r0
//
// Advance in the trap frame
//
add sp, sp, #(4*15)
//
// Restore program execution state
//
ldmia sp, {sp, lr, pc}^
b .
ENTRY_END KiInterruptException
NESTED_ENTRY KiFastInterruptException
@ -377,85 +140,3 @@ IntExit:
b .
ENTRY_END KiReservedException
NESTED_ENTRY KiSystemCall
PROLOG_END KiSystemCall
//
// a1 has the function pointer, a2 has an array of arguments, a3 has the count
// Save these to better locations
//
mov r4, a1
mov r5, a2
mov r6, a3
//
// Load up A1-A4 from the argument array
// It doesn't matter if we had less than 4 arguments, we'll be loading some
// of the registers with garbage, but nobody will know/care.
//
ldmia r5, {a1-a4}
add r5, r5, #(4* 4)
//
//
// This code is complete shit.
//
//
//
// Save stack address and return address
//
mov r11, sp
mov r10, lr
//
// Check if we have more than 4 arguments
//
cmp r6, #4
ble SysCall
//
// Make space on stack
//
sub r6, r6, #4
sub sp, sp, r6, lsl #2
CopyLoop:
//
// Copy one parameter
//
ldr r7, [r5]
str r7, [sp]
add r5, r5, #4
add sp, sp, #4
//
// Keep looping until we've copied them all
//
cmp sp, r11
bne CopyLoop
//
// Set the stack
//
sub sp, sp, r6, lsl #2
//
// Now do the system call
//
SysCall:
mov lr, pc
mov pc, r4
//
// Restore the stack
//
mov sp, r11
//
// Get us back
//
mov pc, r10
ENTRY_END KiSystemCall

View file

@ -18,13 +18,6 @@
#define KiGetPreviousMode(tf) \
((tf->Spsr & CPSR_MODES) == CPSR_USER_MODE) ? UserMode: KernelMode
NTSTATUS
KiSystemCall(
IN PVOID Handler,
IN PULONG Arguments,
IN ULONG ArgumentCount
);
VOID
FASTCALL
KiRetireDpcList(
@ -37,6 +30,13 @@ KiQuantumEnd(
VOID
);
VOID
KiSystemService(
IN PKTHREAD Thread,
IN PKTRAP_FRAME TrapFrame,
IN ULONG Instruction
);
/* FUNCTIONS ******************************************************************/
VOID
@ -237,7 +237,7 @@ KiApcInterrupt(VOID)
KPROCESSOR_MODE PreviousMode;
KEXCEPTION_FRAME ExceptionFrame;
PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
DPRINT1("[APC]\n");
//DPRINT1("[APC]\n");
//
// Isolate previous mode
@ -360,6 +360,7 @@ KiInterruptHandler(IN PKTRAP_FRAME TrapFrame,
ULONG InterruptCause, InterruptMask;
PKPCR Pcr;
PKTRAP_FRAME OldTrapFrame;
ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
//
// Increment interrupt count
@ -424,7 +425,7 @@ KiInterruptHandler(IN PKTRAP_FRAME TrapFrame,
// DPRINT1("[ISR RETURN]\n");
//
// Re-enable interrupts and return IRQL
// Restore IRQL and interrupts
//
KeLowerIrql(OldIrql);
_enable();
@ -435,6 +436,7 @@ KiDataAbortHandler(IN PKTRAP_FRAME TrapFrame)
{
NTSTATUS Status;
PVOID Address = (PVOID)KeArmFaultAddressRegisterGet();
ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
DPRINT1("[ABORT] (%x) @ %p/%p/%p\n",
KeArmFaultStatusRegisterGet(), Address, TrapFrame->SvcLr, TrapFrame->Pc);
@ -455,145 +457,13 @@ KiDataAbortHandler(IN PKTRAP_FRAME TrapFrame)
return STATUS_SUCCESS;
}
VOID
KiSystemService(IN PKTHREAD Thread,
IN PKTRAP_FRAME TrapFrame,
IN ULONG Instruction)
{
ULONG Id, Number, ArgumentCount, i;
PKPCR Pcr;
ULONG_PTR ServiceTable, Offset;
PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
PVOID SystemCall;
PULONG Argument;
ULONG Arguments[16]; // Maximum 20 arguments
//
// Increase count of system calls
//
Pcr = (PKPCR)KeGetPcr();
Pcr->Prcb->KeSystemCalls++;
//
// Get the system call ID
//
Id = Instruction & 0xFFFFF;
DPRINT1("[SWI] (%x) %p (%d) \n", Id, Thread, Thread->PreviousMode);
//
// Get the descriptor table
//
ServiceTable = (ULONG_PTR)Thread->ServiceTable;
Offset = ((Id >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK);
ServiceTable += Offset;
DescriptorTable = (PVOID)ServiceTable;
//
// Get the service call number and validate it
//
Number = Id & SERVICE_NUMBER_MASK;
if (Number > DescriptorTable->Limit)
{
//
// Check if this is a GUI call
//
UNIMPLEMENTED;
ASSERT(FALSE);
}
//
// Save the function responsible for handling this system call
//
SystemCall = (PVOID)DescriptorTable->Base[Number];
//
// Check if this is a GUI call
//
if (Offset & SERVICE_TABLE_TEST)
{
//
// TODO
//
UNIMPLEMENTED;
ASSERT(FALSE);
}
//
// Check how many arguments this system call takes
//
ArgumentCount = DescriptorTable->Number[Number] / 4;
ASSERT(ArgumentCount <= 20);
//
// Copy the register-arguments first
// First four arguments are in a1, a2, a3, a4
//
Argument = &TrapFrame->R0;
for (i = 0; (i < ArgumentCount) && (i < 4); i++)
{
//
// Copy them into the kernel stack
//
DPRINT1("Argument: %p\n", *Argument);
Arguments[i] = *Argument;
Argument++;
}
//
// If more than four, we'll have some on the user stack
//
if (ArgumentCount > 4)
{
//
// Check where the stack is
//
if (Thread->PreviousMode == UserMode)
{
//
// FIXME: Validate the user stack
//
Argument = (PULONG)TrapFrame->UserSp;
}
else
{
//
// We were called from the kernel
//
Argument = (PULONG)TrapFrame->SvcSp;
//
// Bias for the values we saved
//
Argument += 2;
}
//
// Copy the rest
//
for (i = 4; i < ArgumentCount; i++)
{
//
// Copy into kernel stack
//
DPRINT1("Argument: %p\n", *Argument);
Arguments[i] = *Argument;
Argument++;
}
}
//
// Do the system call and save result in EAX
//
TrapFrame->R0 = KiSystemCall(SystemCall, Arguments, ArgumentCount);
DPRINT1("Returned: %lx\n", TrapFrame->R0);
}
VOID
KiSoftwareInterruptHandler(IN PKTRAP_FRAME TrapFrame)
{
PKTHREAD Thread;
KPROCESSOR_MODE PreviousMode;
ULONG Instruction;
ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
//
// Get the current thread
@ -606,9 +476,9 @@ KiSoftwareInterruptHandler(IN PKTRAP_FRAME TrapFrame)
PreviousMode = KiGetPreviousMode(TrapFrame);
//
// FIXME: Save old previous mode
// Save old previous mode
//
//TrapFrame->PreviousMode = PreviousMode;
TrapFrame->PreviousMode = PreviousMode;
//
// Save previous mode and trap frame

View file

@ -0,0 +1,207 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/arm/usercall.c
* PURPOSE: Implements system calls and user-mode callbacks for ARM
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
//
// System call wrapper generator
//
#define BUILD_SYSCALLS \
SYSCALL(00, ()) \
SYSCALL(01, (_1)) \
SYSCALL(02, (_1, _2)) \
SYSCALL(03, (_1, _2, _3)) \
SYSCALL(04, (_1, _2, _3, _4 )) \
SYSCALL(05, (_1, _2, _3, _4, _5)) \
SYSCALL(06, (_1, _2, _3, _4, _5, _6)) \
SYSCALL(07, (_1, _2, _3, _4, _5, _6, _7)) \
SYSCALL(08, (_1, _2, _3, _4, _5, _6, _7, _8)) \
SYSCALL(09, (_1, _2, _3, _4, _5, _6, _7, _8, _9)) \
SYSCALL(0A, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a)) \
SYSCALL(0B, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b)) \
SYSCALL(0C, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c)) \
SYSCALL(0D, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d)) \
SYSCALL(0E, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e)) \
SYSCALL(0F, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e, f)) \
SYSCALL(10, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e, f, _10)) \
SYSCALL(11, (_1, _2, _3, _4, _5, _6, _7, _8, _9, a, b, c, d, e, f, _10, _11))
//
// Generate function pointer definitions
//
#define PROTO
#include "ke_i.h"
BUILD_SYSCALLS
//
// Generate function code
//
#define FUNC
#include "ke_i.h"
BUILD_SYSCALLS
/* SYSTEM CALL STUBS **********************************************************/
typedef NTSTATUS (*PKI_SYSCALL_PARAM_HANDLER)(IN PVOID p, IN PVOID *g);
PKI_SYSCALL_PARAM_HANDLER KiSyscallHandlers[0x12] =
{
KiSyscall00Param,
KiSyscall01Param,
KiSyscall02Param,
KiSyscall03Param,
KiSyscall04Param,
KiSyscall05Param,
KiSyscall06Param,
KiSyscall07Param,
KiSyscall08Param,
KiSyscall09Param,
KiSyscall0AParam,
KiSyscall0BParam,
KiSyscall0CParam,
KiSyscall0DParam,
KiSyscall0EParam,
KiSyscall0FParam,
KiSyscall10Param,
KiSyscall11Param,
};
/* FUNCIONS *******************************************************************/
VOID
KiSystemService(IN PKTHREAD Thread,
IN PKTRAP_FRAME TrapFrame,
IN ULONG Instruction)
{
ULONG Id, Number, ArgumentCount, i;
PKPCR Pcr;
ULONG_PTR ServiceTable, Offset;
PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
PVOID SystemCall;
PVOID* Argument;
PVOID Arguments[0x11]; // Maximum 17 arguments
ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
//
// Increase count of system calls
//
Pcr = (PKPCR)KeGetPcr();
Pcr->Prcb->KeSystemCalls++;
//
// Get the system call ID
//
Id = Instruction & 0xFFFFF;
//DPRINT1("[SWI] (%x) %p (%d) \n", Id, Thread, Thread->PreviousMode);
//
// Get the descriptor table
//
ServiceTable = (ULONG_PTR)Thread->ServiceTable;
Offset = ((Id >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK);
ServiceTable += Offset;
DescriptorTable = (PVOID)ServiceTable;
//
// Get the service call number and validate it
//
Number = Id & SERVICE_NUMBER_MASK;
if (Number > DescriptorTable->Limit)
{
//
// Check if this is a GUI call
//
UNIMPLEMENTED;
ASSERT(FALSE);
}
//
// Save the function responsible for handling this system call
//
SystemCall = (PVOID)DescriptorTable->Base[Number];
//
// Check if this is a GUI call
//
if (Offset & SERVICE_TABLE_TEST)
{
//
// TODO
//
UNIMPLEMENTED;
ASSERT(FALSE);
}
//
// Check how many arguments this system call takes
//
ArgumentCount = DescriptorTable->Number[Number] / 4;
ASSERT(ArgumentCount <= 20);
//
// Copy the register-arguments first
// First four arguments are in a1, a2, a3, a4
//
Argument = (PVOID*)&TrapFrame->R0;
for (i = 0; (i < ArgumentCount) && (i < 4); i++)
{
//
// Copy them into the kernel stack
//
Arguments[i] = *Argument;
Argument++;
}
//
// If more than four, we'll have some on the user stack
//
if (ArgumentCount > 4)
{
//
// Check where the stack is
//
if (Thread->PreviousMode == UserMode)
{
//
// FIXME: Validate the user stack
//
ASSERT(FALSE);
Argument = (PVOID*)TrapFrame->UserSp;
}
else
{
//
// We were called from the kernel
//
Argument = (PVOID*)(TrapFrame + 1);
}
//
// Copy the rest
//
for (i = 4; i < ArgumentCount; i++)
{
//
// Copy into kernel stack
//
Arguments[i] = *Argument;
Argument++;
}
}
//
// Do the system call and save result in EAX
//
TrapFrame->R0 = KiSyscallHandlers[ArgumentCount]((PVOID)SystemCall,
(PVOID)Arguments);
}

View file

@ -69,8 +69,10 @@
<file>stubs_asm.s</file>
<file>stubs.c</file>
<file>thrdini.c</file>
<file>time.c</file>
<file>trap.s</file>
<file>trapc.c</file>
<file>usercall.c</file>
</directory>
</if>
<if property="ARCH" value="powerpc">