|
|
1.1 root 1: /*
2: * SH4 emulation
3: *
4: * Copyright (c) 2005 Samuel Tardieu
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, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19: */
20: #include <stdarg.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24: #include <inttypes.h>
25: #include <signal.h>
26: #include <assert.h>
27:
28: #include "cpu.h"
29: #include "exec-all.h"
30:
1.1.1.2 ! root 31: #if defined(CONFIG_USER_ONLY)
! 32:
! 33: void do_interrupt (CPUState *env)
! 34: {
! 35: env->exception_index = -1;
! 36: }
! 37:
! 38: int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
! 39: int is_user, int is_softmmu)
! 40: {
! 41: env->tea = address;
! 42: switch (rw) {
! 43: case 0:
! 44: env->exception_index = 0x0a0;
! 45: break;
! 46: case 1:
! 47: env->exception_index = 0x0c0;
! 48: break;
! 49: case 2:
! 50: env->exception_index = 0x0a0;
! 51: break;
! 52: }
! 53: return 1;
! 54: }
! 55:
! 56: target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
! 57: {
! 58: return addr;
! 59: }
! 60:
! 61: #else /* !CONFIG_USER_ONLY */
! 62:
1.1 root 63: #define MMU_OK 0
64: #define MMU_ITLB_MISS (-1)
65: #define MMU_ITLB_MULTIPLE (-2)
66: #define MMU_ITLB_VIOLATION (-3)
67: #define MMU_DTLB_MISS_READ (-4)
68: #define MMU_DTLB_MISS_WRITE (-5)
69: #define MMU_DTLB_INITIAL_WRITE (-6)
70: #define MMU_DTLB_VIOLATION_READ (-7)
71: #define MMU_DTLB_VIOLATION_WRITE (-8)
72: #define MMU_DTLB_MULTIPLE (-9)
73: #define MMU_DTLB_MISS (-10)
74:
75: void do_interrupt(CPUState * env)
76: {
77: if (loglevel & CPU_LOG_INT) {
78: const char *expname;
79: switch (env->exception_index) {
80: case 0x0e0:
81: expname = "addr_error";
82: break;
83: case 0x040:
84: expname = "tlb_miss";
85: break;
86: case 0x0a0:
87: expname = "tlb_violation";
88: break;
89: case 0x180:
90: expname = "illegal_instruction";
91: break;
92: case 0x1a0:
93: expname = "slot_illegal_instruction";
94: break;
95: case 0x800:
96: expname = "fpu_disable";
97: break;
98: case 0x820:
99: expname = "slot_fpu";
100: break;
101: case 0x100:
102: expname = "data_write";
103: break;
104: case 0x060:
105: expname = "dtlb_miss_write";
106: break;
107: case 0x0c0:
108: expname = "dtlb_violation_write";
109: break;
110: case 0x120:
111: expname = "fpu_exception";
112: break;
113: case 0x080:
114: expname = "initial_page_write";
115: break;
116: case 0x160:
117: expname = "trapa";
118: break;
119: default:
120: expname = "???";
121: break;
122: }
123: fprintf(logfile, "exception 0x%03x [%s] raised\n",
124: env->exception_index, expname);
125: cpu_dump_state(env, logfile, fprintf, 0);
126: }
127:
128: env->ssr = env->sr;
129: env->spc = env->spc;
130: env->sgr = env->gregs[15];
131: env->sr |= SR_BL | SR_MD | SR_RB;
132:
133: env->expevt = env->exception_index & 0x7ff;
134: switch (env->exception_index) {
135: case 0x040:
136: case 0x060:
137: case 0x080:
138: env->pc = env->vbr + 0x400;
139: break;
140: case 0x140:
141: env->pc = 0xa0000000;
142: break;
143: default:
144: env->pc = env->vbr + 0x100;
145: break;
146: }
147: }
148:
149: static void update_itlb_use(CPUState * env, int itlbnb)
150: {
151: uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
152:
153: switch (itlbnb) {
154: case 0:
155: and_mask = 0x7f;
156: break;
157: case 1:
158: and_mask = 0xe7;
159: or_mask = 0x80;
160: break;
161: case 2:
162: and_mask = 0xfb;
163: or_mask = 0x50;
164: break;
165: case 3:
166: or_mask = 0x2c;
167: break;
168: }
169:
170: env->mmucr &= (and_mask << 24);
171: env->mmucr |= (or_mask << 24);
172: }
173:
174: static int itlb_replacement(CPUState * env)
175: {
176: if ((env->mmucr & 0xe0000000) == 0xe0000000)
177: return 0;
178: if ((env->mmucr & 0x98000000) == 0x08000000)
179: return 1;
180: if ((env->mmucr & 0x54000000) == 0x04000000)
181: return 2;
182: if ((env->mmucr & 0x2c000000) == 0x00000000)
183: return 3;
184: assert(0);
185: }
186:
187: /* Find the corresponding entry in the right TLB
188: Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
189: */
190: static int find_tlb_entry(CPUState * env, target_ulong address,
191: tlb_t * entries, uint8_t nbtlb, int use_asid)
192: {
193: int match = MMU_DTLB_MISS;
194: uint32_t start, end;
195: uint8_t asid;
196: int i;
197:
198: asid = env->pteh & 0xff;
199:
200: for (i = 0; i < nbtlb; i++) {
201: if (!entries[i].v)
202: continue; /* Invalid entry */
203: if (use_asid && entries[i].asid != asid && !entries[i].sh)
204: continue; /* Bad ASID */
205: #if 0
206: switch (entries[i].sz) {
207: case 0:
208: size = 1024; /* 1kB */
209: break;
210: case 1:
211: size = 4 * 1024; /* 4kB */
212: break;
213: case 2:
214: size = 64 * 1024; /* 64kB */
215: break;
216: case 3:
217: size = 1024 * 1024; /* 1MB */
218: break;
219: default:
220: assert(0);
221: }
222: #endif
223: start = (entries[i].vpn << 10) & ~(entries[i].size - 1);
224: end = start + entries[i].size - 1;
225: if (address >= start && address <= end) { /* Match */
226: if (match != -1)
227: return MMU_DTLB_MULTIPLE; /* Multiple match */
228: match = i;
229: }
230: }
231: return match;
232: }
233:
234: /* Find itlb entry - update itlb from utlb if necessary and asked for
235: Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
236: Update the itlb from utlb if update is not 0
237: */
238: int find_itlb_entry(CPUState * env, target_ulong address,
239: int use_asid, int update)
240: {
241: int e, n;
242:
243: e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
244: if (e == MMU_DTLB_MULTIPLE)
245: e = MMU_ITLB_MULTIPLE;
246: else if (e == MMU_DTLB_MISS && update) {
247: e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
248: if (e >= 0) {
249: n = itlb_replacement(env);
250: env->itlb[n] = env->utlb[e];
251: e = n;
252: }
253: }
254: if (e >= 0)
255: update_itlb_use(env, e);
256: return e;
257: }
258:
259: /* Find utlb entry
260: Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
261: int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
262: {
263: uint8_t urb, urc;
264:
265: /* Increment URC */
266: urb = ((env->mmucr) >> 18) & 0x3f;
267: urc = ((env->mmucr) >> 10) & 0x3f;
268: urc++;
269: if (urc == urb || urc == UTLB_SIZE - 1)
270: urc = 0;
271: env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
272:
273: /* Return entry */
274: return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
275: }
276:
277: /* Match address against MMU
278: Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
279: MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
280: MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
281: MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION
282: */
283: static int get_mmu_address(CPUState * env, target_ulong * physical,
284: int *prot, target_ulong address,
285: int rw, int access_type)
286: {
287: int use_asid, is_code, n;
288: tlb_t *matching = NULL;
289:
290: use_asid = (env->mmucr & MMUCR_SV) == 0 && (env->sr & SR_MD) == 0;
291: is_code = env->pc == address; /* Hack */
292:
293: /* Use a hack to find if this is an instruction or data access */
294: if (env->pc == address && !(rw & PAGE_WRITE)) {
295: n = find_itlb_entry(env, address, use_asid, 1);
296: if (n >= 0) {
297: matching = &env->itlb[n];
298: if ((env->sr & SR_MD) & !(matching->pr & 2))
299: n = MMU_ITLB_VIOLATION;
300: else
301: *prot = PAGE_READ;
302: }
303: } else {
304: n = find_utlb_entry(env, address, use_asid);
305: if (n >= 0) {
306: matching = &env->utlb[n];
307: switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) {
308: case 0: /* 000 */
309: case 2: /* 010 */
310: n = (rw & PAGE_WRITE) ? MMU_DTLB_VIOLATION_WRITE :
311: MMU_DTLB_VIOLATION_READ;
312: break;
313: case 1: /* 001 */
314: case 4: /* 100 */
315: case 5: /* 101 */
316: if (rw & PAGE_WRITE)
317: n = MMU_DTLB_VIOLATION_WRITE;
318: else
319: *prot = PAGE_READ;
320: break;
321: case 3: /* 011 */
322: case 6: /* 110 */
323: case 7: /* 111 */
324: *prot = rw & (PAGE_READ | PAGE_WRITE);
325: break;
326: }
327: } else if (n == MMU_DTLB_MISS) {
328: n = (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
329: MMU_DTLB_MISS_READ;
330: }
331: }
332: if (n >= 0) {
333: *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
334: (address & (matching->size - 1));
335: if ((rw & PAGE_WRITE) & !matching->d)
336: n = MMU_DTLB_INITIAL_WRITE;
337: else
338: n = MMU_OK;
339: }
340: return n;
341: }
342:
343: int get_physical_address(CPUState * env, target_ulong * physical,
344: int *prot, target_ulong address,
345: int rw, int access_type)
346: {
347: /* P1, P2 and P4 areas do not use translation */
348: if ((address >= 0x80000000 && address < 0xc0000000) ||
349: address >= 0xe0000000) {
350: if (!(env->sr & SR_MD)
351: && (address < 0xe0000000 || address > 0xe4000000)) {
352: /* Unauthorized access in user mode (only store queues are available) */
353: fprintf(stderr, "Unauthorized access\n");
354: return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
355: MMU_DTLB_MISS_READ;
356: }
357: /* Mask upper 3 bits */
358: *physical = address & 0x1FFFFFFF;
359: *prot = PAGE_READ | PAGE_WRITE;
360: return MMU_OK;
361: }
362:
363: /* If MMU is disabled, return the corresponding physical page */
364: if (!env->mmucr & MMUCR_AT) {
365: *physical = address & 0x1FFFFFFF;
366: *prot = PAGE_READ | PAGE_WRITE;
367: return MMU_OK;
368: }
369:
370: /* We need to resort to the MMU */
371: return get_mmu_address(env, physical, prot, address, rw, access_type);
372: }
373:
374: int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
375: int is_user, int is_softmmu)
376: {
377: target_ulong physical, page_offset, page_size;
378: int prot, ret, access_type;
379:
380: /* XXXXX */
381: #if 0
382: fprintf(stderr, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
383: __func__, env->pc, address, rw, is_user, is_softmmu);
384: #endif
385:
386: access_type = ACCESS_INT;
387: ret =
388: get_physical_address(env, &physical, &prot, address, rw,
389: access_type);
390:
391: if (ret != MMU_OK) {
392: env->tea = address;
393: switch (ret) {
394: case MMU_ITLB_MISS:
395: case MMU_DTLB_MISS_READ:
396: env->exception_index = 0x040;
397: break;
398: case MMU_DTLB_MULTIPLE:
399: case MMU_ITLB_MULTIPLE:
400: env->exception_index = 0x140;
401: break;
402: case MMU_ITLB_VIOLATION:
403: env->exception_index = 0x0a0;
404: break;
405: case MMU_DTLB_MISS_WRITE:
406: env->exception_index = 0x060;
407: break;
408: case MMU_DTLB_INITIAL_WRITE:
409: env->exception_index = 0x080;
410: break;
411: case MMU_DTLB_VIOLATION_READ:
412: env->exception_index = 0x0a0;
413: break;
414: case MMU_DTLB_VIOLATION_WRITE:
415: env->exception_index = 0x0c0;
416: break;
417: default:
418: assert(0);
419: }
420: return 1;
421: }
422:
423: page_size = TARGET_PAGE_SIZE;
424: page_offset =
425: (address - (address & TARGET_PAGE_MASK)) & ~(page_size - 1);
426: address = (address & TARGET_PAGE_MASK) + page_offset;
427: physical = (physical & TARGET_PAGE_MASK) + page_offset;
428:
429: return tlb_set_page(env, address, physical, prot, is_user, is_softmmu);
430: }
1.1.1.2 ! root 431:
! 432: target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
! 433: {
! 434: target_ulong physical;
! 435: int prot;
! 436:
! 437: get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0);
! 438: return physical;
! 439: }
! 440:
! 441: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.