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
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;
|
|
}
|