Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1228 lines
33 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. prefboot.c
  5. Abstract:
  6. This module contains the code for boot prefetching.
  7. Author:
  8. Cenk Ergan (cenke) 15-Mar-2000
  9. Revision History:
  10. --*/
  11. #include "cc.h"
  12. #include "zwapi.h"
  13. #include "prefetch.h"
  14. #include "preftchp.h"
  15. #include "stdio.h"
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE, CcPfBeginBootPhase)
  18. #pragma alloc_text(PAGE, CcPfBootWorker)
  19. #pragma alloc_text(PAGE, CcPfBootQueueEndTraceTimer)
  20. #endif // ALLOC_PRAGMA
  21. //
  22. // Globals:
  23. //
  24. //
  25. // Whether the system is currently prefetching for boot.
  26. //
  27. LOGICAL CcPfPrefetchingForBoot = FALSE;
  28. //
  29. // Current boot phase, only updated in begin boot phase routine.
  30. //
  31. PF_BOOT_PHASE_ID CcPfBootPhase = 0;
  32. //
  33. // Prefetcher globals.
  34. //
  35. extern CCPF_PREFETCHER_GLOBALS CcPfGlobals;
  36. //
  37. // Routines for boot prefetching.
  38. //
  39. NTSTATUS
  40. CcPfBeginBootPhase(
  41. PF_BOOT_PHASE_ID Phase
  42. )
  43. /*++
  44. Routine Description:
  45. This routine is the control center for the boot prefetcher.
  46. It is called to notify boot prefetcher of boot progress.
  47. Arguments:
  48. Phase - Boot phase the system is entering.
  49. Return Value:
  50. Status.
  51. Environment:
  52. Kernel mode. IRQL == PASSIVE_LEVEL.
  53. --*/
  54. {
  55. LARGE_INTEGER VideoInitEndTime;
  56. LARGE_INTEGER MaxWaitTime;
  57. LONGLONG VideoInitTimeIn100ns;
  58. HANDLE ThreadHandle;
  59. PETHREAD Thread;
  60. PERFINFO_BOOT_PHASE_START LogEntry;
  61. PF_BOOT_PHASE_ID OriginalPhase;
  62. PF_BOOT_PHASE_ID NewPhase;
  63. ULONG VideoInitTime;
  64. NTSTATUS Status;
  65. //
  66. // This is the boot prefetcher. It is allocated and free'd in this routine.
  67. // It is passed to the spawned boot worker if boot prefetching is enabled.
  68. //
  69. static PCCPF_BOOT_PREFETCHER BootPrefetcher = NULL;
  70. //
  71. // This is the system time when we started initializing the video.
  72. //
  73. static LARGE_INTEGER VideoInitStartTime;
  74. DBGPR((CCPFID,PFTRC,"CCPF: BeginBootPhase(%d)\n", (ULONG)Phase));
  75. //
  76. // Make sure phase is valid.
  77. //
  78. if (Phase >= PfMaxBootPhaseId) {
  79. Status = STATUS_INVALID_PARAMETER;
  80. goto cleanup;
  81. }
  82. //
  83. // Log phase to trace buffer.
  84. //
  85. if (PERFINFO_IS_GROUP_ON(PERF_LOADER)) {
  86. LogEntry.Phase = Phase;
  87. PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PHASE_START,
  88. &LogEntry,
  89. sizeof(LogEntry));
  90. }
  91. //
  92. // Update the global current boot phase.
  93. //
  94. for (;;) {
  95. OriginalPhase = CcPfBootPhase;
  96. if (Phase <= OriginalPhase) {
  97. Status = STATUS_TOO_LATE;
  98. goto cleanup;
  99. }
  100. //
  101. // If CcPfBootPhase is still OriginalPhase, set it to Phase.
  102. //
  103. NewPhase = InterlockedCompareExchange(&(LONG)CcPfBootPhase, Phase, OriginalPhase);
  104. if (NewPhase == OriginalPhase) {
  105. //
  106. // CcPfBootPhase was still OriginalPhase, so now it is set to
  107. // Phase. We are done.
  108. //
  109. break;
  110. }
  111. }
  112. Status = STATUS_SUCCESS;
  113. //
  114. // Perform the work we have to do for this boot phase.
  115. //
  116. switch (Phase) {
  117. case PfSystemDriverInitPhase:
  118. //
  119. // Update whether prefetcher is enabled or not.
  120. //
  121. CcPfDetermineEnablePrefetcher();
  122. //
  123. // If boot prefetching is not enabled, we are done.
  124. //
  125. if (!CCPF_IS_PREFETCHER_ENABLED() ||
  126. CcPfGlobals.Parameters.Parameters.EnableStatus[PfSystemBootScenarioType] != PfSvEnabled) {
  127. Status = STATUS_NOT_SUPPORTED;
  128. break;
  129. }
  130. //
  131. // Allocate and initialize boot prefetcher.
  132. //
  133. BootPrefetcher = ExAllocatePoolWithTag(NonPagedPool,
  134. sizeof(*BootPrefetcher),
  135. CCPF_ALLOC_BOOTWRKR_TAG);
  136. if (!BootPrefetcher) {
  137. Status = STATUS_INSUFFICIENT_RESOURCES;
  138. break;
  139. }
  140. KeInitializeEvent(&BootPrefetcher->SystemDriversPrefetchingDone,
  141. NotificationEvent,
  142. FALSE);
  143. KeInitializeEvent(&BootPrefetcher->PreSmssPrefetchingDone,
  144. NotificationEvent,
  145. FALSE);
  146. KeInitializeEvent(&BootPrefetcher->VideoInitPrefetchingDone,
  147. NotificationEvent,
  148. FALSE);
  149. KeInitializeEvent(&BootPrefetcher->VideoInitStarted,
  150. NotificationEvent,
  151. FALSE);
  152. //
  153. // Kick off the boot worker in paralel.
  154. //
  155. Status = PsCreateSystemThread(&ThreadHandle,
  156. THREAD_ALL_ACCESS,
  157. NULL,
  158. NULL,
  159. NULL,
  160. CcPfBootWorker,
  161. BootPrefetcher);
  162. if (NT_SUCCESS(Status)) {
  163. //
  164. // Give boot worker some head start by bumping its
  165. // priority. This helps to make sure pages we will
  166. // prefetch are put into transition before boot gets
  167. // ahead of the prefetcher.
  168. //
  169. Status = ObReferenceObjectByHandle(ThreadHandle,
  170. THREAD_SET_INFORMATION,
  171. PsThreadType,
  172. KernelMode,
  173. &Thread,
  174. NULL);
  175. if (NT_SUCCESS(Status)) {
  176. KeSetPriorityThread(&Thread->Tcb, HIGH_PRIORITY - 1);
  177. ObDereferenceObject(Thread);
  178. }
  179. ZwClose(ThreadHandle);
  180. //
  181. // Before returning to initialize system drivers, wait
  182. // for boot worker to make progress.
  183. //
  184. KeWaitForSingleObject(&BootPrefetcher->SystemDriversPrefetchingDone,
  185. Executive,
  186. KernelMode,
  187. FALSE,
  188. NULL);
  189. } else {
  190. //
  191. // Free the allocated boot prefetcher.
  192. //
  193. ExFreePool(BootPrefetcher);
  194. BootPrefetcher = NULL;
  195. }
  196. break;
  197. case PfSessionManagerInitPhase:
  198. //
  199. // Wait for boot worker to make enough progress before launching
  200. // session manager.
  201. //
  202. if (BootPrefetcher) {
  203. KeWaitForSingleObject(&BootPrefetcher->PreSmssPrefetchingDone,
  204. Executive,
  205. KernelMode,
  206. FALSE,
  207. NULL);
  208. }
  209. break;
  210. case PfVideoInitPhase:
  211. //
  212. // Note when video initialization started.
  213. //
  214. KeQuerySystemTime(&VideoInitStartTime);
  215. //
  216. // Signal boot prefetcher to start prefetching in parallel to video
  217. // initialization.
  218. //
  219. if (BootPrefetcher) {
  220. KeSetEvent(&BootPrefetcher->VideoInitStarted,
  221. IO_NO_INCREMENT,
  222. FALSE);
  223. }
  224. break;
  225. case PfPostVideoInitPhase:
  226. //
  227. // Note when we complete video initialization. Save how long video
  228. // initialization took in the registry in milliseconds.
  229. //
  230. KeQuerySystemTime(&VideoInitEndTime);
  231. VideoInitTimeIn100ns = VideoInitEndTime.QuadPart - VideoInitStartTime.QuadPart;
  232. VideoInitTime = (ULONG) (VideoInitTimeIn100ns / (1i64 * 10 * 1000));
  233. KeEnterCriticalRegionThread(KeGetCurrentThread());
  234. ExAcquireResourceSharedLite(&CcPfGlobals.Parameters.ParametersLock, TRUE);
  235. Status = CcPfSetParameter(CcPfGlobals.Parameters.ParametersKey,
  236. CCPF_VIDEO_INIT_TIME_VALUE_NAME,
  237. REG_DWORD,
  238. &VideoInitTime,
  239. sizeof(VideoInitTime));
  240. ExReleaseResourceLite(&CcPfGlobals.Parameters.ParametersLock);
  241. KeLeaveCriticalRegionThread(KeGetCurrentThread());
  242. //
  243. // Wait for prefetching parallel to video initialization to complete.
  244. //
  245. if (BootPrefetcher) {
  246. //
  247. // Make sure video init was signaled if it was skipped somehow.
  248. //
  249. KeSetEvent(&BootPrefetcher->VideoInitStarted, IO_NO_INCREMENT, FALSE);
  250. KeWaitForSingleObject(&BootPrefetcher->VideoInitPrefetchingDone,
  251. Executive,
  252. KernelMode,
  253. FALSE,
  254. NULL);
  255. }
  256. break;
  257. case PfBootAcceptedRegistryInitPhase:
  258. //
  259. // Service Controller has accepted this boot as a valid boot.
  260. // Boot & system services have initialized successfully.
  261. //
  262. //
  263. // We are done with boot prefetching. No one else could be accessing
  264. // BootPrefetcher structure at this point.
  265. //
  266. if (BootPrefetcher) {
  267. //
  268. // Cleanup the allocated boot prefetcher.
  269. //
  270. ExFreePool(BootPrefetcher);
  271. BootPrefetcher = NULL;
  272. //
  273. // Determine if the prefetcher is enabled now that boot
  274. // is over.
  275. //
  276. CcPfDetermineEnablePrefetcher();
  277. }
  278. //
  279. // The user may not log in after booting.
  280. // Queue a timer to end boot trace.
  281. //
  282. MaxWaitTime.QuadPart = -1i64 * 60 * 1000 * 1000 * 10; // 60 seconds.
  283. CcPfBootQueueEndTraceTimer(&MaxWaitTime);
  284. break;
  285. case PfUserShellReadyPhase:
  286. //
  287. // Explorer has started, but start menu items may still be launching.
  288. // Queue a timer to end boot trace.
  289. //
  290. MaxWaitTime.QuadPart = -1i64 * 30 * 1000 * 1000 * 10; // 30 seconds.
  291. CcPfBootQueueEndTraceTimer(&MaxWaitTime);
  292. break;
  293. default:
  294. //
  295. // Ignored for now.
  296. //
  297. Status = STATUS_SUCCESS;
  298. }
  299. //
  300. // Fall through with status from switch statement.
  301. //
  302. cleanup:
  303. DBGPR((CCPFID,PFTRC,"CCPF: BeginBootPhase(%d)=%x\n", (ULONG)Phase, Status));
  304. return Status;
  305. }
  306. VOID
  307. CcPfBootWorker(
  308. PCCPF_BOOT_PREFETCHER BootPrefetcher
  309. )
  310. /*++
  311. Routine Description:
  312. This routine is queued to prefetch and start tracing boot in parallel.
  313. Arguments:
  314. BootPrefetcher - Pointer to boot prefetcher context.
  315. Return Value:
  316. None.
  317. Environment:
  318. Kernel mode. IRQL == PASSIVE_LEVEL.
  319. --*/
  320. {
  321. PF_SCENARIO_ID BootScenarioId;
  322. CCPF_PREFETCH_HEADER PrefetchHeader;
  323. CCPF_BASIC_SCENARIO_INFORMATION ScenarioInfo;
  324. CCPF_BOOT_SCENARIO_INFORMATION BootScenarioInfo;
  325. PERFINFO_BOOT_PREFETCH_INFORMATION LogEntry;
  326. ULONG NumPages;
  327. ULONG RequiredSize;
  328. PFN_NUMBER NumPagesPrefetched;
  329. PFN_NUMBER TotalPagesPrefetched;
  330. ULONG BootPrefetchAdjustment;
  331. PFN_NUMBER AvailablePages;
  332. PFN_NUMBER NumPagesToPrefetch;
  333. ULONG TotalPagesToPrefetch;
  334. ULONG RemainingDataPages;
  335. ULONG RemainingImagePages;
  336. ULONG VideoInitTime;
  337. ULONG VideoInitPagesPerSecond;
  338. ULONG VideoInitMaxPages;
  339. ULONG RemainingVideoInitPages;
  340. ULONG VideoInitDataPages;
  341. ULONG VideoInitImagePages;
  342. ULONG PrefetchPhaseIdx;
  343. ULONG LastPrefetchPhaseIdx;
  344. ULONG SystemDriverPrefetchingPhaseIdx;
  345. ULONG PreSmssPrefetchingPhaseIdx;
  346. ULONG VideoInitPrefetchingPhaseIdx;
  347. ULONG ValueSize;
  348. CCPF_BOOT_SCENARIO_PHASE BootPhaseIdx;
  349. NTSTATUS Status;
  350. BOOLEAN OutOfAvailablePages;
  351. BOOLEAN BootPrefetcherGone;
  352. //
  353. // First we will prefetch data pages, then image pages.
  354. //
  355. enum {
  356. DataCursor = 0,
  357. ImageCursor,
  358. MaxCursor
  359. } CursorIdx;
  360. CCPF_BOOT_PREFETCH_CURSOR Cursors[MaxCursor];
  361. PCCPF_BOOT_PREFETCH_CURSOR Cursor;
  362. //
  363. // Initialize locals.
  364. //
  365. BootPrefetcherGone = FALSE;
  366. CcPfInitializePrefetchHeader(&PrefetchHeader);
  367. TotalPagesPrefetched = 0;
  368. OutOfAvailablePages = FALSE;
  369. DBGPR((CCPFID,PFTRC,"CCPF: BootWorker()\n"));
  370. //
  371. // Initialize boot scenario ID.
  372. //
  373. wcsncpy(BootScenarioId.ScenName,
  374. PF_BOOT_SCENARIO_NAME,
  375. PF_SCEN_ID_MAX_CHARS);
  376. BootScenarioId.ScenName[PF_SCEN_ID_MAX_CHARS] = 0;
  377. BootScenarioId.HashId = PF_BOOT_SCENARIO_HASHID;
  378. //
  379. // Start boot prefetch tracing.
  380. //
  381. CcPfBeginTrace(&BootScenarioId, PfSystemBootScenarioType, PsInitialSystemProcess);
  382. //
  383. // If we try to prefetch more pages then what we have available, we will
  384. // end up cannibalizing the pages we prefetched into the standby list.
  385. // To avoid cannibalizing, we check MmAvailablePages but leave some
  386. // breathing room for metadata pages, allocations from the driver
  387. // initialization phase etc.
  388. //
  389. BootPrefetchAdjustment = 512;
  390. //
  391. // We also know that right after we prefetch for boot, in smss when
  392. // initializing the registry we'll use up 8-10MB of prefetched pages if we
  393. // don't have anything left in the free list. So we leave some room for
  394. // that too.
  395. //
  396. BootPrefetchAdjustment += 8 * 1024 * 1024 / PAGE_SIZE;
  397. //
  398. // Get prefetch instructions.
  399. //
  400. Status = CcPfGetPrefetchInstructions(&BootScenarioId,
  401. PfSystemBootScenarioType,
  402. &PrefetchHeader.Scenario);
  403. if (!NT_SUCCESS(Status)) {
  404. goto cleanup;
  405. }
  406. //
  407. // Query the total number of pages to be prefetched.
  408. //
  409. Status = CcPfQueryScenarioInformation(PrefetchHeader.Scenario,
  410. CcPfBasicScenarioInformation,
  411. &ScenarioInfo,
  412. sizeof(ScenarioInfo),
  413. &RequiredSize);
  414. if (!NT_SUCCESS(Status)) {
  415. goto cleanup;
  416. }
  417. //
  418. // Query the number of pages we have to prefetch for boot phases.
  419. //
  420. Status = CcPfQueryScenarioInformation(PrefetchHeader.Scenario,
  421. CcPfBootScenarioInformation,
  422. &BootScenarioInfo,
  423. sizeof(BootScenarioInfo),
  424. &RequiredSize);
  425. if (!NT_SUCCESS(Status)) {
  426. goto cleanup;
  427. }
  428. //
  429. // Read how long it took to initialize video in the last boot.
  430. //
  431. KeEnterCriticalRegionThread(KeGetCurrentThread());
  432. ExAcquireResourceSharedLite(&CcPfGlobals.Parameters.ParametersLock, TRUE);
  433. ValueSize = sizeof(VideoInitTime);
  434. Status = CcPfGetParameter(CcPfGlobals.Parameters.ParametersKey,
  435. CCPF_VIDEO_INIT_TIME_VALUE_NAME,
  436. REG_DWORD,
  437. &VideoInitTime,
  438. &ValueSize);
  439. ExReleaseResourceLite(&CcPfGlobals.Parameters.ParametersLock);
  440. KeLeaveCriticalRegionThread(KeGetCurrentThread());
  441. if (!NT_SUCCESS(Status)) {
  442. //
  443. // Reset video init time, so we don't attempt to prefetch
  444. // in parallel to it.
  445. //
  446. VideoInitTime = 0;
  447. } else {
  448. //
  449. // Verify the value we read from registry.
  450. //
  451. if (VideoInitTime > CCPF_MAX_VIDEO_INIT_TIME) {
  452. VideoInitTime = 0;
  453. }
  454. }
  455. //
  456. // Read how many pages per second we should be trying to prefetching
  457. // in parallel to video initialization.
  458. //
  459. KeEnterCriticalRegionThread(KeGetCurrentThread());
  460. ExAcquireResourceSharedLite(&CcPfGlobals.Parameters.ParametersLock, TRUE);
  461. ValueSize = sizeof(VideoInitPagesPerSecond);
  462. Status = CcPfGetParameter(CcPfGlobals.Parameters.ParametersKey,
  463. CCPF_VIDEO_INIT_PAGES_PER_SECOND_VALUE_NAME,
  464. REG_DWORD,
  465. &VideoInitPagesPerSecond,
  466. &ValueSize);
  467. ExReleaseResourceLite(&CcPfGlobals.Parameters.ParametersLock);
  468. KeLeaveCriticalRegionThread(KeGetCurrentThread());
  469. if (!NT_SUCCESS(Status)) {
  470. //
  471. // There was no valid value in the registry. Use the default.
  472. //
  473. VideoInitPagesPerSecond = CCPF_VIDEO_INIT_DEFAULT_PAGES_PER_SECOND;
  474. } else {
  475. //
  476. // Verify the value we read from registry.
  477. //
  478. if (VideoInitPagesPerSecond > CCPF_VIDEO_INIT_MAX_PAGES_PER_SECOND) {
  479. VideoInitPagesPerSecond = CCPF_VIDEO_INIT_MAX_PAGES_PER_SECOND;
  480. }
  481. }
  482. //
  483. // Determine how many pages max we can prefetch in parallel to video
  484. // initialization.
  485. //
  486. VideoInitMaxPages = VideoInitTime * VideoInitPagesPerSecond / 1000;
  487. //
  488. // We can only prefetch pages used after winlogon in parallel to video
  489. // initialization. Determine exactly how many pages we will prefetch
  490. // starting from the last boot phase.
  491. //
  492. RemainingVideoInitPages = VideoInitMaxPages;
  493. VideoInitDataPages = 0;
  494. VideoInitImagePages = 0;
  495. for (BootPhaseIdx = CcPfBootScenMaxPhase - 1;
  496. RemainingVideoInitPages && (BootPhaseIdx >= CcPfBootScenSystemProcInitPhase);
  497. BootPhaseIdx--) {
  498. NumPages = CCPF_MIN(RemainingVideoInitPages, BootScenarioInfo.NumDataPages[BootPhaseIdx]);
  499. VideoInitDataPages += NumPages;
  500. RemainingVideoInitPages -= NumPages;
  501. if (RemainingVideoInitPages) {
  502. NumPages = CCPF_MIN(RemainingVideoInitPages, BootScenarioInfo.NumImagePages[BootPhaseIdx]);
  503. VideoInitImagePages += NumPages;
  504. RemainingVideoInitPages -= NumPages;
  505. }
  506. }
  507. //
  508. // Let MM know that we have started prefetching for boot.
  509. //
  510. CcPfPrefetchingForBoot = TRUE;
  511. //
  512. // Log that we are starting prefetch disk I/Os.
  513. //
  514. if (PERFINFO_IS_GROUP_ON(PERF_DISK_IO)) {
  515. LogEntry.Action = 0;
  516. LogEntry.Status = 0;
  517. LogEntry.Pages = ScenarioInfo.NumDataPages + ScenarioInfo.NumImagePages;
  518. PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PREFETCH_INFORMATION,
  519. &LogEntry,
  520. sizeof(LogEntry));
  521. }
  522. //
  523. // Verify & open the volumes that we will prefetch from.
  524. //
  525. Status = CcPfOpenVolumesForPrefetch(&PrefetchHeader);
  526. if (!NT_SUCCESS(Status)) {
  527. goto cleanup;
  528. }
  529. //
  530. // Prefetch the metadata.
  531. //
  532. CcPfPrefetchMetadata(&PrefetchHeader);
  533. //
  534. // Initialize the boot prefetch cursors for data and image.
  535. //
  536. RtlZeroMemory(Cursors, sizeof(Cursors));
  537. Cursors[DataCursor].PrefetchType = CcPfPrefetchPartOfDataPages;
  538. Cursors[ImageCursor].PrefetchType = CcPfPrefetchPartOfImagePages;
  539. PrefetchPhaseIdx = 0;
  540. RemainingDataPages = ScenarioInfo.NumDataPages;
  541. RemainingImagePages = ScenarioInfo.NumImagePages;
  542. //
  543. // Setup the cursors for phases in which we will prefetch for boot.
  544. // First we will prefetch for system drivers.
  545. //
  546. NumPages = BootScenarioInfo.NumDataPages[CcPfBootScenDriverInitPhase];
  547. Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages;
  548. RemainingDataPages -= NumPages;
  549. NumPages = BootScenarioInfo.NumImagePages[CcPfBootScenDriverInitPhase];
  550. Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages;
  551. RemainingImagePages -= NumPages;
  552. SystemDriverPrefetchingPhaseIdx = PrefetchPhaseIdx;
  553. PrefetchPhaseIdx++;
  554. //
  555. // Account for the video init pages we will prefetch last.
  556. //
  557. RemainingDataPages -= VideoInitDataPages;
  558. RemainingImagePages -= VideoInitImagePages;
  559. //
  560. // If we have plenty of available memory, prefetch the rest of the pages
  561. // (i.e. left over after driver init pages) in one pass.
  562. //
  563. TotalPagesToPrefetch = ScenarioInfo.NumDataPages + ScenarioInfo.NumImagePages;
  564. if (MmAvailablePages > BootPrefetchAdjustment + TotalPagesToPrefetch) {
  565. Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = RemainingDataPages;
  566. RemainingDataPages = 0;
  567. Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = RemainingImagePages;
  568. RemainingImagePages = 0;
  569. PrefetchPhaseIdx++;
  570. } else {
  571. //
  572. // We will be short on memory. Try to prefetch for as many phases of
  573. // boot as we can in parallel. Prefetching data & image pages per boot
  574. // phase, so we don't end up with data pages for all phase but no image
  575. // pages so we have to go to the disk in each phase. Prefetching in
  576. // chunks also help that all the pages we need for the initial phases
  577. // of boot ending up at the end of the standby list, since when
  578. // CcPfPrefetchingForBoot is set, prefetched pages will be inserted
  579. // from the front of the standby list.
  580. //
  581. for (BootPhaseIdx = CcPfBootScenDriverInitPhase + 1;
  582. BootPhaseIdx < CcPfBootScenMaxPhase;
  583. BootPhaseIdx++) {
  584. //
  585. // If we don't have any type of pages left to prefetch, we are done.
  586. //
  587. if (!RemainingDataPages && !RemainingImagePages) {
  588. break;
  589. }
  590. NumPages = CCPF_MIN(RemainingDataPages, BootScenarioInfo.NumDataPages[BootPhaseIdx]);
  591. RemainingDataPages -= NumPages;
  592. Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages;
  593. NumPages = CCPF_MIN(RemainingImagePages, BootScenarioInfo.NumImagePages[BootPhaseIdx]);
  594. RemainingImagePages -= NumPages;
  595. Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = NumPages;
  596. PrefetchPhaseIdx++;
  597. }
  598. }
  599. PreSmssPrefetchingPhaseIdx = PrefetchPhaseIdx - 1;
  600. //
  601. // If we'll be prefetching pages in parallel to video initialization, now
  602. // add the phase for it.
  603. //
  604. if (VideoInitDataPages || VideoInitImagePages) {
  605. Cursors[DataCursor].NumPagesForPhase[PrefetchPhaseIdx] = VideoInitDataPages;
  606. Cursors[ImageCursor].NumPagesForPhase[PrefetchPhaseIdx] = VideoInitImagePages;
  607. VideoInitPrefetchingPhaseIdx = PrefetchPhaseIdx;
  608. PrefetchPhaseIdx++;
  609. } else {
  610. //
  611. // We won't have a prefetching phase parallel to video initialization.
  612. //
  613. VideoInitPrefetchingPhaseIdx = CCPF_MAX_BOOT_PREFETCH_PHASES;
  614. }
  615. //
  616. // We should not end up with more prefetch phases than we have room for.
  617. //
  618. CCPF_ASSERT(PrefetchPhaseIdx <= CCPF_MAX_BOOT_PREFETCH_PHASES);
  619. LastPrefetchPhaseIdx = PrefetchPhaseIdx;
  620. //
  621. // Prefetch the data and image pages for each boot prefetching phase,
  622. // waiting for & signaling the events matching those phases so boot
  623. // is synchronized with prefetching. (I.e. we prefetch pages for a boot
  624. // phase before we start that boot phase.)
  625. //
  626. for (PrefetchPhaseIdx = 0; PrefetchPhaseIdx < LastPrefetchPhaseIdx; PrefetchPhaseIdx++) {
  627. //
  628. // If this is the video init prefetching phase, wait for video
  629. // initialization to begin.
  630. //
  631. if (PrefetchPhaseIdx == VideoInitPrefetchingPhaseIdx) {
  632. KeWaitForSingleObject(&BootPrefetcher->VideoInitStarted,
  633. Executive,
  634. KernelMode,
  635. FALSE,
  636. NULL);
  637. }
  638. for (CursorIdx = 0; CursorIdx < MaxCursor; CursorIdx++) {
  639. Cursor = &Cursors[CursorIdx];
  640. NumPagesToPrefetch = Cursor->NumPagesForPhase[PrefetchPhaseIdx];
  641. //
  642. // For prefetch phases before SMSS is launched keep an eye on
  643. // how much memory is still available to prefetch into so we
  644. // don't cannibalize ourselves. After SMSS our heuristics on
  645. // standby-list composition do not make sense.
  646. //
  647. if (PrefetchPhaseIdx <= PreSmssPrefetchingPhaseIdx) {
  648. //
  649. // Check if we have available memory to prefetch more.
  650. //
  651. if (TotalPagesPrefetched + BootPrefetchAdjustment >= MmAvailablePages) {
  652. OutOfAvailablePages = TRUE;
  653. NumPagesToPrefetch = 0;
  654. } else {
  655. //
  656. // Check if we have to adjust NumPagesToPrefetch and prefetch
  657. // one last chunk.
  658. //
  659. AvailablePages = MmAvailablePages;
  660. AvailablePages -= (TotalPagesPrefetched + BootPrefetchAdjustment);
  661. if (AvailablePages < NumPagesToPrefetch) {
  662. OutOfAvailablePages = TRUE;
  663. NumPagesToPrefetch = AvailablePages;
  664. }
  665. }
  666. }
  667. if (NumPagesToPrefetch) {
  668. Status = CcPfPrefetchSections(&PrefetchHeader,
  669. Cursor->PrefetchType,
  670. &Cursor->StartCursor,
  671. NumPagesToPrefetch,
  672. &NumPagesPrefetched,
  673. &Cursor->EndCursor);
  674. if (!NT_SUCCESS(Status)) {
  675. goto cleanup;
  676. }
  677. } else {
  678. NumPagesPrefetched = 0;
  679. }
  680. //
  681. // Update our position.
  682. //
  683. Cursor->StartCursor = Cursor->EndCursor;
  684. TotalPagesPrefetched += NumPagesPrefetched;
  685. }
  686. //
  687. // Note that we are done with this prefetching phase and
  688. // system boot can continue.
  689. //
  690. if (PrefetchPhaseIdx == SystemDriverPrefetchingPhaseIdx) {
  691. KeSetEvent(&BootPrefetcher->SystemDriversPrefetchingDone,
  692. IO_NO_INCREMENT,
  693. FALSE);
  694. }
  695. if (PrefetchPhaseIdx == PreSmssPrefetchingPhaseIdx) {
  696. KeSetEvent(&BootPrefetcher->PreSmssPrefetchingDone,
  697. IO_NO_INCREMENT,
  698. FALSE);
  699. }
  700. if (PrefetchPhaseIdx == VideoInitPrefetchingPhaseIdx) {
  701. KeSetEvent(&BootPrefetcher->VideoInitPrefetchingDone,
  702. IO_NO_INCREMENT,
  703. FALSE);
  704. //
  705. // After we signal this event the BootPrefetcher structure may
  706. // get freed, so don't touch it.
  707. //
  708. BootPrefetcherGone = TRUE;
  709. }
  710. }
  711. Status = STATUS_SUCCESS;
  712. cleanup:
  713. //
  714. // Log that we are done with boot prefetch disk I/Os.
  715. //
  716. if (PERFINFO_IS_GROUP_ON(PERF_DISK_IO)) {
  717. LogEntry.Action = 1;
  718. LogEntry.Status = Status;
  719. LogEntry.Pages = (ULONG) TotalPagesPrefetched;
  720. PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PREFETCH_INFORMATION,
  721. &LogEntry,
  722. sizeof(LogEntry));
  723. }
  724. //
  725. // Make sure all the events system may wait for before proceeding with
  726. // boot are signaled.
  727. //
  728. if (!BootPrefetcherGone) {
  729. //
  730. // Don't access the BootPrefetcher structure after the video-init-done
  731. // event is signaled: it may get freed from beneath us.
  732. //
  733. KeSetEvent(&BootPrefetcher->SystemDriversPrefetchingDone,
  734. IO_NO_INCREMENT,
  735. FALSE);
  736. KeSetEvent(&BootPrefetcher->PreSmssPrefetchingDone,
  737. IO_NO_INCREMENT,
  738. FALSE);
  739. KeSetEvent(&BootPrefetcher->VideoInitPrefetchingDone,
  740. IO_NO_INCREMENT,
  741. FALSE);
  742. BootPrefetcherGone = TRUE;
  743. }
  744. //
  745. // Let MM know that we are done prefetching for boot.
  746. //
  747. CcPfPrefetchingForBoot = FALSE;
  748. //
  749. // Cleanup prefetching context.
  750. //
  751. CcPfCleanupPrefetchHeader(&PrefetchHeader);
  752. if (PrefetchHeader.Scenario) {
  753. ExFreePool(PrefetchHeader.Scenario);
  754. }
  755. DBGPR((CCPFID,PFTRC,"CCPF: BootWorker()=%x,%d\n",Status,(ULONG)OutOfAvailablePages));
  756. }
  757. NTSTATUS
  758. CcPfBootQueueEndTraceTimer (
  759. PLARGE_INTEGER Timeout
  760. )
  761. /*++
  762. Routine Description:
  763. This routine allocates and queues a timer that will attempt to end
  764. the boot trace when it fires.
  765. Arguments:
  766. Timeout - Timeout for the timer.
  767. Return Value:
  768. Status.
  769. Environment:
  770. Kernel mode. IRQL <= PASSIVE_LEVEL.
  771. --*/
  772. {
  773. PVOID Allocation;
  774. PKTIMER Timer;
  775. PKDPC Dpc;
  776. ULONG AllocationSize;
  777. NTSTATUS Status;
  778. BOOLEAN TimerAlreadyQueued;
  779. //
  780. // Initialize locals.
  781. //
  782. Allocation = NULL;
  783. //
  784. // Make a single allocation for the timer and dpc.
  785. //
  786. AllocationSize = sizeof(KTIMER);
  787. AllocationSize += sizeof(KDPC);
  788. Allocation = ExAllocatePoolWithTag(NonPagedPool,
  789. AllocationSize,
  790. CCPF_ALLOC_BOOTWRKR_TAG);
  791. if (!Allocation) {
  792. Status = STATUS_INSUFFICIENT_RESOURCES;
  793. goto cleanup;
  794. }
  795. Timer = Allocation;
  796. Dpc = (PKDPC)(Timer + 1);
  797. //
  798. // Initialize the timer and DPC. We'll be passing the allocation to the
  799. // queued DPC so it can be freed.
  800. //
  801. KeInitializeTimer(Timer);
  802. KeInitializeDpc(Dpc, CcPfEndBootTimerRoutine, Allocation);
  803. //
  804. // Queue the timer.
  805. //
  806. TimerAlreadyQueued = KeSetTimer(Timer, *Timeout, Dpc);
  807. CCPF_ASSERT(!TimerAlreadyQueued);
  808. Status = STATUS_SUCCESS;
  809. cleanup:
  810. if (!NT_SUCCESS(Status)) {
  811. if (Allocation) {
  812. ExFreePool(Allocation);
  813. }
  814. }
  815. return Status;
  816. }
  817. VOID
  818. CcPfEndBootTimerRoutine(
  819. IN PKDPC Dpc,
  820. IN PVOID DeferredContext,
  821. IN PVOID SystemArgument1,
  822. IN PVOID SystemArgument2
  823. )
  824. /*++
  825. Routine Description:
  826. This routine is invoked as the DPC handler for a timer queued to
  827. mark the end of boot and end the boot trace if one is active.
  828. Arguments:
  829. DeferredContext - Allocated memory for the timer & dpc that need
  830. to be freed.
  831. Return Value:
  832. None.
  833. Environment:
  834. Kernel mode. IRQL == DISPATCH_LEVEL.
  835. --*/
  836. {
  837. PCCPF_TRACE_HEADER BootTrace;
  838. PERFINFO_BOOT_PHASE_START LogEntry;
  839. UNREFERENCED_PARAMETER (Dpc);
  840. UNREFERENCED_PARAMETER (SystemArgument1);
  841. UNREFERENCED_PARAMETER (SystemArgument2);
  842. //
  843. // Initialize locals.
  844. //
  845. BootTrace = NULL;
  846. //
  847. // Is the boot trace still active?
  848. //
  849. BootTrace = CcPfReferenceProcessTrace(PsInitialSystemProcess);
  850. if (BootTrace && BootTrace->ScenarioType == PfSystemBootScenarioType) {
  851. //
  852. // Is somebody already ending the boot trace?
  853. //
  854. if (!InterlockedCompareExchange(&BootTrace->EndTraceCalled, 1, 0)) {
  855. //
  856. // We set EndTraceCalled from 0 to 1. Queue the
  857. // workitem to end the trace.
  858. //
  859. ExQueueWorkItem(&BootTrace->EndTraceWorkItem, DelayedWorkQueue);
  860. //
  861. // Log that we are ending the boot trace.
  862. //
  863. if (PERFINFO_IS_GROUP_ON(PERF_LOADER)) {
  864. LogEntry.Phase = PfMaxBootPhaseId;
  865. PerfInfoLogBytes(PERFINFO_LOG_TYPE_BOOT_PHASE_START,
  866. &LogEntry,
  867. sizeof(LogEntry));
  868. }
  869. }
  870. }
  871. //
  872. // Free the memory allocated for the timer and dpc.
  873. //
  874. CCPF_ASSERT(DeferredContext);
  875. ExFreePool(DeferredContext);
  876. if (BootTrace) {
  877. CcPfDecRef(&BootTrace->RefCount);
  878. }
  879. return;
  880. }