1 /** @file 2 * 3 * Copyright (c) 2011-2014, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include "BdsInternal.h" 16 17 #include <Library/NetLib.h> 18 19 #include <Protocol/Bds.h> 20 #include <Protocol/BlockIo.h> 21 #include <Protocol/UsbIo.h> 22 #include <Protocol/DiskIo.h> 23 #include <Protocol/LoadedImage.h> 24 #include <Protocol/SimpleNetwork.h> 25 #include <Protocol/Dhcp4.h> 26 #include <Protocol/Mtftp4.h> 27 28 #include <Guid/Fdt.h> 29 30 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype))) 31 32 /* Type and defines to set up the DHCP4 options */ 33 34 typedef struct { 35 EFI_DHCP4_PACKET_OPTION Head; 36 UINT8 Route; 37 } DHCP4_OPTION; 38 39 #define DHCP_TAG_PARA_LIST 55 40 #define DHCP_TAG_NETMASK 1 41 #define DHCP_TAG_ROUTER 3 42 43 STATIC VOID *gArgs; 44 45 /* 46 Constant strings and define related to the message indicating the amount of 47 progress in the dowloading of a TFTP file. 48 */ 49 50 // Frame for the progression slider 51 STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]"; 52 53 // Number of steps in the progression slider 54 #define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3) 55 56 // Size in number of characters plus one (final zero) of the message to 57 // indicate the progress of a tftp download. The format is "[(progress slider: 58 // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There 59 // are thus the number of characters in mTftpProgressFrame[] plus 11 characters 60 // (2 // spaces, "Kb" and seven characters for the number of KBytes). 61 #define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12) 62 63 // String to delete the tftp progress message to be able to update it : 64 // (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b' 65 STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"; 66 67 68 // Extract the FilePath from the Device Path 69 CHAR16* 70 BdsExtractFilePathFromDevicePath ( 71 IN CONST CHAR16 *StrDevicePath, 72 IN UINTN NumberDevicePathNode 73 ) 74 { 75 UINTN Node; 76 CHAR16 *Str; 77 78 Str = (CHAR16*)StrDevicePath; 79 Node = 0; 80 while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) { 81 if ((*Str == L'/') || (*Str == L'\\')) { 82 Node++; 83 } 84 Str++; 85 } 86 87 if (*Str == L'\0') { 88 return NULL; 89 } else { 90 return Str; 91 } 92 } 93 94 BOOLEAN 95 BdsIsRemovableUsb ( 96 IN EFI_DEVICE_PATH* DevicePath 97 ) 98 { 99 return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && 100 ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) || 101 (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP))); 102 } 103 104 EFI_STATUS 105 BdsGetDeviceUsb ( 106 IN EFI_DEVICE_PATH* RemovableDevicePath, 107 OUT EFI_HANDLE* DeviceHandle, 108 OUT EFI_DEVICE_PATH** NewDevicePath 109 ) 110 { 111 EFI_STATUS Status; 112 UINTN Index; 113 UINTN UsbIoHandleCount; 114 EFI_HANDLE *UsbIoBuffer; 115 EFI_DEVICE_PATH* UsbIoDevicePath; 116 EFI_DEVICE_PATH* TmpDevicePath; 117 USB_WWID_DEVICE_PATH* WwidDevicePath1; 118 USB_WWID_DEVICE_PATH* WwidDevicePath2; 119 USB_CLASS_DEVICE_PATH* UsbClassDevicePath1; 120 USB_CLASS_DEVICE_PATH* UsbClassDevicePath2; 121 122 // Get all the UsbIo handles 123 UsbIoHandleCount = 0; 124 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer); 125 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0)) { 126 return Status; 127 } 128 129 // Check if one of the handles matches the USB description 130 for (Index = 0; Index < UsbIoHandleCount; Index++) { 131 Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath); 132 if (!EFI_ERROR (Status)) { 133 TmpDevicePath = UsbIoDevicePath; 134 while (!IsDevicePathEnd (TmpDevicePath)) { 135 // Check if the Device Path node is a USB Removable device Path node 136 if (BdsIsRemovableUsb (TmpDevicePath)) { 137 if (TmpDevicePath->SubType == MSG_USB_WWID_DP) { 138 WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath; 139 WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath; 140 if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) && 141 (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) && 142 (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof (USB_WWID_DEVICE_PATH)) == 0)) 143 { 144 *DeviceHandle = UsbIoBuffer[Index]; 145 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path 146 *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath)); 147 return EFI_SUCCESS; 148 } 149 } else { 150 UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath; 151 UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath; 152 if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) && 153 (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) && 154 (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) && 155 (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) && 156 (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol)) 157 { 158 *DeviceHandle = UsbIoBuffer[Index]; 159 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path 160 *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode (RemovableDevicePath)); 161 return EFI_SUCCESS; 162 } 163 } 164 } 165 TmpDevicePath = NextDevicePathNode (TmpDevicePath); 166 } 167 168 } 169 } 170 171 return EFI_NOT_FOUND; 172 } 173 174 BOOLEAN 175 BdsIsRemovableHd ( 176 IN EFI_DEVICE_PATH* DevicePath 177 ) 178 { 179 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP); 180 } 181 182 EFI_STATUS 183 BdsGetDeviceHd ( 184 IN EFI_DEVICE_PATH* RemovableDevicePath, 185 OUT EFI_HANDLE* DeviceHandle, 186 OUT EFI_DEVICE_PATH** NewDevicePath 187 ) 188 { 189 EFI_STATUS Status; 190 UINTN Index; 191 UINTN PartitionHandleCount; 192 EFI_HANDLE *PartitionBuffer; 193 EFI_DEVICE_PATH* PartitionDevicePath; 194 EFI_DEVICE_PATH* TmpDevicePath; 195 HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1; 196 HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2; 197 198 // Get all the DiskIo handles 199 PartitionHandleCount = 0; 200 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer); 201 if (EFI_ERROR (Status) || (PartitionHandleCount == 0)) { 202 return Status; 203 } 204 205 // Check if one of the handles matches the Hard Disk Description 206 for (Index = 0; Index < PartitionHandleCount; Index++) { 207 Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath); 208 if (!EFI_ERROR (Status)) { 209 TmpDevicePath = PartitionDevicePath; 210 while (!IsDevicePathEnd (TmpDevicePath)) { 211 // Check if the Device Path node is a HD Removable device Path node 212 if (BdsIsRemovableHd (TmpDevicePath)) { 213 HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath; 214 HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath; 215 if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) && 216 (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature, (EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) && 217 (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber)) 218 { 219 *DeviceHandle = PartitionBuffer[Index]; 220 // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path 221 *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode (RemovableDevicePath)); 222 return EFI_SUCCESS; 223 } 224 } 225 TmpDevicePath = NextDevicePathNode (TmpDevicePath); 226 } 227 228 } 229 } 230 231 return EFI_NOT_FOUND; 232 } 233 234 /*BOOLEAN 235 BdsIsRemovableCdrom ( 236 IN EFI_DEVICE_PATH* DevicePath 237 ) 238 { 239 return IS_DEVICE_PATH_NODE (DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP); 240 } 241 242 EFI_STATUS 243 BdsGetDeviceCdrom ( 244 IN EFI_DEVICE_PATH* RemovableDevicePath, 245 OUT EFI_HANDLE* DeviceHandle, 246 OUT EFI_DEVICE_PATH** DevicePath 247 ) 248 { 249 ASSERT(0); 250 return EFI_UNSUPPORTED; 251 }*/ 252 253 typedef BOOLEAN 254 (*BDS_IS_REMOVABLE) ( 255 IN EFI_DEVICE_PATH* DevicePath 256 ); 257 258 typedef EFI_STATUS 259 (*BDS_GET_DEVICE) ( 260 IN EFI_DEVICE_PATH* RemovableDevicePath, 261 OUT EFI_HANDLE* DeviceHandle, 262 OUT EFI_DEVICE_PATH** DevicePath 263 ); 264 265 typedef struct { 266 BDS_IS_REMOVABLE IsRemovable; 267 BDS_GET_DEVICE GetDevice; 268 } BDS_REMOVABLE_DEVICE_SUPPORT; 269 270 BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = { 271 { BdsIsRemovableUsb, BdsGetDeviceUsb }, 272 { BdsIsRemovableHd, BdsGetDeviceHd }, 273 //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom } 274 }; 275 276 STATIC 277 BOOLEAN 278 IsRemovableDevice ( 279 IN EFI_DEVICE_PATH* DevicePath 280 ) 281 { 282 UINTN Index; 283 EFI_DEVICE_PATH* TmpDevicePath; 284 285 TmpDevicePath = DevicePath; 286 while (!IsDevicePathEnd (TmpDevicePath)) { 287 for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { 288 if (RemovableDeviceSupport[Index].IsRemovable (TmpDevicePath)) { 289 return TRUE; 290 } 291 } 292 TmpDevicePath = NextDevicePathNode (TmpDevicePath); 293 } 294 295 return FALSE; 296 } 297 298 STATIC 299 EFI_STATUS 300 TryRemovableDevice ( 301 IN EFI_DEVICE_PATH* DevicePath, 302 OUT EFI_HANDLE* DeviceHandle, 303 OUT EFI_DEVICE_PATH** NewDevicePath 304 ) 305 { 306 EFI_STATUS Status; 307 UINTN Index; 308 EFI_DEVICE_PATH* TmpDevicePath; 309 BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice; 310 EFI_DEVICE_PATH* RemovableDevicePath; 311 BOOLEAN RemovableFound; 312 313 RemovableDevice = NULL; 314 RemovableDevicePath = NULL; 315 RemovableFound = FALSE; 316 TmpDevicePath = DevicePath; 317 318 while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) { 319 for (Index = 0; Index < sizeof (RemovableDeviceSupport) / sizeof (BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { 320 RemovableDevice = &RemovableDeviceSupport[Index]; 321 if (RemovableDevice->IsRemovable (TmpDevicePath)) { 322 RemovableDevicePath = TmpDevicePath; 323 RemovableFound = TRUE; 324 break; 325 } 326 } 327 TmpDevicePath = NextDevicePathNode (TmpDevicePath); 328 } 329 330 if (!RemovableFound) { 331 return EFI_NOT_FOUND; 332 } 333 334 // Search into the current started drivers 335 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); 336 if (Status == EFI_NOT_FOUND) { 337 // Connect all the drivers 338 BdsConnectAllDrivers (); 339 340 // Search again into all the drivers 341 Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); 342 } 343 344 return Status; 345 } 346 347 STATIC 348 EFI_STATUS 349 BdsConnectAndUpdateDevicePath ( 350 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, 351 OUT EFI_HANDLE *Handle, 352 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath 353 ) 354 { 355 EFI_DEVICE_PATH* Remaining; 356 EFI_DEVICE_PATH* NewDevicePath; 357 EFI_STATUS Status; 358 EFI_HANDLE PreviousHandle; 359 360 if ((DevicePath == NULL) || (*DevicePath == NULL) || (Handle == NULL)) { 361 return EFI_INVALID_PARAMETER; 362 } 363 364 PreviousHandle = NULL; 365 do { 366 Remaining = *DevicePath; 367 368 // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns 369 // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified 370 // to point to the remaining part of the device path 371 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); 372 373 if (!EFI_ERROR (Status)) { 374 if (*Handle == PreviousHandle) { 375 // 376 // If no forward progress is made try invoking the Dispatcher. 377 // A new FV may have been added to the system and new drivers 378 // may now be found. 379 // Status == EFI_SUCCESS means a driver was dispatched 380 // Status == EFI_NOT_FOUND means no new drivers were dispatched 381 // 382 Status = gDS->Dispatch (); 383 } 384 385 if (!EFI_ERROR (Status)) { 386 PreviousHandle = *Handle; 387 388 // Recursive = FALSE: We do not want to start the whole device tree 389 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); 390 } 391 } 392 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); 393 394 if (!EFI_ERROR (Status)) { 395 // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver 396 // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) 397 Remaining = *DevicePath; 398 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); 399 if (!EFI_ERROR (Status)) { 400 Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); 401 if (EFI_ERROR (Status)) { 402 // If the last node is a Memory Map Device Path just return EFI_SUCCESS. 403 if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { 404 Status = EFI_SUCCESS; 405 } 406 } 407 } 408 } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { 409 410 /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly 411 if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { 412 Status = EFI_SUCCESS; 413 } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { 414 Status = EFI_SUCCESS; 415 }*/ 416 417 //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath 418 Status = EFI_SUCCESS; 419 } else { 420 Status = TryRemovableDevice (*DevicePath, Handle, &NewDevicePath); 421 if (!EFI_ERROR (Status)) { 422 Status = BdsConnectAndUpdateDevicePath (&NewDevicePath, Handle, RemainingDevicePath); 423 *DevicePath = NewDevicePath; 424 return Status; 425 } 426 } 427 428 if (RemainingDevicePath) { 429 *RemainingDevicePath = Remaining; 430 } 431 432 return Status; 433 } 434 435 /** 436 Connect a Device Path and return the handle of the driver that support this DevicePath 437 438 @param DevicePath Device Path of the File to connect 439 @param Handle Handle of the driver that support this DevicePath 440 @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath 441 442 @retval EFI_SUCCESS A driver that matches the Device Path has been found 443 @retval EFI_NOT_FOUND No handles match the search. 444 @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL 445 446 **/ 447 EFI_STATUS 448 BdsConnectDevicePath ( 449 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, 450 OUT EFI_HANDLE *Handle, 451 OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath 452 ) 453 { 454 return BdsConnectAndUpdateDevicePath (&DevicePath, Handle, RemainingDevicePath); 455 } 456 457 BOOLEAN 458 BdsFileSystemSupport ( 459 IN EFI_DEVICE_PATH *DevicePath, 460 IN EFI_HANDLE Handle, 461 IN EFI_DEVICE_PATH *RemainingDevicePath 462 ) 463 { 464 EFI_STATUS Status; 465 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; 466 467 if (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) { 468 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); 469 return (!EFI_ERROR (Status)); 470 } 471 return FALSE; 472 } 473 474 EFI_STATUS 475 BdsFileSystemLoadImage ( 476 IN OUT EFI_DEVICE_PATH **DevicePath, 477 IN EFI_HANDLE Handle, 478 IN EFI_DEVICE_PATH *RemainingDevicePath, 479 IN EFI_ALLOCATE_TYPE Type, 480 IN OUT EFI_PHYSICAL_ADDRESS *Image, 481 OUT UINTN *ImageSize 482 ) 483 { 484 EFI_STATUS Status; 485 FILEPATH_DEVICE_PATH *FilePathDevicePath; 486 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; 487 EFI_FILE_PROTOCOL *Fs; 488 EFI_FILE_INFO *FileInfo; 489 EFI_FILE_PROTOCOL *File; 490 UINTN Size; 491 492 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)); 493 494 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath; 495 496 Status = gBS->OpenProtocol ( 497 Handle, 498 &gEfiSimpleFileSystemProtocolGuid, 499 (VOID**)&FsProtocol, 500 gImageHandle, 501 Handle, 502 EFI_OPEN_PROTOCOL_BY_DRIVER 503 ); 504 if (EFI_ERROR (Status)) { 505 return Status; 506 } 507 508 // Try to Open the volume and get root directory 509 Status = FsProtocol->OpenVolume (FsProtocol, &Fs); 510 if (EFI_ERROR (Status)) { 511 goto CLOSE_PROTOCOL; 512 } 513 514 Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); 515 if (EFI_ERROR (Status)) { 516 goto CLOSE_PROTOCOL; 517 } 518 519 Size = 0; 520 File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL); 521 FileInfo = AllocatePool (Size); 522 Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo); 523 if (EFI_ERROR (Status)) { 524 goto CLOSE_FILE; 525 } 526 527 // Get the file size 528 Size = FileInfo->FileSize; 529 if (ImageSize) { 530 *ImageSize = Size; 531 } 532 FreePool (FileInfo); 533 534 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); 535 // Try to allocate in any pages if failed to allocate memory at the defined location 536 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { 537 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); 538 } 539 if (!EFI_ERROR (Status)) { 540 Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); 541 } 542 543 CLOSE_FILE: 544 File->Close (File); 545 546 CLOSE_PROTOCOL: 547 gBS->CloseProtocol ( 548 Handle, 549 &gEfiSimpleFileSystemProtocolGuid, 550 gImageHandle, 551 Handle); 552 553 return Status; 554 } 555 556 BOOLEAN 557 BdsMemoryMapSupport ( 558 IN EFI_DEVICE_PATH *DevicePath, 559 IN EFI_HANDLE Handle, 560 IN EFI_DEVICE_PATH *RemainingDevicePath 561 ) 562 { 563 return IS_DEVICE_PATH_NODE (DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP) || 564 IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP); 565 } 566 567 EFI_STATUS 568 BdsMemoryMapLoadImage ( 569 IN OUT EFI_DEVICE_PATH **DevicePath, 570 IN EFI_HANDLE Handle, 571 IN EFI_DEVICE_PATH *RemainingDevicePath, 572 IN EFI_ALLOCATE_TYPE Type, 573 IN OUT EFI_PHYSICAL_ADDRESS* Image, 574 OUT UINTN *ImageSize 575 ) 576 { 577 EFI_STATUS Status; 578 MEMMAP_DEVICE_PATH* MemMapPathDevicePath; 579 UINTN Size; 580 581 if (IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) { 582 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath; 583 } else { 584 ASSERT (IS_DEVICE_PATH_NODE (*DevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)); 585 MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)*DevicePath; 586 } 587 588 Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress; 589 if (Size == 0) { 590 return EFI_INVALID_PARAMETER; 591 } 592 593 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); 594 // Try to allocate in any pages if failed to allocate memory at the defined location 595 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { 596 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); 597 } 598 if (!EFI_ERROR (Status)) { 599 CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size); 600 601 if (ImageSize != NULL) { 602 *ImageSize = Size; 603 } 604 } 605 606 return Status; 607 } 608 609 BOOLEAN 610 BdsFirmwareVolumeSupport ( 611 IN EFI_DEVICE_PATH *DevicePath, 612 IN EFI_HANDLE Handle, 613 IN EFI_DEVICE_PATH *RemainingDevicePath 614 ) 615 { 616 return IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP); 617 } 618 619 EFI_STATUS 620 BdsFirmwareVolumeLoadImage ( 621 IN OUT EFI_DEVICE_PATH **DevicePath, 622 IN EFI_HANDLE Handle, 623 IN EFI_DEVICE_PATH *RemainingDevicePath, 624 IN EFI_ALLOCATE_TYPE Type, 625 IN OUT EFI_PHYSICAL_ADDRESS* Image, 626 OUT UINTN *ImageSize 627 ) 628 { 629 EFI_STATUS Status; 630 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; 631 EFI_GUID *FvNameGuid; 632 EFI_SECTION_TYPE SectionType; 633 EFI_FV_FILETYPE FvType; 634 EFI_FV_FILE_ATTRIBUTES Attrib; 635 UINT32 AuthenticationStatus; 636 VOID* ImageBuffer; 637 UINTN NoHandles, HandleIndex; 638 EFI_HANDLE *Handles; 639 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwDevicePath; 640 641 ASSERT (IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)); 642 643 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles); 644 if (EFI_ERROR (Status) || (NoHandles == 0)) { 645 DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n")); 646 return Status; 647 } 648 // Search in all Firmware Volume for the EFI Application 649 for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) { 650 Status = gBS->HandleProtocol (Handles[HandleIndex], &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol); 651 if (EFI_ERROR (Status)) 652 continue; 653 654 FwDevicePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath; 655 FvNameGuid = &(FwDevicePath->FvFileName); 656 if (FvNameGuid == NULL) { 657 Status = EFI_INVALID_PARAMETER; 658 continue; 659 } 660 661 SectionType = EFI_SECTION_PE32; 662 AuthenticationStatus = 0; 663 //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file. 664 ImageBuffer = NULL; 665 Status = FwVol->ReadSection ( 666 FwVol, 667 FvNameGuid, 668 SectionType, 669 0, 670 &ImageBuffer, 671 ImageSize, 672 &AuthenticationStatus 673 ); 674 if (!EFI_ERROR (Status)) { 675 #if 0 676 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements 677 if (Type != AllocateAnyPages) { 678 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image); 679 if (!EFI_ERROR (Status)) { 680 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); 681 FreePool (ImageBuffer); 682 } 683 } 684 #else 685 // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation 686 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); 687 // Try to allocate in any pages if failed to allocate memory at the defined location 688 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { 689 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); 690 } 691 if (!EFI_ERROR (Status)) { 692 CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); 693 FreePool (ImageBuffer); 694 return Status; 695 } 696 #endif 697 } else { 698 // Try a raw file, since a PE32 SECTION does not exist 699 Status = FwVol->ReadFile ( 700 FwVol, 701 FvNameGuid, 702 NULL, 703 ImageSize, 704 &FvType, 705 &Attrib, 706 &AuthenticationStatus 707 ); 708 if (!EFI_ERROR (Status)) { 709 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); 710 // Try to allocate in any pages if failed to allocate memory at the defined location 711 if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { 712 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); 713 } 714 if (!EFI_ERROR (Status)) { 715 Status = FwVol->ReadFile ( 716 FwVol, 717 FvNameGuid, 718 (VOID*)(UINTN)(*Image), 719 ImageSize, 720 &FvType, 721 &Attrib, 722 &AuthenticationStatus 723 ); 724 if (!EFI_ERROR (Status)) 725 return Status; 726 } 727 } 728 } 729 } 730 return Status; 731 } 732 733 BOOLEAN 734 BdsPxeSupport ( 735 IN EFI_DEVICE_PATH* DevicePath, 736 IN EFI_HANDLE Handle, 737 IN EFI_DEVICE_PATH* RemainingDevicePath 738 ) 739 { 740 EFI_STATUS Status; 741 EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol; 742 743 if (!IsDevicePathEnd (RemainingDevicePath)) { 744 return FALSE; 745 } 746 747 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); 748 if (EFI_ERROR (Status)) { 749 return FALSE; 750 } else { 751 return TRUE; 752 } 753 } 754 755 EFI_STATUS 756 BdsPxeLoadImage ( 757 IN OUT EFI_DEVICE_PATH **DevicePath, 758 IN EFI_HANDLE Handle, 759 IN EFI_DEVICE_PATH *RemainingDevicePath, 760 IN EFI_ALLOCATE_TYPE Type, 761 IN OUT EFI_PHYSICAL_ADDRESS* Image, 762 OUT UINTN *ImageSize 763 ) 764 { 765 EFI_STATUS Status; 766 EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol; 767 UINTN BufferSize; 768 EFI_PXE_BASE_CODE_PROTOCOL *Pxe; 769 770 // Get Load File Protocol attached to the PXE protocol 771 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol); 772 if (EFI_ERROR (Status)) { 773 return Status; 774 } 775 776 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevicePath, TRUE, &BufferSize, NULL); 777 if (Status == EFI_BUFFER_TOO_SMALL) { 778 Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image); 779 if (EFI_ERROR (Status)) { 780 return Status; 781 } 782 783 Status = LoadFileProtocol->LoadFile (LoadFileProtocol, RemainingDevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image)); 784 if (!EFI_ERROR (Status) && (ImageSize != NULL)) { 785 *ImageSize = BufferSize; 786 } 787 } 788 789 if (Status == EFI_ALREADY_STARTED) { 790 Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); 791 if (!EFI_ERROR(Status)) { 792 // If PXE is already started, we stop it 793 Pxe->Stop (Pxe); 794 // And we try again 795 return BdsPxeLoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, ImageSize); 796 } 797 } 798 return Status; 799 } 800 801 BOOLEAN 802 BdsTftpSupport ( 803 IN EFI_DEVICE_PATH *DevicePath, 804 IN EFI_HANDLE Handle, 805 IN EFI_DEVICE_PATH *RemainingDevicePath 806 ) 807 { 808 EFI_STATUS Status; 809 EFI_DEVICE_PATH *NextDevicePath; 810 VOID *Interface; 811 812 // Validate the Remaining Device Path 813 if (IsDevicePathEnd (RemainingDevicePath)) { 814 return FALSE; 815 } 816 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) && 817 !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) { 818 return FALSE; 819 } 820 NextDevicePath = NextDevicePathNode (RemainingDevicePath); 821 if (IsDevicePathEnd (NextDevicePath)) { 822 return FALSE; 823 } 824 if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) { 825 return FALSE; 826 } 827 828 Status = gBS->HandleProtocol ( 829 Handle, &gEfiDevicePathProtocolGuid, 830 &Interface 831 ); 832 if (EFI_ERROR (Status)) { 833 return FALSE; 834 } 835 836 // 837 // Check that the controller (identified by its handle "Handle") supports the 838 // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the 839 // EFI MTFTPv4 Protocol needed to download the image through TFTP. 840 // 841 Status = gBS->HandleProtocol ( 842 Handle, &gEfiMtftp4ServiceBindingProtocolGuid, 843 &Interface 844 ); 845 if (EFI_ERROR (Status)) { 846 return FALSE; 847 } 848 849 return TRUE; 850 } 851 852 /** 853 Worker function that get the size in numbers of bytes of a file from a TFTP 854 server before to download the file. 855 856 @param[in] Mtftp4 MTFTP4 protocol interface 857 @param[in] FilePath Path of the file, Ascii encoded 858 @param[out] FileSize Address where to store the file size in number of 859 bytes. 860 861 @retval EFI_SUCCESS The size of the file was returned. 862 @retval !EFI_SUCCESS The size of the file was not returned. 863 864 **/ 865 STATIC 866 EFI_STATUS 867 Mtftp4GetFileSize ( 868 IN EFI_MTFTP4_PROTOCOL *Mtftp4, 869 IN CHAR8 *FilePath, 870 OUT UINT64 *FileSize 871 ) 872 { 873 EFI_STATUS Status; 874 EFI_MTFTP4_OPTION ReqOpt[1]; 875 EFI_MTFTP4_PACKET *Packet; 876 UINT32 PktLen; 877 EFI_MTFTP4_OPTION *TableOfOptions; 878 EFI_MTFTP4_OPTION *Option; 879 UINT32 OptCnt; 880 UINT8 OptBuf[128]; 881 882 ReqOpt[0].OptionStr = (UINT8*)"tsize"; 883 OptBuf[0] = '0'; 884 OptBuf[1] = 0; 885 ReqOpt[0].ValueStr = OptBuf; 886 887 Status = Mtftp4->GetInfo ( 888 Mtftp4, 889 NULL, 890 (UINT8*)FilePath, 891 NULL, 892 1, 893 ReqOpt, 894 &PktLen, 895 &Packet 896 ); 897 898 if (EFI_ERROR (Status)) { 899 goto Error; 900 } 901 902 Status = Mtftp4->ParseOptions ( 903 Mtftp4, 904 PktLen, 905 Packet, 906 (UINT32 *) &OptCnt, 907 &TableOfOptions 908 ); 909 if (EFI_ERROR (Status)) { 910 goto Error; 911 } 912 913 Option = TableOfOptions; 914 while (OptCnt != 0) { 915 if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) { 916 *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr); 917 break; 918 } 919 OptCnt--; 920 Option++; 921 } 922 FreePool (TableOfOptions); 923 924 if (OptCnt == 0) { 925 Status = EFI_UNSUPPORTED; 926 } 927 928 Error : 929 930 return Status; 931 } 932 933 /** 934 Update the progress of a file download 935 This procedure is called each time a new TFTP packet is received. 936 937 @param[in] This MTFTP4 protocol interface 938 @param[in] Token Parameters for the download of the file 939 @param[in] PacketLen Length of the packet 940 @param[in] Packet Address of the packet 941 942 @retval EFI_SUCCESS All packets are accepted. 943 944 **/ 945 STATIC 946 EFI_STATUS 947 Mtftp4CheckPacket ( 948 IN EFI_MTFTP4_PROTOCOL *This, 949 IN EFI_MTFTP4_TOKEN *Token, 950 IN UINT16 PacketLen, 951 IN EFI_MTFTP4_PACKET *Packet 952 ) 953 { 954 BDS_TFTP_CONTEXT *Context; 955 CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE]; 956 UINT64 NbOfKb; 957 UINTN Index; 958 UINTN LastStep; 959 UINTN Step; 960 UINT64 LastNbOf50Kb; 961 UINT64 NbOf50Kb; 962 963 if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) { 964 Context = (BDS_TFTP_CONTEXT*)Token->Context; 965 966 if (Context->DownloadedNbOfBytes == 0) { 967 if (Context->FileSize > 0) { 968 Print (L"%s 0 Kb", mTftpProgressFrame); 969 } else { 970 Print (L" 0 Kb"); 971 } 972 } 973 974 // 975 // The data is the packet are prepended with two UINT16 : 976 // . OpCode = EFI_MTFTP4_OPCODE_DATA 977 // . Block = the number of this block of data 978 // 979 Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block); 980 NbOfKb = Context->DownloadedNbOfBytes / 1024; 981 982 Progress[0] = L'\0'; 983 if (Context->FileSize > 0) { 984 LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; 985 Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize; 986 if (Step > LastStep) { 987 Print (mTftpProgressDelete); 988 StrCpy (Progress, mTftpProgressFrame); 989 for (Index = 1; Index < Step; Index++) { 990 Progress[Index] = L'='; 991 } 992 Progress[Step] = L'>'; 993 994 UnicodeSPrint ( 995 Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1, 996 sizeof (Progress) - sizeof (mTftpProgressFrame), 997 L" %7d Kb", 998 NbOfKb 999 ); 1000 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes; 1001 } 1002 } else { 1003 // 1004 // Case when we do not know the size of the final file. 1005 // We print the updated size every 50KB of downloaded data 1006 // 1007 LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024); 1008 NbOf50Kb = Context->DownloadedNbOfBytes / (50*1024); 1009 if (NbOf50Kb > LastNbOf50Kb) { 1010 Print (L"\b\b\b\b\b\b\b\b\b\b"); 1011 UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb); 1012 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes; 1013 } 1014 } 1015 if (Progress[0] != L'\0') { 1016 Print (L"%s", Progress); 1017 } 1018 } 1019 1020 return EFI_SUCCESS; 1021 } 1022 1023 /** 1024 Download an image from a TFTP server 1025 1026 @param[in] DevicePath Device path of the TFTP boot option 1027 @param[in] ControllerHandle Handle of the network controller 1028 @param[in] RemainingDevicePath Device path of the TFTP boot option but 1029 the first node that identifies the network controller 1030 @param[in] Type Type to allocate memory pages 1031 @param[out] Image Address of the bufer where the image is stored in 1032 case of success 1033 @param[out] ImageSize Size in number of bytes of the i;age in case of 1034 success 1035 1036 @retval EFI_SUCCESS The image was returned. 1037 @retval !EFI_SUCCESS Something went wrong. 1038 1039 **/ 1040 EFI_STATUS 1041 BdsTftpLoadImage ( 1042 IN OUT EFI_DEVICE_PATH **DevicePath, 1043 IN EFI_HANDLE ControllerHandle, 1044 IN EFI_DEVICE_PATH *RemainingDevicePath, 1045 IN EFI_ALLOCATE_TYPE Type, 1046 IN OUT EFI_PHYSICAL_ADDRESS *Image, 1047 OUT UINTN *ImageSize 1048 ) 1049 { 1050 EFI_STATUS Status; 1051 EFI_HANDLE Dhcp4ChildHandle; 1052 EFI_DHCP4_PROTOCOL *Dhcp4; 1053 BOOLEAN Dhcp4ToStop; 1054 EFI_HANDLE Mtftp4ChildHandle; 1055 EFI_MTFTP4_PROTOCOL *Mtftp4; 1056 DHCP4_OPTION ParaList; 1057 EFI_DHCP4_PACKET_OPTION *OptionList[2]; 1058 EFI_DHCP4_CONFIG_DATA Dhcp4CfgData; 1059 EFI_DHCP4_MODE_DATA Dhcp4Mode; 1060 EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData; 1061 IPv4_DEVICE_PATH *IPv4DevicePathNode; 1062 CHAR16 *PathName; 1063 CHAR8 *AsciiFilePath; 1064 EFI_MTFTP4_TOKEN Mtftp4Token; 1065 UINT64 FileSize; 1066 UINT64 TftpBufferSize; 1067 BDS_TFTP_CONTEXT *TftpContext; 1068 1069 ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)); 1070 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; 1071 1072 Dhcp4ChildHandle = NULL; 1073 Dhcp4 = NULL; 1074 Dhcp4ToStop = FALSE; 1075 Mtftp4ChildHandle = NULL; 1076 Mtftp4 = NULL; 1077 AsciiFilePath = NULL; 1078 TftpContext = NULL; 1079 1080 if (!IPv4DevicePathNode->StaticIpAddress) { 1081 // 1082 // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and 1083 // install the DHCP4 protocol on it. Then, open the DHCP protocol. 1084 // 1085 Status = NetLibCreateServiceChild ( 1086 ControllerHandle, 1087 gImageHandle, 1088 &gEfiDhcp4ServiceBindingProtocolGuid, 1089 &Dhcp4ChildHandle 1090 ); 1091 if (!EFI_ERROR (Status)) { 1092 Status = gBS->OpenProtocol ( 1093 Dhcp4ChildHandle, 1094 &gEfiDhcp4ProtocolGuid, 1095 (VOID **) &Dhcp4, 1096 gImageHandle, 1097 ControllerHandle, 1098 EFI_OPEN_PROTOCOL_BY_DRIVER 1099 ); 1100 } 1101 if (EFI_ERROR (Status)) { 1102 Print (L"Unable to open DHCP4 protocol\n"); 1103 goto Error; 1104 } 1105 } 1106 1107 // 1108 // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and 1109 // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol. 1110 // 1111 Status = NetLibCreateServiceChild ( 1112 ControllerHandle, 1113 gImageHandle, 1114 &gEfiMtftp4ServiceBindingProtocolGuid, 1115 &Mtftp4ChildHandle 1116 ); 1117 if (!EFI_ERROR (Status)) { 1118 Status = gBS->OpenProtocol ( 1119 Mtftp4ChildHandle, 1120 &gEfiMtftp4ProtocolGuid, 1121 (VOID **) &Mtftp4, 1122 gImageHandle, 1123 ControllerHandle, 1124 EFI_OPEN_PROTOCOL_BY_DRIVER 1125 ); 1126 } 1127 if (EFI_ERROR (Status)) { 1128 Print (L"Unable to open MTFTP4 protocol\n"); 1129 goto Error; 1130 } 1131 1132 if (!IPv4DevicePathNode->StaticIpAddress) { 1133 // 1134 // Configure the DHCP4, all default settings. It is acceptable for the configuration to 1135 // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration 1136 // has been done by another instance of the DHCP4 protocol or that the DHCP configuration 1137 // process has been started but is not completed yet. 1138 // 1139 ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA)); 1140 ParaList.Head.OpCode = DHCP_TAG_PARA_LIST; 1141 ParaList.Head.Length = 2; 1142 ParaList.Head.Data[0] = DHCP_TAG_NETMASK; 1143 ParaList.Route = DHCP_TAG_ROUTER; 1144 OptionList[0] = &ParaList.Head; 1145 Dhcp4CfgData.OptionCount = 1; 1146 Dhcp4CfgData.OptionList = OptionList; 1147 1148 Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData); 1149 if (EFI_ERROR (Status)) { 1150 if (Status != EFI_ACCESS_DENIED) { 1151 Print (L"Error while configuring the DHCP4 protocol\n"); 1152 goto Error; 1153 } 1154 } 1155 1156 // 1157 // Start the DHCP configuration. This may have already been done thus do not leave in error 1158 // if the return code is EFI_ALREADY_STARTED. 1159 // 1160 Status = Dhcp4->Start (Dhcp4, NULL); 1161 if (EFI_ERROR (Status)) { 1162 if (Status != EFI_ALREADY_STARTED) { 1163 Print (L"DHCP configuration failed\n"); 1164 goto Error; 1165 } 1166 } else { 1167 Dhcp4ToStop = TRUE; 1168 } 1169 1170 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode); 1171 if (EFI_ERROR (Status)) { 1172 goto Error; 1173 } 1174 1175 if (Dhcp4Mode.State != Dhcp4Bound) { 1176 Status = EFI_TIMEOUT; 1177 Print (L"DHCP configuration failed\n"); 1178 goto Error; 1179 } 1180 } 1181 1182 // 1183 // Configure the TFTP4 protocol 1184 // 1185 1186 ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA)); 1187 Mtftp4CfgData.UseDefaultSetting = FALSE; 1188 Mtftp4CfgData.TimeoutValue = 4; 1189 Mtftp4CfgData.TryCount = 6; 1190 1191 if (IPv4DevicePathNode->StaticIpAddress) { 1192 CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); 1193 CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); 1194 CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); 1195 } else { 1196 CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS)); 1197 CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask , sizeof (EFI_IPv4_ADDRESS)); 1198 CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS)); 1199 } 1200 1201 CopyMem (&Mtftp4CfgData.ServerIp , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); 1202 1203 Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData); 1204 if (EFI_ERROR (Status)) { 1205 Print (L"Error while configuring the MTFTP4 protocol\n"); 1206 goto Error; 1207 } 1208 1209 // The Device Path might contain multiple FilePath nodes 1210 PathName = ConvertDevicePathToText ((EFI_DEVICE_PATH_PROTOCOL*)(IPv4DevicePathNode + 1), FALSE, FALSE); 1211 AsciiFilePath = AllocatePool (StrLen (PathName) + 1); 1212 UnicodeStrToAsciiStr (PathName, AsciiFilePath); 1213 1214 // 1215 // Try to get the size of the file in bytes from the server. If it fails, 1216 // start with a 8MB buffer to download the file. 1217 // 1218 FileSize = 0; 1219 if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) { 1220 TftpBufferSize = FileSize; 1221 } else { 1222 TftpBufferSize = SIZE_16MB; 1223 } 1224 1225 TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT)); 1226 if (TftpContext == NULL) { 1227 Status = EFI_OUT_OF_RESOURCES; 1228 goto Error; 1229 } 1230 TftpContext->FileSize = FileSize; 1231 1232 for (; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize); 1233 TftpBufferSize = (TftpBufferSize + SIZE_16MB) & (~(SIZE_16MB-1))) { 1234 // 1235 // Allocate a buffer to hold the whole file. 1236 // 1237 Status = gBS->AllocatePages ( 1238 Type, 1239 EfiBootServicesCode, 1240 EFI_SIZE_TO_PAGES (TftpBufferSize), 1241 Image 1242 ); 1243 if (EFI_ERROR (Status)) { 1244 Print (L"Failed to allocate space for image\n"); 1245 goto Error; 1246 } 1247 1248 TftpContext->DownloadedNbOfBytes = 0; 1249 TftpContext->LastReportedNbOfBytes = 0; 1250 1251 ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN)); 1252 Mtftp4Token.Filename = (UINT8*)AsciiFilePath; 1253 Mtftp4Token.BufferSize = TftpBufferSize; 1254 Mtftp4Token.Buffer = (VOID *)(UINTN)*Image; 1255 Mtftp4Token.CheckPacket = Mtftp4CheckPacket; 1256 Mtftp4Token.Context = (VOID*)TftpContext; 1257 1258 Print (L"Downloading the file <%a> from the TFTP server\n", AsciiFilePath); 1259 Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token); 1260 Print (L"\n"); 1261 if (EFI_ERROR (Status)) { 1262 gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize)); 1263 if (Status == EFI_BUFFER_TOO_SMALL) { 1264 Print (L"Downloading failed, file larger than expected.\n"); 1265 continue; 1266 } else { 1267 goto Error; 1268 } 1269 } 1270 1271 *ImageSize = Mtftp4Token.BufferSize; 1272 break; 1273 } 1274 1275 Error: 1276 if (Dhcp4ChildHandle != NULL) { 1277 if (Dhcp4 != NULL) { 1278 if (Dhcp4ToStop) { 1279 Dhcp4->Stop (Dhcp4); 1280 } 1281 gBS->CloseProtocol ( 1282 Dhcp4ChildHandle, 1283 &gEfiDhcp4ProtocolGuid, 1284 gImageHandle, 1285 ControllerHandle 1286 ); 1287 } 1288 NetLibDestroyServiceChild ( 1289 ControllerHandle, 1290 gImageHandle, 1291 &gEfiDhcp4ServiceBindingProtocolGuid, 1292 Dhcp4ChildHandle 1293 ); 1294 } 1295 1296 if (Mtftp4ChildHandle != NULL) { 1297 if (Mtftp4 != NULL) { 1298 if (AsciiFilePath != NULL) { 1299 FreePool (AsciiFilePath); 1300 } 1301 if (TftpContext != NULL) { 1302 FreePool (TftpContext); 1303 } 1304 gBS->CloseProtocol ( 1305 Mtftp4ChildHandle, 1306 &gEfiMtftp4ProtocolGuid, 1307 gImageHandle, 1308 ControllerHandle 1309 ); 1310 } 1311 NetLibDestroyServiceChild ( 1312 ControllerHandle, 1313 gImageHandle, 1314 &gEfiMtftp4ServiceBindingProtocolGuid, 1315 Mtftp4ChildHandle 1316 ); 1317 } 1318 1319 if (EFI_ERROR (Status)) { 1320 *Image = 0; 1321 Print (L"Failed to download the file - Error=%r\n", Status); 1322 } 1323 1324 return Status; 1325 } 1326 1327 #define BOOT_MAGIC "ANDROID!" 1328 #define BOOT_MAGIC_LENGTH sizeof (BOOT_MAGIC) - 1 1329 #define BOOTIMG_KERNEL_ARGS_SIZE 512 1330 1331 1332 // Check Val (unsigned) is a power of 2 (has only one bit set) 1333 #define IS_POWER_OF_2(Val) (Val != 0 && ((Val & (Val - 1)) == 0)) 1334 1335 /* It's the hack value of arm64 efi stub kernel */ 1336 #define KERNEL_IMAGE_STEXT_OFFSET 0x12C 1337 #define KERNEL_IMAGE_RAW_SIZE_OFFSET 0x130 1338 1339 typedef struct { 1340 CHAR8 BootMagic[BOOT_MAGIC_LENGTH]; 1341 UINT32 KernelSize; 1342 UINT32 KernelAddress; 1343 UINT32 RamdiskSize; 1344 UINT32 RamdiskAddress; 1345 UINT32 SecondStageBootloaderSize; 1346 UINT32 SecondStageBootloaderAddress; 1347 UINT32 KernelTaggsAddress; 1348 UINT32 PageSize; 1349 UINT32 Reserved[2]; 1350 CHAR8 ProductName[16]; 1351 CHAR8 KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE]; 1352 UINT32 Id[32]; 1353 } ANDROID_BOOTIMG_HEADER; 1354 1355 EFI_STATUS 1356 STATIC LoadAndroidBootImg ( 1357 IN UINTN BufferSize, 1358 IN VOID *Buffer, 1359 IN BDS_LOAD_OPTION *BdsLoadOption, 1360 OUT EFI_PHYSICAL_ADDRESS *Image, 1361 OUT UINTN *ImageSize 1362 ) 1363 { 1364 EFI_STATUS Status; 1365 EFI_PHYSICAL_ADDRESS KernelBase, RamdiskBase, FdtBase; 1366 UINTN KernelSize; 1367 ANDROID_BOOTIMG_HEADER *Header; 1368 CHAR16 KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE]; 1369 CHAR16 InitrdArgs[64]; 1370 UINTN VariableSize; 1371 CHAR16 SerialNoArgs[40], DataUnicode[17]; 1372 1373 Header = (ANDROID_BOOTIMG_HEADER *) Buffer; 1374 1375 if (AsciiStrnCmp (Header->BootMagic, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) { 1376 return EFI_INVALID_PARAMETER; 1377 } 1378 1379 if (Header->KernelSize == 0) { 1380 return EFI_NOT_FOUND; 1381 } 1382 1383 ASSERT (IS_POWER_OF_2 (Header->PageSize)); 1384 1385 KernelBase = Header->KernelAddress; 1386 Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, 1387 EFI_SIZE_TO_PAGES (Header->KernelSize), (VOID *)&KernelBase); 1388 ASSERT_EFI_ERROR (Status); 1389 CopyMem ((VOID *)KernelBase, 1390 (CONST VOID *)((UINTN)Buffer + Header->PageSize), 1391 Header->KernelSize); 1392 1393 RamdiskBase = Header->RamdiskAddress; 1394 if (Header->RamdiskSize != 0) { 1395 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, 1396 EFI_SIZE_TO_PAGES (Header->RamdiskSize), (VOID *)&RamdiskBase); 1397 ASSERT_EFI_ERROR (Status); 1398 CopyMem ((VOID *)RamdiskBase, 1399 (VOID *)((UINTN)Buffer + Header->PageSize + ALIGN_VALUE (Header->KernelSize, Header->PageSize)), 1400 Header->RamdiskSize 1401 ); 1402 if (RamdiskBase != Header->RamdiskAddress) 1403 Header->RamdiskAddress = RamdiskBase; 1404 } 1405 /* Install Fdt */ 1406 KernelSize = *(UINT32 *)(KernelBase + KERNEL_IMAGE_STEXT_OFFSET) + 1407 *(UINT32 *)(KernelBase + KERNEL_IMAGE_RAW_SIZE_OFFSET); 1408 ASSERT (KernelSize < Header->KernelSize); 1409 1410 /* FDT is at the end of kernel image */ 1411 FdtBase = KernelBase + KernelSize; 1412 Status = gBS->InstallConfigurationTable ( 1413 &gFdtTableGuid, 1414 (VOID *)FdtBase 1415 ); 1416 ASSERT_EFI_ERROR (Status); 1417 1418 /* update kernel args */ 1419 AsciiStrToUnicodeStr (Header->KernelArgs, KernelArgs); 1420 if (StrnCmp (KernelArgs, BdsLoadOption->OptionalData, 1421 BOOTIMG_KERNEL_ARGS_SIZE) != 0) { 1422 ASSERT (BdsLoadOption->OptionalData != NULL); 1423 ASSERT (StrSize (KernelArgs) <= BOOTIMG_KERNEL_ARGS_SIZE); 1424 1425 UnicodeSPrint (InitrdArgs, 64 * sizeof(CHAR16), L" initrd=0x%x,0x%x", 1426 Header->RamdiskAddress, Header->RamdiskSize); 1427 StrCat (KernelArgs, InitrdArgs); 1428 VariableSize = 17 * sizeof (CHAR16); 1429 Status = gRT->GetVariable ( 1430 (CHAR16 *)L"SerialNo", 1431 &gHiKeyVariableGuid, 1432 NULL, 1433 &VariableSize, 1434 &DataUnicode 1435 ); 1436 if (EFI_ERROR (Status)) { 1437 goto out; 1438 } 1439 DataUnicode[(VariableSize / sizeof(CHAR16)) - 1] = '\0'; 1440 ZeroMem (SerialNoArgs, 40 * sizeof (CHAR16)); 1441 UnicodeSPrint (SerialNoArgs, 40 * sizeof(CHAR16), L" androidboot.serialno=%s", DataUnicode); 1442 StrCat (KernelArgs, SerialNoArgs); 1443 ASSERT (StrSize (KernelArgs) <= BOOTIMG_KERNEL_ARGS_SIZE); 1444 if (gArgs != NULL) { 1445 CopyMem ((VOID *)gArgs, 1446 (VOID *)KernelArgs, 1447 StrSize (KernelArgs) 1448 ); 1449 } 1450 } 1451 1452 *Image = KernelBase; 1453 *ImageSize = Header->KernelSize; 1454 return EFI_SUCCESS; 1455 out: 1456 return Status; 1457 } 1458 1459 BOOLEAN 1460 BdsAndroidKernelSupport ( 1461 IN EFI_DEVICE_PATH *DevicePath, 1462 IN EFI_HANDLE Handle, 1463 IN EFI_DEVICE_PATH *RemainingDevicePath 1464 ) 1465 { 1466 // Validate the Remaining Device Path 1467 if (IsDevicePathEnd (RemainingDevicePath)) { 1468 return FALSE; 1469 } 1470 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, 1471 MEDIA_RELATIVE_OFFSET_RANGE_DP)) { 1472 return FALSE; 1473 } 1474 return TRUE; 1475 } 1476 1477 STATIC 1478 BOOLEAN 1479 CompareDevicePath ( 1480 IN EFI_DEVICE_PATH *DevicePath1, 1481 IN EFI_DEVICE_PATH *DevicePath2 1482 ) 1483 { 1484 UINTN Size1, Size2; 1485 1486 Size1 = GetDevicePathSize (DevicePath1); 1487 Size2 = GetDevicePathSize (DevicePath2); 1488 if (Size1 != Size2) 1489 return FALSE; 1490 if (Size1 == 0) 1491 return FALSE; 1492 if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) { 1493 return FALSE; 1494 } 1495 1496 return TRUE; 1497 } 1498 1499 STATIC 1500 EFI_STATUS 1501 BdsLocateBootOption ( 1502 IN EFI_DEVICE_PATH *DevicePath, 1503 OUT BDS_LOAD_OPTION **BdsLoadOption 1504 ) 1505 { 1506 UINTN Index; 1507 EFI_STATUS Status; 1508 BDS_LOAD_OPTION *LoadOption; 1509 1510 for (Index = 0; ; Index++) { 1511 Status = BootOptionFromLoadOptionIndex (Index, &LoadOption); 1512 if (EFI_ERROR (Status)) 1513 return Status; 1514 if (CompareDevicePath (DevicePath, LoadOption->FilePathList) == FALSE) 1515 continue; 1516 *BdsLoadOption = LoadOption; 1517 return EFI_SUCCESS; 1518 } 1519 return Status; 1520 } 1521 1522 EFI_STATUS 1523 BdsAndroidKernelLoadImage ( 1524 IN OUT EFI_DEVICE_PATH **DevicePath, 1525 IN EFI_HANDLE Handle, 1526 IN EFI_DEVICE_PATH *RemainingDevicePath, 1527 IN EFI_ALLOCATE_TYPE Type, 1528 IN OUT EFI_PHYSICAL_ADDRESS *Image, 1529 OUT UINTN *ImageSize 1530 ) 1531 { 1532 EFI_STATUS Status; 1533 EFI_BLOCK_IO_PROTOCOL *BlockIo; 1534 EFI_DEVICE_PATH_PROTOCOL *Node, *NextNode; 1535 HARDDRIVE_DEVICE_PATH *PartitionPath; 1536 UINT32 MediaId; 1537 UINTN BlockSize; 1538 VOID *Buffer; 1539 BDS_LOAD_OPTION *BdsLoadOption = NULL; 1540 1541 /* Find DevicePath node of Partition */ 1542 NextNode = *DevicePath; 1543 do { 1544 Node = NextNode; 1545 NextNode = NextDevicePathNode (Node); 1546 } while (!IS_DEVICE_PATH_NODE (NextNode, MEDIA_DEVICE_PATH, 1547 MEDIA_RELATIVE_OFFSET_RANGE_DP)); 1548 PartitionPath = (HARDDRIVE_DEVICE_PATH *)Node; 1549 1550 Status = BdsLocateBootOption (*DevicePath, &BdsLoadOption); 1551 if (EFI_ERROR (Status)) 1552 return Status; 1553 1554 Status = gBS->OpenProtocol ( 1555 Handle, 1556 &gEfiBlockIoProtocolGuid, 1557 (VOID **) &BlockIo, 1558 gImageHandle, 1559 NULL, 1560 EFI_OPEN_PROTOCOL_GET_PROTOCOL 1561 ); 1562 if (EFI_ERROR (Status)) { 1563 DEBUG ((EFI_D_ERROR, "Can't open BlockIo protocol, Status:%r\n", Status)); 1564 return Status; 1565 } 1566 MediaId = BlockIo->Media->MediaId; 1567 BlockSize = BlockIo->Media->BlockSize; 1568 /* Both PartitionStart and PartitionSize are counted as block size. */ 1569 Buffer = AllocatePages (EFI_SIZE_TO_PAGES(PartitionPath->PartitionSize * BlockSize)); 1570 if (Buffer == NULL) 1571 return EFI_BUFFER_TOO_SMALL; 1572 1573 /* Load header of boot.img */ 1574 Status = BlockIo->ReadBlocks (BlockIo, MediaId, 0, PartitionPath->PartitionSize * BlockSize, Buffer); 1575 if (EFI_ERROR (Status)) { 1576 DEBUG ((EFI_D_ERROR, "Failed to read blocks: %r\n", Status)); 1577 return Status; 1578 } 1579 Status = LoadAndroidBootImg (PartitionPath->PartitionSize, Buffer, BdsLoadOption, Image, ImageSize); 1580 1581 return EFI_SUCCESS; 1582 } 1583 1584 BDS_FILE_LOADER FileLoaders[] = { 1585 { BdsFileSystemSupport, BdsFileSystemLoadImage }, 1586 { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage }, 1587 //{ BdsLoadFileSupport, BdsLoadFileLoadImage }, 1588 { BdsMemoryMapSupport, BdsMemoryMapLoadImage }, 1589 { BdsPxeSupport, BdsPxeLoadImage }, 1590 { BdsTftpSupport, BdsTftpLoadImage }, 1591 { BdsAndroidKernelSupport, BdsAndroidKernelLoadImage }, 1592 { NULL, NULL } 1593 }; 1594 1595 EFI_STATUS 1596 BdsLoadImageAndUpdateDevicePath ( 1597 IN OUT EFI_DEVICE_PATH **DevicePath, 1598 IN EFI_ALLOCATE_TYPE Type, 1599 IN OUT EFI_PHYSICAL_ADDRESS* Image, 1600 OUT UINTN *FileSize 1601 ) 1602 { 1603 EFI_STATUS Status; 1604 EFI_HANDLE Handle; 1605 EFI_DEVICE_PATH *RemainingDevicePath; 1606 BDS_FILE_LOADER* FileLoader; 1607 1608 Status = BdsConnectAndUpdateDevicePath (DevicePath, &Handle, &RemainingDevicePath); 1609 if (EFI_ERROR (Status)) { 1610 return Status; 1611 } 1612 1613 FileLoader = FileLoaders; 1614 while (FileLoader->Support != NULL) { 1615 if (FileLoader->Support (*DevicePath, Handle, RemainingDevicePath)) { 1616 return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize); 1617 } 1618 FileLoader++; 1619 } 1620 1621 return EFI_UNSUPPORTED; 1622 } 1623 1624 EFI_STATUS 1625 BdsLoadImage ( 1626 IN EFI_DEVICE_PATH *DevicePath, 1627 IN EFI_ALLOCATE_TYPE Type, 1628 IN OUT EFI_PHYSICAL_ADDRESS* Image, 1629 OUT UINTN *FileSize 1630 ) 1631 { 1632 return BdsLoadImageAndUpdateDevicePath (&DevicePath, Type, Image, FileSize); 1633 } 1634 1635 /** 1636 Start an EFI Application from a Device Path 1637 1638 @param ParentImageHandle Handle of the calling image 1639 @param DevicePath Location of the EFI Application 1640 1641 @retval EFI_SUCCESS All drivers have been connected 1642 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found 1643 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. 1644 1645 **/ 1646 EFI_STATUS 1647 BdsStartEfiApplication ( 1648 IN EFI_HANDLE ParentImageHandle, 1649 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, 1650 IN UINTN LoadOptionsSize, 1651 IN VOID* LoadOptions 1652 ) 1653 { 1654 EFI_STATUS Status; 1655 EFI_HANDLE ImageHandle; 1656 EFI_PHYSICAL_ADDRESS BinaryBuffer; 1657 UINTN BinarySize; 1658 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; 1659 1660 // Hack for android kernel args 1661 gArgs = LoadOptions; 1662 // Find the nearest supported file loader 1663 Status = BdsLoadImageAndUpdateDevicePath (&DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize); 1664 if (EFI_ERROR (Status)) { 1665 return Status; 1666 } 1667 1668 // Load the image from the Buffer with Boot Services function 1669 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle); 1670 if (EFI_ERROR (Status)) { 1671 return Status; 1672 } 1673 1674 // Passed LoadOptions to the EFI Application 1675 if (LoadOptionsSize != 0) { 1676 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage); 1677 if (EFI_ERROR (Status)) { 1678 return Status; 1679 } 1680 1681 LoadedImage->LoadOptionsSize = LoadOptionsSize; 1682 LoadedImage->LoadOptions = LoadOptions; 1683 } 1684 1685 // Before calling the image, enable the Watchdog Timer for the 5 Minute period 1686 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); 1687 // Start the image 1688 Status = gBS->StartImage (ImageHandle, NULL, NULL); 1689 // Clear the Watchdog Timer after the image returns 1690 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); 1691 1692 return Status; 1693 } 1694