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