2
* Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
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.
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.
29
#include "dyngen-exec.h"
31
#include "host-utils.h"
33
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
37
#define MMUSUFFIX _mmu
40
#include "softmmu_template.h"
43
#include "softmmu_template.h"
46
#include "softmmu_template.h"
49
#include "softmmu_template.h"
51
static void do_restore_state(void *pc_ptr)
54
uint32_t pc = (uint32_t)(intptr_t)pc_ptr;
58
cpu_restore_state(tb, env, pc);
62
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
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);
73
void tlb_fill(CPUState *env1, target_ulong vaddr, int is_write, int mmu_idx,
76
CPUState *saved_env = env;
83
int ret = xtensa_get_physical_addr(env, vaddr, is_write, mmu_idx,
84
&paddr, &page_size, &access);
86
qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__,
87
vaddr, is_write, mmu_idx, paddr, ret);
91
vaddr & TARGET_PAGE_MASK,
92
paddr & TARGET_PAGE_MASK,
93
access, mmu_idx, page_size);
95
do_restore_state(retaddr);
96
HELPER(exception_cause_vaddr)(env->pc, ret, vaddr);
102
void HELPER(exception)(uint32_t excp)
104
env->exception_index = excp;
108
void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
113
if (env->sregs[PS] & PS_EXCM) {
114
if (env->config->ndepc) {
115
env->sregs[DEPC] = pc;
117
env->sregs[EPC1] = pc;
121
env->sregs[EPC1] = pc;
122
vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
125
env->sregs[EXCCAUSE] = cause;
126
env->sregs[PS] |= PS_EXCM;
128
HELPER(exception)(vector);
131
void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
133
env->sregs[EXCVADDR] = vaddr;
134
HELPER(exception_cause)(pc, cause);
137
uint32_t HELPER(nsa)(uint32_t v)
139
if (v & 0x80000000) {
142
return v ? clz32(v) - 1 : 31;
145
uint32_t HELPER(nsau)(uint32_t v)
147
return v ? clz32(v) : 32;
150
static void copy_window_from_phys(CPUState *env,
151
uint32_t window, uint32_t phys, uint32_t n)
153
assert(phys < env->config->nareg);
154
if (phys + n <= env->config->nareg) {
155
memcpy(env->regs + window, env->phys_regs + phys,
156
n * sizeof(uint32_t));
158
uint32_t n1 = env->config->nareg - phys;
159
memcpy(env->regs + window, env->phys_regs + phys,
160
n1 * sizeof(uint32_t));
161
memcpy(env->regs + window + n1, env->phys_regs,
162
(n - n1) * sizeof(uint32_t));
166
static void copy_phys_from_window(CPUState *env,
167
uint32_t phys, uint32_t window, uint32_t n)
169
assert(phys < env->config->nareg);
170
if (phys + n <= env->config->nareg) {
171
memcpy(env->phys_regs + phys, env->regs + window,
172
n * sizeof(uint32_t));
174
uint32_t n1 = env->config->nareg - phys;
175
memcpy(env->phys_regs + phys, env->regs + window,
176
n1 * sizeof(uint32_t));
177
memcpy(env->phys_regs, env->regs + window + n1,
178
(n - n1) * sizeof(uint32_t));
183
static inline unsigned windowbase_bound(unsigned a, const CPUState *env)
185
return a & (env->config->nareg / 4 - 1);
188
static inline unsigned windowstart_bit(unsigned a, const CPUState *env)
190
return 1 << windowbase_bound(a, env);
193
void xtensa_sync_window_from_phys(CPUState *env)
195
copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16);
198
void xtensa_sync_phys_from_window(CPUState *env)
200
copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16);
203
static void rotate_window_abs(uint32_t position)
205
xtensa_sync_phys_from_window(env);
206
env->sregs[WINDOW_BASE] = windowbase_bound(position, env);
207
xtensa_sync_window_from_phys(env);
210
static void rotate_window(uint32_t delta)
212
rotate_window_abs(env->sregs[WINDOW_BASE] + delta);
215
void HELPER(wsr_windowbase)(uint32_t v)
217
rotate_window_abs(v);
220
void HELPER(entry)(uint32_t pc, uint32_t s, uint32_t imm)
222
int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT;
223
if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
224
qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n",
226
HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
228
env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
229
rotate_window(callinc);
230
env->sregs[WINDOW_START] |=
231
windowstart_bit(env->sregs[WINDOW_BASE], env);
235
void HELPER(window_check)(uint32_t pc, uint32_t w)
237
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
238
uint32_t windowstart = env->sregs[WINDOW_START];
241
if ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) {
249
if (windowstart & windowstart_bit(windowbase + n, env)) {
254
m = windowbase_bound(windowbase + n, env);
256
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
257
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
258
env->sregs[EPC1] = env->pc = pc;
260
if (windowstart & windowstart_bit(m + 1, env)) {
261
HELPER(exception)(EXC_WINDOW_OVERFLOW4);
262
} else if (windowstart & windowstart_bit(m + 2, env)) {
263
HELPER(exception)(EXC_WINDOW_OVERFLOW8);
265
HELPER(exception)(EXC_WINDOW_OVERFLOW12);
269
uint32_t HELPER(retw)(uint32_t pc)
271
int n = (env->regs[0] >> 30) & 0x3;
273
uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env);
274
uint32_t windowstart = env->sregs[WINDOW_START];
277
if (windowstart & windowstart_bit(windowbase - 1, env)) {
279
} else if (windowstart & windowstart_bit(windowbase - 2, env)) {
281
} else if (windowstart & windowstart_bit(windowbase - 3, env)) {
285
if (n == 0 || (m != 0 && m != n) ||
286
((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) {
287
qemu_log("Illegal retw instruction(pc = %08x), "
288
"PS = %08x, m = %d, n = %d\n",
289
pc, env->sregs[PS], m, n);
290
HELPER(exception_cause)(pc, ILLEGAL_INSTRUCTION_CAUSE);
292
int owb = windowbase;
294
ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff);
297
if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) {
298
env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env);
300
/* window underflow */
301
env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) |
302
(windowbase << PS_OWB_SHIFT) | PS_EXCM;
303
env->sregs[EPC1] = env->pc = pc;
306
HELPER(exception)(EXC_WINDOW_UNDERFLOW4);
308
HELPER(exception)(EXC_WINDOW_UNDERFLOW8);
310
HELPER(exception)(EXC_WINDOW_UNDERFLOW12);
317
void HELPER(rotw)(uint32_t imm4)
322
void HELPER(restore_owb)(void)
324
rotate_window_abs((env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT);
327
void HELPER(movsp)(uint32_t pc)
329
if ((env->sregs[WINDOW_START] &
330
(windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) |
331
windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) |
332
windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) {
333
HELPER(exception_cause)(pc, ALLOCA_CAUSE);
337
void HELPER(wsr_lbeg)(uint32_t v)
339
if (env->sregs[LBEG] != v) {
340
tb_invalidate_phys_page_range(
341
env->sregs[LEND] - 1, env->sregs[LEND], 0);
342
env->sregs[LBEG] = v;
346
void HELPER(wsr_lend)(uint32_t v)
348
if (env->sregs[LEND] != v) {
349
tb_invalidate_phys_page_range(
350
env->sregs[LEND] - 1, env->sregs[LEND], 0);
351
env->sregs[LEND] = v;
352
tb_invalidate_phys_page_range(
353
env->sregs[LEND] - 1, env->sregs[LEND], 0);
357
void HELPER(dump_state)(void)
359
cpu_dump_state(env, stderr, fprintf, 0);
362
void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
365
env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
366
(intlevel << PS_INTLEVEL_SHIFT);
367
check_interrupts(env);
368
if (env->pending_irq_level) {
373
env->halt_clock = qemu_get_clock_ns(vm_clock);
375
if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
376
xtensa_rearm_ccompare_timer(env);
378
HELPER(exception)(EXCP_HLT);
381
void HELPER(timer_irq)(uint32_t id, uint32_t active)
383
xtensa_timer_irq(env, id, active);
386
void HELPER(advance_ccount)(uint32_t d)
388
xtensa_advance_ccount(env, d);
391
void HELPER(check_interrupts)(CPUState *env)
393
check_interrupts(env);
396
void HELPER(wsr_rasid)(uint32_t v)
398
v = (v & 0xffffff00) | 0x1;
399
if (v != env->sregs[RASID]) {
400
env->sregs[RASID] = v;
405
static uint32_t get_page_size(const CPUState *env, bool dtlb, uint32_t way)
407
uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
411
return (tlbcfg >> 16) & 0x3;
414
return (tlbcfg >> 20) & 0x1;
417
return (tlbcfg >> 24) & 0x1;
425
* Get bit mask for the virtual address bits translated by the TLB way
427
uint32_t xtensa_tlb_get_addr_mask(const CPUState *env, bool dtlb, uint32_t way)
429
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
430
bool varway56 = dtlb ?
431
env->config->dtlb.varway56 :
432
env->config->itlb.varway56;
436
return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
440
return 0xf8000000 << get_page_size(env, dtlb, way);
447
return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
456
return REGION_PAGE_MASK;
461
* Get bit mask for the 'VPN without index' field.
462
* See ISA, 4.6.5.6, data format for RxTLB0
464
static uint32_t get_vpn_mask(const CPUState *env, bool dtlb, uint32_t way)
468
env->config->dtlb.nrefillentries :
469
env->config->itlb.nrefillentries) == 32;
470
return is32 ? 0xffff8000 : 0xffffc000;
471
} else if (way == 4) {
472
return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
473
} else if (way <= 6) {
474
uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
475
bool varway56 = dtlb ?
476
env->config->dtlb.varway56 :
477
env->config->itlb.varway56;
480
return mask << (way == 5 ? 2 : 3);
490
* Split virtual address into VPN (with index) and entry index
491
* for the given TLB way
493
void split_tlb_entry_spec_way(const CPUState *env, uint32_t v, bool dtlb,
494
uint32_t *vpn, uint32_t wi, uint32_t *ei)
496
bool varway56 = dtlb ?
497
env->config->dtlb.varway56 :
498
env->config->itlb.varway56;
506
env->config->dtlb.nrefillentries :
507
env->config->itlb.nrefillentries) == 32;
508
*ei = (v >> 12) & (is32 ? 0x7 : 0x3);
513
uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
514
*ei = (v >> eibase) & 0x3;
520
uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
521
*ei = (v >> eibase) & 0x3;
523
*ei = (v >> 27) & 0x1;
529
uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
530
*ei = (v >> eibase) & 0x7;
532
*ei = (v >> 28) & 0x1;
541
*vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
545
* Split TLB address into TLB way, entry index and VPN (with index).
546
* See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
548
static void split_tlb_entry_spec(uint32_t v, bool dtlb,
549
uint32_t *vpn, uint32_t *wi, uint32_t *ei)
551
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
552
*wi = v & (dtlb ? 0xf : 0x7);
553
split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
555
*vpn = v & REGION_PAGE_MASK;
557
*ei = (v >> 29) & 0x7;
561
static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
567
split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
571
return xtensa_tlb_get_entry(env, dtlb, wi, ei);
574
uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
576
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
578
const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
579
return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
581
return v & REGION_PAGE_MASK;
585
uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
587
const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, NULL);
588
return entry->paddr | entry->attr;
591
void HELPER(itlb)(uint32_t v, uint32_t dtlb)
593
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
595
xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
596
if (entry->variable && entry->asid) {
597
tlb_flush_page(env, entry->vaddr);
603
uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
605
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
609
int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
613
if (ring >= xtensa_get_ring(env)) {
614
return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
618
case INST_TLB_MULTI_HIT_CAUSE:
619
case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
620
HELPER(exception_cause_vaddr)(env->pc, res, v);
625
return (v & REGION_PAGE_MASK) | 0x1;
629
void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
630
unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
632
xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
634
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
635
if (entry->variable) {
637
tlb_flush_page(env, entry->vaddr);
640
entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
641
entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
642
entry->attr = pte & 0xf;
644
qemu_log("%s %d, %d, %d trying to set immutable entry\n",
645
__func__, dtlb, wi, ei);
648
tlb_flush_page(env, entry->vaddr);
649
if (xtensa_option_enabled(env->config,
650
XTENSA_OPTION_REGION_TRANSLATION)) {
651
entry->paddr = pte & REGION_PAGE_MASK;
653
entry->attr = pte & 0xf;
657
void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
662
split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
663
xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);