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.

1453 lines
33 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. efintldr.c
  5. Abstract:
  6. Revision History:
  7. Jeff Sigman 05/01/00 Created
  8. Jeff Sigman 05/10/00 Version 1.5 released
  9. Jeff Sigman 10/18/00 Fix for Soft81 bug(s)
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Open the IA64LDR.EFI image and load the OS
  14. //
  15. BOOLEAN
  16. LaunchOS(
  17. IN char* String,
  18. IN EFI_HANDLE ImageHandle,
  19. IN EFI_FILE_HANDLE* CurDir,
  20. IN EFI_LOADED_IMAGE* LoadedImage
  21. )
  22. {
  23. CHAR16* uniBuf = NULL;
  24. BOOLEAN bError = TRUE;
  25. EFI_STATUS Status;
  26. EFI_HANDLE exeHdl = NULL;
  27. EFI_INPUT_KEY Key;
  28. EFI_FILE_HANDLE FileHandle = NULL;
  29. EFI_DEVICE_PATH* ldrDevPath = NULL;
  30. do
  31. {
  32. //
  33. // Convert OS path to unicode from ACSII
  34. //
  35. uniBuf = RutlUniStrDup(String);
  36. if (!uniBuf)
  37. {
  38. break;
  39. }
  40. //
  41. // Open the ia64ldr.efi
  42. //
  43. Status = (*CurDir)->Open(
  44. *CurDir,
  45. &FileHandle,
  46. uniBuf,
  47. EFI_FILE_MODE_READ,
  48. 0);
  49. if (EFI_ERROR(Status))
  50. {
  51. break;
  52. }
  53. ldrDevPath = FileDevicePath(LoadedImage->DeviceHandle, uniBuf);
  54. if (!ldrDevPath)
  55. {
  56. break;
  57. }
  58. Status = BS->LoadImage(
  59. FALSE,
  60. ImageHandle,
  61. ldrDevPath,
  62. NULL,
  63. 0,
  64. &exeHdl);
  65. if (EFI_ERROR(Status))
  66. {
  67. break;
  68. }
  69. Print (L"\nAttempting to launch... %s\n", uniBuf);
  70. WaitForSingleEvent(ST->ConIn->WaitForKey, 5000000);
  71. ST->ConIn->ReadKeyStroke(ST->ConIn, &Key);
  72. //
  73. // Clean up
  74. //
  75. ldrDevPath = RutlFree(ldrDevPath);
  76. uniBuf = RutlFree(uniBuf);
  77. String = RutlFree(String);
  78. //
  79. // Disable the cursor
  80. //
  81. ST->ConOut->EnableCursor(ST->ConOut, FALSE);
  82. bError = FALSE;
  83. //
  84. // Start the OS baby!!
  85. //
  86. BS->StartImage(exeHdl, 0, NULL);
  87. //
  88. // If we get here the OS failed to load
  89. //
  90. bError = TRUE;
  91. //
  92. // Re-enable the cursor
  93. //
  94. ST->ConOut->EnableCursor(ST->ConOut, TRUE);
  95. } while (FALSE);
  96. //
  97. // Clean up
  98. //
  99. if (ldrDevPath)
  100. {
  101. ldrDevPath = RutlFree(ldrDevPath);
  102. }
  103. if (uniBuf)
  104. {
  105. uniBuf = RutlFree(uniBuf);
  106. }
  107. if (FileHandle)
  108. {
  109. FileHandle->Close(FileHandle);
  110. }
  111. if (String)
  112. {
  113. String = RutlFree(String);
  114. }
  115. //
  116. // Where the heck is the lib for this?
  117. //
  118. // if (exeHdl)
  119. // UnloadImage(&exeHdl);
  120. return bError;
  121. }
  122. //
  123. // Struct Cleanup
  124. //
  125. BOOLEAN
  126. FreeBootData(
  127. IN VOID* hBootData
  128. )
  129. {
  130. UINTN i;
  131. BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
  132. if (!pBootData)
  133. {
  134. return TRUE;
  135. }
  136. for (i = 0; i < pBootData->dwIndex; i++)
  137. {
  138. pBootData->pszSPart[i] = RutlFree(pBootData->pszSPart[i]);
  139. pBootData->pszOSLdr[i] = RutlFree(pBootData->pszOSLdr[i]);
  140. pBootData->pszLPart[i] = RutlFree(pBootData->pszLPart[i]);
  141. pBootData->pszFileN[i] = RutlFree(pBootData->pszFileN[i]);
  142. pBootData->pszIdent[i] = RutlFree(pBootData->pszIdent[i]);
  143. pBootData->pszShort[i] = RutlFree(pBootData->pszShort[i]);
  144. }
  145. pBootData->pszShort[pBootData->dwIndex] =
  146. RutlFree(pBootData->pszShort[pBootData->dwIndex]);
  147. pBootData->pszIdent[pBootData->dwIndex] =
  148. RutlFree(pBootData->pszIdent[pBootData->dwIndex]);
  149. if (pBootData->pszLoadOpt)
  150. {
  151. pBootData->pszLoadOpt = RutlFree(pBootData->pszLoadOpt);
  152. }
  153. pBootData->dwLastKnown = 0;
  154. pBootData->dwIndex = 0;
  155. pBootData->dwCount = 0;
  156. return FALSE;
  157. }
  158. //
  159. // Sort the load options based placing the passed option first
  160. //
  161. BOOLEAN
  162. SortLoadOptions(
  163. IN VOID* hBootData,
  164. IN char* Buffer,
  165. IN UINTN* dwSize,
  166. IN UINTN* dwOption,
  167. IN UINTN* dwMax,
  168. IN EFI_FILE_HANDLE* FileHandle
  169. )
  170. {
  171. char *FndTok[BOOT_MAX],
  172. *Start = NULL,
  173. *End = NULL,
  174. *NewOpt = NULL,
  175. *Sortme = NULL,
  176. *Token = NULL,
  177. *Last = NULL,
  178. *Find = NULL;
  179. UINTN i = 0,
  180. j = 0,
  181. dwIndex = 0,
  182. dwStLen = 0,
  183. dwOrigLen = 0,
  184. dwLen = 0;
  185. BOOLEAN bError = FALSE;
  186. BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
  187. do
  188. {
  189. //
  190. // Find the BOOT_LDOPT option
  191. //
  192. Start = strstr(Buffer, BOOT_LDOPT);
  193. if (!Start)
  194. {
  195. bError = TRUE;
  196. break;
  197. }
  198. //
  199. // Find the end of the option
  200. //
  201. End = (Start += strlena(BOOT_LDOPT));
  202. while (*(End++) != '\r')
  203. ;
  204. dwOrigLen = (End - Start) - 1;
  205. //
  206. // Create buffer to use for temp sort storage
  207. //
  208. NewOpt = AllocateZeroPool(dwOrigLen + 1);
  209. if (!NewOpt)
  210. {
  211. bError = TRUE;
  212. break;
  213. }
  214. //
  215. // Copy only that option to a new buffer
  216. //
  217. CopyMem(NewOpt, Start, dwOrigLen);
  218. //
  219. // Replace any leading ';' with a nodebug
  220. //
  221. while ((NewOpt[i] == ';') && (i < *dwMax))
  222. {
  223. FndTok[i] = RutlStrDup(BL_DEBUG_NONE);
  224. if (!FndTok[i])
  225. {
  226. bError = TRUE;
  227. break;
  228. }
  229. dwIndex += strlena(FndTok[i++]);
  230. }
  231. //
  232. // Remove tokens
  233. //
  234. Token = strtok(NewOpt, BOOT_TOKEN);
  235. while ((Token != NULL) &&
  236. (Token < (NewOpt + dwOrigLen)) &&
  237. (i < *dwMax)
  238. )
  239. {
  240. if (Find = FindAdvLoadOptions(Token))
  241. {
  242. //
  243. // User has booted using adv options, clearing them out
  244. //
  245. // Add a NULL at the location of the adv opt
  246. //
  247. *Find = '\0';
  248. FndTok[i] = RutlStrDup(Token);
  249. }
  250. else
  251. {
  252. FndTok[i] = RutlStrDup(Token);
  253. if (!FndTok[i])
  254. {
  255. bError = TRUE;
  256. break;
  257. }
  258. }
  259. dwIndex += strlena(FndTok[i++]);
  260. Token = strtok(NULL, BOOT_TOKEN);
  261. }
  262. while (i < *dwMax)
  263. {
  264. FndTok[i] = RutlStrDup(BL_DEBUG_NONE);
  265. if (!FndTok[i])
  266. {
  267. bError = TRUE;
  268. break;
  269. }
  270. dwIndex += strlena(FndTok[i++]);
  271. }
  272. //
  273. // Create buffer to store sorted data
  274. //
  275. Sortme = AllocateZeroPool(dwLen = dwIndex + *dwMax + 1);
  276. if (!Sortme)
  277. {
  278. bError = TRUE;
  279. break;
  280. }
  281. //
  282. // Copy selected option as the first option
  283. //
  284. if (pBootData->pszLoadOpt)
  285. {
  286. //
  287. // if user has selected an adv boot option, it is plum'd here
  288. //
  289. dwStLen = strlena(pBootData->pszLoadOpt) + dwLen + strlena(SPACES);
  290. Sortme = ReallocatePool(Sortme, dwLen, dwStLen);
  291. if (!Sortme)
  292. {
  293. bError = TRUE;
  294. break;
  295. }
  296. //
  297. // they will need to match up later
  298. //
  299. dwLen = dwStLen;
  300. dwIndex = strlena(FndTok[*dwOption]);
  301. CopyMem(Sortme, FndTok[*dwOption], dwIndex);
  302. dwStLen = dwIndex;
  303. dwIndex = strlena(SPACES);
  304. CopyMem(Sortme + dwStLen, SPACES, dwIndex);
  305. dwStLen += dwIndex;
  306. dwIndex = strlena(pBootData->pszLoadOpt);
  307. CopyMem(Sortme + dwStLen, pBootData->pszLoadOpt, dwIndex);
  308. dwStLen += dwIndex;
  309. }
  310. else
  311. {
  312. CopyMem(Sortme, FndTok[*dwOption], strlena(FndTok[*dwOption]));
  313. dwStLen = strlena(FndTok[*dwOption]);
  314. }
  315. //
  316. // Append a seperator
  317. //
  318. *(Sortme + (dwStLen++)) = ';';
  319. //
  320. // Smash the rest of the options back in
  321. //
  322. for (j = 0; j < i; j++)
  323. {
  324. //
  325. // Skip the option that was moved to the front
  326. //
  327. if (j == *dwOption)
  328. {
  329. continue;
  330. }
  331. CopyMem(Sortme + dwStLen, FndTok[j], strlena(FndTok[j]));
  332. dwStLen += strlena(FndTok[j]);
  333. //
  334. // Append a seperator
  335. //
  336. *(Sortme + (dwStLen++)) = ';';
  337. }
  338. dwStLen--;
  339. *(Sortme + dwStLen++) = '\r';
  340. *(Sortme + dwStLen++) = '\n';
  341. if (dwLen != dwStLen)
  342. {
  343. bError = TRUE;
  344. break;
  345. }
  346. //
  347. // Write new sorted load options to file
  348. //
  349. (*FileHandle)->SetPosition(*FileHandle, (Start - Buffer));
  350. (*FileHandle)->Write(*FileHandle, &dwStLen, Sortme);
  351. //
  352. // Write options that following load options back to file
  353. //
  354. (*FileHandle)->SetPosition(*FileHandle, (Start - Buffer) + dwStLen - 1);
  355. dwStLen = *dwSize - (End - Buffer);
  356. (*FileHandle)->Write(*FileHandle, &dwStLen, End);
  357. //
  358. // Set last known good
  359. //
  360. if (Last = strstr(End, BOOT_LASTK))
  361. {
  362. (*FileHandle)->SetPosition(
  363. *FileHandle,
  364. (Start - Buffer) + dwLen + (Last - End) - 1);
  365. if (pBootData->dwLastKnown)
  366. {
  367. dwIndex = strlena(LAST_TRUE);
  368. (*FileHandle)->Write(*FileHandle, &dwIndex, LAST_TRUE);
  369. }
  370. else
  371. {
  372. dwIndex = strlena(LAST_FALSE);
  373. (*FileHandle)->Write(*FileHandle, &dwIndex, LAST_FALSE);
  374. }
  375. }
  376. //
  377. // Subtract the terminators
  378. //
  379. dwLen -= 2;
  380. if (dwOrigLen <= dwLen)
  381. {
  382. break;
  383. }
  384. //
  385. // append semi-colon's at the end of the file if we have left over room
  386. //
  387. // don't reuse 'i', need it below to free
  388. //
  389. for (j = 0; j < (dwOrigLen - dwLen); j++)
  390. {
  391. dwStLen = 1;
  392. (*FileHandle)->Write(*FileHandle, &dwStLen, ";");
  393. }
  394. } while (FALSE);
  395. if (Sortme)
  396. {
  397. Sortme = RutlFree(Sortme);
  398. }
  399. for (j = 0; j < i; j++)
  400. {
  401. FndTok[j] = RutlFree(FndTok[j]);
  402. }
  403. if (NewOpt)
  404. {
  405. NewOpt = RutlFree(NewOpt);
  406. }
  407. return bError;
  408. }
  409. //
  410. // Sort the boot options based placing the passed option first
  411. //
  412. BOOLEAN
  413. SortBootData(
  414. IN char* Option,
  415. IN char* StrArr[],
  416. IN UINTN* dwOption,
  417. IN UINTN* dwMax,
  418. IN char* Buffer
  419. )
  420. {
  421. char *Start = NULL,
  422. *End = NULL,
  423. *NewOpt = NULL;
  424. UINTN i,
  425. dwIndex = 0,
  426. dwLen = 0;
  427. BOOLEAN bError = TRUE;
  428. do
  429. {
  430. //
  431. // Find the option header
  432. //
  433. Start = strstr(Buffer, Option);
  434. if (!Start)
  435. {
  436. break;
  437. }
  438. //
  439. // Find the end of the option
  440. //
  441. End = (Start += strlena(Option));
  442. while (*(End++) != '\n')
  443. ;
  444. dwLen = End - Start;
  445. //
  446. // Create buffer to use for temp sort storage
  447. //
  448. NewOpt = AllocateZeroPool(dwLen);
  449. if (!NewOpt)
  450. {
  451. break;
  452. }
  453. //
  454. // Copy only that option to a new buffer
  455. //
  456. CopyMem(NewOpt, StrArr[*dwOption], strlena(StrArr[*dwOption]));
  457. dwIndex += strlena(StrArr[*dwOption]);
  458. //
  459. // Append a seperator
  460. //
  461. *(NewOpt+(dwIndex++)) = ';';
  462. for (i = 0; i < *dwMax; i++)
  463. {
  464. if (i == *dwOption)
  465. {
  466. continue;
  467. }
  468. CopyMem(NewOpt + dwIndex, StrArr[i], strlena(StrArr[i]));
  469. dwIndex += strlena(StrArr[i]);
  470. *(NewOpt+(dwIndex++)) = ';';
  471. }
  472. while (dwIndex++ < (dwLen - 1))
  473. {
  474. *(NewOpt + (dwIndex - 1)) = ';';
  475. }
  476. *(NewOpt + (dwLen - 2)) = '\r';
  477. *(NewOpt + dwLen - 1) = '\n';
  478. if (dwIndex != dwLen)
  479. {
  480. break;
  481. }
  482. //
  483. // Copy new sorted data in the buffer
  484. //
  485. CopyMem(Start, NewOpt, dwIndex);
  486. bError = FALSE;
  487. } while (FALSE);
  488. if (NewOpt)
  489. {
  490. NewOpt = RutlFree(NewOpt);
  491. }
  492. return bError;
  493. }
  494. //
  495. // Parse options from file data
  496. //
  497. BOOLEAN
  498. OrderBootFile(
  499. IN UINTN dwOption,
  500. IN char* Buffer,
  501. IN VOID* hBootData
  502. )
  503. {
  504. BOOLEAN bError = TRUE;
  505. BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
  506. do
  507. {
  508. //
  509. // Find/sort the BOOT_SPART option
  510. //
  511. if (SortBootData(
  512. BOOT_SPART,
  513. pBootData->pszSPart,
  514. &dwOption,
  515. &(pBootData->dwIndex),
  516. Buffer))
  517. {
  518. Print(L"OrderBootFile() failed for BOOT_SPART option!\n");
  519. break;
  520. }
  521. //
  522. // Find/sort the BOOT_OSLDR option
  523. //
  524. if (SortBootData(
  525. BOOT_OSLDR,
  526. pBootData->pszOSLdr,
  527. &dwOption,
  528. &(pBootData->dwIndex),
  529. Buffer))
  530. {
  531. Print(L"OrderBootFile() failed for BOOT_OSLDR option!\n");
  532. break;
  533. }
  534. //
  535. // Find/sort the BOOT_LPART option
  536. //
  537. if (SortBootData(
  538. BOOT_LPART,
  539. pBootData->pszLPart,
  540. &dwOption,
  541. &(pBootData->dwIndex),
  542. Buffer))
  543. {
  544. Print(L"OrderBootFile() failed for BOOT_LPART option!\n");
  545. break;
  546. }
  547. //
  548. // Find/sort the BOOT_FILEN option
  549. //
  550. if (SortBootData(
  551. BOOT_FILEN,
  552. pBootData->pszFileN,
  553. &dwOption,
  554. &(pBootData->dwIndex),
  555. Buffer))
  556. {
  557. Print(L"OrderBootFile() failed for BOOT_FILEN option!\n");
  558. break;
  559. }
  560. //
  561. // Find/sort the BOOT_IDENT option
  562. //
  563. if (SortBootData(
  564. BOOT_IDENT,
  565. pBootData->pszIdent,
  566. &dwOption,
  567. &(pBootData->dwIndex),
  568. Buffer))
  569. {
  570. Print(L"OrderBootFile() failed for BOOT_IDENT option!\n");
  571. break;
  572. }
  573. bError = FALSE;
  574. } while (FALSE);
  575. return bError;
  576. }
  577. //
  578. // Chop-up name to be short to 'pretty up' the menu
  579. //
  580. BOOLEAN
  581. CreateShortNames(
  582. IN VOID* hBootData
  583. )
  584. {
  585. char *start = NULL,
  586. *end = NULL;
  587. UINTN i,
  588. Len = 0;
  589. BOOLEAN bError = FALSE;
  590. BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
  591. do
  592. {
  593. for (i = 0; i < pBootData->dwIndex; i++)
  594. {
  595. start = strstr(pBootData->pszOSLdr[i], wacks);
  596. end = strstr(pBootData->pszOSLdr[i], EFIEXT);
  597. //
  598. // check for foo case (thx jhavens)
  599. //
  600. if ((end == NULL) ||
  601. (start == NULL)
  602. )
  603. {
  604. start = pBootData->pszOSLdr[i];
  605. end = start;
  606. while (*(end++) != '\0')
  607. ;
  608. Len = end - start;
  609. }
  610. //
  611. // Non-foo case, person has atleast one '\' && '.efi'
  612. //
  613. if (!Len)
  614. {
  615. start += 1;
  616. while (*end != wackc)
  617. {
  618. if (end <= start)
  619. {
  620. start = pBootData->pszOSLdr[i];
  621. end = strstr(pBootData->pszOSLdr[i], wacks);
  622. break;
  623. }
  624. end--;
  625. }
  626. Len = end - start;
  627. }
  628. if ((end == NULL) ||
  629. (start == NULL) ||
  630. (Len < 1)
  631. )
  632. {
  633. bError = TRUE;
  634. break;
  635. }
  636. pBootData->pszShort[i] = AllocateZeroPool(Len + 1);
  637. if (!pBootData->pszShort[i])
  638. {
  639. bError = TRUE;
  640. break;
  641. }
  642. CopyMem(pBootData->pszShort[i], start, end - start);
  643. Len = 0;
  644. start = NULL;
  645. end = NULL;
  646. }
  647. } while (FALSE);
  648. return bError;
  649. }
  650. //
  651. // Find the passed option from the file data
  652. //
  653. BOOLEAN
  654. FindOpt(
  655. IN char* pszOption,
  656. IN char* Buffer,
  657. OUT char* pszArray[],
  658. OUT UINTN* dwCount
  659. )
  660. {
  661. char *Start = NULL,
  662. *End = NULL,
  663. *Option = NULL,
  664. *Token = NULL;
  665. UINTN dwIndex = 0;
  666. BOOLEAN bError = TRUE;
  667. do
  668. {
  669. //
  670. // Find the option
  671. //
  672. Start = strstr(Buffer, pszOption);
  673. if (!Start)
  674. {
  675. break;
  676. }
  677. //
  678. // Find the end of the option
  679. //
  680. Start += strlena(pszOption);
  681. End = Start;
  682. while (*(End++) != '\r')
  683. ;
  684. Option = AllocateZeroPool((End-Start));
  685. if (!Option)
  686. {
  687. break;
  688. }
  689. //
  690. // Copy only that option to a new buffer
  691. //
  692. CopyMem(Option, Start, (End-Start)-1);
  693. *(Option+((End-Start)-1)) = 0x00;
  694. //
  695. // Remove tokens
  696. //
  697. Token = strtok(Option, BOOT_TOKEN);
  698. if (!Token)
  699. {
  700. break;
  701. }
  702. if (!(*dwCount))
  703. {
  704. while ((Token != NULL) &&
  705. (dwIndex < BOOT_MAX)
  706. )
  707. {
  708. pszArray[(dwIndex)++] = RutlStrDup(Token);
  709. Token = strtok(NULL, BOOT_TOKEN);
  710. }
  711. *dwCount = dwIndex;
  712. }
  713. else
  714. {
  715. while ((Token != NULL) &&
  716. (dwIndex < *dwCount)
  717. )
  718. {
  719. pszArray[(dwIndex)++] = RutlStrDup(Token);
  720. Token = strtok(NULL, BOOT_TOKEN);
  721. }
  722. }
  723. if (dwIndex == 0)
  724. {
  725. break;
  726. }
  727. bError = FALSE;
  728. } while (FALSE);
  729. if (Option)
  730. {
  731. Option = RutlFree(Option);
  732. }
  733. return bError;
  734. }
  735. //
  736. // Get the options in their entirety from the file data
  737. //
  738. BOOLEAN
  739. GetBootData(
  740. IN VOID* hBootData,
  741. IN char* Buffer
  742. )
  743. {
  744. UINTN i;
  745. char* TempStr = NULL;
  746. CHAR16* UniStr = NULL;
  747. BOOLEAN bError = TRUE;
  748. BOOT_DATA* pBootData = (BOOT_DATA*) hBootData;
  749. do
  750. {
  751. //
  752. // Find the BOOT_IDENT option
  753. //
  754. if (FindOpt(
  755. BOOT_IDENT,
  756. Buffer,
  757. pBootData->pszIdent,
  758. &pBootData->dwIndex))
  759. {
  760. break;
  761. }
  762. pBootData->pszIdent[pBootData->dwIndex] = RutlStrDup(BL_EXIT_EFI1);
  763. if (!pBootData->pszIdent[pBootData->dwIndex])
  764. {
  765. break;
  766. }
  767. //
  768. // Find the BOOT_SPART option
  769. //
  770. if (FindOpt(
  771. BOOT_SPART,
  772. Buffer,
  773. pBootData->pszSPart,
  774. &pBootData->dwIndex))
  775. {
  776. break;
  777. }
  778. //
  779. // Find the BOOT_OSLDR option
  780. //
  781. if (FindOpt(
  782. BOOT_OSLDR,
  783. Buffer,
  784. pBootData->pszOSLdr,
  785. &pBootData->dwIndex))
  786. {
  787. break;
  788. }
  789. if (CreateShortNames(pBootData))
  790. {
  791. break;
  792. }
  793. //
  794. // Append 'exit' to the end of the menu
  795. //
  796. pBootData->pszShort[pBootData->dwIndex] = RutlStrDup(BL_EXIT_EFI2);
  797. if (!pBootData->pszShort[pBootData->dwIndex])
  798. {
  799. break;
  800. }
  801. //
  802. // Find the BOOT_LPART option
  803. //
  804. if (FindOpt(
  805. BOOT_LPART,
  806. Buffer,
  807. pBootData->pszLPart,
  808. &pBootData->dwIndex))
  809. {
  810. break;
  811. }
  812. //
  813. // Find the BOOT_FILEN option
  814. //
  815. if (FindOpt(
  816. BOOT_FILEN,
  817. Buffer,
  818. pBootData->pszFileN,
  819. &pBootData->dwIndex))
  820. {
  821. break;
  822. }
  823. //
  824. // Find the BOOT_CNTDW option
  825. //
  826. if (TempStr = strstr(Buffer, BOOT_CNTDW))
  827. {
  828. UniStr = RutlUniStrDup(TempStr + strlena(BOOT_CNTDW));
  829. if ((UniStr != NULL) &&
  830. (Atoi(UniStr) > 0) &&
  831. (Atoi(UniStr) < BOOT_COUNT)
  832. )
  833. {
  834. pBootData->dwCount = Atoi(UniStr);
  835. bError = FALSE;
  836. break;
  837. }
  838. }
  839. //
  840. // Set the count to the default if setting it failed
  841. //
  842. if (!pBootData->dwCount)
  843. {
  844. pBootData->dwCount = BOOT_COUNT;
  845. }
  846. bError = FALSE;
  847. } while (FALSE);
  848. if (UniStr)
  849. {
  850. UniStr = RutlFree(UniStr);
  851. }
  852. return bError;
  853. }
  854. //
  855. // fill out startup.nsh with the name of this program
  856. //
  857. void
  858. PopulateStartFile(
  859. IN EFI_FILE_HANDLE* StartFile
  860. )
  861. {
  862. UINTN size;
  863. CHAR16 UnicodeMarker = UNICODE_BYTE_ORDER_MARK;
  864. size = sizeof(UnicodeMarker);
  865. (*StartFile)->Write(*StartFile, &size, &UnicodeMarker);
  866. size = (StrLen(THISFILE)) * sizeof(CHAR16);
  867. (*StartFile)->Write(*StartFile, &size, THISFILE);
  868. return;
  869. }
  870. //
  871. // Parse cmdline params
  872. //
  873. void
  874. ParseArgs(
  875. IN EFI_FILE_HANDLE* CurDir,
  876. IN EFI_LOADED_IMAGE* LoadedImage
  877. )
  878. {
  879. EFI_STATUS Status;
  880. EFI_FILE_HANDLE StartFile = NULL;
  881. do
  882. {
  883. if (MetaiMatch(LoadedImage->LoadOptions, REGISTER1) ||
  884. MetaiMatch(LoadedImage->LoadOptions, REGISTER2)
  885. )
  886. {
  887. Status = (*CurDir)->Open(
  888. *CurDir,
  889. &StartFile,
  890. STARTFILE,
  891. EFI_FILE_MODE_READ |
  892. EFI_FILE_MODE_WRITE |
  893. EFI_FILE_MODE_CREATE,
  894. 0);
  895. if (EFI_ERROR(Status))
  896. {
  897. break;
  898. }
  899. Status = StartFile->Delete(StartFile);
  900. if (EFI_ERROR(Status))
  901. {
  902. break;
  903. }
  904. StartFile = NULL;
  905. Status = (*CurDir)->Open(
  906. *CurDir,
  907. &StartFile,
  908. STARTFILE,
  909. EFI_FILE_MODE_READ |
  910. EFI_FILE_MODE_WRITE |
  911. EFI_FILE_MODE_CREATE,
  912. 0);
  913. if (!EFI_ERROR(Status))
  914. {
  915. PopulateStartFile(&StartFile);
  916. }
  917. }
  918. } while (FALSE);
  919. //
  920. // Clean up
  921. //
  922. if (StartFile)
  923. {
  924. StartFile->Close(StartFile);
  925. }
  926. return;
  927. }
  928. //
  929. // Read in BOOT.NVR and return buffer of contents
  930. //
  931. void*
  932. ReadBootFile(
  933. IN UINTN* Size,
  934. IN EFI_FILE_HANDLE* FileHandle
  935. )
  936. {
  937. char* Buffer = NULL;
  938. EFI_STATUS Status;
  939. EFI_FILE_INFO* BootInfo = NULL;
  940. do
  941. {
  942. *Size = (SIZE_OF_EFI_FILE_INFO + 255) * sizeof(CHAR16);
  943. BootInfo = AllocateZeroPool(*Size);
  944. if (!BootInfo)
  945. {
  946. break;
  947. }
  948. Status = (*FileHandle)->GetInfo(
  949. *FileHandle,
  950. &GenericFileInfo,
  951. Size,
  952. BootInfo);
  953. if (EFI_ERROR(Status))
  954. {
  955. break;
  956. }
  957. //
  958. // Find out how much we will need to alloc
  959. //
  960. *Size = (UINTN) BootInfo->FileSize;
  961. Buffer = AllocateZeroPool((*Size) + 1);
  962. if (!Buffer)
  963. {
  964. break;
  965. }
  966. Status = (*FileHandle)->Read(*FileHandle, Size, Buffer);
  967. if (EFI_ERROR(Status))
  968. {
  969. Buffer = RutlFree(Buffer);
  970. break;
  971. }
  972. } while (FALSE);
  973. //
  974. // Clean up
  975. //
  976. if (BootInfo)
  977. {
  978. BootInfo = RutlFree(BootInfo);
  979. }
  980. return Buffer;
  981. }
  982. //
  983. // Remove any extra semi-colons from BOOT.NVR
  984. //
  985. BOOLEAN
  986. CleanBootFile(
  987. IN EFI_FILE_HANDLE* FileHandle,
  988. IN EFI_FILE_HANDLE* CurDir
  989. )
  990. {
  991. char *Buffer = NULL,
  992. *CpBuffer = NULL;
  993. UINTN i,
  994. Size = 0,
  995. NewSize = 0;
  996. BOOLEAN bError = TRUE;
  997. EFI_STATUS Status;
  998. EFI_FILE_HANDLE NewFile = NULL;
  999. do
  1000. {
  1001. (*FileHandle)->SetPosition(*FileHandle, 0);
  1002. Buffer = ReadBootFile(&Size, FileHandle);
  1003. if (!Buffer)
  1004. {
  1005. break;
  1006. }
  1007. CpBuffer = AllocateZeroPool(Size);
  1008. if (!CpBuffer)
  1009. {
  1010. break;
  1011. }
  1012. for (i = 0; i < Size; i++)
  1013. {
  1014. if ((*(Buffer + i) == ';') &&
  1015. ((*(Buffer + i + 1) == ';') ||
  1016. (*(Buffer + i + 1) == '\r') ||
  1017. (i + 1 == Size)
  1018. )
  1019. )
  1020. {
  1021. continue;
  1022. }
  1023. *(CpBuffer + NewSize) = *(Buffer + i);
  1024. NewSize++;
  1025. }
  1026. //
  1027. // Remove the exisiting BOOT.NVR
  1028. //
  1029. Status = (*FileHandle)->Delete(*FileHandle);
  1030. if (EFI_ERROR(Status))
  1031. {
  1032. break;
  1033. }
  1034. *FileHandle = NULL;
  1035. Status = (*CurDir)->Open(
  1036. *CurDir,
  1037. &NewFile,
  1038. BOOT_NVR,
  1039. EFI_FILE_MODE_READ |
  1040. EFI_FILE_MODE_WRITE |
  1041. EFI_FILE_MODE_CREATE,
  1042. 0);
  1043. if (EFI_ERROR(Status))
  1044. {
  1045. break;
  1046. }
  1047. Status = NewFile->Write(NewFile, &NewSize, CpBuffer);
  1048. if (EFI_ERROR(Status))
  1049. {
  1050. break;
  1051. }
  1052. bError = FALSE;
  1053. } while (FALSE);
  1054. //
  1055. // Clean up
  1056. //
  1057. if (NewFile)
  1058. {
  1059. NewFile->Close(NewFile);
  1060. }
  1061. if (CpBuffer)
  1062. {
  1063. CpBuffer = RutlFree(CpBuffer);
  1064. }
  1065. if (Buffer)
  1066. {
  1067. Buffer = RutlFree(Buffer);
  1068. }
  1069. return bError;
  1070. }
  1071. //
  1072. // Backup the BOOT.NVR so we have a fall back
  1073. //
  1074. BOOLEAN
  1075. BackupBootFile(
  1076. IN char* Buffer,
  1077. IN UINTN* Size,
  1078. IN EFI_FILE_HANDLE* CurDir
  1079. )
  1080. {
  1081. BOOLEAN bError = FALSE;
  1082. EFI_STATUS Status;
  1083. EFI_FILE_HANDLE FileHandle = NULL;
  1084. do
  1085. {
  1086. //
  1087. // Delete the backup file if already exists
  1088. //
  1089. Status = (*CurDir)->Open(
  1090. *CurDir,
  1091. &FileHandle,
  1092. BACKUP_NVR,
  1093. EFI_FILE_MODE_READ |
  1094. EFI_FILE_MODE_WRITE,
  1095. 0);
  1096. if (!EFI_ERROR(Status))
  1097. {
  1098. Status = FileHandle->Delete(FileHandle);
  1099. if (EFI_ERROR(Status))
  1100. {
  1101. break;
  1102. }
  1103. }
  1104. FileHandle = NULL;
  1105. //
  1106. // Copy current file data to a newly created backup file
  1107. //
  1108. Status = (*CurDir)->Open(
  1109. *CurDir,
  1110. &FileHandle,
  1111. BACKUP_NVR,
  1112. EFI_FILE_MODE_READ |
  1113. EFI_FILE_MODE_WRITE |
  1114. EFI_FILE_MODE_CREATE,
  1115. 0);
  1116. if (!EFI_ERROR(Status))
  1117. {
  1118. Status = FileHandle->Write(FileHandle, Size, Buffer);
  1119. }
  1120. } while (FALSE);
  1121. //
  1122. // Clean up
  1123. //
  1124. if (FileHandle)
  1125. {
  1126. FileHandle->Close(FileHandle);
  1127. }
  1128. if (EFI_ERROR(Status))
  1129. {
  1130. bError = TRUE;
  1131. }
  1132. return bError;
  1133. }
  1134. //
  1135. // EFI Entry Point
  1136. //
  1137. EFI_STATUS
  1138. EfiMain(
  1139. IN EFI_HANDLE ImageHandle,
  1140. IN EFI_SYSTEM_TABLE* ST
  1141. )
  1142. {
  1143. char* Buffer = NULL;
  1144. char* OSPath = NULL;
  1145. UINTN Size = 0,
  1146. Launch = 0,
  1147. Menu = 0;
  1148. BOOT_DATA* pBootData = NULL;
  1149. EFI_STATUS Status;
  1150. EFI_FILE_HANDLE FileHandle = NULL,
  1151. RootFs = NULL;
  1152. EFI_DEVICE_PATH* DevicePath = NULL;
  1153. EFI_LOADED_IMAGE* LoadedImage = NULL;
  1154. do
  1155. {
  1156. InitializeLib(ImageHandle, ST);
  1157. //
  1158. // Get the device handle and file path to the EFI OS Loader itself.
  1159. //
  1160. Status = BS->HandleProtocol(
  1161. ImageHandle,
  1162. &LoadedImageProtocol,
  1163. &LoadedImage);
  1164. if (EFI_ERROR(Status))
  1165. {
  1166. Print(L"Can not retrieve LoadedImageProtocol handle\n");
  1167. break;
  1168. }
  1169. Status = BS->HandleProtocol(
  1170. LoadedImage->DeviceHandle,
  1171. &DevicePathProtocol,
  1172. &DevicePath);
  1173. if (EFI_ERROR(Status) || DevicePath == NULL)
  1174. {
  1175. Print(L"Can not find DevicePath handle\n");
  1176. break;
  1177. }
  1178. //
  1179. // Open volume for the device where the EFI OS Loader was loaded from
  1180. //
  1181. RootFs = LibOpenRoot(LoadedImage->DeviceHandle);
  1182. if (!RootFs)
  1183. {
  1184. Print(L"Can not open the volume for the file system\n");
  1185. break;
  1186. }
  1187. //
  1188. // Look for any cmd line params
  1189. //
  1190. ParseArgs(&RootFs, LoadedImage);
  1191. //
  1192. // Attempt to open the boot.nvr
  1193. //
  1194. Status = RootFs->Open(
  1195. RootFs,
  1196. &FileHandle,
  1197. BOOT_NVR,
  1198. EFI_FILE_MODE_READ |
  1199. EFI_FILE_MODE_WRITE,
  1200. 0);
  1201. if (EFI_ERROR(Status))
  1202. {
  1203. Print(L"Can not open the file %s\n", BOOT_NVR);
  1204. break;
  1205. }
  1206. Buffer = ReadBootFile(&Size, &FileHandle);
  1207. if (!Buffer)
  1208. {
  1209. Print(L"ReadBootFile() failed!\n");
  1210. break;
  1211. }
  1212. if (BackupBootFile(Buffer, &Size, &RootFs))
  1213. {
  1214. Print(L"BackupBootFile() failed!\n");
  1215. break;
  1216. }
  1217. //
  1218. // Alloc for boot file data struct
  1219. //
  1220. pBootData = (BOOT_DATA*) AllocateZeroPool(sizeof(BOOT_DATA));
  1221. if (!pBootData)
  1222. {
  1223. Print(L"Failed to allocate memory for BOOT_DATA!\n");
  1224. break;
  1225. }
  1226. if (GetBootData(pBootData, Buffer))
  1227. {
  1228. Print(L"Failed in GetBootData()!\n");
  1229. break;
  1230. }
  1231. Menu = DisplayMenu(pBootData);
  1232. if (Menu < pBootData->dwIndex)
  1233. {
  1234. if (!OrderBootFile(Menu, Buffer, pBootData))
  1235. {
  1236. FileHandle->SetPosition(FileHandle, 0);
  1237. FileHandle->Write(FileHandle, &Size, Buffer);
  1238. if (SortLoadOptions(
  1239. pBootData,
  1240. Buffer,
  1241. &Size,
  1242. &Menu,
  1243. &(pBootData->dwIndex),
  1244. &FileHandle)
  1245. )
  1246. {
  1247. Print(L"Failed to SortLoadOptions()!\n");
  1248. break;
  1249. }
  1250. if (CleanBootFile(&FileHandle, &RootFs))
  1251. {
  1252. Print(L"Failed to CleanBootFile()!\n");
  1253. break;
  1254. }
  1255. }
  1256. else
  1257. {
  1258. Print(L"Failed to OrderBootFile()!\n");
  1259. break;
  1260. }
  1261. }
  1262. else
  1263. {
  1264. break;
  1265. }
  1266. OSPath = RutlStrDup(strstr(pBootData->pszOSLdr[Menu], wacks) + 1);
  1267. if (!OSPath)
  1268. {
  1269. Print(L"Failed to allocate memory for OSPath!\n");
  1270. break;
  1271. }
  1272. Launch = 1;
  1273. } while (FALSE);
  1274. //
  1275. // Clean up
  1276. //
  1277. if (pBootData)
  1278. {
  1279. if (pBootData->dwIndex)
  1280. {
  1281. FreeBootData(pBootData);
  1282. }
  1283. pBootData = RutlFree(pBootData);
  1284. }
  1285. if (Buffer)
  1286. {
  1287. Buffer = RutlFree(Buffer);
  1288. }
  1289. if (FileHandle)
  1290. {
  1291. FileHandle->Close(FileHandle);
  1292. }
  1293. if (Launch)
  1294. {
  1295. if (LaunchOS(OSPath, ImageHandle, &RootFs, LoadedImage))
  1296. {
  1297. Print (L"Failed to LaunchOS()!\n");
  1298. }
  1299. }
  1300. return EFI_SUCCESS;
  1301. }