Statistics
| Branch: | Revision:

root / block-vpc.c @ d5e49a81

History | View | Annotate | Download (6.4 kB)

1 6a0f9e82 bellard
/*
2 6a0f9e82 bellard
 * Block driver for Conectix/Microsoft Virtual PC images
3 5fafdf24 ths
 *
4 6a0f9e82 bellard
 * Copyright (c) 2005 Alex Beregszaszi
5 5fafdf24 ths
 *
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 faf07963 pbrook
#include "qemu-common.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 3b46e624 ths
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 3b46e624 ths
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 ffe8ab83 ths
    if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
85 6a0f9e82 bellard
        return 100;
86 6a0f9e82 bellard
    return 0;
87 6a0f9e82 bellard
}
88 6a0f9e82 bellard
89 83f64091 bellard
static int vpc_open(BlockDriverState *bs, const char *filename, int flags)
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 83f64091 bellard
    fd = open(filename, O_RDONLY | O_BINARY);
96 83f64091 bellard
    if (fd < 0)
97 83f64091 bellard
        return -1;
98 83f64091 bellard
99 6a0f9e82 bellard
    bs->read_only = 1; // no write support yet
100 3b46e624 ths
101 6a0f9e82 bellard
    s->fd = fd;
102 6a0f9e82 bellard
103 6a0f9e82 bellard
    if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
104 6a0f9e82 bellard
        goto fail;
105 6a0f9e82 bellard
106 6a0f9e82 bellard
    if (strncmp(header.magic, "conectix", 8))
107 6a0f9e82 bellard
        goto fail;
108 6a0f9e82 bellard
    lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
109 6a0f9e82 bellard
110 6a0f9e82 bellard
    if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
111 6a0f9e82 bellard
        goto fail;
112 6a0f9e82 bellard
113 6a0f9e82 bellard
    if (strncmp(header.magic, "cxsparse", 8))
114 6a0f9e82 bellard
        goto fail;
115 6a0f9e82 bellard
116 6a0f9e82 bellard
    bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
117 6a0f9e82 bellard
                        be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
118 6a0f9e82 bellard
119 6a0f9e82 bellard
    lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
120 6a0f9e82 bellard
121 6a0f9e82 bellard
    s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
122 6a0f9e82 bellard
    s->pagetable = qemu_malloc(s->pagetable_entries * 4);
123 6a0f9e82 bellard
    if (!s->pagetable)
124 6a0f9e82 bellard
        goto fail;
125 6a0f9e82 bellard
    if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
126 6a0f9e82 bellard
        s->pagetable_entries * 4)
127 6a0f9e82 bellard
        goto fail;
128 6a0f9e82 bellard
    for (i = 0; i < s->pagetable_entries; i++)
129 6a0f9e82 bellard
        be32_to_cpus(&s->pagetable[i]);
130 6a0f9e82 bellard
131 6a0f9e82 bellard
    s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
132 6a0f9e82 bellard
#ifdef CACHE
133 6a0f9e82 bellard
    s->pageentry_u8 = qemu_malloc(512);
134 6a0f9e82 bellard
    if (!s->pageentry_u8)
135 6a0f9e82 bellard
        goto fail;
136 6a0f9e82 bellard
    s->pageentry_u32 = s->pageentry_u8;
137 6a0f9e82 bellard
    s->pageentry_u16 = s->pageentry_u8;
138 6a0f9e82 bellard
    s->last_pagetable = -1;
139 6a0f9e82 bellard
#endif
140 6a0f9e82 bellard
141 6a0f9e82 bellard
    return 0;
142 6a0f9e82 bellard
 fail:
143 6a0f9e82 bellard
    close(fd);
144 6a0f9e82 bellard
    return -1;
145 6a0f9e82 bellard
}
146 6a0f9e82 bellard
147 6a0f9e82 bellard
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
148 6a0f9e82 bellard
{
149 6a0f9e82 bellard
    BDRVVPCState *s = bs->opaque;
150 6a0f9e82 bellard
    uint64_t offset = sector_num * 512;
151 6a0f9e82 bellard
    uint64_t bitmap_offset, block_offset;
152 6a0f9e82 bellard
    uint32_t pagetable_index, pageentry_index;
153 6a0f9e82 bellard
154 6a0f9e82 bellard
    pagetable_index = offset / s->pageentry_size;
155 6a0f9e82 bellard
    pageentry_index = (offset % s->pageentry_size) / 512;
156 3b46e624 ths
157 6a0f9e82 bellard
    if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
158 6a0f9e82 bellard
        return -1; // not allocated
159 6a0f9e82 bellard
160 6a0f9e82 bellard
    bitmap_offset = 512 * s->pagetable[pagetable_index];
161 6a0f9e82 bellard
    block_offset = bitmap_offset + 512 + (512 * pageentry_index);
162 3b46e624 ths
163 26a76461 bellard
//    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
164 6a0f9e82 bellard
//        sector_num, pagetable_index, pageentry_index,
165 6a0f9e82 bellard
//        bitmap_offset, block_offset);
166 6a0f9e82 bellard
167 6a0f9e82 bellard
// disabled by reason
168 6a0f9e82 bellard
#if 0
169 6a0f9e82 bellard
#ifdef CACHE
170 6a0f9e82 bellard
    if (bitmap_offset != s->last_bitmap)
171 6a0f9e82 bellard
    {
172 6a0f9e82 bellard
        lseek(s->fd, bitmap_offset, SEEK_SET);
173 6a0f9e82 bellard

174 6a0f9e82 bellard
        s->last_bitmap = bitmap_offset;
175 5fafdf24 ths

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

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