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