block-vpc: Adapt header structures to official documentation (Kevin Wolf)
The current definition of the VirtualPC headers is incomplete and partly even wrong. This patch changes the header structs according to the official VHD specification. Signed-off-by: Kevin Wolf <kwolf@suse.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6455 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
b9fa33a6e4
commit
2cfacb6293
110
block-vpc.c
110
block-vpc.c
|
@ -30,41 +30,87 @@
|
||||||
|
|
||||||
//#define CACHE
|
//#define CACHE
|
||||||
|
|
||||||
|
enum vhd_type {
|
||||||
|
VHD_FIXED = 2,
|
||||||
|
VHD_DYNAMIC = 3,
|
||||||
|
VHD_DIFFERENCING = 4,
|
||||||
|
};
|
||||||
|
|
||||||
// always big-endian
|
// always big-endian
|
||||||
struct vhd_footer {
|
struct vhd_footer {
|
||||||
char creator[8]; // "conectix
|
char creator[8]; // "conectix"
|
||||||
uint32_t unk1[2];
|
uint32_t features;
|
||||||
uint32_t unk2; // always zero?
|
uint32_t version;
|
||||||
uint32_t subheader_offset;
|
|
||||||
uint32_t unk3; // some size?
|
// Offset of next header structure, 0xFFFFFFFF if none
|
||||||
|
uint64_t data_offset;
|
||||||
|
|
||||||
|
// Seconds since Jan 1, 2000 0:00:00 (UTC)
|
||||||
|
uint32_t timestamp;
|
||||||
|
|
||||||
char creator_app[4]; // "vpc "
|
char creator_app[4]; // "vpc "
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
char guest[4]; // "Wi2k"
|
char creator_os[4]; // "Wi2k"
|
||||||
uint32_t unk4[7];
|
|
||||||
uint8_t vnet_id[16]; // virtual network id, purpose unknown
|
uint64_t orig_size;
|
||||||
// next 16 longs are used, but dunno the purpose
|
uint64_t size;
|
||||||
// next 6 longs unknown, following 7 long maybe a serial
|
|
||||||
|
uint16_t cyls;
|
||||||
|
uint8_t heads;
|
||||||
|
uint8_t secs_per_cyl;
|
||||||
|
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
|
// Checksum of the Hard Disk Footer ("one's complement of the sum of all
|
||||||
|
// the bytes in the footer without the checksum field")
|
||||||
|
uint32_t checksum;
|
||||||
|
|
||||||
|
// UUID used to identify a parent hard disk (backing file)
|
||||||
|
uint8_t uuid[16];
|
||||||
|
|
||||||
|
uint8_t in_saved_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vhd_dyndisk_header {
|
struct vhd_dyndisk_header {
|
||||||
char magic[8]; // "cxsparse"
|
char magic[8]; // "cxsparse"
|
||||||
uint32_t unk1[2]; // all bits set
|
|
||||||
uint32_t unk2; // always zero?
|
// Offset of next header structure, 0xFFFFFFFF if none
|
||||||
uint32_t pagetable_offset;
|
uint64_t data_offset;
|
||||||
uint32_t unk3;
|
|
||||||
uint32_t pagetable_entries; // 32bit/entry
|
// Offset of the Block Allocation Table (BAT)
|
||||||
uint32_t pageentry_size; // 512*8*512
|
uint64_t table_offset;
|
||||||
uint32_t nb_sectors;
|
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t max_table_entries; // 32bit/entry
|
||||||
|
|
||||||
|
// 2 MB by default, must be a power of two
|
||||||
|
uint32_t block_size;
|
||||||
|
|
||||||
|
uint32_t checksum;
|
||||||
|
uint8_t parent_uuid[16];
|
||||||
|
uint32_t parent_timestamp;
|
||||||
|
uint32_t reserved;
|
||||||
|
|
||||||
|
// Backing file name (in UTF-16)
|
||||||
|
uint8_t parent_name[512];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t platform;
|
||||||
|
uint32_t data_space;
|
||||||
|
uint32_t data_length;
|
||||||
|
uint32_t reserved;
|
||||||
|
uint64_t data_offset;
|
||||||
|
} parent_locator[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct BDRVVPCState {
|
typedef struct BDRVVPCState {
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
int pagetable_entries;
|
int max_table_entries;
|
||||||
uint32_t *pagetable;
|
uint32_t *pagetable;
|
||||||
|
|
||||||
uint32_t pageentry_size;
|
uint32_t block_size;
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
uint8_t *pageentry_u8;
|
uint8_t *pageentry_u8;
|
||||||
uint32_t *pageentry_u32;
|
uint32_t *pageentry_u32;
|
||||||
|
@ -104,7 +150,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
if (strncmp(footer->creator, "conectix", 8))
|
if (strncmp(footer->creator, "conectix", 8))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
lseek(s->fd, be32_to_cpu(footer->subheader_offset), SEEK_SET);
|
lseek(s->fd, be64_to_cpu(footer->data_offset), SEEK_SET);
|
||||||
if (read(fd, buf, HEADER_SIZE) != HEADER_SIZE)
|
if (read(fd, buf, HEADER_SIZE) != HEADER_SIZE)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -114,22 +160,22 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
if (strncmp(dyndisk_header->magic, "cxsparse", 8))
|
if (strncmp(dyndisk_header->magic, "cxsparse", 8))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
bs->total_sectors = ((uint64_t)be32_to_cpu(dyndisk_header->pagetable_entries) *
|
bs->total_sectors = ((uint64_t)be32_to_cpu(dyndisk_header->max_table_entries) *
|
||||||
be32_to_cpu(dyndisk_header->pageentry_size)) / 512;
|
be32_to_cpu(dyndisk_header->block_size)) / 512;
|
||||||
|
|
||||||
lseek(s->fd, be32_to_cpu(dyndisk_header->pagetable_offset), SEEK_SET);
|
lseek(s->fd, be64_to_cpu(dyndisk_header->table_offset), SEEK_SET);
|
||||||
|
|
||||||
s->pagetable_entries = be32_to_cpu(dyndisk_header->pagetable_entries);
|
s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
|
||||||
s->pagetable = qemu_malloc(s->pagetable_entries * 4);
|
s->pagetable = qemu_malloc(s->max_table_entries * 4);
|
||||||
if (!s->pagetable)
|
if (!s->pagetable)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
|
if (read(s->fd, s->pagetable, s->max_table_entries * 4) !=
|
||||||
s->pagetable_entries * 4)
|
s->max_table_entries * 4)
|
||||||
goto fail;
|
goto fail;
|
||||||
for (i = 0; i < s->pagetable_entries; i++)
|
for (i = 0; i < s->max_table_entries; i++)
|
||||||
be32_to_cpus(&s->pagetable[i]);
|
be32_to_cpus(&s->pagetable[i]);
|
||||||
|
|
||||||
s->pageentry_size = be32_to_cpu(dyndisk_header->pageentry_size);
|
s->block_size = be32_to_cpu(dyndisk_header->block_size);
|
||||||
#ifdef CACHE
|
#ifdef CACHE
|
||||||
s->pageentry_u8 = qemu_malloc(512);
|
s->pageentry_u8 = qemu_malloc(512);
|
||||||
if (!s->pageentry_u8)
|
if (!s->pageentry_u8)
|
||||||
|
@ -152,10 +198,10 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||||
uint64_t bitmap_offset, block_offset;
|
uint64_t bitmap_offset, block_offset;
|
||||||
uint32_t pagetable_index, pageentry_index;
|
uint32_t pagetable_index, pageentry_index;
|
||||||
|
|
||||||
pagetable_index = offset / s->pageentry_size;
|
pagetable_index = offset / s->block_size;
|
||||||
pageentry_index = (offset % s->pageentry_size) / 512;
|
pageentry_index = (offset % s->block_size) / 512;
|
||||||
|
|
||||||
if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
|
if (pagetable_index > s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
|
||||||
return -1; // not allocated
|
return -1; // not allocated
|
||||||
|
|
||||||
bitmap_offset = 512 * s->pagetable[pagetable_index];
|
bitmap_offset = 512 * s->pagetable[pagetable_index];
|
||||||
|
|
Loading…
Reference in a new issue