qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

i440fx-test.c (11922B)


      1 /*
      2  * qtest I440FX test case
      3  *
      4  * Copyright IBM, Corp. 2012-2013
      5  * Copyright Red Hat, Inc. 2013
      6  *
      7  * Authors:
      8  *  Anthony Liguori   <aliguori@us.ibm.com>
      9  *  Laszlo Ersek      <lersek@redhat.com>
     10  *
     11  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     12  * See the COPYING file in the top-level directory.
     13  */
     14 
     15 #include "qemu/osdep.h"
     16 
     17 #include "libqtest-single.h"
     18 #include "libqos/pci.h"
     19 #include "libqos/pci-pc.h"
     20 #include "hw/pci/pci_regs.h"
     21 
     22 #define BROKEN 1
     23 
     24 typedef struct TestData
     25 {
     26     int num_cpus;
     27 } TestData;
     28 
     29 typedef struct FirmwareTestFixture {
     30     /* decides whether we're testing -bios or -pflash */
     31     bool is_bios;
     32 } FirmwareTestFixture;
     33 
     34 static QPCIBus *test_start_get_bus(const TestData *s)
     35 {
     36     char *cmdline;
     37 
     38     cmdline = g_strdup_printf("-machine pc -smp %d", s->num_cpus);
     39     qtest_start(cmdline);
     40     g_free(cmdline);
     41     return qpci_new_pc(global_qtest, NULL);
     42 }
     43 
     44 static void test_i440fx_defaults(gconstpointer opaque)
     45 {
     46     const TestData *s = opaque;
     47     QPCIBus *bus;
     48     QPCIDevice *dev;
     49     uint32_t value;
     50 
     51     bus = test_start_get_bus(s);
     52     dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
     53     g_assert(dev != NULL);
     54 
     55     /* 3.2.2 */
     56     g_assert_cmpint(qpci_config_readw(dev, PCI_VENDOR_ID), ==, 0x8086);
     57     /* 3.2.3 */
     58     g_assert_cmpint(qpci_config_readw(dev, PCI_DEVICE_ID), ==, 0x1237);
     59 #ifndef BROKEN
     60     /* 3.2.4 */
     61     g_assert_cmpint(qpci_config_readw(dev, PCI_COMMAND), ==, 0x0006);
     62     /* 3.2.5 */
     63     g_assert_cmpint(qpci_config_readw(dev, PCI_STATUS), ==, 0x0280);
     64 #endif
     65     /* 3.2.7 */
     66     g_assert_cmpint(qpci_config_readb(dev, PCI_CLASS_PROG), ==, 0x00);
     67     g_assert_cmpint(qpci_config_readw(dev, PCI_CLASS_DEVICE), ==, 0x0600);
     68     /* 3.2.8 */
     69     g_assert_cmpint(qpci_config_readb(dev, PCI_LATENCY_TIMER), ==, 0x00);
     70     /* 3.2.9 */
     71     g_assert_cmpint(qpci_config_readb(dev, PCI_HEADER_TYPE), ==, 0x00);
     72     /* 3.2.10 */
     73     g_assert_cmpint(qpci_config_readb(dev, PCI_BIST), ==, 0x00);
     74 
     75     /* 3.2.11 */
     76     value = qpci_config_readw(dev, 0x50); /* PMCCFG */
     77     if (s->num_cpus == 1) { /* WPE */
     78         g_assert(!(value & (1 << 15)));
     79     } else {
     80         g_assert((value & (1 << 15)));
     81     }
     82 
     83     g_assert(!(value & (1 << 6))); /* EPTE */
     84 
     85     /* 3.2.12 */
     86     g_assert_cmpint(qpci_config_readb(dev, 0x52), ==, 0x00); /* DETURBO */
     87     /* 3.2.13 */
     88 #ifndef BROKEN
     89     g_assert_cmpint(qpci_config_readb(dev, 0x53), ==, 0x80); /* DBC */
     90 #endif
     91     /* 3.2.14 */
     92     g_assert_cmpint(qpci_config_readb(dev, 0x54), ==, 0x00); /* AXC */
     93     /* 3.2.15 */
     94     g_assert_cmpint(qpci_config_readw(dev, 0x55), ==, 0x0000); /* DRT */
     95 #ifndef BROKEN
     96     /* 3.2.16 */
     97     g_assert_cmpint(qpci_config_readb(dev, 0x57), ==, 0x01); /* DRAMC */
     98     /* 3.2.17 */
     99     g_assert_cmpint(qpci_config_readb(dev, 0x58), ==, 0x10); /* DRAMT */
    100 #endif
    101     /* 3.2.18 */
    102     g_assert_cmpint(qpci_config_readb(dev, 0x59), ==, 0x00); /* PAM0 */
    103     g_assert_cmpint(qpci_config_readb(dev, 0x5A), ==, 0x00); /* PAM1 */
    104     g_assert_cmpint(qpci_config_readb(dev, 0x5B), ==, 0x00); /* PAM2 */
    105     g_assert_cmpint(qpci_config_readb(dev, 0x5C), ==, 0x00); /* PAM3 */
    106     g_assert_cmpint(qpci_config_readb(dev, 0x5D), ==, 0x00); /* PAM4 */
    107     g_assert_cmpint(qpci_config_readb(dev, 0x5E), ==, 0x00); /* PAM5 */
    108     g_assert_cmpint(qpci_config_readb(dev, 0x5F), ==, 0x00); /* PAM6 */
    109 #ifndef BROKEN
    110     /* 3.2.19 */
    111     g_assert_cmpint(qpci_config_readb(dev, 0x60), ==, 0x01); /* DRB0 */
    112     g_assert_cmpint(qpci_config_readb(dev, 0x61), ==, 0x01); /* DRB1 */
    113     g_assert_cmpint(qpci_config_readb(dev, 0x62), ==, 0x01); /* DRB2 */
    114     g_assert_cmpint(qpci_config_readb(dev, 0x63), ==, 0x01); /* DRB3 */
    115     g_assert_cmpint(qpci_config_readb(dev, 0x64), ==, 0x01); /* DRB4 */
    116     g_assert_cmpint(qpci_config_readb(dev, 0x65), ==, 0x01); /* DRB5 */
    117     g_assert_cmpint(qpci_config_readb(dev, 0x66), ==, 0x01); /* DRB6 */
    118     g_assert_cmpint(qpci_config_readb(dev, 0x67), ==, 0x01); /* DRB7 */
    119 #endif
    120     /* 3.2.20 */
    121     g_assert_cmpint(qpci_config_readb(dev, 0x68), ==, 0x00); /* FDHC */
    122     /* 3.2.21 */
    123     g_assert_cmpint(qpci_config_readb(dev, 0x70), ==, 0x00); /* MTT */
    124 #ifndef BROKEN
    125     /* 3.2.22 */
    126     g_assert_cmpint(qpci_config_readb(dev, 0x71), ==, 0x10); /* CLT */
    127 #endif
    128     /* 3.2.23 */
    129     g_assert_cmpint(qpci_config_readb(dev, 0x72), ==, 0x02); /* SMRAM */
    130     /* 3.2.24 */
    131     g_assert_cmpint(qpci_config_readb(dev, 0x90), ==, 0x00); /* ERRCMD */
    132     /* 3.2.25 */
    133     g_assert_cmpint(qpci_config_readb(dev, 0x91), ==, 0x00); /* ERRSTS */
    134     /* 3.2.26 */
    135     g_assert_cmpint(qpci_config_readb(dev, 0x93), ==, 0x00); /* TRC */
    136 
    137     g_free(dev);
    138     qpci_free_pc(bus);
    139     qtest_end();
    140 }
    141 
    142 #define PAM_RE 1
    143 #define PAM_WE 2
    144 
    145 static void pam_set(QPCIDevice *dev, int index, int flags)
    146 {
    147     int regno = 0x59 + (index / 2);
    148     uint8_t reg;
    149 
    150     reg = qpci_config_readb(dev, regno);
    151     if (index & 1) {
    152         reg = (reg & 0x0F) | (flags << 4);
    153     } else {
    154         reg = (reg & 0xF0) | flags;
    155     }
    156     qpci_config_writeb(dev, regno, reg);
    157 }
    158 
    159 static gboolean verify_area(uint32_t start, uint32_t end, uint8_t value)
    160 {
    161     uint32_t size = end - start + 1;
    162     gboolean ret = TRUE;
    163     uint8_t *data;
    164     int i;
    165 
    166     data = g_malloc0(size);
    167     memread(start, data, size);
    168 
    169     g_test_message("verify_area: data[0] = 0x%x", data[0]);
    170 
    171     for (i = 0; i < size; i++) {
    172         if (data[i] != value) {
    173             ret = FALSE;
    174             break;
    175         }
    176     }
    177 
    178     g_free(data);
    179 
    180     return ret;
    181 }
    182 
    183 static void write_area(uint32_t start, uint32_t end, uint8_t value)
    184 {
    185     uint32_t size = end - start + 1;
    186     uint8_t *data;
    187 
    188     data = g_malloc(size);
    189     memset(data, value, size);
    190     memwrite(start, data, size);
    191 
    192     g_free(data);
    193 }
    194 
    195 static void test_i440fx_pam(gconstpointer opaque)
    196 {
    197     const TestData *s = opaque;
    198     QPCIBus *bus;
    199     QPCIDevice *dev;
    200     int i;
    201     static struct {
    202         uint32_t start;
    203         uint32_t end;
    204     } pam_area[] = {
    205         { 0, 0 },             /* Reserved */
    206         { 0xF0000, 0xFFFFF }, /* BIOS Area */
    207         { 0xC0000, 0xC3FFF }, /* Option ROM */
    208         { 0xC4000, 0xC7FFF }, /* Option ROM */
    209         { 0xC8000, 0xCBFFF }, /* Option ROM */
    210         { 0xCC000, 0xCFFFF }, /* Option ROM */
    211         { 0xD0000, 0xD3FFF }, /* Option ROM */
    212         { 0xD4000, 0xD7FFF }, /* Option ROM */
    213         { 0xD8000, 0xDBFFF }, /* Option ROM */
    214         { 0xDC000, 0xDFFFF }, /* Option ROM */
    215         { 0xE0000, 0xE3FFF }, /* BIOS Extension */
    216         { 0xE4000, 0xE7FFF }, /* BIOS Extension */
    217         { 0xE8000, 0xEBFFF }, /* BIOS Extension */
    218         { 0xEC000, 0xEFFFF }, /* BIOS Extension */
    219     };
    220 
    221     bus = test_start_get_bus(s);
    222     dev = qpci_device_find(bus, QPCI_DEVFN(0, 0));
    223     g_assert(dev != NULL);
    224 
    225     for (i = 0; i < ARRAY_SIZE(pam_area); i++) {
    226         if (pam_area[i].start == pam_area[i].end) {
    227             continue;
    228         }
    229 
    230         g_test_message("Checking area 0x%05x..0x%05x",
    231                        pam_area[i].start, pam_area[i].end);
    232         /* Switch to RE for the area */
    233         pam_set(dev, i, PAM_RE);
    234         /* Verify the RAM is all zeros */
    235         g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0));
    236 
    237         /* Switch to WE for the area */
    238         pam_set(dev, i, PAM_RE | PAM_WE);
    239         /* Write out a non-zero mask to the full area */
    240         write_area(pam_area[i].start, pam_area[i].end, 0x42);
    241 
    242 #ifndef BROKEN
    243         /* QEMU only supports a limited form of PAM */
    244 
    245         /* Switch to !RE for the area */
    246         pam_set(dev, i, PAM_WE);
    247         /* Verify the area is not our mask */
    248         g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x42));
    249 #endif
    250 
    251         /* Verify the area is our new mask */
    252         g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x42));
    253 
    254         /* Write out a new mask */
    255         write_area(pam_area[i].start, pam_area[i].end, 0x82);
    256 
    257 #ifndef BROKEN
    258         /* QEMU only supports a limited form of PAM */
    259 
    260         /* Verify the area is not our mask */
    261         g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
    262 
    263         /* Switch to RE for the area */
    264         pam_set(dev, i, PAM_RE | PAM_WE);
    265 #endif
    266         /* Verify the area is our new mask */
    267         g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x82));
    268 
    269         /* Reset area */
    270         pam_set(dev, i, 0);
    271 
    272         /* Verify the area is not our new mask */
    273         g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
    274     }
    275 
    276     g_free(dev);
    277     qpci_free_pc(bus);
    278     qtest_end();
    279 }
    280 
    281 #define BLOB_SIZE ((size_t)65536)
    282 #define ISA_BIOS_MAXSZ ((size_t)(128 * 1024))
    283 
    284 /*
    285  * Create a blob file, and return its absolute pathname as a dynamically
    286  * allocated string.
    287  * The file is closed before the function returns.
    288  * In case of error, the function aborts and prints the error message.
    289  */
    290 static char *create_blob_file(void)
    291 {
    292     int i, fd;
    293     char *pathname;
    294     GError *error = NULL;
    295     g_autofree uint8_t *buf = g_malloc(BLOB_SIZE);
    296 
    297     fd = g_file_open_tmp("blob_XXXXXX", &pathname, &error);
    298     g_assert_no_error(error);
    299     close(fd);
    300 
    301     for (i = 0; i < BLOB_SIZE; i++) {
    302         buf[i] = i;
    303     }
    304 
    305     g_file_set_contents(pathname, (char *)buf, BLOB_SIZE, &error);
    306     g_assert_no_error(error);
    307 
    308     return pathname;
    309 }
    310 
    311 static void test_i440fx_firmware(FirmwareTestFixture *fixture,
    312                                  gconstpointer user_data)
    313 {
    314     char *fw_pathname, *cmdline;
    315     uint8_t *buf;
    316     size_t i, isa_bios_size;
    317 
    318     fw_pathname = create_blob_file();
    319     g_assert(fw_pathname != NULL);
    320 
    321     /* Better hope the user didn't put metacharacters in TMPDIR and co. */
    322     cmdline = g_strdup_printf("-S %s%s", fixture->is_bios
    323                                          ? "-bios "
    324                                          : "-drive if=pflash,format=raw,file=",
    325                               fw_pathname);
    326     g_test_message("qemu cmdline: %s", cmdline);
    327     qtest_start(cmdline);
    328     g_free(cmdline);
    329 
    330     /* QEMU has loaded the firmware (because qtest_start() only returns after
    331      * the QMP handshake completes). We must unlink the firmware blob right
    332      * here, because any assertion firing below would leak it in the
    333      * filesystem. This is also the reason why we recreate the blob every time
    334      * this function is invoked.
    335      */
    336     unlink(fw_pathname);
    337     g_free(fw_pathname);
    338 
    339     /* check below 4G */
    340     buf = g_malloc0(BLOB_SIZE);
    341     memread(0x100000000ULL - BLOB_SIZE, buf, BLOB_SIZE);
    342     for (i = 0; i < BLOB_SIZE; ++i) {
    343         g_assert_cmphex(buf[i], ==, (uint8_t)i);
    344     }
    345 
    346     /* check in ISA space too */
    347     memset(buf, 0, BLOB_SIZE);
    348     isa_bios_size = ISA_BIOS_MAXSZ < BLOB_SIZE ? ISA_BIOS_MAXSZ : BLOB_SIZE;
    349     memread(0x100000 - isa_bios_size, buf, isa_bios_size);
    350     for (i = 0; i < isa_bios_size; ++i) {
    351         g_assert_cmphex(buf[i], ==,
    352                         (uint8_t)((BLOB_SIZE - isa_bios_size) + i));
    353     }
    354 
    355     g_free(buf);
    356     qtest_end();
    357 }
    358 
    359 static void add_firmware_test(const char *testpath,
    360                               void (*setup_fixture)(FirmwareTestFixture *f,
    361                                                     gconstpointer test_data))
    362 {
    363     qtest_add(testpath, FirmwareTestFixture, NULL, setup_fixture,
    364               test_i440fx_firmware, NULL);
    365 }
    366 
    367 static void request_bios(FirmwareTestFixture *fixture,
    368                          gconstpointer user_data)
    369 {
    370     fixture->is_bios = true;
    371 }
    372 
    373 static void request_pflash(FirmwareTestFixture *fixture,
    374                            gconstpointer user_data)
    375 {
    376     fixture->is_bios = false;
    377 }
    378 
    379 int main(int argc, char **argv)
    380 {
    381     TestData data;
    382 
    383     g_test_init(&argc, &argv, NULL);
    384 
    385     data.num_cpus = 1;
    386 
    387     qtest_add_data_func("i440fx/defaults", &data, test_i440fx_defaults);
    388     qtest_add_data_func("i440fx/pam", &data, test_i440fx_pam);
    389     add_firmware_test("i440fx/firmware/bios", request_bios);
    390     add_firmware_test("i440fx/firmware/pflash", request_pflash);
    391 
    392     return g_test_run();
    393 }