(linenum→info "unix/slp.c:2238")

qemu/0.9.1/block-vpc.c

    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: };
Syntax (Markdown)