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

rtl8139-test.c (5238B)


      1/*
      2 * QTest testcase for Realtek 8139 NIC
      3 *
      4 * Copyright (c) 2013-2014 SUSE LINUX Products GmbH
      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#include "libqtest-single.h"
     12#include "libqos/pci-pc.h"
     13#include "qemu/timer.h"
     14#include "qemu-common.h"
     15
     16/* Tests only initialization so far. TODO: Replace with functional tests */
     17static void nop(void)
     18{
     19}
     20
     21#define CLK 33333333
     22
     23static QPCIBus *pcibus;
     24static QPCIDevice *dev;
     25static QPCIBar dev_bar;
     26
     27static void save_fn(QPCIDevice *dev, int devfn, void *data)
     28{
     29    QPCIDevice **pdev = (QPCIDevice **) data;
     30
     31    *pdev = dev;
     32}
     33
     34static QPCIDevice *get_device(void)
     35{
     36    QPCIDevice *dev;
     37
     38    pcibus = qpci_new_pc(global_qtest, NULL);
     39    qpci_device_foreach(pcibus, 0x10ec, 0x8139, save_fn, &dev);
     40    g_assert(dev != NULL);
     41
     42    return dev;
     43}
     44
     45#define PORT(name, len, val) \
     46static unsigned __attribute__((unused)) in_##name(void) \
     47{ \
     48    unsigned res = qpci_io_read##len(dev, dev_bar, (val));     \
     49    g_test_message("*%s -> %x", #name, res); \
     50    return res; \
     51} \
     52static void out_##name(unsigned v) \
     53{ \
     54    g_test_message("%x -> *%s", v, #name); \
     55    qpci_io_write##len(dev, dev_bar, (val), v);        \
     56}
     57
     58PORT(Timer, l, 0x48)
     59PORT(IntrMask, w, 0x3c)
     60PORT(IntrStatus, w, 0x3E)
     61PORT(TimerInt, l, 0x54)
     62
     63#define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0)
     64
     65static void test_timer(void)
     66{
     67    const unsigned from = 0.95 * CLK;
     68    const unsigned to = 1.6 * CLK;
     69    unsigned prev, curr, next;
     70    unsigned cnt, diff;
     71
     72    out_IntrMask(0);
     73
     74    in_IntrStatus();
     75    in_Timer();
     76    in_Timer();
     77
     78    /* Test 1. test counter continue and continue */
     79    out_TimerInt(0); /* disable timer */
     80    out_IntrStatus(0x4000);
     81    out_Timer(12345); /* reset timer to 0 */
     82    curr = in_Timer();
     83    if (curr > 0.1 * CLK) {
     84        fatal("time too big %u\n", curr);
     85    }
     86    for (cnt = 0; ; ) {
     87        clock_step(1 * NANOSECONDS_PER_SECOND);
     88        prev = curr;
     89        curr = in_Timer();
     90
     91        /* test skip is in a specific range */
     92        diff = (curr-prev) & 0xffffffffu;
     93        if (diff < from || diff > to) {
     94            fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
     95        }
     96        if (curr < prev && ++cnt == 3) {
     97            break;
     98        }
     99    }
    100
    101    /* Test 2. Check we didn't get an interrupt with TimerInt == 0 */
    102    if (in_IntrStatus() & 0x4000) {
    103        fatal("got an interrupt\n");
    104    }
    105
    106    /* Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt */
    107    out_TimerInt(1);
    108    out_Timer(0);
    109    clock_step(40);
    110    if ((in_IntrStatus() & 0x4000) == 0) {
    111        fatal("we should have an interrupt here!\n");
    112    }
    113
    114    /* Test 3. Check acknowledge */
    115    out_IntrStatus(0x4000);
    116    if (in_IntrStatus() & 0x4000) {
    117        fatal("got an interrupt\n");
    118    }
    119
    120    /* Test. Status set after Timer reset */
    121    out_Timer(0);
    122    out_TimerInt(0);
    123    out_IntrStatus(0x4000);
    124    curr = in_Timer();
    125    out_TimerInt(curr + 0.5 * CLK);
    126    clock_step(1 * NANOSECONDS_PER_SECOND);
    127    out_Timer(0);
    128    if ((in_IntrStatus() & 0x4000) == 0) {
    129        fatal("we should have an interrupt here!\n");
    130    }
    131
    132    /* Test. Status set after TimerInt reset */
    133    out_Timer(0);
    134    out_TimerInt(0);
    135    out_IntrStatus(0x4000);
    136    curr = in_Timer();
    137    out_TimerInt(curr + 0.5 * CLK);
    138    clock_step(1 * NANOSECONDS_PER_SECOND);
    139    out_TimerInt(0);
    140    if ((in_IntrStatus() & 0x4000) == 0) {
    141        fatal("we should have an interrupt here!\n");
    142    }
    143
    144    /* Test 4. Increment TimerInt we should see an interrupt */
    145    curr = in_Timer();
    146    next = curr + 5.0 * CLK;
    147    out_TimerInt(next);
    148    for (cnt = 0; ; ) {
    149        clock_step(1 * NANOSECONDS_PER_SECOND);
    150        prev = curr;
    151        curr = in_Timer();
    152        diff = (curr-prev) & 0xffffffffu;
    153        if (diff < from || diff > to) {
    154            fatal("Invalid diff %u (%u-%u)\n", diff, from, to);
    155        }
    156        if (cnt < 3 && curr > next) {
    157            if ((in_IntrStatus() & 0x4000) == 0) {
    158                fatal("we should have an interrupt here!\n");
    159            }
    160            out_IntrStatus(0x4000);
    161            next = curr + 5.0 * CLK;
    162            out_TimerInt(next);
    163            if (++cnt == 3) {
    164                out_TimerInt(1);
    165            }
    166        /* Test 5. Second time we pass from 0 should see an interrupt */
    167        } else if (cnt >= 3 && curr < prev) {
    168            /* here we should have an interrupt */
    169            if ((in_IntrStatus() & 0x4000) == 0) {
    170                fatal("we should have an interrupt here!\n");
    171            }
    172            out_IntrStatus(0x4000);
    173            if (++cnt == 5) {
    174                break;
    175            }
    176        }
    177    }
    178
    179    g_test_message("Everythink is ok!");
    180}
    181
    182
    183static void test_init(void)
    184{
    185    uint64_t barsize;
    186
    187    dev = get_device();
    188
    189    dev_bar = qpci_iomap(dev, 0, &barsize);
    190
    191    qpci_device_enable(dev);
    192
    193    test_timer();
    194}
    195
    196int main(int argc, char **argv)
    197{
    198    int ret;
    199
    200    qtest_start("-device rtl8139");
    201
    202    g_test_init(&argc, &argv, NULL);
    203    qtest_add_func("/rtl8139/nop", nop);
    204    qtest_add_func("/rtl8139/timer", test_init);
    205
    206    ret = g_test_run();
    207
    208    qtest_end();
    209
    210    return ret;
    211}