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.

2409 lines
58 KiB

  1. /*++
  2. Module Name:
  3. nvrio.c
  4. Abstract:
  5. Access function to r/w environment variables from NVRAM
  6. Author:
  7. Mudit Vats (v-muditv) 12-13-99
  8. Revision History:
  9. --*/
  10. #include <precomp.h>
  11. #define FIELD_OFFSET(type, field) ((UINT32)(UINTN)&(((type *)0)->field))
  12. #define ALIGN_DOWN(length, type) \
  13. ((UINT32)(length) & ~(sizeof(type) - 1))
  14. #define ALIGN_UP(length, type) \
  15. (ALIGN_DOWN(((UINT32)(length) + sizeof(type) - 1), type))
  16. #define EFI_ATTR EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
  17. #if !defined(_WIN64)
  18. typedef unsigned long ULONG_PTR, *PULONG_PTR;
  19. #else
  20. typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
  21. #endif
  22. #ifndef POINTER_IS_ALIGNED
  23. // BOOL
  24. // POINTER_IS_ALIGNED(
  25. // IN LPVOID Ptr,
  26. // IN DWORD Pow2 // undefined if this isn't a power of 2.
  27. // );
  28. //
  29. #define POINTER_IS_ALIGNED(Ptr,Pow2) \
  30. ( ( ( ((ULONG_PTR)(Ptr)) & (((Pow2)-1)) ) == 0) ? TRUE : FALSE )
  31. #endif // !POINTER_IS_ALIGNED
  32. VOID* LoadOptions [MAXBOOTVARS];
  33. UINT64 LoadOptionsSize [MAXBOOTVARS];
  34. VOID* BootOrder;
  35. UINT64 BootOrderCount;
  36. UINT64 OsBootOptionCount;
  37. #define LOAD_OPTION_ACTIVE 0x00000001
  38. //
  39. // local routines
  40. //
  41. BOOLEAN
  42. SetBootManagerVar(
  43. UINTN BootVarNum
  44. );
  45. BOOLEAN
  46. SetBootManagerVarCheck(
  47. UINTN BootVarNum
  48. );
  49. INT32
  50. SafeWcslen (
  51. CHAR16 *String,
  52. CHAR16 *Max
  53. )
  54. {
  55. CHAR16 *p = String;
  56. while ( (p < Max) && (*p != 0) ) {
  57. p++;
  58. }
  59. if ( p < Max ) {
  60. return(UINT32)(p - String);
  61. }
  62. return -1;
  63. } // SafeWclen
  64. #define ISWINDOWSOSCHECK_DEBUG 0
  65. BOOLEAN
  66. isWindowsOsBootOption(
  67. char* elo,
  68. UINT64 eloSize
  69. )
  70. //
  71. // Purpose: determine if the EFI_LOAD_OPTION structure in question is referring to
  72. // a Windows OS boot option
  73. //
  74. // Return:
  75. //
  76. // TRUE elo refers to a Windows OS option
  77. //
  78. {
  79. CHAR16 *max;
  80. INT32 l;
  81. UINTN length;
  82. PEFI_LOAD_OPTION pElo;
  83. char* devicePath;
  84. char* osOptions;
  85. PWINDOWS_OS_OPTIONS pOsOptions;
  86. char* aOsOptions;
  87. BOOLEAN status;
  88. status = TRUE;
  89. aOsOptions = NULL;
  90. pElo = (EFI_LOAD_OPTION*)elo;
  91. if ( eloSize < sizeof(EFI_LOAD_OPTION) ) {
  92. status = FALSE;
  93. goto Done;
  94. }
  95. #if ISWINDOWSOSCHECK_DEBUG
  96. Print( L"Is %s a Windows OS boot option?\n", pElo->Description );
  97. #endif
  98. //
  99. // Is the description properly terminated?
  100. //
  101. max = (CHAR16 *)(elo + eloSize);
  102. l = SafeWcslen( pElo->Description, max );
  103. if ( l < 0 ) {
  104. #if ISWINDOWSOSCHECK_DEBUG
  105. Print (L"Failed: SafeWcslen( pElo->Description, max )\n");
  106. #endif
  107. status = FALSE;
  108. goto Done;
  109. }
  110. //
  111. // get the WINDOWS_OS_OPTIONS structure from the OptionalData field
  112. //
  113. osOptions = elo +
  114. FIELD_OFFSET(EFI_LOAD_OPTION,Description) +
  115. StrSize(pElo->Description) +
  116. pElo->FilePathListLength;
  117. length = (UINTN)eloSize;
  118. length -= (UINTN)(osOptions - elo);
  119. #if ISWINDOWSOSCHECK_DEBUG
  120. Print (L"length = %x\n", length);
  121. #endif
  122. //
  123. // make sure osOptions are atleast the size of the
  124. // WINDOWS_OS_OPTIONS header
  125. //
  126. //
  127. if ( length < FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) ) {
  128. #if ISWINDOWSOSCHECK_DEBUG
  129. Print (L"Failed: invalid length: %x\n", length);
  130. #endif
  131. status = FALSE;
  132. goto Done;
  133. }
  134. //
  135. // align the os options
  136. //
  137. aOsOptions = GetAlignedOsOptions(elo, eloSize);
  138. pOsOptions = (WINDOWS_OS_OPTIONS*)aOsOptions;
  139. #if ISWINDOWSOSCHECK_DEBUG
  140. DisplayOsOptions(aOsOptions);
  141. #endif
  142. //
  143. // Does the OsOptions structure look like a WINDOWS_OS_OPTIONS structure?
  144. //
  145. if ( (length != pOsOptions->Length) ||
  146. (WINDOWS_OS_OPTIONS_VERSION != pOsOptions->Version) ||
  147. (strcmpa(pOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) != 0) ) {
  148. #if ISWINDOWSOSCHECK_DEBUG
  149. Print (L"Failed: OsOptions doesn't look like WINDOWS_OS_OPTIONS structure.\n");
  150. Print (L"test1: %x\n", length != pOsOptions->Length);
  151. Print (L"test2: %x\n", WINDOWS_OS_OPTIONS_VERSION != pOsOptions->Version);
  152. Print (L"test3: %x\n", strcmpa(pOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE) != 0 );
  153. #endif
  154. status = FALSE;
  155. goto Done;
  156. }
  157. //
  158. // Is the OsLoadOptions string properly terminated?
  159. //
  160. //
  161. // create a new max ptr to accomodate the fact that we are
  162. // now using an aligned copy of OsOptions from the Pool
  163. //
  164. max = (CHAR16*)(aOsOptions + pOsOptions->Length);
  165. #if ISWINDOWSOSCHECK_DEBUG
  166. Print (L"max = %x, osloadoptions = %x, diff = %x, strsize=%x\n",
  167. max,
  168. pOsOptions->OsLoadOptions,
  169. (char*)max - (char*)pOsOptions->OsLoadOptions,
  170. StrSize(pOsOptions->OsLoadOptions)
  171. );
  172. #endif
  173. l = SafeWcslen( pOsOptions->OsLoadOptions, max );
  174. if ( l < 0 ) {
  175. #if ISWINDOWSOSCHECK_DEBUG
  176. Print (L"Failed: SafeWcslen( osLoadOptions, max ) = %x\n", l);
  177. #endif
  178. status = FALSE;
  179. goto Done;
  180. }
  181. Done:
  182. //
  183. // we are done with the os options
  184. //
  185. if (aOsOptions != NULL) {
  186. FreePool(aOsOptions);
  187. }
  188. return status;
  189. }
  190. #define GETBOOTVARS_DEBUG GLOBAL_DEBUG
  191. VOID
  192. GetBootManagerVars(
  193. )
  194. {
  195. UINT32 i,j;
  196. CHAR16 szTemp[10];
  197. VOID* bootvar;
  198. UINT64 BootOrderSize = 0;
  199. UINT64 maxBootCount;
  200. //
  201. // Initialize EFI LoadOptions.
  202. //
  203. BootOrderSize = 0;
  204. BootOrderCount = 0;
  205. OsBootOptionCount = 0;
  206. BootOrder = NULL;
  207. #if 1
  208. ZeroMem( LoadOptions, sizeof(VOID*) * MAXBOOTVARS );
  209. ZeroMem( LoadOptionsSize, sizeof(UINT64) * MAXBOOTVARS );
  210. #endif
  211. //
  212. // Ensure that the Load Options have been freed
  213. //
  214. ASSERT(BootOrderCount == 0);
  215. //
  216. // Get BootOrder.
  217. //
  218. BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
  219. if ( BootOrder ) {
  220. BootOrderCount = BootOrderSize / sizeof(CHAR16);
  221. #if GETBOOTVARS_DEBUG
  222. Print (L"BootOrderCount = %x\n", BootOrderCount);
  223. #endif
  224. maxBootCount = (MAXBOOTVARS < BootOrderCount) ? MAXBOOTVARS : BootOrderCount;
  225. //
  226. // Get the boot options.
  227. //
  228. for ( i=0; i<maxBootCount; i++ ) {
  229. SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[i] );
  230. ASSERT(LoadOptions[i] == NULL);
  231. ASSERT(LoadOptionsSize[i] == 0);
  232. LoadOptions[i] = LibGetVariableAndSize( szTemp, &VenEfi, &(LoadOptionsSize[i]) );
  233. //
  234. // The NVRAM variables are case sensitive. The boot order variable said this
  235. // entry should exist. If we did not find it, try again with uppercase
  236. // hexadecimal string
  237. //
  238. if (LoadOptions[i] == NULL && LoadOptionsSize[i] == 0) {
  239. SPrint( szTemp, sizeof(szTemp), L"Boot%04X", ((CHAR16*) BootOrder)[i] );
  240. LoadOptions[i] = LibGetVariableAndSize( szTemp, &VenEfi, &(LoadOptionsSize[i]) );
  241. }
  242. #if GETBOOTVARS_DEBUG
  243. Print (L"i = %x, szTemp = %s, BOCnt = %x, LOptions = %x, BSize = %x\n",
  244. i,
  245. szTemp,
  246. OsBootOptionCount,
  247. LoadOptions[i],
  248. LoadOptionsSize[i]
  249. );
  250. #endif
  251. OsBootOptionCount++;
  252. }
  253. }
  254. #if GETBOOTVARS_DEBUG
  255. Print(L"BootOrderCount: %d OsBootOptionCount: %d\n", BootOrderCount, OsBootOptionCount);
  256. #endif
  257. }
  258. #define ERASEBOOTOPT_DEBUG GLOBAL_DEBUG
  259. BOOLEAN
  260. EraseOsBootOption(
  261. UINTN BootVarNum
  262. )
  263. {
  264. UINTN j;
  265. CHAR16 szTemp[10];
  266. CHAR16* tmpBootOrder;
  267. VOID* bootvar;
  268. UINT64 BootOrderSize = 0;
  269. VOID* pDummy;
  270. UINTN dummySize;
  271. //
  272. // validate BootVarNum
  273. //
  274. if (MAXBOOTVARS <= BootVarNum) {
  275. return FALSE;
  276. }
  277. //
  278. // Initialize EFI LoadOptions.
  279. //
  280. BootOrderSize = 0;
  281. BootOrderCount = 0;
  282. BootOrder = NULL;
  283. //
  284. // Get BootOrder.
  285. //
  286. BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
  287. BootOrderCount = BootOrderSize / sizeof(CHAR16);
  288. ASSERT(BootVarNum < MAXBOOTVARS);
  289. ASSERT(BootOrderCount >= 1);
  290. #if ERASEBOOTOPT_DEBUG
  291. Print (L"BootOrderCount = %x\n", BootOrderCount);
  292. Print (L"BootVarNum = %x\n", BootVarNum);
  293. #endif
  294. //
  295. // if the boot option is populated, then erase it
  296. //
  297. if (LoadOptions[BootVarNum]) {
  298. //
  299. // free the local load option
  300. //
  301. FreePool(LoadOptions[BootVarNum]);
  302. //
  303. // zero the local memory for the load options
  304. //
  305. LoadOptions[BootVarNum] = (VOID*)0;
  306. LoadOptionsSize[BootVarNum] = 0;
  307. //
  308. // Get the boot option
  309. //
  310. SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[BootVarNum] );
  311. #if ERASEBOOTOPT_DEBUG
  312. Print (L"BootXXXX = %s\n", szTemp);
  313. #endif
  314. pDummy = LibGetVariableAndSize( szTemp, &VenEfi, &dummySize );
  315. //
  316. // The NVRAM variables are case sensitive. If we were unable to
  317. // find the variable, perhaps the Boot Entry string has uppercase
  318. // alpha characters in the hexadecimal string. try again with
  319. // an uppercase string
  320. //
  321. if (pDummy == NULL && dummySize == 0) {
  322. SPrint( szTemp, sizeof(szTemp), L"Boot%04X", ((CHAR16*) BootOrder)[BootVarNum] );
  323. pDummy = LibGetVariableAndSize( szTemp, &VenEfi, &dummySize );
  324. }
  325. //
  326. // whack the nvram entry
  327. //
  328. SetVariable(
  329. szTemp,
  330. &VenEfi,
  331. EFI_ATTR,
  332. 0,
  333. NULL
  334. );
  335. #if ERASEBOOTOPT_DEBUG
  336. Print (L"Adjusting boot order [begin]\n");
  337. #endif
  338. //
  339. // adjust the counters for os boot options
  340. //
  341. OsBootOptionCount--;
  342. BootOrderCount--;
  343. //
  344. // Shift the remaining entries in the boot order and the load options
  345. //
  346. tmpBootOrder = (CHAR16*)BootOrder;
  347. for (j = BootVarNum; j < BootOrderCount; j++) {
  348. //
  349. // adjust the boot order for all entries
  350. //
  351. tmpBootOrder[j] = tmpBootOrder[j + 1];
  352. //
  353. // only have a maximum of MAXBOOTVARS boot entries.
  354. // only adjust if we can.
  355. //
  356. if (j < OsBootOptionCount) {
  357. LoadOptions[j] = LoadOptions[j + 1];
  358. LoadOptionsSize[j] = LoadOptionsSize[j + 1];
  359. }
  360. }
  361. //
  362. // Set the modified boot order
  363. //
  364. SetVariable(
  365. L"BootOrder",
  366. &VenEfi,
  367. EFI_ATTR,
  368. BootOrderCount * sizeof(CHAR16),
  369. BootOrder
  370. );
  371. #if ERASEBOOTOPT_DEBUG
  372. Print (L"Adjusting boot order [end]\n");
  373. #endif
  374. return TRUE;
  375. }
  376. return FALSE;
  377. }
  378. BOOLEAN
  379. EraseAllOsBootOptions(
  380. )
  381. {
  382. UINT32 i;
  383. UINT64 BootOrderSize = 0;
  384. BOOLEAN status;
  385. UINT64 maxBootCount;
  386. #if ERASEBOOTOPT_DEBUG
  387. CHAR16 szInput[1024];
  388. #endif
  389. //
  390. // Initialize EFI LoadOptions.
  391. //
  392. BootOrderSize = 0;
  393. BootOrderCount = 0;
  394. BootOrder = NULL;
  395. //
  396. // Get BootOrder.
  397. //
  398. BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
  399. BootOrderCount = BootOrderSize / sizeof(CHAR16);
  400. //
  401. // Make sure there is atleast one OS boot option
  402. //
  403. if ( BootOrder && OsBootOptionCount) {
  404. maxBootCount = (MAXBOOTVARS < BootOrderCount) ? MAXBOOTVARS : BootOrderCount;
  405. //
  406. // erase invidual boot options.
  407. //
  408. for ( i = 0; i < maxBootCount; i++ ) {
  409. #if ERASEBOOTOPT_DEBUG
  410. Print (L"BootOrderCount = %x, Erasing boot option: %x\n", BootOrderCount, i);
  411. #endif
  412. //
  413. // remove the boot entry at the head of the list
  414. //
  415. status = EraseOsBootOption(0);
  416. #if ERASEBOOTOPT_DEBUG
  417. Input (L"Here!\n", szInput, sizeof(szInput));
  418. Print(L"\n");
  419. #endif
  420. if (status == FALSE) {
  421. Print (L"Error: failed to erase boot entry %x\n", i);
  422. break;
  423. }
  424. }
  425. }
  426. return status;
  427. }
  428. BOOLEAN
  429. PushToTop(
  430. IN UINT32 BootVarNum
  431. )
  432. {
  433. UINT32 i;
  434. CHAR16 savBootOption;
  435. CHAR16* tmpBootOrder;
  436. UINT64 BootOrderSize = 0;
  437. //
  438. // check BootVarNum
  439. //
  440. if (MAXBOOTVARS <= BootVarNum) {
  441. return FALSE;
  442. }
  443. i=0;
  444. BootOrderSize = 0;
  445. BootOrder = NULL;
  446. //
  447. // Get BootOrder.
  448. //
  449. BootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &BootOrderSize );
  450. //
  451. // Make sure there is atleast one OS boot option
  452. //
  453. if ( BootOrder && OsBootOptionCount) {
  454. BootOrderCount = BootOrderSize / sizeof(CHAR16);
  455. //
  456. // Get the boot option.
  457. //
  458. tmpBootOrder = (CHAR16*)BootOrder;
  459. savBootOption = tmpBootOrder[BootVarNum];
  460. //
  461. // Now adjust the boot order
  462. //
  463. i=BootVarNum;
  464. while (i > 0) {
  465. tmpBootOrder[i] = tmpBootOrder[i-1];
  466. i--;
  467. }
  468. tmpBootOrder[0] = savBootOption;
  469. //
  470. // Set the changed boot order
  471. //
  472. SetVariable(
  473. L"BootOrder",
  474. &VenEfi,
  475. EFI_ATTR,
  476. BootOrderCount * sizeof(CHAR16),
  477. BootOrder
  478. );
  479. return TRUE;
  480. }
  481. return FALSE;
  482. }
  483. VOID
  484. FreeBootManagerVars(
  485. )
  486. {
  487. UINTN i;
  488. for ( i=0; i<OsBootOptionCount; i++ ) {
  489. if ( LoadOptions[i] ) {
  490. FreePool( LoadOptions[i] );
  491. }
  492. }
  493. if ( BootOrder ) {
  494. FreePool( BootOrder );
  495. }
  496. //
  497. // zero the local memory for the load options
  498. //
  499. ZeroMem( LoadOptions, sizeof(VOID*) * MAXBOOTVARS );
  500. ZeroMem( LoadOptionsSize, sizeof(UINT64) * MAXBOOTVARS );
  501. }
  502. BOOLEAN
  503. CopyVar(
  504. IN UINT32 VarNum
  505. )
  506. {
  507. CHAR16 i;
  508. BOOLEAN RetVal = FALSE;
  509. //
  510. // check to make sure we have room in our static structures
  511. //
  512. if (MAXBOOTVARS <= BootOrderCount) {
  513. return FALSE;
  514. }
  515. if ( VarNum < BootOrderCount ) {
  516. LoadOptions[BootOrderCount] = AllocateZeroPool( LoadOptionsSize[VarNum] );
  517. if ( LoadOptions[BootOrderCount] && LoadOptions[VarNum] ) {
  518. CopyMem( LoadOptions[BootOrderCount], LoadOptions[VarNum], LoadOptionsSize[VarNum] );
  519. LoadOptionsSize[BootOrderCount] = LoadOptionsSize[VarNum];
  520. BootOrder = ReallocatePool(
  521. (VOID*) BootOrder,
  522. BootOrderCount * sizeof(CHAR16),
  523. ( BootOrderCount + 1 ) * sizeof(CHAR16)
  524. );
  525. ((CHAR16*) BootOrder)[BootOrderCount] = FindFreeBootOption();
  526. BootOrderCount++;
  527. OsBootOptionCount++;
  528. RetVal = SetBootManagerVar(BootOrderCount - 1);
  529. }
  530. }
  531. return RetVal;
  532. }
  533. CHAR16
  534. FindFreeBootOption(
  535. )
  536. {
  537. CHAR16 i;
  538. CHAR16 *BootOptionBitmap = NULL;
  539. UINT64 maxBootEntry;
  540. CHAR16 Id = 0xFFFF;
  541. //
  542. // use a bitmask to find an open spot. by the pigeonhole
  543. // principle, we are guaranteed to find a spot if we
  544. // look at BootOrderCount+1 entries
  545. //
  546. BootOptionBitmap = AllocateZeroPool( (BootOrderCount+1) * sizeof(CHAR16) );
  547. if (BootOptionBitmap) {
  548. for ( i=0; i<BootOrderCount; i++ ) {
  549. if ( ((CHAR16*)BootOrder)[i] <= BootOrderCount ) {
  550. BootOptionBitmap[ ((CHAR16*)BootOrder)[i] ] = 1;
  551. }
  552. }
  553. for ( i=0; i <= BootOrderCount; i++ ) {
  554. if ( BootOptionBitmap[i] == 0 ) {
  555. Id = i;
  556. break;
  557. }
  558. }
  559. FreePool(BootOptionBitmap);
  560. }
  561. return Id;
  562. }
  563. BOOLEAN
  564. SetBootManagerVar(
  565. UINTN BootVarNum
  566. )
  567. {
  568. CHAR16 szTemp[50];
  569. BOOLEAN status;
  570. //
  571. // check BootVarNum
  572. //
  573. if (MAXBOOTVARS <= BootVarNum) {
  574. return FALSE;
  575. }
  576. status = TRUE;
  577. SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[BootVarNum] );
  578. if (LoadOptions[BootVarNum]) {
  579. SetVariable(
  580. szTemp,
  581. &VenEfi,
  582. EFI_ATTR,
  583. LoadOptionsSize[BootVarNum],
  584. LoadOptions[BootVarNum]
  585. );
  586. SetVariable(
  587. L"BootOrder",
  588. &VenEfi,
  589. EFI_ATTR,
  590. BootOrderCount * sizeof(CHAR16),
  591. BootOrder
  592. );
  593. }
  594. else
  595. {
  596. status = FALSE;
  597. }
  598. return status;
  599. }
  600. BOOLEAN
  601. SetBootManagerVarCheck(
  602. UINTN BootVarNum
  603. )
  604. {
  605. CHAR16 szTemp[50];
  606. BOOLEAN status;
  607. VOID* pDummy;
  608. UINTN dummySize;
  609. //
  610. // check BootVarNum
  611. //
  612. if (MAXBOOTVARS <= BootVarNum) {
  613. return FALSE;
  614. }
  615. status = FALSE;
  616. SPrint( szTemp, sizeof(szTemp), L"Boot%04x", ((CHAR16*) BootOrder)[BootVarNum] );
  617. if (LoadOptions[BootVarNum]) {
  618. //
  619. // This routine expects to be writing a boot entry that is known
  620. // to exist. We need this routine since we did not track
  621. // if a hexadecimal string containing an alpha character was
  622. // uppercase or lowercase
  623. //
  624. pDummy = LibGetVariableAndSize( szTemp, &VenEfi, &dummySize );
  625. //
  626. // The NVRAM variables are case sensitive. If we were unable to
  627. // find the variable, perhaps the Boot Entry string has uppercase
  628. // alpha characters in the hexadecimal string. try again with
  629. // an uppercase string
  630. //
  631. if (pDummy == NULL && dummySize == 0) {
  632. SPrint( szTemp, sizeof(szTemp), L"Boot%04X", ((CHAR16*) BootOrder)[BootVarNum] );
  633. pDummy = LibGetVariableAndSize( szTemp, &VenEfi, &dummySize );
  634. }
  635. if (pDummy || dummySize) {
  636. //
  637. // the variable exists. modify it now.
  638. //
  639. SetVariable(
  640. szTemp,
  641. &VenEfi,
  642. EFI_ATTR,
  643. LoadOptionsSize[BootVarNum],
  644. LoadOptions[BootVarNum]
  645. );
  646. SetVariable(
  647. L"BootOrder",
  648. &VenEfi,
  649. EFI_ATTR,
  650. BootOrderCount * sizeof(CHAR16),
  651. BootOrder
  652. );
  653. status = TRUE;
  654. }
  655. }
  656. return status;
  657. }
  658. VOID
  659. SetBootManagerVars(
  660. )
  661. {
  662. UINTN BootVarNum;
  663. BOOLEAN status;
  664. UINTN maxBootCount;
  665. maxBootCount = (MAXBOOTVARS < BootOrderCount) ? MAXBOOTVARS : BootOrderCount;
  666. for ( BootVarNum = 0; BootVarNum < maxBootCount; BootVarNum++ ) {
  667. status = SetBootManagerVarCheck(BootVarNum);
  668. if (status == FALSE) {
  669. Print (L"ERROR: Attempt to write non-existent boot option to NVRAM!\n");
  670. }
  671. }
  672. }
  673. UINT64
  674. GetBootOrderCount(
  675. )
  676. {
  677. return BootOrderCount;
  678. }
  679. UINT64
  680. GetOsBootOptionsCount(
  681. )
  682. {
  683. return OsBootOptionCount;
  684. }
  685. VOID
  686. SetEnvVar(
  687. IN CHAR16* szVarName,
  688. IN CHAR16* szVarValue,
  689. IN UINT32 deleteOnly
  690. )
  691. /*
  692. deleteOnly
  693. TRUE - Env var szVarName is deleted from nvr.
  694. FALSE - Env var szVarName overwrites or creates
  695. */
  696. {
  697. EFI_STATUS status;
  698. //
  699. // Erase the previous value
  700. //
  701. SetVariable(
  702. szVarName,
  703. &VenEfi,
  704. 0,
  705. 0,
  706. NULL
  707. );
  708. if ( !deleteOnly ) {
  709. //
  710. // Store the new value
  711. //
  712. status = SetVariable(
  713. szVarName,
  714. &VenEfi,
  715. EFI_ATTR,
  716. StrSize( szVarValue ),
  717. szVarValue
  718. );
  719. }
  720. }
  721. VOID
  722. SubString(
  723. IN OUT char* Dest,
  724. IN UINT32 Start,
  725. IN UINT32 End,
  726. IN char* Src
  727. )
  728. {
  729. UINTN i;
  730. UINTN j=0;
  731. for ( i=Start; i<End; i++ ) {
  732. Dest[ j++ ] = Src[ i ];
  733. }
  734. Dest[ j ] = '\0';
  735. }
  736. VOID
  737. InsertString(
  738. IN OUT char* Dest,
  739. IN UINT32 Start,
  740. IN UINT32 End,
  741. IN char* InsertString
  742. )
  743. {
  744. UINT32 i;
  745. UINT32 j=0;
  746. char first[1024];
  747. char last[1024];
  748. SubString( first, 0, Start, Dest );
  749. SubString( last, End, (UINT32) StrLenA(Dest), Dest );
  750. StrCatA( first, InsertString );
  751. StrCatA( first, last );
  752. StrCpyA( Dest, first );
  753. }
  754. VOID
  755. UtoA(
  756. OUT char* c,
  757. IN CHAR16* u
  758. )
  759. {
  760. UINT32 i = 0;
  761. while ( u[i] ) {
  762. c[i] = u[i] & 0xFF;
  763. i++;
  764. }
  765. c[i] = '\0';
  766. }
  767. VOID
  768. AtoU(
  769. OUT CHAR16* u,
  770. IN char* c
  771. )
  772. {
  773. UINT32 i = 0;
  774. while ( c[i] ) {
  775. u[i] = (CHAR16)c[i];
  776. i++;
  777. }
  778. u[i] = (CHAR16)'\0';
  779. }
  780. VOID
  781. SetFieldFromLoadOption(
  782. IN UINT32 BootVarNum,
  783. IN UINT32 FieldType,
  784. IN VOID* Data
  785. )
  786. {
  787. CHAR16 LoadIdentifier[200];
  788. char OsLoadOptions[200];
  789. char EfiFilePath[1024];
  790. char OsLoadPath[1024];
  791. BOOLEAN status;
  792. UINT16 efiFilePathListLength = 0;
  793. UINT16 osLoadPathListLength = 0;
  794. //
  795. // Make sure it is a valid OS load option
  796. //
  797. if (BootVarNum >= BootOrderCount)
  798. return ;
  799. if (BootVarNum >= MAXBOOTVARS)
  800. return;
  801. if (LoadOptions[BootVarNum] == NULL)
  802. return;
  803. status = GetOsLoadOptionVars(
  804. BootVarNum,
  805. LoadIdentifier,
  806. OsLoadOptions,
  807. EfiFilePath,
  808. OsLoadPath
  809. );
  810. if (status == FALSE) {
  811. #ifdef DEBUG_PACK
  812. Print (L"\nSetFieldFromLoadOption: GetOsLoadOptionVars failed\n");
  813. #endif // DEBUG_PACK
  814. return;
  815. }
  816. //
  817. // Set the field.
  818. //
  819. switch (FieldType) {
  820. case DESCRIPTION:
  821. StrCpy( LoadIdentifier, Data );
  822. break;
  823. case OSLOADOPTIONS:
  824. StrCpy( (CHAR16*)OsLoadOptions, (CHAR16*)Data );
  825. break;
  826. #if 1
  827. case EFIFILEPATHLIST:
  828. efiFilePathListLength = SetFilePathFromShort( (EFI_DEVICE_PATH*) EfiFilePath,
  829. (CHAR16*) Data );
  830. break;
  831. case OSFILEPATHLIST:
  832. {
  833. PFILE_PATH pFilePath;
  834. pFilePath = (FILE_PATH*)OsLoadPath;
  835. osLoadPathListLength = SetFilePathFromShort( (EFI_DEVICE_PATH*) pFilePath->FilePath,
  836. (CHAR16*) Data );
  837. if ( osLoadPathListLength ) {
  838. osLoadPathListLength += (UINT16) FIELD_OFFSET( FILE_PATH, FilePath );
  839. }
  840. }
  841. break;
  842. #endif
  843. default:
  844. break;
  845. }
  846. //
  847. // Pack the new parameters into the the current load option
  848. //
  849. PackLoadOption( BootVarNum,
  850. LoadIdentifier,
  851. (CHAR16*)OsLoadOptions,
  852. EfiFilePath,
  853. efiFilePathListLength,
  854. OsLoadPath,
  855. osLoadPathListLength
  856. );
  857. //
  858. // save the new load option into NVRAM
  859. //
  860. SetBootManagerVarCheck(BootVarNum);
  861. }
  862. VOID
  863. GetFilePathShort(
  864. EFI_DEVICE_PATH *FilePath,
  865. CHAR16 *FilePathShort
  866. )
  867. {
  868. UINT32 i, j, End;
  869. EFI_DEVICE_PATH *n = FilePath;
  870. //
  871. // Advance to FilePath node.
  872. //
  873. while (( n->Type != END_DEVICE_PATH_TYPE ) &&
  874. ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) {
  875. if (( n->Type == MEDIA_DEVICE_PATH ) &&
  876. ( n->SubType == MEDIA_FILEPATH_DP )) {
  877. j = 0;
  878. End = DevicePathNodeLength(n);
  879. for ( i=sizeof(EFI_DEVICE_PATH); i<End; i++ ) {
  880. ((char*) FilePathShort)[j++] = ( (char*) n)[i];
  881. }
  882. break;
  883. }
  884. n = NextDevicePathNode(n);
  885. }
  886. }
  887. VOID
  888. GetDiskGuidFromPath(
  889. EFI_DEVICE_PATH *FilePath,
  890. EFI_GUID *DiskGuid
  891. )
  892. {
  893. UINT32 i, j, End;
  894. EFI_DEVICE_PATH *n = FilePath;
  895. HARDDRIVE_DEVICE_PATH *harddriveDp;
  896. //
  897. // Advance to FilePath node.
  898. //
  899. while (( n->Type != END_DEVICE_PATH_TYPE ) &&
  900. ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) {
  901. if (( n->Type == MEDIA_DEVICE_PATH ) &&
  902. ( n->SubType == MEDIA_HARDDRIVE_DP )) {
  903. harddriveDp = (HARDDRIVE_DEVICE_PATH *)n;
  904. CopyMem( DiskGuid, &harddriveDp->Signature, sizeof(harddriveDp->Signature) );
  905. break;
  906. }
  907. n = NextDevicePathNode(n);
  908. }
  909. }
  910. UINT16 // new FilePathListLength if updated. 0 otherwise.
  911. SetFilePathFromShort(
  912. EFI_DEVICE_PATH *FilePath,
  913. CHAR16* FilePathShort
  914. )
  915. {
  916. UINT32 i, j, End;
  917. EFI_DEVICE_PATH *n = FilePath;
  918. UINT64 DevicePathSize;
  919. UINT16 length = 0;
  920. //
  921. // Advance to FilePath node.
  922. //
  923. while (( n->Type != END_DEVICE_PATH_TYPE ) &&
  924. ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) {
  925. if (( n->Type == MEDIA_DEVICE_PATH ) &&
  926. ( n->SubType == MEDIA_FILEPATH_DP )) {
  927. #if DEBUG_PACK
  928. Print (L"SetFilePathFromShort: Entry found...\n");
  929. #endif // DEBUG_PACK
  930. j = 0;
  931. End = DevicePathNodeLength(n);
  932. //
  933. // Set the new file path
  934. //
  935. DevicePathSize = GetDevPathSize(n);
  936. for ( i=sizeof(EFI_DEVICE_PATH); i<DevicePathSize; i++ ) {
  937. ((char*) n)[i] = '\0';
  938. }
  939. j=sizeof(EFI_DEVICE_PATH);
  940. for ( i=0; i<StrSize(FilePathShort); i++ ) {
  941. ((char*)n)[j++] = ((char*)FilePathShort)[i];
  942. }
  943. SetDevicePathNodeLength( n, StrSize(FilePathShort) + sizeof(EFI_DEVICE_PATH) );
  944. n = NextDevicePathNode(n);
  945. SetDevicePathEndNode(n);
  946. n = NextDevicePathNode(n);
  947. length = (UINT16)((ULONG_PTR)n - (ULONG_PTR)FilePath);
  948. break;
  949. }
  950. n = NextDevicePathNode(n);
  951. }
  952. #if DEBUG_PACK
  953. if (length == 0) Print (L"SetFilePathFromShort: Entry _NOT_ updated...\n");
  954. #endif // DEBUG_PACK
  955. return( length );
  956. }
  957. VOID
  958. SetDiskGuidInPath(
  959. EFI_DEVICE_PATH *FilePath,
  960. EFI_GUID *DiskGuid
  961. )
  962. {
  963. UINT32 i, j, End;
  964. EFI_DEVICE_PATH *n = FilePath;
  965. HARDDRIVE_DEVICE_PATH *harddriveDp;
  966. //
  967. // Advance to FilePath node.
  968. //
  969. while (( n->Type != END_DEVICE_PATH_TYPE ) &&
  970. ( n->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE ) ) {
  971. if (( n->Type == MEDIA_DEVICE_PATH ) &&
  972. ( n->SubType == MEDIA_FILEPATH_DP )) {
  973. harddriveDp = (HARDDRIVE_DEVICE_PATH *)n;
  974. CopyMem( &harddriveDp->Signature, DiskGuid, sizeof(harddriveDp->Signature) );
  975. break;
  976. }
  977. n = NextDevicePathNode(n);
  978. }
  979. }
  980. char*
  981. GetAlignedELOFilePath(
  982. char* elo
  983. )
  984. {
  985. UINTN abufSize;
  986. char* abuf;
  987. PEFI_LOAD_OPTION pElo;
  988. pElo = (EFI_LOAD_OPTION*)elo;
  989. abufSize = pElo->FilePathListLength;
  990. abuf = AllocatePool(abufSize);
  991. CopyMem(abuf,
  992. elo +
  993. FIELD_OFFSET(EFI_LOAD_OPTION, Description) +
  994. StrSize(pElo->Description),
  995. abufSize
  996. );
  997. return abuf;
  998. }
  999. char*
  1000. GetAlignedOptionalData(
  1001. char* elo,
  1002. UINT64 eloSize,
  1003. UINT64* dataSize
  1004. )
  1005. {
  1006. UINTN abufSize;
  1007. char* abuf;
  1008. PEFI_LOAD_OPTION pElo;
  1009. UINTN offset;
  1010. pElo = (EFI_LOAD_OPTION*)elo;
  1011. offset = FIELD_OFFSET(EFI_LOAD_OPTION, Description) +
  1012. StrSize(pElo->Description) +
  1013. pElo->FilePathListLength;
  1014. abufSize = eloSize - offset;
  1015. abuf = AllocatePool(abufSize);
  1016. CopyMem(abuf,
  1017. elo + offset,
  1018. abufSize
  1019. );
  1020. *dataSize = abufSize;
  1021. return abuf;
  1022. }
  1023. char*
  1024. GetAlignedOsOptions(
  1025. char* elo,
  1026. UINT64 eloSize
  1027. )
  1028. {
  1029. UINT64 dummy;
  1030. char* abuf;
  1031. abuf = GetAlignedOptionalData(elo,
  1032. eloSize,
  1033. &dummy
  1034. );
  1035. return abuf;
  1036. }
  1037. char*
  1038. GetAlignedOsLoadPath(
  1039. IN char* osOptions,
  1040. OUT UINTN* osLoadPathSize
  1041. )
  1042. //
  1043. // we need to align the FilePath structure because the load options are
  1044. // variable in length, so the FilePath structure may not be aligned
  1045. //
  1046. {
  1047. UINTN abufSize;
  1048. char* abuf;
  1049. PWINDOWS_OS_OPTIONS pOsOptions;
  1050. pOsOptions = (WINDOWS_OS_OPTIONS*)osOptions;
  1051. abufSize = pOsOptions->Length -
  1052. FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) -
  1053. StrSize(pOsOptions->OsLoadOptions);
  1054. abuf = AllocatePool(abufSize);
  1055. CopyMem(abuf,
  1056. &osOptions[pOsOptions->OsLoadPathOffset],
  1057. abufSize
  1058. );
  1059. *osLoadPathSize = abufSize;
  1060. return abuf;
  1061. }
  1062. VOID
  1063. DisplayLoadPath(
  1064. char* osLoadPath
  1065. )
  1066. {
  1067. PFILE_PATH pFilePath;
  1068. pFilePath = (FILE_PATH*)osLoadPath;
  1069. Print (L"osOptions->FILE_PATH->Version = %x\n", pFilePath->Version);
  1070. Print (L"osOptions->FILE_PATH->Length = %x\n", pFilePath->Length);
  1071. Print (L"osOptions->FILE_PATH->Type = %x\n", pFilePath->Type);
  1072. if (pFilePath->Type == FILE_PATH_TYPE_EFI) {
  1073. CHAR16 FilePathShort[200];
  1074. GetFilePathShort(
  1075. (EFI_DEVICE_PATH *)pFilePath->FilePath,
  1076. FilePathShort
  1077. );
  1078. Print (L"osOptions->FILE_PATH->FilePath(EFI:DP:Short) = %s\n", FilePathShort);
  1079. }
  1080. }
  1081. VOID
  1082. DisplayOsOptions(
  1083. char* osOptions
  1084. )
  1085. {
  1086. PWINDOWS_OS_OPTIONS pOsOptions;
  1087. CHAR16 wideSig[256];
  1088. char* aOsLoadPath;
  1089. UINTN aOsLoadPathSize;
  1090. pOsOptions = (WINDOWS_OS_OPTIONS*)osOptions;
  1091. Print (L">>>>\n");
  1092. //
  1093. // display the attributes
  1094. //
  1095. AtoU(wideSig, pOsOptions->Signature);
  1096. Print (L"osOptions->Signature = %s\n", wideSig);
  1097. Print (L"osOptions->Version = %x\n", pOsOptions->Version);
  1098. Print (L"osOptions->Length = %x\n", pOsOptions->Length);
  1099. Print (L"osOptions->OsLoadPathOffset = %x\n", pOsOptions->OsLoadPathOffset);
  1100. // display the os load options
  1101. Print (L"osOptions->OsLoadOptions = %s\n", pOsOptions->OsLoadOptions);
  1102. //
  1103. // display the FILE PATH
  1104. //
  1105. //
  1106. // we need to align the FilePath structure because the load options are
  1107. // variable in length, so the FilePath structure may not be aligned
  1108. //
  1109. aOsLoadPath = GetAlignedOsLoadPath(osOptions, &aOsLoadPathSize);
  1110. DisplayLoadPath(aOsLoadPath);
  1111. FreePool(aOsLoadPath);
  1112. Print (L"<<<<\n");
  1113. }
  1114. VOID
  1115. DisplayELO(
  1116. char* elo,
  1117. UINT64 eloSize
  1118. )
  1119. {
  1120. PEFI_LOAD_OPTION pElo;
  1121. #if 0
  1122. UINT64 eloSize;
  1123. #endif
  1124. CHAR16 FilePathShort[200];
  1125. char* aOsOptions;
  1126. pElo = (EFI_LOAD_OPTION*)elo;
  1127. Print (L"elo->Attributes = %x\n", pElo->Attributes);
  1128. Print (L"elo->FilePathListLength = %x\n", pElo->FilePathListLength);
  1129. Print (L"elo->Description = %s\n", pElo->Description);
  1130. GetFilePathShort(
  1131. (EFI_DEVICE_PATH *)&elo[FIELD_OFFSET(EFI_LOAD_OPTION, Description) + StrSize(pElo->Description)],
  1132. FilePathShort
  1133. );
  1134. Print (L"elo->FilePath(EFI:DP:SHORT) = %s\n", FilePathShort);
  1135. #if 0
  1136. eloSize = FIELD_OFFSET(EFI_LOAD_OPTION, Description) + StrSize(pElo->Description) + pElo->FilePathListLength;
  1137. DisplayOsOptions(&elo[eloSize]);
  1138. #else
  1139. aOsOptions = GetAlignedOsOptions(
  1140. elo,
  1141. eloSize
  1142. );
  1143. DisplayOsOptions(aOsOptions);
  1144. FreePool(aOsOptions);
  1145. #endif
  1146. }
  1147. VOID
  1148. BuildNewOsOptions(
  1149. IN CHAR16* osLoadOptions,
  1150. IN char* osLoadPath,
  1151. OUT char** osOptions
  1152. )
  1153. //
  1154. //
  1155. // Note: osLoadPath must be aligned
  1156. //
  1157. {
  1158. char* newOsOptions;
  1159. PWINDOWS_OS_OPTIONS pNewOsOptions;
  1160. UINT32 osLoadOptionsLength;
  1161. UINT32 osOptionsLength;
  1162. PFILE_PATH pOsLoadPath;
  1163. //
  1164. // NOTE: aligning the FILE_PATH structure (osLoadPath) works
  1165. // by aligning the osLoadOptionsLength because the
  1166. // WINDOWS_OS_OPTIONS structure has a UINT32 variable
  1167. // before the OsLoadOptions. If anything changes above
  1168. // the OsLoadOptions in the WINDOWS_OS_OPTIONS structure
  1169. // the alignment method may have to change in this structure.
  1170. //
  1171. //
  1172. //
  1173. // determine the size of the os load options (UNICODE) string
  1174. //
  1175. osLoadOptionsLength = (UINT32)StrSize(osLoadOptions);
  1176. osLoadOptionsLength = ALIGN_UP(osLoadOptionsLength, UINT32);
  1177. #if DEBUG_PACK
  1178. Print (L"osLoadOptionsLength = %x\n", osLoadOptionsLength);
  1179. #endif
  1180. pOsLoadPath = (FILE_PATH*)osLoadPath;
  1181. #if DEBUG_PACK
  1182. Print (L"pOsLoadPath->Length = %x\n", pOsLoadPath->Length);
  1183. #endif
  1184. //
  1185. // determine the size of the new WINDOWS_OS_OPTIONS structure
  1186. //
  1187. osOptionsLength = FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) + osLoadOptionsLength + pOsLoadPath->Length;
  1188. #if DEBUG_PACK
  1189. Print (L"osOptionsLength = %x\n", osOptionsLength);
  1190. #endif
  1191. //
  1192. // Allocate memory for the WINDOWS_OS_OPTIONS
  1193. //
  1194. newOsOptions = AllocatePool(osOptionsLength);
  1195. ASSERT(newOsOptions != NULL);
  1196. pNewOsOptions = (WINDOWS_OS_OPTIONS*)newOsOptions;
  1197. //
  1198. // populate the new os options
  1199. //
  1200. StrCpyA((char *)pNewOsOptions->Signature, WINDOWS_OS_OPTIONS_SIGNATURE);
  1201. pNewOsOptions->Version = WINDOWS_OS_OPTIONS_VERSION;
  1202. pNewOsOptions->Length = (UINT32)osOptionsLength;
  1203. pNewOsOptions->OsLoadPathOffset = FIELD_OFFSET(WINDOWS_OS_OPTIONS, OsLoadOptions) + osLoadOptionsLength;
  1204. StrCpy(pNewOsOptions->OsLoadOptions, osLoadOptions);
  1205. CopyMem( &newOsOptions[pNewOsOptions->OsLoadPathOffset], osLoadPath, pOsLoadPath->Length );
  1206. *osOptions = newOsOptions;
  1207. }
  1208. VOID
  1209. PackLoadOption(
  1210. IN UINT32 BootVarNum,
  1211. IN CHAR16* LoadIdentifier,
  1212. IN CHAR16* OsLoadOptions,
  1213. IN char* EfiFilePath,
  1214. IN UINT16 EfiFilePathListLength, // 0 if not updated
  1215. IN char* OsLoadPath,
  1216. IN UINT16 OsLoadPathListLength // 0 if not updated
  1217. )
  1218. /*
  1219. PackLoadOption
  1220. Purpose: To construct an EFI_LOAD_OPTION structure using user arguments
  1221. and load the structure into into BootXXXX, where XXXX = BootVarNum.
  1222. See EFI spec, ch. 17
  1223. Args:
  1224. BootVarNum The boot option being written/modified
  1225. */
  1226. {
  1227. PEFI_LOAD_OPTION pOldElo;
  1228. PEFI_LOAD_OPTION pElo;
  1229. char* elo;
  1230. char* oldElo;
  1231. UINT64 oldEloSize;
  1232. UINT64 eloSize;
  1233. UINT8* oldEloFilePath;
  1234. UINT64 TempEfiFilePathListSize;
  1235. char* aFilePath;
  1236. UINT16 filePathListLength;
  1237. UINT16 loadPathListLength;
  1238. #if DEBUG_PACK
  1239. CHAR16 szInput[1024];
  1240. Print (L"BootVarNum = %x\n", BootVarNum);
  1241. Print (L"LoadIdentifier = %s\n", LoadIdentifier);
  1242. Print (L"OsLoadOptions = %s\n", OsLoadOptions);
  1243. Input (L"Here! [Pack begin] \n", szInput, sizeof(szInput));
  1244. Print(L"\n");
  1245. #endif
  1246. //
  1247. // The following code assumes EfiFilePath and OsLoadPath are pointer-aligned
  1248. // if the corresponding length exposes an update by the caller.
  1249. // Checking and failing at the function entry avoids unneeded memory allocations.
  1250. //
  1251. if ( EfiFilePathListLength && !POINTER_IS_ALIGNED(EfiFilePath, sizeof(void *))) {
  1252. ASSERT( POINTER_IS_ALIGNED(EfiFilePath, sizeof(void *)) );
  1253. Print (L"PackLoadOption: EfiFilePath unaligned.\n");
  1254. return;
  1255. }
  1256. if ( OsLoadPathListLength && !POINTER_IS_ALIGNED(OsLoadPath, sizeof(void *))) {
  1257. ASSERT( POINTER_IS_ALIGNED(OsLoadPath, sizeof(void *)) );
  1258. Print (L"PackLoadOption: OsLoadPath unaligned.\n");
  1259. return;
  1260. }
  1261. oldElo = LoadOptions[BootVarNum];
  1262. oldEloSize = LoadOptionsSize[BootVarNum];
  1263. #if DEBUG_PACK
  1264. DisplayELO(oldElo, oldEloSize);
  1265. Input (L"Here! [Pack begin] \n", szInput, sizeof(szInput));
  1266. Print(L"\n");
  1267. #endif
  1268. //
  1269. // allocate the elo structure with maximal amount of memory allowed for
  1270. // an EFI_LOAD_OPTION
  1271. //
  1272. elo = AllocatePool(MAXBOOTVARSIZE);
  1273. if (elo == NULL) {
  1274. Print (L"PackLoadOption: elo allocation failed. size=%d\n", MAXBOOTVARSIZE);
  1275. return;
  1276. }
  1277. pElo = (EFI_LOAD_OPTION*)elo;
  1278. pOldElo = (EFI_LOAD_OPTION*)oldElo;
  1279. //
  1280. // Efi Attribute.
  1281. //
  1282. eloSize = sizeof(pElo->Attributes);
  1283. pElo->Attributes = pOldElo->Attributes;
  1284. //
  1285. // FilePathListLength
  1286. //
  1287. eloSize += sizeof(pElo->FilePathListLength);
  1288. filePathListLength = EfiFilePathListLength ? EfiFilePathListLength :
  1289. pOldElo->FilePathListLength;
  1290. pElo->FilePathListLength = filePathListLength;
  1291. //
  1292. // Description.
  1293. //
  1294. StrCpy( pElo->Description, LoadIdentifier );
  1295. eloSize += StrSize(LoadIdentifier);
  1296. if ( EfiFilePathListLength == 0 ) {
  1297. //
  1298. // copy the FilePath from the old/existing ELO structure
  1299. //
  1300. // Note: we don't actually need an aligned filepath block for this
  1301. // copy, but there may come a time when we want to modify
  1302. // the filepath, which will require an aligned block.
  1303. //
  1304. aFilePath = GetAlignedELOFilePath(oldElo);
  1305. }
  1306. else {
  1307. // already checked: ASSERT( POINTER_IS_ALIGNED(EfiFilePath, sizeof(void *)) );
  1308. aFilePath = EfiFilePath;
  1309. }
  1310. CopyMem( &elo[eloSize],
  1311. aFilePath,
  1312. filePathListLength
  1313. );
  1314. eloSize += filePathListLength;
  1315. if ( EfiFilePathListLength == 0 ) {
  1316. FreePool(aFilePath);
  1317. }
  1318. #if DEBUG_PACK
  1319. Print (L"eloSize = %x\n", eloSize);
  1320. Input (L"Here! \n", szInput, sizeof(szInput));
  1321. Print(L"\n");
  1322. #endif
  1323. //
  1324. // add or modify the boot option
  1325. //
  1326. if ( BootVarNum == -1 ) {
  1327. Print(L"Adding currently disabled\n");
  1328. } else {
  1329. char* osOptions;
  1330. char* aOsLoadPath = NULL;
  1331. char* aOldOsOptions;
  1332. PWINDOWS_OS_OPTIONS pOldOsOptions;
  1333. PWINDOWS_OS_OPTIONS pOsOptions;
  1334. UINTN aOsLoadPathSize;
  1335. //
  1336. // OptionalData.
  1337. //
  1338. // For a Windows OS boot option, the OptionalData field in the EFI_LOAD_OPTION
  1339. // structure is a WINDOWS_OS_OPTION structure.
  1340. //
  1341. // get the WINDOWS_OS_OPTIONS from the old/existing boot entry
  1342. //
  1343. aOldOsOptions = GetAlignedOsOptions(oldElo, oldEloSize);
  1344. pOldOsOptions = (WINDOWS_OS_OPTIONS*)aOldOsOptions;
  1345. //
  1346. // Get the LoadPath from the old/existing WINDOWS_OS_OPTIONS structure
  1347. //
  1348. // we need to align the FilePath structure because the load options are
  1349. // variable in length, so the FilePath structure may not be aligned
  1350. //
  1351. if ( OsLoadPathListLength == 0 ) {
  1352. aOsLoadPath = GetAlignedOsLoadPath(aOldOsOptions, &aOsLoadPathSize);
  1353. }
  1354. else {
  1355. FILE_PATH *filePath;
  1356. // already checked: ASSERT( POINTER_IS_ALIGNED(OsLoadPath, sizeof(void *)) );
  1357. aOsLoadPath = OsLoadPath;
  1358. filePath = (FILE_PATH *)aOsLoadPath;
  1359. filePath->Length = OsLoadPathListLength;
  1360. }
  1361. FreePool(aOldOsOptions);
  1362. //
  1363. // Construct a new WINDOWS_OS_STRUCTURE with the new values
  1364. //
  1365. BuildNewOsOptions(
  1366. OsLoadOptions,
  1367. aOsLoadPath,
  1368. &osOptions
  1369. );
  1370. if ( OsLoadPathListLength == 0 ) {
  1371. FreePool(aOsLoadPath);
  1372. }
  1373. #if DEBUG_PACK
  1374. Input (L"build\n", szInput, sizeof(szInput) );
  1375. Print(L"\n");
  1376. DisplayOsOptions(osOptions);
  1377. Input (L"elo freed\n", szInput, sizeof(szInput) );
  1378. Print(L"\n");
  1379. #endif
  1380. pOsOptions = (WINDOWS_OS_OPTIONS*)osOptions;
  1381. //
  1382. // Copy the new WINDOWS_OS_OPTIONS structure into the new EFI_LOAD_OPTION structure
  1383. //
  1384. CopyMem( &elo[eloSize], osOptions, pOsOptions->Length);
  1385. eloSize += pOsOptions->Length;
  1386. #if DEBUG_PACK
  1387. Print (L"osOptions->Length = %x\n", pOsOptions->Length);
  1388. Print (L"eloSize = %x\n", eloSize);
  1389. #endif
  1390. FreePool(osOptions);
  1391. //
  1392. // Modify current boot options.
  1393. //
  1394. LoadOptions[BootVarNum] = ReallocatePool( LoadOptions[BootVarNum], LoadOptionsSize[BootVarNum], eloSize );
  1395. LoadOptionsSize[BootVarNum] = eloSize;
  1396. CopyMem( LoadOptions[BootVarNum], elo, eloSize );
  1397. }
  1398. FreePool(elo);
  1399. ASSERT(eloSize < MAXBOOTVARSIZE);
  1400. #if DEBUG_PACK
  1401. Input (L"elo freed\n", szInput, sizeof(szInput) );
  1402. Print(L"\n");
  1403. Print (L">>\n");
  1404. DisplayELO((char*)LoadOptions[BootVarNum], LoadOptionsSize[BootVarNum]);
  1405. Print (L"<<\n");
  1406. Input (L"pack done\n", szInput, sizeof(szInput) );
  1407. Print(L"\n");
  1408. #endif
  1409. }
  1410. EFI_STATUS
  1411. AppendEntryToBootOrder(
  1412. UINT16 BootNumber
  1413. )
  1414. {
  1415. EFI_STATUS status;
  1416. UINT64 oldBootOrderSize;
  1417. UINT64 newBootOrderSize;
  1418. VOID* newBootOrder;
  1419. VOID* oldBootOrder;
  1420. newBootOrder = NULL;
  1421. oldBootOrder = NULL;
  1422. //
  1423. // get the existing boot order array
  1424. //
  1425. oldBootOrder = LibGetVariableAndSize( L"BootOrder", &VenEfi, &oldBootOrderSize );
  1426. if ((!oldBootOrder) &&
  1427. (oldBootOrderSize != 0)
  1428. ) {
  1429. Print(L"\nError: Failed to get old boot order array.\n");
  1430. status = EFI_OUT_OF_RESOURCES;
  1431. goto Done;
  1432. }
  1433. //
  1434. // allocate the new boot order array
  1435. //
  1436. newBootOrderSize = oldBootOrderSize + sizeof(BootNumber);
  1437. newBootOrder = AllocatePool( newBootOrderSize );
  1438. if (! newBootOrder) {
  1439. Print(L"\nError: Failed to allocate new boot order array.\n");
  1440. status = EFI_OUT_OF_RESOURCES;
  1441. goto Done;
  1442. }
  1443. //
  1444. // append the new boot entry to the bottom of the list
  1445. //
  1446. CopyMem(
  1447. (CHAR8*)newBootOrder,
  1448. oldBootOrder,
  1449. oldBootOrderSize
  1450. );
  1451. CopyMem(
  1452. (CHAR8*)newBootOrder + oldBootOrderSize,
  1453. &BootNumber,
  1454. sizeof(BootNumber) );
  1455. status = SetVariable(
  1456. L"BootOrder",
  1457. &VenEfi,
  1458. EFI_ATTR,
  1459. newBootOrderSize,
  1460. newBootOrder
  1461. );
  1462. Done:
  1463. if (oldBootOrder) {
  1464. FreePool( oldBootOrder );
  1465. }
  1466. if (newBootOrder) {
  1467. FreePool(newBootOrder);
  1468. }
  1469. return status;
  1470. }
  1471. EFI_STATUS
  1472. WritePackedDataToNvr(
  1473. UINT16 BootNumber,
  1474. VOID *BootOption,
  1475. UINT32 BootSize
  1476. )
  1477. {
  1478. EFI_STATUS status;
  1479. CHAR16 VariableName[10];
  1480. //
  1481. // Don't attempt to write the BootEntry if it has no size.
  1482. //
  1483. if (BootSize == 0) {
  1484. return EFI_SUCCESS;
  1485. }
  1486. SPrint( VariableName, sizeof(VariableName), L"Boot%04x", BootNumber );
  1487. status = SetVariable(
  1488. VariableName,
  1489. &VenEfi,
  1490. EFI_ATTR,
  1491. BootSize,
  1492. BootOption
  1493. );
  1494. if (status == EFI_SUCCESS) {
  1495. status = AppendEntryToBootOrder(BootNumber);
  1496. if (status != EFI_SUCCESS) {
  1497. Print(L"\nError: Failed to append new boot entry to boot order array\n");
  1498. goto Done;
  1499. }
  1500. } else {
  1501. Print(L"\nError: Failed to set new boot entry variable\n");
  1502. goto Done;
  1503. }
  1504. //
  1505. // repopulate the local info about boot entries
  1506. //
  1507. FreeBootManagerVars();
  1508. GetBootManagerVars();
  1509. Done:
  1510. return status;
  1511. }
  1512. #if DEBUG_PACK
  1513. VOID
  1514. DisplayELOFromLoadOption(
  1515. IN UINT32 OptionNum
  1516. )
  1517. {
  1518. char* elo;
  1519. PEFI_LOAD_OPTION pElo;
  1520. //
  1521. // Make sure it is a valid OS load option
  1522. //
  1523. if (OptionNum >= BootOrderCount) {
  1524. return;
  1525. }
  1526. if (OptionNum >= MAXBOOTVARS) {
  1527. return;
  1528. }
  1529. if (LoadOptions[OptionNum] == NULL) {
  1530. return;
  1531. }
  1532. pElo = (EFI_LOAD_OPTION*)LoadOptions[OptionNum];
  1533. elo = (char*)LoadOptions[OptionNum];
  1534. DisplayELO(elo, LoadOptionsSize[OptionNum]);
  1535. }
  1536. #endif
  1537. VOID
  1538. GetFieldFromLoadOption(
  1539. IN UINT32 OptionNum,
  1540. IN UINT32 FieldType,
  1541. OUT VOID* Data,
  1542. OUT UINT64* DataSize
  1543. )
  1544. {
  1545. char* elo;
  1546. PEFI_LOAD_OPTION pElo;
  1547. //
  1548. // Make sure it is a valid OS load option
  1549. //
  1550. if (OptionNum >= BootOrderCount) {
  1551. return;
  1552. }
  1553. if (OptionNum >= MAXBOOTVARS) {
  1554. return;
  1555. }
  1556. if (LoadOptions[OptionNum] == NULL) {
  1557. *DataSize = 0;
  1558. return;
  1559. }
  1560. pElo = (EFI_LOAD_OPTION*)LoadOptions[OptionNum];
  1561. elo = (char*)LoadOptions[OptionNum];
  1562. switch ( FieldType ) {
  1563. case ATTRIBUTE: {
  1564. *((UINT32*) Data) = pElo->Attributes;
  1565. *DataSize = sizeof(UINT32);
  1566. break;
  1567. }
  1568. case FILEPATHLISTLENGTH: {
  1569. *((UINT16*) Data) = pElo->FilePathListLength;
  1570. *DataSize = sizeof(UINT16);
  1571. break;
  1572. }
  1573. case DESCRIPTION: {
  1574. StrCpy((CHAR16*)Data, pElo->Description);
  1575. *DataSize = StrSize(pElo->Description);
  1576. break;
  1577. }
  1578. case EFIFILEPATHLIST: {
  1579. char* aFilePath;
  1580. aFilePath = GetAlignedELOFilePath(elo);
  1581. CopyMem(Data,
  1582. aFilePath,
  1583. pElo->FilePathListLength
  1584. );
  1585. FreePool(aFilePath);
  1586. *DataSize = pElo->FilePathListLength;
  1587. break;
  1588. }
  1589. case OPTIONALDATA: {
  1590. char* aOptionalData;
  1591. UINT64 eloSize;
  1592. eloSize = LoadOptionsSize[OptionNum];
  1593. aOptionalData = GetAlignedOptionalData(elo,
  1594. eloSize,
  1595. DataSize
  1596. );
  1597. CopyMem(Data, aOptionalData, *DataSize);
  1598. FreePool(aOptionalData);
  1599. break;
  1600. }
  1601. default:
  1602. *DataSize = 0;
  1603. break;
  1604. }
  1605. }
  1606. BOOLEAN
  1607. GetLoadIdentifier(
  1608. IN UINT32 BootVarNum,
  1609. OUT CHAR16* LoadIdentifier
  1610. )
  1611. {
  1612. UINT64 DataSize = 0;
  1613. GetFieldFromLoadOption(
  1614. BootVarNum,
  1615. DESCRIPTION,
  1616. LoadIdentifier,
  1617. &DataSize
  1618. );
  1619. if (!DataSize)
  1620. return FALSE;
  1621. return TRUE;
  1622. }
  1623. VOID
  1624. GetEfiOsLoaderFilePath(
  1625. IN UINT32 BootVarNum,
  1626. OUT char* FilePath
  1627. )
  1628. {
  1629. UINT64 DataSize = 0;
  1630. GetFieldFromLoadOption(
  1631. BootVarNum,
  1632. EFIFILEPATHLIST,
  1633. FilePath,
  1634. &DataSize
  1635. );
  1636. }
  1637. BOOLEAN
  1638. GetOsLoadOptionVars(
  1639. IN UINT32 BootVarNum,
  1640. OUT CHAR16* LoadIdentifier,
  1641. OUT char* OsLoadOptions,
  1642. OUT char* EfiFilePath,
  1643. OUT char* OsLoadPath
  1644. )
  1645. {
  1646. if (BootVarNum >= BootOrderCount)
  1647. return FALSE;
  1648. if (BootVarNum >= MAXBOOTVARS) {
  1649. return FALSE;
  1650. }
  1651. if (!LoadOptions[BootVarNum])
  1652. return FALSE;
  1653. GetLoadIdentifier( BootVarNum, LoadIdentifier );
  1654. GetOptionalDataValue( BootVarNum, OSLOADOPTIONS, OsLoadOptions );
  1655. GetEfiOsLoaderFilePath( BootVarNum, EfiFilePath );
  1656. GetOptionalDataValue( BootVarNum, OSLOADPATH, OsLoadPath);
  1657. return TRUE;
  1658. }
  1659. VOID
  1660. GetOptionalDataValue(
  1661. IN UINT32 BootVarNum,
  1662. IN UINT32 Selection,
  1663. OUT char* OptionalDataValue
  1664. )
  1665. {
  1666. char osOptions[MAXBOOTVARSIZE];
  1667. UINT64 osOptionsSize;
  1668. PWINDOWS_OS_OPTIONS pOsOptions;
  1669. if (BootVarNum < MAXBOOTVARS) {
  1670. GetFieldFromLoadOption(
  1671. BootVarNum,
  1672. OPTIONALDATA,
  1673. osOptions,
  1674. &osOptionsSize
  1675. );
  1676. pOsOptions = (PWINDOWS_OS_OPTIONS)osOptions;
  1677. switch (Selection) {
  1678. case OSLOADOPTIONS: {
  1679. StrCpy( (CHAR16*)OptionalDataValue, pOsOptions->OsLoadOptions );
  1680. break;
  1681. }
  1682. case OSLOADPATH: {
  1683. char* aOsLoadPath;
  1684. UINTN aOsLoadPathSize;
  1685. aOsLoadPath = GetAlignedOsLoadPath(osOptions, &aOsLoadPathSize);
  1686. CopyMem(OptionalDataValue,
  1687. aOsLoadPath,
  1688. aOsLoadPathSize
  1689. );
  1690. FreePool(aOsLoadPath);
  1691. break;
  1692. }
  1693. default: {
  1694. break;
  1695. }
  1696. }
  1697. }
  1698. }
  1699. UINTN
  1700. GetDevPathSize(
  1701. IN EFI_DEVICE_PATH *DevPath
  1702. )
  1703. {
  1704. EFI_DEVICE_PATH *Start;
  1705. ASSERT(DevPath->Type != END_DEVICE_PATH_TYPE);
  1706. //
  1707. // Search for the end of the device path structure
  1708. //
  1709. Start = DevPath;
  1710. do {
  1711. DevPath = NextDevicePathNode(DevPath);
  1712. } while (DevPath->Type != END_DEVICE_PATH_TYPE);
  1713. //
  1714. // Compute the size
  1715. //
  1716. return(UINTN) ((UINT64) DevPath - (UINT64) Start);
  1717. }
  1718. UINT32
  1719. GetPartitions(
  1720. )
  1721. {
  1722. EFI_HANDLE EspHandles[100],FSPath;
  1723. UINT64 HandleArraySize = 100 * sizeof(EFI_HANDLE);
  1724. UINT64 CachedDevicePaths[100];
  1725. UINTN i, j;
  1726. UINTN CachedDevicePathsCount;
  1727. UINT64 SystemPartitionPathSize;
  1728. EFI_DEVICE_PATH *dp;
  1729. EFI_STATUS Status;
  1730. UINT32 PartitionCount;
  1731. char AlignedNode[1024];
  1732. //
  1733. // Get all handles that supports the block I/O protocol.
  1734. //
  1735. ZeroMem( EspHandles, HandleArraySize );
  1736. Status = LocateHandle (
  1737. ByProtocol,
  1738. &EfiESPProtocol,
  1739. 0,
  1740. (UINTN *) &HandleArraySize,
  1741. EspHandles
  1742. );
  1743. //
  1744. // Cache all of the EFI Device Paths.
  1745. //
  1746. for (i = 0; EspHandles[i] != 0; i++) {
  1747. Status = HandleProtocol (
  1748. EspHandles[i],
  1749. &DevicePathProtocol,
  1750. &( (EFI_DEVICE_PATH *) CachedDevicePaths[i] )
  1751. );
  1752. }
  1753. //
  1754. // Save the number of cached Device Paths.
  1755. //
  1756. CachedDevicePathsCount = i;
  1757. PartitionCount = 0;
  1758. //
  1759. // Find the first partition on the first hard drive
  1760. // partition. That is our SystemPartition.
  1761. //
  1762. for ( i=0; i<CachedDevicePathsCount; i++ ) {
  1763. dp = (EFI_DEVICE_PATH*) CachedDevicePaths[i];
  1764. while (( DevicePathType(dp) != END_DEVICE_PATH_TYPE ) &&
  1765. ( DevicePathSubType(dp) != END_ENTIRE_DEVICE_PATH_SUBTYPE )) {
  1766. if (( DevicePathType(dp) == MEDIA_DEVICE_PATH ) &&
  1767. ( DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP )) {
  1768. CopyMem( AlignedNode, dp, DevicePathNodeLength(dp) );
  1769. HandleProtocol (EspHandles[i],&FileSystemProtocol,&FSPath);
  1770. if ( FSPath != NULL) {
  1771. PartitionCount++;
  1772. }
  1773. }
  1774. dp = NextDevicePathNode(dp);
  1775. }
  1776. }
  1777. return PartitionCount;
  1778. }
  1779. EFI_HANDLE
  1780. GetDeviceHandleForPartition(
  1781. )
  1782. {
  1783. EFI_HANDLE EspHandles[100],FSPath;
  1784. UINT64 HandleArraySize = 100 * sizeof(EFI_HANDLE);
  1785. UINT64 CachedDevicePaths[100];
  1786. UINTN i, j;
  1787. UINTN CachedDevicePathsCount;
  1788. UINT64 SystemPartitionPathSize;
  1789. EFI_DEVICE_PATH *dp;
  1790. EFI_STATUS Status;
  1791. char AlignedNode[1024];
  1792. //
  1793. // Get all handles that supports the block I/O protocol.
  1794. //
  1795. ZeroMem( EspHandles, HandleArraySize );
  1796. Status = LocateHandle (
  1797. ByProtocol,
  1798. &EfiESPProtocol,
  1799. 0,
  1800. (UINTN *) &HandleArraySize,
  1801. EspHandles
  1802. );
  1803. //
  1804. // Cache all of the EFI Device Paths.
  1805. //
  1806. for (i = 0; EspHandles[i] != 0; i++) {
  1807. Status = HandleProtocol (
  1808. EspHandles[i],
  1809. &DevicePathProtocol,
  1810. &( (EFI_DEVICE_PATH *) CachedDevicePaths[i] )
  1811. );
  1812. }
  1813. //
  1814. // Save the number of cached Device Paths.
  1815. //
  1816. CachedDevicePathsCount = i;
  1817. //
  1818. // Find the first ESP partition on the first hard drive
  1819. // partition. That is our SystemPartition.
  1820. //
  1821. for ( i=0; i<CachedDevicePathsCount; i++ ) {
  1822. dp = (EFI_DEVICE_PATH*) CachedDevicePaths[i];
  1823. while (( DevicePathType(dp) != END_DEVICE_PATH_TYPE ) &&
  1824. ( DevicePathSubType(dp) != END_ENTIRE_DEVICE_PATH_SUBTYPE )) {
  1825. if (( DevicePathType(dp) == MEDIA_DEVICE_PATH ) &&
  1826. ( DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP )) {
  1827. CopyMem( AlignedNode, dp, DevicePathNodeLength(dp) );
  1828. HandleProtocol (EspHandles[i],&FileSystemProtocol,&FSPath);
  1829. if ( FSPath != NULL) {
  1830. //
  1831. // Found the correct device path partition.
  1832. // Return the device handle.
  1833. //
  1834. return( EspHandles[i] );
  1835. }
  1836. }
  1837. dp = NextDevicePathNode(dp);
  1838. }
  1839. }
  1840. return NULL;
  1841. }
  1842. /*
  1843. ** BUGBUG: These functions need to be eventually placed in lib\str.c
  1844. */
  1845. INTN
  1846. RUNTIMEFUNCTION
  1847. StrCmpA (
  1848. IN CHAR8 *s1,
  1849. IN CHAR8 *s2
  1850. )
  1851. /* compare strings */
  1852. {
  1853. while (*s1) {
  1854. if (*s1 != *s2) {
  1855. break;
  1856. }
  1857. s1 += 1;
  1858. s2 += 1;
  1859. }
  1860. return *s1 - *s2;
  1861. }
  1862. VOID
  1863. RUNTIMEFUNCTION
  1864. StrCpyA (
  1865. IN CHAR8 *Dest,
  1866. IN CHAR8 *Src
  1867. )
  1868. /* copy strings */
  1869. {
  1870. while (*Src) {
  1871. *(Dest++) = *(Src++);
  1872. }
  1873. *Dest = 0;
  1874. }
  1875. VOID
  1876. RUNTIMEFUNCTION
  1877. StrCatA (
  1878. IN CHAR8 *Dest,
  1879. IN CHAR8 *Src
  1880. )
  1881. {
  1882. StrCpyA(Dest+StrLenA(Dest), Src);
  1883. }
  1884. UINTN
  1885. RUNTIMEFUNCTION
  1886. StrLenA (
  1887. IN CHAR8 *s1
  1888. )
  1889. /* string length */
  1890. {
  1891. UINTN len;
  1892. for (len=0; *s1; s1+=1, len+=1) ;
  1893. return len;
  1894. }
  1895. UINTN
  1896. RUNTIMEFUNCTION
  1897. StrSizeA (
  1898. IN CHAR8 *s1
  1899. )
  1900. /* string size */
  1901. {
  1902. UINTN len;
  1903. for (len=0; *s1; s1+=1, len+=1) ;
  1904. return(len + 1) * sizeof(CHAR8);
  1905. }