1*54a5ba13SMarcin Chojnacki /* 2*54a5ba13SMarcin Chojnacki * BCM2835 Random Number Generator emulation 3*54a5ba13SMarcin Chojnacki * 4*54a5ba13SMarcin Chojnacki * Copyright (C) 2017 Marcin Chojnacki <marcinch7@gmail.com> 5*54a5ba13SMarcin Chojnacki * 6*54a5ba13SMarcin Chojnacki * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*54a5ba13SMarcin Chojnacki * See the COPYING file in the top-level directory. 8*54a5ba13SMarcin Chojnacki */ 9*54a5ba13SMarcin Chojnacki 10*54a5ba13SMarcin Chojnacki #include "qemu/osdep.h" 11*54a5ba13SMarcin Chojnacki #include "qemu/log.h" 12*54a5ba13SMarcin Chojnacki #include "hw/misc/bcm2835_rng.h" 13*54a5ba13SMarcin Chojnacki 14*54a5ba13SMarcin Chojnacki static uint64_t bcm2835_rng_read(void *opaque, hwaddr offset, 15*54a5ba13SMarcin Chojnacki unsigned size) 16*54a5ba13SMarcin Chojnacki { 17*54a5ba13SMarcin Chojnacki BCM2835RngState *s = (BCM2835RngState *)opaque; 18*54a5ba13SMarcin Chojnacki uint32_t res = 0; 19*54a5ba13SMarcin Chojnacki 20*54a5ba13SMarcin Chojnacki assert(size == 4); 21*54a5ba13SMarcin Chojnacki 22*54a5ba13SMarcin Chojnacki switch (offset) { 23*54a5ba13SMarcin Chojnacki case 0x0: /* rng_ctrl */ 24*54a5ba13SMarcin Chojnacki res = s->rng_ctrl; 25*54a5ba13SMarcin Chojnacki break; 26*54a5ba13SMarcin Chojnacki case 0x4: /* rng_status */ 27*54a5ba13SMarcin Chojnacki res = s->rng_status | (1 << 24); 28*54a5ba13SMarcin Chojnacki break; 29*54a5ba13SMarcin Chojnacki case 0x8: /* rng_data */ 30*54a5ba13SMarcin Chojnacki res = rand(); 31*54a5ba13SMarcin Chojnacki break; 32*54a5ba13SMarcin Chojnacki 33*54a5ba13SMarcin Chojnacki default: 34*54a5ba13SMarcin Chojnacki qemu_log_mask(LOG_GUEST_ERROR, 35*54a5ba13SMarcin Chojnacki "bcm2835_rng_read: Bad offset %x\n", 36*54a5ba13SMarcin Chojnacki (int)offset); 37*54a5ba13SMarcin Chojnacki res = 0; 38*54a5ba13SMarcin Chojnacki break; 39*54a5ba13SMarcin Chojnacki } 40*54a5ba13SMarcin Chojnacki 41*54a5ba13SMarcin Chojnacki return res; 42*54a5ba13SMarcin Chojnacki } 43*54a5ba13SMarcin Chojnacki 44*54a5ba13SMarcin Chojnacki static void bcm2835_rng_write(void *opaque, hwaddr offset, 45*54a5ba13SMarcin Chojnacki uint64_t value, unsigned size) 46*54a5ba13SMarcin Chojnacki { 47*54a5ba13SMarcin Chojnacki BCM2835RngState *s = (BCM2835RngState *)opaque; 48*54a5ba13SMarcin Chojnacki 49*54a5ba13SMarcin Chojnacki assert(size == 4); 50*54a5ba13SMarcin Chojnacki 51*54a5ba13SMarcin Chojnacki switch (offset) { 52*54a5ba13SMarcin Chojnacki case 0x0: /* rng_ctrl */ 53*54a5ba13SMarcin Chojnacki s->rng_ctrl = value; 54*54a5ba13SMarcin Chojnacki break; 55*54a5ba13SMarcin Chojnacki case 0x4: /* rng_status */ 56*54a5ba13SMarcin Chojnacki /* we shouldn't let the guest write to bits [31..20] */ 57*54a5ba13SMarcin Chojnacki s->rng_status &= ~0xFFFFF; /* clear 20 lower bits */ 58*54a5ba13SMarcin Chojnacki s->rng_status |= value & 0xFFFFF; /* set them to new value */ 59*54a5ba13SMarcin Chojnacki break; 60*54a5ba13SMarcin Chojnacki 61*54a5ba13SMarcin Chojnacki default: 62*54a5ba13SMarcin Chojnacki qemu_log_mask(LOG_GUEST_ERROR, 63*54a5ba13SMarcin Chojnacki "bcm2835_rng_write: Bad offset %x\n", 64*54a5ba13SMarcin Chojnacki (int)offset); 65*54a5ba13SMarcin Chojnacki break; 66*54a5ba13SMarcin Chojnacki } 67*54a5ba13SMarcin Chojnacki } 68*54a5ba13SMarcin Chojnacki 69*54a5ba13SMarcin Chojnacki static const MemoryRegionOps bcm2835_rng_ops = { 70*54a5ba13SMarcin Chojnacki .read = bcm2835_rng_read, 71*54a5ba13SMarcin Chojnacki .write = bcm2835_rng_write, 72*54a5ba13SMarcin Chojnacki .endianness = DEVICE_NATIVE_ENDIAN, 73*54a5ba13SMarcin Chojnacki }; 74*54a5ba13SMarcin Chojnacki 75*54a5ba13SMarcin Chojnacki static const VMStateDescription vmstate_bcm2835_rng = { 76*54a5ba13SMarcin Chojnacki .name = TYPE_BCM2835_RNG, 77*54a5ba13SMarcin Chojnacki .version_id = 1, 78*54a5ba13SMarcin Chojnacki .minimum_version_id = 1, 79*54a5ba13SMarcin Chojnacki .fields = (VMStateField[]) { 80*54a5ba13SMarcin Chojnacki VMSTATE_UINT32(rng_ctrl, BCM2835RngState), 81*54a5ba13SMarcin Chojnacki VMSTATE_UINT32(rng_status, BCM2835RngState), 82*54a5ba13SMarcin Chojnacki VMSTATE_END_OF_LIST() 83*54a5ba13SMarcin Chojnacki } 84*54a5ba13SMarcin Chojnacki }; 85*54a5ba13SMarcin Chojnacki 86*54a5ba13SMarcin Chojnacki static void bcm2835_rng_init(Object *obj) 87*54a5ba13SMarcin Chojnacki { 88*54a5ba13SMarcin Chojnacki BCM2835RngState *s = BCM2835_RNG(obj); 89*54a5ba13SMarcin Chojnacki 90*54a5ba13SMarcin Chojnacki memory_region_init_io(&s->iomem, obj, &bcm2835_rng_ops, s, 91*54a5ba13SMarcin Chojnacki TYPE_BCM2835_RNG, 0x10); 92*54a5ba13SMarcin Chojnacki sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 93*54a5ba13SMarcin Chojnacki } 94*54a5ba13SMarcin Chojnacki 95*54a5ba13SMarcin Chojnacki static void bcm2835_rng_reset(DeviceState *dev) 96*54a5ba13SMarcin Chojnacki { 97*54a5ba13SMarcin Chojnacki BCM2835RngState *s = BCM2835_RNG(dev); 98*54a5ba13SMarcin Chojnacki 99*54a5ba13SMarcin Chojnacki s->rng_ctrl = 0; 100*54a5ba13SMarcin Chojnacki s->rng_status = 0; 101*54a5ba13SMarcin Chojnacki } 102*54a5ba13SMarcin Chojnacki 103*54a5ba13SMarcin Chojnacki static void bcm2835_rng_class_init(ObjectClass *klass, void *data) 104*54a5ba13SMarcin Chojnacki { 105*54a5ba13SMarcin Chojnacki DeviceClass *dc = DEVICE_CLASS(klass); 106*54a5ba13SMarcin Chojnacki 107*54a5ba13SMarcin Chojnacki dc->reset = bcm2835_rng_reset; 108*54a5ba13SMarcin Chojnacki dc->vmsd = &vmstate_bcm2835_rng; 109*54a5ba13SMarcin Chojnacki } 110*54a5ba13SMarcin Chojnacki 111*54a5ba13SMarcin Chojnacki static TypeInfo bcm2835_rng_info = { 112*54a5ba13SMarcin Chojnacki .name = TYPE_BCM2835_RNG, 113*54a5ba13SMarcin Chojnacki .parent = TYPE_SYS_BUS_DEVICE, 114*54a5ba13SMarcin Chojnacki .instance_size = sizeof(BCM2835RngState), 115*54a5ba13SMarcin Chojnacki .class_init = bcm2835_rng_class_init, 116*54a5ba13SMarcin Chojnacki .instance_init = bcm2835_rng_init, 117*54a5ba13SMarcin Chojnacki }; 118*54a5ba13SMarcin Chojnacki 119*54a5ba13SMarcin Chojnacki static void bcm2835_rng_register_types(void) 120*54a5ba13SMarcin Chojnacki { 121*54a5ba13SMarcin Chojnacki type_register_static(&bcm2835_rng_info); 122*54a5ba13SMarcin Chojnacki } 123*54a5ba13SMarcin Chojnacki 124*54a5ba13SMarcin Chojnacki type_init(bcm2835_rng_register_types) 125