Commit 6a0f9e82c5bf457b958fe7918f8ff0080035f35e

Authored by bellard
1 parent c2d551ff

Virtual PC read-only disk image support (Alex Beregszaszi)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1417 c046a42c-6fe2-441c-8c8c-71466251a162
Changelog
... ... @@ -22,6 +22,7 @@ version 0.7.0:
22 22 - Samba 3 support
23 23 - initial Cocoa support (Pierre d'Herbemont)
24 24 - generic FPU emulation code
  25 + - Virtual PC read-only disk image support (Alex Beregszaszi)
25 26  
26 27 version 0.6.1:
27 28  
... ...
Makefile
... ... @@ -25,7 +25,7 @@ else
25 25 endif
26 26 endif
27 27  
28   -qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c
  28 +qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c
29 29 $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
30 30  
31 31 dyngen$(EXESUF): dyngen.c
... ...
Makefile.target
... ... @@ -313,8 +313,8 @@ ifeq ($(ARCH),alpha)
313 313 endif
314 314  
315 315 # must use static linking to avoid leaving stuff in virtual address space
316   -VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
317   -VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o
  316 +VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
  317 +VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o
318 318  
319 319 SOUND_HW = sb16.o
320 320 AUDIODRV = audio.o noaudio.o wavaudio.o
... ...
block-vpc.c 0 → 100644
  1 +/*
  2 + * Block driver for Conectix/Microsoft Virtual PC images
  3 + *
  4 + * Copyright (c) 2005 Alex Beregszaszi
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "vl.h"
  25 +#include "block_int.h"
  26 +
  27 +/**************************************************************/
  28 +
  29 +#define HEADER_SIZE 512
  30 +
  31 +//#define CACHE
  32 +
  33 +// always big-endian
  34 +struct vpc_subheader {
  35 + char magic[8]; // "conectix" / "cxsparse"
  36 + union {
  37 + struct {
  38 + uint32_t unk1[2];
  39 + uint32_t unk2; // always zero?
  40 + uint32_t subheader_offset;
  41 + uint32_t unk3; // some size?
  42 + char creator[4]; // "vpc "
  43 + uint16_t major;
  44 + uint16_t minor;
  45 + char guest[4]; // "Wi2k"
  46 + uint32_t unk4[7];
  47 + uint8_t vnet_id[16]; // virtual network id, purpose unknown
  48 + // next 16 longs are used, but dunno the purpose
  49 + // next 6 longs unknown, following 7 long maybe a serial
  50 + char padding[HEADER_SIZE - 84];
  51 + } main;
  52 + struct {
  53 + uint32_t unk1[2]; // all bits set
  54 + uint32_t unk2; // always zero?
  55 + uint32_t pagetable_offset;
  56 + uint32_t unk3;
  57 + uint32_t pagetable_entries; // 32bit/entry
  58 + uint32_t pageentry_size; // 512*8*512
  59 + uint32_t nb_sectors;
  60 + char padding[HEADER_SIZE - 40];
  61 + } sparse;
  62 + char padding[HEADER_SIZE - 8];
  63 + } type;
  64 +};
  65 +
  66 +typedef struct BDRVVPCState {
  67 + int fd;
  68 +
  69 + int pagetable_entries;
  70 + uint32_t *pagetable;
  71 +
  72 + uint32_t pageentry_size;
  73 +#ifdef CACHE
  74 + uint8_t *pageentry_u8;
  75 + uint32_t *pageentry_u32;
  76 + uint16_t *pageentry_u16;
  77 +
  78 + uint64_t last_bitmap;
  79 +#endif
  80 +} BDRVVPCState;
  81 +
  82 +static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
  83 +{
  84 + if (!strncmp(buf, "conectix", 8))
  85 + return 100;
  86 +
  87 + return 0;
  88 +}
  89 +
  90 +static int vpc_open(BlockDriverState *bs, const char *filename)
  91 +{
  92 + BDRVVPCState *s = bs->opaque;
  93 + int fd, i;
  94 + struct vpc_subheader header;
  95 +
  96 + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
  97 + if (fd < 0) {
  98 + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
  99 + if (fd < 0)
  100 + return -1;
  101 + }
  102 +
  103 + bs->read_only = 1; // no write support yet
  104 +
  105 + s->fd = fd;
  106 +
  107 + if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
  108 + goto fail;
  109 +
  110 + if (strncmp(header.magic, "conectix", 8))
  111 + goto fail;
  112 + lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
  113 +
  114 + if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
  115 + goto fail;
  116 +
  117 + if (strncmp(header.magic, "cxsparse", 8))
  118 + goto fail;
  119 +
  120 + bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
  121 + be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
  122 +
  123 + lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
  124 +
  125 + s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
  126 + s->pagetable = qemu_malloc(s->pagetable_entries * 4);
  127 + if (!s->pagetable)
  128 + goto fail;
  129 + if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
  130 + s->pagetable_entries * 4)
  131 + goto fail;
  132 + for (i = 0; i < s->pagetable_entries; i++)
  133 + be32_to_cpus(&s->pagetable[i]);
  134 +
  135 + s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
  136 +#ifdef CACHE
  137 + s->pageentry_u8 = qemu_malloc(512);
  138 + if (!s->pageentry_u8)
  139 + goto fail;
  140 + s->pageentry_u32 = s->pageentry_u8;
  141 + s->pageentry_u16 = s->pageentry_u8;
  142 + s->last_pagetable = -1;
  143 +#endif
  144 +
  145 + return 0;
  146 + fail:
  147 + close(fd);
  148 + return -1;
  149 +}
  150 +
  151 +static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
  152 +{
  153 + BDRVVPCState *s = bs->opaque;
  154 + uint64_t offset = sector_num * 512;
  155 + uint64_t bitmap_offset, block_offset;
  156 + uint32_t pagetable_index, pageentry_index;
  157 +
  158 + pagetable_index = offset / s->pageentry_size;
  159 + pageentry_index = (offset % s->pageentry_size) / 512;
  160 +
  161 + if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
  162 + return -1; // not allocated
  163 +
  164 + bitmap_offset = 512 * s->pagetable[pagetable_index];
  165 + block_offset = bitmap_offset + 512 + (512 * pageentry_index);
  166 +
  167 +// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
  168 +// sector_num, pagetable_index, pageentry_index,
  169 +// bitmap_offset, block_offset);
  170 +
  171 +// disabled by reason
  172 +#if 0
  173 +#ifdef CACHE
  174 + if (bitmap_offset != s->last_bitmap)
  175 + {
  176 + lseek(s->fd, bitmap_offset, SEEK_SET);
  177 +
  178 + s->last_bitmap = bitmap_offset;
  179 +
  180 + // Scary! Bitmap is stored as big endian 32bit entries,
  181 + // while we used to look it up byte by byte
  182 + read(s->fd, s->pageentry_u8, 512);
  183 + for (i = 0; i < 128; i++)
  184 + be32_to_cpus(&s->pageentry_u32[i]);
  185 + }
  186 +
  187 + if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
  188 + return -1;
  189 +#else
  190 + lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
  191 +
  192 + read(s->fd, &bitmap_entry, 1);
  193 +
  194 + if ((bitmap_entry >> (pageentry_index % 8)) & 1)
  195 + return -1; // not allocated
  196 +#endif
  197 +#endif
  198 + lseek(s->fd, block_offset, SEEK_SET);
  199 +
  200 + return 0;
  201 +}
  202 +
  203 +static int vpc_read(BlockDriverState *bs, int64_t sector_num,
  204 + uint8_t *buf, int nb_sectors)
  205 +{
  206 + BDRVVPCState *s = bs->opaque;
  207 + int ret;
  208 +
  209 + while (nb_sectors > 0) {
  210 + if (!seek_to_sector(bs, sector_num))
  211 + {
  212 + ret = read(s->fd, buf, 512);
  213 + if (ret != 512)
  214 + return -1;
  215 + }
  216 + else
  217 + memset(buf, 0, 512);
  218 + nb_sectors--;
  219 + sector_num++;
  220 + buf += 512;
  221 + }
  222 + return 0;
  223 +}
  224 +
  225 +static void vpc_close(BlockDriverState *bs)
  226 +{
  227 + BDRVVPCState *s = bs->opaque;
  228 + qemu_free(s->pagetable);
  229 +#ifdef CACHE
  230 + qemu_free(s->pageentry_u8);
  231 +#endif
  232 + close(s->fd);
  233 +}
  234 +
  235 +BlockDriver bdrv_vpc = {
  236 + "vpc",
  237 + sizeof(BDRVVPCState),
  238 + vpc_probe,
  239 + vpc_open,
  240 + vpc_read,
  241 + NULL,
  242 + vpc_close,
  243 +};
... ...
... ... @@ -652,4 +652,5 @@ void bdrv_init(void)
652 652 bdrv_register(&bdrv_cloop);
653 653 bdrv_register(&bdrv_dmg);
654 654 bdrv_register(&bdrv_bochs);
  655 + bdrv_register(&bdrv_vpc);
655 656 }
... ...
... ... @@ -383,6 +383,7 @@ extern BlockDriver bdrv_vmdk;
383 383 extern BlockDriver bdrv_cloop;
384 384 extern BlockDriver bdrv_dmg;
385 385 extern BlockDriver bdrv_bochs;
  386 +extern BlockDriver bdrv_vpc;
386 387  
387 388 void bdrv_init(void);
388 389 BlockDriver *bdrv_find_format(const char *format_name);
... ...