add support for linux vdisk(vhd/vdi/raw)

This commit is contained in:
longpanda 2020-09-26 00:04:56 +08:00
parent 3c649b281f
commit d02f184a8d
26 changed files with 1043 additions and 135 deletions

View file

@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ventoy.h>
int g_debug = 0;
int g_hddmode = 0;
char *g_cmdline_copy;
void *g_initrd_addr;
size_t g_initrd_len;
@ -55,6 +56,40 @@ uint64 g_fixup_iso9660_secover_tot_secs = 0;
static struct int13_disk_address __bss16 ( ventoy_address );
#define ventoy_address __use_data16 ( ventoy_address )
static uint64_t ventoy_remap_lba_hdd(uint64_t lba, uint32_t *count)
{
uint32_t i;
uint32_t max_sectors;
ventoy_img_chunk *cur;
if ((NULL == g_cur_chunk) || (lba < g_cur_chunk->img_start_sector) ||
(lba > g_cur_chunk->img_end_sector))
{
g_cur_chunk = NULL;
for (i = 0; i < g_img_chunk_num; i++)
{
cur = g_chunk + i;
if (lba >= cur->img_start_sector && lba <= cur->img_end_sector)
{
g_cur_chunk = cur;
break;
}
}
}
if (g_cur_chunk)
{
max_sectors = g_cur_chunk->img_end_sector - lba + 1;
if (*count > max_sectors)
{
*count = max_sectors;
}
return g_cur_chunk->disk_start_sector + (lba - g_cur_chunk->img_start_sector);
}
return lba;
}
static uint64_t ventoy_remap_lba(uint64_t lba, uint32_t *count)
{
uint32_t i;
@ -92,6 +127,72 @@ static uint64_t ventoy_remap_lba(uint64_t lba, uint32_t *count)
return lba;
}
static int ventoy_vdisk_read_real_hdd(uint64_t lba, unsigned int count, unsigned long buffer)
{
uint32_t left = 0;
uint32_t readcount = 0;
uint32_t tmpcount = 0;
uint16_t status = 0;
uint64_t curlba = 0;
uint64_t maplba = 0;
unsigned long phyaddr;
curlba = lba;
left = count;
#if VTOY_DEBUG
printf("ventoy_vdisk_read_real_hdd: %llu %u\n", lba, count);
#endif
while (left > 0)
{
readcount = left;
maplba = ventoy_remap_lba_hdd(curlba, &readcount);
tmpcount = readcount;
phyaddr = user_to_phys(buffer, 0);
while (tmpcount > 0)
{
/* Use INT 13, 42 to read the data from real disk */
ventoy_address.lba = maplba;
ventoy_address.buffer.segment = (uint16_t)(phyaddr >> 4);
ventoy_address.buffer.offset = (uint16_t)(phyaddr & 0x0F);
if (tmpcount >= 64) /* max sectors per transmit */
{
ventoy_address.count = 64;
tmpcount -= 64;
maplba += 64;
phyaddr += 32768;
}
else
{
ventoy_address.count = tmpcount;
tmpcount = 0;
}
__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
"sti\n\t"
"int $0x13\n\t"
"sti\n\t" /* BIOS bugs */
"jc 1f\n\t"
"xorw %%ax, %%ax\n\t"
"\n1:\n\t" )
: "=a" ( status )
: "a" ( 0x4200 ), "d" ( VENTOY_BIOS_FAKE_DRIVE ),
"S" ( __from_data16 ( &ventoy_address ) ) );
}
curlba += readcount;
left -= readcount;
buffer += (readcount * 512);
}
return 0;
}
static int ventoy_vdisk_read_real(uint64_t lba, unsigned int count, unsigned long buffer)
{
uint32_t i = 0;
@ -297,6 +398,13 @@ int ventoy_vdisk_read(struct san_device *sandev, uint64_t lba, unsigned int coun
ix86 = (struct i386_all_regs *)sandev->x86_regptr;
if (g_hddmode)
{
ventoy_vdisk_read_real_hdd(lba, count, buffer);
ix86->regs.dl = sandev->drive;
return 0;
}
/* Workaround for SSTR PE loader error */
if (g_fixup_iso9660_secover_start)
{
@ -441,9 +549,12 @@ static void ventoy_dump_chain(ventoy_chain_head *chain)
uint32_t i = 0;
uint8_t chksum = 0;
uint8_t *guid;
uint8_t *sig;
uint8_t *vtoy_reserve;
guid = chain->os_param.vtoy_disk_guid;
sig = chain->os_param.vtoy_disk_signature;
for (i = 0; i < sizeof(ventoy_os_param); i++)
{
chksum += *((uint8_t *)(&(chain->os_param)) + i);
@ -457,6 +568,7 @@ static void ventoy_dump_chain(ventoy_chain_head *chain)
printf("os_param->chksum=0x%x (%s)\n", chain->os_param.chksum, chksum ? "FAILED" : "SUCCESS");
printf("os_param->vtoy_disk_guid=%02x%02x%02x%02x\n", guid[0], guid[1], guid[2], guid[3]);
printf("os_param->vtoy_disk_signature=%02x%02x%02x%02x\n", sig[0], sig[1], sig[2], sig[3]);
printf("os_param->vtoy_disk_size=%llu\n", chain->os_param.vtoy_disk_size);
printf("os_param->vtoy_disk_part_id=%u\n", chain->os_param.vtoy_disk_part_id);
printf("os_param->vtoy_disk_part_type=%u\n", chain->os_param.vtoy_disk_part_type);
@ -530,19 +642,33 @@ static int ventoy_update_image_location(ventoy_os_param *param)
}
memcpy(&location->guid, &param->guid, sizeof(ventoy_guid));
location->image_sector_size = 2048;
location->image_sector_size = g_hddmode ? 512 : 2048;
location->disk_sector_size = g_chain->disk_sector_size;
location->region_count = g_img_chunk_num;
region = location->regions;
for (i = 0; i < g_img_chunk_num; i++)
if (g_hddmode)
{
region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
region->image_start_sector = chunk->img_start_sector;
region->disk_start_sector = chunk->disk_start_sector;
region++;
chunk++;
for (i = 0; i < g_img_chunk_num; i++)
{
region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1;
region->image_start_sector = chunk->img_start_sector * 4;
region->disk_start_sector = chunk->disk_start_sector;
region++;
chunk++;
}
}
else
{
for (i = 0; i < g_img_chunk_num; i++)
{
region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1;
region->image_start_sector = chunk->img_start_sector;
region->disk_start_sector = chunk->disk_start_sector;
region++;
chunk++;
}
}
return 0;
@ -553,6 +679,7 @@ int ventoy_boot_vdisk(void *data)
uint8_t chksum = 0;
unsigned int i;
unsigned int drive;
ventoy_img_chunk *cur;
(void)data;
@ -562,8 +689,14 @@ int ventoy_boot_vdisk(void *data)
{
g_debug = 1;
printf("### ventoy chain boot begin... ###\n");
printf("cmdline: <%s>\n", g_cmdline_copy);
ventoy_debug_pause();
}
if (strstr(g_cmdline_copy, "sector512"))
{
g_hddmode = 1;
}
g_chain = (ventoy_chain_head *)g_initrd_addr;
g_chunk = (ventoy_img_chunk *)((char *)g_chain + g_chain->img_chunk_offset);
@ -601,6 +734,16 @@ int ventoy_boot_vdisk(void *data)
ventoy_dump_chain(g_chain);
}
if (g_hddmode)
{
for (i = 0; i < g_img_chunk_num; i++)
{
cur = g_chunk + i;
cur->img_start_sector *= 4;
cur->img_end_sector = cur->img_end_sector * 4 + 3;
}
}
drive = ventoy_int13_hook(g_chain);
if (g_debug)

View file

@ -1051,6 +1051,10 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
/* We simulate a cdrom, so no need to sync hd drive number */
//int13_check_num_drives();
#if VTOY_DEBUG
printf("int13 0x%x 0x%x\n", bios_drive, command); sleep(1);
#endif
if (bios_drive == VENTOY_BIOS_FAKE_DRIVE)
{
ix86->regs.dl = g_sandev->exdrive;
@ -1255,39 +1259,15 @@ static void int13_hook_vector ( void ) {
* @ret rc Return status code
*/
static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
uint16_t status;
int discard_b, discard_c, discard_d;
uint16_t magic;
/* Use INT 13, 02 to read the MBR */
address->segment = 0;
address->offset = 0x7c00;
__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
"pushl %%ebx\n\t"
"popw %%bx\n\t"
"popw %%es\n\t"
"stc\n\t"
"sti\n\t"
"int $0x13\n\t"
"sti\n\t" /* BIOS bugs */
"jc 1f\n\t"
"xorw %%ax, %%ax\n\t"
"\n1:\n\t"
"popw %%es\n\t" )
: "=a" ( status ), "=b" ( discard_b ),
"=c" ( discard_c ), "=d" ( discard_d )
: "a" ( 0x0201 ), "b" ( *address ),
"c" ( 1 ), "d" ( drive ) );
if ( status ) {
DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
drive, status );
return -EIO;
}
address->segment = 0;
address->offset = 0x7c00;
copy_to_real(address->segment, address->offset, g_sandev->boot_catalog_sector, 512);
/* Check magic signature */
get_real ( magic, address->segment,
( address->offset +
offsetof ( struct master_boot_record, magic ) ) );
get_real ( magic, address->segment, (address->offset + offsetof ( struct master_boot_record, magic ) ) );
if ( magic != INT13_MBR_MAGIC ) {
DBG ( "INT13 drive %02x does not contain a valid MBR\n",
drive );
@ -1443,8 +1423,14 @@ unsigned int ventoy_int13_hook (ventoy_chain_head *chain)
/* hook will copy num_drives to dl when int13 08 was called, so must initialize it's value */
get_real(num_drives, BDA_SEG, BDA_NUM_DRIVES);
//natural_drive = num_drives | 0x80;
natural_drive = 0xE0; /* just set a cdrom drive number 224 */
if (g_hddmode)
{
natural_drive = num_drives | 0x80;
}
else
{
natural_drive = 0xE0; /* just set a cdrom drive number 224 */
}
if (chain->disk_drive >= 0x80 && chain->drive_map >= 0x80)
{
@ -1456,8 +1442,8 @@ unsigned int ventoy_int13_hook (ventoy_chain_head *chain)
g_sandev = zalloc(sizeof(struct san_device) + sizeof(struct int13_data));
g_sandev->priv = int13 = (struct int13_data *)(g_sandev + 1);
g_sandev->drive = int13->natural_drive = natural_drive;
g_sandev->is_cdrom = 1;
g_sandev->blksize_shift = 2;
g_sandev->is_cdrom = g_hddmode ? 0 : 1;
g_sandev->blksize_shift = g_hddmode ? 0 : 2;
g_sandev->capacity.blksize = 512;
g_sandev->capacity.blocks = chain->virt_img_size_in_bytes / 512;
g_sandev->exdrive = chain->disk_drive;
@ -1521,9 +1507,20 @@ int ventoy_int13_boot ( unsigned int drive, void *imginfo, const char *cmdline)
struct ibft_table *ibft = NULL;
/* Look for a usable boot sector */
if ( ( ( rc = int13_load_eltorito ( drive, &address ) ) != 0 ) &&
( ( rc = int13_load_mbr ( drive, &address ) ) != 0 ))
if (g_hddmode)
{
if ((rc = int13_load_mbr(drive, &address)) != 0)
{
printf("int13_load_mbr %d\n", rc);
return rc;
}
}
else
{
if ( ( ( rc = int13_load_eltorito ( drive, &address ) ) != 0 ) &&
( ( rc = int13_load_mbr ( drive, &address ) ) != 0 ))
return rc;
}
if (imginfo)
{

View file

@ -4,6 +4,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define VTOY_DEBUG 1
#define grub_uint64_t uint64_t
#define grub_uint32_t uint32_t
#define grub_uint16_t uint16_t
@ -43,7 +45,7 @@ typedef struct ventoy_image_location
{
ventoy_guid guid;
/* image sector size, currently this value is always 2048 */
/* image sector size, 2048/512 */
grub_uint32_t image_sector_size;
/* disk sector size, normally the value is 512 */
@ -86,7 +88,9 @@ typedef struct ventoy_os_param
grub_uint64_t vtoy_reserved[4]; // Internal use by ventoy
grub_uint8_t reserved[31];
grub_uint8_t vtoy_disk_signature[4];
grub_uint8_t reserved[27];
}ventoy_os_param;
typedef struct ventoy_iso9660_override
@ -182,6 +186,7 @@ typedef struct ventoy_sector_flag
#define VENTOY_BOOT_FIXBIN_DRIVE 0xFD
extern int g_debug;
extern int g_hddmode;
extern char *g_cmdline_copy;
extern void *g_initrd_addr;
extern size_t g_initrd_len;