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

aspeed_smc-test.c (10449B)


      1/*
      2 * QTest testcase for the M25P80 Flash (Using the Aspeed SPI
      3 * Controller)
      4 *
      5 * Copyright (C) 2016 IBM Corp.
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a copy
      8 * of this software and associated documentation files (the "Software"), to deal
      9 * in the Software without restriction, including without limitation the rights
     10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 * copies of the Software, and to permit persons to whom the Software is
     12 * furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in
     15 * all copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23 * THE SOFTWARE.
     24 */
     25
     26#include "qemu/osdep.h"
     27#include "qemu/bswap.h"
     28#include "libqtest-single.h"
     29
     30/*
     31 * ASPEED SPI Controller registers
     32 */
     33#define R_CONF              0x00
     34#define   CONF_ENABLE_W0       (1 << 16)
     35#define R_CE_CTRL           0x04
     36#define   CRTL_EXTENDED0       0  /* 32 bit addressing for SPI */
     37#define R_CTRL0             0x10
     38#define   CTRL_CE_STOP_ACTIVE  (1 << 2)
     39#define   CTRL_READMODE        0x0
     40#define   CTRL_FREADMODE       0x1
     41#define   CTRL_WRITEMODE       0x2
     42#define   CTRL_USERMODE        0x3
     43
     44#define ASPEED_FMC_BASE    0x1E620000
     45#define ASPEED_FLASH_BASE  0x20000000
     46
     47/*
     48 * Flash commands
     49 */
     50enum {
     51    JEDEC_READ = 0x9f,
     52    BULK_ERASE = 0xc7,
     53    READ = 0x03,
     54    PP = 0x02,
     55    WREN = 0x6,
     56    RESET_ENABLE = 0x66,
     57    RESET_MEMORY = 0x99,
     58    EN_4BYTE_ADDR = 0xB7,
     59    ERASE_SECTOR = 0xd8,
     60};
     61
     62#define FLASH_JEDEC         0x20ba19  /* n25q256a */
     63#define FLASH_SIZE          (32 * 1024 * 1024)
     64
     65#define FLASH_PAGE_SIZE           256
     66
     67/*
     68 * Use an explicit bswap for the values read/wrote to the flash region
     69 * as they are BE and the Aspeed CPU is LE.
     70 */
     71static inline uint32_t make_be32(uint32_t data)
     72{
     73    return bswap32(data);
     74}
     75
     76static void spi_conf(uint32_t value)
     77{
     78    uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
     79
     80    conf |= value;
     81    writel(ASPEED_FMC_BASE + R_CONF, conf);
     82}
     83
     84static void spi_conf_remove(uint32_t value)
     85{
     86    uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF);
     87
     88    conf &= ~value;
     89    writel(ASPEED_FMC_BASE + R_CONF, conf);
     90}
     91
     92static void spi_ce_ctrl(uint32_t value)
     93{
     94    uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL);
     95
     96    conf |= value;
     97    writel(ASPEED_FMC_BASE + R_CE_CTRL, conf);
     98}
     99
    100static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd)
    101{
    102    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
    103    ctrl &= ~(CTRL_USERMODE | 0xff << 16);
    104    ctrl |= mode | (cmd << 16);
    105    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
    106}
    107
    108static void spi_ctrl_start_user(void)
    109{
    110    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
    111
    112    ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
    113    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
    114
    115    ctrl &= ~CTRL_CE_STOP_ACTIVE;
    116    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
    117}
    118
    119static void spi_ctrl_stop_user(void)
    120{
    121    uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0);
    122
    123    ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
    124    writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
    125}
    126
    127static void flash_reset(void)
    128{
    129    spi_conf(CONF_ENABLE_W0);
    130
    131    spi_ctrl_start_user();
    132    writeb(ASPEED_FLASH_BASE, RESET_ENABLE);
    133    writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
    134    spi_ctrl_stop_user();
    135
    136    spi_conf_remove(CONF_ENABLE_W0);
    137}
    138
    139static void test_read_jedec(void)
    140{
    141    uint32_t jedec = 0x0;
    142
    143    spi_conf(CONF_ENABLE_W0);
    144
    145    spi_ctrl_start_user();
    146    writeb(ASPEED_FLASH_BASE, JEDEC_READ);
    147    jedec |= readb(ASPEED_FLASH_BASE) << 16;
    148    jedec |= readb(ASPEED_FLASH_BASE) << 8;
    149    jedec |= readb(ASPEED_FLASH_BASE);
    150    spi_ctrl_stop_user();
    151
    152    flash_reset();
    153
    154    g_assert_cmphex(jedec, ==, FLASH_JEDEC);
    155}
    156
    157static void read_page(uint32_t addr, uint32_t *page)
    158{
    159    int i;
    160
    161    spi_ctrl_start_user();
    162
    163    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
    164    writeb(ASPEED_FLASH_BASE, READ);
    165    writel(ASPEED_FLASH_BASE, make_be32(addr));
    166
    167    /* Continuous read are supported */
    168    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    169        page[i] = make_be32(readl(ASPEED_FLASH_BASE));
    170    }
    171    spi_ctrl_stop_user();
    172}
    173
    174static void read_page_mem(uint32_t addr, uint32_t *page)
    175{
    176    int i;
    177
    178    /* move out USER mode to use direct reads from the AHB bus */
    179    spi_ctrl_setmode(CTRL_READMODE, READ);
    180
    181    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    182        page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
    183    }
    184}
    185
    186static void test_erase_sector(void)
    187{
    188    uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
    189    uint32_t page[FLASH_PAGE_SIZE / 4];
    190    int i;
    191
    192    spi_conf(CONF_ENABLE_W0);
    193
    194    spi_ctrl_start_user();
    195    writeb(ASPEED_FLASH_BASE, WREN);
    196    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
    197    writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
    198    writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
    199    spi_ctrl_stop_user();
    200
    201    /* Previous page should be full of zeroes as backend is not
    202     * initialized */
    203    read_page(some_page_addr - FLASH_PAGE_SIZE, page);
    204    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    205        g_assert_cmphex(page[i], ==, 0x0);
    206    }
    207
    208    /* But this one was erased */
    209    read_page(some_page_addr, page);
    210    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    211        g_assert_cmphex(page[i], ==, 0xffffffff);
    212    }
    213
    214    flash_reset();
    215}
    216
    217static void test_erase_all(void)
    218{
    219    uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
    220    uint32_t page[FLASH_PAGE_SIZE / 4];
    221    int i;
    222
    223    spi_conf(CONF_ENABLE_W0);
    224
    225    /* Check some random page. Should be full of zeroes as backend is
    226     * not initialized */
    227    read_page(some_page_addr, page);
    228    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    229        g_assert_cmphex(page[i], ==, 0x0);
    230    }
    231
    232    spi_ctrl_start_user();
    233    writeb(ASPEED_FLASH_BASE, WREN);
    234    writeb(ASPEED_FLASH_BASE, BULK_ERASE);
    235    spi_ctrl_stop_user();
    236
    237    /* Recheck that some random page */
    238    read_page(some_page_addr, page);
    239    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    240        g_assert_cmphex(page[i], ==, 0xffffffff);
    241    }
    242
    243    flash_reset();
    244}
    245
    246static void test_write_page(void)
    247{
    248    uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
    249    uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
    250    uint32_t page[FLASH_PAGE_SIZE / 4];
    251    int i;
    252
    253    spi_conf(CONF_ENABLE_W0);
    254
    255    spi_ctrl_start_user();
    256    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
    257    writeb(ASPEED_FLASH_BASE, WREN);
    258    writeb(ASPEED_FLASH_BASE, PP);
    259    writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
    260
    261    /* Fill the page with its own addresses */
    262    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    263        writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
    264    }
    265    spi_ctrl_stop_user();
    266
    267    /* Check what was written */
    268    read_page(my_page_addr, page);
    269    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    270        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
    271    }
    272
    273    /* Check some other page. It should be full of 0xff */
    274    read_page(some_page_addr, page);
    275    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    276        g_assert_cmphex(page[i], ==, 0xffffffff);
    277    }
    278
    279    flash_reset();
    280}
    281
    282static void test_read_page_mem(void)
    283{
    284    uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
    285    uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
    286    uint32_t page[FLASH_PAGE_SIZE / 4];
    287    int i;
    288
    289    /* Enable 4BYTE mode for controller. This is should be strapped by
    290     * HW for CE0 anyhow.
    291     */
    292    spi_ce_ctrl(1 << CRTL_EXTENDED0);
    293
    294    /* Enable 4BYTE mode for flash. */
    295    spi_conf(CONF_ENABLE_W0);
    296    spi_ctrl_start_user();
    297    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
    298    spi_ctrl_stop_user();
    299    spi_conf_remove(CONF_ENABLE_W0);
    300
    301    /* Check what was written */
    302    read_page_mem(my_page_addr, page);
    303    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    304        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
    305    }
    306
    307    /* Check some other page. It should be full of 0xff */
    308    read_page_mem(some_page_addr, page);
    309    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    310        g_assert_cmphex(page[i], ==, 0xffffffff);
    311    }
    312
    313    flash_reset();
    314}
    315
    316static void test_write_page_mem(void)
    317{
    318    uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
    319    uint32_t page[FLASH_PAGE_SIZE / 4];
    320    int i;
    321
    322    /* Enable 4BYTE mode for controller. This is should be strapped by
    323     * HW for CE0 anyhow.
    324     */
    325    spi_ce_ctrl(1 << CRTL_EXTENDED0);
    326
    327    /* Enable 4BYTE mode for flash. */
    328    spi_conf(CONF_ENABLE_W0);
    329    spi_ctrl_start_user();
    330    writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
    331    writeb(ASPEED_FLASH_BASE, WREN);
    332    spi_ctrl_stop_user();
    333
    334    /* move out USER mode to use direct writes to the AHB bus */
    335    spi_ctrl_setmode(CTRL_WRITEMODE, PP);
    336
    337    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    338        writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
    339               make_be32(my_page_addr + i * 4));
    340    }
    341
    342    /* Check what was written */
    343    read_page_mem(my_page_addr, page);
    344    for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
    345        g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
    346    }
    347
    348    flash_reset();
    349}
    350
    351static char tmp_path[] = "/tmp/qtest.m25p80.XXXXXX";
    352
    353int main(int argc, char **argv)
    354{
    355    int ret;
    356    int fd;
    357
    358    g_test_init(&argc, &argv, NULL);
    359
    360    fd = mkstemp(tmp_path);
    361    g_assert(fd >= 0);
    362    ret = ftruncate(fd, FLASH_SIZE);
    363    g_assert(ret == 0);
    364    close(fd);
    365
    366    global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
    367                               "-drive file=%s,format=raw,if=mtd",
    368                               tmp_path);
    369
    370    qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
    371    qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
    372    qtest_add_func("/ast2400/smc/erase_all",  test_erase_all);
    373    qtest_add_func("/ast2400/smc/write_page", test_write_page);
    374    qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
    375    qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
    376
    377    ret = g_test_run();
    378
    379    qtest_quit(global_qtest);
    380    unlink(tmp_path);
    381    return ret;
    382}