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

npcm7xx_smbus-test.c (16045B)


      1/*
      2 * QTests for Nuvoton NPCM7xx SMBus Modules.
      3 *
      4 * Copyright 2020 Google LLC
      5 *
      6 * This program is free software; you can redistribute it and/or modify it
      7 * under the terms of the GNU General Public License as published by the
      8 * Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful, but WITHOUT
     12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
     14 * for more details.
     15 */
     16
     17#include "qemu/osdep.h"
     18#include "qemu/bitops.h"
     19#include "libqos/i2c.h"
     20#include "libqos/libqtest.h"
     21#include "hw/sensor/tmp105_regs.h"
     22
     23#define NR_SMBUS_DEVICES    16
     24#define SMBUS_ADDR(x)       (0xf0080000 + 0x1000 * (x))
     25#define SMBUS_IRQ(x)        (64 + (x))
     26
     27#define EVB_DEVICE_ADDR     0x48
     28#define INVALID_DEVICE_ADDR 0x01
     29
     30const int evb_bus_list[] = {0, 1, 2, 6};
     31
     32/* Offsets */
     33enum CommonRegister {
     34    OFFSET_SDA     = 0x0,
     35    OFFSET_ST      = 0x2,
     36    OFFSET_CST     = 0x4,
     37    OFFSET_CTL1    = 0x6,
     38    OFFSET_ADDR1   = 0x8,
     39    OFFSET_CTL2    = 0xa,
     40    OFFSET_ADDR2   = 0xc,
     41    OFFSET_CTL3    = 0xe,
     42    OFFSET_CST2    = 0x18,
     43    OFFSET_CST3    = 0x19,
     44};
     45
     46enum NPCM7xxSMBusBank0Register {
     47    OFFSET_ADDR3   = 0x10,
     48    OFFSET_ADDR7   = 0x11,
     49    OFFSET_ADDR4   = 0x12,
     50    OFFSET_ADDR8   = 0x13,
     51    OFFSET_ADDR5   = 0x14,
     52    OFFSET_ADDR9   = 0x15,
     53    OFFSET_ADDR6   = 0x16,
     54    OFFSET_ADDR10  = 0x17,
     55    OFFSET_CTL4    = 0x1a,
     56    OFFSET_CTL5    = 0x1b,
     57    OFFSET_SCLLT   = 0x1c,
     58    OFFSET_FIF_CTL = 0x1d,
     59    OFFSET_SCLHT   = 0x1e,
     60};
     61
     62enum NPCM7xxSMBusBank1Register {
     63    OFFSET_FIF_CTS  = 0x10,
     64    OFFSET_FAIR_PER = 0x11,
     65    OFFSET_TXF_CTL  = 0x12,
     66    OFFSET_T_OUT    = 0x14,
     67    OFFSET_TXF_STS  = 0x1a,
     68    OFFSET_RXF_STS  = 0x1c,
     69    OFFSET_RXF_CTL  = 0x1e,
     70};
     71
     72/* ST fields */
     73#define ST_STP              BIT(7)
     74#define ST_SDAST            BIT(6)
     75#define ST_BER              BIT(5)
     76#define ST_NEGACK           BIT(4)
     77#define ST_STASTR           BIT(3)
     78#define ST_NMATCH           BIT(2)
     79#define ST_MODE             BIT(1)
     80#define ST_XMIT             BIT(0)
     81
     82/* CST fields */
     83#define CST_ARPMATCH        BIT(7)
     84#define CST_MATCHAF         BIT(6)
     85#define CST_TGSCL           BIT(5)
     86#define CST_TSDA            BIT(4)
     87#define CST_GCMATCH         BIT(3)
     88#define CST_MATCH           BIT(2)
     89#define CST_BB              BIT(1)
     90#define CST_BUSY            BIT(0)
     91
     92/* CST2 fields */
     93#define CST2_INSTTS         BIT(7)
     94#define CST2_MATCH7F        BIT(6)
     95#define CST2_MATCH6F        BIT(5)
     96#define CST2_MATCH5F        BIT(4)
     97#define CST2_MATCH4F        BIT(3)
     98#define CST2_MATCH3F        BIT(2)
     99#define CST2_MATCH2F        BIT(1)
    100#define CST2_MATCH1F        BIT(0)
    101
    102/* CST3 fields */
    103#define CST3_EO_BUSY        BIT(7)
    104#define CST3_MATCH10F       BIT(2)
    105#define CST3_MATCH9F        BIT(1)
    106#define CST3_MATCH8F        BIT(0)
    107
    108/* CTL1 fields */
    109#define CTL1_STASTRE        BIT(7)
    110#define CTL1_NMINTE         BIT(6)
    111#define CTL1_GCMEN          BIT(5)
    112#define CTL1_ACK            BIT(4)
    113#define CTL1_EOBINTE        BIT(3)
    114#define CTL1_INTEN          BIT(2)
    115#define CTL1_STOP           BIT(1)
    116#define CTL1_START          BIT(0)
    117
    118/* CTL2 fields */
    119#define CTL2_SCLFRQ(rv)     extract8((rv), 1, 6)
    120#define CTL2_ENABLE         BIT(0)
    121
    122/* CTL3 fields */
    123#define CTL3_SCL_LVL        BIT(7)
    124#define CTL3_SDA_LVL        BIT(6)
    125#define CTL3_BNK_SEL        BIT(5)
    126#define CTL3_400K_MODE      BIT(4)
    127#define CTL3_IDL_START      BIT(3)
    128#define CTL3_ARPMEN         BIT(2)
    129#define CTL3_SCLFRQ(rv)     extract8((rv), 0, 2)
    130
    131/* ADDR fields */
    132#define ADDR_EN             BIT(7)
    133#define ADDR_A(rv)          extract8((rv), 0, 6)
    134
    135/* FIF_CTL fields */
    136#define FIF_CTL_FIFO_EN         BIT(4)
    137
    138/* FIF_CTS fields */
    139#define FIF_CTS_CLR_FIFO        BIT(6)
    140#define FIF_CTS_RFTE_IE         BIT(3)
    141#define FIF_CTS_RXF_TXE         BIT(1)
    142
    143/* TXF_CTL fields */
    144#define TXF_CTL_THR_TXIE        BIT(6)
    145#define TXF_CTL_TX_THR(rv)      extract8((rv), 0, 5)
    146
    147/* TXF_STS fields */
    148#define TXF_STS_TX_THST         BIT(6)
    149#define TXF_STS_TX_BYTES(rv)    extract8((rv), 0, 5)
    150
    151/* RXF_CTL fields */
    152#define RXF_CTL_THR_RXIE        BIT(6)
    153#define RXF_CTL_LAST            BIT(5)
    154#define RXF_CTL_RX_THR(rv)      extract8((rv), 0, 5)
    155
    156/* RXF_STS fields */
    157#define RXF_STS_RX_THST         BIT(6)
    158#define RXF_STS_RX_BYTES(rv)    extract8((rv), 0, 5)
    159
    160
    161static void choose_bank(QTestState *qts, uint64_t base_addr, uint8_t bank)
    162{
    163    uint8_t ctl3 = qtest_readb(qts, base_addr + OFFSET_CTL3);
    164
    165    if (bank) {
    166        ctl3 |= CTL3_BNK_SEL;
    167    } else {
    168        ctl3 &= ~CTL3_BNK_SEL;
    169    }
    170
    171    qtest_writeb(qts, base_addr + OFFSET_CTL3, ctl3);
    172}
    173
    174static void check_running(QTestState *qts, uint64_t base_addr)
    175{
    176    g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
    177    g_assert_true(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
    178}
    179
    180static void check_stopped(QTestState *qts, uint64_t base_addr)
    181{
    182    uint8_t cst3;
    183
    184    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
    185    g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BUSY);
    186    g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST) & CST_BB);
    187
    188    cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
    189    g_assert_true(cst3 & CST3_EO_BUSY);
    190    qtest_writeb(qts, base_addr + OFFSET_CST3, cst3);
    191    cst3 = qtest_readb(qts, base_addr + OFFSET_CST3);
    192    g_assert_false(cst3 & CST3_EO_BUSY);
    193}
    194
    195static void enable_bus(QTestState *qts, uint64_t base_addr)
    196{
    197    uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
    198
    199    ctl2 |= CTL2_ENABLE;
    200    qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
    201    g_assert_true(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
    202}
    203
    204static void disable_bus(QTestState *qts, uint64_t base_addr)
    205{
    206    uint8_t ctl2 = qtest_readb(qts, base_addr + OFFSET_CTL2);
    207
    208    ctl2 &= ~CTL2_ENABLE;
    209    qtest_writeb(qts, base_addr + OFFSET_CTL2, ctl2);
    210    g_assert_false(qtest_readb(qts, base_addr + OFFSET_CTL2) & CTL2_ENABLE);
    211}
    212
    213static void start_transfer(QTestState *qts, uint64_t base_addr)
    214{
    215    uint8_t ctl1;
    216
    217    ctl1 = CTL1_START | CTL1_INTEN | CTL1_STASTRE;
    218    qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
    219    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==,
    220                    CTL1_INTEN | CTL1_STASTRE | CTL1_INTEN);
    221    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
    222                    ST_MODE | ST_XMIT | ST_SDAST);
    223    check_running(qts, base_addr);
    224}
    225
    226static void stop_transfer(QTestState *qts, uint64_t base_addr)
    227{
    228    uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
    229
    230    ctl1 &= ~(CTL1_START | CTL1_ACK);
    231    ctl1 |= CTL1_STOP | CTL1_INTEN | CTL1_EOBINTE;
    232    qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
    233    ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
    234    g_assert_false(ctl1 & CTL1_STOP);
    235}
    236
    237static void send_byte(QTestState *qts, uint64_t base_addr, uint8_t byte)
    238{
    239    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==,
    240                    ST_MODE | ST_XMIT | ST_SDAST);
    241    qtest_writeb(qts, base_addr + OFFSET_SDA, byte);
    242}
    243
    244static bool check_recv(QTestState *qts, uint64_t base_addr)
    245{
    246    uint8_t st, fif_ctl, rxf_ctl, rxf_sts;
    247    bool fifo;
    248
    249    st = qtest_readb(qts, base_addr + OFFSET_ST);
    250    choose_bank(qts, base_addr, 0);
    251    fif_ctl = qtest_readb(qts, base_addr + OFFSET_FIF_CTL);
    252    fifo = fif_ctl & FIF_CTL_FIFO_EN;
    253    if (!fifo) {
    254        return st == (ST_MODE | ST_SDAST);
    255    }
    256
    257    choose_bank(qts, base_addr, 1);
    258    rxf_ctl = qtest_readb(qts, base_addr + OFFSET_RXF_CTL);
    259    rxf_sts = qtest_readb(qts, base_addr + OFFSET_RXF_STS);
    260
    261    if ((rxf_ctl & RXF_CTL_THR_RXIE) && RXF_STS_RX_BYTES(rxf_sts) < 16) {
    262        return st == ST_MODE;
    263    } else {
    264        return st == (ST_MODE | ST_SDAST);
    265    }
    266}
    267
    268static uint8_t recv_byte(QTestState *qts, uint64_t base_addr)
    269{
    270    g_assert_true(check_recv(qts, base_addr));
    271    return qtest_readb(qts, base_addr + OFFSET_SDA);
    272}
    273
    274static void send_address(QTestState *qts, uint64_t base_addr, uint8_t addr,
    275                         bool recv, bool valid)
    276{
    277    uint8_t encoded_addr = (addr << 1) | (recv ? 1 : 0);
    278    uint8_t st;
    279
    280    qtest_writeb(qts, base_addr + OFFSET_SDA, encoded_addr);
    281    st = qtest_readb(qts, base_addr + OFFSET_ST);
    282
    283    if (valid) {
    284        if (recv) {
    285            g_assert_cmphex(st, ==, ST_MODE | ST_SDAST | ST_STASTR);
    286        } else {
    287            g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST | ST_STASTR);
    288        }
    289
    290        qtest_writeb(qts, base_addr + OFFSET_ST, ST_STASTR);
    291        st = qtest_readb(qts, base_addr + OFFSET_ST);
    292        if (recv) {
    293            g_assert_true(check_recv(qts, base_addr));
    294        } else {
    295            g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_SDAST);
    296        }
    297    } else {
    298        if (recv) {
    299            g_assert_cmphex(st, ==, ST_MODE | ST_NEGACK);
    300        } else {
    301            g_assert_cmphex(st, ==, ST_MODE | ST_XMIT | ST_NEGACK);
    302        }
    303    }
    304}
    305
    306static void send_nack(QTestState *qts, uint64_t base_addr)
    307{
    308    uint8_t ctl1 = qtest_readb(qts, base_addr + OFFSET_CTL1);
    309
    310    ctl1 &= ~(CTL1_START | CTL1_STOP);
    311    ctl1 |= CTL1_ACK | CTL1_INTEN;
    312    qtest_writeb(qts, base_addr + OFFSET_CTL1, ctl1);
    313}
    314
    315static void start_fifo_mode(QTestState *qts, uint64_t base_addr)
    316{
    317    choose_bank(qts, base_addr, 0);
    318    qtest_writeb(qts, base_addr + OFFSET_FIF_CTL, FIF_CTL_FIFO_EN);
    319    g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTL) &
    320                  FIF_CTL_FIFO_EN);
    321    choose_bank(qts, base_addr, 1);
    322    qtest_writeb(qts, base_addr + OFFSET_FIF_CTS,
    323                 FIF_CTS_CLR_FIFO | FIF_CTS_RFTE_IE);
    324    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_FIF_CTS), ==,
    325                    FIF_CTS_RFTE_IE);
    326    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_TXF_STS), ==, 0);
    327    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_RXF_STS), ==, 0);
    328}
    329
    330static void start_recv_fifo(QTestState *qts, uint64_t base_addr, uint8_t bytes)
    331{
    332    choose_bank(qts, base_addr, 1);
    333    qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, 0);
    334    qtest_writeb(qts, base_addr + OFFSET_RXF_CTL,
    335                 RXF_CTL_THR_RXIE | RXF_CTL_LAST | bytes);
    336}
    337
    338/* Check the SMBus's status is set correctly when disabled. */
    339static void test_disable_bus(gconstpointer data)
    340{
    341    intptr_t index = (intptr_t)data;
    342    uint64_t base_addr = SMBUS_ADDR(index);
    343    QTestState *qts = qtest_init("-machine npcm750-evb");
    344
    345    disable_bus(qts, base_addr);
    346    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CTL1), ==, 0);
    347    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_ST), ==, 0);
    348    g_assert_false(qtest_readb(qts, base_addr + OFFSET_CST3) & CST3_EO_BUSY);
    349    g_assert_cmphex(qtest_readb(qts, base_addr + OFFSET_CST), ==, 0);
    350    qtest_quit(qts);
    351}
    352
    353/* Check the SMBus returns a NACK for an invalid address. */
    354static void test_invalid_addr(gconstpointer data)
    355{
    356    intptr_t index = (intptr_t)data;
    357    uint64_t base_addr = SMBUS_ADDR(index);
    358    int irq = SMBUS_IRQ(index);
    359    QTestState *qts = qtest_init("-machine npcm750-evb");
    360
    361    qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
    362    enable_bus(qts, base_addr);
    363    g_assert_false(qtest_get_irq(qts, irq));
    364    start_transfer(qts, base_addr);
    365    send_address(qts, base_addr, INVALID_DEVICE_ADDR, false, false);
    366    g_assert_true(qtest_get_irq(qts, irq));
    367    stop_transfer(qts, base_addr);
    368    check_running(qts, base_addr);
    369    qtest_writeb(qts, base_addr + OFFSET_ST, ST_NEGACK);
    370    g_assert_false(qtest_readb(qts, base_addr + OFFSET_ST) & ST_NEGACK);
    371    check_stopped(qts, base_addr);
    372    qtest_quit(qts);
    373}
    374
    375/* Check the SMBus can send and receive bytes to a device in single mode. */
    376static void test_single_mode(gconstpointer data)
    377{
    378    intptr_t index = (intptr_t)data;
    379    uint64_t base_addr = SMBUS_ADDR(index);
    380    int irq = SMBUS_IRQ(index);
    381    uint8_t value = 0x60;
    382    QTestState *qts = qtest_init("-machine npcm750-evb");
    383
    384    qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
    385    enable_bus(qts, base_addr);
    386
    387    /* Sending */
    388    g_assert_false(qtest_get_irq(qts, irq));
    389    start_transfer(qts, base_addr);
    390    g_assert_true(qtest_get_irq(qts, irq));
    391    send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
    392    send_byte(qts, base_addr, TMP105_REG_CONFIG);
    393    send_byte(qts, base_addr, value);
    394    stop_transfer(qts, base_addr);
    395    check_stopped(qts, base_addr);
    396
    397    /* Receiving */
    398    start_transfer(qts, base_addr);
    399    send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
    400    send_byte(qts, base_addr, TMP105_REG_CONFIG);
    401    start_transfer(qts, base_addr);
    402    send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
    403    send_nack(qts, base_addr);
    404    stop_transfer(qts, base_addr);
    405    check_running(qts, base_addr);
    406    g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
    407    check_stopped(qts, base_addr);
    408    qtest_quit(qts);
    409}
    410
    411/* Check the SMBus can send and receive bytes in FIFO mode. */
    412static void test_fifo_mode(gconstpointer data)
    413{
    414    intptr_t index = (intptr_t)data;
    415    uint64_t base_addr = SMBUS_ADDR(index);
    416    int irq = SMBUS_IRQ(index);
    417    uint8_t value = 0x60;
    418    QTestState *qts = qtest_init("-machine npcm750-evb");
    419
    420    qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
    421    enable_bus(qts, base_addr);
    422    start_fifo_mode(qts, base_addr);
    423    g_assert_false(qtest_get_irq(qts, irq));
    424
    425    /* Sending */
    426    start_transfer(qts, base_addr);
    427    send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
    428    choose_bank(qts, base_addr, 1);
    429    g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
    430                  FIF_CTS_RXF_TXE);
    431    qtest_writeb(qts, base_addr + OFFSET_TXF_CTL, TXF_CTL_THR_TXIE);
    432    send_byte(qts, base_addr, TMP105_REG_CONFIG);
    433    send_byte(qts, base_addr, value);
    434    g_assert_true(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
    435                  FIF_CTS_RXF_TXE);
    436    g_assert_true(qtest_readb(qts, base_addr + OFFSET_TXF_STS) &
    437                  TXF_STS_TX_THST);
    438    g_assert_cmpuint(TXF_STS_TX_BYTES(
    439                        qtest_readb(qts, base_addr + OFFSET_TXF_STS)), ==, 0);
    440    g_assert_true(qtest_get_irq(qts, irq));
    441    stop_transfer(qts, base_addr);
    442    check_stopped(qts, base_addr);
    443
    444    /* Receiving */
    445    start_fifo_mode(qts, base_addr);
    446    start_transfer(qts, base_addr);
    447    send_address(qts, base_addr, EVB_DEVICE_ADDR, false, true);
    448    send_byte(qts, base_addr, TMP105_REG_CONFIG);
    449    start_transfer(qts, base_addr);
    450    qtest_writeb(qts, base_addr + OFFSET_FIF_CTS, FIF_CTS_RXF_TXE);
    451    start_recv_fifo(qts, base_addr, 1);
    452    send_address(qts, base_addr, EVB_DEVICE_ADDR, true, true);
    453    g_assert_false(qtest_readb(qts, base_addr + OFFSET_FIF_CTS) &
    454                   FIF_CTS_RXF_TXE);
    455    g_assert_true(qtest_readb(qts, base_addr + OFFSET_RXF_STS) &
    456                  RXF_STS_RX_THST);
    457    g_assert_cmpuint(RXF_STS_RX_BYTES(
    458                        qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 1);
    459    send_nack(qts, base_addr);
    460    stop_transfer(qts, base_addr);
    461    check_running(qts, base_addr);
    462    g_assert_cmphex(recv_byte(qts, base_addr), ==, value);
    463    g_assert_cmpuint(RXF_STS_RX_BYTES(
    464                        qtest_readb(qts, base_addr + OFFSET_RXF_STS)), ==, 0);
    465    check_stopped(qts, base_addr);
    466    qtest_quit(qts);
    467}
    468
    469static void smbus_add_test(const char *name, int index, GTestDataFunc fn)
    470{
    471    g_autofree char *full_name = g_strdup_printf(
    472            "npcm7xx_smbus[%d]/%s", index, name);
    473    qtest_add_data_func(full_name, (void *)(intptr_t)index, fn);
    474}
    475#define add_test(name, td) smbus_add_test(#name, td, test_##name)
    476
    477int main(int argc, char **argv)
    478{
    479    int i;
    480
    481    g_test_init(&argc, &argv, NULL);
    482    g_test_set_nonfatal_assertions();
    483
    484    for (i = 0; i < NR_SMBUS_DEVICES; ++i) {
    485        add_test(disable_bus, i);
    486        add_test(invalid_addr, i);
    487    }
    488
    489    for (i = 0; i < ARRAY_SIZE(evb_bus_list); ++i) {
    490        add_test(single_mode, evb_bus_list[i]);
    491        add_test(fifo_mode, evb_bus_list[i]);
    492    }
    493
    494    return g_test_run();
    495}