]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - EDK2/edk2_mod/edk2-edk2-stable201911/MdeModulePkg/Application/Ventoy/VentoyProtocol.c
624055dff974f57be556da592344f77a8b17198b
[Ventoy.git] / EDK2 / edk2_mod / edk2-edk2-stable201911 / MdeModulePkg / Application / Ventoy / VentoyProtocol.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
42 ventoy_sector_flag *g_sector_flag = NULL;
43 UINT32 g_sector_flag_num = 0;
44
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;
48
49 /* EFI block device vendor device path GUID */
50 EFI_GUID gVtoyBlockDevicePathGuid = VTOY_BLOCK_DEVICE_PATH_GUID;
51
52 #define VENTOY_ISO9660_SECTOR_OVERFLOW 2097152
53
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;
59
60 EFI_STATUS EFIAPI ventoy_block_io_reset
61 (
62 IN EFI_BLOCK_IO_PROTOCOL *This,
63 IN BOOLEAN ExtendedVerification
64 )
65 {
66 (VOID)This;
67 (VOID)ExtendedVerification;
68 return EFI_SUCCESS;
69 }
70
71 STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
72 (
73 IN UINT64 Sector,
74 IN UINTN Count,
75 OUT VOID *Buffer
76 )
77 {
78 EFI_STATUS Status = EFI_SUCCESS;
79 EFI_LBA MapLba = 0;
80 UINT32 i = 0;
81 UINTN secLeft = 0;
82 UINTN secRead = 0;
83 UINT64 ReadStart = 0;
84 UINT64 ReadEnd = 0;
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;
91
92 debug("read iso sector %lu count %u", Sector, Count);
93
94 ReadStart = Sector * 2048;
95 ReadEnd = (Sector + Count) * 2048;
96
97 for (i = 0; Count > 0 && i < g_img_chunk_num; i++, pchunk++)
98 {
99 if (Sector >= pchunk->img_start_sector && Sector <= pchunk->img_end_sector)
100 {
101 if (g_chain->disk_sector_size == 512)
102 {
103 MapLba = (Sector - pchunk->img_start_sector) * 4 + pchunk->disk_start_sector;
104 }
105 else
106 {
107 MapLba = (Sector - pchunk->img_start_sector) * 2048 / g_chain->disk_sector_size + pchunk->disk_start_sector;
108 }
109
110 secLeft = pchunk->img_end_sector + 1 - Sector;
111 secRead = (Count < secLeft) ? Count : secLeft;
112
113 Status = pRawBlockIo->ReadBlocks(pRawBlockIo, pRawBlockIo->Media->MediaId,
114 MapLba, secRead * 2048, pCurBuf);
115 if (EFI_ERROR(Status))
116 {
117 debug("Raw disk read block failed %r", Status);
118 return Status;
119 }
120
121 Count -= secRead;
122 Sector += secRead;
123 pCurBuf += secRead * 2048;
124 }
125 }
126
127 if (ReadStart > g_chain->real_img_size_in_bytes)
128 {
129 return EFI_SUCCESS;
130 }
131
132 /* override data */
133 pCurBuf = (UINT8 *)Buffer;
134 for (i = 0; i < g_override_chunk_num; i++, pOverride++)
135 {
136 OverrideStart = pOverride->img_offset;
137 OverrideEnd = pOverride->img_offset + pOverride->override_size;
138
139 if (OverrideStart >= ReadEnd || ReadStart >= OverrideEnd)
140 {
141 continue;
142 }
143
144 if (ReadStart <= OverrideStart)
145 {
146 if (ReadEnd <= OverrideEnd)
147 {
148 CopyMem(pCurBuf + OverrideStart - ReadStart, pOverride->override_data, ReadEnd - OverrideStart);
149 }
150 else
151 {
152 CopyMem(pCurBuf + OverrideStart - ReadStart, pOverride->override_data, pOverride->override_size);
153 }
154 }
155 else
156 {
157 if (ReadEnd <= OverrideEnd)
158 {
159 CopyMem(pCurBuf, pOverride->override_data + ReadStart - OverrideStart, ReadEnd - ReadStart);
160 }
161 else
162 {
163 CopyMem(pCurBuf, pOverride->override_data + ReadStart - OverrideStart, OverrideEnd - ReadStart);
164 }
165 }
166
167 if (g_fixup_iso9660_secover_enable && (!g_fixup_iso9660_secover_start) &&
168 pOverride->override_size == sizeof(ventoy_iso9660_override))
169 {
170 ventoy_iso9660_override *dirent = (ventoy_iso9660_override *)pOverride->override_data;
171 if (dirent->first_sector >= VENTOY_ISO9660_SECTOR_OVERFLOW)
172 {
173 g_fixup_iso9660_secover_start = TRUE;
174 g_fixup_iso9660_secover_cur_secs = 0;
175 }
176 }
177 }
178
179 return EFI_SUCCESS;
180 }
181
182 EFI_STATUS EFIAPI ventoy_block_io_ramdisk_read
183 (
184 IN EFI_BLOCK_IO_PROTOCOL *This,
185 IN UINT32 MediaId,
186 IN EFI_LBA Lba,
187 IN UINTN BufferSize,
188 OUT VOID *Buffer
189 )
190 {
191 //debug("### ventoy_block_io_ramdisk_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
192
193 (VOID)This;
194 (VOID)MediaId;
195
196 CopyMem(Buffer, (char *)g_chain + (Lba * 2048), BufferSize);
197
198 return EFI_SUCCESS;
199 }
200
201 EFI_LBA EFIAPI ventoy_fixup_iso9660_sector(IN EFI_LBA Lba, UINT32 secNum)
202 {
203 UINT32 i = 0;
204
205 if (g_fixup_iso9660_secover_cur_secs > 0)
206 {
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)
210 {
211 g_fixup_iso9660_secover_start = FALSE;
212 goto end;
213 }
214 }
215 else
216 {
217 ventoy_iso9660_override *dirent;
218 ventoy_override_chunk *pOverride;
219
220 for (i = 0, pOverride = g_override_chunk; i < g_override_chunk_num; i++, pOverride++)
221 {
222 dirent = (ventoy_iso9660_override *)pOverride->override_data;
223 if (Lba == dirent->first_sector)
224 {
225 g_fixup_iso9660_secover_start = FALSE;
226 goto end;
227 }
228 }
229
230 if (g_fixup_iso9660_secover_start)
231 {
232 for (i = 0, pOverride = g_override_chunk; i < g_override_chunk_num; i++, pOverride++)
233 {
234 dirent = (ventoy_iso9660_override *)pOverride->override_data;
235 if (Lba + VENTOY_ISO9660_SECTOR_OVERFLOW == dirent->first_sector)
236 {
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)
240 {
241 g_fixup_iso9660_secover_start = FALSE;
242 }
243 Lba += VENTOY_ISO9660_SECTOR_OVERFLOW;
244 goto end;
245 }
246 }
247 }
248 }
249
250 end:
251 return Lba;
252 }
253
254 EFI_STATUS EFIAPI ventoy_block_io_read
255 (
256 IN EFI_BLOCK_IO_PROTOCOL *This,
257 IN UINT32 MediaId,
258 IN EFI_LBA Lba,
259 IN UINTN BufferSize,
260 OUT VOID *Buffer
261 )
262 {
263 UINT32 i = 0;
264 UINT32 j = 0;
265 UINT32 lbacount = 0;
266 UINT32 secNum = 0;
267 UINT64 offset = 0;
268 EFI_LBA curlba = 0;
269 EFI_LBA lastlba = 0;
270 UINT8 *lastbuffer;
271 ventoy_sector_flag *cur_flag;
272 ventoy_virt_chunk *node;
273
274 //debug("### ventoy_block_io_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
275
276 secNum = BufferSize / 2048;
277
278 /* Workaround for SSTR PE loader error */
279 if (g_fixup_iso9660_secover_start)
280 {
281 Lba = ventoy_fixup_iso9660_sector(Lba, secNum);
282 }
283
284 offset = Lba * 2048;
285
286 if (offset + BufferSize <= g_chain->real_img_size_in_bytes)
287 {
288 return ventoy_read_iso_sector(Lba, secNum, Buffer);
289 }
290
291 if (secNum > g_sector_flag_num)
292 {
293 cur_flag = AllocatePool(secNum * sizeof(ventoy_sector_flag));
294 if (NULL == cur_flag)
295 {
296 return EFI_OUT_OF_RESOURCES;
297 }
298
299 FreePool(g_sector_flag);
300 g_sector_flag = cur_flag;
301 g_sector_flag_num = secNum;
302 }
303
304 for (curlba = Lba, cur_flag = g_sector_flag, j = 0; j < secNum; j++, curlba++, cur_flag++)
305 {
306 cur_flag->flag = 0;
307 for (node = g_virt_chunk, i = 0; i < g_virt_chunk_num; i++, node++)
308 {
309 if (curlba >= node->mem_sector_start && curlba < node->mem_sector_end)
310 {
311 CopyMem((UINT8 *)Buffer + j * 2048,
312 (char *)g_virt_chunk + node->mem_sector_offset + (curlba - node->mem_sector_start) * 2048,
313 2048);
314 cur_flag->flag = 1;
315 break;
316 }
317 else if (curlba >= node->remap_sector_start && curlba < node->remap_sector_end)
318 {
319 cur_flag->remap_lba = node->org_sector_start + curlba - node->remap_sector_start;
320 cur_flag->flag = 2;
321 break;
322 }
323 }
324 }
325
326 for (curlba = Lba, cur_flag = g_sector_flag, j = 0; j < secNum; j++, curlba++, cur_flag++)
327 {
328 if (cur_flag->flag == 2)
329 {
330 if (lastlba == 0)
331 {
332 lastbuffer = (UINT8 *)Buffer + j * 2048;
333 lastlba = cur_flag->remap_lba;
334 lbacount = 1;
335 }
336 else if (lastlba + lbacount == cur_flag->remap_lba)
337 {
338 lbacount++;
339 }
340 else
341 {
342 ventoy_read_iso_sector(lastlba, lbacount, lastbuffer);
343 lastbuffer = (UINT8 *)Buffer + j * 2048;
344 lastlba = cur_flag->remap_lba;
345 lbacount = 1;
346 }
347 }
348 }
349
350 if (lbacount > 0)
351 {
352 ventoy_read_iso_sector(lastlba, lbacount, lastbuffer);
353 }
354
355 return EFI_SUCCESS;
356 }
357
358 EFI_STATUS EFIAPI ventoy_block_io_write
359 (
360 IN EFI_BLOCK_IO_PROTOCOL *This,
361 IN UINT32 MediaId,
362 IN EFI_LBA Lba,
363 IN UINTN BufferSize,
364 IN VOID *Buffer
365 )
366 {
367 (VOID)This;
368 (VOID)MediaId;
369 (VOID)Lba;
370 (VOID)BufferSize;
371 (VOID)Buffer;
372 return EFI_WRITE_PROTECTED;
373 }
374
375 EFI_STATUS EFIAPI ventoy_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL *This)
376 {
377 (VOID)This;
378 return EFI_SUCCESS;
379 }
380
381
382 EFI_STATUS EFIAPI ventoy_fill_device_path(VOID)
383 {
384 UINTN NameLen = 0;
385 UINT8 TmpBuf[128] = {0};
386 VENDOR_DEVICE_PATH *venPath = NULL;
387
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);
396
397 gBlockData.Path = AppendDevicePathNode(NULL, (EFI_DEVICE_PATH_PROTOCOL *)TmpBuf);
398 gBlockData.DevicePathCompareLen = sizeof(VENDOR_DEVICE_PATH) + NameLen;
399
400 debug("gBlockData.Path=<%s>\n", ConvertDevicePathToText(gBlockData.Path, FALSE, FALSE));
401
402 return EFI_SUCCESS;
403 }
404
405 EFI_STATUS EFIAPI ventoy_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST CHAR16 *DrvName)
406 {
407 UINTN i = 0;
408 UINTN Count = 0;
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;
415
416 debug("ventoy_connect_driver <%s>...", DrvName);
417
418 Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentName2ProtocolGuid,
419 NULL, &Count, &Handles);
420 if (EFI_ERROR(Status))
421 {
422 return Status;
423 }
424
425 for (i = 0; i < Count; i++)
426 {
427 Status = gBS->HandleProtocol(Handles[i], &gEfiComponentName2ProtocolGuid, (VOID **)&Name2Protocol);
428 if (EFI_ERROR(Status))
429 {
430 continue;
431 }
432
433 Status = Name2Protocol->GetDriverName(Name2Protocol, "en", &DriverName);
434 if (EFI_ERROR(Status) || NULL == DriverName)
435 {
436 continue;
437 }
438
439 if (StrStr(DriverName, DrvName))
440 {
441 debug("Find driver name2:<%s>: <%s>", DriverName, DrvName);
442 DrvHandles[0] = Handles[i];
443 break;
444 }
445 }
446
447 if (i < Count)
448 {
449 Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE);
450 debug("Connect partition driver:<%r>", Status);
451 goto end;
452 }
453
454 debug("%s NOT found, now try COMPONENT_NAME", DrvName);
455
456 Count = 0;
457 FreePool(Handles);
458 Handles = NULL;
459
460 Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentNameProtocolGuid,
461 NULL, &Count, &Handles);
462 if (EFI_ERROR(Status))
463 {
464 return Status;
465 }
466
467 for (i = 0; i < Count; i++)
468 {
469 Status = gBS->HandleProtocol(Handles[i], &gEfiComponentNameProtocolGuid, (VOID **)&NameProtocol);
470 if (EFI_ERROR(Status))
471 {
472 continue;
473 }
474
475 Status = NameProtocol->GetDriverName(NameProtocol, "en", &DriverName);
476 if (EFI_ERROR(Status))
477 {
478 continue;
479 }
480
481 if (StrStr(DriverName, DrvName))
482 {
483 debug("Find driver name:<%s>: <%s>", DriverName, DrvName);
484 DrvHandles[0] = Handles[i];
485 break;
486 }
487 }
488
489 if (i < Count)
490 {
491 Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE);
492 debug("Connect partition driver:<%r>", Status);
493 goto end;
494 }
495
496 Status = EFI_NOT_FOUND;
497
498 end:
499 FreePool(Handles);
500
501 return Status;
502 }
503
504 EFI_STATUS EFIAPI ventoy_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 ImgSize)
505 {
506 EFI_STATUS Status = EFI_SUCCESS;
507 EFI_BLOCK_IO_PROTOCOL *pBlockIo = &(gBlockData.BlockIo);
508
509 ventoy_fill_device_path();
510
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;
516
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;
523
524 Status = gBS->InstallMultipleProtocolInterfaces(&gBlockData.Handle,
525 &gEfiBlockIoProtocolGuid, &gBlockData.BlockIo,
526 &gEfiDevicePathProtocolGuid, gBlockData.Path,
527 NULL);
528 debug("Install protocol %r %p", Status, gBlockData.Handle);
529 if (EFI_ERROR(Status))
530 {
531 return Status;
532 }
533
534 Status = ventoy_connect_driver(gBlockData.Handle, L"Disk I/O Driver");
535 debug("Connect disk IO driver %r", Status);
536 ventoy_debug_pause();
537
538 Status = ventoy_connect_driver(gBlockData.Handle, L"Partition Driver");
539 debug("Connect partition driver %r", Status);
540 if (EFI_ERROR(Status))
541 {
542 Status = gBS->ConnectController(gBlockData.Handle, NULL, NULL, TRUE);
543 debug("Connect all controller %r", Status);
544 }
545
546 ventoy_debug_pause();
547
548 return EFI_SUCCESS;
549 }
550
551 EFI_STATUS EFIAPI ventoy_wrapper_file_open
552 (
553 EFI_FILE_HANDLE This,
554 EFI_FILE_HANDLE *New,
555 CHAR16 *Name,
556 UINT64 Mode,
557 UINT64 Attributes
558 )
559 {
560 UINT32 i = 0;
561 UINT32 j = 0;
562 UINT64 Sectors = 0;
563 EFI_STATUS Status = EFI_SUCCESS;
564 CHAR8 TmpName[256];
565 ventoy_virt_chunk *virt = NULL;
566
567 Status = g_original_fopen(This, New, Name, Mode, Attributes);
568 if (EFI_ERROR(Status))
569 {
570 return Status;
571 }
572
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)
575 {
576 AsciiSPrint(TmpName, sizeof(TmpName), "%s", Name);
577 for (j = 0; j < 4; j++)
578 {
579 if (0 == AsciiStrCmp(g_file_replace_list[i].old_file_name[j], TmpName))
580 {
581 g_original_fclose(*New);
582 *New = &g_efi_file_replace.WrapperHandle;
583 ventoy_wrapper_file_procotol(*New);
584
585 virt = g_virt_chunk + g_file_replace_list->new_file_virtual_id;
586
587 Sectors = (virt->mem_sector_end - virt->mem_sector_start) + (virt->remap_sector_end - virt->remap_sector_start);
588
589 g_efi_file_replace.BlockIoSectorStart = virt->mem_sector_start;
590 g_efi_file_replace.FileSizeBytes = Sectors * 2048;
591
592 if (gDebugPrint)
593 {
594 debug("## ventoy_wrapper_file_open <%s> BlockStart:%lu Sectors:%lu Bytes:%lu", Name,
595 g_efi_file_replace.BlockIoSectorStart, Sectors, Sectors * 2048);
596 sleep(3);
597 }
598
599 return Status;
600 }
601 }
602 }
603
604 return Status;
605 }
606
607 EFI_STATUS EFIAPI ventoy_wrapper_open_volume
608 (
609 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
610 OUT EFI_FILE_PROTOCOL **Root
611 )
612 {
613 EFI_STATUS Status = EFI_SUCCESS;
614
615 Status = g_original_open_volume(This, Root);
616 if (!EFI_ERROR(Status))
617 {
618 g_original_fopen = (*Root)->Open;
619 g_original_fclose = (*Root)->Close;
620 (*Root)->Open = ventoy_wrapper_file_open;
621 }
622
623 return Status;
624 }
625
626 EFI_STATUS EFIAPI ventoy_wrapper_push_openvolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume)
627 {
628 g_original_open_volume = OpenVolume;
629 return EFI_SUCCESS;
630 }
631