bdsutil.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. bdsutil.c
  9. Abstract:
  10. This module implements support routines for the Boot Device Selection
  11. module.
  12. Author:
  13. Evan Green 17-Mar-2014
  14. Environment:
  15. Firmware
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "ueficore.h"
  21. #include "bds.h"
  22. #include "fileinfo.h"
  23. #include <minoca/uefi/protocol/loadimg.h>
  24. #include <minoca/uefi/protocol/sfilesys.h>
  25. //
  26. // ---------------------------------------------------------------- Definitions
  27. //
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. //
  32. // ----------------------------------------------- Internal Function Prototypes
  33. //
  34. EFI_STATUS
  35. EfipBdsConnectAllEfi (
  36. VOID
  37. );
  38. EFI_STATUS
  39. EfipBdsDisconnectAllEfi (
  40. VOID
  41. );
  42. UINT16
  43. EfipBdsGetHexCodeFromString (
  44. CHAR16 *HexCodeString
  45. );
  46. UINTN
  47. EfipBdsStringSize (
  48. CONST CHAR16 *String,
  49. UINTN MaxStringSize
  50. );
  51. UINTN
  52. EfipBdsGetDevicePathSize (
  53. CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  54. UINTN MaxSize
  55. );
  56. UINT16
  57. EfipBdsGetFreeOptionNumber (
  58. CHAR16 *VariableName
  59. );
  60. //
  61. // -------------------------------------------------------------------- Globals
  62. //
  63. //
  64. // ------------------------------------------------------------------ Functions
  65. //
  66. VOID
  67. EfipBdsConnectAll (
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. This routine connects all system drivers to controllers first, then
  73. specially connect the default console. This ensures all system controllers
  74. are available and the platform default console is connected.
  75. Arguments:
  76. None.
  77. Return Value:
  78. None.
  79. --*/
  80. {
  81. EfipBdsConnectAllDefaultConsoles();
  82. EfipBdsConnectAllDriversToAllControllers();
  83. EfipBdsConnectAllDefaultConsoles();
  84. }
  85. VOID
  86. EfipBdsConnectAllDriversToAllControllers (
  87. VOID
  88. )
  89. /*++
  90. Routine Description:
  91. This routine connects all system drivers to controllers.
  92. Arguments:
  93. None.
  94. Return Value:
  95. None.
  96. --*/
  97. {
  98. EFI_STATUS Status;
  99. do {
  100. EfipBdsConnectAllEfi();
  101. Status = EfiCoreDispatcher();
  102. } while (!EFI_ERROR(Status));
  103. return;
  104. }
  105. VOID
  106. EfipBdsLoadDrivers (
  107. PLIST_ENTRY DriverList
  108. )
  109. /*++
  110. Routine Description:
  111. This routine loads and starts every driver on the given load list.
  112. Arguments:
  113. DriverList - Supplies a pointer to the head of the list of boot options
  114. describing the drivers to load.
  115. Return Value:
  116. None.
  117. --*/
  118. {
  119. PLIST_ENTRY CurrentEntry;
  120. CHAR16 *ExitData;
  121. UINTN ExitDataSize;
  122. EFI_HANDLE ImageHandle;
  123. EFI_LOADED_IMAGE_PROTOCOL *ImageInformation;
  124. PEFI_BDS_COMMON_OPTION Option;
  125. BOOLEAN ReconnectAll;
  126. EFI_STATUS Status;
  127. ReconnectAll = FALSE;
  128. CurrentEntry = DriverList->Next;
  129. while (CurrentEntry != DriverList) {
  130. Option = LIST_VALUE(CurrentEntry, EFI_BDS_COMMON_OPTION, ListEntry);
  131. CurrentEntry = CurrentEntry->Next;
  132. ASSERT(Option->Magic == EFI_BDS_COMMON_OPTION_MAGIC);
  133. //
  134. // Skip options not marked active.
  135. //
  136. if ((Option->Attribute & LOAD_OPTION_ACTIVE) == 0) {
  137. continue;
  138. }
  139. //
  140. // If the force reconnect is enabled, then all EFI drivers in the
  141. // system will be disconnected and reconnected after the last driver
  142. // load option is processed.
  143. //
  144. if ((Option->Attribute & LOAD_OPTION_FORCE_RECONNECT) != 0) {
  145. ReconnectAll = TRUE;
  146. }
  147. //
  148. // Make sure the driver path is connected.
  149. //
  150. EfipBdsConnectDevicePath(Option->DevicePath);
  151. //
  152. // Load and start the image that Driver#### describes.
  153. //
  154. Status = EfiLoadImage(FALSE,
  155. EfiFirmwareImageHandle,
  156. Option->DevicePath,
  157. NULL,
  158. 0,
  159. &ImageHandle);
  160. if (!EFI_ERROR(Status)) {
  161. Status = EfiHandleProtocol(ImageHandle,
  162. &EfiLoadedImageProtocolGuid,
  163. (VOID **)&ImageInformation);
  164. ASSERT(!EFI_ERROR(Status));
  165. //
  166. // Verify that this image is a driver.
  167. //
  168. if ((ImageInformation == NULL) ||
  169. ((ImageInformation->ImageCodeType != EfiBootServicesCode) &&
  170. (ImageInformation->ImageCodeType != EfiRuntimeServicesCode))) {
  171. EfiExit(ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
  172. continue;
  173. }
  174. if (Option->LoadOptionsSize != 0) {
  175. ImageInformation->LoadOptionsSize = Option->LoadOptionsSize;
  176. ImageInformation->LoadOptions = Option->LoadOptions;
  177. }
  178. //
  179. // Enable the watchdog timer for 5 minutes.
  180. //
  181. EfiSetWatchdogTimer(EFI_DEFAULT_WATCHDOG_DURATION, 0, 0, NULL);
  182. //
  183. // Go launch the driver.
  184. //
  185. Status = EfiStartImage(ImageHandle, &ExitDataSize, &ExitData);
  186. //
  187. // Clear the watchdog timer, as the image has returned.
  188. //
  189. EfiSetWatchdogTimer(0, 0, 0, NULL);
  190. }
  191. }
  192. if (ReconnectAll != FALSE) {
  193. EfipBdsDisconnectAllEfi();
  194. EfipBdsConnectAll();
  195. }
  196. return;
  197. }
  198. EFI_STATUS
  199. EfipBdsBuildOptionFromVariable (
  200. PLIST_ENTRY OptionList,
  201. CHAR16 *VariableName
  202. )
  203. /*++
  204. Routine Description:
  205. This routine processes BootOrder or DriverOrder variables.
  206. Arguments:
  207. OptionList - Supplies a pointer to the head of the list of boot or
  208. driver options.
  209. VariableName - Supplies a pointer to the variable name indicating the boot
  210. order or driver order. Typically this should be BootOrder or
  211. DriverOrder.
  212. Return Value:
  213. EFI status code.
  214. --*/
  215. {
  216. UINTN Index;
  217. PEFI_BDS_COMMON_OPTION Option;
  218. CHAR16 OptionName[20];
  219. UINT16 *OptionOrder;
  220. UINTN OptionOrderSize;
  221. EfiCoreSetMemory(OptionName, sizeof(OptionName), 0);
  222. //
  223. // Read in the BootOrder or DriverOrder variable.
  224. //
  225. OptionOrder = EfipBdsGetVariable(VariableName,
  226. &EfiGlobalVariableGuid,
  227. &OptionOrderSize);
  228. if (OptionOrder == NULL) {
  229. return EFI_OUT_OF_RESOURCES;
  230. }
  231. for (Index = 0; Index < (OptionOrderSize / sizeof(UINT16)); Index += 1) {
  232. if (*VariableName == 'B') {
  233. EfipBdsCreateHexCodeString(L"Boot",
  234. OptionOrder[Index],
  235. OptionName,
  236. sizeof(OptionName));
  237. } else {
  238. EfipBdsCreateHexCodeString(L"Driver",
  239. OptionOrder[Index],
  240. OptionName,
  241. sizeof(OptionName));
  242. }
  243. Option = EfipBdsConvertVariableToOption(OptionList, OptionName);
  244. if (Option != NULL) {
  245. Option->BootCurrent = OptionOrder[Index];
  246. }
  247. }
  248. EfiCoreFreePool(OptionOrder);
  249. return EFI_SUCCESS;
  250. }
  251. PEFI_BDS_COMMON_OPTION
  252. EfipBdsConvertVariableToOption (
  253. PLIST_ENTRY OptionList,
  254. CHAR16 *VariableName
  255. )
  256. /*++
  257. Routine Description:
  258. This routine builds a Boot#### or Driver#### option from the given variable
  259. name. The new option will also be linked into the given list.
  260. Arguments:
  261. OptionList - Supplies a pointer to the list to link the option into upon
  262. success.
  263. VariableName - Supplies a pointer to the variable name, which is typically
  264. in the form Boot#### or Driver####.
  265. Return Value:
  266. Returns a pointer to the option on success.
  267. NULL on failure.
  268. --*/
  269. {
  270. UINT32 Attribute;
  271. UINT8 *CurrentOffset;
  272. CHAR16 *Description;
  273. UINTN DescriptionSize;
  274. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  275. UINTN DevicePathSize;
  276. UINT16 FilePathSize;
  277. VOID *LoadOptions;
  278. UINT32 LoadOptionsSize;
  279. PEFI_BDS_COMMON_OPTION Option;
  280. EFI_STATUS Status;
  281. UINT8 *Variable;
  282. UINTN VariableSize;
  283. Option = NULL;
  284. Status = EFI_OUT_OF_RESOURCES;
  285. //
  286. // Read in the variable.
  287. //
  288. Variable = EfipBdsGetVariable(VariableName,
  289. &EfiGlobalVariableGuid,
  290. &VariableSize);
  291. if (Variable == NULL) {
  292. return NULL;
  293. }
  294. if (EfipBdsValidateOption(Variable, VariableSize) == FALSE) {
  295. goto BdsVariableToOptionEnd;
  296. }
  297. //
  298. // Pull the members of this variable length structure out of the binary
  299. // blob. Start with the option attribute.
  300. //
  301. CurrentOffset = Variable;
  302. Attribute = *(UINT32 *)Variable;
  303. CurrentOffset += sizeof(UINT32);
  304. //
  305. // Get the options device path size.
  306. //
  307. FilePathSize = *(UINT16 *)CurrentOffset;
  308. CurrentOffset += sizeof(UINT16);
  309. //
  310. // Get the option's description string.
  311. //
  312. Description = (CHAR16 *)CurrentOffset;
  313. DescriptionSize = (EfiCoreStringLength(Description) + 1) * sizeof(CHAR16);
  314. CurrentOffset += DescriptionSize;
  315. //
  316. // Get the option's device path.
  317. //
  318. DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)CurrentOffset;
  319. CurrentOffset += FilePathSize;
  320. //
  321. // Get the load option data.
  322. //
  323. LoadOptions = CurrentOffset;
  324. LoadOptionsSize = (UINT32)(VariableSize -
  325. ((UINTN)CurrentOffset - (UINTN)Variable));
  326. Option = EfiCoreAllocateBootPool(sizeof(EFI_BDS_COMMON_OPTION));
  327. if (Option == NULL) {
  328. goto BdsVariableToOptionEnd;
  329. }
  330. EfiCoreSetMemory(Option, sizeof(EFI_BDS_COMMON_OPTION), 0);
  331. Option->Magic = EFI_BDS_COMMON_OPTION_MAGIC;
  332. DevicePathSize = EfiCoreGetDevicePathSize(DevicePath);
  333. Option->DevicePath = EfiCoreAllocateBootPool(DevicePathSize);
  334. if (Option->DevicePath == NULL) {
  335. goto BdsVariableToOptionEnd;
  336. }
  337. EfiCoreCopyMemory(Option->DevicePath, DevicePath, DevicePathSize);
  338. Option->Attribute = Attribute;
  339. Option->Description = EfiCoreAllocateBootPool(DescriptionSize);
  340. if (Option->Description == NULL) {
  341. goto BdsVariableToOptionEnd;
  342. }
  343. EfiCoreCopyMemory(Option->Description, Description, DescriptionSize);
  344. Option->LoadOptions = EfiCoreAllocateBootPool(LoadOptionsSize);
  345. if (Option->LoadOptions == NULL) {
  346. goto BdsVariableToOptionEnd;
  347. }
  348. EfiCoreCopyMemory(Option->LoadOptions, LoadOptions, LoadOptionsSize);
  349. Option->LoadOptionsSize = LoadOptionsSize;
  350. //
  351. // Get the value from the variable name string if this is a boot option.
  352. //
  353. if (*VariableName == L'B') {
  354. Option->BootCurrent = EfipBdsGetHexCodeFromString(
  355. &(VariableName[0]) + 4);
  356. }
  357. INSERT_BEFORE(&(Option->ListEntry), OptionList);
  358. Status = EFI_SUCCESS;
  359. BdsVariableToOptionEnd:
  360. if (Variable != NULL) {
  361. EfiCoreFreePool(Variable);
  362. }
  363. if (EFI_ERROR(Status)) {
  364. if (Option != NULL) {
  365. if (Option->DevicePath != NULL) {
  366. EfiCoreFreePool(Option->DevicePath);
  367. }
  368. if (Option->Description != NULL) {
  369. EfiCoreFreePool(Option->Description);
  370. }
  371. if (Option->LoadOptions != NULL) {
  372. EfiCoreFreePool(Option->LoadOptions);
  373. }
  374. EfiCoreFreePool(Option);
  375. Option = NULL;
  376. }
  377. }
  378. return Option;
  379. }
  380. VOID *
  381. EfipBdsGetVariable (
  382. CHAR16 *Name,
  383. EFI_GUID *VendorGuid,
  384. UINTN *VariableSize
  385. )
  386. /*++
  387. Routine Description:
  388. This routine reads the given EFI variable and returns a buffer allocated
  389. from pool containing its contents.
  390. Arguments:
  391. Name - Supplies a pointer to the name of the variable to get.
  392. VendorGuid - Supplies the GUID part of the variable name.
  393. VariableSize - Supplies a pointer where the size of the variable contents
  394. will be returned on success.
  395. Return Value:
  396. Returns a pointer to the variable contents allocated from pool on success.
  397. The caller is responsible for freeing this memory.
  398. NULL on failure.
  399. --*/
  400. {
  401. VOID *Buffer;
  402. UINTN BufferSize;
  403. EFI_STATUS Status;
  404. Buffer = NULL;
  405. //
  406. // Call once to find out the size.
  407. //
  408. BufferSize = 0;
  409. Status = EfiGetVariable(Name, VendorGuid, NULL, &BufferSize, Buffer);
  410. if (Status == EFI_BUFFER_TOO_SMALL) {
  411. Buffer = EfiCoreAllocateBootPool(BufferSize);
  412. if (Buffer == NULL) {
  413. *VariableSize = 0;
  414. return NULL;
  415. }
  416. EfiCoreSetMemory(Buffer, BufferSize, 0);
  417. //
  418. // Now read it for real.
  419. //
  420. Status = EfiGetVariable(Name, VendorGuid, NULL, &BufferSize, Buffer);
  421. if (EFI_ERROR(Status)) {
  422. EfiCoreFreePool(Buffer);
  423. BufferSize = 0;
  424. Buffer = NULL;
  425. }
  426. }
  427. ASSERT(((Buffer == NULL) && (BufferSize == 0)) ||
  428. ((Buffer != NULL) && (BufferSize != 0)));
  429. *VariableSize = BufferSize;
  430. return Buffer;
  431. }
  432. EFI_DEVICE_PATH_PROTOCOL *
  433. EfipBdsDeletePartialMatchInstance (
  434. EFI_DEVICE_PATH_PROTOCOL *MultiInstancePath,
  435. EFI_DEVICE_PATH_PROTOCOL *SingleInstance
  436. )
  437. /*++
  438. Routine Description:
  439. This routine deletes the instance in the given multi-instance device path
  440. that matches partly with the given instance.
  441. Arguments:
  442. MultiInstancePath - Supplies a pointer to the multi-instance device path.
  443. SingleInstance - Supplies a pointer to the single-instance device path.
  444. Return Value:
  445. Returns the modified multi-instance path on success.
  446. NULL on failure.
  447. --*/
  448. {
  449. EFI_DEVICE_PATH_PROTOCOL *Instance;
  450. UINTN InstanceSize;
  451. EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
  452. EFI_DEVICE_PATH_PROTOCOL *OldNewDevicePath;
  453. UINT SingleSize;
  454. UINTN Size;
  455. NewDevicePath = NULL;
  456. OldNewDevicePath = NULL;
  457. if ((MultiInstancePath == NULL) || (SingleInstance == NULL)) {
  458. return MultiInstancePath;
  459. }
  460. Instance = EfiCoreGetNextDevicePathInstance(&MultiInstancePath,
  461. &InstanceSize);
  462. SingleSize = EfiCoreGetDevicePathSize(SingleInstance) -
  463. END_DEVICE_PATH_LENGTH;
  464. InstanceSize -= END_DEVICE_PATH_LENGTH;
  465. while (Instance != NULL) {
  466. Size = InstanceSize;
  467. if (SingleSize < InstanceSize) {
  468. Size = SingleSize;
  469. }
  470. //
  471. // If the instance doesn't match, append the instance.
  472. //
  473. if (EfiCoreCompareMemory(Instance, SingleInstance, Size) != 0) {
  474. OldNewDevicePath = NewDevicePath;
  475. NewDevicePath = EfiCoreAppendDevicePathInstance(NewDevicePath,
  476. Instance);
  477. if (OldNewDevicePath != NULL) {
  478. EfiCoreFreePool(OldNewDevicePath);
  479. }
  480. }
  481. EfiCoreFreePool(Instance);
  482. Instance = EfiCoreGetNextDevicePathInstance(&MultiInstancePath,
  483. &InstanceSize);
  484. InstanceSize -= END_DEVICE_PATH_LENGTH;
  485. }
  486. return NewDevicePath;
  487. }
  488. BOOLEAN
  489. EfipBdsMatchDevicePaths (
  490. EFI_DEVICE_PATH_PROTOCOL *MultiInstancePath,
  491. EFI_DEVICE_PATH_PROTOCOL *SingleInstance
  492. )
  493. /*++
  494. Routine Description:
  495. This routine compares a device path structure to that of all nodes of a
  496. second device path instance.
  497. Arguments:
  498. MultiInstancePath - Supplies a pointer to the multi-instance device path to
  499. search through.
  500. SingleInstance - Supplies a pointer to the single-instance device path to
  501. search for.
  502. Return Value:
  503. TRUE if the single instance path exists somewhere in the multi-instance
  504. path.
  505. FALSE if th single instance path is not found anywhere in the
  506. multi-instance path.
  507. --*/
  508. {
  509. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  510. EFI_DEVICE_PATH_PROTOCOL *Instance;
  511. UINTN Size;
  512. if ((MultiInstancePath == NULL) || (SingleInstance == NULL)) {
  513. return FALSE;
  514. }
  515. DevicePath = MultiInstancePath;
  516. Instance = EfiCoreGetNextDevicePathInstance(&DevicePath, &Size);
  517. while (Instance != NULL) {
  518. if (EfiCoreCompareMemory(SingleInstance, Instance, Size) == 0) {
  519. EfiCoreFreePool(Instance);
  520. return TRUE;
  521. }
  522. EfiCoreFreePool(Instance);
  523. Instance = EfiCoreGetNextDevicePathInstance(&DevicePath, &Size);
  524. }
  525. return FALSE;
  526. }
  527. EFI_STATUS
  528. EfipBdsRegisterNewOption (
  529. EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  530. CHAR16 *String,
  531. CHAR16 *VariableName
  532. )
  533. /*++
  534. Routine Description:
  535. This routine registers a new Boot#### or Driver#### option base on the
  536. given variable name. The BootOrder or DriverOrder will also be updated.
  537. Arguments:
  538. DevicePath - Supplies a pointer to the device path of the option.
  539. String - Supplies a pointer to a string describing the option.
  540. VariableName - Supplies a pointer to the string BootOrder or DriverOrder
  541. to update.
  542. Return Value:
  543. EFI status code.
  544. --*/
  545. {
  546. UINT32 Attributes;
  547. UINT16 BootOrderEntry;
  548. INTN CompareResult;
  549. CHAR16 *Description;
  550. UINTN DescriptionSize;
  551. UINTN DevicePathSize;
  552. UINTN Index;
  553. VOID *Option;
  554. EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
  555. UINTN OptionDevicePathSize;
  556. UINT8 *OptionMember;
  557. CHAR16 OptionName[10];
  558. UINT16 *OptionOrder;
  559. UINTN OptionSize;
  560. UINT16 *OptionVariable;
  561. UINTN OptionVariableSize;
  562. UINTN OrderItemCount;
  563. UINT16 RegisterOptionNumber;
  564. EFI_STATUS Status;
  565. UINTN StringSize;
  566. BOOLEAN UpdateDescription;
  567. Option = NULL;
  568. OptionSize = 0;
  569. OptionDevicePath = NULL;
  570. OptionVariable = NULL;
  571. OptionVariableSize = 0;
  572. Description = NULL;
  573. OptionOrder = NULL;
  574. UpdateDescription = FALSE;
  575. Status = EFI_SUCCESS;
  576. EfiCoreSetMemory(OptionName, sizeof(OptionName), 0);
  577. OptionVariable = EfipBdsGetVariable(VariableName,
  578. &EfiGlobalVariableGuid,
  579. &OptionVariableSize);
  580. ASSERT((OptionVariableSize == 0) || (OptionVariable != NULL));
  581. for (Index = 0; Index < OptionVariableSize / sizeof(UINT16); Index += 1) {
  582. if (*VariableName == L'B') {
  583. EfipBdsCreateHexCodeString(L"Boot",
  584. OptionVariable[Index],
  585. OptionName,
  586. sizeof(OptionName));
  587. } else {
  588. EfipBdsCreateHexCodeString(L"Driver",
  589. OptionVariable[Index],
  590. OptionName,
  591. sizeof(OptionName));
  592. }
  593. Option = EfipBdsGetVariable(OptionName,
  594. &EfiGlobalVariableGuid,
  595. &OptionSize);
  596. if (Option == NULL) {
  597. continue;
  598. }
  599. if (EfipBdsValidateOption(Option, OptionSize) == FALSE) {
  600. continue;
  601. }
  602. OptionMember = Option;
  603. OptionMember += sizeof(UINT32) + sizeof(UINT16);
  604. Description = (CHAR16 *)OptionMember;
  605. DescriptionSize = (EfiCoreStringLength(Description) + 1) *
  606. sizeof(CHAR16);
  607. OptionMember += DescriptionSize;
  608. OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)OptionMember;
  609. //
  610. // Check to see if the device path or description changed.
  611. //
  612. OptionDevicePathSize = EfiCoreGetDevicePathSize(OptionDevicePath);
  613. CompareResult = EfiCoreCompareMemory(OptionDevicePath,
  614. DevicePath,
  615. OptionDevicePathSize);
  616. if (CompareResult == 0) {
  617. CompareResult = EfiCoreCompareMemory(Description,
  618. String,
  619. DescriptionSize);
  620. //
  621. // This option already exists, so just return.
  622. //
  623. if (CompareResult == 0) {
  624. EfiCoreFreePool(Option);
  625. EfiCoreFreePool(OptionVariable);
  626. return EFI_SUCCESS;
  627. } else {
  628. UpdateDescription = TRUE;
  629. EfiCoreFreePool(Option);
  630. break;
  631. }
  632. }
  633. EfiCoreFreePool(Option);
  634. }
  635. //
  636. // Create the Boot#### or Driver#### boot option variable.
  637. //
  638. StringSize = (EfiCoreStringLength(String) + 1) * sizeof(CHAR16);
  639. OptionSize = sizeof(UINT32) + sizeof(UINT16) + StringSize;
  640. DevicePathSize = EfiCoreGetDevicePathSize(DevicePath);
  641. OptionSize += DevicePathSize;
  642. Option = EfiCoreAllocateBootPool(OptionSize);
  643. if (Option == NULL) {
  644. return EFI_OUT_OF_RESOURCES;
  645. }
  646. EfiCoreSetMemory(Option, OptionSize, 0);
  647. OptionMember = Option;
  648. *(UINT32 *)OptionMember = LOAD_OPTION_ACTIVE;
  649. OptionMember += sizeof(UINT32);
  650. *(UINT16 *)OptionMember = DevicePathSize;
  651. OptionMember += sizeof(UINT16);
  652. EfiCoreCopyMemory(OptionMember, String, StringSize);
  653. OptionMember += StringSize;
  654. EfiCoreCopyMemory(OptionMember, DevicePath, DevicePathSize);
  655. if (UpdateDescription != FALSE) {
  656. ASSERT(OptionVariable != NULL);
  657. RegisterOptionNumber = OptionVariable[Index];
  658. } else {
  659. RegisterOptionNumber = EfipBdsGetFreeOptionNumber(VariableName);
  660. }
  661. if (*VariableName == L'B') {
  662. EfipBdsCreateHexCodeString(L"Boot",
  663. RegisterOptionNumber,
  664. OptionName,
  665. sizeof(OptionName));
  666. } else {
  667. EfipBdsCreateHexCodeString(L"Driver",
  668. RegisterOptionNumber,
  669. OptionName,
  670. sizeof(OptionName));
  671. }
  672. Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
  673. EFI_VARIABLE_RUNTIME_ACCESS |
  674. EFI_VARIABLE_NON_VOLATILE;
  675. Status = EfiSetVariable(OptionName,
  676. &EfiGlobalVariableGuid,
  677. Attributes,
  678. OptionSize,
  679. Option);
  680. if ((EFI_ERROR(Status)) || (UpdateDescription != FALSE)) {
  681. EfiCoreFreePool(Option);
  682. if (OptionVariable != NULL) {
  683. EfiCoreFreePool(OptionVariable);
  684. }
  685. return Status;
  686. }
  687. EfiCoreFreePool(Option);
  688. //
  689. // Update the option order variable. If there was no option order, set one.
  690. //
  691. if (OptionVariableSize == 0) {
  692. BootOrderEntry = RegisterOptionNumber;
  693. Status = EfiSetVariable(VariableName,
  694. &EfiGlobalVariableGuid,
  695. Attributes,
  696. sizeof(UINT16),
  697. &BootOrderEntry);
  698. if (OptionVariable != NULL) {
  699. EfiCoreFreePool(OptionVariable);
  700. }
  701. return Status;
  702. }
  703. ASSERT(OptionVariable != NULL);
  704. //
  705. // Append the new option number to the original option order.
  706. //
  707. OrderItemCount = (OptionVariableSize / sizeof(UINT16)) + 1;
  708. OptionOrder = EfiCoreAllocateBootPool(OrderItemCount * sizeof(UINT16));
  709. if (OptionOrder == NULL) {
  710. EfiCoreFreePool(OptionVariable);
  711. return EFI_OUT_OF_RESOURCES;
  712. }
  713. EfiCoreCopyMemory(OptionOrder, OptionVariable, OptionVariableSize);
  714. OptionOrder[Index] = RegisterOptionNumber;
  715. Status = EfiSetVariable(VariableName,
  716. &EfiGlobalVariableGuid,
  717. Attributes,
  718. OrderItemCount * sizeof(UINT16),
  719. OptionOrder);
  720. EfiCoreFreePool(OptionVariable);
  721. EfiCoreFreePool(OptionOrder);
  722. return Status;
  723. }
  724. EFI_STATUS
  725. EfipBdsGetImageHeader (
  726. EFI_HANDLE Device,
  727. CHAR16 *FileName,
  728. EFI_IMAGE_DOS_HEADER *DosHeader,
  729. EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header
  730. )
  731. /*++
  732. Routine Description:
  733. This routine gets the image headers from an image.
  734. Arguments:
  735. Device - Supplies the simple file system handle.
  736. FileName - Supplies the path to the file to get the headers for.
  737. DosHeader - Supplies a pointer where the DOS header will be returned.
  738. Header - Supplies a pointer (union) where the PE headers will be returned.
  739. Return Value:
  740. EFI_SUCCESS on success.
  741. EFI_NOT_FOUND if the file was not found.
  742. EFI_LOAD_ERROR if the file is not a valid image.
  743. --*/
  744. {
  745. UINTN BufferSize;
  746. UINT64 FileSize;
  747. EFI_FILE_INFO *Information;
  748. EFI_FILE_HANDLE Root;
  749. EFI_STATUS Status;
  750. EFI_FILE_HANDLE ThisFile;
  751. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
  752. Root = NULL;
  753. ThisFile = NULL;
  754. Status = EfiHandleProtocol(Device,
  755. &EfiSimpleFileSystemProtocolGuid,
  756. (VOID **)&Volume);
  757. if (EFI_ERROR(Status)) {
  758. goto BdsGetImageHeaderEnd;
  759. }
  760. Status = Volume->OpenVolume(Volume, &Root);
  761. if (EFI_ERROR(Status)) {
  762. Root = NULL;
  763. goto BdsGetImageHeaderEnd;
  764. }
  765. ASSERT(Root != NULL);
  766. Status = Root->Open(Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
  767. if (EFI_ERROR(Status)) {
  768. goto BdsGetImageHeaderEnd;
  769. }
  770. ASSERT(ThisFile != NULL);
  771. //
  772. // Get the file information, reallocating the buffer for its needed size.
  773. //
  774. BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
  775. while (TRUE) {
  776. Information = EfiCoreAllocateBootPool(BufferSize);
  777. if (Information == NULL) {
  778. goto BdsGetImageHeaderEnd;
  779. }
  780. Status = ThisFile->GetInfo(ThisFile,
  781. &EfiFileInformationGuid,
  782. &BufferSize,
  783. Information);
  784. if (!EFI_ERROR(Status)) {
  785. break;
  786. }
  787. if (Status != EFI_BUFFER_TOO_SMALL) {
  788. EfiCoreFreePool(Information);
  789. goto BdsGetImageHeaderEnd;
  790. }
  791. EfiCoreFreePool(Information);
  792. }
  793. FileSize = Information->FileSize;
  794. EfiCoreFreePool(Information);
  795. //
  796. // Read the DOS header.
  797. //
  798. BufferSize = sizeof(EFI_IMAGE_DOS_HEADER);
  799. Status = ThisFile->Read(ThisFile, &BufferSize, DosHeader);
  800. if ((EFI_ERROR(Status)) ||
  801. (BufferSize < sizeof(EFI_IMAGE_DOS_HEADER)) ||
  802. (FileSize < DosHeader->e_lfanew) ||
  803. (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE)) {
  804. Status = EFI_LOAD_ERROR;
  805. goto BdsGetImageHeaderEnd;
  806. }
  807. //
  808. // Read the PE header.
  809. //
  810. Status = ThisFile->SetPosition(ThisFile, DosHeader->e_lfanew);
  811. if (EFI_ERROR(Status)) {
  812. Status = EFI_LOAD_ERROR;
  813. goto BdsGetImageHeaderEnd;
  814. }
  815. BufferSize = sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION);
  816. Status = ThisFile->Read(ThisFile, &BufferSize, Header.Pe32);
  817. if ((EFI_ERROR(Status)) ||
  818. (BufferSize < sizeof(EFI_IMAGE_OPTIONAL_HEADER_UNION)) ||
  819. (Header.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE)) {
  820. Status = EFI_LOAD_ERROR;
  821. goto BdsGetImageHeaderEnd;
  822. }
  823. Status = EFI_SUCCESS;
  824. BdsGetImageHeaderEnd:
  825. if (ThisFile != NULL) {
  826. ThisFile->Close(ThisFile);
  827. }
  828. if (Root != NULL) {
  829. Root->Close(Root);
  830. }
  831. return Status;
  832. }
  833. EFI_STATUS
  834. EfipBdsConnectDevicePath (
  835. EFI_DEVICE_PATH_PROTOCOL *Path
  836. )
  837. /*++
  838. Routine Description:
  839. This routine creates all handles associated with every device path node.
  840. Arguments:
  841. Path - Supplies a pointer to the device path to connect.
  842. Return Value:
  843. EFI Status code.
  844. --*/
  845. {
  846. EFI_TPL CurrentTpl;
  847. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  848. EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;
  849. EFI_HANDLE Handle;
  850. EFI_DEVICE_PATH_PROTOCOL *Instance;
  851. EFI_DEVICE_PATH_PROTOCOL *Next;
  852. EFI_HANDLE PreviousHandle;
  853. EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
  854. UINTN Size;
  855. EFI_STATUS Status;
  856. if (Path == NULL) {
  857. return EFI_SUCCESS;
  858. }
  859. CurrentTpl = EfiCoreGetCurrentTpl();
  860. DevicePath = EfiCoreDuplicateDevicePath(Path);
  861. if (DevicePath == NULL) {
  862. return EFI_OUT_OF_RESOURCES;
  863. }
  864. DevicePathCopy = DevicePath;
  865. //
  866. // Loop through every instance in a multi-instance device path. Only
  867. // console variables contain multi-instance device paths.
  868. //
  869. do {
  870. Instance = EfiCoreGetNextDevicePathInstance(&DevicePath, &Size);
  871. if (Instance == NULL) {
  872. EfiCoreFreePool(DevicePathCopy);
  873. return EFI_OUT_OF_RESOURCES;
  874. }
  875. Next = Instance;
  876. while (EfiCoreIsDevicePathEndType(Next) == FALSE) {
  877. Next = EfiCoreGetNextDevicePathNode(Next);
  878. }
  879. EfiCoreSetDevicePathEndNode(Next);
  880. //
  881. // This is the main loop.
  882. //
  883. PreviousHandle = NULL;
  884. do {
  885. //
  886. // Find the handle that best matches the device path. This may only
  887. // be a partial match.
  888. //
  889. RemainingDevicePath = Instance;
  890. Status = EfiLocateDevicePath(&EfiDevicePathProtocolGuid,
  891. &RemainingDevicePath,
  892. &Handle);
  893. if (!EFI_ERROR(Status)) {
  894. if (Handle == PreviousHandle) {
  895. //
  896. // If no forward progress was made try invoking the
  897. // dispatcher to load any pending drivers.
  898. //
  899. if (CurrentTpl == TPL_APPLICATION) {
  900. Status = EfiCoreDispatcher();
  901. } else {
  902. Status = EFI_NOT_FOUND;
  903. }
  904. }
  905. if (!EFI_ERROR(Status)) {
  906. PreviousHandle = Handle;
  907. //
  908. // Connect all drivers that apply to the handle and
  909. // remaining device path. Only go one level deep.
  910. //
  911. EfiConnectController(Handle,
  912. NULL,
  913. RemainingDevicePath,
  914. FALSE);
  915. }
  916. }
  917. } while ((!EFI_ERROR(Status)) &&
  918. (EfiCoreIsDevicePathEnd(RemainingDevicePath) == FALSE));
  919. } while (DevicePath != NULL);
  920. if (DevicePathCopy != NULL) {
  921. EfiCoreFreePool(DevicePathCopy);
  922. }
  923. return Status;
  924. }
  925. BOOLEAN
  926. EfipBdsValidateOption (
  927. UINT8 *Variable,
  928. UINTN VariableSize
  929. )
  930. /*++
  931. Routine Description:
  932. This routine validates the contents of a Boot#### option variable.
  933. Arguments:
  934. Variable - Supplies a pointer to the variable contents.
  935. VariableSize - Supplies the size of the variable contents buffer in bytes.
  936. Return Value:
  937. TRUE if the variable data is correct.
  938. FALSE if the variable data is not correct.
  939. --*/
  940. {
  941. UINT8 *CurrentOffset;
  942. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  943. UINT16 FilePathSize;
  944. UINTN Size;
  945. if (VariableSize < sizeof(UINT16) + sizeof(UINT32)) {
  946. return FALSE;
  947. }
  948. //
  949. // Skip the attributes.
  950. //
  951. CurrentOffset = Variable;
  952. CurrentOffset += sizeof(UINT32);
  953. //
  954. // Get the option's device path size.
  955. //
  956. FilePathSize = *(UINT16 *)CurrentOffset;
  957. CurrentOffset += sizeof(UINT16);
  958. //
  959. // Get the option's description string size.
  960. //
  961. Size = EfipBdsStringSize((CHAR16 *)CurrentOffset,
  962. VariableSize - sizeof(UINT16) - sizeof(UINT32));
  963. CurrentOffset += Size;
  964. //
  965. // Get the option's device path.
  966. //
  967. DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)CurrentOffset;
  968. CurrentOffset += FilePathSize;
  969. //
  970. // Validate the boot option variable.
  971. //
  972. if ((FilePathSize == 0) || (Size == 0)) {
  973. return FALSE;
  974. }
  975. if (Size + FilePathSize + sizeof(UINT16) + sizeof(UINT32) > VariableSize) {
  976. return FALSE;
  977. }
  978. if (EfipBdsGetDevicePathSize(DevicePath, FilePathSize) == 0) {
  979. return FALSE;
  980. }
  981. return TRUE;
  982. }
  983. VOID
  984. EfipBdsCreateHexCodeString (
  985. CHAR16 *String,
  986. UINT16 HexInteger,
  987. CHAR16 *Destination,
  988. UINTN DestinationSize
  989. )
  990. /*++
  991. Routine Description:
  992. This routine appends a four-digit hex code to a string. For example,
  993. Boot####.
  994. Arguments:
  995. String - Supplies a pointer to the string to prepend to the destination
  996. string.
  997. HexInteger - Supplies the four digit hex integer to append.
  998. Destination - Supplies a pointer to the destination string buffer.
  999. DestinationSize - Supplies the size of the destination string in bytes.
  1000. Return Value:
  1001. None.
  1002. --*/
  1003. {
  1004. CHAR16 Digit;
  1005. UINTN DigitIndex;
  1006. //
  1007. // Convert the destination size to be in characters instead of bytes.
  1008. //
  1009. DestinationSize /= sizeof(UINT16);
  1010. //
  1011. // Prepend the given string first.
  1012. //
  1013. if (String != NULL) {
  1014. while ((*String != L'\0') && (DestinationSize > 1)) {
  1015. *Destination = *String;
  1016. Destination += 1;
  1017. DestinationSize -= 1;
  1018. String += 1;
  1019. }
  1020. }
  1021. for (DigitIndex = 0; DigitIndex < 4; DigitIndex += 1) {
  1022. Digit = (HexInteger >> ((3 - DigitIndex) * 4)) & 0x000F;
  1023. if (Digit > 9) {
  1024. Digit = Digit - 0xA + L'A';
  1025. } else {
  1026. Digit += L'0';
  1027. }
  1028. if (DestinationSize > 1) {
  1029. *Destination = Digit;
  1030. Destination += 1;
  1031. DestinationSize -= 1;
  1032. }
  1033. }
  1034. if (DestinationSize > 0) {
  1035. *Destination = L'\0';
  1036. }
  1037. return;
  1038. }
  1039. //
  1040. // --------------------------------------------------------- Internal Functions
  1041. //
  1042. EFI_STATUS
  1043. EfipBdsConnectAllEfi (
  1044. VOID
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. This routine connects all current system handles recursively.
  1049. Arguments:
  1050. None.
  1051. Return Value:
  1052. EFI Status code.
  1053. --*/
  1054. {
  1055. EFI_HANDLE *HandleBuffer;
  1056. UINTN HandleCount;
  1057. UINTN Index;
  1058. EFI_STATUS Status;
  1059. HandleBuffer = NULL;
  1060. Status = EfiLocateHandleBuffer(AllHandles,
  1061. NULL,
  1062. NULL,
  1063. &HandleCount,
  1064. &HandleBuffer);
  1065. if (EFI_ERROR(Status)) {
  1066. return Status;
  1067. }
  1068. for (Index = 0; Index < HandleCount; Index += 1) {
  1069. EfiConnectController(HandleBuffer[Index], NULL, NULL, TRUE);
  1070. }
  1071. if (HandleBuffer != NULL) {
  1072. EfiCoreFreePool(HandleBuffer);
  1073. }
  1074. return EFI_SUCCESS;
  1075. }
  1076. EFI_STATUS
  1077. EfipBdsDisconnectAllEfi (
  1078. VOID
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. This routine disconnects all current system handles.
  1083. Arguments:
  1084. None.
  1085. Return Value:
  1086. EFI Status code.
  1087. --*/
  1088. {
  1089. EFI_HANDLE *HandleBuffer;
  1090. UINTN HandleCount;
  1091. UINTN Index;
  1092. EFI_STATUS Status;
  1093. Status = EfiLocateHandleBuffer(AllHandles,
  1094. NULL,
  1095. NULL,
  1096. &HandleCount,
  1097. &HandleBuffer);
  1098. if (EFI_ERROR(Status)) {
  1099. return Status;
  1100. }
  1101. for (Index = 0; Index < HandleCount; Index += 1) {
  1102. EfiDisconnectController(HandleBuffer[Index], NULL, NULL);
  1103. }
  1104. if (HandleBuffer != NULL) {
  1105. EfiCoreFreePool(HandleBuffer);
  1106. }
  1107. return EFI_SUCCESS;
  1108. }
  1109. UINT16
  1110. EfipBdsGetHexCodeFromString (
  1111. CHAR16 *HexCodeString
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. This routine converts a four digit hex code string to its numerical value.
  1116. Arguments:
  1117. HexCodeString - Supplies a pointer to the numerical portion of the string.
  1118. Return Value:
  1119. Returns the hex integer representation of the string value.
  1120. --*/
  1121. {
  1122. UINTN Index;
  1123. UINT16 Value;
  1124. Value = 0;
  1125. for (Index = 0; Index < 4; Index += 1) {
  1126. Value = Value << 4;
  1127. if (*HexCodeString == L'\0') {
  1128. break;
  1129. }
  1130. if ((*HexCodeString >= L'0') && (*HexCodeString <= '9')) {
  1131. Value += *HexCodeString - L'0';
  1132. } else if ((*HexCodeString >= L'A') && (*HexCodeString <= L'F')) {
  1133. Value += *HexCodeString - L'A' + 0xA;
  1134. } else if ((*HexCodeString >= L'a') && (*HexCodeString <= L'f')) {
  1135. Value += *HexCodeString - L'a' + 0xA;
  1136. }
  1137. }
  1138. return Value;
  1139. }
  1140. UINTN
  1141. EfipBdsStringSize (
  1142. CONST CHAR16 *String,
  1143. UINTN MaxStringSize
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. This routine returns the length of a null-terminated unicode string.
  1148. Arguments:
  1149. String - Supplies a pointer to the string to get the length of.
  1150. MaxStringSize - Supplies the size of the buffer containing the string in
  1151. bytes.
  1152. Return Value:
  1153. 0 if the string is invalid (it is not terminated before the string size).
  1154. Returns the size of the string in bytes.
  1155. --*/
  1156. {
  1157. UINTN Length;
  1158. ASSERT((String != NULL) && (MaxStringSize != 0));
  1159. ASSERT(((UINTN)String & 0x1) == 0);
  1160. Length = 0;
  1161. while ((*String != L'\0') && (Length < MaxStringSize)) {
  1162. String += 1;
  1163. Length += sizeof(CHAR16);
  1164. }
  1165. if ((*String != L'\0') && (Length >= MaxStringSize)) {
  1166. return 0;
  1167. }
  1168. return Length + sizeof(CHAR16);
  1169. }
  1170. UINTN
  1171. EfipBdsGetDevicePathSize (
  1172. CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  1173. UINTN MaxSize
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. This routine returns size of the given device path including the end node,
  1178. limited by the given size.
  1179. Arguments:
  1180. DevicePath - Supplies a pointer to the device path.
  1181. MaxSize - Supplies the size of the buffer containing the device path.
  1182. Return Value:
  1183. 0 if the path is invalid (it is not terminated before the max size).
  1184. Returns the size of the device path in bytes.
  1185. --*/
  1186. {
  1187. UINTN NodeSize;
  1188. UINTN Size;
  1189. if (DevicePath == NULL) {
  1190. return 0;
  1191. }
  1192. Size = 0;
  1193. while (EfiCoreIsDevicePathEnd(DevicePath) == FALSE) {
  1194. NodeSize = EfiCoreGetDevicePathNodeLength(DevicePath);
  1195. if (NodeSize < END_DEVICE_PATH_LENGTH) {
  1196. return 0;
  1197. }
  1198. Size += NodeSize;
  1199. if (Size > MaxSize) {
  1200. return 0;
  1201. }
  1202. DevicePath = EfiCoreGetNextDevicePathNode(DevicePath);
  1203. }
  1204. Size += EfiCoreGetDevicePathNodeLength(DevicePath);
  1205. if (Size > MaxSize) {
  1206. return 0;
  1207. }
  1208. return Size;
  1209. }
  1210. UINT16
  1211. EfipBdsGetFreeOptionNumber (
  1212. CHAR16 *VariableName
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. This routine attempts to find an unused Boot#### or Driver#### variable.
  1217. Arguments:
  1218. VariableName - Supplies a pointer to the string containing the variable
  1219. name.
  1220. Return Value:
  1221. Returns the first available option number.
  1222. --*/
  1223. {
  1224. UINTN Index;
  1225. UINT16 *OptionBuffer;
  1226. UINTN OptionSize;
  1227. CHAR16 String[10];
  1228. for (Index = 0; Index < 0xFFFF; Index += 1) {
  1229. if (*VariableName == L'B') {
  1230. EfipBdsCreateHexCodeString(L"Boot", Index, String, sizeof(String));
  1231. } else {
  1232. EfipBdsCreateHexCodeString(L"Driver",
  1233. Index,
  1234. String,
  1235. sizeof(String));
  1236. }
  1237. OptionBuffer = EfipBdsGetVariable(String,
  1238. &EfiGlobalVariableGuid,
  1239. &OptionSize);
  1240. if (OptionBuffer == NULL) {
  1241. break;
  1242. }
  1243. EfiCoreFreePool(OptionBuffer);
  1244. }
  1245. ASSERT(Index <= 0xFFFF);
  1246. return (UINT16)Index;
  1247. }