]> Git Repo - qemu.git/blob - target-mips/helper.c
Merge remote-tracking branch 'remotes/mjt/tags/pull-trivial-patches-2015-09-11' into...
[qemu.git] / target-mips / helper.c
1 /*
2  *  MIPS emulation helpers for qemu.
3  *
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
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <inttypes.h>
24
25 #include "cpu.h"
26 #include "sysemu/kvm.h"
27 #include "exec/cpu_ldst.h"
28
29 enum {
30     TLBRET_XI = -6,
31     TLBRET_RI = -5,
32     TLBRET_DIRTY = -4,
33     TLBRET_INVALID = -3,
34     TLBRET_NOMATCH = -2,
35     TLBRET_BADADDR = -1,
36     TLBRET_MATCH = 0
37 };
38
39 #if !defined(CONFIG_USER_ONLY)
40
41 /* no MMU emulation */
42 int no_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
43                         target_ulong address, int rw, int access_type)
44 {
45     *physical = address;
46     *prot = PAGE_READ | PAGE_WRITE;
47     return TLBRET_MATCH;
48 }
49
50 /* fixed mapping MMU emulation */
51 int fixed_mmu_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
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 */
69 int r4k_map_address (CPUMIPSState *env, hwaddr *physical, int *prot,
70                      target_ulong address, int rw, int access_type)
71 {
72     uint8_t ASID = env->CP0_EntryHi & 0xFF;
73     int i;
74
75     for (i = 0; i < env->tlb->tlb_in_use; i++) {
76         r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
77         /* 1k pages are not supported. */
78         target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
79         target_ulong tag = address & ~mask;
80         target_ulong VPN = tlb->VPN & ~mask;
81 #if defined(TARGET_MIPS64)
82         tag &= env->SEGMask;
83 #endif
84
85         /* Check ASID, virtual page number & size */
86         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
87             /* TLB match */
88             int n = !!(address & mask & ~(mask >> 1));
89             /* Check access rights */
90             if (!(n ? tlb->V1 : tlb->V0)) {
91                 return TLBRET_INVALID;
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             }
99             if (rw != MMU_DATA_STORE || (n ? tlb->D1 : tlb->D0)) {
100                 *physical = tlb->PFN[n] | (address & (mask >> 1));
101                 *prot = PAGE_READ;
102                 if (n ? tlb->D1 : tlb->D0)
103                     *prot |= PAGE_WRITE;
104                 return TLBRET_MATCH;
105             }
106             return TLBRET_DIRTY;
107         }
108     }
109     return TLBRET_NOMATCH;
110 }
111
112 static int get_physical_address (CPUMIPSState *env, hwaddr *physical,
113                                 int *prot, target_ulong real_address,
114                                 int rw, int access_type)
115 {
116     /* User mode can only access useg/xuseg */
117     int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
118     int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
119     int kernel_mode = !user_mode && !supervisor_mode;
120 #if defined(TARGET_MIPS64)
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
125     int ret = TLBRET_MATCH;
126     /* effective address (modified for KVM T&E kernel segments) */
127     target_ulong address = real_address;
128
129 #define USEG_LIMIT      0x7FFFFFFFUL
130 #define KSEG0_BASE      0x80000000UL
131 #define KSEG1_BASE      0xA0000000UL
132 #define KSEG2_BASE      0xC0000000UL
133 #define KSEG3_BASE      0xE0000000UL
134
135 #define KVM_KSEG0_BASE  0x40000000UL
136 #define KVM_KSEG2_BASE  0x60000000UL
137
138     if (kvm_enabled()) {
139         /* KVM T&E adds guest kernel segments in useg */
140         if (real_address >= KVM_KSEG0_BASE) {
141             if (real_address < KVM_KSEG2_BASE) {
142                 /* kseg0 */
143                 address += KSEG0_BASE - KVM_KSEG0_BASE;
144             } else if (real_address <= USEG_LIMIT) {
145                 /* kseg2/3 */
146                 address += KSEG2_BASE - KVM_KSEG2_BASE;
147             }
148         }
149     }
150
151     if (address <= USEG_LIMIT) {
152         /* useg */
153         if (env->CP0_Status & (1 << CP0St_ERL)) {
154             *physical = address & 0xFFFFFFFF;
155             *prot = PAGE_READ | PAGE_WRITE;
156         } else {
157             ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
158         }
159 #if defined(TARGET_MIPS64)
160     } else if (address < 0x4000000000000000ULL) {
161         /* xuseg */
162         if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
163             ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
164         } else {
165             ret = TLBRET_BADADDR;
166         }
167     } else if (address < 0x8000000000000000ULL) {
168         /* xsseg */
169         if ((supervisor_mode || kernel_mode) &&
170             SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
171             ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
172         } else {
173             ret = TLBRET_BADADDR;
174         }
175     } else if (address < 0xC000000000000000ULL) {
176         /* xkphys */
177         if (kernel_mode && KX &&
178             (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
179             *physical = address & env->PAMask;
180             *prot = PAGE_READ | PAGE_WRITE;
181         } else {
182             ret = TLBRET_BADADDR;
183         }
184     } else if (address < 0xFFFFFFFF80000000ULL) {
185         /* xkseg */
186         if (kernel_mode && KX &&
187             address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
188             ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
189         } else {
190             ret = TLBRET_BADADDR;
191         }
192 #endif
193     } else if (address < (int32_t)KSEG1_BASE) {
194         /* kseg0 */
195         if (kernel_mode) {
196             *physical = address - (int32_t)KSEG0_BASE;
197             *prot = PAGE_READ | PAGE_WRITE;
198         } else {
199             ret = TLBRET_BADADDR;
200         }
201     } else if (address < (int32_t)KSEG2_BASE) {
202         /* kseg1 */
203         if (kernel_mode) {
204             *physical = address - (int32_t)KSEG1_BASE;
205             *prot = PAGE_READ | PAGE_WRITE;
206         } else {
207             ret = TLBRET_BADADDR;
208         }
209     } else if (address < (int32_t)KSEG3_BASE) {
210         /* sseg (kseg2) */
211         if (supervisor_mode || kernel_mode) {
212             ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
213         } else {
214             ret = TLBRET_BADADDR;
215         }
216     } else {
217         /* kseg3 */
218         /* XXX: debug segment is not emulated */
219         if (kernel_mode) {
220             ret = env->tlb->map_address(env, physical, prot, real_address, rw, access_type);
221         } else {
222             ret = TLBRET_BADADDR;
223         }
224     }
225     return ret;
226 }
227 #endif
228
229 static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
230                                 int rw, int tlb_error)
231 {
232     CPUState *cs = CPU(mips_env_get_cpu(env));
233     int exception = 0, error_code = 0;
234
235     if (rw == MMU_INST_FETCH) {
236         error_code |= EXCP_INST_NOTAVAIL;
237     }
238
239     switch (tlb_error) {
240     default:
241     case TLBRET_BADADDR:
242         /* Reference to kernel address from user mode or supervisor mode */
243         /* Reference to supervisor address from user mode */
244         if (rw == MMU_DATA_STORE) {
245             exception = EXCP_AdES;
246         } else {
247             exception = EXCP_AdEL;
248         }
249         break;
250     case TLBRET_NOMATCH:
251         /* No TLB match for a mapped address */
252         if (rw == MMU_DATA_STORE) {
253             exception = EXCP_TLBS;
254         } else {
255             exception = EXCP_TLBL;
256         }
257         error_code |= EXCP_TLB_NOMATCH;
258         break;
259     case TLBRET_INVALID:
260         /* TLB match with no valid bit */
261         if (rw == MMU_DATA_STORE) {
262             exception = EXCP_TLBS;
263         } else {
264             exception = EXCP_TLBL;
265         }
266         break;
267     case TLBRET_DIRTY:
268         /* TLB match but 'D' bit is cleared */
269         exception = EXCP_LTLBL;
270         break;
271     case TLBRET_XI:
272         /* Execute-Inhibit Exception */
273         if (env->CP0_PageGrain & (1 << CP0PG_IEC)) {
274             exception = EXCP_TLBXI;
275         } else {
276             exception = EXCP_TLBL;
277         }
278         break;
279     case TLBRET_RI:
280         /* Read-Inhibit Exception */
281         if (env->CP0_PageGrain & (1 << CP0PG_IEC)) {
282             exception = EXCP_TLBRI;
283         } else {
284             exception = EXCP_TLBL;
285         }
286         break;
287     }
288     /* Raise exception */
289     env->CP0_BadVAddr = address;
290     env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
291                        ((address >> 9) & 0x007ffff0);
292     env->CP0_EntryHi =
293         (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
294 #if defined(TARGET_MIPS64)
295     env->CP0_EntryHi &= env->SEGMask;
296     env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
297                         ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
298                         ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
299 #endif
300     cs->exception_index = exception;
301     env->error_code = error_code;
302 }
303
304 #if !defined(CONFIG_USER_ONLY)
305 hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
306 {
307     MIPSCPU *cpu = MIPS_CPU(cs);
308     hwaddr phys_addr;
309     int prot;
310
311     if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0,
312                              ACCESS_INT) != 0) {
313         return -1;
314     }
315     return phys_addr;
316 }
317 #endif
318
319 int mips_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw,
320                               int mmu_idx)
321 {
322     MIPSCPU *cpu = MIPS_CPU(cs);
323     CPUMIPSState *env = &cpu->env;
324 #if !defined(CONFIG_USER_ONLY)
325     hwaddr physical;
326     int prot;
327     int access_type;
328 #endif
329     int ret = 0;
330
331 #if 0
332     log_cpu_state(cs, 0);
333 #endif
334     qemu_log_mask(CPU_LOG_MMU,
335               "%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
336               __func__, env->active_tc.PC, address, rw, mmu_idx);
337
338     /* data access */
339 #if !defined(CONFIG_USER_ONLY)
340     /* XXX: put correct access by using cpu_restore_state()
341        correctly */
342     access_type = ACCESS_INT;
343     ret = get_physical_address(env, &physical, &prot,
344                                address, rw, access_type);
345     qemu_log_mask(CPU_LOG_MMU,
346              "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
347              " prot %d\n",
348              __func__, address, ret, physical, prot);
349     if (ret == TLBRET_MATCH) {
350         tlb_set_page(cs, address & TARGET_PAGE_MASK,
351                      physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
352                      mmu_idx, TARGET_PAGE_SIZE);
353         ret = 0;
354     } else if (ret < 0)
355 #endif
356     {
357         raise_mmu_exception(env, address, rw, ret);
358         ret = 1;
359     }
360
361     return ret;
362 }
363
364 #if !defined(CONFIG_USER_ONLY)
365 hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int rw)
366 {
367     hwaddr physical;
368     int prot;
369     int access_type;
370     int ret = 0;
371
372     /* data access */
373     access_type = ACCESS_INT;
374     ret = get_physical_address(env, &physical, &prot,
375                                address, rw, access_type);
376     if (ret != TLBRET_MATCH) {
377         raise_mmu_exception(env, address, rw, ret);
378         return -1LL;
379     } else {
380         return physical;
381     }
382 }
383
384 static const char * const excp_names[EXCP_LAST + 1] = {
385     [EXCP_RESET] = "reset",
386     [EXCP_SRESET] = "soft reset",
387     [EXCP_DSS] = "debug single step",
388     [EXCP_DINT] = "debug interrupt",
389     [EXCP_NMI] = "non-maskable interrupt",
390     [EXCP_MCHECK] = "machine check",
391     [EXCP_EXT_INTERRUPT] = "interrupt",
392     [EXCP_DFWATCH] = "deferred watchpoint",
393     [EXCP_DIB] = "debug instruction breakpoint",
394     [EXCP_IWATCH] = "instruction fetch watchpoint",
395     [EXCP_AdEL] = "address error load",
396     [EXCP_AdES] = "address error store",
397     [EXCP_TLBF] = "TLB refill",
398     [EXCP_IBE] = "instruction bus error",
399     [EXCP_DBp] = "debug breakpoint",
400     [EXCP_SYSCALL] = "syscall",
401     [EXCP_BREAK] = "break",
402     [EXCP_CpU] = "coprocessor unusable",
403     [EXCP_RI] = "reserved instruction",
404     [EXCP_OVERFLOW] = "arithmetic overflow",
405     [EXCP_TRAP] = "trap",
406     [EXCP_FPE] = "floating point",
407     [EXCP_DDBS] = "debug data break store",
408     [EXCP_DWATCH] = "data watchpoint",
409     [EXCP_LTLBL] = "TLB modify",
410     [EXCP_TLBL] = "TLB load",
411     [EXCP_TLBS] = "TLB store",
412     [EXCP_DBE] = "data bus error",
413     [EXCP_DDBL] = "debug data break load",
414     [EXCP_THREAD] = "thread",
415     [EXCP_MDMX] = "MDMX",
416     [EXCP_C2E] = "precise coprocessor 2",
417     [EXCP_CACHE] = "cache error",
418     [EXCP_TLBXI] = "TLB execute-inhibit",
419     [EXCP_TLBRI] = "TLB read-inhibit",
420     [EXCP_MSADIS] = "MSA disabled",
421     [EXCP_MSAFPE] = "MSA floating point",
422 };
423 #endif
424
425 target_ulong exception_resume_pc (CPUMIPSState *env)
426 {
427     target_ulong bad_pc;
428     target_ulong isa_mode;
429
430     isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
431     bad_pc = env->active_tc.PC | isa_mode;
432     if (env->hflags & MIPS_HFLAG_BMASK) {
433         /* If the exception was raised from a delay slot, come back to
434            the jump.  */
435         bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
436     }
437
438     return bad_pc;
439 }
440
441 #if !defined(CONFIG_USER_ONLY)
442 static void set_hflags_for_handler (CPUMIPSState *env)
443 {
444     /* Exception handlers are entered in 32-bit mode.  */
445     env->hflags &= ~(MIPS_HFLAG_M16);
446     /* ...except that microMIPS lets you choose.  */
447     if (env->insn_flags & ASE_MICROMIPS) {
448         env->hflags |= (!!(env->CP0_Config3
449                            & (1 << CP0C3_ISA_ON_EXC))
450                         << MIPS_HFLAG_M16_SHIFT);
451     }
452 }
453
454 static inline void set_badinstr_registers(CPUMIPSState *env)
455 {
456     if (env->hflags & MIPS_HFLAG_M16) {
457         /* TODO: add BadInstr support for microMIPS */
458         return;
459     }
460     if (env->CP0_Config3 & (1 << CP0C3_BI)) {
461         env->CP0_BadInstr = cpu_ldl_code(env, env->active_tc.PC);
462     }
463     if ((env->CP0_Config3 & (1 << CP0C3_BP)) &&
464         (env->hflags & MIPS_HFLAG_BMASK)) {
465         env->CP0_BadInstrP = cpu_ldl_code(env, env->active_tc.PC - 4);
466     }
467 }
468 #endif
469
470 void mips_cpu_do_interrupt(CPUState *cs)
471 {
472 #if !defined(CONFIG_USER_ONLY)
473     MIPSCPU *cpu = MIPS_CPU(cs);
474     CPUMIPSState *env = &cpu->env;
475     bool update_badinstr = 0;
476     target_ulong offset;
477     int cause = -1;
478     const char *name;
479
480     if (qemu_loglevel_mask(CPU_LOG_INT)
481         && cs->exception_index != EXCP_EXT_INTERRUPT) {
482         if (cs->exception_index < 0 || cs->exception_index > EXCP_LAST) {
483             name = "unknown";
484         } else {
485             name = excp_names[cs->exception_index];
486         }
487
488         qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx
489                  " %s exception\n",
490                  __func__, env->active_tc.PC, env->CP0_EPC, name);
491     }
492     if (cs->exception_index == EXCP_EXT_INTERRUPT &&
493         (env->hflags & MIPS_HFLAG_DM)) {
494         cs->exception_index = EXCP_DINT;
495     }
496     offset = 0x180;
497     switch (cs->exception_index) {
498     case EXCP_DSS:
499         env->CP0_Debug |= 1 << CP0DB_DSS;
500         /* Debug single step cannot be raised inside a delay slot and
501            resume will always occur on the next instruction
502            (but we assume the pc has always been updated during
503            code translation). */
504         env->CP0_DEPC = env->active_tc.PC | !!(env->hflags & MIPS_HFLAG_M16);
505         goto enter_debug_mode;
506     case EXCP_DINT:
507         env->CP0_Debug |= 1 << CP0DB_DINT;
508         goto set_DEPC;
509     case EXCP_DIB:
510         env->CP0_Debug |= 1 << CP0DB_DIB;
511         goto set_DEPC;
512     case EXCP_DBp:
513         env->CP0_Debug |= 1 << CP0DB_DBp;
514         goto set_DEPC;
515     case EXCP_DDBS:
516         env->CP0_Debug |= 1 << CP0DB_DDBS;
517         goto set_DEPC;
518     case EXCP_DDBL:
519         env->CP0_Debug |= 1 << CP0DB_DDBL;
520     set_DEPC:
521         env->CP0_DEPC = exception_resume_pc(env);
522         env->hflags &= ~MIPS_HFLAG_BMASK;
523  enter_debug_mode:
524         if (env->insn_flags & ISA_MIPS3) {
525             env->hflags |= MIPS_HFLAG_64;
526         }
527         env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_CP0;
528         env->hflags &= ~(MIPS_HFLAG_KSU);
529         /* EJTAG probe trap enable is not implemented... */
530         if (!(env->CP0_Status & (1 << CP0St_EXL)))
531             env->CP0_Cause &= ~(1U << CP0Ca_BD);
532         env->active_tc.PC = (int32_t)0xBFC00480;
533         set_hflags_for_handler(env);
534         break;
535     case EXCP_RESET:
536         cpu_reset(CPU(cpu));
537         break;
538     case EXCP_SRESET:
539         env->CP0_Status |= (1 << CP0St_SR);
540         memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
541         goto set_error_EPC;
542     case EXCP_NMI:
543         env->CP0_Status |= (1 << CP0St_NMI);
544  set_error_EPC:
545         env->CP0_ErrorEPC = exception_resume_pc(env);
546         env->hflags &= ~MIPS_HFLAG_BMASK;
547         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
548         if (env->insn_flags & ISA_MIPS3) {
549             env->hflags |= MIPS_HFLAG_64;
550         }
551         env->hflags |= MIPS_HFLAG_CP0;
552         env->hflags &= ~(MIPS_HFLAG_KSU);
553         if (!(env->CP0_Status & (1 << CP0St_EXL)))
554             env->CP0_Cause &= ~(1U << CP0Ca_BD);
555         env->active_tc.PC = (int32_t)0xBFC00000;
556         set_hflags_for_handler(env);
557         break;
558     case EXCP_EXT_INTERRUPT:
559         cause = 0;
560         if (env->CP0_Cause & (1 << CP0Ca_IV)) {
561             uint32_t spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & 0x1f;
562
563             if ((env->CP0_Status & (1 << CP0St_BEV)) || spacing == 0) {
564                 offset = 0x200;
565             } else {
566                 uint32_t vector = 0;
567                 uint32_t pending = (env->CP0_Cause & CP0Ca_IP_mask) >> CP0Ca_IP;
568
569                 if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
570                     /* For VEIC mode, the external interrupt controller feeds
571                      * the vector through the CP0Cause IP lines.  */
572                     vector = pending;
573                 } else {
574                     /* Vectored Interrupts
575                      * Mask with Status.IM7-IM0 to get enabled interrupts. */
576                     pending &= (env->CP0_Status >> CP0St_IM) & 0xff;
577                     /* Find the highest-priority interrupt. */
578                     while (pending >>= 1) {
579                         vector++;
580                     }
581                 }
582                 offset = 0x200 + (vector * (spacing << 5));
583             }
584         }
585         goto set_EPC;
586     case EXCP_LTLBL:
587         cause = 1;
588         update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL);
589         goto set_EPC;
590     case EXCP_TLBL:
591         cause = 2;
592         update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL);
593         if ((env->error_code & EXCP_TLB_NOMATCH) &&
594             !(env->CP0_Status & (1 << CP0St_EXL))) {
595 #if defined(TARGET_MIPS64)
596             int R = env->CP0_BadVAddr >> 62;
597             int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
598             int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
599             int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
600
601             if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
602                 (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
603                 offset = 0x080;
604             else
605 #endif
606                 offset = 0x000;
607         }
608         goto set_EPC;
609     case EXCP_TLBS:
610         cause = 3;
611         update_badinstr = 1;
612         if ((env->error_code & EXCP_TLB_NOMATCH) &&
613             !(env->CP0_Status & (1 << CP0St_EXL))) {
614 #if defined(TARGET_MIPS64)
615             int R = env->CP0_BadVAddr >> 62;
616             int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
617             int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
618             int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
619
620             if (((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX)) &&
621                 (!(env->insn_flags & (INSN_LOONGSON2E | INSN_LOONGSON2F))))
622                 offset = 0x080;
623             else
624 #endif
625                 offset = 0x000;
626         }
627         goto set_EPC;
628     case EXCP_AdEL:
629         cause = 4;
630         update_badinstr = !(env->error_code & EXCP_INST_NOTAVAIL);
631         goto set_EPC;
632     case EXCP_AdES:
633         cause = 5;
634         update_badinstr = 1;
635         goto set_EPC;
636     case EXCP_IBE:
637         cause = 6;
638         goto set_EPC;
639     case EXCP_DBE:
640         cause = 7;
641         goto set_EPC;
642     case EXCP_SYSCALL:
643         cause = 8;
644         update_badinstr = 1;
645         goto set_EPC;
646     case EXCP_BREAK:
647         cause = 9;
648         update_badinstr = 1;
649         goto set_EPC;
650     case EXCP_RI:
651         cause = 10;
652         update_badinstr = 1;
653         goto set_EPC;
654     case EXCP_CpU:
655         cause = 11;
656         update_badinstr = 1;
657         env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
658                          (env->error_code << CP0Ca_CE);
659         goto set_EPC;
660     case EXCP_OVERFLOW:
661         cause = 12;
662         update_badinstr = 1;
663         goto set_EPC;
664     case EXCP_TRAP:
665         cause = 13;
666         update_badinstr = 1;
667         goto set_EPC;
668     case EXCP_MSAFPE:
669         cause = 14;
670         update_badinstr = 1;
671         goto set_EPC;
672     case EXCP_FPE:
673         cause = 15;
674         update_badinstr = 1;
675         goto set_EPC;
676     case EXCP_C2E:
677         cause = 18;
678         goto set_EPC;
679     case EXCP_TLBRI:
680         cause = 19;
681         update_badinstr = 1;
682         goto set_EPC;
683     case EXCP_TLBXI:
684         cause = 20;
685         goto set_EPC;
686     case EXCP_MSADIS:
687         cause = 21;
688         update_badinstr = 1;
689         goto set_EPC;
690     case EXCP_MDMX:
691         cause = 22;
692         goto set_EPC;
693     case EXCP_DWATCH:
694         cause = 23;
695         /* XXX: TODO: manage deferred watch exceptions */
696         goto set_EPC;
697     case EXCP_MCHECK:
698         cause = 24;
699         goto set_EPC;
700     case EXCP_THREAD:
701         cause = 25;
702         goto set_EPC;
703     case EXCP_DSPDIS:
704         cause = 26;
705         goto set_EPC;
706     case EXCP_CACHE:
707         cause = 30;
708         if (env->CP0_Status & (1 << CP0St_BEV)) {
709             offset = 0x100;
710         } else {
711             offset = 0x20000100;
712         }
713  set_EPC:
714         if (!(env->CP0_Status & (1 << CP0St_EXL))) {
715             env->CP0_EPC = exception_resume_pc(env);
716             if (update_badinstr) {
717                 set_badinstr_registers(env);
718             }
719             if (env->hflags & MIPS_HFLAG_BMASK) {
720                 env->CP0_Cause |= (1U << CP0Ca_BD);
721             } else {
722                 env->CP0_Cause &= ~(1U << CP0Ca_BD);
723             }
724             env->CP0_Status |= (1 << CP0St_EXL);
725             if (env->insn_flags & ISA_MIPS3) {
726                 env->hflags |= MIPS_HFLAG_64;
727             }
728             env->hflags |= MIPS_HFLAG_CP0;
729             env->hflags &= ~(MIPS_HFLAG_KSU);
730         }
731         env->hflags &= ~MIPS_HFLAG_BMASK;
732         if (env->CP0_Status & (1 << CP0St_BEV)) {
733             env->active_tc.PC = (int32_t)0xBFC00200;
734         } else {
735             env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
736         }
737         env->active_tc.PC += offset;
738         set_hflags_for_handler(env);
739         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
740         break;
741     default:
742         abort();
743     }
744     if (qemu_loglevel_mask(CPU_LOG_INT)
745         && cs->exception_index != EXCP_EXT_INTERRUPT) {
746         qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
747                  "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
748                  __func__, env->active_tc.PC, env->CP0_EPC, cause,
749                  env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
750                  env->CP0_DEPC);
751     }
752 #endif
753     cs->exception_index = EXCP_NONE;
754 }
755
756 bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
757 {
758     if (interrupt_request & CPU_INTERRUPT_HARD) {
759         MIPSCPU *cpu = MIPS_CPU(cs);
760         CPUMIPSState *env = &cpu->env;
761
762         if (cpu_mips_hw_interrupts_pending(env)) {
763             /* Raise it */
764             cs->exception_index = EXCP_EXT_INTERRUPT;
765             env->error_code = 0;
766             mips_cpu_do_interrupt(cs);
767             return true;
768         }
769     }
770     return false;
771 }
772
773 #if !defined(CONFIG_USER_ONLY)
774 void r4k_invalidate_tlb (CPUMIPSState *env, int idx, int use_extra)
775 {
776     MIPSCPU *cpu = mips_env_get_cpu(env);
777     CPUState *cs;
778     r4k_tlb_t *tlb;
779     target_ulong addr;
780     target_ulong end;
781     uint8_t ASID = env->CP0_EntryHi & 0xFF;
782     target_ulong mask;
783
784     tlb = &env->tlb->mmu.r4k.tlb[idx];
785     /* The qemu TLB is flushed when the ASID changes, so no need to
786        flush these entries again.  */
787     if (tlb->G == 0 && tlb->ASID != ASID) {
788         return;
789     }
790
791     if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
792         /* For tlbwr, we can shadow the discarded entry into
793            a new (fake) TLB entry, as long as the guest can not
794            tell that it's there.  */
795         env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
796         env->tlb->tlb_in_use++;
797         return;
798     }
799
800     /* 1k pages are not supported. */
801     mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
802     if (tlb->V0) {
803         cs = CPU(cpu);
804         addr = tlb->VPN & ~mask;
805 #if defined(TARGET_MIPS64)
806         if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
807             addr |= 0x3FFFFF0000000000ULL;
808         }
809 #endif
810         end = addr | (mask >> 1);
811         while (addr < end) {
812             tlb_flush_page(cs, addr);
813             addr += TARGET_PAGE_SIZE;
814         }
815     }
816     if (tlb->V1) {
817         cs = CPU(cpu);
818         addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
819 #if defined(TARGET_MIPS64)
820         if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
821             addr |= 0x3FFFFF0000000000ULL;
822         }
823 #endif
824         end = addr | mask;
825         while (addr - 1 < end) {
826             tlb_flush_page(cs, addr);
827             addr += TARGET_PAGE_SIZE;
828         }
829     }
830 }
831 #endif
This page took 0.069786 seconds and 4 git commands to generate.