1 /* 2 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the Open Source and Linux Lab nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "qemu/osdep.h" 29 #include "qemu/units.h" 30 #include "cpu.h" 31 #include "exec/exec-all.h" 32 #include "exec/gdbstub.h" 33 #include "qemu/host-utils.h" 34 #if !defined(CONFIG_USER_ONLY) 35 #include "hw/loader.h" 36 #endif 37 38 static struct XtensaConfigList *xtensa_cores; 39 40 static void xtensa_core_class_init(ObjectClass *oc, void *data) 41 { 42 CPUClass *cc = CPU_CLASS(oc); 43 XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc); 44 const XtensaConfig *config = data; 45 46 xcc->config = config; 47 48 /* Use num_core_regs to see only non-privileged registers in an unmodified 49 * gdb. Use num_regs to see all registers. gdb modification is required 50 * for that: reset bit 0 in the 'flags' field of the registers definitions 51 * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. 52 */ 53 cc->gdb_num_core_regs = config->gdb_regmap.num_regs; 54 } 55 56 static void init_libisa(XtensaConfig *config) 57 { 58 unsigned i, j; 59 unsigned opcodes; 60 61 config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL); 62 assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH); 63 opcodes = xtensa_isa_num_opcodes(config->isa); 64 config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes); 65 66 for (i = 0; i < opcodes; ++i) { 67 const char *opc_name = xtensa_opcode_name(config->isa, i); 68 XtensaOpcodeOps *ops = NULL; 69 70 assert(xtensa_opcode_num_operands(config->isa, i) <= MAX_OPCODE_ARGS); 71 if (!config->opcode_translators) { 72 ops = xtensa_find_opcode_ops(&xtensa_core_opcodes, opc_name); 73 } else { 74 for (j = 0; !ops && config->opcode_translators[j]; ++j) { 75 ops = xtensa_find_opcode_ops(config->opcode_translators[j], 76 opc_name); 77 } 78 } 79 #ifdef DEBUG 80 if (ops == NULL) { 81 fprintf(stderr, 82 "opcode translator not found for %s's opcode '%s'\n", 83 config->name, opc_name); 84 } 85 #endif 86 config->opcode_ops[i] = ops; 87 } 88 } 89 90 void xtensa_finalize_config(XtensaConfig *config) 91 { 92 if (config->isa_internal) { 93 init_libisa(config); 94 } 95 96 if (config->gdb_regmap.num_regs == 0 || 97 config->gdb_regmap.num_core_regs == 0) { 98 unsigned i; 99 unsigned n_regs = 0; 100 unsigned n_core_regs = 0; 101 102 for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) { 103 if (config->gdb_regmap.reg[i].type != 6) { 104 ++n_regs; 105 if ((config->gdb_regmap.reg[i].flags & 0x1) == 0) { 106 ++n_core_regs; 107 } 108 } 109 } 110 if (config->gdb_regmap.num_regs == 0) { 111 config->gdb_regmap.num_regs = n_regs; 112 } 113 if (config->gdb_regmap.num_core_regs == 0) { 114 config->gdb_regmap.num_core_regs = n_core_regs; 115 } 116 } 117 } 118 119 void xtensa_register_core(XtensaConfigList *node) 120 { 121 TypeInfo type = { 122 .parent = TYPE_XTENSA_CPU, 123 .class_init = xtensa_core_class_init, 124 .class_data = (void *)node->config, 125 }; 126 127 node->next = xtensa_cores; 128 xtensa_cores = node; 129 type.name = g_strdup_printf(XTENSA_CPU_TYPE_NAME("%s"), node->config->name); 130 type_register(&type); 131 g_free((gpointer)type.name); 132 } 133 134 static uint32_t check_hw_breakpoints(CPUXtensaState *env) 135 { 136 unsigned i; 137 138 for (i = 0; i < env->config->ndbreak; ++i) { 139 if (env->cpu_watchpoint[i] && 140 env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) { 141 return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT); 142 } 143 } 144 return 0; 145 } 146 147 void xtensa_breakpoint_handler(CPUState *cs) 148 { 149 XtensaCPU *cpu = XTENSA_CPU(cs); 150 CPUXtensaState *env = &cpu->env; 151 152 if (cs->watchpoint_hit) { 153 if (cs->watchpoint_hit->flags & BP_CPU) { 154 uint32_t cause; 155 156 cs->watchpoint_hit = NULL; 157 cause = check_hw_breakpoints(env); 158 if (cause) { 159 debug_exception_env(env, cause); 160 } 161 cpu_loop_exit_noexc(cs); 162 } 163 } 164 } 165 166 void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf) 167 { 168 XtensaConfigList *core = xtensa_cores; 169 cpu_fprintf(f, "Available CPUs:\n"); 170 for (; core; core = core->next) { 171 cpu_fprintf(f, " %s\n", core->config->name); 172 } 173 } 174 175 hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 176 { 177 #ifndef CONFIG_USER_ONLY 178 XtensaCPU *cpu = XTENSA_CPU(cs); 179 uint32_t paddr; 180 uint32_t page_size; 181 unsigned access; 182 183 if (xtensa_get_physical_addr(&cpu->env, false, addr, 0, 0, 184 &paddr, &page_size, &access) == 0) { 185 return paddr; 186 } 187 if (xtensa_get_physical_addr(&cpu->env, false, addr, 2, 0, 188 &paddr, &page_size, &access) == 0) { 189 return paddr; 190 } 191 return ~0; 192 #else 193 return addr; 194 #endif 195 } 196 197 #ifndef CONFIG_USER_ONLY 198 199 static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector) 200 { 201 if (xtensa_option_enabled(env->config, 202 XTENSA_OPTION_RELOCATABLE_VECTOR)) { 203 return vector - env->config->vecbase + env->sregs[VECBASE]; 204 } else { 205 return vector; 206 } 207 } 208 209 /*! 210 * Handle penging IRQ. 211 * For the high priority interrupt jump to the corresponding interrupt vector. 212 * For the level-1 interrupt convert it to either user, kernel or double 213 * exception with the 'level-1 interrupt' exception cause. 214 */ 215 static void handle_interrupt(CPUXtensaState *env) 216 { 217 int level = env->pending_irq_level; 218 219 if (level > xtensa_get_cintlevel(env) && 220 level <= env->config->nlevel && 221 (env->config->level_mask[level] & 222 env->sregs[INTSET] & 223 env->sregs[INTENABLE])) { 224 CPUState *cs = CPU(xtensa_env_get_cpu(env)); 225 226 if (level > 1) { 227 env->sregs[EPC1 + level - 1] = env->pc; 228 env->sregs[EPS2 + level - 2] = env->sregs[PS]; 229 env->sregs[PS] = 230 (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM; 231 env->pc = relocated_vector(env, 232 env->config->interrupt_vector[level]); 233 } else { 234 env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE; 235 236 if (env->sregs[PS] & PS_EXCM) { 237 if (env->config->ndepc) { 238 env->sregs[DEPC] = env->pc; 239 } else { 240 env->sregs[EPC1] = env->pc; 241 } 242 cs->exception_index = EXC_DOUBLE; 243 } else { 244 env->sregs[EPC1] = env->pc; 245 cs->exception_index = 246 (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; 247 } 248 env->sregs[PS] |= PS_EXCM; 249 } 250 env->exception_taken = 1; 251 } 252 } 253 254 /* Called from cpu_handle_interrupt with BQL held */ 255 void xtensa_cpu_do_interrupt(CPUState *cs) 256 { 257 XtensaCPU *cpu = XTENSA_CPU(cs); 258 CPUXtensaState *env = &cpu->env; 259 260 if (cs->exception_index == EXC_IRQ) { 261 qemu_log_mask(CPU_LOG_INT, 262 "%s(EXC_IRQ) level = %d, cintlevel = %d, " 263 "pc = %08x, a0 = %08x, ps = %08x, " 264 "intset = %08x, intenable = %08x, " 265 "ccount = %08x\n", 266 __func__, env->pending_irq_level, xtensa_get_cintlevel(env), 267 env->pc, env->regs[0], env->sregs[PS], 268 env->sregs[INTSET], env->sregs[INTENABLE], 269 env->sregs[CCOUNT]); 270 handle_interrupt(env); 271 } 272 273 switch (cs->exception_index) { 274 case EXC_WINDOW_OVERFLOW4: 275 case EXC_WINDOW_UNDERFLOW4: 276 case EXC_WINDOW_OVERFLOW8: 277 case EXC_WINDOW_UNDERFLOW8: 278 case EXC_WINDOW_OVERFLOW12: 279 case EXC_WINDOW_UNDERFLOW12: 280 case EXC_KERNEL: 281 case EXC_USER: 282 case EXC_DOUBLE: 283 case EXC_DEBUG: 284 qemu_log_mask(CPU_LOG_INT, "%s(%d) " 285 "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n", 286 __func__, cs->exception_index, 287 env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]); 288 if (env->config->exception_vector[cs->exception_index]) { 289 env->pc = relocated_vector(env, 290 env->config->exception_vector[cs->exception_index]); 291 env->exception_taken = 1; 292 } else { 293 qemu_log_mask(CPU_LOG_INT, "%s(pc = %08x) bad exception_index: %d\n", 294 __func__, env->pc, cs->exception_index); 295 } 296 break; 297 298 case EXC_IRQ: 299 break; 300 301 default: 302 qemu_log("%s(pc = %08x) unknown exception_index: %d\n", 303 __func__, env->pc, cs->exception_index); 304 break; 305 } 306 check_interrupts(env); 307 } 308 #else 309 void xtensa_cpu_do_interrupt(CPUState *cs) 310 { 311 } 312 #endif 313 314 bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 315 { 316 if (interrupt_request & CPU_INTERRUPT_HARD) { 317 cs->exception_index = EXC_IRQ; 318 xtensa_cpu_do_interrupt(cs); 319 return true; 320 } 321 return false; 322 } 323 324 #ifdef CONFIG_USER_ONLY 325 326 int xtensa_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw, 327 int mmu_idx) 328 { 329 XtensaCPU *cpu = XTENSA_CPU(cs); 330 CPUXtensaState *env = &cpu->env; 331 332 qemu_log_mask(CPU_LOG_INT, 333 "%s: rw = %d, address = 0x%08" VADDR_PRIx ", size = %d\n", 334 __func__, rw, address, size); 335 env->sregs[EXCVADDR] = address; 336 env->sregs[EXCCAUSE] = rw ? STORE_PROHIBITED_CAUSE : LOAD_PROHIBITED_CAUSE; 337 cs->exception_index = EXC_USER; 338 return 1; 339 } 340 341 #else 342 343 static void reset_tlb_mmu_all_ways(CPUXtensaState *env, 344 const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) 345 { 346 unsigned wi, ei; 347 348 for (wi = 0; wi < tlb->nways; ++wi) { 349 for (ei = 0; ei < tlb->way_size[wi]; ++ei) { 350 entry[wi][ei].asid = 0; 351 entry[wi][ei].variable = true; 352 } 353 } 354 } 355 356 static void reset_tlb_mmu_ways56(CPUXtensaState *env, 357 const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) 358 { 359 if (!tlb->varway56) { 360 static const xtensa_tlb_entry way5[] = { 361 { 362 .vaddr = 0xd0000000, 363 .paddr = 0, 364 .asid = 1, 365 .attr = 7, 366 .variable = false, 367 }, { 368 .vaddr = 0xd8000000, 369 .paddr = 0, 370 .asid = 1, 371 .attr = 3, 372 .variable = false, 373 } 374 }; 375 static const xtensa_tlb_entry way6[] = { 376 { 377 .vaddr = 0xe0000000, 378 .paddr = 0xf0000000, 379 .asid = 1, 380 .attr = 7, 381 .variable = false, 382 }, { 383 .vaddr = 0xf0000000, 384 .paddr = 0xf0000000, 385 .asid = 1, 386 .attr = 3, 387 .variable = false, 388 } 389 }; 390 memcpy(entry[5], way5, sizeof(way5)); 391 memcpy(entry[6], way6, sizeof(way6)); 392 } else { 393 uint32_t ei; 394 for (ei = 0; ei < 8; ++ei) { 395 entry[6][ei].vaddr = ei << 29; 396 entry[6][ei].paddr = ei << 29; 397 entry[6][ei].asid = 1; 398 entry[6][ei].attr = 3; 399 } 400 } 401 } 402 403 static void reset_tlb_region_way0(CPUXtensaState *env, 404 xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) 405 { 406 unsigned ei; 407 408 for (ei = 0; ei < 8; ++ei) { 409 entry[0][ei].vaddr = ei << 29; 410 entry[0][ei].paddr = ei << 29; 411 entry[0][ei].asid = 1; 412 entry[0][ei].attr = 2; 413 entry[0][ei].variable = true; 414 } 415 } 416 417 void reset_mmu(CPUXtensaState *env) 418 { 419 if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { 420 env->sregs[RASID] = 0x04030201; 421 env->sregs[ITLBCFG] = 0; 422 env->sregs[DTLBCFG] = 0; 423 env->autorefill_idx = 0; 424 reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb); 425 reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb); 426 reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb); 427 reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb); 428 } else { 429 reset_tlb_region_way0(env, env->itlb); 430 reset_tlb_region_way0(env, env->dtlb); 431 } 432 } 433 434 static unsigned get_ring(const CPUXtensaState *env, uint8_t asid) 435 { 436 unsigned i; 437 for (i = 0; i < 4; ++i) { 438 if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) { 439 return i; 440 } 441 } 442 return 0xff; 443 } 444 445 /*! 446 * Lookup xtensa TLB for the given virtual address. 447 * See ISA, 4.6.2.2 448 * 449 * \param pwi: [out] way index 450 * \param pei: [out] entry index 451 * \param pring: [out] access ring 452 * \return 0 if ok, exception cause code otherwise 453 */ 454 int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, 455 uint32_t *pwi, uint32_t *pei, uint8_t *pring) 456 { 457 const xtensa_tlb *tlb = dtlb ? 458 &env->config->dtlb : &env->config->itlb; 459 const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ? 460 env->dtlb : env->itlb; 461 462 int nhits = 0; 463 unsigned wi; 464 465 for (wi = 0; wi < tlb->nways; ++wi) { 466 uint32_t vpn; 467 uint32_t ei; 468 split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei); 469 if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) { 470 unsigned ring = get_ring(env, entry[wi][ei].asid); 471 if (ring < 4) { 472 if (++nhits > 1) { 473 return dtlb ? 474 LOAD_STORE_TLB_MULTI_HIT_CAUSE : 475 INST_TLB_MULTI_HIT_CAUSE; 476 } 477 *pwi = wi; 478 *pei = ei; 479 *pring = ring; 480 } 481 } 482 } 483 return nhits ? 0 : 484 (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE); 485 } 486 487 /*! 488 * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask. 489 * See ISA, 4.6.5.10 490 */ 491 static unsigned mmu_attr_to_access(uint32_t attr) 492 { 493 unsigned access = 0; 494 495 if (attr < 12) { 496 access |= PAGE_READ; 497 if (attr & 0x1) { 498 access |= PAGE_EXEC; 499 } 500 if (attr & 0x2) { 501 access |= PAGE_WRITE; 502 } 503 504 switch (attr & 0xc) { 505 case 0: 506 access |= PAGE_CACHE_BYPASS; 507 break; 508 509 case 4: 510 access |= PAGE_CACHE_WB; 511 break; 512 513 case 8: 514 access |= PAGE_CACHE_WT; 515 break; 516 } 517 } else if (attr == 13) { 518 access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE; 519 } 520 return access; 521 } 522 523 /*! 524 * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask. 525 * See ISA, 4.6.3.3 526 */ 527 static unsigned region_attr_to_access(uint32_t attr) 528 { 529 static const unsigned access[16] = { 530 [0] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_WT, 531 [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, 532 [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, 533 [3] = PAGE_EXEC | PAGE_CACHE_WB, 534 [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, 535 [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, 536 [14] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE, 537 }; 538 539 return access[attr & 0xf]; 540 } 541 542 /*! 543 * Convert cacheattr to PAGE_{READ,WRITE,EXEC} mask. 544 * See ISA, A.2.14 The Cache Attribute Register 545 */ 546 static unsigned cacheattr_attr_to_access(uint32_t attr) 547 { 548 static const unsigned access[16] = { 549 [0] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_WT, 550 [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, 551 [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, 552 [3] = PAGE_EXEC | PAGE_CACHE_WB, 553 [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, 554 [14] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE, 555 }; 556 557 return access[attr & 0xf]; 558 } 559 560 static bool is_access_granted(unsigned access, int is_write) 561 { 562 switch (is_write) { 563 case 0: 564 return access & PAGE_READ; 565 566 case 1: 567 return access & PAGE_WRITE; 568 569 case 2: 570 return access & PAGE_EXEC; 571 572 default: 573 return 0; 574 } 575 } 576 577 static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte); 578 579 static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb, 580 uint32_t vaddr, int is_write, int mmu_idx, 581 uint32_t *paddr, uint32_t *page_size, unsigned *access, 582 bool may_lookup_pt) 583 { 584 bool dtlb = is_write != 2; 585 uint32_t wi; 586 uint32_t ei; 587 uint8_t ring; 588 uint32_t vpn; 589 uint32_t pte; 590 const xtensa_tlb_entry *entry = NULL; 591 xtensa_tlb_entry tmp_entry; 592 int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring); 593 594 if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) && 595 may_lookup_pt && get_pte(env, vaddr, &pte) == 0) { 596 ring = (pte >> 4) & 0x3; 597 wi = 0; 598 split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei); 599 600 if (update_tlb) { 601 wi = ++env->autorefill_idx & 0x3; 602 xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte); 603 env->sregs[EXCVADDR] = vaddr; 604 qemu_log_mask(CPU_LOG_MMU, "%s: autorefill(%08x): %08x -> %08x\n", 605 __func__, vaddr, vpn, pte); 606 } else { 607 xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte); 608 entry = &tmp_entry; 609 } 610 ret = 0; 611 } 612 if (ret != 0) { 613 return ret; 614 } 615 616 if (entry == NULL) { 617 entry = xtensa_tlb_get_entry(env, dtlb, wi, ei); 618 } 619 620 if (ring < mmu_idx) { 621 return dtlb ? 622 LOAD_STORE_PRIVILEGE_CAUSE : 623 INST_FETCH_PRIVILEGE_CAUSE; 624 } 625 626 *access = mmu_attr_to_access(entry->attr) & 627 ~(dtlb ? PAGE_EXEC : PAGE_READ | PAGE_WRITE); 628 if (!is_access_granted(*access, is_write)) { 629 return dtlb ? 630 (is_write ? 631 STORE_PROHIBITED_CAUSE : 632 LOAD_PROHIBITED_CAUSE) : 633 INST_FETCH_PROHIBITED_CAUSE; 634 } 635 636 *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi)); 637 *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1; 638 639 return 0; 640 } 641 642 static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte) 643 { 644 CPUState *cs = CPU(xtensa_env_get_cpu(env)); 645 uint32_t paddr; 646 uint32_t page_size; 647 unsigned access; 648 uint32_t pt_vaddr = 649 (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc; 650 int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0, 651 &paddr, &page_size, &access, false); 652 653 qemu_log_mask(CPU_LOG_MMU, "%s: trying autorefill(%08x) -> %08x\n", 654 __func__, vaddr, ret ? ~0 : paddr); 655 656 if (ret == 0) { 657 *pte = ldl_phys(cs->as, paddr); 658 } 659 return ret; 660 } 661 662 static int get_physical_addr_region(CPUXtensaState *env, 663 uint32_t vaddr, int is_write, int mmu_idx, 664 uint32_t *paddr, uint32_t *page_size, unsigned *access) 665 { 666 bool dtlb = is_write != 2; 667 uint32_t wi = 0; 668 uint32_t ei = (vaddr >> 29) & 0x7; 669 const xtensa_tlb_entry *entry = 670 xtensa_tlb_get_entry(env, dtlb, wi, ei); 671 672 *access = region_attr_to_access(entry->attr); 673 if (!is_access_granted(*access, is_write)) { 674 return dtlb ? 675 (is_write ? 676 STORE_PROHIBITED_CAUSE : 677 LOAD_PROHIBITED_CAUSE) : 678 INST_FETCH_PROHIBITED_CAUSE; 679 } 680 681 *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK); 682 *page_size = ~REGION_PAGE_MASK + 1; 683 684 return 0; 685 } 686 687 /*! 688 * Convert virtual address to physical addr. 689 * MMU may issue pagewalk and change xtensa autorefill TLB way entry. 690 * 691 * \return 0 if ok, exception cause code otherwise 692 */ 693 int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, 694 uint32_t vaddr, int is_write, int mmu_idx, 695 uint32_t *paddr, uint32_t *page_size, unsigned *access) 696 { 697 if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { 698 return get_physical_addr_mmu(env, update_tlb, 699 vaddr, is_write, mmu_idx, paddr, page_size, access, true); 700 } else if (xtensa_option_bits_enabled(env->config, 701 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | 702 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) { 703 return get_physical_addr_region(env, vaddr, is_write, mmu_idx, 704 paddr, page_size, access); 705 } else { 706 *paddr = vaddr; 707 *page_size = TARGET_PAGE_SIZE; 708 *access = cacheattr_attr_to_access( 709 env->sregs[CACHEATTR] >> ((vaddr & 0xe0000000) >> 27)); 710 return 0; 711 } 712 } 713 714 static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, 715 CPUXtensaState *env, bool dtlb) 716 { 717 unsigned wi, ei; 718 const xtensa_tlb *conf = 719 dtlb ? &env->config->dtlb : &env->config->itlb; 720 unsigned (*attr_to_access)(uint32_t) = 721 xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ? 722 mmu_attr_to_access : region_attr_to_access; 723 724 for (wi = 0; wi < conf->nways; ++wi) { 725 uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1; 726 const char *sz_text; 727 bool print_header = true; 728 729 if (sz >= 0x100000) { 730 sz /= MiB; 731 sz_text = "MB"; 732 } else { 733 sz /= KiB; 734 sz_text = "KB"; 735 } 736 737 for (ei = 0; ei < conf->way_size[wi]; ++ei) { 738 const xtensa_tlb_entry *entry = 739 xtensa_tlb_get_entry(env, dtlb, wi, ei); 740 741 if (entry->asid) { 742 static const char * const cache_text[8] = { 743 [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass", 744 [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT", 745 [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB", 746 [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate", 747 }; 748 unsigned access = attr_to_access(entry->attr); 749 unsigned cache_idx = (access & PAGE_CACHE_MASK) >> 750 PAGE_CACHE_SHIFT; 751 752 if (print_header) { 753 print_header = false; 754 cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text); 755 cpu_fprintf(f, 756 "\tVaddr Paddr ASID Attr RWX Cache\n" 757 "\t---------- ---------- ---- ---- --- -------\n"); 758 } 759 cpu_fprintf(f, 760 "\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c %-7s\n", 761 entry->vaddr, 762 entry->paddr, 763 entry->asid, 764 entry->attr, 765 (access & PAGE_READ) ? 'R' : '-', 766 (access & PAGE_WRITE) ? 'W' : '-', 767 (access & PAGE_EXEC) ? 'X' : '-', 768 cache_text[cache_idx] ? cache_text[cache_idx] : 769 "Invalid"); 770 } 771 } 772 } 773 } 774 775 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env) 776 { 777 if (xtensa_option_bits_enabled(env->config, 778 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | 779 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) | 780 XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) { 781 782 cpu_fprintf(f, "ITLB:\n"); 783 dump_tlb(f, cpu_fprintf, env, false); 784 cpu_fprintf(f, "\nDTLB:\n"); 785 dump_tlb(f, cpu_fprintf, env, true); 786 } else { 787 cpu_fprintf(f, "No TLB for this CPU core\n"); 788 } 789 } 790 791 void xtensa_runstall(CPUXtensaState *env, bool runstall) 792 { 793 CPUState *cpu = CPU(xtensa_env_get_cpu(env)); 794 795 env->runstall = runstall; 796 cpu->halted = runstall; 797 if (runstall) { 798 cpu_interrupt(cpu, CPU_INTERRUPT_HALT); 799 } else { 800 cpu_reset_interrupt(cpu, CPU_INTERRUPT_HALT); 801 } 802 } 803 #endif 804