2 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
11 #include <ipxe/blockdev.h>
13 #include <ipxe/acpi.h>
14 #include <ipxe/sanboot.h>
15 #include <ipxe/device.h>
17 #include <ipxe/eltorito.h>
18 #include <ipxe/timer.h>
19 #include <ipxe/umalloc.h>
23 #include <bootsector.h>
29 int g_bios_disk80
= 0;
33 ventoy_chain_head
*g_chain
;
34 ventoy_img_chunk
*g_chunk
;
35 uint32_t g_img_chunk_num
;
36 ventoy_img_chunk
*g_cur_chunk
;
37 uint32_t g_disk_sector_size
;
38 uint8_t *g_os_param_reserved
;
41 ventoy_override_chunk
*g_override_chunk
;
42 uint32_t g_override_chunk_num
;
44 ventoy_virt_chunk
*g_virt_chunk
;
45 uint32_t g_virt_chunk_num
;
47 ventoy_sector_flag g_sector_flag
[128];
49 #define VENTOY_ISO9660_SECTOR_OVERFLOW 2097152
51 int g_fixup_iso9660_secover_enable
= 0;
52 int g_fixup_iso9660_secover_start
= 0;
53 uint64 g_fixup_iso9660_secover_1st_secs
= 0;
54 uint64 g_fixup_iso9660_secover_cur_secs
= 0;
55 uint64 g_fixup_iso9660_secover_tot_secs
= 0;
57 static struct int13_disk_address
__bss16 ( ventoy_address
);
58 #define ventoy_address __use_data16 ( ventoy_address )
60 static uint64_t ventoy_remap_lba_hdd(uint64_t lba
, uint32_t *count
)
64 ventoy_img_chunk
*cur
;
66 if ((NULL
== g_cur_chunk
) || (lba
< g_cur_chunk
->img_start_sector
) ||
67 (lba
> g_cur_chunk
->img_end_sector
))
70 for (i
= 0; i
< g_img_chunk_num
; i
++)
73 if (lba
>= cur
->img_start_sector
&& lba
<= cur
->img_end_sector
)
83 max_sectors
= g_cur_chunk
->img_end_sector
- lba
+ 1;
84 if (*count
> max_sectors
)
89 return g_cur_chunk
->disk_start_sector
+ (lba
- g_cur_chunk
->img_start_sector
);
94 static uint64_t ventoy_remap_lba(uint64_t lba
, uint32_t *count
)
98 ventoy_img_chunk
*cur
;
100 if ((NULL
== g_cur_chunk
) || ((lba
) < g_cur_chunk
->img_start_sector
) || ((lba
) > g_cur_chunk
->img_end_sector
))
103 for (i
= 0; i
< g_img_chunk_num
; i
++)
106 if (lba
>= cur
->img_start_sector
&& lba
<= cur
->img_end_sector
)
116 max_sectors
= g_cur_chunk
->img_end_sector
- lba
+ 1;
117 if (*count
> max_sectors
)
119 *count
= max_sectors
;
122 if (512 == g_disk_sector_size
)
124 return g_cur_chunk
->disk_start_sector
+ ((lba
- g_cur_chunk
->img_start_sector
) << 2);
126 return g_cur_chunk
->disk_start_sector
+ (lba
- g_cur_chunk
->img_start_sector
) * 2048 / g_disk_sector_size
;
131 static int ventoy_vdisk_read_real_hdd(uint64_t lba
, unsigned int count
, unsigned long buffer
)
134 uint32_t readcount
= 0;
135 uint32_t tmpcount
= 0;
139 unsigned long phyaddr
;
145 printf("ventoy_vdisk_read_real_hdd: %llu %u\n", lba
, count
);
151 maplba
= ventoy_remap_lba_hdd(curlba
, &readcount
);
153 tmpcount
= readcount
;
155 phyaddr
= user_to_phys(buffer
, 0);
159 /* Use INT 13, 42 to read the data from real disk */
160 ventoy_address
.lba
= maplba
;
161 ventoy_address
.buffer
.segment
= (uint16_t)(phyaddr
>> 4);
162 ventoy_address
.buffer
.offset
= (uint16_t)(phyaddr
& 0x0F);
164 if (tmpcount
>= 64) /* max sectors per transmit */
166 ventoy_address
.count
= 64;
173 ventoy_address
.count
= tmpcount
;
177 __asm__
__volatile__ ( REAL_CODE ( "stc\n\t"
180 "sti\n\t" /* BIOS bugs */
182 "xorw %%ax, %%ax\n\t"
185 : "a" ( 0x4200 ), "d" ( VENTOY_BIOS_FAKE_DRIVE
),
186 "S" ( __from_data16 ( &ventoy_address
) ) );
191 buffer
+= (readcount
* 512);
197 static int ventoy_vdisk_read_real(uint64_t lba
, unsigned int count
, unsigned long buffer
)
201 uint32_t readcount
= 0;
202 uint32_t tmpcount
= 0;
208 uint64_t override_start
= 0;
209 uint64_t override_end
= 0;
210 unsigned long phyaddr
;
211 unsigned long databuffer
= buffer
;
212 uint8_t *override_data
;
220 maplba
= ventoy_remap_lba(curlba
, &readcount
);
222 if (g_disk_sector_size
== 512)
224 tmpcount
= (readcount
<< 2);
228 tmpcount
= (readcount
* 2048) / g_disk_sector_size
;
231 phyaddr
= user_to_phys(buffer
, 0);
235 /* Use INT 13, 42 to read the data from real disk */
236 ventoy_address
.lba
= maplba
;
237 ventoy_address
.buffer
.segment
= (uint16_t)(phyaddr
>> 4);
238 ventoy_address
.buffer
.offset
= (uint16_t)(phyaddr
& 0x0F);
240 if (tmpcount
>= 64) /* max sectors per transmit */
242 ventoy_address
.count
= 64;
249 ventoy_address
.count
= tmpcount
;
253 __asm__
__volatile__ ( REAL_CODE ( "stc\n\t"
256 "sti\n\t" /* BIOS bugs */
258 "xorw %%ax, %%ax\n\t"
261 : "a" ( 0x4200 ), "d" ( VENTOY_BIOS_FAKE_DRIVE
),
262 "S" ( __from_data16 ( &ventoy_address
) ) );
267 buffer
+= (readcount
* 2048);
271 if (start
> g_chain
->real_img_size_in_bytes
)
276 end
= start
+ count
* 2048;
277 for (i
= 0; i
< g_override_chunk_num
; i
++)
279 override_data
= g_override_chunk
[i
].override_data
;
280 override_start
= g_override_chunk
[i
].img_offset
;
281 override_end
= override_start
+ g_override_chunk
[i
].override_size
;
283 if (end
<= override_start
|| start
>= override_end
)
288 if (start
<= override_start
)
290 if (end
<= override_end
)
292 memcpy((char *)databuffer
+ override_start
- start
, override_data
, end
- override_start
);
296 memcpy((char *)databuffer
+ override_start
- start
, override_data
, override_end
- override_start
);
301 if (end
<= override_end
)
303 memcpy((char *)databuffer
, override_data
+ start
- override_start
, end
- start
);
307 memcpy((char *)databuffer
, override_data
+ start
- override_start
, override_end
- start
);
311 if (g_fixup_iso9660_secover_enable
&& (!g_fixup_iso9660_secover_start
) &&
312 g_override_chunk
[i
].override_size
== sizeof(ventoy_iso9660_override
))
314 ventoy_iso9660_override
*dirent
= (ventoy_iso9660_override
*)override_data
;
315 if (dirent
->first_sector
>= VENTOY_ISO9660_SECTOR_OVERFLOW
)
317 g_fixup_iso9660_secover_start
= 1;
318 g_fixup_iso9660_secover_cur_secs
= 0;
328 uint64_t ventoy_fixup_iso9660_sector(uint64_t Lba
, uint32_t secNum
)
332 if (g_fixup_iso9660_secover_cur_secs
> 0)
334 Lba
+= VENTOY_ISO9660_SECTOR_OVERFLOW
;
335 g_fixup_iso9660_secover_cur_secs
+= secNum
;
336 if (g_fixup_iso9660_secover_cur_secs
>= g_fixup_iso9660_secover_tot_secs
)
338 g_fixup_iso9660_secover_start
= 0;
344 ventoy_iso9660_override
*dirent
;
345 ventoy_override_chunk
*pOverride
;
347 for (i
= 0, pOverride
= g_override_chunk
; i
< g_override_chunk_num
; i
++, pOverride
++)
349 dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
350 if (Lba
== dirent
->first_sector
)
352 g_fixup_iso9660_secover_start
= 0;
357 if (g_fixup_iso9660_secover_start
)
359 for (i
= 0, pOverride
= g_override_chunk
; i
< g_override_chunk_num
; i
++, pOverride
++)
361 dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
362 if (Lba
+ VENTOY_ISO9660_SECTOR_OVERFLOW
== dirent
->first_sector
)
364 g_fixup_iso9660_secover_tot_secs
= (dirent
->size
+ 2047) / 2048;
365 g_fixup_iso9660_secover_cur_secs
= secNum
;
366 if (g_fixup_iso9660_secover_cur_secs
>= g_fixup_iso9660_secover_tot_secs
)
368 g_fixup_iso9660_secover_start
= 0;
370 Lba
+= VENTOY_ISO9660_SECTOR_OVERFLOW
;
381 int ventoy_vdisk_read(struct san_device
*sandev
, uint64_t lba
, unsigned int count
, unsigned long buffer
)
385 uint64_t lastlba
= 0;
386 uint32_t lbacount
= 0;
387 unsigned long lastbuffer
;
390 ventoy_virt_chunk
*node
;
391 ventoy_sector_flag
*cur_flag
;
392 ventoy_sector_flag
*sector_flag
= g_sector_flag
;
393 struct i386_all_regs
*ix86
;
395 if (INT13_EXTENDED_READ
!= sandev
->int13_command
)
397 DBGC(sandev
, "invalid cmd %u\n", sandev
->int13_command
);
401 ix86
= (struct i386_all_regs
*)sandev
->x86_regptr
;
405 ventoy_vdisk_read_real_hdd(lba
, count
, buffer
);
406 ix86
->regs
.dl
= sandev
->drive
;
410 /* Workaround for SSTR PE loader error */
411 if (g_fixup_iso9660_secover_start
)
413 lba
= ventoy_fixup_iso9660_sector(lba
, count
);
416 readend
= (lba
+ count
) * 2048;
417 if (readend
<= g_chain
->real_img_size_in_bytes
)
419 ventoy_vdisk_read_real(lba
, count
, buffer
);
420 ix86
->regs
.dl
= sandev
->drive
;
423 else if ((lba
* 2048) < g_chain
->real_img_size_in_bytes
)
425 /* fix for grub4dos Inconsistent data read from error */
426 memset((void *)(buffer
+ (count
- 1) * 2048), 0, 2048);
428 count
= (g_chain
->real_img_size_in_bytes
/ 2048) - lba
;
429 ventoy_vdisk_read_real(lba
, count
, buffer
);
430 ix86
->regs
.dl
= sandev
->drive
;
433 buffer
+= count
* 2048;
434 count
= (readend
- g_chain
->real_img_size_in_bytes
) / 2048;
437 VirtSec
= g_chain
->virt_img_size_in_bytes
/ 2048;
438 if (lba
+ count
> VirtSec
)
440 count
= VirtSec
- lba
;
443 if (count
> sizeof(g_sector_flag
))
445 sector_flag
= (ventoy_sector_flag
*)malloc(count
* sizeof(ventoy_sector_flag
));
448 for (curlba
= lba
, cur_flag
= sector_flag
, j
= 0; j
< count
; j
++, curlba
++, cur_flag
++)
451 for (node
= g_virt_chunk
, i
= 0; i
< g_virt_chunk_num
; i
++, node
++)
453 if (curlba
>= node
->mem_sector_start
&& curlba
< node
->mem_sector_end
)
455 memcpy((void *)(buffer
+ j
* 2048),
456 (char *)g_virt_chunk
+ node
->mem_sector_offset
+ (curlba
- node
->mem_sector_start
) * 2048,
461 else if (curlba
>= node
->remap_sector_start
&& curlba
< node
->remap_sector_end
)
463 cur_flag
->remap_lba
= node
->org_sector_start
+ curlba
- node
->remap_sector_start
;
470 for (curlba
= lba
, cur_flag
= sector_flag
, j
= 0; j
< count
; j
++, curlba
++, cur_flag
++)
472 if (cur_flag
->flag
== 2)
476 lastbuffer
= buffer
+ j
* 2048;
477 lastlba
= cur_flag
->remap_lba
;
480 else if (lastlba
+ lbacount
== cur_flag
->remap_lba
)
486 ventoy_vdisk_read_real(lastlba
, lbacount
, lastbuffer
);
487 lastbuffer
= buffer
+ j
* 2048;
488 lastlba
= cur_flag
->remap_lba
;
496 ventoy_vdisk_read_real(lastlba
, lbacount
, lastbuffer
);
499 if (sector_flag
!= g_sector_flag
)
504 ix86
->regs
.dl
= sandev
->drive
;
508 static void ventoy_dump_img_chunk(ventoy_chain_head
*chain
)
511 ventoy_img_chunk
*chunk
;
513 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
515 printf("##################### ventoy_dump_img_chunk #######################\n");
517 for (i
= 0; i
< chain
->img_chunk_num
; i
++)
519 printf("%2u: [ %u - %u ] <==> [ %llu - %llu ]\n",
520 i
, chunk
[i
].img_start_sector
, chunk
[i
].img_end_sector
,
521 chunk
[i
].disk_start_sector
, chunk
[i
].disk_end_sector
);
524 ventoy_debug_pause();
527 static void ventoy_dump_override_chunk(ventoy_chain_head
*chain
)
530 ventoy_override_chunk
*chunk
;
532 chunk
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
534 printf("##################### ventoy_dump_override_chunk #######################\n");
536 for (i
= 0; i
< g_override_chunk_num
; i
++)
538 printf("%2u: [ %llu, %u ]\n", i
, chunk
[i
].img_offset
, chunk
[i
].override_size
);
541 ventoy_debug_pause();
544 static void ventoy_dump_virt_chunk(ventoy_chain_head
*chain
)
547 ventoy_virt_chunk
*node
;
549 printf("##################### ventoy_dump_virt_chunk #######################\n");
550 printf("virt_chunk_offset=%u\n", chain
->virt_chunk_offset
);
551 printf("virt_chunk_num=%u\n", chain
->virt_chunk_num
);
553 node
= (ventoy_virt_chunk
*)((char *)chain
+ chain
->virt_chunk_offset
);
554 for (i
= 0; i
< chain
->virt_chunk_num
; i
++, node
++)
556 printf("%2u: mem:[ %u, %u, %u ] remap:[ %u, %u, %u ]\n", i
,
557 node
->mem_sector_start
,
558 node
->mem_sector_end
,
559 node
->mem_sector_offset
,
560 node
->remap_sector_start
,
561 node
->remap_sector_end
,
562 node
->org_sector_start
);
565 ventoy_debug_pause();
568 static void ventoy_dump_chain(ventoy_chain_head
*chain
)
574 uint8_t *vtoy_reserve
;
576 guid
= chain
->os_param
.vtoy_disk_guid
;
577 sig
= chain
->os_param
.vtoy_disk_signature
;
579 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
581 chksum
+= *((uint8_t *)(&(chain
->os_param
)) + i
);
584 vtoy_reserve
= (uint8_t *)(chain
->os_param
.vtoy_reserved
);
586 printf("##################### ventoy_dump_chain #######################\n");
588 printf("os_param will be save at %p\n", ventoy_get_runtime_addr());
590 printf("os_param->chksum=0x%x (%s)\n", chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
591 printf("os_param->vtoy_disk_guid=%02x%02x%02x%02x\n", guid
[0], guid
[1], guid
[2], guid
[3]);
592 printf("os_param->vtoy_disk_signature=%02x%02x%02x%02x\n", sig
[0], sig
[1], sig
[2], sig
[3]);
593 printf("os_param->vtoy_disk_size=%llu\n", chain
->os_param
.vtoy_disk_size
);
594 printf("os_param->vtoy_disk_part_id=%u\n", chain
->os_param
.vtoy_disk_part_id
);
595 printf("os_param->vtoy_disk_part_type=%u\n", chain
->os_param
.vtoy_disk_part_type
);
596 printf("os_param->vtoy_img_path=<%s>\n", chain
->os_param
.vtoy_img_path
);
597 printf("os_param->vtoy_img_size=<%llu>\n", chain
->os_param
.vtoy_img_size
);
598 printf("os_param->vtoy_reserve[0]=<%u>\n", vtoy_reserve
[0]);
599 printf("os_param->vtoy_reserve[1]=<%u>\n", vtoy_reserve
[1]);
600 printf("os_param->vtoy_reserve[2]=<%u>\n", vtoy_reserve
[2]);
601 printf("os_param->vtoy_reserve[3]=<%u>\n", vtoy_reserve
[3]);
602 printf("os_param->vtoy_img_location_addr=<0x%llx>\n", chain
->os_param
.vtoy_img_location_addr
);
603 printf("os_param->vtoy_img_location_len=<%u>\n", chain
->os_param
.vtoy_img_location_len
);
604 ventoy_debug_pause();
606 printf("chain->disk_drive=0x%x\n", chain
->disk_drive
);
607 printf("chain->drive_map=0x%x\n", chain
->drive_map
);
608 printf("chain->disk_sector_size=%u\n", chain
->disk_sector_size
);
609 printf("chain->real_img_size_in_bytes=%llu\n", chain
->real_img_size_in_bytes
);
610 printf("chain->virt_img_size_in_bytes=%llu\n", chain
->virt_img_size_in_bytes
);
611 printf("chain->boot_catalog=%u\n", chain
->boot_catalog
);
612 printf("chain->img_chunk_offset=%u\n", chain
->img_chunk_offset
);
613 printf("chain->img_chunk_num=%u\n", chain
->img_chunk_num
);
614 printf("chain->override_chunk_offset=%u\n", chain
->override_chunk_offset
);
615 printf("chain->override_chunk_num=%u\n", chain
->override_chunk_num
);
616 printf("chain->virt_chunk_offset=%u\n", chain
->virt_chunk_offset
);
617 printf("chain->virt_chunk_num=%u\n", chain
->virt_chunk_num
);
618 ventoy_debug_pause();
620 ventoy_dump_img_chunk(chain
);
621 ventoy_dump_override_chunk(chain
);
622 ventoy_dump_virt_chunk(chain
);
625 static int ventoy_update_image_location(ventoy_os_param
*param
)
630 userptr_t address
= 0;
631 ventoy_image_location
*location
= NULL
;
632 ventoy_image_disk_region
*region
= NULL
;
633 ventoy_img_chunk
*chunk
= g_chunk
;
635 length
= sizeof(ventoy_image_location
) + (g_img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
637 address
= umalloc(length
+ 4096 * 2);
645 address
+= 4096 - (address
% 4096);
649 param
->vtoy_img_location_addr
= user_to_phys(address
, 0);
650 param
->vtoy_img_location_len
= length
;
652 /* update check sum */
653 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
655 chksum
+= *((uint8_t *)param
+ i
);
657 param
->chksum
= (chksum
== 0) ? 0 : (uint8_t)(0x100 - chksum
);
659 location
= (ventoy_image_location
*)(unsigned long)(address
);
660 if (NULL
== location
)
665 memcpy(&location
->guid
, ¶m
->guid
, sizeof(ventoy_guid
));
666 location
->image_sector_size
= g_hddmode
? 512 : 2048;
667 location
->disk_sector_size
= g_chain
->disk_sector_size
;
668 location
->region_count
= g_img_chunk_num
;
670 region
= location
->regions
;
674 for (i
= 0; i
< g_img_chunk_num
; i
++)
676 region
->image_sector_count
= chunk
->disk_end_sector
- chunk
->disk_start_sector
+ 1;
677 region
->image_start_sector
= chunk
->img_start_sector
* 4;
678 region
->disk_start_sector
= chunk
->disk_start_sector
;
685 for (i
= 0; i
< g_img_chunk_num
; i
++)
687 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
688 region
->image_start_sector
= chunk
->img_start_sector
;
689 region
->disk_start_sector
= chunk
->disk_start_sector
;
698 int ventoy_boot_vdisk(void *data
)
703 ventoy_img_chunk
*cur
;
707 ventoy_address
.bufsize
= offsetof ( typeof ( ventoy_address
), buffer_phys
);
709 if (strstr(g_cmdline_copy
, "debug"))
712 printf("### ventoy chain boot begin... ###\n");
713 printf("cmdline: <%s>\n", g_cmdline_copy
);
714 ventoy_debug_pause();
717 if (strstr(g_cmdline_copy
, "sector512"))
722 if (strstr(g_cmdline_copy
, "bios80"))
727 g_chain
= (ventoy_chain_head
*)g_initrd_addr
;
728 g_chunk
= (ventoy_img_chunk
*)((char *)g_chain
+ g_chain
->img_chunk_offset
);
729 g_img_chunk_num
= g_chain
->img_chunk_num
;
730 g_disk_sector_size
= g_chain
->disk_sector_size
;
731 g_cur_chunk
= g_chunk
;
733 g_os_param_reserved
= (uint8_t *)(g_chain
->os_param
.vtoy_reserved
);
735 /* Workaround for Windows & ISO9660 */
736 if (g_os_param_reserved
[2] == ventoy_chain_windows
&& g_os_param_reserved
[3] == 0)
738 g_fixup_iso9660_secover_enable
= 1;
741 g_override_chunk
= (ventoy_override_chunk
*)((char *)g_chain
+ g_chain
->override_chunk_offset
);
742 g_override_chunk_num
= g_chain
->override_chunk_num
;
744 g_virt_chunk
= (ventoy_virt_chunk
*)((char *)g_chain
+ g_chain
->virt_chunk_offset
);
745 g_virt_chunk_num
= g_chain
->virt_chunk_num
;
749 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
751 chksum
+= *((uint8_t *)(&(g_chain
->os_param
)) + i
);
753 printf("os param checksum: 0x%x %s\n", g_chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
756 ventoy_update_image_location(&(g_chain
->os_param
));
760 ventoy_dump_chain(g_chain
);
765 for (i
= 0; i
< g_img_chunk_num
; i
++)
768 cur
->img_start_sector
*= 4;
769 cur
->img_end_sector
= cur
->img_end_sector
* 4 + 3;
773 drive
= ventoy_int13_hook(g_chain
);
777 printf("### ventoy chain boot before boot image ... ###\n");
778 ventoy_debug_pause();
781 ventoy_int13_boot(drive
, &(g_chain
->os_param
), g_cmdline_copy
);
785 printf("!!!!!!!!!! ventoy boot failed !!!!!!!!!!\n");
786 ventoy_debug_pause();