Commit 2cfacb629365afba4ec8e2fd80a46f6d083c3a78

Authored by aliguori
1 parent b9fa33a6

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
Showing 1 changed file with 82 additions and 36 deletions
block-vpc.c
... ... @@ -30,41 +30,87 @@
30 30  
31 31 //#define CACHE
32 32  
  33 +enum vhd_type {
  34 + VHD_FIXED = 2,
  35 + VHD_DYNAMIC = 3,
  36 + VHD_DIFFERENCING = 4,
  37 +};
  38 +
33 39 // always big-endian
34 40 struct vhd_footer {
35   - char creator[8]; // "conectix
36   - uint32_t unk1[2];
37   - uint32_t unk2; // always zero?
38   - uint32_t subheader_offset;
39   - uint32_t unk3; // some size?
40   - char creator_app[4]; // "vpc "
41   - uint16_t major;
42   - uint16_t minor;
43   - char guest[4]; // "Wi2k"
44   - uint32_t unk4[7];
45   - uint8_t vnet_id[16]; // virtual network id, purpose unknown
46   - // next 16 longs are used, but dunno the purpose
47   - // next 6 longs unknown, following 7 long maybe a serial
  41 + char creator[8]; // "conectix"
  42 + uint32_t features;
  43 + uint32_t version;
  44 +
  45 + // Offset of next header structure, 0xFFFFFFFF if none
  46 + uint64_t data_offset;
  47 +
  48 + // Seconds since Jan 1, 2000 0:00:00 (UTC)
  49 + uint32_t timestamp;
  50 +
  51 + char creator_app[4]; // "vpc "
  52 + uint16_t major;
  53 + uint16_t minor;
  54 + char creator_os[4]; // "Wi2k"
  55 +
  56 + uint64_t orig_size;
  57 + uint64_t size;
  58 +
  59 + uint16_t cyls;
  60 + uint8_t heads;
  61 + uint8_t secs_per_cyl;
  62 +
  63 + uint32_t type;
  64 +
  65 + // Checksum of the Hard Disk Footer ("one's complement of the sum of all
  66 + // the bytes in the footer without the checksum field")
  67 + uint32_t checksum;
  68 +
  69 + // UUID used to identify a parent hard disk (backing file)
  70 + uint8_t uuid[16];
  71 +
  72 + uint8_t in_saved_state;
48 73 };
49 74  
50 75 struct vhd_dyndisk_header {
51   - char magic[8]; // "cxsparse"
52   - uint32_t unk1[2]; // all bits set
53   - uint32_t unk2; // always zero?
54   - uint32_t pagetable_offset;
55   - uint32_t unk3;
56   - uint32_t pagetable_entries; // 32bit/entry
57   - uint32_t pageentry_size; // 512*8*512
58   - uint32_t nb_sectors;
  76 + char magic[8]; // "cxsparse"
  77 +
  78 + // Offset of next header structure, 0xFFFFFFFF if none
  79 + uint64_t data_offset;
  80 +
  81 + // Offset of the Block Allocation Table (BAT)
  82 + uint64_t table_offset;
  83 +
  84 + uint32_t version;
  85 + uint32_t max_table_entries; // 32bit/entry
  86 +
  87 + // 2 MB by default, must be a power of two
  88 + uint32_t block_size;
  89 +
  90 + uint32_t checksum;
  91 + uint8_t parent_uuid[16];
  92 + uint32_t parent_timestamp;
  93 + uint32_t reserved;
  94 +
  95 + // Backing file name (in UTF-16)
  96 + uint8_t parent_name[512];
  97 +
  98 + struct {
  99 + uint32_t platform;
  100 + uint32_t data_space;
  101 + uint32_t data_length;
  102 + uint32_t reserved;
  103 + uint64_t data_offset;
  104 + } parent_locator[8];
59 105 };
60 106  
61 107 typedef struct BDRVVPCState {
62 108 int fd;
63 109  
64   - int pagetable_entries;
  110 + int max_table_entries;
65 111 uint32_t *pagetable;
66 112  
67   - uint32_t pageentry_size;
  113 + uint32_t block_size;
68 114 #ifdef CACHE
69 115 uint8_t *pageentry_u8;
70 116 uint32_t *pageentry_u32;
... ... @@ -104,7 +150,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
104 150 if (strncmp(footer->creator, "conectix", 8))
105 151 goto fail;
106 152  
107   - lseek(s->fd, be32_to_cpu(footer->subheader_offset), SEEK_SET);
  153 + lseek(s->fd, be64_to_cpu(footer->data_offset), SEEK_SET);
108 154 if (read(fd, buf, HEADER_SIZE) != HEADER_SIZE)
109 155 goto fail;
110 156  
... ... @@ -114,22 +160,22 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
114 160 if (strncmp(dyndisk_header->magic, "cxsparse", 8))
115 161 goto fail;
116 162  
117   - bs->total_sectors = ((uint64_t)be32_to_cpu(dyndisk_header->pagetable_entries) *
118   - be32_to_cpu(dyndisk_header->pageentry_size)) / 512;
  163 + bs->total_sectors = ((uint64_t)be32_to_cpu(dyndisk_header->max_table_entries) *
  164 + be32_to_cpu(dyndisk_header->block_size)) / 512;
119 165  
120   - lseek(s->fd, be32_to_cpu(dyndisk_header->pagetable_offset), SEEK_SET);
  166 + lseek(s->fd, be64_to_cpu(dyndisk_header->table_offset), SEEK_SET);
121 167  
122   - s->pagetable_entries = be32_to_cpu(dyndisk_header->pagetable_entries);
123   - s->pagetable = qemu_malloc(s->pagetable_entries * 4);
  168 + s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
  169 + s->pagetable = qemu_malloc(s->max_table_entries * 4);
124 170 if (!s->pagetable)
125 171 goto fail;
126   - if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
127   - s->pagetable_entries * 4)
  172 + if (read(s->fd, s->pagetable, s->max_table_entries * 4) !=
  173 + s->max_table_entries * 4)
128 174 goto fail;
129   - for (i = 0; i < s->pagetable_entries; i++)
  175 + for (i = 0; i < s->max_table_entries; i++)
130 176 be32_to_cpus(&s->pagetable[i]);
131 177  
132   - s->pageentry_size = be32_to_cpu(dyndisk_header->pageentry_size);
  178 + s->block_size = be32_to_cpu(dyndisk_header->block_size);
133 179 #ifdef CACHE
134 180 s->pageentry_u8 = qemu_malloc(512);
135 181 if (!s->pageentry_u8)
... ... @@ -152,10 +198,10 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
152 198 uint64_t bitmap_offset, block_offset;
153 199 uint32_t pagetable_index, pageentry_index;
154 200  
155   - pagetable_index = offset / s->pageentry_size;
156   - pageentry_index = (offset % s->pageentry_size) / 512;
  201 + pagetable_index = offset / s->block_size;
  202 + pageentry_index = (offset % s->block_size) / 512;
157 203  
158   - if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
  204 + if (pagetable_index > s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
159 205 return -1; // not allocated
160 206  
161 207 bitmap_offset = 512 * s->pagetable[pagetable_index];
... ...