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

sifive_u_otp.c (8729B)


      1/*
      2 * QEMU SiFive U OTP (One-Time Programmable) Memory interface
      3 *
      4 * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
      5 *
      6 * Simple model of the OTP to emulate register reads made by the SDK BSP
      7 *
      8 * This program is free software; you can redistribute it and/or modify it
      9 * under the terms and conditions of the GNU General Public License,
     10 * version 2 or later, as published by the Free Software Foundation.
     11 *
     12 * This program is distributed in the hope it will be useful, but WITHOUT
     13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     15 * more details.
     16 *
     17 * You should have received a copy of the GNU General Public License along with
     18 * this program.  If not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "qapi/error.h"
     23#include "hw/qdev-properties.h"
     24#include "hw/qdev-properties-system.h"
     25#include "hw/sysbus.h"
     26#include "qemu/error-report.h"
     27#include "qemu/log.h"
     28#include "qemu/module.h"
     29#include "hw/misc/sifive_u_otp.h"
     30#include "sysemu/blockdev.h"
     31#include "sysemu/block-backend.h"
     32
     33#define WRITTEN_BIT_ON 0x1
     34
     35#define SET_FUSEARRAY_BIT(map, i, off, bit)    \
     36    map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off))
     37
     38#define GET_FUSEARRAY_BIT(map, i, off)    \
     39    ((map[i] >> off) & 0x1)
     40
     41static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
     42{
     43    SiFiveUOTPState *s = opaque;
     44
     45    switch (addr) {
     46    case SIFIVE_U_OTP_PA:
     47        return s->pa;
     48    case SIFIVE_U_OTP_PAIO:
     49        return s->paio;
     50    case SIFIVE_U_OTP_PAS:
     51        return s->pas;
     52    case SIFIVE_U_OTP_PCE:
     53        return s->pce;
     54    case SIFIVE_U_OTP_PCLK:
     55        return s->pclk;
     56    case SIFIVE_U_OTP_PDIN:
     57        return s->pdin;
     58    case SIFIVE_U_OTP_PDOUT:
     59        if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
     60            (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
     61            (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
     62
     63            /* read from backend */
     64            if (s->blk) {
     65                int32_t buf;
     66
     67                if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf,
     68                              SIFIVE_U_OTP_FUSE_WORD) < 0) {
     69                    error_report("read error index<%d>", s->pa);
     70                    return 0xff;
     71                }
     72
     73                return buf;
     74            }
     75
     76            return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
     77        } else {
     78            return 0xff;
     79        }
     80    case SIFIVE_U_OTP_PDSTB:
     81        return s->pdstb;
     82    case SIFIVE_U_OTP_PPROG:
     83        return s->pprog;
     84    case SIFIVE_U_OTP_PTC:
     85        return s->ptc;
     86    case SIFIVE_U_OTP_PTM:
     87        return s->ptm;
     88    case SIFIVE_U_OTP_PTM_REP:
     89        return s->ptm_rep;
     90    case SIFIVE_U_OTP_PTR:
     91        return s->ptr;
     92    case SIFIVE_U_OTP_PTRIM:
     93        return s->ptrim;
     94    case SIFIVE_U_OTP_PWE:
     95        return s->pwe;
     96    }
     97
     98    qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
     99                  __func__, addr);
    100    return 0;
    101}
    102
    103static void sifive_u_otp_write(void *opaque, hwaddr addr,
    104                               uint64_t val64, unsigned int size)
    105{
    106    SiFiveUOTPState *s = opaque;
    107    uint32_t val32 = (uint32_t)val64;
    108
    109    switch (addr) {
    110    case SIFIVE_U_OTP_PA:
    111        s->pa = val32 & SIFIVE_U_OTP_PA_MASK;
    112        break;
    113    case SIFIVE_U_OTP_PAIO:
    114        s->paio = val32;
    115        break;
    116    case SIFIVE_U_OTP_PAS:
    117        s->pas = val32;
    118        break;
    119    case SIFIVE_U_OTP_PCE:
    120        s->pce = val32;
    121        break;
    122    case SIFIVE_U_OTP_PCLK:
    123        s->pclk = val32;
    124        break;
    125    case SIFIVE_U_OTP_PDIN:
    126        s->pdin = val32;
    127        break;
    128    case SIFIVE_U_OTP_PDOUT:
    129        /* read-only */
    130        break;
    131    case SIFIVE_U_OTP_PDSTB:
    132        s->pdstb = val32;
    133        break;
    134    case SIFIVE_U_OTP_PPROG:
    135        s->pprog = val32;
    136        break;
    137    case SIFIVE_U_OTP_PTC:
    138        s->ptc = val32;
    139        break;
    140    case SIFIVE_U_OTP_PTM:
    141        s->ptm = val32;
    142        break;
    143    case SIFIVE_U_OTP_PTM_REP:
    144        s->ptm_rep = val32;
    145        break;
    146    case SIFIVE_U_OTP_PTR:
    147        s->ptr = val32;
    148        break;
    149    case SIFIVE_U_OTP_PTRIM:
    150        s->ptrim = val32;
    151        break;
    152    case SIFIVE_U_OTP_PWE:
    153        s->pwe = val32 & SIFIVE_U_OTP_PWE_EN;
    154
    155        /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */
    156        if (s->pwe && !s->pas) {
    157            if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) {
    158                qemu_log_mask(LOG_GUEST_ERROR,
    159                              "write once error: idx<%u>, bit<%u>\n",
    160                              s->pa, s->paio);
    161                break;
    162            }
    163
    164            /* write bit data */
    165            SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin);
    166
    167            /* write to backend */
    168            if (s->blk) {
    169                if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD,
    170                               &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD,
    171                               0) < 0) {
    172                    error_report("write error index<%d>", s->pa);
    173                }
    174            }
    175
    176            /* update written bit */
    177            SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON);
    178        }
    179
    180        break;
    181    default:
    182        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
    183                      " v=0x%x\n", __func__, addr, val32);
    184    }
    185}
    186
    187static const MemoryRegionOps sifive_u_otp_ops = {
    188    .read = sifive_u_otp_read,
    189    .write = sifive_u_otp_write,
    190    .endianness = DEVICE_NATIVE_ENDIAN,
    191    .valid = {
    192        .min_access_size = 4,
    193        .max_access_size = 4
    194    }
    195};
    196
    197static Property sifive_u_otp_properties[] = {
    198    DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
    199    DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk),
    200    DEFINE_PROP_END_OF_LIST(),
    201};
    202
    203static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
    204{
    205    SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
    206    DriveInfo *dinfo;
    207
    208    memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
    209                          TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
    210    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
    211
    212    dinfo = drive_get_next(IF_NONE);
    213    if (dinfo) {
    214        int ret;
    215        uint64_t perm;
    216        int filesize;
    217        BlockBackend *blk;
    218
    219        blk = blk_by_legacy_dinfo(dinfo);
    220        filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD;
    221        if (blk_getlength(blk) < filesize) {
    222            error_setg(errp, "OTP drive size < 16K");
    223            return;
    224        }
    225
    226        qdev_prop_set_drive_err(dev, "drive", blk, errp);
    227
    228        if (s->blk) {
    229            perm = BLK_PERM_CONSISTENT_READ |
    230                   (blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
    231            ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp);
    232            if (ret < 0) {
    233                return;
    234            }
    235
    236            if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) {
    237                error_setg(errp, "failed to read the initial flash content");
    238            }
    239        }
    240    }
    241}
    242
    243static void sifive_u_otp_reset(DeviceState *dev)
    244{
    245    SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
    246
    247    /* Initialize all fuses' initial value to 0xFFs */
    248    memset(s->fuse, 0xff, sizeof(s->fuse));
    249
    250    /* Make a valid content of serial number */
    251    s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
    252    s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
    253
    254    if (s->blk) {
    255        /* Put serial number to backend as well*/
    256        uint32_t serial_data;
    257        int index = SIFIVE_U_OTP_SERIAL_ADDR;
    258
    259        serial_data = s->serial;
    260        if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD,
    261                       &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) {
    262            error_report("write error index<%d>", index);
    263        }
    264
    265        serial_data = ~(s->serial);
    266        if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD,
    267                       &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) {
    268            error_report("write error index<%d>", index + 1);
    269        }
    270    }
    271
    272    /* Initialize write-once map */
    273    memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo));
    274}
    275
    276static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
    277{
    278    DeviceClass *dc = DEVICE_CLASS(klass);
    279
    280    device_class_set_props(dc, sifive_u_otp_properties);
    281    dc->realize = sifive_u_otp_realize;
    282    dc->reset = sifive_u_otp_reset;
    283}
    284
    285static const TypeInfo sifive_u_otp_info = {
    286    .name          = TYPE_SIFIVE_U_OTP,
    287    .parent        = TYPE_SYS_BUS_DEVICE,
    288    .instance_size = sizeof(SiFiveUOTPState),
    289    .class_init    = sifive_u_otp_class_init,
    290};
    291
    292static void sifive_u_otp_register_types(void)
    293{
    294    type_register_static(&sifive_u_otp_info);
    295}
    296
    297type_init(sifive_u_otp_register_types)