qemu

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

q35-test.c (10162B)


      1 /*
      2  * QTest testcase for Q35 northbridge
      3  *
      4  * Copyright (c) 2015 Red Hat, Inc.
      5  *
      6  * Author: Gerd Hoffmann <kraxel@redhat.com>
      7  *
      8  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      9  * See the COPYING file in the top-level directory.
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "libqtest.h"
     14 #include "libqos/pci.h"
     15 #include "libqos/pci-pc.h"
     16 #include "hw/pci-host/q35.h"
     17 #include "qapi/qmp/qdict.h"
     18 
     19 #define TSEG_SIZE_TEST_GUEST_RAM_MBYTES 128
     20 
     21 /* @esmramc_tseg_sz: ESMRAMC.TSEG_SZ bitmask for selecting the requested TSEG
     22  *                   size. Must be a subset of
     23  *                   MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK.
     24  *
     25  * @extended_tseg_mbytes: Size of the extended TSEG. Only consulted if
     26  *                        @esmramc_tseg_sz equals
     27  *                        MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK precisely.
     28  *
     29  * @expected_tseg_mbytes: Expected guest-visible TSEG size in megabytes,
     30  *                        matching @esmramc_tseg_sz and @extended_tseg_mbytes
     31  *                        above.
     32  */
     33 struct TsegSizeArgs {
     34     uint8_t esmramc_tseg_sz;
     35     uint16_t extended_tseg_mbytes;
     36     uint16_t expected_tseg_mbytes;
     37 };
     38 typedef struct TsegSizeArgs TsegSizeArgs;
     39 
     40 static const TsegSizeArgs tseg_1mb = {
     41     .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB,
     42     .extended_tseg_mbytes = 0,
     43     .expected_tseg_mbytes = 1,
     44 };
     45 static const TsegSizeArgs tseg_2mb = {
     46     .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB,
     47     .extended_tseg_mbytes = 0,
     48     .expected_tseg_mbytes = 2,
     49 };
     50 static const TsegSizeArgs tseg_8mb = {
     51     .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB,
     52     .extended_tseg_mbytes = 0,
     53     .expected_tseg_mbytes = 8,
     54 };
     55 static const TsegSizeArgs tseg_ext_16mb = {
     56     .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK,
     57     .extended_tseg_mbytes = 16,
     58     .expected_tseg_mbytes = 16,
     59 };
     60 
     61 static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled)
     62 {
     63     uint8_t smram;
     64 
     65     smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
     66     if (enabled) {
     67         smram |= mask;
     68     } else {
     69         smram &= ~mask;
     70     }
     71     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram);
     72 }
     73 
     74 static bool smram_test_bit(QPCIDevice *pcidev, uint8_t mask)
     75 {
     76     uint8_t smram;
     77 
     78     smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
     79     return smram & mask;
     80 }
     81 
     82 static void test_smram_lock(void)
     83 {
     84     QPCIBus *pcibus;
     85     QPCIDevice *pcidev;
     86     QDict *response;
     87     QTestState *qts;
     88 
     89     qts = qtest_init("-M q35");
     90 
     91     pcibus = qpci_new_pc(qts, NULL);
     92     g_assert(pcibus != NULL);
     93 
     94     pcidev = qpci_device_find(pcibus, 0);
     95     g_assert(pcidev != NULL);
     96 
     97     /* check open is settable */
     98     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
     99     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
    100     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
    101     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
    102 
    103     /* lock, check open is cleared & not settable */
    104     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_LCK, true);
    105     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
    106     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
    107     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
    108 
    109     /* reset */
    110     response = qtest_qmp(qts, "{'execute': 'system_reset', 'arguments': {} }");
    111     g_assert(response);
    112     g_assert(!qdict_haskey(response, "error"));
    113     qobject_unref(response);
    114 
    115     /* check open is settable again */
    116     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
    117     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
    118     smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
    119     g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
    120 
    121     g_free(pcidev);
    122     qpci_free_pc(pcibus);
    123 
    124     qtest_quit(qts);
    125 }
    126 
    127 static void test_tseg_size(const void *data)
    128 {
    129     const TsegSizeArgs *args = data;
    130     QPCIBus *pcibus;
    131     QPCIDevice *pcidev;
    132     uint8_t smram_val;
    133     uint8_t esmramc_val;
    134     uint32_t ram_offs;
    135     QTestState *qts;
    136 
    137     if (args->esmramc_tseg_sz == MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
    138         qts = qtest_initf("-M q35 -m %uM -global mch.extended-tseg-mbytes=%u",
    139                           TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
    140                           args->extended_tseg_mbytes);
    141     } else {
    142         qts = qtest_initf("-M q35 -m %uM", TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
    143     }
    144 
    145     /* locate the DRAM controller */
    146     pcibus = qpci_new_pc(qts, NULL);
    147     g_assert(pcibus != NULL);
    148     pcidev = qpci_device_find(pcibus, 0);
    149     g_assert(pcidev != NULL);
    150 
    151     /* Set TSEG size. Restrict TSEG visibility to SMM by setting T_EN. */
    152     esmramc_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_ESMRAMC);
    153     esmramc_val &= ~MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK;
    154     esmramc_val |= args->esmramc_tseg_sz;
    155     esmramc_val |= MCH_HOST_BRIDGE_ESMRAMC_T_EN;
    156     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_ESMRAMC, esmramc_val);
    157 
    158     /* Enable TSEG by setting G_SMRAME. Close TSEG by setting D_CLS. */
    159     smram_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
    160     smram_val &= ~(MCH_HOST_BRIDGE_SMRAM_D_OPEN |
    161                    MCH_HOST_BRIDGE_SMRAM_D_LCK);
    162     smram_val |= (MCH_HOST_BRIDGE_SMRAM_D_CLS |
    163                   MCH_HOST_BRIDGE_SMRAM_G_SMRAME);
    164     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
    165 
    166     /* lock TSEG */
    167     smram_val |= MCH_HOST_BRIDGE_SMRAM_D_LCK;
    168     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
    169 
    170     /* Now check that the byte right before the TSEG is r/w, and that the first
    171      * byte in the TSEG always reads as 0xff.
    172      */
    173     ram_offs = (TSEG_SIZE_TEST_GUEST_RAM_MBYTES - args->expected_tseg_mbytes) *
    174                1024 * 1024 - 1;
    175     g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0);
    176     qtest_writeb(qts, ram_offs, 1);
    177     g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 1);
    178 
    179     ram_offs++;
    180     g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
    181     qtest_writeb(qts, ram_offs, 1);
    182     g_assert_cmpint(qtest_readb(qts, ram_offs), ==, 0xff);
    183 
    184     g_free(pcidev);
    185     qpci_free_pc(pcibus);
    186     qtest_quit(qts);
    187 }
    188 
    189 #define SMBASE 0x30000
    190 #define SMRAM_TEST_PATTERN 0x32
    191 #define SMRAM_TEST_RESET_PATTERN 0x23
    192 
    193 static void test_smram_smbase_lock(void)
    194 {
    195     QPCIBus *pcibus;
    196     QPCIDevice *pcidev;
    197     QDict *response;
    198     QTestState *qts;
    199     int i;
    200 
    201     qts = qtest_init("-M q35");
    202 
    203     pcibus = qpci_new_pc(qts, NULL);
    204     g_assert(pcibus != NULL);
    205 
    206     pcidev = qpci_device_find(pcibus, 0);
    207     g_assert(pcidev != NULL);
    208 
    209     /* check that SMRAM is not enabled by default */
    210     g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == 0);
    211     qtest_writeb(qts, SMBASE, SMRAM_TEST_PATTERN);
    212     g_assert_cmpint(qtest_readb(qts, SMBASE), ==, SMRAM_TEST_PATTERN);
    213 
    214     /* check that writing junk to 0x9c before before negotiating is ignored */
    215     for (i = 0; i < 0xff; i++) {
    216         qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_F_SMBASE, i);
    217         g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == 0);
    218     }
    219 
    220     /* enable SMRAM at SMBASE */
    221     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_F_SMBASE, 0xff);
    222     g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == 0x01);
    223     /* lock SMRAM at SMBASE */
    224     qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_F_SMBASE, 0x02);
    225     g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == 0x02);
    226 
    227     /* check that SMRAM at SMBASE is locked and can't be unlocked */
    228     g_assert_cmpint(qtest_readb(qts, SMBASE), ==, 0xff);
    229     for (i = 0; i <= 0xff; i++) {
    230         /* make sure register is immutable */
    231         qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_F_SMBASE, i);
    232         g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == 0x02);
    233 
    234         /* RAM access should go into black hole */
    235         qtest_writeb(qts, SMBASE, SMRAM_TEST_PATTERN);
    236         g_assert_cmpint(qtest_readb(qts, SMBASE), ==, 0xff);
    237     }
    238 
    239     /* reset */
    240     response = qtest_qmp(qts, "{'execute': 'system_reset', 'arguments': {} }");
    241     g_assert(response);
    242     g_assert(!qdict_haskey(response, "error"));
    243     qobject_unref(response);
    244 
    245     /* check RAM at SMBASE is available after reset */
    246     g_assert_cmpint(qtest_readb(qts, SMBASE), ==, SMRAM_TEST_PATTERN);
    247     g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == 0);
    248     qtest_writeb(qts, SMBASE, SMRAM_TEST_RESET_PATTERN);
    249     g_assert_cmpint(qtest_readb(qts, SMBASE), ==, SMRAM_TEST_RESET_PATTERN);
    250 
    251     g_free(pcidev);
    252     qpci_free_pc(pcibus);
    253 
    254     qtest_quit(qts);
    255 }
    256 
    257 static void test_without_smram_base(void)
    258 {
    259     QPCIBus *pcibus;
    260     QPCIDevice *pcidev;
    261     QTestState *qts;
    262     int i;
    263 
    264     qts = qtest_init("-M pc-q35-4.1");
    265 
    266     pcibus = qpci_new_pc(qts, NULL);
    267     g_assert(pcibus != NULL);
    268 
    269     pcidev = qpci_device_find(pcibus, 0);
    270     g_assert(pcidev != NULL);
    271 
    272     /* check that RAM is accessible */
    273     qtest_writeb(qts, SMBASE, SMRAM_TEST_PATTERN);
    274     g_assert_cmpint(qtest_readb(qts, SMBASE), ==, SMRAM_TEST_PATTERN);
    275 
    276     /* check that writing to 0x9c succeeds */
    277     for (i = 0; i <= 0xff; i++) {
    278         qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_F_SMBASE, i);
    279         g_assert(qpci_config_readb(pcidev, MCH_HOST_BRIDGE_F_SMBASE) == i);
    280     }
    281 
    282     /* check that RAM is still accessible */
    283     qtest_writeb(qts, SMBASE, SMRAM_TEST_PATTERN + 1);
    284     g_assert_cmpint(qtest_readb(qts, SMBASE), ==, (SMRAM_TEST_PATTERN + 1));
    285 
    286     g_free(pcidev);
    287     qpci_free_pc(pcibus);
    288 
    289     qtest_quit(qts);
    290 }
    291 
    292 int main(int argc, char **argv)
    293 {
    294     g_test_init(&argc, &argv, NULL);
    295 
    296     qtest_add_func("/q35/smram/lock", test_smram_lock);
    297 
    298     qtest_add_data_func("/q35/tseg-size/1mb", &tseg_1mb, test_tseg_size);
    299     qtest_add_data_func("/q35/tseg-size/2mb", &tseg_2mb, test_tseg_size);
    300     qtest_add_data_func("/q35/tseg-size/8mb", &tseg_8mb, test_tseg_size);
    301     qtest_add_data_func("/q35/tseg-size/ext/16mb", &tseg_ext_16mb,
    302                         test_tseg_size);
    303     qtest_add_func("/q35/smram/smbase_lock", test_smram_smbase_lock);
    304     qtest_add_func("/q35/smram/legacy_smbase", test_without_smram_base);
    305     return g_test_run();
    306 }