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

allwinner-sid.c (4718B)


      1/*
      2 * Allwinner Security ID emulation
      3 *
      4 * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
      5 *
      6 * This program is free software: you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the 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,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "qemu/units.h"
     22#include "hw/sysbus.h"
     23#include "migration/vmstate.h"
     24#include "qemu/log.h"
     25#include "qemu/module.h"
     26#include "qemu/guest-random.h"
     27#include "qapi/error.h"
     28#include "hw/qdev-properties.h"
     29#include "hw/qdev-properties-system.h"
     30#include "hw/misc/allwinner-sid.h"
     31#include "trace.h"
     32
     33/* SID register offsets */
     34enum {
     35    REG_PRCTL = 0x40,   /* Control */
     36    REG_RDKEY = 0x60,   /* Read Key */
     37};
     38
     39/* SID register flags */
     40enum {
     41    REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
     42    REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
     43};
     44
     45static uint64_t allwinner_sid_read(void *opaque, hwaddr offset,
     46                                   unsigned size)
     47{
     48    const AwSidState *s = AW_SID(opaque);
     49    uint64_t val = 0;
     50
     51    switch (offset) {
     52    case REG_PRCTL:    /* Control */
     53        val = s->control;
     54        break;
     55    case REG_RDKEY:    /* Read Key */
     56        val = s->rdkey;
     57        break;
     58    default:
     59        qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
     60                      __func__, (uint32_t)offset);
     61        return 0;
     62    }
     63
     64    trace_allwinner_sid_read(offset, val, size);
     65
     66    return val;
     67}
     68
     69static void allwinner_sid_write(void *opaque, hwaddr offset,
     70                                uint64_t val, unsigned size)
     71{
     72    AwSidState *s = AW_SID(opaque);
     73
     74    trace_allwinner_sid_write(offset, val, size);
     75
     76    switch (offset) {
     77    case REG_PRCTL:    /* Control */
     78        s->control = val;
     79
     80        if ((s->control & REG_PRCTL_OP_LOCK) &&
     81            (s->control & REG_PRCTL_WRITE)) {
     82            uint32_t id = s->control >> 16;
     83
     84            if (id <= sizeof(QemuUUID) - sizeof(s->rdkey)) {
     85                s->rdkey = ldl_be_p(&s->identifier.data[id]);
     86            }
     87        }
     88        s->control &= ~REG_PRCTL_WRITE;
     89        break;
     90    case REG_RDKEY:    /* Read Key */
     91        break;
     92    default:
     93        qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
     94                      __func__, (uint32_t)offset);
     95        break;
     96    }
     97}
     98
     99static const MemoryRegionOps allwinner_sid_ops = {
    100    .read = allwinner_sid_read,
    101    .write = allwinner_sid_write,
    102    .endianness = DEVICE_NATIVE_ENDIAN,
    103    .valid = {
    104        .min_access_size = 4,
    105        .max_access_size = 4,
    106    },
    107    .impl.min_access_size = 4,
    108};
    109
    110static void allwinner_sid_reset(DeviceState *dev)
    111{
    112    AwSidState *s = AW_SID(dev);
    113
    114    /* Set default values for registers */
    115    s->control = 0;
    116    s->rdkey = 0;
    117}
    118
    119static void allwinner_sid_init(Object *obj)
    120{
    121    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    122    AwSidState *s = AW_SID(obj);
    123
    124    /* Memory mapping */
    125    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sid_ops, s,
    126                           TYPE_AW_SID, 1 * KiB);
    127    sysbus_init_mmio(sbd, &s->iomem);
    128}
    129
    130static Property allwinner_sid_properties[] = {
    131    DEFINE_PROP_UUID_NODEFAULT("identifier", AwSidState, identifier),
    132    DEFINE_PROP_END_OF_LIST()
    133};
    134
    135static const VMStateDescription allwinner_sid_vmstate = {
    136    .name = "allwinner-sid",
    137    .version_id = 1,
    138    .minimum_version_id = 1,
    139    .fields = (VMStateField[]) {
    140        VMSTATE_UINT32(control, AwSidState),
    141        VMSTATE_UINT32(rdkey, AwSidState),
    142        VMSTATE_UINT8_ARRAY_V(identifier.data, AwSidState, sizeof(QemuUUID), 1),
    143        VMSTATE_END_OF_LIST()
    144    }
    145};
    146
    147static void allwinner_sid_class_init(ObjectClass *klass, void *data)
    148{
    149    DeviceClass *dc = DEVICE_CLASS(klass);
    150
    151    dc->reset = allwinner_sid_reset;
    152    dc->vmsd = &allwinner_sid_vmstate;
    153    device_class_set_props(dc, allwinner_sid_properties);
    154}
    155
    156static const TypeInfo allwinner_sid_info = {
    157    .name          = TYPE_AW_SID,
    158    .parent        = TYPE_SYS_BUS_DEVICE,
    159    .instance_init = allwinner_sid_init,
    160    .instance_size = sizeof(AwSidState),
    161    .class_init    = allwinner_sid_class_init,
    162};
    163
    164static void allwinner_sid_register(void)
    165{
    166    type_register_static(&allwinner_sid_info);
    167}
    168
    169type_init(allwinner_sid_register)