1 /* 2 * ITS emulation for a GICv3-based system 3 * 4 * Copyright Linaro.org 2021 5 * 6 * Authors: 7 * Shashi Mallela <shashi.mallela@linaro.org> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 10 * option) any later version. See the COPYING file in the top-level directory. 11 * 12 */ 13 14 #include "qemu/osdep.h" 15 #include "qemu/log.h" 16 #include "hw/qdev-properties.h" 17 #include "hw/intc/arm_gicv3_its_common.h" 18 #include "gicv3_internal.h" 19 #include "qom/object.h" 20 #include "qapi/error.h" 21 22 typedef struct GICv3ITSClass GICv3ITSClass; 23 /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */ 24 DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass, 25 ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS) 26 27 struct GICv3ITSClass { 28 GICv3ITSCommonClass parent_class; 29 void (*parent_reset)(DeviceState *dev); 30 }; 31 32 static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz) 33 { 34 uint64_t result = 0; 35 36 switch (page_sz) { 37 case GITS_PAGE_SIZE_4K: 38 case GITS_PAGE_SIZE_16K: 39 result = FIELD_EX64(value, GITS_BASER, PHYADDR) << 12; 40 break; 41 42 case GITS_PAGE_SIZE_64K: 43 result = FIELD_EX64(value, GITS_BASER, PHYADDRL_64K) << 16; 44 result |= FIELD_EX64(value, GITS_BASER, PHYADDRH_64K) << 48; 45 break; 46 47 default: 48 break; 49 } 50 return result; 51 } 52 53 /* 54 * This function extracts the ITS Device and Collection table specific 55 * parameters (like base_addr, size etc) from GITS_BASER register. 56 * It is called during ITS enable and also during post_load migration 57 */ 58 static void extract_table_params(GICv3ITSState *s) 59 { 60 uint16_t num_pages = 0; 61 uint8_t page_sz_type; 62 uint8_t type; 63 uint32_t page_sz = 0; 64 uint64_t value; 65 66 for (int i = 0; i < 8; i++) { 67 value = s->baser[i]; 68 69 if (!value) { 70 continue; 71 } 72 73 page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE); 74 75 switch (page_sz_type) { 76 case 0: 77 page_sz = GITS_PAGE_SIZE_4K; 78 break; 79 80 case 1: 81 page_sz = GITS_PAGE_SIZE_16K; 82 break; 83 84 case 2: 85 case 3: 86 page_sz = GITS_PAGE_SIZE_64K; 87 break; 88 89 default: 90 g_assert_not_reached(); 91 } 92 93 num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1; 94 95 type = FIELD_EX64(value, GITS_BASER, TYPE); 96 97 switch (type) { 98 99 case GITS_BASER_TYPE_DEVICE: 100 memset(&s->dt, 0 , sizeof(s->dt)); 101 s->dt.valid = FIELD_EX64(value, GITS_BASER, VALID); 102 103 if (!s->dt.valid) { 104 return; 105 } 106 107 s->dt.page_sz = page_sz; 108 s->dt.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT); 109 s->dt.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE); 110 111 if (!s->dt.indirect) { 112 s->dt.max_entries = (num_pages * page_sz) / s->dt.entry_sz; 113 } else { 114 s->dt.max_entries = (((num_pages * page_sz) / 115 L1TABLE_ENTRY_SIZE) * 116 (page_sz / s->dt.entry_sz)); 117 } 118 119 s->dt.maxids.max_devids = (1UL << (FIELD_EX64(s->typer, GITS_TYPER, 120 DEVBITS) + 1)); 121 122 s->dt.base_addr = baser_base_addr(value, page_sz); 123 124 break; 125 126 case GITS_BASER_TYPE_COLLECTION: 127 memset(&s->ct, 0 , sizeof(s->ct)); 128 s->ct.valid = FIELD_EX64(value, GITS_BASER, VALID); 129 130 /* 131 * GITS_TYPER.HCC is 0 for this implementation 132 * hence writes are discarded if ct.valid is 0 133 */ 134 if (!s->ct.valid) { 135 return; 136 } 137 138 s->ct.page_sz = page_sz; 139 s->ct.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT); 140 s->ct.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE); 141 142 if (!s->ct.indirect) { 143 s->ct.max_entries = (num_pages * page_sz) / s->ct.entry_sz; 144 } else { 145 s->ct.max_entries = (((num_pages * page_sz) / 146 L1TABLE_ENTRY_SIZE) * 147 (page_sz / s->ct.entry_sz)); 148 } 149 150 if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) { 151 s->ct.maxids.max_collids = (1UL << (FIELD_EX64(s->typer, 152 GITS_TYPER, CIDBITS) + 1)); 153 } else { 154 /* 16-bit CollectionId supported when CIL == 0 */ 155 s->ct.maxids.max_collids = (1UL << 16); 156 } 157 158 s->ct.base_addr = baser_base_addr(value, page_sz); 159 160 break; 161 162 default: 163 break; 164 } 165 } 166 } 167 168 static void extract_cmdq_params(GICv3ITSState *s) 169 { 170 uint16_t num_pages = 0; 171 uint64_t value = s->cbaser; 172 173 num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1; 174 175 memset(&s->cq, 0 , sizeof(s->cq)); 176 s->cq.valid = FIELD_EX64(value, GITS_CBASER, VALID); 177 178 if (s->cq.valid) { 179 s->cq.max_entries = (num_pages * GITS_PAGE_SIZE_4K) / 180 GITS_CMDQ_ENTRY_SIZE; 181 s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR); 182 s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT; 183 } 184 } 185 186 static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset, 187 uint64_t data, unsigned size, 188 MemTxAttrs attrs) 189 { 190 return MEMTX_OK; 191 } 192 193 static bool its_writel(GICv3ITSState *s, hwaddr offset, 194 uint64_t value, MemTxAttrs attrs) 195 { 196 bool result = true; 197 int index; 198 199 switch (offset) { 200 case GITS_CTLR: 201 s->ctlr |= (value & ~(s->ctlr)); 202 203 if (s->ctlr & ITS_CTLR_ENABLED) { 204 extract_table_params(s); 205 extract_cmdq_params(s); 206 s->creadr = 0; 207 } 208 break; 209 case GITS_CBASER: 210 /* 211 * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is 212 * already enabled 213 */ 214 if (!(s->ctlr & ITS_CTLR_ENABLED)) { 215 s->cbaser = deposit64(s->cbaser, 0, 32, value); 216 s->creadr = 0; 217 s->cwriter = s->creadr; 218 } 219 break; 220 case GITS_CBASER + 4: 221 /* 222 * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is 223 * already enabled 224 */ 225 if (!(s->ctlr & ITS_CTLR_ENABLED)) { 226 s->cbaser = deposit64(s->cbaser, 32, 32, value); 227 s->creadr = 0; 228 s->cwriter = s->creadr; 229 } 230 break; 231 case GITS_CWRITER: 232 s->cwriter = deposit64(s->cwriter, 0, 32, 233 (value & ~R_GITS_CWRITER_RETRY_MASK)); 234 break; 235 case GITS_CWRITER + 4: 236 s->cwriter = deposit64(s->cwriter, 32, 32, value); 237 break; 238 case GITS_CREADR: 239 if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) { 240 s->creadr = deposit64(s->creadr, 0, 32, 241 (value & ~R_GITS_CREADR_STALLED_MASK)); 242 } else { 243 /* RO register, ignore the write */ 244 qemu_log_mask(LOG_GUEST_ERROR, 245 "%s: invalid guest write to RO register at offset " 246 TARGET_FMT_plx "\n", __func__, offset); 247 } 248 break; 249 case GITS_CREADR + 4: 250 if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) { 251 s->creadr = deposit64(s->creadr, 32, 32, value); 252 } else { 253 /* RO register, ignore the write */ 254 qemu_log_mask(LOG_GUEST_ERROR, 255 "%s: invalid guest write to RO register at offset " 256 TARGET_FMT_plx "\n", __func__, offset); 257 } 258 break; 259 case GITS_BASER ... GITS_BASER + 0x3f: 260 /* 261 * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is 262 * already enabled 263 */ 264 if (!(s->ctlr & ITS_CTLR_ENABLED)) { 265 index = (offset - GITS_BASER) / 8; 266 267 if (offset & 7) { 268 value <<= 32; 269 value &= ~GITS_BASER_RO_MASK; 270 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32); 271 s->baser[index] |= value; 272 } else { 273 value &= ~GITS_BASER_RO_MASK; 274 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32); 275 s->baser[index] |= value; 276 } 277 } 278 break; 279 case GITS_IIDR: 280 case GITS_IDREGS ... GITS_IDREGS + 0x2f: 281 /* RO registers, ignore the write */ 282 qemu_log_mask(LOG_GUEST_ERROR, 283 "%s: invalid guest write to RO register at offset " 284 TARGET_FMT_plx "\n", __func__, offset); 285 break; 286 default: 287 result = false; 288 break; 289 } 290 return result; 291 } 292 293 static bool its_readl(GICv3ITSState *s, hwaddr offset, 294 uint64_t *data, MemTxAttrs attrs) 295 { 296 bool result = true; 297 int index; 298 299 switch (offset) { 300 case GITS_CTLR: 301 *data = s->ctlr; 302 break; 303 case GITS_IIDR: 304 *data = gicv3_iidr(); 305 break; 306 case GITS_IDREGS ... GITS_IDREGS + 0x2f: 307 /* ID registers */ 308 *data = gicv3_idreg(offset - GITS_IDREGS); 309 break; 310 case GITS_TYPER: 311 *data = extract64(s->typer, 0, 32); 312 break; 313 case GITS_TYPER + 4: 314 *data = extract64(s->typer, 32, 32); 315 break; 316 case GITS_CBASER: 317 *data = extract64(s->cbaser, 0, 32); 318 break; 319 case GITS_CBASER + 4: 320 *data = extract64(s->cbaser, 32, 32); 321 break; 322 case GITS_CREADR: 323 *data = extract64(s->creadr, 0, 32); 324 break; 325 case GITS_CREADR + 4: 326 *data = extract64(s->creadr, 32, 32); 327 break; 328 case GITS_CWRITER: 329 *data = extract64(s->cwriter, 0, 32); 330 break; 331 case GITS_CWRITER + 4: 332 *data = extract64(s->cwriter, 32, 32); 333 break; 334 case GITS_BASER ... GITS_BASER + 0x3f: 335 index = (offset - GITS_BASER) / 8; 336 if (offset & 7) { 337 *data = extract64(s->baser[index], 32, 32); 338 } else { 339 *data = extract64(s->baser[index], 0, 32); 340 } 341 break; 342 default: 343 result = false; 344 break; 345 } 346 return result; 347 } 348 349 static bool its_writell(GICv3ITSState *s, hwaddr offset, 350 uint64_t value, MemTxAttrs attrs) 351 { 352 bool result = true; 353 int index; 354 355 switch (offset) { 356 case GITS_BASER ... GITS_BASER + 0x3f: 357 /* 358 * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is 359 * already enabled 360 */ 361 if (!(s->ctlr & ITS_CTLR_ENABLED)) { 362 index = (offset - GITS_BASER) / 8; 363 s->baser[index] &= GITS_BASER_RO_MASK; 364 s->baser[index] |= (value & ~GITS_BASER_RO_MASK); 365 } 366 break; 367 case GITS_CBASER: 368 /* 369 * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is 370 * already enabled 371 */ 372 if (!(s->ctlr & ITS_CTLR_ENABLED)) { 373 s->cbaser = value; 374 s->creadr = 0; 375 s->cwriter = s->creadr; 376 } 377 break; 378 case GITS_CWRITER: 379 s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK; 380 break; 381 case GITS_CREADR: 382 if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) { 383 s->creadr = value & ~R_GITS_CREADR_STALLED_MASK; 384 } else { 385 /* RO register, ignore the write */ 386 qemu_log_mask(LOG_GUEST_ERROR, 387 "%s: invalid guest write to RO register at offset " 388 TARGET_FMT_plx "\n", __func__, offset); 389 } 390 break; 391 case GITS_TYPER: 392 /* RO registers, ignore the write */ 393 qemu_log_mask(LOG_GUEST_ERROR, 394 "%s: invalid guest write to RO register at offset " 395 TARGET_FMT_plx "\n", __func__, offset); 396 break; 397 default: 398 result = false; 399 break; 400 } 401 return result; 402 } 403 404 static bool its_readll(GICv3ITSState *s, hwaddr offset, 405 uint64_t *data, MemTxAttrs attrs) 406 { 407 bool result = true; 408 int index; 409 410 switch (offset) { 411 case GITS_TYPER: 412 *data = s->typer; 413 break; 414 case GITS_BASER ... GITS_BASER + 0x3f: 415 index = (offset - GITS_BASER) / 8; 416 *data = s->baser[index]; 417 break; 418 case GITS_CBASER: 419 *data = s->cbaser; 420 break; 421 case GITS_CREADR: 422 *data = s->creadr; 423 break; 424 case GITS_CWRITER: 425 *data = s->cwriter; 426 break; 427 default: 428 result = false; 429 break; 430 } 431 return result; 432 } 433 434 static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data, 435 unsigned size, MemTxAttrs attrs) 436 { 437 GICv3ITSState *s = (GICv3ITSState *)opaque; 438 bool result; 439 440 switch (size) { 441 case 4: 442 result = its_readl(s, offset, data, attrs); 443 break; 444 case 8: 445 result = its_readll(s, offset, data, attrs); 446 break; 447 default: 448 result = false; 449 break; 450 } 451 452 if (!result) { 453 qemu_log_mask(LOG_GUEST_ERROR, 454 "%s: invalid guest read at offset " TARGET_FMT_plx 455 "size %u\n", __func__, offset, size); 456 /* 457 * The spec requires that reserved registers are RAZ/WI; 458 * so use false returns from leaf functions as a way to 459 * trigger the guest-error logging but don't return it to 460 * the caller, or we'll cause a spurious guest data abort. 461 */ 462 *data = 0; 463 } 464 return MEMTX_OK; 465 } 466 467 static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data, 468 unsigned size, MemTxAttrs attrs) 469 { 470 GICv3ITSState *s = (GICv3ITSState *)opaque; 471 bool result; 472 473 switch (size) { 474 case 4: 475 result = its_writel(s, offset, data, attrs); 476 break; 477 case 8: 478 result = its_writell(s, offset, data, attrs); 479 break; 480 default: 481 result = false; 482 break; 483 } 484 485 if (!result) { 486 qemu_log_mask(LOG_GUEST_ERROR, 487 "%s: invalid guest write at offset " TARGET_FMT_plx 488 "size %u\n", __func__, offset, size); 489 /* 490 * The spec requires that reserved registers are RAZ/WI; 491 * so use false returns from leaf functions as a way to 492 * trigger the guest-error logging but don't return it to 493 * the caller, or we'll cause a spurious guest data abort. 494 */ 495 } 496 return MEMTX_OK; 497 } 498 499 static const MemoryRegionOps gicv3_its_control_ops = { 500 .read_with_attrs = gicv3_its_read, 501 .write_with_attrs = gicv3_its_write, 502 .valid.min_access_size = 4, 503 .valid.max_access_size = 8, 504 .impl.min_access_size = 4, 505 .impl.max_access_size = 8, 506 .endianness = DEVICE_NATIVE_ENDIAN, 507 }; 508 509 static const MemoryRegionOps gicv3_its_translation_ops = { 510 .write_with_attrs = gicv3_its_translation_write, 511 .valid.min_access_size = 2, 512 .valid.max_access_size = 4, 513 .impl.min_access_size = 2, 514 .impl.max_access_size = 4, 515 .endianness = DEVICE_NATIVE_ENDIAN, 516 }; 517 518 static void gicv3_arm_its_realize(DeviceState *dev, Error **errp) 519 { 520 GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); 521 int i; 522 523 for (i = 0; i < s->gicv3->num_cpu; i++) { 524 if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) { 525 error_setg(errp, "Physical LPI not supported by CPU %d", i); 526 return; 527 } 528 } 529 530 gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops); 531 532 address_space_init(&s->gicv3->dma_as, s->gicv3->dma, 533 "gicv3-its-sysmem"); 534 535 /* set the ITS default features supported */ 536 s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 537 GITS_TYPE_PHYSICAL); 538 s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE, 539 ITS_ITT_ENTRY_SIZE - 1); 540 s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS); 541 s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS); 542 s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1); 543 s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS); 544 } 545 546 static void gicv3_its_reset(DeviceState *dev) 547 { 548 GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); 549 GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s); 550 551 c->parent_reset(dev); 552 553 /* Quiescent bit reset to 1 */ 554 s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1); 555 556 /* 557 * setting GITS_BASER0.Type = 0b001 (Device) 558 * GITS_BASER1.Type = 0b100 (Collection Table) 559 * GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented) 560 * GITS_BASER<0,1>.Page_Size = 64KB 561 * and default translation table entry size to 16 bytes 562 */ 563 s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE, 564 GITS_BASER_TYPE_DEVICE); 565 s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE, 566 GITS_BASER_PAGESIZE_64K); 567 s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE, 568 GITS_DTE_SIZE - 1); 569 570 s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE, 571 GITS_BASER_TYPE_COLLECTION); 572 s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE, 573 GITS_BASER_PAGESIZE_64K); 574 s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE, 575 GITS_CTE_SIZE - 1); 576 } 577 578 static void gicv3_its_post_load(GICv3ITSState *s) 579 { 580 if (s->ctlr & ITS_CTLR_ENABLED) { 581 extract_table_params(s); 582 extract_cmdq_params(s); 583 } 584 } 585 586 static Property gicv3_its_props[] = { 587 DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3", 588 GICv3State *), 589 DEFINE_PROP_END_OF_LIST(), 590 }; 591 592 static void gicv3_its_class_init(ObjectClass *klass, void *data) 593 { 594 DeviceClass *dc = DEVICE_CLASS(klass); 595 GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass); 596 GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); 597 598 dc->realize = gicv3_arm_its_realize; 599 device_class_set_props(dc, gicv3_its_props); 600 device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset); 601 icc->post_load = gicv3_its_post_load; 602 } 603 604 static const TypeInfo gicv3_its_info = { 605 .name = TYPE_ARM_GICV3_ITS, 606 .parent = TYPE_ARM_GICV3_ITS_COMMON, 607 .instance_size = sizeof(GICv3ITSState), 608 .class_init = gicv3_its_class_init, 609 .class_size = sizeof(GICv3ITSClass), 610 }; 611 612 static void gicv3_its_register_types(void) 613 { 614 type_register_static(&gicv3_its_info); 615 } 616 617 type_init(gicv3_its_register_types) 618