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
;
37 ventoy_override_chunk
*g_override_chunk
;
38 uint32_t g_override_chunk_num
;
40 ventoy_virt_chunk
*g_virt_chunk
;
41 uint32_t g_virt_chunk_num
;
43 ventoy_sector_flag g_sector_flag
[128];
45 static struct int13_disk_address
__bss16 ( ventoy_address
);
46 #define ventoy_address __use_data16 ( ventoy_address )
48 static uint64_t ventoy_remap_lba(uint64_t lba
, uint32_t *count
)
52 ventoy_img_chunk
*cur
;
54 if ((NULL
== g_cur_chunk
) || ((lba
) < g_cur_chunk
->img_start_sector
) || ((lba
) > g_cur_chunk
->img_end_sector
))
57 for (i
= 0; i
< g_img_chunk_num
; i
++)
60 if (lba
>= cur
->img_start_sector
&& lba
<= cur
->img_end_sector
)
70 max_sectors
= g_cur_chunk
->img_end_sector
- lba
+ 1;
71 if (*count
> max_sectors
)
76 if (512 == g_disk_sector_size
)
78 return g_cur_chunk
->disk_start_sector
+ ((lba
- g_cur_chunk
->img_start_sector
) << 2);
80 return g_cur_chunk
->disk_start_sector
+ (lba
- g_cur_chunk
->img_start_sector
) * 2048 / g_disk_sector_size
;
85 static int ventoy_vdisk_read_real(uint64_t lba
, unsigned int count
, unsigned long buffer
)
89 uint32_t readcount
= 0;
90 uint32_t tmpcount
= 0;
96 uint64_t override_start
= 0;
97 uint64_t override_end
= 0;
98 unsigned long phyaddr
;
99 unsigned long databuffer
= buffer
;
100 uint8_t *override_data
;
108 maplba
= ventoy_remap_lba(curlba
, &readcount
);
110 if (g_disk_sector_size
== 512)
112 tmpcount
= (readcount
<< 2);
116 tmpcount
= (readcount
* 2048) / g_disk_sector_size
;
119 phyaddr
= user_to_phys(buffer
, 0);
123 /* Use INT 13, 42 to read the data from real disk */
124 ventoy_address
.lba
= maplba
;
125 ventoy_address
.buffer
.segment
= (uint16_t)(phyaddr
>> 4);
126 ventoy_address
.buffer
.offset
= (uint16_t)(phyaddr
& 0x0F);
128 if (tmpcount
>= 64) /* max sectors per transmit */
130 ventoy_address
.count
= 64;
137 ventoy_address
.count
= tmpcount
;
141 __asm__
__volatile__ ( REAL_CODE ( "stc\n\t"
144 "sti\n\t" /* BIOS bugs */
146 "xorw %%ax, %%ax\n\t"
149 : "a" ( 0x4200 ), "d" ( VENTOY_BIOS_FAKE_DRIVE
),
150 "S" ( __from_data16 ( &ventoy_address
) ) );
155 buffer
+= (readcount
* 2048);
159 if (start
> g_chain
->real_img_size_in_bytes
)
164 end
= start
+ count
* 2048;
165 for (i
= 0; i
< g_override_chunk_num
; i
++)
167 override_data
= g_override_chunk
[i
].override_data
;
168 override_start
= g_override_chunk
[i
].img_offset
;
169 override_end
= override_start
+ g_override_chunk
[i
].override_size
;
171 if (end
<= override_start
|| start
>= override_end
)
176 if (start
<= override_start
)
178 if (end
<= override_end
)
180 memcpy((char *)databuffer
+ override_start
- start
, override_data
, end
- override_start
);
184 memcpy((char *)databuffer
+ override_start
- start
, override_data
, override_end
- override_start
);
189 if (end
<= override_end
)
191 memcpy((char *)databuffer
, override_data
+ start
- override_start
, end
- start
);
195 memcpy((char *)databuffer
, override_data
+ start
- override_start
, override_end
- start
);
205 int ventoy_vdisk_read(struct san_device
*sandev
, uint64_t lba
, unsigned int count
, unsigned long buffer
)
209 uint64_t lastlba
= 0;
210 uint32_t lbacount
= 0;
211 unsigned long lastbuffer
;
213 ventoy_virt_chunk
*node
;
214 ventoy_sector_flag
*cur_flag
;
215 ventoy_sector_flag
*sector_flag
= g_sector_flag
;
216 struct i386_all_regs
*ix86
;
218 if (INT13_EXTENDED_READ
!= sandev
->int13_command
)
220 DBGC(sandev
, "invalid cmd %u\n", sandev
->int13_command
);
224 ix86
= (struct i386_all_regs
*)sandev
->x86_regptr
;
226 readend
= (lba
+ count
) * 2048;
227 if (readend
<= g_chain
->real_img_size_in_bytes
)
229 ventoy_vdisk_read_real(lba
, count
, buffer
);
230 ix86
->regs
.dl
= sandev
->drive
;
234 if (count
> sizeof(g_sector_flag
))
236 sector_flag
= (ventoy_sector_flag
*)malloc(count
* sizeof(ventoy_sector_flag
));
239 for (curlba
= lba
, cur_flag
= sector_flag
, j
= 0; j
< count
; j
++, curlba
++, cur_flag
++)
242 for (node
= g_virt_chunk
, i
= 0; i
< g_virt_chunk_num
; i
++, node
++)
244 if (curlba
>= node
->mem_sector_start
&& curlba
< node
->mem_sector_end
)
246 memcpy((void *)(buffer
+ j
* 2048),
247 (char *)g_virt_chunk
+ node
->mem_sector_offset
+ (curlba
- node
->mem_sector_start
) * 2048,
252 else if (curlba
>= node
->remap_sector_start
&& curlba
< node
->remap_sector_end
)
254 cur_flag
->remap_lba
= node
->org_sector_start
+ curlba
- node
->remap_sector_start
;
261 for (curlba
= lba
, cur_flag
= sector_flag
, j
= 0; j
< count
; j
++, curlba
++, cur_flag
++)
263 if (cur_flag
->flag
== 2)
267 lastbuffer
= buffer
+ j
* 2048;
268 lastlba
= cur_flag
->remap_lba
;
271 else if (lastlba
+ lbacount
== cur_flag
->remap_lba
)
277 ventoy_vdisk_read_real(lastlba
, lbacount
, lastbuffer
);
278 lastbuffer
= buffer
+ j
* 2048;
279 lastlba
= cur_flag
->remap_lba
;
287 ventoy_vdisk_read_real(lastlba
, lbacount
, lastbuffer
);
290 if (sector_flag
!= g_sector_flag
)
295 ix86
->regs
.dl
= sandev
->drive
;
299 static void ventoy_dump_img_chunk(ventoy_chain_head
*chain
)
302 ventoy_img_chunk
*chunk
;
304 chunk
= (ventoy_img_chunk
*)((char *)chain
+ chain
->img_chunk_offset
);
306 printf("##################### ventoy_dump_img_chunk #######################\n");
308 for (i
= 0; i
< chain
->img_chunk_num
; i
++)
310 printf("%2u: [ %u - %u ] <==> [ %llu - %llu ]\n",
311 i
, chunk
[i
].img_start_sector
, chunk
[i
].img_end_sector
,
312 chunk
[i
].disk_start_sector
, chunk
[i
].disk_end_sector
);
315 ventoy_debug_pause();
318 static void ventoy_dump_override_chunk(ventoy_chain_head
*chain
)
321 ventoy_override_chunk
*chunk
;
323 chunk
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
325 printf("##################### ventoy_dump_override_chunk #######################\n");
327 for (i
= 0; i
< g_override_chunk_num
; i
++)
329 printf("%2u: [ %llu, %u ]\n", i
, chunk
[i
].img_offset
, chunk
[i
].override_size
);
332 ventoy_debug_pause();
335 static void ventoy_dump_virt_chunk(ventoy_chain_head
*chain
)
338 ventoy_virt_chunk
*node
;
340 printf("##################### ventoy_dump_virt_chunk #######################\n");
341 printf("virt_chunk_offset=%u\n", chain
->virt_chunk_offset
);
342 printf("virt_chunk_num=%u\n", chain
->virt_chunk_num
);
344 node
= (ventoy_virt_chunk
*)((char *)chain
+ chain
->virt_chunk_offset
);
345 for (i
= 0; i
< chain
->virt_chunk_num
; i
++, node
++)
347 printf("%2u: mem:[ %u, %u, %u ] remap:[ %u, %u, %u ]\n", i
,
348 node
->mem_sector_start
,
349 node
->mem_sector_end
,
350 node
->mem_sector_offset
,
351 node
->remap_sector_start
,
352 node
->remap_sector_end
,
353 node
->org_sector_start
);
356 ventoy_debug_pause();
359 static void ventoy_dump_chain(ventoy_chain_head
*chain
)
364 uint8_t *vtoy_reserve
;
366 guid
= chain
->os_param
.vtoy_disk_guid
;
367 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
369 chksum
+= *((uint8_t *)(&(chain
->os_param
)) + i
);
372 vtoy_reserve
= (uint8_t *)(chain
->os_param
.vtoy_reserved
);
374 printf("##################### ventoy_dump_chain #######################\n");
376 printf("os_param will be save at %p\n", ventoy_get_runtime_addr());
378 printf("os_param->chksum=0x%x (%s)\n", chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
379 printf("os_param->vtoy_disk_guid=%02x%02x%02x%02x\n", guid
[0], guid
[1], guid
[2], guid
[3]);
380 printf("os_param->vtoy_disk_size=%llu\n", chain
->os_param
.vtoy_disk_size
);
381 printf("os_param->vtoy_disk_part_id=%u\n", chain
->os_param
.vtoy_disk_part_id
);
382 printf("os_param->vtoy_disk_part_type=%u\n", chain
->os_param
.vtoy_disk_part_type
);
383 printf("os_param->vtoy_img_path=<%s>\n", chain
->os_param
.vtoy_img_path
);
384 printf("os_param->vtoy_img_size=<%llu>\n", chain
->os_param
.vtoy_img_size
);
385 printf("os_param->vtoy_reserve[0]=<%u>\n", vtoy_reserve
[0]);
386 printf("os_param->vtoy_reserve[1]=<%u>\n", vtoy_reserve
[1]);
387 printf("os_param->vtoy_img_location_addr=<0x%llx>\n", chain
->os_param
.vtoy_img_location_addr
);
388 printf("os_param->vtoy_img_location_len=<%u>\n", chain
->os_param
.vtoy_img_location_len
);
389 ventoy_debug_pause();
391 printf("chain->disk_drive=0x%x\n", chain
->disk_drive
);
392 printf("chain->drive_map=0x%x\n", chain
->drive_map
);
393 printf("chain->disk_sector_size=%u\n", chain
->disk_sector_size
);
394 printf("chain->real_img_size_in_bytes=%llu\n", chain
->real_img_size_in_bytes
);
395 printf("chain->virt_img_size_in_bytes=%llu\n", chain
->virt_img_size_in_bytes
);
396 printf("chain->boot_catalog=%u\n", chain
->boot_catalog
);
397 printf("chain->img_chunk_offset=%u\n", chain
->img_chunk_offset
);
398 printf("chain->img_chunk_num=%u\n", chain
->img_chunk_num
);
399 printf("chain->override_chunk_offset=%u\n", chain
->override_chunk_offset
);
400 printf("chain->override_chunk_num=%u\n", chain
->override_chunk_num
);
401 printf("chain->virt_chunk_offset=%u\n", chain
->virt_chunk_offset
);
402 printf("chain->virt_chunk_num=%u\n", chain
->virt_chunk_num
);
403 ventoy_debug_pause();
405 ventoy_dump_img_chunk(chain
);
406 ventoy_dump_override_chunk(chain
);
407 ventoy_dump_virt_chunk(chain
);
410 static int ventoy_update_image_location(ventoy_os_param
*param
)
415 userptr_t address
= 0;
416 ventoy_image_location
*location
= NULL
;
417 ventoy_image_disk_region
*region
= NULL
;
418 ventoy_img_chunk
*chunk
= g_chunk
;
420 length
= sizeof(ventoy_image_location
) + (g_img_chunk_num
- 1) * sizeof(ventoy_image_disk_region
);
422 address
= umalloc(length
+ 4096 * 2);
430 address
+= 4096 - (address
% 4096);
434 param
->vtoy_img_location_addr
= user_to_phys(address
, 0);
435 param
->vtoy_img_location_len
= length
;
437 /* update check sum */
438 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
440 chksum
+= *((uint8_t *)param
+ i
);
442 param
->chksum
= (chksum
== 0) ? 0 : (uint8_t)(0x100 - chksum
);
444 location
= (ventoy_image_location
*)(unsigned long)(address
);
445 if (NULL
== location
)
450 memcpy(&location
->guid
, ¶m
->guid
, sizeof(ventoy_guid
));
451 location
->image_sector_size
= 2048;
452 location
->disk_sector_size
= g_chain
->disk_sector_size
;
453 location
->region_count
= g_img_chunk_num
;
455 region
= location
->regions
;
457 for (i
= 0; i
< g_img_chunk_num
; i
++)
459 region
->image_sector_count
= chunk
->img_end_sector
- chunk
->img_start_sector
+ 1;
460 region
->image_start_sector
= chunk
->img_start_sector
;
461 region
->disk_start_sector
= chunk
->disk_start_sector
;
469 int ventoy_boot_vdisk(void *data
)
477 ventoy_address
.bufsize
= offsetof ( typeof ( ventoy_address
), buffer_phys
);
479 if (strstr(g_cmdline_copy
, "debug"))
482 printf("### ventoy chain boot begin... ###\n");
483 ventoy_debug_pause();
486 g_chain
= (ventoy_chain_head
*)g_initrd_addr
;
487 g_chunk
= (ventoy_img_chunk
*)((char *)g_chain
+ g_chain
->img_chunk_offset
);
488 g_img_chunk_num
= g_chain
->img_chunk_num
;
489 g_disk_sector_size
= g_chain
->disk_sector_size
;
490 g_cur_chunk
= g_chunk
;
492 g_override_chunk
= (ventoy_override_chunk
*)((char *)g_chain
+ g_chain
->override_chunk_offset
);
493 g_override_chunk_num
= g_chain
->override_chunk_num
;
495 g_virt_chunk
= (ventoy_virt_chunk
*)((char *)g_chain
+ g_chain
->virt_chunk_offset
);
496 g_virt_chunk_num
= g_chain
->virt_chunk_num
;
500 for (i
= 0; i
< sizeof(ventoy_os_param
); i
++)
502 chksum
+= *((uint8_t *)(&(g_chain
->os_param
)) + i
);
504 printf("os param checksum: 0x%x %s\n", g_chain
->os_param
.chksum
, chksum
? "FAILED" : "SUCCESS");
507 ventoy_update_image_location(&(g_chain
->os_param
));
511 ventoy_dump_chain(g_chain
);
514 drive
= ventoy_int13_hook(g_chain
);
518 printf("### ventoy chain boot before boot image ... ###\n");
519 ventoy_debug_pause();
522 ventoy_int13_boot(drive
, &(g_chain
->os_param
), g_cmdline_copy
);
526 printf("!!!!!!!!!! ventoy boot failed !!!!!!!!!!\n");
527 ventoy_debug_pause();