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 for RV32/RV64 or timecmp for RV64 */ 130 uint64_t timecmp = env->timecmp; 131 return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp; 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 for RV32/RV64 or timecmp for RV64 */ 143 uint64_t rtc = cpu_riscv_read_rtc(mtimer->timebase_freq); 144 return (size == 4) ? (rtc & 0xFFFFFFFF) : rtc; 145 } else if (addr == mtimer->time_base + 4) { 146 /* time_hi */ 147 return (cpu_riscv_read_rtc(mtimer->timebase_freq) >> 32) & 0xFFFFFFFF; 148 } 149 150 qemu_log_mask(LOG_UNIMP, 151 "aclint-mtimer: invalid read: %08x", (uint32_t)addr); 152 return 0; 153 } 154 155 /* CPU write MTIMER register */ 156 static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, 157 uint64_t value, unsigned size) 158 { 159 RISCVAclintMTimerState *mtimer = opaque; 160 161 if (addr >= mtimer->timecmp_base && 162 addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) { 163 size_t hartid = mtimer->hartid_base + 164 ((addr - mtimer->timecmp_base) >> 3); 165 CPUState *cpu = qemu_get_cpu(hartid); 166 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 167 if (!env) { 168 qemu_log_mask(LOG_GUEST_ERROR, 169 "aclint-mtimer: invalid hartid: %zu", hartid); 170 } else if ((addr & 0x7) == 0) { 171 if (size == 4) { 172 /* timecmp_lo for RV32/RV64 */ 173 uint64_t timecmp_hi = env->timecmp >> 32; 174 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, 175 timecmp_hi << 32 | (value & 0xFFFFFFFF), 176 mtimer->timebase_freq); 177 } else { 178 /* timecmp for RV64 */ 179 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, 180 value, mtimer->timebase_freq); 181 } 182 } else if ((addr & 0x7) == 4) { 183 if (size == 4) { 184 /* timecmp_hi for RV32/RV64 */ 185 uint64_t timecmp_lo = env->timecmp; 186 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, 187 value << 32 | (timecmp_lo & 0xFFFFFFFF), 188 mtimer->timebase_freq); 189 } else { 190 qemu_log_mask(LOG_GUEST_ERROR, 191 "aclint-mtimer: invalid timecmp_hi write: %08x", 192 (uint32_t)addr); 193 } 194 } else { 195 qemu_log_mask(LOG_UNIMP, 196 "aclint-mtimer: invalid timecmp write: %08x", 197 (uint32_t)addr); 198 } 199 return; 200 } else if (addr == mtimer->time_base) { 201 /* time_lo */ 202 qemu_log_mask(LOG_UNIMP, 203 "aclint-mtimer: time_lo write not implemented"); 204 return; 205 } else if (addr == mtimer->time_base + 4) { 206 /* time_hi */ 207 qemu_log_mask(LOG_UNIMP, 208 "aclint-mtimer: time_hi write not implemented"); 209 return; 210 } 211 212 qemu_log_mask(LOG_UNIMP, 213 "aclint-mtimer: invalid write: %08x", (uint32_t)addr); 214 } 215 216 static const MemoryRegionOps riscv_aclint_mtimer_ops = { 217 .read = riscv_aclint_mtimer_read, 218 .write = riscv_aclint_mtimer_write, 219 .endianness = DEVICE_LITTLE_ENDIAN, 220 .valid = { 221 .min_access_size = 4, 222 .max_access_size = 8 223 }, 224 .impl = { 225 .min_access_size = 4, 226 .max_access_size = 8, 227 } 228 }; 229 230 static Property riscv_aclint_mtimer_properties[] = { 231 DEFINE_PROP_UINT32("hartid-base", RISCVAclintMTimerState, 232 hartid_base, 0), 233 DEFINE_PROP_UINT32("num-harts", RISCVAclintMTimerState, num_harts, 1), 234 DEFINE_PROP_UINT32("timecmp-base", RISCVAclintMTimerState, 235 timecmp_base, RISCV_ACLINT_DEFAULT_MTIMECMP), 236 DEFINE_PROP_UINT32("time-base", RISCVAclintMTimerState, 237 time_base, RISCV_ACLINT_DEFAULT_MTIME), 238 DEFINE_PROP_UINT32("aperture-size", RISCVAclintMTimerState, 239 aperture_size, RISCV_ACLINT_DEFAULT_MTIMER_SIZE), 240 DEFINE_PROP_UINT32("timebase-freq", RISCVAclintMTimerState, 241 timebase_freq, 0), 242 DEFINE_PROP_END_OF_LIST(), 243 }; 244 245 static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp) 246 { 247 RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev); 248 int i; 249 250 memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops, 251 s, TYPE_RISCV_ACLINT_MTIMER, s->aperture_size); 252 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 253 254 s->timer_irqs = g_new(qemu_irq, s->num_harts); 255 qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts); 256 257 /* Claim timer interrupt bits */ 258 for (i = 0; i < s->num_harts; i++) { 259 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i)); 260 if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) { 261 error_report("MTIP already claimed"); 262 exit(1); 263 } 264 } 265 } 266 267 static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) 268 { 269 DeviceClass *dc = DEVICE_CLASS(klass); 270 dc->realize = riscv_aclint_mtimer_realize; 271 device_class_set_props(dc, riscv_aclint_mtimer_properties); 272 } 273 274 static const TypeInfo riscv_aclint_mtimer_info = { 275 .name = TYPE_RISCV_ACLINT_MTIMER, 276 .parent = TYPE_SYS_BUS_DEVICE, 277 .instance_size = sizeof(RISCVAclintMTimerState), 278 .class_init = riscv_aclint_mtimer_class_init, 279 }; 280 281 /* 282 * Create ACLINT MTIMER device. 283 */ 284 DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, 285 uint32_t hartid_base, uint32_t num_harts, 286 uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq, 287 bool provide_rdtime) 288 { 289 int i; 290 DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER); 291 292 assert(num_harts <= RISCV_ACLINT_MAX_HARTS); 293 assert(!(addr & 0x7)); 294 assert(!(timecmp_base & 0x7)); 295 assert(!(time_base & 0x7)); 296 297 qdev_prop_set_uint32(dev, "hartid-base", hartid_base); 298 qdev_prop_set_uint32(dev, "num-harts", num_harts); 299 qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); 300 qdev_prop_set_uint32(dev, "time-base", time_base); 301 qdev_prop_set_uint32(dev, "aperture-size", size); 302 qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq); 303 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 304 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 305 306 for (i = 0; i < num_harts; i++) { 307 CPUState *cpu = qemu_get_cpu(hartid_base + i); 308 RISCVCPU *rvcpu = RISCV_CPU(cpu); 309 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 310 riscv_aclint_mtimer_callback *cb = 311 g_new0(riscv_aclint_mtimer_callback, 1); 312 313 if (!env) { 314 g_free(cb); 315 continue; 316 } 317 if (provide_rdtime) { 318 riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq); 319 } 320 321 cb->s = RISCV_ACLINT_MTIMER(dev); 322 cb->num = i; 323 env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 324 &riscv_aclint_mtimer_cb, cb); 325 env->timecmp = 0; 326 327 qdev_connect_gpio_out(dev, i, 328 qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER)); 329 } 330 331 return dev; 332 } 333 334 /* CPU read [M|S]SWI register */ 335 static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr, 336 unsigned size) 337 { 338 RISCVAclintSwiState *swi = opaque; 339 340 if (addr < (swi->num_harts << 2)) { 341 size_t hartid = swi->hartid_base + (addr >> 2); 342 CPUState *cpu = qemu_get_cpu(hartid); 343 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 344 if (!env) { 345 qemu_log_mask(LOG_GUEST_ERROR, 346 "aclint-swi: invalid hartid: %zu", hartid); 347 } else if ((addr & 0x3) == 0) { 348 return (swi->sswi) ? 0 : ((env->mip & MIP_MSIP) > 0); 349 } 350 } 351 352 qemu_log_mask(LOG_UNIMP, 353 "aclint-swi: invalid read: %08x", (uint32_t)addr); 354 return 0; 355 } 356 357 /* CPU write [M|S]SWI register */ 358 static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value, 359 unsigned size) 360 { 361 RISCVAclintSwiState *swi = opaque; 362 363 if (addr < (swi->num_harts << 2)) { 364 size_t hartid = swi->hartid_base + (addr >> 2); 365 CPUState *cpu = qemu_get_cpu(hartid); 366 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 367 if (!env) { 368 qemu_log_mask(LOG_GUEST_ERROR, 369 "aclint-swi: invalid hartid: %zu", hartid); 370 } else if ((addr & 0x3) == 0) { 371 if (value & 0x1) { 372 qemu_irq_raise(swi->soft_irqs[hartid - swi->hartid_base]); 373 } else { 374 if (!swi->sswi) { 375 qemu_irq_lower(swi->soft_irqs[hartid - swi->hartid_base]); 376 } 377 } 378 return; 379 } 380 } 381 382 qemu_log_mask(LOG_UNIMP, 383 "aclint-swi: invalid write: %08x", (uint32_t)addr); 384 } 385 386 static const MemoryRegionOps riscv_aclint_swi_ops = { 387 .read = riscv_aclint_swi_read, 388 .write = riscv_aclint_swi_write, 389 .endianness = DEVICE_LITTLE_ENDIAN, 390 .valid = { 391 .min_access_size = 4, 392 .max_access_size = 4 393 } 394 }; 395 396 static Property riscv_aclint_swi_properties[] = { 397 DEFINE_PROP_UINT32("hartid-base", RISCVAclintSwiState, hartid_base, 0), 398 DEFINE_PROP_UINT32("num-harts", RISCVAclintSwiState, num_harts, 1), 399 DEFINE_PROP_UINT32("sswi", RISCVAclintSwiState, sswi, false), 400 DEFINE_PROP_END_OF_LIST(), 401 }; 402 403 static void riscv_aclint_swi_realize(DeviceState *dev, Error **errp) 404 { 405 RISCVAclintSwiState *swi = RISCV_ACLINT_SWI(dev); 406 int i; 407 408 memory_region_init_io(&swi->mmio, OBJECT(dev), &riscv_aclint_swi_ops, swi, 409 TYPE_RISCV_ACLINT_SWI, RISCV_ACLINT_SWI_SIZE); 410 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &swi->mmio); 411 412 swi->soft_irqs = g_new(qemu_irq, swi->num_harts); 413 qdev_init_gpio_out(dev, swi->soft_irqs, swi->num_harts); 414 415 /* Claim software interrupt bits */ 416 for (i = 0; i < swi->num_harts; i++) { 417 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(swi->hartid_base + i)); 418 /* We don't claim mip.SSIP because it is writeable by software */ 419 if (riscv_cpu_claim_interrupts(cpu, swi->sswi ? 0 : MIP_MSIP) < 0) { 420 error_report("MSIP already claimed"); 421 exit(1); 422 } 423 } 424 } 425 426 static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data) 427 { 428 DeviceClass *dc = DEVICE_CLASS(klass); 429 dc->realize = riscv_aclint_swi_realize; 430 device_class_set_props(dc, riscv_aclint_swi_properties); 431 } 432 433 static const TypeInfo riscv_aclint_swi_info = { 434 .name = TYPE_RISCV_ACLINT_SWI, 435 .parent = TYPE_SYS_BUS_DEVICE, 436 .instance_size = sizeof(RISCVAclintSwiState), 437 .class_init = riscv_aclint_swi_class_init, 438 }; 439 440 /* 441 * Create ACLINT [M|S]SWI device. 442 */ 443 DeviceState *riscv_aclint_swi_create(hwaddr addr, uint32_t hartid_base, 444 uint32_t num_harts, bool sswi) 445 { 446 int i; 447 DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_SWI); 448 449 assert(num_harts <= RISCV_ACLINT_MAX_HARTS); 450 assert(!(addr & 0x3)); 451 452 qdev_prop_set_uint32(dev, "hartid-base", hartid_base); 453 qdev_prop_set_uint32(dev, "num-harts", num_harts); 454 qdev_prop_set_uint32(dev, "sswi", sswi ? true : false); 455 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 456 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 457 458 for (i = 0; i < num_harts; i++) { 459 CPUState *cpu = qemu_get_cpu(hartid_base + i); 460 RISCVCPU *rvcpu = RISCV_CPU(cpu); 461 462 qdev_connect_gpio_out(dev, i, 463 qdev_get_gpio_in(DEVICE(rvcpu), 464 (sswi) ? IRQ_S_SOFT : IRQ_M_SOFT)); 465 } 466 467 return dev; 468 } 469 470 static void riscv_aclint_register_types(void) 471 { 472 type_register_static(&riscv_aclint_mtimer_info); 473 type_register_static(&riscv_aclint_swi_info); 474 } 475 476 type_init(riscv_aclint_register_types) 477