symbian-qemu-0.9.1-12/qemu-symbian-svp/block-bochs.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Block driver for the various disk image formats used by Bochs
       
     3  * Currently only for "growing" type in read-only mode
       
     4  *
       
     5  * Copyright (c) 2005 Alex Beregszaszi
       
     6  *
       
     7  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     8  * of this software and associated documentation files (the "Software"), to deal
       
     9  * in the Software without restriction, including without limitation the rights
       
    10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    11  * copies of the Software, and to permit persons to whom the Software is
       
    12  * furnished to do so, subject to the following conditions:
       
    13  *
       
    14  * The above copyright notice and this permission notice shall be included in
       
    15  * all copies or substantial portions of the Software.
       
    16  *
       
    17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    23  * THE SOFTWARE.
       
    24  */
       
    25 #include "qemu-common.h"
       
    26 #include "block_int.h"
       
    27 
       
    28 /**************************************************************/
       
    29 
       
    30 #define HEADER_MAGIC "Bochs Virtual HD Image"
       
    31 #define HEADER_VERSION 0x00020000
       
    32 #define HEADER_V1 0x00010000
       
    33 #define HEADER_SIZE 512
       
    34 
       
    35 #define REDOLOG_TYPE "Redolog"
       
    36 #define GROWING_TYPE "Growing"
       
    37 
       
    38 // not allocated: 0xffffffff
       
    39 
       
    40 // always little-endian
       
    41 struct bochs_header_v1 {
       
    42     char magic[32]; // "Bochs Virtual HD Image"
       
    43     char type[16]; // "Redolog"
       
    44     char subtype[16]; // "Undoable" / "Volatile" / "Growing"
       
    45     uint32_t version;
       
    46     uint32_t header; // size of header
       
    47 
       
    48     union {
       
    49 	struct {
       
    50 	    uint32_t catalog; // num of entries
       
    51 	    uint32_t bitmap; // bitmap size
       
    52 	    uint32_t extent; // extent size
       
    53 	    uint64_t disk; // disk size
       
    54 	    char padding[HEADER_SIZE - 64 - 8 - 20];
       
    55 	} redolog;
       
    56 	char padding[HEADER_SIZE - 64 - 8];
       
    57     } extra;
       
    58 };
       
    59 
       
    60 // always little-endian
       
    61 struct bochs_header {
       
    62     char magic[32]; // "Bochs Virtual HD Image"
       
    63     char type[16]; // "Redolog"
       
    64     char subtype[16]; // "Undoable" / "Volatile" / "Growing"
       
    65     uint32_t version;
       
    66     uint32_t header; // size of header
       
    67 
       
    68     union {
       
    69 	struct {
       
    70 	    uint32_t catalog; // num of entries
       
    71 	    uint32_t bitmap; // bitmap size
       
    72 	    uint32_t extent; // extent size
       
    73 	    uint32_t reserved; // for ???
       
    74 	    uint64_t disk; // disk size
       
    75 	    char padding[HEADER_SIZE - 64 - 8 - 24];
       
    76 	} redolog;
       
    77 	char padding[HEADER_SIZE - 64 - 8];
       
    78     } extra;
       
    79 };
       
    80 
       
    81 typedef struct BDRVBochsState {
       
    82     int fd;
       
    83 
       
    84     uint32_t *catalog_bitmap;
       
    85     int catalog_size;
       
    86 
       
    87     int data_offset;
       
    88 
       
    89     int bitmap_blocks;
       
    90     int extent_blocks;
       
    91     int extent_size;
       
    92 } BDRVBochsState;
       
    93 
       
    94 static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
       
    95 {
       
    96     const struct bochs_header *bochs = (const void *)buf;
       
    97 
       
    98     if (buf_size < HEADER_SIZE)
       
    99 	return 0;
       
   100 
       
   101     if (!strcmp(bochs->magic, HEADER_MAGIC) &&
       
   102 	!strcmp(bochs->type, REDOLOG_TYPE) &&
       
   103 	!strcmp(bochs->subtype, GROWING_TYPE) &&
       
   104 	((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
       
   105 	(le32_to_cpu(bochs->version) == HEADER_V1)))
       
   106 	return 100;
       
   107 
       
   108     return 0;
       
   109 }
       
   110 
       
   111 static int bochs_open(BlockDriverState *bs, const char *filename, int flags)
       
   112 {
       
   113     BDRVBochsState *s = bs->opaque;
       
   114     int fd, i;
       
   115     struct bochs_header bochs;
       
   116     struct bochs_header_v1 header_v1;
       
   117 
       
   118     fd = open(filename, O_RDWR | O_BINARY);
       
   119     if (fd < 0) {
       
   120         fd = open(filename, O_RDONLY | O_BINARY);
       
   121         if (fd < 0)
       
   122             return -1;
       
   123     }
       
   124 
       
   125     bs->read_only = 1; // no write support yet
       
   126 
       
   127     s->fd = fd;
       
   128 
       
   129     if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
       
   130         goto fail;
       
   131     }
       
   132 
       
   133     if (strcmp(bochs.magic, HEADER_MAGIC) ||
       
   134         strcmp(bochs.type, REDOLOG_TYPE) ||
       
   135         strcmp(bochs.subtype, GROWING_TYPE) ||
       
   136 	((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
       
   137 	(le32_to_cpu(bochs.version) != HEADER_V1))) {
       
   138         goto fail;
       
   139     }
       
   140 
       
   141     if (le32_to_cpu(bochs.version) == HEADER_V1) {
       
   142       memcpy(&header_v1, &bochs, sizeof(bochs));
       
   143       bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512;
       
   144     } else {
       
   145       bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
       
   146     }
       
   147 
       
   148     lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
       
   149 
       
   150     s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
       
   151     s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
       
   152     if (!s->catalog_bitmap)
       
   153 	goto fail;
       
   154     if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
       
   155 	s->catalog_size * 4)
       
   156 	goto fail;
       
   157     for (i = 0; i < s->catalog_size; i++)
       
   158 	le32_to_cpus(&s->catalog_bitmap[i]);
       
   159 
       
   160     s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
       
   161 
       
   162     s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
       
   163     s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
       
   164 
       
   165     s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
       
   166 
       
   167     return 0;
       
   168  fail:
       
   169     close(fd);
       
   170     return -1;
       
   171 }
       
   172 
       
   173 static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
       
   174 {
       
   175     BDRVBochsState *s = bs->opaque;
       
   176     int64_t offset = sector_num * 512;
       
   177     int64_t extent_index, extent_offset, bitmap_offset, block_offset;
       
   178     char bitmap_entry;
       
   179 
       
   180     // seek to sector
       
   181     extent_index = offset / s->extent_size;
       
   182     extent_offset = (offset % s->extent_size) / 512;
       
   183 
       
   184     if (s->catalog_bitmap[extent_index] == 0xffffffff)
       
   185     {
       
   186 //	fprintf(stderr, "page not allocated [%x - %x:%x]\n",
       
   187 //	    sector_num, extent_index, extent_offset);
       
   188 	return -1; // not allocated
       
   189     }
       
   190 
       
   191     bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
       
   192 	(s->extent_blocks + s->bitmap_blocks));
       
   193     block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
       
   194 
       
   195 //    fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
       
   196 //	sector_num, extent_index, extent_offset,
       
   197 //	le32_to_cpu(s->catalog_bitmap[extent_index]),
       
   198 //	bitmap_offset, block_offset);
       
   199 
       
   200     // read in bitmap for current extent
       
   201     lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
       
   202 
       
   203     read(s->fd, &bitmap_entry, 1);
       
   204 
       
   205     if (!((bitmap_entry >> (extent_offset % 8)) & 1))
       
   206     {
       
   207 //	fprintf(stderr, "sector (%x) in bitmap not allocated\n",
       
   208 //	    sector_num);
       
   209 	return -1; // not allocated
       
   210     }
       
   211 
       
   212     lseek(s->fd, block_offset, SEEK_SET);
       
   213 
       
   214     return 0;
       
   215 }
       
   216 
       
   217 static int bochs_read(BlockDriverState *bs, int64_t sector_num,
       
   218                     uint8_t *buf, int nb_sectors)
       
   219 {
       
   220     BDRVBochsState *s = bs->opaque;
       
   221     int ret;
       
   222 
       
   223     while (nb_sectors > 0) {
       
   224 	if (!seek_to_sector(bs, sector_num))
       
   225 	{
       
   226 	    ret = read(s->fd, buf, 512);
       
   227 	    if (ret != 512)
       
   228 		return -1;
       
   229 	}
       
   230 	else
       
   231             memset(buf, 0, 512);
       
   232         nb_sectors--;
       
   233         sector_num++;
       
   234         buf += 512;
       
   235     }
       
   236     return 0;
       
   237 }
       
   238 
       
   239 static void bochs_close(BlockDriverState *bs)
       
   240 {
       
   241     BDRVBochsState *s = bs->opaque;
       
   242     qemu_free(s->catalog_bitmap);
       
   243     close(s->fd);
       
   244 }
       
   245 
       
   246 BlockDriver bdrv_bochs = {
       
   247     "bochs",
       
   248     sizeof(BDRVBochsState),
       
   249     bochs_probe,
       
   250     bochs_open,
       
   251     bochs_read,
       
   252     NULL,
       
   253     bochs_close,
       
   254 };