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