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.

972 lines
27 KiB

  1. #include "efinvram.h"
  2. PWSTR SystemPartitionNtName;
  3. PBOOT_OPTIONS BootOptions;
  4. ULONG BootOptionsLength;
  5. PBOOT_OPTIONS OriginalBootOptions;
  6. ULONG OriginalBootOptionsLength;
  7. PULONG BootEntryOrder;
  8. ULONG BootEntryOrderCount;
  9. PULONG OriginalBootEntryOrder;
  10. ULONG OriginalBootEntryOrderCount;
  11. LIST_ENTRY BootEntries;
  12. LIST_ENTRY DeletedBootEntries;
  13. LIST_ENTRY ActiveUnorderedBootEntries;
  14. LIST_ENTRY InactiveUnorderedBootEntries;
  15. VOID
  16. ConcatenatePaths (
  17. IN OUT PTSTR Path1,
  18. IN LPCTSTR Path2,
  19. IN DWORD BufferSizeChars
  20. );
  21. VOID
  22. ConvertBootEntries (
  23. PBOOT_ENTRY_LIST BootEntries
  24. );
  25. PMY_BOOT_ENTRY
  26. CreateBootEntryFromBootEntry (
  27. IN PMY_BOOT_ENTRY OldBootEntry
  28. );
  29. VOID
  30. FreeBootEntry (
  31. IN PMY_BOOT_ENTRY BootEntry
  32. );
  33. VOID
  34. InitializeEfi (
  35. VOID
  36. );
  37. NTSTATUS
  38. (*AddBootEntry) (
  39. IN PBOOT_ENTRY BootEntry,
  40. OUT PULONG Id OPTIONAL
  41. );
  42. NTSTATUS
  43. (*DeleteBootEntry) (
  44. IN ULONG Id
  45. );
  46. NTSTATUS
  47. (*ModifyBootEntry) (
  48. IN PBOOT_ENTRY BootEntry
  49. );
  50. NTSTATUS
  51. (*EnumerateBootEntries) (
  52. OUT PVOID Buffer,
  53. IN OUT PULONG BufferLength
  54. );
  55. NTSTATUS
  56. (*QueryBootEntryOrder) (
  57. OUT PULONG Ids,
  58. IN OUT PULONG Count
  59. );
  60. NTSTATUS
  61. (*SetBootEntryOrder) (
  62. IN PULONG Ids,
  63. IN ULONG Count
  64. );
  65. NTSTATUS
  66. (*QueryBootOptions) (
  67. OUT PBOOT_OPTIONS BootOptions,
  68. IN OUT PULONG BootOptionsLength
  69. );
  70. NTSTATUS
  71. (*SetBootOptions) (
  72. IN PBOOT_OPTIONS BootOptions,
  73. IN ULONG FieldsToChange
  74. );
  75. NTSTATUS
  76. (*TranslateFilePath) (
  77. IN PFILE_PATH InputFilePath,
  78. IN ULONG OutputType,
  79. OUT PFILE_PATH OutputFilePath,
  80. IN OUT PULONG OutputFilePathLength
  81. );
  82. int
  83. __cdecl
  84. main (
  85. int argc,
  86. char *argv[]
  87. )
  88. {
  89. UNREFERENCED_PARAMETER(argc);
  90. UNREFERENCED_PARAMETER(argv);
  91. InitializeMenuSystem( );
  92. InitializeEfi( );
  93. MainMenu( );
  94. return 0;
  95. }
  96. VOID
  97. ConvertBootEntries (
  98. PBOOT_ENTRY_LIST NtBootEntries
  99. )
  100. /*++
  101. Routine Description:
  102. Convert boot entries read from EFI NVRAM into our internal format.
  103. Arguments:
  104. None.
  105. Return Value:
  106. NTSTATUS - Not STATUS_SUCCESS if an unexpected error occurred.
  107. --*/
  108. {
  109. PBOOT_ENTRY_LIST bootEntryList;
  110. PBOOT_ENTRY bootEntry;
  111. PBOOT_ENTRY bootEntryCopy;
  112. PMY_BOOT_ENTRY myBootEntry;
  113. PWINDOWS_OS_OPTIONS osOptions;
  114. ULONG length;
  115. bootEntryList = NtBootEntries;
  116. while (TRUE) {
  117. bootEntry = &bootEntryList->BootEntry;
  118. //
  119. // Calculate the length of our internal structure. This includes
  120. // the base part of MY_BOOT_ENTRY plus the NT BOOT_ENTRY.
  121. //
  122. length = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry) + bootEntry->Length;
  123. myBootEntry = MemAlloc(length);
  124. RtlZeroMemory(myBootEntry, length);
  125. //
  126. // Link the new entry into the list.
  127. //
  128. if ( (bootEntry->Attributes & BOOT_ENTRY_ATTRIBUTE_ACTIVE) != 0 ) {
  129. InsertTailList( &ActiveUnorderedBootEntries, &myBootEntry->ListEntry );
  130. myBootEntry->ListHead = &ActiveUnorderedBootEntries;
  131. } else {
  132. InsertTailList( &InactiveUnorderedBootEntries, &myBootEntry->ListEntry );
  133. myBootEntry->ListHead = &InactiveUnorderedBootEntries;
  134. }
  135. //
  136. // Copy the NT BOOT_ENTRY into the allocated buffer.
  137. //
  138. bootEntryCopy = &myBootEntry->NtBootEntry;
  139. memcpy(bootEntryCopy, bootEntry, bootEntry->Length);
  140. //
  141. // Fill in the base part of the structure.
  142. //
  143. myBootEntry->AllocationEnd = (PUCHAR)myBootEntry + length - 1;
  144. myBootEntry->Id = bootEntry->Id;
  145. myBootEntry->Attributes = bootEntry->Attributes;
  146. myBootEntry->FriendlyName = ADD_OFFSET(bootEntryCopy, FriendlyNameOffset);
  147. myBootEntry->FriendlyNameLength =
  148. ((ULONG)wcslen(myBootEntry->FriendlyName) + 1) * sizeof(WCHAR);
  149. myBootEntry->BootFilePath = ADD_OFFSET(bootEntryCopy, BootFilePathOffset);
  150. //
  151. // If this is an NT boot entry, capture the NT-specific information in
  152. // the OsOptions.
  153. //
  154. osOptions = (PWINDOWS_OS_OPTIONS)bootEntryCopy->OsOptions;
  155. if ((bootEntryCopy->OsOptionsLength >= FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions)) &&
  156. (strcmp((char *)osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) == 0)) {
  157. MBE_SET_IS_NT( myBootEntry );
  158. myBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  159. myBootEntry->OsLoadOptionsLength =
  160. ((ULONG)wcslen(myBootEntry->OsLoadOptions) + 1) * sizeof(WCHAR);
  161. myBootEntry->OsFilePath = ADD_OFFSET(osOptions, OsLoadPathOffset);
  162. } else {
  163. //
  164. // Foreign boot entry. Just capture whatever OS options exist.
  165. //
  166. myBootEntry->ForeignOsOptions = bootEntryCopy->OsOptions;
  167. myBootEntry->ForeignOsOptionsLength = bootEntryCopy->OsOptionsLength;
  168. }
  169. //
  170. // Move to the next entry in the enumeration list, if any.
  171. //
  172. if (bootEntryList->NextEntryOffset == 0) {
  173. break;
  174. }
  175. bootEntryList = ADD_OFFSET(bootEntryList, NextEntryOffset);
  176. }
  177. return;
  178. } // ConvertBootEntries
  179. VOID
  180. ConcatenatePaths (
  181. IN OUT PTSTR Path1,
  182. IN LPCTSTR Path2,
  183. IN DWORD BufferSizeChars
  184. )
  185. /*++
  186. Routine Description:
  187. Concatenate two path strings together, supplying a path separator
  188. character (\) if necessary between the 2 parts.
  189. Arguments:
  190. Path1 - supplies prefix part of path. Path2 is concatenated to Path1.
  191. Path2 - supplies the suffix part of path. If Path1 does not end with a
  192. path separator and Path2 does not start with one, then a path sep
  193. is appended to Path1 before appending Path2.
  194. BufferSizeChars - supplies the size in chars (Unicode version) or
  195. bytes (Ansi version) of the buffer pointed to by Path1. The string
  196. will be truncated as necessary to not overflow that size.
  197. Return Value:
  198. None.
  199. --*/
  200. {
  201. BOOL NeedBackslash = TRUE;
  202. DWORD l;
  203. if(!Path1)
  204. return;
  205. l = lstrlen(Path1);
  206. if(BufferSizeChars >= sizeof(TCHAR)) {
  207. //
  208. // Leave room for terminating nul.
  209. //
  210. BufferSizeChars -= sizeof(TCHAR);
  211. }
  212. //
  213. // Determine whether we need to stick a backslash
  214. // between the components.
  215. //
  216. if(l && (Path1[l-1] == TEXT('\\'))) {
  217. NeedBackslash = FALSE;
  218. }
  219. if(Path2 && *Path2 == TEXT('\\')) {
  220. if(NeedBackslash) {
  221. NeedBackslash = FALSE;
  222. } else {
  223. //
  224. // Not only do we not need a backslash, but we
  225. // need to eliminate one before concatenating.
  226. //
  227. Path2++;
  228. }
  229. }
  230. //
  231. // Append backslash if necessary and if it fits.
  232. //
  233. if(NeedBackslash && (l < BufferSizeChars)) {
  234. lstrcat(Path1,TEXT("\\"));
  235. }
  236. //
  237. // Append second part of string to first part if it fits.
  238. //
  239. if(Path2 && ((l+lstrlen(Path2)) < BufferSizeChars)) {
  240. lstrcat(Path1,Path2);
  241. }
  242. }
  243. PMY_BOOT_ENTRY
  244. CreateBootEntryFromBootEntry (
  245. IN PMY_BOOT_ENTRY OldBootEntry
  246. )
  247. {
  248. ULONG requiredLength;
  249. ULONG osOptionsOffset;
  250. ULONG osLoadOptionsLength;
  251. ULONG osLoadPathOffset;
  252. ULONG osLoadPathLength;
  253. ULONG osOptionsLength;
  254. ULONG friendlyNameOffset;
  255. ULONG friendlyNameLength;
  256. ULONG bootPathOffset;
  257. ULONG bootPathLength;
  258. PMY_BOOT_ENTRY newBootEntry;
  259. PBOOT_ENTRY ntBootEntry;
  260. PWINDOWS_OS_OPTIONS osOptions;
  261. PFILE_PATH osLoadPath;
  262. PWSTR friendlyName;
  263. PFILE_PATH bootPath;
  264. //
  265. // Calculate how long the internal boot entry needs to be. This includes
  266. // our internal structure, plus the BOOT_ENTRY structure that the NT APIs
  267. // use.
  268. //
  269. // Our structure:
  270. //
  271. requiredLength = FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  272. //
  273. // Base part of NT structure:
  274. //
  275. requiredLength += FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  276. //
  277. // Save offset to BOOT_ENTRY.OsOptions. Add in base part of
  278. // WINDOWS_OS_OPTIONS. Calculate length in bytes of OsLoadOptions
  279. // and add that in.
  280. //
  281. osOptionsOffset = requiredLength;
  282. if ( MBE_IS_NT( OldBootEntry ) ) {
  283. //
  284. // Add in base part of WINDOWS_OS_OPTIONS. Calculate length in
  285. // bytes of OsLoadOptions and add that in.
  286. //
  287. requiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  288. osLoadOptionsLength = OldBootEntry->OsLoadOptionsLength;
  289. requiredLength += osLoadOptionsLength;
  290. //
  291. // Round up to a ULONG boundary for the OS FILE_PATH in the
  292. // WINDOWS_OS_OPTIONS. Save offset to OS FILE_PATH. Calculate length
  293. // in bytes of FILE_PATH and add that in. Calculate total length of
  294. // WINDOWS_OS_OPTIONS.
  295. //
  296. requiredLength = ALIGN_UP(requiredLength, ULONG);
  297. osLoadPathOffset = requiredLength;
  298. requiredLength += OldBootEntry->OsFilePath->Length;
  299. osLoadPathLength = requiredLength - osLoadPathOffset;
  300. } else {
  301. //
  302. // Add in length of foreign OS options.
  303. //
  304. requiredLength += OldBootEntry->ForeignOsOptionsLength;
  305. osLoadOptionsLength = 0;
  306. osLoadPathOffset = 0;
  307. osLoadPathLength = 0;
  308. }
  309. osOptionsLength = requiredLength - osOptionsOffset;
  310. //
  311. // Round up to a ULONG boundary for the friendly name in the BOOT_ENTRY.
  312. // Save offset to friendly name. Calculate length in bytes of friendly name
  313. // and add that in.
  314. //
  315. requiredLength = ALIGN_UP(requiredLength, ULONG);
  316. friendlyNameOffset = requiredLength;
  317. friendlyNameLength = OldBootEntry->FriendlyNameLength;
  318. requiredLength += friendlyNameLength;
  319. //
  320. // Round up to a ULONG boundary for the boot FILE_PATH in the BOOT_ENTRY.
  321. // Save offset to boot FILE_PATH. Calculate length in bytes of FILE_PATH
  322. // and add that in.
  323. //
  324. requiredLength = ALIGN_UP(requiredLength, ULONG);
  325. bootPathOffset = requiredLength;
  326. requiredLength += OldBootEntry->BootFilePath->Length;
  327. bootPathLength = requiredLength - bootPathOffset;
  328. //
  329. // Allocate memory for the boot entry.
  330. //
  331. newBootEntry = MemAlloc(requiredLength);
  332. ASSERT(newBootEntry != NULL);
  333. RtlZeroMemory(newBootEntry, requiredLength);
  334. //
  335. // Calculate addresses of various substructures using the saved offsets.
  336. //
  337. ntBootEntry = &newBootEntry->NtBootEntry;
  338. osOptions = (PWINDOWS_OS_OPTIONS)ntBootEntry->OsOptions;
  339. osLoadPath = (PFILE_PATH)((PUCHAR)newBootEntry + osLoadPathOffset);
  340. friendlyName = (PWSTR)((PUCHAR)newBootEntry + friendlyNameOffset);
  341. bootPath = (PFILE_PATH)((PUCHAR)newBootEntry + bootPathOffset);
  342. //
  343. // Fill in the internal-format structure.
  344. //
  345. newBootEntry->AllocationEnd = (PUCHAR)newBootEntry + requiredLength;
  346. newBootEntry->Status = OldBootEntry->Status & MBE_STATUS_IS_NT;
  347. newBootEntry->Attributes = OldBootEntry->Attributes;
  348. newBootEntry->Id = OldBootEntry->Id;
  349. newBootEntry->FriendlyName = friendlyName;
  350. newBootEntry->FriendlyNameLength = friendlyNameLength;
  351. newBootEntry->BootFilePath = bootPath;
  352. if ( MBE_IS_NT( OldBootEntry ) ) {
  353. newBootEntry->OsLoadOptions = osOptions->OsLoadOptions;
  354. newBootEntry->OsLoadOptionsLength = osLoadOptionsLength;
  355. newBootEntry->OsFilePath = osLoadPath;
  356. }
  357. //
  358. // Fill in the base part of the NT boot entry.
  359. //
  360. ntBootEntry->Version = BOOT_ENTRY_VERSION;
  361. ntBootEntry->Length = requiredLength - FIELD_OFFSET(MY_BOOT_ENTRY, NtBootEntry);
  362. ntBootEntry->Attributes = OldBootEntry->Attributes;
  363. ntBootEntry->Id = OldBootEntry->Id;
  364. ntBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)friendlyName - (PUCHAR)ntBootEntry);
  365. ntBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)bootPath - (PUCHAR)ntBootEntry);
  366. ntBootEntry->OsOptionsLength = osOptionsLength;
  367. if ( MBE_IS_NT( OldBootEntry ) ) {
  368. //
  369. // Fill in the base part of the WINDOWS_OS_OPTIONS, including the
  370. // OsLoadOptions.
  371. //
  372. strcpy((char *)osOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  373. osOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  374. osOptions->Length = osOptionsLength;
  375. osOptions->OsLoadPathOffset = (ULONG)((PUCHAR)osLoadPath - (PUCHAR)osOptions);
  376. wcscpy(osOptions->OsLoadOptions, OldBootEntry->OsLoadOptions);
  377. //
  378. // Copy the OS FILE_PATH.
  379. //
  380. memcpy( osLoadPath, OldBootEntry->OsFilePath, osLoadPathLength );
  381. } else {
  382. //
  383. // Copy the foreign OS options.
  384. //
  385. memcpy( osOptions, OldBootEntry->ForeignOsOptions, osOptionsLength );
  386. }
  387. //
  388. // Copy the friendly name.
  389. //
  390. wcscpy(friendlyName, OldBootEntry->FriendlyName);
  391. //
  392. // Copy the boot FILE_PATH.
  393. //
  394. memcpy( bootPath, OldBootEntry->BootFilePath, bootPathLength );
  395. return newBootEntry;
  396. } // CreateBootEntryFromBootEntry
  397. VOID
  398. FreeBootEntry (
  399. IN PMY_BOOT_ENTRY BootEntry
  400. )
  401. {
  402. FREE_IF_SEPARATE_ALLOCATION( BootEntry, FriendlyName );
  403. FREE_IF_SEPARATE_ALLOCATION( BootEntry, OsLoadOptions );
  404. FREE_IF_SEPARATE_ALLOCATION( BootEntry, BootFilePath );
  405. FREE_IF_SEPARATE_ALLOCATION( BootEntry, OsFilePath );
  406. MemFree( BootEntry );
  407. return;
  408. } // FreeBootEntry
  409. VOID
  410. InitializeEfi (
  411. VOID
  412. )
  413. {
  414. DWORD error;
  415. NTSTATUS status;
  416. BOOLEAN wasEnabled;
  417. HMODULE h;
  418. WCHAR dllName[MAX_PATH];
  419. ULONG length;
  420. HKEY key;
  421. DWORD type;
  422. PBOOT_ENTRY_LIST ntBootEntries;
  423. ULONG i;
  424. PLIST_ENTRY listEntry;
  425. PMY_BOOT_ENTRY bootEntry;
  426. //
  427. // Enable the privilege that is necessary to query/set NVRAM.
  428. //
  429. status = RtlAdjustPrivilege(
  430. SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  431. TRUE,
  432. FALSE,
  433. &wasEnabled
  434. );
  435. if ( !NT_SUCCESS(status) ) {
  436. error = RtlNtStatusToDosError( status );
  437. FatalError( error, L"Insufficient privilege.\n" );
  438. }
  439. //
  440. // Get the NT name of the system partition from the registry.
  441. //
  442. error = RegOpenKey( HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), &key );
  443. if ( error != ERROR_SUCCESS ) {
  444. FatalError( error, L"Unable to read SystemPartition registry value: %d\n", error );
  445. }
  446. error = RegQueryValueEx( key, TEXT("SystemPartition"), NULL, &type, NULL, &length );
  447. if ( error != ERROR_SUCCESS ) {
  448. FatalError( error, L"Unable to read SystemPartition registry value: %d\n", error );
  449. }
  450. if ( type != REG_SZ ) {
  451. FatalError(
  452. ERROR_INVALID_PARAMETER,
  453. L"Unable to read SystemPartition registry value: wrong type\n"
  454. );
  455. }
  456. SystemPartitionNtName = MemAlloc( length );
  457. error = RegQueryValueEx(
  458. key,
  459. TEXT("SystemPartition"),
  460. NULL,
  461. &type,
  462. (PBYTE)SystemPartitionNtName,
  463. &length
  464. );
  465. if ( error != ERROR_SUCCESS ) {
  466. FatalError( error, L"Unable to read SystemPartition registry value: %d\n", error );
  467. }
  468. RegCloseKey( key );
  469. //
  470. // Load ntdll.dll from the system directory.
  471. //
  472. GetSystemDirectory( dllName, MAX_PATH );
  473. ConcatenatePaths( dllName, TEXT("ntdll.dll"), MAX_PATH );
  474. h = LoadLibrary( dllName );
  475. if ( h == NULL ) {
  476. error = GetLastError();
  477. FatalError( error, L"Can't load NTDLL.DLL: %d\n", error );
  478. }
  479. //
  480. // Get the addresses of the NVRAM APIs that we need to use. If any of
  481. // these APIs are not available, this must be a pre-EFI NVRAM build.
  482. //
  483. (FARPROC)AddBootEntry = GetProcAddress( h, "NtAddBootEntry" );
  484. (FARPROC)DeleteBootEntry = GetProcAddress( h, "NtDeleteBootEntry" );
  485. (FARPROC)ModifyBootEntry = GetProcAddress( h, "NtModifyBootEntry" );
  486. (FARPROC)EnumerateBootEntries = GetProcAddress( h, "NtEnumerateBootEntries" );
  487. (FARPROC)QueryBootEntryOrder = GetProcAddress( h, "NtQueryBootEntryOrder" );
  488. (FARPROC)SetBootEntryOrder = GetProcAddress( h, "NtSetBootEntryOrder" );
  489. (FARPROC)QueryBootOptions = GetProcAddress( h, "NtQueryBootOptions" );
  490. (FARPROC)SetBootOptions = GetProcAddress( h, "NtSetBootOptions" );
  491. (FARPROC)TranslateFilePath = GetProcAddress( h, "NtTranslateFilePath" );
  492. if ( (AddBootEntry == NULL) ||
  493. (DeleteBootEntry == NULL) ||
  494. (ModifyBootEntry == NULL) ||
  495. (EnumerateBootEntries == NULL) ||
  496. (QueryBootEntryOrder == NULL) ||
  497. (SetBootEntryOrder == NULL) ||
  498. (QueryBootOptions == NULL) ||
  499. (SetBootOptions == NULL) ||
  500. (TranslateFilePath == NULL) ) {
  501. FatalError( ERROR_OLD_WIN_VERSION, L"This build does not support EFI NVRAM\n" );
  502. }
  503. //
  504. // Get the global system boot options. If the call fails with
  505. // STATUS_NOT_IMPLEMENTED, this is not an EFI machine.
  506. //
  507. length = 0;
  508. status = QueryBootOptions( NULL, &length );
  509. if ( status == STATUS_NOT_IMPLEMENTED ) {
  510. FatalError( ERROR_OLD_WIN_VERSION, L"This build does not support EFI NVRAM\n" );
  511. }
  512. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  513. error = RtlNtStatusToDosError( status );
  514. FatalError( error, L"Unexpected error from NtQueryBootOptions: 0x%x\n", status );
  515. }
  516. BootOptions = MemAlloc( length );
  517. OriginalBootOptions = MemAlloc( length );
  518. status = QueryBootOptions( BootOptions, &length );
  519. if ( status != STATUS_SUCCESS ) {
  520. error = RtlNtStatusToDosError( status );
  521. FatalError( error, L"Unexpected error from NtQueryBootOptions: 0x%x\n", status );
  522. }
  523. memcpy( OriginalBootOptions, BootOptions, length );
  524. BootOptionsLength = length;
  525. OriginalBootOptionsLength = length;
  526. //
  527. // Get the system boot order list.
  528. //
  529. length = 0;
  530. status = QueryBootEntryOrder( NULL, &length );
  531. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  532. if ( status == STATUS_SUCCESS ) {
  533. length = 0;
  534. } else {
  535. error = RtlNtStatusToDosError( status );
  536. FatalError( error, L"Unexpected error from NtQueryBootEntryOrder: 0x%x\n", status );
  537. }
  538. }
  539. if ( length != 0 ) {
  540. BootEntryOrder = MemAlloc( length * sizeof(ULONG) );
  541. OriginalBootEntryOrder = MemAlloc( length * sizeof(ULONG) );
  542. status = QueryBootEntryOrder( BootEntryOrder, &length );
  543. if ( status != STATUS_SUCCESS ) {
  544. error = RtlNtStatusToDosError( status );
  545. FatalError( error, L"Unexpected error from NtQueryBootEntryOrder: 0x%x\n", status );
  546. }
  547. memcpy( OriginalBootEntryOrder, BootEntryOrder, length * sizeof(ULONG) );
  548. }
  549. BootEntryOrderCount = length;
  550. OriginalBootEntryOrderCount = length;
  551. //
  552. // Get all existing boot entries.
  553. //
  554. length = 0;
  555. status = EnumerateBootEntries( NULL, &length );
  556. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  557. if ( status == STATUS_SUCCESS ) {
  558. length = 0;
  559. } else {
  560. error = RtlNtStatusToDosError( status );
  561. FatalError( error, L"Unexpected error from NtEnumerateBootEntries: 0x%x\n", status );
  562. }
  563. }
  564. InitializeListHead( &BootEntries );
  565. InitializeListHead( &DeletedBootEntries );
  566. InitializeListHead( &ActiveUnorderedBootEntries );
  567. InitializeListHead( &InactiveUnorderedBootEntries );
  568. if ( length != 0 ) {
  569. ntBootEntries = MemAlloc( length );
  570. status = EnumerateBootEntries( ntBootEntries, &length );
  571. if ( status != STATUS_SUCCESS ) {
  572. error = RtlNtStatusToDosError( status );
  573. FatalError( error, L"Unexpected error from NtEnumerateBootEntries: 0x%x\n", status );
  574. }
  575. //
  576. // Convert the boot entries into an internal representation.
  577. //
  578. ConvertBootEntries( ntBootEntries );
  579. //
  580. // Free the enumeration buffer.
  581. //
  582. MemFree( ntBootEntries );
  583. }
  584. //
  585. // Build the ordered boot entry list.
  586. //
  587. for ( i = 0; i < BootEntryOrderCount; i++ ) {
  588. ULONG id = BootEntryOrder[i];
  589. for ( listEntry = ActiveUnorderedBootEntries.Flink;
  590. listEntry != &ActiveUnorderedBootEntries;
  591. listEntry = listEntry->Flink ) {
  592. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  593. if ( bootEntry->Id == id ) {
  594. listEntry = listEntry->Blink;
  595. RemoveEntryList( &bootEntry->ListEntry );
  596. InsertTailList( &BootEntries, &bootEntry->ListEntry );
  597. bootEntry->ListHead = &BootEntries;
  598. }
  599. }
  600. for ( listEntry = InactiveUnorderedBootEntries.Flink;
  601. listEntry != &InactiveUnorderedBootEntries;
  602. listEntry = listEntry->Flink ) {
  603. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  604. if ( bootEntry->Id == id ) {
  605. listEntry = listEntry->Blink;
  606. RemoveEntryList( &bootEntry->ListEntry );
  607. InsertTailList( &BootEntries, &bootEntry->ListEntry );
  608. bootEntry->ListHead = &BootEntries;
  609. }
  610. }
  611. }
  612. return;
  613. } // InitializeEfi
  614. PMY_BOOT_ENTRY
  615. SaveChanges (
  616. PMY_BOOT_ENTRY CurrentBootEntry
  617. )
  618. {
  619. NTSTATUS status;
  620. DWORD error;
  621. PLIST_ENTRY listHeads[4];
  622. PLIST_ENTRY listHead;
  623. PLIST_ENTRY listEntry;
  624. ULONG list;
  625. PMY_BOOT_ENTRY bootEntry;
  626. PMY_BOOT_ENTRY newBootEntry;
  627. PMY_BOOT_ENTRY newCurrentBootEntry;
  628. ULONG count;
  629. SetStatusLine( L"Saving changes..." );
  630. //
  631. // Walk the three lists, updating boot entries in NVRAM.
  632. //
  633. newCurrentBootEntry = CurrentBootEntry;
  634. listHeads[0] = &DeletedBootEntries;
  635. listHeads[1] = &InactiveUnorderedBootEntries;
  636. listHeads[2] = &ActiveUnorderedBootEntries;
  637. listHeads[3] = &BootEntries;
  638. for ( list = 0; list < 4; list++ ) {
  639. listHead = listHeads[list];
  640. for ( listEntry = listHead->Flink; listEntry != listHead; listEntry = listEntry->Flink ) {
  641. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  642. //
  643. // Check first for deleted entries, then for new entries, and
  644. // finally for modified entries.
  645. //
  646. if ( MBE_IS_DELETED( bootEntry ) ) {
  647. //
  648. // If it's also marked as new, it's not in NVRAM, so there's
  649. // nothing to delete.
  650. //
  651. if ( !MBE_IS_NEW( bootEntry ) ) {
  652. status = DeleteBootEntry( bootEntry->Id );
  653. if ( !NT_SUCCESS(status) ) {
  654. if ( status != STATUS_VARIABLE_NOT_FOUND ) {
  655. error = RtlNtStatusToDosError( status );
  656. FatalError( error, L"Unable to delete boot entry: 0x%x\n", status );
  657. }
  658. }
  659. }
  660. //
  661. // Delete this entry from the list and from memory.
  662. //
  663. listEntry = listEntry->Blink;
  664. RemoveEntryList( &bootEntry->ListEntry );
  665. FreeBootEntry( bootEntry );
  666. ASSERT( bootEntry != CurrentBootEntry );
  667. } else if ( MBE_IS_NEW( bootEntry ) ) {
  668. //
  669. // We don't support this yet.
  670. //
  671. FatalError(
  672. ERROR_GEN_FAILURE,
  673. L"How did we end up in SaveChanges with a NEW boot entry?!?\n"
  674. );
  675. } else if ( MBE_IS_MODIFIED( bootEntry ) ) {
  676. //
  677. // Create a new boot entry structure using the existing one.
  678. // This is necessary to make an NT BOOT_ENTRY that can be
  679. // passed to NtModifyBootEntry.
  680. //
  681. newBootEntry = CreateBootEntryFromBootEntry( bootEntry );
  682. status = ModifyBootEntry( &newBootEntry->NtBootEntry );
  683. if ( !NT_SUCCESS(status) ) {
  684. error = RtlNtStatusToDosError( status );
  685. FatalError( error, L"Unable to modify boot entry: 0x%x\n", status );
  686. }
  687. //
  688. // Insert the new boot entry in place of the existing one.
  689. // Free the old one.
  690. //
  691. InsertHeadList( &bootEntry->ListEntry, &newBootEntry->ListEntry );
  692. RemoveEntryList( &bootEntry->ListEntry );
  693. FreeBootEntry( bootEntry );
  694. if ( bootEntry == CurrentBootEntry ) {
  695. newCurrentBootEntry = newBootEntry;
  696. }
  697. }
  698. }
  699. }
  700. //
  701. // Build and write the new boot entry order list.
  702. //
  703. listHead = &BootEntries;
  704. count = 0;
  705. for ( listEntry = listHead->Flink; listEntry != listHead; listEntry = listEntry->Flink ) {
  706. count++;
  707. }
  708. MemFree( BootEntryOrder );
  709. BootEntryOrder = MemAlloc( count * sizeof(ULONG) );
  710. count = 0;
  711. for ( listEntry = listHead->Flink; listEntry != listHead; listEntry = listEntry->Flink ) {
  712. bootEntry = CONTAINING_RECORD( listEntry, MY_BOOT_ENTRY, ListEntry );
  713. BootEntryOrder[count++] = bootEntry->Id;
  714. }
  715. status = SetBootEntryOrder( BootEntryOrder, count );
  716. if ( !NT_SUCCESS(status) ) {
  717. error = RtlNtStatusToDosError( status );
  718. FatalError( error, L"Unable to set boot entry order: 0x%x\n", status );
  719. }
  720. MemFree( OriginalBootEntryOrder );
  721. OriginalBootEntryOrder = MemAlloc( count * sizeof(ULONG) );
  722. memcpy( OriginalBootEntryOrder, BootEntryOrder, count * sizeof(ULONG) );
  723. //
  724. // Write the new timeout.
  725. //
  726. status = SetBootOptions( BootOptions, BOOT_OPTIONS_FIELD_TIMEOUT );
  727. if ( !NT_SUCCESS(status) ) {
  728. error = RtlNtStatusToDosError( status );
  729. FatalError( error, L"Unable to set boot options: 0x%x\n", status );
  730. }
  731. MemFree( OriginalBootOptions );
  732. OriginalBootOptions = MemAlloc( BootOptionsLength );
  733. memcpy( OriginalBootOptions, BootOptions, BootOptionsLength );
  734. OriginalBootOptionsLength = BootOptionsLength;
  735. return newCurrentBootEntry;
  736. } // SaveChanges
  737. PWSTR
  738. GetNtNameForFilePath (
  739. IN PFILE_PATH FilePath
  740. )
  741. {
  742. NTSTATUS status;
  743. ULONG length;
  744. PFILE_PATH ntPath;
  745. PWSTR osDeviceNtName;
  746. PWSTR osDirectoryNtName;
  747. PWSTR fullNtName;
  748. length = 0;
  749. status = TranslateFilePath(
  750. FilePath,
  751. FILE_PATH_TYPE_NT,
  752. NULL,
  753. &length
  754. );
  755. if ( status != STATUS_BUFFER_TOO_SMALL ) {
  756. return NULL;
  757. }
  758. ntPath = MemAlloc( length );
  759. status = TranslateFilePath(
  760. FilePath,
  761. FILE_PATH_TYPE_NT,
  762. ntPath,
  763. &length
  764. );
  765. if ( !NT_SUCCESS(status) ) {
  766. MemFree( ntPath );
  767. return NULL;
  768. }
  769. osDeviceNtName = (PWSTR)ntPath->FilePath;
  770. osDirectoryNtName = osDeviceNtName + wcslen(osDeviceNtName) + 1;
  771. length = (ULONG)(wcslen(osDeviceNtName) + wcslen(osDirectoryNtName) + 1) * sizeof(WCHAR);
  772. fullNtName = MemAlloc( length );
  773. wcscpy( fullNtName, osDeviceNtName );
  774. wcscat( fullNtName, osDirectoryNtName );
  775. MemFree( ntPath );
  776. return fullNtName;
  777. } // GetNtNameForFilePath