/** 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; }
BOOLEAN BdsLoadOptionPxeIsSupported ( IN EFI_DEVICE_PATH *DevicePath ) { EFI_STATUS Status; EFI_HANDLE Handle; EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); if (EFI_ERROR(Status)) { return FALSE; } if (!IsDevicePathEnd(RemainingDevicePath)) { return FALSE; } Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); if (EFI_ERROR (Status)) { return FALSE; } else { 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; }
EFI_STATUS BdsLoadImage ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS* Image, OUT UINTN *FileSize ) { EFI_STATUS Status; EFI_HANDLE Handle; EFI_DEVICE_PATH *RemainingDevicePath; BDS_FILE_LOADER* FileLoader; Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); if (EFI_ERROR (Status)) { return Status; } FileLoader = FileLoaders; while (FileLoader->Support != NULL) { if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) { return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize); } FileLoader++; } return EFI_UNSUPPORTED; }
BOOLEAN BdsLoadOptionTftpIsSupported ( IN EFI_DEVICE_PATH *DevicePath ) { EFI_STATUS Status; EFI_HANDLE Handle; EFI_DEVICE_PATH *RemainingDevicePath; EFI_DEVICE_PATH *NextDevicePath; EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); if (EFI_ERROR(Status)) { return FALSE; } // 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; } }
STATIC EFI_STATUS InitializeConsolePipe ( IN EFI_DEVICE_PATH *ConsoleDevicePaths, IN EFI_GUID *Protocol, OUT EFI_HANDLE *Handle, OUT VOID* *Interface ) { EFI_STATUS Status; UINTN Size; UINTN NoHandles; EFI_HANDLE *Buffer; EFI_DEVICE_PATH_PROTOCOL* DevicePath; // Connect all the Device Path Consoles while (ConsoleDevicePaths != NULL) { DevicePath = GetNextDevicePathInstance (&ConsoleDevicePaths, &Size); Status = BdsConnectDevicePath (DevicePath, Handle, NULL); DEBUG_CODE_BEGIN(); if (EFI_ERROR(Status)) { // We convert back to the text representation of the device Path EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol; CHAR16* DevicePathTxt; EFI_STATUS Status; Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); if (!EFI_ERROR(Status)) { DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (DevicePath, TRUE, TRUE); DEBUG((EFI_D_ERROR,"Fail to start the console with the Device Path '%s'. (Error '%r')\n", DevicePathTxt, Status)); FreePool (DevicePathTxt); } } DEBUG_CODE_END(); // If the console splitter driver is not supported by the platform then use the first Device Path // instance for the console interface. if (!EFI_ERROR(Status) && (*Interface == NULL)) { Status = gBS->HandleProtocol (*Handle, Protocol, Interface); } } // No Device Path has been defined for this console interface. We take the first protocol implementation if (*Interface == NULL) { Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer); if (EFI_ERROR (Status)) { BdsConnectAllDrivers(); Status = gBS->LocateHandleBuffer (ByProtocol, Protocol, NULL, &NoHandles, &Buffer); } if (!EFI_ERROR(Status)) { *Handle = Buffer[0]; Status = gBS->HandleProtocol (*Handle, Protocol, Interface); ASSERT_EFI_ERROR(Status); FreePool (Buffer); } } else { Status = EFI_SUCCESS; } return Status; }
/** Connect a Device Path and return the handle of the driver that support this DevicePath @param DevicePath Device Path of the File to connect @param Handle Handle of the driver that support this DevicePath @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath @retval EFI_SUCCESS A driver that matches the Device Path has been found @retval EFI_NOT_FOUND No handles match the search. @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL **/ EFI_STATUS BdsConnectDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, OUT EFI_HANDLE *Handle, OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath ) { EFI_DEVICE_PATH* Remaining; EFI_DEVICE_PATH* NewDevicePath; EFI_STATUS Status; if ((DevicePath == NULL) || (Handle == NULL)) { return EFI_INVALID_PARAMETER; } do { Remaining = DevicePath; // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified // to point to the remaining part of the device path Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); if (!EFI_ERROR (Status)) { // Recursive = FALSE: We do not want to start all the device tree Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); } /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling // NextDevicePathNode() will return an undetermined Device Path Node if (!IsDevicePathEnd (RemainingDevicePath)) { RemainingDevicePath = NextDevicePathNode (RemainingDevicePath); }*/ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); if (!EFI_ERROR (Status)) { // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) Remaining = DevicePath; Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle); if (!EFI_ERROR (Status)) { Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); if (EFI_ERROR (Status)) { // If the last node is a Memory Map Device Path just return EFI_SUCCESS. if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { Status = EFI_SUCCESS; } } } } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { Status = EFI_SUCCESS; } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { Status = EFI_SUCCESS; }*/ //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath Status = EFI_SUCCESS; } else { Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath); if (!EFI_ERROR (Status)) { return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath); } } if (RemainingDevicePath) { *RemainingDevicePath = Remaining; } return Status; }