1 /* 2 * RISC-V ACLINT (Advanced Core Local Interruptor) 3 * URL: https://github.com/riscv/riscv-aclint 4 * 5 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu 6 * Copyright (c) 2017 SiFive, Inc. 7 * Copyright (c) 2021 Western Digital Corporation or its affiliates. 8 * 9 * This provides real-time clock, timer and interprocessor interrupts. 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms and conditions of the GNU General Public License, 13 * version 2 or later, as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 18 * more details. 19 * 20 * You should have received a copy of the GNU General Public License along with 21 * this program. If not, see <http://www.gnu.org/licenses/>. 22 */ 23 24 #include "qemu/osdep.h" 25 #include "qapi/error.h" 26 #include "qemu/error-report.h" 27 #include "qemu/log.h" 28 #include "qemu/module.h" 29 #include "hw/sysbus.h" 30 #include "target/riscv/cpu.h" 31 #include "hw/qdev-properties.h" 32 #include "hw/intc/riscv_aclint.h" 33 #include "qemu/timer.h" 34 #include "hw/irq.h" 35 36 typedef struct riscv_aclint_mtimer_callback { 37 RISCVAclintMTimerState *s; 38 int num; 39 } riscv_aclint_mtimer_callback; 40 41 static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) 42 { 43 return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 44 timebase_freq, NANOSECONDS_PER_SECOND); 45 } 46 47 /* 48 * Called when timecmp is written to update the QEMU timer or immediately 49 * trigger timer interrupt if mtimecmp <= current timer value. 50 */ 51 static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, 52 RISCVCPU *cpu, 53 int hartid, 54 uint64_t value, 55 uint32_t timebase_freq) 56 { 57 uint64_t next; 58 uint64_t diff; 59 60 uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq); 61 62 cpu->env.timecmp = value; 63 if (cpu->env.timecmp <= rtc_r) { 64 /* 65 * If we're setting an MTIMECMP value in the "past", 66 * immediately raise the timer interrupt 67 */ 68 qemu_irq_raise(mtimer->timer_irqs[hartid - mtimer->hartid_base]); 69 return; 70 } 71 72 /* otherwise, set up the future timer interrupt */ 73 qemu_irq_lower(mtimer->timer_irqs[hartid - mtimer->hartid_base]); 74 diff = cpu->env.timecmp - rtc_r; 75 /* back to ns (note args switched in muldiv64) */ 76 uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); 77 78 /* 79 * check if ns_diff overflowed and check if the addition would potentially 80 * overflow 81 */ 82 if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) || 83 ns_diff > INT64_MAX) { 84 next = INT64_MAX; 85 } else { 86 /* 87 * as it is very unlikely qemu_clock_get_ns will return a value 88 * greater than INT64_MAX, no additional check is needed for an 89 * unsigned integer overflow. 90 */ 91 next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff; 92 /* 93 * if ns_diff is INT64_MAX next may still be outside the range 94 * of a signed integer. 95 */ 96 next = MIN(next, INT64_MAX); 97 } 98 99 timer_mod(cpu->env.timer, next); 100 } 101 102 /* 103 * Callback used when the timer set using timer_mod expires. 104 * Should raise the timer interrupt line 105 */ 106 static void riscv_aclint_mtimer_cb(void *opaque) 107 { 108 riscv_aclint_mtimer_callback *state = opaque; 109 110 qemu_irq_raise(state->s->timer_irqs[state->num]); 111 } 112 113 /* CPU read MTIMER register */ 114 static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr, 115 unsigned size) 116 { 117 RISCVAclintMTimerState *mtimer = opaque; 118 119 if (addr >= mtimer->timecmp_base && 120 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) { 121 size_t hartid = mtimer->hartid_base + 122 ((addr - mtimer->timecmp_base) >> 3); 123 CPUState *cpu = qemu_get_cpu(hartid); 124 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 125 if (!env) { 126 qemu_log_mask(LOG_GUEST_ERROR, 127 "aclint-mtimer: invalid hartid: %zu", hartid); 128 } else if ((addr & 0x7) == 0) { 129 /* timecmp_lo */ 130 uint64_t timecmp = env->timecmp; 131 return timecmp & 0xFFFFFFFF; 132 } else if ((addr & 0x7) == 4) { 133 /* timecmp_hi */ 134 uint64_t timecmp = env->timecmp; 135 return (timecmp >> 32) & 0xFFFFFFFF; 136 } else { 137 qemu_log_mask(LOG_UNIMP, 138 "aclint-mtimer: invalid read: %08x", (uint32_t)addr); 139 return 0; 140 } 141 } else if (addr == mtimer->time_base) { 142 /* time_lo */ 143 return cpu_riscv_read_rtc(mtimer->timebase_freq) & 0xFFFFFFFF; 144 } else if (addr == mtimer->time_base + 4) { 145 /* time_hi */ 146 return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF; 147 } 148 149 qemu_log_mask(LOG_UNIMP, 150 "aclint-mtimer: invalid read: %08x", (uint32_t)addr); 151 return 0; 152 } 153 154 /* CPU write MTIMER register */ 155 static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, 156 uint64_t value, unsigned size) 157 { 158 RISCVAclintMTimerState *mtimer = opaque; 159 160 if (addr >= mtimer->timecmp_base && 161 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) { 162 size_t hartid = mtimer->hartid_base + 163 ((addr - mtimer->timecmp_base) >> 3); 164 CPUState *cpu = qemu_get_cpu(hartid); 165 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 166 if (!env) { 167 qemu_log_mask(LOG_GUEST_ERROR, 168 "aclint-mtimer: invalid hartid: %zu", hartid); 169 } else if ((addr & 0x7) == 0) { 170 /* timecmp_lo */ 171 uint64_t timecmp_hi = env->timecmp >> 32; 172 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, 173 timecmp_hi << 32 | (value & 0xFFFFFFFF), 174 mtimer->timebase_freq); 175 return; 176 } else if ((addr & 0x7) == 4) { 177 /* timecmp_hi */ 178 uint64_t timecmp_lo = env->timecmp; 179 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, 180 value << 32 | (timecmp_lo & 0xFFFFFFFF), 181 mtimer->timebase_freq); 182 } else { 183 qemu_log_mask(LOG_UNIMP, 184 "aclint-mtimer: invalid timecmp write: %08x", 185 (uint32_t)addr); 186 } 187 return; 188 } else if (addr == mtimer->time_base) { 189 /* time_lo */ 190 qemu_log_mask(LOG_UNIMP, 191 "aclint-mtimer: time_lo write not implemented"); 192 return; 193 } else if (addr == mtimer->time_base + 4) { 194 /* time_hi */ 195 qemu_log_mask(LOG_UNIMP, 196 "aclint-mtimer: time_hi write not implemented"); 197 return; 198 } 199 200 qemu_log_mask(LOG_UNIMP, 201 "aclint-mtimer: invalid write: %08x", (uint32_t)addr); 202 } 203 204 static const MemoryRegionOps riscv_aclint_mtimer_ops = { 205 .read = riscv_aclint_mtimer_read, 206 .write = riscv_aclint_mtimer_write, 207 .endianness = DEVICE_LITTLE_ENDIAN, 208 .valid = { 209 .min_access_size = 4, 210 .max_access_size = 8 211 }, 212 .impl = { 213 .min_access_size = 4, 214 .max_access_size = 8, 215 } 216 }; 217 218 static Property riscv_aclint_mtimer_properties[] = { 219 DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState, 220 hartid_base, 0), 221 DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 1), 222 DEFINE_PROP_UINT32("timecmp-base", RISCVAclintMTimerState, 223 timecmp_base, RISCV_ACLINT_DEFAULT_MTIMECMP), 224 DEFINE_PROP_UINT32("time-base", RISCVAclintMTimerState, 225 time_base, RISCV_ACLINT_DEFAULT_MTIME), 226 DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState, 227 aperture_size, RISCV_ACLINT_DEFAULT_MTIMER_SIZE), 228 DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState, 229 timebase_freq, 0), 230 DEFINE_PROP_END_OF_LIST(), 231 }; 232 233 static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp) 234 { 235 RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev); 236 int i; 237 238 memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, 239 s, TYPE_RISCV_ACLINT_MTIMER, s->aperture_size); 240 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 241 242 s->timer_irqs = g_new(qemu_irq, s->num_harts); 243 qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts); 244 245 /* Claim timer interrupt bits */ 246 for (i = 0; i < s->num_harts; i++) { 247 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i)); 248 if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) { 249 error_report("MTIP already claimed"); 250 exit(1); 251 } 252 } 253 } 254 255 static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) 256 { 257 DeviceClass *dc = DEVICE_CLASS(klass); 258 dc->realize = riscv_aclint_mtimer_realize; 259 device_class_set_props(dc, riscv_aclint_mtimer_properties); 260 } 261 262 static const TypeInfo riscv_aclint_mtimer_info = { 263 .name = TYPE_RISCV_ACLINT_MTIMER, 264 .parent = TYPE_SYS_BUS_DEVICE, 265 .instance_size = sizeof(RISCVAclintMTimerState), 266 .class_init = riscv_aclint_mtimer_class_init, 267 }; 268 269 /* 270 * Create ACLINT MTIMER device. 271 */ 272 DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, 273 uint32_t hartid_base, uint32_t num_harts, 274 uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq, 275 bool provide_rdtime) 276 { 277 int i; 278 DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER); 279 280 assert(num_harts <= RISCV_ACLINT_MAX_HARTS); 281 assert(!(addr & 0x7)); 282 assert(!(timecmp_base & 0x7)); 283 assert(!(time_base & 0x7)); 284 285 qdev_prop_set_uint32(dev, "hartid-base", hartid_base); 286 qdev_prop_set_uint32(dev, "num-harts", num_harts); 287 qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); 288 qdev_prop_set_uint32(dev, "time-base", time_base); 289 qdev_prop_set_uint32(dev, "aperture-size", size); 290 qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq); 291 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 292 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 293 294 for (i = 0; i < num_harts; i++) { 295 CPUState *cpu = qemu_get_cpu(hartid_base + i); 296 RISCVCPU *rvcpu = RISCV_CPU(cpu); 297 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 298 riscv_aclint_mtimer_callback *cb = 299 g_new0(riscv_aclint_mtimer_callback, 1); 300 301 if (!env) { 302 g_free(cb); 303 continue; 304 } 305 if (provide_rdtime) { 306 riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq); 307 } 308 309 cb->s = RISCV_ACLINT_MTIMER(dev); 310 cb->num = i; 311 env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 312 &riscv_aclint_mtimer_cb, cb); 313 env->timecmp = 0; 314 315 qdev_connect_gpio_out(dev, i, 316 qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER)); 317 } 318 319 return dev; 320 } 321 322 /* CPU read [M|S]SWI register */ 323 static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr, 324 unsigned size) 325 { 326 RISCVAclintSwiState *swi = opaque; 327 328 if (addr < (swi->num_harts << 2)) { 329 size_t hartid = swi->hartid_base + (addr >> 2); 330 CPUState *cpu = qemu_get_cpu(hartid); 331 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 332 if (!env) { 333 qemu_log_mask(LOG_GUEST_ERROR, 334 "aclint-swi: invalid hartid: %zu", hartid); 335 } else if ((addr & 0x3) == 0) { 336 return (swi->sswi) ? 0 : ((env->mip & MIP_MSIP) > 0); 337 } 338 } 339 340 qemu_log_mask(LOG_UNIMP, 341 "aclint-swi: invalid read: %08x", (uint32_t)addr); 342 return 0; 343 } 344 345 /* CPU write [M|S]SWI register */ 346 static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value, 347 unsigned size) 348 { 349 RISCVAclintSwiState *swi = opaque; 350 351 if (addr < (swi->num_harts << 2)) { 352 size_t hartid = swi->hartid_base + (addr >> 2); 353 CPUState *cpu = qemu_get_cpu(hartid); 354 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 355 if (!env) { 356 qemu_log_mask(LOG_GUEST_ERROR, 357 "aclint-swi: invalid hartid: %zu", hartid); 358 } else if ((addr & 0x3) == 0) { 359 if (value & 0x1) { 360 qemu_irq_raise(swi->soft_irqs[hartid - swi->hartid_base]); 361 } else { 362 if (!swi->sswi) { 363 qemu_irq_lower(swi->soft_irqs[hartid - swi->hartid_base]); 364 } 365 } 366 return; 367 } 368 } 369 370 qemu_log_mask(LOG_UNIMP, 371 "aclint-swi: invalid write: %08x", (uint32_t)addr); 372 } 373 374 static const MemoryRegionOps riscv_aclint_swi_ops = { 375 .read = riscv_aclint_swi_read, 376 .write = riscv_aclint_swi_write, 377 .endianness = DEVICE_LITTLE_ENDIAN, 378 .valid = { 379 .min_access_size = 4, 380 .max_access_size = 4 381 } 382 }; 383 384 static Property riscv_aclint_swi_properties[] = { 385 DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0), 386 DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 1), 387 DEFINE_PROP_UINT32("sswi", RISCVAclintSwiState, sswi, false), 388 DEFINE_PROP_END_OF_LIST(), 389 }; 390 391 static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp) 392 { 393 RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(dev); 394 int i; 395 396 memory_region_init_io(&swi->mmio, OBJECT(dev), &riscv_aclint_swi_ops, swi, 397 TYPE_RISCV_ACLINT_SWI, RISCV_ACLINT_SWI_SIZE); 398 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &swi->mmio); 399 400 swi->soft_irqs = g_new(qemu_irq, swi->num_harts); 401 qdev_init_gpio_out(dev, swi->soft_irqs, swi->num_harts); 402 403 /* Claim software interrupt bits */ 404 for (i = 0; i < swi->num_harts; i++) { 405 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i)); 406 /* We don't claim mip.SSIP because it is writeable by software */ 407 if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) { 408 error_report("MSIP already claimed"); 409 exit(1); 410 } 411 } 412 } 413 414 static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data) 415 { 416 DeviceClass *dc = DEVICE_CLASS(klass); 417 dc->realize = riscv_aclint_swi_realize; 418 device_class_set_props(dc, riscv_aclint_swi_properties); 419 } 420 421 static const TypeInfo riscv_aclint_swi_info = { 422 .name = TYPE_RISCV_ACLINT_SWI, 423 .parent = TYPE_SYS_BUS_DEVICE, 424 .instance_size = sizeof(RISCVAclintSwiState), 425 .class_init = riscv_aclint_swi_class_init, 426 }; 427 428 /* 429 * Create ACLINT [M|S]SWI device. 430 */ 431 DeviceState *riscv_aclint_swi_create(hwaddr addr, uint32_t hartid_base, 432 uint32_t num_harts, bool sswi) 433 { 434 int i; 435 DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI); 436 437 assert(num_harts <= RISCV_ACLINT_MAX_HARTS); 438 assert(!(addr & 0x3)); 439 440 qdev_prop_set_uint32(dev, "hartid-base", hartid_base); 441 qdev_prop_set_uint32(dev, "num-harts", num_harts); 442 qdev_prop_set_uint32(dev, "sswi", sswi ? true : false); 443 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 444 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 445 446 for (i = 0; i < num_harts; i++) { 447 CPUState *cpu = qemu_get_cpu(hartid_base + i); 448 RISCVCPU *rvcpu = RISCV_CPU(cpu); 449 450 qdev_connect_gpio_out(dev, i, 451 qdev_get_gpio_in(DEVICE(rvcpu), 452 (sswi) ? IRQ_S_SOFT : IRQ_M_SOFT)); 453 } 454 455 return dev; 456 } 457 458 static void riscv_aclint_register_types(void) 459 { 460 type_register_static(&riscv_aclint_mtimer_info); 461 type_register_static(&riscv_aclint_swi_info); 462 } 463 464 type_init(riscv_aclint_register_types) 465