test: callback.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# callback.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1994  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     callback.c
    00008
    00009 Abstract:
    00010
    00011     This module implements user mode call back services.
    00012
    00013 Author:
    00014
    00015     William K. Cheung (wcheung) 30-Oct-1995
    00016
    00017     based on David N. Cutler (davec) 29-Oct-1994
    00018
    00019 Environment:
    00020
    00021     Kernel mode only.
    00022
    00023 Revision History:
    00024
    00025 --*/
    00026
    00027 #include "ki.h"
    00028
    00029 NTSTATUS
    00030 KeUserModeCallback (
    00031     IN ULONG ApiNumber,
    00032     IN PVOID InputBuffer,
    00033     IN ULONG InputLength,
    00034     OUT PVOID *OutputBuffer,
    00035     IN PULONG OutputLength
    00036     )
    00037
    00038 /*++
    00039
    00040 Routine Description:
    00041
    00042     This function call out from kernel mode to a user mode function.
    00043
    00044 Arguments:
    00045
    00046     ApiNumber - Supplies the API number.
    00047
    00048     InputBuffer - Supplies a pointer to a structure that is copied
    00049         to the user stack.
    00050
    00051     InputLength - Supplies the length of the input structure.
    00052
    00053     Outputbuffer - Supplies a pointer to a variable that receives
    00054         the address of the output buffer.
    00055
    00056     Outputlength - Supplies a pointer to a variable that receives
    00057         the length of the output buffer.
    00058
    00059 Return Value:
    00060
    00061     If the callout cannot be executed, then an error status is
    00062     returned. Otherwise, the status returned by the callback function
    00063     is returned.
    00064
    00065 --*/
    00066
    00067 {
    00068     PUCALLOUT_FRAME CalloutFrame;
    00069     ULONGLONG OldStack;
    00070     ULONGLONG NewStack;
    00071     ULONGLONG OldStIFS;
    00072     PKTRAP_FRAME TrapFrame;
    00073     NTSTATUS Status;
    00074     ULONG Length;
    00075     SHORT BsFrameSize;
    00076     USHORT TearPointOffset;
    00077
    00078     ASSERT(KeGetPreviousMode() == UserMode);
    00079
    00080     //
    00081     // Get the user mode stack pointer and attempt to copy input buffer
    00082     // to the user stack.
    00083     //
    00084
    00085     TrapFrame = KeGetCurrentThread()->TrapFrame;
    00086     OldStack = TrapFrame->IntSp;
    00087     OldStIFS = TrapFrame->StIFS;
    00088
    00089     try {
    00090
    00091         //
    00092         // Compute new user mode stack address, probe for writability,
    00093         // and copy the input buffer to the user stack.
    00094         //
    00095         // N.B. EM requires stacks to be 16-byte aligned, therefore
    00096         //      the input length must be rounded up to a 16-byte boundary.
    00097         //
    00098
    00099         Length =  (InputLength + 16 - 1 + sizeof(UCALLOUT_FRAME) + STACK_SCRATCH_AREA) & ~(16 - 1);
    00100         NewStack = OldStack - Length;
    00101         CalloutFrame = (PUCALLOUT_FRAME)(NewStack + STACK_SCRATCH_AREA);
    00102         ProbeForWrite((PVOID)NewStack, Length, sizeof(QUAD));
    00103         RtlCopyMemory(CalloutFrame + 1, InputBuffer, InputLength);
    00104
    00105         //
    00106         // Fill in the callout arguments.
    00107         //
    00108
    00109         CalloutFrame->Buffer = (PVOID)(CalloutFrame + 1);
    00110         CalloutFrame->Length = InputLength;
    00111         CalloutFrame->ApiNumber = ApiNumber;
    00112         CalloutFrame->IntSp = OldStack;
    00113         CalloutFrame->RsPFS = TrapFrame->StIFS;
    00114         CalloutFrame->BrRp = TrapFrame->BrRp;
    00115
    00116       if (PsGetCurrentProcess()->DebugPort != NULL) {
    00117         KiFlushRse();
    00118         BsFrameSize = (SHORT)(TrapFrame->RsBSP - TrapFrame->RsBSPSTORE);
    00119         if (BsFrameSize) {
    00120
    00121             ULONGLONG TopBound, BottomBound;
    00122             ULONGLONG UserRnats1, UserRnats2;
    00123             ULONGLONG Mask;
    00124             ULONGLONG CurrentRNAT = 0;
    00125             SHORT RNatSaveIndex;
    00126
    00127             //
    00128             // Copy the dirty stacked registers back into the
    00129             // user backing store
    00130             //
    00131
    00132             TearPointOffset = (USHORT) TrapFrame->RsBSPSTORE & 0x1F8;
    00133             RtlCopyMemory((PVOID)(TrapFrame->RsBSPSTORE),
    00134                          (PVOID)(PCR->InitialBStore + TearPointOffset),
    00135                          BsFrameSize);
    00136
    00137             TopBound = TrapFrame->RsBSP | RNAT_ALIGNMENT;
    00138             BottomBound = TrapFrame->RsBSPSTORE | RNAT_ALIGNMENT;
    00139
    00140             RNatSaveIndex = TearPointOffset >> 3;
    00141             Mask = (((1ULL << (NAT_BITS_PER_RNAT_REG - RNatSaveIndex)) - 1) << RNatSaveIndex);
    00142             UserRnats1 = TrapFrame->RsRNAT & ((1ULL << RNatSaveIndex) - 1);
    00143
    00144             if (TopBound > BottomBound) {
    00145
    00146                 //
    00147                 // user dirty stacked GR span across at least one RNAT
    00148                 // boundary; need to deposit the valid RNAT bits from
    00149                 // the trap frame into the kernel backing store.  Also,
    00150                 // the RNAT field in the trap frame has to be updated.
    00151                 //
    00152
    00153                 UserRnats2 = *(PULONGLONG)BottomBound & Mask;
    00154                 *(PULONGLONG)BottomBound = UserRnats1 | UserRnats2;
    00155                 TrapFrame->RsRNAT = CurrentRNAT;
    00156
    00157             } else {
    00158
    00159                 //
    00160                 // user stacked register region does not span across an
    00161                 // RNAT boundary; combine the RNAT fields from both the
    00162                 // trap frame and the context frame.
    00163                 //
    00164
    00165                 UserRnats2 = CurrentRNAT & Mask;
    00166                 TrapFrame->RsRNAT = UserRnats1 | UserRnats2;
    00167
    00168             }
    00169
    00170             TrapFrame->RsBSPSTORE = TrapFrame->RsBSP;
    00171         }
    00172       }
    00173
    00174     //
    00175     // If an exception occurs during the probe of the user stack, then
    00176     // always handle the exception and return the exception code as the
    00177     // status value.
    00178     //
    00179
    00180     } except (EXCEPTION_EXECUTE_HANDLER) {
    00181         return GetExceptionCode();
    00182     }
    00183
    00184     //
    00185     // Call user mode.
    00186     //
    00187
    00188     TrapFrame->StIFS = 0xC000000000000000i64;
    00189     TrapFrame->IntSp = NewStack;
    00190     Status = KiCallUserMode(OutputBuffer, OutputLength);
    00191
    00192     //
    00193     // When returning from user mode, any drawing done to the GDI TEB
    00194     // batch must be flushed.
    00195     //
    00196
    00197     if (((PTEB)KeGetCurrentThread()->Teb)->GdiBatchCount > 0) {
    00198
    00199         //
    00200         // call GDI batch flush routine
    00201         //
    00202
    00203         KeGdiFlushUserBatch();
    00204     }
    00205
    00206     TrapFrame->IntSp = OldStack;
    00207     TrapFrame->StIFS = OldStIFS;
    00208     return Status;
    00209
    00210 }
    00211
    00212 NTSTATUS
    00213 NtW32Call (
    00214     IN ULONG ApiNumber,
    00215     IN PVOID InputBuffer,
    00216     IN ULONG InputLength,
    00217     OUT PVOID *OutputBuffer,
    00218     OUT PULONG OutputLength
    00219     )
    00220
    00221 /*++
    00222
    00223 Routine Description:
    00224
    00225     This function calls a W32 function.
    00226
    00227     N.B. ************** This is a temporary service *****************
    00228
    00229 Arguments:
    00230
    00231     ApiNumber - Supplies the API number.
    00232
    00233     InputBuffer - Supplies a pointer to a structure that is copied to
    00234         the user stack.
    00235
    00236     InputLength - Supplies the length of the input structure.
    00237
    00238     Outputbuffer - Supplies a pointer to a variable that recevies the
    00239         output buffer address.
    00240
    00241     Outputlength - Supplies a pointer to a variable that recevies the
    00242         output buffer length.
    00243
    00244 Return Value:
    00245
    00246     TBS.
    00247
    00248 --*/
    00249
    00250 {
    00251
    00252     PVOID ValueBuffer;
    00253     ULONG ValueLength;
    00254     NTSTATUS Status;
    00255
    00256     ASSERT(KeGetPreviousMode() == UserMode);
    00257
    00258     //
    00259     // If the current thread is not a GUI thread, then fail the service
    00260     // since the thread does not have a large stack.
    00261     //
    00262
    00263     if (KeGetCurrentThread()->Win32Thread == (PVOID)&KeServiceDescriptorTable[0]) {
    00264         return STATUS_NOT_IMPLEMENTED;
    00265     }
    00266
    00267     //
    00268     // Probe the output buffer address and length for writeability.
    00269     //
    00270
    00271     try {
    00272         ProbeForWriteUlong((PULONG)OutputBuffer);
    00273         ProbeForWriteUlong(OutputLength);
    00274
    00275     //
    00276     // If an exception occurs during the probe of the output buffer or
    00277     // length, then always handle the exception and return the exception
    00278     // code as the status value.
    00279     //
    00280
    00281     } except(EXCEPTION_EXECUTE_HANDLER) {
    00282         return GetExceptionCode();
    00283     }
    00284
    00285     //
    00286     // Call out to user mode specifying the input buffer and API number.
    00287     //
    00288
    00289     Status = KeUserModeCallback(ApiNumber,
    00290                                 InputBuffer,
    00291                                 InputLength,
    00292                                 &ValueBuffer,
    00293                                 &ValueLength);
    00294
    00295     //
    00296     // If the callout is successful, then the output buffer address and
    00297     // length.
    00298     //
    00299
    00300     if (NT_SUCCESS(Status)) {
    00301         try {
    00302             *OutputBuffer = ValueBuffer;
    00303             *OutputLength = ValueLength;
    00304
    00305         } except(EXCEPTION_EXECUTE_HANDLER) {
    00306         }
    00307     }
    00308
    00309     return Status;
    00310 }