Statistics
| Branch: | Revision:

root / block-vpc.c @ 09b26c5e

History | View | Annotate | Download (6.5 kB)

1 6a0f9e82 bellard
/*
2 6a0f9e82 bellard
 * Block driver for Conectix/Microsoft Virtual PC images
3 6a0f9e82 bellard
 * 
4 6a0f9e82 bellard
 * Copyright (c) 2005 Alex Beregszaszi
5 6a0f9e82 bellard
 * 
6 6a0f9e82 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 6a0f9e82 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 6a0f9e82 bellard
 * in the Software without restriction, including without limitation the rights
9 6a0f9e82 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 6a0f9e82 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 6a0f9e82 bellard
 * furnished to do so, subject to the following conditions:
12 6a0f9e82 bellard
 *
13 6a0f9e82 bellard
 * The above copyright notice and this permission notice shall be included in
14 6a0f9e82 bellard
 * all copies or substantial portions of the Software.
15 6a0f9e82 bellard
 *
16 6a0f9e82 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 6a0f9e82 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 6a0f9e82 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 6a0f9e82 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 6a0f9e82 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 6a0f9e82 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 6a0f9e82 bellard
 * THE SOFTWARE.
23 6a0f9e82 bellard
 */
24 6a0f9e82 bellard
#include "vl.h"
25 6a0f9e82 bellard
#include "block_int.h"
26 6a0f9e82 bellard
27 6a0f9e82 bellard
/**************************************************************/
28 6a0f9e82 bellard
29 6a0f9e82 bellard
#define HEADER_SIZE 512
30 6a0f9e82 bellard
31 6a0f9e82 bellard
//#define CACHE
32 6a0f9e82 bellard
33 6a0f9e82 bellard
// always big-endian
34 6a0f9e82 bellard
struct vpc_subheader {
35 6a0f9e82 bellard
    char magic[8]; // "conectix" / "cxsparse"
36 6a0f9e82 bellard
    union {
37 6a0f9e82 bellard
        struct {
38 6a0f9e82 bellard
            uint32_t unk1[2];
39 6a0f9e82 bellard
            uint32_t unk2; // always zero?
40 6a0f9e82 bellard
            uint32_t subheader_offset;
41 6a0f9e82 bellard
            uint32_t unk3; // some size?
42 6a0f9e82 bellard
            char creator[4]; // "vpc "
43 6a0f9e82 bellard
            uint16_t major;
44 6a0f9e82 bellard
            uint16_t minor;
45 6a0f9e82 bellard
            char guest[4]; // "Wi2k"
46 6a0f9e82 bellard
            uint32_t unk4[7];
47 6a0f9e82 bellard
            uint8_t vnet_id[16]; // virtual network id, purpose unknown
48 6a0f9e82 bellard
            // next 16 longs are used, but dunno the purpose
49 6a0f9e82 bellard
            // next 6 longs unknown, following 7 long maybe a serial
50 6a0f9e82 bellard
            char padding[HEADER_SIZE - 84];
51 6a0f9e82 bellard
        } main;
52 6a0f9e82 bellard
        struct {
53 6a0f9e82 bellard
            uint32_t unk1[2]; // all bits set
54 6a0f9e82 bellard
            uint32_t unk2; // always zero?
55 6a0f9e82 bellard
            uint32_t pagetable_offset;
56 6a0f9e82 bellard
            uint32_t unk3;
57 6a0f9e82 bellard
            uint32_t pagetable_entries; // 32bit/entry
58 6a0f9e82 bellard
            uint32_t pageentry_size; // 512*8*512
59 6a0f9e82 bellard
            uint32_t nb_sectors;
60 6a0f9e82 bellard
            char padding[HEADER_SIZE - 40];
61 6a0f9e82 bellard
        } sparse;
62 6a0f9e82 bellard
        char padding[HEADER_SIZE - 8];
63 6a0f9e82 bellard
    } type;
64 6a0f9e82 bellard
};
65 6a0f9e82 bellard
66 6a0f9e82 bellard
typedef struct BDRVVPCState {
67 6a0f9e82 bellard
    int fd;
68 6a0f9e82 bellard
    
69 6a0f9e82 bellard
    int pagetable_entries;
70 6a0f9e82 bellard
    uint32_t *pagetable;
71 6a0f9e82 bellard
72 6a0f9e82 bellard
    uint32_t pageentry_size;
73 6a0f9e82 bellard
#ifdef CACHE
74 6a0f9e82 bellard
    uint8_t *pageentry_u8;
75 6a0f9e82 bellard
    uint32_t *pageentry_u32;
76 6a0f9e82 bellard
    uint16_t *pageentry_u16;
77 6a0f9e82 bellard
    
78 6a0f9e82 bellard
    uint64_t last_bitmap;
79 6a0f9e82 bellard
#endif
80 6a0f9e82 bellard
} BDRVVPCState;
81 6a0f9e82 bellard
82 6a0f9e82 bellard
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
83 6a0f9e82 bellard
{
84 712e7874 bellard
    if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
85 6a0f9e82 bellard
        return 100;
86 6a0f9e82 bellard
    return 0;
87 6a0f9e82 bellard
}
88 6a0f9e82 bellard
89 6a0f9e82 bellard
static int vpc_open(BlockDriverState *bs, const char *filename)
90 6a0f9e82 bellard
{
91 6a0f9e82 bellard
    BDRVVPCState *s = bs->opaque;
92 6a0f9e82 bellard
    int fd, i;
93 6a0f9e82 bellard
    struct vpc_subheader header;
94 6a0f9e82 bellard
95 6a0f9e82 bellard
    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
96 6a0f9e82 bellard
    if (fd < 0) {
97 6a0f9e82 bellard
        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
98 6a0f9e82 bellard
        if (fd < 0)
99 6a0f9e82 bellard
            return -1;
100 6a0f9e82 bellard
    }
101 6a0f9e82 bellard
    
102 6a0f9e82 bellard
    bs->read_only = 1; // no write support yet
103 6a0f9e82 bellard
    
104 6a0f9e82 bellard
    s->fd = fd;
105 6a0f9e82 bellard
106 6a0f9e82 bellard
    if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
107 6a0f9e82 bellard
        goto fail;
108 6a0f9e82 bellard
109 6a0f9e82 bellard
    if (strncmp(header.magic, "conectix", 8))
110 6a0f9e82 bellard
        goto fail;
111 6a0f9e82 bellard
    lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
112 6a0f9e82 bellard
113 6a0f9e82 bellard
    if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
114 6a0f9e82 bellard
        goto fail;
115 6a0f9e82 bellard
116 6a0f9e82 bellard
    if (strncmp(header.magic, "cxsparse", 8))
117 6a0f9e82 bellard
        goto fail;
118 6a0f9e82 bellard
119 6a0f9e82 bellard
    bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
120 6a0f9e82 bellard
                        be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
121 6a0f9e82 bellard
122 6a0f9e82 bellard
    lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
123 6a0f9e82 bellard
124 6a0f9e82 bellard
    s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
125 6a0f9e82 bellard
    s->pagetable = qemu_malloc(s->pagetable_entries * 4);
126 6a0f9e82 bellard
    if (!s->pagetable)
127 6a0f9e82 bellard
        goto fail;
128 6a0f9e82 bellard
    if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
129 6a0f9e82 bellard
        s->pagetable_entries * 4)
130 6a0f9e82 bellard
        goto fail;
131 6a0f9e82 bellard
    for (i = 0; i < s->pagetable_entries; i++)
132 6a0f9e82 bellard
        be32_to_cpus(&s->pagetable[i]);
133 6a0f9e82 bellard
134 6a0f9e82 bellard
    s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
135 6a0f9e82 bellard
#ifdef CACHE
136 6a0f9e82 bellard
    s->pageentry_u8 = qemu_malloc(512);
137 6a0f9e82 bellard
    if (!s->pageentry_u8)
138 6a0f9e82 bellard
        goto fail;
139 6a0f9e82 bellard
    s->pageentry_u32 = s->pageentry_u8;
140 6a0f9e82 bellard
    s->pageentry_u16 = s->pageentry_u8;
141 6a0f9e82 bellard
    s->last_pagetable = -1;
142 6a0f9e82 bellard
#endif
143 6a0f9e82 bellard
144 6a0f9e82 bellard
    return 0;
145 6a0f9e82 bellard
 fail:
146 6a0f9e82 bellard
    close(fd);
147 6a0f9e82 bellard
    return -1;
148 6a0f9e82 bellard
}
149 6a0f9e82 bellard
150 6a0f9e82 bellard
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
151 6a0f9e82 bellard
{
152 6a0f9e82 bellard
    BDRVVPCState *s = bs->opaque;
153 6a0f9e82 bellard
    uint64_t offset = sector_num * 512;
154 6a0f9e82 bellard
    uint64_t bitmap_offset, block_offset;
155 6a0f9e82 bellard
    uint32_t pagetable_index, pageentry_index;
156 6a0f9e82 bellard
157 6a0f9e82 bellard
    pagetable_index = offset / s->pageentry_size;
158 6a0f9e82 bellard
    pageentry_index = (offset % s->pageentry_size) / 512;
159 6a0f9e82 bellard
    
160 6a0f9e82 bellard
    if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
161 6a0f9e82 bellard
        return -1; // not allocated
162 6a0f9e82 bellard
163 6a0f9e82 bellard
    bitmap_offset = 512 * s->pagetable[pagetable_index];
164 6a0f9e82 bellard
    block_offset = bitmap_offset + 512 + (512 * pageentry_index);
165 6a0f9e82 bellard
    
166 6a0f9e82 bellard
//    printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
167 6a0f9e82 bellard
//        sector_num, pagetable_index, pageentry_index,
168 6a0f9e82 bellard
//        bitmap_offset, block_offset);
169 6a0f9e82 bellard
170 6a0f9e82 bellard
// disabled by reason
171 6a0f9e82 bellard
#if 0
172 6a0f9e82 bellard
#ifdef CACHE
173 6a0f9e82 bellard
    if (bitmap_offset != s->last_bitmap)
174 6a0f9e82 bellard
    {
175 6a0f9e82 bellard
        lseek(s->fd, bitmap_offset, SEEK_SET);
176 6a0f9e82 bellard

177 6a0f9e82 bellard
        s->last_bitmap = bitmap_offset;
178 6a0f9e82 bellard
        
179 6a0f9e82 bellard
        // Scary! Bitmap is stored as big endian 32bit entries,
180 6a0f9e82 bellard
        // while we used to look it up byte by byte
181 6a0f9e82 bellard
        read(s->fd, s->pageentry_u8, 512);
182 6a0f9e82 bellard
        for (i = 0; i < 128; i++)
183 6a0f9e82 bellard
            be32_to_cpus(&s->pageentry_u32[i]);
184 6a0f9e82 bellard
    }
185 6a0f9e82 bellard

186 6a0f9e82 bellard
    if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
187 6a0f9e82 bellard
        return -1;
188 6a0f9e82 bellard
#else
189 6a0f9e82 bellard
    lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
190 6a0f9e82 bellard
        
191 6a0f9e82 bellard
    read(s->fd, &bitmap_entry, 1);
192 6a0f9e82 bellard
193 6a0f9e82 bellard
    if ((bitmap_entry >> (pageentry_index % 8)) & 1)
194 6a0f9e82 bellard
        return -1; // not allocated
195 6a0f9e82 bellard
#endif
196 6a0f9e82 bellard
#endif
197 6a0f9e82 bellard
    lseek(s->fd, block_offset, SEEK_SET);
198 6a0f9e82 bellard
199 6a0f9e82 bellard
    return 0;
200 6a0f9e82 bellard
}
201 6a0f9e82 bellard
202 6a0f9e82 bellard
static int vpc_read(BlockDriverState *bs, int64_t sector_num, 
203 6a0f9e82 bellard
                    uint8_t *buf, int nb_sectors)
204 6a0f9e82 bellard
{
205 6a0f9e82 bellard
    BDRVVPCState *s = bs->opaque;
206 6a0f9e82 bellard
    int ret;
207 6a0f9e82 bellard
208 6a0f9e82 bellard
    while (nb_sectors > 0) {
209 6a0f9e82 bellard
        if (!seek_to_sector(bs, sector_num))
210 6a0f9e82 bellard
        {
211 6a0f9e82 bellard
            ret = read(s->fd, buf, 512);
212 6a0f9e82 bellard
            if (ret != 512)
213 6a0f9e82 bellard
                return -1;
214 6a0f9e82 bellard
        }
215 6a0f9e82 bellard
        else
216 6a0f9e82 bellard
            memset(buf, 0, 512);
217 6a0f9e82 bellard
        nb_sectors--;
218 6a0f9e82 bellard
        sector_num++;
219 6a0f9e82 bellard
        buf += 512;
220 6a0f9e82 bellard
    }
221 6a0f9e82 bellard
    return 0;
222 6a0f9e82 bellard
}
223 6a0f9e82 bellard
224 6a0f9e82 bellard
static void vpc_close(BlockDriverState *bs)
225 6a0f9e82 bellard
{
226 6a0f9e82 bellard
    BDRVVPCState *s = bs->opaque;
227 6a0f9e82 bellard
    qemu_free(s->pagetable);
228 6a0f9e82 bellard
#ifdef CACHE
229 6a0f9e82 bellard
    qemu_free(s->pageentry_u8);
230 6a0f9e82 bellard
#endif
231 6a0f9e82 bellard
    close(s->fd);
232 6a0f9e82 bellard
}
233 6a0f9e82 bellard
234 6a0f9e82 bellard
BlockDriver bdrv_vpc = {
235 6a0f9e82 bellard
    "vpc",
236 6a0f9e82 bellard
    sizeof(BDRVVPCState),
237 6a0f9e82 bellard
    vpc_probe,
238 6a0f9e82 bellard
    vpc_open,
239 6a0f9e82 bellard
    vpc_read,
240 6a0f9e82 bellard
    NULL,
241 6a0f9e82 bellard
    vpc_close,
242 6a0f9e82 bellard
};