]> Git Repo - qemu.git/blob - target-xtensa/op_helper.c
Merge branch 'xtensa' of git://jcmvbkbc.spb.ru/dumb/qemu-xtensa
[qemu.git] / target-xtensa / op_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 "dyngen-exec.h"
30 #include "helpers.h"
31 #include "host-utils.h"
32
33 static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
34         void *retaddr);
35
36 #define ALIGNED_ONLY
37 #define MMUSUFFIX _mmu
38
39 #define SHIFT 0
40 #include "softmmu_template.h"
41
42 #define SHIFT 1
43 #include "softmmu_template.h"
44
45 #define SHIFT 2
46 #include "softmmu_template.h"
47
48 #define SHIFT 3
49 #include "softmmu_template.h"
50
51 static void do_restore_state(void *pc_ptr)
52 {
53     TranslationBlock *tb;
54     uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
55
56     tb = tb_find_pc(pc);
57     if (tb) {
58         cpu_restore_state(tb, env, pc);
59     }
60 }
61
62 static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
63         void *retaddr)
64 {
65     if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
66             !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
67         do_restore_state(retaddr);
68         HELPER(exception_cause_vaddr)(
69                 env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
70     }
71 }
72
73 void tlb_fill(CPUState *env1, target_ulong vaddr, int is_write, int mmu_idx,
74               void *retaddr)
75 {
76     CPUState *saved_env = env;
77
78     env = env1;
79     {
80         uint32_t paddr;
81         uint32_t page_size;
82         unsigned access;
83         int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
84                 &paddr, &page_size, &access);
85
86         qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
87                 vaddr, is_write, mmu_idx, paddr, ret);
88
89         if (ret == 0) {
90             tlb_set_page(env,
91                     vaddr & TARGET_PAGE_MASK,
92                     paddr & TARGET_PAGE_MASK,
93                     access, mmu_idx, page_size);
94         } else {
95             do_restore_state(retaddr);
96             HELPER(exception_cause_vaddr)(env->pc, ret, vaddr);
97         }
98     }
99     env = saved_env;
100 }
101
102 void HELPER(exception)(uint32_t excp)
103 {
104     env->exception_index = excp;
105     cpu_loop_exit(env);
106 }
107
108 void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
109 {
110     uint32_t vector;
111
112     env->pc = pc;
113     if (env->sregs[PS] & PS_EXCM) {
114         if (env->config->ndepc) {
115             env->sregs[DEPC] = pc;
116         } else {
117             env->sregs[EPC1] = pc;
118         }
119         vector = EXC_DOUBLE;
120     } else {
121         env->sregs[EPC1] = pc;
122         vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
123     }
124
125     env->sregs[EXCCAUSE] = cause;
126     env->sregs[PS] |= PS_EXCM;
127
128     HELPER(exception)(vector);
129 }
130
131 void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
132 {
133     env->sregs[EXCVADDR] = vaddr;
134     HELPER(exception_cause)(pc, cause);
135 }
136
137 void debug_exception_env(CPUState *new_env, uint32_t cause)
138 {
139     if (xtensa_get_cintlevel(new_env) < new_env->config->debug_level) {
140         env = new_env;
141         HELPER(debug_exception)(env->pc, cause);
142     }
143 }
144
145 void HELPER(debug_exception)(uint32_t pc, uint32_t cause)
146 {
147     unsigned level = env->config->debug_level;
148
149     env->pc = pc;
150     env->sregs[DEBUGCAUSE] = cause;
151     env->sregs[EPC1 + level - 1] = pc;
152     env->sregs[EPS2 + level - 2] = env->sregs[PS];
153     env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM |
154         (level << PS_INTLEVEL_SHIFT);
155     HELPER(exception)(EXC_DEBUG);
156 }
157
158 uint32_t HELPER(nsa)(uint32_t v)
159 {
160     if (v & 0x80000000) {
161         v = ~v;
162     }
163     return v ? clz32(v) - 1 : 31;
164 }
165
166 uint32_t HELPER(nsau)(uint32_t v)
167 {
168     return v ? clz32(v) : 32;
169 }
170
171 static void copy_window_from_phys(CPUState *env,
172         uint32_t window, uint32_t phys, uint32_t n)
173 {
174     assert(phys < env->config->nareg);
175     if (phys + n <= env->config->nareg) {
176         memcpy(env->regs + window, env->phys_regs + phys,
177                 n * sizeof(uint32_t));
178     } else {
179         uint32_t n1 = env->config->nareg - phys;
180         memcpy(env->regs + window, env->phys_regs + phys,
181                 n1 * sizeof(uint32_t));
182         memcpy(env->regs + window + n1, env->phys_regs,
183                 (n - n1) * sizeof(uint32_t));
184     }
185 }
186
187 static void copy_phys_from_window(CPUState *env,
188         uint32_t phys, uint32_t window, uint32_t n)
189 {
190     assert(phys < env->config->nareg);
191     if (phys + n <= env->config->nareg) {
192         memcpy(env->phys_regs + phys, env->regs + window,
193                 n * sizeof(uint32_t));
194     } else {
195         uint32_t n1 = env->config->nareg - phys;
196         memcpy(env->phys_regs + phys, env->regs + window,
197                 n1 * sizeof(uint32_t));
198         memcpy(env->phys_regs, env->regs + window + n1,
199                 (n - n1) * sizeof(uint32_t));
200     }
201 }
202
203
204 static inline unsigned windowbase_bound(unsigned a, const CPUState *env)
205 {
206     return a & (env->config->nareg / 4 - 1);
207 }
208
209 static inline unsigned windowstart_bit(unsigned a, const CPUState *env)
210 {
211     return 1 << windowbase_bound(a, env);
212 }
213
214 void xtensa_sync_window_from_phys(CPUState *env)
215 {
216     copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
217 }
218
219 void xtensa_sync_phys_from_window(CPUState *env)
220 {
221     copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
222 }
223
224 static void rotate_window_abs(uint32_t position)
225 {
226     xtensa_sync_phys_from_window(env);
227     env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
228     xtensa_sync_window_from_phys(env);
229 }
230
231 static void rotate_window(uint32_t delta)
232 {
233     rotate_window_abs(env->sregs[WINDOW_BASE] + delta);
234 }
235
236 void HELPER(wsr_windowbase)(uint32_t v)
237 {
238     rotate_window_abs(v);
239 }
240
241 void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm)
242 {
243     int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
244     if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
245         qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n",
246                 pc, env->sregs[PS]);
247         HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
248     } else {
249         env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
250         rotate_window(callinc);
251         env->sregs[WINDOW_START] |=
252             windowstart_bit(env->sregs[WINDOW_BASE], env);
253     }
254 }
255
256 void HELPER(window_check)(uint32_t pc, uint32_t w)
257 {
258     uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
259     uint32_t windowstart = env->sregs[WINDOW_START];
260     uint32_t m, n;
261
262     if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
263         return;
264     }
265
266     for (n = 1; ; ++n) {
267         if (n > w) {
268             return;
269         }
270         if (windowstart & windowstart_bit(windowbase + n, env)) {
271             break;
272         }
273     }
274
275     m = windowbase_bound(windowbase + n, env);
276     rotate_window(n);
277     env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
278         (windowbase << PS_OWB_SHIFT) | PS_EXCM;
279     env->sregs[EPC1] = env->pc = pc;
280
281     if (windowstart & windowstart_bit(m + 1, env)) {
282         HELPER(exception)(EXC_WINDOW_OVERFLOW4);
283     } else if (windowstart & windowstart_bit(m + 2, env)) {
284         HELPER(exception)(EXC_WINDOW_OVERFLOW8);
285     } else {
286         HELPER(exception)(EXC_WINDOW_OVERFLOW12);
287     }
288 }
289
290 uint32_t HELPER(retw)(uint32_t pc)
291 {
292     int n = (env->regs[0] >> 30) & 0x3;
293     int m = 0;
294     uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
295     uint32_t windowstart = env->sregs[WINDOW_START];
296     uint32_t ret_pc = 0;
297
298     if (windowstart & windowstart_bit(windowbase - 1, env)) {
299         m = 1;
300     } else if (windowstart & windowstart_bit(windowbase - 2, env)) {
301         m = 2;
302     } else if (windowstart & windowstart_bit(windowbase - 3, env)) {
303         m = 3;
304     }
305
306     if (n == 0 || (m != 0 && m != n) ||
307             ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
308         qemu_log("Illegal retw instruction(pc = %08x), "
309                 "PS = %08x, m = %d, n = %d\n",
310                 pc, env->sregs[PS], m, n);
311         HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
312     } else {
313         int owb = windowbase;
314
315         ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
316
317         rotate_window(-n);
318         if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
319             env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
320         } else {
321             /* window underflow */
322             env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
323                 (windowbase << PS_OWB_SHIFT) | PS_EXCM;
324             env->sregs[EPC1] = env->pc = pc;
325
326             if (n == 1) {
327                 HELPER(exception)(EXC_WINDOW_UNDERFLOW4);
328             } else if (n == 2) {
329                 HELPER(exception)(EXC_WINDOW_UNDERFLOW8);
330             } else if (n == 3) {
331                 HELPER(exception)(EXC_WINDOW_UNDERFLOW12);
332             }
333         }
334     }
335     return ret_pc;
336 }
337
338 void HELPER(rotw)(uint32_t imm4)
339 {
340     rotate_window(imm4);
341 }
342
343 void HELPER(restore_owb)(void)
344 {
345     rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
346 }
347
348 void HELPER(movsp)(uint32_t pc)
349 {
350     if ((env->sregs[WINDOW_START] &
351             (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
352              windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
353              windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
354         HELPER(exception_cause)(pc, ALLOCA_CAUSE);
355     }
356 }
357
358 void HELPER(wsr_lbeg)(uint32_t v)
359 {
360     if (env->sregs[LBEG] != v) {
361         tb_invalidate_phys_page_range(
362                 env->sregs[LEND] - 1, env->sregs[LEND], 0);
363         env->sregs[LBEG] = v;
364     }
365 }
366
367 void HELPER(wsr_lend)(uint32_t v)
368 {
369     if (env->sregs[LEND] != v) {
370         tb_invalidate_phys_page_range(
371                 env->sregs[LEND] - 1, env->sregs[LEND], 0);
372         env->sregs[LEND] = v;
373         tb_invalidate_phys_page_range(
374                 env->sregs[LEND] - 1, env->sregs[LEND], 0);
375     }
376 }
377
378 void HELPER(dump_state)(void)
379 {
380     cpu_dump_state(env, stderr, fprintf, 0);
381 }
382
383 void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
384 {
385     env->pc = pc;
386     env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
387         (intlevel << PS_INTLEVEL_SHIFT);
388     check_interrupts(env);
389     if (env->pending_irq_level) {
390         cpu_loop_exit(env);
391         return;
392     }
393
394     env->halt_clock = qemu_get_clock_ns(vm_clock);
395     env->halted = 1;
396     if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
397         xtensa_rearm_ccompare_timer(env);
398     }
399     HELPER(exception)(EXCP_HLT);
400 }
401
402 void HELPER(timer_irq)(uint32_t id, uint32_t active)
403 {
404     xtensa_timer_irq(env, id, active);
405 }
406
407 void HELPER(advance_ccount)(uint32_t d)
408 {
409     xtensa_advance_ccount(env, d);
410 }
411
412 void HELPER(check_interrupts)(CPUState *env)
413 {
414     check_interrupts(env);
415 }
416
417 void HELPER(wsr_rasid)(uint32_t v)
418 {
419     v = (v & 0xffffff00) | 0x1;
420     if (v != env->sregs[RASID]) {
421         env->sregs[RASID] = v;
422         tlb_flush(env, 1);
423     }
424 }
425
426 static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way)
427 {
428     uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
429
430     switch (way) {
431     case 4:
432         return (tlbcfg >> 16) & 0x3;
433
434     case 5:
435         return (tlbcfg >> 20) & 0x1;
436
437     case 6:
438         return (tlbcfg >> 24) & 0x1;
439
440     default:
441         return 0;
442     }
443 }
444
445 /*!
446  * Get bit mask for the virtual address bits translated by the TLB way
447  */
448 uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way)
449 {
450     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
451         bool varway56 = dtlb ?
452             env->config->dtlb.varway56 :
453             env->config->itlb.varway56;
454
455         switch (way) {
456         case 4:
457             return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
458
459         case 5:
460             if (varway56) {
461                 return 0xf8000000 << get_page_size(env, dtlb, way);
462             } else {
463                 return 0xf8000000;
464             }
465
466         case 6:
467             if (varway56) {
468                 return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
469             } else {
470                 return 0xf0000000;
471             }
472
473         default:
474             return 0xfffff000;
475         }
476     } else {
477         return REGION_PAGE_MASK;
478     }
479 }
480
481 /*!
482  * Get bit mask for the 'VPN without index' field.
483  * See ISA, 4.6.5.6, data format for RxTLB0
484  */
485 static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way)
486 {
487     if (way < 4) {
488         bool is32 = (dtlb ?
489                 env->config->dtlb.nrefillentries :
490                 env->config->itlb.nrefillentries) == 32;
491         return is32 ? 0xffff8000 : 0xffffc000;
492     } else if (way == 4) {
493         return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
494     } else if (way <= 6) {
495         uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
496         bool varway56 = dtlb ?
497             env->config->dtlb.varway56 :
498             env->config->itlb.varway56;
499
500         if (varway56) {
501             return mask << (way == 5 ? 2 : 3);
502         } else {
503             return mask << 1;
504         }
505     } else {
506         return 0xfffff000;
507     }
508 }
509
510 /*!
511  * Split virtual address into VPN (with index) and entry index
512  * for the given TLB way
513  */
514 void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
515         uint32_t *vpn, uint32_t wi, uint32_t *ei)
516 {
517     bool varway56 = dtlb ?
518         env->config->dtlb.varway56 :
519         env->config->itlb.varway56;
520
521     if (!dtlb) {
522         wi &= 7;
523     }
524
525     if (wi < 4) {
526         bool is32 = (dtlb ?
527                 env->config->dtlb.nrefillentries :
528                 env->config->itlb.nrefillentries) == 32;
529         *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
530     } else {
531         switch (wi) {
532         case 4:
533             {
534                 uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
535                 *ei = (v >> eibase) & 0x3;
536             }
537             break;
538
539         case 5:
540             if (varway56) {
541                 uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
542                 *ei = (v >> eibase) & 0x3;
543             } else {
544                 *ei = (v >> 27) & 0x1;
545             }
546             break;
547
548         case 6:
549             if (varway56) {
550                 uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
551                 *ei = (v >> eibase) & 0x7;
552             } else {
553                 *ei = (v >> 28) & 0x1;
554             }
555             break;
556
557         default:
558             *ei = 0;
559             break;
560         }
561     }
562     *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
563 }
564
565 /*!
566  * Split TLB address into TLB way, entry index and VPN (with index).
567  * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
568  */
569 static void split_tlb_entry_spec(uint32_t v, bool dtlb,
570         uint32_t *vpn, uint32_t *wi, uint32_t *ei)
571 {
572     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
573         *wi = v & (dtlb ? 0xf : 0x7);
574         split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
575     } else {
576         *vpn = v & REGION_PAGE_MASK;
577         *wi = 0;
578         *ei = (v >> 29) & 0x7;
579     }
580 }
581
582 static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
583 {
584     uint32_t vpn;
585     uint32_t wi;
586     uint32_t ei;
587
588     split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
589     if (pwi) {
590         *pwi = wi;
591     }
592     return xtensa_tlb_get_entry(env, dtlb, wi, ei);
593 }
594
595 uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
596 {
597     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
598         uint32_t wi;
599         const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
600         return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
601     } else {
602         return v & REGION_PAGE_MASK;
603     }
604 }
605
606 uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
607 {
608     const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL);
609     return entry->paddr | entry->attr;
610 }
611
612 void HELPER(itlb)(uint32_t v, uint32_t dtlb)
613 {
614     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
615         uint32_t wi;
616         xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
617         if (entry->variable && entry->asid) {
618             tlb_flush_page(env, entry->vaddr);
619             entry->asid = 0;
620         }
621     }
622 }
623
624 uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
625 {
626     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
627         uint32_t wi;
628         uint32_t ei;
629         uint8_t ring;
630         int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
631
632         switch (res) {
633         case 0:
634             if (ring >= xtensa_get_ring(env)) {
635                 return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
636             }
637             break;
638
639         case INST_TLB_MULTI_HIT_CAUSE:
640         case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
641             HELPER(exception_cause_vaddr)(env->pc, res, v);
642             break;
643         }
644         return 0;
645     } else {
646         return (v & REGION_PAGE_MASK) | 0x1;
647     }
648 }
649
650 void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
651         unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
652 {
653     xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
654
655     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
656         if (entry->variable) {
657             if (entry->asid) {
658                 tlb_flush_page(env, entry->vaddr);
659             }
660             entry->vaddr = vpn;
661             entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
662             entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
663             entry->attr = pte & 0xf;
664         } else {
665             qemu_log("%s %d, %d, %d trying to set immutable entry\n",
666                     __func__, dtlb, wi, ei);
667         }
668     } else {
669         tlb_flush_page(env, entry->vaddr);
670         if (xtensa_option_enabled(env->config,
671                     XTENSA_OPTION_REGION_TRANSLATION)) {
672             entry->paddr = pte & REGION_PAGE_MASK;
673         }
674         entry->attr = pte & 0xf;
675     }
676 }
677
678 void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
679 {
680     uint32_t vpn;
681     uint32_t wi;
682     uint32_t ei;
683     split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
684     xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
685 }
686
687
688 void HELPER(wsr_ibreakenable)(uint32_t v)
689 {
690     uint32_t change = v ^ env->sregs[IBREAKENABLE];
691     unsigned i;
692
693     for (i = 0; i < env->config->nibreak; ++i) {
694         if (change & (1 << i)) {
695             tb_invalidate_phys_page_range(
696                     env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
697         }
698     }
699     env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
700 }
701
702 void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v)
703 {
704     if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) {
705         tb_invalidate_phys_page_range(
706                 env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
707         tb_invalidate_phys_page_range(v, v + 1, 0);
708     }
709     env->sregs[IBREAKA + i] = v;
710 }
711
712 static void set_dbreak(unsigned i, uint32_t dbreaka, uint32_t dbreakc)
713 {
714     int flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
715     uint32_t mask = dbreakc | ~DBREAKC_MASK;
716
717     if (env->cpu_watchpoint[i]) {
718         cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]);
719     }
720     if (dbreakc & DBREAKC_SB) {
721         flags |= BP_MEM_WRITE;
722     }
723     if (dbreakc & DBREAKC_LB) {
724         flags |= BP_MEM_READ;
725     }
726     /* contiguous mask after inversion is one less than some power of 2 */
727     if ((~mask + 1) & ~mask) {
728         qemu_log("DBREAKC mask is not contiguous: 0x%08x\n", dbreakc);
729         /* cut mask after the first zero bit */
730         mask = 0xffffffff << (32 - clo32(mask));
731     }
732     if (cpu_watchpoint_insert(env, dbreaka & mask, ~mask + 1,
733             flags, &env->cpu_watchpoint[i])) {
734         env->cpu_watchpoint[i] = NULL;
735         qemu_log("Failed to set data breakpoint at 0x%08x/%d\n",
736                 dbreaka & mask, ~mask + 1);
737     }
738 }
739
740 void HELPER(wsr_dbreaka)(uint32_t i, uint32_t v)
741 {
742     uint32_t dbreakc = env->sregs[DBREAKC + i];
743
744     if ((dbreakc & DBREAKC_SB_LB) &&
745             env->sregs[DBREAKA + i] != v) {
746         set_dbreak(i, v, dbreakc);
747     }
748     env->sregs[DBREAKA + i] = v;
749 }
750
751 void HELPER(wsr_dbreakc)(uint32_t i, uint32_t v)
752 {
753     if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) {
754         if (v & DBREAKC_SB_LB) {
755             set_dbreak(i, env->sregs[DBREAKA + i], v);
756         } else {
757             if (env->cpu_watchpoint[i]) {
758                 cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]);
759                 env->cpu_watchpoint[i] = NULL;
760             }
761         }
762     }
763     env->sregs[DBREAKC + i] = v;
764 }
This page took 0.066997 seconds and 4 git commands to generate.