qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

target-arm: Implement BCM2835 hardware RNG

Recent vanilla Raspberry Pi kernels started to make use of
the hardware random number generator in BCM2835 SoC. As a
result, those kernels wouldn't work anymore under QEMU
but rather just freeze during the boot process.

This patch implements a trivial BCM2835 compatible RNG,
and adds it as a peripheral to BCM2835 platform, which
allows to boot a vanilla Raspberry Pi kernel under Qemu.

Changes since v1:
* Prevented guest from writing [31..20] bits in rng_status
* Removed redundant minimum_version_id_old
* Added field entries for the state
* Changed realize function to reset

Signed-off-by: Marcin Chojnacki <marcinch7@gmail.com>
Message-id: 20170210210857.47893-1-marcinch7@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Marcin Chojnacki and committed by
Peter Maydell
54a5ba13 6181478f

+169
+15
hw/arm/bcm2835_peripherals.c
··· 86 86 object_property_add_const_link(OBJECT(&s->property), "dma-mr", 87 87 OBJECT(&s->gpu_bus_mr), &error_abort); 88 88 89 + /* Random Number Generator */ 90 + object_initialize(&s->rng, sizeof(s->rng), TYPE_BCM2835_RNG); 91 + object_property_add_child(obj, "rng", OBJECT(&s->rng), NULL); 92 + qdev_set_parent_bus(DEVICE(&s->rng), sysbus_get_default()); 93 + 89 94 /* Extended Mass Media Controller */ 90 95 object_initialize(&s->sdhci, sizeof(s->sdhci), TYPE_SYSBUS_SDHCI); 91 96 object_property_add_child(obj, "sdhci", OBJECT(&s->sdhci), NULL); ··· 225 230 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->property), 0)); 226 231 sysbus_connect_irq(SYS_BUS_DEVICE(&s->property), 0, 227 232 qdev_get_gpio_in(DEVICE(&s->mboxes), MBOX_CHAN_PROPERTY)); 233 + 234 + /* Random Number Generator */ 235 + object_property_set_bool(OBJECT(&s->rng), true, "realized", &err); 236 + if (err) { 237 + error_propagate(errp, err); 238 + return; 239 + } 240 + 241 + memory_region_add_subregion(&s->peri_mr, RNG_OFFSET, 242 + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0)); 228 243 229 244 /* Extended Mass Media Controller */ 230 245 object_property_set_int(OBJECT(&s->sdhci), BCM2835_SDHC_CAPAREG, "capareg",
+1
hw/misc/Makefile.objs
··· 42 42 obj-$(CONFIG_OMAP) += omap_tap.o 43 43 obj-$(CONFIG_RASPI) += bcm2835_mbox.o 44 44 obj-$(CONFIG_RASPI) += bcm2835_property.o 45 + obj-$(CONFIG_RASPI) += bcm2835_rng.o 45 46 obj-$(CONFIG_SLAVIO) += slavio_misc.o 46 47 obj-$(CONFIG_ZYNQ) += zynq_slcr.o 47 48 obj-$(CONFIG_ZYNQ) += zynq-xadc.o
+124
hw/misc/bcm2835_rng.c
··· 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 "hw/misc/bcm2835_rng.h" 13 + 14 + static uint64_t bcm2835_rng_read(void *opaque, hwaddr offset, 15 + unsigned size) 16 + { 17 + BCM2835RngState *s = (BCM2835RngState *)opaque; 18 + uint32_t res = 0; 19 + 20 + assert(size == 4); 21 + 22 + switch (offset) { 23 + case 0x0: /* rng_ctrl */ 24 + res = s->rng_ctrl; 25 + break; 26 + case 0x4: /* rng_status */ 27 + res = s->rng_status | (1 << 24); 28 + break; 29 + case 0x8: /* rng_data */ 30 + res = rand(); 31 + break; 32 + 33 + default: 34 + qemu_log_mask(LOG_GUEST_ERROR, 35 + "bcm2835_rng_read: Bad offset %x\n", 36 + (int)offset); 37 + res = 0; 38 + break; 39 + } 40 + 41 + return res; 42 + } 43 + 44 + static void bcm2835_rng_write(void *opaque, hwaddr offset, 45 + uint64_t value, unsigned size) 46 + { 47 + BCM2835RngState *s = (BCM2835RngState *)opaque; 48 + 49 + assert(size == 4); 50 + 51 + switch (offset) { 52 + case 0x0: /* rng_ctrl */ 53 + s->rng_ctrl = value; 54 + break; 55 + case 0x4: /* rng_status */ 56 + /* we shouldn't let the guest write to bits [31..20] */ 57 + s->rng_status &= ~0xFFFFF; /* clear 20 lower bits */ 58 + s->rng_status |= value & 0xFFFFF; /* set them to new value */ 59 + break; 60 + 61 + default: 62 + qemu_log_mask(LOG_GUEST_ERROR, 63 + "bcm2835_rng_write: Bad offset %x\n", 64 + (int)offset); 65 + break; 66 + } 67 + } 68 + 69 + static const MemoryRegionOps bcm2835_rng_ops = { 70 + .read = bcm2835_rng_read, 71 + .write = bcm2835_rng_write, 72 + .endianness = DEVICE_NATIVE_ENDIAN, 73 + }; 74 + 75 + static const VMStateDescription vmstate_bcm2835_rng = { 76 + .name = TYPE_BCM2835_RNG, 77 + .version_id = 1, 78 + .minimum_version_id = 1, 79 + .fields = (VMStateField[]) { 80 + VMSTATE_UINT32(rng_ctrl, BCM2835RngState), 81 + VMSTATE_UINT32(rng_status, BCM2835RngState), 82 + VMSTATE_END_OF_LIST() 83 + } 84 + }; 85 + 86 + static void bcm2835_rng_init(Object *obj) 87 + { 88 + BCM2835RngState *s = BCM2835_RNG(obj); 89 + 90 + memory_region_init_io(&s->iomem, obj, &bcm2835_rng_ops, s, 91 + TYPE_BCM2835_RNG, 0x10); 92 + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); 93 + } 94 + 95 + static void bcm2835_rng_reset(DeviceState *dev) 96 + { 97 + BCM2835RngState *s = BCM2835_RNG(dev); 98 + 99 + s->rng_ctrl = 0; 100 + s->rng_status = 0; 101 + } 102 + 103 + static void bcm2835_rng_class_init(ObjectClass *klass, void *data) 104 + { 105 + DeviceClass *dc = DEVICE_CLASS(klass); 106 + 107 + dc->reset = bcm2835_rng_reset; 108 + dc->vmsd = &vmstate_bcm2835_rng; 109 + } 110 + 111 + static TypeInfo bcm2835_rng_info = { 112 + .name = TYPE_BCM2835_RNG, 113 + .parent = TYPE_SYS_BUS_DEVICE, 114 + .instance_size = sizeof(BCM2835RngState), 115 + .class_init = bcm2835_rng_class_init, 116 + .instance_init = bcm2835_rng_init, 117 + }; 118 + 119 + static void bcm2835_rng_register_types(void) 120 + { 121 + type_register_static(&bcm2835_rng_info); 122 + } 123 + 124 + type_init(bcm2835_rng_register_types)
+2
include/hw/arm/bcm2835_peripherals.h
··· 19 19 #include "hw/dma/bcm2835_dma.h" 20 20 #include "hw/intc/bcm2835_ic.h" 21 21 #include "hw/misc/bcm2835_property.h" 22 + #include "hw/misc/bcm2835_rng.h" 22 23 #include "hw/misc/bcm2835_mbox.h" 23 24 #include "hw/sd/sdhci.h" 24 25 ··· 41 42 BCM2835DMAState dma; 42 43 BCM2835ICState ic; 43 44 BCM2835PropertyState property; 45 + BCM2835RngState rng; 44 46 BCM2835MboxState mboxes; 45 47 SDHCIState sdhci; 46 48 } BCM2835PeripheralState;
+27
include/hw/misc/bcm2835_rng.h
··· 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 + #ifndef BCM2835_RNG_H 11 + #define BCM2835_RNG_H 12 + 13 + #include "hw/sysbus.h" 14 + 15 + #define TYPE_BCM2835_RNG "bcm2835-rng" 16 + #define BCM2835_RNG(obj) \ 17 + OBJECT_CHECK(BCM2835RngState, (obj), TYPE_BCM2835_RNG) 18 + 19 + typedef struct { 20 + SysBusDevice busdev; 21 + MemoryRegion iomem; 22 + 23 + uint32_t rng_ctrl; 24 + uint32_t rng_status; 25 + } BCM2835RngState; 26 + 27 + #endif