1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
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>
39 UINTN g_iso_buf_size
= 0;
40 BOOLEAN gMemdiskMode
= FALSE
;
41 BOOLEAN gDebugPrint
= FALSE
;
42 BOOLEAN gLoadIsoEfi
= FALSE
;
43 ventoy_ram_disk g_ramdisk_param
;
44 ventoy_chain_head
*g_chain
;
45 ventoy_img_chunk
*g_chunk
;
46 UINT32 g_img_chunk_num
;
47 ventoy_override_chunk
*g_override_chunk
;
48 UINT32 g_override_chunk_num
;
49 ventoy_virt_chunk
*g_virt_chunk
;
50 UINT32 g_virt_chunk_num
;
51 vtoy_block_data gBlockData
;
52 ventoy_sector_flag
*g_sector_flag
= NULL
;
53 UINT32 g_sector_flag_num
= 0;
54 static grub_env_get_pf grub_env_get
= NULL
;
56 EFI_FILE_OPEN g_original_fopen
= NULL
;
57 EFI_FILE_CLOSE g_original_fclose
= NULL
;
58 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME g_original_open_volume
= NULL
;
60 ventoy_grub_param_file_replace
*g_file_replace_list
= NULL
;
61 ventoy_efi_file_replace g_efi_file_replace
;
63 CHAR16 gFirstTryBootFile
[256] = {0};
65 CONST CHAR16 gIso9660EfiDriverPath
[] = ISO9660_EFI_DRIVER_PATH
;
68 UINTN gBootFileStartIndex
= 1;
69 CONST CHAR16
*gEfiBootFileName
[] =
72 EFI_REMOVABLE_MEDIA_FILE_NAME
,
73 L
"\\EFI\\BOOT\\GRUBX64.EFI",
74 L
"\\EFI\\BOOT\\BOOTx64.EFI",
75 L
"\\EFI\\BOOT\\bootx64.efi",
76 L
"\\efi\\boot\\bootx64.efi",
79 /* EFI block device vendor device path GUID */
80 EFI_GUID gVtoyBlockDevicePathGuid
= VTOY_BLOCK_DEVICE_PATH_GUID
;
82 VOID EFIAPI
VtoyDebug(IN CONST CHAR8
*Format
, ...)
87 VA_START (Marker
, Format
);
88 UnicodeVSPrintAsciiFormat(Buffer
, sizeof(Buffer
), Format
, Marker
);
91 gST
->ConOut
->OutputString(gST
->ConOut
, Buffer
);
94 VOID EFIAPI
ventoy_clear_input(VOID
)
98 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
99 while (EFI_SUCCESS
== gST
->ConIn
->ReadKeyStroke(gST
->ConIn
, &Key
))
103 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
106 static void EFIAPI
ventoy_dump_img_chunk(ventoy_chain_head
*chain
)
111 ventoy_img_chunk
*chunk
;
113 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
115 debug("##################### ventoy_dump_img_chunk #######################");
117 for (i
= 0; i
< chain
->img_chunk_num
; i
++)
119 debug("%2u: [ %u - %u ] <==> [ %llu - %llu ]",
120 i
, chunk
[i
].img_start_sector
, chunk
[i
].img_end_sector
,
121 chunk
[i
].disk_start_sector
, chunk
[i
].disk_end_sector
);
123 if (i
> 0 && (chunk
[i
].img_start_sector
!= chunk
[i
- 1].img_end_sector
+ 1))
128 img_sec
+= chunk
[i
].img_end_sector
- chunk
[i
].img_start_sector
+ 1;
131 if (errcnt
== 0 && (img_sec
* 2048 == g_chain
->real_img_size_in_bytes
))
133 debug("image chunk size check success");
137 debug("image chunk size check failed %d", errcnt
);
140 ventoy_debug_pause();
143 static void EFIAPI
ventoy_dump_override_chunk(ventoy_chain_head
*chain
)
146 ventoy_override_chunk
*chunk
;
148 chunk
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
150 debug("##################### ventoy_dump_override_chunk #######################");
152 for (i
= 0; i
< g_override_chunk_num
; i
++)
154 debug("%2u: [ %llu, %u ]", i
, chunk
[i
].img_offset
, chunk
[i
].override_size
);
157 ventoy_debug_pause();
160 static void EFIAPI
ventoy_dump_virt_chunk(ventoy_chain_head
*chain
)
163 ventoy_virt_chunk
*node
;
165 debug("##################### ventoy_dump_virt_chunk #######################");
166 debug("virt_chunk_offset=%u", chain
->virt_chunk_offset
);
167 debug("virt_chunk_num=%u", chain
->virt_chunk_num
);
169 node
= (ventoy_virt_chunk
*)((char *)chain
+ chain
->virt_chunk_offset
);
170 for (i
= 0; i
< chain
->virt_chunk_num
; i
++, node
++)
172 debug("%2u: mem:[ %u, %u, %u ] remap:[ %u, %u, %u ]", i
,
173 node
->mem_sector_start
,
174 node
->mem_sector_end
,
175 node
->mem_sector_offset
,
176 node
->remap_sector_start
,
177 node
->remap_sector_end
,
178 node
->org_sector_start
);
181 ventoy_debug_pause();
184 static void EFIAPI
ventoy_dump_chain(ventoy_chain_head
*chain
)
190 guid
= chain
->os_param
.vtoy_disk_guid
;
191 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
193 chksum
+= *((UINT8
*)(&(chain
->os_param
)) + i
);
196 debug("##################### ventoy_dump_chain #######################");
198 debug("os_param->chksum=0x%x (%a)", chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
199 debug("os_param->vtoy_disk_guid=%02x%02x%02x%02x", guid
[0], guid
[1], guid
[2], guid
[3]);
200 debug("os_param->vtoy_disk_size=%llu", chain
->os_param
.vtoy_disk_size
);
201 debug("os_param->vtoy_disk_part_id=%u", chain
->os_param
.vtoy_disk_part_id
);
202 debug("os_param->vtoy_disk_part_type=%u", chain
->os_param
.vtoy_disk_part_type
);
203 debug("os_param->vtoy_img_path=<%a>", chain
->os_param
.vtoy_img_path
);
204 debug("os_param->vtoy_img_size=<%llu>", chain
->os_param
.vtoy_img_size
);
205 debug("os_param->vtoy_img_location_addr=<0x%llx>", chain
->os_param
.vtoy_img_location_addr
);
206 debug("os_param->vtoy_img_location_len=<%u>", chain
->os_param
.vtoy_img_location_len
);
208 ventoy_debug_pause();
210 debug("chain->disk_drive=0x%x", chain
->disk_drive
);
211 debug("chain->disk_sector_size=%u", chain
->disk_sector_size
);
212 debug("chain->real_img_size_in_bytes=%llu", chain
->real_img_size_in_bytes
);
213 debug("chain->virt_img_size_in_bytes=%llu", chain
->virt_img_size_in_bytes
);
214 debug("chain->boot_catalog=%u", chain
->boot_catalog
);
215 debug("chain->img_chunk_offset=%u", chain
->img_chunk_offset
);
216 debug("chain->img_chunk_num=%u", chain
->img_chunk_num
);
217 debug("chain->override_chunk_offset=%u", chain
->override_chunk_offset
);
218 debug("chain->override_chunk_num=%u", chain
->override_chunk_num
);
220 ventoy_debug_pause();
222 ventoy_dump_img_chunk(chain
);
223 ventoy_dump_override_chunk(chain
);
224 ventoy_dump_virt_chunk(chain
);
227 EFI_HANDLE EFIAPI
ventoy_get_parent_handle(IN EFI_DEVICE_PATH_PROTOCOL
*pDevPath
)
229 EFI_HANDLE Handle
= NULL
;
230 EFI_STATUS Status
= EFI_SUCCESS
;
231 EFI_DEVICE_PATH_PROTOCOL
*pLastNode
= NULL
;
232 EFI_DEVICE_PATH_PROTOCOL
*pCurNode
= NULL
;
233 EFI_DEVICE_PATH_PROTOCOL
*pTmpDevPath
= NULL
;
235 pTmpDevPath
= DuplicateDevicePath(pDevPath
);
241 pCurNode
= pTmpDevPath
;
242 while (!IsDevicePathEnd(pCurNode
))
244 pLastNode
= pCurNode
;
245 pCurNode
= NextDevicePathNode(pCurNode
);
249 CopyMem(pLastNode
, pCurNode
, sizeof(EFI_DEVICE_PATH_PROTOCOL
));
252 pCurNode
= pTmpDevPath
;
253 Status
= gBS
->LocateDevicePath(&gEfiDevicePathProtocolGuid
, &pCurNode
, &Handle
);
254 debug("Status:%r Parent Handle:%p DP:%s", Status
, Handle
, ConvertDevicePathToText(pTmpDevPath
, FALSE
, FALSE
));
256 FreePool(pTmpDevPath
);
261 EFI_STATUS EFIAPI ventoy_block_io_reset
263 IN EFI_BLOCK_IO_PROTOCOL
*This
,
264 IN BOOLEAN ExtendedVerification
268 (VOID
)ExtendedVerification
;
272 STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
279 EFI_STATUS Status
= EFI_SUCCESS
;
284 UINT64 ReadStart
= 0;
286 UINT64 OverrideStart
= 0;
287 UINT64 OverrideEnd
= 0;
288 UINT8
*pCurBuf
= (UINT8
*)Buffer
;
289 ventoy_img_chunk
*pchunk
= g_chunk
;
290 ventoy_override_chunk
*pOverride
= g_override_chunk
;
291 EFI_BLOCK_IO_PROTOCOL
*pRawBlockIo
= gBlockData
.pRawBlockIo
;
293 debug("read iso sector %lu count %u", Sector
, Count
);
295 ReadStart
= Sector
* 2048;
296 ReadEnd
= (Sector
+ Count
) * 2048;
298 for (i
= 0; Count
> 0 && i
< g_img_chunk_num
; i
++, pchunk
++)
300 if (Sector
>= pchunk
->img_start_sector
&& Sector
<= pchunk
->img_end_sector
)
302 if (g_chain
->disk_sector_size
== 512)
304 MapLba
= (Sector
- pchunk
->img_start_sector
) * 4 + pchunk
->disk_start_sector
;
308 MapLba
= (Sector
- pchunk
->img_start_sector
) * 2048 / g_chain
->disk_sector_size
+ pchunk
->disk_start_sector
;
311 secLeft
= pchunk
->img_end_sector
+ 1 - Sector
;
312 secRead
= (Count
< secLeft
) ? Count
: secLeft
;
314 Status
= pRawBlockIo
->ReadBlocks(pRawBlockIo
, pRawBlockIo
->Media
->MediaId
,
315 MapLba
, secRead
* 2048, pCurBuf
);
316 if (EFI_ERROR(Status
))
318 debug("Raw disk read block failed %r", Status
);
324 pCurBuf
+= secRead
* 2048;
328 if (ReadStart
> g_chain
->real_img_size_in_bytes
)
334 pCurBuf
= (UINT8
*)Buffer
;
335 for (i
= 0; i
< g_override_chunk_num
; i
++, pOverride
++)
337 OverrideStart
= pOverride
->img_offset
;
338 OverrideEnd
= pOverride
->img_offset
+ pOverride
->override_size
;
340 if (OverrideStart
>= ReadEnd
|| ReadStart
>= OverrideEnd
)
345 if (ReadStart
<= OverrideStart
)
347 if (ReadEnd
<= OverrideEnd
)
349 CopyMem(pCurBuf
+ OverrideStart
- ReadStart
, pOverride
->override_data
, ReadEnd
- OverrideStart
);
353 CopyMem(pCurBuf
+ OverrideStart
- ReadStart
, pOverride
->override_data
, pOverride
->override_size
);
358 if (ReadEnd
<= OverrideEnd
)
360 CopyMem(pCurBuf
, pOverride
->override_data
+ ReadStart
- OverrideStart
, ReadEnd
- ReadStart
);
364 CopyMem(pCurBuf
, pOverride
->override_data
+ ReadStart
- OverrideStart
, OverrideEnd
- ReadStart
);
372 EFI_STATUS EFIAPI ventoy_block_io_ramdisk_read
374 IN EFI_BLOCK_IO_PROTOCOL
*This
,
381 //debug("### ventoy_block_io_ramdisk_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
386 CopyMem(Buffer
, (char *)g_chain
+ (Lba
* 2048), BufferSize
);
391 EFI_STATUS EFIAPI ventoy_block_io_read
393 IN EFI_BLOCK_IO_PROTOCOL
*This
,
408 ventoy_sector_flag
*cur_flag
;
409 ventoy_virt_chunk
*node
;
411 //debug("### ventoy_block_io_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
413 secNum
= BufferSize
/ 2048;
416 if (offset
+ BufferSize
< g_chain
->real_img_size_in_bytes
)
418 return ventoy_read_iso_sector(Lba
, secNum
, Buffer
);
421 if (secNum
> g_sector_flag_num
)
423 cur_flag
= AllocatePool(secNum
* sizeof(ventoy_sector_flag
));
424 if (NULL
== cur_flag
)
426 return EFI_OUT_OF_RESOURCES
;
429 FreePool(g_sector_flag
);
430 g_sector_flag
= cur_flag
;
431 g_sector_flag_num
= secNum
;
434 for (curlba
= Lba
, cur_flag
= g_sector_flag
, j
= 0; j
< secNum
; j
++, curlba
++, cur_flag
++)
437 for (node
= g_virt_chunk
, i
= 0; i
< g_virt_chunk_num
; i
++, node
++)
439 if (curlba
>= node
->mem_sector_start
&& curlba
< node
->mem_sector_end
)
441 CopyMem((UINT8
*)Buffer
+ j
* 2048,
442 (char *)g_virt_chunk
+ node
->mem_sector_offset
+ (curlba
- node
->mem_sector_start
) * 2048,
447 else if (curlba
>= node
->remap_sector_start
&& curlba
< node
->remap_sector_end
)
449 cur_flag
->remap_lba
= node
->org_sector_start
+ curlba
- node
->remap_sector_start
;
456 for (curlba
= Lba
, cur_flag
= g_sector_flag
, j
= 0; j
< secNum
; j
++, curlba
++, cur_flag
++)
458 if (cur_flag
->flag
== 2)
462 lastbuffer
= (UINT8
*)Buffer
+ j
* 2048;
463 lastlba
= cur_flag
->remap_lba
;
466 else if (lastlba
+ lbacount
== cur_flag
->remap_lba
)
472 ventoy_read_iso_sector(lastlba
, lbacount
, lastbuffer
);
473 lastbuffer
= (UINT8
*)Buffer
+ j
* 2048;
474 lastlba
= cur_flag
->remap_lba
;
482 ventoy_read_iso_sector(lastlba
, lbacount
, lastbuffer
);
488 EFI_STATUS EFIAPI ventoy_block_io_write
490 IN EFI_BLOCK_IO_PROTOCOL
*This
,
502 return EFI_WRITE_PROTECTED
;
505 EFI_STATUS EFIAPI
ventoy_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL
*This
)
512 EFI_STATUS EFIAPI
ventoy_fill_device_path(VOID
)
515 UINT8 TmpBuf
[128] = {0};
516 VENDOR_DEVICE_PATH
*venPath
= NULL
;
518 venPath
= (VENDOR_DEVICE_PATH
*)TmpBuf
;
519 NameLen
= StrSize(VTOY_BLOCK_DEVICE_PATH_NAME
);
520 venPath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
521 venPath
->Header
.SubType
= HW_VENDOR_DP
;
522 venPath
->Header
.Length
[0] = sizeof(VENDOR_DEVICE_PATH
) + NameLen
;
523 venPath
->Header
.Length
[1] = 0;
524 CopyMem(&venPath
->Guid
, &gVtoyBlockDevicePathGuid
, sizeof(EFI_GUID
));
525 CopyMem(venPath
+ 1, VTOY_BLOCK_DEVICE_PATH_NAME
, NameLen
);
527 gBlockData
.Path
= AppendDevicePathNode(NULL
, (EFI_DEVICE_PATH_PROTOCOL
*)TmpBuf
);
528 gBlockData
.DevicePathCompareLen
= sizeof(VENDOR_DEVICE_PATH
) + NameLen
;
530 debug("gBlockData.Path=<%s>\n", ConvertDevicePathToText(gBlockData
.Path
, FALSE
, FALSE
));
535 EFI_STATUS EFIAPI
ventoy_save_ramdisk_param(VOID
)
537 EFI_STATUS Status
= EFI_SUCCESS
;
538 EFI_GUID VarGuid
= VENTOY_GUID
;
540 Status
= gRT
->SetVariable(L
"VentoyRamDisk", &VarGuid
,
541 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
542 sizeof(g_ramdisk_param
), &(g_ramdisk_param
));
543 debug("set efi variable %r", Status
);
548 EFI_STATUS EFIAPI
ventoy_del_ramdisk_param(VOID
)
550 EFI_STATUS Status
= EFI_SUCCESS
;
551 EFI_GUID VarGuid
= VENTOY_GUID
;
553 Status
= gRT
->SetVariable(L
"VentoyRamDisk", &VarGuid
,
554 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
556 debug("delete efi variable %r", Status
);
562 EFI_STATUS EFIAPI
ventoy_set_variable(VOID
)
564 EFI_STATUS Status
= EFI_SUCCESS
;
565 EFI_GUID VarGuid
= VENTOY_GUID
;
567 Status
= gRT
->SetVariable(L
"VentoyOsParam", &VarGuid
,
568 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
569 sizeof(g_chain
->os_param
), &(g_chain
->os_param
));
570 debug("set efi variable %r", Status
);
575 EFI_STATUS EFIAPI
ventoy_delete_variable(VOID
)
577 EFI_STATUS Status
= EFI_SUCCESS
;
578 EFI_GUID VarGuid
= VENTOY_GUID
;
580 Status
= gRT
->SetVariable(L
"VentoyOsParam", &VarGuid
,
581 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
583 debug("delete efi variable %r", Status
);
589 EFI_STATUS EFIAPI
ventoy_install_blockio(IN EFI_HANDLE ImageHandle
, IN UINT64 ImgSize
)
591 EFI_STATUS Status
= EFI_SUCCESS
;
592 EFI_BLOCK_IO_PROTOCOL
*pBlockIo
= &(gBlockData
.BlockIo
);
594 ventoy_fill_device_path();
596 gBlockData
.Media
.BlockSize
= 2048;
597 gBlockData
.Media
.LastBlock
= ImgSize
/ 2048 - 1;
598 gBlockData
.Media
.ReadOnly
= TRUE
;
599 gBlockData
.Media
.MediaPresent
= 1;
600 gBlockData
.Media
.LogicalBlocksPerPhysicalBlock
= 1;
602 pBlockIo
->Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
603 pBlockIo
->Media
= &(gBlockData
.Media
);
604 pBlockIo
->Reset
= ventoy_block_io_reset
;
608 pBlockIo
->ReadBlocks
= ventoy_block_io_ramdisk_read
;
612 pBlockIo
->ReadBlocks
= ventoy_block_io_read
;
615 pBlockIo
->WriteBlocks
= ventoy_block_io_write
;
616 pBlockIo
->FlushBlocks
= ventoy_block_io_flush
;
618 Status
= gBS
->InstallMultipleProtocolInterfaces(&gBlockData
.Handle
,
619 &gEfiBlockIoProtocolGuid
, &gBlockData
.BlockIo
,
620 &gEfiDevicePathProtocolGuid
, gBlockData
.Path
,
623 debug("Install protocol %r", Status
);
625 if (EFI_ERROR(Status
))
630 Status
= gBS
->ConnectController(gBlockData
.Handle
, NULL
, NULL
, 1);
631 debug("Connect controller %r", Status
);
637 EFI_STATUS EFIAPI ventoy_load_image
639 IN EFI_HANDLE ImageHandle
,
640 IN EFI_DEVICE_PATH_PROTOCOL
*pDevicePath
,
641 IN CONST CHAR16
*FileName
,
642 IN UINTN FileNameLen
,
643 OUT EFI_HANDLE
*Image
646 EFI_STATUS Status
= EFI_SUCCESS
;
647 CHAR16 TmpBuf
[256] = {0};
648 FILEPATH_DEVICE_PATH
*pFilePath
= NULL
;
649 EFI_DEVICE_PATH_PROTOCOL
*pImgPath
= NULL
;
651 pFilePath
= (FILEPATH_DEVICE_PATH
*)TmpBuf
;
652 pFilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
653 pFilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
654 pFilePath
->Header
.Length
[0] = FileNameLen
+ sizeof(EFI_DEVICE_PATH_PROTOCOL
);
655 pFilePath
->Header
.Length
[1] = 0;
656 CopyMem(pFilePath
->PathName
, FileName
, FileNameLen
);
658 pImgPath
= AppendDevicePathNode(pDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)pFilePath
);
661 return EFI_NOT_FOUND
;
664 Status
= gBS
->LoadImage(FALSE
, ImageHandle
, pImgPath
, NULL
, 0, Image
);
666 debug("Load Image File %r DP: <%s>", Status
, ConvertDevicePathToText(pImgPath
, FALSE
, FALSE
));
674 STATIC EFI_STATUS EFIAPI
ventoy_find_iso_disk(IN EFI_HANDLE ImageHandle
)
679 UINT8
*pBuffer
= NULL
;
681 EFI_STATUS Status
= EFI_SUCCESS
;
682 EFI_BLOCK_IO_PROTOCOL
*pBlockIo
;
684 pBuffer
= AllocatePool(2048);
687 return EFI_OUT_OF_RESOURCES
;
690 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiBlockIoProtocolGuid
,
691 NULL
, &Count
, &Handles
);
692 if (EFI_ERROR(Status
))
698 for (i
= 0; i
< Count
; i
++)
700 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiBlockIoProtocolGuid
, (VOID
**)&pBlockIo
);
701 if (EFI_ERROR(Status
))
706 DiskSize
= (pBlockIo
->Media
->LastBlock
+ 1) * pBlockIo
->Media
->BlockSize
;
707 debug("This Disk size: %llu", DiskSize
);
708 if (g_chain
->os_param
.vtoy_disk_size
!= DiskSize
)
713 Status
= pBlockIo
->ReadBlocks(pBlockIo
, pBlockIo
->Media
->MediaId
, 0, 512, pBuffer
);
714 if (EFI_ERROR(Status
))
716 debug("ReadBlocks filed %r", Status
);
720 if (CompareMem(g_chain
->os_param
.vtoy_disk_guid
, pBuffer
+ 0x180, 16) == 0)
722 gBlockData
.RawBlockIoHandle
= Handles
[i
];
723 gBlockData
.pRawBlockIo
= pBlockIo
;
724 gBS
->OpenProtocol(Handles
[i
], &gEfiDevicePathProtocolGuid
,
725 (VOID
**)&(gBlockData
.pDiskDevPath
),
728 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
730 debug("Find Ventoy Disk Handle:%p DP:%s", Handles
[i
],
731 ConvertDevicePathToText(gBlockData
.pDiskDevPath
, FALSE
, FALSE
));
740 return EFI_NOT_FOUND
;
748 STATIC EFI_STATUS EFIAPI
ventoy_find_iso_disk_fs(IN EFI_HANDLE ImageHandle
)
752 EFI_HANDLE Parent
= NULL
;
753 EFI_HANDLE
*Handles
= NULL
;
754 EFI_STATUS Status
= EFI_SUCCESS
;
755 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*pFile
= NULL
;
756 EFI_DEVICE_PATH_PROTOCOL
*pDevPath
= NULL
;
758 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
,
759 NULL
, &Count
, &Handles
);
760 if (EFI_ERROR(Status
))
765 debug("ventoy_find_iso_disk_fs fs count:%u", Count
);
767 for (i
= 0; i
< Count
; i
++)
769 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&pFile
);
770 if (EFI_ERROR(Status
))
775 Status
= gBS
->OpenProtocol(Handles
[i
], &gEfiDevicePathProtocolGuid
,
779 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
780 if (EFI_ERROR(Status
))
782 debug("Failed to open device path protocol %r", Status
);
786 debug("Handle:%p FS DP: <%s>", Handles
[i
], ConvertDevicePathToText(pDevPath
, FALSE
, FALSE
));
787 Parent
= ventoy_get_parent_handle(pDevPath
);
789 if (Parent
== gBlockData
.RawBlockIoHandle
)
791 debug("Find ventoy disk fs");
792 gBlockData
.DiskFsHandle
= Handles
[i
];
793 gBlockData
.pDiskFs
= pFile
;
794 gBlockData
.pDiskFsDevPath
= pDevPath
;
804 STATIC EFI_STATUS EFIAPI
ventoy_load_isoefi_driver(IN EFI_HANDLE ImageHandle
)
806 EFI_HANDLE Image
= NULL
;
807 EFI_STATUS Status
= EFI_SUCCESS
;
808 CHAR16 LogVar
[4] = L
"5";
810 Status
= ventoy_load_image(ImageHandle
, gBlockData
.pDiskFsDevPath
,
811 gIso9660EfiDriverPath
,
812 sizeof(gIso9660EfiDriverPath
),
814 debug("load iso efi driver status:%r", Status
);
818 gRT
->SetVariable(L
"FS_LOGGING", &gShellVariableGuid
,
819 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
820 sizeof(LogVar
), LogVar
);
823 gRT
->SetVariable(L
"FS_NAME_NOCASE", &gShellVariableGuid
,
824 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
825 sizeof(LogVar
), LogVar
);
827 gBlockData
.IsoDriverImage
= Image
;
828 Status
= gBS
->StartImage(Image
, NULL
, NULL
);
829 debug("Start iso efi driver status:%r", Status
);
834 static int ventoy_update_image_location(ventoy_os_param
*param
)
836 EFI_STATUS Status
= EFI_SUCCESS
;
842 ventoy_image_location
*location
= NULL
;
843 ventoy_image_disk_region
*region
= NULL
;
844 ventoy_img_chunk
*chunk
= g_chunk
;
846 length
= sizeof(ventoy_image_location
) + (g_img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
848 Status
= gBS
->AllocatePool(EfiRuntimeServicesData
, length
+ 4096 * 2, &buffer
);
849 if (EFI_ERROR(Status
) || NULL
== buffer
)
851 debug("Failed to allocate runtime pool %r\n", Status
);
855 address
= (UINTN
)buffer
;
859 address
+= 4096 - (address
% 4096);
863 param
->vtoy_img_location_addr
= address
;
864 param
->vtoy_img_location_len
= length
;
866 /* update check sum */
867 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
869 chksum
+= *((UINT8
*)param
+ i
);
871 param
->chksum
= (chksum
== 0) ? 0 : (UINT8
)(0x100 - chksum
);
873 location
= (ventoy_image_location
*)(unsigned long)(param
->vtoy_img_location_addr
);
874 if (NULL
== location
)
879 CopyMem(&location
->guid
, ¶m
->guid
, sizeof(ventoy_guid
));
880 location
->image_sector_size
= 2048;
881 location
->disk_sector_size
= g_chain
->disk_sector_size
;
882 location
->region_count
= g_img_chunk_num
;
884 region
= location
->regions
;
886 for (i
= 0; i
< g_img_chunk_num
; i
++)
888 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
889 region
->image_start_sector
= chunk
->img_start_sector
;
890 region
->disk_start_sector
= chunk
->disk_start_sector
;
898 STATIC EFI_STATUS EFIAPI
ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle
)
905 CHAR16
*pCmdLine
= NULL
;
906 EFI_STATUS Status
= EFI_SUCCESS
;
907 ventoy_grub_param
*pGrubParam
= NULL
;
908 EFI_LOADED_IMAGE_PROTOCOL
*pImageInfo
= NULL
;
910 Status
= gBS
->HandleProtocol(ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&pImageInfo
);
911 if (EFI_ERROR(Status
))
913 VtoyDebug("Failed to handle load image protocol %r", Status
);
917 pCmdLine
= (CHAR16
*)AllocatePool(pImageInfo
->LoadOptionsSize
+ 4);
918 SetMem(pCmdLine
, pImageInfo
->LoadOptionsSize
+ 4, 0);
919 CopyMem(pCmdLine
, pImageInfo
->LoadOptions
, pImageInfo
->LoadOptionsSize
);
921 if (StrStr(pCmdLine
, L
"debug"))
926 if (StrStr(pCmdLine
, L
"isoefi=on"))
931 pPos
= StrStr(pCmdLine
, L
"FirstTry=@");
934 pPos
+= StrLen(L
"FirstTry=");
935 for (i
= 0; i
< ARRAY_SIZE(gFirstTryBootFile
); i
++, pPos
++)
937 if (*pPos
!= L
' ' && *pPos
!= L
'\t' && *pPos
)
939 gFirstTryBootFile
[i
] = (*pPos
== '@') ? '\\' : *pPos
;
947 gEfiBootFileName
[0] = gFirstTryBootFile
;
948 gBootFileStartIndex
= 0;
951 debug("cmdline:<%s>", pCmdLine
);
953 if (gFirstTryBootFile
[0])
955 debug("First Try:<%s>", gFirstTryBootFile
);
958 pPos
= StrStr(pCmdLine
, L
"env_param=");
961 return EFI_INVALID_PARAMETER
;
964 pGrubParam
= (ventoy_grub_param
*)StrHexToUintn(pPos
+ StrLen(L
"env_param="));
965 grub_env_get
= pGrubParam
->grub_env_get
;
967 g_file_replace_list
= &pGrubParam
->file_replace
;
968 old_cnt
= g_file_replace_list
->old_file_cnt
;
969 debug("file replace: magic:0x%x virtid:%u name count:%u <%a> <%a> <%a> <%a>",
970 g_file_replace_list
->magic
,
971 g_file_replace_list
->new_file_virtual_id
,
973 old_cnt
> 0 ? g_file_replace_list
->old_file_name
[0] : "",
974 old_cnt
> 1 ? g_file_replace_list
->old_file_name
[1] : "",
975 old_cnt
> 2 ? g_file_replace_list
->old_file_name
[2] : "",
976 old_cnt
> 3 ? g_file_replace_list
->old_file_name
[3] : ""
979 pPos
= StrStr(pCmdLine
, L
"mem:");
980 g_chain
= (ventoy_chain_head
*)StrHexToUintn(pPos
+ 4);
982 pPos
= StrStr(pPos
, L
"size:");
983 size
= StrDecimalToUintn(pPos
+ 5);
985 debug("memory addr:%p size:%lu", g_chain
, size
);
987 if (StrStr(pCmdLine
, L
"memdisk"))
989 g_iso_buf_size
= size
;
994 g_chunk
= (ventoy_img_chunk
*)((char *)g_chain
+ g_chain
->img_chunk_offset
);
995 g_img_chunk_num
= g_chain
->img_chunk_num
;
996 g_override_chunk
= (ventoy_override_chunk
*)((char *)g_chain
+ g_chain
->override_chunk_offset
);
997 g_override_chunk_num
= g_chain
->override_chunk_num
;
998 g_virt_chunk
= (ventoy_virt_chunk
*)((char *)g_chain
+ g_chain
->virt_chunk_offset
);
999 g_virt_chunk_num
= g_chain
->virt_chunk_num
;
1001 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
1003 chksum
+= *((UINT8
*)(&(g_chain
->os_param
)) + i
);
1008 debug("os param checksum: 0x%x %a", g_chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
1011 ventoy_update_image_location(&(g_chain
->os_param
));
1015 ventoy_dump_chain(g_chain
);
1023 EFI_STATUS EFIAPI ventoy_wrapper_file_open
1025 EFI_FILE_HANDLE This
,
1026 EFI_FILE_HANDLE
*New
,
1035 EFI_STATUS Status
= EFI_SUCCESS
;
1037 ventoy_virt_chunk
*virt
= NULL
;
1039 Status
= g_original_fopen(This
, New
, Name
, Mode
, Attributes
);
1040 if (EFI_ERROR(Status
))
1045 if (g_file_replace_list
&& g_file_replace_list
->magic
== GRUB_FILE_REPLACE_MAGIC
&&
1046 g_file_replace_list
->new_file_virtual_id
< g_virt_chunk_num
)
1048 AsciiSPrint(TmpName
, sizeof(TmpName
), "%s", Name
);
1049 for (j
= 0; j
< 4; j
++)
1051 if (0 == AsciiStrCmp(g_file_replace_list
[i
].old_file_name
[j
], TmpName
))
1053 g_original_fclose(*New
);
1054 *New
= &g_efi_file_replace
.WrapperHandle
;
1055 ventoy_wrapper_file_procotol(*New
);
1057 virt
= g_virt_chunk
+ g_file_replace_list
->new_file_virtual_id
;
1059 Sectors
= (virt
->mem_sector_end
- virt
->mem_sector_start
) + (virt
->remap_sector_end
- virt
->remap_sector_start
);
1061 g_efi_file_replace
.BlockIoSectorStart
= virt
->mem_sector_start
;
1062 g_efi_file_replace
.FileSizeBytes
= Sectors
* 2048;
1066 debug("## ventoy_wrapper_file_open <%s> BlockStart:%lu Sectors:%lu Bytes:%lu", Name
,
1067 g_efi_file_replace
.BlockIoSectorStart
, Sectors
, Sectors
* 2048);
1079 EFI_STATUS EFIAPI ventoy_wrapper_open_volume
1081 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
1082 OUT EFI_FILE_PROTOCOL
**Root
1085 EFI_STATUS Status
= EFI_SUCCESS
;
1087 Status
= g_original_open_volume(This
, Root
);
1088 if (!EFI_ERROR(Status
))
1090 g_original_fopen
= (*Root
)->Open
;
1091 g_original_fclose
= (*Root
)->Close
;
1092 (*Root
)->Open
= ventoy_wrapper_file_open
;
1099 EFI_STATUS EFIAPI
ventoy_boot(IN EFI_HANDLE ImageHandle
)
1106 EFI_HANDLE Image
= NULL
;
1107 EFI_HANDLE
*Handles
= NULL
;
1108 EFI_STATUS Status
= EFI_SUCCESS
;
1109 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*pFile
= NULL
;
1110 EFI_DEVICE_PATH_PROTOCOL
*pDevPath
= NULL
;
1112 for (t
= 0; t
< 3; t
++)
1117 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
,
1118 NULL
, &Count
, &Handles
);
1119 if (EFI_ERROR(Status
))
1124 debug("ventoy_boot fs count:%u", Count
);
1126 for (i
= 0; i
< Count
; i
++)
1128 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&pFile
);
1129 if (EFI_ERROR(Status
))
1134 debug("FS:%u Protocol:%p OpenVolume:%p", i
, pFile
, pFile
->OpenVolume
);
1136 Status
= gBS
->OpenProtocol(Handles
[i
], &gEfiDevicePathProtocolGuid
,
1140 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1141 if (EFI_ERROR(Status
))
1143 debug("Failed to open device path protocol %r", Status
);
1147 debug("Handle:%p FS DP: <%s>", Handles
[i
], ConvertDevicePathToText(pDevPath
, FALSE
, FALSE
));
1148 if (CompareMem(gBlockData
.Path
, pDevPath
, gBlockData
.DevicePathCompareLen
))
1150 debug("Not ventoy disk file system");
1154 for (j
= gBootFileStartIndex
; j
< ARRAY_SIZE(gEfiBootFileName
); j
++)
1156 Status
= ventoy_load_image(ImageHandle
, pDevPath
, gEfiBootFileName
[j
],
1157 StrSize(gEfiBootFileName
[j
]), &Image
);
1158 if (EFI_SUCCESS
== Status
)
1162 debug("Failed to load image %r <%s>", Status
, gEfiBootFileName
[j
]);
1165 if (j
>= ARRAY_SIZE(gEfiBootFileName
))
1171 debug("Find boot file, now try to boot .....");
1172 ventoy_debug_pause();
1176 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
1177 //ventoy_wrapper_system();
1180 if (g_file_replace_list
&& g_file_replace_list
->magic
== GRUB_FILE_REPLACE_MAGIC
)
1182 g_original_open_volume
= pFile
->OpenVolume
;
1183 pFile
->OpenVolume
= ventoy_wrapper_open_volume
;
1186 Status
= gBS
->StartImage(Image
, NULL
, NULL
);
1187 if (EFI_ERROR(Status
))
1189 debug("Failed to start image %r", Status
);
1191 gBS
->UnloadImage(Image
);
1200 debug("Fs not found, now wait and retry...");
1207 return EFI_NOT_FOUND
;
1213 EFI_STATUS EFIAPI
ventoy_clean_env(VOID
)
1215 FreePool(g_sector_flag
);
1216 g_sector_flag_num
= 0;
1218 if (gLoadIsoEfi
&& gBlockData
.IsoDriverImage
)
1220 gBS
->UnloadImage(gBlockData
.IsoDriverImage
);
1223 gBS
->DisconnectController(gBlockData
.Handle
, NULL
, NULL
);
1225 gBS
->UninstallMultipleProtocolInterfaces(gBlockData
.Handle
,
1226 &gEfiBlockIoProtocolGuid
, &gBlockData
.BlockIo
,
1227 &gEfiDevicePathProtocolGuid
, gBlockData
.Path
,
1230 ventoy_delete_variable();
1232 if (g_chain
->os_param
.vtoy_img_location_addr
)
1234 FreePool((VOID
*)(UINTN
)g_chain
->os_param
.vtoy_img_location_addr
);
1240 EFI_STATUS EFIAPI
ventoy_ramdisk_boot(IN EFI_HANDLE ImageHandle
)
1242 EFI_STATUS Status
= EFI_SUCCESS
;
1243 EFI_RAM_DISK_PROTOCOL
*RamDisk
= NULL
;
1244 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
= NULL
;
1246 debug("RamDisk Boot ...");
1248 Status
= gBS
->LocateProtocol(&gEfiRamDiskProtocolGuid
, NULL
, (VOID
**)&RamDisk
);
1249 if (EFI_ERROR(Status
))
1251 debug("Failed to locate ramdisk protocol %r", Status
);
1254 debug("Locate RamDisk Protocol %r ...", Status
);
1256 Status
= RamDisk
->Register((UINTN
)g_chain
, (UINT64
)g_iso_buf_size
, &gEfiVirtualCdGuid
, NULL
, &DevicePath
);
1257 if (EFI_ERROR(Status
))
1259 debug("Failed to register ramdisk %r", Status
);
1263 debug("Register RamDisk %r ...", Status
);
1264 debug("RamDisk DevicePath:<%s> ...", ConvertDevicePathToText(DevicePath
, FALSE
, FALSE
));
1266 ventoy_debug_pause();
1268 gBlockData
.Path
= DevicePath
;
1269 gBlockData
.DevicePathCompareLen
= GetDevicePathSize(DevicePath
) - sizeof(EFI_DEVICE_PATH_PROTOCOL
);
1271 Status
= ventoy_boot(ImageHandle
);
1272 if (EFI_NOT_FOUND
== Status
)
1274 gST
->ConOut
->OutputString(gST
->ConOut
, L
"No bootfile found for UEFI!\r\n");
1275 gST
->ConOut
->OutputString(gST
->ConOut
, L
"Maybe the image does not support " VENTOY_UEFI_DESC L
"!\r\n");
1282 EFI_STATUS EFIAPI VentoyEfiMain
1284 IN EFI_HANDLE ImageHandle
,
1285 IN EFI_SYSTEM_TABLE
*SystemTable
1288 EFI_STATUS Status
= EFI_SUCCESS
;
1290 g_sector_flag_num
= 512; /* initial value */
1292 g_sector_flag
= AllocatePool(g_sector_flag_num
* sizeof(ventoy_sector_flag
));
1293 if (NULL
== g_sector_flag
)
1295 return EFI_OUT_OF_RESOURCES
;
1298 gST
->ConOut
->ClearScreen(gST
->ConOut
);
1299 ventoy_clear_input();
1301 ventoy_parse_cmdline(ImageHandle
);
1305 g_ramdisk_param
.PhyAddr
= (UINT64
)(UINTN
)g_chain
;
1306 g_ramdisk_param
.DiskSize
= (UINT64
)g_iso_buf_size
;
1308 ventoy_save_ramdisk_param();
1310 ventoy_install_blockio(ImageHandle
, g_iso_buf_size
);
1311 Status
= ventoy_boot(ImageHandle
);
1312 if (EFI_NOT_FOUND
== Status
)
1314 gST
->ConOut
->OutputString(gST
->ConOut
, L
"No bootfile found for UEFI!\r\n");
1315 gST
->ConOut
->OutputString(gST
->ConOut
, L
"Maybe the image does not support " VENTOY_UEFI_DESC L
"!\r\n");
1319 ventoy_del_ramdisk_param();
1323 ventoy_set_variable();
1324 ventoy_find_iso_disk(ImageHandle
);
1328 ventoy_find_iso_disk_fs(ImageHandle
);
1329 ventoy_load_isoefi_driver(ImageHandle
);
1332 ventoy_debug_pause();
1334 ventoy_install_blockio(ImageHandle
, g_chain
->virt_img_size_in_bytes
);
1336 ventoy_debug_pause();
1338 Status
= ventoy_boot(ImageHandle
);
1339 if (EFI_NOT_FOUND
== Status
)
1344 ventoy_find_iso_disk_fs(ImageHandle
);
1345 ventoy_load_isoefi_driver(ImageHandle
);
1347 Status
= ventoy_boot(ImageHandle
);
1350 if (EFI_NOT_FOUND
== Status
)
1352 gST
->ConOut
->OutputString(gST
->ConOut
, L
"No bootfile found for UEFI!\r\n");
1353 gST
->ConOut
->OutputString(gST
->ConOut
, L
"Maybe the image does not support " VENTOY_UEFI_DESC L
"!\r\n");
1361 ventoy_clear_input();
1362 gST
->ConOut
->ClearScreen(gST
->ConOut
);