17
#include "qemu/osdep.h"
19
#include "hw/misc/npcm7xx_rng.h"
20
#include "migration/vmstate.h"
21
#include "qemu/bitops.h"
22
#include "qemu/guest-random.h"
24
#include "qemu/module.h"
25
#include "qemu/units.h"
29
#define NPCM7XX_RNG_REGS_SIZE (4 * KiB)
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)
36
#define NPCM7XX_RNGD (0x04)
37
#define NPCM7XX_RNGMODE (0x08)
38
#define NPCM7XX_RNGMODE_NORMAL (0x02)
40
static bool npcm7xx_rng_is_enabled(NPCM7xxRNGState *s)
42
return (s->rngcs & NPCM7XX_RNGCS_RNGE) &&
43
(s->rngmode == NPCM7XX_RNGMODE_NORMAL);
46
static uint64_t npcm7xx_rng_read(void *opaque, hwaddr offset, unsigned size)
48
NPCM7xxRNGState *s = opaque;
57
if (!npcm7xx_rng_is_enabled(s)) {
58
s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
59
} else if (!(s->rngcs & NPCM7XX_RNGCS_DVALID)) {
62
if (qemu_guest_getrandom(&byte, sizeof(byte), NULL) == 0) {
64
s->rngcs |= NPCM7XX_RNGCS_DVALID;
70
if (npcm7xx_rng_is_enabled(s) && s->rngcs & NPCM7XX_RNGCS_DVALID) {
71
s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
81
qemu_log_mask(LOG_GUEST_ERROR,
82
"%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
83
DEVICE(s)->canonical_path, offset);
87
trace_npcm7xx_rng_read(offset, value, size);
92
static void npcm7xx_rng_write(void *opaque, hwaddr offset, uint64_t value,
95
NPCM7xxRNGState *s = opaque;
97
trace_npcm7xx_rng_write(offset, value, size);
101
s->rngcs &= NPCM7XX_RNGCS_DVALID;
102
s->rngcs |= value & ~NPCM7XX_RNGCS_DVALID;
105
qemu_log_mask(LOG_GUEST_ERROR,
106
"%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
107
DEVICE(s)->canonical_path, offset);
109
case NPCM7XX_RNGMODE:
113
qemu_log_mask(LOG_GUEST_ERROR,
114
"%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
115
DEVICE(s)->canonical_path, offset);
120
static const MemoryRegionOps npcm7xx_rng_ops = {
121
.read = npcm7xx_rng_read,
122
.write = npcm7xx_rng_write,
123
.endianness = DEVICE_LITTLE_ENDIAN,
125
.min_access_size = 1,
126
.max_access_size = 4,
131
static void npcm7xx_rng_enter_reset(Object *obj, ResetType type)
133
NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
140
static void npcm7xx_rng_init(Object *obj)
142
NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
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);
149
static const VMStateDescription vmstate_npcm7xx_rng = {
150
.name = "npcm7xx-rng",
152
.minimum_version_id = 0,
153
.fields = (const VMStateField[]) {
154
VMSTATE_UINT8(rngcs, NPCM7xxRNGState),
155
VMSTATE_UINT8(rngd, NPCM7xxRNGState),
156
VMSTATE_UINT8(rngmode, NPCM7xxRNGState),
157
VMSTATE_END_OF_LIST(),
161
static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
163
ResettableClass *rc = RESETTABLE_CLASS(klass);
164
DeviceClass *dc = DEVICE_CLASS(klass);
166
dc->desc = "NPCM7xx Random Number Generator";
167
dc->vmsd = &vmstate_npcm7xx_rng;
168
rc->phases.enter = npcm7xx_rng_enter_reset;
171
static const TypeInfo npcm7xx_rng_types[] = {
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,
180
DEFINE_TYPES(npcm7xx_rng_types);