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