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
;
42 ventoy_sector_flag
*g_sector_flag
= NULL
;
43 UINT32 g_sector_flag_num
= 0;
45 EFI_FILE_OPEN g_original_fopen
= NULL
;
46 EFI_FILE_CLOSE g_original_fclose
= NULL
;
47 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME g_original_open_volume
= NULL
;
49 /* EFI block device vendor device path GUID */
50 EFI_GUID gVtoyBlockDevicePathGuid
= VTOY_BLOCK_DEVICE_PATH_GUID
;
52 #define VENTOY_ISO9660_SECTOR_OVERFLOW 2097152
54 BOOLEAN g_fixup_iso9660_secover_enable
= FALSE
;
55 BOOLEAN g_fixup_iso9660_secover_start
= FALSE
;
56 UINT64 g_fixup_iso9660_secover_1st_secs
= 0;
57 UINT64 g_fixup_iso9660_secover_cur_secs
= 0;
58 UINT64 g_fixup_iso9660_secover_tot_secs
= 0;
60 EFI_STATUS EFIAPI ventoy_block_io_reset
62 IN EFI_BLOCK_IO_PROTOCOL
*This
,
63 IN BOOLEAN ExtendedVerification
67 (VOID
)ExtendedVerification
;
71 STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
78 EFI_STATUS Status
= EFI_SUCCESS
;
85 UINT64 OverrideStart
= 0;
86 UINT64 OverrideEnd
= 0;
87 UINT8
*pCurBuf
= (UINT8
*)Buffer
;
88 ventoy_img_chunk
*pchunk
= g_chunk
;
89 ventoy_override_chunk
*pOverride
= g_override_chunk
;
90 EFI_BLOCK_IO_PROTOCOL
*pRawBlockIo
= gBlockData
.pRawBlockIo
;
92 debug("read iso sector %lu count %u", Sector
, Count
);
94 ReadStart
= Sector
* 2048;
95 ReadEnd
= (Sector
+ Count
) * 2048;
97 for (i
= 0; Count
> 0 && i
< g_img_chunk_num
; i
++, pchunk
++)
99 if (Sector
>= pchunk
->img_start_sector
&& Sector
<= pchunk
->img_end_sector
)
101 if (g_chain
->disk_sector_size
== 512)
103 MapLba
= (Sector
- pchunk
->img_start_sector
) * 4 + pchunk
->disk_start_sector
;
107 MapLba
= (Sector
- pchunk
->img_start_sector
) * 2048 / g_chain
->disk_sector_size
+ pchunk
->disk_start_sector
;
110 secLeft
= pchunk
->img_end_sector
+ 1 - Sector
;
111 secRead
= (Count
< secLeft
) ? Count
: secLeft
;
113 Status
= pRawBlockIo
->ReadBlocks(pRawBlockIo
, pRawBlockIo
->Media
->MediaId
,
114 MapLba
, secRead
* 2048, pCurBuf
);
115 if (EFI_ERROR(Status
))
117 debug("Raw disk read block failed %r", Status
);
123 pCurBuf
+= secRead
* 2048;
127 if (ReadStart
> g_chain
->real_img_size_in_bytes
)
133 pCurBuf
= (UINT8
*)Buffer
;
134 for (i
= 0; i
< g_override_chunk_num
; i
++, pOverride
++)
136 OverrideStart
= pOverride
->img_offset
;
137 OverrideEnd
= pOverride
->img_offset
+ pOverride
->override_size
;
139 if (OverrideStart
>= ReadEnd
|| ReadStart
>= OverrideEnd
)
144 if (ReadStart
<= OverrideStart
)
146 if (ReadEnd
<= OverrideEnd
)
148 CopyMem(pCurBuf
+ OverrideStart
- ReadStart
, pOverride
->override_data
, ReadEnd
- OverrideStart
);
152 CopyMem(pCurBuf
+ OverrideStart
- ReadStart
, pOverride
->override_data
, pOverride
->override_size
);
157 if (ReadEnd
<= OverrideEnd
)
159 CopyMem(pCurBuf
, pOverride
->override_data
+ ReadStart
- OverrideStart
, ReadEnd
- ReadStart
);
163 CopyMem(pCurBuf
, pOverride
->override_data
+ ReadStart
- OverrideStart
, OverrideEnd
- ReadStart
);
167 if (g_fixup_iso9660_secover_enable
&& (!g_fixup_iso9660_secover_start
) &&
168 pOverride
->override_size
== sizeof(ventoy_iso9660_override
))
170 ventoy_iso9660_override
*dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
171 if (dirent
->first_sector
>= VENTOY_ISO9660_SECTOR_OVERFLOW
)
173 g_fixup_iso9660_secover_start
= TRUE
;
174 g_fixup_iso9660_secover_cur_secs
= 0;
182 EFI_STATUS EFIAPI ventoy_block_io_ramdisk_read
184 IN EFI_BLOCK_IO_PROTOCOL
*This
,
191 //debug("### ventoy_block_io_ramdisk_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
196 CopyMem(Buffer
, (char *)g_chain
+ (Lba
* 2048), BufferSize
);
201 EFI_LBA EFIAPI
ventoy_fixup_iso9660_sector(IN EFI_LBA Lba
, UINT32 secNum
)
205 if (g_fixup_iso9660_secover_cur_secs
> 0)
207 Lba
+= VENTOY_ISO9660_SECTOR_OVERFLOW
;
208 g_fixup_iso9660_secover_cur_secs
+= secNum
;
209 if (g_fixup_iso9660_secover_cur_secs
>= g_fixup_iso9660_secover_tot_secs
)
211 g_fixup_iso9660_secover_start
= FALSE
;
217 ventoy_iso9660_override
*dirent
;
218 ventoy_override_chunk
*pOverride
;
220 for (i
= 0, pOverride
= g_override_chunk
; i
< g_override_chunk_num
; i
++, pOverride
++)
222 dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
223 if (Lba
== dirent
->first_sector
)
225 g_fixup_iso9660_secover_start
= FALSE
;
230 if (g_fixup_iso9660_secover_start
)
232 for (i
= 0, pOverride
= g_override_chunk
; i
< g_override_chunk_num
; i
++, pOverride
++)
234 dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
235 if (Lba
+ VENTOY_ISO9660_SECTOR_OVERFLOW
== dirent
->first_sector
)
237 g_fixup_iso9660_secover_tot_secs
= (dirent
->size
+ 2047) / 2048;
238 g_fixup_iso9660_secover_cur_secs
= secNum
;
239 if (g_fixup_iso9660_secover_cur_secs
>= g_fixup_iso9660_secover_tot_secs
)
241 g_fixup_iso9660_secover_start
= FALSE
;
243 Lba
+= VENTOY_ISO9660_SECTOR_OVERFLOW
;
254 EFI_STATUS EFIAPI ventoy_block_io_read
256 IN EFI_BLOCK_IO_PROTOCOL
*This
,
271 ventoy_sector_flag
*cur_flag
;
272 ventoy_virt_chunk
*node
;
274 //debug("### ventoy_block_io_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
276 secNum
= BufferSize
/ 2048;
278 /* Workaround for SSTR PE loader error */
279 if (g_fixup_iso9660_secover_start
)
281 Lba
= ventoy_fixup_iso9660_sector(Lba
, secNum
);
286 if (offset
+ BufferSize
<= g_chain
->real_img_size_in_bytes
)
288 return ventoy_read_iso_sector(Lba
, secNum
, Buffer
);
291 if (secNum
> g_sector_flag_num
)
293 cur_flag
= AllocatePool(secNum
* sizeof(ventoy_sector_flag
));
294 if (NULL
== cur_flag
)
296 return EFI_OUT_OF_RESOURCES
;
299 FreePool(g_sector_flag
);
300 g_sector_flag
= cur_flag
;
301 g_sector_flag_num
= secNum
;
304 for (curlba
= Lba
, cur_flag
= g_sector_flag
, j
= 0; j
< secNum
; j
++, curlba
++, cur_flag
++)
307 for (node
= g_virt_chunk
, i
= 0; i
< g_virt_chunk_num
; i
++, node
++)
309 if (curlba
>= node
->mem_sector_start
&& curlba
< node
->mem_sector_end
)
311 CopyMem((UINT8
*)Buffer
+ j
* 2048,
312 (char *)g_virt_chunk
+ node
->mem_sector_offset
+ (curlba
- node
->mem_sector_start
) * 2048,
317 else if (curlba
>= node
->remap_sector_start
&& curlba
< node
->remap_sector_end
)
319 cur_flag
->remap_lba
= node
->org_sector_start
+ curlba
- node
->remap_sector_start
;
326 for (curlba
= Lba
, cur_flag
= g_sector_flag
, j
= 0; j
< secNum
; j
++, curlba
++, cur_flag
++)
328 if (cur_flag
->flag
== 2)
332 lastbuffer
= (UINT8
*)Buffer
+ j
* 2048;
333 lastlba
= cur_flag
->remap_lba
;
336 else if (lastlba
+ lbacount
== cur_flag
->remap_lba
)
342 ventoy_read_iso_sector(lastlba
, lbacount
, lastbuffer
);
343 lastbuffer
= (UINT8
*)Buffer
+ j
* 2048;
344 lastlba
= cur_flag
->remap_lba
;
352 ventoy_read_iso_sector(lastlba
, lbacount
, lastbuffer
);
358 EFI_STATUS EFIAPI ventoy_block_io_write
360 IN EFI_BLOCK_IO_PROTOCOL
*This
,
372 return EFI_WRITE_PROTECTED
;
375 EFI_STATUS EFIAPI
ventoy_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL
*This
)
382 EFI_STATUS EFIAPI
ventoy_fill_device_path(VOID
)
385 UINT8 TmpBuf
[128] = {0};
386 VENDOR_DEVICE_PATH
*venPath
= NULL
;
388 venPath
= (VENDOR_DEVICE_PATH
*)TmpBuf
;
389 NameLen
= StrSize(VTOY_BLOCK_DEVICE_PATH_NAME
);
390 venPath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
391 venPath
->Header
.SubType
= HW_VENDOR_DP
;
392 venPath
->Header
.Length
[0] = sizeof(VENDOR_DEVICE_PATH
) + NameLen
;
393 venPath
->Header
.Length
[1] = 0;
394 CopyMem(&venPath
->Guid
, &gVtoyBlockDevicePathGuid
, sizeof(EFI_GUID
));
395 CopyMem(venPath
+ 1, VTOY_BLOCK_DEVICE_PATH_NAME
, NameLen
);
397 gBlockData
.Path
= AppendDevicePathNode(NULL
, (EFI_DEVICE_PATH_PROTOCOL
*)TmpBuf
);
398 gBlockData
.DevicePathCompareLen
= sizeof(VENDOR_DEVICE_PATH
) + NameLen
;
400 debug("gBlockData.Path=<%s>\n", ConvertDevicePathToText(gBlockData
.Path
, FALSE
, FALSE
));
405 EFI_STATUS EFIAPI
ventoy_connect_driver(IN EFI_HANDLE ControllerHandle
, IN CONST CHAR16
*DrvName
)
409 CHAR16
*DriverName
= NULL
;
410 EFI_HANDLE
*Handles
= NULL
;
411 EFI_HANDLE DrvHandles
[2] = { NULL
};
412 EFI_STATUS Status
= EFI_SUCCESS
;
413 EFI_COMPONENT_NAME_PROTOCOL
*NameProtocol
= NULL
;
414 EFI_COMPONENT_NAME2_PROTOCOL
*Name2Protocol
= NULL
;
416 debug("ventoy_connect_driver <%s>...", DrvName
);
418 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiComponentName2ProtocolGuid
,
419 NULL
, &Count
, &Handles
);
420 if (EFI_ERROR(Status
))
425 for (i
= 0; i
< Count
; i
++)
427 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiComponentName2ProtocolGuid
, (VOID
**)&Name2Protocol
);
428 if (EFI_ERROR(Status
))
433 Status
= Name2Protocol
->GetDriverName(Name2Protocol
, "en", &DriverName
);
434 if (EFI_ERROR(Status
) || NULL
== DriverName
)
439 if (StrStr(DriverName
, DrvName
))
441 debug("Find driver name2:<%s>: <%s>", DriverName
, DrvName
);
442 DrvHandles
[0] = Handles
[i
];
449 Status
= gBS
->ConnectController(ControllerHandle
, DrvHandles
, NULL
, TRUE
);
450 debug("Connect partition driver:<%r>", Status
);
454 debug("%s NOT found, now try COMPONENT_NAME", DrvName
);
460 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiComponentNameProtocolGuid
,
461 NULL
, &Count
, &Handles
);
462 if (EFI_ERROR(Status
))
467 for (i
= 0; i
< Count
; i
++)
469 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiComponentNameProtocolGuid
, (VOID
**)&NameProtocol
);
470 if (EFI_ERROR(Status
))
475 Status
= NameProtocol
->GetDriverName(NameProtocol
, "en", &DriverName
);
476 if (EFI_ERROR(Status
))
481 if (StrStr(DriverName
, DrvName
))
483 debug("Find driver name:<%s>: <%s>", DriverName
, DrvName
);
484 DrvHandles
[0] = Handles
[i
];
491 Status
= gBS
->ConnectController(ControllerHandle
, DrvHandles
, NULL
, TRUE
);
492 debug("Connect partition driver:<%r>", Status
);
496 Status
= EFI_NOT_FOUND
;
504 EFI_STATUS EFIAPI
ventoy_install_blockio(IN EFI_HANDLE ImageHandle
, IN UINT64 ImgSize
)
506 EFI_STATUS Status
= EFI_SUCCESS
;
507 EFI_BLOCK_IO_PROTOCOL
*pBlockIo
= &(gBlockData
.BlockIo
);
509 ventoy_fill_device_path();
511 gBlockData
.Media
.BlockSize
= 2048;
512 gBlockData
.Media
.LastBlock
= ImgSize
/ 2048 - 1;
513 gBlockData
.Media
.ReadOnly
= TRUE
;
514 gBlockData
.Media
.MediaPresent
= 1;
515 gBlockData
.Media
.LogicalBlocksPerPhysicalBlock
= 1;
517 pBlockIo
->Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
518 pBlockIo
->Media
= &(gBlockData
.Media
);
519 pBlockIo
->Reset
= ventoy_block_io_reset
;
520 pBlockIo
->ReadBlocks
= gMemdiskMode
? ventoy_block_io_ramdisk_read
: ventoy_block_io_read
;
521 pBlockIo
->WriteBlocks
= ventoy_block_io_write
;
522 pBlockIo
->FlushBlocks
= ventoy_block_io_flush
;
524 Status
= gBS
->InstallMultipleProtocolInterfaces(&gBlockData
.Handle
,
525 &gEfiBlockIoProtocolGuid
, &gBlockData
.BlockIo
,
526 &gEfiDevicePathProtocolGuid
, gBlockData
.Path
,
528 debug("Install protocol %r %p", Status
, gBlockData
.Handle
);
529 if (EFI_ERROR(Status
))
534 Status
= ventoy_connect_driver(gBlockData
.Handle
, L
"Disk I/O Driver");
535 debug("Connect disk IO driver %r", Status
);
536 ventoy_debug_pause();
538 Status
= ventoy_connect_driver(gBlockData
.Handle
, L
"Partition Driver");
539 debug("Connect partition driver %r", Status
);
540 if (EFI_ERROR(Status
))
542 Status
= gBS
->ConnectController(gBlockData
.Handle
, NULL
, NULL
, TRUE
);
543 debug("Connect all controller %r", Status
);
546 ventoy_debug_pause();
551 EFI_STATUS EFIAPI ventoy_wrapper_file_open
553 EFI_FILE_HANDLE This
,
554 EFI_FILE_HANDLE
*New
,
563 EFI_STATUS Status
= EFI_SUCCESS
;
565 ventoy_virt_chunk
*virt
= NULL
;
567 Status
= g_original_fopen(This
, New
, Name
, Mode
, Attributes
);
568 if (EFI_ERROR(Status
))
573 if (g_file_replace_list
&& g_file_replace_list
->magic
== GRUB_FILE_REPLACE_MAGIC
&&
574 g_file_replace_list
->new_file_virtual_id
< g_virt_chunk_num
)
576 AsciiSPrint(TmpName
, sizeof(TmpName
), "%s", Name
);
577 for (j
= 0; j
< 4; j
++)
579 if (0 == AsciiStrCmp(g_file_replace_list
[i
].old_file_name
[j
], TmpName
))
581 g_original_fclose(*New
);
582 *New
= &g_efi_file_replace
.WrapperHandle
;
583 ventoy_wrapper_file_procotol(*New
);
585 virt
= g_virt_chunk
+ g_file_replace_list
->new_file_virtual_id
;
587 Sectors
= (virt
->mem_sector_end
- virt
->mem_sector_start
) + (virt
->remap_sector_end
- virt
->remap_sector_start
);
589 g_efi_file_replace
.BlockIoSectorStart
= virt
->mem_sector_start
;
590 g_efi_file_replace
.FileSizeBytes
= Sectors
* 2048;
594 debug("## ventoy_wrapper_file_open <%s> BlockStart:%lu Sectors:%lu Bytes:%lu", Name
,
595 g_efi_file_replace
.BlockIoSectorStart
, Sectors
, Sectors
* 2048);
607 EFI_STATUS EFIAPI ventoy_wrapper_open_volume
609 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*This
,
610 OUT EFI_FILE_PROTOCOL
**Root
613 EFI_STATUS Status
= EFI_SUCCESS
;
615 Status
= g_original_open_volume(This
, Root
);
616 if (!EFI_ERROR(Status
))
618 g_original_fopen
= (*Root
)->Open
;
619 g_original_fclose
= (*Root
)->Close
;
620 (*Root
)->Open
= ventoy_wrapper_file_open
;
626 EFI_STATUS EFIAPI
ventoy_wrapper_push_openvolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume
)
628 g_original_open_volume
= OpenVolume
;