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

psctx.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 psctx.c 00008 00009 Abstract: 00010 00011 This procedure implements Get/Set Context Thread 00012 00013 Author: 00014 00015 Mark Lucovsky (markl) 25-May-1989 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "psp.h" 00022 00023 VOID 00024 PspQueueApcSpecialApc( 00025 IN PKAPC Apc, 00026 IN PKNORMAL_ROUTINE *NormalRoutine, 00027 IN PVOID *NormalContext, 00028 IN PVOID *SystemArgument1, 00029 IN PVOID *SystemArgument2 00030 ); 00031 00032 #ifdef ALLOC_PRAGMA 00033 #pragma alloc_text(PAGE, NtGetContextThread) 00034 #pragma alloc_text(PAGE, NtSetContextThread) 00035 #pragma alloc_text(PAGE, NtQueueApcThread) 00036 #pragma alloc_text(PAGE, PspQueueApcSpecialApc ) 00037 #endif 00038 00039 VOID 00040 PspQueueApcSpecialApc( 00041 IN PKAPC Apc, 00042 IN PKNORMAL_ROUTINE *NormalRoutine, 00043 IN PVOID *NormalContext, 00044 IN PVOID *SystemArgument1, 00045 IN PVOID *SystemArgument2 00046 ) 00047 { 00048 PAGED_CODE(); 00049 00050 ExFreePool(Apc); 00051 } 00052 00053 NTSYSAPI 00054 NTSTATUS 00055 NTAPI 00056 NtQueueApcThread( 00057 IN HANDLE ThreadHandle, 00058 IN PPS_APC_ROUTINE ApcRoutine, 00059 IN PVOID ApcArgument1, 00060 IN PVOID ApcArgument2, 00061 IN PVOID ApcArgument3 00062 ) 00063 00064 /*++ 00065 00066 Routine Description: 00067 00068 This function is used to queue a user-mode APC to the specified thread. The APC 00069 will fire when the specified thread does an alertable wait 00070 00071 Arguments: 00072 00073 ThreadHandle - Supplies a handle to a thread object. The caller 00074 must have THREAD_SET_CONTEXT access to the thread. 00075 00076 ApcRoutine - Supplies the address of the APC routine to execute when the 00077 APC fires. 00078 00079 ApcArgument1 - Supplies the first PVOID passed to the APC 00080 00081 ApcArgument2 - Supplies the second PVOID passed to the APC 00082 00083 ApcArgument3 - Supplies the third PVOID passed to the APC 00084 00085 Return Value: 00086 00087 Returns an NT Status code indicating success or failure of the API 00088 00089 --*/ 00090 00091 { 00092 PETHREAD Thread; 00093 NTSTATUS st; 00094 KPROCESSOR_MODE Mode; 00095 KIRQL Irql; 00096 PKAPC Apc; 00097 00098 PAGED_CODE(); 00099 00100 Mode = KeGetPreviousMode(); 00101 00102 st = ObReferenceObjectByHandle( 00103 ThreadHandle, 00104 THREAD_SET_CONTEXT, 00105 PsThreadType, 00106 Mode, 00107 (PVOID *)&Thread, 00108 NULL 00109 ); 00110 00111 if ( NT_SUCCESS(st) ) { 00112 st = STATUS_SUCCESS; 00113 if ( IS_SYSTEM_THREAD(Thread) ) { 00114 st = STATUS_INVALID_HANDLE; 00115 } 00116 else { 00117 Apc = ExAllocatePoolWithQuotaTag( 00118 (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE), 00119 sizeof(*Apc), 00120 'pasP' 00121 ); 00122 00123 if ( !Apc ) { 00124 st = STATUS_NO_MEMORY; 00125 } 00126 else { 00127 KeInitializeApc( 00128 Apc, 00129 &Thread->Tcb, 00130 OriginalApcEnvironment, 00131 PspQueueApcSpecialApc, 00132 NULL, 00133 (PKNORMAL_ROUTINE)ApcRoutine, 00134 UserMode, 00135 ApcArgument1 00136 ); 00137 00138 if ( !KeInsertQueueApc(Apc,ApcArgument2,ApcArgument3,0) ) { 00139 ExFreePool(Apc); 00140 st = STATUS_UNSUCCESSFUL; 00141 } 00142 } 00143 } 00144 ObDereferenceObject(Thread); 00145 } 00146 00147 return st; 00148 } 00149 00150 NTSTATUS 00151 NtGetContextThread( 00152 IN HANDLE ThreadHandle, 00153 IN OUT PCONTEXT ThreadContext 00154 ) 00155 00156 /*++ 00157 00158 Routine Description: 00159 00160 This function returns the usermode context of the specified thread. This 00161 function will fail if the specified thread is a system thread. It will 00162 return the wrong answer if the thread is a non-system thread that does 00163 not execute in user-mode. 00164 00165 Arguments: 00166 00167 ThreadHandle - Supplies an open handle to the thread object from 00168 which to retrieve context information. The handle 00169 must allow THREAD_GET_CONTEXT access to the thread. 00170 00171 ThreadContext - Supplies the address of a buffer that will receive 00172 the context of the specified thread. 00173 00174 Return Value: 00175 00176 None. 00177 00178 --*/ 00179 00180 { 00181 00182 ULONG Alignment; 00183 ULONG ContextFlags; 00184 GETSETCONTEXT ContextFrame; 00185 ULONG ContextLength; 00186 KIRQL Irql; 00187 KPROCESSOR_MODE Mode; 00188 NTSTATUS Status; 00189 PETHREAD Thread; 00190 00191 PAGED_CODE(); 00192 00193 // 00194 // Get previous mode and reference specified thread. 00195 // 00196 00197 Mode = KeGetPreviousMode(); 00198 Status = ObReferenceObjectByHandle(ThreadHandle, 00199 THREAD_GET_CONTEXT, 00200 PsThreadType, 00201 Mode, 00202 (PVOID *)&Thread, 00203 NULL); 00204 00205 // 00206 // If the reference was successful, the check if the specified thread 00207 // is a system thread. 00208 // 00209 00210 if (NT_SUCCESS(Status)) { 00211 00212 // 00213 // If the thread is not a system thread, then attempt to get the 00214 // context of the thread. 00215 // 00216 00217 if (IS_SYSTEM_THREAD(Thread) == FALSE) { 00218 00219 // 00220 // Attempt to get the context of the specified thread. 00221 // 00222 00223 try { 00224 00225 // 00226 // Set the default alignment, capture the context flags, 00227 // and set the default size of the context record. 00228 // 00229 00230 Alignment = CONTEXT_ALIGN; 00231 ContextFlags = ProbeAndReadUlong(&ThreadContext->ContextFlags); 00232 ContextLength = sizeof(CONTEXT); 00233 00234 #if defined(_X86_) 00235 // 00236 // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above 00237 // otherwise (not set) we only want the old part of the context record. 00238 // 00239 if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) { 00240 ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 00241 } 00242 #endif 00243 00244 #if defined(_MIPS_) 00245 00246 // 00247 // The following code is included for backward compatibility 00248 // with old code that does not understand extended context 00249 // records on MIPS systems. 00250 // 00251 00252 if ((ContextFlags & CONTEXT_EXTENDED_INTEGER) != CONTEXT_EXTENDED_INTEGER) { 00253 Alignment = sizeof(ULONG); 00254 ContextLength = FIELD_OFFSET(CONTEXT, ContextFlags) + 4; 00255 } 00256 00257 #endif 00258 00259 if (Mode != KernelMode) { 00260 ProbeForWrite(ThreadContext, ContextLength, Alignment); 00261 } 00262 00263 } except(EXCEPTION_EXECUTE_HANDLER) { 00264 Status = GetExceptionCode(); 00265 } 00266 00267 // 00268 // If an exception did not occur during the probe of the thread 00269 // context, then get the context of the target thread. 00270 // 00271 00272 if (NT_SUCCESS(Status)) { 00273 KeInitializeEvent(&ContextFrame.OperationComplete, 00274 NotificationEvent, 00275 FALSE); 00276 00277 ContextFrame.Context.ContextFlags = ContextFlags; 00278 00279 ContextFrame.Mode = Mode; 00280 if (Thread == PsGetCurrentThread()) { 00281 ContextFrame.Apc.SystemArgument1 = NULL; 00282 ContextFrame.Apc.SystemArgument2 = Thread; 00283 KeRaiseIrql(APC_LEVEL, &Irql); 00284 PspGetSetContextSpecialApc(&ContextFrame.Apc, 00285 NULL, 00286 NULL, 00287 &ContextFrame.Apc.SystemArgument1, 00288 &ContextFrame.Apc.SystemArgument2); 00289 00290 KeLowerIrql(Irql); 00291 00292 // 00293 // Move context to specfied context record. If an exception 00294 // occurs, then silently handle it and return success. 00295 // 00296 00297 try { 00298 RtlMoveMemory(ThreadContext, 00299 &ContextFrame.Context, 00300 ContextLength); 00301 00302 } except(EXCEPTION_EXECUTE_HANDLER) { 00303 } 00304 00305 } else { 00306 KeInitializeApc(&ContextFrame.Apc, 00307 &Thread->Tcb, 00308 OriginalApcEnvironment, 00309 PspGetSetContextSpecialApc, 00310 NULL, 00311 NULL, 00312 KernelMode, 00313 NULL); 00314 00315 if (!KeInsertQueueApc(&ContextFrame.Apc, NULL, Thread, 2)) { 00316 Status = STATUS_UNSUCCESSFUL; 00317 00318 } else { 00319 KeWaitForSingleObject(&ContextFrame.OperationComplete, 00320 Executive, 00321 KernelMode, 00322 FALSE, 00323 NULL); 00324 // 00325 // Move context to specfied context record. If an 00326 // exception occurs, then silently handle it and 00327 // return success. 00328 // 00329 00330 try { 00331 RtlMoveMemory(ThreadContext, 00332 &ContextFrame.Context, 00333 ContextLength); 00334 00335 } except(EXCEPTION_EXECUTE_HANDLER) { 00336 } 00337 } 00338 } 00339 } 00340 00341 } else { 00342 Status = STATUS_INVALID_HANDLE; 00343 } 00344 00345 ObDereferenceObject(Thread); 00346 } 00347 00348 return Status; 00349 } 00350 00351 NTSTATUS 00352 NtSetContextThread( 00353 IN HANDLE ThreadHandle, 00354 IN PCONTEXT ThreadContext 00355 ) 00356 00357 /*++ 00358 00359 Routine Description: 00360 00361 This function sets the usermode context of the specified thread. This 00362 function will fail if the specified thread is a system thread. It will 00363 return the wrong answer if the thread is a non-system thread that does 00364 not execute in user-mode. 00365 00366 Arguments: 00367 00368 ThreadHandle - Supplies an open handle to the thread object from 00369 which to retrieve context information. The handle 00370 must allow THREAD_SET_CONTEXT access to the thread. 00371 00372 ThreadContext - Supplies the address of a buffer that contains new 00373 context for the specified thread. 00374 00375 Return Value: 00376 00377 None. 00378 00379 --*/ 00380 00381 { 00382 00383 ULONG Alignment; 00384 ULONG ContextFlags; 00385 GETSETCONTEXT ContextFrame; 00386 ULONG ContextLength; 00387 KIRQL Irql; 00388 KPROCESSOR_MODE Mode; 00389 NTSTATUS Status; 00390 PETHREAD Thread; 00391 00392 PAGED_CODE(); 00393 00394 // 00395 // Get previous mode and reference specified thread. 00396 // 00397 00398 Mode = KeGetPreviousMode(); 00399 Status = ObReferenceObjectByHandle(ThreadHandle, 00400 THREAD_SET_CONTEXT, 00401 PsThreadType, 00402 Mode, 00403 (PVOID *)&Thread, 00404 NULL); 00405 00406 // 00407 // If the reference was successful, the check if the specified thread 00408 // is a system thread. 00409 // 00410 00411 if (NT_SUCCESS(Status)) { 00412 00413 // 00414 // If the thread is not a system thread, then attempt to get the 00415 // context of the thread. 00416 // 00417 00418 if (IS_SYSTEM_THREAD(Thread) == FALSE) { 00419 00420 // 00421 // Attempt to get the context of the specified thread. 00422 // 00423 00424 try { 00425 00426 // 00427 // Set the default alignment, capture the context flags, 00428 // and set the default size of the context record. 00429 // 00430 00431 Alignment = CONTEXT_ALIGN; 00432 ContextFlags = ProbeAndReadUlong(&ThreadContext->ContextFlags); 00433 ContextLength = sizeof(CONTEXT); 00434 00435 #if defined(_X86_) 00436 // 00437 // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above 00438 // otherwise (not set) we only want the old part of the context record. 00439 // 00440 if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) { 00441 ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 00442 } 00443 #endif 00444 00445 #if defined(_MIPS_) 00446 00447 // 00448 // The following code is included for backward compatibility 00449 // with old code that does not understand extended context 00450 // records on MIPS systems. 00451 // 00452 00453 if ((ContextFlags & CONTEXT_EXTENDED_INTEGER) != CONTEXT_EXTENDED_INTEGER) { 00454 Alignment = sizeof(ULONG); 00455 ContextLength = FIELD_OFFSET(CONTEXT, ContextFlags) + 4; 00456 } 00457 00458 #endif 00459 00460 if (Mode != KernelMode) { 00461 ProbeForRead(ThreadContext, ContextLength, Alignment); 00462 } 00463 00464 RtlMoveMemory(&ContextFrame.Context, ThreadContext, ContextLength); 00465 00466 } except(EXCEPTION_EXECUTE_HANDLER) { 00467 Status = GetExceptionCode(); 00468 } 00469 00470 // 00471 // If an exception did not occur during the probe of the thread 00472 // context, then set the context of the target thread. 00473 // 00474 00475 if (NT_SUCCESS(Status)) { 00476 KeInitializeEvent(&ContextFrame.OperationComplete, 00477 NotificationEvent, 00478 FALSE); 00479 00480 ContextFrame.Context.ContextFlags = ContextFlags; 00481 00482 ContextFrame.Mode = Mode; 00483 if (Thread == PsGetCurrentThread()) { 00484 ContextFrame.Apc.SystemArgument1 = (PVOID)1; 00485 ContextFrame.Apc.SystemArgument2 = Thread; 00486 KeRaiseIrql(APC_LEVEL, &Irql); 00487 PspGetSetContextSpecialApc(&ContextFrame.Apc, 00488 NULL, 00489 NULL, 00490 &ContextFrame.Apc.SystemArgument1, 00491 &ContextFrame.Apc.SystemArgument2); 00492 00493 KeLowerIrql(Irql); 00494 00495 } else { 00496 KeInitializeApc(&ContextFrame.Apc, 00497 &Thread->Tcb, 00498 OriginalApcEnvironment, 00499 PspGetSetContextSpecialApc, 00500 NULL, 00501 NULL, 00502 KernelMode, 00503 NULL); 00504 00505 if (!KeInsertQueueApc(&ContextFrame.Apc, (PVOID)1, Thread, 2)) { 00506 Status = STATUS_UNSUCCESSFUL; 00507 00508 } else { 00509 KeWaitForSingleObject(&ContextFrame.OperationComplete, 00510 Executive, 00511 KernelMode, 00512 FALSE, 00513 NULL); 00514 } 00515 } 00516 } 00517 00518 } else { 00519 Status = STATUS_INVALID_HANDLE; 00520 } 00521 00522 ObDereferenceObject(Thread); 00523 } 00524 00525 return Status; 00526 }

Generated on Sat May 15 19:41:31 2004 for test by doxygen 1.3.7