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