Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

146 lines
3.4 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
callback.c
Abstract:
This module implements user mode call back services.
Author:
David N. Cutler (davec) 5-Jul-2000
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
#pragma alloc_text(PAGE, KeUserModeCallback)
NTSTATUS
KeUserModeCallback (
IN ULONG ApiNumber,
IN PVOID InputBuffer,
IN ULONG InputLength,
OUT PVOID *OutputBuffer,
IN PULONG OutputLength
)
/*++
Routine Description:
This function call out from kernel mode to a user mode function.
Arguments:
ApiNumber - Supplies the API number.
InputBuffer - Supplies a pointer to a structure that is copied
to the user stack.
InputLength - Supplies the length of the input structure.
Outputbuffer - Supplies a pointer to a variable that receives
the address of the output buffer.
Outputlength - Supplies a pointer to a variable that receives
the length of the output buffer.
Return Value:
If the callout cannot be executed, then an error status is returned.
Otherwise, the status returned by the callback function is returned.
--*/
{
volatile ULONG BatchCount;
PUCALLOUT_FRAME CalloutFrame;
ULONG Length;
ULONG64 OldStack;
NTSTATUS Status;
PKTRAP_FRAME TrapFrame;
ASSERT(KeGetPreviousMode() == UserMode);
//
// Get the user mode stack pointer and attempt to copy input buffer
// to the user stack.
//
TrapFrame = KeGetCurrentThread()->TrapFrame;
OldStack = TrapFrame->Rsp;
try {
//
// Compute new user mode stack address, probe for writability, and
// copy the input buffer to the user stack.
//
Length = ((InputLength + STACK_ROUND) & ~STACK_ROUND) + UCALLOUT_FRAME_LENGTH;
CalloutFrame = (PUCALLOUT_FRAME)((OldStack - Length) & ~STACK_ROUND);
ProbeForWrite(CalloutFrame, Length, STACK_ALIGN);
RtlCopyMemory(CalloutFrame + 1, InputBuffer, InputLength);
//
// Fill in callout arguments.
//
CalloutFrame->Buffer = (PVOID)(CalloutFrame + 1);
CalloutFrame->Length = InputLength;
CalloutFrame->ApiNumber = ApiNumber;
CalloutFrame->MachineFrame.Rsp = OldStack;
CalloutFrame->MachineFrame.Rip = TrapFrame->Rip;
//
// If an exception occurs during the probe of the user stack, then
// always handle the exception and return the exception code as the
// status value.
//
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode();
}
//
// Call user mode.
//
TrapFrame->Rsp = (ULONG64)CalloutFrame;
Status = KiCallUserMode(OutputBuffer, OutputLength);
//
// When returning from user mode, any drawing done to the GDI TEB
// batch must be flushed.
//
// N.B. It is possible to fault while referencing the user TEB. If
// a fault occurs, then always flush the batch count.
//
BatchCount = 1;
try {
BatchCount = ((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount;
} except (EXCEPTION_EXECUTE_HANDLER) {
NOTHING;
}
if (BatchCount > 0) {
TrapFrame->Rsp -= 256;
KeGdiFlushUserBatch();
}
TrapFrame->Rsp = OldStack;
return Status;
}