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