|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
prefboot.c
Abstract:
This module contains the code for boot prefetching.
Author:
Cenk Ergan (cenke) 15-Mar-2000
Revision History:
--*/
#include "cc.h"
#include "zwapi.h"
#include "prefetch.h"
#include "preftchp.h"
#include "stdio.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CcPfBeginBootPhase)
#pragma alloc_text(PAGE, CcPfBootWorker)
#pragma alloc_text(PAGE, CcPfBootQueueEndTraceTimer)
#endif // ALLOC_PRAGMA
//
// Globals:
//
//
// Whether the system is currently prefetching for boot.
//
LOGICAL CcPfPrefetchingForBoot = FALSE;
//
// Current boot phase, only updated in begin boot phase routine.
//
PF_BOOT_PHASE_ID CcPfBootPhase = 0;
//
// Prefetcher globals.
//
extern CCPF_PREFETCHER_GLOBALS CcPfGlobals;
//
// Routines for boot prefetching.
//
NTSTATUS CcPfBeginBootPhase( PF_BOOT_PHASE_ID Phase )
/*++
Routine Description:
This routine is the control center for the boot prefetcher. It is called to notify boot prefetcher of boot progress.
Arguments:
Phase - Boot phase the system is entering.
Return Value:
Status.
Environment:
Kernel mode. IRQL == PASSIVE_LEVEL.
--*/
{ LARGE_INTEGER VideoInitEndTime; LARGE_INTEGER MaxWaitTime; LONGLONG VideoInitTimeIn100ns; HANDLE ThreadHandle; PETHREAD Thread; PERFINFO_BOOT_PHASE_START LogEntry; PF_BOOT_PHASE_ID OriginalPhase; PF_BOOT_PHASE_ID NewPhase; ULONG VideoInitTime; NTSTATUS Status;
//
// This is the boot prefetcher. It is allocated and free'd in this routine.
// It is passed to the spawned boot worker if boot prefetching is enabled.
//
static PCCPF_BOOT_PREFETCHER BootPrefetcher = NULL;
//
// This is the system time when we started initializing the video.
//
static LARGE_INTEGER VideoInitStartTime;
DBGPR((CCPFID,PFTRC,"CCPF: BeginBootPhase(%d)\n", (ULONG)Phase));
//
// Make sure phase is valid.
//
if (Phase >= PfMaxBootPhaseId) { Status = STATUS_INVALID_PARAMETER; goto cleanup; }
//
// Log phase to trace buffer.
//
if (PERFINFO_IS_GROUP_ON(PERF_LOADER)) {
LogEntry.Phase = Phase; PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PHASE_START, &LogEntry, sizeof(LogEntry)); }
//
// Update the global current boot phase.
//
for (;;) { OriginalPhase = CcPfBootPhase;
if (Phase <= OriginalPhase) { Status = STATUS_TOO_LATE; goto cleanup; }
//
// If CcPfBootPhase is still OriginalPhase, set it to Phase.
//
NewPhase = InterlockedCompareExchange(&(LONG)CcPfBootPhase, Phase, OriginalPhase);
if (NewPhase == OriginalPhase) {
//
// CcPfBootPhase was still OriginalPhase, so now it is set to
// Phase. We are done.
//
break; } }
Status = STATUS_SUCCESS;
//
// Perform the work we have to do for this boot phase.
//
switch (Phase) {
case PfSystemDriverInitPhase:
//
// Update whether prefetcher is enabled or not.
//
CcPfDetermineEnablePrefetcher();
//
// If boot prefetching is not enabled, we are done.
//
if (!CCPF_IS_PREFETCHER_ENABLED() || CcPfGlobals.Parameters.Parameters.EnableStatus[PfSystemBootScenarioType] != PfSvEnabled) { Status = STATUS_NOT_SUPPORTED; break; }
//
// Allocate and initialize boot prefetcher.
//
BootPrefetcher = ExAllocatePoolWithTag(NonPagedPool, sizeof(*BootPrefetcher), CCPF_ALLOC_BOOTWRKR_TAG);
if (!BootPrefetcher) { Status = STATUS_INSUFFICIENT_RESOURCES; break; }
KeInitializeEvent(&BootPrefetcher->SystemDriversPrefetchingDone, NotificationEvent, FALSE); KeInitializeEvent(&BootPrefetcher->PreSmssPrefetchingDone, NotificationEvent, FALSE); KeInitializeEvent(&BootPrefetcher->VideoInitPrefetchingDone, NotificationEvent, FALSE); KeInitializeEvent(&BootPrefetcher->VideoInitStarted, NotificationEvent, FALSE);
//
// Kick off the boot worker in paralel.
//
Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, CcPfBootWorker, BootPrefetcher); if (NT_SUCCESS(Status)) {
//
// Give boot worker some head start by bumping its
// priority. This helps to make sure pages we will
// prefetch are put into transition before boot gets
// ahead of the prefetcher.
//
Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_SET_INFORMATION, PsThreadType, KernelMode, &Thread, NULL);
if (NT_SUCCESS(Status)) { KeSetPriorityThread(&Thread->Tcb, HIGH_PRIORITY - 1); ObDereferenceObject(Thread); }
ZwClose(ThreadHandle);
//
// Before returning to initialize system drivers, wait
// for boot worker to make progress.
//
KeWaitForSingleObject(&BootPrefetcher->SystemDriversPrefetchingDone, Executive, KernelMode, FALSE, NULL);
} else {
//
// Free the allocated boot prefetcher.
//
ExFreePool(BootPrefetcher); BootPrefetcher = NULL; }
break;
case PfSessionManagerInitPhase:
//
// Wait for boot worker to make enough progress before launching
// session manager.
//
if (BootPrefetcher) { KeWaitForSingleObject(&BootPrefetcher->PreSmssPrefetchingDone, Executive, KernelMode, FALSE, NULL); }
break;
case PfVideoInitPhase:
//
// Note when video initialization started.
//
KeQuerySystemTime(&VideoInitStartTime);
//
// Signal boot prefetcher to start prefetching in parallel to video
// initialization.
//
if (BootPrefetcher) { KeSetEvent(&BootPrefetcher->VideoInitStarted, IO_NO_INCREMENT, FALSE); }
break;
case PfPostVideoInitPhase:
//
// Note when we complete video initialization. Save how long video
// initialization took in the registry in milliseconds.
//
KeQuerySystemTime(&VideoInitEndTime);
VideoInitTimeIn100ns = VideoInitEndTime.QuadPart - VideoInitStartTime.QuadPart; VideoInitTime = (ULONG) (VideoInitTimeIn100ns / (1i64 * 10 * 1000));
KeEnterCriticalRegionThread(KeGetCurrentThread()); ExAcquireResourceSharedLite(&CcPfGlobals.Parameters.ParametersLock, TRUE);
Status = CcPfSetParameter(CcPfGlobals.Parameters.ParametersKey, CCPF_VIDEO_INIT_TIME_VALUE_NAME, REG_DWORD, &VideoInitTime, sizeof(VideoInitTime));
ExReleaseResourceLite(&CcPfGlobals.Parameters.ParametersLock); KeLeaveCriticalRegionThread(KeGetCurrentThread());
//
// Wait for prefetching parallel to video initialization to complete.
//
if (BootPrefetcher) { KeWaitForSingleObject(&BootPrefetcher->VideoInitPrefetchingDone, Executive, KernelMode, FALSE, NULL); }
break;
case PfBootAcceptedRegistryInitPhase:
//
// Service Controller has accepted this boot as a valid boot.
// Boot & system services have initialized successfully.
//
//
// We are done with boot prefetching. No one else could be accessing
// BootPrefetcher structure at this point.
//
if (BootPrefetcher) {
//
// Cleanup the allocated boot prefetcher.
//
ExFreePool(BootPrefetcher); BootPrefetcher = NULL;
//
// Determine if the prefetcher is enabled now that boot
// is over.
//
CcPfDetermineEnablePrefetcher(); }
//
// The user may not log in after booting.
// Queue a timer to end boot trace.
//
MaxWaitTime.QuadPart = -1i64 * 60 * 1000 * 1000 * 10; // 60 seconds.
CcPfBootQueueEndTraceTimer(&MaxWaitTime);
break; case PfUserShellReadyPhase: //
// Explorer has started, but start menu items may still be launching.
// Queue a timer to end boot trace.
//
MaxWaitTime.QuadPart = -1i64 * 30 * 1000 * 1000 * 10; // 30 seconds.
CcPfBootQueueEndTraceTimer(&MaxWaitTime);
break;
default: //
// Ignored for now.
//
Status = STATUS_SUCCESS; }
//
// Fall through with status from switch statement.
//
cleanup:
DBGPR((CCPFID,PFTRC,"CCPF: BeginBootPhase(%d)=%x\n", (ULONG)Phase, Status));
return Status; }
VOID CcPfBootWorker( PCCPF_BOOT_PREFETCHER BootPrefetcher )
/*++
Routine Description:
This routine is queued to prefetch and start tracing boot in parallel.
Arguments:
BootPrefetcher - Pointer to boot prefetcher context.
Return Value:
None.
Environment:
Kernel mode. IRQL == PASSIVE_LEVEL.
--*/
{ PF_SCENARIO_ID BootScenarioId; CCPF_PREFETCH_HEADER PrefetchHeader; CCPF_BASIC_SCENARIO_INFORMATION ScenarioInfo; CCPF_BOOT_SCENARIO_INFORMATION BootScenarioInfo; PERFINFO_BOOT_PREFETCH_INFORMATION LogEntry; ULONG NumPages; ULONG RequiredSize; ULONG NumPagesPrefetched; ULONG TotalPagesPrefetched; ULONG BootPrefetchAdjustment; ULONG AvailablePages; ULONG NumPagesToPrefetch; ULONG TotalPagesToPrefetch; ULONG RemainingDataPages; ULONG RemainingImagePages; ULONG VideoInitTime; ULONG VideoInitPagesPerSecond; ULONG VideoInitMaxPages; ULONG RemainingVideoInitPages; ULONG VideoInitDataPages; ULONG VideoInitImagePages; ULONG PrefetchPhaseIdx; ULONG LastPrefetchPhaseIdx; ULONG SystemDriverPrefetchingPhaseIdx; ULONG PreSmssPrefetchingPhaseIdx; ULONG VideoInitPrefetchingPhaseIdx; ULONG ValueSize; CCPF_BOOT_SCENARIO_PHASE BootPhaseIdx; NTSTATUS Status; BOOLEAN OutOfAvailablePages;
//
// First we will prefetch data pages, then image pages.
//
enum { DataCursor = 0, ImageCursor, MaxCursor } CursorIdx;
CCPF_BOOT_PREFETCH_CURSOR Cursors[MaxCursor]; PCCPF_BOOT_PREFETCH_CURSOR Cursor;
//
// Initialize locals.
//
CcPfInitializePrefetchHeader(&PrefetchHeader); TotalPagesPrefetched = 0; OutOfAvailablePages = FALSE;
DBGPR((CCPFID,PFTRC,"CCPF: BootWorker()\n"));
//
// Initialize boot scenario ID.
//
wcsncpy(BootScenarioId.ScenName, PF_BOOT_SCENARIO_NAME, PF_SCEN_ID_MAX_CHARS);
BootScenarioId.ScenName[PF_SCEN_ID_MAX_CHARS] = 0; BootScenarioId.HashId = PF_BOOT_SCENARIO_HASHID;
//
// Start boot prefetch tracing.
//
CcPfBeginTrace(&BootScenarioId, PfSystemBootScenarioType, PsInitialSystemProcess);
//
// If we try to prefetch more pages then what we have available, we will
// end up cannibalizing the pages we prefetched into the standby list.
// To avoid cannibalizing, we check MmAvailablePages but leave some
// breathing room for metadata pages, allocations from the driver
// initialization phase etc.
//
BootPrefetchAdjustment = 512;
//
// We also know that right after we prefetch for boot, in smss when
// initializing the registry we'll use up 8-10MB of prefetched pages if we
// don't have anything left in the free list. So we leave some room for
// that too.
//
BootPrefetchAdjustment += 8 * 1024 * 1024 / PAGE_SIZE;
//
// Get prefetch instructions.
//
Status = CcPfGetPrefetchInstructions(&BootScenarioId, PfSystemBootScenarioType, &PrefetchHeader.Scenario);
if (!NT_SUCCESS(Status)) { goto cleanup; } //
// Query the total number of pages to be prefetched.
//
Status = CcPfQueryScenarioInformation(PrefetchHeader.Scenario, CcPfBasicScenarioInformation, &ScenarioInfo, sizeof(ScenarioInfo), &RequiredSize);
if (!NT_SUCCESS(Status)) { goto cleanup; } //
// Query the number of pages we have to prefetch for boot phases.
//
Status = CcPfQueryScenarioInformation(PrefetchHeader.Scenario, CcPfBootScenarioInformation, &BootScenarioInfo, sizeof(BootScenarioInfo), &RequiredSize);
if (!NT_SUCCESS(Status)) { goto cleanup; }
//
// Read how long it took to initialize video in the last boot.
//
KeEnterCriticalRegionThread(KeGetCurrentThread()); ExAcquireResourceSharedLite(&CcPfGlobals.Parameters.ParametersLock, TRUE);
ValueSize = sizeof(VideoInitTime); Status = CcPfGetParameter(CcPfGlobals.Parameters.ParametersKey, CCPF_VIDEO_INIT_TIME_VALUE_NAME, REG_DWORD, &VideoInitTime, &ValueSize);
ExReleaseResourceLite(&CcPfGlobals.Parameters.ParametersLock); KeLeaveCriticalRegionThread(KeGetCurrentThread());
if (!NT_SUCCESS(Status)) {
//
// Reset video init time, so we don't attempt to prefetch
// in parallel to it.
//
VideoInitTime = 0;
} else {
//
// Verify the value we read from registry.
//
if (VideoInitTime > CCPF_MAX_VIDEO_INIT_TIME) { VideoInitTime = 0; } }
//
// Read how many pages per second we should be trying to prefetching
// in parallel to video initialization.
//
KeEnterCriticalRegionThread(KeGetCurrentThread()); ExAcquireResourceSharedLite(&CcPfGlobals.Parameters.ParametersLock, TRUE);
ValueSize = sizeof(VideoInitPagesPerSecond); Status = CcPfGetParameter(CcPfGlobals.Parameters.ParametersKey, CCPF_VIDEO_INIT_PAGES_PER_SECOND_VALUE_NAME, REG_DWORD, &VideoInitPagesPerSecond, &ValueSize);
ExReleaseResourceLite(&CcPfGlobals.Parameters.ParametersLock); KeLeaveCriticalRegionThread(KeGetCurrentThread());
if (!NT_SUCCESS(Status)) {
//
// There was no valid value in the registry. Use the default.
//
VideoInitPagesPerSecond = CCPF_VIDEO_INIT_DEFAULT_PAGES_PER_SECOND;
} else {
//
// Verify the value we read from registry.
//
if (VideoInitPagesPerSecond > CCPF_VIDEO_INIT_MAX_PAGES_PER_SECOND) { VideoInitPagesPerSecond = CCPF_VIDEO_INIT_MAX_PAGES_PER_SECOND; } }
//
// Determine how many pages max we can prefetch in parallel to video
// initialization.
//
VideoInitMaxPages = (VideoInitTime / 1000) * VideoInitPagesPerSecond;
//
// We can only prefetch pages used after winlogon in parallel to video
// initialization. Determine exactly how many pages we will prefetch
// starting from the last boot phase.
//
RemainingVideoInitPages = VideoInitMaxPages; VideoInitDataPages = 0; VideoInitImagePages = 0;
for (BootPhaseIdx = CcPfBootScenMaxPhase - 1; RemainingVideoInitPages && (BootPhaseIdx >= CcPfBootScenSystemProcInitPhase); BootPhaseIdx--) {
NumPages = CCPF_MIN(RemainingVideoInitPages, BootScenarioInfo.NumImagePages[BootPhaseIdx]); VideoInitImagePages += NumPages; RemainingVideoInitPages -= NumPages;
if (RemainingVideoInitPages) { NumPages = CCPF_MIN(RemainingVideoInitPages, BootScenarioInfo.NumDataPages[BootPhaseIdx]); VideoInitDataPages += NumPages; RemainingVideoInitPages -= NumPages; } }
//
// Let MM know that we have started prefetching for boot.
//
CcPfPrefetchingForBoot = TRUE;
//
// Log that we are starting prefetch disk I/Os.
//
if (PERFINFO_IS_GROUP_ON(PERF_DISK_IO)) {
LogEntry.Action = 0; LogEntry.Status = 0; LogEntry.Pages = ScenarioInfo.NumDataPages + ScenarioInfo.NumImagePages; PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PREFETCH_INFORMATION, &LogEntry, sizeof(LogEntry)); }
//
// Verify & open the volumes that we will prefetch from.
//
Status = CcPfOpenVolumesForPrefetch(&PrefetchHeader);
if (!NT_SUCCESS(Status)) { goto cleanup; }
//
// Prefetch the metadata.
//
CcPfPrefetchMetadata(&PrefetchHeader);
//
// Initialize the boot prefetch cursors for data and image.
//
RtlZeroMemory(Cursors, sizeof(Cursors));
Cursors[DataCursor].PrefetchType = CcPfPrefetchPartOfDataPages; Cursors[ImageCursor].PrefetchType = CcPfPrefetchPartOfImagePages;
PrefetchPhaseIdx = 0; RemainingDataPages = ScenarioInfo.NumDataPages; RemainingImagePages = ScenarioInfo.NumImagePages;
//
// Setup the cursors for phases in which we will prefetch for boot.
// First we will prefetch for system drivers.
//
NumPages = BootScenarioInfo.NumDataPages[CcPfBootScenDriverInitPhase]; Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages; RemainingDataPages -= NumPages;
NumPages = BootScenarioInfo.NumImagePages[CcPfBootScenDriverInitPhase]; Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages; RemainingImagePages -= NumPages;
SystemDriverPrefetchingPhaseIdx = PrefetchPhaseIdx;
PrefetchPhaseIdx++;
//
// Account for the video init pages we will prefetch last.
//
RemainingDataPages -= VideoInitDataPages; RemainingImagePages -= VideoInitImagePages;
//
// If we have plenty of available memory, prefetch the rest of the pages
// (i.e. left over after driver init pages) in one pass.
//
TotalPagesToPrefetch = ScenarioInfo.NumDataPages + ScenarioInfo.NumImagePages;
if (MmAvailablePages > BootPrefetchAdjustment + TotalPagesToPrefetch) { Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = RemainingDataPages; RemainingDataPages = 0; Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = RemainingImagePages; RemainingImagePages = 0;
PrefetchPhaseIdx++;
} else {
//
// We will be short on memory. Try to prefetch for as many phases of
// boot as we can in parallel. Prefetching data & image pages per boot
// phase, so we don't end up with data pages for all phase but no image
// pages so we have to go to the disk in each phase. Prefetching in
// chunks also help that all the pages we need for the initial phases
// of boot ending up at the end of the standby list, since when
// CcPfPrefetchingForBoot is set, prefetched pages will be inserted
// from the front of the standby list.
//
for (BootPhaseIdx = CcPfBootScenDriverInitPhase + 1; BootPhaseIdx < CcPfBootScenMaxPhase; BootPhaseIdx++) {
//
// If we don't have any type of pages left to prefetch, we are done.
//
if (!RemainingDataPages && !RemainingImagePages) { break; }
NumPages = CCPF_MIN(RemainingDataPages, BootScenarioInfo.NumDataPages[BootPhaseIdx]); RemainingDataPages -= NumPages; Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages;
NumPages = CCPF_MIN(RemainingImagePages, BootScenarioInfo.NumImagePages[BootPhaseIdx]); RemainingImagePages -= NumPages; Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages;
PrefetchPhaseIdx++; } }
PreSmssPrefetchingPhaseIdx = PrefetchPhaseIdx - 1;
//
// If we'll be prefetching pages in parallel to video initialization, now
// add the phase for it.
//
if (VideoInitDataPages || VideoInitImagePages) {
Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = VideoInitDataPages; Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = VideoInitImagePages;
VideoInitPrefetchingPhaseIdx = PrefetchPhaseIdx;
PrefetchPhaseIdx++;
} else {
//
// We won't have a prefetching phase parallel to video initialization.
//
VideoInitPrefetchingPhaseIdx = CCPF_MAX_BOOT_PREFETCH_PHASES; }
//
// We should not end up with more prefetch phases than we have room for.
//
CCPF_ASSERT(PrefetchPhaseIdx < CCPF_MAX_BOOT_PREFETCH_PHASES);
LastPrefetchPhaseIdx = PrefetchPhaseIdx;
//
// Prefetch the data and image pages for each boot prefetching phase,
// waiting for & signaling the events matching those phases so boot
// is synchronized with prefetching. (I.e. we prefetch pages for a boot
// phase before we start that boot phase.)
//
for (PrefetchPhaseIdx = 0; PrefetchPhaseIdx < LastPrefetchPhaseIdx; PrefetchPhaseIdx++) {
//
// If this is the video init prefetching phase, wait for video
// initialization to begin.
//
if (PrefetchPhaseIdx == VideoInitPrefetchingPhaseIdx) { KeWaitForSingleObject(&BootPrefetcher->VideoInitStarted, Executive, KernelMode, FALSE, NULL); }
for (CursorIdx = 0; CursorIdx < MaxCursor; CursorIdx++) {
Cursor = &Cursors[CursorIdx];
NumPagesToPrefetch = Cursor->NumPagesForPhase[PrefetchPhaseIdx];
//
// For prefetch phases before SMSS is launched keep an eye on
// how much memory is still available to prefetch into so we
// don't cannibalize ourselves. After SMSS our heuristics on
// standby-list composition do not make sense.
//
if (PrefetchPhaseIdx <= PreSmssPrefetchingPhaseIdx) {
//
// Check if we have available memory to prefetch more.
//
if (TotalPagesPrefetched + BootPrefetchAdjustment >= MmAvailablePages) {
OutOfAvailablePages = TRUE;
NumPagesToPrefetch = 0;
} else {
//
// Check if we have to adjust NumPagesToPrefetch and prefetch
// one last chunk.
//
AvailablePages = MmAvailablePages; AvailablePages -= (TotalPagesPrefetched + BootPrefetchAdjustment);
if (AvailablePages < NumPagesToPrefetch) { NumPagesToPrefetch = AvailablePages; } } }
if (NumPagesToPrefetch) {
Status = CcPfPrefetchSections(&PrefetchHeader, Cursor->PrefetchType, &Cursor->StartCursor, NumPagesToPrefetch, &NumPagesPrefetched, &Cursor->EndCursor);
if (!NT_SUCCESS(Status)) { goto cleanup; }
} else {
NumPagesPrefetched = 0; }
//
// Update our position.
//
Cursor->StartCursor = Cursor->EndCursor;
TotalPagesPrefetched += NumPagesPrefetched;
}
//
// Note that we are done with this prefetching phase and
// system boot can continue.
//
if (PrefetchPhaseIdx == SystemDriverPrefetchingPhaseIdx) { KeSetEvent(&BootPrefetcher->SystemDriversPrefetchingDone, IO_NO_INCREMENT, FALSE); }
if (PrefetchPhaseIdx == PreSmssPrefetchingPhaseIdx) { KeSetEvent(&BootPrefetcher->PreSmssPrefetchingDone, IO_NO_INCREMENT, FALSE); }
if (PrefetchPhaseIdx == VideoInitPrefetchingPhaseIdx) { KeSetEvent(&BootPrefetcher->VideoInitPrefetchingDone, IO_NO_INCREMENT, FALSE); } }
Status = STATUS_SUCCESS;
cleanup:
//
// Log that we are done with boot prefetch disk I/Os.
//
if (PERFINFO_IS_GROUP_ON(PERF_DISK_IO)) {
LogEntry.Action = 1; LogEntry.Status = Status; LogEntry.Pages = TotalPagesPrefetched; PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PREFETCH_INFORMATION, &LogEntry, sizeof(LogEntry)); }
//
// Make sure all the events system may wait for before proceeding with
// boot are signaled.
//
KeSetEvent(&BootPrefetcher->SystemDriversPrefetchingDone, IO_NO_INCREMENT, FALSE);
KeSetEvent(&BootPrefetcher->PreSmssPrefetchingDone, IO_NO_INCREMENT, FALSE);
KeSetEvent(&BootPrefetcher->VideoInitPrefetchingDone, IO_NO_INCREMENT, FALSE);
//
// Let MM know that we are done prefetching for boot.
//
CcPfPrefetchingForBoot = FALSE;
//
// Cleanup prefetching context.
//
CcPfCleanupPrefetchHeader(&PrefetchHeader);
if (PrefetchHeader.Scenario) { ExFreePool(PrefetchHeader.Scenario); }
DBGPR((CCPFID,PFTRC,"CCPF: BootWorker()=%x,%d\n",Status,(ULONG)OutOfAvailablePages)); }
NTSTATUS CcPfBootQueueEndTraceTimer ( PLARGE_INTEGER Timeout )
/*++
Routine Description:
This routine allocates and queues a timer that will attempt to end the boot trace when it fires.
Arguments:
Timeout - Timeout for the timer.
Return Value:
Status.
Environment:
Kernel mode. IRQL <= PASSIVE_LEVEL.
--*/
{ PVOID Allocation; PKTIMER Timer; PKDPC Dpc; ULONG AllocationSize; NTSTATUS Status; BOOLEAN TimerAlreadyQueued;
//
// Initialize locals.
//
Allocation = NULL;
//
// Make a single allocation for the timer and dpc.
//
AllocationSize = sizeof(KTIMER); AllocationSize += sizeof(KDPC);
Allocation = ExAllocatePoolWithTag(NonPagedPool, AllocationSize, CCPF_ALLOC_BOOTWRKR_TAG);
if (!Allocation) { Status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; }
Timer = Allocation; Dpc = (PKDPC)(Timer + 1);
//
// Initialize the timer and DPC. We'll be passing the allocation to the
// queued DPC so it can be freed.
//
KeInitializeTimer(Timer); KeInitializeDpc(Dpc, CcPfEndBootTimerRoutine, Allocation);
//
// Queue the timer.
//
TimerAlreadyQueued = KeSetTimer(Timer, *Timeout, Dpc);
CCPF_ASSERT(!TimerAlreadyQueued);
Status = STATUS_SUCCESS; cleanup:
if (!NT_SUCCESS(Status)) { if (Allocation) { ExFreePool(Allocation); } }
return Status; }
VOID CcPfEndBootTimerRoutine( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 )
/*++
Routine Description:
This routine is invoked as the DPC handler for a timer queued to mark the end of boot and end the boot trace if one is active.
Arguments:
DeferredContext - Allocated memory for the timer & dpc that need to be freed.
Return Value:
None.
Environment:
Kernel mode. IRQL == DISPATCH_LEVEL.
--*/
{ PCCPF_TRACE_HEADER BootTrace; PERFINFO_BOOT_PHASE_START LogEntry;
UNREFERENCED_PARAMETER (Dpc); UNREFERENCED_PARAMETER (SystemArgument1); UNREFERENCED_PARAMETER (SystemArgument2);
//
// Initialize locals.
//
BootTrace = NULL;
//
// Is the boot trace still active?
//
BootTrace = CcPfReferenceProcessTrace(PsInitialSystemProcess);
if (BootTrace && BootTrace->ScenarioType == PfSystemBootScenarioType) {
//
// Is somebody already ending the boot trace?
//
if (!InterlockedCompareExchange(&BootTrace->EndTraceCalled, 1, 0)) { //
// We set EndTraceCalled from 0 to 1. Queue the
// workitem to end the trace.
//
ExQueueWorkItem(&BootTrace->EndTraceWorkItem, DelayedWorkQueue);
//
// Log that we are ending the boot trace.
//
if (PERFINFO_IS_GROUP_ON(PERF_LOADER)) {
LogEntry.Phase = PfMaxBootPhaseId; PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PHASE_START, &LogEntry, sizeof(LogEntry)); } } }
//
// Free the memory allocated for the timer and dpc.
//
CCPF_ASSERT(DeferredContext); ExFreePool(DeferredContext);
if (BootTrace) { CcPfDecRef(&BootTrace->RefCount); }
return; }
|