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.

1044 lines
34 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 <efidrvent.h>
  15. #include <ntosp.h>
  16. #include <efi.h>
  17. #include <stdio.h>
  18. //
  19. // global variables
  20. //
  21. BOOLEAN PriviledgeSet = FALSE;
  22. //
  23. // Helper functions
  24. //
  25. static
  26. BOOLEAN
  27. EFIGetHardDrivePath(
  28. IN PFILE_PATH SrcFilePath,
  29. OUT PFILE_PATH NewFilePath
  30. );
  31. //
  32. // EFI_OS_BOOT_ENTRY Methods
  33. //
  34. static
  35. VOID
  36. EFIOSBEInit(
  37. IN PEFI_OS_BOOT_ENTRY This
  38. )
  39. {
  40. This->OsBootEntry.Delete = EFIOSBEDelete;
  41. This->OsBootEntry.Flush = EFIOSBEFlush;
  42. }
  43. static
  44. POS_BOOT_ENTRY
  45. EFIOSBECreate(
  46. IN PBOOT_ENTRY NtBootEntry,
  47. IN POS_BOOT_OPTIONS Container
  48. )
  49. {
  50. PEFI_OS_BOOT_ENTRY Entry = NULL;
  51. if (NtBootEntry && Container) {
  52. Entry = SBE_MALLOC(sizeof(EFI_OS_BOOT_ENTRY));
  53. if (Entry) {
  54. PWSTR TempUniStr;
  55. NTSTATUS Status = STATUS_SUCCESS;
  56. ULONG Size;
  57. PFILE_PATH FilePath;
  58. memset(Entry, 0, sizeof(EFI_OS_BOOT_ENTRY));
  59. EFIOSBEInit(Entry);
  60. Entry->OsBootEntry.Id = NtBootEntry->Id;
  61. Entry->OsBootEntry.BootOptions = Container;
  62. //
  63. // If this is a Windows boot options set the windows attribute
  64. //
  65. if ( IS_BOOT_ENTRY_WINDOWS(NtBootEntry) ) {
  66. OSBE_SET_WINDOWS(Entry);
  67. }
  68. //
  69. // Get the friendly name
  70. //
  71. TempUniStr = ADD_OFFSET(NtBootEntry, FriendlyNameOffset);
  72. OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, TempUniStr);
  73. //
  74. // Get the loader path
  75. //
  76. FilePath = ADD_OFFSET(NtBootEntry, BootFilePathOffset);
  77. if (FilePath->Type != FILE_PATH_TYPE_NT) {
  78. PFILE_PATH NewPath;
  79. Size = sizeof(FILE_PATH) + FilePath->Length;
  80. NewPath = SBE_MALLOC(Size);
  81. if (NewPath) {
  82. memset(NewPath, 0, Size);
  83. if (EFIGetHardDrivePath(FilePath, NewPath)) {
  84. FilePath = NewPath;
  85. Size = 0;
  86. Status = NtTranslateFilePath(FilePath,
  87. FILE_PATH_TYPE_NT,
  88. NULL,
  89. &Size);
  90. if (Size != 0) {
  91. PFILE_PATH NtFilePath = SBE_MALLOC(Size);
  92. if (NtFilePath) {
  93. Status = NtTranslateFilePath(FilePath,
  94. FILE_PATH_TYPE_NT,
  95. NtFilePath,
  96. &Size);
  97. if (NT_SUCCESS(Status)) {
  98. PWSTR VolumeName = (PWSTR)(NtFilePath->FilePath);
  99. OSBESetOsLoaderVolumeName((POS_BOOT_ENTRY)Entry,
  100. VolumeName);
  101. OSBESetOsLoaderPath((POS_BOOT_ENTRY)Entry,
  102. VolumeName + wcslen(VolumeName) + 1);
  103. }
  104. SBE_FREE(NtFilePath);
  105. } else {
  106. Status = STATUS_NO_MEMORY;
  107. }
  108. }
  109. }
  110. SBE_FREE(NewPath);
  111. }
  112. //
  113. // Its possible for some reason we didn't get NT path
  114. // for loader volume, for e.g. it may not be present at all
  115. // So ignore such cases
  116. //
  117. Status = STATUS_SUCCESS;
  118. } else {
  119. PWSTR VolumeName = (PWSTR)(FilePath->FilePath);
  120. OSBESetOsLoaderVolumeName((POS_BOOT_ENTRY)Entry,
  121. VolumeName);
  122. OSBESetOsLoaderPath((POS_BOOT_ENTRY)Entry,
  123. VolumeName + wcslen(VolumeName) + 1);
  124. }
  125. if (NT_SUCCESS(Status)) {
  126. PWINDOWS_OS_OPTIONS OsOptions;
  127. //
  128. // Get the OsLoadOptions & Boot path if its windows
  129. // entry
  130. //
  131. OsOptions = (PWINDOWS_OS_OPTIONS)NtBootEntry->OsOptions;
  132. if (IS_BOOT_ENTRY_WINDOWS(NtBootEntry)) {
  133. OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry,
  134. OsOptions->OsLoadOptions);
  135. FilePath = ADD_OFFSET(OsOptions, OsLoadPathOffset);
  136. if (FilePath->Type != FILE_PATH_TYPE_NT) {
  137. PFILE_PATH NewPath;
  138. Size = sizeof(FILE_PATH) + FilePath->Length;
  139. NewPath = SBE_MALLOC(Size);
  140. if (NewPath) {
  141. memset(NewPath, 0, Size);
  142. if (EFIGetHardDrivePath(FilePath, NewPath)) {
  143. FilePath = NewPath;
  144. Size = 0;
  145. Status = NtTranslateFilePath(FilePath,
  146. FILE_PATH_TYPE_NT,
  147. NULL,
  148. &Size);
  149. if (Size != 0) {
  150. PFILE_PATH NtFilePath = SBE_MALLOC(Size);
  151. if (NtFilePath) {
  152. Status = NtTranslateFilePath(FilePath,
  153. FILE_PATH_TYPE_NT,
  154. NtFilePath,
  155. &Size);
  156. if (NT_SUCCESS(Status)) {
  157. PWSTR VolumeName = (PWSTR)(NtFilePath->FilePath);
  158. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry,
  159. VolumeName);
  160. OSBESetBootPath((POS_BOOT_ENTRY)Entry,
  161. VolumeName + wcslen(VolumeName) + 1);
  162. }
  163. SBE_FREE(NtFilePath);
  164. } else {
  165. Status = STATUS_NO_MEMORY;
  166. }
  167. }
  168. }
  169. SBE_FREE(NewPath);
  170. }
  171. //
  172. // Its possible for some reason we didn't get NT path
  173. // for Boot volume, for e.g. it may not be present at all
  174. // So ignore such cases
  175. //
  176. Status = STATUS_SUCCESS;
  177. } else {
  178. PWSTR VolumeName = (PWSTR)(FilePath->FilePath);
  179. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry,
  180. VolumeName);
  181. OSBESetBootPath((POS_BOOT_ENTRY)Entry,
  182. VolumeName + wcslen(VolumeName) + 1);
  183. }
  184. }
  185. }
  186. if (!NT_SUCCESS(Status)) {
  187. SBE_FREE(Entry);
  188. Entry = NULL;
  189. }
  190. }
  191. }
  192. return (POS_BOOT_ENTRY)Entry;
  193. }
  194. static
  195. BOOLEAN
  196. EFIOSBEFillNtBootEntry(
  197. IN PEFI_OS_BOOT_ENTRY Entry
  198. )
  199. {
  200. BOOLEAN Result = FALSE;
  201. if (Entry) {
  202. ULONG RequiredLength;
  203. ULONG OsOptionsOffset;
  204. ULONG OsOptionsLength;
  205. ULONG FriendlyNameOffset;
  206. ULONG BootPathOffset;
  207. ULONG BootPathLength;
  208. ULONG LoaderPathOffset;
  209. ULONG LoaderPathLength;
  210. ULONG WinOsOptionsLength;
  211. POS_BOOT_ENTRY BaseEntry = (POS_BOOT_ENTRY)Entry;
  212. if (Entry->NtBootEntry) {
  213. SBE_FREE(Entry->NtBootEntry);
  214. }
  215. RequiredLength = FIELD_OFFSET(BOOT_ENTRY, OsOptions);
  216. //
  217. // TDB : What about non windows OS options ?
  218. //
  219. OsOptionsOffset = RequiredLength;
  220. RequiredLength += FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions);
  221. RequiredLength += (wcslen(OSBEGetOsLoadOptions(BaseEntry)) + 1) * sizeof(WCHAR);
  222. //
  223. // for boot path as part of windows OS options
  224. //
  225. RequiredLength = BootPathOffset = ALIGN_UP(RequiredLength, ULONG);
  226. RequiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  227. RequiredLength += (wcslen(OSBEGetBootVolumeName(BaseEntry)) + 1) * sizeof(WCHAR);
  228. RequiredLength += (wcslen(OSBEGetBootPath(BaseEntry)) + 1) * sizeof(WCHAR);
  229. BootPathLength = (RequiredLength - BootPathOffset);
  230. OsOptionsLength = (RequiredLength - OsOptionsOffset);
  231. //
  232. // for friendly name
  233. //
  234. RequiredLength = FriendlyNameOffset = ALIGN_UP(RequiredLength, ULONG);
  235. RequiredLength += (wcslen(OSBEGetFriendlyName(BaseEntry)) + 1) * sizeof(WCHAR);
  236. //
  237. // for loader path
  238. //
  239. RequiredLength = LoaderPathOffset = ALIGN_UP(RequiredLength, ULONG);
  240. RequiredLength += FIELD_OFFSET(FILE_PATH, FilePath);
  241. RequiredLength += (wcslen(OSBEGetOsLoaderVolumeName(BaseEntry)) + 1) * sizeof(WCHAR);
  242. RequiredLength += (wcslen(OSBEGetOsLoaderPath(BaseEntry)) + 1) * sizeof(WCHAR);
  243. LoaderPathLength = (RequiredLength - LoaderPathOffset);
  244. Entry->NtBootEntry = (PBOOT_ENTRY)SBE_MALLOC(RequiredLength);
  245. if (Entry->NtBootEntry) {
  246. PBOOT_ENTRY NtBootEntry = Entry->NtBootEntry;
  247. PFILE_PATH BootPath = ADD_BYTE_OFFSET(NtBootEntry, BootPathOffset);
  248. PFILE_PATH LoaderPath = ADD_BYTE_OFFSET(NtBootEntry, LoaderPathOffset);
  249. PWSTR FriendlyName = (PWSTR)(ADD_BYTE_OFFSET(NtBootEntry, FriendlyNameOffset));
  250. PWINDOWS_OS_OPTIONS WindowsOptions = ADD_BYTE_OFFSET(NtBootEntry, OsOptionsOffset);
  251. PWSTR TempStr;
  252. memset(NtBootEntry, 0, RequiredLength);
  253. //
  254. // Fill the base part
  255. //
  256. NtBootEntry->Version = BOOT_ENTRY_VERSION;
  257. NtBootEntry->Length = RequiredLength;
  258. NtBootEntry->Id = OSBEGetId(BaseEntry);
  259. NtBootEntry->Attributes = BOOT_ENTRY_ATTRIBUTE_ACTIVE | BOOT_ENTRY_ATTRIBUTE_WINDOWS;
  260. NtBootEntry->OsOptionsLength = OsOptionsLength;
  261. NtBootEntry->FriendlyNameOffset = (ULONG)((PUCHAR)FriendlyName - (PUCHAR)NtBootEntry);
  262. NtBootEntry->BootFilePathOffset = (ULONG)((PUCHAR)LoaderPath - (PUCHAR)NtBootEntry);
  263. //
  264. // Fill in the windows os options
  265. //
  266. strcpy(WindowsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  267. WindowsOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  268. WindowsOptions->Length = OsOptionsLength;
  269. WindowsOptions->OsLoadPathOffset = (ULONG)((PUCHAR)BootPath - (PUCHAR)WindowsOptions);
  270. wcscpy(WindowsOptions->OsLoadOptions, OSBEGetOsLoadOptions(BaseEntry));
  271. //
  272. // Fill in the Boot path FILE_PATH
  273. //
  274. BootPath->Version = FILE_PATH_VERSION;
  275. BootPath->Length = BootPathLength;
  276. BootPath->Type = FILE_PATH_TYPE_NT;
  277. TempStr = (PWSTR)(BootPath->FilePath);
  278. wcscpy(TempStr, OSBEGetBootVolumeName(BaseEntry));
  279. TempStr += wcslen(TempStr) + 1;
  280. wcscpy(TempStr, OSBEGetBootPath(BaseEntry));
  281. //
  282. // Fill the friendly name
  283. //
  284. wcscpy(FriendlyName, OSBEGetFriendlyName(BaseEntry));
  285. //
  286. // Fill in the loader path FILE_PATH
  287. //
  288. LoaderPath->Version = FILE_PATH_VERSION;
  289. LoaderPath->Length = LoaderPathLength;
  290. LoaderPath->Type = FILE_PATH_TYPE_NT;
  291. TempStr = (PWSTR)(LoaderPath->FilePath);
  292. wcscpy(TempStr, OSBEGetOsLoaderVolumeName(BaseEntry));
  293. TempStr += wcslen(TempStr) + 1;
  294. wcscpy(TempStr, OSBEGetOsLoaderPath(BaseEntry));
  295. Result = TRUE;
  296. }
  297. }
  298. return Result;
  299. }
  300. static
  301. VOID
  302. EFIOSBEDelete(
  303. IN POS_BOOT_ENTRY Obj
  304. )
  305. {
  306. PEFI_OS_BOOT_ENTRY This = (PEFI_OS_BOOT_ENTRY)Obj;
  307. if (This) {
  308. if (This->NtBootEntry) {
  309. SBE_FREE(This->NtBootEntry);
  310. }
  311. SBE_FREE(This);
  312. }
  313. }
  314. static
  315. BOOLEAN
  316. EFIOSBEFlush(
  317. IN POS_BOOT_ENTRY Obj
  318. )
  319. {
  320. BOOLEAN Result = FALSE;
  321. PEFI_OS_BOOT_ENTRY This = (PEFI_OS_BOOT_ENTRY)Obj;
  322. if (This) {
  323. NTSTATUS Status = STATUS_SUCCESS;
  324. if (OSBE_IS_DIRTY(This)) {
  325. if (OSBE_IS_DELETED(This)) {
  326. //
  327. // Delete this entry
  328. //
  329. Status = NtDeleteBootEntry(This->OsBootEntry.Id);
  330. } else if (OSBE_IS_NEW(This)) {
  331. //
  332. // Add this as new boot entry
  333. //
  334. Status = EFIOSBEFillNtBootEntry(This);
  335. if (NT_SUCCESS(Status)) {
  336. Status = NtAddBootEntry(This->NtBootEntry,
  337. &(This->OsBootEntry.Id));
  338. }
  339. } else {
  340. //
  341. // Just change this boot entry
  342. //
  343. Status = EFIOSBEFillNtBootEntry(This);
  344. if (NT_SUCCESS(Status)) {
  345. Status = NtModifyBootEntry(This->NtBootEntry);
  346. }
  347. }
  348. if (NT_SUCCESS(Status)) {
  349. OSBE_RESET_DIRTY(This);
  350. Result = TRUE;
  351. }
  352. } else {
  353. Result = TRUE; // nothing to flush
  354. }
  355. }
  356. return Result;
  357. }
  358. //
  359. // EFI_OS_BOOT_OPTIONS Methods
  360. //
  361. static
  362. VOID
  363. EFIOSBOInit(
  364. IN PEFI_OS_BOOT_OPTIONS This
  365. )
  366. {
  367. This->OsBootOptions.Delete = EFIOSBODelete;
  368. This->OsBootOptions.Flush = EFIOSBOFlush;
  369. This->OsBootOptions.AddNewBootEntry = EFIOSBOAddNewBootEntry;
  370. This->OsBootOptions.DeleteBootEntry = OSBODeleteBootEntry;
  371. This->OsBootOptions.AddNewDriverEntry = EFIDEAddNewDriverEntry;
  372. This->OsBootOptions.DeleteDriverEntry = OSBODeleteDriverEntry;
  373. }
  374. POS_BOOT_OPTIONS
  375. EFIOSBOCreate(
  376. VOID
  377. )
  378. {
  379. PEFI_OS_BOOT_OPTIONS This = NULL;
  380. BOOLEAN WasEnabled = FALSE;
  381. if (PriviledgeSet ||
  382. NT_SUCCESS(RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
  383. TRUE,
  384. FALSE,
  385. &WasEnabled))) {
  386. PriviledgeSet = TRUE;
  387. This = SBE_MALLOC(sizeof(EFI_OS_BOOT_OPTIONS));
  388. }
  389. if (This) {
  390. NTSTATUS Status;
  391. ULONG Length = 0;
  392. memset(This, 0, sizeof(EFI_OS_BOOT_OPTIONS));
  393. EFIOSBOInit(This);
  394. //
  395. // Get hold of NT boot entries
  396. //
  397. Status = NtQueryBootOptions(NULL, &Length);
  398. if (Length) {
  399. This->NtBootOptions = SBE_MALLOC(Length);
  400. if (This->NtBootOptions) {
  401. Status = NtQueryBootOptions(This->NtBootOptions,
  402. &Length);
  403. if (NT_SUCCESS(Status)) {
  404. //
  405. // save off the timeout period
  406. //
  407. This->OsBootOptions.Timeout = This->NtBootOptions->Timeout;
  408. //
  409. // enumerate all the boot entries
  410. //
  411. Length = 0;
  412. Status = NtEnumerateBootEntries(NULL, &Length);
  413. if (Length) {
  414. This->NtBootEntries = SBE_MALLOC(Length);
  415. if (This->NtBootEntries) {
  416. Status = NtEnumerateBootEntries(This->NtBootEntries,
  417. &Length);
  418. } else {
  419. Status = STATUS_NO_MEMORY;
  420. }
  421. }
  422. }
  423. } else {
  424. Status = STATUS_NO_MEMORY;
  425. }
  426. }
  427. //
  428. // Convert the NT boot entries to our representation
  429. //
  430. if (NT_SUCCESS(Status) && (This->NtBootEntries)) {
  431. PBOOT_ENTRY_LIST ListEntry = This->NtBootEntries;
  432. PBOOT_ENTRY CurrentNtEntry = &(ListEntry->BootEntry);
  433. PEFI_OS_BOOT_ENTRY CurrentOsEntry = NULL;
  434. PEFI_OS_BOOT_ENTRY LastEntry = NULL;
  435. while (CurrentNtEntry) {
  436. //
  437. // Create the OS entry
  438. //
  439. CurrentOsEntry = (PEFI_OS_BOOT_ENTRY)EFIOSBECreate(CurrentNtEntry,
  440. (POS_BOOT_OPTIONS)This);
  441. if (!CurrentOsEntry) {
  442. Status = STATUS_NO_MEMORY;
  443. break;
  444. }
  445. //
  446. // found one more valid entry
  447. //
  448. This->OsBootOptions.EntryCount++;
  449. CurrentOsEntry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
  450. //
  451. // If this is the first entry then setup the linked list head
  452. //
  453. if (!This->OsBootOptions.BootEntries) {
  454. This->OsBootOptions.BootEntries = (POS_BOOT_ENTRY)(CurrentOsEntry);
  455. }
  456. if (LastEntry) {
  457. LastEntry->OsBootEntry.NextEntry = (POS_BOOT_ENTRY)CurrentOsEntry;
  458. }
  459. LastEntry = CurrentOsEntry;
  460. //
  461. // process the next entry, if available
  462. //
  463. if (ListEntry->NextEntryOffset) {
  464. ListEntry = ADD_OFFSET(ListEntry, NextEntryOffset);
  465. CurrentNtEntry = &(ListEntry->BootEntry);
  466. } else {
  467. CurrentNtEntry = NULL;
  468. }
  469. }
  470. }
  471. //
  472. // Now query the boot order
  473. //
  474. if (NT_SUCCESS(Status)) {
  475. Length = 0;
  476. Status = NtQueryBootEntryOrder(NULL,
  477. &Length);
  478. if (Length) {
  479. PULONG BootOrder = SBE_MALLOC(Length * sizeof(ULONG));
  480. if (BootOrder) {
  481. memset(BootOrder, 0, Length);
  482. This->OsBootOptions.BootOrder = BootOrder;
  483. This->OsBootOptions.BootOrderCount = Length;
  484. Status = NtQueryBootEntryOrder(BootOrder,
  485. &Length);
  486. } else {
  487. Status = STATUS_NO_MEMORY;
  488. }
  489. }
  490. }
  491. //
  492. // Now setup the valid entries
  493. //
  494. if (NT_SUCCESS(Status)) {
  495. ULONG FirstEntryId = OSBOGetBootEntryIdByOrder((POS_BOOT_OPTIONS)This,
  496. 0);
  497. if (FirstEntryId != (-1)) {
  498. This->OsBootOptions.CurrentEntry =
  499. OSBOFindBootEntry((POS_BOOT_OPTIONS)This,
  500. FirstEntryId);
  501. } else {
  502. This->OsBootOptions.CurrentEntry = NULL;
  503. }
  504. }
  505. //
  506. // Enumerate the driver entries
  507. //
  508. if (NT_SUCCESS(Status)){
  509. Status = NtEnumerateDriverEntries(NULL, &Length);
  510. if (!NT_SUCCESS(Status) && (STATUS_BUFFER_TOO_SMALL==Status)){
  511. PEFI_DRIVER_ENTRY_LIST Entry;
  512. PEFI_DRIVER_ENTRY_LIST DriverList = (PEFI_DRIVER_ENTRY_LIST) SBE_MALLOC(Length);
  513. if (DriverList){
  514. Status = NtEnumerateDriverEntries(DriverList, &Length);
  515. if (NT_SUCCESS(Status)){
  516. This->DriverEntries = DriverList;
  517. //
  518. // Convert driver enties to our internal format.
  519. //
  520. Status = EFIDEInterpretDriverEntries((POS_BOOT_OPTIONS)This,
  521. DriverList);
  522. }
  523. } else {
  524. Status = STATUS_NO_MEMORY;
  525. }
  526. }
  527. }
  528. //
  529. // Now query the driver entry order
  530. //
  531. if (NT_SUCCESS(Status)) {
  532. Length = 0;
  533. Status = NtQueryDriverEntryOrder(NULL,
  534. &Length);
  535. if (Length) {
  536. PULONG DriverEntryOrder = SBE_MALLOC(Length * sizeof(ULONG));
  537. if (DriverEntryOrder) {
  538. memset(DriverEntryOrder, 0, Length);
  539. This->OsBootOptions.DriverEntryOrder = DriverEntryOrder;
  540. This->OsBootOptions.DriverEntryOrderCount = Length;
  541. Status = NtQueryDriverEntryOrder(DriverEntryOrder,
  542. &Length);
  543. } else {
  544. Status = STATUS_NO_MEMORY;
  545. }
  546. }
  547. }
  548. if (!NT_SUCCESS(Status)) {
  549. EFIOSBODelete((POS_BOOT_OPTIONS)This);
  550. This = NULL;
  551. }
  552. }
  553. return (POS_BOOT_OPTIONS)This;
  554. }
  555. static
  556. VOID
  557. EFIOSBODelete(
  558. IN POS_BOOT_OPTIONS Obj
  559. )
  560. {
  561. PEFI_OS_BOOT_OPTIONS This = (PEFI_OS_BOOT_OPTIONS)Obj;
  562. if (This) {
  563. ULONG Index = 0;
  564. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj, &Index);
  565. POS_BOOT_ENTRY NextEntry;
  566. PDRIVER_ENTRY DriverEntries = OSBOGetFirstDriverEntry(Obj);
  567. PDRIVER_ENTRY NextDrvEntry;
  568. //
  569. // delete each boot entry
  570. //
  571. while (Entry) {
  572. NextEntry = Entry->NextEntry;
  573. OSBEDelete(Entry);
  574. Entry = NextEntry;
  575. }
  576. //
  577. // delete boot entry order.
  578. //
  579. if (This->OsBootOptions.BootOrder){
  580. SBE_FREE(This->OsBootOptions.BootOrder);
  581. }
  582. //
  583. // Delete all the driver entries
  584. //
  585. while (DriverEntries){
  586. NextDrvEntry = DriverEntries->NextEntry;
  587. SBE_FREE(DriverEntries);
  588. DriverEntries = NextDrvEntry;
  589. }
  590. //
  591. // delete driver entry order.
  592. //
  593. if (This->OsBootOptions.DriverEntryOrder){
  594. SBE_FREE(This->OsBootOptions.DriverEntryOrder);
  595. }
  596. //
  597. // delete the options
  598. //
  599. if (This->NtBootOptions){
  600. SBE_FREE(This->NtBootOptions);
  601. }
  602. SBE_FREE(This);
  603. }
  604. }
  605. static
  606. POS_BOOT_ENTRY
  607. EFIOSBOAddNewBootEntry(
  608. IN POS_BOOT_OPTIONS This,
  609. IN PCWSTR FriendlyName,
  610. IN PCWSTR OsLoaderVolumeName,
  611. IN PCWSTR OsLoaderPath,
  612. IN PCWSTR BootVolumeName,
  613. IN PCWSTR BootPath,
  614. IN PCWSTR OsLoadOptions
  615. )
  616. {
  617. PEFI_OS_BOOT_ENTRY Entry = NULL;
  618. if (This && FriendlyName && OsLoaderVolumeName && OsLoaderPath &&
  619. BootVolumeName && BootPath) {
  620. Entry = SBE_MALLOC(sizeof(EFI_OS_BOOT_ENTRY));
  621. if (Entry) {
  622. memset(Entry, 0, sizeof(EFI_OS_BOOT_ENTRY));
  623. //
  624. // init core fields
  625. //
  626. EFIOSBEInit(Entry);
  627. Entry->OsBootEntry.BootOptions = This;
  628. //
  629. // fill in the attributes
  630. //
  631. OSBESetFriendlyName((POS_BOOT_ENTRY)Entry, FriendlyName);
  632. OSBESetOsLoaderVolumeName((POS_BOOT_ENTRY)Entry, OsLoaderVolumeName);
  633. OSBESetOsLoaderPath((POS_BOOT_ENTRY)Entry, OsLoaderPath);
  634. OSBESetBootVolumeName((POS_BOOT_ENTRY)Entry, BootVolumeName);
  635. OSBESetBootPath((POS_BOOT_ENTRY)Entry, BootPath);
  636. if (OsLoadOptions) {
  637. OSBESetOsLoadOptions((POS_BOOT_ENTRY)Entry, OsLoadOptions);
  638. }
  639. //
  640. // Set the attribute specifying that this is a Windows option
  641. //
  642. OSBE_SET_WINDOWS(Entry);
  643. //
  644. // mark it dirty and new for flushing
  645. //
  646. OSBE_SET_NEW(Entry);
  647. OSBE_SET_DIRTY(Entry);
  648. //
  649. // Flush the entry now to get a proper Id;
  650. //
  651. if (!OSBEFlush((POS_BOOT_ENTRY)Entry)) {
  652. SBE_FREE(Entry);
  653. Entry = NULL;
  654. } else {
  655. ULONG OrderCount;
  656. PULONG NewOrder;
  657. Entry->OsBootEntry.BootOptions = (POS_BOOT_OPTIONS)This;
  658. Entry->OsBootEntry.NextEntry = This->BootEntries;
  659. This->BootEntries = (POS_BOOT_ENTRY)Entry;
  660. This->EntryCount++;
  661. //
  662. // Put the new entry at the end of the boot order
  663. //
  664. OrderCount = OSBOGetOrderedBootEntryCount(This);
  665. NewOrder = (PULONG)SBE_MALLOC((OrderCount + 1) * sizeof(ULONG));
  666. if (NewOrder) {
  667. memset(NewOrder, 0, sizeof(ULONG) * (OrderCount + 1));
  668. //
  669. // copy over the old ordered list
  670. //
  671. memcpy(NewOrder, This->BootOrder, sizeof(ULONG) * OrderCount);
  672. NewOrder[OrderCount] = OSBEGetId((POS_BOOT_ENTRY)Entry);
  673. SBE_FREE(This->BootOrder);
  674. This->BootOrder = NewOrder;
  675. This->BootOrderCount = OrderCount + 1;
  676. } else {
  677. SBE_FREE(Entry);
  678. Entry = NULL;
  679. }
  680. }
  681. }
  682. }
  683. return (POS_BOOT_ENTRY)Entry;
  684. }
  685. static
  686. BOOLEAN
  687. EFIOSBOFlush(
  688. IN POS_BOOT_OPTIONS Obj
  689. )
  690. {
  691. BOOLEAN Result = FALSE;
  692. PEFI_OS_BOOT_OPTIONS This = (PEFI_OS_BOOT_OPTIONS)Obj;
  693. if (This) {
  694. ULONG Index;
  695. ULONG FieldsToChange = BOOT_OPTIONS_FIELD_COUNTDOWN |
  696. BOOT_OPTIONS_FIELD_NEXT_BOOT_ENTRY_ID;
  697. ULONG OrderCount;
  698. POS_BOOT_ENTRY Entry = OSBOGetFirstBootEntry(Obj, &Index);
  699. //
  700. // First update the required entries
  701. //
  702. Result = TRUE;
  703. while (Entry) {
  704. if (!OSBE_IS_DELETED(Entry) && !OSBE_IS_NEW(Entry) &&
  705. !NT_SUCCESS(EFIOSBEFlush(Entry))) {
  706. Result = FALSE;
  707. }
  708. Entry = OSBOGetNextBootEntry(Obj, &Index);
  709. }
  710. if (Result) {
  711. Entry = OSBOGetFirstBootEntry(Obj, &Index);
  712. //
  713. // Next delete the required entries
  714. //
  715. Result = TRUE;
  716. while (Entry) {
  717. if (OSBE_IS_DELETED(Entry) && !NT_SUCCESS(EFIOSBEFlush(Entry))) {
  718. Result = FALSE;
  719. }
  720. Entry = OSBOGetNextBootEntry(Obj, &Index);
  721. }
  722. }
  723. if (Result) {
  724. POS_BOOT_ENTRY TmpEntry = OSBOGetFirstBootEntry(Obj, &Index);
  725. //
  726. // Now create the required entries
  727. //
  728. while (TmpEntry) {
  729. if (OSBE_IS_NEW(TmpEntry) && !NT_SUCCESS(EFIOSBEFlush(TmpEntry))) {
  730. Result = FALSE;
  731. }
  732. TmpEntry = OSBOGetNextBootEntry(Obj, &Index);
  733. }
  734. }
  735. //
  736. // Safety check
  737. //
  738. OrderCount = min(Obj->BootOrderCount, Obj->EntryCount);
  739. //
  740. // Write the boot entry order
  741. //
  742. if (!NT_SUCCESS(NtSetBootEntryOrder(Obj->BootOrder,
  743. OrderCount))) {
  744. Result = FALSE;
  745. }
  746. //
  747. // Write the other boot options
  748. //
  749. This->NtBootOptions->Timeout = Obj->Timeout;
  750. //
  751. // Make sure NextBootEntry points to the active boot entry
  752. // so that we can boot the active boot entry
  753. //
  754. if (Obj->BootOrderCount) {
  755. This->NtBootOptions->NextBootEntryId = Obj->BootOrder[0];
  756. }
  757. if (!NT_SUCCESS(NtSetBootOptions(This->NtBootOptions,
  758. FieldsToChange))) {
  759. Result = FALSE;
  760. }
  761. //
  762. // Logic for drivers here so that they get flushed like boot entries.
  763. //
  764. //
  765. // Flush the modified entries.
  766. //
  767. if (Result){
  768. PDRIVER_ENTRY DriverListEntry = NULL;
  769. DriverListEntry = Obj->DriverEntries;
  770. while (DriverListEntry){
  771. if (!DRIVERENT_IS_DELETED(DriverListEntry) &&
  772. !DRIVERENT_IS_NEW(DriverListEntry) &&
  773. !NT_SUCCESS(OSDriverEntryFlush(DriverListEntry))){
  774. Result = FALSE;
  775. }
  776. DriverListEntry = OSBOGetNextDriverEntry(Obj, DriverListEntry);
  777. }
  778. }
  779. //
  780. // Process Deleted driver entries.
  781. //
  782. if (Result){
  783. PDRIVER_ENTRY DriverListEntry = NULL;
  784. DriverListEntry = Obj->DriverEntries;
  785. while (DriverListEntry){
  786. if (DRIVERENT_IS_DELETED(DriverListEntry) &&
  787. !NT_SUCCESS(OSDriverEntryFlush(DriverListEntry))){
  788. Result = FALSE;
  789. }
  790. DriverListEntry = OSBOGetNextDriverEntry(Obj, DriverListEntry);
  791. }
  792. }
  793. //
  794. // Process new added driver entries.
  795. //
  796. if (Result){
  797. PDRIVER_ENTRY DriverListEntry = NULL;
  798. DriverListEntry = Obj->DriverEntries;
  799. while (DriverListEntry){
  800. if (DRIVERENT_IS_NEW(DriverListEntry) &&
  801. !NT_SUCCESS(OSDriverEntryFlush(DriverListEntry))){
  802. Result = FALSE;
  803. }
  804. DriverListEntry = OSBOGetNextDriverEntry(Obj, DriverListEntry);
  805. }
  806. }
  807. //
  808. // Safety check
  809. //
  810. OrderCount = min(Obj->DriverEntryOrderCount, Obj->DriverEntryCount);
  811. //
  812. // Write the driver entry order
  813. //
  814. if (!NT_SUCCESS(NtSetDriverEntryOrder(Obj->DriverEntryOrder,
  815. OrderCount))) {
  816. Result = FALSE;
  817. }
  818. }
  819. return Result;
  820. }
  821. static
  822. BOOLEAN
  823. EFIGetHardDrivePath(
  824. IN PFILE_PATH SrcFilePath,
  825. OUT PFILE_PATH NewFilePath
  826. )
  827. {
  828. BOOLEAN Result = FALSE;
  829. if (SrcFilePath && NewFilePath) {
  830. EFI_DEVICE_PATH UNALIGNED *Node = (EFI_DEVICE_PATH UNALIGNED *)SrcFilePath->FilePath;
  831. while (FALSE == IsDevicePathEndType(Node)) {
  832. if ((DevicePathType(Node) == MEDIA_DEVICE_PATH) &&
  833. (DevicePathSubType(Node) == MEDIA_HARDDRIVE_DP)) {
  834. ULONG LengthToDelete = (ULONG)((PUCHAR)Node - (PUCHAR)SrcFilePath->FilePath);
  835. NewFilePath->Version = SrcFilePath->Version;
  836. NewFilePath->Length = SrcFilePath->Length - LengthToDelete;
  837. NewFilePath->Type = SrcFilePath->Type;
  838. memcpy(NewFilePath->FilePath, Node,
  839. NewFilePath->Length);
  840. Result = TRUE;
  841. break;
  842. }
  843. Node = NextDevicePathNode(Node);
  844. }
  845. }
  846. return Result;
  847. }