154a5ba13SMarcin Chojnacki /* 254a5ba13SMarcin Chojnacki * BCM2835 Random Number Generator emulation 354a5ba13SMarcin Chojnacki * 454a5ba13SMarcin Chojnacki * Copyright (C) 2017 Marcin Chojnacki <marcinch7@gmail.com> 554a5ba13SMarcin Chojnacki * 654a5ba13SMarcin Chojnacki * This work is licensed under the terms of the GNU GPL, version 2 or later. 754a5ba13SMarcin Chojnacki * See the COPYING file in the top-level directory. 854a5ba13SMarcin Chojnacki */ 954a5ba13SMarcin Chojnacki 1054a5ba13SMarcin Chojnacki #include "qemu/osdep.h" 1154a5ba13SMarcin Chojnacki #include "qemu/log.h" 12*3090c980SRichard Henderson #include "qemu/guest-random.h" 1354a5ba13SMarcin Chojnacki #include "hw/misc/bcm2835_rng.h" 1454a5ba13SMarcin Chojnacki 15373442eaSPeter Maydell static uint32_t get_random_bytes(void) 16373442eaSPeter Maydell { 17373442eaSPeter Maydell uint32_t res; 18373442eaSPeter Maydell 19*3090c980SRichard Henderson /* 20*3090c980SRichard Henderson * On failure we don't want to return the guest a non-random 21373442eaSPeter Maydell * value in case they're really using it for cryptographic 22373442eaSPeter Maydell * purposes, so the best we can do is die here. 23373442eaSPeter Maydell * This shouldn't happen unless something's broken. 24373442eaSPeter Maydell * In theory we could implement this device's full FIFO 25373442eaSPeter Maydell * and interrupt semantics and then just stop filling the 26373442eaSPeter Maydell * FIFO. That's a lot of work, though, so we assume any 27373442eaSPeter Maydell * errors are systematic problems and trust that if we didn't 28373442eaSPeter Maydell * fail as the guest inited then we won't fail later on 29373442eaSPeter Maydell * mid-run. 30373442eaSPeter Maydell */ 31*3090c980SRichard Henderson qemu_guest_getrandom_nofail(&res, sizeof(res)); 32373442eaSPeter Maydell return res; 33373442eaSPeter Maydell } 34373442eaSPeter Maydell 3554a5ba13SMarcin Chojnacki static uint64_t bcm2835_rng_read(void *opaque, hwaddr offset, 3654a5ba13SMarcin Chojnacki unsigned size) 3754a5ba13SMarcin Chojnacki { 3854a5ba13SMarcin Chojnacki BCM2835RngState *s = (BCM2835RngState *)opaque; 3954a5ba13SMarcin Chojnacki uint32_t res = 0; 4054a5ba13SMarcin Chojnacki 4154a5ba13SMarcin Chojnacki assert(size == 4); 4254a5ba13SMarcin Chojnacki 4354a5ba13SMarcin Chojnacki switch (offset) { 4454a5ba13SMarcin Chojnacki case 0x0: /* rng_ctrl */ 4554a5ba13SMarcin Chojnacki res = s->rng_ctrl; 4654a5ba13SMarcin Chojnacki break; 4754a5ba13SMarcin Chojnacki case 0x4: /* rng_status */ 4854a5ba13SMarcin Chojnacki res = s->rng_status | (1 << 24); 4954a5ba13SMarcin Chojnacki break; 5054a5ba13SMarcin Chojnacki case 0x8: /* rng_data */ 51373442eaSPeter Maydell res = get_random_bytes(); 5254a5ba13SMarcin Chojnacki break; 5354a5ba13SMarcin Chojnacki 5454a5ba13SMarcin Chojnacki default: 5554a5ba13SMarcin Chojnacki qemu_log_mask(LOG_GUEST_ERROR, 5654a5ba13SMarcin Chojnacki "bcm2835_rng_read: Bad offset %x\n", 5754a5ba13SMarcin Chojnacki (int)offset); 5854a5ba13SMarcin Chojnacki res = 0; 5954a5ba13SMarcin Chojnacki break; 6054a5ba13SMarcin Chojnacki } 6154a5ba13SMarcin Chojnacki 6254a5ba13SMarcin Chojnacki return res; 6354a5ba13SMarcin Chojnacki } 6454a5ba13SMarcin Chojnacki 6554a5ba13SMarcin Chojnacki static void bcm2835_rng_write(void *opaque, hwaddr offset, 6654a5ba13SMarcin Chojnacki uint64_t value, unsigned size) 6754a5ba13SMarcin Chojnacki { 6854a5ba13SMarcin Chojnacki BCM2835RngState *s = (BCM2835RngState *)opaque; 6954a5ba13SMarcin Chojnacki 7054a5ba13SMarcin Chojnacki assert(size == 4); 7154a5ba13SMarcin Chojnacki 7254a5ba13SMarcin Chojnacki switch (offset) { 7354a5ba13SMarcin Chojnacki case 0x0: /* rng_ctrl */ 7454a5ba13SMarcin Chojnacki s->rng_ctrl = value; 7554a5ba13SMarcin Chojnacki break; 7654a5ba13SMarcin Chojnacki case 0x4: /* rng_status */ 7754a5ba13SMarcin Chojnacki /* we shouldn't let the guest write to bits [31..20] */ 7854a5ba13SMarcin Chojnacki s->rng_status &= ~0xFFFFF; /* clear 20 lower bits */ 7954a5ba13SMarcin Chojnacki s->rng_status |= value & 0xFFFFF; /* set them to new value */ 8054a5ba13SMarcin Chojnacki break; 8154a5ba13SMarcin Chojnacki 8254a5ba13SMarcin Chojnacki default: 8354a5ba13SMarcin Chojnacki qemu_log_mask(LOG_GUEST_ERROR, 8454a5ba13SMarcin Chojnacki "bcm2835_rng_write: Bad offset %x\n", 8554a5ba13SMarcin Chojnacki (int)offset); 8654a5ba13SMarcin Chojnacki break; 8754a5ba13SMarcin Chojnacki } 8854a5ba13SMarcin Chojnacki } 8954a5ba13SMarcin Chojnacki 9054a5ba13SMarcin Chojnacki static const MemoryRegionOps bcm2835_rng_ops = { 9154a5ba13SMarcin Chojnacki .read = bcm2835_rng_read, 9254a5ba13SMarcin Chojnacki .write = bcm2835_rng_write, 9354a5ba13SMarcin Chojnacki .endianness = DEVICE_NATIVE_ENDIAN, 9454a5ba13SMarcin Chojnacki }; 9554a5ba13SMarcin Chojnacki 9654a5ba13SMarcin Chojnacki static const VMStateDescription vmstate_bcm2835_rng = { 9754a5ba13SMarcin Chojnacki .name = TYPE_BCM2835_RNG, 9854a5ba13SMarcin Chojnacki .version_id = 1, 9954a5ba13SMarcin Chojnacki .minimum_version_id = 1, 10054a5ba13SMarcin Chojnacki .fields = (VMStateField[]) { 10154a5ba13SMarcin Chojnacki VMSTATE_UINT32(rng_ctrl, BCM2835RngState), 10254a5ba13SMarcin Chojnacki VMSTATE_UINT32(rng_status, BCM2835RngState), 10354a5ba13SMarcin Chojnacki VMSTATE_END_OF_LIST() 10454a5ba13SMarcin Chojnacki } 10554a5ba13SMarcin Chojnacki }; 10654a5ba13SMarcin Chojnacki 10754a5ba13SMarcin Chojnacki static void bcm2835_rng_init(Object *obj) 10854a5ba13SMarcin Chojnacki { 10954a5ba13SMarcin Chojnacki BCM2835RngState *s = BCM2835_RNG(obj); 11054a5ba13SMarcin Chojnacki 11154a5ba13SMarcin Chojnacki memory_region_init_io(&s->iomem, obj, &bcm2835_rng_ops, s, 11254a5ba13SMarcin Chojnacki TYPE_BCM2835_RNG, 0x10); 11354a5ba13SMarcin Chojnacki sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 11454a5ba13SMarcin Chojnacki } 11554a5ba13SMarcin Chojnacki 11654a5ba13SMarcin Chojnacki static void bcm2835_rng_reset(DeviceState *dev) 11754a5ba13SMarcin Chojnacki { 11854a5ba13SMarcin Chojnacki BCM2835RngState *s = BCM2835_RNG(dev); 11954a5ba13SMarcin Chojnacki 12054a5ba13SMarcin Chojnacki s->rng_ctrl = 0; 12154a5ba13SMarcin Chojnacki s->rng_status = 0; 12254a5ba13SMarcin Chojnacki } 12354a5ba13SMarcin Chojnacki 12454a5ba13SMarcin Chojnacki static void bcm2835_rng_class_init(ObjectClass *klass, void *data) 12554a5ba13SMarcin Chojnacki { 12654a5ba13SMarcin Chojnacki DeviceClass *dc = DEVICE_CLASS(klass); 12754a5ba13SMarcin Chojnacki 12854a5ba13SMarcin Chojnacki dc->reset = bcm2835_rng_reset; 12954a5ba13SMarcin Chojnacki dc->vmsd = &vmstate_bcm2835_rng; 13054a5ba13SMarcin Chojnacki } 13154a5ba13SMarcin Chojnacki 13254a5ba13SMarcin Chojnacki static TypeInfo bcm2835_rng_info = { 13354a5ba13SMarcin Chojnacki .name = TYPE_BCM2835_RNG, 13454a5ba13SMarcin Chojnacki .parent = TYPE_SYS_BUS_DEVICE, 13554a5ba13SMarcin Chojnacki .instance_size = sizeof(BCM2835RngState), 13654a5ba13SMarcin Chojnacki .class_init = bcm2835_rng_class_init, 13754a5ba13SMarcin Chojnacki .instance_init = bcm2835_rng_init, 13854a5ba13SMarcin Chojnacki }; 13954a5ba13SMarcin Chojnacki 14054a5ba13SMarcin Chojnacki static void bcm2835_rng_register_types(void) 14154a5ba13SMarcin Chojnacki { 14254a5ba13SMarcin Chojnacki type_register_static(&bcm2835_rng_info); 14354a5ba13SMarcin Chojnacki } 14454a5ba13SMarcin Chojnacki 14554a5ba13SMarcin Chojnacki type_init(bcm2835_rng_register_types) 146