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