Statistics
| Branch: | Revision:

root / tests / hd-geo-test.c @ 5e954943

History | View | Annotate | Download (10.5 kB)

1
/*
2
 * Hard disk geometry test cases.
3
 *
4
 * Copyright (c) 2012 Red Hat Inc.
5
 *
6
 * Authors:
7
 *  Markus Armbruster <armbru@redhat.com>,
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10
 * See the COPYING file in the top-level directory.
11
 */
12

    
13
/*
14
 * Covers only IDE and tests only CMOS contents.  Better than nothing.
15
 * Improvements welcome.
16
 */
17

    
18
#include <glib.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#include <unistd.h>
22
#include "qemu-common.h"
23
#include "libqtest.h"
24

    
25
static const char test_image[] = "/tmp/qtest.XXXXXX";
26

    
27
static char *create_test_img(int secs)
28
{
29
    char *template = strdup("/tmp/qtest.XXXXXX");
30
    int fd, ret;
31

    
32
    fd = mkstemp(template);
33
    g_assert(fd >= 0);
34
    ret = ftruncate(fd, (off_t)secs * 512);
35
    g_assert(ret == 0);
36
    close(fd);
37
    return template;
38
}
39

    
40
typedef struct {
41
    int cyls, heads, secs, trans;
42
} CHST;
43

    
44
typedef enum {
45
    mbr_blank, mbr_lba, mbr_chs,
46
    mbr_last
47
} MBRcontents;
48

    
49
typedef enum {
50
    /* order is relevant */
51
    backend_small, backend_large, backend_empty,
52
    backend_last
53
} Backend;
54

    
55
static const int img_secs[backend_last] = {
56
    [backend_small] = 61440,
57
    [backend_large] = 8388608,
58
    [backend_empty] = -1,
59
};
60

    
61
static const CHST hd_chst[backend_last][mbr_last] = {
62
    [backend_small] = {
63
        [mbr_blank] = { 60, 16, 63, 0 },
64
        [mbr_lba]   = { 60, 16, 63, 2 },
65
        [mbr_chs]   = { 60, 16, 63, 0 }
66
    },
67
    [backend_large] = {
68
        [mbr_blank] = { 8322, 16, 63, 1 },
69
        [mbr_lba]   = { 8322, 16, 63, 1 },
70
        [mbr_chs]   = { 8322, 16, 63, 0 }
71
    },
72
};
73

    
74
static const char *img_file_name[backend_last];
75

    
76
static const CHST *cur_ide[4];
77

    
78
static bool is_hd(const CHST *expected_chst)
79
{
80
    return expected_chst && expected_chst->cyls;
81
}
82

    
83
static void test_cmos_byte(int reg, int expected)
84
{
85
    enum { cmos_base = 0x70 };
86
    int actual;
87

    
88
    outb(cmos_base + 0, reg);
89
    actual = inb(cmos_base + 1);
90
    g_assert(actual == expected);
91
}
92

    
93
static void test_cmos_bytes(int reg0, int n, uint8_t expected[])
94
{
95
    int i;
96

    
97
    for (i = 0; i < 9; i++) {
98
        test_cmos_byte(reg0 + i, expected[i]);
99
    }
100
}
101

    
102
static void test_cmos_disk_data(void)
103
{
104
    test_cmos_byte(0x12,
105
                   (is_hd(cur_ide[0]) ? 0xf0 : 0) |
106
                   (is_hd(cur_ide[1]) ? 0x0f : 0));
107
}
108

    
109
static void test_cmos_drive_cyl(int reg0, const CHST *expected_chst)
110
{
111
    if (is_hd(expected_chst)) {
112
        int c = expected_chst->cyls;
113
        int h = expected_chst->heads;
114
        int s = expected_chst->secs;
115
        uint8_t expected_bytes[9] = {
116
            c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
117
            c & 0xff, c >> 8, s
118
        };
119
        test_cmos_bytes(reg0, 9, expected_bytes);
120
    } else {
121
        int i;
122

    
123
        for (i = 0; i < 9; i++) {
124
            test_cmos_byte(reg0 + i, 0);
125
        }
126
    }
127
}
128

    
129
static void test_cmos_drive1(void)
130
{
131
    test_cmos_byte(0x19, is_hd(cur_ide[0]) ? 47 : 0);
132
    test_cmos_drive_cyl(0x1b, cur_ide[0]);
133
}
134

    
135
static void test_cmos_drive2(void)
136
{
137
    test_cmos_byte(0x1a, is_hd(cur_ide[1]) ? 47 : 0);
138
    test_cmos_drive_cyl(0x24, cur_ide[1]);
139
}
140

    
141
static void test_cmos_disktransflag(void)
142
{
143
    int val, i;
144

    
145
    val = 0;
146
    for (i = 0; i < ARRAY_SIZE(cur_ide); i++) {
147
        if (is_hd(cur_ide[i])) {
148
            val |= cur_ide[i]->trans << (2 * i);
149
        }
150
    }
151
    test_cmos_byte(0x39, val);
152
}
153

    
154
static void test_cmos(void)
155
{
156
    test_cmos_disk_data();
157
    test_cmos_drive1();
158
    test_cmos_drive2();
159
    test_cmos_disktransflag();
160
}
161

    
162
static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
163
{
164
    g_assert(argc + 1 < argv_sz);
165
    argv[argc++] = arg;
166
    argv[argc] = NULL;
167
    return argc;
168
}
169

    
170
static int setup_common(char *argv[], int argv_sz)
171
{
172
    memset(cur_ide, 0, sizeof(cur_ide));
173
    return append_arg(0, argv, argv_sz,
174
                      g_strdup("-nodefaults"));
175
}
176

    
177
static void setup_mbr(int img_idx, MBRcontents mbr)
178
{
179
    static const uint8_t part_lba[16] = {
180
        /* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
181
        0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
182
    };
183
    static const uint8_t part_chs[16] = {
184
        /* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
185
        0x80, 1, 1, 0, 6,  15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
186
    };
187
    uint8_t buf[512];
188
    int fd, ret;
189

    
190
    memset(buf, 0, sizeof(buf));
191

    
192
    if (mbr != mbr_blank) {
193
        buf[0x1fe] = 0x55;
194
        buf[0x1ff] = 0xAA;
195
        memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16);
196
    }
197

    
198
    fd = open(img_file_name[img_idx], O_WRONLY);
199
    g_assert(fd >= 0);
200
    ret = write(fd, buf, sizeof(buf));
201
    g_assert(ret == sizeof(buf));
202
    close(fd);
203
}
204

    
205
static int setup_ide(int argc, char *argv[], int argv_sz,
206
                     int ide_idx, const char *dev, int img_idx,
207
                     MBRcontents mbr, const char *opts)
208
{
209
    char *s1, *s2, *s3;
210

    
211
    s1 = g_strdup_printf("-drive id=drive%d,if=%s",
212
                         ide_idx, dev ? "none" : "ide");
213
    s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
214

    
215
    if (img_secs[img_idx] >= 0) {
216
        setup_mbr(img_idx, mbr);
217
        s3 = g_strdup_printf(",file=%s", img_file_name[img_idx]);
218
    } else {
219
        s3 = g_strdup(",media=cdrom");
220
    }
221
    argc = append_arg(argc, argv, argv_sz,
222
                      g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
223
    g_free(s1);
224
    g_free(s2);
225
    g_free(s3);
226

    
227
    if (dev) {
228
        argc = append_arg(argc, argv, argv_sz,
229
                          g_strdup_printf("-device %s,drive=drive%d,"
230
                                          "bus=ide.%d,unit=%d",
231
                                          dev, ide_idx,
232
                                          ide_idx / 2, ide_idx % 2));
233
    }
234
    return argc;
235
}
236

    
237
/*
238
 * Test case: no IDE devices
239
 */
240
static void test_ide_none(void)
241
{
242
    char *argv[256];
243

    
244
    setup_common(argv, ARRAY_SIZE(argv));
245
    qtest_start(g_strjoinv(" ", argv));
246
    test_cmos();
247
    qtest_end();
248
}
249

    
250
static void test_ide_mbr(bool use_device, MBRcontents mbr)
251
{
252
    char *argv[256];
253
    int argc;
254
    Backend i;
255
    const char *dev;
256

    
257
    argc = setup_common(argv, ARRAY_SIZE(argv));
258
    for (i = 0; i < backend_last; i++) {
259
        cur_ide[i] = &hd_chst[i][mbr];
260
        dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
261
        argc = setup_ide(argc, argv, ARRAY_SIZE(argv), i, dev, i, mbr, "");
262
    }
263
    qtest_start(g_strjoinv(" ", argv));
264
    test_cmos();
265
    qtest_end();
266
}
267

    
268
/*
269
 * Test case: IDE devices (if=ide) with blank MBRs
270
 */
271
static void test_ide_drive_mbr_blank(void)
272
{
273
    test_ide_mbr(false, mbr_blank);
274
}
275

    
276
/*
277
 * Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
278
 */
279
static void test_ide_drive_mbr_lba(void)
280
{
281
    test_ide_mbr(false, mbr_lba);
282
}
283

    
284
/*
285
 * Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
286
 */
287
static void test_ide_drive_mbr_chs(void)
288
{
289
    test_ide_mbr(false, mbr_chs);
290
}
291

    
292
/*
293
 * Test case: IDE devices (if=none) with blank MBRs
294
 */
295
static void test_ide_device_mbr_blank(void)
296
{
297
    test_ide_mbr(true, mbr_blank);
298
}
299

    
300
/*
301
 * Test case: IDE devices (if=none) with MBRs indicating LBA is in use
302
 */
303
static void test_ide_device_mbr_lba(void)
304
{
305
    test_ide_mbr(true, mbr_lba);
306
}
307

    
308
/*
309
 * Test case: IDE devices (if=none) with MBRs indicating CHS is in use
310
 */
311
static void test_ide_device_mbr_chs(void)
312
{
313
    test_ide_mbr(true, mbr_chs);
314
}
315

    
316
static void test_ide_drive_user(const char *dev, bool trans)
317
{
318
    char *argv[256], *opts;
319
    int argc;
320
    int secs = img_secs[backend_small];
321
    const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
322

    
323
    argc = setup_common(argv, ARRAY_SIZE(argv));
324
    opts = g_strdup_printf("%s,%s%scyls=%d,heads=%d,secs=%d",
325
                           dev ?: "",
326
                           trans && dev ? "bios-chs-" : "",
327
                           trans ? "trans=lba," : "",
328
                           expected_chst.cyls, expected_chst.heads,
329
                           expected_chst.secs);
330
    cur_ide[0] = &expected_chst;
331
    argc = setup_ide(argc, argv, ARRAY_SIZE(argv),
332
                     0, dev ? opts : NULL, backend_small, mbr_chs,
333
                     dev ? "" : opts);
334
    g_free(opts);
335
    qtest_start(g_strjoinv(" ", argv));
336
    test_cmos();
337
    qtest_end();
338
}
339

    
340
/*
341
 * Test case: IDE device (if=ide) with explicit CHS
342
 */
343
static void test_ide_drive_user_chs(void)
344
{
345
    test_ide_drive_user(NULL, false);
346
}
347

    
348
/*
349
 * Test case: IDE device (if=ide) with explicit CHS and translation
350
 */
351
static void test_ide_drive_user_chst(void)
352
{
353
    test_ide_drive_user(NULL, true);
354
}
355

    
356
/*
357
 * Test case: IDE device (if=none) with explicit CHS
358
 */
359
static void test_ide_device_user_chs(void)
360
{
361
    test_ide_drive_user("ide-hd", false);
362
}
363

    
364
/*
365
 * Test case: IDE device (if=none) with explicit CHS and translation
366
 */
367
static void test_ide_device_user_chst(void)
368
{
369
    test_ide_drive_user("ide-hd", true);
370
}
371

    
372
/*
373
 * Test case: IDE devices (if=ide), but use index=0 for CD-ROM
374
 */
375
static void test_ide_drive_cd_0(void)
376
{
377
    char *argv[256];
378
    int argc, ide_idx;
379
    Backend i;
380

    
381
    argc = setup_common(argv, ARRAY_SIZE(argv));
382
    for (i = 0; i <= backend_empty; i++) {
383
        ide_idx = backend_empty - i;
384
        cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
385
        argc = setup_ide(argc, argv, ARRAY_SIZE(argv),
386
                         ide_idx, NULL, i, mbr_blank, "");
387
    }
388
    qtest_start(g_strjoinv(" ", argv));
389
    test_cmos();
390
    qtest_end();
391
}
392

    
393
int main(int argc, char **argv)
394
{
395
    Backend i;
396
    int ret;
397

    
398
    g_test_init(&argc, &argv, NULL);
399

    
400
    for (i = 0; i < backend_last; i++) {
401
        if (img_secs[i] >= 0) {
402
            img_file_name[i] = create_test_img(img_secs[i]);
403
        } else {
404
            img_file_name[i] = NULL;
405
        }
406
    }
407

    
408
    qtest_add_func("hd-geo/ide/none", test_ide_none);
409
    qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
410
    qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
411
    qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
412
    qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
413
    qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
414
    qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
415
    qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
416
    qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
417
    qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
418
    qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
419
    qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
420

    
421
    ret = g_test_run();
422

    
423
    for (i = 0; i < backend_last; i++) {
424
        unlink(img_file_name[i]);
425
    }
426

    
427
    return ret;
428
}