bdsboot.c 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. bdsboot.c
  5. Abstract:
  6. This module implements boot support for the BDS module.
  7. Author:
  8. Evan Green 17-Mar-2014
  9. Environment:
  10. Firmware
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include "ueficore.h"
  16. #include "bds.h"
  17. #include "efiimg.h"
  18. #include "fv2.h"
  19. #include <minoca/uefi/protocol/blockio.h>
  20. #include <minoca/uefi/protocol/loadimg.h>
  21. #include <minoca/uefi/protocol/sfilesys.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. VOID
  32. EfipBdsBuildOptionFromHandle (
  33. EFI_HANDLE Handle,
  34. CHAR16 *String
  35. );
  36. VOID
  37. EfipBdsBuildOptionFromShell (
  38. EFI_HANDLE Handle
  39. );
  40. UINT32
  41. EfipBdsGetBootTypeFromDevicePath (
  42. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  43. );
  44. EFI_STATUS
  45. EfipBdsDeleteOptionFromHandle (
  46. EFI_HANDLE Handle
  47. );
  48. EFI_STATUS
  49. EfipBdsDeleteBootOption (
  50. UINTN OptionNumber,
  51. UINT16 *BootOrder,
  52. UINTN *BootOrderSize
  53. );
  54. EFI_DEVICE_PATH_PROTOCOL *
  55. EfipBdsExpandPartitionDevicePath (
  56. HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
  57. );
  58. BOOLEAN
  59. EfipBdsMatchPartitionDevicePathNode (
  60. EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
  61. HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
  62. );
  63. BOOLEAN
  64. EfipBdsIsBootOptionValidVariable (
  65. PEFI_BDS_COMMON_OPTION Option
  66. );
  67. VOID
  68. EfipBdsSignalReadyToBootEvent (
  69. VOID
  70. );
  71. EFI_HANDLE
  72. EfipBdsGetBootableHandle (
  73. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  74. );
  75. //
  76. // -------------------------------------------------------------------- Globals
  77. //
  78. //
  79. // Define the file path to the flash shell to be tested for existence. This
  80. // can be overridden by platform-specific code.
  81. //
  82. EFI_GUID EfiDefaultShellFileGuid = EFI_DEFAULT_SHELL_FILE_GUID;
  83. BOOLEAN EfiBootDevicesEnumerated;
  84. EFI_GUID EfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
  85. EFI_GUID EfiHdBootDevicePathVariableGuid =
  86. EFI_HD_BOOT_DEVICE_PATH_VARIABLE_GUID;
  87. //
  88. // ------------------------------------------------------------------ Functions
  89. //
  90. EFI_STATUS
  91. EfipBdsBootViaBootOption (
  92. PEFI_BDS_COMMON_OPTION Option,
  93. EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  94. UINTN *ExitDataSize,
  95. CHAR16 **ExitData
  96. )
  97. /*++
  98. Routine Description:
  99. This routine attempts to boot the given boot option.
  100. Arguments:
  101. Option - Supplies a pointer to the option to boot.
  102. DevicePath - Supplies a pointer to the device path describing where to
  103. load the boot image or legacy BBS device path.
  104. ExitDataSize - Supplies a pointer where the exit data size will be returned.
  105. ExitData - Supplies a pointer where a pointer to the exit data will be
  106. returned.
  107. Return Value:
  108. EFI status code.
  109. --*/
  110. {
  111. UINT32 Attributes;
  112. EFI_DEVICE_PATH_PROTOCOL *FilePath;
  113. EFI_HANDLE Handle;
  114. EFI_HANDLE ImageHandle;
  115. EFI_LOADED_IMAGE_PROTOCOL *ImageInformation;
  116. EFI_STATUS Status;
  117. EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
  118. *ExitDataSize = 0;
  119. *ExitData = NULL;
  120. ImageHandle = NULL;
  121. Status = EFI_SUCCESS;
  122. Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
  123. //
  124. // If the device path starts with a hard drive path, append it to the
  125. // front part to create a full device path.
  126. //
  127. WorkingDevicePath = NULL;
  128. if ((EfiCoreGetDevicePathType(DevicePath) == MEDIA_DEVICE_PATH) &&
  129. (EfiCoreGetDevicePathSubType(DevicePath) == MEDIA_HARDDRIVE_DP)) {
  130. WorkingDevicePath = EfipBdsExpandPartitionDevicePath(
  131. (HARDDRIVE_DEVICE_PATH *)DevicePath);
  132. if (WorkingDevicePath != NULL) {
  133. DevicePath = WorkingDevicePath;
  134. }
  135. }
  136. //
  137. // Set boot current.
  138. //
  139. if (EfipBdsIsBootOptionValidVariable(Option) != FALSE) {
  140. EfiSetVariable(L"BootCurrent",
  141. &EfiGlobalVariableGuid,
  142. Attributes,
  143. sizeof(UINT16),
  144. &(Option->BootCurrent));
  145. }
  146. //
  147. // Signal the EVT_SIGNAL_READY_TO_BOOT event.
  148. //
  149. EfipBdsSignalReadyToBootEvent();
  150. EfiCoreSaveVariablesToFileSystem();
  151. //
  152. // Get the image handle for non-USB class or WWID device paths.
  153. //
  154. if (ImageHandle == NULL) {
  155. ASSERT(Option->DevicePath != NULL);
  156. //
  157. // Legacy BBS options are not supported in this implementation.
  158. //
  159. if ((EfiCoreGetDevicePathType(Option->DevicePath) == BBS_DEVICE_PATH) &&
  160. (EfiCoreGetDevicePathSubType(Option->DevicePath) == BBS_BBS_DP)) {
  161. return EFI_UNSUPPORTED;
  162. }
  163. Status = EfiLoadImage(TRUE,
  164. EfiFirmwareImageHandle,
  165. DevicePath,
  166. NULL,
  167. 0,
  168. &ImageHandle);
  169. //
  170. // If an image wasn't found directly, try as if it is a removable
  171. // device boot option and load the image according to the default
  172. // behavior for a removable device.
  173. //
  174. if (EFI_ERROR(Status)) {
  175. Handle = EfipBdsGetBootableHandle(DevicePath);
  176. if (Handle != NULL) {
  177. FilePath = EfiCoreCreateFileDevicePath(
  178. Handle,
  179. EFI_REMOVABLE_MEDIA_FILE_NAME);
  180. if (FilePath != NULL) {
  181. Status = EfiLoadImage(TRUE,
  182. EfiFirmwareImageHandle,
  183. FilePath,
  184. NULL,
  185. 0,
  186. &ImageHandle);
  187. }
  188. }
  189. }
  190. }
  191. //
  192. // Provide the image with its load options.
  193. //
  194. if ((ImageHandle == NULL) || (EFI_ERROR(Status))) {
  195. goto BdsBootViaBootOptionEnd;
  196. }
  197. Status = EfiHandleProtocol(ImageHandle,
  198. &EfiLoadedImageProtocolGuid,
  199. (VOID **)&ImageInformation);
  200. ASSERT(!EFI_ERROR(Status));
  201. if (Option->LoadOptionsSize != 0) {
  202. ImageInformation->LoadOptionsSize = Option->LoadOptionsSize;
  203. ImageInformation->LoadOptions = Option->LoadOptions;
  204. }
  205. //
  206. // NULL out the parent handle since this image is loaded directly by the
  207. // firmware boot manager.
  208. //
  209. ImageInformation->ParentHandle = NULL;
  210. //
  211. // Set the watchdog timer before launching the boot option.
  212. //
  213. EfiSetWatchdogTimer(EFI_DEFAULT_WATCHDOG_DURATION, 0, 0, NULL);
  214. Status = EfiStartImage(ImageHandle, ExitDataSize, ExitData);
  215. RtlDebugPrint("EFI Image Returned: %x\n", Status);
  216. //
  217. // Disable the watchdog timer.
  218. //
  219. EfiSetWatchdogTimer(0, 0, 0, NULL);
  220. BdsBootViaBootOptionEnd:
  221. //
  222. // Clear the boot current variable.
  223. //
  224. EfiSetVariable(L"BootCurrent",
  225. &EfiGlobalVariableGuid,
  226. Attributes,
  227. 0,
  228. &(Option->BootCurrent));
  229. return Status;
  230. }
  231. EFI_STATUS
  232. EfipBdsEnumerateAllBootOptions (
  233. PLIST_ENTRY OptionList
  234. )
  235. /*++
  236. Routine Description:
  237. This routine enumerates all possible boot devices in the system, and
  238. creates boot options for them. There are six types of automatic boot
  239. options:
  240. 1. Network - Creates boot options on any load file protocol instances.
  241. 2. Shell - Creates boot options for any firmware volumes that contain a
  242. specific path on them.
  243. 3. Removable Block I/O - Creates a boot option for any removable block I/O
  244. device.
  245. 4. Fixed Block I/O - Does not create a boot option for fixed drives.
  246. 5. Non-Block I/O Simple File Systems - Creates a boot option for
  247. \EFI\BOOT\boot{machine}.EFI using the Simple File System Protocol.
  248. 6. File - Does not create, modify, or delete a boot option pointing at a
  249. file.
  250. Arguments:
  251. OptionList - Supplies a pointer to the head of the boot option list.
  252. Return Value:
  253. EFI status code.
  254. --*/
  255. {
  256. EFI_FV_FILE_ATTRIBUTES Attributes;
  257. UINT32 AuthenticationStatus;
  258. EFI_BLOCK_IO_PROTOCOL *BlockIo;
  259. UINTN BlockIoHandleCount;
  260. EFI_HANDLE *BlockIoHandles;
  261. CHAR16 Buffer[40];
  262. UINT16 CdromNumber;
  263. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  264. UINTN DevicePathType;
  265. EFI_IMAGE_DOS_HEADER DosHeader;
  266. UINTN FileSystemHandleCount;
  267. EFI_HANDLE *FileSystemHandles;
  268. EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume;
  269. UINTN FirmwareVolumeHandleCount;
  270. EFI_HANDLE *FirmwareVolumeHandles;
  271. UINT16 FloppyNumber;
  272. UINT16 HarddriveNumber;
  273. EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header;
  274. EFI_IMAGE_OPTIONAL_HEADER_UNION HeaderData;
  275. UINTN Index;
  276. UINTN LoadFileHandleCount;
  277. EFI_HANDLE *LoadFileHandles;
  278. UINT16 MiscNumber;
  279. BOOLEAN NeedDelete;
  280. UINT16 NonBlockNumber;
  281. UINTN RemovableIndex;
  282. BOOLEAN RemovableSkip;
  283. UINT16 ScsiNumber;
  284. UINTN Size;
  285. EFI_STATUS Status;
  286. EFI_FV_FILETYPE Type;
  287. UINT16 UsbNumber;
  288. FloppyNumber = 0;
  289. HarddriveNumber = 0;
  290. CdromNumber = 0;
  291. UsbNumber = 0;
  292. MiscNumber = 0;
  293. ScsiNumber = 0;
  294. //
  295. // If the boot device enumeration happened, just get the boot device from
  296. // the boot order variable.
  297. //
  298. if (EfiBootDevicesEnumerated != FALSE) {
  299. Status = EfipBdsBuildOptionFromVariable(OptionList, L"BootOrder");
  300. return Status;
  301. }
  302. EfiLocateHandleBuffer(ByProtocol,
  303. &EfiBlockIoProtocolGuid,
  304. NULL,
  305. &BlockIoHandleCount,
  306. &BlockIoHandles);
  307. //
  308. // Loop twice, once for removable media and once for non-removable media.
  309. //
  310. for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex += 1) {
  311. RemovableSkip = FALSE;
  312. if (RemovableIndex != 0) {
  313. RemovableSkip = TRUE;
  314. }
  315. //
  316. // Loop through every block I/O handle.
  317. //
  318. for (Index = 0; Index < BlockIoHandleCount; Index += 1) {
  319. Status = EfiHandleProtocol(BlockIoHandles[Index],
  320. &EfiBlockIoProtocolGuid,
  321. (VOID **)&BlockIo);
  322. //
  323. // Skip invalid or inapplicable handles.
  324. //
  325. if ((EFI_ERROR(Status)) ||
  326. (BlockIo->Media->RemovableMedia == RemovableSkip)) {
  327. continue;
  328. }
  329. DevicePath = EfiCoreGetDevicePathFromHandle(BlockIoHandles[Index]);
  330. DevicePathType = EfipBdsGetBootTypeFromDevicePath(DevicePath);
  331. switch (DevicePathType) {
  332. case BDS_EFI_ACPI_FLOPPY_BOOT:
  333. if (FloppyNumber == 0) {
  334. EfiCoreCopyString(Buffer, L"Floppy");
  335. } else {
  336. EfipBdsCreateHexCodeString(L"Floppy",
  337. FloppyNumber,
  338. Buffer,
  339. sizeof(Buffer));
  340. }
  341. EfipBdsBuildOptionFromHandle(BlockIoHandles[Index], Buffer);
  342. FloppyNumber += 1;
  343. break;
  344. case BDS_EFI_MESSAGE_ATAPI_BOOT:
  345. case BDS_EFI_MESSAGE_SATA_BOOT:
  346. case BDS_EFI_MEDIA_HD_BOOT:
  347. case BDS_EFI_MEDIA_CDROM_BOOT:
  348. if (BlockIo->Media->RemovableMedia != FALSE) {
  349. if (CdromNumber == 0) {
  350. EfiCoreCopyString(Buffer, L"CD/DVD");
  351. } else {
  352. EfipBdsCreateHexCodeString(L"CD/DVD",
  353. CdromNumber,
  354. Buffer,
  355. sizeof(Buffer));
  356. }
  357. CdromNumber += 1;
  358. } else {
  359. if (HarddriveNumber == 0) {
  360. EfiCoreCopyString(Buffer, L"HardDrive");
  361. } else {
  362. EfipBdsCreateHexCodeString(L"HardDrive",
  363. HarddriveNumber,
  364. Buffer,
  365. sizeof(Buffer));
  366. }
  367. HarddriveNumber += 1;
  368. }
  369. EfipBdsBuildOptionFromHandle(BlockIoHandles[Index], Buffer);
  370. break;
  371. case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
  372. if (UsbNumber == 0) {
  373. EfiCoreCopyString(Buffer, L"USB");
  374. } else {
  375. EfipBdsCreateHexCodeString(L"USB",
  376. UsbNumber,
  377. Buffer,
  378. sizeof(Buffer));
  379. }
  380. EfipBdsBuildOptionFromHandle(BlockIoHandles[Index], Buffer);
  381. UsbNumber += 1;
  382. break;
  383. case BDS_EFI_MESSAGE_SCSI_BOOT:
  384. if (ScsiNumber == 0) {
  385. EfiCoreCopyString(Buffer, L"SCSI");
  386. } else {
  387. EfipBdsCreateHexCodeString(L"SCSI",
  388. ScsiNumber,
  389. Buffer,
  390. sizeof(Buffer));
  391. }
  392. EfipBdsBuildOptionFromHandle(BlockIoHandles[Index], Buffer);
  393. ScsiNumber += 1;
  394. break;
  395. case BDS_EFI_MESSAGE_MISC_BOOT:
  396. if (MiscNumber == 0) {
  397. EfiCoreCopyString(Buffer, L"Misc");
  398. } else {
  399. EfipBdsCreateHexCodeString(L"Misc",
  400. MiscNumber,
  401. Buffer,
  402. sizeof(Buffer));
  403. }
  404. EfipBdsBuildOptionFromHandle(BlockIoHandles[Index], Buffer);
  405. MiscNumber += 1;
  406. break;
  407. default:
  408. break;
  409. }
  410. }
  411. }
  412. if (BlockIoHandleCount != 0) {
  413. EfiCoreFreePool(BlockIoHandles);
  414. }
  415. //
  416. // Look for simple file system protocols which do not consume block I/O
  417. // protocols, and create boot options for each of those.
  418. //
  419. NonBlockNumber = 0;
  420. EfiLocateHandleBuffer(ByProtocol,
  421. &EfiSimpleFileSystemProtocolGuid,
  422. NULL,
  423. &FileSystemHandleCount,
  424. &FileSystemHandles);
  425. for (Index = 0; Index < FileSystemHandleCount; Index += 1) {
  426. //
  427. // Skip it if there's a block I/O protocol on here as well.
  428. //
  429. Status = EfiHandleProtocol(FileSystemHandles[Index],
  430. &EfiBlockIoProtocolGuid,
  431. (VOID **)&BlockIo);
  432. if (!EFI_ERROR(Status)) {
  433. continue;
  434. }
  435. //
  436. // Do that removable media thang: \EFI\BOOT\boot{arch}.EFI.
  437. //
  438. Header.Union = &HeaderData;
  439. NeedDelete = TRUE;
  440. Status = EfipBdsGetImageHeader(FileSystemHandles[Index],
  441. EFI_REMOVABLE_MEDIA_FILE_NAME,
  442. &DosHeader,
  443. Header);
  444. if ((!EFI_ERROR(Status)) &&
  445. (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(
  446. Header.Pe32->FileHeader.Machine)) &&
  447. (Header.Pe32->OptionalHeader.Subsystem ==
  448. EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
  449. NeedDelete = FALSE;
  450. }
  451. //
  452. // If there was no valid image there, delete the boot option.
  453. //
  454. if (NeedDelete != FALSE) {
  455. EfipBdsDeleteOptionFromHandle(FileSystemHandles[Index]);
  456. //
  457. // Create a boot option.
  458. //
  459. } else {
  460. if (NonBlockNumber == 0) {
  461. EfiCoreCopyString(Buffer, L"NonBlock");
  462. } else {
  463. EfipBdsCreateHexCodeString(L"NonBlock",
  464. NonBlockNumber,
  465. Buffer,
  466. sizeof(Buffer));
  467. }
  468. EfipBdsBuildOptionFromHandle(FileSystemHandles[Index], Buffer);
  469. NonBlockNumber += 1;
  470. }
  471. }
  472. if (FileSystemHandleCount != 0) {
  473. EfiCoreFreePool(FileSystemHandles);
  474. }
  475. //
  476. // Add network/load file entries.
  477. //
  478. LoadFileHandleCount = 0;
  479. EfiLocateHandleBuffer(ByProtocol,
  480. &EfiLoadFileProtocolGuid,
  481. NULL,
  482. &LoadFileHandleCount,
  483. &LoadFileHandles);
  484. for (Index = 0; Index < LoadFileHandleCount; Index += 1) {
  485. if (Index == 0) {
  486. EfiCoreCopyString(Buffer, L"Net");
  487. } else {
  488. EfipBdsCreateHexCodeString(L"Net",
  489. Index,
  490. Buffer,
  491. sizeof(Buffer));
  492. }
  493. EfipBdsBuildOptionFromHandle(LoadFileHandles[Index], Buffer);
  494. }
  495. if (LoadFileHandleCount != 0) {
  496. EfiCoreFreePool(LoadFileHandles);
  497. }
  498. //
  499. // Add the flash shell if there is one.
  500. //
  501. FirmwareVolumeHandleCount = 0;
  502. EfiLocateHandleBuffer(ByProtocol,
  503. &EfiLoadFileProtocolGuid,
  504. NULL,
  505. &FirmwareVolumeHandleCount,
  506. &FirmwareVolumeHandles);
  507. for (Index = 0; Index < FirmwareVolumeHandleCount; Index += 1) {
  508. Status = EfiHandleProtocol(FirmwareVolumeHandles[Index],
  509. &EfiFirmwareVolume2ProtocolGuid,
  510. (VOID **)&FirmwareVolume);
  511. if ((EFI_ERROR(Status)) || (FirmwareVolume == NULL)) {
  512. continue;
  513. }
  514. Status = FirmwareVolume->ReadFile(FirmwareVolume,
  515. &EfiDefaultShellFileGuid,
  516. NULL,
  517. &Size,
  518. &Type,
  519. &Attributes,
  520. &AuthenticationStatus);
  521. if (EFI_ERROR(Status)) {
  522. continue;
  523. }
  524. EfipBdsBuildOptionFromShell(FirmwareVolumeHandles[Index]);
  525. }
  526. if (FirmwareVolumeHandleCount != 0) {
  527. EfiCoreFreePool(FirmwareVolumeHandles);
  528. }
  529. Status = EfipBdsBuildOptionFromVariable(OptionList, L"BootOrder");
  530. EfiBootDevicesEnumerated = TRUE;
  531. return Status;
  532. }
  533. //
  534. // --------------------------------------------------------- Internal Functions
  535. //
  536. VOID
  537. EfipBdsBuildOptionFromHandle (
  538. EFI_HANDLE Handle,
  539. CHAR16 *String
  540. )
  541. /*++
  542. Routine Description:
  543. This routine builds a boot option off the given handle.
  544. Arguments:
  545. Handle - Supplies the handle to build the boot option around.
  546. OptionList - Supplies a pointer to the boot option list. This option will
  547. be added.
  548. String - Supplies a pointer to a string describing the option. A copy of
  549. this string will be made.
  550. Return Value:
  551. None.
  552. --*/
  553. {
  554. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  555. DevicePath = EfiCoreGetDevicePathFromHandle(Handle);
  556. EfipBdsRegisterNewOption(DevicePath, String, L"BootOrder");
  557. return;
  558. }
  559. VOID
  560. EfipBdsBuildOptionFromShell (
  561. EFI_HANDLE Handle
  562. )
  563. /*++
  564. Routine Description:
  565. This routine builds a boot option off the given handle for the internal
  566. flash shell.
  567. Arguments:
  568. Handle - Supplies the handle to build the boot option around.
  569. OptionList - Supplies a pointer to the boot option list. This option will
  570. be added.
  571. Return Value:
  572. None.
  573. --*/
  574. {
  575. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  576. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
  577. DevicePath = EfiCoreGetDevicePathFromHandle(Handle);
  578. EfiCoreInitializeFirmwareVolumeDevicePathNode(&ShellNode,
  579. &EfiDefaultShellFileGuid);
  580. DevicePath = EfiCoreAppendDevicePathNode(
  581. DevicePath,
  582. (EFI_DEVICE_PATH_PROTOCOL *)&ShellNode);
  583. EfipBdsRegisterNewOption(DevicePath, L"EFI Shell", L"BootOrder");
  584. return;
  585. }
  586. UINT32
  587. EfipBdsGetBootTypeFromDevicePath (
  588. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  589. )
  590. /*++
  591. Routine Description:
  592. This routine returns a boot type associated with a given device path.
  593. Arguments:
  594. DevicePath - Supplies a pointer to the device path.
  595. Return Value:
  596. Returns a BDS_EFI_* definition.
  597. --*/
  598. {
  599. ACPI_HID_DEVICE_PATH *Acpi;
  600. UINT32 BootType;
  601. EFI_DEVICE_PATH_PROTOCOL *CurrentPath;
  602. EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
  603. UINT8 SubType;
  604. if (DevicePath == NULL) {
  605. return BDS_EFI_UNSUPPORTED;
  606. }
  607. CurrentPath = DevicePath;
  608. while (EfiCoreIsDevicePathEndType(CurrentPath) == FALSE) {
  609. switch (EfiCoreGetDevicePathType(CurrentPath)) {
  610. case BBS_DEVICE_PATH:
  611. return BDS_LEGACY_BBS_BOOT;
  612. case MEDIA_DEVICE_PATH:
  613. SubType = EfiCoreGetDevicePathSubType(CurrentPath);
  614. if (SubType == MEDIA_HARDDRIVE_DP) {
  615. return BDS_EFI_MEDIA_HD_BOOT;
  616. } else if (SubType == MEDIA_CDROM_DP) {
  617. return BDS_EFI_MEDIA_CDROM_BOOT;
  618. }
  619. break;
  620. case ACPI_DEVICE_PATH:
  621. Acpi = (ACPI_HID_DEVICE_PATH *)CurrentPath;
  622. if (EISA_ID_TO_NUM(Acpi->HID) == 0x0604) {
  623. return BDS_EFI_ACPI_FLOPPY_BOOT;
  624. }
  625. break;
  626. case MESSAGING_DEVICE_PATH:
  627. LastDeviceNode = EfiCoreGetNextDevicePathNode(CurrentPath);
  628. //
  629. // If the next node type is Device Logical Unit (which specifies
  630. // the Logical Unit Number (LUN)), skip it.
  631. //
  632. if (EfiCoreGetDevicePathSubType(LastDeviceNode) ==
  633. MSG_DEVICE_LOGICAL_UNIT_DP) {
  634. LastDeviceNode = EfiCoreGetNextDevicePathNode(LastDeviceNode);
  635. }
  636. //
  637. // The next one should really be the last. Ignore it if it's not.
  638. //
  639. if (EfiCoreIsDevicePathEndType(LastDeviceNode) == FALSE) {
  640. break;
  641. }
  642. SubType = EfiCoreGetDevicePathSubType(CurrentPath);
  643. switch (SubType) {
  644. case MSG_ATAPI_DP:
  645. BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;
  646. break;
  647. case MSG_USB_DP:
  648. BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
  649. break;
  650. case MSG_SCSI_DP:
  651. BootType = BDS_EFI_MESSAGE_SCSI_BOOT;
  652. break;
  653. case MSG_SATA_DP:
  654. BootType = BDS_EFI_MESSAGE_SATA_BOOT;
  655. break;
  656. case MSG_MAC_ADDR_DP:
  657. case MSG_VLAN_DP:
  658. case MSG_IPv4_DP:
  659. case MSG_IPv6_DP:
  660. BootType = BDS_EFI_MESSAGE_MAC_BOOT;
  661. break;
  662. default:
  663. BootType = BDS_EFI_MESSAGE_MISC_BOOT;
  664. break;
  665. }
  666. return BootType;
  667. default:
  668. break;
  669. }
  670. CurrentPath = EfiCoreGetNextDevicePathNode(CurrentPath);
  671. }
  672. return BDS_EFI_UNSUPPORTED;
  673. }
  674. EFI_STATUS
  675. EfipBdsDeleteOptionFromHandle (
  676. EFI_HANDLE Handle
  677. )
  678. /*++
  679. Routine Description:
  680. This routine deletes a boot option associated with the given handle.
  681. Arguments:
  682. Handle - Supplies the handle associated with the boot option to delete.
  683. Return Value:
  684. EFI status code.
  685. --*/
  686. {
  687. UINT32 Attributes;
  688. UINT16 BootOption[EFI_BOOT_OPTION_MAX_CHAR];
  689. UINTN BootOptionSize;
  690. UINT8 *BootOptionVariable;
  691. UINT16 *BootOrder;
  692. UINTN BootOrderSize;
  693. INTN CompareResult;
  694. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  695. UINTN DevicePathSize;
  696. UINTN Index;
  697. EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
  698. UINTN OptionDevicePathSize;
  699. UINT8 *OptionMember;
  700. EFI_STATUS Status;
  701. Status = EFI_SUCCESS;
  702. BootOrder = NULL;
  703. BootOrderSize = 0;
  704. BootOrder = EfipBdsGetVariable(L"BootOrder",
  705. &EfiGlobalVariableGuid,
  706. &BootOrderSize);
  707. if (BootOrder == NULL) {
  708. return EFI_NOT_FOUND;
  709. }
  710. DevicePath = EfiCoreGetDevicePathFromHandle(Handle);
  711. if (DevicePath == NULL) {
  712. return EFI_NOT_FOUND;
  713. }
  714. DevicePathSize = EfiCoreGetDevicePathSize(DevicePath);
  715. //
  716. // Loop over all the boot order variables to find the matching device path.
  717. //
  718. Index = 0;
  719. while (Index < BootOrderSize / sizeof(UINT16)) {
  720. EfipBdsCreateHexCodeString(L"Boot",
  721. BootOrder[Index],
  722. BootOption,
  723. sizeof(BootOption));
  724. BootOptionVariable = EfipBdsGetVariable(BootOption,
  725. &EfiGlobalVariableGuid,
  726. &BootOptionSize);
  727. if (BootOptionVariable == NULL) {
  728. EfiCoreFreePool(BootOrder);
  729. return EFI_OUT_OF_RESOURCES;
  730. }
  731. if (EfipBdsValidateOption(BootOptionVariable, BootOptionSize) ==
  732. FALSE) {
  733. EfipBdsDeleteBootOption(BootOrder[Index],
  734. BootOrder,
  735. &BootOrderSize);
  736. EfiCoreFreePool(BootOptionVariable);
  737. Index += 1;
  738. continue;
  739. }
  740. OptionMember = BootOptionVariable;
  741. OptionMember += sizeof(UINT32) + sizeof(UINT16);
  742. OptionMember += (EfiCoreStringLength((CHAR16 *)OptionMember) + 1) *
  743. sizeof(CHAR16);
  744. OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)OptionMember;
  745. OptionDevicePathSize = EfiCoreGetDevicePathSize(OptionDevicePath);
  746. //
  747. // Match against the device path.
  748. //
  749. if (OptionDevicePathSize == DevicePathSize) {
  750. CompareResult = EfiCoreCompareMemory(DevicePath,
  751. OptionDevicePath,
  752. DevicePathSize);
  753. if (CompareResult == 0) {
  754. EfipBdsDeleteBootOption(BootOrder[Index],
  755. BootOrder,
  756. &BootOrderSize);
  757. EfiCoreFreePool(BootOptionVariable);
  758. break;
  759. }
  760. }
  761. EfiCoreFreePool(BootOptionVariable);
  762. Index += 1;
  763. }
  764. //
  765. // Adjust the number of options for the BootOrder variable.
  766. //
  767. Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
  768. EFI_VARIABLE_RUNTIME_ACCESS |
  769. EFI_VARIABLE_NON_VOLATILE;
  770. Status = EfiSetVariable(L"BootOrder",
  771. &EfiGlobalVariableGuid,
  772. Attributes,
  773. BootOrderSize,
  774. BootOrder);
  775. EfiCoreFreePool(BootOrder);
  776. return Status;
  777. }
  778. EFI_STATUS
  779. EfipBdsDeleteBootOption (
  780. UINTN OptionNumber,
  781. UINT16 *BootOrder,
  782. UINTN *BootOrderSize
  783. )
  784. /*++
  785. Routine Description:
  786. This routine deletes the boot option from EFI boot variables. The boot
  787. order array is also updated.
  788. Arguments:
  789. OptionNumber - Supplies the option number to delete.
  790. BootOrder - Supplies a pointer to the boot order array.
  791. BootOrderSize - Supplies a pointer that on input contains the size of the
  792. boot order array. On output this will be updated if an entry was
  793. deleted.
  794. Return Value:
  795. EFI status code.
  796. --*/
  797. {
  798. CHAR16 BootOption[EFI_BOOT_OPTION_MAX_CHAR];
  799. UINTN Index;
  800. EFI_STATUS Status;
  801. EfipBdsCreateHexCodeString(L"Boot",
  802. OptionNumber,
  803. BootOption,
  804. sizeof(BootOption));
  805. Status = EfiSetVariable(BootOption,
  806. &EfiGlobalVariableGuid,
  807. 0,
  808. 0,
  809. NULL);
  810. //
  811. // Adjust the boot order array.
  812. //
  813. for (Index = 0; Index < *BootOrderSize / sizeof(UINT16); Index += 1) {
  814. if (BootOrder[Index] == OptionNumber) {
  815. EfiCoreCopyMemory(&(BootOrder[Index]),
  816. &(BootOrder[Index + 1]),
  817. *BootOrderSize - ((Index + 1) * sizeof(UINT16)));
  818. *BootOrderSize -= sizeof(UINT16);
  819. break;
  820. }
  821. }
  822. return Status;
  823. }
  824. EFI_DEVICE_PATH_PROTOCOL *
  825. EfipBdsExpandPartitionDevicePath (
  826. HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
  827. )
  828. /*++
  829. Routine Description:
  830. This routine expands a device path that starts with a hard drive media
  831. device path node to be a full device path that includes the full hardware
  832. path to the device. As an optimization the front match (the part pointing
  833. to the partition node. E.g. ACPI() /PCI()/ATA()/Partition()) is saved in a
  834. variable so a connect all is not required on every boot. All successful
  835. device paths which point to partition nodes (the front part) will be saved.
  836. Arguments:
  837. HardDriveDevicePath - Supplies a pointer to the hard drive device path.
  838. Return Value:
  839. Returns a pointer to the fully expanded device path.
  840. --*/
  841. {
  842. UINT32 Attributes;
  843. EFI_HANDLE *BlockIoBuffer;
  844. EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
  845. UINTN BlockIoHandleCount;
  846. EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
  847. UINTN CachedDevicePathSize;
  848. BOOLEAN DeviceExists;
  849. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  850. EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
  851. UINTN Index;
  852. EFI_DEVICE_PATH_PROTOCOL *Instance;
  853. UINTN InstanceCount;
  854. BOOLEAN Match;
  855. BOOLEAN NeedsAdjustment;
  856. EFI_DEVICE_PATH_PROTOCOL *OldDevicePath;
  857. UINTN Size;
  858. EFI_STATUS Status;
  859. FullDevicePath = NULL;
  860. Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS |
  861. EFI_VARIABLE_RUNTIME_ACCESS |
  862. EFI_VARIABLE_NON_VOLATILE;
  863. //
  864. // Check to see if there is a cached variable of the translation.
  865. //
  866. CachedDevicePath = EfipBdsGetVariable(EFI_HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
  867. &EfiHdBootDevicePathVariableGuid,
  868. &CachedDevicePathSize);
  869. if (CachedDevicePath != NULL) {
  870. OldDevicePath = CachedDevicePath;
  871. DeviceExists = FALSE;
  872. NeedsAdjustment = FALSE;
  873. do {
  874. //
  875. // Check every instance of the variable. First, check whether the
  876. // instance contains the partition node, needed for distinguishing
  877. // partial partition boot options. Second, check whether or not the
  878. // instance can be connected.
  879. //
  880. Instance = EfiCoreGetNextDevicePathInstance(&OldDevicePath, &Size);
  881. Match = EfipBdsMatchPartitionDevicePathNode(Instance,
  882. HardDriveDevicePath);
  883. if (Match != FALSE) {
  884. Status = EfipBdsConnectDevicePath(Instance);
  885. if (!EFI_ERROR(Status)) {
  886. DeviceExists = TRUE;
  887. break;
  888. }
  889. }
  890. NeedsAdjustment = TRUE;
  891. EfiCoreFreePool(Instance);
  892. } while (OldDevicePath != NULL);
  893. //
  894. // If a matching device was found, append the file path information
  895. // from the boot option and return the fully expanded path.
  896. //
  897. if (DeviceExists != FALSE) {
  898. DevicePath = EfiCoreGetNextDevicePathNode(
  899. (EFI_DEVICE_PATH_PROTOCOL *)HardDriveDevicePath);
  900. FullDevicePath = EfiCoreAppendDevicePath(Instance, DevicePath);
  901. //
  902. // Adjust the cached variable instance sequence if the matched one
  903. // is not the first one.
  904. //
  905. if (NeedsAdjustment != FALSE) {
  906. //
  907. // First, delete the matched instance.
  908. //
  909. OldDevicePath = CachedDevicePath;
  910. CachedDevicePath = EfipBdsDeletePartialMatchInstance(
  911. CachedDevicePath,
  912. Instance);
  913. EfiCoreFreePool(OldDevicePath);
  914. //
  915. // Next, append the remaining device path after the matched
  916. // instance.
  917. //
  918. OldDevicePath = CachedDevicePath;
  919. CachedDevicePath = EfiCoreAppendDevicePathInstance(
  920. Instance,
  921. CachedDevicePath);
  922. EfiCoreFreePool(OldDevicePath);
  923. //
  924. // Save the variable for future speedups.
  925. //
  926. Status = EfiSetVariable(
  927. EFI_HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
  928. &EfiHdBootDevicePathVariableGuid,
  929. Attributes,
  930. EfiCoreGetDevicePathSize(CachedDevicePath),
  931. CachedDevicePath);
  932. }
  933. EfiCoreFreePool(Instance);
  934. EfiCoreFreePool(CachedDevicePath);
  935. return FullDevicePath;
  936. }
  937. }
  938. //
  939. // The device was not found in the cached variable, so it's time to search
  940. // all devices for a matched partition.
  941. //
  942. EfipBdsConnectAllDriversToAllControllers();
  943. Status = EfiLocateHandleBuffer(ByProtocol,
  944. &EfiBlockIoProtocolGuid,
  945. NULL,
  946. &BlockIoHandleCount,
  947. &BlockIoBuffer);
  948. if ((EFI_ERROR(Status)) || (BlockIoHandleCount == 0) ||
  949. (BlockIoBuffer == NULL)) {
  950. return NULL;
  951. }
  952. //
  953. // Loop through everything that supports block I/O.
  954. //
  955. for (Index = 0; Index < BlockIoHandleCount; Index += 1) {
  956. Status = EfiHandleProtocol(BlockIoBuffer[Index],
  957. &EfiDevicePathProtocolGuid,
  958. (VOID **)&BlockIoDevicePath);
  959. if ((EFI_ERROR(Status)) || (BlockIoDevicePath == NULL)) {
  960. continue;
  961. }
  962. Match = EfipBdsMatchPartitionDevicePathNode(BlockIoDevicePath,
  963. HardDriveDevicePath);
  964. if (Match != FALSE) {
  965. //
  966. // Find the matched partition device path.
  967. //
  968. DevicePath = EfiCoreGetNextDevicePathNode(
  969. (EFI_DEVICE_PATH_PROTOCOL *)HardDriveDevicePath);
  970. FullDevicePath = EfiCoreAppendDevicePath(BlockIoDevicePath,
  971. DevicePath);
  972. //
  973. // Save the matched partition device path in the variable.
  974. //
  975. if (CachedDevicePath != NULL) {
  976. Match = EfipBdsMatchDevicePaths(CachedDevicePath,
  977. BlockIoDevicePath);
  978. if (Match != FALSE) {
  979. OldDevicePath = CachedDevicePath;
  980. CachedDevicePath = EfipBdsDeletePartialMatchInstance(
  981. CachedDevicePath,
  982. BlockIoDevicePath);
  983. EfiCoreFreePool(OldDevicePath);
  984. }
  985. if (CachedDevicePath != NULL) {
  986. OldDevicePath = CachedDevicePath;
  987. CachedDevicePath = EfiCoreAppendDevicePathInstance(
  988. BlockIoDevicePath,
  989. CachedDevicePath);
  990. EfiCoreFreePool(OldDevicePath);
  991. } else {
  992. CachedDevicePath =
  993. EfiCoreDuplicateDevicePath(BlockIoDevicePath);
  994. }
  995. //
  996. // Limit the device path instance number to avoid growing the
  997. // variable infinitely.
  998. //
  999. InstanceCount = 0;
  1000. ASSERT(CachedDevicePath != NULL);
  1001. //
  1002. // Count the instances.
  1003. //
  1004. OldDevicePath = CachedDevicePath;
  1005. while (EfiCoreIsDevicePathEnd(OldDevicePath) == FALSE) {
  1006. OldDevicePath = EfiCoreGetNextDevicePathNode(OldDevicePath);
  1007. //
  1008. // Parse one instance.
  1009. //
  1010. while (EfiCoreIsDevicePathEndType(OldDevicePath) == FALSE) {
  1011. OldDevicePath =
  1012. EfiCoreGetNextDevicePathNode(OldDevicePath);
  1013. }
  1014. InstanceCount += 1;
  1015. if (InstanceCount >= EFI_MAX_HD_DEVICE_PATH_CACHE_SIZE) {
  1016. EfiCoreSetDevicePathEndNode(OldDevicePath);
  1017. break;
  1018. }
  1019. }
  1020. } else {
  1021. CachedDevicePath =
  1022. EfiCoreDuplicateDevicePath(BlockIoDevicePath);
  1023. }
  1024. //
  1025. // Save the matching device path variable for speedups on future
  1026. // boots.
  1027. //
  1028. Status = EfiSetVariable(EFI_HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
  1029. &EfiHdBootDevicePathVariableGuid,
  1030. Attributes,
  1031. EfiCoreGetDevicePathSize(CachedDevicePath),
  1032. CachedDevicePath);
  1033. break;
  1034. }
  1035. }
  1036. if (CachedDevicePath != NULL) {
  1037. EfiCoreFreePool(CachedDevicePath);
  1038. }
  1039. if (BlockIoBuffer != NULL) {
  1040. EfiCoreFreePool(BlockIoBuffer);
  1041. }
  1042. return FullDevicePath;
  1043. }
  1044. BOOLEAN
  1045. EfipBdsMatchPartitionDevicePathNode (
  1046. EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
  1047. HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This routine looks for the given hard drive device path node in the
  1052. block I/O device path.
  1053. Arguments:
  1054. BlockIoDevicePath - Supplies a pointer to the block I/O device path node
  1055. to search.
  1056. HardDriveDevicePath - Supplies a pointer to the node to search for.
  1057. Return Value:
  1058. TRUE if the hard drive node is in the block I/O node.
  1059. FALSE if the hard drive node is not contained within the block I/O node.
  1060. --*/
  1061. {
  1062. EFI_DEVICE_PATH_PROTOCOL *BlockIoDriveNode;
  1063. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  1064. HARDDRIVE_DEVICE_PATH *DriveNode;
  1065. BOOLEAN Match;
  1066. if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
  1067. return FALSE;
  1068. }
  1069. DevicePath = BlockIoDevicePath;
  1070. BlockIoDriveNode = NULL;
  1071. //
  1072. // Find the partition node.
  1073. //
  1074. while (EfiCoreIsDevicePathEnd(DevicePath) == FALSE) {
  1075. if ((EfiCoreGetDevicePathType(DevicePath) == MEDIA_DEVICE_PATH) &&
  1076. (EfiCoreGetDevicePathSubType(DevicePath) ==
  1077. MEDIA_HARDDRIVE_DP)) {
  1078. BlockIoDriveNode = DevicePath;
  1079. break;
  1080. }
  1081. DevicePath = EfiCoreGetNextDevicePathNode(DevicePath);
  1082. }
  1083. if (BlockIoDriveNode == NULL) {
  1084. return FALSE;
  1085. }
  1086. DriveNode = (HARDDRIVE_DEVICE_PATH *)BlockIoDriveNode;
  1087. Match = FALSE;
  1088. if ((DriveNode->MBRType == HardDriveDevicePath->MBRType) &&
  1089. (DriveNode->SignatureType == HardDriveDevicePath->SignatureType)) {
  1090. switch (DriveNode->SignatureType) {
  1091. case SIGNATURE_TYPE_GUID:
  1092. Match = EfiCoreCompareGuids(
  1093. (EFI_GUID *)DriveNode->Signature,
  1094. (EFI_GUID *)HardDriveDevicePath->Signature);
  1095. break;
  1096. case SIGNATURE_TYPE_MBR:
  1097. Match = EfiCoreCompareMemory(&(DriveNode->Signature[0]),
  1098. &(HardDriveDevicePath->Signature[0]),
  1099. sizeof(UINT32));
  1100. break;
  1101. default:
  1102. Match = FALSE;
  1103. break;
  1104. }
  1105. }
  1106. return Match;
  1107. }
  1108. BOOLEAN
  1109. EfipBdsIsBootOptionValidVariable (
  1110. PEFI_BDS_COMMON_OPTION Option
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This routine determines if the given EFI boot option is a valid
  1115. non-volatile boot option variable.
  1116. Arguments:
  1117. Option - Supplies a pointer to the option to check.
  1118. Return Value:
  1119. TRUE if the boot option is a non-volatile variable boot option.
  1120. FALSE if the boot option is some sort of temporary boot selection.
  1121. --*/
  1122. {
  1123. PEFI_BDS_COMMON_OPTION BootOption;
  1124. INTN CompareResult;
  1125. LIST_ENTRY List;
  1126. CHAR16 OptionName[EFI_BOOT_OPTION_MAX_CHAR];
  1127. BOOLEAN Valid;
  1128. Valid = FALSE;
  1129. INITIALIZE_LIST_HEAD(&List);
  1130. EfipBdsCreateHexCodeString(L"Boot",
  1131. Option->BootCurrent,
  1132. OptionName,
  1133. sizeof(OptionName));
  1134. BootOption = EfipBdsConvertVariableToOption(&List, OptionName);
  1135. if (BootOption == NULL) {
  1136. return FALSE;
  1137. }
  1138. if (Option->BootCurrent == BootOption->BootCurrent) {
  1139. CompareResult = EfiCoreCompareMemory(
  1140. Option->DevicePath,
  1141. BootOption->DevicePath,
  1142. EfiCoreGetDevicePathSize(Option->DevicePath));
  1143. if (CompareResult == 0) {
  1144. Valid = TRUE;
  1145. }
  1146. }
  1147. EfiCoreFreePool(BootOption);
  1148. return Valid;
  1149. }
  1150. VOID
  1151. EfipBdsSignalReadyToBootEvent (
  1152. VOID
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. This routine creates, signals, and closes a "ready to boot" event group.
  1157. Arguments:
  1158. None.
  1159. Return Value:
  1160. None.
  1161. --*/
  1162. {
  1163. EFI_EVENT ReadyToBootEvent;
  1164. EFI_STATUS Status;
  1165. Status = EfiCreateEventEx(EVT_NOTIFY_SIGNAL,
  1166. TPL_CALLBACK,
  1167. EfiCoreEmptyCallbackFunction,
  1168. NULL,
  1169. &EfiEventReadyToBootGuid,
  1170. &ReadyToBootEvent);
  1171. if (!EFI_ERROR(Status)) {
  1172. EfiSignalEvent(ReadyToBootEvent);
  1173. EfiCloseEvent(ReadyToBootEvent);
  1174. }
  1175. return;
  1176. }
  1177. EFI_HANDLE
  1178. EfipBdsGetBootableHandle (
  1179. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. This routine returns the bootable media handle. It checks to see if the
  1184. device is connected, opens the simple file system interface, and then
  1185. detects a boot file in the media.
  1186. Arguments:
  1187. DevicePath - Supplies a pointer to the device path of a bootable device.
  1188. Return Value:
  1189. Returns the bootable media handle.
  1190. NULL if the media is not bootable.
  1191. --*/
  1192. {
  1193. EFI_BLOCK_IO_PROTOCOL *BlockIo;
  1194. VOID *Buffer;
  1195. EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;
  1196. EFI_IMAGE_DOS_HEADER DosHeader;
  1197. EFI_HANDLE Handle;
  1198. EFI_IMAGE_OPTIONAL_HEADER_UNION Header;
  1199. EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION HeaderPointer;
  1200. UINTN Index;
  1201. EFI_TPL OldTpl;
  1202. EFI_DEVICE_PATH_PROTOCOL *PotentialPath;
  1203. UINTN PotentialPathSize;
  1204. EFI_HANDLE ReturnHandle;
  1205. UINTN SimpleFileSystemHandleCount;
  1206. EFI_HANDLE *SimpleFileSystemHandles;
  1207. UINTN Size;
  1208. EFI_STATUS Status;
  1209. EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
  1210. DevicePathCopy = NULL;
  1211. UpdatedDevicePath = DevicePath;
  1212. //
  1213. // Raise the TPL to prevent the block I/O instance from getting released
  1214. // due to a USB hot plug event.
  1215. //
  1216. OldTpl = EfiRaiseTPL(TPL_CALLBACK);
  1217. //
  1218. // Find out whether or not the device is connected.
  1219. //
  1220. Status = EfiLocateDevicePath(&EfiBlockIoProtocolGuid,
  1221. &UpdatedDevicePath,
  1222. &Handle);
  1223. if (EFI_ERROR(Status)) {
  1224. Status = EfiLocateDevicePath(&EfiSimpleFileSystemProtocolGuid,
  1225. &UpdatedDevicePath,
  1226. &Handle);
  1227. //
  1228. // If the simple file system and block I/O protocols are not present,
  1229. // perhaps it's just because the device is not connected.
  1230. //
  1231. if (EFI_ERROR(Status)) {
  1232. UpdatedDevicePath = DevicePath;
  1233. Status = EfiLocateDevicePath(&EfiDevicePathProtocolGuid,
  1234. &UpdatedDevicePath,
  1235. &Handle);
  1236. if (!EFI_ERROR(Status)) {
  1237. EfiConnectController(Handle, NULL, NULL, TRUE);
  1238. }
  1239. }
  1240. } else {
  1241. //
  1242. // For a removable device boot option, make sure all children are
  1243. // created.
  1244. //
  1245. EfiConnectController(Handle, NULL, NULL, TRUE);
  1246. //
  1247. // Get the block I/O protocol and check the removable attribute.
  1248. //
  1249. Status = EfiHandleProtocol(Handle,
  1250. &EfiBlockIoProtocolGuid,
  1251. (VOID **)&BlockIo);
  1252. ASSERT(!EFI_ERROR(Status));
  1253. //
  1254. // Issue a dummy read to check for media change.
  1255. //
  1256. Buffer = EfiCoreAllocateBootPool(BlockIo->Media->BlockSize);
  1257. if (Buffer != NULL) {
  1258. BlockIo->ReadBlocks(BlockIo,
  1259. BlockIo->Media->MediaId,
  1260. 0,
  1261. BlockIo->Media->BlockSize,
  1262. Buffer);
  1263. EfiCoreFreePool(Buffer);
  1264. }
  1265. }
  1266. //
  1267. // Detect the default boot file from removable media.
  1268. //
  1269. DevicePathCopy = EfiCoreDuplicateDevicePath(DevicePath);
  1270. if (DevicePathCopy == NULL) {
  1271. return NULL;
  1272. }
  1273. UpdatedDevicePath = DevicePathCopy;
  1274. Status = EfiLocateDevicePath(&EfiDevicePathProtocolGuid,
  1275. &UpdatedDevicePath,
  1276. &Handle);
  1277. //
  1278. // If the resulting device path points to a USB node and the USB node is
  1279. // a dummy node, only let the device path point to the previous PCI node:
  1280. // ACPI/PCI/USB --> ACPI/PCI.
  1281. //
  1282. if ((EfiCoreGetDevicePathType(UpdatedDevicePath) ==
  1283. MESSAGING_DEVICE_PATH) &&
  1284. (EfiCoreGetDevicePathSubType(UpdatedDevicePath) == MSG_USB_DP)) {
  1285. //
  1286. // Remove the USB node, let the device path point to the PCI node.
  1287. //
  1288. EfiCoreSetDevicePathEndNode(UpdatedDevicePath);
  1289. UpdatedDevicePath = DevicePathCopy;
  1290. } else {
  1291. UpdatedDevicePath = DevicePath;
  1292. }
  1293. //
  1294. // Get the device path size of the boot option.
  1295. //
  1296. Size = EfiCoreGetDevicePathSize(UpdatedDevicePath) - END_DEVICE_PATH_LENGTH;
  1297. ReturnHandle = NULL;
  1298. Status = EfiLocateHandleBuffer(ByProtocol,
  1299. &EfiSimpleFileSystemProtocolGuid,
  1300. NULL,
  1301. &SimpleFileSystemHandleCount,
  1302. &SimpleFileSystemHandles);
  1303. for (Index = 0; Index < SimpleFileSystemHandleCount; Index += 1) {
  1304. PotentialPath = EfiCoreGetDevicePathFromHandle(
  1305. SimpleFileSystemHandles[Index]);
  1306. PotentialPathSize = EfiCoreGetDevicePathSize(PotentialPath) -
  1307. END_DEVICE_PATH_LENGTH;
  1308. //
  1309. // Determine whether or not the device path of the boot option is part
  1310. // of the simple file system handle's device path.
  1311. //
  1312. if ((Size <= PotentialPathSize) &&
  1313. (EfiCoreCompareMemory(PotentialPath, UpdatedDevicePath, Size) ==
  1314. 0)) {
  1315. HeaderPointer.Union = &Header;
  1316. Status = EfipBdsGetImageHeader(SimpleFileSystemHandles[Index],
  1317. EFI_REMOVABLE_MEDIA_FILE_NAME,
  1318. &DosHeader,
  1319. HeaderPointer);
  1320. if ((!EFI_ERROR(Status)) &&
  1321. (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(
  1322. HeaderPointer.Pe32->FileHeader.Machine)) &&
  1323. (HeaderPointer.Pe32->OptionalHeader.Subsystem ==
  1324. EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
  1325. ReturnHandle = SimpleFileSystemHandles[Index];
  1326. break;
  1327. }
  1328. }
  1329. }
  1330. EfiCoreFreePool(DevicePathCopy);
  1331. if (SimpleFileSystemHandles != NULL) {
  1332. EfiCoreFreePool(SimpleFileSystemHandles);
  1333. }
  1334. EfiRestoreTPL(OldTpl);
  1335. return ReturnHandle;
  1336. }