]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/Ventoy.c
issue #710
[Ventoy.git] / EDK2 / edk2_mod / edk2-edk2-stable201911 / MdeModulePkg / Application / Ventoy / Ventoy.c
1 /******************************************************************************
2 * Ventoy.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <Uefi.h>
22 #include <Library/DebugLib.h>
23 #include <Library/PrintLib.h>
24 #include <Library/UefiLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/DevicePathLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/UefiApplicationEntryPoint.h>
31 #include <Protocol/LoadedImage.h>
32 #include <Guid/FileInfo.h>
33 #include <Guid/FileSystemInfo.h>
34 #include <Protocol/BlockIo.h>
35 #include <Protocol/RamDisk.h>
36 #include <Protocol/SimpleFileSystem.h>
37 #include <Ventoy.h>
38
39 BOOLEAN gDebugPrint = FALSE;
40 BOOLEAN gDotEfiBoot = FALSE;
41 BOOLEAN gLoadIsoEfi = FALSE;
42 BOOLEAN gIsoUdf = FALSE;
43 ventoy_ram_disk g_ramdisk_param;
44 ventoy_chain_head *g_chain;
45 ventoy_img_chunk *g_chunk;
46 UINT8 *g_os_param_reserved;
47 UINT32 g_img_chunk_num;
48 ventoy_override_chunk *g_override_chunk;
49 UINT32 g_override_chunk_num;
50 ventoy_virt_chunk *g_virt_chunk;
51 UINT32 g_virt_chunk_num;
52 vtoy_block_data gBlockData;
53 static grub_env_get_pf grub_env_get = NULL;
54 static grub_env_set_pf grub_env_set = NULL;
55
56 ventoy_grub_param_file_replace *g_file_replace_list = NULL;
57 ventoy_efi_file_replace g_efi_file_replace;
58
59 CONST CHAR16 gIso9660EfiDriverPath[] = ISO9660_EFI_DRIVER_PATH;
60 CONST CHAR16 gUdfEfiDriverPath[] = UDF_EFI_DRIVER_PATH;
61
62 BOOLEAN g_fix_windows_1st_cdrom_issue = FALSE;
63
64 STATIC BOOLEAN g_hook_keyboard = FALSE;
65
66 CHAR16 gFirstTryBootFile[256] = {0};
67
68 /* Boot filename */
69 UINTN gBootFileStartIndex = 1;
70 CONST CHAR16 *gEfiBootFileName[] =
71 {
72 L"@",
73 EFI_REMOVABLE_MEDIA_FILE_NAME,
74 #if defined (MDE_CPU_IA32)
75 L"\\EFI\\BOOT\\GRUBIA32.EFI",
76 L"\\EFI\\BOOT\\BOOTia32.EFI",
77 L"\\EFI\\BOOT\\bootia32.efi",
78 L"\\efi\\boot\\bootia32.efi",
79 #elif defined (MDE_CPU_X64)
80 L"\\EFI\\BOOT\\GRUBX64.EFI",
81 L"\\EFI\\BOOT\\BOOTx64.EFI",
82 L"\\EFI\\BOOT\\bootx64.efi",
83 L"\\efi\\boot\\bootx64.efi",
84 #elif defined (MDE_CPU_ARM)
85 L"\\EFI\\BOOT\\GRUBARM.EFI",
86 L"\\EFI\\BOOT\\BOOTarm.EFI",
87 L"\\EFI\\BOOT\\bootarm.efi",
88 L"\\efi\\boot\\bootarm.efi",
89 #elif defined (MDE_CPU_AARCH64)
90 L"\\EFI\\BOOT\\GRUBAA64.EFI",
91 L"\\EFI\\BOOT\\BOOTaa64.EFI",
92 L"\\EFI\\BOOT\\bootaa64.efi",
93 L"\\efi\\boot\\bootaa64.efi",
94 #endif
95
96 };
97
98 VOID EFIAPI VtoyDebug(IN CONST CHAR8 *Format, ...)
99 {
100 VA_LIST Marker;
101 CHAR16 Buffer[512];
102
103 VA_START (Marker, Format);
104 UnicodeVSPrintAsciiFormat(Buffer, sizeof(Buffer), Format, Marker);
105 VA_END (Marker);
106
107 gST->ConOut->OutputString(gST->ConOut, Buffer);
108 }
109
110 VOID EFIAPI ventoy_clear_input(VOID)
111 {
112 EFI_INPUT_KEY Key;
113
114 gST->ConIn->Reset(gST->ConIn, FALSE);
115 while (EFI_SUCCESS == gST->ConIn->ReadKeyStroke(gST->ConIn, &Key))
116 {
117 ;
118 }
119 gST->ConIn->Reset(gST->ConIn, FALSE);
120 }
121
122 static void EFIAPI ventoy_dump_img_chunk(ventoy_chain_head *chain)
123 {
124 UINT32 i;
125 int errcnt = 0;
126 UINT64 img_sec = 0;
127 ventoy_img_chunk *chunk;
128
129 chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset);
130
131 debug("##################### ventoy_dump_img_chunk #######################");
132
133 for (i = 0; i < chain->img_chunk_num; i++)
134 {
135 debug("%2u: [ %u - %u ] <==> [ %llu - %llu ]",
136 i, chunk[i].img_start_sector, chunk[i].img_end_sector,
137 chunk[i].disk_start_sector, chunk[i].disk_end_sector);
138
139 if (i > 0 && (chunk[i].img_start_sector != chunk[i - 1].img_end_sector + 1))
140 {
141 errcnt++;
142 }
143
144 img_sec += chunk[i].img_end_sector - chunk[i].img_start_sector + 1;
145 }
146
147 if (errcnt == 0 && (img_sec * 2048 == g_chain->real_img_size_in_bytes))
148 {
149 debug("image chunk size check success");
150 }
151 else
152 {
153 debug("image chunk size check failed %d", errcnt);
154 }
155
156 ventoy_debug_pause();
157 }
158
159 static void EFIAPI ventoy_dump_override_chunk(ventoy_chain_head *chain)
160 {
161 UINT32 i;
162 ventoy_override_chunk *chunk;
163
164 chunk = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
165
166 debug("##################### ventoy_dump_override_chunk #######################");
167
168 for (i = 0; i < g_override_chunk_num; i++)
169 {
170 debug("%2u: [ %llu, %u ]", i, chunk[i].img_offset, chunk[i].override_size);
171 }
172
173 ventoy_debug_pause();
174 }
175
176 static void EFIAPI ventoy_dump_virt_chunk(ventoy_chain_head *chain)
177 {
178 UINT32 i;
179 ventoy_virt_chunk *node;
180
181 debug("##################### ventoy_dump_virt_chunk #######################");
182 debug("virt_chunk_offset=%u", chain->virt_chunk_offset);
183 debug("virt_chunk_num=%u", chain->virt_chunk_num);
184
185 node = (ventoy_virt_chunk *)((char *)chain + chain->virt_chunk_offset);
186 for (i = 0; i < chain->virt_chunk_num; i++, node++)
187 {
188 debug("%2u: mem:[ %u, %u, %u ] remap:[ %u, %u, %u ]", i,
189 node->mem_sector_start,
190 node->mem_sector_end,
191 node->mem_sector_offset,
192 node->remap_sector_start,
193 node->remap_sector_end,
194 node->org_sector_start);
195 }
196
197 ventoy_debug_pause();
198 }
199
200 static void EFIAPI ventoy_dump_chain(ventoy_chain_head *chain)
201 {
202 UINT32 i = 0;
203 UINT8 chksum = 0;
204 UINT8 *guid;
205
206 guid = chain->os_param.vtoy_disk_guid;
207 for (i = 0; i < sizeof(ventoy_os_param); i++)
208 {
209 chksum += *((UINT8 *)(&(chain->os_param)) + i);
210 }
211
212 debug("##################### ventoy_dump_chain #######################");
213
214 debug("os_param->chksum=0x%x (%a)", chain->os_param.chksum, chksum ? "FAILED" : "SUCCESS");
215 debug("os_param->vtoy_disk_guid=%02x%02x%02x%02x", guid[0], guid[1], guid[2], guid[3]);
216 debug("os_param->vtoy_disk_size=%llu", chain->os_param.vtoy_disk_size);
217 debug("os_param->vtoy_disk_part_id=%u", chain->os_param.vtoy_disk_part_id);
218 debug("os_param->vtoy_disk_part_type=%u", chain->os_param.vtoy_disk_part_type);
219 debug("os_param->vtoy_img_path=<%a>", chain->os_param.vtoy_img_path);
220 debug("os_param->vtoy_img_size=<%llu>", chain->os_param.vtoy_img_size);
221 debug("os_param->vtoy_img_location_addr=<0x%llx>", chain->os_param.vtoy_img_location_addr);
222 debug("os_param->vtoy_img_location_len=<%u>", chain->os_param.vtoy_img_location_len);
223 debug("os_param->vtoy_reserved=<%u %u %u %u %u>",
224 g_os_param_reserved[0],
225 g_os_param_reserved[1],
226 g_os_param_reserved[2],
227 g_os_param_reserved[3],
228 g_os_param_reserved[4]
229 );
230
231 ventoy_debug_pause();
232
233 debug("chain->disk_drive=0x%x", chain->disk_drive);
234 debug("chain->disk_sector_size=%u", chain->disk_sector_size);
235 debug("chain->real_img_size_in_bytes=%llu", chain->real_img_size_in_bytes);
236 debug("chain->virt_img_size_in_bytes=%llu", chain->virt_img_size_in_bytes);
237 debug("chain->boot_catalog=%u", chain->boot_catalog);
238 debug("chain->img_chunk_offset=%u", chain->img_chunk_offset);
239 debug("chain->img_chunk_num=%u", chain->img_chunk_num);
240 debug("chain->override_chunk_offset=%u", chain->override_chunk_offset);
241 debug("chain->override_chunk_num=%u", chain->override_chunk_num);
242
243 ventoy_debug_pause();
244
245 ventoy_dump_img_chunk(chain);
246 ventoy_dump_override_chunk(chain);
247 ventoy_dump_virt_chunk(chain);
248 }
249
250 static int ventoy_update_image_location(ventoy_os_param *param)
251 {
252 EFI_STATUS Status = EFI_SUCCESS;
253 UINT8 chksum = 0;
254 unsigned int i;
255 unsigned int length;
256 UINTN address = 0;
257 void *buffer = NULL;
258 ventoy_image_location *location = NULL;
259 ventoy_image_disk_region *region = NULL;
260 ventoy_img_chunk *chunk = g_chunk;
261
262 length = sizeof(ventoy_image_location) + (g_img_chunk_num - 1) * sizeof(ventoy_image_disk_region);
263
264 Status = gBS->AllocatePool(EfiRuntimeServicesData, length + 4096 * 2, &buffer);
265 if (EFI_ERROR(Status) || NULL == buffer)
266 {
267 debug("Failed to allocate runtime pool %r\n", Status);
268 return 1;
269 }
270
271 address = (UINTN)buffer;
272
273 if (address % 4096)
274 {
275 address += 4096 - (address % 4096);
276 }
277
278 param->chksum = 0;
279 param->vtoy_img_location_addr = address;
280 param->vtoy_img_location_len = length;
281
282 /* update check sum */
283 for (i = 0; i < sizeof(ventoy_os_param); i++)
284 {
285 chksum += *((UINT8 *)param + i);
286 }
287 param->chksum = (chksum == 0) ? 0 : (UINT8)(0x100 - chksum);
288
289 location = (ventoy_image_location *)(unsigned long)(param->vtoy_img_location_addr);
290 if (NULL == location)
291 {
292 return 0;
293 }
294
295 CopyMem(&location->guid, &param->guid, sizeof(ventoy_guid));
296 location->image_sector_size = gSector512Mode ? 512 : 2048;
297 location->disk_sector_size = g_chain->disk_sector_size;
298 location->region_count = g_img_chunk_num;
299
300 region = location->regions;
301
302 if (gSector512Mode)
303 {
304 for (i = 0; i < g_img_chunk_num; i++)
305 {
306 region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
307 region->image_start_sector = chunk->img_start_sector * 4;
308 region->disk_start_sector = chunk->disk_start_sector;
309 region++;
310 chunk++;
311 }
312 }
313 else
314 {
315 for (i = 0; i < g_img_chunk_num; i++)
316 {
317 region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
318 region->image_start_sector = chunk->img_start_sector;
319 region->disk_start_sector = chunk->disk_start_sector;
320 region++;
321 chunk++;
322 }
323 }
324
325 return 0;
326 }
327
328 EFI_HANDLE EFIAPI ventoy_get_parent_handle(IN EFI_DEVICE_PATH_PROTOCOL *pDevPath)
329 {
330 EFI_HANDLE Handle = NULL;
331 EFI_STATUS Status = EFI_SUCCESS;
332 EFI_DEVICE_PATH_PROTOCOL *pLastNode = NULL;
333 EFI_DEVICE_PATH_PROTOCOL *pCurNode = NULL;
334 EFI_DEVICE_PATH_PROTOCOL *pTmpDevPath = NULL;
335
336 pTmpDevPath = DuplicateDevicePath(pDevPath);
337 if (!pTmpDevPath)
338 {
339 return NULL;
340 }
341
342 pCurNode = pTmpDevPath;
343 while (!IsDevicePathEnd(pCurNode))
344 {
345 pLastNode = pCurNode;
346 pCurNode = NextDevicePathNode(pCurNode);
347 }
348 if (pLastNode)
349 {
350 CopyMem(pLastNode, pCurNode, sizeof(EFI_DEVICE_PATH_PROTOCOL));
351 }
352
353 pCurNode = pTmpDevPath;
354 Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &pCurNode, &Handle);
355 debug("Status:%r Parent Handle:%p DP:%s", Status, Handle, ConvertDevicePathToText(pTmpDevPath, FALSE, FALSE));
356
357 FreePool(pTmpDevPath);
358
359 return Handle;
360 }
361
362 EFI_STATUS EFIAPI ventoy_save_ramdisk_param(VOID)
363 {
364 EFI_STATUS Status = EFI_SUCCESS;
365 EFI_GUID VarGuid = VENTOY_GUID;
366
367 Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
368 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
369 sizeof(g_ramdisk_param), &(g_ramdisk_param));
370 debug("set ramdisk variable %r", Status);
371
372 return Status;
373 }
374
375 EFI_STATUS EFIAPI ventoy_delete_ramdisk_param(VOID)
376 {
377 EFI_STATUS Status = EFI_SUCCESS;
378 EFI_GUID VarGuid = VENTOY_GUID;
379
380 Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
381 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
382 0, NULL);
383 debug("delete efi variable %r", Status);
384
385 return Status;
386 }
387
388
389 EFI_STATUS EFIAPI ventoy_save_variable(VOID)
390 {
391 EFI_STATUS Status = EFI_SUCCESS;
392 EFI_GUID VarGuid = VENTOY_GUID;
393
394 Status = gRT->SetVariable(L"VentoyOsParam", &VarGuid,
395 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
396 sizeof(g_chain->os_param), &(g_chain->os_param));
397 debug("set efi variable %r", Status);
398
399 return Status;
400 }
401
402 EFI_STATUS EFIAPI ventoy_delete_variable(VOID)
403 {
404 EFI_STATUS Status = EFI_SUCCESS;
405 EFI_GUID VarGuid = VENTOY_GUID;
406
407 Status = gRT->SetVariable(L"VentoyOsParam", &VarGuid,
408 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
409 0, NULL);
410 debug("delete efi variable %r", Status);
411
412 return Status;
413 }
414
415 #if (VENTOY_DEVICE_WARN != 0)
416 STATIC VOID ventoy_warn_invalid_device(VOID)
417 {
418 STATIC BOOLEAN flag = FALSE;
419
420 if (flag)
421 {
422 return;
423 }
424
425 flag = TRUE;
426 gST->ConOut->ClearScreen(gST->ConOut);
427 gST->ConOut->OutputString(gST->ConOut, VTOY_WARNING L"\r\n");
428 gST->ConOut->OutputString(gST->ConOut, VTOY_WARNING L"\r\n");
429 gST->ConOut->OutputString(gST->ConOut, VTOY_WARNING L"\r\n\r\n\r\n");
430
431 gST->ConOut->OutputString(gST->ConOut, L"This is NOT a standard Ventoy device and is NOT supported.\r\n\r\n");
432 gST->ConOut->OutputString(gST->ConOut, L"You should follow the official instructions in https://www.ventoy.net\r\n");
433
434 gST->ConOut->OutputString(gST->ConOut, L"\r\n\r\nWill exit after 10 seconds ...... ");
435
436 sleep(10);
437 }
438 #else
439 STATIC VOID ventoy_warn_invalid_device(VOID)
440 {
441
442 }
443 #endif
444
445 STATIC EFI_STATUS EFIAPI ventoy_load_image
446 (
447 IN EFI_HANDLE ImageHandle,
448 IN EFI_DEVICE_PATH_PROTOCOL *pDevicePath,
449 IN CONST CHAR16 *FileName,
450 IN UINTN FileNameLen,
451 OUT EFI_HANDLE *Image
452 )
453 {
454 EFI_STATUS Status = EFI_SUCCESS;
455 CHAR16 TmpBuf[256] = {0};
456 FILEPATH_DEVICE_PATH *pFilePath = NULL;
457 EFI_DEVICE_PATH_PROTOCOL *pImgPath = NULL;
458
459 pFilePath = (FILEPATH_DEVICE_PATH *)TmpBuf;
460 pFilePath->Header.Type = MEDIA_DEVICE_PATH;
461 pFilePath->Header.SubType = MEDIA_FILEPATH_DP;
462 pFilePath->Header.Length[0] = FileNameLen + sizeof(EFI_DEVICE_PATH_PROTOCOL);
463 pFilePath->Header.Length[1] = 0;
464 CopyMem(pFilePath->PathName, FileName, FileNameLen);
465
466 pImgPath = AppendDevicePathNode(pDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)pFilePath);
467 if (!pImgPath)
468 {
469 return EFI_NOT_FOUND;
470 }
471
472 Status = gBS->LoadImage(FALSE, ImageHandle, pImgPath, NULL, 0, Image);
473
474 debug("Load Image File %r DP: <%s>", Status, ConvertDevicePathToText(pImgPath, FALSE, FALSE));
475
476 FreePool(pImgPath);
477
478 return Status;
479 }
480
481
482 STATIC EFI_STATUS EFIAPI ventoy_find_iso_disk(IN EFI_HANDLE ImageHandle)
483 {
484 UINTN i = 0;
485 UINTN Count = 0;
486 UINT64 DiskSize = 0;
487 MBR_HEAD *pMBR = NULL;
488 UINT8 *pBuffer = NULL;
489 EFI_HANDLE *Handles;
490 EFI_STATUS Status = EFI_SUCCESS;
491 EFI_BLOCK_IO_PROTOCOL *pBlockIo;
492
493 pBuffer = AllocatePool(2048);
494 if (!pBuffer)
495 {
496 return EFI_OUT_OF_RESOURCES;
497 }
498
499 Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiBlockIoProtocolGuid,
500 NULL, &Count, &Handles);
501 if (EFI_ERROR(Status))
502 {
503 FreePool(pBuffer);
504 return Status;
505 }
506
507 for (i = 0; i < Count; i++)
508 {
509 Status = gBS->HandleProtocol(Handles[i], &gEfiBlockIoProtocolGuid, (VOID **)&pBlockIo);
510 if (EFI_ERROR(Status))
511 {
512 continue;
513 }
514
515 DiskSize = (pBlockIo->Media->LastBlock + 1) * pBlockIo->Media->BlockSize;
516 debug("This Disk size: %llu", DiskSize);
517 if (g_chain->os_param.vtoy_disk_size != DiskSize)
518 {
519 continue;
520 }
521
522 Status = pBlockIo->ReadBlocks(pBlockIo, pBlockIo->Media->MediaId, 0, 512, pBuffer);
523 if (EFI_ERROR(Status))
524 {
525 debug("ReadBlocks filed %r", Status);
526 continue;
527 }
528
529 if (CompareMem(g_chain->os_param.vtoy_disk_guid, pBuffer + 0x180, 16) == 0)
530 {
531 pMBR = (MBR_HEAD *)pBuffer;
532 if (pMBR->PartTbl[0].FsFlag != 0xEE)
533 {
534 if (pMBR->PartTbl[0].StartSectorId != 2048 ||
535 pMBR->PartTbl[1].SectorCount != 65536 ||
536 pMBR->PartTbl[1].StartSectorId != pMBR->PartTbl[0].StartSectorId + pMBR->PartTbl[0].SectorCount)
537 {
538 debug("Failed to check disk part table");
539 ventoy_warn_invalid_device();
540 }
541 }
542
543 gBlockData.RawBlockIoHandle = Handles[i];
544 gBlockData.pRawBlockIo = pBlockIo;
545 gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,
546 (VOID **)&(gBlockData.pDiskDevPath),
547 ImageHandle,
548 Handles[i],
549 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
550
551 debug("Find Ventoy Disk Handle:%p DP:%s", Handles[i],
552 ConvertDevicePathToText(gBlockData.pDiskDevPath, FALSE, FALSE));
553 break;
554 }
555 }
556
557 FreePool(Handles);
558
559 if (i >= Count)
560 {
561 return EFI_NOT_FOUND;
562 }
563 else
564 {
565 return EFI_SUCCESS;
566 }
567 }
568
569
570 STATIC EFI_STATUS EFIAPI ventoy_find_iso_disk_fs(IN EFI_HANDLE ImageHandle)
571 {
572 UINTN i = 0;
573 UINTN Count = 0;
574 EFI_HANDLE Parent = NULL;
575 EFI_HANDLE *Handles = NULL;
576 EFI_STATUS Status = EFI_SUCCESS;
577 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFile = NULL;
578 EFI_DEVICE_PATH_PROTOCOL *pDevPath = NULL;
579
580 Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid,
581 NULL, &Count, &Handles);
582 if (EFI_ERROR(Status))
583 {
584 return Status;
585 }
586
587 debug("ventoy_find_iso_disk_fs fs count:%u", Count);
588
589 for (i = 0; i < Count; i++)
590 {
591 Status = gBS->HandleProtocol(Handles[i], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&pFile);
592 if (EFI_ERROR(Status))
593 {
594 continue;
595 }
596
597 Status = gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,
598 (VOID **)&pDevPath,
599 ImageHandle,
600 Handles[i],
601 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
602 if (EFI_ERROR(Status))
603 {
604 debug("Failed to open device path protocol %r", Status);
605 continue;
606 }
607
608 debug("Handle:%p FS DP: <%s>", Handles[i], ConvertDevicePathToText(pDevPath, FALSE, FALSE));
609 Parent = ventoy_get_parent_handle(pDevPath);
610
611 if (Parent == gBlockData.RawBlockIoHandle)
612 {
613 debug("Find ventoy disk fs");
614 gBlockData.DiskFsHandle = Handles[i];
615 gBlockData.pDiskFs = pFile;
616 gBlockData.pDiskFsDevPath = pDevPath;
617 break;
618 }
619 }
620
621 FreePool(Handles);
622
623 return EFI_SUCCESS;
624 }
625
626 STATIC EFI_STATUS EFIAPI ventoy_load_isoefi_driver(IN EFI_HANDLE ImageHandle)
627 {
628 EFI_HANDLE Image = NULL;
629 EFI_STATUS Status = EFI_SUCCESS;
630 CHAR16 LogVar[4] = L"5";
631
632 if (gIsoUdf)
633 {
634 Status = ventoy_load_image(ImageHandle, gBlockData.pDiskFsDevPath,
635 gUdfEfiDriverPath,
636 sizeof(gUdfEfiDriverPath),
637 &Image);
638 debug("load iso UDF efi driver status:%r", Status);
639 }
640 else
641 {
642 Status = ventoy_load_image(ImageHandle, gBlockData.pDiskFsDevPath,
643 gIso9660EfiDriverPath,
644 sizeof(gIso9660EfiDriverPath),
645 &Image);
646 debug("load iso 9660 efi driver status:%r", Status);
647 }
648
649 if (gDebugPrint)
650 {
651 gRT->SetVariable(L"FS_LOGGING", &gShellVariableGuid,
652 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
653 sizeof(LogVar), LogVar);
654 }
655
656 gRT->SetVariable(L"FS_NAME_NOCASE", &gShellVariableGuid,
657 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
658 sizeof(LogVar), LogVar);
659
660 gBlockData.IsoDriverImage = Image;
661 Status = gBS->StartImage(Image, NULL, NULL);
662 debug("Start iso efi driver status:%r", Status);
663
664 return EFI_SUCCESS;
665 }
666
667 STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
668 {
669 UINT32 i = 0;
670 UINT32 old_cnt = 0;
671 UINTN size = 0;
672 UINT8 chksum = 0;
673 const char *pEnv = NULL;
674 CHAR16 *pPos = NULL;
675 CHAR16 *pCmdLine = NULL;
676 EFI_STATUS Status = EFI_SUCCESS;
677 ventoy_grub_param *pGrubParam = NULL;
678 EFI_LOADED_IMAGE_PROTOCOL *pImageInfo = NULL;
679 ventoy_chain_head *chain = NULL;
680
681 Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&pImageInfo);
682 if (EFI_ERROR(Status))
683 {
684 VtoyDebug("Failed to handle load image protocol %r", Status);
685 return Status;
686 }
687
688 pCmdLine = (CHAR16 *)AllocatePool(pImageInfo->LoadOptionsSize + 4);
689 SetMem(pCmdLine, pImageInfo->LoadOptionsSize + 4, 0);
690 CopyMem(pCmdLine, pImageInfo->LoadOptions, pImageInfo->LoadOptionsSize);
691
692 if (StrStr(pCmdLine, L"debug"))
693 {
694 gDebugPrint = TRUE;
695 }
696
697 if (StrStr(pCmdLine, L"dotefi"))
698 {
699 gDotEfiBoot = TRUE;
700 }
701
702 if (StrStr(pCmdLine, L"isoefi=on"))
703 {
704 gLoadIsoEfi = TRUE;
705 }
706
707 if (StrStr(pCmdLine, L"iso_udf"))
708 {
709 gIsoUdf = TRUE;
710 }
711
712 pPos = StrStr(pCmdLine, L"FirstTry=@");
713 if (pPos)
714 {
715 pPos += StrLen(L"FirstTry=");
716 for (i = 0; i < ARRAY_SIZE(gFirstTryBootFile); i++, pPos++)
717 {
718 if (*pPos != L' ' && *pPos != L'\t' && *pPos)
719 {
720 gFirstTryBootFile[i] = (*pPos == '@') ? '\\' : *pPos;
721 }
722 else
723 {
724 break;
725 }
726 }
727
728 gEfiBootFileName[0] = gFirstTryBootFile;
729 gBootFileStartIndex = 0;
730 }
731
732 debug("cmdline:<%s>", pCmdLine);
733
734 if (gFirstTryBootFile[0])
735 {
736 debug("First Try:<%s>", gFirstTryBootFile);
737 }
738
739 pPos = StrStr(pCmdLine, L"env_param=");
740 if (!pPos)
741 {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 pGrubParam = (ventoy_grub_param *)StrHexToUintn(pPos + StrLen(L"env_param="));
746 grub_env_set = pGrubParam->grub_env_set;
747 grub_env_get = pGrubParam->grub_env_get;
748 pEnv = grub_env_get("VTOY_CHKDEV_RESULT_STRING");
749 if (!pEnv)
750 {
751 return EFI_INVALID_PARAMETER;
752 }
753
754 if (pEnv[0] != '0' || pEnv[1] != 0)
755 {
756 ventoy_warn_invalid_device();
757 return EFI_INVALID_PARAMETER;
758 }
759
760 g_file_replace_list = &pGrubParam->file_replace;
761 old_cnt = g_file_replace_list->old_file_cnt;
762 debug("file replace: magic:0x%x virtid:%u name count:%u <%a> <%a> <%a> <%a>",
763 g_file_replace_list->magic,
764 g_file_replace_list->new_file_virtual_id,
765 old_cnt,
766 old_cnt > 0 ? g_file_replace_list->old_file_name[0] : "",
767 old_cnt > 1 ? g_file_replace_list->old_file_name[1] : "",
768 old_cnt > 2 ? g_file_replace_list->old_file_name[2] : "",
769 old_cnt > 3 ? g_file_replace_list->old_file_name[3] : ""
770 );
771
772 pPos = StrStr(pCmdLine, L"mem:");
773 chain = (ventoy_chain_head *)StrHexToUintn(pPos + 4);
774
775 pPos = StrStr(pPos, L"size:");
776 size = StrDecimalToUintn(pPos + 5);
777
778 debug("memory addr:%p size:%lu", chain, size);
779
780 if (StrStr(pCmdLine, L"sector512"))
781 {
782 gSector512Mode = TRUE;
783 }
784
785 if (StrStr(pCmdLine, L"memdisk"))
786 {
787 g_iso_data_buf = (UINT8 *)chain + sizeof(ventoy_chain_head);
788 g_iso_buf_size = size - sizeof(ventoy_chain_head);
789 debug("memdisk mode iso_buf_size:%u", g_iso_buf_size);
790
791 g_chain = chain;
792 gMemdiskMode = TRUE;
793 }
794 else
795 {
796 debug("This is normal mode");
797 g_chain = AllocatePool(size);
798 CopyMem(g_chain, chain, size);
799
800 g_chunk = (ventoy_img_chunk *)((char *)g_chain + g_chain->img_chunk_offset);
801 g_img_chunk_num = g_chain->img_chunk_num;
802 g_override_chunk = (ventoy_override_chunk *)((char *)g_chain + g_chain->override_chunk_offset);
803 g_override_chunk_num = g_chain->override_chunk_num;
804 g_virt_chunk = (ventoy_virt_chunk *)((char *)g_chain + g_chain->virt_chunk_offset);
805 g_virt_chunk_num = g_chain->virt_chunk_num;
806
807 g_os_param_reserved = (UINT8 *)(g_chain->os_param.vtoy_reserved);
808
809 /* Workaround for Windows & ISO9660 */
810 if (g_os_param_reserved[2] == ventoy_chain_windows && g_os_param_reserved[3] == 0)
811 {
812 g_fixup_iso9660_secover_enable = TRUE;
813 }
814
815 if (g_os_param_reserved[2] == ventoy_chain_windows && g_os_param_reserved[4] != 1)
816 {
817 g_hook_keyboard = TRUE;
818 }
819
820 debug("internal param: secover:%u keyboard:%u", g_fixup_iso9660_secover_enable, g_hook_keyboard);
821
822 for (i = 0; i < sizeof(ventoy_os_param); i++)
823 {
824 chksum += *((UINT8 *)(&(g_chain->os_param)) + i);
825 }
826
827 if (gDebugPrint)
828 {
829 debug("os param checksum: 0x%x %a", g_chain->os_param.chksum, chksum ? "FAILED" : "SUCCESS");
830 }
831
832 ventoy_update_image_location(&(g_chain->os_param));
833
834 if (gDebugPrint)
835 {
836 ventoy_dump_chain(g_chain);
837 }
838 }
839
840 g_fix_windows_1st_cdrom_issue = FALSE;
841 if (ventoy_chain_windows == g_os_param_reserved[2] ||
842 ventoy_chain_wim == g_os_param_reserved[2])
843 {
844 if (ventoy_is_cdrom_dp_exist())
845 {
846 debug("fixup the 1st cdrom influences when boot windows ...");
847 g_fix_windows_1st_cdrom_issue = TRUE;
848 }
849 }
850
851 ventoy_debug_pause();
852
853 FreePool(pCmdLine);
854 return EFI_SUCCESS;
855 }
856
857 EFI_STATUS EFIAPI ventoy_clean_env(VOID)
858 {
859 FreePool(g_sector_flag);
860 g_sector_flag_num = 0;
861
862 if (gLoadIsoEfi && gBlockData.IsoDriverImage)
863 {
864 gBS->UnloadImage(gBlockData.IsoDriverImage);
865 }
866
867 gBS->DisconnectController(gBlockData.Handle, NULL, NULL);
868
869 gBS->UninstallMultipleProtocolInterfaces(gBlockData.Handle,
870 &gEfiBlockIoProtocolGuid, &gBlockData.BlockIo,
871 &gEfiDevicePathProtocolGuid, gBlockData.Path,
872 NULL);
873
874 ventoy_delete_variable();
875
876 if (g_chain->os_param.vtoy_img_location_addr)
877 {
878 FreePool((VOID *)(UINTN)g_chain->os_param.vtoy_img_location_addr);
879 }
880
881 FreePool(g_chain);
882
883 return EFI_SUCCESS;
884 }
885
886 STATIC EFI_STATUS ventoy_hook_start(VOID)
887 {
888 /* don't add debug print in this function */
889
890 if (g_fix_windows_1st_cdrom_issue)
891 {
892 ventoy_hook_1st_cdrom_start();
893 }
894
895 /* let this the last */
896 if (g_hook_keyboard)
897 {
898 ventoy_hook_keyboard_start();
899 }
900
901 return EFI_SUCCESS;
902 }
903
904 STATIC EFI_STATUS ventoy_hook_stop(VOID)
905 {
906 /* don't add debug print in this function */
907
908 if (g_fix_windows_1st_cdrom_issue)
909 {
910 ventoy_hook_1st_cdrom_stop();
911 }
912
913 /* let this the last */
914 if (g_hook_keyboard)
915 {
916 ventoy_hook_keyboard_stop();
917 }
918
919 return EFI_SUCCESS;
920 }
921
922 EFI_STATUS EFIAPI ventoy_boot(IN EFI_HANDLE ImageHandle)
923 {
924 UINTN t = 0;
925 UINTN i = 0;
926 UINTN j = 0;
927 UINTN Find = 0;
928 UINTN Count = 0;
929 EFI_HANDLE Image = NULL;
930 EFI_HANDLE *Handles = NULL;
931 EFI_STATUS Status = EFI_SUCCESS;
932 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFile = NULL;
933 EFI_DEVICE_PATH_PROTOCOL *pDevPath = NULL;
934
935 for (t = 0; t < 3; t++)
936 {
937 Count = 0;
938 Handles = NULL;
939
940 Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid,
941 NULL, &Count, &Handles);
942 if (EFI_ERROR(Status))
943 {
944 return Status;
945 }
946
947 debug("ventoy_boot fs count:%u", Count);
948
949 for (i = 0; i < Count; i++)
950 {
951 Status = gBS->HandleProtocol(Handles[i], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&pFile);
952 if (EFI_ERROR(Status))
953 {
954 continue;
955 }
956
957 debug("FS:%u Protocol:%p OpenVolume:%p", i, pFile, pFile->OpenVolume);
958
959 Status = gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,
960 (VOID **)&pDevPath,
961 ImageHandle,
962 Handles[i],
963 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
964 if (EFI_ERROR(Status))
965 {
966 debug("Failed to open device path protocol %r", Status);
967 continue;
968 }
969
970 debug("Handle:%p FS DP: <%s>", Handles[i], ConvertDevicePathToText(pDevPath, FALSE, FALSE));
971 if (CompareMem(gBlockData.Path, pDevPath, gBlockData.DevicePathCompareLen))
972 {
973 debug("Not ventoy disk file system");
974 continue;
975 }
976
977 for (j = gBootFileStartIndex; j < ARRAY_SIZE(gEfiBootFileName); j++)
978 {
979 Status = ventoy_load_image(ImageHandle, pDevPath, gEfiBootFileName[j],
980 StrSize(gEfiBootFileName[j]), &Image);
981 if (EFI_SUCCESS == Status)
982 {
983 break;
984 }
985 debug("Failed to load image %r <%s>", Status, gEfiBootFileName[j]);
986 }
987
988 if (j >= ARRAY_SIZE(gEfiBootFileName))
989 {
990 continue;
991 }
992
993 Find++;
994 debug("Find boot file, now try to boot .....");
995 ventoy_debug_pause();
996
997 if (gDebugPrint)
998 {
999 gST->ConIn->Reset(gST->ConIn, FALSE);
1000 }
1001
1002 if (g_file_replace_list && g_file_replace_list->magic == GRUB_FILE_REPLACE_MAGIC)
1003 {
1004 ventoy_wrapper_push_openvolume(pFile->OpenVolume);
1005 pFile->OpenVolume = ventoy_wrapper_open_volume;
1006 }
1007
1008 ventoy_hook_start();
1009 /* can't add debug print here */
1010 //ventoy_wrapper_system();
1011 Status = gBS->StartImage(Image, NULL, NULL);
1012 ventoy_hook_stop();
1013
1014 if (EFI_ERROR(Status))
1015 {
1016 debug("Failed to start image %r", Status);
1017 sleep(3);
1018 gBS->UnloadImage(Image);
1019 break;
1020 }
1021 }
1022
1023 FreePool(Handles);
1024
1025 if (Find == 0)
1026 {
1027 if (gDotEfiBoot)
1028 {
1029 break;
1030 }
1031
1032 debug("Fs not found, now wait and retry...");
1033 sleep(2);
1034 }
1035 }
1036
1037 if (Find == 0)
1038 {
1039 return EFI_NOT_FOUND;
1040 }
1041
1042 return EFI_SUCCESS;
1043 }
1044
1045 EFI_STATUS EFIAPI VentoyEfiMain
1046 (
1047 IN EFI_HANDLE ImageHandle,
1048 IN EFI_SYSTEM_TABLE *SystemTable
1049 )
1050 {
1051 EFI_STATUS Status = EFI_SUCCESS;
1052 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *Protocol;
1053
1054 g_sector_flag_num = 512; /* initial value */
1055
1056 g_sector_flag = AllocatePool(g_sector_flag_num * sizeof(ventoy_sector_flag));
1057 if (NULL == g_sector_flag)
1058 {
1059 return EFI_OUT_OF_RESOURCES;
1060 }
1061
1062 Status = gBS->HandleProtocol(gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&Protocol);
1063 if (EFI_SUCCESS == Status)
1064 {
1065 g_con_simple_input_ex = Protocol;
1066 }
1067
1068 gST->ConOut->ClearScreen(gST->ConOut);
1069 ventoy_clear_input();
1070
1071 Status = ventoy_parse_cmdline(ImageHandle);
1072 if (EFI_ERROR(Status))
1073 {
1074 return Status;
1075 }
1076
1077 if (gMemdiskMode)
1078 {
1079 g_ramdisk_param.PhyAddr = (UINT64)(UINTN)g_iso_data_buf;
1080 g_ramdisk_param.DiskSize = (UINT64)g_iso_buf_size;
1081
1082 ventoy_save_ramdisk_param();
1083
1084 if (gLoadIsoEfi)
1085 {
1086 ventoy_find_iso_disk(ImageHandle);
1087 ventoy_find_iso_disk_fs(ImageHandle);
1088 ventoy_load_isoefi_driver(ImageHandle);
1089 }
1090
1091 ventoy_install_blockio(ImageHandle, g_iso_buf_size);
1092 ventoy_debug_pause();
1093
1094 Status = ventoy_boot(ImageHandle);
1095
1096 ventoy_delete_ramdisk_param();
1097
1098 if (gLoadIsoEfi && gBlockData.IsoDriverImage)
1099 {
1100 gBS->UnloadImage(gBlockData.IsoDriverImage);
1101 }
1102
1103 gBS->DisconnectController(gBlockData.Handle, NULL, NULL);
1104 gBS->UninstallMultipleProtocolInterfaces(gBlockData.Handle,
1105 &gEfiBlockIoProtocolGuid, &gBlockData.BlockIo,
1106 &gEfiDevicePathProtocolGuid, gBlockData.Path,
1107 NULL);
1108 }
1109 else
1110 {
1111 ventoy_save_variable();
1112 Status = ventoy_find_iso_disk(ImageHandle);
1113 if (!EFI_ERROR(Status))
1114 {
1115 if (gLoadIsoEfi)
1116 {
1117 ventoy_find_iso_disk_fs(ImageHandle);
1118 ventoy_load_isoefi_driver(ImageHandle);
1119 }
1120
1121 ventoy_debug_pause();
1122
1123 ventoy_install_blockio(ImageHandle, g_chain->virt_img_size_in_bytes);
1124
1125 ventoy_debug_pause();
1126
1127 Status = ventoy_boot(ImageHandle);
1128 }
1129
1130 ventoy_clean_env();
1131 }
1132
1133 if (FALSE == gDotEfiBoot)
1134 {
1135 if (EFI_NOT_FOUND == Status)
1136 {
1137 gST->ConOut->OutputString(gST->ConOut, L"No bootfile found for UEFI!\r\n");
1138 gST->ConOut->OutputString(gST->ConOut, L"Maybe the image does not support " VENTOY_UEFI_DESC L"!\r\n");
1139 sleep(30);
1140 }
1141 }
1142
1143 ventoy_clear_input();
1144 gST->ConOut->ClearScreen(gST->ConOut);
1145
1146 if (gDotEfiBoot && (EFI_NOT_FOUND == Status))
1147 {
1148 grub_env_set("vtoy_dotefi_retry", "YES");
1149 }
1150
1151 return EFI_SUCCESS;
1152 }
1153