cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

tco-test.c (12731B)


      1/*
      2 * QEMU ICH9 TCO emulation tests
      3 *
      4 * Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com>
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7 * See the COPYING file in the top-level directory.
      8 */
      9
     10#include "qemu/osdep.h"
     11
     12#include "libqos/libqtest.h"
     13#include "libqos/pci.h"
     14#include "libqos/pci-pc.h"
     15#include "qapi/qmp/qdict.h"
     16#include "hw/pci/pci_regs.h"
     17#include "hw/i386/ich9.h"
     18#include "hw/acpi/ich9.h"
     19#include "hw/acpi/tco.h"
     20
     21#define RCBA_BASE_ADDR    0xfed1c000
     22#define PM_IO_BASE_ADDR   0xb000
     23
     24enum {
     25    TCO_RLD_DEFAULT         = 0x0000,
     26    TCO_DAT_IN_DEFAULT      = 0x00,
     27    TCO_DAT_OUT_DEFAULT     = 0x00,
     28    TCO1_STS_DEFAULT        = 0x0000,
     29    TCO2_STS_DEFAULT        = 0x0000,
     30    TCO1_CNT_DEFAULT        = 0x0000,
     31    TCO2_CNT_DEFAULT        = 0x0008,
     32    TCO_MESSAGE1_DEFAULT    = 0x00,
     33    TCO_MESSAGE2_DEFAULT    = 0x00,
     34    TCO_WDCNT_DEFAULT       = 0x00,
     35    TCO_TMR_DEFAULT         = 0x0004,
     36    SW_IRQ_GEN_DEFAULT      = 0x03,
     37};
     38
     39#define TCO_SECS_TO_TICKS(secs)     (((secs) * 10) / 6)
     40#define TCO_TICKS_TO_SECS(ticks)    (((ticks) * 6) / 10)
     41
     42typedef struct {
     43    const char *args;
     44    bool noreboot;
     45    QPCIDevice *dev;
     46    QPCIBar tco_io_bar;
     47    QPCIBus *bus;
     48    QTestState *qts;
     49} TestData;
     50
     51static void test_end(TestData *d)
     52{
     53    g_free(d->dev);
     54    qpci_free_pc(d->bus);
     55    qtest_quit(d->qts);
     56}
     57
     58static void test_init(TestData *d)
     59{
     60    QTestState *qs;
     61
     62    qs = qtest_initf("-machine q35 %s %s",
     63                     d->noreboot ? "" : "-global ICH9-LPC.noreboot=false",
     64                     !d->args ? "" : d->args);
     65    qtest_irq_intercept_in(qs, "ioapic");
     66
     67    d->bus = qpci_new_pc(qs, NULL);
     68    d->dev = qpci_device_find(d->bus, QPCI_DEVFN(0x1f, 0x00));
     69    g_assert(d->dev != NULL);
     70
     71    qpci_device_enable(d->dev);
     72
     73    /* set ACPI PM I/O space base address */
     74    qpci_config_writel(d->dev, ICH9_LPC_PMBASE, PM_IO_BASE_ADDR | 0x1);
     75    /* enable ACPI I/O */
     76    qpci_config_writeb(d->dev, ICH9_LPC_ACPI_CTRL, 0x80);
     77    /* set Root Complex BAR */
     78    qpci_config_writel(d->dev, ICH9_LPC_RCBA, RCBA_BASE_ADDR | 0x1);
     79
     80    d->tco_io_bar = qpci_legacy_iomap(d->dev, PM_IO_BASE_ADDR + 0x60);
     81    d->qts = qs;
     82}
     83
     84static void stop_tco(const TestData *d)
     85{
     86    uint32_t val;
     87
     88    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
     89    val |= TCO_TMR_HLT;
     90    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
     91}
     92
     93static void start_tco(const TestData *d)
     94{
     95    uint32_t val;
     96
     97    val = qpci_io_readw(d->dev, d->tco_io_bar, TCO1_CNT);
     98    val &= ~TCO_TMR_HLT;
     99    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_CNT, val);
    100}
    101
    102static void load_tco(const TestData *d)
    103{
    104    qpci_io_writew(d->dev, d->tco_io_bar, TCO_RLD, 4);
    105}
    106
    107static void set_tco_timeout(const TestData *d, uint16_t ticks)
    108{
    109    qpci_io_writew(d->dev, d->tco_io_bar, TCO_TMR, ticks);
    110}
    111
    112static void clear_tco_status(const TestData *d)
    113{
    114    qpci_io_writew(d->dev, d->tco_io_bar, TCO1_STS, 0x0008);
    115    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0002);
    116    qpci_io_writew(d->dev, d->tco_io_bar, TCO2_STS, 0x0004);
    117}
    118
    119static void reset_on_second_timeout(const TestData *td, bool enable)
    120{
    121    uint32_t val;
    122
    123    val = qtest_readl(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS);
    124    if (enable) {
    125        val &= ~ICH9_CC_GCS_NO_REBOOT;
    126    } else {
    127        val |= ICH9_CC_GCS_NO_REBOOT;
    128    }
    129    qtest_writel(td->qts, RCBA_BASE_ADDR + ICH9_CC_GCS, val);
    130}
    131
    132static void test_tco_defaults(void)
    133{
    134    TestData d;
    135
    136    d.args = NULL;
    137    d.noreboot = true;
    138    test_init(&d);
    139    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD), ==,
    140                    TCO_RLD_DEFAULT);
    141    /* TCO_DAT_IN & TCO_DAT_OUT */
    142    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_DAT_IN), ==,
    143                    (TCO_DAT_OUT_DEFAULT << 8) | TCO_DAT_IN_DEFAULT);
    144    /* TCO1_STS & TCO2_STS */
    145    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_STS), ==,
    146                    (TCO2_STS_DEFAULT << 16) | TCO1_STS_DEFAULT);
    147    /* TCO1_CNT & TCO2_CNT */
    148    g_assert_cmpint(qpci_io_readl(d.dev, d.tco_io_bar, TCO1_CNT), ==,
    149                    (TCO2_CNT_DEFAULT << 16) | TCO1_CNT_DEFAULT);
    150    /* TCO_MESSAGE1 & TCO_MESSAGE2 */
    151    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_MESSAGE1), ==,
    152                    (TCO_MESSAGE2_DEFAULT << 8) | TCO_MESSAGE1_DEFAULT);
    153    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, TCO_WDCNT), ==,
    154                    TCO_WDCNT_DEFAULT);
    155    g_assert_cmpint(qpci_io_readb(d.dev, d.tco_io_bar, SW_IRQ_GEN), ==,
    156                    SW_IRQ_GEN_DEFAULT);
    157    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO_TMR), ==,
    158                    TCO_TMR_DEFAULT);
    159    test_end(&d);
    160}
    161
    162static void test_tco_timeout(void)
    163{
    164    TestData d;
    165    const uint16_t ticks = TCO_SECS_TO_TICKS(4);
    166    uint32_t val;
    167    int ret;
    168
    169    d.args = NULL;
    170    d.noreboot = true;
    171    test_init(&d);
    172
    173    stop_tco(&d);
    174    clear_tco_status(&d);
    175    reset_on_second_timeout(&d, false);
    176    set_tco_timeout(&d, ticks);
    177    load_tco(&d);
    178    start_tco(&d);
    179    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
    180
    181    /* test first timeout */
    182    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
    183    ret = val & TCO_TIMEOUT ? 1 : 0;
    184    g_assert(ret == 1);
    185
    186    /* test clearing timeout bit */
    187    val |= TCO_TIMEOUT;
    188    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
    189    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
    190    ret = val & TCO_TIMEOUT ? 1 : 0;
    191    g_assert(ret == 0);
    192
    193    /* test second timeout */
    194    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
    195    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
    196    ret = val & TCO_TIMEOUT ? 1 : 0;
    197    g_assert(ret == 1);
    198    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
    199    ret = val & TCO_SECOND_TO_STS ? 1 : 0;
    200    g_assert(ret == 1);
    201
    202    stop_tco(&d);
    203    test_end(&d);
    204}
    205
    206static void test_tco_max_timeout(void)
    207{
    208    TestData d;
    209    const uint16_t ticks = 0xffff;
    210    uint32_t val;
    211    int ret;
    212
    213    d.args = NULL;
    214    d.noreboot = true;
    215    test_init(&d);
    216
    217    stop_tco(&d);
    218    clear_tco_status(&d);
    219    reset_on_second_timeout(&d, false);
    220    set_tco_timeout(&d, ticks);
    221    load_tco(&d);
    222    start_tco(&d);
    223    qtest_clock_step(d.qts, ((ticks & TCO_TMR_MASK) - 1) * TCO_TICK_NSEC);
    224
    225    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD);
    226    g_assert_cmpint(val & TCO_RLD_MASK, ==, 1);
    227    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
    228    ret = val & TCO_TIMEOUT ? 1 : 0;
    229    g_assert(ret == 0);
    230    qtest_clock_step(d.qts, TCO_TICK_NSEC);
    231    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
    232    ret = val & TCO_TIMEOUT ? 1 : 0;
    233    g_assert(ret == 1);
    234
    235    stop_tco(&d);
    236    test_end(&d);
    237}
    238
    239static QDict *get_watchdog_action(const TestData *td)
    240{
    241    QDict *ev = qtest_qmp_eventwait_ref(td->qts, "WATCHDOG");
    242    QDict *data;
    243
    244    data = qdict_get_qdict(ev, "data");
    245    qobject_ref(data);
    246    qobject_unref(ev);
    247    return data;
    248}
    249
    250static void test_tco_second_timeout_pause(void)
    251{
    252    TestData td;
    253    const uint16_t ticks = TCO_SECS_TO_TICKS(32);
    254    QDict *ad;
    255
    256    td.args = "-watchdog-action pause";
    257    td.noreboot = false;
    258    test_init(&td);
    259
    260    stop_tco(&td);
    261    clear_tco_status(&td);
    262    reset_on_second_timeout(&td, true);
    263    set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
    264    load_tco(&td);
    265    start_tco(&td);
    266    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
    267    ad = get_watchdog_action(&td);
    268    g_assert(!strcmp(qdict_get_str(ad, "action"), "pause"));
    269    qobject_unref(ad);
    270
    271    stop_tco(&td);
    272    test_end(&td);
    273}
    274
    275static void test_tco_second_timeout_reset(void)
    276{
    277    TestData td;
    278    const uint16_t ticks = TCO_SECS_TO_TICKS(16);
    279    QDict *ad;
    280
    281    td.args = "-watchdog-action reset";
    282    td.noreboot = false;
    283    test_init(&td);
    284
    285    stop_tco(&td);
    286    clear_tco_status(&td);
    287    reset_on_second_timeout(&td, true);
    288    set_tco_timeout(&td, TCO_SECS_TO_TICKS(16));
    289    load_tco(&td);
    290    start_tco(&td);
    291    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
    292    ad = get_watchdog_action(&td);
    293    g_assert(!strcmp(qdict_get_str(ad, "action"), "reset"));
    294    qobject_unref(ad);
    295
    296    stop_tco(&td);
    297    test_end(&td);
    298}
    299
    300static void test_tco_second_timeout_shutdown(void)
    301{
    302    TestData td;
    303    const uint16_t ticks = TCO_SECS_TO_TICKS(128);
    304    QDict *ad;
    305
    306    td.args = "-watchdog-action shutdown";
    307    td.noreboot = false;
    308    test_init(&td);
    309
    310    stop_tco(&td);
    311    clear_tco_status(&td);
    312    reset_on_second_timeout(&td, true);
    313    set_tco_timeout(&td, ticks);
    314    load_tco(&td);
    315    start_tco(&td);
    316    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
    317    ad = get_watchdog_action(&td);
    318    g_assert(!strcmp(qdict_get_str(ad, "action"), "shutdown"));
    319    qobject_unref(ad);
    320
    321    stop_tco(&td);
    322    test_end(&td);
    323}
    324
    325static void test_tco_second_timeout_none(void)
    326{
    327    TestData td;
    328    const uint16_t ticks = TCO_SECS_TO_TICKS(256);
    329    QDict *ad;
    330
    331    td.args = "-watchdog-action none";
    332    td.noreboot = false;
    333    test_init(&td);
    334
    335    stop_tco(&td);
    336    clear_tco_status(&td);
    337    reset_on_second_timeout(&td, true);
    338    set_tco_timeout(&td, ticks);
    339    load_tco(&td);
    340    start_tco(&td);
    341    qtest_clock_step(td.qts, ticks * TCO_TICK_NSEC * 2);
    342    ad = get_watchdog_action(&td);
    343    g_assert(!strcmp(qdict_get_str(ad, "action"), "none"));
    344    qobject_unref(ad);
    345
    346    stop_tco(&td);
    347    test_end(&td);
    348}
    349
    350static void test_tco_ticks_counter(void)
    351{
    352    TestData d;
    353    uint16_t ticks = TCO_SECS_TO_TICKS(8);
    354    uint16_t rld;
    355
    356    d.args = NULL;
    357    d.noreboot = true;
    358    test_init(&d);
    359
    360    stop_tco(&d);
    361    clear_tco_status(&d);
    362    reset_on_second_timeout(&d, false);
    363    set_tco_timeout(&d, ticks);
    364    load_tco(&d);
    365    start_tco(&d);
    366
    367    do {
    368        rld = qpci_io_readw(d.dev, d.tco_io_bar, TCO_RLD) & TCO_RLD_MASK;
    369        g_assert_cmpint(rld, ==, ticks);
    370        qtest_clock_step(d.qts, TCO_TICK_NSEC);
    371        ticks--;
    372    } while (!(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS) & TCO_TIMEOUT));
    373
    374    stop_tco(&d);
    375    test_end(&d);
    376}
    377
    378static void test_tco1_control_bits(void)
    379{
    380    TestData d;
    381    uint16_t val;
    382
    383    d.args = NULL;
    384    d.noreboot = true;
    385    test_init(&d);
    386
    387    val = TCO_LOCK;
    388    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
    389    val &= ~TCO_LOCK;
    390    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_CNT, val);
    391    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_CNT), ==,
    392                    TCO_LOCK);
    393    test_end(&d);
    394}
    395
    396static void test_tco1_status_bits(void)
    397{
    398    TestData d;
    399    uint16_t ticks = 8;
    400    uint16_t val;
    401    int ret;
    402
    403    d.args = NULL;
    404    d.noreboot = true;
    405    test_init(&d);
    406
    407    stop_tco(&d);
    408    clear_tco_status(&d);
    409    reset_on_second_timeout(&d, false);
    410    set_tco_timeout(&d, ticks);
    411    load_tco(&d);
    412    start_tco(&d);
    413    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC);
    414
    415    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_IN, 0);
    416    qpci_io_writeb(d.dev, d.tco_io_bar, TCO_DAT_OUT, 0);
    417    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS);
    418    ret = val & (TCO_TIMEOUT | SW_TCO_SMI | TCO_INT_STS) ? 1 : 0;
    419    g_assert(ret == 1);
    420    qpci_io_writew(d.dev, d.tco_io_bar, TCO1_STS, val);
    421    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO1_STS), ==, 0);
    422    test_end(&d);
    423}
    424
    425static void test_tco2_status_bits(void)
    426{
    427    TestData d;
    428    uint16_t ticks = 8;
    429    uint16_t val;
    430    int ret;
    431
    432    d.args = NULL;
    433    d.noreboot = true;
    434    test_init(&d);
    435
    436    stop_tco(&d);
    437    clear_tco_status(&d);
    438    reset_on_second_timeout(&d, true);
    439    set_tco_timeout(&d, ticks);
    440    load_tco(&d);
    441    start_tco(&d);
    442    qtest_clock_step(d.qts, ticks * TCO_TICK_NSEC * 2);
    443
    444    val = qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS);
    445    ret = val & (TCO_SECOND_TO_STS | TCO_BOOT_STS) ? 1 : 0;
    446    g_assert(ret == 1);
    447    qpci_io_writew(d.dev, d.tco_io_bar, TCO2_STS, val);
    448    g_assert_cmpint(qpci_io_readw(d.dev, d.tco_io_bar, TCO2_STS), ==, 0);
    449    test_end(&d);
    450}
    451
    452int main(int argc, char **argv)
    453{
    454    g_test_init(&argc, &argv, NULL);
    455
    456    qtest_add_func("tco/defaults", test_tco_defaults);
    457    qtest_add_func("tco/timeout/no_action", test_tco_timeout);
    458    qtest_add_func("tco/timeout/no_action/max", test_tco_max_timeout);
    459    qtest_add_func("tco/second_timeout/pause", test_tco_second_timeout_pause);
    460    qtest_add_func("tco/second_timeout/reset", test_tco_second_timeout_reset);
    461    qtest_add_func("tco/second_timeout/shutdown",
    462                   test_tco_second_timeout_shutdown);
    463    qtest_add_func("tco/second_timeout/none", test_tco_second_timeout_none);
    464    qtest_add_func("tco/counter", test_tco_ticks_counter);
    465    qtest_add_func("tco/tco1_control/bits", test_tco1_control_bits);
    466    qtest_add_func("tco/tco1_status/bits", test_tco1_status_bits);
    467    qtest_add_func("tco/tco2_status/bits", test_tco2_status_bits);
    468    return g_test_run();
    469}