Source code of Windows XP (NT5)
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.

1012 lines
31 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. virtmem.c
  5. Abstract:
  6. Routines to configure and set up virtual memory -- pagefiles, etc.
  7. Author:
  8. Ted Miller (tedm) 22-Apr-1995
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #pragma hdrstop
  13. //
  14. // What's the ratio of 'beginning' pagefile size to 'max' pagefile size?
  15. //
  16. #define MAX_PAGEFILE_RATIO (2)
  17. #define MAX_PAGEFILE_SIZEMB ((2*1024) - 2)
  18. #define TINY_WINDIR_PAGEFILE_SIZE (2)
  19. //
  20. // Keys and values names
  21. //
  22. #define szMemoryManagementKeyPath L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"
  23. #define szPageFileValueName L"PagingFiles"
  24. #define szSetupPageFileKeyPath L"SYSTEM\\Setup\\PageFile"
  25. #define szSetupKey L"SYSTEM\\Setup"
  26. #define szPageFileKeyName L"PageFile"
  27. WCHAR ExistingPagefileDrive = 0;
  28. DWORD Zero = 0;
  29. DWORD One = 1;
  30. DWORD Two = 2;
  31. DWORD Three = 3;
  32. //
  33. // Keep AutoReboot as the last entry as we won't be updating that key on
  34. // upgrades. This is for Stress so we quit setting this key on each upgrade.
  35. //
  36. REGVALITEM CrashDumpValues[] = {{ L"LogEvent" ,&One,sizeof(DWORD),REG_DWORD },
  37. { L"SendAlert" ,&One,sizeof(DWORD),REG_DWORD },
  38. { L"CrashDumpEnabled",&One,sizeof(DWORD),REG_DWORD },
  39. { L"AutoReboot" ,&One,sizeof(DWORD),REG_DWORD }};
  40. VOID
  41. LOGITEM(
  42. IN PCWSTR p,
  43. ...
  44. )
  45. {
  46. WCHAR str[1024];
  47. va_list arglist;
  48. va_start(arglist,p);
  49. wvsprintf(str,p,arglist);
  50. va_end(arglist);
  51. //
  52. // Used to debug problem on MIPS that was the result of a chip
  53. // errata, when dividing 64 bit numbers with multiplies pending.
  54. //
  55. SetuplogError(
  56. LogSevInformation,str,0,NULL,NULL);
  57. }
  58. VOID
  59. CalculatePagefileSizes(
  60. OUT PDWORD PagefileMinMB,
  61. OUT PDWORD RecommendedPagefileMB,
  62. OUT PDWORD CrashDumpPagefileMinMB
  63. )
  64. /*++
  65. Routine Description:
  66. Calculate various key sizes relating to pagefile size.
  67. Arguments:
  68. PagefileMinMB - receives the minimum recommended size for a pagefile,
  69. in MB.
  70. RecommendedPagefileMB - receives the recommended size for a pagefile,
  71. in MB.
  72. CrashDumpPagefileMinMB - receives the size in MB for a pagefile to be
  73. used for crashdumps.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. MEMORYSTATUSEX MemoryStatusEx;
  79. SYSTEM_INFO SystemInfo;
  80. DWORD AvailableMB;
  81. MemoryStatusEx.dwLength = sizeof(MEMORYSTATUSEX);
  82. GlobalMemoryStatusEx(&MemoryStatusEx);
  83. GetSystemInfo(&SystemInfo);
  84. //
  85. // Figure out how much memory we have available.
  86. //
  87. AvailableMB = (DWORD)(MemoryStatusEx.ullTotalPhys / (1024*1024));
  88. //
  89. // It's likely that our calculation is off because the BIOS may
  90. // be eat part of our first MB. Let's make sure we're mod-4.
  91. //
  92. AvailableMB = (AvailableMB + 3) & (0xFFFFFFF8);
  93. //
  94. // Set minimum acceptable size for the pagefile.
  95. //
  96. *PagefileMinMB = 48;
  97. //
  98. // Min size for crash dump pagefile is also physical memory+12mb.
  99. //
  100. *CrashDumpPagefileMinMB = AvailableMB + 12;
  101. //
  102. // Calculate the recommended size for the pagefile.
  103. // The recommended size is (memory size * 1.5)mb.
  104. //
  105. *RecommendedPagefileMB = AvailableMB + (AvailableMB >> 1);
  106. #if 1
  107. //
  108. // Set a Maximum of 2Gig.
  109. //
  110. if( *RecommendedPagefileMB > MAX_PAGEFILE_SIZEMB ) {
  111. *RecommendedPagefileMB = MAX_PAGEFILE_SIZEMB;
  112. }
  113. #endif
  114. //
  115. // If we're doing an upgrade, we're going to retrieve what
  116. // the user was using for a pagefile size. We'll take the
  117. // max of our RecommendedPagefileMB and what the user had.
  118. //
  119. if(Upgrade) {
  120. LONG Error;
  121. HKEY Key;
  122. DWORD cbData;
  123. PWCHAR Data;
  124. DWORD Type;
  125. //
  126. // Get the original page file info from
  127. // HKEY_LOCAL_MACHINE\SYSTEM\Setup\PageFile
  128. //
  129. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  130. szSetupPageFileKeyPath,
  131. 0,
  132. KEY_READ,
  133. &Key );
  134. if( Error == ERROR_SUCCESS ) {
  135. //
  136. // Find out the size of the data to be retrieved
  137. //
  138. cbData = 0;
  139. Error = RegQueryValueEx( Key,
  140. szPageFileValueName,
  141. 0,
  142. NULL,
  143. NULL,
  144. &cbData );
  145. if( Error == ERROR_SUCCESS ) {
  146. //
  147. // Allocate a buffer for the data, and retrieve the data
  148. //
  149. Data = (PWCHAR)MyMalloc(cbData);
  150. if( Data ) {
  151. Error = RegQueryValueEx( Key,
  152. szPageFileValueName,
  153. 0,
  154. &Type,
  155. ( LPBYTE )Data,
  156. &cbData );
  157. if( (Error == ERROR_SUCCESS) ) {
  158. //
  159. // We got the data. Take the bigger value.
  160. //
  161. if( wcsstr( Data, TEXT(" ") ) ) {
  162. DWORD ExistingPageFileSize = 0;
  163. ExistingPageFileSize = (int)wcstoul(wcsstr( Data, TEXT(" ") ),NULL,10);
  164. if( ExistingPageFileSize >= *RecommendedPagefileMB ) {
  165. //
  166. // The user has a bigger pagefile than we think he needs.
  167. // Assume he knows better and take the bigger value.
  168. //
  169. *RecommendedPagefileMB = ExistingPageFileSize;
  170. //
  171. // Remember his drive letter too. This tells us that
  172. // the user may already have a decent pagefile and
  173. // we don't need to mess with it.
  174. //
  175. ExistingPagefileDrive = towupper( (WCHAR)Data[0] );
  176. //
  177. // If it's not valid, nuke the flag.
  178. //
  179. if( (ExistingPagefileDrive > 'Z') ||
  180. (ExistingPagefileDrive < 'A') ) {
  181. ExistingPagefileDrive = 0;
  182. }
  183. }
  184. }
  185. }
  186. MyFree( Data );
  187. }
  188. }
  189. RegCloseKey( Key );
  190. }
  191. //
  192. // Delete our record of what the user was previously using
  193. // for a pagefile.
  194. //
  195. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  196. szSetupKey,
  197. 0,
  198. MAXIMUM_ALLOWED,
  199. &Key );
  200. if( Error == ERROR_SUCCESS ) {
  201. RegDeleteKey( Key,
  202. szPageFileKeyName );
  203. RegCloseKey( Key );
  204. }
  205. }
  206. }
  207. VOID
  208. BuildVolumeFreeSpaceList(
  209. OUT DWORD VolumeFreeSpaceMB[26]
  210. )
  211. /*++
  212. Routine Description:
  213. Build a list of free space available on each hard drive in the system.
  214. The space will include space taken up by a file called \pagefile.sys
  215. on each drive. Existing pagefiles are marked for deletion on the next boot.
  216. Arguments:
  217. VolumeFreeSpaceMB - receives free space for each of the 26 drives
  218. potentially describable in the drive letter namespace.
  219. Entries for drives that do not exist are left alone, so the caller
  220. should zero out the array before calling this routine.
  221. Return Value:
  222. None.
  223. --*/
  224. {
  225. DWORD SectorsPerCluster;
  226. DWORD BytesPerSector;
  227. DWORD FreeClusters;
  228. DWORD TotalClusters;
  229. DWORD d;
  230. PWCHAR p;
  231. ULONGLONG FreeSpace;
  232. INT DriveNo;
  233. WIN32_FIND_DATA FindData;
  234. WCHAR Filename[] = L"?:\\pagefile.sys";
  235. //
  236. // Space for logical drive strings. Each is x:\ + nul, and
  237. // there is an extra nul terminating the list.
  238. //
  239. WCHAR Buffer[(26*4)+1];
  240. //
  241. // Build up a list of free space on each available hard drive.
  242. //
  243. d = GetLogicalDriveStrings(sizeof(Buffer)/sizeof(Buffer[0]),Buffer);
  244. CharUpperBuff(Buffer,d);
  245. for(p=Buffer; *p; p+=lstrlen(p)+1) {
  246. DriveNo = (*p) - L'A';
  247. if((DriveNo >= 0) && (DriveNo < 26) && (p[1] == L':')
  248. && (MyGetDriveType(*p) == DRIVE_FIXED)
  249. && GetDiskFreeSpace(p,&SectorsPerCluster,&BytesPerSector,&FreeClusters,&TotalClusters)) {
  250. LOGITEM(
  251. L"BuildVolumeFreeSpaceList: %s, spc=%u, bps=%u, freeclus=%u, totalclus=%u\r\n",
  252. p,
  253. SectorsPerCluster,
  254. BytesPerSector,
  255. FreeClusters,
  256. TotalClusters
  257. );
  258. FreeSpace = UInt32x32To64(BytesPerSector * SectorsPerCluster, FreeClusters);
  259. LOGITEM(
  260. L"BuildVolumeFreeSpaceList: %s, FreeSpace = %u%u\r\n",
  261. p,
  262. (DWORD)(FreeSpace >> 32),
  263. (DWORD)FreeSpace
  264. );
  265. //
  266. // If there's already a page file here, include its size in the free space
  267. // for the drive. Delete the existing pagefile on the next reboot.
  268. //
  269. Filename[0] = *p;
  270. if(FileExists(Filename,&FindData)) {
  271. FreeSpace += FindData.nFileSizeLow;
  272. LOGITEM(
  273. L"BuildVolumeFreeSpaceList: %s had %u byte pagefile, new FreeSpace = %u%u\r\n",
  274. p,
  275. FindData.nFileSizeLow,
  276. (DWORD)(FreeSpace >> 32),
  277. (DWORD)FreeSpace
  278. );
  279. MoveFileEx(Filename,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);
  280. }
  281. VolumeFreeSpaceMB[DriveNo] = (DWORD)(FreeSpace / (1024*1024));
  282. LOGITEM(L"BuildVolumeFreeSpaceList: Free space on %s is %u MB\r\n",p,VolumeFreeSpaceMB[DriveNo]);
  283. }
  284. }
  285. }
  286. BOOL
  287. SetUpVirtualMemory(
  288. VOID
  289. )
  290. /*++
  291. Routine Description:
  292. Configure a pagefile. If setting up a server, we attempt to set up a pagefile
  293. suitable for use with crashdump, meaning it has to be at least the size of
  294. system memory, and has to go on the nt drive. Otherwise we attempt to place
  295. a pagefile on the nt drive if there's enough space, and if that fails, we
  296. place it on any drive with any space.
  297. Arguments:
  298. None.
  299. Return Value:
  300. Boolean value indicating outcome.
  301. --*/
  302. {
  303. #define SYS_DRIVE_FREE_SPACE_BUFFER (100)
  304. #define ALT_DRIVE_FREE_SPACE_BUFFER (25)
  305. #define AnswerBufLen (4*MAX_PATH)
  306. #define RECORD_VM_SETTINGS( Drive, Size, Buffer ) { \
  307. PagefileDrive = Drive; \
  308. PagefileSizeMB = Size; \
  309. MaxPagefileSizeMB = __min( (VolumeFreeSpaceMB[PagefileDrive] - Buffer), \
  310. PagefileSizeMB * MAX_PAGEFILE_RATIO ); \
  311. \
  312. MaxPagefileSizeMB = __max( MaxPagefileSizeMB, PagefileSizeMB ); \
  313. \
  314. if( PagefileSizeMB >= CrashDumpPagefileMinMB ) { \
  315. EnableCrashDump = TRUE; \
  316. } \
  317. }
  318. DWORD VolumeFreeSpaceMB[26];
  319. DWORD PagefileMinMB;
  320. DWORD RecommendedPagefileMB;
  321. DWORD CrashDumpPagefileMinMB;
  322. WCHAR WindowsDirectory[MAX_PATH];
  323. UINT WindowsDriveNo,DriveNo;
  324. UINT PagefileDrive;
  325. BOOL EnableCrashDump;
  326. INT MaxSpaceDrive;
  327. DWORD PagefileSizeMB;
  328. DWORD MaxPagefileSizeMB;
  329. WCHAR PagefileTemplate[128];
  330. PWSTR PagefileSpec;
  331. DWORD d;
  332. BOOL b;
  333. BOOL UseExistingPageFile = FALSE;
  334. WCHAR AnswerFile[AnswerBufLen];
  335. WCHAR Answer[AnswerBufLen];
  336. WCHAR DriveName[] = L"?:\\";
  337. LOGITEM(L"SetUpVirtualMemory: ENTER\r\n");
  338. if( !GetWindowsDirectory(WindowsDirectory,MAX_PATH) ) {
  339. return FALSE;
  340. }
  341. WindowsDriveNo = (UINT)PtrToUlong(CharUpper((PWSTR)WindowsDirectory[0])) - (UINT)L'A';
  342. PagefileDrive = -1;
  343. EnableCrashDump = FALSE;
  344. //
  345. // Take care of some preliminaries.
  346. //
  347. CalculatePagefileSizes(
  348. &PagefileMinMB,
  349. &RecommendedPagefileMB,
  350. &CrashDumpPagefileMinMB
  351. );
  352. ZeroMemory(VolumeFreeSpaceMB,sizeof(VolumeFreeSpaceMB));
  353. BuildVolumeFreeSpaceList(VolumeFreeSpaceMB);
  354. //
  355. // Now figure out how large and where the pagefile will be.
  356. //
  357. //
  358. // ================================================================
  359. // 0. See if the user already has a reasonable pagefile.
  360. // ================================================================
  361. //
  362. if( (Upgrade) &&
  363. (ExistingPagefileDrive) ) {
  364. //
  365. // See if there's enough room on the existing drive
  366. // for the pagefile.
  367. //
  368. if( VolumeFreeSpaceMB[(UINT)(ExistingPagefileDrive - L'A')] > (RecommendedPagefileMB + ALT_DRIVE_FREE_SPACE_BUFFER) ) {
  369. //
  370. // He's already got something that will work. We're done.
  371. //
  372. LOGITEM(L"SetUpVirtualMemory: loc 0 - keep user's pagefile settings.\r\n");
  373. UseExistingPageFile = TRUE;
  374. PagefileDrive = (UINT)(ExistingPagefileDrive - L'A');
  375. }
  376. }
  377. //
  378. // ================================================================
  379. // 1. See if the NT drive has enough space for the MAX pagefile
  380. // size.
  381. // ================================================================
  382. //
  383. if(PagefileDrive == -1) {
  384. if( VolumeFreeSpaceMB[WindowsDriveNo] > ((RecommendedPagefileMB * MAX_PAGEFILE_RATIO) + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  385. LOGITEM(L"SetUpVirtualMemory: loc 1\r\n");
  386. //
  387. // Record our settings.
  388. //
  389. RECORD_VM_SETTINGS( WindowsDriveNo, RecommendedPagefileMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  390. }
  391. }
  392. //
  393. // ================================================================
  394. // 2. See if any drive has enough space for the MAX pagefile
  395. // size.
  396. // ================================================================
  397. //
  398. if(PagefileDrive == -1) {
  399. for(DriveNo=0; DriveNo<26; DriveNo++) {
  400. if( (DriveNo != WindowsDriveNo) &&
  401. (VolumeFreeSpaceMB[DriveNo] > ((RecommendedPagefileMB * MAX_PAGEFILE_RATIO) + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  402. //
  403. // He's got the space, but let's make sure he's not removable.
  404. //
  405. DriveName[0] = DriveNo + L'A';
  406. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  407. LOGITEM(L"SetUpVirtualMemory: loc 2 - found space on driveno %u\r\n",DriveNo);
  408. //
  409. // Record our settings.
  410. //
  411. RECORD_VM_SETTINGS( DriveNo, RecommendedPagefileMB, ALT_DRIVE_FREE_SPACE_BUFFER );
  412. break;
  413. }
  414. }
  415. }
  416. }
  417. //
  418. // ================================================================
  419. // 3. See if the NT drive has enough space for the recommended pagefile
  420. // size.
  421. // ================================================================
  422. //
  423. if(PagefileDrive == -1) {
  424. if( VolumeFreeSpaceMB[WindowsDriveNo] > (RecommendedPagefileMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  425. LOGITEM(L"SetUpVirtualMemory: loc 3\r\n");
  426. //
  427. // Record our settings.
  428. //
  429. RECORD_VM_SETTINGS( WindowsDriveNo, RecommendedPagefileMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  430. }
  431. }
  432. //
  433. // ================================================================
  434. // 4. See if any drive has enough space for the recommended pagefile
  435. // size.
  436. // ================================================================
  437. //
  438. if(PagefileDrive == -1) {
  439. for(DriveNo=0; DriveNo<26; DriveNo++) {
  440. if( (DriveNo != WindowsDriveNo) &&
  441. (VolumeFreeSpaceMB[DriveNo] > (RecommendedPagefileMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  442. //
  443. // He's got the space, but let's make sure he's not removable.
  444. //
  445. DriveName[0] = DriveNo + L'A';
  446. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  447. LOGITEM(L"SetUpVirtualMemory: loc 4 - found space on driveno %u\r\n",DriveNo);
  448. //
  449. // Record our settings.
  450. //
  451. RECORD_VM_SETTINGS( DriveNo, RecommendedPagefileMB, ALT_DRIVE_FREE_SPACE_BUFFER );
  452. break;
  453. }
  454. }
  455. }
  456. }
  457. //
  458. // ================================================================
  459. // 5. See if the NT drive has enough space for the CrashDump pagefile
  460. // size.
  461. // ================================================================
  462. //
  463. if(PagefileDrive == -1) {
  464. if( VolumeFreeSpaceMB[WindowsDriveNo] > (CrashDumpPagefileMinMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  465. LOGITEM(L"SetUpVirtualMemory: loc 5\r\n");
  466. //
  467. // Record our settings.
  468. //
  469. RECORD_VM_SETTINGS( WindowsDriveNo, CrashDumpPagefileMinMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  470. }
  471. }
  472. //
  473. // ================================================================
  474. // 6. See if any drive has enough space for the CrashDump pagefile
  475. // size.
  476. // ================================================================
  477. //
  478. if(PagefileDrive == -1) {
  479. for(DriveNo=0; DriveNo<26; DriveNo++) {
  480. if( (DriveNo != WindowsDriveNo) &&
  481. (VolumeFreeSpaceMB[DriveNo] > (CrashDumpPagefileMinMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  482. //
  483. // He's got the space, but let's make sure he's not removable.
  484. //
  485. DriveName[0] = DriveNo + L'A';
  486. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  487. LOGITEM(L"SetUpVirtualMemory: loc 6 - found space on driveno %u\r\n",DriveNo);
  488. //
  489. // Record our settings.
  490. //
  491. RECORD_VM_SETTINGS( DriveNo, CrashDumpPagefileMinMB, ALT_DRIVE_FREE_SPACE_BUFFER);
  492. break;
  493. }
  494. }
  495. }
  496. }
  497. //
  498. // ================================================================
  499. // 7. See if the NT drive has enough space for the minimum pagefile
  500. // size.
  501. // ================================================================
  502. //
  503. if(PagefileDrive == -1) {
  504. if( VolumeFreeSpaceMB[WindowsDriveNo] > (PagefileMinMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  505. LOGITEM(L"SetUpVirtualMemory: loc 7\r\n");
  506. //
  507. // Record our settings.
  508. //
  509. RECORD_VM_SETTINGS( WindowsDriveNo, PagefileMinMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  510. }
  511. }
  512. //
  513. // ================================================================
  514. // 8. See if any drive has enough space for the minimum pagefile
  515. // size.
  516. // ================================================================
  517. //
  518. if(PagefileDrive == -1) {
  519. for(DriveNo=0; DriveNo<26; DriveNo++) {
  520. if( (DriveNo != WindowsDriveNo) &&
  521. (VolumeFreeSpaceMB[DriveNo] > (PagefileMinMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  522. //
  523. // He's got the space, but let's make sure he's not removable.
  524. //
  525. DriveName[0] = DriveNo + L'A';
  526. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  527. LOGITEM(L"SetUpVirtualMemory: loc 8 - found space on driveno %u\r\n",DriveNo);
  528. //
  529. // Record our settings.
  530. //
  531. RECORD_VM_SETTINGS( DriveNo, PagefileMinMB, ALT_DRIVE_FREE_SPACE_BUFFER );
  532. break;
  533. }
  534. }
  535. }
  536. }
  537. //
  538. // ================================================================
  539. // 9. Pick the drive with the most free space.
  540. // ================================================================
  541. //
  542. if(PagefileDrive == -1) {
  543. MaxSpaceDrive = 0;
  544. for(DriveNo=0; DriveNo<26; DriveNo++) {
  545. if(VolumeFreeSpaceMB[DriveNo] > VolumeFreeSpaceMB[MaxSpaceDrive]) {
  546. MaxSpaceDrive = DriveNo;
  547. }
  548. }
  549. if( VolumeFreeSpaceMB[MaxSpaceDrive] > ALT_DRIVE_FREE_SPACE_BUFFER ) {
  550. //
  551. // We're desperate here, so don't bother checking if he's
  552. // removable.
  553. //
  554. LOGITEM(L"SetUpVirtualMemory: loc 9 - MaxSpaceDrive is %u\r\n",MaxSpaceDrive);
  555. //
  556. // Record our settings.
  557. //
  558. RECORD_VM_SETTINGS( MaxSpaceDrive, VolumeFreeSpaceMB[MaxSpaceDrive] - ALT_DRIVE_FREE_SPACE_BUFFER, 0 );
  559. }
  560. }
  561. //
  562. // If we still don't have space for a pagefile, the user is out of luck.
  563. //
  564. if(PagefileDrive == -1) {
  565. LOGITEM(L"SetUpVirtualMemory: loc 10 -- out of luck\r\n");
  566. PagefileSpec = NULL;
  567. b = FALSE;
  568. SetuplogError(
  569. LogSevWarning,
  570. SETUPLOG_USE_MESSAGEID,
  571. MSG_LOG_PAGEFILE_FAIL,NULL,
  572. SETUPLOG_USE_MESSAGEID,
  573. MSG_LOG_NO_PAGING_DRIVES,
  574. NULL,NULL);
  575. } else {
  576. b = TRUE;
  577. PagefileSpec = PagefileTemplate;
  578. _snwprintf(
  579. PagefileTemplate,
  580. sizeof(PagefileTemplate)/sizeof(PagefileTemplate[0]),
  581. L"%c:\\pagefile.sys %u %u",
  582. PagefileDrive + L'A',
  583. PagefileSizeMB,
  584. MaxPagefileSizeMB
  585. );
  586. }
  587. if( b ) {
  588. //
  589. // Set pagefile in registry. I only want to do this in the
  590. // case of clean installs, and on upgrades if the existing
  591. // pagefile wasn't big enough. In the case of upgrades, if
  592. // the existing pagefile was big enough, then we will have
  593. // set UseExistingPageFile, which will tell us to leave the
  594. // registry settings as is.
  595. //
  596. if( !UseExistingPageFile ) {
  597. d = pSetupSetArrayToMultiSzValue(
  598. HKEY_LOCAL_MACHINE,
  599. szMemoryManagementKeyPath,
  600. szPageFileValueName,
  601. &PagefileSpec,
  602. PagefileSpec ? 1 : 0
  603. );
  604. if(d == NO_ERROR) {
  605. if(b) {
  606. SetuplogError(
  607. LogSevInformation,
  608. SETUPLOG_USE_MESSAGEID,
  609. MSG_LOG_CREATED_PAGEFILE,
  610. PagefileDrive+L'A',
  611. PagefileSizeMB,
  612. NULL,NULL);
  613. }
  614. } else {
  615. SetuplogError(
  616. LogSevWarning,
  617. SETUPLOG_USE_MESSAGEID,
  618. MSG_LOG_PAGEFILE_FAIL, NULL,
  619. SETUPLOG_USE_MESSAGEID,
  620. MSG_LOG_X_RETURNED_WINERR,
  621. szSetArrayToMultiSzValue,
  622. d,
  623. NULL,NULL);
  624. }
  625. //
  626. // Make sure there's at least a small pagefile
  627. // on the windows drive. Ignore errors here.
  628. //
  629. if( (PagefileDrive != WindowsDriveNo) &&
  630. (VolumeFreeSpaceMB[WindowsDriveNo] > TINY_WINDIR_PAGEFILE_SIZE) ) {
  631. //
  632. // There's not. Write a second string into our buffer just past
  633. // the first string (remember this will become a REG_MULTI_SZ
  634. //
  635. _snwprintf(
  636. PagefileTemplate,
  637. sizeof(PagefileTemplate)/sizeof(PagefileTemplate[0]),
  638. L"%c:\\pagefile.sys %u %u",
  639. WindowsDriveNo + L'A',
  640. TINY_WINDIR_PAGEFILE_SIZE,
  641. TINY_WINDIR_PAGEFILE_SIZE
  642. );
  643. pSetupAppendStringToMultiSz(
  644. HKEY_LOCAL_MACHINE,
  645. szMemoryManagementKeyPath,
  646. 0,
  647. szPageFileValueName,
  648. PagefileTemplate,
  649. TRUE
  650. );
  651. }
  652. b = b && (d == NO_ERROR);
  653. }
  654. }
  655. //
  656. // Now set the crashdump.
  657. //
  658. // The proper settings are as follows:
  659. //
  660. // Server Upgrades
  661. // ===============
  662. // existing setting new setting
  663. // 0 3
  664. // 1 1
  665. //
  666. // Workstation Upgrades
  667. // ====================
  668. // existing setting new setting
  669. // 0 3
  670. // 1 1
  671. //
  672. // Server Clean Install
  673. // ====================
  674. // new setting
  675. // 1 iff pagefile < MAX_PAGEFILE_SIZEMB else 2
  676. //
  677. // Workstation Clean Install
  678. // =========================
  679. // new setting
  680. // 3
  681. //
  682. //
  683. // Where:
  684. // 0 - no crash dump
  685. // 1 - dump all memory to crash file
  686. // 2 - dump kernel memory to crash file
  687. // 3 - dump a select set of memory (amounting to 64K) to crash file
  688. //
  689. //
  690. // See if the user has asked us to go a particular way
  691. // on the crashdump settings.
  692. //
  693. GetSystemDirectory(AnswerFile,MAX_PATH);
  694. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  695. GetPrivateProfileString( TEXT("Unattended"),
  696. TEXT("CrashDumpSetting"),
  697. pwNull,
  698. Answer,
  699. AnswerBufLen,
  700. AnswerFile );
  701. if( lstrcmp( pwNull, Answer ) ) {
  702. d = wcstoul(Answer,NULL,10);
  703. if( d <= Three ) {
  704. CrashDumpValues[2].Data = &d;
  705. } else {
  706. CrashDumpValues[2].Data = &Three;
  707. }
  708. } else {
  709. //
  710. // No unattended values. Set it manually.
  711. //
  712. //
  713. // Take care of clean installs first.
  714. //
  715. if( !Upgrade ) {
  716. if( ProductType == PRODUCT_WORKSTATION ) {
  717. CrashDumpValues[2].Data = &Three;
  718. } else {
  719. if( PagefileSizeMB >= MAX_PAGEFILE_SIZEMB ) {
  720. CrashDumpValues[2].Data = &Two;
  721. } else {
  722. CrashDumpValues[2].Data = &One;
  723. }
  724. }
  725. } else {
  726. //
  727. // Upgrade.
  728. //
  729. // Here, we need to go retrieve the current value to
  730. // see what's there now. This will tell us how to migrate.
  731. //
  732. HKEY Key;
  733. DWORD cbData;
  734. DWORD ExistingCrashDumpSetting = 0;
  735. DWORD Type;
  736. d = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  737. L"System\\CurrentControlSet\\Control\\CrashControl",
  738. 0,
  739. KEY_READ,
  740. &Key );
  741. if( d == ERROR_SUCCESS ) {
  742. //
  743. // Find out the size of the data to be retrieved
  744. //
  745. cbData = sizeof(DWORD);
  746. d = RegQueryValueEx( Key,
  747. CrashDumpValues[2].Name,
  748. 0,
  749. &Type,
  750. ( LPBYTE )&ExistingCrashDumpSetting,
  751. &cbData );
  752. RegCloseKey( Key );
  753. }
  754. //
  755. // Make sure ExistingCrashDumpSetting is set.
  756. //
  757. if( d != ERROR_SUCCESS ) {
  758. ExistingCrashDumpSetting = (ProductType == PRODUCT_WORKSTATION) ? 0 : 1;
  759. }
  760. if( ProductType == PRODUCT_WORKSTATION ) {
  761. if( ExistingCrashDumpSetting == 0 ) {
  762. CrashDumpValues[2].Data = &Three;
  763. } else {
  764. CrashDumpValues[2].Data = &One;
  765. }
  766. } else {
  767. if( ExistingCrashDumpSetting == 0 ) {
  768. CrashDumpValues[2].Data = &Three;
  769. } else {
  770. CrashDumpValues[2].Data = &One;
  771. }
  772. }
  773. }
  774. }
  775. #ifdef PRERELEASE
  776. if( Upgrade ) {
  777. d = SetGroupOfValues(
  778. HKEY_LOCAL_MACHINE,
  779. L"System\\CurrentControlSet\\Control\\CrashControl",
  780. CrashDumpValues,
  781. sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0]) - 1
  782. );
  783. } else {
  784. d = SetGroupOfValues(
  785. HKEY_LOCAL_MACHINE,
  786. L"System\\CurrentControlSet\\Control\\CrashControl",
  787. CrashDumpValues,
  788. sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0])
  789. );
  790. }
  791. #else
  792. d = SetGroupOfValues(
  793. HKEY_LOCAL_MACHINE,
  794. L"System\\CurrentControlSet\\Control\\CrashControl",
  795. CrashDumpValues,
  796. sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0])
  797. );
  798. #endif
  799. if(d == NO_ERROR) {
  800. SetuplogError(
  801. LogSevInformation,
  802. SETUPLOG_USE_MESSAGEID,
  803. MSG_LOG_CRASHDUMPOK,
  804. NULL,NULL);
  805. } else {
  806. SetuplogError(
  807. LogSevWarning,
  808. SETUPLOG_USE_MESSAGEID,
  809. MSG_LOG_CRASHDUMPFAIL, NULL,
  810. SETUPLOG_USE_MESSAGEID,
  811. MSG_LOG_X_RETURNED_STRING,
  812. szSetGroupOfValues,
  813. d,
  814. NULL,NULL);
  815. b = FALSE;
  816. }
  817. LOGITEM(L"SetUpVirtualMemory: EXIT (%u)\r\n",b);
  818. return(b);
  819. }