]> Git Repo - qemu.git/blame - target-mips/helper.c
target-mips: update PageGrain and m{t,f}c0 EntryLo{0,1}
[qemu.git] / target-mips / helper.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS emulation helpers for qemu.
5fafdf24 3 *
6af0bf9c
FB
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
6af0bf9c 18 */
e37e863f
FB
19#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24#include <signal.h>
e37e863f
FB
25
26#include "cpu.h"
4ef37e69 27#include "sysemu/kvm.h"
6af0bf9c 28
43057ab1 29enum {
2fb58b73
LA
30 TLBRET_XI = -6,
31 TLBRET_RI = -5,
43057ab1
FB
32 TLBRET_DIRTY = -4,
33 TLBRET_INVALID = -3,
34 TLBRET_NOMATCH = -2,
35 TLBRET_BADADDR = -1,
36 TLBRET_MATCH = 0
37};
38
3c7b48b7
PB
39#if !defined(CONFIG_USER_ONLY)
40
29929e34 41/* no MMU emulation */
a8170e5e 42int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
6af0bf9c 43 target_ulong address, int rw, int access_type)
29929e34
TS
44{
45 *physical = address;
46 *prot = PAGE_READ | PAGE_WRITE;
47 return TLBRET_MATCH;
48}
49
50/* fixed mapping MMU emulation */
a8170e5e 51int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
29929e34
TS
52 target_ulong address, int rw, int access_type)
53{
54 if (address <= (int32_t)0x7FFFFFFFUL) {
55 if (!(env->CP0_Status & (1 << CP0St_ERL)))
56 *physical = address + 0x40000000UL;
57 else
58 *physical = address;
59 } else if (address <= (int32_t)0xBFFFFFFFUL)
60 *physical = address & 0x1FFFFFFF;
61 else
62 *physical = address;
63
64 *prot = PAGE_READ | PAGE_WRITE;
65 return TLBRET_MATCH;
66}
67
68/* MIPS32/MIPS64 R4000-style MMU emulation */
a8170e5e 69int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
29929e34 70 target_ulong address, int rw, int access_type)
6af0bf9c 71{
925fd0f2 72 uint8_t ASID = env->CP0_EntryHi & 0xFF;
3b1c8be4 73 int i;
6af0bf9c 74
ead9360e 75 for (i = 0; i < env->tlb->tlb_in_use; i++) {
c227f099 76 r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
3b1c8be4 77 /* 1k pages are not supported. */
f2e9ebef 78 target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
3b1c8be4 79 target_ulong tag = address & ~mask;
f2e9ebef 80 target_ulong VPN = tlb->VPN & ~mask;
d26bc211 81#if defined(TARGET_MIPS64)
e034e2c3 82 tag &= env->SEGMask;
100ce988 83#endif
3b1c8be4 84
6af0bf9c 85 /* Check ASID, virtual page number & size */
f2e9ebef 86 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
6af0bf9c 87 /* TLB match */
f2e9ebef 88 int n = !!(address & mask & ~(mask >> 1));
6af0bf9c 89 /* Check access rights */
2fb58b73 90 if (!(n ? tlb->V1 : tlb->V0)) {
43057ab1 91 return TLBRET_INVALID;
2fb58b73
LA
92 }
93 if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) {
94 return TLBRET_XI;
95 }
96 if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) {
97 return TLBRET_RI;
98 }
9f6bcedb 99 if (rw != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) {
3b1c8be4 100 *physical = tlb->PFN[n] | (address & (mask >> 1));
9fb63ac2 101 *prot = PAGE_READ;
98c1b82b 102 if (n ? tlb->D1 : tlb->D0)
9fb63ac2 103 *prot |= PAGE_WRITE;
43057ab1 104 return TLBRET_MATCH;
6af0bf9c 105 }
43057ab1 106 return TLBRET_DIRTY;
6af0bf9c
FB
107 }
108 }
43057ab1 109 return TLBRET_NOMATCH;
6af0bf9c 110}
6af0bf9c 111
a8170e5e 112static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
4ef37e69 113 int *prot, target_ulong real_address,
43057ab1 114 int rw, int access_type)
6af0bf9c 115{
b4ab4b4e 116 /* User mode can only access useg/xuseg */
43057ab1 117 int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
671880e6
TS
118 int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
119 int kernel_mode = !user_mode && !supervisor_mode;
d26bc211 120#if defined(TARGET_MIPS64)
b4ab4b4e
TS
121 int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
122 int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
123 int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
124#endif
43057ab1 125 int ret = TLBRET_MATCH;
4ef37e69
JH
126 /* effective address (modified for KVM T&E kernel segments) */
127 target_ulong address = real_address;
43057ab1 128
6af0bf9c 129#if 0
93fcfe39 130 qemu_log("user mode %d h %08x\n", user_mode, env->hflags);
6af0bf9c 131#endif
b4ab4b4e 132
22010ce7
JH
133#define USEG_LIMIT 0x7FFFFFFFUL
134#define KSEG0_BASE 0x80000000UL
135#define KSEG1_BASE 0xA0000000UL
136#define KSEG2_BASE 0xC0000000UL
137#define KSEG3_BASE 0xE0000000UL
138
4ef37e69
JH
139#define KVM_KSEG0_BASE 0x40000000UL
140#define KVM_KSEG2_BASE 0x60000000UL
141
142 if (kvm_enabled()) {
143 /* KVM T&E adds guest kernel segments in useg */
144 if (real_address >= KVM_KSEG0_BASE) {
145 if (real_address < KVM_KSEG2_BASE) {
146 /* kseg0 */
147 address += KSEG0_BASE - KVM_KSEG0_BASE;
148 } else if (real_address <= USEG_LIMIT) {
149 /* kseg2/3 */
150 address += KSEG2_BASE - KVM_KSEG2_BASE;
151 }
152 }
153 }
154
22010ce7 155 if (address <= USEG_LIMIT) {
b4ab4b4e 156 /* useg */
996ba2cc 157 if (env->CP0_Status & (1 << CP0St_ERL)) {
29929e34 158 *physical = address & 0xFFFFFFFF;
6af0bf9c 159 *prot = PAGE_READ | PAGE_WRITE;
996ba2cc 160 } else {
4ef37e69 161 ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
6af0bf9c 162 }
d26bc211 163#if defined(TARGET_MIPS64)
89fc88da 164 } else if (address < 0x4000000000000000ULL) {
b4ab4b4e 165 /* xuseg */
6958549d 166 if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
4ef37e69 167 ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
6958549d
AJ
168 } else {
169 ret = TLBRET_BADADDR;
b4ab4b4e 170 }
89fc88da 171 } else if (address < 0x8000000000000000ULL) {
b4ab4b4e 172 /* xsseg */
6958549d
AJ
173 if ((supervisor_mode || kernel_mode) &&
174 SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
4ef37e69 175 ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
6958549d
AJ
176 } else {
177 ret = TLBRET_BADADDR;
b4ab4b4e 178 }
89fc88da 179 } else if (address < 0xC000000000000000ULL) {
b4ab4b4e 180 /* xkphys */
671880e6 181 if (kernel_mode && KX &&
6d35524c
TS
182 (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
183 *physical = address & env->PAMask;
b4ab4b4e 184 *prot = PAGE_READ | PAGE_WRITE;
6958549d
AJ
185 } else {
186 ret = TLBRET_BADADDR;
187 }
89fc88da 188 } else if (address < 0xFFFFFFFF80000000ULL) {
b4ab4b4e 189 /* xkseg */
6958549d
AJ
190 if (kernel_mode && KX &&
191 address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
4ef37e69 192 ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
6958549d
AJ
193 } else {
194 ret = TLBRET_BADADDR;
195 }
b4ab4b4e 196#endif
22010ce7 197 } else if (address < (int32_t)KSEG1_BASE) {
6af0bf9c 198 /* kseg0 */
671880e6 199 if (kernel_mode) {
22010ce7 200 *physical = address - (int32_t)KSEG0_BASE;
671880e6
TS
201 *prot = PAGE_READ | PAGE_WRITE;
202 } else {
203 ret = TLBRET_BADADDR;
204 }
22010ce7 205 } else if (address < (int32_t)KSEG2_BASE) {
6af0bf9c 206 /* kseg1 */
671880e6 207 if (kernel_mode) {
22010ce7 208 *physical = address - (int32_t)KSEG1_BASE;
671880e6
TS
209 *prot = PAGE_READ | PAGE_WRITE;
210 } else {
211 ret = TLBRET_BADADDR;
212 }
22010ce7 213 } else if (address < (int32_t)KSEG3_BASE) {
89fc88da 214 /* sseg (kseg2) */
671880e6 215 if (supervisor_mode || kernel_mode) {
4ef37e69 216 ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
671880e6
TS
217 } else {
218 ret = TLBRET_BADADDR;
219 }
6af0bf9c
FB
220 } else {
221 /* kseg3 */
6af0bf9c 222 /* XXX: debug segment is not emulated */
671880e6 223 if (kernel_mode) {
4ef37e69 224 ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
671880e6
TS
225 } else {
226 ret = TLBRET_BADADDR;
227 }
6af0bf9c
FB
228 }
229#if 0
951fab99 230 qemu_log(TARGET_FMT_lx " %d %d => %" HWADDR_PRIx " %d (%d)\n",
93fcfe39 231 address, rw, access_type, *physical, *prot, ret);
6af0bf9c
FB
232#endif
233
234 return ret;
235}
932e71cd 236#endif
6af0bf9c 237
7db13fae 238static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
1147e189
AJ
239 int rw, int tlb_error)
240{
27103424 241 CPUState *cs = CPU(mips_env_get_cpu(env));
1147e189
AJ
242 int exception = 0, error_code = 0;
243
244 switch (tlb_error) {
245 default:
246 case TLBRET_BADADDR:
247 /* Reference to kernel address from user mode or supervisor mode */
248 /* Reference to supervisor address from user mode */
9f6bcedb 249 if (rw == MMU_DATA_STORE) {
1147e189 250 exception = EXCP_AdES;
9f6bcedb 251 } else {
1147e189 252 exception = EXCP_AdEL;
9f6bcedb 253 }
1147e189
AJ
254 break;
255 case TLBRET_NOMATCH:
256 /* No TLB match for a mapped address */
9f6bcedb 257 if (rw == MMU_DATA_STORE) {
1147e189 258 exception = EXCP_TLBS;
9f6bcedb 259 } else {
1147e189 260 exception = EXCP_TLBL;
9f6bcedb 261 }
1147e189
AJ
262 error_code = 1;
263 break;
264 case TLBRET_INVALID:
265 /* TLB match with no valid bit */
9f6bcedb 266 if (rw == MMU_DATA_STORE) {
1147e189 267 exception = EXCP_TLBS;
9f6bcedb 268 } else {
1147e189 269 exception = EXCP_TLBL;
9f6bcedb 270 }
1147e189
AJ
271 break;
272 case TLBRET_DIRTY:
273 /* TLB match but 'D' bit is cleared */
274 exception = EXCP_LTLBL;
275 break;
276
277 }
278 /* Raise exception */
279 env->CP0_BadVAddr = address;
280 env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
281 ((address >> 9) & 0x007ffff0);
282 env->CP0_EntryHi =
283 (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
284#if defined(TARGET_MIPS64)
285 env->CP0_EntryHi &= env->SEGMask;
286 env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
287 ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
288 ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
289#endif
27103424 290 cs->exception_index = exception;
1147e189
AJ
291 env->error_code = error_code;
292}
293
4fcc562b 294#if !defined(CONFIG_USER_ONLY)
00b941e5 295hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
6af0bf9c 296{
00b941e5 297 MIPSCPU *cpu = MIPS_CPU(cs);
a8170e5e 298 hwaddr phys_addr;
932e71cd 299 int prot;
6af0bf9c 300
00b941e5
AF
301 if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0,
302 ACCESS_INT) != 0) {
932e71cd 303 return -1;
00b941e5 304 }
932e71cd 305 return phys_addr;
6af0bf9c 306}
4fcc562b 307#endif
6af0bf9c 308
7510454e
AF
309int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
310 int mmu_idx)
6af0bf9c 311{
7510454e
AF
312 MIPSCPU *cpu = MIPS_CPU(cs);
313 CPUMIPSState *env = &cpu->env;
932e71cd 314#if !defined(CONFIG_USER_ONLY)
a8170e5e 315 hwaddr physical;
6af0bf9c 316 int prot;
6af0bf9c 317 int access_type;
99e43d36 318#endif
6af0bf9c
FB
319 int ret = 0;
320
4ad40f36 321#if 0
7510454e 322 log_cpu_state(cs, 0);
4ad40f36 323#endif
7510454e 324 qemu_log("%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
97b348e7 325 __func__, env->active_tc.PC, address, rw, mmu_idx);
4ad40f36 326
6af0bf9c 327 /* data access */
99e43d36 328#if !defined(CONFIG_USER_ONLY)
6af0bf9c
FB
329 /* XXX: put correct access by using cpu_restore_state()
330 correctly */
331 access_type = ACCESS_INT;
6af0bf9c
FB
332 ret = get_physical_address(env, &physical, &prot,
333 address, rw, access_type);
7510454e
AF
334 qemu_log("%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
335 " prot %d\n",
336 __func__, address, ret, physical, prot);
43057ab1 337 if (ret == TLBRET_MATCH) {
0c591eb0 338 tlb_set_page(cs, address & TARGET_PAGE_MASK,
99e43d36
AJ
339 physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
340 mmu_idx, TARGET_PAGE_SIZE);
341 ret = 0;
932e71cd
AJ
342 } else if (ret < 0)
343#endif
344 {
1147e189 345 raise_mmu_exception(env, address, rw, ret);
6af0bf9c
FB
346 ret = 1;
347 }
348
349 return ret;
350}
351
25b91e32 352#if !defined(CONFIG_USER_ONLY)
a8170e5e 353hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int rw)
25b91e32 354{
a8170e5e 355 hwaddr physical;
25b91e32
AJ
356 int prot;
357 int access_type;
358 int ret = 0;
359
25b91e32
AJ
360 /* data access */
361 access_type = ACCESS_INT;
362 ret = get_physical_address(env, &physical, &prot,
363 address, rw, access_type);
364 if (ret != TLBRET_MATCH) {
365 raise_mmu_exception(env, address, rw, ret);
c36bbb28
AJ
366 return -1LL;
367 } else {
368 return physical;
25b91e32 369 }
25b91e32
AJ
370}
371#endif
372
9a5d878f
TS
373static const char * const excp_names[EXCP_LAST + 1] = {
374 [EXCP_RESET] = "reset",
375 [EXCP_SRESET] = "soft reset",
376 [EXCP_DSS] = "debug single step",
377 [EXCP_DINT] = "debug interrupt",
378 [EXCP_NMI] = "non-maskable interrupt",
379 [EXCP_MCHECK] = "machine check",
380 [EXCP_EXT_INTERRUPT] = "interrupt",
381 [EXCP_DFWATCH] = "deferred watchpoint",
382 [EXCP_DIB] = "debug instruction breakpoint",
383 [EXCP_IWATCH] = "instruction fetch watchpoint",
384 [EXCP_AdEL] = "address error load",
385 [EXCP_AdES] = "address error store",
386 [EXCP_TLBF] = "TLB refill",
387 [EXCP_IBE] = "instruction bus error",
388 [EXCP_DBp] = "debug breakpoint",
389 [EXCP_SYSCALL] = "syscall",
390 [EXCP_BREAK] = "break",
391 [EXCP_CpU] = "coprocessor unusable",
392 [EXCP_RI] = "reserved instruction",
393 [EXCP_OVERFLOW] = "arithmetic overflow",
394 [EXCP_TRAP] = "trap",
395 [EXCP_FPE] = "floating point",
396 [EXCP_DDBS] = "debug data break store",
397 [EXCP_DWATCH] = "data watchpoint",
398 [EXCP_LTLBL] = "TLB modify",
399 [EXCP_TLBL] = "TLB load",
400 [EXCP_TLBS] = "TLB store",
401 [EXCP_DBE] = "data bus error",
402 [EXCP_DDBL] = "debug data break load",
403 [EXCP_THREAD] = "thread",
404 [EXCP_MDMX] = "MDMX",
405 [EXCP_C2E] = "precise coprocessor 2",
406 [EXCP_CACHE] = "cache error",
14e51cc7 407};
14e51cc7 408
1239b472 409target_ulong exception_resume_pc (CPUMIPSState *env)
32188a03
NF
410{
411 target_ulong bad_pc;
412 target_ulong isa_mode;
413
414 isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
415 bad_pc = env->active_tc.PC | isa_mode;
416 if (env->hflags & MIPS_HFLAG_BMASK) {
417 /* If the exception was raised from a delay slot, come back to
418 the jump. */
419 bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
420 }
421
422 return bad_pc;
423}
bbfa8f72 424
1239b472 425#if !defined(CONFIG_USER_ONLY)
7db13fae 426static void set_hflags_for_handler (CPUMIPSState *env)
bbfa8f72
NF
427{
428 /* Exception handlers are entered in 32-bit mode. */
429 env->hflags &= ~(MIPS_HFLAG_M16);
430 /* ...except that microMIPS lets you choose. */
431 if (env->insn_flags & ASE_MICROMIPS) {
432 env->hflags |= (!!(env->CP0_Config3
433 & (1 << CP0C3_ISA_ON_EXC))
434 << MIPS_HFLAG_M16_SHIFT);
435 }
436}
32188a03
NF
437#endif
438
97a8ea5a 439void mips_cpu_do_interrupt(CPUState *cs)
6af0bf9c 440{
27103424 441#if !defined(CONFIG_USER_ONLY)
97a8ea5a
AF
442 MIPSCPU *cpu = MIPS_CPU(cs);
443 CPUMIPSState *env = &cpu->env;
932e71cd
AJ
444 target_ulong offset;
445 int cause = -1;
446 const char *name;
100ce988 447
27103424
AF
448 if (qemu_log_enabled() && cs->exception_index != EXCP_EXT_INTERRUPT) {
449 if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) {
932e71cd 450 name = "unknown";
27103424
AF
451 } else {
452 name = excp_names[cs->exception_index];
453 }
b67bfe8d 454
93fcfe39
AL
455 qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
456 __func__, env->active_tc.PC, env->CP0_EPC, name);
932e71cd 457 }
27103424
AF
458 if (cs->exception_index == EXCP_EXT_INTERRUPT &&
459 (env->hflags & MIPS_HFLAG_DM)) {
460 cs->exception_index = EXCP_DINT;
461 }
932e71cd 462 offset = 0x180;
27103424 463 switch (cs->exception_index) {
932e71cd
AJ
464 case EXCP_DSS:
465 env->CP0_Debug |= 1 << CP0DB_DSS;
466 /* Debug single step cannot be raised inside a delay slot and
467 resume will always occur on the next instruction
468 (but we assume the pc has always been updated during
469 code translation). */
32188a03 470 env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
932e71cd
AJ
471 goto enter_debug_mode;
472 case EXCP_DINT:
473 env->CP0_Debug |= 1 << CP0DB_DINT;
474 goto set_DEPC;
475 case EXCP_DIB:
476 env->CP0_Debug |= 1 << CP0DB_DIB;
477 goto set_DEPC;
478 case EXCP_DBp:
479 env->CP0_Debug |= 1 << CP0DB_DBp;
480 goto set_DEPC;
481 case EXCP_DDBS:
482 env->CP0_Debug |= 1 << CP0DB_DDBS;
483 goto set_DEPC;
484 case EXCP_DDBL:
485 env->CP0_Debug |= 1 << CP0DB_DDBL;
486 set_DEPC:
32188a03
NF
487 env->CP0_DEPC = exception_resume_pc(env);
488 env->hflags &= ~MIPS_HFLAG_BMASK;
0eaef5aa 489 enter_debug_mode:
932e71cd
AJ
490 env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
491 env->hflags &= ~(MIPS_HFLAG_KSU);
492 /* EJTAG probe trap enable is not implemented... */
493 if (!(env->CP0_Status & (1 << CP0St_EXL)))
f45cb2f4 494 env->CP0_Cause &= ~(1U << CP0Ca_BD);
932e71cd 495 env->active_tc.PC = (int32_t)0xBFC00480;
bbfa8f72 496 set_hflags_for_handler(env);
932e71cd
AJ
497 break;
498 case EXCP_RESET:
fca1be7c 499 cpu_reset(CPU(cpu));
932e71cd
AJ
500 break;
501 case EXCP_SRESET:
502 env->CP0_Status |= (1 << CP0St_SR);
503 memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
504 goto set_error_EPC;
505 case EXCP_NMI:
506 env->CP0_Status |= (1 << CP0St_NMI);
0eaef5aa 507 set_error_EPC:
32188a03
NF
508 env->CP0_ErrorEPC = exception_resume_pc(env);
509 env->hflags &= ~MIPS_HFLAG_BMASK;
932e71cd
AJ
510 env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
511 env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
512 env->hflags &= ~(MIPS_HFLAG_KSU);
513 if (!(env->CP0_Status & (1 << CP0St_EXL)))
f45cb2f4 514 env->CP0_Cause &= ~(1U << CP0Ca_BD);
932e71cd 515 env->active_tc.PC = (int32_t)0xBFC00000;
bbfa8f72 516 set_hflags_for_handler(env);
932e71cd
AJ
517 break;
518 case EXCP_EXT_INTERRUPT:
519 cause = 0;
520 if (env->CP0_Cause & (1 << CP0Ca_IV))
521 offset = 0x200;
138afb02
EI
522
523 if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) {
524 /* Vectored Interrupts. */
525 unsigned int spacing;
526 unsigned int vector;
527 unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8;
528
e4280973 529 pending &= env->CP0_Status >> 8;
138afb02
EI
530 /* Compute the Vector Spacing. */
531 spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1);
532 spacing <<= 5;
533
534 if (env->CP0_Config3 & (1 << CP0C3_VInt)) {
535 /* For VInt mode, the MIPS computes the vector internally. */
e4280973
EI
536 for (vector = 7; vector > 0; vector--) {
537 if (pending & (1 << vector)) {
138afb02
EI
538 /* Found it. */
539 break;
540 }
138afb02
EI
541 }
542 } else {
543 /* For VEIC mode, the external interrupt controller feeds the
e7d81004 544 vector through the CP0Cause IP lines. */
138afb02
EI
545 vector = pending;
546 }
547 offset = 0x200 + vector * spacing;
548 }
932e71cd
AJ
549 goto set_EPC;
550 case EXCP_LTLBL:
551 cause = 1;
552 goto set_EPC;
553 case EXCP_TLBL:
554 cause = 2;
555 if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
0eaef5aa 556#if defined(TARGET_MIPS64)
932e71cd
AJ
557 int R = env->CP0_BadVAddr >> 62;
558 int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
559 int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
560 int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
0eaef5aa 561
3fc00a7b
AJ
562 if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
563 (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
932e71cd
AJ
564 offset = 0x080;
565 else
0eaef5aa 566#endif
932e71cd
AJ
567 offset = 0x000;
568 }
569 goto set_EPC;
570 case EXCP_TLBS:
571 cause = 3;
572 if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
0eaef5aa 573#if defined(TARGET_MIPS64)
932e71cd
AJ
574 int R = env->CP0_BadVAddr >> 62;
575 int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
576 int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
577 int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
0eaef5aa 578
3fc00a7b
AJ
579 if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
580 (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
932e71cd
AJ
581 offset = 0x080;
582 else
0eaef5aa 583#endif
932e71cd
AJ
584 offset = 0x000;
585 }
586 goto set_EPC;
587 case EXCP_AdEL:
588 cause = 4;
589 goto set_EPC;
590 case EXCP_AdES:
591 cause = 5;
592 goto set_EPC;
593 case EXCP_IBE:
594 cause = 6;
595 goto set_EPC;
596 case EXCP_DBE:
597 cause = 7;
598 goto set_EPC;
599 case EXCP_SYSCALL:
600 cause = 8;
601 goto set_EPC;
602 case EXCP_BREAK:
603 cause = 9;
604 goto set_EPC;
605 case EXCP_RI:
606 cause = 10;
607 goto set_EPC;
608 case EXCP_CpU:
609 cause = 11;
610 env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
611 (env->error_code << CP0Ca_CE);
612 goto set_EPC;
613 case EXCP_OVERFLOW:
614 cause = 12;
615 goto set_EPC;
616 case EXCP_TRAP:
617 cause = 13;
618 goto set_EPC;
619 case EXCP_FPE:
620 cause = 15;
621 goto set_EPC;
622 case EXCP_C2E:
623 cause = 18;
624 goto set_EPC;
625 case EXCP_MDMX:
626 cause = 22;
627 goto set_EPC;
628 case EXCP_DWATCH:
629 cause = 23;
630 /* XXX: TODO: manage defered watch exceptions */
631 goto set_EPC;
632 case EXCP_MCHECK:
633 cause = 24;
634 goto set_EPC;
635 case EXCP_THREAD:
636 cause = 25;
637 goto set_EPC;
853c3240
JL
638 case EXCP_DSPDIS:
639 cause = 26;
640 goto set_EPC;
932e71cd
AJ
641 case EXCP_CACHE:
642 cause = 30;
643 if (env->CP0_Status & (1 << CP0St_BEV)) {
644 offset = 0x100;
645 } else {
646 offset = 0x20000100;
647 }
0eaef5aa 648 set_EPC:
932e71cd 649 if (!(env->CP0_Status & (1 << CP0St_EXL))) {
32188a03 650 env->CP0_EPC = exception_resume_pc(env);
932e71cd 651 if (env->hflags & MIPS_HFLAG_BMASK) {
f45cb2f4 652 env->CP0_Cause |= (1U << CP0Ca_BD);
0eaef5aa 653 } else {
f45cb2f4 654 env->CP0_Cause &= ~(1U << CP0Ca_BD);
0eaef5aa 655 }
932e71cd
AJ
656 env->CP0_Status |= (1 << CP0St_EXL);
657 env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
658 env->hflags &= ~(MIPS_HFLAG_KSU);
6af0bf9c 659 }
932e71cd
AJ
660 env->hflags &= ~MIPS_HFLAG_BMASK;
661 if (env->CP0_Status & (1 << CP0St_BEV)) {
662 env->active_tc.PC = (int32_t)0xBFC00200;
663 } else {
664 env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
6af0bf9c 665 }
932e71cd 666 env->active_tc.PC += offset;
bbfa8f72 667 set_hflags_for_handler(env);
932e71cd
AJ
668 env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
669 break;
670 default:
27103424
AF
671 qemu_log("Invalid MIPS exception %d. Exiting\n", cs->exception_index);
672 printf("Invalid MIPS exception %d. Exiting\n", cs->exception_index);
932e71cd
AJ
673 exit(1);
674 }
27103424 675 if (qemu_log_enabled() && cs->exception_index != EXCP_EXT_INTERRUPT) {
93fcfe39 676 qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
932e71cd
AJ
677 " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
678 __func__, env->active_tc.PC, env->CP0_EPC, cause,
679 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
680 env->CP0_DEPC);
6af0bf9c 681 }
932e71cd 682#endif
27103424 683 cs->exception_index = EXCP_NONE;
6af0bf9c 684}
2ee4aed8 685
fa4faba4
RH
686bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
687{
688 if (interrupt_request & CPU_INTERRUPT_HARD) {
689 MIPSCPU *cpu = MIPS_CPU(cs);
690 CPUMIPSState *env = &cpu->env;
691
692 if (cpu_mips_hw_interrupts_pending(env)) {
693 /* Raise it */
694 cs->exception_index = EXCP_EXT_INTERRUPT;
695 env->error_code = 0;
696 mips_cpu_do_interrupt(cs);
697 return true;
698 }
699 }
700 return false;
701}
702
3c7b48b7 703#if !defined(CONFIG_USER_ONLY)
7db13fae 704void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra)
2ee4aed8 705{
31b030d4
AF
706 MIPSCPU *cpu = mips_env_get_cpu(env);
707 CPUState *cs;
c227f099 708 r4k_tlb_t *tlb;
3b1c8be4
TS
709 target_ulong addr;
710 target_ulong end;
711 uint8_t ASID = env->CP0_EntryHi & 0xFF;
712 target_ulong mask;
2ee4aed8 713
ead9360e 714 tlb = &env->tlb->mmu.r4k.tlb[idx];
f2e9ebef 715 /* The qemu TLB is flushed when the ASID changes, so no need to
2ee4aed8
FB
716 flush these entries again. */
717 if (tlb->G == 0 && tlb->ASID != ASID) {
718 return;
719 }
720
ead9360e 721 if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
2ee4aed8 722 /* For tlbwr, we can shadow the discarded entry into
6958549d
AJ
723 a new (fake) TLB entry, as long as the guest can not
724 tell that it's there. */
ead9360e
TS
725 env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
726 env->tlb->tlb_in_use++;
2ee4aed8
FB
727 return;
728 }
729
3b1c8be4 730 /* 1k pages are not supported. */
f2e9ebef 731 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
3b1c8be4 732 if (tlb->V0) {
31b030d4 733 cs = CPU(cpu);
f2e9ebef 734 addr = tlb->VPN & ~mask;
d26bc211 735#if defined(TARGET_MIPS64)
e034e2c3 736 if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
100ce988
TS
737 addr |= 0x3FFFFF0000000000ULL;
738 }
739#endif
3b1c8be4
TS
740 end = addr | (mask >> 1);
741 while (addr < end) {
31b030d4 742 tlb_flush_page(cs, addr);
3b1c8be4
TS
743 addr += TARGET_PAGE_SIZE;
744 }
745 }
746 if (tlb->V1) {
31b030d4 747 cs = CPU(cpu);
f2e9ebef 748 addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
d26bc211 749#if defined(TARGET_MIPS64)
e034e2c3 750 if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
100ce988
TS
751 addr |= 0x3FFFFF0000000000ULL;
752 }
753#endif
3b1c8be4 754 end = addr | mask;
53715e48 755 while (addr - 1 < end) {
31b030d4 756 tlb_flush_page(cs, addr);
3b1c8be4
TS
757 addr += TARGET_PAGE_SIZE;
758 }
759 }
2ee4aed8 760}
3c7b48b7 761#endif
This page took 0.882061 seconds and 4 git commands to generate.