BOOLEAN BdsTftpSupport ( IN EFI_DEVICE_PATH* DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH* RemainingDevicePath ) { EFI_STATUS Status; EFI_DEVICE_PATH *NextDevicePath; EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; // Validate the Remaining Device Path if (IsDevicePathEnd(RemainingDevicePath)) { return FALSE; } if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) && !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) { return FALSE; } NextDevicePath = NextDevicePathNode (RemainingDevicePath); if (IsDevicePathEnd(NextDevicePath)) { return FALSE; } if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) { return FALSE; } Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); if (EFI_ERROR (Status)) { return FALSE; } else { return TRUE; } }
BOOLEAN BdsMemoryMapSupport ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath ) { return IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP) || IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP); }
BOOLEAN BdsTftpSupport ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath ) { EFI_STATUS Status; EFI_DEVICE_PATH *NextDevicePath; VOID *Interface; // Validate the Remaining Device Path if (IsDevicePathEnd (RemainingDevicePath)) { return FALSE; } if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP) && !IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv6_DP)) { return FALSE; } NextDevicePath = NextDevicePathNode (RemainingDevicePath); if (IsDevicePathEnd (NextDevicePath)) { return FALSE; } if (!IS_DEVICE_PATH_NODE (NextDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) { return FALSE; } Status = gBS->HandleProtocol ( Handle, &gEfiDevicePathProtocolGuid, &Interface ); if (EFI_ERROR (Status)) { return FALSE; } // // Check that the controller (identified by its handle "Handle") supports the // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the // EFI MTFTPv4 Protocol needed to download the image through TFTP. // Status = gBS->HandleProtocol ( Handle, &gEfiMtftp4ServiceBindingProtocolGuid, &Interface ); if (EFI_ERROR (Status)) { return FALSE; } return TRUE; }
/** Check if a boot option path is a memory map boot option path or not. The device specified by the beginning of the path has to support the BlockIo protocol. Furthermore, the remaining part of the path has to be composed of a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP. @param[in] DevicePath Complete device path of a boot option. @retval FALSE The boot option path has not been identified as that of a memory map boot option. @retval TRUE The boot option path is a a memory map boot option. **/ BOOLEAN BdsLoadOptionMemMapIsSupported ( IN EFI_DEVICE_PATH *DevicePath ) { EFI_STATUS Status; EFI_HANDLE Handle; EFI_DEVICE_PATH *RemainingDevicePath; EFI_BLOCK_IO_PROTOCOL *BlockIoProtocol; Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); if (EFI_ERROR (Status)) { return FALSE; } Status = gBS->HandleProtocol ( Handle, &gEfiBlockIoProtocolGuid, (VOID **)(&BlockIoProtocol) ); if (EFI_ERROR (Status)) { return FALSE; } if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP)) return FALSE; return TRUE; }
/** Check if a boot option path is a file system boot option path or not. The device specified by the beginning of the path has to support the Simple File System protocol. Furthermore, the remaining part of the path has to be composed of a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP. @param[in] DevicePath Complete device path of a boot option. @retval FALSE The boot option path has not been identified as that of a file system boot option. @retval TRUE The boot option path is a file system boot option. **/ BOOLEAN BdsLoadOptionFileSystemIsSupported ( IN EFI_DEVICE_PATH *DevicePath ) { EFI_STATUS Status; EFI_HANDLE Handle; EFI_DEVICE_PATH *RemainingDevicePath; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileProtocol; Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); if (EFI_ERROR (Status)) { return FALSE; } Status = gBS->HandleProtocol ( Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)(&FileProtocol) ); if (EFI_ERROR (Status)) { return FALSE; } if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP)) return FALSE; return TRUE; }
BOOLEAN BdsIsRemovableHd ( IN EFI_DEVICE_PATH* DevicePath ) { return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP); }
BOOLEAN BdsFirmwareVolumeSupport ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath ) { return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP); }
EFI_STATUS BdsMemoryMapLoadImage ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS* Image, OUT UINTN *ImageSize ) { EFI_STATUS Status; MEMMAP_DEVICE_PATH* MemMapPathDevicePath; UINTN Size; if (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)) { MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath; } else { ASSERT (IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)); MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath; } Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress; if (Size == 0) { return EFI_INVALID_PARAMETER; } Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); // Try to allocate in any pages if failed to allocate memory at the defined location if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); } if (!EFI_ERROR(Status)) { CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size); if (ImageSize != NULL) { *ImageSize = Size; } } return Status; }
BOOLEAN BdsFileSystemSupport ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath ) { EFI_STATUS Status; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); }
/** Update the parameters of a TFTP boot option The function asks sequentially to update the IPv4 parameters as well as the boot file path, providing the previously set value if any. @param[in] OldDevicePath Current complete device path of the Tftp boot option. This has to be a valid complete Tftp boot option path. By complete, we mean that it is not only the Tftp specific end part built by the "BdsLoadOptionTftpCreateDevicePath()" function. This path is handled as read only. @param[in] FileName Description of the file the path is asked for @param[out] NewDevicePath Pointer to the new complete device path. @retval EFI_SUCCESS Update completed @retval EFI_ABORTED Update aborted by the user @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource **/ EFI_STATUS BdsLoadOptionTftpUpdateDevicePath ( IN EFI_DEVICE_PATH *OldDevicePath, IN CHAR16 *FileName, OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath ) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath; EFI_DEVICE_PATH *DevicePathNode; UINT8 *Ipv4NodePtr; IPv4_DEVICE_PATH Ipv4Node; BOOLEAN IsDHCP; EFI_IP_ADDRESS OldIp; EFI_IP_ADDRESS OldSubnetMask; EFI_IP_ADDRESS OldGatewayIp; EFI_IP_ADDRESS LocalIp; EFI_IP_ADDRESS SubnetMask; EFI_IP_ADDRESS GatewayIp; EFI_IP_ADDRESS RemoteIp; UINT8 *FileNodePtr; CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX]; UINTN PathSize; UINTN BootFilePathSize; FILEPATH_DEVICE_PATH *NewFilePathNode; Ipv4NodePtr = NULL; // // Make a copy of the complete device path that is made of : // the device path of the device that support the Simple Network protocol // followed by an IPv4 node (type IPv4_DEVICE_PATH), // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up // by an end node. The IPv6 case is not handled yet. // DevicePath = DuplicateDevicePath (OldDevicePath); if (DevicePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ErrorExit; } // // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the // call to this function, we know that the device path ends with an IPv4 node // followed by a file path node and finally an end node. To get the address of // the last IPv4 node, we loop over the whole device path, noting down the // address of each encountered IPv4 node. // for (DevicePathNode = DevicePath; !IsDevicePathEnd (DevicePathNode); DevicePathNode = NextDevicePathNode (DevicePathNode)) { if (IS_DEVICE_PATH_NODE (DevicePathNode, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)) { Ipv4NodePtr = (UINT8*)DevicePathNode; } } // Copy for alignment of the IPv4 node data CopyMem (&Ipv4Node, Ipv4NodePtr, sizeof (IPv4_DEVICE_PATH)); Print (L"Get the IP address from DHCP: "); Status = GetHIInputBoolean (&IsDHCP); if (EFI_ERROR (Status)) { goto ErrorExit; } if (!IsDHCP) { Print (L"Local static IP address: "); if (Ipv4Node.StaticIpAddress) { CopyMem (&OldIp.v4, &Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldIp, &LocalIp); } else { Status = GetHIInputIP (&LocalIp); } if (EFI_ERROR (Status)) { goto ErrorExit; } Print (L"Get the network mask: "); if (Ipv4Node.StaticIpAddress) { CopyMem (&OldSubnetMask.v4, &Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldSubnetMask, &SubnetMask); } else { Status = GetHIInputIP (&SubnetMask); } if (EFI_ERROR (Status)) { goto ErrorExit; } Print (L"Get the gateway IP address: "); if (Ipv4Node.StaticIpAddress) { CopyMem (&OldGatewayIp.v4, &Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldGatewayIp, &GatewayIp); } else { Status = GetHIInputIP (&GatewayIp); } if (EFI_ERROR (Status)) { goto ErrorExit; } } Print (L"TFTP server IP address: "); // Copy remote IPv4 address into IPv4 or IPv6 union CopyMem (&OldIp.v4, &Ipv4Node.RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = EditHIInputIP (&OldIp, &RemoteIp); if (EFI_ERROR (Status)) { goto ErrorExit; } // Get the path of the boot file and its size in number of bytes FileNodePtr = Ipv4NodePtr + sizeof (IPv4_DEVICE_PATH); BootFilePathSize = DevicePathNodeLength (FileNodePtr) - SIZE_OF_FILEPATH_DEVICE_PATH; // // Ask for update of the boot file path // do { // Copy for 2-byte alignment of the Unicode string CopyMem ( BootFilePath, FileNodePtr + SIZE_OF_FILEPATH_DEVICE_PATH, MIN (BootFilePathSize, BOOT_DEVICE_FILEPATH_MAX) ); BootFilePath[BOOT_DEVICE_FILEPATH_MAX - 1] = L'\0'; Print (L"File path of the %s: ", FileName); Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX); if (EFI_ERROR (Status)) { goto ErrorExit; } PathSize = StrSize (BootFilePath); if (PathSize > 2) { break; } // Empty string, give the user another try Print (L"Empty string - Invalid path\n"); } while (PathSize <= 2) ; // // Update the IPv4 node. IPv6 case not handled yet. // if (IsDHCP) { Ipv4Node.StaticIpAddress = FALSE; ZeroMem (&Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); ZeroMem (&Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); ZeroMem (&Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); } else { Ipv4Node.StaticIpAddress = TRUE; CopyMem (&Ipv4Node.LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Ipv4Node.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Ipv4Node.GatewayIpAddress, &GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS)); } CopyMem (&Ipv4Node.RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS)); CopyMem (Ipv4NodePtr, &Ipv4Node, sizeof (IPv4_DEVICE_PATH)); // // Create the new file path node // NewFilePathNode = (FILEPATH_DEVICE_PATH*)AllocatePool ( SIZE_OF_FILEPATH_DEVICE_PATH + PathSize ); NewFilePathNode->Header.Type = MEDIA_DEVICE_PATH; NewFilePathNode->Header.SubType = MEDIA_FILEPATH_DP; SetDevicePathNodeLength ( NewFilePathNode, SIZE_OF_FILEPATH_DEVICE_PATH + PathSize ); CopyMem (NewFilePathNode->PathName, BootFilePath, PathSize); // // Generate the new Device Path by replacing the file path node at address // "FileNodePtr" by the new one "NewFilePathNode" and return its address. // SetDevicePathEndNode (FileNodePtr); *NewDevicePath = AppendDevicePathNode ( DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL*)NewFilePathNode ); ErrorExit: if (DevicePath != NULL) { FreePool (DevicePath) ; } return Status; }
EFI_STATUS BdsTftpLoadImage ( IN EFI_DEVICE_PATH* DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH* RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS *Image, OUT UINTN *ImageSize ) { EFI_STATUS Status; EFI_PXE_BASE_CODE_PROTOCOL *Pxe; UINT64 TftpBufferSize; VOID* TftpBuffer; EFI_IP_ADDRESS ServerIp; IPv4_DEVICE_PATH* IPv4DevicePathNode; FILEPATH_DEVICE_PATH* FilePathDevicePath; EFI_IP_ADDRESS LocalIp; ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP)); IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); if (EFI_ERROR(Status)) { return Status; } Status = Pxe->Start (Pxe, FALSE); if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { return Status; } if (!IPv4DevicePathNode->StaticIpAddress) { Status = Pxe->Dhcp(Pxe, TRUE); } else { CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL); } if (EFI_ERROR(Status)) { return Status; } CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = Pxe->Mtftp ( Pxe, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, NULL, FALSE, &TftpBufferSize, NULL, &ServerIp, (UINT8 *)FilePathDevicePath->PathName, NULL, TRUE ); if (EFI_ERROR(Status)) { return Status; } // Allocate a buffer to hold the whole file. TftpBuffer = AllocatePool(TftpBufferSize); if (TftpBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } Status = Pxe->Mtftp ( Pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE, TftpBuffer, FALSE, &TftpBufferSize, NULL, &ServerIp, (UINT8 *)FilePathDevicePath->PathName, NULL, FALSE ); if (EFI_ERROR(Status)) { FreePool(TftpBuffer); } else if (ImageSize != NULL) { *ImageSize = (UINTN)TftpBufferSize; } return Status; }
EFI_STATUS BdsFirmwareVolumeLoadImage ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS* Image, OUT UINTN *ImageSize ) { EFI_STATUS Status; EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; EFI_GUID *FvNameGuid; EFI_SECTION_TYPE SectionType; EFI_FV_FILETYPE FvType; EFI_FV_FILE_ATTRIBUTES Attrib; UINT32 AuthenticationStatus; VOID* ImageBuffer; ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)); Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol); if (EFI_ERROR(Status)) { return Status; } FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath); if (FvNameGuid == NULL) { Status = EFI_INVALID_PARAMETER; } SectionType = EFI_SECTION_PE32; AuthenticationStatus = 0; //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file. ImageBuffer = NULL; Status = FwVol->ReadSection ( FwVol, FvNameGuid, SectionType, 0, &ImageBuffer, ImageSize, &AuthenticationStatus ); if (!EFI_ERROR (Status)) { #if 0 // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements if (Type != AllocateAnyPages) { Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image); if (!EFI_ERROR(Status)) { CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); FreePool (ImageBuffer); } } #else // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); // Try to allocate in any pages if failed to allocate memory at the defined location if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); } if (!EFI_ERROR(Status)) { CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); FreePool (ImageBuffer); } #endif } else { // Try a raw file, since a PE32 SECTION does not exist Status = FwVol->ReadFile ( FwVol, FvNameGuid, NULL, ImageSize, &FvType, &Attrib, &AuthenticationStatus ); if (!EFI_ERROR(Status)) { Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); // Try to allocate in any pages if failed to allocate memory at the defined location if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); } if (!EFI_ERROR(Status)) { Status = FwVol->ReadFile ( FwVol, FvNameGuid, (VOID*)(UINTN)(*Image), ImageSize, &FvType, &Attrib, &AuthenticationStatus ); } } } return Status; }
EFI_STATUS BdsFileSystemLoadImage ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS* Image, OUT UINTN *ImageSize ) { FILEPATH_DEVICE_PATH* FilePathDevicePath; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; EFI_FILE_PROTOCOL *Fs; EFI_STATUS Status; EFI_FILE_INFO *FileInfo; EFI_FILE_PROTOCOL *File; UINTN Size; ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath; Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); if (EFI_ERROR(Status)) { return Status; } // Try to Open the volume and get root directory Status = FsProtocol->OpenVolume (FsProtocol, &Fs); if (EFI_ERROR(Status)) { return Status; } File = NULL; Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) { return Status; } Size = 0; File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL); FileInfo = AllocatePool (Size); Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo); if (EFI_ERROR(Status)) { return Status; } // Get the file size Size = FileInfo->FileSize; if (ImageSize) { *ImageSize = Size; } FreePool(FileInfo); Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); // Try to allocate in any pages if failed to allocate memory at the defined location if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); } if (!EFI_ERROR(Status)) { Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); } return Status; }
/** Download an image from a TFTP server @param[in] DevicePath Device path of the TFTP boot option @param[in] ControllerHandle Handle of the network controller @param[in] RemainingDevicePath Device path of the TFTP boot option but the first node that identifies the network controller @param[in] Type Type to allocate memory pages @param[out] Image Address of the bufer where the image is stored in case of success @param[out] ImageSize Size in number of bytes of the i;age in case of success @retval EFI_SUCCESS The image was returned. @retval !EFI_SUCCESS Something went wrong. **/ EFI_STATUS BdsTftpLoadImage ( IN OUT EFI_DEVICE_PATH **DevicePath, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH *RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS *Image, OUT UINTN *ImageSize ) { EFI_STATUS Status; EFI_HANDLE Dhcp4ChildHandle; EFI_DHCP4_PROTOCOL *Dhcp4; BOOLEAN Dhcp4ToStop; EFI_HANDLE Mtftp4ChildHandle; EFI_MTFTP4_PROTOCOL *Mtftp4; DHCP4_OPTION ParaList; EFI_DHCP4_PACKET_OPTION *OptionList[2]; EFI_DHCP4_CONFIG_DATA Dhcp4CfgData; EFI_DHCP4_MODE_DATA Dhcp4Mode; EFI_MTFTP4_CONFIG_DATA Mtftp4CfgData; IPv4_DEVICE_PATH *IPv4DevicePathNode; FILEPATH_DEVICE_PATH *FilePathDevicePathNode; CHAR8 *AsciiFilePath; EFI_MTFTP4_TOKEN Mtftp4Token; UINT64 FileSize; UINT64 TftpBufferSize; BDS_TFTP_CONTEXT *TftpContext; ASSERT(IS_DEVICE_PATH_NODE (RemainingDevicePath, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)); IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; Dhcp4ChildHandle = NULL; Dhcp4 = NULL; Dhcp4ToStop = FALSE; Mtftp4ChildHandle = NULL; Mtftp4 = NULL; AsciiFilePath = NULL; TftpContext = NULL; if (!IPv4DevicePathNode->StaticIpAddress) { // // Using the DHCP4 Service Binding Protocol, create a child handle of the DHCP4 service and // install the DHCP4 protocol on it. Then, open the DHCP protocol. // Status = NetLibCreateServiceChild ( ControllerHandle, gImageHandle, &gEfiDhcp4ServiceBindingProtocolGuid, &Dhcp4ChildHandle ); if (!EFI_ERROR (Status)) { Status = gBS->OpenProtocol ( Dhcp4ChildHandle, &gEfiDhcp4ProtocolGuid, (VOID **) &Dhcp4, gImageHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); } if (EFI_ERROR (Status)) { Print (L"Unable to open DHCP4 protocol\n"); goto Error; } } // // Using the MTFTP4 Service Binding Protocol, create a child handle of the MTFTP4 service and // install the MTFTP4 protocol on it. Then, open the MTFTP4 protocol. // Status = NetLibCreateServiceChild ( ControllerHandle, gImageHandle, &gEfiMtftp4ServiceBindingProtocolGuid, &Mtftp4ChildHandle ); if (!EFI_ERROR (Status)) { Status = gBS->OpenProtocol ( Mtftp4ChildHandle, &gEfiMtftp4ProtocolGuid, (VOID **) &Mtftp4, gImageHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER ); } if (EFI_ERROR (Status)) { Print (L"Unable to open MTFTP4 protocol\n"); goto Error; } if (!IPv4DevicePathNode->StaticIpAddress) { // // Configure the DHCP4, all default settings. It is acceptable for the configuration to // fail if the return code is equal to EFI_ACCESS_DENIED which means that the configuration // has been done by another instance of the DHCP4 protocol or that the DHCP configuration // process has been started but is not completed yet. // ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA)); ParaList.Head.OpCode = DHCP_TAG_PARA_LIST; ParaList.Head.Length = 2; ParaList.Head.Data[0] = DHCP_TAG_NETMASK; ParaList.Route = DHCP_TAG_ROUTER; OptionList[0] = &ParaList.Head; Dhcp4CfgData.OptionCount = 1; Dhcp4CfgData.OptionList = OptionList; Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData); if (EFI_ERROR (Status)) { if (Status != EFI_ACCESS_DENIED) { Print (L"Error while configuring the DHCP4 protocol\n"); goto Error; } } // // Start the DHCP configuration. This may have already been done thus do not leave in error // if the return code is EFI_ALREADY_STARTED. // Status = Dhcp4->Start (Dhcp4, NULL); if (EFI_ERROR (Status)) { if (Status != EFI_ALREADY_STARTED) { Print (L"DHCP configuration failed\n"); goto Error; } } else { Dhcp4ToStop = TRUE; } Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode); if (EFI_ERROR (Status)) { goto Error; } if (Dhcp4Mode.State != Dhcp4Bound) { Status = EFI_TIMEOUT; Print (L"DHCP configuration failed\n"); goto Error; } } // // Configure the TFTP4 protocol // ZeroMem (&Mtftp4CfgData, sizeof (EFI_MTFTP4_CONFIG_DATA)); Mtftp4CfgData.UseDefaultSetting = FALSE; Mtftp4CfgData.TimeoutValue = 4; Mtftp4CfgData.TryCount = 6; if (IPv4DevicePathNode->StaticIpAddress) { CopyMem (&Mtftp4CfgData.StationIp , &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Mtftp4CfgData.SubnetMask, &IPv4DevicePathNode->SubnetMask, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Mtftp4CfgData.GatewayIp , &IPv4DevicePathNode->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS)); } else { CopyMem (&Mtftp4CfgData.StationIp , &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Mtftp4CfgData.SubnetMask, &Dhcp4Mode.SubnetMask , sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Mtftp4CfgData.GatewayIp , &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS)); } CopyMem (&Mtftp4CfgData.ServerIp , &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = Mtftp4->Configure (Mtftp4, &Mtftp4CfgData); if (EFI_ERROR (Status)) { Print (L"Error while configuring the MTFTP4 protocol\n"); goto Error; } // // Convert the Unicode path of the file to Ascii // FilePathDevicePathNode = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); AsciiFilePath = AllocatePool ((StrLen (FilePathDevicePathNode->PathName) + 1) * sizeof (CHAR8)); if (AsciiFilePath == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } UnicodeStrToAsciiStr (FilePathDevicePathNode->PathName, AsciiFilePath); // // Try to get the size of the file in bytes from the server. If it fails, // start with a 8MB buffer to download the file. // FileSize = 0; if (Mtftp4GetFileSize (Mtftp4, AsciiFilePath, &FileSize) == EFI_SUCCESS) { TftpBufferSize = FileSize; } else { TftpBufferSize = SIZE_8MB; } TftpContext = AllocatePool (sizeof (BDS_TFTP_CONTEXT)); if (TftpContext == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } TftpContext->FileSize = FileSize; for (; TftpBufferSize <= FixedPcdGet32 (PcdMaxTftpFileSize); TftpBufferSize = (TftpBufferSize + SIZE_8MB) & (~(SIZE_8MB-1))) { // // Allocate a buffer to hold the whole file. // Status = gBS->AllocatePages ( Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES (TftpBufferSize), Image ); if (EFI_ERROR (Status)) { Print (L"Failed to allocate space for image\n"); goto Error; } TftpContext->DownloadedNbOfBytes = 0; TftpContext->LastReportedNbOfBytes = 0; ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN)); Mtftp4Token.Filename = (UINT8*)AsciiFilePath; Mtftp4Token.BufferSize = TftpBufferSize; Mtftp4Token.Buffer = (VOID *)(UINTN)*Image; Mtftp4Token.CheckPacket = Mtftp4CheckPacket; Mtftp4Token.Context = (VOID*)TftpContext; Print (L"Downloading the file <%s> from the TFTP server\n", FilePathDevicePathNode->PathName); Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token); Print (L"\n"); if (EFI_ERROR (Status)) { gBS->FreePages (*Image, EFI_SIZE_TO_PAGES (TftpBufferSize)); if (Status == EFI_BUFFER_TOO_SMALL) { Print (L"Downloading failed, file larger than expected.\n"); continue; } else { goto Error; } } *ImageSize = Mtftp4Token.BufferSize; break; } Error: if (Dhcp4ChildHandle != NULL) { if (Dhcp4 != NULL) { if (Dhcp4ToStop) { Dhcp4->Stop (Dhcp4); } gBS->CloseProtocol ( Dhcp4ChildHandle, &gEfiDhcp4ProtocolGuid, gImageHandle, ControllerHandle ); } NetLibDestroyServiceChild ( ControllerHandle, gImageHandle, &gEfiDhcp4ServiceBindingProtocolGuid, Dhcp4ChildHandle ); } if (Mtftp4ChildHandle != NULL) { if (Mtftp4 != NULL) { if (AsciiFilePath != NULL) { FreePool (AsciiFilePath); } if (TftpContext != NULL) { FreePool (TftpContext); } gBS->CloseProtocol ( Mtftp4ChildHandle, &gEfiMtftp4ProtocolGuid, gImageHandle, ControllerHandle ); } NetLibDestroyServiceChild ( ControllerHandle, gImageHandle, &gEfiMtftp4ServiceBindingProtocolGuid, Mtftp4ChildHandle ); } if (EFI_ERROR (Status)) { Print (L"Failed to download the file - Error=%r\n", Status); } return Status; }
STATIC VOID AddEfiBootOptions ( VOID ) { UINTN Index; EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; UINTN BootOptionCount; BOOLEAN First = TRUE; MENU_ENTRY *Entry; EFI_DEVICE_PATH* DevicePathNode; BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); for (Index = 0; Index < BootOptionCount; Index++) { // // Don't display the hidden/inactive boot option // if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) { continue; } if (First) { // GROUP: UEFI Entry = MenuCreateGroupEntry(); Entry->Name = AsciiStrDup("UEFI"); Entry->Update = UefiMenuEntryUpdate; MenuAddEntry(mBootMenuMain, Entry); First = FALSE; } Entry = MenuCreateEntry(); if(Entry == NULL) { break; } CONST CHAR8* IconPath = "icons/uefi.png"; DevicePathNode = BootOption[Index].FilePath; while ((DevicePathNode != NULL) && !IsDevicePathEnd (DevicePathNode)) { // detect shell if (IS_DEVICE_PATH_NODE (DevicePathNode, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)) { CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH* FvDevicePathNode = ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)DevicePathNode); if (FvDevicePathNode != NULL && CompareGuid (&FvDevicePathNode->FvFileName, &mUefiShellFileGuid)) { IconPath = "icons/efi_shell.png"; break; } } // next DevicePathNode = NextDevicePathNode (DevicePathNode); } Entry->Icon = libaroma_stream_ramdisk(IconPath); Entry->Name = Unicode2Ascii(BootOption[Index].Description); Entry->Callback = BootOptionEfiOption; Entry->Private = &BootOption[Index]; Entry->ResetGop = TRUE; Entry->Update = UefiMenuEntryUpdate; MenuAddEntry(mBootMenuMain, Entry); } }