/*++ Copyright (c) 1994 Microsoft Corporation Module Name: callback.c Abstract: This module implements user mode call back services. Author: David N. Cutler (davec) 29-Oct-1994 Environment: Kernel mode only. --*/ #include "ki.h" 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. --*/ { PUCALLOUT_FRAME CalloutFrame; ULONG Length; ULONG OldStack; NTSTATUS Status; PKTRAP_FRAME TrapFrame; PULONG UserStack; PVOID ValueBuffer; ULONG ValueLength; ASSERT(KeGetPreviousMode() == UserMode); // Get the user mode stack pointer and attempt to copy input buffer to the user stack. TrapFrame = KeGetCurrentThread()->TrapFrame; OldStack = (ULONG)TrapFrame->XIntSp; try { // Compute new user mode stack address, probe for writability, and copy the input buffer to the user stack. Length = (InputLength + sizeof(QUAD) - 1 + sizeof(UCALLOUT_FRAME)) & ~(sizeof(QUAD) - 1); CalloutFrame = (PUCALLOUT_FRAME)(OldStack - Length); ProbeForWrite(CalloutFrame, Length, sizeof(QUAD)); RtlMoveMemory(CalloutFrame + 1, InputBuffer, InputLength); // Allocate stack frame fill in callout arguments. CalloutFrame->Buffer = (PVOID)(CalloutFrame + 1); CalloutFrame->Length = InputLength; CalloutFrame->ApiNumber = ApiNumber; CalloutFrame->Pad = 0; CalloutFrame->Sp = TrapFrame->XIntSp; CalloutFrame->Ra = TrapFrame->XIntRa; } except (EXCEPTION_EXECUTE_HANDLER) {// If an exception occurs during the probe of the user stack, return GetExceptionCode();//then always handle the exception and return the exception code as the status value. } // Call user mode. TrapFrame->XIntSp = (LONG)CalloutFrame; Status = KiCallUserMode(OutputBuffer, OutputLength); TrapFrame->XIntSp = (LONG)OldStack; // If the GDI TEB batch contains any entries, it must be flushed. if (((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount > 0) { KeGdiFlushUserBatch(); } return Status; } NTSTATUS NtW32Call (IN ULONG ApiNumber, IN PVOID InputBuffer, IN ULONG InputLength, OUT PVOID *OutputBuffer, OUT PULONG OutputLength) /*++ Routine Description: This function calls a W32 function. N.B. ************** This is a temporary service ***************** 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 recevies the output buffer address. Outputlength - Supplies a pointer to a variable that recevies the output buffer length. Return Value: TBS. --*/ { PVOID ValueBuffer; ULONG ValueLength; NTSTATUS Status; ASSERT(KeGetPreviousMode() == UserMode); // If the current thread is not a GUI thread, then fail the service since the thread does not have a large stack. if (KeGetCurrentThread()->Win32Thread == (PVOID)&KeServiceDescriptorTable[0]) { return STATUS_NOT_IMPLEMENTED; } // Probe the output buffer address and length for writeability. try { ProbeForWriteUlong((PULONG)OutputBuffer); ProbeForWriteUlong(OutputLength); // If an exception occurs during the probe of the output buffer or length, then always handle the exception and return the exception code as the status value. } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } // Call out to user mode specifying the input buffer and API number. Status = KeUserModeCallback(ApiNumber, InputBuffer, InputLength, &ValueBuffer, &ValueLength); if (NT_SUCCESS(Status)) {// If the callout is successful, then the output buffer address and length. try { *OutputBuffer = ValueBuffer; *OutputLength = ValueLength; } except(EXCEPTION_EXECUTE_HANDLER) { } } return Status; }