qemu

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

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 */
     34 enum {
     35     REG_PRCTL = 0x40,   /* Control */
     36     REG_RDKEY = 0x60,   /* Read Key */
     37 };
     38 
     39 /* SID register flags */
     40 enum {
     41     REG_PRCTL_WRITE   = 0x0002, /* Unknown write flag */
     42     REG_PRCTL_OP_LOCK = 0xAC00, /* Lock operation */
     43 };
     44 
     45 static 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 
     69 static 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 
     99 static 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 
    110 static 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 
    119 static 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 
    130 static Property allwinner_sid_properties[] = {
    131     DEFINE_PROP_UUID_NODEFAULT("identifier", AwSidState, identifier),
    132     DEFINE_PROP_END_OF_LIST()
    133 };
    134 
    135 static 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 
    147 static 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 
    156 static 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 
    164 static void allwinner_sid_register(void)
    165 {
    166     type_register_static(&allwinner_sid_info);
    167 }
    168 
    169 type_init(allwinner_sid_register)