qemu/tests/q35-test.c
<<
>>
Prefs
   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
  18#define TSEG_SIZE_TEST_GUEST_RAM_MBYTES 128
  19
  20/* @esmramc_tseg_sz: ESMRAMC.TSEG_SZ bitmask for selecting the requested TSEG
  21 *                   size. Must be a subset of
  22 *                   MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK.
  23 *
  24 * @extended_tseg_mbytes: Size of the extended TSEG. Only consulted if
  25 *                        @esmramc_tseg_sz equals
  26 *                        MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK precisely.
  27 *
  28 * @expected_tseg_mbytes: Expected guest-visible TSEG size in megabytes,
  29 *                        matching @esmramc_tseg_sz and @extended_tseg_mbytes
  30 *                        above.
  31 */
  32struct TsegSizeArgs {
  33    uint8_t esmramc_tseg_sz;
  34    uint16_t extended_tseg_mbytes;
  35    uint16_t expected_tseg_mbytes;
  36};
  37typedef struct TsegSizeArgs TsegSizeArgs;
  38
  39static const TsegSizeArgs tseg_1mb = {
  40    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB,
  41    .extended_tseg_mbytes = 0,
  42    .expected_tseg_mbytes = 1,
  43};
  44static const TsegSizeArgs tseg_2mb = {
  45    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB,
  46    .extended_tseg_mbytes = 0,
  47    .expected_tseg_mbytes = 2,
  48};
  49static const TsegSizeArgs tseg_8mb = {
  50    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB,
  51    .extended_tseg_mbytes = 0,
  52    .expected_tseg_mbytes = 8,
  53};
  54static const TsegSizeArgs tseg_ext_16mb = {
  55    .esmramc_tseg_sz      = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK,
  56    .extended_tseg_mbytes = 16,
  57    .expected_tseg_mbytes = 16,
  58};
  59
  60static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled)
  61{
  62    uint8_t smram;
  63
  64    smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
  65    if (enabled) {
  66        smram |= mask;
  67    } else {
  68        smram &= ~mask;
  69    }
  70    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram);
  71}
  72
  73static bool smram_test_bit(QPCIDevice *pcidev, uint8_t mask)
  74{
  75    uint8_t smram;
  76
  77    smram = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
  78    return smram & mask;
  79}
  80
  81static void test_smram_lock(void)
  82{
  83    QPCIBus *pcibus;
  84    QPCIDevice *pcidev;
  85    QDict *response;
  86
  87    qtest_start("-M q35");
  88
  89    pcibus = qpci_init_pc(NULL);
  90    g_assert(pcibus != NULL);
  91
  92    pcidev = qpci_device_find(pcibus, 0);
  93    g_assert(pcidev != NULL);
  94
  95    /* check open is settable */
  96    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
  97    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
  98    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
  99    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
 100
 101    /* lock, check open is cleared & not settable */
 102    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_LCK, true);
 103    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
 104    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
 105    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
 106
 107    /* reset */
 108    response = qmp("{'execute': 'system_reset', 'arguments': {} }");
 109    g_assert(response);
 110    g_assert(!qdict_haskey(response, "error"));
 111    QDECREF(response);
 112
 113    /* check open is settable again */
 114    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, false);
 115    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == false);
 116    smram_set_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN, true);
 117    g_assert(smram_test_bit(pcidev, MCH_HOST_BRIDGE_SMRAM_D_OPEN) == true);
 118
 119    g_free(pcidev);
 120    qpci_free_pc(pcibus);
 121
 122    qtest_end();
 123}
 124
 125static void test_tseg_size(const void *data)
 126{
 127    const TsegSizeArgs *args = data;
 128    char *cmdline;
 129    QPCIBus *pcibus;
 130    QPCIDevice *pcidev;
 131    uint8_t smram_val;
 132    uint8_t esmramc_val;
 133    uint32_t ram_offs;
 134
 135    if (args->esmramc_tseg_sz == MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
 136        cmdline = g_strdup_printf("-M q35 -m %uM "
 137                                  "-global mch.extended-tseg-mbytes=%u",
 138                                  TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
 139                                  args->extended_tseg_mbytes);
 140    } else {
 141        cmdline = g_strdup_printf("-M q35 -m %uM",
 142                                  TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
 143    }
 144    qtest_start(cmdline);
 145    g_free(cmdline);
 146
 147    /* locate the DRAM controller */
 148    pcibus = qpci_init_pc(NULL);
 149    g_assert(pcibus != NULL);
 150    pcidev = qpci_device_find(pcibus, 0);
 151    g_assert(pcidev != NULL);
 152
 153    /* Set TSEG size. Restrict TSEG visibility to SMM by setting T_EN. */
 154    esmramc_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_ESMRAMC);
 155    esmramc_val &= ~MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK;
 156    esmramc_val |= args->esmramc_tseg_sz;
 157    esmramc_val |= MCH_HOST_BRIDGE_ESMRAMC_T_EN;
 158    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_ESMRAMC, esmramc_val);
 159
 160    /* Enable TSEG by setting G_SMRAME. Close TSEG by setting D_CLS. */
 161    smram_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
 162    smram_val &= ~(MCH_HOST_BRIDGE_SMRAM_D_OPEN |
 163                   MCH_HOST_BRIDGE_SMRAM_D_LCK);
 164    smram_val |= (MCH_HOST_BRIDGE_SMRAM_D_CLS |
 165                  MCH_HOST_BRIDGE_SMRAM_G_SMRAME);
 166    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
 167
 168    /* lock TSEG */
 169    smram_val |= MCH_HOST_BRIDGE_SMRAM_D_LCK;
 170    qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
 171
 172    /* Now check that the byte right before the TSEG is r/w, and that the first
 173     * byte in the TSEG always reads as 0xff.
 174     */
 175    ram_offs = (TSEG_SIZE_TEST_GUEST_RAM_MBYTES - args->expected_tseg_mbytes) *
 176               1024 * 1024 - 1;
 177    g_assert_cmpint(readb(ram_offs), ==, 0);
 178    writeb(ram_offs, 1);
 179    g_assert_cmpint(readb(ram_offs), ==, 1);
 180
 181    ram_offs++;
 182    g_assert_cmpint(readb(ram_offs), ==, 0xff);
 183    writeb(ram_offs, 1);
 184    g_assert_cmpint(readb(ram_offs), ==, 0xff);
 185
 186    g_free(pcidev);
 187    qpci_free_pc(pcibus);
 188    qtest_end();
 189}
 190
 191int main(int argc, char **argv)
 192{
 193    g_test_init(&argc, &argv, NULL);
 194
 195    qtest_add_func("/q35/smram/lock", test_smram_lock);
 196
 197    qtest_add_data_func("/q35/tseg-size/1mb", &tseg_1mb, test_tseg_size);
 198    qtest_add_data_func("/q35/tseg-size/2mb", &tseg_2mb, test_tseg_size);
 199    qtest_add_data_func("/q35/tseg-size/8mb", &tseg_8mb, test_tseg_size);
 200    qtest_add_data_func("/q35/tseg-size/ext/16mb", &tseg_ext_16mb,
 201                        test_tseg_size);
 202    return g_test_run();
 203}
 204