OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
BmBoot.c
Go to the documentation of this file.
1
12#include "NetworkBootInternal.h"
13
14EFI_RAM_DISK_PROTOCOL *mRamDisk = NULL;
15
27STATIC
28EFI_DEVICE_PATH_PROTOCOL *
30 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
31 IN EFI_DEVICE_PATH_PROTOCOL *FullPath
32 )
33{
34 EFI_STATUS Status;
35 EFI_HANDLE Handle;
36 EFI_BLOCK_IO_PROTOCOL *BlockIo;
37 VOID *Buffer;
38 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
39 EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
40 UINTN Size;
41 UINTN TempSize;
42 EFI_HANDLE *SimpleFileSystemHandles;
43 UINTN NumberSimpleFileSystemHandles;
44 UINTN Index;
45 BOOLEAN GetNext;
46
47 GetNext = (BOOLEAN)(FullPath == NULL);
48 //
49 // Check whether the device is connected
50 //
51 TempDevicePath = DevicePath;
52 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
53 if (!EFI_ERROR (Status)) {
54 ASSERT (IsDevicePathEnd (TempDevicePath));
55
56 NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
57 //
58 // For device path pointing to simple file system, it only expands to one full path.
59 //
60 if (GetNext) {
61 return NextFullPath;
62 } else {
63 FreePool (NextFullPath);
64 return NULL;
65 }
66 }
67
68 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
69 ASSERT_EFI_ERROR (Status);
70
71 //
72 // For device boot option only pointing to the removable device handle,
73 // should make sure all its children handles (its child partion or media handles)
74 // are created and connected.
75 //
76 gBS->ConnectController (Handle, NULL, NULL, TRUE);
77
78 //
79 // Issue a dummy read to the device to check for media change.
80 // When the removable media is changed, any Block IO read/write will
81 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
82 // returned. After the Block IO protocol is reinstalled, subsequent
83 // Block IO read/write will success.
84 //
85 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
86 ASSERT_EFI_ERROR (Status);
87 if (EFI_ERROR (Status)) {
88 return NULL;
89 }
90
91 Buffer = AllocatePool (BlockIo->Media->BlockSize);
92 if (Buffer != NULL) {
93 BlockIo->ReadBlocks (
94 BlockIo,
95 BlockIo->Media->MediaId,
96 0,
97 BlockIo->Media->BlockSize,
98 Buffer
99 );
100 FreePool (Buffer);
101 }
102
103 //
104 // Detect the the default boot file from removable Media
105 //
106 NextFullPath = NULL;
107 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
108 gBS->LocateHandleBuffer (
109 ByProtocol,
111 NULL,
112 &NumberSimpleFileSystemHandles,
113 &SimpleFileSystemHandles
114 );
115 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
116 //
117 // Get the device path size of SimpleFileSystem handle
118 //
119 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
120 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
121 //
122 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
123 //
124 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
125 NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
126 if (GetNext) {
127 break;
128 } else {
129 GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
130 FreePool (NextFullPath);
131 NextFullPath = NULL;
132 }
133 }
134 }
135
136 if (SimpleFileSystemHandles != NULL) {
137 FreePool (SimpleFileSystemHandles);
138 }
139
140 return NextFullPath;
141}
142
150STATIC
151BOOLEAN
153 IN EFI_DEVICE_PATH_PROTOCOL *Left,
154 IN EFI_DEVICE_PATH_PROTOCOL *Right
155 )
156{
157 for ( ; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
158 ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
159 )
160 {
161 if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
162 if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
163 return FALSE;
164 }
165
166 if (DevicePathSubType (Left) == MSG_DNS_DP) {
167 Left = NextDevicePathNode (Left);
168 }
169
170 if (DevicePathSubType (Right) == MSG_DNS_DP) {
171 Right = NextDevicePathNode (Right);
172 }
173
174 if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
175 ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
176 ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
177 )
178 {
179 return FALSE;
180 }
181 }
182 }
183
184 return (BOOLEAN)(IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
185}
186
196STATIC
197EFI_DEVICE_PATH_PROTOCOL *
199 IN EFI_HANDLE LoadFileHandle,
200 OUT EFI_HANDLE *RamDiskHandle
201 )
202{
203 EFI_STATUS Status;
204 EFI_HANDLE Handle;
205 EFI_HANDLE *Handles;
206 UINTN HandleCount;
207 UINTN Index;
208 EFI_DEVICE_PATH_PROTOCOL *Node;
209
210 Status = gBS->LocateHandleBuffer (
211 ByProtocol,
213 NULL,
214 &HandleCount,
215 &Handles
216 );
217 if (EFI_ERROR (Status)) {
218 Handles = NULL;
219 HandleCount = 0;
220 }
221
222 Handle = NULL;
223 for (Index = 0; Index < HandleCount; Index++) {
224 Node = DevicePathFromHandle (Handles[Index]);
225 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
226 if (!EFI_ERROR (Status) &&
227 (Handle == LoadFileHandle) &&
228 (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP))
229 {
230 //
231 // Find the BlockIo instance populated from the LoadFile.
232 //
233 Handle = Handles[Index];
234 break;
235 }
236 }
237
238 if (Handles != NULL) {
239 FreePool (Handles);
240 }
241
242 if (Index == HandleCount) {
243 Handle = NULL;
244 }
245
246 *RamDiskHandle = Handle;
247
248 if (Handle != NULL) {
249 //
250 // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
251 // But assume only one SimpleFileSystem can be found under the BlockIo.
252 //
254 } else {
255 return NULL;
256 }
257}
258
266EFI_DEVICE_PATH_PROTOCOL *
268 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
269 )
270{
271 EFI_STATUS Status;
272 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
273 EFI_DEVICE_PATH_PROTOCOL *Node;
274 EFI_HANDLE Handle;
275
276 Node = FilePath;
277 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
278 if (!EFI_ERROR (Status) &&
279 (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&
280 (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)
281 )
282 {
283 //
284 // Construct the device path pointing to RAM Disk
285 //
286 Node = NextDevicePathNode (Node);
287 RamDiskDevicePath = DuplicateDevicePath (FilePath);
288 ASSERT (RamDiskDevicePath != NULL);
289 SetDevicePathEndNode ((VOID *)((UINTN)RamDiskDevicePath + ((UINTN)Node - (UINTN)FilePath)));
290 return RamDiskDevicePath;
291 }
292
293 return NULL;
294}
295
304STATIC
305VOID *
307 IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,
308 OUT UINTN *RamDiskSizeInPages
309 )
310{
311 EFI_STATUS Status;
312 EFI_HANDLE Handle;
313 UINT64 StartingAddr;
314 UINT64 EndingAddr;
315
316 ASSERT (RamDiskDevicePath != NULL);
317
318 *RamDiskSizeInPages = 0;
319
320 //
321 // Get the buffer occupied by RAM Disk.
322 //
323 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);
324 ASSERT_EFI_ERROR (Status);
325 ASSERT (
326 (DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&
327 (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP)
328 );
329 StartingAddr = ReadUnaligned64 ((UINT64 *)((MEDIA_RAM_DISK_DEVICE_PATH *)RamDiskDevicePath)->StartingAddr);
330 EndingAddr = ReadUnaligned64 ((UINT64 *)((MEDIA_RAM_DISK_DEVICE_PATH *)RamDiskDevicePath)->EndingAddr);
331 *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN)(EndingAddr - StartingAddr + 1));
332 return (VOID *)(UINTN)StartingAddr;
333}
334
344VOID
346 IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
347 )
348{
349 EFI_STATUS Status;
350 VOID *RamDiskBuffer;
351 UINTN RamDiskSizeInPages;
352
353 ASSERT (RamDiskDevicePath != NULL);
354
355 RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);
356
357 //
358 // Destroy RAM Disk.
359 //
360 if (mRamDisk == NULL) {
361 Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *)&mRamDisk);
362 ASSERT_EFI_ERROR (Status);
363 }
364
365 Status = mRamDisk->Unregister (RamDiskDevicePath);
366 ASSERT_EFI_ERROR (Status);
367 FreePages (RamDiskBuffer, RamDiskSizeInPages);
368}
369
378STATIC
379EFI_DEVICE_PATH_PROTOCOL *
381 IN EFI_HANDLE LoadFileHandle,
382 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
383 OUT VOID **Data,
384 OUT UINT32 *DataSize
385 )
386{
387 EFI_STATUS Status;
388 EFI_LOAD_FILE_PROTOCOL *LoadFile;
389 VOID *FileBuffer;
390 EFI_HANDLE RamDiskHandle;
391 UINTN BufferSize;
392 EFI_DEVICE_PATH_PROTOCOL *FullPath;
393
394 ASSERT (Data != NULL);
395 ASSERT (DataSize != NULL);
396
397 *Data = NULL;
398 *DataSize = 0;
399
400 Status = gBS->OpenProtocol (
401 LoadFileHandle,
402 &gEfiLoadFileProtocolGuid,
403 (VOID **)&LoadFile,
405 NULL,
406 EFI_OPEN_PROTOCOL_GET_PROTOCOL
407 );
408 ASSERT_EFI_ERROR (Status);
409
410 FileBuffer = NULL;
411 BufferSize = 0;
412 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
413 if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
414 return NULL;
415 }
416
417 //
418 // In call tree of original BmGetLoadOptionBuffer, handling this case
419 // is deferred to subsequent call to GetFileBufferByFilePath.
420 //
421 if (Status == EFI_BUFFER_TOO_SMALL) {
422 //
423 // Limited to UINT32 by DataSize in OC_CUSTOM_READ, which is limited
424 // by Size in OcGetFileSize.
425 //
426 if (BufferSize > MAX_UINT32) {
427 return NULL;
428 }
429
430 FileBuffer = AllocatePool (BufferSize);
431 if (FileBuffer == NULL) {
432 return NULL;
433 }
434
435 //
436 // Call LoadFile with the correct buffer size.
437 //
438 FullPath = DevicePathFromHandle (LoadFileHandle);
439 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
440 if (EFI_ERROR (Status)) {
441 FreePool (FileBuffer);
442 return NULL;
443 }
444
445 *DataSize = (UINT32)BufferSize;
446 *Data = FileBuffer;
447
448 return DuplicateDevicePath (FullPath);
449 }
450
451 //
452 // The load option resides in a RAM disk.
453 //
454 FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
455 if (FileBuffer == NULL) {
456 DEBUG_CODE_BEGIN ();
457 EFI_DEVICE_PATH *LoadFilePath;
458 CHAR16 *LoadFileText;
459 CHAR16 *FileText;
460
461 LoadFilePath = DevicePathFromHandle (LoadFileHandle);
462 if (LoadFilePath == NULL) {
463 LoadFileText = NULL;
464 } else {
465 LoadFileText = ConvertDevicePathToText (LoadFilePath, FALSE, FALSE);
466 }
467
468 FileText = ConvertDevicePathToText (FilePath, FALSE, FALSE);
469
470 DEBUG ((
471 DEBUG_ERROR,
472 "%a:%a: failed to allocate reserved pages: "
473 "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
475 __func__,
476 (UINT64)BufferSize,
477 LoadFileText,
478 FileText
479 ));
480
481 if (FileText != NULL) {
482 FreePool (FileText);
483 }
484
485 if (LoadFileText != NULL) {
486 FreePool (LoadFileText);
487 }
488
489 DEBUG_CODE_END ();
490 return NULL;
491 }
492
493 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
494 if (EFI_ERROR (Status)) {
495 FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
496 return NULL;
497 }
498
499 FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);
500 if (FullPath == NULL) {
501 //
502 // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
503 //
504 BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
505 }
506
507 return FullPath;
508}
509
529EFI_DEVICE_PATH_PROTOCOL *
531 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
532 OUT VOID **Data,
533 OUT UINT32 *DataSize,
534 IN BOOLEAN ValidateHttp
535 )
536{
537 EFI_STATUS Status;
538 EFI_HANDLE Handle;
539 EFI_HANDLE *Handles;
540 UINTN HandleCount;
541 UINTN Index;
542 EFI_DEVICE_PATH_PROTOCOL *Node;
543 EFI_EVENT NotifyEvent;
544
545 //
546 // Get file buffer from load file instance.
547 //
548 Node = FilePath;
549 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
550 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
551 //
552 // When wide match happens, pass full device path to LoadFile (),
553 // otherwise, pass remaining device path to LoadFile ().
554 //
555 FilePath = Node;
556 } else {
557 Handle = NULL;
558 //
559 // Use wide match algorithm to find one when
560 // cannot find a LoadFile instance to exactly match the FilePath
561 //
562 Status = gBS->LocateHandleBuffer (
563 ByProtocol,
564 &gEfiLoadFileProtocolGuid,
565 NULL,
566 &HandleCount,
567 &Handles
568 );
569 if (EFI_ERROR (Status)) {
570 Handles = NULL;
571 HandleCount = 0;
572 }
573
574 for (Index = 0; Index < HandleCount; Index++) {
576 Handle = Handles[Index];
577 break;
578 }
579 }
580
581 if (Handles != NULL) {
582 FreePool (Handles);
583 }
584 }
585
586 if (Handle == NULL) {
587 return NULL;
588 }
589
590 if (ValidateHttp) {
591 NotifyEvent = MonitorHttpBootCallback (Handle);
592 if (NotifyEvent == NULL) {
593 return NULL;
594 }
595 }
596
597 Node = BmExpandLoadFile (Handle, FilePath, Data, DataSize);
598
599 if (ValidateHttp) {
600 gBS->CloseEvent (NotifyEvent);
601
602 if ((Node != NULL) && !UriWasValidated ()) {
603 Print (L"\n");
604 DEBUG ((DEBUG_ERROR, "NETB: LoadFile returned value but URI was never validated\n"));
605 FreePool (Node);
606 return NULL;
607 }
608 }
609
610 return Node;
611}
STATIC VOID * BmGetRamDiskMemoryInfo(IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath, OUT UINTN *RamDiskSizeInPages)
Definition BmBoot.c:306
EFI_DEVICE_PATH_PROTOCOL * BmExpandLoadFiles(IN EFI_DEVICE_PATH_PROTOCOL *FilePath, OUT VOID **Data, OUT UINT32 *DataSize, IN BOOLEAN ValidateHttp)
Definition BmBoot.c:530
EFI_RAM_DISK_PROTOCOL * mRamDisk
Definition BmBoot.c:14
EFI_DEVICE_PATH_PROTOCOL * BmGetRamDiskDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *FilePath)
Definition BmBoot.c:267
VOID BmDestroyRamDisk(IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath)
Definition BmBoot.c:345
STATIC BOOLEAN BmMatchHttpBootDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *Left, IN EFI_DEVICE_PATH_PROTOCOL *Right)
Definition BmBoot.c:152
STATIC EFI_DEVICE_PATH_PROTOCOL * BmExpandLoadFile(IN EFI_HANDLE LoadFileHandle, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, OUT VOID **Data, OUT UINT32 *DataSize)
Definition BmBoot.c:380
STATIC EFI_DEVICE_PATH_PROTOCOL * BmExpandNetworkFileSystem(IN EFI_HANDLE LoadFileHandle, OUT EFI_HANDLE *RamDiskHandle)
Definition BmBoot.c:198
STATIC EFI_DEVICE_PATH_PROTOCOL * BmExpandMediaDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN EFI_DEVICE_PATH_PROTOCOL *FullPath)
Definition BmBoot.c:29
BOOLEAN UriWasValidated(VOID)
EFI_EVENT MonitorHttpBootCallback(EFI_HANDLE LoadFileHandle)
DMG_FILEPATH_DEVICE_PATH FilePath
DMG_SIZE_DEVICE_PATH Size
EFI_HANDLE gImageHandle
EFI_BOOT_SERVICES * gBS
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
APPLE_EVENT_HANDLE Handle
Definition OcTypingLib.h:45
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
UINT64 EFIAPI ReadUnaligned64(IN CONST UINT64 *Buffer)
EFI_GUID gEfiSimpleFileSystemProtocolGuid
CONST CHAR8 * gEfiCallerBaseName
EFI_GUID gEfiBlockIoProtocolGuid
EFI_DEVICE_PATH_PROTOCOL *EFIAPI DevicePathFromHandle(IN EFI_HANDLE Handle)
Definition UserMisc.c:680
#define ASSERT(x)
Definition coder.h:55