qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 06/32] qtest: Add hard disk geometry test


From: Blue Swirl
Subject: Re: [Qemu-devel] [PATCH 06/32] qtest: Add hard disk geometry test
Date: Fri, 29 Jun 2012 20:16:24 +0000

On Fri, Jun 29, 2012 at 3:34 PM, Markus Armbruster <address@hidden> wrote:
> So far covers only IDE and tests only CMOS contents.
>
> Signed-off-by: Markus Armbruster <address@hidden>
> ---
>  tests/Makefile      |    2 +
>  tests/hd-geo-test.c |  402 
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 404 insertions(+), 0 deletions(-)
>  create mode 100644 tests/hd-geo-test.c
>
> diff --git a/tests/Makefile b/tests/Makefile
> index d66ab19..5d362bd 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -20,6 +20,7 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
>  # All QTests for now are POSIX-only, but the dependencies are
>  # really in libqtest, not in the testcases themselves.
>  check-qtest-i386-y = tests/fdc-test$(EXESUF)
> +check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
>  check-qtest-i386-y += tests/rtc-test$(EXESUF)
>  check-qtest-x86_64-y = $(check-qtest-i386-y)
>  check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
> @@ -70,6 +71,7 @@ tests/test-visitor-serialization$(EXESUF): 
> tests/test-visitor-serialization.o $(
>  tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
>  tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
>  tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y)
> +tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o 
> $(trace-obj-y)
>
>  # QTest rules
>
> diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
> new file mode 100644
> index 0000000..0ab573c
> --- /dev/null
> +++ b/tests/hd-geo-test.c
> @@ -0,0 +1,402 @@
> +/*
> + * Hard disk geometry test cases.
> + *
> + * Copyright (c) 2012 Red Hat Inc.
> + *
> + * Authors:
> + *  Markus Armbruster <address@hidden>,
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +/*
> + * Covers only IDE and tests only CMOS contents.  Better than nothing.

The test is slightly unorthodox since IDE, disks and CMOS RAM are
actually separate devices. Moreover, QEMU shouldn't touch CMOS RAM but
let the BIOS (instructed by fw_cfg) manage it. But this can be seen as
a nice test for the integration between all those components. If ever
CMOS handling is pushed to BIOS level, this will break.

> + * Improvements welcome.
> + */
> +
> +#include <glib.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "qemu-common.h"
> +#include "libqtest.h"
> +
> +const char test_image[] = "/tmp/qtest.XXXXXX";

'static'

> +
> +static char *create_test_img(int secs)
> +{
> +    char *template = strdup("/tmp/qtest.XXXXXX");
> +    int fd, ret;
> +
> +    fd = mkstemp(template);
> +    g_assert(fd >= 0);
> +    ret = ftruncate(fd, (off_t)secs * 512);
> +    g_assert(ret == 0);
> +    close(fd);
> +    return template;
> +}
> +
> +typedef struct {
> +    int cyls, heads, secs, trans;
> +} chst;

CHST

> +
> +typedef enum {
> +    mbr_blank, mbr_lba, mbr_chs,
> +    mbr_last
> +} mbr_contents;

MBRContents


> +
> +typedef enum {
> +    /* order is relevant */
> +    backend_small, backend_large, backend_empty,
> +    backend_last
> +} backend;

Backend, though maybe CODING_STYLE does not specify enums.

> +
> +static const int img_secs[backend_last] = {
> +    [backend_small] = 61440,
> +    [backend_large] = 8388608,
> +    [backend_empty] = -1,
> +};
> +
> +static const chst hd_chst[backend_last][mbr_last] = {
> +    [backend_small] = {
> +        [mbr_blank] = { 60, 16, 63, 0 },
> +        [mbr_lba]   = { 60, 16, 63, 2 },
> +        [mbr_chs]   = { 60, 16, 63, 0 }
> +    },
> +    [backend_large] = {
> +        [mbr_blank] = { 8322, 16, 63, 1 },
> +        [mbr_lba]   = { 8322, 16, 63, 1 },
> +        [mbr_chs]   = { 8322, 16, 63, 0 }
> +    },
> +};
> +
> +static const char *img_file_name[backend_last];
> +
> +static const chst *cur_ide[4];
> +
> +static bool is_hd(const chst *expected_chst)
> +{
> +    return expected_chst && expected_chst->cyls;
> +}
> +
> +static void test_cmos_byte(int reg, int expected)
> +{
> +    enum { cmos_base = 0x70 };
> +    int actual;
> +
> +    outb(cmos_base + 0, reg);
> +    actual = inb(cmos_base + 1);
> +    g_assert(actual == expected);
> +}
> +
> +static void test_cmos_bytes(int reg0, int n, uint8_t expected[])
> +{
> +    int i;
> +
> +    for (i = 0; i < 9; i++) {
> +        test_cmos_byte(reg0 + i, expected[i]);
> +    }
> +}
> +
> +static void test_cmos_disk_data(void)
> +{
> +    test_cmos_byte(0x12,
> +                   (is_hd(cur_ide[0]) ? 0xf0 : 0) |
> +                   (is_hd(cur_ide[1]) ? 0x0f : 0));
> +}
> +
> +static void test_cmos_drive_cyl(int reg0, const chst *expected_chst)
> +{
> +    if (is_hd(expected_chst)) {
> +        int c = expected_chst->cyls;
> +        int h = expected_chst->heads;
> +        int s = expected_chst->secs;
> +        uint8_t expected_bytes[9] = {
> +            c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
> +            c & 0xff, c >> 8, s
> +        };
> +        test_cmos_bytes(reg0, 9, expected_bytes);
> +    } else {
> +        int i;
> +
> +        for (i = 0; i < 9; i++) {
> +            test_cmos_byte(reg0 + i, 0);
> +        }
> +    }
> +}
> +
> +static void test_cmos_drive1(void)
> +{
> +    test_cmos_byte(0x19, is_hd(cur_ide[0]) ? 47 : 0);
> +    test_cmos_drive_cyl(0x1b, cur_ide[0]);
> +}
> +
> +static void test_cmos_drive2(void)
> +{
> +    test_cmos_byte(0x1a, is_hd(cur_ide[1]) ? 47 : 0);
> +    test_cmos_drive_cyl(0x24, cur_ide[1]);
> +}
> +
> +static void test_cmos_disktransflag(void)
> +{
> +    int val, i;
> +
> +    val = 0;
> +    for (i = 0; i < ARRAY_SIZE(cur_ide); i++) {
> +        if (is_hd(cur_ide[i])) {
> +            val |= cur_ide[i]->trans << (2 * i);
> +        }
> +    }
> +    test_cmos_byte(0x39, val);
> +}
> +
> +static void test_cmos(void)
> +{
> +    test_cmos_disk_data();
> +    test_cmos_drive1();
> +    test_cmos_drive2();
> +    test_cmos_disktransflag();
> +}
> +
> +static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
> +{
> +    g_assert(argc + 1 < argv_sz);
> +    argv[argc++] = arg;
> +    argv[argc] = NULL;
> +    return argc;
> +}
> +
> +static int setup_common(char *argv[], int argv_sz)
> +{
> +    memset(cur_ide, 0, sizeof(cur_ide));
> +    return append_arg(0, argv, argv_sz,
> +                      g_strdup("-nodefaults -display none"));
> +}
> +
> +static void setup_mbr(int img_idx, mbr_contents mbr)
> +{
> +    uint8_t part_lba[16] = {

'static const'

> +        /* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
> +        0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
> +    };
> +    uint8_t part_chs[16] = {

Ditto

> +        /* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
> +        0x80, 1, 1, 0, 6,  15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
> +    };
> +    uint8_t buf[512];
> +    int fd, ret;
> +
> +    memset(buf, 0, sizeof(buf));
> +
> +    if (mbr != mbr_blank) {
> +        buf[0x1fe] = 0x55;
> +        buf[0x1ff] = 0xAA;
> +        memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16);
> +    }
> +
> +    fd = open(img_file_name[img_idx], O_WRONLY);
> +    g_assert(fd >= 0);
> +    ret = write(fd, buf, sizeof(buf));
> +    g_assert(ret == sizeof(buf));
> +    close(fd);
> +}
> +
> +static int setup_ide(int argc, char *argv[], int argv_sz,
> +                     int ide_idx, const char *dev, int img_idx,
> +                     mbr_contents mbr, const char *opts)
> +{
> +    char *s1, *s2, *s3;
> +
> +    s1 = g_strdup_printf("-drive id=drive%d,if=%s",
> +                         ide_idx, dev ? "none" : "ide");
> +    s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
> +
> +    if (img_secs[img_idx] >= 0) {
> +        setup_mbr(img_idx, mbr);
> +        s3 = g_strdup_printf(",file=%s", img_file_name[img_idx]);
> +    } else {
> +        s3 = g_strdup(",media=cdrom");
> +    }
> +    argc = append_arg(argc, argv, argv_sz,
> +                      g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
> +    g_free(s1);
> +    g_free(s2);
> +    g_free(s3);
> +
> +    if (dev) {
> +        argc = append_arg(argc, argv, argv_sz,
> +                          g_strdup_printf("-device %s,drive=drive%d,"
> +                                          "bus=ide.%d,unit=%d",
> +                                          dev, ide_idx,
> +                                          ide_idx / 2, ide_idx % 2));
> +    }
> +    return argc;
> +}
> +
> +/*
> + * Test case: no IDE devices
> + */
> +static void test_ide_none(void)
> +{
> +    char *argv[256];
> +
> +    setup_common(argv, ARRAY_SIZE(argv));
> +    qtest_start(g_strjoinv(" ", argv));
> +    test_cmos();
> +    qtest_quit(global_qtest);
> +}
> +
> +static void test_ide_mbr(bool use_device, mbr_contents mbr)
> +{
> +    char *argv[256];
> +    int argc;
> +    backend i;
> +    const char *dev;
> +
> +    argc = setup_common(argv, ARRAY_SIZE(argv));
> +    for (i = 0; i < backend_last; i++) {
> +        cur_ide[i] = &hd_chst[i][mbr];
> +        dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
> +        argc = setup_ide(argc, argv, ARRAY_SIZE(argv), i, dev, i, mbr, "");
> +    }
> +    qtest_start(g_strjoinv(" ", argv));
> +    test_cmos();
> +    qtest_quit(global_qtest);
> +}
> +
> +/*
> + * Test case: IDE devices (if=ide) with blank MBRs
> + */
> +static void test_ide_drive_mbr_blank(void)
> +{
> +    test_ide_mbr(false, mbr_blank);
> +}
> +
> +/*
> + * Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
> + */
> +static void test_ide_drive_mbr_lba(void)
> +{
> +    test_ide_mbr(false, mbr_lba);
> +}
> +
> +/*
> + * Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
> + */
> +static void test_ide_drive_mbr_chs(void)
> +{
> +    test_ide_mbr(false, mbr_chs);
> +}
> +
> +/*
> + * Test case: IDE devices (if=none) with blank MBRs
> + */
> +static void test_ide_device_mbr_blank(void)
> +{
> +    test_ide_mbr(true, mbr_blank);
> +}
> +
> +/*
> + * Test case: IDE devices (if=none) with MBRs indicating LBA is in use
> + */
> +static void test_ide_device_mbr_lba(void)
> +{
> +    test_ide_mbr(true, mbr_lba);
> +}
> +
> +/*
> + * Test case: IDE devices (if=none) with MBRs indicating CHS is in use
> + */
> +static void test_ide_device_mbr_chs(void)
> +{
> +    test_ide_mbr(true, mbr_chs);
> +}
> +
> +static void test_ide_drive_user(const char *dev, bool trans)
> +{
> +    char *argv[256], *opts;
> +    int argc;
> +    int secs = img_secs[backend_small];
> +    const chst expected_chst = { secs / (4 * 32) , 4, 32, trans };
> +
> +    argc = setup_common(argv, ARRAY_SIZE(argv));
> +    opts = g_strdup_printf(",cyls=%d,heads=%d,secs=%d%s",
> +                           expected_chst.cyls, expected_chst.heads,
> +                           expected_chst.secs,
> +                           trans ? ",trans=lba" : "");
> +    cur_ide[0] = &expected_chst;
> +    argc = setup_ide(argc, argv, ARRAY_SIZE(argv),
> +                     0, dev, backend_small, mbr_chs, opts);
> +    qtest_start(g_strjoinv(" ", argv));
> +    test_cmos();

g_free(opts);

> +    qtest_quit(global_qtest);
> +}
> +
> +/*
> + * Test case: IDE device (if=ide) with explicit CHS
> + */
> +static void test_ide_drive_user_chs(void)
> +{
> +    test_ide_drive_user(NULL, false);
> +}
> +
> +/*
> + * Test case: IDE device (if=ide) with explicit CHS and translation
> + */
> +static void test_ide_drive_user_chst(void)
> +{
> +    test_ide_drive_user(NULL, true);
> +}
> +
> +/*
> + * Test case: IDE device (if=none) with explicit CHS
> + */
> +static void test_ide_device_user_chs(void)
> +{
> +    test_ide_drive_user("ide-hd", false);
> +}
> +
> +/*
> + * Test case: IDE device (if=none) with explicit CHS and translation
> + */
> +static void test_ide_device_user_chst(void)
> +{
> +    test_ide_drive_user("ide-hd", true);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    backend i;
> +    int ret;
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    for (i = 0; i < backend_last; i++) {
> +        if (img_secs[i] >= 0) {
> +            img_file_name[i] = create_test_img(img_secs[i]);
> +        } else {
> +            img_file_name[i] = NULL;
> +        }
> +    }
> +
> +    qtest_add_func("hd-geo/ide/none", test_ide_none);
> +    qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
> +    qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
> +    qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
> +    qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
> +    qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
> +    qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
> +    qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
> +    qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
> +    qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
> +    qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
> +
> +    ret = g_test_run();
> +
> +    for (i = 0; i < backend_last; i++) {
> +        unlink(img_file_name[i]);
> +    }
> +
> +    return ret;
> +}
> --
> 1.7.6.5
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]