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

flushbuf.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 flushbuf.c 00008 00009 Abstract: 00010 00011 This module contains the code to flush the write buffer or otherwise 00012 synchronize writes on the host processor. Also, contains code 00013 to flush instruction cache of specified process. 00014 00015 Author: 00016 00017 David N. Cutler 24-Apr-1991 00018 00019 Revision History: 00020 00021 --*/ 00022 00023 #include "mi.h" 00024 00025 #ifdef ALLOC_PRAGMA 00026 #pragma alloc_text(PAGE,NtFlushWriteBuffer) 00027 #pragma alloc_text(PAGE,NtFlushInstructionCache) 00028 #endif 00029 00030 00031 NTSTATUS 00032 NtFlushWriteBuffer ( 00033 VOID 00034 ) 00035 00036 /*++ 00037 00038 Routine Description: 00039 00040 This function flushes the write buffer on the current processor. 00041 00042 Arguments: 00043 00044 None. 00045 00046 Return Value: 00047 00048 STATUS_SUCCESS. 00049 00050 --*/ 00051 00052 { 00053 PAGED_CODE(); 00054 00055 KeFlushWriteBuffer(); 00056 return STATUS_SUCCESS; 00057 } 00058 00059 ULONG 00060 MiFlushRangeFilter ( 00061 IN PEXCEPTION_POINTERS ExceptionPointers, 00062 IN PVOID *BaseAddress, 00063 IN PULONG Length, 00064 IN PBOOLEAN Retry 00065 ) 00066 00067 /*++ 00068 00069 Routine Description: 00070 00071 This is the exception handler used by NtFlushInstructionCache to protect 00072 against bad virtual addresses passed to KeSweepIcacheRange. If an 00073 access violation occurs, this routine causes NtFlushInstructionCache to 00074 restart the sweep at the page following the failing page. 00075 00076 Arguments: 00077 00078 ExceptionPointers - Supplies exception information. 00079 00080 BaseAddress - Supplies a pointer to address the base of the region 00081 being flushed. If the failing address is not in the last page 00082 of the region, this routine updates BaseAddress to point to the 00083 next page of the region. 00084 00085 Length - Supplies a pointer the length of the region being flushed. 00086 If the failing address is not in the last page of the region, 00087 this routine updates Length to reflect restarting the flush at 00088 the next page of the region. 00089 00090 Retry - Supplies a pointer to a boolean that the caller has initialized 00091 to FALSE. This routine sets this boolean to TRUE if an access 00092 violation occurs in a page before the last page of the flush region. 00093 00094 Return Value: 00095 00096 EXCEPTION_EXECUTE_HANDLER. 00097 00098 --*/ 00099 00100 { 00101 PEXCEPTION_RECORD ExceptionRecord; 00102 ULONG_PTR BadVa; 00103 ULONG_PTR NextVa; 00104 ULONG_PTR EndVa; 00105 00106 ExceptionRecord = ExceptionPointers->ExceptionRecord; 00107 00108 // 00109 // If the exception was an access violation, skip the current page of the 00110 // region and move to the next page. 00111 // 00112 00113 if ( ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION ) { 00114 00115 // 00116 // Get the failing address, calculate the base address of the next page, 00117 // and calculate the address at the end of the region. 00118 // 00119 00120 BadVa = ExceptionRecord->ExceptionInformation[1]; 00121 NextVa = ROUND_TO_PAGES( BadVa + 1 ); 00122 EndVa = *(PULONG_PTR)BaseAddress + *Length; 00123 00124 // 00125 // If the next page didn't wrap, and the next page is below the end of 00126 // the region, update Length and BaseAddress appropriately and set Retry 00127 // to TRUE to indicate to NtFlushInstructionCache that it should call 00128 // KeSweepIcacheRange again. 00129 // 00130 00131 if ( (NextVa > BadVa) && (NextVa < EndVa) ) { 00132 *Length = (ULONG) (EndVa - NextVa); 00133 *BaseAddress = (PVOID)NextVa; 00134 *Retry = TRUE; 00135 } 00136 } 00137 00138 return EXCEPTION_EXECUTE_HANDLER; 00139 } 00140 00141 NTSTATUS 00142 NtFlushInstructionCache ( 00143 IN HANDLE ProcessHandle, 00144 IN PVOID BaseAddress OPTIONAL, 00145 IN ULONG Length 00146 ) 00147 00148 /*++ 00149 00150 Routine Description: 00151 00152 This function flushes the instruction cache for the specified process. 00153 00154 Arguments: 00155 00156 ProcessHandle - Supplies a handle to the process in which the instruction 00157 cache is to be flushed. Must have PROCESS_VM_WRITE access to the 00158 specified process. 00159 00160 BaseAddress - Supplies an optional pointer to base of the region that 00161 is flushed. 00162 00163 Length - Supplies the length of the region that is flushed if the base 00164 address is specified. 00165 00166 Return Value: 00167 00168 STATUS_SUCCESS. 00169 00170 --*/ 00171 00172 { 00173 00174 KPROCESSOR_MODE PreviousMode; 00175 PEPROCESS Process; 00176 NTSTATUS Status; 00177 BOOLEAN Retry; 00178 PVOID RangeBase; 00179 ULONG RangeLength; 00180 00181 PAGED_CODE(); 00182 00183 PreviousMode = KeGetPreviousMode(); 00184 00185 // 00186 // If the base address is not specified, or the base address is specified 00187 // and the length is not zero, then flush the specified instruction cache 00188 // range. 00189 // 00190 00191 if ((ARGUMENT_PRESENT(BaseAddress) == FALSE) || (Length != 0)) { 00192 00193 // 00194 // If previous mode is user and the range specified falls in kernel 00195 // address space, return an error. 00196 // 00197 00198 if ((ARGUMENT_PRESENT(BaseAddress) != FALSE) && 00199 (PreviousMode != KernelMode)) { 00200 try { 00201 ProbeForRead(BaseAddress, Length, sizeof(UCHAR)); 00202 } except(EXCEPTION_EXECUTE_HANDLER) { 00203 return GetExceptionCode(); 00204 } 00205 } 00206 00207 // 00208 // If the specified process is not the current process, then 00209 // the process must be attached to during the flush. 00210 // 00211 00212 if (ProcessHandle != NtCurrentProcess()) { 00213 00214 // 00215 // Reference the specified process checking for PROCESS_VM_WRITE 00216 // access. 00217 // 00218 00219 Status = ObReferenceObjectByHandle(ProcessHandle, 00220 PROCESS_VM_WRITE, 00221 PsProcessType, 00222 PreviousMode, 00223 (PVOID *)&Process, 00224 NULL); 00225 00226 if (!NT_SUCCESS(Status)) { 00227 return Status; 00228 } 00229 00230 // 00231 // Attach to the process. 00232 // 00233 00234 KeAttachProcess(&Process->Pcb); 00235 } 00236 00237 // 00238 // If the base address is not specified, sweep the entire instruction 00239 // cache. If the base address is specified, flush the specified range. 00240 // 00241 00242 if (ARGUMENT_PRESENT(BaseAddress) == FALSE) { 00243 KeSweepIcache(FALSE); 00244 00245 } else { 00246 00247 // 00248 // Parts of the specified range may be invalid. An exception 00249 // handler is used to skip over those parts. Before calling 00250 // KeSweepIcacheRange, we set Retry to FALSE. If an access 00251 // violation occurs in KeSweepIcacheRange, the MiFlushRangeFilter 00252 // exception filter is called. It updates RangeBase and 00253 // RangeLength to skip over the failing page, and sets Retry to 00254 // TRUE. As long as Retry is TRUE, we continue to call 00255 // KeSweepIcacheRange. 00256 // 00257 00258 RangeBase = BaseAddress; 00259 RangeLength = Length; 00260 00261 do { 00262 Retry = FALSE; 00263 try { 00264 KeSweepIcacheRange(FALSE, RangeBase, RangeLength); 00265 } except(MiFlushRangeFilter(GetExceptionInformation(), 00266 &RangeBase, 00267 &RangeLength, 00268 &Retry)) { 00269 if (GetExceptionCode() != STATUS_ACCESS_VIOLATION) { 00270 Status = GetExceptionCode(); 00271 } 00272 } 00273 } while (Retry != FALSE); 00274 } 00275 00276 // 00277 // If the specified process is not the current process, then 00278 // detach from it and dereference it. 00279 // 00280 00281 if (ProcessHandle != NtCurrentProcess()) { 00282 KeDetachProcess(); 00283 ObDereferenceObject(Process); 00284 } 00285 } 00286 00287 return STATUS_SUCCESS; 00288 } 00289

Generated on Sat May 15 19:40:02 2004 for test by doxygen 1.3.7