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