symbian-qemu-0.9.1-12/qemu-symbian-svp/block-vpc.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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 "qemu-common.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 (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
       
    85 	return 100;
       
    86     return 0;
       
    87 }
       
    88 
       
    89 static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
       
    90 {
       
    91     BDRVVPCState *s = bs->opaque;
       
    92     int fd, i;
       
    93     struct vpc_subheader header;
       
    94 
       
    95     fd = open(filename, O_RDONLY | O_BINARY);
       
    96     if (fd < 0)
       
    97         return -1;
       
    98 
       
    99     bs->read_only = 1; // no write support yet
       
   100 
       
   101     s->fd = fd;
       
   102 
       
   103     if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
       
   104         goto fail;
       
   105 
       
   106     if (strncmp(header.magic, "conectix", 8))
       
   107         goto fail;
       
   108     lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
       
   109 
       
   110     if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
       
   111         goto fail;
       
   112 
       
   113     if (strncmp(header.magic, "cxsparse", 8))
       
   114 	goto fail;
       
   115 
       
   116     bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
       
   117 			be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
       
   118 
       
   119     lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
       
   120 
       
   121     s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
       
   122     s->pagetable = qemu_malloc(s->pagetable_entries * 4);
       
   123     if (!s->pagetable)
       
   124 	goto fail;
       
   125     if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
       
   126 	s->pagetable_entries * 4)
       
   127 	goto fail;
       
   128     for (i = 0; i < s->pagetable_entries; i++)
       
   129 	be32_to_cpus(&s->pagetable[i]);
       
   130 
       
   131     s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
       
   132 #ifdef CACHE
       
   133     s->pageentry_u8 = qemu_malloc(512);
       
   134     if (!s->pageentry_u8)
       
   135 	goto fail;
       
   136     s->pageentry_u32 = s->pageentry_u8;
       
   137     s->pageentry_u16 = s->pageentry_u8;
       
   138     s->last_pagetable = -1;
       
   139 #endif
       
   140 
       
   141     return 0;
       
   142  fail:
       
   143     close(fd);
       
   144     return -1;
       
   145 }
       
   146 
       
   147 static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
       
   148 {
       
   149     BDRVVPCState *s = bs->opaque;
       
   150     uint64_t offset = sector_num * 512;
       
   151     uint64_t bitmap_offset, block_offset;
       
   152     uint32_t pagetable_index, pageentry_index;
       
   153 
       
   154     pagetable_index = offset / s->pageentry_size;
       
   155     pageentry_index = (offset % s->pageentry_size) / 512;
       
   156 
       
   157     if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
       
   158 	return -1; // not allocated
       
   159 
       
   160     bitmap_offset = 512 * s->pagetable[pagetable_index];
       
   161     block_offset = bitmap_offset + 512 + (512 * pageentry_index);
       
   162 
       
   163 //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
       
   164 //	sector_num, pagetable_index, pageentry_index,
       
   165 //	bitmap_offset, block_offset);
       
   166 
       
   167 // disabled by reason
       
   168 #if 0
       
   169 #ifdef CACHE
       
   170     if (bitmap_offset != s->last_bitmap)
       
   171     {
       
   172 	lseek(s->fd, bitmap_offset, SEEK_SET);
       
   173 
       
   174 	s->last_bitmap = bitmap_offset;
       
   175 
       
   176 	// Scary! Bitmap is stored as big endian 32bit entries,
       
   177 	// while we used to look it up byte by byte
       
   178 	read(s->fd, s->pageentry_u8, 512);
       
   179 	for (i = 0; i < 128; i++)
       
   180 	    be32_to_cpus(&s->pageentry_u32[i]);
       
   181     }
       
   182 
       
   183     if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
       
   184 	return -1;
       
   185 #else
       
   186     lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
       
   187 
       
   188     read(s->fd, &bitmap_entry, 1);
       
   189 
       
   190     if ((bitmap_entry >> (pageentry_index % 8)) & 1)
       
   191 	return -1; // not allocated
       
   192 #endif
       
   193 #endif
       
   194     lseek(s->fd, block_offset, SEEK_SET);
       
   195 
       
   196     return 0;
       
   197 }
       
   198 
       
   199 static int vpc_read(BlockDriverState *bs, int64_t sector_num,
       
   200                     uint8_t *buf, int nb_sectors)
       
   201 {
       
   202     BDRVVPCState *s = bs->opaque;
       
   203     int ret;
       
   204 
       
   205     while (nb_sectors > 0) {
       
   206 	if (!seek_to_sector(bs, sector_num))
       
   207 	{
       
   208 	    ret = read(s->fd, buf, 512);
       
   209 	    if (ret != 512)
       
   210 		return -1;
       
   211 	}
       
   212 	else
       
   213             memset(buf, 0, 512);
       
   214         nb_sectors--;
       
   215         sector_num++;
       
   216         buf += 512;
       
   217     }
       
   218     return 0;
       
   219 }
       
   220 
       
   221 static void vpc_close(BlockDriverState *bs)
       
   222 {
       
   223     BDRVVPCState *s = bs->opaque;
       
   224     qemu_free(s->pagetable);
       
   225 #ifdef CACHE
       
   226     qemu_free(s->pageentry_u8);
       
   227 #endif
       
   228     close(s->fd);
       
   229 }
       
   230 
       
   231 BlockDriver bdrv_vpc = {
       
   232     "vpc",
       
   233     sizeof(BDRVVPCState),
       
   234     vpc_probe,
       
   235     vpc_open,
       
   236     vpc_read,
       
   237     NULL,
       
   238     vpc_close,
       
   239 };