1 /******************************************************************************
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include <Library/DebugLib.h>
23 #include <Library/PrintLib.h>
24 #include <Library/UefiLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/DevicePathLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/UefiApplicationEntryPoint.h>
31 #include <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 <VDiskChain.h>
39 /* EFI block device vendor device path GUID */
40 EFI_GUID gVDiskBlockDevicePathGuid
= VDISK_BLOCK_DEVICE_PATH_GUID
;
42 EFI_STATUS EFIAPI vdisk_block_io_reset
44 IN EFI_BLOCK_IO_PROTOCOL
*This
,
45 IN BOOLEAN ExtendedVerification
49 (VOID
)ExtendedVerification
;
53 EFI_STATUS EFIAPI
vdisk_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL
*This
)
59 EFI_STATUS EFIAPI vdisk_block_io_read
61 IN EFI_BLOCK_IO_PROTOCOL
*This
,
71 debug("vdisk_block_io_read %lu %lu\n", Lba
, BufferSize
/ 512);
72 CopyMem(Buffer
, g_disk_buf_addr
+ (Lba
* 512), BufferSize
);
77 EFI_STATUS EFIAPI vdisk_block_io_write
79 IN EFI_BLOCK_IO_PROTOCOL
*This
,
90 debug("vdisk_block_io_read %lu %lu\n", Lba
, BufferSize
/ 512);
91 return EFI_WRITE_PROTECTED
;
94 EFI_STATUS EFIAPI
vdisk_fill_device_path(VOID
)
97 UINT8 TmpBuf
[128] = {0};
98 VENDOR_DEVICE_PATH
*venPath
= NULL
;
100 venPath
= (VENDOR_DEVICE_PATH
*)TmpBuf
;
101 NameLen
= StrSize(VDISK_BLOCK_DEVICE_PATH_NAME
);
102 venPath
->Header
.Type
= HARDWARE_DEVICE_PATH
;
103 venPath
->Header
.SubType
= HW_VENDOR_DP
;
104 venPath
->Header
.Length
[0] = sizeof(VENDOR_DEVICE_PATH
) + NameLen
;
105 venPath
->Header
.Length
[1] = 0;
106 CopyMem(&venPath
->Guid
, &gVDiskBlockDevicePathGuid
, sizeof(EFI_GUID
));
107 CopyMem(venPath
+ 1, VDISK_BLOCK_DEVICE_PATH_NAME
, NameLen
);
109 gVDiskBlockData
.Path
= AppendDevicePathNode(NULL
, (EFI_DEVICE_PATH_PROTOCOL
*)TmpBuf
);
110 gVDiskBlockData
.DevicePathCompareLen
= sizeof(VENDOR_DEVICE_PATH
) + NameLen
;
112 debug("gVDiskBlockData.Path=<%s>\n", ConvertDevicePathToText(gVDiskBlockData
.Path
, FALSE
, FALSE
));
117 EFI_STATUS EFIAPI
vdisk_connect_driver(IN EFI_HANDLE ControllerHandle
, IN CONST CHAR16
*DrvName
)
121 CHAR16
*DriverName
= NULL
;
122 EFI_HANDLE
*Handles
= NULL
;
123 EFI_HANDLE DrvHandles
[2] = { NULL
};
124 EFI_STATUS Status
= EFI_SUCCESS
;
125 EFI_COMPONENT_NAME_PROTOCOL
*NameProtocol
= NULL
;
126 EFI_COMPONENT_NAME2_PROTOCOL
*Name2Protocol
= NULL
;
128 debug("vdisk_connect_driver <%s>...", DrvName
);
130 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiComponentName2ProtocolGuid
,
131 NULL
, &Count
, &Handles
);
132 if (EFI_ERROR(Status
))
137 for (i
= 0; i
< Count
; i
++)
139 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiComponentName2ProtocolGuid
, (VOID
**)&Name2Protocol
);
140 if (EFI_ERROR(Status
))
145 Status
= Name2Protocol
->GetDriverName(Name2Protocol
, "en", &DriverName
);
146 if (EFI_ERROR(Status
) || NULL
== DriverName
)
151 if (StrStr(DriverName
, DrvName
))
153 debug("Find driver name2:<%s>: <%s>", DriverName
, DrvName
);
154 DrvHandles
[0] = Handles
[i
];
161 Status
= gBS
->ConnectController(ControllerHandle
, DrvHandles
, NULL
, TRUE
);
162 debug("vdisk_connect_driver:<%s> <%r>", DrvName
, Status
);
166 debug("%s NOT found, now try COMPONENT_NAME", DrvName
);
172 Status
= gBS
->LocateHandleBuffer(ByProtocol
, &gEfiComponentNameProtocolGuid
,
173 NULL
, &Count
, &Handles
);
174 if (EFI_ERROR(Status
))
179 for (i
= 0; i
< Count
; i
++)
181 Status
= gBS
->HandleProtocol(Handles
[i
], &gEfiComponentNameProtocolGuid
, (VOID
**)&NameProtocol
);
182 if (EFI_ERROR(Status
))
187 Status
= NameProtocol
->GetDriverName(NameProtocol
, "en", &DriverName
);
188 if (EFI_ERROR(Status
))
193 if (StrStr(DriverName
, DrvName
))
195 debug("Find driver name:<%s>: <%s>", DriverName
, DrvName
);
196 DrvHandles
[0] = Handles
[i
];
203 Status
= gBS
->ConnectController(ControllerHandle
, DrvHandles
, NULL
, TRUE
);
204 debug("vdisk_connect_driver:<%s> <%r>", DrvName
, Status
);
208 Status
= EFI_NOT_FOUND
;
216 EFI_STATUS EFIAPI
vdisk_install_blockio(IN EFI_HANDLE ImageHandle
, IN UINT64 ImgSize
)
218 EFI_STATUS Status
= EFI_SUCCESS
;
219 EFI_BLOCK_IO_PROTOCOL
*pBlockIo
= &(gVDiskBlockData
.BlockIo
);
221 vdisk_fill_device_path();
223 debug("install block io protocol %p", ImageHandle
);
226 gVDiskBlockData
.Media
.BlockSize
= 512;
227 gVDiskBlockData
.Media
.LastBlock
= ImgSize
/ 512 - 1;
228 gVDiskBlockData
.Media
.ReadOnly
= TRUE
;
229 gVDiskBlockData
.Media
.MediaPresent
= 1;
230 gVDiskBlockData
.Media
.LogicalBlocksPerPhysicalBlock
= 1;
232 pBlockIo
->Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION3
;
233 pBlockIo
->Media
= &(gVDiskBlockData
.Media
);
234 pBlockIo
->Reset
= vdisk_block_io_reset
;
235 pBlockIo
->ReadBlocks
= vdisk_block_io_read
;
236 pBlockIo
->WriteBlocks
= vdisk_block_io_write
;
237 pBlockIo
->FlushBlocks
= vdisk_block_io_flush
;
239 Status
= gBS
->InstallMultipleProtocolInterfaces(&gVDiskBlockData
.Handle
,
240 &gEfiBlockIoProtocolGuid
, &gVDiskBlockData
.BlockIo
,
241 &gEfiDevicePathProtocolGuid
, gVDiskBlockData
.Path
,
243 debug("Install protocol %r %p", Status
, gVDiskBlockData
.Handle
);
244 if (EFI_ERROR(Status
))
249 Status
= vdisk_connect_driver(gVDiskBlockData
.Handle
, L
"Disk I/O Driver");
250 debug("Connect disk IO driver %r", Status
);
252 Status
= vdisk_connect_driver(gVDiskBlockData
.Handle
, L
"Partition Driver");
253 debug("Connect partition driver %r", Status
);
254 if (EFI_ERROR(Status
))
256 Status
= gBS
->ConnectController(gVDiskBlockData
.Handle
, NULL
, NULL
, TRUE
);
257 debug("Connect all controller %r", Status
);