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