mirror of
https://github.com/reactos/reactos.git
synced 2025-04-22 05:00:27 +00:00
[NTOS]: Convert system call handling to C. Only kernel system calls are done this way for now, not SYSENTER calls from user-mode. A small ASM trampoline is used inline for the call itself.
svn path=/trunk/; revision=45147
This commit is contained in:
parent
9ef69503ed
commit
d4efc1a06c
3 changed files with 253 additions and 9 deletions
|
@ -111,15 +111,55 @@ KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
|
||||||
while (TRUE);
|
while (TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
VOID
|
||||||
|
KiExitSystemCallDebugChecks(IN ULONG SystemCall,
|
||||||
|
IN PKTRAP_FRAME TrapFrame)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
/* Check if this was a user call */
|
||||||
|
if (KiUserMode(TrapFrame))
|
||||||
|
{
|
||||||
|
/* Make sure we are not returning with elevated IRQL */
|
||||||
|
OldIrql = KeGetCurrentIrql();
|
||||||
|
if (OldIrql != PASSIVE_LEVEL)
|
||||||
|
{
|
||||||
|
/* Forcibly put us in a sane state */
|
||||||
|
KeGetPcr()->CurrentIrql = PASSIVE_LEVEL;
|
||||||
|
_disable();
|
||||||
|
|
||||||
|
/* Fail */
|
||||||
|
KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
|
||||||
|
SystemCall,
|
||||||
|
OldIrql,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we're not attached and that APCs are not disabled */
|
||||||
|
if ((KeGetCurrentThread()->ApcStateIndex != CurrentApcEnvironment) ||
|
||||||
|
(KeGetCurrentThread()->CombinedApcDisable != 0))
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
KeBugCheckEx(APC_INDEX_MISMATCH,
|
||||||
|
SystemCall,
|
||||||
|
KeGetCurrentThread()->ApcStateIndex,
|
||||||
|
KeGetCurrentThread()->CombinedApcDisable,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define KiExitTrapDebugChecks(x, y)
|
#define KiExitTrapDebugChecks(x, y)
|
||||||
#define KiFillTrapFrameDebug(x)
|
#define KiFillTrapFrameDebug(x)
|
||||||
|
#define KiExitSystemCallDebugChecks(x, y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Helper Code
|
// Helper Code
|
||||||
//
|
//
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
KiUserTrap(IN PKTRAP_FRAME TrapFrame)
|
KiUserTrap(IN PKTRAP_FRAME TrapFrame)
|
||||||
|
@ -354,3 +394,45 @@ KiEditedTrapReturn(IN PKTRAP_FRAME TrapFrame)
|
||||||
: "%esp"
|
: "%esp"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FORCEINLINE
|
||||||
|
KiSystemCallTrampoline(IN PVOID Handler,
|
||||||
|
IN PVOID Arguments,
|
||||||
|
IN ULONG StackBytes)
|
||||||
|
{
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This sequence does a RtlCopyMemory(Stack - StackBytes, Arguments, StackBytes)
|
||||||
|
* and then calls the function associated with the system call.
|
||||||
|
*
|
||||||
|
* It's done in assembly for two reasons: we need to muck with the stack,
|
||||||
|
* and the call itself restores the stack back for us. The only way to do
|
||||||
|
* this in C is to do manual C handlers for every possible number of args on
|
||||||
|
* the stack, and then have the handler issue a call by pointer. This is
|
||||||
|
* wasteful since it'll basically push the values twice and require another
|
||||||
|
* level of call indirection.
|
||||||
|
*
|
||||||
|
* The ARM kernel currently does this, but it should probably be changed
|
||||||
|
* later to function like this as well.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
__asm__ __volatile__
|
||||||
|
(
|
||||||
|
"subl %1, %%esp\n"
|
||||||
|
"movl %%esp, %%edi\n"
|
||||||
|
"movl %2, %%esi\n"
|
||||||
|
"shrl $2, %1\n"
|
||||||
|
"rep movsd\n"
|
||||||
|
"call *%3\n"
|
||||||
|
"movl %%eax, %0\n"
|
||||||
|
: "=r"(Result)
|
||||||
|
: "c"(StackBytes),
|
||||||
|
"d"(Arguments),
|
||||||
|
"r"(Handler)
|
||||||
|
: "%esp", "%esi", "%edi"
|
||||||
|
);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
|
@ -66,8 +66,6 @@ GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
|
||||||
.globl _KiSystemService
|
.globl _KiSystemService
|
||||||
|
|
||||||
/* And special system-defined software traps: */
|
/* And special system-defined software traps: */
|
||||||
.globl _NtRaiseException@12
|
|
||||||
.globl _NtContinue@8
|
|
||||||
.globl _KiDispatchInterrupt@0
|
.globl _KiDispatchInterrupt@0
|
||||||
|
|
||||||
/* Interrupt template entrypoints */
|
/* Interrupt template entrypoints */
|
||||||
|
@ -84,7 +82,6 @@ GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
|
||||||
|
|
||||||
/* We implement the following trap exit points: */
|
/* We implement the following trap exit points: */
|
||||||
.globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
|
.globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
|
||||||
.globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
|
|
||||||
|
|
||||||
.globl _KiIdtDescriptor
|
.globl _KiIdtDescriptor
|
||||||
_KiIdtDescriptor:
|
_KiIdtDescriptor:
|
||||||
|
@ -115,14 +112,20 @@ _IsrOverflowMsg:
|
||||||
.text
|
.text
|
||||||
|
|
||||||
.func KiSystemService
|
.func KiSystemService
|
||||||
TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios
|
|
||||||
_KiSystemService:
|
_KiSystemService:
|
||||||
|
|
||||||
/* Enter the shared system call prolog */
|
/* Make space for trap frame on the stack */
|
||||||
SYSCALL_PROLOG kss_a, kss_t
|
sub esp, KTRAP_FRAME_EIP
|
||||||
|
|
||||||
/* Jump to the actual handler */
|
/* Save EBP, EBX, ESI, EDI only! */
|
||||||
jmp SharedCode
|
mov [esp+KTRAP_FRAME_EBX], ebx
|
||||||
|
mov [esp+KTRAP_FRAME_ESI], esi
|
||||||
|
mov [esp+KTRAP_FRAME_EDI], edi
|
||||||
|
mov [esp+KTRAP_FRAME_EBP], ebp
|
||||||
|
|
||||||
|
/* Call C handler -- note that EDX is the caller stack, EAX is the ID */
|
||||||
|
mov ecx, esp
|
||||||
|
jmp _KiSystemServiceHandler
|
||||||
.endfunc
|
.endfunc
|
||||||
|
|
||||||
.func KiFastCallEntry
|
.func KiFastCallEntry
|
||||||
|
|
|
@ -1691,6 +1691,165 @@ KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
|
||||||
KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
|
KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
FASTCALL
|
||||||
|
KiSystemCall(IN ULONG SystemCallNumber,
|
||||||
|
IN PVOID Arguments)
|
||||||
|
{
|
||||||
|
PKTHREAD Thread;
|
||||||
|
PKTRAP_FRAME TrapFrame;
|
||||||
|
PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
|
||||||
|
ULONG Id, Offset, StackBytes, Result;
|
||||||
|
PVOID Handler;
|
||||||
|
|
||||||
|
/* Loop because we might need to try this twice in case of a GUI call */
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* Decode the system call number */
|
||||||
|
Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
|
||||||
|
Id = SystemCallNumber & SERVICE_NUMBER_MASK;
|
||||||
|
|
||||||
|
/* Get current thread, trap frame, and descriptor table */
|
||||||
|
Thread = KeGetCurrentThread();
|
||||||
|
TrapFrame = Thread->TrapFrame;
|
||||||
|
DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
|
||||||
|
|
||||||
|
/* Validate the system call number */
|
||||||
|
if (__builtin_expect(Id > DescriptorTable->Limit, 0))
|
||||||
|
{
|
||||||
|
/* Check if this is a GUI call */
|
||||||
|
if (__builtin_expect(!(Offset & SERVICE_TABLE_TEST), 0))
|
||||||
|
{
|
||||||
|
/* Fail the call */
|
||||||
|
Result = STATUS_INVALID_SYSTEM_SERVICE;
|
||||||
|
goto ExitCall;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GUI calls are not yet supported */
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
while (TRUE);
|
||||||
|
|
||||||
|
/* Try the call again */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we made it here, the call is good */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if this is a GUI call */
|
||||||
|
if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
|
||||||
|
{
|
||||||
|
/* Get the batch count and flush if necessary */
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
while (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase system call count */
|
||||||
|
KeGetCurrentPrcb()->KeSystemCalls++;
|
||||||
|
|
||||||
|
/* FIXME: Increase individual counts on debug systems */
|
||||||
|
//KiIncreaseSystemCallCount(DescriptorTable, Id);
|
||||||
|
|
||||||
|
/* Get stack bytes */
|
||||||
|
StackBytes = DescriptorTable->Number[Id];
|
||||||
|
|
||||||
|
/* Probe caller stack */
|
||||||
|
if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
|
||||||
|
{
|
||||||
|
/* Access violation */
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
while (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the handler and make the system call */
|
||||||
|
Handler = (PVOID)DescriptorTable->Base[Id];
|
||||||
|
Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
|
||||||
|
|
||||||
|
/* Make sure we're exiting correctly */
|
||||||
|
KiExitSystemCallDebugChecks(Id, TrapFrame);
|
||||||
|
|
||||||
|
/* Restore the old trap frame */
|
||||||
|
ExitCall:
|
||||||
|
Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
|
||||||
|
|
||||||
|
/* Exit from system call */
|
||||||
|
KiServiceExit(TrapFrame, Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
FORCEINLINE
|
||||||
|
KiSystemCallHandler(IN PKTRAP_FRAME TrapFrame,
|
||||||
|
IN ULONG ServiceNumber,
|
||||||
|
IN PVOID Arguments,
|
||||||
|
IN PKTHREAD Thread,
|
||||||
|
IN KPROCESSOR_MODE PreviousMode,
|
||||||
|
IN KPROCESSOR_MODE PreviousPreviousMode,
|
||||||
|
IN USHORT SegFs)
|
||||||
|
{
|
||||||
|
/* No error code */
|
||||||
|
TrapFrame->ErrCode = 0;
|
||||||
|
|
||||||
|
/* Save previous mode and FS segment */
|
||||||
|
TrapFrame->PreviousPreviousMode = PreviousPreviousMode;
|
||||||
|
TrapFrame->SegFs = SegFs;
|
||||||
|
|
||||||
|
/* Save the SEH chain and terminate it for now */
|
||||||
|
TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList;
|
||||||
|
KeGetPcr()->Tib.ExceptionList = EXCEPTION_CHAIN_END;
|
||||||
|
|
||||||
|
/* Clear DR7 and check for debugging */
|
||||||
|
TrapFrame->Dr7 = 0;
|
||||||
|
if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0))
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
while (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set thread fields */
|
||||||
|
Thread->TrapFrame = TrapFrame;
|
||||||
|
Thread->PreviousMode = PreviousMode;
|
||||||
|
|
||||||
|
/* Set debug header */
|
||||||
|
KiFillTrapFrameDebug(TrapFrame);
|
||||||
|
|
||||||
|
/* Enable interrupts and make the call */
|
||||||
|
_enable();
|
||||||
|
KiSystemCall(ServiceNumber, Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
__attribute__((regparm(3)))
|
||||||
|
KiSystemServiceHandler(IN ULONG ServiceNumber,
|
||||||
|
IN PVOID Arguments,
|
||||||
|
IN PKTRAP_FRAME TrapFrame)
|
||||||
|
{
|
||||||
|
USHORT SegFs;
|
||||||
|
PKTHREAD Thread;
|
||||||
|
|
||||||
|
/* Save and fixup FS */
|
||||||
|
SegFs = Ke386GetFs();
|
||||||
|
Ke386SetFs(KGDT_R0_PCR);
|
||||||
|
|
||||||
|
/* Get the current thread */
|
||||||
|
Thread = KeGetCurrentThread();
|
||||||
|
|
||||||
|
/* Chain trap frames */
|
||||||
|
TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
|
||||||
|
|
||||||
|
/* Clear direction flag */
|
||||||
|
Ke386ClearDirectionFlag();
|
||||||
|
|
||||||
|
/* Call the shared handler (inline) */
|
||||||
|
KiSystemCallHandler(TrapFrame,
|
||||||
|
ServiceNumber,
|
||||||
|
Arguments,
|
||||||
|
Thread,
|
||||||
|
KiUserTrap(TrapFrame),
|
||||||
|
Thread->PreviousMode,
|
||||||
|
SegFs);
|
||||||
|
}
|
||||||
|
|
||||||
/* HARDWARE INTERRUPTS ********************************************************/
|
/* HARDWARE INTERRUPTS ********************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue