mirror of
				https://github.com/ventoy/Ventoy.git
				synced 2025-10-30 00:05:09 -04:00 
			
		
		
		
	add vdiskchain module
This commit is contained in:
		
							parent
							
								
									8f711c9db9
								
							
						
					
					
						commit
						8632e56561
					
				
							
								
								
									
										59
									
								
								EDK2/build.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								EDK2/build.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| #!/bin/sh | ||||
| 
 | ||||
| if [ -z "$1" ]; then | ||||
|     EDKARCH=X64 | ||||
|     postfix=x64 | ||||
| elif [ "$1" = "ia32" ]; then | ||||
|     EDKARCH=IA32 | ||||
|     postfix=ia32 | ||||
|     shift | ||||
| elif [ "$1" = "aa64" ]; then | ||||
|     EDKARCH=AARCH64 | ||||
|     postfix=aa64 | ||||
|     shift | ||||
| fi | ||||
| 
 | ||||
| cd edk2-edk2-stable201911 | ||||
| 
 | ||||
| rm -rf ./Conf/.cache | ||||
| rm -f ./Conf/.AutoGenIdFile.txt | ||||
| 
 | ||||
| VTEFI_PATH=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/Ventoy/Ventoy/OUTPUT/Ventoy.efi | ||||
| DST_PATH=../../INSTALL/ventoy/ventoy_${postfix}.efi | ||||
| 
 | ||||
| VTEFI_PATH2=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/VtoyUtil/VtoyUtil/OUTPUT/VtoyUtil.efi | ||||
| DST_PATH2=../../INSTALL/ventoy/vtoyutil_${postfix}.efi | ||||
| 
 | ||||
| VTEFI_PATH3=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/VDiskChain/VDiskChain/OUTPUT/VDiskChain.efi | ||||
| DST_PATH3=../../VDiskChain/Tool/vdiskchain_${postfix}.efi | ||||
| 
 | ||||
| 
 | ||||
| rm -f $VTEFI_PATH | ||||
| rm -f $DST_PATH | ||||
| rm -f $VTEFI_PATH2 | ||||
| rm -f $DST_PATH2 | ||||
| rm -f $VTEFI_PATH3 | ||||
| rm -f $DST_PATH3 | ||||
| 
 | ||||
| source ./edksetup.sh | ||||
| 
 | ||||
| if [ "$EDKARCH" = "AARCH64" ]; then     | ||||
|     PATH=$PATH:/opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/bin \ | ||||
|     GCC48_AARCH64_PREFIX=aarch64-linux-gnu- \ | ||||
|     build -p MdeModulePkg/MdeModulePkg.dsc -a $EDKARCH -b RELEASE -t GCC48 | ||||
| else | ||||
|     build -p MdeModulePkg/MdeModulePkg.dsc -a $EDKARCH -b RELEASE -t GCC48 | ||||
| fi | ||||
| 
 | ||||
| if [ -e $VTEFI_PATH ] && [ -e $VTEFI_PATH2 ] && [ -e $VTEFI_PATH3 ]; then | ||||
|     echo -e '\n\n====================== SUCCESS ========================\n\n'     | ||||
|     cp -a $VTEFI_PATH $DST_PATH | ||||
|     cp -a $VTEFI_PATH2 $DST_PATH2 | ||||
|     cp -a $VTEFI_PATH3 $DST_PATH3 | ||||
|     cd .. | ||||
| else | ||||
|     echo -e '\n\n====================== FAILED ========================\n\n' | ||||
|     cd .. | ||||
|     exit 1 | ||||
| fi | ||||
| 
 | ||||
| @ -0,0 +1,410 @@ | ||||
| /******************************************************************************
 | ||||
|  * VDiskChain.c | ||||
|  * | ||||
|  * Copyright (c) 2021, longpanda <admin@ventoy.net> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  *  | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  *  | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <Uefi.h> | ||||
| #include <Library/DebugLib.h> | ||||
| #include <Library/PrintLib.h> | ||||
| #include <Library/UefiLib.h> | ||||
| #include <Library/BaseMemoryLib.h> | ||||
| #include <Library/DevicePathLib.h> | ||||
| #include <Library/MemoryAllocationLib.h> | ||||
| #include <Library/UefiBootServicesTableLib.h> | ||||
| #include <Library/UefiRuntimeServicesTableLib.h> | ||||
| #include <Library/UefiApplicationEntryPoint.h> | ||||
| #include <Library/UefiDecompressLib.h> | ||||
| #include <Protocol/LoadedImage.h> | ||||
| #include <Guid/FileInfo.h> | ||||
| #include <Guid/FileSystemInfo.h> | ||||
| #include <Protocol/BlockIo.h> | ||||
| #include <Protocol/RamDisk.h> | ||||
| #include <Protocol/SimpleFileSystem.h> | ||||
| #include <VDiskChain.h> | ||||
| 
 | ||||
| BOOLEAN gVDiskDebugPrint = FALSE; | ||||
| vdisk_block_data gVDiskBlockData; | ||||
| 
 | ||||
| /* Boot filename */ | ||||
| CONST CHAR16 *gEfiBootFileName[] =  | ||||
| { | ||||
|     L"@", | ||||
|     EFI_REMOVABLE_MEDIA_FILE_NAME, | ||||
| #if   defined (MDE_CPU_IA32) | ||||
|     L"\\EFI\\BOOT\\GRUBIA32.EFI", | ||||
|     L"\\EFI\\BOOT\\BOOTia32.EFI", | ||||
|     L"\\EFI\\BOOT\\bootia32.efi", | ||||
|     L"\\efi\\boot\\bootia32.efi", | ||||
| #elif defined (MDE_CPU_X64) | ||||
|     L"\\EFI\\BOOT\\GRUBX64.EFI", | ||||
|     L"\\EFI\\BOOT\\BOOTx64.EFI", | ||||
|     L"\\EFI\\BOOT\\bootx64.efi", | ||||
|     L"\\efi\\boot\\bootx64.efi", | ||||
| #elif defined (MDE_CPU_ARM) | ||||
|     L"\\EFI\\BOOT\\GRUBARM.EFI", | ||||
|     L"\\EFI\\BOOT\\BOOTarm.EFI", | ||||
|     L"\\EFI\\BOOT\\bootarm.efi", | ||||
|     L"\\efi\\boot\\bootarm.efi", | ||||
| #elif defined (MDE_CPU_AARCH64) | ||||
|     L"\\EFI\\BOOT\\GRUBAA64.EFI", | ||||
|     L"\\EFI\\BOOT\\BOOTaa64.EFI", | ||||
|     L"\\EFI\\BOOT\\bootaa64.efi", | ||||
|     L"\\efi\\boot\\bootaa64.efi", | ||||
| #endif | ||||
|      | ||||
| }; | ||||
| 
 | ||||
| UINT8 *g_disk_buf_addr = NULL; | ||||
| UINT64 g_disk_buf_size = 0; | ||||
|          | ||||
| VOID EFIAPI VDiskDebug(IN CONST CHAR8  *Format, ...) | ||||
| { | ||||
|     VA_LIST  Marker; | ||||
|     CHAR16   Buffer[512]; | ||||
| 
 | ||||
|     VA_START (Marker, Format); | ||||
|     UnicodeVSPrintAsciiFormat(Buffer, sizeof(Buffer), Format, Marker); | ||||
|     VA_END (Marker); | ||||
|      | ||||
|     gST->ConOut->OutputString(gST->ConOut, Buffer); | ||||
| } | ||||
| 
 | ||||
| VOID EFIAPI vdisk_clear_input(VOID) | ||||
| { | ||||
|     EFI_INPUT_KEY Key; | ||||
|      | ||||
|     gST->ConIn->Reset(gST->ConIn, FALSE); | ||||
|     while (EFI_SUCCESS == gST->ConIn->ReadKeyStroke(gST->ConIn, &Key)) | ||||
|     { | ||||
|         ; | ||||
|     } | ||||
|     gST->ConIn->Reset(gST->ConIn, FALSE); | ||||
| } | ||||
| 
 | ||||
| STATIC EFI_STATUS EFIAPI vdisk_load_image | ||||
| ( | ||||
|     IN EFI_HANDLE ImageHandle, | ||||
|     IN EFI_DEVICE_PATH_PROTOCOL *pDevicePath, | ||||
|     IN CONST CHAR16 *FileName, | ||||
|     IN UINTN FileNameLen, | ||||
|     OUT EFI_HANDLE *Image | ||||
| ) | ||||
| { | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
|     CHAR16 TmpBuf[256] = {0}; | ||||
|     FILEPATH_DEVICE_PATH *pFilePath = NULL; | ||||
|     EFI_DEVICE_PATH_PROTOCOL *pImgPath = NULL; | ||||
| 
 | ||||
|     pFilePath = (FILEPATH_DEVICE_PATH *)TmpBuf; | ||||
|     pFilePath->Header.Type = MEDIA_DEVICE_PATH; | ||||
|     pFilePath->Header.SubType = MEDIA_FILEPATH_DP; | ||||
|     pFilePath->Header.Length[0] = FileNameLen + sizeof(EFI_DEVICE_PATH_PROTOCOL); | ||||
|     pFilePath->Header.Length[1] = 0; | ||||
|     CopyMem(pFilePath->PathName, FileName, FileNameLen); | ||||
|      | ||||
|     pImgPath = AppendDevicePathNode(pDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)pFilePath); | ||||
|     if (!pImgPath) | ||||
|     { | ||||
|         return EFI_NOT_FOUND; | ||||
|     } | ||||
|      | ||||
|     Status = gBS->LoadImage(FALSE, ImageHandle, pImgPath, NULL, 0, Image); | ||||
|      | ||||
|     debug("Load Image File %r DP: <%s>", Status, ConvertDevicePathToText(pImgPath, FALSE, FALSE)); | ||||
| 
 | ||||
|     FreePool(pImgPath); | ||||
|      | ||||
|     return Status; | ||||
| } | ||||
| 
 | ||||
| STATIC EFI_STATUS EFIAPI vdisk_decompress_vdisk(IN EFI_LOADED_IMAGE_PROTOCOL *pImageInfo) | ||||
| { | ||||
|     UINT32 Size; | ||||
|     UINT32 DestinationSize; | ||||
|     UINT32 ScratchSize; | ||||
|     UINT8 *buf; | ||||
|     VOID  *ScratchBuf; | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
| 
 | ||||
|     (VOID)pImageInfo; | ||||
| 
 | ||||
|     vdisk_get_vdisk_raw(&buf, &Size); | ||||
|     UefiDecompressGetInfo(buf + VDISK_MAGIC_LEN, Size - VDISK_MAGIC_LEN, &DestinationSize, &ScratchSize); | ||||
|     debug("vdisk: size:%u realsize:%u", Size, DestinationSize); | ||||
| 
 | ||||
|     g_disk_buf_size = DestinationSize; | ||||
|     g_disk_buf_addr = AllocatePool(DestinationSize); | ||||
|     ScratchBuf = AllocatePool(ScratchSize); | ||||
|      | ||||
|     Status = UefiDecompress(buf + VDISK_MAGIC_LEN, g_disk_buf_addr, ScratchBuf); | ||||
|     FreePool(ScratchBuf); | ||||
| 
 | ||||
|     debug("Status:%r %p %u", Status, g_disk_buf_addr, (UINT32)g_disk_buf_size); | ||||
|      | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| STATIC EFI_STATUS vdisk_patch_vdisk_path(CHAR16 *pos) | ||||
| { | ||||
|     UINTN i; | ||||
|     UINTN j; | ||||
|     CHAR16 *end; | ||||
|     CHAR8 *buf = (char *)g_disk_buf_addr; | ||||
|      | ||||
|     if (*pos == L'\"') | ||||
|     { | ||||
|         pos++; | ||||
|     } | ||||
| 
 | ||||
|     end = StrStr(pos, L".vtoy"); | ||||
|     end += 5;//string length
 | ||||
|      | ||||
|     for (i = 0; i < g_disk_buf_size; i++) | ||||
|     { | ||||
|         if (*(UINT32 *)(buf + i) == 0x59595959) | ||||
|         { | ||||
|             for (j = 0; j < 300; j++) | ||||
|             { | ||||
|                 if (buf[i + j] != 'Y') | ||||
|                 { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (j >= 300) | ||||
|             { | ||||
|                 break;  | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (i >= g_disk_buf_size) | ||||
|     { | ||||
|         debug("No need to fill vdisk path"); | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     debug("Fill vdisk path at %d", i);         | ||||
| 
 | ||||
|     while (pos != end) | ||||
|     { | ||||
|         buf[i++] = (CHAR8)(*pos++); | ||||
|     } | ||||
| 
 | ||||
|     buf[i++] = '\"'; | ||||
|      | ||||
|     while (buf[i] == 'Y' || buf[i] == '\"') | ||||
|     { | ||||
|         buf[i] = ' '; | ||||
|         i++; | ||||
|     }    | ||||
| 
 | ||||
|     return 0;     | ||||
| } | ||||
| 
 | ||||
| STATIC EFI_STATUS EFIAPI vdisk_parse_cmdline(IN EFI_HANDLE ImageHandle) | ||||
| {    | ||||
|     CHAR16 *Pos = NULL; | ||||
|     CHAR16 *pCmdLine = NULL; | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
|     EFI_LOADED_IMAGE_PROTOCOL *pImageInfo = NULL; | ||||
| 
 | ||||
|     Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&pImageInfo); | ||||
|     if (EFI_ERROR(Status)) | ||||
|     { | ||||
|         VDiskDebug("Failed to handle load image protocol %r\n", Status); | ||||
|         return Status; | ||||
|     } | ||||
| 
 | ||||
|     pCmdLine = (CHAR16 *)AllocatePool(pImageInfo->LoadOptionsSize + 4); | ||||
|     SetMem(pCmdLine, pImageInfo->LoadOptionsSize + 4, 0); | ||||
|     CopyMem(pCmdLine, pImageInfo->LoadOptions, pImageInfo->LoadOptionsSize); | ||||
| 
 | ||||
|     if (StrStr(pCmdLine, L"debug")) | ||||
|     { | ||||
|         gVDiskDebugPrint = TRUE; | ||||
|     } | ||||
|      | ||||
|     debug("cmdline:<%s>", pCmdLine); | ||||
|     vdisk_debug_pause(); | ||||
| 
 | ||||
|     Pos = StrStr(pCmdLine, L"vdisk="); | ||||
|     if (NULL == Pos || NULL == StrStr(pCmdLine, L".vtoy")) | ||||
|     { | ||||
|         VDiskDebug("vdisk parameter not found!\n"); | ||||
|         return EFI_NOT_FOUND; | ||||
|     } | ||||
| 
 | ||||
|     vdisk_decompress_vdisk(pImageInfo); | ||||
| 
 | ||||
|     vdisk_patch_vdisk_path(Pos + 6); | ||||
| 
 | ||||
|     FreePool(pCmdLine); | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_boot(IN EFI_HANDLE ImageHandle) | ||||
| { | ||||
|     UINTN t = 0; | ||||
|     UINTN i = 0; | ||||
|     UINTN j = 0; | ||||
|     UINTN Find = 0; | ||||
|     UINTN Count = 0; | ||||
|     EFI_HANDLE Image = NULL; | ||||
|     EFI_HANDLE *Handles = NULL; | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
|     EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFile = NULL; | ||||
|     EFI_DEVICE_PATH_PROTOCOL *pDevPath = NULL; | ||||
| 
 | ||||
|     for (t = 0; t < 3; t++) | ||||
|     { | ||||
|         Count = 0; | ||||
|         Handles = NULL; | ||||
| 
 | ||||
|         Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid,  | ||||
|                                      NULL, &Count, &Handles); | ||||
|         if (EFI_ERROR(Status)) | ||||
|         { | ||||
|             return Status; | ||||
|         } | ||||
| 
 | ||||
|         debug("vdisk_boot fs count:%u", Count); | ||||
| 
 | ||||
|         for (i = 0; i < Count; i++) | ||||
|         { | ||||
|             Status = gBS->HandleProtocol(Handles[i], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&pFile); | ||||
|             if (EFI_ERROR(Status)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             debug("FS:%u Protocol:%p  OpenVolume:%p", i, pFile, pFile->OpenVolume); | ||||
| 
 | ||||
|             Status = gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,  | ||||
|                                        (VOID **)&pDevPath, | ||||
|                                        ImageHandle, | ||||
|                                        Handles[i], | ||||
|                                        EFI_OPEN_PROTOCOL_GET_PROTOCOL); | ||||
|             if (EFI_ERROR(Status)) | ||||
|             { | ||||
|                 debug("Failed to open device path protocol %r", Status); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             debug("Handle:%p FS DP: <%s>", Handles[i], ConvertDevicePathToText(pDevPath, FALSE, FALSE)); | ||||
|             if (CompareMem(gVDiskBlockData.Path, pDevPath, gVDiskBlockData.DevicePathCompareLen)) | ||||
|             { | ||||
|                 debug("Not ventoy disk file system"); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             for (j = 1; j < ARRAY_SIZE(gEfiBootFileName); j++) | ||||
|             { | ||||
|                 Status = vdisk_load_image(ImageHandle, pDevPath, gEfiBootFileName[j],  | ||||
|                                            StrSize(gEfiBootFileName[j]), &Image); | ||||
|                 if (EFI_SUCCESS == Status) | ||||
|                 { | ||||
|                     break; | ||||
|                 } | ||||
|                 debug("Failed to load image %r <%s>", Status, gEfiBootFileName[j]); | ||||
|             } | ||||
| 
 | ||||
|             if (j >= ARRAY_SIZE(gEfiBootFileName)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             Find++; | ||||
|             debug("Find boot file, now try to boot ....."); | ||||
|             vdisk_debug_pause(); | ||||
| 
 | ||||
|             if (gVDiskDebugPrint) | ||||
|             { | ||||
|                 gST->ConIn->Reset(gST->ConIn, FALSE); | ||||
|             } | ||||
| 
 | ||||
|             /* can't add debug print here */ | ||||
|             //ventoy_wrapper_system();
 | ||||
|             Status = gBS->StartImage(Image, NULL, NULL); | ||||
|             if (EFI_ERROR(Status)) | ||||
|             { | ||||
|                 debug("Failed to start image %r", Status); | ||||
|                 sleep(3); | ||||
|                 gBS->UnloadImage(Image); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         FreePool(Handles); | ||||
| 
 | ||||
|         if (Find == 0) | ||||
|         { | ||||
|             debug("Fs not found, now wait and retry..."); | ||||
|             sleep(2); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (Find == 0) | ||||
|     { | ||||
|         return EFI_NOT_FOUND; | ||||
|     } | ||||
| 
 | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI VDiskChainEfiMain | ||||
| ( | ||||
|     IN EFI_HANDLE         ImageHandle, | ||||
|     IN EFI_SYSTEM_TABLE  *SystemTable | ||||
| ) | ||||
| { | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
| 
 | ||||
|     gST->ConOut->ClearScreen(gST->ConOut); | ||||
|     vdisk_clear_input(); | ||||
| 
 | ||||
|     Status = vdisk_parse_cmdline(ImageHandle); | ||||
|     if (EFI_ERROR(Status)) | ||||
|     { | ||||
|         return Status; | ||||
|     } | ||||
| 
 | ||||
|     vdisk_install_blockio(ImageHandle, g_disk_buf_size); | ||||
|     vdisk_debug_pause(); | ||||
| 
 | ||||
|     Status = vdisk_boot(ImageHandle); | ||||
|      | ||||
|     gBS->DisconnectController(gVDiskBlockData.Handle, NULL, NULL); | ||||
|     gBS->UninstallMultipleProtocolInterfaces(gVDiskBlockData.Handle, | ||||
|             &gEfiBlockIoProtocolGuid, &gVDiskBlockData.BlockIo, | ||||
|             &gEfiDevicePathProtocolGuid, gVDiskBlockData.Path, | ||||
|             NULL); | ||||
| 
 | ||||
|     if (EFI_NOT_FOUND == Status) | ||||
|     { | ||||
|         gST->ConOut->OutputString(gST->ConOut, L"No bootfile found for UEFI!\r\n"); | ||||
|         gST->ConOut->OutputString(gST->ConOut, L"Maybe the image does not support " VENTOY_UEFI_DESC  L"!\r\n"); | ||||
|         sleep(30); | ||||
|     } | ||||
|      | ||||
|     vdisk_clear_input(); | ||||
|     gST->ConOut->ClearScreen(gST->ConOut); | ||||
| 
 | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,97 @@ | ||||
| /******************************************************************************
 | ||||
|  * VDiskChain.h | ||||
|  * | ||||
|  * Copyright (c) 2021, longpanda <admin@ventoy.net> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  *  | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  *  | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
|   | ||||
| #ifndef __VENTOY_H__ | ||||
| #define __VENTOY_H__ | ||||
| 
 | ||||
| #define VDISK_MAGIC_LEN  32 | ||||
| 
 | ||||
| #define VDISK_BLOCK_DEVICE_PATH_GUID					\ | ||||
| 	{ 0x6ed2134e, 0xc2ea, 0x4943, { 0x99, 0x54, 0xa7, 0x76, 0xe5, 0x9c, 0x12, 0xc3 }} | ||||
| 
 | ||||
| #define VDISK_BLOCK_DEVICE_PATH_NAME  L"vdisk" | ||||
| 
 | ||||
| #if   defined (MDE_CPU_IA32) | ||||
|   #define VENTOY_UEFI_DESC   L"IA32 UEFI" | ||||
| #elif defined (MDE_CPU_X64) | ||||
|   #define VENTOY_UEFI_DESC   L"X64 UEFI" | ||||
| #elif defined (MDE_CPU_EBC) | ||||
| #elif defined (MDE_CPU_ARM) | ||||
|   #define VENTOY_UEFI_DESC   L"ARM UEFI" | ||||
| #elif defined (MDE_CPU_AARCH64) | ||||
|   #define VENTOY_UEFI_DESC   L"ARM64 UEFI" | ||||
| #else | ||||
|   #error Unknown Processor Type | ||||
| #endif | ||||
| 
 | ||||
| typedef struct vdisk_block_data  | ||||
| { | ||||
| 	EFI_HANDLE Handle; | ||||
| 	EFI_BLOCK_IO_MEDIA Media;       /* Media descriptor */ | ||||
| 	EFI_BLOCK_IO_PROTOCOL BlockIo;	/* Block I/O protocol */ | ||||
| 
 | ||||
|     UINTN DevicePathCompareLen; | ||||
| 	EFI_DEVICE_PATH_PROTOCOL *Path;	/* Device path protocol */ | ||||
| 
 | ||||
|     EFI_HANDLE RawBlockIoHandle; | ||||
|     EFI_BLOCK_IO_PROTOCOL *pRawBlockIo; | ||||
|     EFI_DEVICE_PATH_PROTOCOL *pDiskDevPath; | ||||
| 
 | ||||
|     /* ventoy disk part2 ESP */ | ||||
|     EFI_HANDLE DiskFsHandle; | ||||
|     EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pDiskFs; | ||||
|     EFI_DEVICE_PATH_PROTOCOL *pDiskFsDevPath; | ||||
| 
 | ||||
|     EFI_HANDLE IsoDriverImage; | ||||
| }vdisk_block_data; | ||||
| 
 | ||||
| 
 | ||||
| #define debug(expr, ...) if (gVDiskDebugPrint) VDiskDebug("[VDISK] "expr"\r\n", ##__VA_ARGS__) | ||||
| #define trace(expr, ...) VDiskDebug("[VDISK] "expr"\r\n", ##__VA_ARGS__) | ||||
| #define sleep(sec) gBS->Stall(1000000 * (sec)) | ||||
| 
 | ||||
| #define vdisk_debug_pause() \ | ||||
| if (gVDiskDebugPrint) \ | ||||
| { \ | ||||
|     UINTN __Index = 0; \ | ||||
|     gST->ConOut->OutputString(gST->ConOut, L"[VDISK] ###### Press Enter to continue... ######\r\n");\ | ||||
|     gST->ConIn->Reset(gST->ConIn, FALSE); \ | ||||
|     gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &__Index);\ | ||||
| } | ||||
| 
 | ||||
| extern BOOLEAN gVDiskDebugPrint; | ||||
| VOID EFIAPI VDiskDebug(IN CONST CHAR8  *Format, ...); | ||||
| EFI_STATUS EFIAPI vdisk_block_io_read  | ||||
| ( | ||||
|     IN EFI_BLOCK_IO_PROTOCOL          *This, | ||||
|     IN UINT32                          MediaId, | ||||
|     IN EFI_LBA                         Lba, | ||||
|     IN UINTN                           BufferSize, | ||||
|     OUT VOID                          *Buffer | ||||
| ); | ||||
| 
 | ||||
| extern UINT8 *g_disk_buf_addr; | ||||
| extern UINT64 g_disk_buf_size; | ||||
| extern vdisk_block_data gVDiskBlockData; | ||||
| EFI_STATUS EFIAPI vdisk_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 ImgSize); | ||||
| int vdisk_get_vdisk_raw(UINT8 **buf, UINT32 *size); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| @ -0,0 +1,82 @@ | ||||
| #************************************************************************************ | ||||
| # Copyright (c) 2020, longpanda <admin@ventoy.net> | ||||
| #  | ||||
| # This program is free software; you can redistribute it and/or | ||||
| # modify it under the terms of the GNU General Public License as | ||||
| # published by the Free Software Foundation; either version 3 of the | ||||
| # License, or (at your option) any later version. | ||||
| #  | ||||
| # This program is distributed in the hope that it will be useful, but | ||||
| # WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
| # General Public License for more details. | ||||
| #  | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, see <http://www.gnu.org/licenses/>. | ||||
| #  | ||||
| #************************************************************************************ | ||||
| 
 | ||||
| [Defines] | ||||
|   INF_VERSION                    = 0x00010005 | ||||
|   BASE_NAME                      = VDiskChain | ||||
|   FILE_GUID                      = 5bce96e3-ba11-4440-833b-299cf5849193 | ||||
|   MODULE_TYPE                    = UEFI_APPLICATION | ||||
|   VERSION_STRING                 = 1.0 | ||||
|   ENTRY_POINT                    = VDiskChainEfiMain | ||||
| 
 | ||||
| 
 | ||||
| [Sources] | ||||
|   VDiskChain.h | ||||
|   VDiskChain.c | ||||
|   VDiskRawData.c | ||||
|   VDiskChainProtocol.c | ||||
| 
 | ||||
| [Packages] | ||||
|   MdePkg/MdePkg.dec | ||||
|   MdeModulePkg/MdeModulePkg.dec | ||||
|   ShellPkg/ShellPkg.dec | ||||
| 
 | ||||
| [LibraryClasses] | ||||
|   UefiApplicationEntryPoint | ||||
|   UefiLib | ||||
|   DebugLib | ||||
|   UefiDecompressLib | ||||
| 
 | ||||
| [Guids] | ||||
|   gShellVariableGuid | ||||
|   gEfiVirtualCdGuid | ||||
|   gEfiFileInfoGuid | ||||
|    | ||||
| [Protocols] | ||||
|   gEfiLoadedImageProtocolGuid | ||||
|   gEfiBlockIoProtocolGuid | ||||
|   gEfiDevicePathProtocolGuid | ||||
|   gEfiSimpleFileSystemProtocolGuid | ||||
|   gEfiRamDiskProtocolGuid | ||||
|   gEfiAbsolutePointerProtocolGuid | ||||
|   gEfiAcpiTableProtocolGuid | ||||
|   gEfiBlockIo2ProtocolGuid | ||||
|   gEfiBusSpecificDriverOverrideProtocolGuid | ||||
|   gEfiComponentNameProtocolGuid | ||||
|   gEfiComponentName2ProtocolGuid | ||||
|   gEfiDriverBindingProtocolGuid | ||||
|   gEfiDiskIoProtocolGuid | ||||
|   gEfiDiskIo2ProtocolGuid | ||||
|   gEfiGraphicsOutputProtocolGuid | ||||
|   gEfiHiiConfigAccessProtocolGuid | ||||
|   gEfiHiiFontProtocolGuid | ||||
|   gEfiLoadFileProtocolGuid | ||||
|   gEfiLoadFile2ProtocolGuid | ||||
|   gEfiLoadedImageProtocolGuid | ||||
|   gEfiLoadedImageDevicePathProtocolGuid | ||||
|   gEfiPciIoProtocolGuid | ||||
|   gEfiSerialIoProtocolGuid | ||||
|   gEfiSimpleTextInProtocolGuid | ||||
|   gEfiSimpleTextInputExProtocolGuid | ||||
|   gEfiSimpleTextOutProtocolGuid | ||||
|    | ||||
|    | ||||
|    | ||||
|    | ||||
|    | ||||
|    | ||||
| @ -0,0 +1,264 @@ | ||||
| /******************************************************************************
 | ||||
|  * VDiskChainProtocol.c | ||||
|  * | ||||
|  * Copyright (c) 2021, longpanda <admin@ventoy.net> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License as | ||||
|  * published by the Free Software Foundation; either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  *  | ||||
|  * This program is distributed in the hope that it will be useful, but | ||||
|  * WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * General Public License for more details. | ||||
|  *  | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, see <http://www.gnu.org/licenses/>.
 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <Uefi.h> | ||||
| #include <Library/DebugLib.h> | ||||
| #include <Library/PrintLib.h> | ||||
| #include <Library/UefiLib.h> | ||||
| #include <Library/BaseMemoryLib.h> | ||||
| #include <Library/DevicePathLib.h> | ||||
| #include <Library/MemoryAllocationLib.h> | ||||
| #include <Library/UefiBootServicesTableLib.h> | ||||
| #include <Library/UefiRuntimeServicesTableLib.h> | ||||
| #include <Library/UefiApplicationEntryPoint.h> | ||||
| #include <Protocol/LoadedImage.h> | ||||
| #include <Guid/FileInfo.h> | ||||
| #include <Guid/FileSystemInfo.h> | ||||
| #include <Protocol/BlockIo.h> | ||||
| #include <Protocol/RamDisk.h> | ||||
| #include <Protocol/SimpleFileSystem.h> | ||||
| #include <VDiskChain.h> | ||||
| 
 | ||||
| /* EFI block device vendor device path GUID */ | ||||
| EFI_GUID gVDiskBlockDevicePathGuid = VDISK_BLOCK_DEVICE_PATH_GUID; | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_block_io_reset  | ||||
| ( | ||||
|     IN EFI_BLOCK_IO_PROTOCOL          *This, | ||||
|     IN BOOLEAN                        ExtendedVerification | ||||
| )  | ||||
| { | ||||
|     (VOID)This; | ||||
|     (VOID)ExtendedVerification; | ||||
| 	return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL *This) | ||||
| { | ||||
| 	(VOID)This; | ||||
| 	return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_block_io_read | ||||
| ( | ||||
|     IN EFI_BLOCK_IO_PROTOCOL          *This, | ||||
|     IN UINT32                          MediaId, | ||||
|     IN EFI_LBA                         Lba, | ||||
|     IN UINTN                           BufferSize, | ||||
|     OUT VOID                          *Buffer | ||||
| ) | ||||
| { | ||||
|     (VOID)This; | ||||
|     (VOID)MediaId; | ||||
| 
 | ||||
|     debug("vdisk_block_io_read %lu %lu\n", Lba, BufferSize / 512); | ||||
|     CopyMem(Buffer, g_disk_buf_addr + (Lba * 512), BufferSize); | ||||
| 
 | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_block_io_write | ||||
| ( | ||||
|     IN EFI_BLOCK_IO_PROTOCOL          *This, | ||||
|     IN UINT32                          MediaId, | ||||
|     IN EFI_LBA                         Lba, | ||||
|     IN UINTN                           BufferSize, | ||||
|     IN VOID                           *Buffer | ||||
| ) | ||||
| { | ||||
|     (VOID)This; | ||||
|     (VOID)MediaId; | ||||
|     (VOID)Buffer; | ||||
| 
 | ||||
|     debug("vdisk_block_io_read %lu %lu\n", Lba, BufferSize / 512); | ||||
|     return EFI_WRITE_PROTECTED; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_fill_device_path(VOID) | ||||
| { | ||||
|     UINTN NameLen = 0; | ||||
|     UINT8 TmpBuf[128] = {0}; | ||||
|     VENDOR_DEVICE_PATH *venPath = NULL; | ||||
| 
 | ||||
|     venPath = (VENDOR_DEVICE_PATH *)TmpBuf; | ||||
|     NameLen = StrSize(VDISK_BLOCK_DEVICE_PATH_NAME); | ||||
|     venPath->Header.Type = HARDWARE_DEVICE_PATH; | ||||
|     venPath->Header.SubType = HW_VENDOR_DP; | ||||
|     venPath->Header.Length[0] = sizeof(VENDOR_DEVICE_PATH) + NameLen; | ||||
|     venPath->Header.Length[1] = 0; | ||||
|     CopyMem(&venPath->Guid, &gVDiskBlockDevicePathGuid, sizeof(EFI_GUID)); | ||||
|     CopyMem(venPath + 1, VDISK_BLOCK_DEVICE_PATH_NAME, NameLen); | ||||
|      | ||||
|     gVDiskBlockData.Path = AppendDevicePathNode(NULL, (EFI_DEVICE_PATH_PROTOCOL *)TmpBuf); | ||||
|     gVDiskBlockData.DevicePathCompareLen = sizeof(VENDOR_DEVICE_PATH) + NameLen; | ||||
| 
 | ||||
|     debug("gVDiskBlockData.Path=<%s>\n", ConvertDevicePathToText(gVDiskBlockData.Path, FALSE, FALSE)); | ||||
| 
 | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST CHAR16 *DrvName) | ||||
| { | ||||
|     UINTN i = 0; | ||||
|     UINTN Count = 0; | ||||
|     CHAR16 *DriverName = NULL; | ||||
|     EFI_HANDLE *Handles = NULL; | ||||
|     EFI_HANDLE DrvHandles[2] = { NULL }; | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
|     EFI_COMPONENT_NAME_PROTOCOL *NameProtocol = NULL; | ||||
|     EFI_COMPONENT_NAME2_PROTOCOL *Name2Protocol = NULL; | ||||
| 
 | ||||
|     debug("vdisk_connect_driver <%s>...", DrvName); | ||||
| 
 | ||||
|     Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentName2ProtocolGuid,  | ||||
|                                      NULL, &Count, &Handles); | ||||
|     if (EFI_ERROR(Status)) | ||||
|     { | ||||
|         return Status; | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < Count; i++) | ||||
|     { | ||||
|         Status = gBS->HandleProtocol(Handles[i], &gEfiComponentName2ProtocolGuid, (VOID **)&Name2Protocol); | ||||
|         if (EFI_ERROR(Status)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         Status = Name2Protocol->GetDriverName(Name2Protocol, "en", &DriverName); | ||||
|         if (EFI_ERROR(Status) || NULL == DriverName) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (StrStr(DriverName, DrvName)) | ||||
|         { | ||||
|             debug("Find driver name2:<%s>: <%s>", DriverName, DrvName); | ||||
|             DrvHandles[0] = Handles[i]; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (i < Count) | ||||
|     { | ||||
|         Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE); | ||||
|         debug("vdisk_connect_driver:<%s> <%r>", DrvName, Status); | ||||
|         goto end; | ||||
|     } | ||||
| 
 | ||||
|     debug("%s NOT found, now try COMPONENT_NAME", DrvName); | ||||
| 
 | ||||
|     Count = 0; | ||||
|     FreePool(Handles); | ||||
|     Handles = NULL; | ||||
| 
 | ||||
|     Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentNameProtocolGuid,  | ||||
|                                      NULL, &Count, &Handles); | ||||
|     if (EFI_ERROR(Status)) | ||||
|     { | ||||
|         return Status; | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < Count; i++) | ||||
|     { | ||||
|         Status = gBS->HandleProtocol(Handles[i], &gEfiComponentNameProtocolGuid, (VOID **)&NameProtocol); | ||||
|         if (EFI_ERROR(Status)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         Status = NameProtocol->GetDriverName(NameProtocol, "en", &DriverName); | ||||
|         if (EFI_ERROR(Status)) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (StrStr(DriverName, DrvName)) | ||||
|         { | ||||
|             debug("Find driver name:<%s>: <%s>", DriverName, DrvName); | ||||
|             DrvHandles[0] = Handles[i]; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (i < Count) | ||||
|     { | ||||
|         Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE); | ||||
|         debug("vdisk_connect_driver:<%s> <%r>", DrvName, Status); | ||||
|         goto end; | ||||
|     } | ||||
| 
 | ||||
|     Status = EFI_NOT_FOUND; | ||||
|      | ||||
| end: | ||||
|     FreePool(Handles); | ||||
|      | ||||
|     return Status; | ||||
| } | ||||
| 
 | ||||
| EFI_STATUS EFIAPI vdisk_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 ImgSize) | ||||
| {    | ||||
|     EFI_STATUS Status = EFI_SUCCESS; | ||||
|     EFI_BLOCK_IO_PROTOCOL *pBlockIo = &(gVDiskBlockData.BlockIo); | ||||
|      | ||||
|     vdisk_fill_device_path(); | ||||
| 
 | ||||
|     debug("install block io protocol %p", ImageHandle); | ||||
|     vdisk_debug_pause(); | ||||
| 
 | ||||
|     gVDiskBlockData.Media.BlockSize = 512; | ||||
|     gVDiskBlockData.Media.LastBlock = ImgSize / 512 - 1; | ||||
|     gVDiskBlockData.Media.ReadOnly = TRUE; | ||||
|     gVDiskBlockData.Media.MediaPresent = 1; | ||||
|     gVDiskBlockData.Media.LogicalBlocksPerPhysicalBlock = 1; | ||||
| 
 | ||||
| 	pBlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3; | ||||
| 	pBlockIo->Media = &(gVDiskBlockData.Media); | ||||
| 	pBlockIo->Reset = vdisk_block_io_reset; | ||||
|     pBlockIo->ReadBlocks = vdisk_block_io_read; | ||||
| 	pBlockIo->WriteBlocks = vdisk_block_io_write; | ||||
| 	pBlockIo->FlushBlocks = vdisk_block_io_flush; | ||||
| 
 | ||||
|     Status = gBS->InstallMultipleProtocolInterfaces(&gVDiskBlockData.Handle, | ||||
|             &gEfiBlockIoProtocolGuid, &gVDiskBlockData.BlockIo, | ||||
|             &gEfiDevicePathProtocolGuid, gVDiskBlockData.Path, | ||||
|             NULL); | ||||
|     debug("Install protocol %r %p", Status, gVDiskBlockData.Handle); | ||||
|     if (EFI_ERROR(Status)) | ||||
|     { | ||||
|         return Status; | ||||
|     } | ||||
| 
 | ||||
|     Status = vdisk_connect_driver(gVDiskBlockData.Handle, L"Disk I/O Driver"); | ||||
|     debug("Connect disk IO driver %r", Status); | ||||
| 
 | ||||
|     Status = vdisk_connect_driver(gVDiskBlockData.Handle, L"Partition Driver"); | ||||
|     debug("Connect partition driver %r", Status); | ||||
|     if (EFI_ERROR(Status)) | ||||
|     { | ||||
|         Status = gBS->ConnectController(gVDiskBlockData.Handle, NULL, NULL, TRUE); | ||||
|         debug("Connect all controller %r", Status); | ||||
|     } | ||||
| 
 | ||||
|     vdisk_debug_pause(); | ||||
| 
 | ||||
|     return EFI_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1 @@ | ||||
| 123 | ||||
| @ -205,6 +205,7 @@ | ||||
| [Components] | ||||
|   MdeModulePkg/Application/Ventoy/Ventoy.inf | ||||
|   MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf | ||||
|   MdeModulePkg/Application/VDiskChain/VDiskChain.inf | ||||
|   MdeModulePkg/Application/HelloWorld/HelloWorld.inf | ||||
|   MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf | ||||
|   MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user