/* $Id: sysinfo.c,v 1.57 2004/11/06 01:42:04 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/sysinfo.c * PURPOSE: System information functions * PROGRAMMER: David Welch (welch@mcmail.com) * UPDATE HISTORY: * Created 22/05/98 * 20/03/2003: implemented querying SystemProcessInformation, * no more copying to-from the caller (Aleksey * Bragin ) */ /* INCLUDES *****************************************************************/ #include #define NDEBUG #include extern ULONG NtGlobalFlag; /* FIXME: it should go in a ddk/?.h */ ULONGLONG STDCALL KeQueryInterruptTime(VOID); VOID MmPrintMemoryStatistic(VOID); extern ULONG Ke386CpuidFlags; extern ULONG Ke386Cpuid; /* FUNCTIONS *****************************************************************/ /* * @unimplemented */ VOID STDCALL ExEnumHandleTable ( PULONG HandleTable, PVOID Callback, PVOID Param, PHANDLE Handle OPTIONAL ) { UNIMPLEMENTED; } /* * @implemented */ VOID STDCALL ExGetCurrentProcessorCpuUsage ( PULONG CpuUsage ) { PKPCR Pcr; ULONG TotalTime; ULONG PercentTime = 0; ULONGLONG ScaledIdle; Pcr = KeGetCurrentKPCR(); ScaledIdle = Pcr->PrcbData.IdleThread->KernelTime * 100; TotalTime = Pcr->PrcbData.KernelTime + Pcr->PrcbData.UserTime; if (TotalTime) PercentTime = 100 - (ScaledIdle / TotalTime); CpuUsage = &PercentTime; } /* * @implemented */ VOID STDCALL ExGetCurrentProcessorCounts ( PULONG ThreadKernelTime, PULONG TotalCpuTime, PULONG ProcessorNumber ) { PKPCR Pcr; ULONG TotalTime; ULONG ThreadTime; ULONG ProcNumber; Pcr = KeGetCurrentKPCR(); TotalTime = Pcr->PrcbData.KernelTime + Pcr->PrcbData.UserTime; ThreadTime = Pcr->PrcbData.CurrentThread->KernelTime; ProcNumber = Pcr->ProcessorNumber; ThreadKernelTime = &ThreadTime; TotalCpuTime = &TotalTime; ProcessorNumber = &ProcNumber; } NTSTATUS STDCALL NtQuerySystemEnvironmentValue (IN PUNICODE_STRING UnsafeName, OUT PVOID UnsafeValue, IN ULONG Length, IN OUT PULONG UnsafeReturnLength) { NTSTATUS Status; ANSI_STRING AName; UNICODE_STRING WName; BOOLEAN Result; PCH Value; ANSI_STRING AValue; UNICODE_STRING WValue; ULONG ReturnLength; /* * Copy the name to kernel space if necessary and convert it to ANSI. */ if (ExGetPreviousMode() != KernelMode) { Status = RtlCaptureUnicodeString(&WName, UnsafeName); if (!NT_SUCCESS(Status)) { return(Status); } Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); if (!NT_SUCCESS(Status)) { return(Status); } } else { Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); if (!NT_SUCCESS(Status)) { return(Status); } } /* * Create a temporary buffer for the value */ Value = ExAllocatePool(NonPagedPool, Length); if (Value == NULL) { RtlFreeAnsiString(&AName); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); } return(STATUS_NO_MEMORY); } /* * Get the environment variable */ Result = HalGetEnvironmentVariable(AName.Buffer, Value, Length); if (!Result) { RtlFreeAnsiString(&AName); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); } ExFreePool(Value); return(STATUS_UNSUCCESSFUL); } /* * Convert the result to UNICODE. */ RtlInitAnsiString(&AValue, Value); Status = RtlAnsiStringToUnicodeString(&WValue, &AValue, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeAnsiString(&AName); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); } ExFreePool(Value); return(Status); } ReturnLength = WValue.Length; /* * Copy the result back to the caller. */ if (ExGetPreviousMode() != KernelMode) { Status = MmCopyToCaller(UnsafeValue, WValue.Buffer, ReturnLength); if (!NT_SUCCESS(Status)) { RtlFreeAnsiString(&AName); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); } ExFreePool(Value); RtlFreeUnicodeString(&WValue); return(Status); } Status = MmCopyToCaller(UnsafeReturnLength, &ReturnLength, sizeof(ULONG)); if (!NT_SUCCESS(Status)) { RtlFreeAnsiString(&AName); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); } ExFreePool(Value); RtlFreeUnicodeString(&WValue); return(Status); } } else { memcpy(UnsafeValue, WValue.Buffer, ReturnLength); memcpy(UnsafeReturnLength, &ReturnLength, sizeof(ULONG)); } /* * Free temporary buffers. */ RtlFreeAnsiString(&AName); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); } ExFreePool(Value); RtlFreeUnicodeString(&WValue); return(STATUS_SUCCESS); } NTSTATUS STDCALL NtSetSystemEnvironmentValue (IN PUNICODE_STRING UnsafeName, IN PUNICODE_STRING UnsafeValue) { UNICODE_STRING WName; ANSI_STRING AName; UNICODE_STRING WValue; ANSI_STRING AValue; BOOLEAN Result; NTSTATUS Status; /* * Check for required privilege. */ /* FIXME: Not implemented. */ /* * Copy the name to kernel space if necessary and convert it to ANSI. */ if (ExGetPreviousMode() != KernelMode) { Status = RtlCaptureUnicodeString(&WName, UnsafeName); if (!NT_SUCCESS(Status)) { return(Status); } Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); if (!NT_SUCCESS(Status)) { return(Status); } } else { Status = RtlUnicodeStringToAnsiString(&AName, UnsafeName, TRUE); if (!NT_SUCCESS(Status)) { return(Status); } } /* * Copy the value to kernel space and convert to ANSI. */ if (ExGetPreviousMode() != KernelMode) { Status = RtlCaptureUnicodeString(&WValue, UnsafeValue); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&WName); RtlFreeAnsiString(&AName); return(Status); } Status = RtlUnicodeStringToAnsiString(&AValue, UnsafeValue, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeUnicodeString(&WName); RtlFreeAnsiString(&AName); RtlFreeUnicodeString(&WValue); return(Status); } } else { Status = RtlUnicodeStringToAnsiString(&AValue, UnsafeValue, TRUE); if (!NT_SUCCESS(Status)) { RtlFreeAnsiString(&AName); return(Status); } } /* * Set the environment variable */ Result = HalSetEnvironmentVariable(AName.Buffer, AValue.Buffer); /* * Free everything and return status. */ RtlFreeAnsiString(&AName); RtlFreeAnsiString(&AValue); if (ExGetPreviousMode() != KernelMode) { RtlFreeUnicodeString(&WName); RtlFreeUnicodeString(&WValue); } if (!Result) { return(STATUS_UNSUCCESSFUL); } return(STATUS_SUCCESS); } /* --- Query/Set System Information --- */ /* * NOTE: QSI_DEF(n) and SSI_DEF(n) define _cdecl function symbols * so the stack is popped only in one place on x86 platform. */ #define QSI_USE(n) QSI##n #define QSI_DEF(n) \ static NTSTATUS QSI_USE(n) (PVOID Buffer, ULONG Size, PULONG ReqSize) #define SSI_USE(n) SSI##n #define SSI_DEF(n) \ static NTSTATUS SSI_USE(n) (PVOID Buffer, ULONG Size) /* Class 0 - Basic Information */ QSI_DEF(SystemBasicInformation) { PSYSTEM_BASIC_INFORMATION Sbi = (PSYSTEM_BASIC_INFORMATION) Buffer; *ReqSize = sizeof (SYSTEM_BASIC_INFORMATION); /* * Check user buffer's size */ if (Size < sizeof (SYSTEM_BASIC_INFORMATION)) { return (STATUS_INFO_LENGTH_MISMATCH); } Sbi->Unknown = 0; Sbi->MaximumIncrement = KeMaximumIncrement; Sbi->PhysicalPageSize = PAGE_SIZE; /* FIXME: it should be PAGE_SIZE */ Sbi->NumberOfPhysicalPages = MmStats.NrTotalPages; Sbi->LowestPhysicalPage = 0; /* FIXME */ Sbi->HighestPhysicalPage = MmStats.NrTotalPages; /* FIXME */ Sbi->AllocationGranularity = MM_VIRTMEM_GRANULARITY; /* hard coded on Intel? */ Sbi->LowestUserAddress = 0x10000; /* Top of 64k */ Sbi->HighestUserAddress = (ULONG_PTR)MmHighestUserAddress; Sbi->ActiveProcessors = KeActiveProcessors; Sbi->NumberProcessors = KeNumberProcessors; return (STATUS_SUCCESS); } /* Class 1 - Processor Information */ QSI_DEF(SystemProcessorInformation) { PSYSTEM_PROCESSOR_INFORMATION Spi = (PSYSTEM_PROCESSOR_INFORMATION) Buffer; *ReqSize = sizeof (SYSTEM_PROCESSOR_INFORMATION); /* * Check user buffer's size */ if (Size < sizeof (SYSTEM_PROCESSOR_INFORMATION)) { return (STATUS_INFO_LENGTH_MISMATCH); } Spi->ProcessorArchitecture = 0; /* Intel Processor */ Spi->ProcessorLevel = ((Ke386Cpuid >> 8) & 0xf); Spi->ProcessorRevision = (Ke386Cpuid & 0xf) | ((Ke386Cpuid << 4) & 0xf00); Spi->Unknown = 0; Spi->FeatureBits = Ke386CpuidFlags; DPRINT("Arch %d Level %d Rev 0x%x\n", Spi->ProcessorArchitecture, Spi->ProcessorLevel, Spi->ProcessorRevision); return (STATUS_SUCCESS); } /* Class 2 - Performance Information */ QSI_DEF(SystemPerformanceInformation) { PSYSTEM_PERFORMANCE_INFORMATION Spi = (PSYSTEM_PERFORMANCE_INFORMATION) Buffer; PEPROCESS TheIdleProcess; *ReqSize = sizeof (SYSTEM_PERFORMANCE_INFORMATION); /* * Check user buffer's size */ if (Size < sizeof (SYSTEM_PERFORMANCE_INFORMATION)) { return (STATUS_INFO_LENGTH_MISMATCH); } PsLookupProcessByProcessId((PVOID) 1, &TheIdleProcess); Spi->IdleTime.QuadPart = TheIdleProcess->Pcb.KernelTime * 100000LL; Spi->ReadTransferCount.QuadPart = IoReadTransferCount; Spi->WriteTransferCount.QuadPart = IoWriteTransferCount; Spi->OtherTransferCount.QuadPart = IoOtherTransferCount; Spi->ReadOperationCount = IoReadOperationCount; Spi->WriteOperationCount = IoWriteOperationCount; Spi->OtherOperationCount = IoOtherOperationCount; Spi->AvailablePages = MmStats.NrFreePages; /* Add up all the used "Commitied" memory + pagefile. Not sure this is right. 8^\ */ Spi->TotalCommittedPages = MiMemoryConsumers[MC_PPOOL].PagesUsed + MiMemoryConsumers[MC_NPPOOL].PagesUsed+ MiMemoryConsumers[MC_CACHE].PagesUsed+ MiMemoryConsumers[MC_USER].PagesUsed+ MiUsedSwapPages; /* Add up the full system total + pagefile. All this make Taskmgr happy but not sure it is the right numbers. This too, fixes some of GlobalMemoryStatusEx numbers. */ Spi->TotalCommitLimit = MmStats.NrTotalPages + MiFreeSwapPages + MiUsedSwapPages; Spi->PeakCommitment = 0; /* FIXME */ Spi->PageFaults = 0; /* FIXME */ Spi->WriteCopyFaults = 0; /* FIXME */ Spi->TransitionFaults = 0; /* FIXME */ Spi->CacheTransitionFaults = 0; /* FIXME */ Spi->DemandZeroFaults = 0; /* FIXME */ Spi->PagesRead = 0; /* FIXME */ Spi->PageReadIos = 0; /* FIXME */ Spi->CacheReads = 0; /* FIXME */ Spi->CacheIos = 0; /* FIXME */ Spi->PagefilePagesWritten = 0; /* FIXME */ Spi->PagefilePageWriteIos = 0; /* FIXME */ Spi->MappedFilePagesWritten = 0; /* FIXME */ Spi->MappedFilePageWriteIos = 0; /* FIXME */ Spi->PagedPoolUsage = MiMemoryConsumers[MC_PPOOL].PagesUsed; Spi->PagedPoolAllocs = 0; /* FIXME */ Spi->PagedPoolFrees = 0; /* FIXME */ Spi->NonPagedPoolUsage = MiMemoryConsumers[MC_NPPOOL].PagesUsed; Spi->NonPagedPoolAllocs = 0; /* FIXME */ Spi->NonPagedPoolFrees = 0; /* FIXME */ Spi->TotalFreeSystemPtes = 0; /* FIXME */ Spi->SystemCodePage = MmStats.NrSystemPages; /* FIXME */ Spi->TotalSystemDriverPages = 0; /* FIXME */ Spi->TotalSystemCodePages = 0; /* FIXME */ Spi->SmallNonPagedLookasideListAllocateHits = 0; /* FIXME */ Spi->SmallPagedLookasideListAllocateHits = 0; /* FIXME */ Spi->Reserved3 = 0; /* FIXME */ Spi->MmSystemCachePage = MiMemoryConsumers[MC_CACHE].PagesUsed; Spi->PagedPoolPage = MmPagedPoolSize; /* FIXME */ Spi->SystemDriverPage = 0; /* FIXME */ Spi->FastReadNoWait = 0; /* FIXME */ Spi->FastReadWait = 0; /* FIXME */ Spi->FastReadResourceMiss = 0; /* FIXME */ Spi->FastReadNotPossible = 0; /* FIXME */ Spi->FastMdlReadNoWait = 0; /* FIXME */ Spi->FastMdlReadWait = 0; /* FIXME */ Spi->FastMdlReadResourceMiss = 0; /* FIXME */ Spi->FastMdlReadNotPossible = 0; /* FIXME */ Spi->MapDataNoWait = 0; /* FIXME */ Spi->MapDataWait = 0; /* FIXME */ Spi->MapDataNoWaitMiss = 0; /* FIXME */ Spi->MapDataWaitMiss = 0; /* FIXME */ Spi->PinMappedDataCount = 0; /* FIXME */ Spi->PinReadNoWait = 0; /* FIXME */ Spi->PinReadWait = 0; /* FIXME */ Spi->PinReadNoWaitMiss = 0; /* FIXME */ Spi->PinReadWaitMiss = 0; /* FIXME */ Spi->CopyReadNoWait = 0; /* FIXME */ Spi->CopyReadWait = 0; /* FIXME */ Spi->CopyReadNoWaitMiss = 0; /* FIXME */ Spi->CopyReadWaitMiss = 0; /* FIXME */ Spi->MdlReadNoWait = 0; /* FIXME */ Spi->MdlReadWait = 0; /* FIXME */ Spi->MdlReadNoWaitMiss = 0; /* FIXME */ Spi->MdlReadWaitMiss = 0; /* FIXME */ Spi->ReadAheadIos = 0; /* FIXME */ Spi->LazyWriteIos = 0; /* FIXME */ Spi->LazyWritePages = 0; /* FIXME */ Spi->DataFlushes = 0; /* FIXME */ Spi->DataPages = 0; /* FIXME */ Spi->ContextSwitches = 0; /* FIXME */ Spi->FirstLevelTbFills = 0; /* FIXME */ Spi->SecondLevelTbFills = 0; /* FIXME */ Spi->SystemCalls = 0; /* FIXME */ ObDereferenceObject(TheIdleProcess); return (STATUS_SUCCESS); } /* Class 3 - Time Of Day Information */ QSI_DEF(SystemTimeOfDayInformation) { LARGE_INTEGER CurrentTime; PSYSTEM_TIMEOFDAY_INFORMATION Sti = (PSYSTEM_TIMEOFDAY_INFORMATION) Buffer; *ReqSize = sizeof (SYSTEM_TIMEOFDAY_INFORMATION); /* * Check user buffer's size */ if (Size < sizeof (SYSTEM_TIMEOFDAY_INFORMATION)) { return (STATUS_INFO_LENGTH_MISMATCH); } KeQuerySystemTime(&CurrentTime); Sti->BootTime= SystemBootTime; Sti->CurrentTime = CurrentTime; Sti->TimeZoneBias.QuadPart = 0; /* FIXME */ Sti->TimeZoneId = 0; /* FIXME */ Sti->Reserved = 0; /* FIXME */ return (STATUS_SUCCESS); } /* Class 4 - Path Information */ QSI_DEF(SystemPathInformation) { /* FIXME: QSI returns STATUS_BREAKPOINT. Why? */ DPRINT1("NtQuerySystemInformation - SystemPathInformation not implemented\n"); return (STATUS_BREAKPOINT); } /* Class 5 - Process Information */ QSI_DEF(SystemProcessInformation) { ULONG ovlSize=0, nThreads; PEPROCESS pr, syspr; unsigned char *pCur; /* scan the process list */ PSYSTEM_PROCESSES Spi = (PSYSTEM_PROCESSES) Buffer; *ReqSize = sizeof(SYSTEM_PROCESSES); if (Size < sizeof(SYSTEM_PROCESSES)) { return (STATUS_INFO_LENGTH_MISMATCH); // in case buffer size is too small } syspr = PsGetNextProcess(NULL); pr = syspr; pCur = (unsigned char *)Spi; do { PSYSTEM_PROCESSES SpiCur; int curSize, i = 0; ANSI_STRING imgName; int inLen=32; // image name len in bytes PLIST_ENTRY current_entry; PETHREAD current; SpiCur = (PSYSTEM_PROCESSES)pCur; nThreads = PsEnumThreadsByProcess(pr); // size of the structure for every process curSize = sizeof(SYSTEM_PROCESSES)-sizeof(SYSTEM_THREADS)+sizeof(SYSTEM_THREADS)*nThreads; ovlSize += curSize+inLen; if (ovlSize > Size) { *ReqSize = ovlSize; ObDereferenceObject(pr); return (STATUS_INFO_LENGTH_MISMATCH); // in case buffer size is too small } // fill system information SpiCur->NextEntryDelta = curSize+inLen; // relative offset to the beginnnig of the next structure SpiCur->ThreadCount = nThreads; SpiCur->CreateTime = pr->CreateTime; SpiCur->UserTime.QuadPart = pr->Pcb.UserTime * 100000LL; SpiCur->KernelTime.QuadPart = pr->Pcb.KernelTime * 100000LL; SpiCur->ProcessName.Length = strlen(pr->ImageFileName) * sizeof(WCHAR); SpiCur->ProcessName.MaximumLength = inLen; SpiCur->ProcessName.Buffer = (void*)(pCur+curSize); // copy name to the end of the struct RtlInitAnsiString(&imgName, pr->ImageFileName); RtlAnsiStringToUnicodeString(&SpiCur->ProcessName, &imgName, FALSE); SpiCur->BasePriority = pr->Pcb.BasePriority; SpiCur->ProcessId = pr->UniqueProcessId; SpiCur->InheritedFromProcessId = (DWORD)(pr->InheritedFromUniqueProcessId); SpiCur->HandleCount = ObpGetHandleCountByHandleTable(&pr->HandleTable); SpiCur->VmCounters.PeakVirtualSize = pr->PeakVirtualSize; SpiCur->VmCounters.VirtualSize = pr->VirtualSize.QuadPart; SpiCur->VmCounters.PageFaultCount = pr->LastFaultCount; SpiCur->VmCounters.PeakWorkingSetSize = pr->Vm.PeakWorkingSetSize; // Is this right using ->Vm. here ? SpiCur->VmCounters.WorkingSetSize = pr->Vm.WorkingSetSize; // Is this right using ->Vm. here ? SpiCur->VmCounters.QuotaPeakPagedPoolUsage = pr->QuotaPeakPoolUsage[0]; SpiCur->VmCounters.QuotaPagedPoolUsage = pr->QuotaPoolUsage[0]; SpiCur->VmCounters.QuotaPeakNonPagedPoolUsage = pr->QuotaPeakPoolUsage[1]; SpiCur->VmCounters.QuotaNonPagedPoolUsage = pr->QuotaPoolUsage[1]; SpiCur->VmCounters.PagefileUsage = pr->PagefileUsage; // FIXME SpiCur->VmCounters.PeakPagefileUsage = pr->PeakPagefileUsage; // KJK::Hyperion: I don't know what does this mean. VM_COUNTERS // doesn't seem to contain any equivalent field //SpiCur->TotalPrivateBytes = pr->NumberOfPrivatePages; //FIXME: bytes != pages current_entry = pr->ThreadListHead.Flink; while (current_entry != &pr->ThreadListHead) { current = CONTAINING_RECORD(current_entry, ETHREAD, ThreadListEntry); SpiCur->Threads[i].KernelTime.QuadPart = current->Tcb.KernelTime * 100000LL; SpiCur->Threads[i].UserTime.QuadPart = current->Tcb.UserTime * 100000LL; // SpiCur->Threads[i].CreateTime = current->CreateTime; SpiCur->Threads[i].WaitTime = current->Tcb.WaitTime; SpiCur->Threads[i].StartAddress = (PVOID) current->StartAddress; SpiCur->Threads[i].ClientId = current->Cid; SpiCur->Threads[i].Priority = current->Tcb.Priority; SpiCur->Threads[i].BasePriority = current->Tcb.BasePriority; SpiCur->Threads[i].ContextSwitchCount = current->Tcb.ContextSwitches; SpiCur->Threads[i].State = current->Tcb.State; SpiCur->Threads[i].WaitReason = current->Tcb.WaitReason; i++; current_entry = current_entry->Flink; } pr = PsGetNextProcess(pr); if ((pr == syspr) || (pr == NULL)) { SpiCur->NextEntryDelta = 0; break; } else pCur = pCur + curSize + inLen; } while ((pr != syspr) && (pr != NULL)); *ReqSize = ovlSize; if (pr != NULL) { ObDereferenceObject(pr); } return (STATUS_SUCCESS); } /* Class 6 - Call Count Information */ QSI_DEF(SystemCallCountInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemCallCountInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 7 - Device Information */ QSI_DEF(SystemDeviceInformation) { PSYSTEM_DEVICE_INFORMATION Sdi = (PSYSTEM_DEVICE_INFORMATION) Buffer; PCONFIGURATION_INFORMATION ConfigInfo; *ReqSize = sizeof (SYSTEM_DEVICE_INFORMATION); /* * Check user buffer's size */ if (Size < sizeof (SYSTEM_DEVICE_INFORMATION)) { return (STATUS_INFO_LENGTH_MISMATCH); } ConfigInfo = IoGetConfigurationInformation (); Sdi->NumberOfDisks = ConfigInfo->DiskCount; Sdi->NumberOfFloppies = ConfigInfo->FloppyCount; Sdi->NumberOfCdRoms = ConfigInfo->CdRomCount; Sdi->NumberOfTapes = ConfigInfo->TapeCount; Sdi->NumberOfSerialPorts = ConfigInfo->SerialCount; Sdi->NumberOfParallelPorts = ConfigInfo->ParallelCount; return (STATUS_SUCCESS); } /* Class 8 - Processor Performance Information */ QSI_DEF(SystemProcessorPerformanceInformation) { PSYSTEM_PROCESSORTIME_INFO Spi = (PSYSTEM_PROCESSORTIME_INFO) Buffer; ULONG i; TIME CurrentTime; PKPCR Pcr; *ReqSize = KeNumberProcessors * sizeof (SYSTEM_PROCESSORTIME_INFO); /* * Check user buffer's size */ if (Size < KeNumberProcessors * sizeof(SYSTEM_PROCESSORTIME_INFO)) { return (STATUS_INFO_LENGTH_MISMATCH); } CurrentTime.QuadPart = KeQueryInterruptTime(); Pcr = (PKPCR)KPCR_BASE; for (i = 0; i < KeNumberProcessors; i++) { Spi->TotalProcessorRunTime.QuadPart = (Pcr->PrcbData.IdleThread->KernelTime + Pcr->PrcbData.IdleThread->UserTime) * 100000LL; // IdleTime Spi->TotalProcessorTime.QuadPart = Pcr->PrcbData.KernelTime * 100000LL; // KernelTime Spi->TotalProcessorUserTime.QuadPart = Pcr->PrcbData.UserTime * 100000LL; Spi->TotalDPCTime.QuadPart = Pcr->PrcbData.DpcTime * 100000LL; Spi->TotalInterruptTime.QuadPart = Pcr->PrcbData.InterruptTime * 100000LL; Spi->TotalInterrupts = Pcr->PrcbData.InterruptCount; // Interrupt Count Spi++; // Pcr++; Pcr = (PKPCR)((ULONG_PTR)Pcr + PAGE_SIZE); } return (STATUS_SUCCESS); } /* Class 9 - Flags Information */ QSI_DEF(SystemFlagsInformation) { if (sizeof (SYSTEM_FLAGS_INFORMATION) != Size) { * ReqSize = sizeof (SYSTEM_FLAGS_INFORMATION); return (STATUS_INFO_LENGTH_MISMATCH); } ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags = NtGlobalFlag; return (STATUS_SUCCESS); } SSI_DEF(SystemFlagsInformation) { if (sizeof (SYSTEM_FLAGS_INFORMATION) != Size) { return (STATUS_INFO_LENGTH_MISMATCH); } NtGlobalFlag = ((PSYSTEM_FLAGS_INFORMATION) Buffer)->Flags; return (STATUS_SUCCESS); } /* Class 10 - Call Time Information */ QSI_DEF(SystemCallTimeInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemCallTimeInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 11 - Module Information */ QSI_DEF(SystemModuleInformation) { return LdrpQueryModuleInformation(Buffer, Size, ReqSize); } /* Class 12 - Locks Information */ QSI_DEF(SystemLocksInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemLocksInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 13 - Stack Trace Information */ QSI_DEF(SystemStackTraceInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemStackTraceInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 14 - Paged Pool Information */ QSI_DEF(SystemPagedPoolInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemPagedPoolInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 15 - Non Paged Pool Information */ QSI_DEF(SystemNonPagedPoolInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemNonPagedPoolInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 16 - Handle Information */ QSI_DEF(SystemHandleInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemHandleInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 17 - Information */ QSI_DEF(SystemObjectInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemObjectInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 18 - Information */ QSI_DEF(SystemPageFileInformation) { SYSTEM_PAGEFILE_INFORMATION *Spfi = (SYSTEM_PAGEFILE_INFORMATION *) Buffer; if (Size < sizeof (SYSTEM_PAGEFILE_INFORMATION)) { * ReqSize = sizeof (SYSTEM_PAGEFILE_INFORMATION); return (STATUS_INFO_LENGTH_MISMATCH); } UNICODE_STRING FileName; /* FIXME */ /* FIXME */ Spfi->NextEntryOffset = 0; Spfi->TotalSize = MiFreeSwapPages + MiUsedSwapPages; Spfi->TotalInUse = MiUsedSwapPages; Spfi->PeakUsage = MiUsedSwapPages; /* FIXME */ Spfi->PageFileName = FileName; return (STATUS_SUCCESS); } /* Class 19 - Vdm Instemul Information */ QSI_DEF(SystemVdmInstemulInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemVdmInstemulInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 20 - Vdm Bop Information */ QSI_DEF(SystemVdmBopInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemVdmBopInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 21 - File Cache Information */ QSI_DEF(SystemFileCacheInformation) { SYSTEM_CACHE_INFORMATION *Sci = (SYSTEM_CACHE_INFORMATION *) Buffer; if (Size < sizeof (SYSTEM_CACHE_INFORMATION)) { * ReqSize = sizeof (SYSTEM_CACHE_INFORMATION); return (STATUS_INFO_LENGTH_MISMATCH); } /* Return the Byte size not the page size. */ Sci->CurrentSize = MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; Sci->PeakSize = MiMemoryConsumers[MC_CACHE].PagesUsed * PAGE_SIZE; /* FIXME */ Sci->PageFaultCount = 0; /* FIXME */ Sci->MinimumWorkingSet = 0; /* FIXME */ Sci->MaximumWorkingSet = 0; /* FIXME */ Sci->TransitionSharedPages = 0; /* FIXME */ Sci->TransitionSharedPagesPeak = 0; /* FIXME */ return (STATUS_SUCCESS); } SSI_DEF(SystemFileCacheInformation) { if (Size < sizeof (SYSTEM_CACHE_INFORMATION)) { return (STATUS_INFO_LENGTH_MISMATCH); } /* FIXME */ DPRINT1("NtSetSystemInformation - SystemFileCacheInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 22 - Pool Tag Information */ QSI_DEF(SystemPoolTagInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemPoolTagInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 23 - Interrupt Information */ QSI_DEF(SystemInterruptInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemInterruptInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 24 - DPC Behaviour Information */ QSI_DEF(SystemDpcBehaviourInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemDpcBehaviourInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } SSI_DEF(SystemDpcBehaviourInformation) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemDpcBehaviourInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 25 - Full Memory Information */ QSI_DEF(SystemFullMemoryInformation) { PULONG Spi = (PULONG) Buffer; PEPROCESS TheIdleProcess; * ReqSize = sizeof (ULONG); if (sizeof (ULONG) != Size) { return (STATUS_INFO_LENGTH_MISMATCH); } DPRINT("SystemFullMemoryInformation\n"); PsLookupProcessByProcessId((PVOID) 1, &TheIdleProcess); DPRINT("PID: %d, KernelTime: %u PFFree: %d PFUsed: %d\n", TheIdleProcess->UniqueProcessId, TheIdleProcess->Pcb.KernelTime, MiFreeSwapPages, MiUsedSwapPages); #ifndef NDEBUG MmPrintMemoryStatistic(); #endif *Spi = MiMemoryConsumers[MC_USER].PagesUsed; ObDereferenceObject(TheIdleProcess); return (STATUS_SUCCESS); } /* Class 26 - Load Image */ SSI_DEF(SystemLoadImage) { PSYSTEM_LOAD_IMAGE Sli = (PSYSTEM_LOAD_IMAGE)Buffer; if (sizeof(SYSTEM_LOAD_IMAGE) != Size) { return(STATUS_INFO_LENGTH_MISMATCH); } return(LdrpLoadImage(&Sli->ModuleName, &Sli->ModuleBase, &Sli->SectionPointer, &Sli->EntryPoint, &Sli->ExportDirectory)); } /* Class 27 - Unload Image */ SSI_DEF(SystemUnloadImage) { PSYSTEM_UNLOAD_IMAGE Sui = (PSYSTEM_UNLOAD_IMAGE)Buffer; if (sizeof(SYSTEM_UNLOAD_IMAGE) != Size) { return(STATUS_INFO_LENGTH_MISMATCH); } return(LdrpUnloadImage(Sui->ModuleBase)); } /* Class 28 - Time Adjustment Information */ QSI_DEF(SystemTimeAdjustmentInformation) { if (sizeof (SYSTEM_SET_TIME_ADJUSTMENT) > Size) { * ReqSize = sizeof (SYSTEM_SET_TIME_ADJUSTMENT); return (STATUS_INFO_LENGTH_MISMATCH); } /* FIXME: */ DPRINT1("NtQuerySystemInformation - SystemTimeAdjustmentInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } SSI_DEF(SystemTimeAdjustmentInformation) { if (sizeof (SYSTEM_SET_TIME_ADJUSTMENT) > Size) { return (STATUS_INFO_LENGTH_MISMATCH); } /* FIXME: */ DPRINT1("NtSetSystemInformation - SystemTimeAdjustmentInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 29 - Summary Memory Information */ QSI_DEF(SystemSummaryMemoryInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemSummaryMemoryInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 30 - Next Event Id Information */ QSI_DEF(SystemNextEventIdInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemNextEventIdInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 31 - Event Ids Information */ QSI_DEF(SystemEventIdsInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemEventIdsInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 32 - Crash Dump Information */ QSI_DEF(SystemCrashDumpInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemCrashDumpInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 33 - Exception Information */ QSI_DEF(SystemExceptionInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemExceptionInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 34 - Crash Dump State Information */ QSI_DEF(SystemCrashDumpStateInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemCrashDumpStateInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 35 - Kernel Debugger Information */ QSI_DEF(SystemKernelDebuggerInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemKernelDebuggerInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 36 - Context Switch Information */ QSI_DEF(SystemContextSwitchInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemContextSwitchInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 37 - Registry Quota Information */ QSI_DEF(SystemRegistryQuotaInformation) { PSYSTEM_REGISTRY_QUOTA_INFORMATION srqi = (PSYSTEM_REGISTRY_QUOTA_INFORMATION) Buffer; *ReqSize = sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION); if (Size < sizeof(SYSTEM_REGISTRY_QUOTA_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } DPRINT1("Faking max registry size of 32 MB\n"); srqi->RegistryQuotaAllowed = 0x2000000; srqi->RegistryQuotaUsed = 0x200000; srqi->Reserved1 = (void*)0x200000; return STATUS_SUCCESS; } SSI_DEF(SystemRegistryQuotaInformation) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemRegistryQuotaInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 38 - Load And Call Image */ SSI_DEF(SystemLoadAndCallImage) { PSYSTEM_LOAD_AND_CALL_IMAGE Slci = (PSYSTEM_LOAD_AND_CALL_IMAGE)Buffer; if (sizeof(SYSTEM_LOAD_AND_CALL_IMAGE) != Size) { return(STATUS_INFO_LENGTH_MISMATCH); } return(LdrpLoadAndCallImage(&Slci->ModuleName)); } /* Class 39 - Priority Separation */ SSI_DEF(SystemPrioritySeperation) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemPrioritySeperation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 40 - Plug Play Bus Information */ QSI_DEF(SystemPlugPlayBusInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemPlugPlayBusInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 41 - Dock Information */ QSI_DEF(SystemDockInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemDockInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 42 - Power Information */ QSI_DEF(SystemPowerInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemPowerInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 43 - Processor Speed Information */ QSI_DEF(SystemProcessorSpeedInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemProcessorSpeedInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 44 - Current Time Zone Information */ QSI_DEF(SystemCurrentTimeZoneInformation) { * ReqSize = sizeof (TIME_ZONE_INFORMATION); if (sizeof (TIME_ZONE_INFORMATION) != Size) { return STATUS_INFO_LENGTH_MISMATCH; } /* Copy the time zone information struct */ memcpy(Buffer, &ExpTimeZoneInfo, sizeof(TIME_ZONE_INFORMATION)); return STATUS_SUCCESS; } SSI_DEF(SystemCurrentTimeZoneInformation) { /* Check user buffer's size */ if (Size < sizeof (TIME_ZONE_INFORMATION)) { return STATUS_INFO_LENGTH_MISMATCH; } /* Copy the time zone information struct */ memcpy(&ExpTimeZoneInfo, (TIME_ZONE_INFORMATION *)Buffer, sizeof(TIME_ZONE_INFORMATION)); return STATUS_SUCCESS; } /* Class 45 - Lookaside Information */ QSI_DEF(SystemLookasideInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemLookasideInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 46 - Set time slip event */ SSI_DEF(SystemSetTimeSlipEvent) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemSetTimSlipEvent not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 47 - Create a new session (TSE) */ SSI_DEF(SystemCreateSession) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemCreateSession not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 48 - Delete an existing session (TSE) */ SSI_DEF(SystemDeleteSession) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemDeleteSession not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 49 - UNKNOWN */ QSI_DEF(SystemInvalidInfoClass4) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemInvalidInfoClass4 not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 50 - System range start address */ QSI_DEF(SystemRangeStartInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemRangeStartInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 51 - Driver verifier information */ QSI_DEF(SystemVerifierInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemVerifierInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } SSI_DEF(SystemVerifierInformation) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemVerifierInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 52 - Add a driver verifier */ SSI_DEF(SystemAddVerifier) { /* FIXME */ DPRINT1("NtSetSystemInformation - SystemAddVerifier not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Class 53 - A session's processes */ QSI_DEF(SystemSessionProcessesInformation) { /* FIXME */ DPRINT1("NtQuerySystemInformation - SystemSessionProcessInformation not implemented\n"); return (STATUS_NOT_IMPLEMENTED); } /* Query/Set Calls Table */ typedef struct _QSSI_CALLS { NTSTATUS (* Query) (PVOID,ULONG,PULONG); NTSTATUS (* Set) (PVOID,ULONG); } QSSI_CALLS; // QS Query & Set // QX Query // XS Set // XX unknown behaviour // #define SI_QS(n) {QSI_USE(n),SSI_USE(n)} #define SI_QX(n) {QSI_USE(n),NULL} #define SI_XS(n) {NULL,SSI_USE(n)} #define SI_XX(n) {NULL,NULL} static QSSI_CALLS CallQS [] = { SI_QX(SystemBasicInformation), SI_QX(SystemProcessorInformation), SI_QX(SystemPerformanceInformation), SI_QX(SystemTimeOfDayInformation), SI_QX(SystemPathInformation), /* should be SI_XX */ SI_QX(SystemProcessInformation), SI_QX(SystemCallCountInformation), SI_QX(SystemDeviceInformation), SI_QX(SystemProcessorPerformanceInformation), SI_QS(SystemFlagsInformation), SI_QX(SystemCallTimeInformation), /* should be SI_XX */ SI_QX(SystemModuleInformation), SI_QX(SystemLocksInformation), SI_QX(SystemStackTraceInformation), /* should be SI_XX */ SI_QX(SystemPagedPoolInformation), /* should be SI_XX */ SI_QX(SystemNonPagedPoolInformation), /* should be SI_XX */ SI_QX(SystemHandleInformation), SI_QX(SystemObjectInformation), SI_QX(SystemPageFileInformation), SI_QX(SystemVdmInstemulInformation), SI_QX(SystemVdmBopInformation), /* it should be SI_XX */ SI_QS(SystemFileCacheInformation), SI_QX(SystemPoolTagInformation), SI_QX(SystemInterruptInformation), SI_QS(SystemDpcBehaviourInformation), SI_QX(SystemFullMemoryInformation), /* it should be SI_XX */ SI_XS(SystemLoadImage), SI_XS(SystemUnloadImage), SI_QS(SystemTimeAdjustmentInformation), SI_QX(SystemSummaryMemoryInformation), /* it should be SI_XX */ SI_QX(SystemNextEventIdInformation), /* it should be SI_XX */ SI_QX(SystemEventIdsInformation), /* it should be SI_XX */ SI_QX(SystemCrashDumpInformation), SI_QX(SystemExceptionInformation), SI_QX(SystemCrashDumpStateInformation), SI_QX(SystemKernelDebuggerInformation), SI_QX(SystemContextSwitchInformation), SI_QS(SystemRegistryQuotaInformation), SI_XS(SystemLoadAndCallImage), SI_XS(SystemPrioritySeperation), SI_QX(SystemPlugPlayBusInformation), /* it should be SI_XX */ SI_QX(SystemDockInformation), /* it should be SI_XX */ SI_QX(SystemPowerInformation), /* it should be SI_XX */ SI_QX(SystemProcessorSpeedInformation), /* it should be SI_XX */ SI_QS(SystemCurrentTimeZoneInformation), /* it should be SI_QX */ SI_QX(SystemLookasideInformation), SI_XS(SystemSetTimeSlipEvent), SI_XS(SystemCreateSession), SI_XS(SystemDeleteSession), SI_QX(SystemInvalidInfoClass4), /* it should be SI_XX */ SI_QX(SystemRangeStartInformation), SI_QS(SystemVerifierInformation), SI_XS(SystemAddVerifier), SI_QX(SystemSessionProcessesInformation) }; /* * @implemented */ NTSTATUS STDCALL NtQuerySystemInformation (IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID UnsafeSystemInformation, IN ULONG Length, OUT PULONG UnsafeResultLength) { ULONG ResultLength; PVOID SystemInformation; NTSTATUS Status; NTSTATUS FStatus; /* DPRINT("NtQuerySystemInformation Start. Class:%d\n", SystemInformationClass ); */ /*if (ExGetPreviousMode() == KernelMode) {*/ SystemInformation = UnsafeSystemInformation; /*} else { SystemInformation = ExAllocatePool(NonPagedPool, Length); if (SystemInformation == NULL) { return(STATUS_NO_MEMORY); } }*/ /* Clear user buffer. */ RtlZeroMemory(SystemInformation, Length); /* * Check the request is valid. */ if ((SystemInformationClass >= SystemInformationClassMin) && (SystemInformationClass < SystemInformationClassMax)) { if (NULL != CallQS [SystemInformationClass].Query) { /* * Hand the request to a subhandler. */ FStatus = CallQS [SystemInformationClass].Query(SystemInformation, Length, &ResultLength); /*if (ExGetPreviousMode() != KernelMode) { Status = MmCopyToCaller(UnsafeSystemInformation, SystemInformation, Length); ExFreePool(SystemInformation); if (!NT_SUCCESS(Status)) { return(Status); } }*/ if (UnsafeResultLength != NULL) { /*if (ExGetPreviousMode() == KernelMode) { *UnsafeResultLength = ResultLength; } else {*/ Status = MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG)); if (!NT_SUCCESS(Status)) { return(Status); } /*}*/ } return(FStatus); } } return (STATUS_INVALID_INFO_CLASS); } NTSTATUS STDCALL NtSetSystemInformation ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength ) { /* * If called from user mode, check * possible unsafe arguments. */ #if 0 if (KernelMode != KeGetPreviousMode()) { // Check arguments //ProbeForWrite( // SystemInformation, // Length // ); //ProbeForWrite( // ResultLength, // sizeof (ULONG) // ); } #endif /* * Check the request is valid. */ if ( (SystemInformationClass >= SystemInformationClassMin) && (SystemInformationClass < SystemInformationClassMax) ) { if (NULL != CallQS [SystemInformationClass].Set) { /* * Hand the request to a subhandler. */ return CallQS [SystemInformationClass].Set ( SystemInformation, SystemInformationLength ); } } return (STATUS_INVALID_INFO_CLASS); } NTSTATUS STDCALL NtFlushInstructionCache ( IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN UINT NumberOfBytesToFlush ) { UNIMPLEMENTED; return(STATUS_NOT_IMPLEMENTED); } /* EOF */