qemu

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

npcm7xx_rng.c (5154B)


      1 /*
      2  * Nuvoton NPCM7xx Random Number Generator.
      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/misc/npcm7xx_rng.h"
     20 #include "migration/vmstate.h"
     21 #include "qemu/bitops.h"
     22 #include "qemu/guest-random.h"
     23 #include "qemu/log.h"
     24 #include "qemu/module.h"
     25 #include "qemu/units.h"
     26 
     27 #include "trace.h"
     28 
     29 #define NPCM7XX_RNG_REGS_SIZE   (4 * KiB)
     30 
     31 #define NPCM7XX_RNGCS           (0x00)
     32 #define NPCM7XX_RNGCS_CLKP(rv)      extract32(rv, 2, 4)
     33 #define NPCM7XX_RNGCS_DVALID        BIT(1)
     34 #define NPCM7XX_RNGCS_RNGE          BIT(0)
     35 
     36 #define NPCM7XX_RNGD            (0x04)
     37 #define NPCM7XX_RNGMODE         (0x08)
     38 #define NPCM7XX_RNGMODE_NORMAL      (0x02)
     39 
     40 static bool npcm7xx_rng_is_enabled(NPCM7xxRNGState *s)
     41 {
     42     return (s->rngcs & NPCM7XX_RNGCS_RNGE) &&
     43         (s->rngmode == NPCM7XX_RNGMODE_NORMAL);
     44 }
     45 
     46 static uint64_t npcm7xx_rng_read(void *opaque, hwaddr offset, unsigned size)
     47 {
     48     NPCM7xxRNGState *s = opaque;
     49     uint64_t value = 0;
     50 
     51     switch (offset) {
     52     case NPCM7XX_RNGCS:
     53         /*
     54          * If the RNG is enabled, but we don't have any valid random data, try
     55          * obtaining some and update the DVALID bit accordingly.
     56          */
     57         if (!npcm7xx_rng_is_enabled(s)) {
     58             s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
     59         } else if (!(s->rngcs & NPCM7XX_RNGCS_DVALID)) {
     60             uint8_t byte = 0;
     61 
     62             if (qemu_guest_getrandom(&byte, sizeof(byte), NULL) == 0) {
     63                 s->rngd = byte;
     64                 s->rngcs |= NPCM7XX_RNGCS_DVALID;
     65             }
     66         }
     67         value = s->rngcs;
     68         break;
     69     case NPCM7XX_RNGD:
     70         if (npcm7xx_rng_is_enabled(s) && s->rngcs & NPCM7XX_RNGCS_DVALID) {
     71             s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
     72             value = s->rngd;
     73             s->rngd = 0;
     74         }
     75         break;
     76     case NPCM7XX_RNGMODE:
     77         value = s->rngmode;
     78         break;
     79 
     80     default:
     81         qemu_log_mask(LOG_GUEST_ERROR,
     82                       "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
     83                       DEVICE(s)->canonical_path, offset);
     84         break;
     85     }
     86 
     87     trace_npcm7xx_rng_read(offset, value, size);
     88 
     89     return value;
     90 }
     91 
     92 static void npcm7xx_rng_write(void *opaque, hwaddr offset, uint64_t value,
     93                               unsigned size)
     94 {
     95     NPCM7xxRNGState *s = opaque;
     96 
     97     trace_npcm7xx_rng_write(offset, value, size);
     98 
     99     switch (offset) {
    100     case NPCM7XX_RNGCS:
    101         s->rngcs &= NPCM7XX_RNGCS_DVALID;
    102         s->rngcs |= value & ~NPCM7XX_RNGCS_DVALID;
    103         break;
    104     case NPCM7XX_RNGD:
    105         qemu_log_mask(LOG_GUEST_ERROR,
    106                       "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
    107                       DEVICE(s)->canonical_path, offset);
    108         break;
    109     case NPCM7XX_RNGMODE:
    110         s->rngmode = value;
    111         break;
    112     default:
    113         qemu_log_mask(LOG_GUEST_ERROR,
    114                       "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
    115                       DEVICE(s)->canonical_path, offset);
    116         break;
    117     }
    118 }
    119 
    120 static const MemoryRegionOps npcm7xx_rng_ops = {
    121     .read = npcm7xx_rng_read,
    122     .write = npcm7xx_rng_write,
    123     .endianness = DEVICE_LITTLE_ENDIAN,
    124     .valid = {
    125         .min_access_size = 1,
    126         .max_access_size = 4,
    127         .unaligned = false,
    128     },
    129 };
    130 
    131 static void npcm7xx_rng_enter_reset(Object *obj, ResetType type)
    132 {
    133     NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
    134 
    135     s->rngcs = 0;
    136     s->rngd = 0;
    137     s->rngmode = 0;
    138 }
    139 
    140 static void npcm7xx_rng_init(Object *obj)
    141 {
    142     NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
    143 
    144     memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
    145                           NPCM7XX_RNG_REGS_SIZE);
    146     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
    147 }
    148 
    149 static const VMStateDescription vmstate_npcm7xx_rng = {
    150     .name = "npcm7xx-rng",
    151     .version_id = 0,
    152     .minimum_version_id = 0,
    153     .fields = (VMStateField[]) {
    154         VMSTATE_UINT8(rngcs, NPCM7xxRNGState),
    155         VMSTATE_UINT8(rngd, NPCM7xxRNGState),
    156         VMSTATE_UINT8(rngmode, NPCM7xxRNGState),
    157         VMSTATE_END_OF_LIST(),
    158     },
    159 };
    160 
    161 static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
    162 {
    163     ResettableClass *rc = RESETTABLE_CLASS(klass);
    164     DeviceClass *dc = DEVICE_CLASS(klass);
    165 
    166     dc->desc = "NPCM7xx Random Number Generator";
    167     dc->vmsd = &vmstate_npcm7xx_rng;
    168     rc->phases.enter = npcm7xx_rng_enter_reset;
    169 }
    170 
    171 static const TypeInfo npcm7xx_rng_types[] = {
    172     {
    173         .name = TYPE_NPCM7XX_RNG,
    174         .parent = TYPE_SYS_BUS_DEVICE,
    175         .instance_size = sizeof(NPCM7xxRNGState),
    176         .class_init = npcm7xx_rng_class_init,
    177         .instance_init = npcm7xx_rng_init,
    178     },
    179 };
    180 DEFINE_TYPES(npcm7xx_rng_types);