ArmPlatformPkg/Bds: Corrected boot type detection
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOptionSupport.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
55a9f75d 3* Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
ea46ebbe 4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
17#include <Library/NetLib.h>\r
18\r
19#include <Protocol/BlockIo.h>\r
20#include <Protocol/DevicePathToText.h>\r
21#include <Protocol/PxeBaseCode.h>\r
22#include <Protocol/SimpleFileSystem.h>\r
23#include <Protocol/SimpleNetwork.h>\r
24\r
25#include <Guid/FileSystemInfo.h>\r
26\r
27#define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))\r
28\r
29EFI_STATUS\r
30BdsLoadOptionFileSystemList (\r
31 IN OUT LIST_ENTRY* BdsLoadOptionList\r
32 );\r
33\r
34EFI_STATUS\r
35BdsLoadOptionFileSystemCreateDevicePath (\r
22a262c8 36 IN CHAR16* FileName,\r
889ac6a8 37 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 38 );\r
39\r
40EFI_STATUS\r
41BdsLoadOptionFileSystemUpdateDevicePath (\r
22a262c8 42 IN EFI_DEVICE_PATH *OldDevicePath,\r
43 IN CHAR16* FileName,\r
889ac6a8 44 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 45 );\r
46\r
47BOOLEAN\r
48BdsLoadOptionFileSystemIsSupported (\r
22a262c8 49 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 50 );\r
51\r
52EFI_STATUS\r
53BdsLoadOptionMemMapList (\r
54 IN OUT LIST_ENTRY* BdsLoadOptionList\r
55 );\r
56\r
57EFI_STATUS\r
58BdsLoadOptionMemMapCreateDevicePath (\r
22a262c8 59 IN CHAR16* FileName,\r
889ac6a8 60 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 61 );\r
62\r
63EFI_STATUS\r
64BdsLoadOptionMemMapUpdateDevicePath (\r
22a262c8 65 IN EFI_DEVICE_PATH *OldDevicePath,\r
66 IN CHAR16* FileName,\r
889ac6a8 67 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 68 );\r
69\r
70BOOLEAN\r
71BdsLoadOptionMemMapIsSupported (\r
22a262c8 72 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 73 );\r
74\r
75EFI_STATUS\r
76BdsLoadOptionPxeList (\r
77 IN OUT LIST_ENTRY* BdsLoadOptionList\r
78 );\r
79\r
80EFI_STATUS\r
81BdsLoadOptionPxeCreateDevicePath (\r
22a262c8 82 IN CHAR16* FileName,\r
889ac6a8 83 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 84 );\r
85\r
86EFI_STATUS\r
87BdsLoadOptionPxeUpdateDevicePath (\r
22a262c8 88 IN EFI_DEVICE_PATH *OldDevicePath,\r
89 IN CHAR16* FileName,\r
889ac6a8 90 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 91 );\r
92\r
93BOOLEAN\r
94BdsLoadOptionPxeIsSupported (\r
22a262c8 95 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 96 );\r
97\r
98EFI_STATUS\r
99BdsLoadOptionTftpList (\r
100 IN OUT LIST_ENTRY* BdsLoadOptionList\r
101 );\r
102\r
103EFI_STATUS\r
104BdsLoadOptionTftpCreateDevicePath (\r
22a262c8 105 IN CHAR16* FileName,\r
889ac6a8 106 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 107 );\r
108\r
109EFI_STATUS\r
110BdsLoadOptionTftpUpdateDevicePath (\r
22a262c8 111 IN EFI_DEVICE_PATH *OldDevicePath,\r
112 IN CHAR16* FileName,\r
889ac6a8 113 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 114 );\r
115\r
116BOOLEAN\r
117BdsLoadOptionTftpIsSupported (\r
22a262c8 118 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 119 );\r
120\r
121BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {\r
2ccfb71e 122 {\r
123 BDS_DEVICE_FILESYSTEM,\r
124 BdsLoadOptionFileSystemList,\r
125 BdsLoadOptionFileSystemIsSupported,\r
126 BdsLoadOptionFileSystemCreateDevicePath,\r
889ac6a8
RC
127 BdsLoadOptionFileSystemUpdateDevicePath,\r
128 TRUE\r
2ccfb71e 129 },\r
130 {\r
131 BDS_DEVICE_MEMMAP,\r
132 BdsLoadOptionMemMapList,\r
133 BdsLoadOptionMemMapIsSupported,\r
134 BdsLoadOptionMemMapCreateDevicePath,\r
889ac6a8
RC
135 BdsLoadOptionMemMapUpdateDevicePath,\r
136 TRUE\r
2ccfb71e 137 },\r
138 {\r
139 BDS_DEVICE_PXE,\r
140 BdsLoadOptionPxeList,\r
141 BdsLoadOptionPxeIsSupported,\r
142 BdsLoadOptionPxeCreateDevicePath,\r
889ac6a8
RC
143 BdsLoadOptionPxeUpdateDevicePath,\r
144 FALSE\r
2ccfb71e 145 },\r
146 {\r
147 BDS_DEVICE_TFTP,\r
148 BdsLoadOptionTftpList,\r
149 BdsLoadOptionTftpIsSupported,\r
150 BdsLoadOptionTftpCreateDevicePath,\r
889ac6a8
RC
151 BdsLoadOptionTftpUpdateDevicePath,\r
152 TRUE\r
2ccfb71e 153 }\r
ea46ebbe 154};\r
155\r
156EFI_STATUS\r
157BootDeviceListSupportedInit (\r
158 IN OUT LIST_ENTRY *SupportedDeviceList\r
159 )\r
160{\r
161 UINTN Index;\r
162\r
163 // Initialize list of supported devices\r
164 InitializeListHead (SupportedDeviceList);\r
165\r
166 for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {\r
2ccfb71e 167 BdsLoadOptionSupportList[Index].ListDevices (SupportedDeviceList);\r
ea46ebbe 168 }\r
169\r
170 return EFI_SUCCESS;\r
171}\r
172\r
173EFI_STATUS\r
174BootDeviceListSupportedFree (\r
656416bc 175 IN LIST_ENTRY *SupportedDeviceList,\r
176 IN BDS_SUPPORTED_DEVICE *Except\r
ea46ebbe 177 )\r
178{\r
179 LIST_ENTRY *Entry;\r
180 BDS_SUPPORTED_DEVICE* SupportedDevice;\r
181\r
182 Entry = GetFirstNode (SupportedDeviceList);\r
183 while (Entry != SupportedDeviceList) {\r
184 SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
185 Entry = RemoveEntryList (Entry);\r
656416bc 186 if (SupportedDevice != Except) {\r
2ccfb71e 187 FreePool (SupportedDevice);\r
656416bc 188 }\r
ea46ebbe 189 }\r
190\r
191 return EFI_SUCCESS;\r
192}\r
193\r
194EFI_STATUS\r
195BootDeviceGetDeviceSupport (\r
22a262c8 196 IN EFI_DEVICE_PATH *DevicePath,\r
197 OUT BDS_LOAD_OPTION_SUPPORT **DeviceSupport\r
ea46ebbe 198 )\r
199{\r
200 UINTN Index;\r
201\r
202 // Find which supported device is the most appropriate\r
203 for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {\r
22a262c8 204 if (BdsLoadOptionSupportList[Index].IsSupported (DevicePath)) {\r
ea46ebbe 205 *DeviceSupport = &BdsLoadOptionSupportList[Index];\r
206 return EFI_SUCCESS;\r
207 }\r
208 }\r
209\r
210 return EFI_UNSUPPORTED;\r
211}\r
212\r
ea46ebbe 213EFI_STATUS\r
214BootDeviceGetType (\r
55a9f75d 215 IN EFI_DEVICE_PATH* DevicePath,\r
2ccfb71e 216 OUT ARM_BDS_LOADER_TYPE *BootType,\r
ea46ebbe 217 OUT UINT32 *Attributes\r
218 )\r
219{\r
55a9f75d
OM
220 EFI_STATUS Status;\r
221 BOOLEAN IsEfiApp;\r
222 BOOLEAN IsBootLoader;\r
223 BOOLEAN HasFDTSupport;\r
224 CHAR16* FileName;\r
225 EFI_DEVICE_PATH* PrevDevicePathNode;\r
226 EFI_DEVICE_PATH* DevicePathNode;\r
227 EFI_PHYSICAL_ADDRESS Image;\r
228 UINTN FileSize;\r
229 EFI_IMAGE_DOS_HEADER* DosHeader;\r
230 UINTN PeCoffHeaderOffset;\r
231 EFI_IMAGE_NT_HEADERS32* NtHeader;\r
232\r
233 //\r
234 // Check if the last node of the device path is a FilePath node\r
235 //\r
236 PrevDevicePathNode = NULL;\r
237 DevicePathNode = DevicePath;\r
238 while ((DevicePathNode != NULL) && !IsDevicePathEnd (DevicePathNode)) {\r
239 PrevDevicePathNode = DevicePathNode;\r
240 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
241 }\r
242\r
243 if ((PrevDevicePathNode != NULL) &&\r
244 (PrevDevicePathNode->Type == MEDIA_DEVICE_PATH) &&\r
245 (PrevDevicePathNode->SubType == MEDIA_FILEPATH_DP))\r
246 {\r
247 FileName = ((FILEPATH_DEVICE_PATH*)PrevDevicePathNode)->PathName;\r
248 } else {\r
249 FileName = NULL;\r
250 }\r
ea46ebbe 251\r
252 if (FileName == NULL) {\r
253 Print(L"Is an EFI Application? ");\r
254 Status = GetHIInputBoolean (&IsEfiApp);\r
255 if (EFI_ERROR(Status)) {\r
256 return EFI_ABORTED;\r
257 }\r
258 } else if (HasFilePathEfiExtension(FileName)) {\r
259 IsEfiApp = TRUE;\r
260 } else {\r
55a9f75d
OM
261 // Check if the file exist\r
262 Status = BdsLoadImage (DevicePath, AllocateAnyPages, &Image, &FileSize);\r
263 if (!EFI_ERROR (Status)) {\r
264\r
265 DosHeader = (EFI_IMAGE_DOS_HEADER *)(UINTN) Image;\r
266 if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
267 //\r
268 // DOS image header is present,\r
269 // so read the PE header after the DOS image header.\r
270 //\r
271 PeCoffHeaderOffset = DosHeader->e_lfanew;\r
272 } else {\r
273 PeCoffHeaderOffset = 0;\r
274 }\r
275\r
276 //\r
277 // Check PE/COFF image.\r
278 //\r
279 NtHeader = (EFI_IMAGE_NT_HEADERS32 *)(UINTN) (Image + PeCoffHeaderOffset);\r
280 if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
281 IsEfiApp = FALSE;\r
282 } else {\r
283 IsEfiApp = TRUE;\r
284 }\r
285\r
286 // Free memory\r
287 gBS->FreePages (Image, EFI_SIZE_TO_PAGES(FileSize));\r
288 } else {\r
289 // If we did not manage to open it then ask for the type\r
290 Print(L"Is an EFI Application? ");\r
291 Status = GetHIInputBoolean (&IsEfiApp);\r
292 if (EFI_ERROR(Status)) {\r
293 return EFI_ABORTED;\r
294 }\r
295 }\r
ea46ebbe 296 }\r
297\r
298 if (IsEfiApp) {\r
299 Print(L"Is your application is an OS loader? ");\r
300 Status = GetHIInputBoolean (&IsBootLoader);\r
301 if (EFI_ERROR(Status)) {\r
302 return EFI_ABORTED;\r
303 }\r
304 if (!IsBootLoader) {\r
305 *Attributes |= LOAD_OPTION_CATEGORY_APP;\r
306 }\r
307 *BootType = BDS_LOADER_EFI_APPLICATION;\r
308 } else {\r
309 Print(L"Has FDT support? ");\r
310 Status = GetHIInputBoolean (&HasFDTSupport);\r
311 if (EFI_ERROR(Status)) {\r
312 return EFI_ABORTED;\r
313 }\r
314 if (HasFDTSupport) {\r
315 *BootType = BDS_LOADER_KERNEL_LINUX_FDT;\r
316 } else {\r
317 *BootType = BDS_LOADER_KERNEL_LINUX_ATAG;\r
318 }\r
319 }\r
320\r
321 return EFI_SUCCESS;\r
322}\r
323\r
324EFI_STATUS\r
325BdsLoadOptionFileSystemList (\r
326 IN OUT LIST_ENTRY* BdsLoadOptionList\r
327 )\r
328{\r
329 EFI_STATUS Status;\r
330 UINTN HandleCount;\r
331 EFI_HANDLE *HandleBuffer;\r
332 UINTN Index;\r
333 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
334 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileProtocol;\r
335 EFI_FILE_HANDLE Fs;\r
336 UINTN Size;\r
337 EFI_FILE_SYSTEM_INFO* FsInfo;\r
338 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
339\r
340 // List all the Simple File System Protocols\r
341 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
342 if (EFI_ERROR (Status)) {\r
343 return Status;\r
344 }\r
345\r
346 for (Index = 0; Index < HandleCount; Index++) {\r
347 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
348 if (!EFI_ERROR(Status)) {\r
349 // Allocate BDS Supported Device structure\r
2ccfb71e 350 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE));\r
ea46ebbe 351\r
352 FileProtocol = NULL;\r
353 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileProtocol);\r
354 ASSERT_EFI_ERROR(Status);\r
355\r
356 FileProtocol->OpenVolume (FileProtocol, &Fs);\r
357\r
358 // Generate a Description from the file system\r
359 Size = 0;\r
360 FsInfo = NULL;\r
361 Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);\r
362 if (Status == EFI_BUFFER_TOO_SMALL) {\r
363 FsInfo = AllocatePool (Size);\r
364 Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);\r
365 }\r
366 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"%s (%d MB)",FsInfo->VolumeLabel,(UINT32)(FsInfo->VolumeSize / (1024 * 1024)));\r
367 FreePool(FsInfo);\r
368 Fs->Close (Fs);\r
369\r
370 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
371 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_FILESYSTEM];\r
372\r
373 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
374 }\r
375 }\r
376\r
377 return EFI_SUCCESS;\r
378}\r
379\r
380EFI_STATUS\r
381BdsLoadOptionFileSystemCreateDevicePath (\r
22a262c8 382 IN CHAR16* FileName,\r
889ac6a8 383 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 384 )\r
385{\r
386 EFI_STATUS Status;\r
387 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
74b96132 388 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
ea46ebbe 389 UINTN BootFilePathSize;\r
390\r
22a262c8 391 Print(L"File path of the %s: ", FileName);\r
74b96132 392 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
ea46ebbe 393 if (EFI_ERROR(Status)) {\r
394 return EFI_ABORTED;\r
395 }\r
396\r
74b96132 397 BootFilePathSize = StrSize (BootFilePath);\r
398 if (BootFilePathSize == 2) {\r
ecc62d13 399 *DevicePathNodes = NULL;\r
656416bc 400 return EFI_NOT_FOUND;\r
401 }\r
402\r
ea46ebbe 403 // Create the FilePath Device Path node\r
ecc62d13 404 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);\r
ea46ebbe 405 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
406 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
407 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
408 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
ecc62d13 409 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));\r
55a9f75d 410 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;\r
ea46ebbe 411\r
412 return Status;\r
413}\r
414\r
415EFI_STATUS\r
416BdsLoadOptionFileSystemUpdateDevicePath (\r
22a262c8 417 IN EFI_DEVICE_PATH *OldDevicePath,\r
418 IN CHAR16* FileName,\r
889ac6a8 419 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 420 )\r
421{\r
422 EFI_STATUS Status;\r
74b96132 423 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
ea46ebbe 424 UINTN BootFilePathSize;\r
425 FILEPATH_DEVICE_PATH* EndingDevicePath;\r
426 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
427 EFI_DEVICE_PATH* DevicePath;\r
428\r
0db25ccc 429 DevicePath = DuplicateDevicePath (OldDevicePath);\r
ea46ebbe 430\r
656416bc 431 EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);\r
432 \r
22a262c8 433 Print(L"File path of the %s: ", FileName);\r
74b96132 434 StrnCpy (BootFilePath, EndingDevicePath->PathName, BOOT_DEVICE_FILEPATH_MAX);\r
435 Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
ea46ebbe 436 if (EFI_ERROR(Status)) {\r
437 return Status;\r
438 }\r
439\r
74b96132 440 BootFilePathSize = StrSize(BootFilePath);\r
441 if (BootFilePathSize == 2) {\r
656416bc 442 *NewDevicePath = NULL;\r
443 return EFI_NOT_FOUND;\r
444 }\r
445\r
ea46ebbe 446 // Create the FilePath Device Path node\r
447 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
448 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
449 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
450 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
451 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
ea46ebbe 452\r
453 // Generate the new Device Path by replacing the last node by the updated node\r
454 SetDevicePathEndNode (EndingDevicePath);\r
455 *NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath);\r
456 FreePool(DevicePath);\r
457\r
656416bc 458 return EFI_SUCCESS;\r
ea46ebbe 459}\r
460\r
22a50a13
RC
461/**\r
462 Check if a boot option path is a file system boot option path or not.\r
463\r
464 The device specified by the beginning of the path has to support the Simple File\r
465 System protocol. Furthermore, the remaining part of the path has to be composed of\r
466 a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP.\r
467\r
468 @param[in] DevicePath Complete device path of a boot option.\r
469\r
470 @retval FALSE The boot option path has not been identified as that of a\r
471 file system boot option.\r
472 @retval TRUE The boot option path is a file system boot option.\r
473**/\r
ea46ebbe 474BOOLEAN\r
475BdsLoadOptionFileSystemIsSupported (\r
22a50a13 476 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 477 )\r
478{\r
22a50a13
RC
479 EFI_STATUS Status;\r
480 EFI_HANDLE Handle;\r
481 EFI_DEVICE_PATH *RemainingDevicePath;\r
482 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileProtocol;\r
ea46ebbe 483\r
22a50a13
RC
484 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
485 if (EFI_ERROR (Status)) {\r
486 return FALSE;\r
487 }\r
488\r
489 Status = gBS->HandleProtocol (\r
490 Handle,\r
491 &gEfiSimpleFileSystemProtocolGuid,\r
492 (VOID **)(&FileProtocol)\r
493 );\r
494 if (EFI_ERROR (Status)) {\r
495 return FALSE;\r
496 }\r
ea46ebbe 497\r
22a50a13
RC
498 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP))\r
499 return FALSE;\r
500\r
501 return TRUE;\r
ea46ebbe 502}\r
503\r
504STATIC\r
505BOOLEAN\r
506IsParentDevicePath (\r
507 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
508 IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath\r
509 )\r
510{\r
511 UINTN ParentSize;\r
512 UINTN ChildSize;\r
513\r
514 ParentSize = GetDevicePathSize (ParentDevicePath);\r
515 ChildSize = GetDevicePathSize (ChildDevicePath);\r
516\r
517 if (ParentSize > ChildSize) {\r
518 return FALSE;\r
519 }\r
520\r
521 if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {\r
522 return FALSE;\r
523 }\r
524\r
525 return TRUE;\r
526}\r
527\r
528EFI_STATUS\r
529BdsLoadOptionMemMapList (\r
530 IN OUT LIST_ENTRY* BdsLoadOptionList\r
531 )\r
532{\r
533 EFI_STATUS Status;\r
534 UINTN HandleCount;\r
535 EFI_HANDLE *HandleBuffer;\r
536 UINTN DevicePathHandleCount;\r
537 EFI_HANDLE *DevicePathHandleBuffer;\r
538 BOOLEAN IsParent;\r
539 UINTN Index;\r
540 UINTN Index2;\r
541 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
542 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
543 EFI_DEVICE_PATH* DevicePath;\r
544\r
545 // List all the BlockIo Protocols\r
546 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
547 if (EFI_ERROR (Status)) {\r
548 return Status;\r
549 }\r
550\r
551 for (Index = 0; Index < HandleCount; Index++) {\r
552 // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)\r
553 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
554 if (!EFI_ERROR(Status)) {\r
555 // BlockIo is not part of Media Device Path\r
556 DevicePath = DevicePathProtocol;\r
557 while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {\r
558 DevicePath = NextDevicePathNode (DevicePath);\r
559 }\r
560 if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {\r
561 continue;\r
562 }\r
563\r
564 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child\r
565 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);\r
566 ASSERT_EFI_ERROR (Status);\r
567 IsParent = FALSE;\r
568 for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {\r
569 if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {\r
570 gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);\r
571 if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {\r
572 IsParent = TRUE;\r
573 }\r
574 }\r
575 }\r
576 if (IsParent) {\r
577 continue;\r
578 }\r
579\r
580 // Allocate BDS Supported Device structure\r
581 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
582\r
583 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);\r
584 ASSERT_EFI_ERROR (Status);\r
585\r
586 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
587 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];\r
588\r
589 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
590 }\r
591 }\r
592\r
593 return EFI_SUCCESS;\r
594}\r
595\r
596EFI_STATUS\r
597BdsLoadOptionMemMapCreateDevicePath (\r
22a262c8 598 IN CHAR16* FileName,\r
889ac6a8 599 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 600 )\r
601{\r
22a262c8 602 EFI_STATUS Status;\r
603 MEMMAP_DEVICE_PATH *MemMapDevicePath;\r
604 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
605 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
ea46ebbe 606\r
22a262c8 607 Print(L"Starting Address of the %s: ", FileName);\r
608 Status = GetHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
ea46ebbe 609 if (EFI_ERROR(Status)) {\r
610 return EFI_ABORTED;\r
611 }\r
612\r
22a262c8 613 Print(L"Ending Address of the %s: ", FileName);\r
614 Status = GetHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
ea46ebbe 615 if (EFI_ERROR(Status)) {\r
616 return EFI_ABORTED;\r
617 }\r
618\r
619 // Create the MemMap Device Path Node\r
22a262c8 620 MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);\r
ea46ebbe 621 MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;\r
622 MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;\r
22a262c8 623 SetDevicePathNodeLength (MemMapDevicePath, sizeof(MEMMAP_DEVICE_PATH));\r
ea46ebbe 624 MemMapDevicePath->MemoryType = EfiBootServicesData;\r
74b96132 625 MemMapDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);\r
626 MemMapDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);\r
ea46ebbe 627\r
22a262c8 628 // Set a Device Path End Node after the Memory Map Device Path Node\r
629 SetDevicePathEndNode (MemMapDevicePath + 1);\r
55a9f75d 630 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;\r
ea46ebbe 631\r
632 return Status;\r
633}\r
634\r
635EFI_STATUS\r
636BdsLoadOptionMemMapUpdateDevicePath (\r
22a262c8 637 IN EFI_DEVICE_PATH *OldDevicePath,\r
638 IN CHAR16* FileName,\r
889ac6a8 639 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 640 )\r
641{\r
6bab33c7 642 EFI_STATUS Status;\r
74b96132 643 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
644 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
6bab33c7 645 MEMMAP_DEVICE_PATH* EndingDevicePath;\r
646 EFI_DEVICE_PATH* DevicePath;\r
647\r
656416bc 648 DevicePath = DuplicateDevicePath (OldDevicePath);\r
6bab33c7 649 EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);\r
650\r
22a262c8 651 Print(L"Starting Address of the %s: ", FileName);\r
74b96132 652 UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress);\r
653 Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
6bab33c7 654 if (EFI_ERROR(Status)) {\r
655 return EFI_ABORTED;\r
656 }\r
657\r
22a262c8 658 Print(L"Ending Address of the %s: ", FileName);\r
74b96132 659 UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress);\r
660 Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
6bab33c7 661 if (EFI_ERROR(Status)) {\r
662 return EFI_ABORTED;\r
663 }\r
664\r
74b96132 665 EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);\r
666 EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);\r
6bab33c7 667\r
6bab33c7 668 if (EFI_ERROR(Status)) {\r
669 FreePool(DevicePath);\r
670 } else {\r
671 *NewDevicePath = DevicePath;\r
672 }\r
673\r
674 return Status;\r
ea46ebbe 675}\r
676\r
22a50a13
RC
677/**\r
678 Check if a boot option path is a memory map boot option path or not.\r
679\r
680 The device specified by the beginning of the path has to support the BlockIo\r
681 protocol. Furthermore, the remaining part of the path has to be composed of\r
682 a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP.\r
683\r
684 @param[in] DevicePath Complete device path of a boot option.\r
685\r
686 @retval FALSE The boot option path has not been identified as that of a\r
687 memory map boot option.\r
688 @retval TRUE The boot option path is a a memory map boot option.\r
689**/\r
ea46ebbe 690BOOLEAN\r
691BdsLoadOptionMemMapIsSupported (\r
22a50a13 692 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 693 )\r
694{\r
22a50a13
RC
695 EFI_STATUS Status;\r
696 EFI_HANDLE Handle;\r
697 EFI_DEVICE_PATH *RemainingDevicePath;\r
698 EFI_BLOCK_IO_PROTOCOL *BlockIoProtocol;\r
699\r
700 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
701 if (EFI_ERROR (Status)) {\r
702 return FALSE;\r
703 }\r
ea46ebbe 704\r
22a50a13
RC
705 Status = gBS->HandleProtocol (\r
706 Handle,\r
707 &gEfiBlockIoProtocolGuid,\r
708 (VOID **)(&BlockIoProtocol)\r
709 );\r
710 if (EFI_ERROR (Status)) {\r
711 return FALSE;\r
712 }\r
ea46ebbe 713\r
22a50a13
RC
714 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP))\r
715 return FALSE;\r
716\r
717 return TRUE;\r
ea46ebbe 718}\r
719\r
720EFI_STATUS\r
721BdsLoadOptionPxeList (\r
722 IN OUT LIST_ENTRY* BdsLoadOptionList\r
723 )\r
724{\r
725 EFI_STATUS Status;\r
726 UINTN HandleCount;\r
727 EFI_HANDLE *HandleBuffer;\r
728 UINTN Index;\r
729 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
730 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
731 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;\r
732 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
733 EFI_MAC_ADDRESS *Mac;\r
734\r
735 // List all the PXE Protocols\r
736 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
737 if (EFI_ERROR (Status)) {\r
738 return Status;\r
739 }\r
740\r
741 for (Index = 0; Index < HandleCount; Index++) {\r
742 // We only select the handle WITH a Device Path AND the PXE Protocol\r
743 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
744 if (!EFI_ERROR(Status)) {\r
745 // Allocate BDS Supported Device structure\r
746 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
747\r
748 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);\r
749 if (!EFI_ERROR(Status)) {\r
750 Mac = &SimpleNet->Mode->CurrentAddress;\r
751 UnicodeSPrint (DeviceDescription,BOOT_DEVICE_DESCRIPTION_MAX,L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac->Addr[0], Mac->Addr[1], Mac->Addr[2], Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]);\r
752 } else {\r
753 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);\r
754 ASSERT_EFI_ERROR (Status);\r
755 }\r
756 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);\r
757\r
758 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
759 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];\r
760\r
761 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
762 }\r
763 }\r
764\r
765 return EFI_SUCCESS;\r
766}\r
767\r
768EFI_STATUS\r
769BdsLoadOptionPxeCreateDevicePath (\r
22a262c8 770 IN CHAR16* FileName,\r
889ac6a8 771 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 772 )\r
773{\r
ecc62d13 774 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);\r
775 SetDevicePathEndNode (*DevicePathNodes);\r
55a9f75d 776\r
ea46ebbe 777 return EFI_SUCCESS;\r
778}\r
779\r
2db16368
RC
780/**\r
781 Update the parameters of a Pxe boot option\r
782\r
783 @param[in] OldDevicePath Current complete device path of the Pxe boot option.\r
784 This has to be a valid complete Pxe boot option path.\r
785 @param[in] FileName Description of the file the path is asked for\r
786 @param[out] NewDevicePath Pointer to the new complete device path.\r
787\r
788 @retval EFI_SUCCESS Update completed\r
789 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource\r
790**/\r
ea46ebbe 791EFI_STATUS\r
792BdsLoadOptionPxeUpdateDevicePath (\r
22a262c8 793 IN EFI_DEVICE_PATH *OldDevicePath,\r
794 IN CHAR16* FileName,\r
889ac6a8 795 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 796 )\r
797{\r
2db16368
RC
798 //\r
799 // Make a copy of the complete device path that is made of :\r
800 // the device path of the device supporting the Pxe base code protocol\r
801 // followed by an end node.\r
802 //\r
803 *NewDevicePath = DuplicateDevicePath (OldDevicePath);\r
804 if (*NewDevicePath == NULL) {\r
805 return EFI_OUT_OF_RESOURCES;\r
806 } else {\r
807 return EFI_SUCCESS;\r
808 }\r
ea46ebbe 809}\r
810\r
811BOOLEAN\r
812BdsLoadOptionPxeIsSupported (\r
22a50a13 813 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 814 )\r
815{\r
816 EFI_STATUS Status;\r
817 EFI_HANDLE Handle;\r
818 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
819 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
820\r
22a262c8 821 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
ea46ebbe 822 if (EFI_ERROR(Status)) {\r
823 return FALSE;\r
824 }\r
825\r
826 if (!IsDevicePathEnd(RemainingDevicePath)) {\r
827 return FALSE;\r
828 }\r
829\r
830 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
831 if (EFI_ERROR (Status)) {\r
832 return FALSE;\r
833 } else {\r
834 return TRUE;\r
835 }\r
836}\r
837\r
838EFI_STATUS\r
839BdsLoadOptionTftpList (\r
840 IN OUT LIST_ENTRY* BdsLoadOptionList\r
841 )\r
842{\r
843 EFI_STATUS Status;\r
844 UINTN HandleCount;\r
845 EFI_HANDLE *HandleBuffer;\r
846 UINTN Index;\r
847 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
848 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
849 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;\r
850 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
851 EFI_MAC_ADDRESS *Mac;\r
852\r
853 // List all the PXE Protocols\r
854 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
855 if (EFI_ERROR (Status)) {\r
856 return Status;\r
857 }\r
858\r
859 for (Index = 0; Index < HandleCount; Index++) {\r
860 // We only select the handle WITH a Device Path AND the PXE Protocol AND the TFTP Protocol (the TFTP protocol is required to start PXE)\r
861 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
862 if (!EFI_ERROR(Status)) {\r
863 // Allocate BDS Supported Device structure\r
864 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
865\r
866 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);\r
867 if (!EFI_ERROR(Status)) {\r
868 Mac = &SimpleNet->Mode->CurrentAddress;\r
869 UnicodeSPrint (DeviceDescription,BOOT_DEVICE_DESCRIPTION_MAX,L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac->Addr[0], Mac->Addr[1], Mac->Addr[2], Mac->Addr[3], Mac->Addr[4], Mac->Addr[5]);\r
870 } else {\r
871 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);\r
872 ASSERT_EFI_ERROR (Status);\r
873 }\r
b34e4db3 874 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFTP on %s",DeviceDescription);\r
ea46ebbe 875\r
876 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
877 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];\r
878\r
879 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
880 }\r
881 }\r
882\r
883 return EFI_SUCCESS;\r
884}\r
885\r
886EFI_STATUS\r
887BdsLoadOptionTftpCreateDevicePath (\r
22a262c8 888 IN CHAR16* FileName,\r
889ac6a8 889 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
ea46ebbe 890 )\r
891{\r
892 EFI_STATUS Status;\r
893 BOOLEAN IsDHCP;\r
894 EFI_IP_ADDRESS LocalIp;\r
895 EFI_IP_ADDRESS RemoteIp;\r
896 IPv4_DEVICE_PATH* IPv4DevicePathNode;\r
897 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
74b96132 898 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
ea46ebbe 899 UINTN BootFilePathSize;\r
900\r
901 Print(L"Get the IP address from DHCP: ");\r
902 Status = GetHIInputBoolean (&IsDHCP);\r
903 if (EFI_ERROR(Status)) {\r
904 return EFI_ABORTED;\r
905 }\r
906\r
907 if (!IsDHCP) {\r
908 Print(L"Get the static IP address: ");\r
909 Status = GetHIInputIP (&LocalIp);\r
910 if (EFI_ERROR(Status)) {\r
911 return EFI_ABORTED;\r
912 }\r
913 }\r
914\r
915 Print(L"Get the TFTP server IP address: ");\r
916 Status = GetHIInputIP (&RemoteIp);\r
917 if (EFI_ERROR(Status)) {\r
918 return EFI_ABORTED;\r
919 }\r
920\r
22a262c8 921 Print(L"File path of the %s : ", FileName);\r
74b96132 922 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
ea46ebbe 923 if (EFI_ERROR(Status)) {\r
924 return EFI_ABORTED;\r
925 }\r
926\r
ea46ebbe 927 BootFilePathSize = StrSize(BootFilePath);\r
74b96132 928 if (BootFilePathSize == 2) {\r
929 return EFI_NOT_FOUND;\r
930 }\r
ea46ebbe 931\r
932 // Allocate the memory for the IPv4 + File Path Device Path Nodes\r
ecc62d13 933 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);\r
ea46ebbe 934\r
935 // Create the IPv4 Device Path\r
936 IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;\r
937 IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;\r
938 SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));\r
939 CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
940 CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
941 IPv4DevicePathNode->LocalPort = 0;\r
942 IPv4DevicePathNode->RemotePort = 0;\r
943 IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;\r
944 IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);\r
945\r
946 // Create the FilePath Device Path node\r
947 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
948 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
949 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
950 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
951 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
ea46ebbe 952\r
ecc62d13 953 // Set the End Device Path Node\r
954 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));\r
55a9f75d 955 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;\r
ea46ebbe 956\r
957 return Status;\r
958}\r
959\r
152286ce
RC
960/**\r
961 Update the parameters of a TFTP boot option\r
962\r
963 The function asks sequentially to update the IPv4 parameters as well as the boot file path,\r
964 providing the previously set value if any.\r
965\r
966 @param[in] OldDevicePath Current complete device path of the Tftp boot option.\r
967 This has to be a valid complete Tftp boot option path.\r
968 By complete, we mean that it is not only the Tftp\r
969 specific end part built by the\r
970 "BdsLoadOptionTftpCreateDevicePath()" function.\r
971 This path is handled as read only.\r
972 @param[in] FileName Description of the file the path is asked for\r
973 @param[out] NewDevicePath Pointer to the new complete device path.\r
974\r
975 @retval EFI_SUCCESS Update completed\r
976 @retval EFI_ABORTED Update aborted by the user\r
977 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource\r
978**/\r
ea46ebbe 979EFI_STATUS\r
980BdsLoadOptionTftpUpdateDevicePath (\r
152286ce
RC
981 IN EFI_DEVICE_PATH *OldDevicePath,\r
982 IN CHAR16 *FileName,\r
983 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
ea46ebbe 984 )\r
985{\r
152286ce
RC
986 EFI_STATUS Status;\r
987 EFI_DEVICE_PATH *DevicePath;\r
988 EFI_DEVICE_PATH *DevicePathNode;\r
989 UINT8 *Ipv4NodePtr;\r
990 IPv4_DEVICE_PATH Ipv4Node;\r
991 BOOLEAN IsDHCP;\r
992 EFI_IP_ADDRESS OldIp;\r
993 EFI_IP_ADDRESS LocalIp;\r
994 EFI_IP_ADDRESS RemoteIp;\r
995 UINT8 *FileNodePtr;\r
996 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
997 UINTN PathSize;\r
998 UINTN BootFilePathSize;\r
999 FILEPATH_DEVICE_PATH *NewFilePathNode;\r
1000\r
1001 Ipv4NodePtr = NULL;\r
1002\r
1003 //\r
1004 // Make a copy of the complete device path that is made of :\r
1005 // the device path of the device that support the Simple Network protocol\r
1006 // followed by an IPv4 node (type IPv4_DEVICE_PATH),\r
1007 // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up\r
1008 // by an end node. The IPv6 case is not handled yet.\r
1009 //\r
1010\r
1011 DevicePath = DuplicateDevicePath (OldDevicePath);\r
1012 if (DevicePath == NULL) {\r
1013 Status = EFI_OUT_OF_RESOURCES;\r
1014 goto ErrorExit;\r
1015 }\r
1016\r
1017 //\r
1018 // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the\r
1019 // call to this function, we know that the device path ends with an IPv4 node\r
1020 // followed by a file path node and finally an end node. To get the address of\r
1021 // the last IPv4 node, we loop over the whole device path, noting down the\r
1022 // address of each encountered IPv4 node.\r
1023 //\r
1024\r
1025 for (DevicePathNode = DevicePath;\r
1026 !IsDevicePathEnd (DevicePathNode);\r
1027 DevicePathNode = NextDevicePathNode (DevicePathNode))\r
1028 {\r
1029 if (IS_DEVICE_PATH_NODE (DevicePathNode, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)) {\r
1030 Ipv4NodePtr = (UINT8*)DevicePathNode;\r
1031 }\r
1032 }\r
1033\r
1034 // Copy for alignment of the IPv4 node data\r
1035 CopyMem (&Ipv4Node, Ipv4NodePtr, sizeof (IPv4_DEVICE_PATH));\r
1036\r
1037 Print (L"Get the IP address from DHCP: ");\r
1038 Status = GetHIInputBoolean (&IsDHCP);\r
1039 if (EFI_ERROR (Status)) {\r
1040 goto ErrorExit;\r
1041 }\r
1042\r
1043 if (!IsDHCP) {\r
1044 Print (L"Local static IP address: ");\r
1045 if (Ipv4Node.StaticIpAddress) {\r
1046 // Copy local IPv4 address into IPv4 or IPv6 union\r
1047 CopyMem (&OldIp.v4, &Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
1048\r
1049 Status = EditHIInputIP (&OldIp, &LocalIp);\r
1050 } else {\r
1051 Status = GetHIInputIP (&LocalIp);\r
1052 }\r
1053 if (EFI_ERROR (Status)) {\r
1054 goto ErrorExit;\r
1055 }\r
1056 }\r
1057\r
1058 Print (L"TFTP server IP address: ");\r
1059 // Copy remote IPv4 address into IPv4 or IPv6 union\r
1060 CopyMem (&OldIp.v4, &Ipv4Node.RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
1061\r
1062 Status = EditHIInputIP (&OldIp, &RemoteIp);\r
1063 if (EFI_ERROR (Status)) {\r
1064 goto ErrorExit;\r
1065 }\r
1066\r
1067 // Get the path of the boot file and its size in number of bytes\r
1068 FileNodePtr = Ipv4NodePtr + sizeof (IPv4_DEVICE_PATH);\r
1069 BootFilePathSize = DevicePathNodeLength (FileNodePtr) - SIZE_OF_FILEPATH_DEVICE_PATH;\r
1070\r
1071 //\r
1072 // Ask for update of the boot file path\r
1073 //\r
1074 do {\r
1075 // Copy for 2-byte alignment of the Unicode string\r
1076 CopyMem (\r
1077 BootFilePath, FileNodePtr + SIZE_OF_FILEPATH_DEVICE_PATH,\r
1078 MIN (BootFilePathSize, BOOT_DEVICE_FILEPATH_MAX)\r
1079 );\r
1080 BootFilePath[BOOT_DEVICE_FILEPATH_MAX - 1] = L'\0';\r
1081\r
1082 Print (L"File path of the %s: ", FileName);\r
1083 Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
1084 if (EFI_ERROR (Status)) {\r
1085 goto ErrorExit;\r
1086 }\r
1087 PathSize = StrSize (BootFilePath);\r
1088 if (PathSize > 2) {\r
1089 break;\r
1090 }\r
1091 // Empty string, give the user another try\r
1092 Print (L"Empty string - Invalid path\n");\r
1093 } while (PathSize <= 2) ;\r
1094\r
1095 //\r
1096 // Update the IPv4 node. IPv6 case not handled yet.\r
1097 //\r
1098 if (IsDHCP == TRUE) {\r
1099 Ipv4Node.StaticIpAddress = FALSE;\r
1100 } else {\r
1101 Ipv4Node.StaticIpAddress = TRUE;\r
1102 }\r
1103 CopyMem (&Ipv4Node.LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
1104 CopyMem (&Ipv4Node.RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
1105 CopyMem (Ipv4NodePtr, &Ipv4Node, sizeof (IPv4_DEVICE_PATH));\r
1106\r
1107 //\r
1108 // Create the new file path node\r
1109 //\r
1110 NewFilePathNode = (FILEPATH_DEVICE_PATH*)AllocatePool (\r
1111 SIZE_OF_FILEPATH_DEVICE_PATH +\r
1112 PathSize\r
1113 );\r
1114 NewFilePathNode->Header.Type = MEDIA_DEVICE_PATH;\r
1115 NewFilePathNode->Header.SubType = MEDIA_FILEPATH_DP;\r
1116 SetDevicePathNodeLength (\r
1117 NewFilePathNode,\r
1118 SIZE_OF_FILEPATH_DEVICE_PATH + PathSize\r
1119 );\r
1120 CopyMem (NewFilePathNode->PathName, BootFilePath, PathSize);\r
1121\r
1122 //\r
1123 // Generate the new Device Path by replacing the file path node at address\r
1124 // "FileNodePtr" by the new one "NewFilePathNode" and return its address.\r
1125 //\r
1126 SetDevicePathEndNode (FileNodePtr);\r
1127 *NewDevicePath = AppendDevicePathNode (\r
1128 DevicePath,\r
1129 (CONST EFI_DEVICE_PATH_PROTOCOL*)NewFilePathNode\r
1130 );\r
1131\r
1132ErrorExit:\r
1133 if (DevicePath != NULL) {\r
1134 FreePool (DevicePath) ;\r
1135 }\r
1136\r
1137 return Status;\r
ea46ebbe 1138}\r
1139\r
1140BOOLEAN\r
1141BdsLoadOptionTftpIsSupported (\r
22a262c8 1142 IN EFI_DEVICE_PATH *DevicePath\r
ea46ebbe 1143 )\r
1144{\r
1145 EFI_STATUS Status;\r
1146 EFI_HANDLE Handle;\r
1147 EFI_DEVICE_PATH *RemainingDevicePath;\r
1148 EFI_DEVICE_PATH *NextDevicePath;\r
1149 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
1150\r
22a262c8 1151 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
ea46ebbe 1152 if (EFI_ERROR(Status)) {\r
1153 return FALSE;\r
1154 }\r
1155\r
1156 // Validate the Remaining Device Path\r
1157 if (IsDevicePathEnd(RemainingDevicePath)) {\r
1158 return FALSE;\r
1159 }\r
1160 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&\r
1161 !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {\r
1162 return FALSE;\r
1163 }\r
1164 NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
1165 if (IsDevicePathEnd(NextDevicePath)) {\r
1166 return FALSE;\r
1167 }\r
1168 if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {\r
1169 return FALSE;\r
1170 }\r
1171\r
1172 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
1173 if (EFI_ERROR (Status)) {\r
1174 return FALSE;\r
1175 } else {\r
1176 return TRUE;\r
1177 }\r
1178}\r