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.

1800 lines
47 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. prefparm.c
  5. Abstract:
  6. This module contains the code for prefetcher parameter handling.
  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(INIT, CcPfParametersInitialize)
  18. #pragma alloc_text(INIT, CcPfParametersSetDefaults)
  19. #pragma alloc_text(PAGE, CcPfParametersRead)
  20. #pragma alloc_text(PAGE, CcPfParametersSave)
  21. #pragma alloc_text(PAGE, CcPfParametersVerify)
  22. #pragma alloc_text(PAGE, CcPfParametersWatcher)
  23. #pragma alloc_text(PAGE, CcPfParametersSetChangedEvent)
  24. #pragma alloc_text(PAGE, CcPfGetParameter)
  25. #pragma alloc_text(PAGE, CcPfSetParameter)
  26. #pragma alloc_text(PAGE, CcPfDetermineEnablePrefetcher)
  27. #pragma alloc_text(PAGE, CcPfIsHostingApplication)
  28. #endif // ALLOC_PRAGMA
  29. //
  30. // Globals:
  31. //
  32. extern CCPF_PREFETCHER_GLOBALS CcPfGlobals;
  33. //
  34. // Constants:
  35. //
  36. //
  37. // The following are used as prefixs for the value names for registry
  38. // parameters that are per scenario type.
  39. //
  40. WCHAR *CcPfAppLaunchScenarioTypePrefix = L"AppLaunch";
  41. WCHAR *CcPfBootScenarioTypePrefix = L"Boot";
  42. WCHAR *CcPfInvalidScenarioTypePrefix = L"Invalid";
  43. //
  44. // Routines for prefetcher parameter handling.
  45. //
  46. NTSTATUS
  47. CcPfParametersInitialize (
  48. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  49. )
  50. /*++
  51. Routine Description:
  52. Initializes specified prefetcher parameters structure.
  53. Arguments:
  54. PrefetcherParameters - Pointer to structure to initialize.
  55. Return Value:
  56. Status.
  57. Environment:
  58. Kernel mode. IRQL == PASSIVE_LEVEL.
  59. Notes:
  60. The code & local constants for this function gets discarded after system boots.
  61. --*/
  62. {
  63. OBJECT_ATTRIBUTES ObjectAttributes;
  64. UNICODE_STRING KeyName;
  65. NTSTATUS Status;
  66. //
  67. // Zero out the structure. This initializes:
  68. // ParametersVersion
  69. //
  70. RtlZeroMemory(PrefetcherParameters, sizeof(*PrefetcherParameters));
  71. //
  72. // Initialize the lock protecting the parameters and parameters
  73. // version. Each time parameters are updated, the version is
  74. // bumped.
  75. //
  76. ExInitializeResourceLite(&PrefetcherParameters->ParametersLock);
  77. //
  78. // Initialize the workitem used for registry notifications on the
  79. // parameters key.
  80. //
  81. ExInitializeWorkItem(&PrefetcherParameters->RegistryWatchWorkItem,
  82. CcPfParametersWatcher,
  83. PrefetcherParameters);
  84. //
  85. // Set default parameters.
  86. //
  87. CcPfParametersSetDefaults(PrefetcherParameters);
  88. //
  89. // Create / Open the registry key that contains our parameters.
  90. //
  91. RtlInitUnicodeString(&KeyName, CCPF_PARAMETERS_KEY);
  92. InitializeObjectAttributes(&ObjectAttributes,
  93. &KeyName,
  94. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  95. NULL,
  96. NULL);
  97. Status = ZwCreateKey(&PrefetcherParameters->ParametersKey,
  98. KEY_ALL_ACCESS,
  99. &ObjectAttributes,
  100. 0,
  101. NULL,
  102. REG_OPTION_NON_VOLATILE,
  103. 0);
  104. if (NT_SUCCESS(Status)) {
  105. //
  106. // Update the default parameters with those in the registry.
  107. //
  108. Status = CcPfParametersRead(PrefetcherParameters);
  109. if (!NT_SUCCESS(Status)) {
  110. DBGPR((CCPFID,PFERR,"CCPF: Init-FailedReadParams=%x\n",Status));
  111. }
  112. //
  113. // Request notification when something changes in the
  114. // prefetcher parameters key.
  115. //
  116. Status = ZwNotifyChangeKey(PrefetcherParameters->ParametersKey,
  117. NULL,
  118. (PIO_APC_ROUTINE)&PrefetcherParameters->RegistryWatchWorkItem,
  119. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  120. &PrefetcherParameters->RegistryWatchIosb,
  121. REG_LEGAL_CHANGE_FILTER,
  122. FALSE,
  123. &PrefetcherParameters->RegistryWatchBuffer,
  124. sizeof(PrefetcherParameters->RegistryWatchBuffer),
  125. TRUE);
  126. if (!NT_SUCCESS(Status)) {
  127. //
  128. // Although we could not register a notification, this
  129. // is not a fatal error.
  130. //
  131. DBGPR((CCPFID,PFERR,"CCPF: Init-FailedSetParamNotify=%x\n",Status));
  132. }
  133. } else {
  134. DBGPR((CCPFID,PFERR,"CCPF: Init-FailedCreateParamKey=%x\n",Status));
  135. //
  136. // Make sure parameters key handle is invalid.
  137. //
  138. PrefetcherParameters->ParametersKey = NULL;
  139. }
  140. return Status;
  141. }
  142. VOID
  143. CcPfParametersSetDefaults (
  144. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  145. )
  146. /*++
  147. Routine Description:
  148. Initializes specified parameters structure to default values.
  149. Arguments:
  150. Parameters - Pointer to structure to initialize.
  151. Return Value:
  152. None.
  153. Environment:
  154. Kernel mode. IRQL == PASSIVE_LEVEL.
  155. Notes:
  156. The code & local constants for this function gets discarded after system boots.
  157. --*/
  158. {
  159. PPF_SYSTEM_PREFETCH_PARAMETERS Parameters;
  160. PPF_TRACE_LIMITS TraceLimits;
  161. PF_SCENARIO_TYPE ScenarioType;
  162. //
  163. // Initialize locals.
  164. //
  165. Parameters = &PrefetcherParameters->Parameters;
  166. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  167. //
  168. // PfSvNotSpecified is currently treated as disabled.
  169. //
  170. Parameters->EnableStatus[ScenarioType] = PfSvNotSpecified;
  171. //
  172. // Trace limits are determined based on scenario type.
  173. //
  174. TraceLimits = &Parameters->TraceLimits[ScenarioType];
  175. switch(ScenarioType) {
  176. case PfApplicationLaunchScenarioType:
  177. TraceLimits->MaxNumPages = 4000;
  178. TraceLimits->MaxNumSections = 170;
  179. TraceLimits->TimerPeriod = (-1 * 1000 * 1000 * 10);
  180. PrefetcherParameters->ScenarioTypePrefixes[ScenarioType] =
  181. CcPfAppLaunchScenarioTypePrefix;
  182. break;
  183. case PfSystemBootScenarioType:
  184. TraceLimits->MaxNumPages = 128000;
  185. TraceLimits->MaxNumSections = 4080;
  186. TraceLimits->TimerPeriod = (-1 * 12000 * 1000 * 10);
  187. PrefetcherParameters->ScenarioTypePrefixes[ScenarioType] =
  188. CcPfBootScenarioTypePrefix;
  189. break;
  190. default:
  191. //
  192. // We should be handling all scenario types above.
  193. //
  194. CCPF_ASSERT(FALSE);
  195. TraceLimits->MaxNumPages = PF_MAXIMUM_PAGES;
  196. TraceLimits->MaxNumSections = PF_MAXIMUM_SECTIONS;
  197. TraceLimits->TimerPeriod = (-1 * 1000 * 1000 * 10);
  198. PrefetcherParameters->ScenarioTypePrefixes[ScenarioType] =
  199. CcPfInvalidScenarioTypePrefix;
  200. }
  201. }
  202. //
  203. // These limits ensure that we don't monopolize system resources
  204. // for prefetching.
  205. //
  206. Parameters->MaxNumActiveTraces = 8;
  207. Parameters->MaxNumSavedTraces = 8;
  208. //
  209. // This is the default directory under SystemRoot where we
  210. // find prefetch instructions for scenarios. During upgrades
  211. // we remove the contents of this directory, so "Prefetch" is
  212. // hardcoded in txtsetup.inx.
  213. //
  214. wcsncpy(Parameters->RootDirPath,
  215. L"Prefetch",
  216. PF_MAX_PREFETCH_ROOT_PATH);
  217. Parameters->RootDirPath[PF_MAX_PREFETCH_ROOT_PATH - 1] = 0;
  218. //
  219. // This is the default list of known hosting applications.
  220. //
  221. wcsncpy(Parameters->HostingApplicationList,
  222. L"DLLHOST.EXE,MMC.EXE,RUNDLL32.EXE",
  223. PF_HOSTING_APP_LIST_MAX_CHARS);
  224. Parameters->HostingApplicationList[PF_HOSTING_APP_LIST_MAX_CHARS - 1] = 0;
  225. //
  226. // Make sure the default parameters make sense.
  227. //
  228. CCPF_ASSERT(NT_SUCCESS(CcPfParametersVerify(Parameters)));
  229. }
  230. NTSTATUS
  231. CcPfParametersRead (
  232. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  233. )
  234. /*++
  235. Routine Description:
  236. This routine updates the parameters structure with the
  237. parameters in the registry.
  238. Keep the value names that are used in sync with the function to
  239. save the parameters.
  240. Arguments:
  241. PrefetcherParameters - Pointer to parameters.
  242. Return Value:
  243. Status.
  244. Environment:
  245. Kernel mode. IRQL == PASSIVE_LEVEL.
  246. --*/
  247. {
  248. NTSTATUS Status;
  249. PF_SYSTEM_PREFETCH_PARAMETERS Parameters;
  250. PPF_TRACE_LIMITS TraceLimits;
  251. PF_SCENARIO_TYPE ScenarioType;
  252. WCHAR ValueName[CCPF_MAX_PARAMETER_NAME_LENGTH];
  253. WCHAR *ValueNamePrefix;
  254. HANDLE ParametersKey;
  255. BOOLEAN EnableStatusSpecified;
  256. ULONG EnablePrefetcher;
  257. BOOLEAN AcquiredParametersLock;
  258. ULONG Length;
  259. LONG CurrentVersion;
  260. ULONG RetryCount;
  261. PKTHREAD CurrentThread;
  262. //
  263. // Initialize locals.
  264. //
  265. CurrentThread = KeGetCurrentThread ();
  266. AcquiredParametersLock = FALSE;
  267. RetryCount = 0;
  268. DBGPR((CCPFID,PFTRC,"CCPF: ParametersRead()\n"));
  269. do {
  270. //
  271. // Get the parameters lock shared.
  272. //
  273. KeEnterCriticalRegionThread(CurrentThread);
  274. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  275. AcquiredParametersLock = TRUE;
  276. //
  277. // If we could not initialize the parameters key, we would fail
  278. // all the following ops miserably.
  279. //
  280. if (!PrefetcherParameters->ParametersKey) {
  281. Status = STATUS_REINITIALIZATION_NEEDED;
  282. goto cleanup;
  283. }
  284. ParametersKey = PrefetcherParameters->ParametersKey;
  285. //
  286. // Save current version of parameters. Each time parameters gets
  287. // updated, the version is bumped.
  288. //
  289. CurrentVersion = PrefetcherParameters->ParametersVersion;
  290. //
  291. // Copy over existing parameters to the parameters structure we
  292. // are building. This way, if we cannot get a value from the
  293. // registry we'll keep the value we already have.
  294. //
  295. Parameters = PrefetcherParameters->Parameters;
  296. //
  297. // Read the prefetcher enable value. Depending on whether it is
  298. // specified and if so its value we will set enable status for
  299. // prefetch scenario types.
  300. //
  301. Length = sizeof(EnablePrefetcher);
  302. Status = CcPfGetParameter(ParametersKey,
  303. L"EnablePrefetcher",
  304. REG_DWORD,
  305. &EnablePrefetcher,
  306. &Length);
  307. if (!NT_SUCCESS(Status)) {
  308. //
  309. // Enable status is not specified or we cannot access it.
  310. //
  311. EnableStatusSpecified = FALSE;
  312. } else {
  313. EnableStatusSpecified = TRUE;
  314. }
  315. //
  316. // Get per scenario parameters.
  317. //
  318. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  319. ValueNamePrefix = PrefetcherParameters->ScenarioTypePrefixes[ScenarioType];
  320. //
  321. // Determine enable status. If EnableStatusSpecified, whether
  322. // prefeching for this scenario type is on or off is
  323. // determined by the ScenarioType'th bit in EnablePrefetcher.
  324. //
  325. if (EnableStatusSpecified) {
  326. if (EnablePrefetcher & (1 << ScenarioType)) {
  327. Parameters.EnableStatus[ScenarioType] = PfSvEnabled;
  328. } else {
  329. Parameters.EnableStatus[ScenarioType] = PfSvDisabled;
  330. }
  331. } else {
  332. Parameters.EnableStatus[ScenarioType] = PfSvNotSpecified;
  333. }
  334. //
  335. // Update trace limits for this scenario type. Ignore return
  336. // value from GetParameter since the value may not be
  337. // specified in the registry. If so the current value is kept
  338. // intact.
  339. //
  340. TraceLimits = &Parameters.TraceLimits[ScenarioType];
  341. wcscpy(ValueName, ValueNamePrefix);
  342. wcscat(ValueName, L"MaxNumPages");
  343. Length = sizeof(TraceLimits->MaxNumPages);
  344. CcPfGetParameter(ParametersKey,
  345. ValueName,
  346. REG_DWORD,
  347. &TraceLimits->MaxNumPages,
  348. &Length);
  349. wcscpy(ValueName, ValueNamePrefix);
  350. wcscat(ValueName, L"MaxNumSections");
  351. Length = sizeof(TraceLimits->MaxNumSections);
  352. CcPfGetParameter(ParametersKey,
  353. ValueName,
  354. REG_DWORD,
  355. &TraceLimits->MaxNumSections,
  356. &Length);
  357. wcscpy(ValueName, ValueNamePrefix);
  358. wcscat(ValueName, L"TimerPeriod");
  359. Length = sizeof(TraceLimits->TimerPeriod);
  360. CcPfGetParameter(ParametersKey,
  361. ValueName,
  362. REG_BINARY,
  363. &TraceLimits->TimerPeriod,
  364. &Length);
  365. }
  366. //
  367. // Update maximum number of active traces.
  368. //
  369. Length = sizeof(Parameters.MaxNumActiveTraces);
  370. CcPfGetParameter(ParametersKey,
  371. L"MaxNumActiveTraces",
  372. REG_DWORD,
  373. &Parameters.MaxNumActiveTraces,
  374. &Length);
  375. //
  376. // Update maximum number of saved traces.
  377. //
  378. Length = sizeof(Parameters.MaxNumSavedTraces);
  379. CcPfGetParameter(ParametersKey,
  380. L"MaxNumSavedTraces",
  381. REG_DWORD,
  382. &Parameters.MaxNumSavedTraces,
  383. &Length);
  384. //
  385. // Update the root directory path.
  386. //
  387. Length = sizeof(Parameters.RootDirPath);
  388. CcPfGetParameter(ParametersKey,
  389. L"RootDirPath",
  390. REG_SZ,
  391. Parameters.RootDirPath,
  392. &Length);
  393. Parameters.RootDirPath[PF_MAX_PREFETCH_ROOT_PATH - 1] = 0;
  394. //
  395. // Update list of known hosting applications.
  396. //
  397. Length = sizeof(Parameters.HostingApplicationList);
  398. CcPfGetParameter(ParametersKey,
  399. L"HostingAppList",
  400. REG_SZ,
  401. Parameters.HostingApplicationList,
  402. &Length);
  403. Parameters.HostingApplicationList[PF_HOSTING_APP_LIST_MAX_CHARS - 1] = 0;
  404. _wcsupr(Parameters.HostingApplicationList);
  405. //
  406. // Verify the parameters updated from the registry.
  407. //
  408. Status = CcPfParametersVerify(&Parameters);
  409. if (!NT_SUCCESS(Status)) {
  410. goto cleanup;
  411. }
  412. //
  413. // Release the shared lock and acquire it exclusive.
  414. //
  415. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  416. KeLeaveCriticalRegionThread(CurrentThread);
  417. KeEnterCriticalRegionThread(CurrentThread);
  418. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  419. //
  420. // Check if somebody already updated the parameters before us.
  421. //
  422. if (CurrentVersion != PrefetcherParameters->ParametersVersion) {
  423. //
  424. // Bummer. Somebody updated parameters when we released
  425. // our shared lock to acquire it exclusive. We have to try
  426. // again. The default values we used for parameters that
  427. // were not in the registry may have been changed.
  428. //
  429. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  430. KeLeaveCriticalRegionThread(CurrentThread);
  431. AcquiredParametersLock = FALSE;
  432. RetryCount++;
  433. continue;
  434. }
  435. //
  436. // We are updating the parameters, bump the version.
  437. //
  438. PrefetcherParameters->ParametersVersion++;
  439. PrefetcherParameters->Parameters = Parameters;
  440. //
  441. // Release the exclusive lock and break out.
  442. //
  443. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  444. KeLeaveCriticalRegionThread(CurrentThread);
  445. AcquiredParametersLock = FALSE;
  446. break;
  447. } while (RetryCount < 10);
  448. //
  449. // See if we looped too many times and could not achive updating
  450. // the parameters.
  451. //
  452. if (RetryCount >= 10) {
  453. Status = STATUS_RETRY;
  454. goto cleanup;
  455. }
  456. //
  457. // Otherwise we were successful.
  458. //
  459. Status = STATUS_SUCCESS;
  460. cleanup:
  461. if (AcquiredParametersLock) {
  462. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  463. KeLeaveCriticalRegionThread(CurrentThread);
  464. }
  465. DBGPR((CCPFID,PFTRC,"CCPF: ParametersRead()=%x\n", Status));
  466. return Status;
  467. }
  468. NTSTATUS
  469. CcPfParametersSave (
  470. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  471. )
  472. /*++
  473. Routine Description:
  474. This routine updates the registry with the specified prefetch
  475. parameters.
  476. Arguments:
  477. PrefetcherParameters - Pointer to parameters structure.
  478. Return Value:
  479. Status.
  480. Environment:
  481. Kernel mode. IRQL == PASSIVE_LEVEL.
  482. --*/
  483. {
  484. NTSTATUS Status;
  485. PPF_TRACE_LIMITS TraceLimits;
  486. PF_SCENARIO_TYPE ScenarioType;
  487. WCHAR ValueName[CCPF_MAX_PARAMETER_NAME_LENGTH];
  488. WCHAR *ValueNamePrefix;
  489. HANDLE ParametersKey;
  490. BOOLEAN EnableStatusSpecified;
  491. ULONG EnablePrefetcher;
  492. BOOLEAN AcquiredParametersLock;
  493. ULONG Length;
  494. PPF_SYSTEM_PREFETCH_PARAMETERS Parameters;
  495. PKTHREAD CurrentThread;
  496. //
  497. // Initialize locals.
  498. //
  499. CurrentThread = KeGetCurrentThread ();
  500. Parameters = &PrefetcherParameters->Parameters;
  501. AcquiredParametersLock = FALSE;
  502. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSave()\n"));
  503. //
  504. // Get the parameters lock shared.
  505. //
  506. KeEnterCriticalRegionThread(CurrentThread);
  507. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  508. AcquiredParametersLock = TRUE;
  509. //
  510. // If we could not initialize the parameters key, we would fail
  511. // all the following ops miserably.
  512. //
  513. if (!PrefetcherParameters->ParametersKey) {
  514. Status = STATUS_REINITIALIZATION_NEEDED;
  515. goto cleanup;
  516. }
  517. ParametersKey = PrefetcherParameters->ParametersKey;
  518. //
  519. // Build up the prefetcher enable value.
  520. //
  521. EnableStatusSpecified = FALSE;
  522. EnablePrefetcher = 0;
  523. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  524. //
  525. // By default prefetching for all scenario types will be
  526. // disabled, except it is explicitly enabled.
  527. //
  528. if (Parameters->EnableStatus[ScenarioType] == PfSvEnabled) {
  529. EnablePrefetcher |= (1 << ScenarioType);
  530. }
  531. //
  532. // Even if enable status for one scenario type is specified,
  533. // we have to save the enable prefetcher key.
  534. //
  535. if (Parameters->EnableStatus[ScenarioType] != PfSvNotSpecified) {
  536. EnableStatusSpecified = TRUE;
  537. }
  538. }
  539. if (EnableStatusSpecified) {
  540. //
  541. // Save the prefetcher enable key.
  542. //
  543. Length = sizeof(EnablePrefetcher);
  544. Status = CcPfSetParameter(ParametersKey,
  545. L"EnablePrefetcher",
  546. REG_DWORD,
  547. &EnablePrefetcher,
  548. Length);
  549. if (!NT_SUCCESS(Status)) {
  550. goto cleanup;
  551. }
  552. }
  553. //
  554. // Save per scenario parameters.
  555. //
  556. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  557. ValueNamePrefix = PrefetcherParameters->ScenarioTypePrefixes[ScenarioType];
  558. //
  559. // Update trace limits for this scenario type.
  560. //
  561. TraceLimits = &Parameters->TraceLimits[ScenarioType];
  562. wcscpy(ValueName, ValueNamePrefix);
  563. wcscat(ValueName, L"MaxNumPages");
  564. Length = sizeof(TraceLimits->MaxNumPages);
  565. Status = CcPfSetParameter(ParametersKey,
  566. ValueName,
  567. REG_DWORD,
  568. &TraceLimits->MaxNumPages,
  569. Length);
  570. if (!NT_SUCCESS(Status)) {
  571. goto cleanup;
  572. }
  573. wcscpy(ValueName, ValueNamePrefix);
  574. wcscat(ValueName, L"MaxNumSections");
  575. Length = sizeof(TraceLimits->MaxNumSections);
  576. Status = CcPfSetParameter(ParametersKey,
  577. ValueName,
  578. REG_DWORD,
  579. &TraceLimits->MaxNumSections,
  580. Length);
  581. if (!NT_SUCCESS(Status)) {
  582. goto cleanup;
  583. }
  584. wcscpy(ValueName, ValueNamePrefix);
  585. wcscat(ValueName, L"TimerPeriod");
  586. Length = sizeof(TraceLimits->TimerPeriod);
  587. Status = CcPfSetParameter(ParametersKey,
  588. ValueName,
  589. REG_BINARY,
  590. &TraceLimits->TimerPeriod,
  591. Length);
  592. if (!NT_SUCCESS(Status)) {
  593. goto cleanup;
  594. }
  595. }
  596. //
  597. // Update maximum number of active traces.
  598. //
  599. Length = sizeof(Parameters->MaxNumActiveTraces);
  600. Status = CcPfSetParameter(ParametersKey,
  601. L"MaxNumActiveTraces",
  602. REG_DWORD,
  603. &Parameters->MaxNumActiveTraces,
  604. Length);
  605. if (!NT_SUCCESS(Status)) {
  606. goto cleanup;
  607. }
  608. //
  609. // Update maximum number of saved traces.
  610. //
  611. Length = sizeof(Parameters->MaxNumSavedTraces);
  612. Status = CcPfSetParameter(ParametersKey,
  613. L"MaxNumSavedTraces",
  614. REG_DWORD,
  615. &Parameters->MaxNumSavedTraces,
  616. Length);
  617. if (!NT_SUCCESS(Status)) {
  618. goto cleanup;
  619. }
  620. //
  621. // Update the root directory path.
  622. //
  623. Length = (wcslen(Parameters->RootDirPath) + 1) * sizeof(WCHAR);
  624. Status = CcPfSetParameter(ParametersKey,
  625. L"RootDirPath",
  626. REG_SZ,
  627. Parameters->RootDirPath,
  628. Length);
  629. if (!NT_SUCCESS(Status)) {
  630. goto cleanup;
  631. }
  632. //
  633. // Update the hosting application list path.
  634. //
  635. Length = (wcslen(Parameters->HostingApplicationList) + 1) * sizeof(WCHAR);
  636. Status = CcPfSetParameter(ParametersKey,
  637. L"HostingAppList",
  638. REG_SZ,
  639. Parameters->HostingApplicationList,
  640. Length);
  641. if (!NT_SUCCESS(Status)) {
  642. goto cleanup;
  643. }
  644. Status = STATUS_SUCCESS;
  645. cleanup:
  646. if (AcquiredParametersLock) {
  647. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  648. KeLeaveCriticalRegionThread(CurrentThread);
  649. }
  650. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSave()=%x\n", Status));
  651. return Status;
  652. }
  653. NTSTATUS
  654. CcPfParametersVerify (
  655. PPF_SYSTEM_PREFETCH_PARAMETERS Parameters
  656. )
  657. /*++
  658. Routine Description:
  659. This routine verifies that the specified parameters structure is
  660. valid and within sanity limits.
  661. Arguments:
  662. Parameters - Pointer to parameters structure.
  663. Return Value:
  664. Status.
  665. Environment:
  666. Kernel mode. IRQL == PASSIVE_LEVEL.
  667. --*/
  668. {
  669. NTSTATUS Status;
  670. ULONG FailedCheckId;
  671. ULONG CharIdx;
  672. BOOLEAN FoundNUL;
  673. PF_SCENARIO_TYPE ScenarioType;
  674. PPF_TRACE_LIMITS TraceLimits;
  675. //
  676. // Initialize locals.
  677. //
  678. Status = STATUS_INVALID_PARAMETER;
  679. FailedCheckId = 0;
  680. DBGPR((CCPFID,PFTRC,"CCPF: ParametersVerify\n"));
  681. //
  682. // Make sure RootDirPath is NUL terminated.
  683. //
  684. FoundNUL = FALSE;
  685. for (CharIdx = 0; CharIdx < PF_MAX_PREFETCH_ROOT_PATH; CharIdx++) {
  686. if (Parameters->RootDirPath[CharIdx] == 0) {
  687. FoundNUL = TRUE;
  688. break;
  689. }
  690. }
  691. if (FoundNUL == FALSE) {
  692. FailedCheckId = 10;
  693. goto cleanup;
  694. }
  695. //
  696. // Make sure HostingApplicationList is NUL terminated.
  697. //
  698. FoundNUL = FALSE;
  699. for (CharIdx = 0; CharIdx < PF_HOSTING_APP_LIST_MAX_CHARS; CharIdx++) {
  700. if (Parameters->HostingApplicationList[CharIdx] == 0) {
  701. FoundNUL = TRUE;
  702. break;
  703. }
  704. //
  705. // Make sure the list is upper case.
  706. //
  707. if (towupper(Parameters->HostingApplicationList[CharIdx]) !=
  708. Parameters->HostingApplicationList[CharIdx]) {
  709. FailedCheckId = 13;
  710. goto cleanup;
  711. }
  712. }
  713. if (FoundNUL == FALSE) {
  714. FailedCheckId = 15;
  715. goto cleanup;
  716. }
  717. //
  718. // Make sure all per scenario type parameters types are within
  719. // sanity limits.
  720. //
  721. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  722. if (Parameters->EnableStatus[ScenarioType] < 0 ||
  723. Parameters->EnableStatus[ScenarioType] >= PfSvMaxEnableStatus) {
  724. FailedCheckId = 20;
  725. goto cleanup;
  726. }
  727. //
  728. // Check trace limits.
  729. //
  730. TraceLimits = &Parameters->TraceLimits[ScenarioType];
  731. if (TraceLimits->MaxNumPages > PF_MAXIMUM_PAGES) {
  732. FailedCheckId = 30;
  733. goto cleanup;
  734. }
  735. if (TraceLimits->MaxNumSections > PF_MAXIMUM_SECTIONS) {
  736. FailedCheckId = 40;
  737. goto cleanup;
  738. }
  739. if ((TraceLimits->TimerPeriod < PF_MAXIMUM_TIMER_PERIOD) ||
  740. (TraceLimits->TimerPeriod >= 0)) {
  741. FailedCheckId = 50;
  742. goto cleanup;
  743. }
  744. }
  745. //
  746. // Check limits on active/saved traces.
  747. //
  748. if (Parameters->MaxNumActiveTraces > PF_MAXIMUM_ACTIVE_TRACES) {
  749. FailedCheckId = 60;
  750. goto cleanup;
  751. }
  752. if (Parameters->MaxNumSavedTraces > PF_MAXIMUM_SAVED_TRACES) {
  753. FailedCheckId = 70;
  754. goto cleanup;
  755. }
  756. //
  757. // We passed all the checks.
  758. //
  759. Status = STATUS_SUCCESS;
  760. cleanup:
  761. DBGPR((CCPFID,PFTRC,"CCPF: ParametersVerify()=%x,%d\n", Status, FailedCheckId));
  762. return Status;
  763. }
  764. VOID
  765. CcPfParametersWatcher(
  766. IN PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  767. )
  768. /*++
  769. Routine Description:
  770. This routine gets called when our parameters in the registry change.
  771. Arguments:
  772. PrefetcherParameters - Pointer to parameters structure.
  773. Return Value:
  774. None.
  775. Environment:
  776. Kernel mode. IRQL == PASSIVE_LEVEL.
  777. --*/
  778. {
  779. NTSTATUS Status;
  780. UNICODE_STRING KeyName;
  781. OBJECT_ATTRIBUTES ObjectAttributes;
  782. HANDLE ParametersKey;
  783. PKTHREAD CurrentThread;
  784. HANDLE TempHandle;
  785. BOOLEAN HoldingParametersLock;
  786. //
  787. // Initialize locals.
  788. //
  789. HoldingParametersLock = FALSE;
  790. DBGPR((CCPFID,PFTRC,"CCPF: ParametersWatcher()\n"));
  791. //
  792. // Our change notify triggered. Request further notification. But
  793. // first wait until we can get the parameters lock exclusive, so
  794. // while we are saving parameters to the registry we don't kick
  795. // off a notification for each key.
  796. //
  797. CurrentThread = KeGetCurrentThread ();
  798. KeEnterCriticalRegionThread(CurrentThread);
  799. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  800. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  801. KeLeaveCriticalRegionThread(CurrentThread);
  802. //
  803. // Hold the parameters lock shared since we are using ParametersKey.
  804. //
  805. KeEnterCriticalRegionThread(CurrentThread);
  806. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  807. HoldingParametersLock = TRUE;
  808. //
  809. // Make sure we still have a parameters key.
  810. //
  811. if (!PrefetcherParameters->ParametersKey) {
  812. //
  813. // In order to have setup a registry watch, we should have
  814. // initialized the parameters key successfully.
  815. //
  816. CCPF_ASSERT(PrefetcherParameters->ParametersKey);
  817. Status = STATUS_UNSUCCESSFUL;
  818. goto cleanup;
  819. }
  820. Status = ZwNotifyChangeKey(PrefetcherParameters->ParametersKey,
  821. NULL,
  822. (PIO_APC_ROUTINE)&PrefetcherParameters->RegistryWatchWorkItem,
  823. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  824. &PrefetcherParameters->RegistryWatchIosb,
  825. REG_LEGAL_CHANGE_FILTER,
  826. FALSE,
  827. &PrefetcherParameters->RegistryWatchBuffer,
  828. sizeof(PrefetcherParameters->RegistryWatchBuffer),
  829. TRUE);
  830. if (!NT_SUCCESS(Status)) {
  831. //
  832. // Somebody may have deleted the key. We have to recreate it then.
  833. //
  834. if (Status == STATUS_KEY_DELETED) {
  835. RtlInitUnicodeString(&KeyName, CCPF_PARAMETERS_KEY);
  836. InitializeObjectAttributes(&ObjectAttributes,
  837. &KeyName,
  838. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  839. NULL,
  840. NULL);
  841. Status = ZwCreateKey(&ParametersKey,
  842. KEY_ALL_ACCESS,
  843. &ObjectAttributes,
  844. 0,
  845. NULL,
  846. REG_OPTION_NON_VOLATILE,
  847. 0);
  848. if (!NT_SUCCESS(Status)) {
  849. DBGPR((CCPFID,PFERR,"CCPF: ParametersWatcher-FailedRecreate=%x\n",Status));
  850. goto cleanup;
  851. }
  852. //
  853. // Update global key handle. To do this release the shared lock
  854. // and get it exclusive.
  855. //
  856. CCPF_ASSERT(HoldingParametersLock);
  857. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  858. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  859. TempHandle = PrefetcherParameters->ParametersKey;
  860. PrefetcherParameters->ParametersKey = ParametersKey;
  861. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  862. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  863. //
  864. // Close the old handle.
  865. //
  866. if (TempHandle) {
  867. ZwClose(TempHandle);
  868. }
  869. //
  870. // Did someone steal the parameters key from beneath us?
  871. //
  872. if (!PrefetcherParameters->ParametersKey) {
  873. Status = STATUS_UNSUCCESSFUL;
  874. goto cleanup;
  875. }
  876. //
  877. // Retry setting a notification again.
  878. //
  879. Status = ZwNotifyChangeKey(PrefetcherParameters->ParametersKey,
  880. NULL,
  881. (PIO_APC_ROUTINE)&PrefetcherParameters->RegistryWatchWorkItem,
  882. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  883. &PrefetcherParameters->RegistryWatchIosb,
  884. REG_LEGAL_CHANGE_FILTER,
  885. FALSE,
  886. &PrefetcherParameters->RegistryWatchBuffer,
  887. sizeof(PrefetcherParameters->RegistryWatchBuffer),
  888. TRUE);
  889. if (!NT_SUCCESS(Status)) {
  890. DBGPR((CCPFID,PFERR,"CCPF: ParametersWatcher-FailedReSetNotify=%x\n",Status));
  891. goto cleanup;
  892. }
  893. } else {
  894. DBGPR((CCPFID,PFERR,"CCPF: ParametersWatcher-FailedSetNotify=%x\n",Status));
  895. goto cleanup;
  896. }
  897. }
  898. //
  899. // Release the parameters lock as we'll need it when re-reading the
  900. // parameters.
  901. //
  902. if (HoldingParametersLock) {
  903. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  904. KeLeaveCriticalRegionThread(CurrentThread);
  905. HoldingParametersLock = FALSE;
  906. }
  907. //
  908. // Update the global parameters.
  909. //
  910. Status = CcPfParametersRead(PrefetcherParameters);
  911. if (NT_SUCCESS(Status)) {
  912. //
  913. // Determine if prefetching is enabled.
  914. //
  915. CcPfDetermineEnablePrefetcher();
  916. //
  917. // Set the event so the service queries for the latest parameters.
  918. //
  919. CcPfParametersSetChangedEvent(PrefetcherParameters);
  920. }
  921. cleanup:
  922. if (HoldingParametersLock) {
  923. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  924. KeLeaveCriticalRegionThread(CurrentThread);
  925. HoldingParametersLock = FALSE;
  926. }
  927. return;
  928. }
  929. NTSTATUS
  930. CcPfParametersSetChangedEvent(
  931. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters
  932. )
  933. /*++
  934. Routine Description:
  935. This routine tries to open and set the event that tells the
  936. service system prefetch parameters have changed.
  937. Arguments:
  938. None.
  939. Return Value:
  940. Status.
  941. Environment:
  942. Kernel mode. IRQL == PASSIVE_LEVEL.
  943. --*/
  944. {
  945. NTSTATUS Status;
  946. UNICODE_STRING EventName;
  947. OBJECT_ATTRIBUTES EventObjAttr;
  948. HANDLE EventHandle;
  949. PKTHREAD CurrentThread;
  950. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSetChangedEvent()\n"));
  951. //
  952. // If we have already opened the event, just signal it.
  953. //
  954. if (PrefetcherParameters->ParametersChangedEvent) {
  955. ZwSetEvent(PrefetcherParameters->ParametersChangedEvent, NULL);
  956. Status = STATUS_SUCCESS;
  957. } else {
  958. //
  959. // Try to open the event. We don't open this at initialization
  960. // because our service may not have started to create this
  961. // event yet. If csrss.exe has not initialized, we may not
  962. // even have the BaseNamedObjects object directory created, in
  963. // which Win32 events reside.
  964. //
  965. RtlInitUnicodeString(&EventName, PF_PARAMETERS_CHANGED_EVENT_NAME);
  966. InitializeObjectAttributes(&EventObjAttr,
  967. &EventName,
  968. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  969. NULL,
  970. NULL);
  971. Status = ZwOpenEvent(&EventHandle,
  972. EVENT_ALL_ACCESS,
  973. &EventObjAttr);
  974. if (NT_SUCCESS(Status)) {
  975. //
  976. // Acquire the lock and set the global handle.
  977. //
  978. CurrentThread = KeGetCurrentThread ();
  979. KeEnterCriticalRegionThread(CurrentThread);
  980. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  981. if (!PrefetcherParameters->ParametersChangedEvent) {
  982. //
  983. // Set the global handle.
  984. //
  985. PrefetcherParameters->ParametersChangedEvent = EventHandle;
  986. CCPF_ASSERT(EventHandle);
  987. EventHandle = NULL;
  988. }
  989. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  990. KeLeaveCriticalRegionThread(CurrentThread);
  991. if (EventHandle != NULL) {
  992. //
  993. // Somebody already initialized the global handle
  994. // before us. Close our handle and use the one they
  995. // initialized.
  996. //
  997. ZwClose(EventHandle);
  998. }
  999. //
  1000. // We have an event now. Signal it.
  1001. //
  1002. ZwSetEvent(PrefetcherParameters->ParametersChangedEvent, NULL);
  1003. }
  1004. }
  1005. DBGPR((CCPFID,PFTRC,"CCPF: ParametersSetChangedEvent()=%x\n", Status));
  1006. return Status;
  1007. }
  1008. NTSTATUS
  1009. CcPfGetParameter (
  1010. HANDLE ParametersKey,
  1011. WCHAR *ValueNameBuffer,
  1012. ULONG ValueType,
  1013. PVOID Value,
  1014. ULONG *ValueSize
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. This routine queries a value under the specified registry into the
  1019. specified buffer. Contents of Value and ValueSize are not changed
  1020. if returning failure.
  1021. Arguments:
  1022. ParametersKey - Handle to key to query value under.
  1023. ValueNameBuffer - Name of the value.
  1024. ValueType - What the type of that value should be. (e.g. REG_DWORD).
  1025. Value - Queried value data gets put here.
  1026. ValueSize - Size of Value buffer in bytes. On successful return
  1027. this is set to number of bytes copied into Value.
  1028. Return Value:
  1029. Status.
  1030. Environment:
  1031. Kernel mode. IRQL == PASSIVE_LEVEL.
  1032. --*/
  1033. {
  1034. UNICODE_STRING ValueName;
  1035. CHAR Buffer[CCPF_MAX_PARAMETER_VALUE_BUFFER];
  1036. PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer;
  1037. ULONG Length;
  1038. NTSTATUS Status;
  1039. //
  1040. // Initialize locals.
  1041. //
  1042. ValueBuffer = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
  1043. Length = CCPF_MAX_PARAMETER_VALUE_BUFFER;
  1044. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  1045. DBGPR((CCPFID,PFTRC,"CCPF: GetParameter(%ws,%x)\n", ValueNameBuffer, ValueType));
  1046. //
  1047. // Verify parameters.
  1048. //
  1049. if (!ParametersKey) {
  1050. return STATUS_INVALID_PARAMETER;
  1051. }
  1052. //
  1053. // Query value.
  1054. //
  1055. Status = ZwQueryValueKey(ParametersKey,
  1056. &ValueName,
  1057. KeyValuePartialInformation,
  1058. ValueBuffer,
  1059. Length,
  1060. &Length);
  1061. if (!NT_SUCCESS(Status)) {
  1062. goto cleanup;
  1063. }
  1064. //
  1065. // Make sure ZwQueryValue returns valid information.
  1066. //
  1067. if (Length < sizeof(KEY_VALUE_PARTIAL_INFORMATION)) {
  1068. CCPF_ASSERT(Length >= sizeof(KEY_VALUE_PARTIAL_INFORMATION));
  1069. Status = STATUS_UNSUCCESSFUL;
  1070. goto cleanup;
  1071. }
  1072. //
  1073. // Check value type.
  1074. //
  1075. if (ValueBuffer->Type != ValueType) {
  1076. Status = STATUS_OBJECT_TYPE_MISMATCH;
  1077. goto cleanup;
  1078. }
  1079. //
  1080. // Check if data will fit into the buffer caller passed in.
  1081. //
  1082. if (ValueBuffer->DataLength > *ValueSize) {
  1083. Status = STATUS_BUFFER_TOO_SMALL;
  1084. goto cleanup;
  1085. }
  1086. //
  1087. // Copy data into user's buffer.
  1088. //
  1089. RtlCopyMemory(Value, ValueBuffer->Data, ValueBuffer->DataLength);
  1090. //
  1091. // Set copied number of bytes.
  1092. //
  1093. *ValueSize = ValueBuffer->DataLength;
  1094. Status = STATUS_SUCCESS;
  1095. cleanup:
  1096. DBGPR((CCPFID,PFTRC,"CCPF: GetParameter(%ws)=%x\n", ValueNameBuffer, Status));
  1097. return Status;
  1098. }
  1099. NTSTATUS
  1100. CcPfSetParameter (
  1101. HANDLE ParametersKey,
  1102. WCHAR *ValueNameBuffer,
  1103. ULONG ValueType,
  1104. PVOID Value,
  1105. ULONG ValueSize
  1106. )
  1107. /*++
  1108. Routine Description:
  1109. This routine sets a parameter under the specified registry.
  1110. Arguments:
  1111. ParametersKey - Handle to key to query value under.
  1112. ValueNameBuffer - Name of the value.
  1113. ValueType - What the type of that value should be. (e.g. REG_DWORD).
  1114. Value - Data to save.
  1115. ValueSize - Size of Value buffer in bytes.
  1116. Return Value:
  1117. Status.
  1118. Environment:
  1119. Kernel mode. IRQL == PASSIVE_LEVEL.
  1120. --*/
  1121. {
  1122. UNICODE_STRING ValueName;
  1123. NTSTATUS Status;
  1124. //
  1125. // Initialize locals.
  1126. //
  1127. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  1128. DBGPR((CCPFID,PFTRC,"CCPF: SetParameter(%ws,%x)\n", ValueNameBuffer, ValueType));
  1129. //
  1130. // Verify parameters.
  1131. //
  1132. if (!ParametersKey) {
  1133. return STATUS_INVALID_PARAMETER;
  1134. }
  1135. //
  1136. // Save the value.
  1137. //
  1138. Status = ZwSetValueKey(ParametersKey,
  1139. &ValueName,
  1140. 0,
  1141. ValueType,
  1142. Value,
  1143. ValueSize);
  1144. //
  1145. // Return the status.
  1146. //
  1147. DBGPR((CCPFID,PFTRC,"CCPF: SetParameter(%ws)=%x\n", ValueNameBuffer, Status));
  1148. return Status;
  1149. }
  1150. LOGICAL
  1151. CcPfDetermineEnablePrefetcher(
  1152. VOID
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. This routine sets the global CcPfEnablePrefetcher based on the
  1157. EnableStatus'es for all scenario types in global parameters as
  1158. well as other factors, such as whether we have booted safe mode.
  1159. Note: Acquires Parameters lock exclusive.
  1160. Arguments:
  1161. None.
  1162. Return Value:
  1163. New value of CcPfEnablePrefetcher.
  1164. Environment:
  1165. Kernel mode. IRQL == PASSIVE_LEVEL.
  1166. --*/
  1167. {
  1168. PF_SCENARIO_TYPE ScenarioType;
  1169. LOGICAL EnablePrefetcher;
  1170. PKTHREAD CurrentThread;
  1171. BOOLEAN IgnoreBootScenarioType;
  1172. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters;
  1173. extern PF_BOOT_PHASE_ID CcPfBootPhase;
  1174. //
  1175. // Initialize locals.
  1176. //
  1177. EnablePrefetcher = FALSE;
  1178. PrefetcherParameters = &CcPfGlobals.Parameters;
  1179. CurrentThread = KeGetCurrentThread ();
  1180. //
  1181. // Ignore whether prefetching is enabled for boot, if we've
  1182. // already past the point in boot where this matters.
  1183. //
  1184. IgnoreBootScenarioType = (CcPfBootPhase >= PfSessionManagerInitPhase) ? TRUE : FALSE;
  1185. KeEnterCriticalRegionThread(CurrentThread);
  1186. ExAcquireResourceExclusiveLite(&PrefetcherParameters->ParametersLock, TRUE);
  1187. //
  1188. // If we have booted to safe mode, the prefetcher will be disabled.
  1189. //
  1190. if (InitSafeBootMode) {
  1191. EnablePrefetcher = FALSE;
  1192. } else {
  1193. //
  1194. // By default prefetching is disabled. If prefetching is
  1195. // enabled for any scenario type, then the prefetcher is
  1196. // enabled.
  1197. //
  1198. for (ScenarioType = 0; ScenarioType < PfMaxScenarioType; ScenarioType++) {
  1199. //
  1200. // Skip enable status for the boot scenario if requested.
  1201. //
  1202. if (IgnoreBootScenarioType) {
  1203. if (ScenarioType == PfSystemBootScenarioType) {
  1204. continue;
  1205. }
  1206. }
  1207. if (PrefetcherParameters->Parameters.EnableStatus[ScenarioType] == PfSvEnabled) {
  1208. EnablePrefetcher = TRUE;
  1209. break;
  1210. }
  1211. }
  1212. }
  1213. //
  1214. // Update global enable status.
  1215. //
  1216. CcPfEnablePrefetcher = EnablePrefetcher;
  1217. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  1218. KeLeaveCriticalRegionThread(CurrentThread);
  1219. return CcPfEnablePrefetcher;
  1220. }
  1221. BOOLEAN
  1222. CcPfIsHostingApplication(
  1223. IN PWCHAR ExecutableName
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. This routine determines whether the specified executable is in the
  1228. list of known hosting applications, e.g. rundll32, dllhost etc.
  1229. Arguments:
  1230. ExecutableName - NUL terminated UPCASED executable name, e.g. "MMC.EXE"
  1231. Return Value:
  1232. TRUE - Executable is for a known hosting application.
  1233. FALSE - It is not.
  1234. Environment:
  1235. Kernel mode. IRQL == PASSIVE_LEVEL.
  1236. --*/
  1237. {
  1238. PCCPF_PREFETCHER_PARAMETERS PrefetcherParameters;
  1239. PKTHREAD CurrentThread;
  1240. PWCHAR CurrentPosition;
  1241. PWCHAR ListStart;
  1242. PWCHAR ListEnd;
  1243. ULONG ExecutableNameLength;
  1244. BOOLEAN FoundInList;
  1245. //
  1246. // Initialize locals.
  1247. //
  1248. PrefetcherParameters = &CcPfGlobals.Parameters;
  1249. CurrentThread = KeGetCurrentThread();
  1250. ExecutableNameLength = wcslen(ExecutableName);
  1251. FoundInList = FALSE;
  1252. //
  1253. // Get the parameters lock for read.
  1254. //
  1255. KeEnterCriticalRegionThread(CurrentThread);
  1256. ExAcquireResourceSharedLite(&PrefetcherParameters->ParametersLock, TRUE);
  1257. //
  1258. // Search for executable in hosting application list.
  1259. //
  1260. ListStart = PrefetcherParameters->Parameters.HostingApplicationList;
  1261. ListEnd = ListStart + wcslen(PrefetcherParameters->Parameters.HostingApplicationList);
  1262. for (CurrentPosition = wcsstr(ListStart, ExecutableName);
  1263. CurrentPosition != NULL;
  1264. CurrentPosition = wcsstr(CurrentPosition + 1, ExecutableName)) {
  1265. //
  1266. // We should not go beyond the limits.
  1267. //
  1268. if (CurrentPosition < ListStart || CurrentPosition >= ListEnd) {
  1269. CCPF_ASSERT(CurrentPosition >= ListStart);
  1270. CCPF_ASSERT(CurrentPosition < ListEnd);
  1271. break;
  1272. }
  1273. //
  1274. // It should be the first item in the list or be preceded by a comma.
  1275. //
  1276. if (CurrentPosition != ListStart && *(CurrentPosition - 1) != L',') {
  1277. continue;
  1278. }
  1279. //
  1280. // It should be the last item in the list or be followed by a comma.
  1281. //
  1282. if (CurrentPosition + ExecutableNameLength != ListEnd &&
  1283. CurrentPosition[ExecutableNameLength] != L',') {
  1284. continue;
  1285. }
  1286. //
  1287. // We found it in the list.
  1288. //
  1289. FoundInList = TRUE;
  1290. break;
  1291. }
  1292. //
  1293. // Release the parameters lock.
  1294. //
  1295. ExReleaseResourceLite(&PrefetcherParameters->ParametersLock);
  1296. KeLeaveCriticalRegionThread(CurrentThread);
  1297. //
  1298. // Return whether the executable was found in the list.
  1299. //
  1300. return FoundInList;
  1301. }