bcm2835_rng.c (3966B)
1/* 2 * BCM2835 Random Number Generator emulation 3 * 4 * Copyright (C) 2017 Marcin Chojnacki <marcinch7@gmail.com> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10#include "qemu/osdep.h" 11#include "qemu/log.h" 12#include "qemu/guest-random.h" 13#include "qemu/module.h" 14#include "hw/misc/bcm2835_rng.h" 15#include "migration/vmstate.h" 16 17static uint32_t get_random_bytes(void) 18{ 19 uint32_t res; 20 21 /* 22 * On failure we don't want to return the guest a non-random 23 * value in case they're really using it for cryptographic 24 * purposes, so the best we can do is die here. 25 * This shouldn't happen unless something's broken. 26 * In theory we could implement this device's full FIFO 27 * and interrupt semantics and then just stop filling the 28 * FIFO. That's a lot of work, though, so we assume any 29 * errors are systematic problems and trust that if we didn't 30 * fail as the guest inited then we won't fail later on 31 * mid-run. 32 */ 33 qemu_guest_getrandom_nofail(&res, sizeof(res)); 34 return res; 35} 36 37static uint64_t bcm2835_rng_read(void *opaque, hwaddr offset, 38 unsigned size) 39{ 40 BCM2835RngState *s = (BCM2835RngState *)opaque; 41 uint32_t res = 0; 42 43 assert(size == 4); 44 45 switch (offset) { 46 case 0x0: /* rng_ctrl */ 47 res = s->rng_ctrl; 48 break; 49 case 0x4: /* rng_status */ 50 res = s->rng_status | (1 << 24); 51 break; 52 case 0x8: /* rng_data */ 53 res = get_random_bytes(); 54 break; 55 56 default: 57 qemu_log_mask(LOG_GUEST_ERROR, 58 "bcm2835_rng_read: Bad offset %x\n", 59 (int)offset); 60 res = 0; 61 break; 62 } 63 64 return res; 65} 66 67static void bcm2835_rng_write(void *opaque, hwaddr offset, 68 uint64_t value, unsigned size) 69{ 70 BCM2835RngState *s = (BCM2835RngState *)opaque; 71 72 assert(size == 4); 73 74 switch (offset) { 75 case 0x0: /* rng_ctrl */ 76 s->rng_ctrl = value; 77 break; 78 case 0x4: /* rng_status */ 79 /* we shouldn't let the guest write to bits [31..20] */ 80 s->rng_status &= ~0xFFFFF; /* clear 20 lower bits */ 81 s->rng_status |= value & 0xFFFFF; /* set them to new value */ 82 break; 83 84 default: 85 qemu_log_mask(LOG_GUEST_ERROR, 86 "bcm2835_rng_write: Bad offset %x\n", 87 (int)offset); 88 break; 89 } 90} 91 92static const MemoryRegionOps bcm2835_rng_ops = { 93 .read = bcm2835_rng_read, 94 .write = bcm2835_rng_write, 95 .endianness = DEVICE_NATIVE_ENDIAN, 96}; 97 98static const VMStateDescription vmstate_bcm2835_rng = { 99 .name = TYPE_BCM2835_RNG, 100 .version_id = 1, 101 .minimum_version_id = 1, 102 .fields = (VMStateField[]) { 103 VMSTATE_UINT32(rng_ctrl, BCM2835RngState), 104 VMSTATE_UINT32(rng_status, BCM2835RngState), 105 VMSTATE_END_OF_LIST() 106 } 107}; 108 109static void bcm2835_rng_init(Object *obj) 110{ 111 BCM2835RngState *s = BCM2835_RNG(obj); 112 113 memory_region_init_io(&s->iomem, obj, &bcm2835_rng_ops, s, 114 TYPE_BCM2835_RNG, 0x10); 115 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 116} 117 118static void bcm2835_rng_reset(DeviceState *dev) 119{ 120 BCM2835RngState *s = BCM2835_RNG(dev); 121 122 s->rng_ctrl = 0; 123 s->rng_status = 0; 124} 125 126static void bcm2835_rng_class_init(ObjectClass *klass, void *data) 127{ 128 DeviceClass *dc = DEVICE_CLASS(klass); 129 130 dc->reset = bcm2835_rng_reset; 131 dc->vmsd = &vmstate_bcm2835_rng; 132} 133 134static TypeInfo bcm2835_rng_info = { 135 .name = TYPE_BCM2835_RNG, 136 .parent = TYPE_SYS_BUS_DEVICE, 137 .instance_size = sizeof(BCM2835RngState), 138 .class_init = bcm2835_rng_class_init, 139 .instance_init = bcm2835_rng_init, 140}; 141 142static void bcm2835_rng_register_types(void) 143{ 144 type_register_static(&bcm2835_rng_info); 145} 146 147type_init(bcm2835_rng_register_types)