/*++

Copyright (cİ 1999 Microsoft Corporation

Module Name:

    preftchp.h

Abstract:

    This module contains the private definitions for the kernel mode
    prefetcher for optimizing demand paging. Page faults for a
    scenario are logged and the next time scenario starts, these pages
    are prefetched efficiently via asynchronous paging I/O.

Author:

    Stuart Sechrest (stuartse)
    Chuck Lenzmeier (chuckl)
    Cenk Ergan (cenke)

Revision History:

--*/

#ifndef _PREFTCHP_H
#define _PREFTCHP_H

//
// Define tags used in prefetcher routines.
//

#define CCPF_PREFETCHER_TAG         'fPcC'

#define CCPF_ALLOC_SCENARIO_TAG     'SPcC'
#define CCPF_ALLOC_TRACE_TAG        'TPcC'
#define CCPF_ALLOC_TRCBUF_TAG       'BPcC'
#define CCPF_ALLOC_SECTTBL_TAG      'sPcC'
#define CCPF_ALLOC_TRCDMP_TAG       'DPcC'
#define CCPF_ALLOC_QUERY_TAG        'qPcC'
#define CCPF_ALLOC_FILENAME_TAG     'FPcC'
#define CCPF_ALLOC_CONTEXT_TAG      'CPcC'
#define CCPF_ALLOC_INTRTABL_TAG     'IPcC'
#define CCPF_ALLOC_PREFSCEN_TAG     'pPcC'
#define CCPF_ALLOC_BOOTWRKR_TAG     'wPcC'
#define CCPF_ALLOC_VOLUME_TAG       'vPcC'
#define CCPF_ALLOC_READLIST_TAG     'LPcC'
#define CCPF_ALLOC_METADATA_TAG     'MPcC'

//
// Whether the scenario type is for a system-wide scenario, meaning that 
// only it can be active while running.
//

#define CCPF_IS_SYSTEM_WIDE_SCENARIO_TYPE(ScenarioType) \
    ((ScenarioType) == PfSystemBootScenarioType)

//
// In the kernel, we have to look for named objects under this
// directory for them to visible to Win32 prefetcher service.
//

#define CCPF_BASE_NAMED_OBJ_ROOT_DIR L"\\BaseNamedObjects"

//
// This is the invalid index value used with section tables.
//

#define CCPF_INVALID_TABLE_INDEX     (-1)

//
// This is the max number of file metadata that NTFS can prefetch
// at a time.
//

#define CCPF_MAX_FILE_METADATA_PREFETCH_COUNT 0x300

//
// Define structure to hold prefetcher parameters state.
//

typedef struct _CCPF_PREFETCHER_PARAMETERS {

    //
    // This is the named event that is used to signal the service that
    // parameters have been updated.
    //

    HANDLE ParametersChangedEvent;

    //
    // This is the registry key containing prefetch parameters.
    //
    
    HANDLE ParametersKey;

    //
    // Fields used in registering for change notify on parameters
    // registry key.
    //

    IO_STATUS_BLOCK RegistryWatchIosb;
    WORK_QUEUE_ITEM RegistryWatchWorkItem;
    ULONG RegistryWatchBuffer;

    //
    // System wide prefetching parameters. When using any parameters
    // whose update may cause problems [e.g. strings], get the
    // ParametersLock shared. When you need to update Parameters,
    // after getting the ParametersLock exclusive, bump
    // ParametersVersion before updating parameters.
    //

    PF_SYSTEM_PREFETCH_PARAMETERS Parameters;
    ERESOURCE ParametersLock;
    LONG ParametersVersion;

    //
    // Prefixes to registry values for different scenario types.
    //

    WCHAR *ScenarioTypePrefixes[PfMaxScenarioType];

    //
    // This is set to InitSafeBootMode during initialization.
    //
    
    ULONG SafeBootMode;

} CCPF_PREFETCHER_PARAMETERS, *PCCPF_PREFETCHER_PARAMETERS;

//
// Define structure to hold prefetcher's global state.
//

typedef struct _CCPF_PREFETCHER_GLOBALS {

    //
    // List of active traces and the lock to protect it. The number
    // of items on this list is a global, since it is used by other
    // kernel components to make a fast check.
    //

    LIST_ENTRY ActiveTraces;
    KSPIN_LOCK ActiveTracesLock;

    //
    // Pointer to the global trace if one is active. While there is a
    // global trace active we don't trace & prefetch other scenarios.
    // Boot tracing is an example of global trace.
    //

    struct _CCPF_TRACE_HEADER *SystemWideTrace;

    //
    // List and number of saved completed prefetch traces and lock to
    // protect it.
    //

    LIST_ENTRY CompletedTraces; 
    FAST_MUTEX CompletedTracesLock;
    LONG NumCompletedTraces;

    //
    // This is the named event that is used to signal the service that
    // there are traces ready for it to get.
    //

    HANDLE CompletedTracesEvent;

    //
    // Prefetcher parameters.
    //

    CCPF_PREFETCHER_PARAMETERS Parameters;

} CCPF_PREFETCHER_GLOBALS, *PCCPF_PREFETCHER_GLOBALS;

//
// Reference count structure.
//

typedef struct _CCPF_REFCOUNT {

    //
    // When initialized or reset, this reference count starts from
    // 1. When exclusive access is granted it stays at 0: even if it
    // may get bumped by an AddRef by mistake, it will return to 0.
    //

    LONG RefCount;

    //
    // This is set when somebody wants to gain exclusive access to the
    // protected structure.
    //

    LONG Exclusive;   

} CCPF_REFCOUNT, *PCCPF_REFCOUNT;

//
// Define structures used for logging pagefaults:
//

//
// One of these is logged for every page fault.
//

typedef struct _CCPF_LOG_ENTRY {

    //
    // File offset of the page that was faulted.
    //
    
    ULONG FileOffset;

    //
    // Index into the section table in the trace header that helps us
    // identify the file.
    //

    USHORT SectionId;

    //
    // Whether this page was faulted as an image page or data page.
    //

    BOOLEAN IsImage;

    //
    // Whether this is a fault that happened in the process in which
    // the scenario is associated with.
    //

    BOOLEAN InProcess;

} CCPF_LOG_ENTRY, *PCCPF_LOG_ENTRY;

//
// CCPF_LOG_ENTRIES is a buffer of log entries with a small header containing
// an index to the highest used entry. This is used so that a trace can consist
// of several smaller trace buffers instead of one large, fixed-size buffer.
// The current index must be contained in the buffer in order to allow entries
// to be added without acquiring a spin lock.
//

typedef struct _CCPF_LOG_ENTRIES {

    //
    // Link used to put this buffer in the traces's buffer list.
    //

    LIST_ENTRY TraceBuffersLink;

    //
    // NumEntries is the current number of entries in the buffer. MaxEntries
    // is the maximum number of entries that can be placed in the buffer.
    // (Currently MaxEntries always equals CCPF_TRACE_BUFFER_MAX_ENTRIES.)
    //

    LONG NumEntries;
    LONG MaxEntries;

    //
    // The logged entries start here.
    //

    CCPF_LOG_ENTRY Entries[1];

} CCPF_LOG_ENTRIES, *PCCPF_LOG_ENTRIES;

//
// CCPF_TRACE_BUFFER_SIZE is the size of an allocated CCPF_LOG_ENTRIES structure
// (including the header). This should be a multiple of the page size.
//

#define CCPF_TRACE_BUFFER_SIZE 8192

//
// CCPF_TRACE_BUFFER_MAX_ENTRIES is the number of log entries that will fit in
// a trace buffer of size CCPF_TRACE_BUFFER_SIZE.
//

#define CCPF_TRACE_BUFFER_MAX_ENTRIES (((CCPF_TRACE_BUFFER_SIZE - sizeof(CCPF_LOG_ENTRIES)) / sizeof(CCPF_LOG_ENTRY)) + 1)

//
// This structure associates a SectionObjectPointer with a file name
// in the runtime trace buffer. There is a table of these in the trace
// header and every page fault has an index into this table denoting
// which file it is to.
//

typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _CCPF_SECTION_INFO {

    //
    // Section info entries are kept in a hash. This field is
    // InterlockedCompareExchange'd to denote that it is in use.
    //

    LONG EntryValid;

    //
    // Whether this section is used for file systems to map metafile.
    //

    ULONG Metafile:1;
    ULONG Unused:31;

    //
    // SectionObjectPointer used as a unique identifier to a file
    // mapping. The same file may be mapped using a number of file
    // objects, but the SectionObjectPointer fields of all those file
    // objects will be the same.
    //

    PSECTION_OBJECT_POINTERS SectionObjectPointer;

    //
    // All references to all file objects for a file may be released,
    // and a new file may be opened using the same memory block for
    // its FCB at which point the SectionObjectPointer would no longer
    // be unique. This would result in pagefaults getting logged under
    // the entry for the file that was closed. The consequences would
    // be misprefetching wrong pages from a couple of sections until
    // the scenario corrects itself by looking at new traces. By
    // keeping track of these two fields of the SectionObjectPointers
    // to check for uniqueness we make this case very unlikely to
    // happen. The other solutions we thought of to solve this issue
    // 100% were too costly in terms of complication or efficiency.
    //

    //
    // In order to avoid adding two entries to the table for the
    // section when it is used as data first then image (or vice
    // versa) it is assumed that it is still the same section if the
    // current entry's Data/ImageSectionObject is NULL but the
    // Data/ImageSectionObject of the section we are logging a new
    // pagefault to is not. Then we try to update the NULL pointer
    // with the new value using InterlockedCompareExchangePointer.
    //

    PVOID DataSectionObject;
    PVOID ImageSectionObject;

    //
    // This may point to a file object that we have referenced to
    // ensure the section object stays around until we can get a name.
    //

    PFILE_OBJECT ReferencedFileObject;

    //
    // The name is set as soon as we can get a file name. We cannot
    // access the file name while running at a high IRQL.
    //

    WCHAR *FileName;

    //
    // We queue a section to the get-file-name list using this field.
    //

    SINGLE_LIST_ENTRY GetNameLink;

} CCPF_SECTION_INFO, *PCCPF_SECTION_INFO;

//
// This structure contains information on a volume on which sections
// in the trace are located on.
//

typedef struct _CCPF_VOLUME_INFO {
    
    //
    // Link in the trace's volume list.
    //

    LIST_ENTRY VolumeLink;

    //
    // Volume creation time and serial number used to identify the
    // volume in case its NT/device path e.g. \Device\HarddiskVolume1
    // changes.
    //

    LARGE_INTEGER CreationTime;
    ULONG SerialNumber;

    //
    // Current NT/device path for the volume and its length in
    // characters excluding terminating NUL.
    //

    ULONG VolumePathLength;
    WCHAR VolumePath[1];

} CCPF_VOLUME_INFO, *PCCPF_VOLUME_INFO;

//
// This is the runtime trace header for a scenario.
//

typedef struct _CCPF_TRACE_HEADER {

    //
    // Magic number identifying this structure as a trace.
    //

    ULONG Magic;

    //
    // Link in the active traces list.
    //

    LIST_ENTRY ActiveTracesLink;

    //
    // Scenario id for which we are acquiring this trace.
    //

    PF_SCENARIO_ID ScenarioId;

    //
    // Type of this scenario.
    //

    PF_SCENARIO_TYPE ScenarioType;

    //
    // CurrentTraceBuffer is the active trace buffer. 
    //
    
    PCCPF_LOG_ENTRIES CurrentTraceBuffer;

    //
    // This is the list of trace buffers for this trace.
    // CurrentTraceBuffer is the last element. Both this list and
    // CurrentTraceBuffer are protected by TraceBufferSpinLock.
    //

    LIST_ENTRY TraceBuffersList;
    ULONG NumTraceBuffers;
    KSPIN_LOCK TraceBufferSpinLock;

    //
    // This is the table for section info.
    //
    
    PCCPF_SECTION_INFO SectionInfoTable;
    LONG NumSections;
    LONG MaxSections;
    ULONG SectionTableSize;

    //
    // We don't log timestamps with page faults but it helps to know
    // how many we are logging per given time. This information can be
    // used to mark the end of a scenario.
    //

    KTIMER TraceTimer;
    LARGE_INTEGER TraceTimerPeriod;
    KDPC TraceTimerDpc;
    KSPIN_LOCK TraceTimerSpinLock;
    
    //
    // This array contains the number of page faults logged per trace
    // period.
    //

    ULONG FaultsPerPeriod[PF_MAX_NUM_TRACE_PERIODS];
    LONG LastNumFaults;
    LONG CurPeriod;
    
    //
    // NumFaults is the number of faults that have been logged so far, in all
    // trace buffers. MaxFaults is the maximum number of page faults we will
    // log, in all trace buffers.
    //

    LONG NumFaults;
    LONG MaxFaults;

    //
    // This workitem is queued to get names for file objects we are
    // logging page faults to. First GetFileNameWorkItemQueued should
    // be InterlockedCompareExchange'd from 0 to 1 and a reference
    // should be acquired on the scenario. The workitem will free this
    // reference just before it completes.
    //

    WORK_QUEUE_ITEM GetFileNameWorkItem;
    LONG GetFileNameWorkItemQueued;

    //
    // Sections for which we have to get names are pushed and popped
    // to/from this slist.
    //

    SLIST_HEADER SectionsWithoutNamesList;

    //
    // Because we don't want to incur the cost of queuing a work item
    // to get file names for every one or two sections, the worker we
    // queue will wait on this event before returning. The event can
    // be signaled when a new section comes, or when the scenario is
    // ending.
    //

    KEVENT GetFileNameWorkerEvent;

    //
    // This is the process we are associated with.
    //

    PEPROCESS Process;

    //
    // This is the removal reference count protecting us.
    //

    CCPF_REFCOUNT RefCount;

    //
    // This work item can be queued to call the end trace function if
    // the trace times out or we log to many entries etc. First
    // EndTraceCalled should be InterlockedCompareExchange'd from 0 to
    // 1.
    //

    WORK_QUEUE_ITEM EndTraceWorkItem;

    //
    // Before anybody calls end trace function, they have to
    // InterlockedCompareExchange this from 0 to 1 to ensure this
    // function gets called only once.
    //

    LONG EndTraceCalled;

    //
    // This is the list of volumes the sections we are tracing are
    // located on. It is sorted lexically by the volume NT/device path.
    //

    LIST_ENTRY VolumeList;
    ULONG NumVolumes;

    //
    // This is the pointer to the built trace dump from this runtime
    // trace structure and the status with which dumping failed if it
    // did.
    //
    
    struct _CCPF_TRACE_DUMP *TraceDump;
    NTSTATUS TraceDumpStatus;

    //
    // System time when we started tracing.
    //
    
    LARGE_INTEGER LaunchTime;

} CCPF_TRACE_HEADER, *PCCPF_TRACE_HEADER;

//
// This structure is used to save completed traces in a list. The
// trace extends beyond this structure as necessary.
//

typedef struct _CCPF_TRACE_DUMP {
    
    //
    // Link in the completed traces list.
    //

    LIST_ENTRY CompletedTracesLink;
    
    //
    // Completed trace.
    //

    PF_TRACE_HEADER Trace;

} CCPF_TRACE_DUMP, *PCCPF_TRACE_DUMP;

//
// This structure contains information for a volume used during prefetching.
//

typedef struct _CCPF_PREFETCH_VOLUME_INFO {

    //
    // Link in the lists this volume gets put on.
    //

    LIST_ENTRY VolumeLink;

    //
    // Volume path.
    //

    WCHAR *VolumePath;
    ULONG VolumePathLength;

    //
    // Handle to the opened volume.
    //

    HANDLE VolumeHandle;

} CCPF_PREFETCH_VOLUME_INFO, *PCCPF_PREFETCH_VOLUME_INFO;

//
// This structure is used to keep track of prefetched pages & context.
//

//
// Note: This structure is used as a stack variable. Don't add events
// etc, without changing that.
//

typedef struct _CCPF_PREFETCH_HEADER {

    //
    // Pointer to prefetch instructions. The instructions should not
    // be removed / freed until the prefetch header is cleaned up.
    // E.g. VolumeNodes may point to volume paths in the scenario.
    //

    PPF_SCENARIO_HEADER Scenario;

    //
    // Nodes for the volumes we are going to prefetch from.
    //

    PCCPF_PREFETCH_VOLUME_INFO VolumeNodes;

    //
    // List of volumes we won't prefetch on.
    //

    LIST_ENTRY BadVolumeList;

    //
    // List of volumes we have opened. They are opened with the following 
    // flags: FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE
    //

    LIST_ENTRY OpenedVolumeList;

} CCPF_PREFETCH_HEADER, *PCCPF_PREFETCH_HEADER;

//
// Define types of prefetching CcPfPrefetchSections can be called to
// perform.
//

typedef enum _CCPF_PREFETCH_TYPE {
    CcPfPrefetchAllDataPages,
    CcPfPrefetchAllImagePages,
    CcPfPrefetchPartOfDataPages,
    CcPfPrefetchPartOfImagePages,
    CcPfMaxPrefetchType
} CCPF_PREFETCH_TYPE, *PCCPF_PREFETCH_TYPE;

//
// This structure stands for the position in the prefetch
// instructions. It is used and updated by CcPfPrefetchSections when
// prefetching parts of a scenario at a time.
//

typedef struct _CCPF_PREFETCH_CURSOR {
    
    //
    // Index of the current section and the page in that section.
    //

    ULONG SectionIdx;
    ULONG PageIdx;
    
} CCPF_PREFETCH_CURSOR, *PCCPF_PREFETCH_CURSOR;

//
// This type is used in CcPfPrefetchSections.
//

typedef struct _SECTION *PSECTION;

//
// Define types of information CcPfQueryScenarioInformation can be
// asked to return.
//

typedef enum _CCPF_SCENARIO_INFORMATION_TYPE {
    CcPfBasicScenarioInformation,
    CcPfBootScenarioInformation,
    CcPfMaxScenarioInformationType
} CCPF_SCENARIO_INFORMATION_TYPE, *PCCPF_SCENARIO_INFORMATION_TYPE;

//
// This structure contains basic scenario information.
//

typedef struct _CCPF_BASIC_SCENARIO_INFORMATION {
    
    //
    // Number of pages that will be prefetched as data pages.
    //
    
    ULONG NumDataPages;

    //
    // Number of pages that will be prefetched as image pages.
    //

    ULONG NumImagePages;

    //
    // Number of sections for which only data pages will be
    // prefetched.
    //

    ULONG NumDataOnlySections;

    //
    // Number of sections for which only image pages will be
    // prefetched excluding the header page.
    //

    ULONG NumImageOnlySections;

    //
    // Number of ignored pages.
    //
    
    ULONG NumIgnoredPages;

    //
    // Number of ignored sections.
    //

    ULONG NumIgnoredSections;

} CCPF_BASIC_SCENARIO_INFORMATION, *PCCPF_BASIC_SCENARIO_INFORMATION;

//
// Routines used in the core prefetcher.
//

//
// Routines used in prefetch tracing.
//

NTSTATUS
CcPfBeginTrace(
    IN PF_SCENARIO_ID *ScenarioId,
    IN PF_SCENARIO_TYPE ScenarioType,
    IN HANDLE ProcessHandle
    );

NTSTATUS
CcPfActivateTrace(
    IN PCCPF_TRACE_HEADER Scenario
    );

NTSTATUS
CcPfDeactivateTrace(
    IN PCCPF_TRACE_HEADER Scenario
    );

NTSTATUS
CcPfEndTrace(
    IN PCCPF_TRACE_HEADER Trace
    );

NTSTATUS
CcPfBuildDumpFromTrace(
    OUT PCCPF_TRACE_DUMP *TraceDump, 
    IN PCCPF_TRACE_HEADER RuntimeTrace
    );

VOID
CcPfCleanupTrace(
    IN PCCPF_TRACE_HEADER Trace
    );

VOID
CcPfTraceTimerRoutine(
    IN PKDPC Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

NTSTATUS
CcPfCancelTraceTimer(
    IN PCCPF_TRACE_HEADER Trace
    );

VOID
CcPfEndTraceWorkerThreadRoutine(
    PVOID Parameter
    );

VOID
CcPfGetFileNamesWorkerRoutine(
    PVOID Parameter
    );

LONG
CcPfLookUpSection(
    PCCPF_SECTION_INFO Table,
    ULONG TableSize,
    PSECTION_OBJECT_POINTERS SectionObjectPointer,
    PLONG AvailablePosition
    );

NTSTATUS
CcPfGetCompletedTrace (
    PVOID Buffer,
    ULONG BufferSize,
    PULONG ReturnSize
    );               

NTSTATUS
CcPfUpdateVolumeList(
    PCCPF_TRACE_HEADER Trace,
    WCHAR *VolumePath,
    ULONG VolumePathLength
    );
    
//
// Routines used for prefetching and dealing with prefetch instructions.
//

NTSTATUS
CcPfPrefetchScenario (
    PPF_SCENARIO_HEADER Scenario
    );

NTSTATUS
CcPfPrefetchSections(
    IN PCCPF_PREFETCH_HEADER PrefetchHeader,
    IN CCPF_PREFETCH_TYPE PrefetchType,
    OPTIONAL IN PCCPF_PREFETCH_CURSOR StartCursor,
    OPTIONAL ULONG TotalPagesToPrefetch,
    OPTIONAL OUT PULONG NumPagesPrefetched,
    OPTIONAL OUT PCCPF_PREFETCH_CURSOR EndCursor
    );

NTSTATUS
CcPfPrefetchMetadata(
    IN PCCPF_PREFETCH_HEADER PrefetchHeader
    );

NTSTATUS
CcPfPrefetchDirectoryContents(
    WCHAR *DirectoryPath,
    WCHAR DirectoryPathlength
    );

NTSTATUS
CcPfPrefetchFileMetadata(
    HANDLE VolumeHandle,
    PFILE_PREFETCH FilePrefetch
    );

VOID
CcPfInitializePrefetchHeader (
    OUT PCCPF_PREFETCH_HEADER PrefetchHeader
);

VOID
CcPfCleanupPrefetchHeader (
    IN PCCPF_PREFETCH_HEADER PrefetchHeader
    );

NTSTATUS
CcPfGetPrefetchInstructions(
    IN PPF_SCENARIO_ID ScenarioId,
    IN PF_SCENARIO_TYPE ScenarioType,
    OUT PPF_SCENARIO_HEADER *Scenario
    );

NTSTATUS
CcPfQueryScenarioInformation(
    IN PPF_SCENARIO_HEADER Scenario,
    IN CCPF_SCENARIO_INFORMATION_TYPE InformationType,
    OUT PVOID Buffer,
    IN ULONG BufferSize,
    OUT PULONG RequiredSize
    );

NTSTATUS
CcPfOpenVolumesForPrefetch (
    IN PCCPF_PREFETCH_HEADER PrefetchHeader
    );

PCCPF_PREFETCH_VOLUME_INFO 
CcPfFindPrefetchVolumeInfoInList(
    WCHAR *Path,
    PLIST_ENTRY List
    );
    
NTSTATUS
CcPfGetSectionObject(
    IN PUNICODE_STRING FileName,
    IN LOGICAL ImageSection,
    OUT PVOID* SectionObject,
    OUT PFILE_OBJECT* FileObject,
    OUT HANDLE* FileHandle
    );

//
// Routines used for application launch prefetching.
//

BOOLEAN
CcPfIsHostingApplication(
    IN PWCHAR ExecutableName
    );

NTSTATUS
CcPfScanCommandLine(
    OUT PULONG PrefetchHint,
    OPTIONAL OUT PULONG HashId
    );

//
// Reference count functions:
//

VOID
CcPfInitializeRefCount(
    PCCPF_REFCOUNT RefCount
    );

NTSTATUS
FASTCALL
CcPfAddRef(
    PCCPF_REFCOUNT RefCount
    );

VOID
FASTCALL
CcPfDecRef(
    PCCPF_REFCOUNT RefCount
    );

NTSTATUS
FASTCALL
CcPfAddRefEx(
    PCCPF_REFCOUNT RefCount,
    ULONG Count
    );

VOID
FASTCALL
CcPfDecRefEx(
    PCCPF_REFCOUNT RefCount,
    ULONG Count
    );

NTSTATUS
CcPfAcquireExclusiveRef(
    PCCPF_REFCOUNT RefCount
    );

PCCPF_TRACE_HEADER
CcPfReferenceProcessTrace(
    PEPROCESS Process
    );

PCCPF_TRACE_HEADER
CcPfRemoveProcessTrace(
    PEPROCESS Process
    );

NTSTATUS
CcPfAddProcessTrace(
    PEPROCESS Process,
    PCCPF_TRACE_HEADER Trace
    );

//
// Utility routines.
//

PWCHAR
CcPfFindString (
    PUNICODE_STRING SearchIn,
    PUNICODE_STRING SearchFor
    );
    
ULONG
CcPfHashValue(
    PVOID Key,
    ULONG Len
    );

NTSTATUS 
CcPfIsVolumeMounted (
    IN WCHAR *VolumePath,
    OUT BOOLEAN *VolumeMounted
    );
    
NTSTATUS
CcPfQueryVolumeInfo (
    IN WCHAR *VolumePath,
    OPTIONAL OUT HANDLE *VolumeHandleOut,
    OUT PLARGE_INTEGER CreationTime,
    OUT PULONG SerialNumber
    );
    
//
// Declarations and definitions for prefetcher parameters.
//

//
// Define location of registry key for prefetch parameters.
//

#define CCPF_PARAMETERS_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Memory Management\\PrefetchParameters"

//
// Maximum characters in registry value names for prefetch parameters.
//

#define CCPF_MAX_PARAMETER_NAME_LENGTH  80

//
// Maximum bytes needed to query a prefetch parameter from the
// registry. Currently our largest parameter would be the hosting
// application list.
//

#define CCPF_MAX_PARAMETER_VALUE_BUFFER ((PF_HOSTING_APP_LIST_MAX_CHARS * sizeof(WCHAR)) + sizeof(KEY_VALUE_PARTIAL_INFORMATION))

NTSTATUS
CcPfParametersInitialize (
    PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
    );
    
VOID
CcPfParametersSetDefaults (
    PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
    );
    
NTSTATUS
CcPfParametersRead (
    PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
    );
 
NTSTATUS
CcPfParametersSave (
    PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
    );

NTSTATUS
CcPfParametersVerify (
    PPF_SYSTEM_PREFETCH_PARAMETERS Parameters
    );

VOID
CcPfParametersWatcher (
    IN PVOID Context
    );

NTSTATUS
CcPfParametersSetChangedEvent (
    PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
    );

NTSTATUS
CcPfGetParameter (
    HANDLE ParametersKey,
    WCHAR *ValueNameBuffer,
    ULONG ValueType,
    PVOID Value,
    ULONG *ValueSize
    );

NTSTATUS
CcPfSetParameter (
    HANDLE ParametersKey,
    WCHAR *ValueNameBuffer,
    ULONG ValueType,
    PVOID Value,
    ULONG ValueSize
    );

LOGICAL
CcPfDetermineEnablePrefetcher(
    VOID
    );

//
// Declarations and definitions for boot prefetching.
//

//
// Value name under prefetcher parameters key where we store how long
// video initialization took during boot.
//

#define CCPF_VIDEO_INIT_TIME_VALUE_NAME      L"VideoInitTime"

//
// How long (in milliseconds) video initialization could take max. This value 
// is used to sanity check the value read from the registry.
//

#define CCPF_MAX_VIDEO_INIT_TIME             (10 * 1000) // 10 seconds

//
// Value name under prefetcher parameters key where we store how many
// pages we should try to prefetch per second of video initialization.
//

#define CCPF_VIDEO_INIT_PAGES_PER_SECOND_VALUE_NAME L"VideoInitPagesPerSecond"

//
// Sanity check maximum value for video init pages per second.
//

#define CCPF_VIDEO_INIT_MAX_PAGES_PER_SECOND        128000

//
// How many pages will we try to prefetch in parallel to video initialization
// per second of it.
//

#define CCPF_VIDEO_INIT_DEFAULT_PAGES_PER_SECOND    1500

//
// Maximum number of chunks in which we will prefetch for boot.
//

#define CCPF_MAX_BOOT_PREFETCH_PHASES        16

//
// Different phases of boot we return page counts for in
// CCPF_BOOT_SCENARIO_INFORMATION.
//

typedef enum _CCPF_BOOT_SCENARIO_PHASE {

    CcPfBootScenDriverInitPhase,
    CcPfBootScenSubsystemInitPhase,
    CcPfBootScenSystemProcInitPhase,
    CcPfBootScenServicesInitPhase,
    CcPfBootScenUserInitPhase,
    CcPfBootScenMaxPhase

} CCPF_BOOT_SCENARIO_PHASE, *PCCPF_BOOT_SCENARIO_PHASE;

//
// Define structure to hold boot prefetching state.
//

typedef struct _CCPF_BOOT_PREFETCHER {

    //
    // These events are signaled by the boot prefetch worker when 
    // it has completed prefetching for the specified phase. 
    //

    KEVENT SystemDriversPrefetchingDone;
    KEVENT PreSmssPrefetchingDone;
    KEVENT VideoInitPrefetchingDone;

    //
    // This event will be signaled when we start initializing video
    // on the console. Boot prefetcher waits on this event to perform
    // prefetching parallel to video initialization.
    //
    
    KEVENT VideoInitStarted;

} CCPF_BOOT_PREFETCHER, *PCCPF_BOOT_PREFETCHER;

//
// This structure contains boot scenario information.
//

typedef struct _CCPF_BOOT_SCENARIO_INFORMATION {

    //
    // These are the number of data/image pages to prefetch for the
    // different phase of boot.
    //

    ULONG NumDataPages[CcPfBootScenMaxPhase];
    ULONG NumImagePages[CcPfBootScenMaxPhase];
    
} CCPF_BOOT_SCENARIO_INFORMATION, *PCCPF_BOOT_SCENARIO_INFORMATION;

//
// We will be prefetching data and image pages for boot in parts. Since the
// code is mostly same to prefetch the data and image pages, we keep track
// of where we left off and what to prefetch next in a common boot prefetch 
// cursor structure and make two passes (first for data, then for image).
//

typedef struct _CCPF_BOOT_PREFETCH_CURSOR {

    //
    // Start & end cursors passed to prefetch sections function.
    //

    CCPF_PREFETCH_CURSOR StartCursor;
    CCPF_PREFETCH_CURSOR EndCursor;

    //
    // How to prefetch (e.g. part of data pages or part of image pages).
    //

    CCPF_PREFETCH_TYPE PrefetchType; 

    //
    // How many pages to prefetch per phase.
    //

    ULONG NumPagesForPhase[CCPF_MAX_BOOT_PREFETCH_PHASES];
   
} CCPF_BOOT_PREFETCH_CURSOR, *PCCPF_BOOT_PREFETCH_CURSOR;

//
// Boot prefetching routines.
//

VOID
CcPfBootWorker(
    PCCPF_BOOT_PREFETCHER BootPrefetcher
    );

NTSTATUS
CcPfBootQueueEndTraceTimer (
    PLARGE_INTEGER Timeout
    );    

VOID
CcPfEndBootTimerRoutine(
    IN PKDPC Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );

//
// Debug routines.
//

#if CCPF_DBG

NTSTATUS
CcPfWriteToFile(
    IN PVOID pData,
    IN ULONG Size,
    IN WCHAR *pFileName
    );

#endif // CCPF_DBG

//
// Define useful macros. As with all macros, must be careful of
// parameter reevalation. Don't use expressions as macro parameters.
//

#define CCPF_MAX(A,B) (((A) >= (B)) ? (A) : (B))
#define CCPF_MIN(A,B) (((A) <= (B)) ? (A) : (B))
        
//
// Define debugging macros:
//

//
// Define the component ID we use.
//

#define CCPFID     DPFLTR_PREFETCHER_ID

//
// Define DbgPrintEx levels.
//

#define PFERR      DPFLTR_ERROR_LEVEL
#define PFWARN     DPFLTR_WARNING_LEVEL
#define PFTRC      DPFLTR_TRACE_LEVEL
#define PFINFO     DPFLTR_INFO_LEVEL
#define PFPREF     4
#define PFPRFD     5
#define PFPRFF     6
#define PFPRFZ     7
#define PFTRAC     8
#define PFTMR      9
#define PFNAME     10
#define PFNAMS     11
#define PFLKUP     12
#define PFBOOT     13

//
// DbgPrintEx levels 20 - 31 are reserved for the service.
//

//
//  This may help you determine what to set the DbgPrintEx mask.
//
//  3 3 2 2  2 2 2 2  2 2 2 2  1 1 1 1   1 1 1 1  1 1 0 0  0 0 0 0  0 0 0 0
//  1 0 9 8  7 6 5 4  3 2 1 0  9 8 7 6   5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
//  _ _ _ _  _ _ _ _  _ _ _ _  _ _ _ _   _ _ _ _  _ _ _ _  _ _ _ _  _ _ _ _
//

//
// CCPF_DBG can be defined if you want to turn on asserts and debug
// prints in prefetcher code but you do not want to have a checked
// kernel. Defining CCPF_DBG overrides defining DBG.
//

#if CCPF_DBG

NTSYSAPI
VOID
NTAPI
RtlAssert(
    PVOID FailedAssertion,
    PVOID FileName,
    ULONG LineNumber,
    PCHAR Message
    );

#define DBGPR(x) DbgPrintEx x
#define CCPF_ASSERT(x) if (!(x)) RtlAssert(#x, __FILE__, __LINE__, NULL )

#else  // CCPF_DBG

//
// If CCPF_DBG is not defined, build with debug prints and asserts
// only on checked build.
//

#if DBG

#define DBGPR(x) DbgPrintEx x
#define CCPF_ASSERT(x) ASSERT(x)

#else // DBG

//
// On a free build we don't compile with debug prints or asserts.
//

#define DBGPR(x)
#define CCPF_ASSERT(x)

#endif // DBG

#endif // CCPF_DBG

#endif // _PREFTCHP_H
