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

SiFive RISC-V GPIO Device

QEMU model of the GPIO device on the SiFive E300 series SOCs.

The pins are not used by a board definition yet, however this
implementation can already be used to trigger GPIO interrupts from the
software by configuring a pin as both output and input.

Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>

authored by

Fabien Chouteau and committed by
Palmer Dabbelt
30efbf33 a7b21f67

+501 -4
+1
Makefile.objs
··· 182 182 trace-events-subdirs += hw/watchdog 183 183 trace-events-subdirs += hw/xen 184 184 trace-events-subdirs += hw/gpio 185 + trace-events-subdirs += hw/riscv 185 186 trace-events-subdirs += migration 186 187 trace-events-subdirs += net 187 188 trace-events-subdirs += ui
+1
hw/riscv/Makefile.objs
··· 2 2 obj-$(CONFIG_HART) += riscv_hart.o 3 3 obj-$(CONFIG_SIFIVE_E) += sifive_e.o 4 4 obj-$(CONFIG_SIFIVE) += sifive_clint.o 5 + obj-$(CONFIG_SIFIVE) += sifive_gpio.o 5 6 obj-$(CONFIG_SIFIVE) += sifive_prci.o 6 7 obj-$(CONFIG_SIFIVE) += sifive_plic.o 7 8 obj-$(CONFIG_SIFIVE) += sifive_test.o
+26 -2
hw/riscv/sifive_e.c
··· 146 146 &error_abort); 147 147 object_property_set_int(OBJECT(&s->cpus), smp_cpus, "num-harts", 148 148 &error_abort); 149 + sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0", 150 + &s->gpio, sizeof(s->gpio), 151 + TYPE_SIFIVE_GPIO); 149 152 } 150 153 151 154 static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) 152 155 { 153 156 const struct MemmapEntry *memmap = sifive_e_memmap; 157 + Error *err = NULL; 154 158 155 159 SiFiveESoCState *s = RISCV_E_SOC(dev); 156 160 MemoryRegion *sys_mem = get_system_memory(); ··· 184 188 sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon", 185 189 memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); 186 190 sifive_prci_create(memmap[SIFIVE_E_PRCI].base); 187 - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.gpio0", 188 - memmap[SIFIVE_E_GPIO0].base, memmap[SIFIVE_E_GPIO0].size); 191 + 192 + /* GPIO */ 193 + 194 + object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); 195 + if (err) { 196 + error_propagate(errp, err); 197 + return; 198 + } 199 + 200 + /* Map GPIO registers */ 201 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_E_GPIO0].base); 202 + 203 + /* Pass all GPIOs to the SOC layer so they are available to the board */ 204 + qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL); 205 + 206 + /* Connect GPIO interrupts to the PLIC */ 207 + for (int i = 0; i < 32; i++) { 208 + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i, 209 + qdev_get_gpio_in(DEVICE(s->plic), 210 + SIFIVE_E_GPIO0_IRQ0 + i)); 211 + } 212 + 189 213 sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base, 190 214 serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ)); 191 215 sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0",
+388
hw/riscv/sifive_gpio.c
··· 1 + /* 2 + * sifive System-on-Chip general purpose input/output register definition 3 + * 4 + * Copyright 2019 AdaCore 5 + * 6 + * Base on nrf51_gpio.c: 7 + * 8 + * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de> 9 + * 10 + * This code is licensed under the GPL version 2 or later. See 11 + * the COPYING file in the top-level directory. 12 + */ 13 + 14 + #include "qemu/osdep.h" 15 + #include "qemu/log.h" 16 + #include "hw/riscv/sifive_gpio.h" 17 + #include "trace.h" 18 + 19 + static void update_output_irq(SIFIVEGPIOState *s) 20 + { 21 + 22 + uint32_t pending; 23 + uint32_t pin; 24 + 25 + pending = s->high_ip & s->high_ie; 26 + pending |= s->low_ip & s->low_ie; 27 + pending |= s->rise_ip & s->rise_ie; 28 + pending |= s->fall_ip & s->fall_ie; 29 + 30 + for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { 31 + pin = 1 << i; 32 + qemu_set_irq(s->irq[i], (pending & pin) != 0); 33 + trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0); 34 + } 35 + } 36 + 37 + static void update_state(SIFIVEGPIOState *s) 38 + { 39 + size_t i; 40 + bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en, 41 + rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival; 42 + 43 + for (i = 0; i < SIFIVE_GPIO_PINS; i++) { 44 + 45 + prev_ival = extract32(s->value, i, 1); 46 + in = extract32(s->in, i, 1); 47 + in_mask = extract32(s->in_mask, i, 1); 48 + port = extract32(s->port, i, 1); 49 + out_xor = extract32(s->out_xor, i, 1); 50 + pull = extract32(s->pue, i, 1); 51 + output_en = extract32(s->output_en, i, 1); 52 + input_en = extract32(s->input_en, i, 1); 53 + rise_ip = extract32(s->rise_ip, i, 1); 54 + fall_ip = extract32(s->fall_ip, i, 1); 55 + low_ip = extract32(s->low_ip, i, 1); 56 + high_ip = extract32(s->high_ip, i, 1); 57 + 58 + /* Output value (IOF not supported) */ 59 + oval = output_en && (port ^ out_xor); 60 + 61 + /* Pin both driven externally and internally */ 62 + if (output_en && in_mask) { 63 + qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i); 64 + } 65 + 66 + if (in_mask) { 67 + /* The pin is driven by external device */ 68 + actual_value = in; 69 + } else if (output_en) { 70 + /* The pin is driven by internal circuit */ 71 + actual_value = oval; 72 + } else { 73 + /* Floating? Apply pull-up resistor */ 74 + actual_value = pull; 75 + } 76 + 77 + qemu_set_irq(s->output[i], actual_value); 78 + 79 + /* Input value */ 80 + ival = input_en && actual_value; 81 + 82 + /* Interrupts */ 83 + high_ip = high_ip || ival; 84 + s->high_ip = deposit32(s->high_ip, i, 1, high_ip); 85 + 86 + low_ip = low_ip || !ival; 87 + s->low_ip = deposit32(s->low_ip, i, 1, low_ip); 88 + 89 + rise_ip = rise_ip || (ival && !prev_ival); 90 + s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip); 91 + 92 + fall_ip = fall_ip || (!ival && prev_ival); 93 + s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip); 94 + 95 + /* Update value */ 96 + s->value = deposit32(s->value, i, 1, ival); 97 + } 98 + update_output_irq(s); 99 + } 100 + 101 + static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size) 102 + { 103 + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); 104 + uint64_t r = 0; 105 + 106 + switch (offset) { 107 + case SIFIVE_GPIO_REG_VALUE: 108 + r = s->value; 109 + break; 110 + 111 + case SIFIVE_GPIO_REG_INPUT_EN: 112 + r = s->input_en; 113 + break; 114 + 115 + case SIFIVE_GPIO_REG_OUTPUT_EN: 116 + r = s->output_en; 117 + break; 118 + 119 + case SIFIVE_GPIO_REG_PORT: 120 + r = s->port; 121 + break; 122 + 123 + case SIFIVE_GPIO_REG_PUE: 124 + r = s->pue; 125 + break; 126 + 127 + case SIFIVE_GPIO_REG_DS: 128 + r = s->ds; 129 + break; 130 + 131 + case SIFIVE_GPIO_REG_RISE_IE: 132 + r = s->rise_ie; 133 + break; 134 + 135 + case SIFIVE_GPIO_REG_RISE_IP: 136 + r = s->rise_ip; 137 + break; 138 + 139 + case SIFIVE_GPIO_REG_FALL_IE: 140 + r = s->fall_ie; 141 + break; 142 + 143 + case SIFIVE_GPIO_REG_FALL_IP: 144 + r = s->fall_ip; 145 + break; 146 + 147 + case SIFIVE_GPIO_REG_HIGH_IE: 148 + r = s->high_ie; 149 + break; 150 + 151 + case SIFIVE_GPIO_REG_HIGH_IP: 152 + r = s->high_ip; 153 + break; 154 + 155 + case SIFIVE_GPIO_REG_LOW_IE: 156 + r = s->low_ie; 157 + break; 158 + 159 + case SIFIVE_GPIO_REG_LOW_IP: 160 + r = s->low_ip; 161 + break; 162 + 163 + case SIFIVE_GPIO_REG_IOF_EN: 164 + r = s->iof_en; 165 + break; 166 + 167 + case SIFIVE_GPIO_REG_IOF_SEL: 168 + r = s->iof_sel; 169 + break; 170 + 171 + case SIFIVE_GPIO_REG_OUT_XOR: 172 + r = s->out_xor; 173 + break; 174 + 175 + default: 176 + qemu_log_mask(LOG_GUEST_ERROR, 177 + "%s: bad read offset 0x%" HWADDR_PRIx "\n", 178 + __func__, offset); 179 + } 180 + 181 + trace_sifive_gpio_read(offset, r); 182 + 183 + return r; 184 + } 185 + 186 + static void sifive_gpio_write(void *opaque, hwaddr offset, 187 + uint64_t value, unsigned int size) 188 + { 189 + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); 190 + 191 + trace_sifive_gpio_write(offset, value); 192 + 193 + switch (offset) { 194 + 195 + case SIFIVE_GPIO_REG_INPUT_EN: 196 + s->input_en = value; 197 + break; 198 + 199 + case SIFIVE_GPIO_REG_OUTPUT_EN: 200 + s->output_en = value; 201 + break; 202 + 203 + case SIFIVE_GPIO_REG_PORT: 204 + s->port = value; 205 + break; 206 + 207 + case SIFIVE_GPIO_REG_PUE: 208 + s->pue = value; 209 + break; 210 + 211 + case SIFIVE_GPIO_REG_DS: 212 + s->ds = value; 213 + break; 214 + 215 + case SIFIVE_GPIO_REG_RISE_IE: 216 + s->rise_ie = value; 217 + break; 218 + 219 + case SIFIVE_GPIO_REG_RISE_IP: 220 + /* Write 1 to clear */ 221 + s->rise_ip &= ~value; 222 + break; 223 + 224 + case SIFIVE_GPIO_REG_FALL_IE: 225 + s->fall_ie = value; 226 + break; 227 + 228 + case SIFIVE_GPIO_REG_FALL_IP: 229 + /* Write 1 to clear */ 230 + s->fall_ip &= ~value; 231 + break; 232 + 233 + case SIFIVE_GPIO_REG_HIGH_IE: 234 + s->high_ie = value; 235 + break; 236 + 237 + case SIFIVE_GPIO_REG_HIGH_IP: 238 + /* Write 1 to clear */ 239 + s->high_ip &= ~value; 240 + break; 241 + 242 + case SIFIVE_GPIO_REG_LOW_IE: 243 + s->low_ie = value; 244 + break; 245 + 246 + case SIFIVE_GPIO_REG_LOW_IP: 247 + /* Write 1 to clear */ 248 + s->low_ip &= ~value; 249 + break; 250 + 251 + case SIFIVE_GPIO_REG_IOF_EN: 252 + s->iof_en = value; 253 + break; 254 + 255 + case SIFIVE_GPIO_REG_IOF_SEL: 256 + s->iof_sel = value; 257 + break; 258 + 259 + case SIFIVE_GPIO_REG_OUT_XOR: 260 + s->out_xor = value; 261 + break; 262 + 263 + default: 264 + qemu_log_mask(LOG_GUEST_ERROR, 265 + "%s: bad write offset 0x%" HWADDR_PRIx "\n", 266 + __func__, offset); 267 + } 268 + 269 + update_state(s); 270 + } 271 + 272 + static const MemoryRegionOps gpio_ops = { 273 + .read = sifive_gpio_read, 274 + .write = sifive_gpio_write, 275 + .endianness = DEVICE_LITTLE_ENDIAN, 276 + .impl.min_access_size = 4, 277 + .impl.max_access_size = 4, 278 + }; 279 + 280 + static void sifive_gpio_set(void *opaque, int line, int value) 281 + { 282 + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); 283 + 284 + trace_sifive_gpio_set(line, value); 285 + 286 + assert(line >= 0 && line < SIFIVE_GPIO_PINS); 287 + 288 + s->in_mask = deposit32(s->in_mask, line, 1, value >= 0); 289 + if (value >= 0) { 290 + s->in = deposit32(s->in, line, 1, value != 0); 291 + } 292 + 293 + update_state(s); 294 + } 295 + 296 + static void sifive_gpio_reset(DeviceState *dev) 297 + { 298 + SIFIVEGPIOState *s = SIFIVE_GPIO(dev); 299 + 300 + s->value = 0; 301 + s->input_en = 0; 302 + s->output_en = 0; 303 + s->port = 0; 304 + s->pue = 0; 305 + s->ds = 0; 306 + s->rise_ie = 0; 307 + s->rise_ip = 0; 308 + s->fall_ie = 0; 309 + s->fall_ip = 0; 310 + s->high_ie = 0; 311 + s->high_ip = 0; 312 + s->low_ie = 0; 313 + s->low_ip = 0; 314 + s->iof_en = 0; 315 + s->iof_sel = 0; 316 + s->out_xor = 0; 317 + s->in = 0; 318 + s->in_mask = 0; 319 + 320 + } 321 + 322 + static const VMStateDescription vmstate_sifive_gpio = { 323 + .name = TYPE_SIFIVE_GPIO, 324 + .version_id = 1, 325 + .minimum_version_id = 1, 326 + .fields = (VMStateField[]) { 327 + VMSTATE_UINT32(value, SIFIVEGPIOState), 328 + VMSTATE_UINT32(input_en, SIFIVEGPIOState), 329 + VMSTATE_UINT32(output_en, SIFIVEGPIOState), 330 + VMSTATE_UINT32(port, SIFIVEGPIOState), 331 + VMSTATE_UINT32(pue, SIFIVEGPIOState), 332 + VMSTATE_UINT32(rise_ie, SIFIVEGPIOState), 333 + VMSTATE_UINT32(rise_ip, SIFIVEGPIOState), 334 + VMSTATE_UINT32(fall_ie, SIFIVEGPIOState), 335 + VMSTATE_UINT32(fall_ip, SIFIVEGPIOState), 336 + VMSTATE_UINT32(high_ie, SIFIVEGPIOState), 337 + VMSTATE_UINT32(high_ip, SIFIVEGPIOState), 338 + VMSTATE_UINT32(low_ie, SIFIVEGPIOState), 339 + VMSTATE_UINT32(low_ip, SIFIVEGPIOState), 340 + VMSTATE_UINT32(iof_en, SIFIVEGPIOState), 341 + VMSTATE_UINT32(iof_sel, SIFIVEGPIOState), 342 + VMSTATE_UINT32(out_xor, SIFIVEGPIOState), 343 + VMSTATE_UINT32(in, SIFIVEGPIOState), 344 + VMSTATE_UINT32(in_mask, SIFIVEGPIOState), 345 + VMSTATE_END_OF_LIST() 346 + } 347 + }; 348 + 349 + static void sifive_gpio_init(Object *obj) 350 + { 351 + SIFIVEGPIOState *s = SIFIVE_GPIO(obj); 352 + 353 + memory_region_init_io(&s->mmio, obj, &gpio_ops, s, 354 + TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); 355 + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 356 + 357 + 358 + for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { 359 + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]); 360 + } 361 + 362 + qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, SIFIVE_GPIO_PINS); 363 + qdev_init_gpio_out(DEVICE(s), s->output, SIFIVE_GPIO_PINS); 364 + } 365 + 366 + static void sifive_gpio_class_init(ObjectClass *klass, void *data) 367 + { 368 + DeviceClass *dc = DEVICE_CLASS(klass); 369 + 370 + dc->vmsd = &vmstate_sifive_gpio; 371 + dc->reset = sifive_gpio_reset; 372 + dc->desc = "sifive GPIO"; 373 + } 374 + 375 + static const TypeInfo sifive_gpio_info = { 376 + .name = TYPE_SIFIVE_GPIO, 377 + .parent = TYPE_SYS_BUS_DEVICE, 378 + .instance_size = sizeof(SIFIVEGPIOState), 379 + .instance_init = sifive_gpio_init, 380 + .class_init = sifive_gpio_class_init 381 + }; 382 + 383 + static void sifive_gpio_register_types(void) 384 + { 385 + type_register_static(&sifive_gpio_info); 386 + } 387 + 388 + type_init(sifive_gpio_register_types)
+7
hw/riscv/trace-events
··· 1 + # See docs/devel/tracing.txt for syntax documentation. 2 + 3 + # hw/gpio/sifive_gpio.c 4 + sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64 5 + sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 6 + sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 7 + sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
+6 -2
include/hw/riscv/sifive_e.h
··· 19 19 #ifndef HW_SIFIVE_E_H 20 20 #define HW_SIFIVE_E_H 21 21 22 + #include "hw/riscv/sifive_gpio.h" 23 + 22 24 #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" 23 25 #define RISCV_E_SOC(obj) \ 24 26 OBJECT_CHECK(SiFiveESoCState, (obj), TYPE_RISCV_E_SOC) ··· 30 32 /*< public >*/ 31 33 RISCVHartArrayState cpus; 32 34 DeviceState *plic; 35 + SIFIVEGPIOState gpio; 33 36 } SiFiveESoCState; 34 37 35 38 typedef struct SiFiveEState { ··· 63 66 }; 64 67 65 68 enum { 66 - SIFIVE_E_UART0_IRQ = 3, 67 - SIFIVE_E_UART1_IRQ = 4 69 + SIFIVE_E_UART0_IRQ = 3, 70 + SIFIVE_E_UART1_IRQ = 4, 71 + SIFIVE_E_GPIO0_IRQ0 = 8 68 72 }; 69 73 70 74 #define SIFIVE_E_PLIC_HART_CONFIG "M"
+72
include/hw/riscv/sifive_gpio.h
··· 1 + /* 2 + * sifive System-on-Chip general purpose input/output register definition 3 + * 4 + * Copyright 2019 AdaCore 5 + * 6 + * Base on nrf51_gpio.c: 7 + * 8 + * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de> 9 + * 10 + * This code is licensed under the GPL version 2 or later. See 11 + * the COPYING file in the top-level directory. 12 + */ 13 + #ifndef SIFIVE_GPIO_H 14 + #define SIFIVE_GPIO_H 15 + 16 + #include "hw/sysbus.h" 17 + #define TYPE_SIFIVE_GPIO "sifive_soc.gpio" 18 + #define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO) 19 + 20 + #define SIFIVE_GPIO_PINS 32 21 + 22 + #define SIFIVE_GPIO_SIZE 0x100 23 + 24 + #define SIFIVE_GPIO_REG_VALUE 0x000 25 + #define SIFIVE_GPIO_REG_INPUT_EN 0x004 26 + #define SIFIVE_GPIO_REG_OUTPUT_EN 0x008 27 + #define SIFIVE_GPIO_REG_PORT 0x00C 28 + #define SIFIVE_GPIO_REG_PUE 0x010 29 + #define SIFIVE_GPIO_REG_DS 0x014 30 + #define SIFIVE_GPIO_REG_RISE_IE 0x018 31 + #define SIFIVE_GPIO_REG_RISE_IP 0x01C 32 + #define SIFIVE_GPIO_REG_FALL_IE 0x020 33 + #define SIFIVE_GPIO_REG_FALL_IP 0x024 34 + #define SIFIVE_GPIO_REG_HIGH_IE 0x028 35 + #define SIFIVE_GPIO_REG_HIGH_IP 0x02C 36 + #define SIFIVE_GPIO_REG_LOW_IE 0x030 37 + #define SIFIVE_GPIO_REG_LOW_IP 0x034 38 + #define SIFIVE_GPIO_REG_IOF_EN 0x038 39 + #define SIFIVE_GPIO_REG_IOF_SEL 0x03C 40 + #define SIFIVE_GPIO_REG_OUT_XOR 0x040 41 + 42 + typedef struct SIFIVEGPIOState { 43 + SysBusDevice parent_obj; 44 + 45 + MemoryRegion mmio; 46 + 47 + qemu_irq irq[SIFIVE_GPIO_PINS]; 48 + qemu_irq output[SIFIVE_GPIO_PINS]; 49 + 50 + uint32_t value; /* Actual value of the pin */ 51 + uint32_t input_en; 52 + uint32_t output_en; 53 + uint32_t port; /* Pin value requested by the user */ 54 + uint32_t pue; 55 + uint32_t ds; 56 + uint32_t rise_ie; 57 + uint32_t rise_ip; 58 + uint32_t fall_ie; 59 + uint32_t fall_ip; 60 + uint32_t high_ie; 61 + uint32_t high_ip; 62 + uint32_t low_ie; 63 + uint32_t low_ip; 64 + uint32_t iof_en; 65 + uint32_t iof_sel; 66 + uint32_t out_xor; 67 + uint32_t in; 68 + uint32_t in_mask; 69 + 70 + } SIFIVEGPIOState; 71 + 72 + #endif