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