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>
31 ventoy_chain_head
*g_chain
;
32 ventoy_img_chunk
*g_chunk
;
33 uint32_t g_img_chunk_num
;
34 ventoy_img_chunk
*g_cur_chunk
;
35 uint32_t g_disk_sector_size
;
36 uint8_t *g_os_param_reserved
;
39 ventoy_override_chunk
*g_override_chunk
;
40 uint32_t g_override_chunk_num
;
42 ventoy_virt_chunk
*g_virt_chunk
;
43 uint32_t g_virt_chunk_num
;
45 ventoy_sector_flag g_sector_flag
[128];
47 #define VENTOY_ISO9660_SECTOR_OVERFLOW 2097152
49 int g_fixup_iso9660_secover_enable
= 0;
50 int g_fixup_iso9660_secover_start
= 0;
51 uint64 g_fixup_iso9660_secover_1st_secs
= 0;
52 uint64 g_fixup_iso9660_secover_cur_secs
= 0;
53 uint64 g_fixup_iso9660_secover_tot_secs
= 0;
55 static struct int13_disk_address
__bss16 ( ventoy_address
);
56 #define ventoy_address __use_data16 ( ventoy_address )
58 static uint64_t ventoy_remap_lba(uint64_t lba
, uint32_t *count
)
62 ventoy_img_chunk
*cur
;
64 if ((NULL
== g_cur_chunk
) || ((lba
) < g_cur_chunk
->img_start_sector
) || ((lba
) > g_cur_chunk
->img_end_sector
))
67 for (i
= 0; i
< g_img_chunk_num
; i
++)
70 if (lba
>= cur
->img_start_sector
&& lba
<= cur
->img_end_sector
)
80 max_sectors
= g_cur_chunk
->img_end_sector
- lba
+ 1;
81 if (*count
> max_sectors
)
86 if (512 == g_disk_sector_size
)
88 return g_cur_chunk
->disk_start_sector
+ ((lba
- g_cur_chunk
->img_start_sector
) << 2);
90 return g_cur_chunk
->disk_start_sector
+ (lba
- g_cur_chunk
->img_start_sector
) * 2048 / g_disk_sector_size
;
95 static int ventoy_vdisk_read_real(uint64_t lba
, unsigned int count
, unsigned long buffer
)
99 uint32_t readcount
= 0;
100 uint32_t tmpcount
= 0;
106 uint64_t override_start
= 0;
107 uint64_t override_end
= 0;
108 unsigned long phyaddr
;
109 unsigned long databuffer
= buffer
;
110 uint8_t *override_data
;
118 maplba
= ventoy_remap_lba(curlba
, &readcount
);
120 if (g_disk_sector_size
== 512)
122 tmpcount
= (readcount
<< 2);
126 tmpcount
= (readcount
* 2048) / g_disk_sector_size
;
129 phyaddr
= user_to_phys(buffer
, 0);
133 /* Use INT 13, 42 to read the data from real disk */
134 ventoy_address
.lba
= maplba
;
135 ventoy_address
.buffer
.segment
= (uint16_t)(phyaddr
>> 4);
136 ventoy_address
.buffer
.offset
= (uint16_t)(phyaddr
& 0x0F);
138 if (tmpcount
>= 64) /* max sectors per transmit */
140 ventoy_address
.count
= 64;
147 ventoy_address
.count
= tmpcount
;
151 __asm__
__volatile__ ( REAL_CODE ( "stc\n\t"
154 "sti\n\t" /* BIOS bugs */
156 "xorw %%ax, %%ax\n\t"
159 : "a" ( 0x4200 ), "d" ( VENTOY_BIOS_FAKE_DRIVE
),
160 "S" ( __from_data16 ( &ventoy_address
) ) );
165 buffer
+= (readcount
* 2048);
169 if (start
> g_chain
->real_img_size_in_bytes
)
174 end
= start
+ count
* 2048;
175 for (i
= 0; i
< g_override_chunk_num
; i
++)
177 override_data
= g_override_chunk
[i
].override_data
;
178 override_start
= g_override_chunk
[i
].img_offset
;
179 override_end
= override_start
+ g_override_chunk
[i
].override_size
;
181 if (end
<= override_start
|| start
>= override_end
)
186 if (start
<= override_start
)
188 if (end
<= override_end
)
190 memcpy((char *)databuffer
+ override_start
- start
, override_data
, end
- override_start
);
194 memcpy((char *)databuffer
+ override_start
- start
, override_data
, override_end
- override_start
);
199 if (end
<= override_end
)
201 memcpy((char *)databuffer
, override_data
+ start
- override_start
, end
- start
);
205 memcpy((char *)databuffer
, override_data
+ start
- override_start
, override_end
- start
);
209 if (g_fixup_iso9660_secover_enable
&& (!g_fixup_iso9660_secover_start
) &&
210 g_override_chunk
[i
].override_size
== sizeof(ventoy_iso9660_override
))
212 ventoy_iso9660_override
*dirent
= (ventoy_iso9660_override
*)override_data
;
213 if (dirent
->first_sector
>= VENTOY_ISO9660_SECTOR_OVERFLOW
)
215 g_fixup_iso9660_secover_start
= 1;
216 g_fixup_iso9660_secover_cur_secs
= 0;
226 uint64_t ventoy_fixup_iso9660_sector(uint64_t Lba
, uint32_t secNum
)
230 if (g_fixup_iso9660_secover_cur_secs
> 0)
232 Lba
+= VENTOY_ISO9660_SECTOR_OVERFLOW
;
233 g_fixup_iso9660_secover_cur_secs
+= secNum
;
234 if (g_fixup_iso9660_secover_cur_secs
>= g_fixup_iso9660_secover_tot_secs
)
236 g_fixup_iso9660_secover_start
= 0;
242 ventoy_iso9660_override
*dirent
;
243 ventoy_override_chunk
*pOverride
;
245 for (i
= 0, pOverride
= g_override_chunk
; i
< g_override_chunk_num
; i
++, pOverride
++)
247 dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
248 if (Lba
== dirent
->first_sector
)
250 g_fixup_iso9660_secover_start
= 0;
255 if (g_fixup_iso9660_secover_start
)
257 for (i
= 0, pOverride
= g_override_chunk
; i
< g_override_chunk_num
; i
++, pOverride
++)
259 dirent
= (ventoy_iso9660_override
*)pOverride
->override_data
;
260 if (Lba
+ VENTOY_ISO9660_SECTOR_OVERFLOW
== dirent
->first_sector
)
262 g_fixup_iso9660_secover_tot_secs
= (dirent
->size
+ 2047) / 2048;
263 g_fixup_iso9660_secover_cur_secs
= secNum
;
264 if (g_fixup_iso9660_secover_cur_secs
>= g_fixup_iso9660_secover_tot_secs
)
266 g_fixup_iso9660_secover_start
= 0;
268 Lba
+= VENTOY_ISO9660_SECTOR_OVERFLOW
;
279 int ventoy_vdisk_read(struct san_device
*sandev
, uint64_t lba
, unsigned int count
, unsigned long buffer
)
283 uint64_t lastlba
= 0;
284 uint32_t lbacount
= 0;
285 unsigned long lastbuffer
;
287 ventoy_virt_chunk
*node
;
288 ventoy_sector_flag
*cur_flag
;
289 ventoy_sector_flag
*sector_flag
= g_sector_flag
;
290 struct i386_all_regs
*ix86
;
292 if (INT13_EXTENDED_READ
!= sandev
->int13_command
)
294 DBGC(sandev
, "invalid cmd %u\n", sandev
->int13_command
);
298 ix86
= (struct i386_all_regs
*)sandev
->x86_regptr
;
300 /* Workaround for SSTR PE loader error */
301 if (g_fixup_iso9660_secover_start
)
303 lba
= ventoy_fixup_iso9660_sector(lba
, count
);
306 readend
= (lba
+ count
) * 2048;
307 if (readend
<= g_chain
->real_img_size_in_bytes
)
309 ventoy_vdisk_read_real(lba
, count
, buffer
);
310 ix86
->regs
.dl
= sandev
->drive
;
314 if (count
> sizeof(g_sector_flag
))
316 sector_flag
= (ventoy_sector_flag
*)malloc(count
* sizeof(ventoy_sector_flag
));
319 for (curlba
= lba
, cur_flag
= sector_flag
, j
= 0; j
< count
; j
++, curlba
++, cur_flag
++)
322 for (node
= g_virt_chunk
, i
= 0; i
< g_virt_chunk_num
; i
++, node
++)
324 if (curlba
>= node
->mem_sector_start
&& curlba
< node
->mem_sector_end
)
326 memcpy((void *)(buffer
+ j
* 2048),
327 (char *)g_virt_chunk
+ node
->mem_sector_offset
+ (curlba
- node
->mem_sector_start
) * 2048,
332 else if (curlba
>= node
->remap_sector_start
&& curlba
< node
->remap_sector_end
)
334 cur_flag
->remap_lba
= node
->org_sector_start
+ curlba
- node
->remap_sector_start
;
341 for (curlba
= lba
, cur_flag
= sector_flag
, j
= 0; j
< count
; j
++, curlba
++, cur_flag
++)
343 if (cur_flag
->flag
== 2)
347 lastbuffer
= buffer
+ j
* 2048;
348 lastlba
= cur_flag
->remap_lba
;
351 else if (lastlba
+ lbacount
== cur_flag
->remap_lba
)
357 ventoy_vdisk_read_real(lastlba
, lbacount
, lastbuffer
);
358 lastbuffer
= buffer
+ j
* 2048;
359 lastlba
= cur_flag
->remap_lba
;
367 ventoy_vdisk_read_real(lastlba
, lbacount
, lastbuffer
);
370 if (sector_flag
!= g_sector_flag
)
375 ix86
->regs
.dl
= sandev
->drive
;
379 static void ventoy_dump_img_chunk(ventoy_chain_head
*chain
)
382 ventoy_img_chunk
*chunk
;
384 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
386 printf("##################### ventoy_dump_img_chunk #######################\n");
388 for (i
= 0; i
< chain
->img_chunk_num
; i
++)
390 printf("%2u: [ %u - %u ] <==> [ %llu - %llu ]\n",
391 i
, chunk
[i
].img_start_sector
, chunk
[i
].img_end_sector
,
392 chunk
[i
].disk_start_sector
, chunk
[i
].disk_end_sector
);
395 ventoy_debug_pause();
398 static void ventoy_dump_override_chunk(ventoy_chain_head
*chain
)
401 ventoy_override_chunk
*chunk
;
403 chunk
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
405 printf("##################### ventoy_dump_override_chunk #######################\n");
407 for (i
= 0; i
< g_override_chunk_num
; i
++)
409 printf("%2u: [ %llu, %u ]\n", i
, chunk
[i
].img_offset
, chunk
[i
].override_size
);
412 ventoy_debug_pause();
415 static void ventoy_dump_virt_chunk(ventoy_chain_head
*chain
)
418 ventoy_virt_chunk
*node
;
420 printf("##################### ventoy_dump_virt_chunk #######################\n");
421 printf("virt_chunk_offset=%u\n", chain
->virt_chunk_offset
);
422 printf("virt_chunk_num=%u\n", chain
->virt_chunk_num
);
424 node
= (ventoy_virt_chunk
*)((char *)chain
+ chain
->virt_chunk_offset
);
425 for (i
= 0; i
< chain
->virt_chunk_num
; i
++, node
++)
427 printf("%2u: mem:[ %u, %u, %u ] remap:[ %u, %u, %u ]\n", i
,
428 node
->mem_sector_start
,
429 node
->mem_sector_end
,
430 node
->mem_sector_offset
,
431 node
->remap_sector_start
,
432 node
->remap_sector_end
,
433 node
->org_sector_start
);
436 ventoy_debug_pause();
439 static void ventoy_dump_chain(ventoy_chain_head
*chain
)
444 uint8_t *vtoy_reserve
;
446 guid
= chain
->os_param
.vtoy_disk_guid
;
447 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
449 chksum
+= *((uint8_t *)(&(chain
->os_param
)) + i
);
452 vtoy_reserve
= (uint8_t *)(chain
->os_param
.vtoy_reserved
);
454 printf("##################### ventoy_dump_chain #######################\n");
456 printf("os_param will be save at %p\n", ventoy_get_runtime_addr());
458 printf("os_param->chksum=0x%x (%s)\n", chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
459 printf("os_param->vtoy_disk_guid=%02x%02x%02x%02x\n", guid
[0], guid
[1], guid
[2], guid
[3]);
460 printf("os_param->vtoy_disk_size=%llu\n", chain
->os_param
.vtoy_disk_size
);
461 printf("os_param->vtoy_disk_part_id=%u\n", chain
->os_param
.vtoy_disk_part_id
);
462 printf("os_param->vtoy_disk_part_type=%u\n", chain
->os_param
.vtoy_disk_part_type
);
463 printf("os_param->vtoy_img_path=<%s>\n", chain
->os_param
.vtoy_img_path
);
464 printf("os_param->vtoy_img_size=<%llu>\n", chain
->os_param
.vtoy_img_size
);
465 printf("os_param->vtoy_reserve[0]=<%u>\n", vtoy_reserve
[0]);
466 printf("os_param->vtoy_reserve[1]=<%u>\n", vtoy_reserve
[1]);
467 printf("os_param->vtoy_reserve[2]=<%u>\n", vtoy_reserve
[2]);
468 printf("os_param->vtoy_reserve[3]=<%u>\n", vtoy_reserve
[3]);
469 printf("os_param->vtoy_img_location_addr=<0x%llx>\n", chain
->os_param
.vtoy_img_location_addr
);
470 printf("os_param->vtoy_img_location_len=<%u>\n", chain
->os_param
.vtoy_img_location_len
);
471 ventoy_debug_pause();
473 printf("chain->disk_drive=0x%x\n", chain
->disk_drive
);
474 printf("chain->drive_map=0x%x\n", chain
->drive_map
);
475 printf("chain->disk_sector_size=%u\n", chain
->disk_sector_size
);
476 printf("chain->real_img_size_in_bytes=%llu\n", chain
->real_img_size_in_bytes
);
477 printf("chain->virt_img_size_in_bytes=%llu\n", chain
->virt_img_size_in_bytes
);
478 printf("chain->boot_catalog=%u\n", chain
->boot_catalog
);
479 printf("chain->img_chunk_offset=%u\n", chain
->img_chunk_offset
);
480 printf("chain->img_chunk_num=%u\n", chain
->img_chunk_num
);
481 printf("chain->override_chunk_offset=%u\n", chain
->override_chunk_offset
);
482 printf("chain->override_chunk_num=%u\n", chain
->override_chunk_num
);
483 printf("chain->virt_chunk_offset=%u\n", chain
->virt_chunk_offset
);
484 printf("chain->virt_chunk_num=%u\n", chain
->virt_chunk_num
);
485 ventoy_debug_pause();
487 ventoy_dump_img_chunk(chain
);
488 ventoy_dump_override_chunk(chain
);
489 ventoy_dump_virt_chunk(chain
);
492 static int ventoy_update_image_location(ventoy_os_param
*param
)
497 userptr_t address
= 0;
498 ventoy_image_location
*location
= NULL
;
499 ventoy_image_disk_region
*region
= NULL
;
500 ventoy_img_chunk
*chunk
= g_chunk
;
502 length
= sizeof(ventoy_image_location
) + (g_img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
504 address
= umalloc(length
+ 4096 * 2);
512 address
+= 4096 - (address
% 4096);
516 param
->vtoy_img_location_addr
= user_to_phys(address
, 0);
517 param
->vtoy_img_location_len
= length
;
519 /* update check sum */
520 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
522 chksum
+= *((uint8_t *)param
+ i
);
524 param
->chksum
= (chksum
== 0) ? 0 : (uint8_t)(0x100 - chksum
);
526 location
= (ventoy_image_location
*)(unsigned long)(address
);
527 if (NULL
== location
)
532 memcpy(&location
->guid
, ¶m
->guid
, sizeof(ventoy_guid
));
533 location
->image_sector_size
= 2048;
534 location
->disk_sector_size
= g_chain
->disk_sector_size
;
535 location
->region_count
= g_img_chunk_num
;
537 region
= location
->regions
;
539 for (i
= 0; i
< g_img_chunk_num
; i
++)
541 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
542 region
->image_start_sector
= chunk
->img_start_sector
;
543 region
->disk_start_sector
= chunk
->disk_start_sector
;
551 int ventoy_boot_vdisk(void *data
)
559 ventoy_address
.bufsize
= offsetof ( typeof ( ventoy_address
), buffer_phys
);
561 if (strstr(g_cmdline_copy
, "debug"))
564 printf("### ventoy chain boot begin... ###\n");
565 ventoy_debug_pause();
568 g_chain
= (ventoy_chain_head
*)g_initrd_addr
;
569 g_chunk
= (ventoy_img_chunk
*)((char *)g_chain
+ g_chain
->img_chunk_offset
);
570 g_img_chunk_num
= g_chain
->img_chunk_num
;
571 g_disk_sector_size
= g_chain
->disk_sector_size
;
572 g_cur_chunk
= g_chunk
;
574 g_os_param_reserved
= (uint8_t *)(g_chain
->os_param
.vtoy_reserved
);
576 /* Workaround for Windows & ISO9660 */
577 if (g_os_param_reserved
[2] == 1 && g_os_param_reserved
[3] == 0)
579 g_fixup_iso9660_secover_enable
= 1;
582 g_override_chunk
= (ventoy_override_chunk
*)((char *)g_chain
+ g_chain
->override_chunk_offset
);
583 g_override_chunk_num
= g_chain
->override_chunk_num
;
585 g_virt_chunk
= (ventoy_virt_chunk
*)((char *)g_chain
+ g_chain
->virt_chunk_offset
);
586 g_virt_chunk_num
= g_chain
->virt_chunk_num
;
590 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
592 chksum
+= *((uint8_t *)(&(g_chain
->os_param
)) + i
);
594 printf("os param checksum: 0x%x %s\n", g_chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
597 ventoy_update_image_location(&(g_chain
->os_param
));
601 ventoy_dump_chain(g_chain
);
604 drive
= ventoy_int13_hook(g_chain
);
608 printf("### ventoy chain boot before boot image ... ###\n");
609 ventoy_debug_pause();
612 ventoy_int13_boot(drive
, &(g_chain
->os_param
), g_cmdline_copy
);
616 printf("!!!!!!!!!! ventoy boot failed !!!!!!!!!!\n");
617 ventoy_debug_pause();