1 /******************************************************************************
4 * Copyright (c) 2021, 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 <Library/UefiDecompressLib.h>
32 #include <Protocol/LoadedImage.h>
33 #include <Guid/FileInfo.h>
34 #include <Guid/FileSystemInfo.h>
35 #include <Protocol/BlockIo.h>
36 #include <Protocol/RamDisk.h>
37 #include <Protocol/SimpleFileSystem.h>
38 #include <VDiskChain.h>
40 BOOLEAN gVDiskDebugPrint
= FALSE
;
41 vdisk_block_data gVDiskBlockData
;
44 CONST CHAR16
*gEfiBootFileName
[] =
47 EFI_REMOVABLE_MEDIA_FILE_NAME
,
48 #if defined (MDE_CPU_IA32)
49 L
"\\EFI\\BOOT\\GRUBIA32.EFI",
50 L
"\\EFI\\BOOT\\BOOTia32.EFI",
51 L
"\\EFI\\BOOT\\bootia32.efi",
52 L
"\\efi\\boot\\bootia32.efi",
53 #elif defined (MDE_CPU_X64)
54 L
"\\EFI\\BOOT\\GRUBX64.EFI",
55 L
"\\EFI\\BOOT\\BOOTx64.EFI",
56 L
"\\EFI\\BOOT\\bootx64.efi",
57 L
"\\efi\\boot\\bootx64.efi",
58 #elif defined (MDE_CPU_ARM)
59 L
"\\EFI\\BOOT\\GRUBARM.EFI",
60 L
"\\EFI\\BOOT\\BOOTarm.EFI",
61 L
"\\EFI\\BOOT\\bootarm.efi",
62 L
"\\efi\\boot\\bootarm.efi",
63 #elif defined (MDE_CPU_AARCH64)
64 L
"\\EFI\\BOOT\\GRUBAA64.EFI",
65 L
"\\EFI\\BOOT\\BOOTaa64.EFI",
66 L
"\\EFI\\BOOT\\bootaa64.efi",
67 L
"\\efi\\boot\\bootaa64.efi",
72 UINT8
*g_disk_buf_addr
= NULL
;
73 UINT64 g_disk_buf_size
= 0;
75 VOID EFIAPI
VDiskDebug(IN CONST CHAR8
*Format
, ...)
80 VA_START (Marker
, Format
);
81 UnicodeVSPrintAsciiFormat(Buffer
, sizeof(Buffer
), Format
, Marker
);
84 gST
->ConOut
->OutputString(gST
->ConOut
, Buffer
);
87 VOID EFIAPI
vdisk_clear_input(VOID
)
91 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
92 while (EFI_SUCCESS
== gST
->ConIn
->ReadKeyStroke(gST
->ConIn
, &Key
))
96 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
99 STATIC EFI_STATUS EFIAPI vdisk_load_image
101 IN EFI_HANDLE ImageHandle
,
102 IN EFI_DEVICE_PATH_PROTOCOL
*pDevicePath
,
103 IN CONST CHAR16
*FileName
,
104 IN UINTN FileNameLen
,
105 OUT EFI_HANDLE
*Image
108 EFI_STATUS Status
= EFI_SUCCESS
;
109 CHAR16 TmpBuf
[256] = {0};
110 FILEPATH_DEVICE_PATH
*pFilePath
= NULL
;
111 EFI_DEVICE_PATH_PROTOCOL
*pImgPath
= NULL
;
113 pFilePath
= (FILEPATH_DEVICE_PATH
*)TmpBuf
;
114 pFilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
115 pFilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
116 pFilePath
->Header
.Length
[0] = FileNameLen
+ sizeof(EFI_DEVICE_PATH_PROTOCOL
);
117 pFilePath
->Header
.Length
[1] = 0;
118 CopyMem(pFilePath
->PathName
, FileName
, FileNameLen
);
120 pImgPath
= AppendDevicePathNode(pDevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)pFilePath
);
123 return EFI_NOT_FOUND
;
126 Status
= gBS
->LoadImage(FALSE
, ImageHandle
, pImgPath
, NULL
, 0, Image
);
128 debug("Load Image File %r DP: <%s>", Status
, ConvertDevicePathToText(pImgPath
, FALSE
, FALSE
));
135 STATIC EFI_STATUS EFIAPI
vdisk_decompress_vdisk(IN EFI_LOADED_IMAGE_PROTOCOL
*pImageInfo
)
138 UINT32 DestinationSize
;
142 EFI_STATUS Status
= EFI_SUCCESS
;
146 vdisk_get_vdisk_raw(&buf
, &Size
);
147 UefiDecompressGetInfo(buf
+ VDISK_MAGIC_LEN
, Size
- VDISK_MAGIC_LEN
, &DestinationSize
, &ScratchSize
);
148 debug("vdisk: size:%u realsize:%u", Size
, DestinationSize
);
150 g_disk_buf_size
= DestinationSize
;
151 g_disk_buf_addr
= AllocatePool(DestinationSize
);
152 ScratchBuf
= AllocatePool(ScratchSize
);
154 Status
= UefiDecompress(buf
+ VDISK_MAGIC_LEN
, g_disk_buf_addr
, ScratchBuf
);
155 FreePool(ScratchBuf
);
157 debug("Status:%r %p %u", Status
, g_disk_buf_addr
, (UINT32
)g_disk_buf_size
);
162 STATIC EFI_STATUS
vdisk_patch_vdisk_path(CHAR16
*pos
)
167 CHAR8
*buf
= (char *)g_disk_buf_addr
;
174 end
= StrStr(pos
, L
".vtoy");
175 end
+= 5;//string length
177 for (i
= 0; i
< g_disk_buf_size
; i
++)
179 if (*(UINT32
*)(buf
+ i
) == 0x59595959)
181 for (j
= 0; j
< 300; j
++)
183 if (buf
[i
+ j
] != 'Y')
196 if (i
>= g_disk_buf_size
)
198 debug("No need to fill vdisk path");
202 debug("Fill vdisk path at %d", i
);
206 buf
[i
++] = (CHAR8
)(*pos
++);
211 while (buf
[i
] == 'Y' || buf
[i
] == '\"')
220 STATIC EFI_STATUS EFIAPI
vdisk_parse_cmdline(IN EFI_HANDLE ImageHandle
)
223 CHAR16
*pCmdLine
= NULL
;
224 EFI_STATUS Status
= EFI_SUCCESS
;
225 EFI_LOADED_IMAGE_PROTOCOL
*pImageInfo
= NULL
;
227 Status
= gBS
->HandleProtocol(ImageHandle
, &gEfiLoadedImageProtocolGuid
, (VOID
**)&pImageInfo
);
228 if (EFI_ERROR(Status
))
230 VDiskDebug("Failed to handle load image protocol %r\n", Status
);
234 pCmdLine
= (CHAR16
*)AllocatePool(pImageInfo
->LoadOptionsSize
+ 4);
235 SetMem(pCmdLine
, pImageInfo
->LoadOptionsSize
+ 4, 0);
236 CopyMem(pCmdLine
, pImageInfo
->LoadOptions
, pImageInfo
->LoadOptionsSize
);
238 if (StrStr(pCmdLine
, L
"debug"))
240 gVDiskDebugPrint
= TRUE
;
243 debug("cmdline:<%s>", pCmdLine
);
246 Pos
= StrStr(pCmdLine
, L
"vdisk=");
247 if (NULL
== Pos
|| NULL
== StrStr(pCmdLine
, L
".vtoy"))
249 VDiskDebug("vdisk parameter not found!\n");
250 return EFI_NOT_FOUND
;
253 vdisk_decompress_vdisk(pImageInfo
);
255 vdisk_patch_vdisk_path(Pos
+ 6);
261 EFI_STATUS EFIAPI
vdisk_boot(IN EFI_HANDLE ImageHandle
)
268 EFI_HANDLE Image
= NULL
;
269 EFI_HANDLE
*Handles
= NULL
;
270 EFI_STATUS Status
= EFI_SUCCESS
;
271 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*pFile
= NULL
;
272 EFI_DEVICE_PATH_PROTOCOL
*pDevPath
= NULL
;
274 for (t
= 0; t
< 3; t
++)
279 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
,
280 NULL
, &Count
, &Handles
);
281 if (EFI_ERROR(Status
))
286 debug("vdisk_boot fs count:%u", Count
);
288 for (i
= 0; i
< Count
; i
++)
290 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&pFile
);
291 if (EFI_ERROR(Status
))
296 debug("FS:%u Protocol:%p OpenVolume:%p", i
, pFile
, pFile
->OpenVolume
);
298 Status
= gBS
->OpenProtocol(Handles
[i
], &gEfiDevicePathProtocolGuid
,
302 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
303 if (EFI_ERROR(Status
))
305 debug("Failed to open device path protocol %r", Status
);
309 debug("Handle:%p FS DP: <%s>", Handles
[i
], ConvertDevicePathToText(pDevPath
, FALSE
, FALSE
));
310 if (CompareMem(gVDiskBlockData
.Path
, pDevPath
, gVDiskBlockData
.DevicePathCompareLen
))
312 debug("Not ventoy disk file system");
316 for (j
= 1; j
< ARRAY_SIZE(gEfiBootFileName
); j
++)
318 Status
= vdisk_load_image(ImageHandle
, pDevPath
, gEfiBootFileName
[j
],
319 StrSize(gEfiBootFileName
[j
]), &Image
);
320 if (EFI_SUCCESS
== Status
)
324 debug("Failed to load image %r <%s>", Status
, gEfiBootFileName
[j
]);
327 if (j
>= ARRAY_SIZE(gEfiBootFileName
))
333 debug("Find boot file, now try to boot .....");
336 if (gVDiskDebugPrint
)
338 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
341 /* can't add debug print here */
342 //ventoy_wrapper_system();
343 Status
= gBS
->StartImage(Image
, NULL
, NULL
);
344 if (EFI_ERROR(Status
))
346 debug("Failed to start image %r", Status
);
348 gBS
->UnloadImage(Image
);
357 debug("Fs not found, now wait and retry...");
364 return EFI_NOT_FOUND
;
370 EFI_STATUS EFIAPI VDiskChainEfiMain
372 IN EFI_HANDLE ImageHandle
,
373 IN EFI_SYSTEM_TABLE
*SystemTable
376 EFI_STATUS Status
= EFI_SUCCESS
;
378 gST
->ConOut
->ClearScreen(gST
->ConOut
);
381 Status
= vdisk_parse_cmdline(ImageHandle
);
382 if (EFI_ERROR(Status
))
387 vdisk_install_blockio(ImageHandle
, g_disk_buf_size
);
390 Status
= vdisk_boot(ImageHandle
);
392 gBS
->DisconnectController(gVDiskBlockData
.Handle
, NULL
, NULL
);
393 gBS
->UninstallMultipleProtocolInterfaces(gVDiskBlockData
.Handle
,
394 &gEfiBlockIoProtocolGuid
, &gVDiskBlockData
.BlockIo
,
395 &gEfiDevicePathProtocolGuid
, gVDiskBlockData
.Path
,
398 if (EFI_NOT_FOUND
== Status
)
400 gST
->ConOut
->OutputString(gST
->ConOut
, L
"No bootfile found for UEFI!\r\n");
401 gST
->ConOut
->OutputString(gST
->ConOut
, L
"Maybe the image does not support " VENTOY_UEFI_DESC L
"!\r\n");
406 gST
->ConOut
->ClearScreen(gST
->ConOut
);