1 /* 2 * SiFive PLIC (Platform Level Interrupt Controller) 3 * 4 * Copyright (c) 2017 SiFive, Inc. 5 * 6 * This provides a parameterizable interrupt controller based on SiFive's PLIC. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2 or later, as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qapi/error.h" 23 #include "qemu/log.h" 24 #include "qemu/module.h" 25 #include "qemu/error-report.h" 26 #include "hw/sysbus.h" 27 #include "hw/pci/msi.h" 28 #include "hw/qdev-properties.h" 29 #include "hw/intc/sifive_plic.h" 30 #include "target/riscv/cpu.h" 31 #include "migration/vmstate.h" 32 33 #define RISCV_DEBUG_PLIC 0 34 35 static PLICMode char_to_mode(char c) 36 { 37 switch (c) { 38 case 'U': return PLICMode_U; 39 case 'S': return PLICMode_S; 40 case 'H': return PLICMode_H; 41 case 'M': return PLICMode_M; 42 default: 43 error_report("plic: invalid mode '%c'", c); 44 exit(1); 45 } 46 } 47 48 static char mode_to_char(PLICMode m) 49 { 50 switch (m) { 51 case PLICMode_U: return 'U'; 52 case PLICMode_S: return 'S'; 53 case PLICMode_H: return 'H'; 54 case PLICMode_M: return 'M'; 55 default: return '?'; 56 } 57 } 58 59 static void sifive_plic_print_state(SiFivePLICState *plic) 60 { 61 int i; 62 int addrid; 63 64 /* pending */ 65 qemu_log("pending : "); 66 for (i = plic->bitfield_words - 1; i >= 0; i--) { 67 qemu_log("%08x", plic->pending[i]); 68 } 69 qemu_log("\n"); 70 71 /* pending */ 72 qemu_log("claimed : "); 73 for (i = plic->bitfield_words - 1; i >= 0; i--) { 74 qemu_log("%08x", plic->claimed[i]); 75 } 76 qemu_log("\n"); 77 78 for (addrid = 0; addrid < plic->num_addrs; addrid++) { 79 qemu_log("hart%d-%c enable: ", 80 plic->addr_config[addrid].hartid, 81 mode_to_char(plic->addr_config[addrid].mode)); 82 for (i = plic->bitfield_words - 1; i >= 0; i--) { 83 qemu_log("%08x", plic->enable[addrid * plic->bitfield_words + i]); 84 } 85 qemu_log("\n"); 86 } 87 } 88 89 static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value) 90 { 91 uint32_t old, new, cmp = qatomic_read(a); 92 93 do { 94 old = cmp; 95 new = (old & ~mask) | (value & mask); 96 cmp = qatomic_cmpxchg(a, old, new); 97 } while (old != cmp); 98 99 return old; 100 } 101 102 static void sifive_plic_set_pending(SiFivePLICState *plic, int irq, bool level) 103 { 104 atomic_set_masked(&plic->pending[irq >> 5], 1 << (irq & 31), -!!level); 105 } 106 107 static void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool level) 108 { 109 atomic_set_masked(&plic->claimed[irq >> 5], 1 << (irq & 31), -!!level); 110 } 111 112 static int sifive_plic_irqs_pending(SiFivePLICState *plic, uint32_t addrid) 113 { 114 int i, j; 115 for (i = 0; i < plic->bitfield_words; i++) { 116 uint32_t pending_enabled_not_claimed = 117 (plic->pending[i] & ~plic->claimed[i]) & 118 plic->enable[addrid * plic->bitfield_words + i]; 119 if (!pending_enabled_not_claimed) { 120 continue; 121 } 122 for (j = 0; j < 32; j++) { 123 int irq = (i << 5) + j; 124 uint32_t prio = plic->source_priority[irq]; 125 int enabled = pending_enabled_not_claimed & (1 << j); 126 if (enabled && prio > plic->target_priority[addrid]) { 127 return 1; 128 } 129 } 130 } 131 return 0; 132 } 133 134 static void sifive_plic_update(SiFivePLICState *plic) 135 { 136 int addrid; 137 138 /* raise irq on harts where this irq is enabled */ 139 for (addrid = 0; addrid < plic->num_addrs; addrid++) { 140 uint32_t hartid = plic->addr_config[addrid].hartid; 141 PLICMode mode = plic->addr_config[addrid].mode; 142 CPUState *cpu = qemu_get_cpu(hartid); 143 CPURISCVState *env = cpu ? cpu->env_ptr : NULL; 144 if (!env) { 145 continue; 146 } 147 int level = sifive_plic_irqs_pending(plic, addrid); 148 switch (mode) { 149 case PLICMode_M: 150 riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level)); 151 break; 152 case PLICMode_S: 153 riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level)); 154 break; 155 default: 156 break; 157 } 158 } 159 160 if (RISCV_DEBUG_PLIC) { 161 sifive_plic_print_state(plic); 162 } 163 } 164 165 static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid) 166 { 167 int i, j; 168 uint32_t max_irq = 0; 169 uint32_t max_prio = plic->target_priority[addrid]; 170 171 for (i = 0; i < plic->bitfield_words; i++) { 172 uint32_t pending_enabled_not_claimed = 173 (plic->pending[i] & ~plic->claimed[i]) & 174 plic->enable[addrid * plic->bitfield_words + i]; 175 if (!pending_enabled_not_claimed) { 176 continue; 177 } 178 for (j = 0; j < 32; j++) { 179 int irq = (i << 5) + j; 180 uint32_t prio = plic->source_priority[irq]; 181 int enabled = pending_enabled_not_claimed & (1 << j); 182 if (enabled && prio > max_prio) { 183 max_irq = irq; 184 max_prio = prio; 185 } 186 } 187 } 188 189 if (max_irq) { 190 sifive_plic_set_pending(plic, max_irq, false); 191 sifive_plic_set_claimed(plic, max_irq, true); 192 } 193 return max_irq; 194 } 195 196 static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) 197 { 198 SiFivePLICState *plic = opaque; 199 200 /* writes must be 4 byte words */ 201 if ((addr & 0x3) != 0) { 202 goto err; 203 } 204 205 if (addr >= plic->priority_base && /* 4 bytes per source */ 206 addr < plic->priority_base + (plic->num_sources << 2)) 207 { 208 uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; 209 if (RISCV_DEBUG_PLIC) { 210 qemu_log("plic: read priority: irq=%d priority=%d\n", 211 irq, plic->source_priority[irq]); 212 } 213 return plic->source_priority[irq]; 214 } else if (addr >= plic->pending_base && /* 1 bit per source */ 215 addr < plic->pending_base + (plic->num_sources >> 3)) 216 { 217 uint32_t word = (addr - plic->pending_base) >> 2; 218 if (RISCV_DEBUG_PLIC) { 219 qemu_log("plic: read pending: word=%d value=%d\n", 220 word, plic->pending[word]); 221 } 222 return plic->pending[word]; 223 } else if (addr >= plic->enable_base && /* 1 bit per source */ 224 addr < plic->enable_base + plic->num_addrs * plic->enable_stride) 225 { 226 uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride; 227 uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2; 228 if (wordid < plic->bitfield_words) { 229 if (RISCV_DEBUG_PLIC) { 230 qemu_log("plic: read enable: hart%d-%c word=%d value=%x\n", 231 plic->addr_config[addrid].hartid, 232 mode_to_char(plic->addr_config[addrid].mode), wordid, 233 plic->enable[addrid * plic->bitfield_words + wordid]); 234 } 235 return plic->enable[addrid * plic->bitfield_words + wordid]; 236 } 237 } else if (addr >= plic->context_base && /* 1 bit per source */ 238 addr < plic->context_base + plic->num_addrs * plic->context_stride) 239 { 240 uint32_t addrid = (addr - plic->context_base) / plic->context_stride; 241 uint32_t contextid = (addr & (plic->context_stride - 1)); 242 if (contextid == 0) { 243 if (RISCV_DEBUG_PLIC) { 244 qemu_log("plic: read priority: hart%d-%c priority=%x\n", 245 plic->addr_config[addrid].hartid, 246 mode_to_char(plic->addr_config[addrid].mode), 247 plic->target_priority[addrid]); 248 } 249 return plic->target_priority[addrid]; 250 } else if (contextid == 4) { 251 uint32_t value = sifive_plic_claim(plic, addrid); 252 if (RISCV_DEBUG_PLIC) { 253 qemu_log("plic: read claim: hart%d-%c irq=%x\n", 254 plic->addr_config[addrid].hartid, 255 mode_to_char(plic->addr_config[addrid].mode), 256 value); 257 } 258 sifive_plic_update(plic); 259 return value; 260 } 261 } 262 263 err: 264 qemu_log_mask(LOG_GUEST_ERROR, 265 "%s: Invalid register read 0x%" HWADDR_PRIx "\n", 266 __func__, addr); 267 return 0; 268 } 269 270 static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, 271 unsigned size) 272 { 273 SiFivePLICState *plic = opaque; 274 275 /* writes must be 4 byte words */ 276 if ((addr & 0x3) != 0) { 277 goto err; 278 } 279 280 if (addr >= plic->priority_base && /* 4 bytes per source */ 281 addr < plic->priority_base + (plic->num_sources << 2)) 282 { 283 uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; 284 plic->source_priority[irq] = value & 7; 285 if (RISCV_DEBUG_PLIC) { 286 qemu_log("plic: write priority: irq=%d priority=%d\n", 287 irq, plic->source_priority[irq]); 288 } 289 sifive_plic_update(plic); 290 return; 291 } else if (addr >= plic->pending_base && /* 1 bit per source */ 292 addr < plic->pending_base + (plic->num_sources >> 3)) 293 { 294 qemu_log_mask(LOG_GUEST_ERROR, 295 "%s: invalid pending write: 0x%" HWADDR_PRIx "", 296 __func__, addr); 297 return; 298 } else if (addr >= plic->enable_base && /* 1 bit per source */ 299 addr < plic->enable_base + plic->num_addrs * plic->enable_stride) 300 { 301 uint32_t addrid = (addr - plic->enable_base) / plic->enable_stride; 302 uint32_t wordid = (addr & (plic->enable_stride - 1)) >> 2; 303 if (wordid < plic->bitfield_words) { 304 plic->enable[addrid * plic->bitfield_words + wordid] = value; 305 if (RISCV_DEBUG_PLIC) { 306 qemu_log("plic: write enable: hart%d-%c word=%d value=%x\n", 307 plic->addr_config[addrid].hartid, 308 mode_to_char(plic->addr_config[addrid].mode), wordid, 309 plic->enable[addrid * plic->bitfield_words + wordid]); 310 } 311 return; 312 } 313 } else if (addr >= plic->context_base && /* 4 bytes per reg */ 314 addr < plic->context_base + plic->num_addrs * plic->context_stride) 315 { 316 uint32_t addrid = (addr - plic->context_base) / plic->context_stride; 317 uint32_t contextid = (addr & (plic->context_stride - 1)); 318 if (contextid == 0) { 319 if (RISCV_DEBUG_PLIC) { 320 qemu_log("plic: write priority: hart%d-%c priority=%x\n", 321 plic->addr_config[addrid].hartid, 322 mode_to_char(plic->addr_config[addrid].mode), 323 plic->target_priority[addrid]); 324 } 325 if (value <= plic->num_priorities) { 326 plic->target_priority[addrid] = value; 327 sifive_plic_update(plic); 328 } 329 return; 330 } else if (contextid == 4) { 331 if (RISCV_DEBUG_PLIC) { 332 qemu_log("plic: write claim: hart%d-%c irq=%x\n", 333 plic->addr_config[addrid].hartid, 334 mode_to_char(plic->addr_config[addrid].mode), 335 (uint32_t)value); 336 } 337 if (value < plic->num_sources) { 338 sifive_plic_set_claimed(plic, value, false); 339 sifive_plic_update(plic); 340 } 341 return; 342 } 343 } 344 345 err: 346 qemu_log_mask(LOG_GUEST_ERROR, 347 "%s: Invalid register write 0x%" HWADDR_PRIx "\n", 348 __func__, addr); 349 } 350 351 static const MemoryRegionOps sifive_plic_ops = { 352 .read = sifive_plic_read, 353 .write = sifive_plic_write, 354 .endianness = DEVICE_LITTLE_ENDIAN, 355 .valid = { 356 .min_access_size = 4, 357 .max_access_size = 4 358 } 359 }; 360 361 static Property sifive_plic_properties[] = { 362 DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config), 363 DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0), 364 DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0), 365 DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0), 366 DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0), 367 DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0), 368 DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0), 369 DEFINE_PROP_UINT32("enable-stride", SiFivePLICState, enable_stride, 0), 370 DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0), 371 DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0), 372 DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0), 373 DEFINE_PROP_END_OF_LIST(), 374 }; 375 376 /* 377 * parse PLIC hart/mode address offset config 378 * 379 * "M" 1 hart with M mode 380 * "MS,MS" 2 harts, 0-1 with M and S mode 381 * "M,MS,MS,MS,MS" 5 harts, 0 with M mode, 1-5 with M and S mode 382 */ 383 static void parse_hart_config(SiFivePLICState *plic) 384 { 385 int addrid, hartid, modes; 386 const char *p; 387 char c; 388 389 /* count and validate hart/mode combinations */ 390 addrid = 0, hartid = 0, modes = 0; 391 p = plic->hart_config; 392 while ((c = *p++)) { 393 if (c == ',') { 394 addrid += ctpop8(modes); 395 modes = 0; 396 hartid++; 397 } else { 398 int m = 1 << char_to_mode(c); 399 if (modes == (modes | m)) { 400 error_report("plic: duplicate mode '%c' in config: %s", 401 c, plic->hart_config); 402 exit(1); 403 } 404 modes |= m; 405 } 406 } 407 if (modes) { 408 addrid += ctpop8(modes); 409 } 410 hartid++; 411 412 plic->num_addrs = addrid; 413 plic->num_harts = hartid; 414 415 /* store hart/mode combinations */ 416 plic->addr_config = g_new(PLICAddr, plic->num_addrs); 417 addrid = 0, hartid = plic->hartid_base; 418 p = plic->hart_config; 419 while ((c = *p++)) { 420 if (c == ',') { 421 hartid++; 422 } else { 423 plic->addr_config[addrid].addrid = addrid; 424 plic->addr_config[addrid].hartid = hartid; 425 plic->addr_config[addrid].mode = char_to_mode(c); 426 addrid++; 427 } 428 } 429 } 430 431 static void sifive_plic_irq_request(void *opaque, int irq, int level) 432 { 433 SiFivePLICState *plic = opaque; 434 if (RISCV_DEBUG_PLIC) { 435 qemu_log("sifive_plic_irq_request: irq=%d level=%d\n", irq, level); 436 } 437 sifive_plic_set_pending(plic, irq, level > 0); 438 sifive_plic_update(plic); 439 } 440 441 static void sifive_plic_realize(DeviceState *dev, Error **errp) 442 { 443 SiFivePLICState *plic = SIFIVE_PLIC(dev); 444 int i; 445 446 memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic, 447 TYPE_SIFIVE_PLIC, plic->aperture_size); 448 parse_hart_config(plic); 449 plic->bitfield_words = (plic->num_sources + 31) >> 5; 450 plic->num_enables = plic->bitfield_words * plic->num_addrs; 451 plic->source_priority = g_new0(uint32_t, plic->num_sources); 452 plic->target_priority = g_new(uint32_t, plic->num_addrs); 453 plic->pending = g_new0(uint32_t, plic->bitfield_words); 454 plic->claimed = g_new0(uint32_t, plic->bitfield_words); 455 plic->enable = g_new0(uint32_t, plic->num_enables); 456 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio); 457 qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources); 458 459 /* We can't allow the supervisor to control SEIP as this would allow the 460 * supervisor to clear a pending external interrupt which will result in 461 * lost a interrupt in the case a PLIC is attached. The SEIP bit must be 462 * hardware controlled when a PLIC is attached. 463 */ 464 for (i = 0; i < plic->num_harts; i++) { 465 RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(plic->hartid_base + i)); 466 if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { 467 error_report("SEIP already claimed"); 468 exit(1); 469 } 470 } 471 472 msi_nonbroken = true; 473 } 474 475 static const VMStateDescription vmstate_sifive_plic = { 476 .name = "riscv_sifive_plic", 477 .version_id = 1, 478 .minimum_version_id = 1, 479 .fields = (VMStateField[]) { 480 VMSTATE_VARRAY_UINT32(source_priority, SiFivePLICState, 481 num_sources, 0, 482 vmstate_info_uint32, uint32_t), 483 VMSTATE_VARRAY_UINT32(target_priority, SiFivePLICState, 484 num_addrs, 0, 485 vmstate_info_uint32, uint32_t), 486 VMSTATE_VARRAY_UINT32(pending, SiFivePLICState, bitfield_words, 0, 487 vmstate_info_uint32, uint32_t), 488 VMSTATE_VARRAY_UINT32(claimed, SiFivePLICState, bitfield_words, 0, 489 vmstate_info_uint32, uint32_t), 490 VMSTATE_VARRAY_UINT32(enable, SiFivePLICState, num_enables, 0, 491 vmstate_info_uint32, uint32_t), 492 VMSTATE_END_OF_LIST() 493 } 494 }; 495 496 static void sifive_plic_class_init(ObjectClass *klass, void *data) 497 { 498 DeviceClass *dc = DEVICE_CLASS(klass); 499 500 device_class_set_props(dc, sifive_plic_properties); 501 dc->realize = sifive_plic_realize; 502 dc->vmsd = &vmstate_sifive_plic; 503 } 504 505 static const TypeInfo sifive_plic_info = { 506 .name = TYPE_SIFIVE_PLIC, 507 .parent = TYPE_SYS_BUS_DEVICE, 508 .instance_size = sizeof(SiFivePLICState), 509 .class_init = sifive_plic_class_init, 510 }; 511 512 static void sifive_plic_register_types(void) 513 { 514 type_register_static(&sifive_plic_info); 515 } 516 517 type_init(sifive_plic_register_types) 518 519 /* 520 * Create PLIC device. 521 */ 522 DeviceState *sifive_plic_create(hwaddr addr, char *hart_config, 523 uint32_t hartid_base, uint32_t num_sources, 524 uint32_t num_priorities, uint32_t priority_base, 525 uint32_t pending_base, uint32_t enable_base, 526 uint32_t enable_stride, uint32_t context_base, 527 uint32_t context_stride, uint32_t aperture_size) 528 { 529 DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC); 530 assert(enable_stride == (enable_stride & -enable_stride)); 531 assert(context_stride == (context_stride & -context_stride)); 532 qdev_prop_set_string(dev, "hart-config", hart_config); 533 qdev_prop_set_uint32(dev, "hartid-base", hartid_base); 534 qdev_prop_set_uint32(dev, "num-sources", num_sources); 535 qdev_prop_set_uint32(dev, "num-priorities", num_priorities); 536 qdev_prop_set_uint32(dev, "priority-base", priority_base); 537 qdev_prop_set_uint32(dev, "pending-base", pending_base); 538 qdev_prop_set_uint32(dev, "enable-base", enable_base); 539 qdev_prop_set_uint32(dev, "enable-stride", enable_stride); 540 qdev_prop_set_uint32(dev, "context-base", context_base); 541 qdev_prop_set_uint32(dev, "context-stride", context_stride); 542 qdev_prop_set_uint32(dev, "aperture-size", aperture_size); 543 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 544 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); 545 return dev; 546 } 547