qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

xlnx-efuse.c (8141B)


      1 /*
      2  * QEMU model of the EFUSE eFuse
      3  *
      4  * Copyright (c) 2015 Xilinx Inc.
      5  *
      6  * Written by Edgar E. Iglesias <edgari@xilinx.com>
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a copy
      9  * of this software and associated documentation files (the "Software"), to deal
     10  * in the Software without restriction, including without limitation the rights
     11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12  * copies of the Software, and to permit persons to whom the Software is
     13  * furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included in
     16  * all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     24  * THE SOFTWARE.
     25  */
     26 
     27 #include "qemu/osdep.h"
     28 #include "hw/nvram/xlnx-efuse.h"
     29 
     30 #include "qemu/error-report.h"
     31 #include "qemu/log.h"
     32 #include "qapi/error.h"
     33 #include "sysemu/blockdev.h"
     34 #include "hw/qdev-properties.h"
     35 #include "hw/qdev-properties-system.h"
     36 
     37 #define TBIT0_OFFSET     28
     38 #define TBIT1_OFFSET     29
     39 #define TBIT2_OFFSET     30
     40 #define TBIT3_OFFSET     31
     41 #define TBITS_PATTERN    (0x0AU << TBIT0_OFFSET)
     42 #define TBITS_MASK       (0x0FU << TBIT0_OFFSET)
     43 
     44 bool xlnx_efuse_get_bit(XlnxEFuse *s, unsigned int bit)
     45 {
     46     bool b = s->fuse32[bit / 32] & (1 << (bit % 32));
     47     return b;
     48 }
     49 
     50 static int efuse_bytes(XlnxEFuse *s)
     51 {
     52     return ROUND_UP((s->efuse_nr * s->efuse_size) / 8, 4);
     53 }
     54 
     55 static int efuse_bdrv_read(XlnxEFuse *s, Error **errp)
     56 {
     57     uint32_t *ram = s->fuse32;
     58     int nr = efuse_bytes(s);
     59 
     60     if (!s->blk) {
     61         return 0;
     62     }
     63 
     64     s->blk_ro = !blk_supports_write_perm(s->blk);
     65     if (!s->blk_ro) {
     66         int rc;
     67 
     68         rc = blk_set_perm(s->blk,
     69                           (BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE),
     70                           BLK_PERM_ALL, NULL);
     71         if (rc) {
     72             s->blk_ro = true;
     73         }
     74     }
     75     if (s->blk_ro) {
     76         warn_report("%s: Skip saving updates to read-only eFUSE backstore.",
     77                     blk_name(s->blk));
     78     }
     79 
     80     if (blk_pread(s->blk, 0, nr, ram, 0) < 0) {
     81         error_setg(errp, "%s: Failed to read %u bytes from eFUSE backstore.",
     82                    blk_name(s->blk), nr);
     83         return -1;
     84     }
     85 
     86     /* Convert from little-endian backstore for each 32-bit row */
     87     nr /= 4;
     88     while (nr--) {
     89         ram[nr] = le32_to_cpu(ram[nr]);
     90     }
     91 
     92     return 0;
     93 }
     94 
     95 static void efuse_bdrv_sync(XlnxEFuse *s, unsigned int bit)
     96 {
     97     unsigned int row_offset;
     98     uint32_t le32;
     99 
    100     if (!s->blk || s->blk_ro) {
    101         return;  /* Silent on read-only backend to avoid message flood */
    102     }
    103 
    104     /* Backstore is always in little-endian */
    105     le32 = cpu_to_le32(xlnx_efuse_get_row(s, bit));
    106 
    107     row_offset = (bit / 32) * 4;
    108     if (blk_pwrite(s->blk, row_offset, 4, &le32, 0) < 0) {
    109         error_report("%s: Failed to write offset %u of eFUSE backstore.",
    110                      blk_name(s->blk), row_offset);
    111     }
    112 }
    113 
    114 static int efuse_ro_bits_cmp(const void *a, const void *b)
    115 {
    116     uint32_t i = *(const uint32_t *)a;
    117     uint32_t j = *(const uint32_t *)b;
    118 
    119     return (i > j) - (i < j);
    120 }
    121 
    122 static void efuse_ro_bits_sort(XlnxEFuse *s)
    123 {
    124     uint32_t *ary = s->ro_bits;
    125     const uint32_t cnt = s->ro_bits_cnt;
    126 
    127     if (ary && cnt > 1) {
    128         qsort(ary, cnt, sizeof(ary[0]), efuse_ro_bits_cmp);
    129     }
    130 }
    131 
    132 static bool efuse_ro_bits_find(XlnxEFuse *s, uint32_t k)
    133 {
    134     const uint32_t *ary = s->ro_bits;
    135     const uint32_t cnt = s->ro_bits_cnt;
    136 
    137     if (!ary || !cnt) {
    138         return false;
    139     }
    140 
    141     return bsearch(&k, ary, cnt, sizeof(ary[0]), efuse_ro_bits_cmp) != NULL;
    142 }
    143 
    144 bool xlnx_efuse_set_bit(XlnxEFuse *s, unsigned int bit)
    145 {
    146     if (efuse_ro_bits_find(s, bit)) {
    147         g_autofree char *path = object_get_canonical_path(OBJECT(s));
    148 
    149         qemu_log_mask(LOG_GUEST_ERROR, "%s: WARN: "
    150                       "Ignored setting of readonly efuse bit<%u,%u>!\n",
    151                       path, (bit / 32), (bit % 32));
    152         return false;
    153     }
    154 
    155     s->fuse32[bit / 32] |= 1 << (bit % 32);
    156     efuse_bdrv_sync(s, bit);
    157     return true;
    158 }
    159 
    160 bool xlnx_efuse_k256_check(XlnxEFuse *s, uint32_t crc, unsigned start)
    161 {
    162     uint32_t calc;
    163 
    164     /* A key always occupies multiple of whole rows */
    165     assert((start % 32) == 0);
    166 
    167     calc = xlnx_efuse_calc_crc(&s->fuse32[start / 32], (256 / 32), 0);
    168     return calc == crc;
    169 }
    170 
    171 uint32_t xlnx_efuse_tbits_check(XlnxEFuse *s)
    172 {
    173     int nr;
    174     uint32_t check = 0;
    175 
    176     for (nr = s->efuse_nr; nr-- > 0; ) {
    177         int efuse_start_row_num = (s->efuse_size * nr) / 32;
    178         uint32_t data = s->fuse32[efuse_start_row_num];
    179 
    180         /*
    181          * If the option is on, auto-init blank T-bits.
    182          * (non-blank will still be reported as '0' in the check, e.g.,
    183          *  for error-injection tests)
    184          */
    185         if ((data & TBITS_MASK) == 0 && s->init_tbits) {
    186             data |= TBITS_PATTERN;
    187 
    188             s->fuse32[efuse_start_row_num] = data;
    189             efuse_bdrv_sync(s, (efuse_start_row_num * 32 + TBIT0_OFFSET));
    190         }
    191 
    192         check = (check << 1) | ((data & TBITS_MASK) == TBITS_PATTERN);
    193     }
    194 
    195     return check;
    196 }
    197 
    198 static void efuse_realize(DeviceState *dev, Error **errp)
    199 {
    200     XlnxEFuse *s = XLNX_EFUSE(dev);
    201 
    202     /* Sort readonly-list for bsearch lookup */
    203     efuse_ro_bits_sort(s);
    204 
    205     if ((s->efuse_size % 32) != 0) {
    206         g_autofree char *path = object_get_canonical_path(OBJECT(s));
    207 
    208         error_setg(errp,
    209                    "%s.efuse-size: %u: property value not multiple of 32.",
    210                    path, s->efuse_size);
    211         return;
    212     }
    213 
    214     s->fuse32 = g_malloc0(efuse_bytes(s));
    215     if (efuse_bdrv_read(s, errp)) {
    216         g_free(s->fuse32);
    217     }
    218 }
    219 
    220 static void efuse_prop_set_drive(Object *obj, Visitor *v, const char *name,
    221                                  void *opaque, Error **errp)
    222 {
    223     DeviceState *dev = DEVICE(obj);
    224 
    225     qdev_prop_drive.set(obj, v, name, opaque, errp);
    226 
    227     /* Fill initial data if backend is attached after realized */
    228     if (dev->realized) {
    229         efuse_bdrv_read(XLNX_EFUSE(obj), errp);
    230     }
    231 }
    232 
    233 static void efuse_prop_get_drive(Object *obj, Visitor *v, const char *name,
    234                                  void *opaque, Error **errp)
    235 {
    236     qdev_prop_drive.get(obj, v, name, opaque, errp);
    237 }
    238 
    239 static void efuse_prop_release_drive(Object *obj, const char *name,
    240                                      void *opaque)
    241 {
    242     qdev_prop_drive.release(obj, name, opaque);
    243 }
    244 
    245 static const PropertyInfo efuse_prop_drive = {
    246     .name  = "str",
    247     .description = "Node name or ID of a block device to use as eFUSE backend",
    248     .realized_set_allowed = true,
    249     .get = efuse_prop_get_drive,
    250     .set = efuse_prop_set_drive,
    251     .release = efuse_prop_release_drive,
    252 };
    253 
    254 static Property efuse_properties[] = {
    255     DEFINE_PROP("drive", XlnxEFuse, blk, efuse_prop_drive, BlockBackend *),
    256     DEFINE_PROP_UINT8("efuse-nr", XlnxEFuse, efuse_nr, 3),
    257     DEFINE_PROP_UINT32("efuse-size", XlnxEFuse, efuse_size, 64 * 32),
    258     DEFINE_PROP_BOOL("init-factory-tbits", XlnxEFuse, init_tbits, true),
    259     DEFINE_PROP_ARRAY("read-only", XlnxEFuse, ro_bits_cnt, ro_bits,
    260                       qdev_prop_uint32, uint32_t),
    261     DEFINE_PROP_END_OF_LIST(),
    262 };
    263 
    264 static void efuse_class_init(ObjectClass *klass, void *data)
    265 {
    266     DeviceClass *dc = DEVICE_CLASS(klass);
    267 
    268     dc->realize = efuse_realize;
    269     device_class_set_props(dc, efuse_properties);
    270 }
    271 
    272 static const TypeInfo efuse_info = {
    273     .name          = TYPE_XLNX_EFUSE,
    274     .parent        = TYPE_DEVICE,
    275     .instance_size = sizeof(XlnxEFuse),
    276     .class_init    = efuse_class_init,
    277 };
    278 
    279 static void efuse_register_types(void)
    280 {
    281     type_register_static(&efuse_info);
    282 }
    283 type_init(efuse_register_types)