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

armv7m: Split systick out from NVIC

The SysTick timer isn't really part of the NVIC proper;
we just modelled it that way back when we couldn't
easily have devices that only occupied a small chunk
of a memory region. Split it out into its own device.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1487604965-23220-10-git-send-email-peter.maydell@linaro.org
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

+318 -133
+34 -126
hw/intc/armv7m_nvic.c
··· 58 58 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 59 59 }; 60 60 61 - /* qemu timers run at 1GHz. We want something closer to 1MHz. */ 62 - #define SYSTICK_SCALE 1000ULL 63 - 64 - #define SYSTICK_ENABLE (1 << 0) 65 - #define SYSTICK_TICKINT (1 << 1) 66 - #define SYSTICK_CLKSOURCE (1 << 2) 67 - #define SYSTICK_COUNTFLAG (1 << 16) 68 - 69 - int system_clock_scale; 70 - 71 - /* Conversion factor from qemu timer to SysTick frequencies. */ 72 - static inline int64_t systick_scale(NVICState *s) 73 - { 74 - if (s->systick.control & SYSTICK_CLKSOURCE) 75 - return system_clock_scale; 76 - else 77 - return 1000; 78 - } 79 - 80 - static void systick_reload(NVICState *s, int reset) 81 - { 82 - /* The Cortex-M3 Devices Generic User Guide says that "When the 83 - * ENABLE bit is set to 1, the counter loads the RELOAD value from the 84 - * SYST RVR register and then counts down". So, we need to check the 85 - * ENABLE bit before reloading the value. 86 - */ 87 - if ((s->systick.control & SYSTICK_ENABLE) == 0) { 88 - return; 89 - } 90 - 91 - if (reset) 92 - s->systick.tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 93 - s->systick.tick += (s->systick.reload + 1) * systick_scale(s); 94 - timer_mod(s->systick.timer, s->systick.tick); 95 - } 96 - 97 - static void systick_timer_tick(void * opaque) 98 - { 99 - NVICState *s = (NVICState *)opaque; 100 - s->systick.control |= SYSTICK_COUNTFLAG; 101 - if (s->systick.control & SYSTICK_TICKINT) { 102 - /* Trigger the interrupt. */ 103 - armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); 104 - } 105 - if (s->systick.reload == 0) { 106 - s->systick.control &= ~SYSTICK_ENABLE; 107 - } else { 108 - systick_reload(s, 0); 109 - } 110 - } 111 - 112 - static void systick_reset(NVICState *s) 113 - { 114 - s->systick.control = 0; 115 - s->systick.reload = 0; 116 - s->systick.tick = 0; 117 - timer_del(s->systick.timer); 118 - } 119 - 120 61 static int nvic_pending_prio(NVICState *s) 121 62 { 122 63 /* return the priority of the current pending interrupt, ··· 462 403 switch (offset) { 463 404 case 4: /* Interrupt Control Type. */ 464 405 return ((s->num_irq - NVIC_FIRST_IRQ) / 32) - 1; 465 - case 0x10: /* SysTick Control and Status. */ 466 - val = s->systick.control; 467 - s->systick.control &= ~SYSTICK_COUNTFLAG; 468 - return val; 469 - case 0x14: /* SysTick Reload Value. */ 470 - return s->systick.reload; 471 - case 0x18: /* SysTick Current Value. */ 472 - { 473 - int64_t t; 474 - if ((s->systick.control & SYSTICK_ENABLE) == 0) 475 - return 0; 476 - t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 477 - if (t >= s->systick.tick) 478 - return 0; 479 - val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1; 480 - /* The interrupt in triggered when the timer reaches zero. 481 - However the counter is not reloaded until the next clock 482 - tick. This is a hack to return zero during the first tick. */ 483 - if (val > s->systick.reload) 484 - val = 0; 485 - return val; 486 - } 487 - case 0x1c: /* SysTick Calibration Value. */ 488 - return 10000; 489 406 case 0xd00: /* CPUID Base. */ 490 407 return cpu->midr; 491 408 case 0xd04: /* Interrupt Control State. */ ··· 620 537 static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value) 621 538 { 622 539 ARMCPU *cpu = s->cpu; 623 - uint32_t oldval; 540 + 624 541 switch (offset) { 625 - case 0x10: /* SysTick Control and Status. */ 626 - oldval = s->systick.control; 627 - s->systick.control &= 0xfffffff8; 628 - s->systick.control |= value & 7; 629 - if ((oldval ^ value) & SYSTICK_ENABLE) { 630 - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 631 - if (value & SYSTICK_ENABLE) { 632 - if (s->systick.tick) { 633 - s->systick.tick += now; 634 - timer_mod(s->systick.timer, s->systick.tick); 635 - } else { 636 - systick_reload(s, 1); 637 - } 638 - } else { 639 - timer_del(s->systick.timer); 640 - s->systick.tick -= now; 641 - if (s->systick.tick < 0) 642 - s->systick.tick = 0; 643 - } 644 - } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 645 - /* This is a hack. Force the timer to be reloaded 646 - when the reference clock is changed. */ 647 - systick_reload(s, 1); 648 - } 649 - break; 650 - case 0x14: /* SysTick Reload Value. */ 651 - s->systick.reload = value; 652 - break; 653 - case 0x18: /* SysTick Current Value. Writes reload the timer. */ 654 - systick_reload(s, 1); 655 - s->systick.control &= ~SYSTICK_COUNTFLAG; 656 - break; 657 542 case 0xd04: /* Interrupt Control State. */ 658 543 if (value & (1 << 31)) { 659 544 armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI); ··· 952 837 953 838 static const VMStateDescription vmstate_nvic = { 954 839 .name = "armv7m_nvic", 955 - .version_id = 3, 956 - .minimum_version_id = 3, 840 + .version_id = 4, 841 + .minimum_version_id = 4, 957 842 .post_load = &nvic_post_load, 958 843 .fields = (VMStateField[]) { 959 844 VMSTATE_STRUCT_ARRAY(vectors, NVICState, NVIC_MAX_VECTORS, 1, 960 845 vmstate_VecInfo, VecInfo), 961 - VMSTATE_UINT32(systick.control, NVICState), 962 - VMSTATE_UINT32(systick.reload, NVICState), 963 - VMSTATE_INT64(systick.tick, NVICState), 964 - VMSTATE_TIMER_PTR(systick.timer, NVICState), 965 846 VMSTATE_UINT32(prigroup, NVICState), 966 847 VMSTATE_END_OF_LIST() 967 848 } ··· 999 880 1000 881 s->exception_prio = NVIC_NOEXC_PRIO; 1001 882 s->vectpending = 0; 883 + } 1002 884 1003 - systick_reset(s); 885 + static void nvic_systick_trigger(void *opaque, int n, int level) 886 + { 887 + NVICState *s = opaque; 888 + 889 + if (level) { 890 + /* SysTick just asked us to pend its exception. 891 + * (This is different from an external interrupt line's 892 + * behaviour.) 893 + */ 894 + armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); 895 + } 1004 896 } 1005 897 1006 898 static void armv7m_nvic_realize(DeviceState *dev, Error **errp) 1007 899 { 1008 900 NVICState *s = NVIC(dev); 901 + SysBusDevice *systick_sbd; 902 + Error *err = NULL; 1009 903 1010 904 s->cpu = ARM_CPU(qemu_get_cpu(0)); 1011 905 assert(s->cpu); ··· 1020 914 /* include space for internal exception vectors */ 1021 915 s->num_irq += NVIC_FIRST_IRQ; 1022 916 917 + object_property_set_bool(OBJECT(&s->systick), true, "realized", &err); 918 + if (err != NULL) { 919 + error_propagate(errp, err); 920 + return; 921 + } 922 + systick_sbd = SYS_BUS_DEVICE(&s->systick); 923 + sysbus_connect_irq(systick_sbd, 0, 924 + qdev_get_gpio_in_named(dev, "systick-trigger", 0)); 925 + 1023 926 /* The NVIC and System Control Space (SCS) starts at 0xe000e000 1024 927 * and looks like this: 1025 928 * 0x004 - ICTR 1026 - * 0x010 - 0x1c - systick 929 + * 0x010 - 0xff - systick 1027 930 * 0x100..0x7ec - NVIC 1028 931 * 0x7f0..0xcff - Reserved 1029 932 * 0xd00..0xd3c - SCS registers ··· 1041 944 memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s, 1042 945 "nvic_sysregs", 0x1000); 1043 946 memory_region_add_subregion(&s->container, 0, &s->sysregmem); 947 + memory_region_add_subregion_overlap(&s->container, 0x10, 948 + sysbus_mmio_get_region(systick_sbd, 0), 949 + 1); 1044 950 1045 951 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container); 1046 - 1047 - s->systick.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s); 1048 952 } 1049 953 1050 954 static void armv7m_nvic_instance_init(Object *obj) ··· 1059 963 NVICState *nvic = NVIC(obj); 1060 964 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1061 965 966 + object_initialize(&nvic->systick, sizeof(nvic->systick), TYPE_SYSTICK); 967 + qdev_set_parent_bus(DEVICE(&nvic->systick), sysbus_get_default()); 968 + 1062 969 sysbus_init_irq(sbd, &nvic->excpout); 1063 970 qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1); 971 + qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger", 1); 1064 972 } 1065 973 1066 974 static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+1
hw/timer/Makefile.objs
··· 1 1 common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o 2 2 common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o 3 + common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o 3 4 common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o 4 5 common-obj-$(CONFIG_CADENCE) += cadence_ttc.o 5 6 common-obj-$(CONFIG_DS1338) += ds1338.o
+240
hw/timer/armv7m_systick.c
··· 1 + /* 2 + * ARMv7M SysTick timer 3 + * 4 + * Copyright (c) 2006-2007 CodeSourcery. 5 + * Written by Paul Brook 6 + * Copyright (c) 2017 Linaro Ltd 7 + * Written by Peter Maydell 8 + * 9 + * This code is licensed under the GPL (version 2 or later). 10 + */ 11 + 12 + #include "qemu/osdep.h" 13 + #include "hw/timer/armv7m_systick.h" 14 + #include "qemu-common.h" 15 + #include "hw/sysbus.h" 16 + #include "qemu/timer.h" 17 + #include "qemu/log.h" 18 + #include "trace.h" 19 + 20 + /* qemu timers run at 1GHz. We want something closer to 1MHz. */ 21 + #define SYSTICK_SCALE 1000ULL 22 + 23 + #define SYSTICK_ENABLE (1 << 0) 24 + #define SYSTICK_TICKINT (1 << 1) 25 + #define SYSTICK_CLKSOURCE (1 << 2) 26 + #define SYSTICK_COUNTFLAG (1 << 16) 27 + 28 + int system_clock_scale; 29 + 30 + /* Conversion factor from qemu timer to SysTick frequencies. */ 31 + static inline int64_t systick_scale(SysTickState *s) 32 + { 33 + if (s->control & SYSTICK_CLKSOURCE) { 34 + return system_clock_scale; 35 + } else { 36 + return 1000; 37 + } 38 + } 39 + 40 + static void systick_reload(SysTickState *s, int reset) 41 + { 42 + /* The Cortex-M3 Devices Generic User Guide says that "When the 43 + * ENABLE bit is set to 1, the counter loads the RELOAD value from the 44 + * SYST RVR register and then counts down". So, we need to check the 45 + * ENABLE bit before reloading the value. 46 + */ 47 + trace_systick_reload(); 48 + 49 + if ((s->control & SYSTICK_ENABLE) == 0) { 50 + return; 51 + } 52 + 53 + if (reset) { 54 + s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 55 + } 56 + s->tick += (s->reload + 1) * systick_scale(s); 57 + timer_mod(s->timer, s->tick); 58 + } 59 + 60 + static void systick_timer_tick(void *opaque) 61 + { 62 + SysTickState *s = (SysTickState *)opaque; 63 + 64 + trace_systick_timer_tick(); 65 + 66 + s->control |= SYSTICK_COUNTFLAG; 67 + if (s->control & SYSTICK_TICKINT) { 68 + /* Tell the NVIC to pend the SysTick exception */ 69 + qemu_irq_pulse(s->irq); 70 + } 71 + if (s->reload == 0) { 72 + s->control &= ~SYSTICK_ENABLE; 73 + } else { 74 + systick_reload(s, 0); 75 + } 76 + } 77 + 78 + static uint64_t systick_read(void *opaque, hwaddr addr, unsigned size) 79 + { 80 + SysTickState *s = opaque; 81 + uint32_t val; 82 + 83 + switch (addr) { 84 + case 0x0: /* SysTick Control and Status. */ 85 + val = s->control; 86 + s->control &= ~SYSTICK_COUNTFLAG; 87 + break; 88 + case 0x4: /* SysTick Reload Value. */ 89 + val = s->reload; 90 + break; 91 + case 0x8: /* SysTick Current Value. */ 92 + { 93 + int64_t t; 94 + 95 + if ((s->control & SYSTICK_ENABLE) == 0) { 96 + val = 0; 97 + break; 98 + } 99 + t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 100 + if (t >= s->tick) { 101 + val = 0; 102 + break; 103 + } 104 + val = ((s->tick - (t + 1)) / systick_scale(s)) + 1; 105 + /* The interrupt in triggered when the timer reaches zero. 106 + However the counter is not reloaded until the next clock 107 + tick. This is a hack to return zero during the first tick. */ 108 + if (val > s->reload) { 109 + val = 0; 110 + } 111 + break; 112 + } 113 + case 0xc: /* SysTick Calibration Value. */ 114 + val = 10000; 115 + break; 116 + default: 117 + val = 0; 118 + qemu_log_mask(LOG_GUEST_ERROR, 119 + "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr); 120 + break; 121 + } 122 + 123 + trace_systick_read(addr, val, size); 124 + return val; 125 + } 126 + 127 + static void systick_write(void *opaque, hwaddr addr, 128 + uint64_t value, unsigned size) 129 + { 130 + SysTickState *s = opaque; 131 + 132 + trace_systick_write(addr, value, size); 133 + 134 + switch (addr) { 135 + case 0x0: /* SysTick Control and Status. */ 136 + { 137 + uint32_t oldval = s->control; 138 + 139 + s->control &= 0xfffffff8; 140 + s->control |= value & 7; 141 + if ((oldval ^ value) & SYSTICK_ENABLE) { 142 + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 143 + if (value & SYSTICK_ENABLE) { 144 + if (s->tick) { 145 + s->tick += now; 146 + timer_mod(s->timer, s->tick); 147 + } else { 148 + systick_reload(s, 1); 149 + } 150 + } else { 151 + timer_del(s->timer); 152 + s->tick -= now; 153 + if (s->tick < 0) { 154 + s->tick = 0; 155 + } 156 + } 157 + } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 158 + /* This is a hack. Force the timer to be reloaded 159 + when the reference clock is changed. */ 160 + systick_reload(s, 1); 161 + } 162 + break; 163 + } 164 + case 0x4: /* SysTick Reload Value. */ 165 + s->reload = value; 166 + break; 167 + case 0x8: /* SysTick Current Value. Writes reload the timer. */ 168 + systick_reload(s, 1); 169 + s->control &= ~SYSTICK_COUNTFLAG; 170 + break; 171 + default: 172 + qemu_log_mask(LOG_GUEST_ERROR, 173 + "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr); 174 + } 175 + } 176 + 177 + static const MemoryRegionOps systick_ops = { 178 + .read = systick_read, 179 + .write = systick_write, 180 + .endianness = DEVICE_NATIVE_ENDIAN, 181 + .valid.min_access_size = 4, 182 + .valid.max_access_size = 4, 183 + }; 184 + 185 + static void systick_reset(DeviceState *dev) 186 + { 187 + SysTickState *s = SYSTICK(dev); 188 + 189 + s->control = 0; 190 + s->reload = 0; 191 + s->tick = 0; 192 + timer_del(s->timer); 193 + } 194 + 195 + static void systick_instance_init(Object *obj) 196 + { 197 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 198 + SysTickState *s = SYSTICK(obj); 199 + 200 + memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0); 201 + sysbus_init_mmio(sbd, &s->iomem); 202 + sysbus_init_irq(sbd, &s->irq); 203 + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s); 204 + } 205 + 206 + static const VMStateDescription vmstate_systick = { 207 + .name = "armv7m_systick", 208 + .version_id = 1, 209 + .minimum_version_id = 1, 210 + .fields = (VMStateField[]) { 211 + VMSTATE_UINT32(control, SysTickState), 212 + VMSTATE_UINT32(reload, SysTickState), 213 + VMSTATE_INT64(tick, SysTickState), 214 + VMSTATE_TIMER_PTR(timer, SysTickState), 215 + VMSTATE_END_OF_LIST() 216 + } 217 + }; 218 + 219 + static void systick_class_init(ObjectClass *klass, void *data) 220 + { 221 + DeviceClass *dc = DEVICE_CLASS(klass); 222 + 223 + dc->vmsd = &vmstate_systick; 224 + dc->reset = systick_reset; 225 + } 226 + 227 + static const TypeInfo armv7m_systick_info = { 228 + .name = TYPE_SYSTICK, 229 + .parent = TYPE_SYS_BUS_DEVICE, 230 + .instance_init = systick_instance_init, 231 + .instance_size = sizeof(SysTickState), 232 + .class_init = systick_class_init, 233 + }; 234 + 235 + static void armv7m_systick_register_types(void) 236 + { 237 + type_register_static(&armv7m_systick_info); 238 + } 239 + 240 + type_init(armv7m_systick_register_types)
+6
hw/timer/trace-events
··· 49 49 aspeed_timer_set_ctrl2(uint32_t value) "Value: 0x%" PRIx32 50 50 aspeed_timer_set_value(int timer, int reg, uint32_t value) "Timer %d register %d: 0x%" PRIx32 51 51 aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRIx64 ": of size %u: 0x%" PRIx64 52 + 53 + # hw/timer/armv7m_systick.c 54 + systick_reload(void) "systick reload" 55 + systick_timer_tick(void) "systick reload" 56 + systick_read(uint64_t addr, uint32_t value, unsigned size) "systick read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" 57 + systick_write(uint64_t addr, uint32_t value, unsigned size) "systick write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+3 -7
include/hw/arm/armv7m_nvic.h
··· 12 12 13 13 #include "target/arm/cpu.h" 14 14 #include "hw/sysbus.h" 15 + #include "hw/timer/armv7m_systick.h" 15 16 16 17 #define TYPE_NVIC "armv7m_nvic" 17 18 ··· 48 49 unsigned int vectpending; /* highest prio pending enabled exception */ 49 50 int exception_prio; /* group prio of the highest prio active exception */ 50 51 51 - struct { 52 - uint32_t control; 53 - uint32_t reload; 54 - int64_t tick; 55 - QEMUTimer *timer; 56 - } systick; 57 - 58 52 MemoryRegion sysregmem; 59 53 MemoryRegion container; 60 54 61 55 uint32_t num_irq; 62 56 qemu_irq excpout; 63 57 qemu_irq sysresetreq; 58 + 59 + SysTickState systick; 64 60 } NVICState; 65 61 66 62 #endif
+34
include/hw/timer/armv7m_systick.h
··· 1 + /* 2 + * ARMv7M SysTick timer 3 + * 4 + * Copyright (c) 2006-2007 CodeSourcery. 5 + * Written by Paul Brook 6 + * Copyright (c) 2017 Linaro Ltd 7 + * Written by Peter Maydell 8 + * 9 + * This code is licensed under the GPL (version 2 or later). 10 + */ 11 + 12 + #ifndef HW_TIMER_ARMV7M_SYSTICK_H 13 + #define HW_TIMER_ARMV7M_SYSTICK_H 14 + 15 + #include "hw/sysbus.h" 16 + 17 + #define TYPE_SYSTICK "armv7m_systick" 18 + 19 + #define SYSTICK(obj) OBJECT_CHECK(SysTickState, (obj), TYPE_SYSTICK) 20 + 21 + typedef struct SysTickState { 22 + /*< private >*/ 23 + SysBusDevice parent_obj; 24 + /*< public >*/ 25 + 26 + uint32_t control; 27 + uint32_t reload; 28 + int64_t tick; 29 + QEMUTimer *timer; 30 + MemoryRegion iomem; 31 + qemu_irq irq; 32 + } SysTickState; 33 + 34 + #endif