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_otp.c (13174B)


      1/*
      2 * Nuvoton NPCM7xx OTP (Fuse Array) Interface
      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
     19#include "hw/nvram/npcm7xx_otp.h"
     20#include "migration/vmstate.h"
     21#include "qapi/error.h"
     22#include "qemu/bitops.h"
     23#include "qemu/log.h"
     24#include "qemu/module.h"
     25#include "qemu/units.h"
     26
     27/* Each module has 4 KiB of register space. Only a fraction of it is used. */
     28#define NPCM7XX_OTP_REGS_SIZE (4 * KiB)
     29
     30/* 32-bit register indices. */
     31typedef enum NPCM7xxOTPRegister {
     32    NPCM7XX_OTP_FST,
     33    NPCM7XX_OTP_FADDR,
     34    NPCM7XX_OTP_FDATA,
     35    NPCM7XX_OTP_FCFG,
     36    /* Offset 0x10 is FKEYIND in OTP1, FUSTRAP in OTP2 */
     37    NPCM7XX_OTP_FKEYIND = 0x0010 / sizeof(uint32_t),
     38    NPCM7XX_OTP_FUSTRAP = 0x0010 / sizeof(uint32_t),
     39    NPCM7XX_OTP_FCTL,
     40    NPCM7XX_OTP_REGS_END,
     41} NPCM7xxOTPRegister;
     42
     43/* Register field definitions. */
     44#define FST_RIEN BIT(2)
     45#define FST_RDST BIT(1)
     46#define FST_RDY BIT(0)
     47#define FST_RO_MASK (FST_RDST | FST_RDY)
     48
     49#define FADDR_BYTEADDR(rv) extract32((rv), 0, 10)
     50#define FADDR_BITPOS(rv) extract32((rv), 10, 3)
     51
     52#define FDATA_CLEAR 0x00000001
     53
     54#define FCFG_FDIS BIT(31)
     55#define FCFG_FCFGLK_MASK 0x00ff0000
     56
     57#define FCTL_PROG_CMD1 0x00000001
     58#define FCTL_PROG_CMD2 0xbf79e5d0
     59#define FCTL_READ_CMD 0x00000002
     60
     61/**
     62 * struct NPCM7xxOTPClass - OTP module class.
     63 * @parent: System bus device class.
     64 * @mmio_ops: MMIO register operations for this type of module.
     65 *
     66 * The two OTP modules (key-storage and fuse-array) have slightly different
     67 * behavior, so we give them different MMIO register operations.
     68 */
     69struct NPCM7xxOTPClass {
     70    SysBusDeviceClass parent;
     71
     72    const MemoryRegionOps *mmio_ops;
     73};
     74
     75#define NPCM7XX_OTP_CLASS(klass) \
     76    OBJECT_CLASS_CHECK(NPCM7xxOTPClass, (klass), TYPE_NPCM7XX_OTP)
     77#define NPCM7XX_OTP_GET_CLASS(obj) \
     78    OBJECT_GET_CLASS(NPCM7xxOTPClass, (obj), TYPE_NPCM7XX_OTP)
     79
     80static uint8_t ecc_encode_nibble(uint8_t n)
     81{
     82    uint8_t result = n;
     83
     84    result |= (((n >> 0) & 1) ^ ((n >> 1) & 1)) << 4;
     85    result |= (((n >> 2) & 1) ^ ((n >> 3) & 1)) << 5;
     86    result |= (((n >> 0) & 1) ^ ((n >> 2) & 1)) << 6;
     87    result |= (((n >> 1) & 1) ^ ((n >> 3) & 1)) << 7;
     88
     89    return result;
     90}
     91
     92void npcm7xx_otp_array_write(NPCM7xxOTPState *s, const void *data,
     93                             unsigned int offset, unsigned int len)
     94{
     95    const uint8_t *src = data;
     96    uint8_t *dst = &s->array[offset];
     97
     98    while (len-- > 0) {
     99        uint8_t c = *src++;
    100
    101        *dst++ = ecc_encode_nibble(extract8(c, 0, 4));
    102        *dst++ = ecc_encode_nibble(extract8(c, 4, 4));
    103    }
    104}
    105
    106/* Common register read handler for both OTP classes. */
    107static uint64_t npcm7xx_otp_read(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg)
    108{
    109    uint32_t value = 0;
    110
    111    switch (reg) {
    112    case NPCM7XX_OTP_FST:
    113    case NPCM7XX_OTP_FADDR:
    114    case NPCM7XX_OTP_FDATA:
    115    case NPCM7XX_OTP_FCFG:
    116        value = s->regs[reg];
    117        break;
    118
    119    case NPCM7XX_OTP_FCTL:
    120        qemu_log_mask(LOG_GUEST_ERROR,
    121                      "%s: read from write-only FCTL register\n",
    122                      DEVICE(s)->canonical_path);
    123        break;
    124
    125    default:
    126        qemu_log_mask(LOG_GUEST_ERROR, "%s: read from invalid offset 0x%zx\n",
    127                      DEVICE(s)->canonical_path, reg * sizeof(uint32_t));
    128        break;
    129    }
    130
    131    return value;
    132}
    133
    134/* Read a byte from the OTP array into the data register. */
    135static void npcm7xx_otp_read_array(NPCM7xxOTPState *s)
    136{
    137    uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR];
    138
    139    s->regs[NPCM7XX_OTP_FDATA] = s->array[FADDR_BYTEADDR(faddr)];
    140    s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY;
    141}
    142
    143/* Program a byte from the data register into the OTP array. */
    144static void npcm7xx_otp_program_array(NPCM7xxOTPState *s)
    145{
    146    uint32_t faddr = s->regs[NPCM7XX_OTP_FADDR];
    147
    148    /* Bits can only go 0->1, never 1->0. */
    149    s->array[FADDR_BYTEADDR(faddr)] |= (1U << FADDR_BITPOS(faddr));
    150    s->regs[NPCM7XX_OTP_FST] |= FST_RDST | FST_RDY;
    151}
    152
    153/* Compute the next value of the FCFG register. */
    154static uint32_t npcm7xx_otp_compute_fcfg(uint32_t cur_value, uint32_t new_value)
    155{
    156    uint32_t lock_mask;
    157    uint32_t value;
    158
    159    /*
    160     * FCFGLK holds sticky bits 16..23, indicating which bits in FPRGLK (8..15)
    161     * and FRDLK (0..7) that are read-only.
    162     */
    163    lock_mask = (cur_value & FCFG_FCFGLK_MASK) >> 8;
    164    lock_mask |= lock_mask >> 8;
    165    /* FDIS and FCFGLK bits are sticky (write 1 to set; can't clear). */
    166    value = cur_value & (FCFG_FDIS | FCFG_FCFGLK_MASK);
    167    /* Preserve read-only bits in FPRGLK and FRDLK */
    168    value |= cur_value & lock_mask;
    169    /* Set all bits that aren't read-only. */
    170    value |= new_value & ~lock_mask;
    171
    172    return value;
    173}
    174
    175/* Common register write handler for both OTP classes. */
    176static void npcm7xx_otp_write(NPCM7xxOTPState *s, NPCM7xxOTPRegister reg,
    177                              uint32_t value)
    178{
    179    switch (reg) {
    180    case NPCM7XX_OTP_FST:
    181        /* RDST is cleared by writing 1 to it. */
    182        if (value & FST_RDST) {
    183            s->regs[NPCM7XX_OTP_FST] &= ~FST_RDST;
    184        }
    185        /* Preserve read-only and write-one-to-clear bits */
    186        value &= ~FST_RO_MASK;
    187        value |= s->regs[NPCM7XX_OTP_FST] & FST_RO_MASK;
    188        break;
    189
    190    case NPCM7XX_OTP_FADDR:
    191        break;
    192
    193    case NPCM7XX_OTP_FDATA:
    194        /*
    195         * This register is cleared by writing a magic value to it; no other
    196         * values can be written.
    197         */
    198        if (value == FDATA_CLEAR) {
    199            value = 0;
    200        } else {
    201            value = s->regs[NPCM7XX_OTP_FDATA];
    202        }
    203        break;
    204
    205    case NPCM7XX_OTP_FCFG:
    206        value = npcm7xx_otp_compute_fcfg(s->regs[NPCM7XX_OTP_FCFG], value);
    207        break;
    208
    209    case NPCM7XX_OTP_FCTL:
    210        switch (value) {
    211        case FCTL_READ_CMD:
    212            npcm7xx_otp_read_array(s);
    213            break;
    214
    215        case FCTL_PROG_CMD1:
    216            /*
    217             * Programming requires writing two separate magic values to this
    218             * register; this is the first one. Just store it so it can be
    219             * verified later when the second magic value is received.
    220             */
    221            break;
    222
    223        case FCTL_PROG_CMD2:
    224            /*
    225             * Only initiate programming if we received the first half of the
    226             * command immediately before this one.
    227             */
    228            if (s->regs[NPCM7XX_OTP_FCTL] == FCTL_PROG_CMD1) {
    229                npcm7xx_otp_program_array(s);
    230            }
    231            break;
    232
    233        default:
    234            qemu_log_mask(LOG_GUEST_ERROR,
    235                          "%s: unrecognized FCNTL value 0x%" PRIx32 "\n",
    236                          DEVICE(s)->canonical_path, value);
    237            break;
    238        }
    239        if (value != FCTL_PROG_CMD1) {
    240            value = 0;
    241        }
    242        break;
    243
    244    default:
    245        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to invalid offset 0x%zx\n",
    246                      DEVICE(s)->canonical_path, reg * sizeof(uint32_t));
    247        return;
    248    }
    249
    250    s->regs[reg] = value;
    251}
    252
    253/* Register read handler specific to the fuse array OTP module. */
    254static uint64_t npcm7xx_fuse_array_read(void *opaque, hwaddr addr,
    255                                        unsigned int size)
    256{
    257    NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
    258    NPCM7xxOTPState *s = opaque;
    259    uint32_t value;
    260
    261    /*
    262     * Only the Fuse Strap register needs special handling; all other registers
    263     * work the same way for both kinds of OTP modules.
    264     */
    265    if (reg != NPCM7XX_OTP_FUSTRAP) {
    266        value = npcm7xx_otp_read(s, reg);
    267    } else {
    268        /* FUSTRAP is stored as three copies in the OTP array. */
    269        uint32_t fustrap[3];
    270
    271        memcpy(fustrap, &s->array[0], sizeof(fustrap));
    272
    273        /* Determine value by a majority vote on each bit. */
    274        value = (fustrap[0] & fustrap[1]) | (fustrap[0] & fustrap[2]) |
    275                (fustrap[1] & fustrap[2]);
    276    }
    277
    278    return value;
    279}
    280
    281/* Register write handler specific to the fuse array OTP module. */
    282static void npcm7xx_fuse_array_write(void *opaque, hwaddr addr, uint64_t v,
    283                                     unsigned int size)
    284{
    285    NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
    286    NPCM7xxOTPState *s = opaque;
    287
    288    /*
    289     * The Fuse Strap register is read-only. Other registers are handled by
    290     * common code.
    291     */
    292    if (reg != NPCM7XX_OTP_FUSTRAP) {
    293        npcm7xx_otp_write(s, reg, v);
    294    }
    295}
    296
    297static const MemoryRegionOps npcm7xx_fuse_array_ops = {
    298    .read       = npcm7xx_fuse_array_read,
    299    .write      = npcm7xx_fuse_array_write,
    300    .endianness = DEVICE_LITTLE_ENDIAN,
    301    .valid      = {
    302        .min_access_size        = 4,
    303        .max_access_size        = 4,
    304        .unaligned              = false,
    305    },
    306};
    307
    308/* Register read handler specific to the key storage OTP module. */
    309static uint64_t npcm7xx_key_storage_read(void *opaque, hwaddr addr,
    310                                         unsigned int size)
    311{
    312    NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
    313    NPCM7xxOTPState *s = opaque;
    314
    315    /*
    316     * Only the Fuse Key Index register needs special handling; all other
    317     * registers work the same way for both kinds of OTP modules.
    318     */
    319    if (reg != NPCM7XX_OTP_FKEYIND) {
    320        return npcm7xx_otp_read(s, reg);
    321    }
    322
    323    qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__);
    324
    325    return s->regs[NPCM7XX_OTP_FKEYIND];
    326}
    327
    328/* Register write handler specific to the key storage OTP module. */
    329static void npcm7xx_key_storage_write(void *opaque, hwaddr addr, uint64_t v,
    330                                      unsigned int size)
    331{
    332    NPCM7xxOTPRegister reg = addr / sizeof(uint32_t);
    333    NPCM7xxOTPState *s = opaque;
    334
    335    /*
    336     * Only the Fuse Key Index register needs special handling; all other
    337     * registers work the same way for both kinds of OTP modules.
    338     */
    339    if (reg != NPCM7XX_OTP_FKEYIND) {
    340        npcm7xx_otp_write(s, reg, v);
    341        return;
    342    }
    343
    344    qemu_log_mask(LOG_UNIMP, "%s: FKEYIND is not implemented\n", __func__);
    345
    346    s->regs[NPCM7XX_OTP_FKEYIND] = v;
    347}
    348
    349static const MemoryRegionOps npcm7xx_key_storage_ops = {
    350    .read       = npcm7xx_key_storage_read,
    351    .write      = npcm7xx_key_storage_write,
    352    .endianness = DEVICE_LITTLE_ENDIAN,
    353    .valid      = {
    354        .min_access_size        = 4,
    355        .max_access_size        = 4,
    356        .unaligned              = false,
    357    },
    358};
    359
    360static void npcm7xx_otp_enter_reset(Object *obj, ResetType type)
    361{
    362    NPCM7xxOTPState *s = NPCM7XX_OTP(obj);
    363
    364    memset(s->regs, 0, sizeof(s->regs));
    365
    366    s->regs[NPCM7XX_OTP_FST] = 0x00000001;
    367    s->regs[NPCM7XX_OTP_FCFG] = 0x20000000;
    368}
    369
    370static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
    371{
    372    NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
    373    NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
    374    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    375
    376    memset(s->array, 0, sizeof(s->array));
    377
    378    memory_region_init_io(&s->mmio, OBJECT(s), oc->mmio_ops, s, "regs",
    379                          NPCM7XX_OTP_REGS_SIZE);
    380    sysbus_init_mmio(sbd, &s->mmio);
    381}
    382
    383static const VMStateDescription vmstate_npcm7xx_otp = {
    384    .name = "npcm7xx-otp",
    385    .version_id = 0,
    386    .minimum_version_id = 0,
    387    .fields = (VMStateField[]) {
    388        VMSTATE_UINT32_ARRAY(regs, NPCM7xxOTPState, NPCM7XX_OTP_NR_REGS),
    389        VMSTATE_UINT8_ARRAY(array, NPCM7xxOTPState, NPCM7XX_OTP_ARRAY_BYTES),
    390        VMSTATE_END_OF_LIST(),
    391    },
    392};
    393
    394static void npcm7xx_otp_class_init(ObjectClass *klass, void *data)
    395{
    396    ResettableClass *rc = RESETTABLE_CLASS(klass);
    397    DeviceClass *dc = DEVICE_CLASS(klass);
    398
    399    QEMU_BUILD_BUG_ON(NPCM7XX_OTP_REGS_END > NPCM7XX_OTP_NR_REGS);
    400
    401    dc->realize = npcm7xx_otp_realize;
    402    dc->vmsd = &vmstate_npcm7xx_otp;
    403    rc->phases.enter = npcm7xx_otp_enter_reset;
    404}
    405
    406static void npcm7xx_key_storage_class_init(ObjectClass *klass, void *data)
    407{
    408    NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
    409
    410    oc->mmio_ops = &npcm7xx_key_storage_ops;
    411}
    412
    413static void npcm7xx_fuse_array_class_init(ObjectClass *klass, void *data)
    414{
    415    NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass);
    416
    417    oc->mmio_ops = &npcm7xx_fuse_array_ops;
    418}
    419
    420static const TypeInfo npcm7xx_otp_types[] = {
    421    {
    422        .name = TYPE_NPCM7XX_OTP,
    423        .parent = TYPE_SYS_BUS_DEVICE,
    424        .instance_size = sizeof(NPCM7xxOTPState),
    425        .class_size = sizeof(NPCM7xxOTPClass),
    426        .class_init = npcm7xx_otp_class_init,
    427        .abstract = true,
    428    },
    429    {
    430        .name = TYPE_NPCM7XX_KEY_STORAGE,
    431        .parent = TYPE_NPCM7XX_OTP,
    432        .class_init = npcm7xx_key_storage_class_init,
    433    },
    434    {
    435        .name = TYPE_NPCM7XX_FUSE_ARRAY,
    436        .parent = TYPE_NPCM7XX_OTP,
    437        .class_init = npcm7xx_fuse_array_class_init,
    438    },
    439};
    440DEFINE_TYPES(npcm7xx_otp_types);