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.

815 lines
25 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. efisbent.c
  5. Abstract:
  6. Contains the EFI OS boot entry and boot options
  7. abstraction implementation.
  8. Author:
  9. Vijay Jayaseelan (vijayj@microsoft.com) 14 Feb 2001
  10. Revision History:
  11. None.
  12. --*/
  13. #include <efisbent.h>
  14. #include <ntosp.h>
  15. #include <stdio.h>
  16. //
  17. // global variables
  18. //
  19. BOOLEAN PriviledgeSet = FALSE;
  20. //
  21. // EFI_OS_BOOT_ENTRY Methods
  22. //
  23. static
  24. VOID
  25. EFIOSBEInit(
  26. IN PEFI_OS_BOOT_ENTRY This
  27. )
  28. {
  29. This->OsBootEntry.Delete = EFIOSBEDelete;
  30. This->OsBootEntry.Flush = EFIOSBEFlush;
  31. }
  32. static
  33. POS_BOOT_ENTRY
  34. EFIOSBECreate(
  35. IN PBOOT_ENTRY NtBootEntry,
  36. IN POS_BOOT_OPTIONS Container
  37. )
  38. {
  39. PEFI_OS_BOOT_ENTRY Entry = NULL;
  40. if (NtBootEntry && Container) {
  41. Entry = SBE_MALLOC(sizeof(EFI_OS_BOOT_ENTRY));
  42. if (Entry) {
  43. PWSTR TempUniStr;
  44. NTSTATUS Status = STATUS_SUCCESS;
  45. ULONG Size;
  46. PFILE_PATH FilePath;
  47. memset(Entry, 0, sizeof(EFI_OS_BOOT_ENTRY));
  48. EFIOSBEInit(Entry);
  49. Entry->OsBootEntry.Id = NtBootEntry->Id;
  50. Entry->OsBootEntry.BootOptions = Container;
  51. //
  52. // If this is a Windows boot options set the windows attribute
  53. //
  54. if ( IS_BOOT_ENTRY_WINDOWS(NtBootEntry) ) {
  55. OSBE_SET_WINDOWS(Entry);
  56. }
  57. //
  58. // Get the friendly name
  59. //
  60. TempUniStr = ADD_OFFSET(NtBootEntry, FriendlyNameOffset);
  61. OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, TempUniStr);
  62. //
  63. // Get the loader path
  64. //
  65. FilePath = ADD_OFFSET(NtBootEntry, BootFilePathOffset);
  66. if (FilePath->Type != FILE_PATH_TYPE_NT) {
  67. Size = 0;
  68. Status = NtTranslateFilePath(FilePath,
  69. FILE_PATH_TYPE_NT,
  70. NULL,
  71. &Size);
  72. if (Size != 0) {
  73. PFILE_PATH NtFilePath = SBE_MALLOC(Size);
  74. if (NtFilePath) {
  75. Status = NtTranslateFilePath(FilePath,
  76. FILE_PATH_TYPE_NT,
  77. NtFilePath,
  78. &Size);
  79. if (NT_SUCCESS(Status)) {
  80. PWSTR VolumeName = (PWSTR)(NtFilePath->FilePath);
  81. OSBESetOsLoaderVolumeName((POS_BOOT_ENTRY)Entry,
  82. VolumeName);
  83. OSBESetOsLoaderPath((POS_BOOT_ENTRY)Entry,
  84. VolumeName + wcslen(VolumeName) + 1);
  85. }
  86. SBE_FREE(NtFilePath);
  87. } else {
  88. Status = STATUS_NO_MEMORY;
  89. }
  90. }
  91. //
  92. // Its possible for some reason we didn't get NT path
  93. // for loader volume, for e.g. it may not be present at all
  94. // So ignore such cases
  95. //
  96. Status = STATUS_SUCCESS;
  97. } else {
  98. PWSTR VolumeName = (PWSTR)(FilePath->FilePath);
  99. OSBESetOsLoaderVolumeName((POS_BOOT_ENTRY)Entry,
  100. VolumeName);
  101. OSBESetOsLoaderPath((POS_BOOT_ENTRY)Entry,
  102. VolumeName + wcslen(VolumeName) + 1);
  103. }
  104. if (NT_SUCCESS(Status)) {
  105. PWINDOWS_OS_OPTIONS OsOptions;
  106. //
  107. // Get the OsLoadOptions & Boot path if its windows
  108. // entry
  109. //
  110. OsOptions = (PWINDOWS_OS_OPTIONS)NtBootEntry->OsOptions;
  111. if (IS_BOOT_ENTRY_WINDOWS(NtBootEntry)) {
  112. OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry,
  113. OsOptions->OsLoadOptions);
  114. FilePath = ADD_OFFSET(OsOptions, OsLoadPathOffset);
  115. if (FilePath->Type != FILE_PATH_TYPE_NT) {
  116. Size = 0;
  117. Status = NtTranslateFilePath(FilePath,
  118. FILE_PATH_TYPE_NT,
  119. NULL,
  120. &Size);
  121. if (Size != 0) {
  122. PFILE_PATH NtFilePath = SBE_MALLOC(Size);
  123. if (NtFilePath) {
  124. Status = NtTranslateFilePath(FilePath,
  125. FILE_PATH_TYPE_NT,
  126. NtFilePath,
  127. &Size);
  128. if (NT_SUCCESS(Status)) {
  129. PWSTR VolumeName = (PWSTR)(NtFilePath->FilePath);
  130. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry,
  131. VolumeName);
  132. OSBESetBootPath((POS_BOOT_ENTRY)Entry,
  133. VolumeName + wcslen(VolumeName) + 1);
  134. }
  135. SBE_FREE(NtFilePath);
  136. } else {
  137. Status = STATUS_NO_MEMORY;
  138. }
  139. }
  140. //
  141. // Its possible for some reason we didn't get NT path
  142. // for Boot volume, for e.g. it may not be present at all
  143. // So ignore such cases
  144. //
  145. Status = STATUS_SUCCESS;
  146. } else {
  147. PWSTR VolumeName = (PWSTR)(FilePath->FilePath);
  148. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry,
  149. VolumeName);
  150. OSBESetBootPath((POS_BOOT_ENTRY)Entry,
  151. VolumeName + wcslen(VolumeName) + 1);
  152. }
  153. }
  154. }
  155. if (!NT_SUCCESS(Status)) {
  156. SBE_FREE(Entry);
  157. Entry = NULL;
  158. }
  159. }
  160. }
  161. return (POS_BOOT_ENTRY)Entry;
  162. }
  163. static
  164. BOOLEAN
  165. EFIOSBEFillNtBootEntry(
  166. IN PEFI_OS_BOOT_ENTRY Entry
  167. )
  168. {
  169. BOOLEAN Result = FALSE;
  170. if (Entry) {
  171. ULONG RequiredLength;
  172. ULONG OsOptionsOffset;
  173. ULONG OsOptionsLength;
  174. ULONG FriendlyNameOffset;
  175. ULONG BootPathOffset;
  176. ULONG BootPathLength;
  177. ULONG LoaderPathOffset;
  178. ULONG LoaderPathLength;
  179. ULONG WinOsOptionsLength;
  180. POS_BOOT_ENTRY BaseEntry = (POS_BOOT_ENTRY)Entry;
  181. if (Entry->NtBootEntry) {
  182. SBE_FREE(Entry->NtBootEntry);
  183. }
  184. RequiredLength = FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  185. //
  186. // TDB : What about non windows OS options ?
  187. //
  188. OsOptionsOffset = RequiredLength;
  189. RequiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  190. RequiredLength += (wcslen(OSBEGetOsLoadOptions(BaseEntry)) + 1) * sizeof(WCHAR);
  191. //
  192. // for boot path as part of windows OS options
  193. //
  194. RequiredLength = BootPathOffset = ALIGN_UP(RequiredLength, ULONG);
  195. RequiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  196. RequiredLength += (wcslen(OSBEGetBootVolumeName(BaseEntry)) + 1) * sizeof(WCHAR);
  197. RequiredLength += (wcslen(OSBEGetBootPath(BaseEntry)) + 1) * sizeof(WCHAR);
  198. BootPathLength = (RequiredLength - BootPathOffset);
  199. OsOptionsLength = (RequiredLength - OsOptionsOffset);
  200. //
  201. // for friendly name
  202. //
  203. RequiredLength = FriendlyNameOffset = ALIGN_UP(RequiredLength, ULONG);
  204. RequiredLength += (wcslen(OSBEGetFriendlyName(BaseEntry)) + 1) * sizeof(WCHAR);
  205. //
  206. // for loader path
  207. //
  208. RequiredLength = LoaderPathOffset = ALIGN_UP(RequiredLength, ULONG);
  209. RequiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  210. RequiredLength += (wcslen(OSBEGetOsLoaderVolumeName(BaseEntry)) + 1) * sizeof(WCHAR);
  211. RequiredLength += (wcslen(OSBEGetOsLoaderPath(BaseEntry)) + 1) * sizeof(WCHAR);
  212. LoaderPathLength = (RequiredLength - LoaderPathOffset);
  213. Entry->NtBootEntry = (PBOOT_ENTRY)SBE_MALLOC(RequiredLength);
  214. if (Entry->NtBootEntry) {
  215. PBOOT_ENTRY NtBootEntry = Entry->NtBootEntry;
  216. PFILE_PATH BootPath = ADD_BYTE_OFFSET(NtBootEntry, BootPathOffset);
  217. PFILE_PATH LoaderPath = ADD_BYTE_OFFSET(NtBootEntry, LoaderPathOffset);
  218. PWSTR FriendlyName = (PWSTR)(ADD_BYTE_OFFSET(NtBootEntry, FriendlyNameOffset));
  219. PWINDOWS_OS_OPTIONS WindowsOptions = ADD_BYTE_OFFSET(NtBootEntry, OsOptionsOffset);
  220. PWSTR TempStr;
  221. memset(NtBootEntry, 0, RequiredLength);
  222. //
  223. // Fill the base part
  224. //
  225. NtBootEntry->Version = BOOT_ENTRY_VERSION;
  226. NtBootEntry->Length = RequiredLength;
  227. NtBootEntry->Id = OSBEGetId(BaseEntry);
  228. NtBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE | BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  229. NtBootEntry->OsOptionsLength = OsOptionsLength;
  230. NtBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)FriendlyName - (PUCHAR)NtBootEntry);
  231. NtBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)LoaderPath - (PUCHAR)NtBootEntry);
  232. //
  233. // Fill in the windows os options
  234. //
  235. strcpy(WindowsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  236. WindowsOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  237. WindowsOptions->Length = OsOptionsLength;
  238. WindowsOptions->OsLoadPathOffset = (ULONG)((PUCHAR)BootPath - (PUCHAR)WindowsOptions);
  239. wcscpy(WindowsOptions->OsLoadOptions, OSBEGetOsLoadOptions(BaseEntry));
  240. //
  241. // Fill in the Boot path FILE_PATH
  242. //
  243. BootPath->Version = FILE_PATH_VERSION;
  244. BootPath->Length = BootPathLength;
  245. BootPath->Type = FILE_PATH_TYPE_NT;
  246. TempStr = (PWSTR)(BootPath->FilePath);
  247. wcscpy(TempStr, OSBEGetBootVolumeName(BaseEntry));
  248. TempStr += wcslen(TempStr) + 1;
  249. wcscpy(TempStr, OSBEGetBootPath(BaseEntry));
  250. //
  251. // Fill the friendly name
  252. //
  253. wcscpy(FriendlyName, OSBEGetFriendlyName(BaseEntry));
  254. //
  255. // Fill in the loader path FILE_PATH
  256. //
  257. LoaderPath->Version = FILE_PATH_VERSION;
  258. LoaderPath->Length = LoaderPathLength;
  259. LoaderPath->Type = FILE_PATH_TYPE_NT;
  260. TempStr = (PWSTR)(LoaderPath->FilePath);
  261. wcscpy(TempStr, OSBEGetOsLoaderVolumeName(BaseEntry));
  262. TempStr += wcslen(TempStr) + 1;
  263. wcscpy(TempStr, OSBEGetOsLoaderPath(BaseEntry));
  264. Result = TRUE;
  265. }
  266. }
  267. return Result;
  268. }
  269. static
  270. VOID
  271. EFIOSBEDelete(
  272. IN POS_BOOT_ENTRY Obj
  273. )
  274. {
  275. PEFI_OS_BOOT_ENTRY This = (PEFI_OS_BOOT_ENTRY)Obj;
  276. if (This) {
  277. if (This->NtBootEntry) {
  278. SBE_FREE(This->NtBootEntry);
  279. }
  280. SBE_FREE(This);
  281. }
  282. }
  283. static
  284. BOOLEAN
  285. EFIOSBEFlush(
  286. IN POS_BOOT_ENTRY Obj
  287. )
  288. {
  289. BOOLEAN Result = FALSE;
  290. PEFI_OS_BOOT_ENTRY This = (PEFI_OS_BOOT_ENTRY)Obj;
  291. if (This) {
  292. NTSTATUS Status = STATUS_SUCCESS;
  293. if (OSBE_IS_DIRTY(This)) {
  294. if (OSBE_IS_DELETED(This)) {
  295. //
  296. // Delete this entry
  297. //
  298. Status = NtDeleteBootEntry(This->OsBootEntry.Id);
  299. } else if (OSBE_IS_NEW(This)) {
  300. //
  301. // Add this as new boot entry
  302. //
  303. Status = EFIOSBEFillNtBootEntry(This);
  304. if (NT_SUCCESS(Status)) {
  305. Status = NtAddBootEntry(This->NtBootEntry,
  306. &(This->OsBootEntry.Id));
  307. }
  308. } else {
  309. //
  310. // Just change this boot entry
  311. //
  312. Status = EFIOSBEFillNtBootEntry(This);
  313. if (NT_SUCCESS(Status)) {
  314. Status = NtModifyBootEntry(This->NtBootEntry);
  315. }
  316. }
  317. if (NT_SUCCESS(Status)) {
  318. OSBE_RESET_DIRTY(This);
  319. Result = TRUE;
  320. }
  321. } else {
  322. Result = TRUE; // nothing to flush
  323. }
  324. }
  325. return Result;
  326. }
  327. //
  328. // EFI_OS_BOOT_OPTIONS Methods
  329. //
  330. static
  331. VOID
  332. EFIOSBOInit(
  333. IN PEFI_OS_BOOT_OPTIONS This
  334. )
  335. {
  336. This->OsBootOptions.Delete = EFIOSBODelete;
  337. This->OsBootOptions.Flush = EFIOSBOFlush;
  338. This->OsBootOptions.AddNewBootEntry = EFIOSBOAddNewBootEntry;
  339. This->OsBootOptions.DeleteBootEntry = OSBODeleteBootEntry;
  340. }
  341. POS_BOOT_OPTIONS
  342. EFIOSBOCreate(
  343. VOID
  344. )
  345. {
  346. PEFI_OS_BOOT_OPTIONS This = NULL;
  347. BOOLEAN WasEnabled = FALSE;
  348. if (PriviledgeSet ||
  349. NT_SUCCESS(RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  350. TRUE,
  351. FALSE,
  352. &WasEnabled))) {
  353. PriviledgeSet = TRUE;
  354. This = SBE_MALLOC(sizeof(EFI_OS_BOOT_OPTIONS));
  355. }
  356. if (This) {
  357. NTSTATUS Status;
  358. ULONG Length = 0;
  359. memset(This, 0, sizeof(EFI_OS_BOOT_OPTIONS));
  360. EFIOSBOInit(This);
  361. //
  362. // Get hold of NT boot entries
  363. //
  364. Status = NtQueryBootOptions(NULL, &Length);
  365. if (Length) {
  366. This->NtBootOptions = SBE_MALLOC(Length);
  367. if (This->NtBootOptions) {
  368. Status = NtQueryBootOptions(This->NtBootOptions,
  369. &Length);
  370. if (NT_SUCCESS(Status)) {
  371. //
  372. // save off the timeout period
  373. //
  374. This->OsBootOptions.Timeout = This->NtBootOptions->Timeout;
  375. //
  376. // enumerate all the boot entries
  377. //
  378. Length = 0;
  379. Status = NtEnumerateBootEntries(NULL, &Length);
  380. if (Length) {
  381. This->NtBootEntries = SBE_MALLOC(Length);
  382. if (This->NtBootEntries) {
  383. Status = NtEnumerateBootEntries(This->NtBootEntries,
  384. &Length);
  385. } else {
  386. Status = STATUS_NO_MEMORY;
  387. }
  388. }
  389. }
  390. } else {
  391. Status = STATUS_NO_MEMORY;
  392. }
  393. }
  394. //
  395. // Convert the NT boot entries to our representation
  396. //
  397. if (NT_SUCCESS(Status) && (This->NtBootEntries)) {
  398. PBOOT_ENTRY_LIST ListEntry = This->NtBootEntries;
  399. PBOOT_ENTRY CurrentNtEntry = &(ListEntry->BootEntry);
  400. PEFI_OS_BOOT_ENTRY CurrentOsEntry = NULL;
  401. PEFI_OS_BOOT_ENTRY LastEntry = NULL;
  402. while (CurrentNtEntry) {
  403. //
  404. // Create the OS entry
  405. //
  406. CurrentOsEntry = (PEFI_OS_BOOT_ENTRY)EFIOSBECreate(CurrentNtEntry,
  407. (POS_BOOT_OPTIONS)This);
  408. if (!CurrentOsEntry) {
  409. Status = STATUS_NO_MEMORY;
  410. break;
  411. }
  412. //
  413. // found one more valid entry
  414. //
  415. This->OsBootOptions.EntryCount++;
  416. CurrentOsEntry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
  417. //
  418. // If this is the first entry then setup the linked list head
  419. //
  420. if (!This->OsBootOptions.BootEntries) {
  421. This->OsBootOptions.BootEntries = (POS_BOOT_ENTRY)(CurrentOsEntry);
  422. }
  423. if (LastEntry) {
  424. LastEntry->OsBootEntry.NextEntry = (POS_BOOT_ENTRY)CurrentOsEntry;
  425. }
  426. LastEntry = CurrentOsEntry;
  427. //
  428. // process the next entry, if available
  429. //
  430. if (ListEntry->NextEntryOffset) {
  431. ListEntry = ADD_OFFSET(ListEntry, NextEntryOffset);
  432. CurrentNtEntry = &(ListEntry->BootEntry);
  433. } else {
  434. CurrentNtEntry = NULL;
  435. }
  436. }
  437. }
  438. //
  439. // Now query the boot order
  440. //
  441. if (NT_SUCCESS(Status)) {
  442. Length = 0;
  443. Status = NtQueryBootEntryOrder(NULL,
  444. &Length);
  445. if (Length) {
  446. PULONG BootOrder = SBE_MALLOC(Length * sizeof(ULONG));
  447. if (BootOrder) {
  448. memset(BootOrder, 0, Length);
  449. This->OsBootOptions.BootOrder = BootOrder;
  450. This->OsBootOptions.BootOrderCount = Length;
  451. Status = NtQueryBootEntryOrder(BootOrder,
  452. &Length);
  453. } else {
  454. Status = STATUS_NO_MEMORY;
  455. }
  456. }
  457. }
  458. //
  459. // Now setup the valid entries
  460. //
  461. if (NT_SUCCESS(Status)) {
  462. ULONG FirstEntryId = OSBOGetBootEntryIdByOrder((POS_BOOT_OPTIONS)This,
  463. 0);
  464. if (FirstEntryId != (-1)) {
  465. This->OsBootOptions.CurrentEntry =
  466. OSBOFindBootEntry((POS_BOOT_OPTIONS)This,
  467. FirstEntryId);
  468. } else {
  469. This->OsBootOptions.CurrentEntry = NULL;
  470. }
  471. }
  472. if (!NT_SUCCESS(Status)) {
  473. EFIOSBODelete((POS_BOOT_OPTIONS)This);
  474. This = NULL;
  475. }
  476. }
  477. return (POS_BOOT_OPTIONS)This;
  478. }
  479. static
  480. VOID
  481. EFIOSBODelete(
  482. IN POS_BOOT_OPTIONS Obj
  483. )
  484. {
  485. PEFI_OS_BOOT_OPTIONS This = (PEFI_OS_BOOT_OPTIONS)Obj;
  486. if (This) {
  487. //
  488. // delete each boot entry
  489. //
  490. ULONG Index = 0;
  491. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj, &Index);
  492. POS_BOOT_ENTRY NextEntry;
  493. while (Entry) {
  494. NextEntry = Entry->NextEntry;
  495. OSBEDelete(Entry);
  496. Entry = NextEntry;
  497. }
  498. //
  499. // delete the options
  500. //
  501. if (This->NtBootOptions)
  502. SBE_FREE(This->NtBootOptions);
  503. SBE_FREE(This);
  504. }
  505. }
  506. static
  507. POS_BOOT_ENTRY
  508. EFIOSBOAddNewBootEntry(
  509. IN POS_BOOT_OPTIONS This,
  510. IN PCWSTR FriendlyName,
  511. IN PCWSTR OsLoaderVolumeName,
  512. IN PCWSTR OsLoaderPath,
  513. IN PCWSTR BootVolumeName,
  514. IN PCWSTR BootPath,
  515. IN PCWSTR OsLoadOptions
  516. )
  517. {
  518. PEFI_OS_BOOT_ENTRY Entry = NULL;
  519. if (This && FriendlyName && OsLoaderVolumeName && OsLoaderPath &&
  520. BootVolumeName && BootPath) {
  521. Entry = SBE_MALLOC(sizeof(EFI_OS_BOOT_ENTRY));
  522. if (Entry) {
  523. memset(Entry, 0, sizeof(EFI_OS_BOOT_ENTRY));
  524. //
  525. // init core fields
  526. //
  527. EFIOSBEInit(Entry);
  528. Entry->OsBootEntry.BootOptions = This;
  529. //
  530. // fill in the attributes
  531. //
  532. OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, FriendlyName);
  533. OSBESetOsLoaderVolumeName((POS_BOOT_ENTRY)Entry, OsLoaderVolumeName);
  534. OSBESetOsLoaderPath((POS_BOOT_ENTRY)Entry, OsLoaderPath);
  535. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry, BootVolumeName);
  536. OSBESetBootPath((POS_BOOT_ENTRY)Entry, BootPath);
  537. if (OsLoadOptions) {
  538. OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry, OsLoadOptions);
  539. }
  540. //
  541. // Set the attribute specifying that this is a Windows option
  542. //
  543. OSBE_SET_WINDOWS(Entry);
  544. //
  545. // mark it dirty and new for flushing
  546. //
  547. OSBE_SET_NEW(Entry);
  548. OSBE_SET_DIRTY(Entry);
  549. //
  550. // Flush the entry now to get a proper Id;
  551. //
  552. if (!OSBEFlush((POS_BOOT_ENTRY)Entry)) {
  553. SBE_FREE(Entry);
  554. Entry = NULL;
  555. } else {
  556. ULONG OrderCount;
  557. PULONG NewOrder;
  558. Entry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
  559. Entry->OsBootEntry.NextEntry = This->BootEntries;
  560. This->BootEntries = (POS_BOOT_ENTRY)Entry;
  561. This->EntryCount++;
  562. //
  563. // Put the new entry at the end of the boot order
  564. //
  565. OrderCount = OSBOGetOrderedBootEntryCount(This);
  566. NewOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
  567. if (NewOrder) {
  568. memset(NewOrder, 0, sizeof(ULONG) * (OrderCount + 1));
  569. //
  570. // copy over the old ordered list
  571. //
  572. memcpy(NewOrder, This->BootOrder, sizeof(ULONG) * OrderCount);
  573. NewOrder[OrderCount] = OSBEGetId((POS_BOOT_ENTRY)Entry);
  574. SBE_FREE(This->BootOrder);
  575. This->BootOrder = NewOrder;
  576. This->BootOrderCount = OrderCount + 1;
  577. } else {
  578. SBE_FREE(Entry);
  579. Entry = NULL;
  580. }
  581. }
  582. }
  583. }
  584. return (POS_BOOT_ENTRY)Entry;
  585. }
  586. static
  587. BOOLEAN
  588. EFIOSBOFlush(
  589. IN POS_BOOT_OPTIONS Obj
  590. )
  591. {
  592. BOOLEAN Result = FALSE;
  593. PEFI_OS_BOOT_OPTIONS This = (PEFI_OS_BOOT_OPTIONS)Obj;
  594. if (This) {
  595. ULONG Index;
  596. ULONG FieldsToChange = BOOT_OPTIONS_FIELD_COUNTDOWN |
  597. BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID;
  598. ULONG OrderCount;
  599. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj, &Index);
  600. //
  601. // First update the required entries
  602. //
  603. Result = TRUE;
  604. while (Entry) {
  605. if (!OSBE_IS_DELETED(Entry) && !OSBE_IS_NEW(Entry) &&
  606. !NT_SUCCESS(EFIOSBEFlush(Entry))) {
  607. Result = FALSE;
  608. }
  609. Entry = OSBOGetNextBootEntry(Obj, &Index);
  610. }
  611. if (Result) {
  612. Entry = OSBOGetFirstBootEntry(Obj, &Index);
  613. //
  614. // Next delete the required entries
  615. //
  616. Result = TRUE;
  617. while (Entry) {
  618. if (OSBE_IS_DELETED(Entry) && !NT_SUCCESS(EFIOSBEFlush(Entry))) {
  619. Result = FALSE;
  620. }
  621. Entry = OSBOGetNextBootEntry(Obj, &Index);
  622. }
  623. }
  624. if (Result) {
  625. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj, &Index);
  626. //
  627. // Now create the required entries
  628. //
  629. while (Entry) {
  630. if (OSBE_IS_NEW(Entry) && !NT_SUCCESS(EFIOSBEFlush(Entry))) {
  631. Result = FALSE;
  632. }
  633. Entry = OSBOGetNextBootEntry(Obj, &Index);
  634. }
  635. }
  636. //
  637. // Safety check
  638. //
  639. OrderCount = min(Obj->BootOrderCount, Obj->EntryCount);
  640. //
  641. // Write the boot entry order
  642. //
  643. if (!NT_SUCCESS(NtSetBootEntryOrder(Obj->BootOrder,
  644. OrderCount))) {
  645. Result = FALSE;
  646. }
  647. //
  648. // Write the other boot options
  649. //
  650. This->NtBootOptions->Timeout = Obj->Timeout;
  651. //
  652. // Make sure NextBootEntry points to the active boot entry
  653. // so that we can boot the active boot entry
  654. //
  655. if (Obj->BootOrderCount) {
  656. This->NtBootOptions->NextBootEntryId = Obj->BootOrder[0];
  657. }
  658. if (!NT_SUCCESS(NtSetBootOptions(This->NtBootOptions,
  659. FieldsToChange))) {
  660. Result = FALSE;
  661. }
  662. }
  663. return Result;
  664. }