andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 1 | /** @file |
| 2 | * |
| 3 | * Copyright (c) 2011, 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 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 17 | #include <Protocol/UsbIo.h> |
| 18 | #include <Protocol/DiskIo.h> |
oliviermartin | 2755d84 | 2011-09-09 10:53:42 +0000 | [diff] [blame] | 19 | #include <Protocol/LoadedImage.h> |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 20 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 21 | #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype))) |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 22 | |
| 23 | // Extract the FilePath from the Device Path |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 24 | CHAR16* |
| 25 | BdsExtractFilePathFromDevicePath ( |
| 26 | IN CONST CHAR16 *StrDevicePath, |
| 27 | IN UINTN NumberDevicePathNode |
| 28 | ) |
| 29 | { |
| 30 | UINTN Node; |
| 31 | CHAR16 *Str; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 32 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 33 | Str = (CHAR16*)StrDevicePath; |
| 34 | Node = 0; |
| 35 | while ((Str != NULL) && (*Str != L'\0') && (Node < NumberDevicePathNode)) { |
| 36 | if ((*Str == L'/') || (*Str == L'\\')) { |
| 37 | Node++; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 38 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 39 | Str++; |
| 40 | } |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 41 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 42 | if (*Str == L'\0') { |
| 43 | return NULL; |
| 44 | } else { |
| 45 | return Str; |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | BOOLEAN |
| 50 | BdsIsRemovableUsb ( |
| 51 | IN EFI_DEVICE_PATH* DevicePath |
| 52 | ) |
| 53 | { |
| 54 | return ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && |
| 55 | ((DevicePathSubType (DevicePath) == MSG_USB_CLASS_DP) || |
| 56 | (DevicePathSubType (DevicePath) == MSG_USB_WWID_DP))); |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 57 | } |
| 58 | |
| 59 | EFI_STATUS |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 60 | BdsGetDeviceUsb ( |
| 61 | IN EFI_DEVICE_PATH* RemovableDevicePath, |
| 62 | OUT EFI_HANDLE* DeviceHandle, |
| 63 | OUT EFI_DEVICE_PATH** NewDevicePath |
| 64 | ) |
| 65 | { |
| 66 | EFI_STATUS Status; |
| 67 | UINTN Index; |
| 68 | UINTN UsbIoHandleCount; |
| 69 | EFI_HANDLE *UsbIoBuffer; |
| 70 | EFI_DEVICE_PATH* UsbIoDevicePath; |
| 71 | EFI_DEVICE_PATH* TmpDevicePath; |
| 72 | USB_WWID_DEVICE_PATH* WwidDevicePath1; |
| 73 | USB_WWID_DEVICE_PATH* WwidDevicePath2; |
| 74 | USB_CLASS_DEVICE_PATH* UsbClassDevicePath1; |
| 75 | USB_CLASS_DEVICE_PATH* UsbClassDevicePath2; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 76 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 77 | // Get all the UsbIo handles |
| 78 | UsbIoHandleCount = 0; |
| 79 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer); |
| 80 | if (EFI_ERROR(Status) || (UsbIoHandleCount == 0)) { |
| 81 | return Status; |
| 82 | } |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 83 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 84 | // Check if one of the handles matches the USB description |
| 85 | for (Index = 0; Index < UsbIoHandleCount; Index++) { |
oliviermartin | 7598f36 | 2012-02-09 15:27:22 +0000 | [diff] [blame^] | 86 | Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &UsbIoDevicePath); |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 87 | if (!EFI_ERROR(Status)) { |
| 88 | TmpDevicePath = UsbIoDevicePath; |
| 89 | while (!IsDevicePathEnd (TmpDevicePath)) { |
| 90 | // Check if the Device Path node is a USB Removable device Path node |
| 91 | if (BdsIsRemovableUsb (TmpDevicePath)) { |
| 92 | if (TmpDevicePath->SubType == MSG_USB_WWID_DP) { |
| 93 | WwidDevicePath1 = (USB_WWID_DEVICE_PATH*)RemovableDevicePath; |
| 94 | WwidDevicePath2 = (USB_WWID_DEVICE_PATH*)TmpDevicePath; |
| 95 | if ((WwidDevicePath1->VendorId == WwidDevicePath2->VendorId) && |
| 96 | (WwidDevicePath1->ProductId == WwidDevicePath2->ProductId) && |
| 97 | (CompareMem (WwidDevicePath1+1, WwidDevicePath2+1, DevicePathNodeLength(WwidDevicePath1)-sizeof(USB_WWID_DEVICE_PATH)) == 0)) |
| 98 | { |
| 99 | *DeviceHandle = UsbIoBuffer[Index]; |
| 100 | // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path |
| 101 | *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath)); |
| 102 | return EFI_SUCCESS; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 103 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 104 | } else { |
| 105 | UsbClassDevicePath1 = (USB_CLASS_DEVICE_PATH*)RemovableDevicePath; |
| 106 | UsbClassDevicePath2 = (USB_CLASS_DEVICE_PATH*)TmpDevicePath; |
| 107 | if ((UsbClassDevicePath1->VendorId != 0xFFFF) && (UsbClassDevicePath1->VendorId == UsbClassDevicePath2->VendorId) && |
| 108 | (UsbClassDevicePath1->ProductId != 0xFFFF) && (UsbClassDevicePath1->ProductId == UsbClassDevicePath2->ProductId) && |
| 109 | (UsbClassDevicePath1->DeviceClass != 0xFF) && (UsbClassDevicePath1->DeviceClass == UsbClassDevicePath2->DeviceClass) && |
| 110 | (UsbClassDevicePath1->DeviceSubClass != 0xFF) && (UsbClassDevicePath1->DeviceSubClass == UsbClassDevicePath2->DeviceSubClass) && |
| 111 | (UsbClassDevicePath1->DeviceProtocol != 0xFF) && (UsbClassDevicePath1->DeviceProtocol == UsbClassDevicePath2->DeviceProtocol)) |
| 112 | { |
| 113 | *DeviceHandle = UsbIoBuffer[Index]; |
| 114 | // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path |
| 115 | *NewDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePathNode(RemovableDevicePath)); |
| 116 | return EFI_SUCCESS; |
| 117 | } |
| 118 | } |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 119 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 120 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
| 121 | } |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 122 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | |
| 126 | return EFI_NOT_FOUND; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 127 | } |
| 128 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 129 | BOOLEAN |
| 130 | BdsIsRemovableHd ( |
| 131 | IN EFI_DEVICE_PATH* DevicePath |
| 132 | ) |
| 133 | { |
| 134 | return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP); |
| 135 | } |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 136 | |
| 137 | EFI_STATUS |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 138 | BdsGetDeviceHd ( |
| 139 | IN EFI_DEVICE_PATH* RemovableDevicePath, |
| 140 | OUT EFI_HANDLE* DeviceHandle, |
| 141 | OUT EFI_DEVICE_PATH** NewDevicePath |
| 142 | ) |
| 143 | { |
| 144 | EFI_STATUS Status; |
| 145 | UINTN Index; |
| 146 | UINTN PartitionHandleCount; |
| 147 | EFI_HANDLE *PartitionBuffer; |
| 148 | EFI_DEVICE_PATH* PartitionDevicePath; |
| 149 | EFI_DEVICE_PATH* TmpDevicePath; |
| 150 | HARDDRIVE_DEVICE_PATH* HardDriveDevicePath1; |
| 151 | HARDDRIVE_DEVICE_PATH* HardDriveDevicePath2; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 152 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 153 | // Get all the DiskIo handles |
| 154 | PartitionHandleCount = 0; |
| 155 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &PartitionHandleCount, &PartitionBuffer); |
| 156 | if (EFI_ERROR(Status) || (PartitionHandleCount == 0)) { |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 157 | return Status; |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | // Check if one of the handles matches the Hard Disk Description |
| 161 | for (Index = 0; Index < PartitionHandleCount; Index++) { |
oliviermartin | 7598f36 | 2012-02-09 15:27:22 +0000 | [diff] [blame^] | 162 | Status = gBS->HandleProtocol (PartitionBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &PartitionDevicePath); |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 163 | if (!EFI_ERROR(Status)) { |
| 164 | TmpDevicePath = PartitionDevicePath; |
| 165 | while (!IsDevicePathEnd (TmpDevicePath)) { |
| 166 | // Check if the Device Path node is a HD Removable device Path node |
| 167 | if (BdsIsRemovableHd (TmpDevicePath)) { |
| 168 | HardDriveDevicePath1 = (HARDDRIVE_DEVICE_PATH*)RemovableDevicePath; |
| 169 | HardDriveDevicePath2 = (HARDDRIVE_DEVICE_PATH*)TmpDevicePath; |
| 170 | if ((HardDriveDevicePath1->SignatureType == HardDriveDevicePath2->SignatureType) && |
| 171 | (CompareGuid ((EFI_GUID *)HardDriveDevicePath1->Signature,(EFI_GUID *)HardDriveDevicePath2->Signature) == TRUE) && |
| 172 | (HardDriveDevicePath1->PartitionNumber == HardDriveDevicePath2->PartitionNumber)) |
| 173 | { |
| 174 | *DeviceHandle = PartitionBuffer[Index]; |
| 175 | // Add the additional original Device Path Nodes (eg: FilePath Device Path Node) to the new Device Path |
| 176 | *NewDevicePath = AppendDevicePath (PartitionDevicePath, NextDevicePathNode(RemovableDevicePath)); |
| 177 | return EFI_SUCCESS; |
| 178 | } |
| 179 | } |
| 180 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
| 181 | } |
| 182 | |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | return EFI_NOT_FOUND; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 187 | } |
| 188 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 189 | /*BOOLEAN |
| 190 | BdsIsRemovableCdrom ( |
| 191 | IN EFI_DEVICE_PATH* DevicePath |
| 192 | ) |
| 193 | { |
| 194 | return IS_DEVICE_PATH_NODE(DevicePath, MEDIA_DEVICE_PATH, MEDIA_CDROM_DP); |
| 195 | } |
| 196 | |
| 197 | EFI_STATUS |
| 198 | BdsGetDeviceCdrom ( |
| 199 | IN EFI_DEVICE_PATH* RemovableDevicePath, |
| 200 | OUT EFI_HANDLE* DeviceHandle, |
| 201 | OUT EFI_DEVICE_PATH** DevicePath |
| 202 | ) |
| 203 | { |
| 204 | ASSERT(0); |
| 205 | return EFI_UNSUPPORTED; |
| 206 | }*/ |
| 207 | |
| 208 | typedef BOOLEAN |
| 209 | (*BDS_IS_REMOVABLE) ( |
| 210 | IN EFI_DEVICE_PATH* DevicePath |
| 211 | ); |
| 212 | |
| 213 | typedef EFI_STATUS |
| 214 | (*BDS_GET_DEVICE) ( |
| 215 | IN EFI_DEVICE_PATH* RemovableDevicePath, |
| 216 | OUT EFI_HANDLE* DeviceHandle, |
| 217 | OUT EFI_DEVICE_PATH** DevicePath |
| 218 | ); |
| 219 | |
| 220 | typedef struct { |
| 221 | BDS_IS_REMOVABLE IsRemovable; |
| 222 | BDS_GET_DEVICE GetDevice; |
| 223 | } BDS_REMOVABLE_DEVICE_SUPPORT; |
| 224 | |
| 225 | BDS_REMOVABLE_DEVICE_SUPPORT RemovableDeviceSupport[] = { |
| 226 | { BdsIsRemovableUsb, BdsGetDeviceUsb }, |
| 227 | { BdsIsRemovableHd, BdsGetDeviceHd }, |
| 228 | //{ BdsIsRemovableCdrom, BdsGetDeviceCdrom } |
| 229 | }; |
| 230 | |
| 231 | STATIC |
| 232 | BOOLEAN |
| 233 | IsRemovableDevice ( |
| 234 | IN EFI_DEVICE_PATH* DevicePath |
| 235 | ) |
| 236 | { |
| 237 | UINTN Index; |
| 238 | EFI_DEVICE_PATH* TmpDevicePath; |
| 239 | |
| 240 | TmpDevicePath = DevicePath; |
| 241 | while (!IsDevicePathEnd (TmpDevicePath)) { |
| 242 | for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { |
| 243 | if (RemovableDeviceSupport[Index].IsRemovable(TmpDevicePath)) { |
| 244 | return TRUE; |
| 245 | } |
| 246 | } |
| 247 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
| 248 | } |
| 249 | |
| 250 | return FALSE; |
| 251 | } |
| 252 | |
| 253 | STATIC |
| 254 | EFI_STATUS |
| 255 | TryRemovableDevice ( |
| 256 | IN EFI_DEVICE_PATH* DevicePath, |
| 257 | OUT EFI_HANDLE* DeviceHandle, |
| 258 | OUT EFI_DEVICE_PATH** NewDevicePath |
| 259 | ) |
| 260 | { |
| 261 | EFI_STATUS Status; |
| 262 | UINTN Index; |
| 263 | EFI_DEVICE_PATH* TmpDevicePath; |
| 264 | BDS_REMOVABLE_DEVICE_SUPPORT* RemovableDevice; |
| 265 | EFI_DEVICE_PATH* RemovableDevicePath; |
| 266 | BOOLEAN RemovableFound; |
| 267 | |
oliviermartin | e862cd5 | 2011-06-15 19:53:15 +0000 | [diff] [blame] | 268 | RemovableDevice = NULL; |
| 269 | RemovableDevicePath = NULL; |
| 270 | RemovableFound = FALSE; |
| 271 | TmpDevicePath = DevicePath; |
| 272 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 273 | while (!IsDevicePathEnd (TmpDevicePath) && !RemovableFound) { |
| 274 | for (Index = 0; Index < sizeof(RemovableDeviceSupport) / sizeof(BDS_REMOVABLE_DEVICE_SUPPORT); Index++) { |
| 275 | RemovableDevice = &RemovableDeviceSupport[Index]; |
| 276 | if (RemovableDevice->IsRemovable(TmpDevicePath)) { |
| 277 | RemovableDevicePath = TmpDevicePath; |
| 278 | RemovableFound = TRUE; |
| 279 | break; |
| 280 | } |
| 281 | } |
| 282 | TmpDevicePath = NextDevicePathNode (TmpDevicePath); |
| 283 | } |
| 284 | |
| 285 | if (!RemovableFound) { |
| 286 | return EFI_NOT_FOUND; |
| 287 | } |
| 288 | |
| 289 | // Search into the current started drivers |
| 290 | Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); |
| 291 | if (Status == EFI_NOT_FOUND) { |
| 292 | // Connect all the drivers |
| 293 | BdsConnectAllDrivers (); |
| 294 | |
| 295 | // Search again into all the drivers |
| 296 | Status = RemovableDevice->GetDevice (RemovableDevicePath, DeviceHandle, NewDevicePath); |
| 297 | } |
| 298 | |
| 299 | return Status; |
| 300 | } |
| 301 | |
oliviermartin | 6bab33c | 2011-06-15 19:56:50 +0000 | [diff] [blame] | 302 | /** |
| 303 | Connect a Device Path and return the handle of the driver that support this DevicePath |
| 304 | |
| 305 | @param DevicePath Device Path of the File to connect |
| 306 | @param Handle Handle of the driver that support this DevicePath |
| 307 | @param RemainingDevicePath Remaining DevicePath nodes that do not match the driver DevicePath |
| 308 | |
| 309 | @retval EFI_SUCCESS A driver that matches the Device Path has been found |
| 310 | @retval EFI_NOT_FOUND No handles match the search. |
| 311 | @retval EFI_INVALID_PARAMETER DevicePath or Handle is NULL |
| 312 | |
| 313 | **/ |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 314 | EFI_STATUS |
| 315 | BdsConnectDevicePath ( |
| 316 | IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, |
| 317 | OUT EFI_HANDLE *Handle, |
| 318 | OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath |
| 319 | ) |
| 320 | { |
| 321 | EFI_DEVICE_PATH* Remaining; |
| 322 | EFI_DEVICE_PATH* NewDevicePath; |
| 323 | EFI_STATUS Status; |
| 324 | |
| 325 | if ((DevicePath == NULL) || (Handle == NULL)) { |
| 326 | return EFI_INVALID_PARAMETER; |
| 327 | } |
| 328 | |
| 329 | do { |
| 330 | Remaining = DevicePath; |
| 331 | // The LocateDevicePath() function locates all devices on DevicePath that support Protocol and returns |
| 332 | // the handle to the device that is closest to DevicePath. On output, the device path pointer is modified |
| 333 | // to point to the remaining part of the device path |
| 334 | Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &Remaining, Handle); |
| 335 | if (!EFI_ERROR (Status)) { |
| 336 | // Recursive = FALSE: We do not want to start all the device tree |
| 337 | Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 338 | } |
| 339 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 340 | /*// We need to check if RemainingDevicePath does not point on the last node. Otherwise, calling |
| 341 | // NextDevicePathNode() will return an undetermined Device Path Node |
| 342 | if (!IsDevicePathEnd (RemainingDevicePath)) { |
| 343 | RemainingDevicePath = NextDevicePathNode (RemainingDevicePath); |
| 344 | }*/ |
| 345 | } while (!EFI_ERROR (Status) && !IsDevicePathEnd (Remaining)); |
| 346 | |
| 347 | if (!EFI_ERROR (Status)) { |
| 348 | // Now, we have got the whole Device Path connected, call again ConnectController to ensure all the supported Driver |
| 349 | // Binding Protocol are connected (such as DiskIo and SimpleFileSystem) |
| 350 | Remaining = DevicePath; |
oliviermartin | 6bab33c | 2011-06-15 19:56:50 +0000 | [diff] [blame] | 351 | Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid,&Remaining,Handle); |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 352 | if (!EFI_ERROR (Status)) { |
| 353 | Status = gBS->ConnectController (*Handle, NULL, Remaining, FALSE); |
| 354 | if (EFI_ERROR (Status)) { |
| 355 | // If the last node is a Memory Map Device Path just return EFI_SUCCESS. |
| 356 | if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { |
| 357 | Status = EFI_SUCCESS; |
| 358 | } |
| 359 | } |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 360 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 361 | } else if (!IsDevicePathEnd (Remaining) && !IsRemovableDevice (Remaining)) { |
| 362 | |
| 363 | /*// If the remaining Device Path is a FilePath or MemoryMap then we consider the Device Path has been loaded correctly |
| 364 | if ((Remaining->Type == MEDIA_DEVICE_PATH) && (Remaining->SubType == MEDIA_FILEPATH_DP)) { |
| 365 | Status = EFI_SUCCESS; |
| 366 | } else if ((Remaining->Type == HARDWARE_DEVICE_PATH) && (Remaining->SubType == HW_MEMMAP_DP)) { |
| 367 | Status = EFI_SUCCESS; |
| 368 | }*/ |
| 369 | |
| 370 | //TODO: Should we just return success and leave the caller decide if it is the expected RemainingPath |
| 371 | Status = EFI_SUCCESS; |
| 372 | } else { |
| 373 | Status = TryRemovableDevice (DevicePath, Handle, &NewDevicePath); |
| 374 | if (!EFI_ERROR (Status)) { |
| 375 | return BdsConnectDevicePath (NewDevicePath, Handle, RemainingDevicePath); |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | if (RemainingDevicePath) { |
| 380 | *RemainingDevicePath = Remaining; |
| 381 | } |
| 382 | |
| 383 | return Status; |
| 384 | } |
| 385 | |
| 386 | BOOLEAN |
| 387 | BdsFileSystemSupport ( |
| 388 | IN EFI_DEVICE_PATH *DevicePath, |
| 389 | IN EFI_HANDLE Handle, |
| 390 | IN EFI_DEVICE_PATH *RemainingDevicePath |
| 391 | ) |
| 392 | { |
| 393 | EFI_STATUS Status; |
| 394 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; |
| 395 | |
| 396 | Status = gBS->HandleProtocol (Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); |
| 397 | |
| 398 | return (!EFI_ERROR(Status) && IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); |
| 399 | } |
| 400 | |
| 401 | EFI_STATUS |
| 402 | BdsFileSystemLoadImage ( |
| 403 | IN EFI_DEVICE_PATH *DevicePath, |
| 404 | IN EFI_HANDLE Handle, |
| 405 | IN EFI_DEVICE_PATH *RemainingDevicePath, |
| 406 | IN EFI_ALLOCATE_TYPE Type, |
| 407 | IN OUT EFI_PHYSICAL_ADDRESS* Image, |
| 408 | OUT UINTN *ImageSize |
| 409 | ) |
| 410 | { |
| 411 | FILEPATH_DEVICE_PATH* FilePathDevicePath; |
| 412 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; |
| 413 | EFI_FILE_PROTOCOL *Fs; |
| 414 | EFI_STATUS Status; |
| 415 | EFI_FILE_INFO *FileInfo; |
| 416 | EFI_FILE_PROTOCOL *File; |
| 417 | UINTN Size; |
| 418 | |
| 419 | ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); |
| 420 | |
| 421 | FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath; |
| 422 | |
| 423 | Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); |
| 424 | if (EFI_ERROR(Status)) { |
| 425 | return Status; |
| 426 | } |
| 427 | |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 428 | // Try to Open the volume and get root directory |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 429 | Status = FsProtocol->OpenVolume (FsProtocol, &Fs); |
| 430 | if (EFI_ERROR(Status)) { |
| 431 | return Status; |
| 432 | } |
| 433 | |
| 434 | File = NULL; |
| 435 | Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); |
oliviermartin | 6bab33c | 2011-06-15 19:56:50 +0000 | [diff] [blame] | 436 | if (EFI_ERROR(Status)) { |
| 437 | return Status; |
| 438 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 439 | |
| 440 | Size = 0; |
| 441 | File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL); |
| 442 | FileInfo = AllocatePool (Size); |
| 443 | Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo); |
| 444 | if (EFI_ERROR(Status)) { |
| 445 | return Status; |
| 446 | } |
| 447 | |
| 448 | // Get the file size |
| 449 | Size = FileInfo->FileSize; |
| 450 | if (ImageSize) { |
| 451 | *ImageSize = Size; |
| 452 | } |
| 453 | FreePool(FileInfo); |
| 454 | |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 455 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
| 456 | // Try to allocate in any pages if failed to allocate memory at the defined location |
| 457 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { |
| 458 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
| 459 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 460 | if (!EFI_ERROR(Status)) { |
| 461 | Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); |
| 462 | } |
| 463 | |
| 464 | return Status; |
| 465 | } |
| 466 | |
| 467 | BOOLEAN |
| 468 | BdsMemoryMapSupport ( |
| 469 | IN EFI_DEVICE_PATH *DevicePath, |
| 470 | IN EFI_HANDLE Handle, |
| 471 | IN EFI_DEVICE_PATH *RemainingDevicePath |
| 472 | ) |
| 473 | { |
oliviermartin | aa863d3 | 2011-09-09 10:55:26 +0000 | [diff] [blame] | 474 | return IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP) || |
| 475 | IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP); |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 476 | } |
| 477 | |
| 478 | EFI_STATUS |
| 479 | BdsMemoryMapLoadImage ( |
| 480 | IN EFI_DEVICE_PATH *DevicePath, |
| 481 | IN EFI_HANDLE Handle, |
| 482 | IN EFI_DEVICE_PATH *RemainingDevicePath, |
| 483 | IN EFI_ALLOCATE_TYPE Type, |
| 484 | IN OUT EFI_PHYSICAL_ADDRESS* Image, |
| 485 | OUT UINTN *ImageSize |
| 486 | ) |
| 487 | { |
| 488 | EFI_STATUS Status; |
| 489 | MEMMAP_DEVICE_PATH* MemMapPathDevicePath; |
| 490 | UINTN Size; |
| 491 | |
oliviermartin | aa863d3 | 2011-09-09 10:55:26 +0000 | [diff] [blame] | 492 | if (IS_DEVICE_PATH_NODE(RemainingDevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)) { |
| 493 | MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)RemainingDevicePath; |
| 494 | } else { |
| 495 | ASSERT (IS_DEVICE_PATH_NODE(DevicePath,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP)); |
| 496 | MemMapPathDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath; |
| 497 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 498 | |
| 499 | Size = MemMapPathDevicePath->EndingAddress - MemMapPathDevicePath->StartingAddress; |
| 500 | if (Size == 0) { |
| 501 | return EFI_INVALID_PARAMETER; |
| 502 | } |
| 503 | |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 504 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
| 505 | // Try to allocate in any pages if failed to allocate memory at the defined location |
| 506 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { |
| 507 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); |
| 508 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 509 | if (!EFI_ERROR(Status)) { |
| 510 | CopyMem ((VOID*)(UINTN)(*Image), (CONST VOID*)(UINTN)MemMapPathDevicePath->StartingAddress, Size); |
| 511 | |
| 512 | if (ImageSize != NULL) { |
| 513 | *ImageSize = Size; |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | return Status; |
| 518 | } |
| 519 | |
| 520 | BOOLEAN |
| 521 | BdsFirmwareVolumeSupport ( |
| 522 | IN EFI_DEVICE_PATH *DevicePath, |
| 523 | IN EFI_HANDLE Handle, |
| 524 | IN EFI_DEVICE_PATH *RemainingDevicePath |
| 525 | ) |
| 526 | { |
| 527 | return IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP); |
| 528 | } |
| 529 | |
| 530 | EFI_STATUS |
| 531 | BdsFirmwareVolumeLoadImage ( |
| 532 | IN EFI_DEVICE_PATH *DevicePath, |
| 533 | IN EFI_HANDLE Handle, |
| 534 | IN EFI_DEVICE_PATH *RemainingDevicePath, |
| 535 | IN EFI_ALLOCATE_TYPE Type, |
| 536 | IN OUT EFI_PHYSICAL_ADDRESS* Image, |
| 537 | OUT UINTN *ImageSize |
| 538 | ) |
| 539 | { |
| 540 | EFI_STATUS Status; |
| 541 | EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; |
| 542 | EFI_GUID *FvNameGuid; |
| 543 | EFI_SECTION_TYPE SectionType; |
| 544 | EFI_FV_FILETYPE FvType; |
| 545 | EFI_FV_FILE_ATTRIBUTES Attrib; |
| 546 | UINT32 AuthenticationStatus; |
| 547 | VOID* ImageBuffer; |
| 548 | |
| 549 | ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_PIWG_FW_FILE_DP)); |
| 550 | |
| 551 | Status = gBS->HandleProtocol(Handle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FwVol); |
| 552 | if (EFI_ERROR(Status)) { |
| 553 | return Status; |
| 554 | } |
| 555 | |
| 556 | FvNameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)RemainingDevicePath); |
| 557 | if (FvNameGuid == NULL) { |
| 558 | Status = EFI_INVALID_PARAMETER; |
| 559 | } |
| 560 | |
| 561 | SectionType = EFI_SECTION_PE32; |
| 562 | AuthenticationStatus = 0; |
| 563 | //Note: ReadSection at the opposite of ReadFile does not allow to pass ImageBuffer == NULL to get the size of the file. |
| 564 | ImageBuffer = NULL; |
| 565 | Status = FwVol->ReadSection ( |
| 566 | FwVol, |
| 567 | FvNameGuid, |
| 568 | SectionType, |
| 569 | 0, |
| 570 | &ImageBuffer, |
| 571 | ImageSize, |
| 572 | &AuthenticationStatus |
| 573 | ); |
| 574 | if (!EFI_ERROR (Status)) { |
| 575 | #if 0 |
| 576 | // In case the buffer has some address requirements, we must copy the buffer to a buffer following the requirements |
| 577 | if (Type != AllocateAnyPages) { |
| 578 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize),Image); |
| 579 | if (!EFI_ERROR(Status)) { |
| 580 | CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); |
| 581 | FreePool (ImageBuffer); |
| 582 | } |
| 583 | } |
| 584 | #else |
| 585 | // We must copy the buffer into a page allocations. Otherwise, the caller could call gBS->FreePages() on the pool allocation |
| 586 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 587 | // Try to allocate in any pages if failed to allocate memory at the defined location |
| 588 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { |
oliviermartin | 1c6f402 | 2011-08-19 15:37:16 +0000 | [diff] [blame] | 589 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 590 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 591 | if (!EFI_ERROR(Status)) { |
| 592 | CopyMem ((VOID*)(UINTN)(*Image), ImageBuffer, *ImageSize); |
| 593 | FreePool (ImageBuffer); |
| 594 | } |
| 595 | #endif |
| 596 | } else { |
| 597 | // Try a raw file, since a PE32 SECTION does not exist |
| 598 | Status = FwVol->ReadFile ( |
| 599 | FwVol, |
| 600 | FvNameGuid, |
| 601 | NULL, |
| 602 | ImageSize, |
| 603 | &FvType, |
| 604 | &Attrib, |
| 605 | &AuthenticationStatus |
| 606 | ); |
| 607 | if (!EFI_ERROR(Status)) { |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 608 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
| 609 | // Try to allocate in any pages if failed to allocate memory at the defined location |
| 610 | if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { |
oliviermartin | 1c6f402 | 2011-08-19 15:37:16 +0000 | [diff] [blame] | 611 | Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(*ImageSize), Image); |
oliviermartin | bd54c23 | 2011-08-18 21:11:27 +0000 | [diff] [blame] | 612 | } |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 613 | if (!EFI_ERROR(Status)) { |
| 614 | Status = FwVol->ReadFile ( |
| 615 | FwVol, |
| 616 | FvNameGuid, |
| 617 | (VOID*)(UINTN)(*Image), |
| 618 | ImageSize, |
| 619 | &FvType, |
| 620 | &Attrib, |
| 621 | &AuthenticationStatus |
| 622 | ); |
| 623 | } |
| 624 | } |
| 625 | } |
| 626 | return Status; |
| 627 | } |
| 628 | |
| 629 | BOOLEAN |
| 630 | BdsPxeSupport ( |
| 631 | IN EFI_DEVICE_PATH* DevicePath, |
| 632 | IN EFI_HANDLE Handle, |
| 633 | IN EFI_DEVICE_PATH* RemainingDevicePath |
| 634 | ) |
| 635 | { |
| 636 | EFI_STATUS Status; |
| 637 | EFI_PXE_BASE_CODE_PROTOCOL* PxeBcProtocol; |
| 638 | |
| 639 | if (!IsDevicePathEnd(RemainingDevicePath)) { |
| 640 | return FALSE; |
| 641 | } |
| 642 | |
| 643 | Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); |
| 644 | if (EFI_ERROR (Status)) { |
| 645 | return FALSE; |
| 646 | } else { |
| 647 | return TRUE; |
| 648 | } |
| 649 | } |
| 650 | |
| 651 | EFI_STATUS |
| 652 | BdsPxeLoadImage ( |
| 653 | IN EFI_DEVICE_PATH* DevicePath, |
| 654 | IN EFI_HANDLE Handle, |
| 655 | IN EFI_DEVICE_PATH* RemainingDevicePath, |
| 656 | IN EFI_ALLOCATE_TYPE Type, |
| 657 | IN OUT EFI_PHYSICAL_ADDRESS *Image, |
| 658 | OUT UINTN *ImageSize |
| 659 | ) |
| 660 | { |
| 661 | EFI_STATUS Status; |
| 662 | EFI_LOAD_FILE_PROTOCOL *LoadFileProtocol; |
| 663 | UINTN BufferSize; |
| 664 | |
| 665 | // Get Load File Protocol attached to the PXE protocol |
| 666 | Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFileProtocol); |
| 667 | if (EFI_ERROR (Status)) { |
| 668 | return Status; |
| 669 | } |
| 670 | |
| 671 | Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, NULL); |
| 672 | if (Status == EFI_BUFFER_TOO_SMALL) { |
| 673 | Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(BufferSize), Image); |
| 674 | if (EFI_ERROR(Status)) { |
| 675 | return Status; |
| 676 | } |
| 677 | |
| 678 | Status = LoadFileProtocol->LoadFile (LoadFileProtocol, DevicePath, TRUE, &BufferSize, (VOID*)(UINTN)(*Image)); |
| 679 | if (!EFI_ERROR(Status) && (ImageSize != NULL)) { |
| 680 | *ImageSize = BufferSize; |
| 681 | } |
| 682 | } |
| 683 | |
| 684 | return Status; |
| 685 | } |
| 686 | |
| 687 | BOOLEAN |
| 688 | BdsTftpSupport ( |
| 689 | IN EFI_DEVICE_PATH* DevicePath, |
| 690 | IN EFI_HANDLE Handle, |
| 691 | IN EFI_DEVICE_PATH* RemainingDevicePath |
| 692 | ) |
| 693 | { |
| 694 | EFI_STATUS Status; |
| 695 | EFI_DEVICE_PATH *NextDevicePath; |
| 696 | EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol; |
| 697 | |
| 698 | // Validate the Remaining Device Path |
| 699 | if (IsDevicePathEnd(RemainingDevicePath)) { |
| 700 | return FALSE; |
| 701 | } |
| 702 | if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) && |
| 703 | !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) { |
| 704 | return FALSE; |
| 705 | } |
| 706 | NextDevicePath = NextDevicePathNode (RemainingDevicePath); |
| 707 | if (IsDevicePathEnd(NextDevicePath)) { |
| 708 | return FALSE; |
| 709 | } |
| 710 | if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) { |
| 711 | return FALSE; |
| 712 | } |
| 713 | |
| 714 | Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol); |
| 715 | if (EFI_ERROR (Status)) { |
| 716 | return FALSE; |
| 717 | } else { |
| 718 | return TRUE; |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | EFI_STATUS |
| 723 | BdsTftpLoadImage ( |
| 724 | IN EFI_DEVICE_PATH* DevicePath, |
| 725 | IN EFI_HANDLE Handle, |
| 726 | IN EFI_DEVICE_PATH* RemainingDevicePath, |
| 727 | IN EFI_ALLOCATE_TYPE Type, |
| 728 | IN OUT EFI_PHYSICAL_ADDRESS *Image, |
| 729 | OUT UINTN *ImageSize |
| 730 | ) |
| 731 | { |
| 732 | EFI_STATUS Status; |
| 733 | EFI_PXE_BASE_CODE_PROTOCOL *Pxe; |
| 734 | UINT64 TftpBufferSize; |
| 735 | VOID* TftpBuffer; |
| 736 | EFI_IP_ADDRESS ServerIp; |
| 737 | IPv4_DEVICE_PATH* IPv4DevicePathNode; |
| 738 | FILEPATH_DEVICE_PATH* FilePathDevicePath; |
| 739 | EFI_IP_ADDRESS LocalIp; |
| 740 | |
| 741 | ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP)); |
| 742 | |
| 743 | IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; |
| 744 | FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); |
| 745 | |
| 746 | Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); |
| 747 | if (EFI_ERROR(Status)) { |
| 748 | return Status; |
| 749 | } |
| 750 | |
| 751 | Status = Pxe->Start (Pxe, FALSE); |
| 752 | if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { |
| 753 | return Status; |
| 754 | } |
| 755 | |
| 756 | if (!IPv4DevicePathNode->StaticIpAddress) { |
| 757 | Status = Pxe->Dhcp(Pxe, TRUE); |
| 758 | } else { |
| 759 | CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); |
| 760 | Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL); |
| 761 | } |
| 762 | if (EFI_ERROR(Status)) { |
| 763 | return Status; |
| 764 | } |
| 765 | |
| 766 | CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); |
| 767 | |
| 768 | Status = Pxe->Mtftp ( |
| 769 | Pxe, |
| 770 | EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, |
| 771 | NULL, |
| 772 | FALSE, |
| 773 | &TftpBufferSize, |
| 774 | NULL, |
| 775 | &ServerIp, |
| 776 | (UINT8 *)FilePathDevicePath->PathName, |
| 777 | NULL, |
| 778 | TRUE |
| 779 | ); |
| 780 | if (EFI_ERROR(Status)) { |
| 781 | return Status; |
| 782 | } |
| 783 | |
| 784 | // Allocate a buffer to hold the whole file. |
| 785 | TftpBuffer = AllocatePool(TftpBufferSize); |
| 786 | if (TftpBuffer == NULL) { |
| 787 | return EFI_OUT_OF_RESOURCES; |
| 788 | } |
| 789 | |
| 790 | Status = Pxe->Mtftp ( |
| 791 | Pxe, |
| 792 | EFI_PXE_BASE_CODE_TFTP_READ_FILE, |
| 793 | TftpBuffer, |
| 794 | FALSE, |
| 795 | &TftpBufferSize, |
| 796 | NULL, |
| 797 | &ServerIp, |
| 798 | (UINT8 *)FilePathDevicePath->PathName, |
| 799 | NULL, |
| 800 | FALSE |
| 801 | ); |
| 802 | if (EFI_ERROR(Status)) { |
| 803 | FreePool(TftpBuffer); |
| 804 | } else if (ImageSize != NULL) { |
| 805 | *ImageSize = (UINTN)TftpBufferSize; |
| 806 | } |
| 807 | |
| 808 | return Status; |
| 809 | } |
| 810 | |
| 811 | BDS_FILE_LOADER FileLoaders[] = { |
| 812 | { BdsFileSystemSupport, BdsFileSystemLoadImage }, |
| 813 | { BdsFirmwareVolumeSupport, BdsFirmwareVolumeLoadImage }, |
| 814 | //{ BdsLoadFileSupport, BdsLoadFileLoadImage }, |
| 815 | { BdsMemoryMapSupport, BdsMemoryMapLoadImage }, |
| 816 | { BdsPxeSupport, BdsPxeLoadImage }, |
| 817 | { BdsTftpSupport, BdsTftpLoadImage }, |
| 818 | { NULL, NULL } |
| 819 | }; |
| 820 | |
| 821 | EFI_STATUS |
| 822 | BdsLoadImage ( |
| 823 | IN EFI_DEVICE_PATH *DevicePath, |
| 824 | IN EFI_ALLOCATE_TYPE Type, |
| 825 | IN OUT EFI_PHYSICAL_ADDRESS* Image, |
| 826 | OUT UINTN *FileSize |
| 827 | ) |
| 828 | { |
| 829 | EFI_STATUS Status; |
| 830 | EFI_HANDLE Handle; |
| 831 | EFI_DEVICE_PATH *RemainingDevicePath; |
| 832 | BDS_FILE_LOADER* FileLoader; |
| 833 | |
| 834 | Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath); |
| 835 | if (EFI_ERROR (Status)) { |
| 836 | return Status; |
| 837 | } |
| 838 | |
| 839 | FileLoader = FileLoaders; |
| 840 | while (FileLoader->Support != NULL) { |
| 841 | if (FileLoader->Support (DevicePath, Handle, RemainingDevicePath)) { |
| 842 | return FileLoader->LoadImage (DevicePath, Handle, RemainingDevicePath, Type, Image, FileSize); |
| 843 | } |
| 844 | FileLoader++; |
| 845 | } |
| 846 | |
| 847 | return EFI_UNSUPPORTED; |
| 848 | } |
| 849 | |
oliviermartin | 6bab33c | 2011-06-15 19:56:50 +0000 | [diff] [blame] | 850 | /** |
| 851 | Start an EFI Application from a Device Path |
| 852 | |
| 853 | @param ParentImageHandle Handle of the calling image |
| 854 | @param DevicePath Location of the EFI Application |
| 855 | |
| 856 | @retval EFI_SUCCESS All drivers have been connected |
| 857 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found |
| 858 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. |
| 859 | |
| 860 | **/ |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 861 | EFI_STATUS |
| 862 | BdsStartEfiApplication ( |
| 863 | IN EFI_HANDLE ParentImageHandle, |
oliviermartin | 2755d84 | 2011-09-09 10:53:42 +0000 | [diff] [blame] | 864 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, |
| 865 | IN UINTN LoadOptionsSize, |
| 866 | IN VOID* LoadOptions |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 867 | ) |
| 868 | { |
| 869 | EFI_STATUS Status; |
| 870 | EFI_HANDLE ImageHandle; |
| 871 | EFI_PHYSICAL_ADDRESS BinaryBuffer; |
| 872 | UINTN BinarySize; |
oliviermartin | 2755d84 | 2011-09-09 10:53:42 +0000 | [diff] [blame] | 873 | EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 874 | |
| 875 | // Find the nearest supported file loader |
oliviermartin | 2755d84 | 2011-09-09 10:53:42 +0000 | [diff] [blame] | 876 | Status = BdsLoadImage (DevicePath, AllocateAnyPages, &BinaryBuffer, &BinarySize); |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 877 | if (EFI_ERROR(Status)) { |
| 878 | return Status; |
| 879 | } |
| 880 | |
| 881 | // Load the image from the Buffer with Boot Services function |
| 882 | Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, (VOID*)(UINTN)BinaryBuffer, BinarySize, &ImageHandle); |
| 883 | if (EFI_ERROR(Status)) { |
| 884 | return Status; |
| 885 | } |
| 886 | |
oliviermartin | 2755d84 | 2011-09-09 10:53:42 +0000 | [diff] [blame] | 887 | // Passed LoadOptions to the EFI Application |
| 888 | if (LoadOptionsSize != 0) { |
| 889 | Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage); |
| 890 | if (EFI_ERROR(Status)) { |
| 891 | return Status; |
| 892 | } |
| 893 | |
| 894 | LoadedImage->LoadOptionsSize = LoadOptionsSize; |
| 895 | LoadedImage->LoadOptions = LoadOptions; |
| 896 | } |
| 897 | |
oliviermartin | a355a36 | 2011-06-11 11:56:30 +0000 | [diff] [blame] | 898 | // Before calling the image, enable the Watchdog Timer for the 5 Minute period |
| 899 | gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); |
| 900 | // Start the image |
| 901 | Status = gBS->StartImage (ImageHandle, NULL, NULL); |
| 902 | // Clear the Watchdog Timer after the image returns |
| 903 | gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); |
| 904 | |
| 905 | return Status; |
andrewfish | 1bfda05 | 2011-02-02 22:35:30 +0000 | [diff] [blame] | 906 | } |