Revision a541f297 target-ppc/helper.c
b/target-ppc/helper.c | ||
---|---|---|
21 | 21 |
|
22 | 22 |
#include "exec.h" |
23 | 23 |
#if defined (USE_OPEN_FIRMWARE) |
24 |
#include <time.h> |
|
24 | 25 |
#include "of.h" |
25 | 26 |
#endif |
26 | 27 |
|
... | ... | |
28 | 29 |
//#define DEBUG_BATS |
29 | 30 |
//#define DEBUG_EXCEPTIONS |
30 | 31 |
|
31 |
extern FILE *logfile, *stderr; |
|
32 |
extern FILE *logfile, *stdout, *stderr;
|
|
32 | 33 |
void exit (int); |
33 | 34 |
void abort (void); |
34 | 35 |
|
... | ... | |
74 | 75 |
|
75 | 76 |
/*****************************************************************************/ |
76 | 77 |
/* PPC MMU emulation */ |
78 |
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
|
79 |
int is_user, int is_softmmu); |
|
80 |
|
|
77 | 81 |
/* Perform BAT hit & translation */ |
78 | 82 |
static int get_bat (CPUState *env, uint32_t *real, int *prot, |
79 | 83 |
uint32_t virtual, int rw, int type) |
... | ... | |
88 | 92 |
fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__, |
89 | 93 |
type == ACCESS_CODE ? 'I' : 'D', virtual); |
90 | 94 |
} |
91 |
printf("%s: %cBAT v 0x%08x\n", __func__, |
|
92 |
type == ACCESS_CODE ? 'I' : 'D', virtual); |
|
93 | 95 |
#endif |
94 | 96 |
switch (type) { |
95 | 97 |
case ACCESS_CODE: |
... | ... | |
106 | 108 |
fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__, |
107 | 109 |
type == ACCESS_CODE ? 'I' : 'D', virtual); |
108 | 110 |
} |
109 |
printf("%s...: %cBAT v 0x%08x\n", __func__, |
|
110 |
type == ACCESS_CODE ? 'I' : 'D', virtual); |
|
111 | 111 |
#endif |
112 | 112 |
base = virtual & 0xFFFC0000; |
113 | 113 |
for (i = 0; i < 4; i++) { |
... | ... | |
121 | 121 |
fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", |
122 | 122 |
__func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, |
123 | 123 |
*BATu, *BATl); |
124 |
} else { |
|
125 |
printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n", |
|
126 |
__func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, |
|
127 |
*BATu, *BATl); |
|
128 | 124 |
} |
129 | 125 |
#endif |
130 | 126 |
if ((virtual & 0xF0000000) == BEPIu && |
... | ... | |
135 | 131 |
/* Get physical address */ |
136 | 132 |
*real = (*BATl & 0xF0000000) | |
137 | 133 |
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) | |
138 |
(virtual & 0x0001FFFF);
|
|
134 |
(virtual & 0x0001F000);
|
|
139 | 135 |
if (*BATl & 0x00000001) |
140 | 136 |
*prot = PROT_READ; |
141 | 137 |
if (*BATl & 0x00000002) |
... | ... | |
145 | 141 |
fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n", |
146 | 142 |
i, *real, *prot & PROT_READ ? 'R' : '-', |
147 | 143 |
*prot & PROT_WRITE ? 'W' : '-'); |
148 |
} else { |
|
149 |
printf("BAT %d match: 0x%08x => 0x%08x prot=%c%c\n", |
|
150 |
i, virtual, *real, *prot & PROT_READ ? 'R' : '-', |
|
151 |
*prot & PROT_WRITE ? 'W' : '-'); |
|
152 | 144 |
} |
153 | 145 |
#endif |
154 | 146 |
ret = 0; |
... | ... | |
181 | 173 |
static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va, |
182 | 174 |
int h, int key, int rw) |
183 | 175 |
{ |
184 |
uint32_t pte0, pte1, keep = 0; |
|
176 |
uint32_t pte0, pte1, keep = 0, access = 0;
|
|
185 | 177 |
int i, good = -1, store = 0; |
186 | 178 |
int ret = -1; /* No entry found */ |
187 | 179 |
|
... | ... | |
189 | 181 |
pte0 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8))); |
190 | 182 |
pte1 = ldl_raw((void *)((uint32_t)phys_ram_base + base + (i * 8) + 4)); |
191 | 183 |
#if defined (DEBUG_MMU) |
192 |
printf("Load pte from 0x%08x => 0x%08x 0x%08x\n", base + (i * 8), |
|
193 |
pte0, pte1); |
|
184 |
if (loglevel > 0) { |
|
185 |
fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x " |
|
186 |
"%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1, |
|
187 |
pte0 >> 31, h, (pte0 >> 6) & 1, va); |
|
188 |
} |
|
194 | 189 |
#endif |
195 | 190 |
/* Check validity and table match */ |
196 | 191 |
if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) { |
197 |
#if defined (DEBUG_MMU) |
|
198 |
printf("PTE is valid and table matches... compare 0x%08x:%08x\n", |
|
199 |
pte0 & 0x7FFFFFBF, va); |
|
200 |
#endif |
|
201 | 192 |
/* Check vsid & api */ |
202 | 193 |
if ((pte0 & 0x7FFFFFBF) == va) { |
203 |
#if defined (DEBUG_MMU) |
|
204 |
printf("PTE match !\n"); |
|
205 |
#endif |
|
206 | 194 |
if (good == -1) { |
207 | 195 |
good = i; |
208 | 196 |
keep = pte1; |
209 | 197 |
} else { |
210 | 198 |
/* All matches should have equal RPN, WIMG & PP */ |
211 | 199 |
if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) { |
212 |
printf("Bad RPN/WIMG/PP\n"); |
|
200 |
if (loglevel > 0) |
|
201 |
fprintf(logfile, "Bad RPN/WIMG/PP\n"); |
|
213 | 202 |
return -1; |
214 | 203 |
} |
215 | 204 |
} |
216 | 205 |
/* Check access rights */ |
217 | 206 |
if (key == 0) { |
218 |
*prot = PROT_READ;
|
|
207 |
access = PROT_READ;
|
|
219 | 208 |
if ((pte1 & 0x00000003) != 0x3) |
220 |
*prot |= PROT_WRITE;
|
|
209 |
access |= PROT_WRITE;
|
|
221 | 210 |
} else { |
222 | 211 |
switch (pte1 & 0x00000003) { |
223 | 212 |
case 0x0: |
224 |
*prot = 0;
|
|
213 |
access = 0;
|
|
225 | 214 |
break; |
226 | 215 |
case 0x1: |
227 | 216 |
case 0x3: |
228 |
*prot = PROT_READ;
|
|
217 |
access = PROT_READ;
|
|
229 | 218 |
break; |
230 | 219 |
case 0x2: |
231 |
*prot = PROT_READ | PROT_WRITE;
|
|
220 |
access = PROT_READ | PROT_WRITE;
|
|
232 | 221 |
break; |
233 | 222 |
} |
234 | 223 |
} |
235 |
if ((rw == 0 && *prot != 0) || |
|
236 |
(rw == 1 && (*prot & PROT_WRITE))) { |
|
224 |
if (ret < 0) { |
|
225 |
if ((rw == 0 && (access & PROT_READ)) || |
|
226 |
(rw == 1 && (access & PROT_WRITE))) { |
|
237 | 227 |
#if defined (DEBUG_MMU) |
238 |
printf("PTE access granted !\n"); |
|
228 |
if (loglevel > 0) |
|
229 |
fprintf(logfile, "PTE access granted !\n"); |
|
239 | 230 |
#endif |
240 | 231 |
good = i; |
241 | 232 |
keep = pte1; |
242 | 233 |
ret = 0; |
243 |
} else if (ret == -1) { |
|
244 |
ret = -2; /* Access right violation */ |
|
234 |
} else { |
|
235 |
/* Access right violation */ |
|
236 |
ret = -2; |
|
245 | 237 |
#if defined (DEBUG_MMU) |
246 |
printf("PTE access rejected\n"); |
|
238 |
if (loglevel > 0) |
|
239 |
fprintf(logfile, "PTE access rejected\n"); |
|
247 | 240 |
#endif |
248 | 241 |
} |
242 |
*prot = access; |
|
243 |
} |
|
249 | 244 |
} |
250 | 245 |
} |
251 | 246 |
} |
252 | 247 |
if (good != -1) { |
253 | 248 |
*RPN = keep & 0xFFFFF000; |
254 | 249 |
#if defined (DEBUG_MMU) |
255 |
printf("found PTE at addr 0x%08x prot=0x%01x ret=%d\n", |
|
250 |
if (loglevel > 0) { |
|
251 |
fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n", |
|
256 | 252 |
*RPN, *prot, ret); |
253 |
} |
|
257 | 254 |
#endif |
258 | 255 |
/* Update page flags */ |
259 | 256 |
if (!(keep & 0x00000100)) { |
257 |
/* Access flag */ |
|
260 | 258 |
keep |= 0x00000100; |
261 | 259 |
store = 1; |
262 | 260 |
} |
263 |
if (rw) { |
|
264 | 261 |
if (!(keep & 0x00000080)) { |
262 |
if (rw && ret == 0) { |
|
263 |
/* Change flag */ |
|
265 | 264 |
keep |= 0x00000080; |
266 | 265 |
store = 1; |
266 |
} else { |
|
267 |
/* Force page fault for first write access */ |
|
268 |
*prot &= ~PROT_WRITE; |
|
267 | 269 |
} |
268 | 270 |
} |
269 |
if (store) |
|
270 |
stl_raw((void *)(base + (good * 2) + 1), keep); |
|
271 |
if (store) { |
|
272 |
stl_raw((void *)((uint32_t)phys_ram_base + base + (good * 8) + 4), |
|
273 |
keep); |
|
274 |
} |
|
271 | 275 |
} |
272 | 276 |
|
273 | 277 |
return ret; |
... | ... | |
290 | 294 |
|
291 | 295 |
sr = env->sr[virtual >> 28]; |
292 | 296 |
#if defined (DEBUG_MMU) |
293 |
printf("Check segment v=0x%08x %d 0x%08x nip=0x%08x lr=0x%08x ir=%d dr=%d " |
|
294 |
"pr=%d t=%d\n", virtual, virtual >> 28, sr, env->nip, |
|
295 |
env->lr, msr_ir, msr_dr, msr_pr, type); |
|
297 |
if (loglevel > 0) { |
|
298 |
fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x " |
|
299 |
"lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n", |
|
300 |
virtual, virtual >> 28, sr, env->nip, |
|
301 |
env->lr, msr_ir, msr_dr, msr_pr, rw, type); |
|
302 |
} |
|
296 | 303 |
#endif |
297 |
key = ((sr & 0x20000000) && msr_pr == 1) || |
|
298 |
((sr & 0x40000000) && msr_pr == 0) ? 1 : 0; |
|
304 |
key = (((sr & 0x20000000) && msr_pr == 1) ||
|
|
305 |
((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
|
|
299 | 306 |
if ((sr & 0x80000000) == 0) { |
300 | 307 |
#if defined (DEBUG_MMU) |
301 |
printf("pte segment: key=%d n=0x%08x\n", key, sr & 0x10000000); |
|
308 |
if (loglevel > 0) |
|
309 |
fprintf(logfile, "pte segment: key=%d n=0x%08x\n", |
|
310 |
key, sr & 0x10000000); |
|
302 | 311 |
#endif |
303 | 312 |
/* Check if instruction fetch is allowed, if needed */ |
304 | 313 |
if (type != ACCESS_CODE || (sr & 0x10000000) == 0) { |
305 | 314 |
/* Page address translation */ |
306 | 315 |
vsid = sr & 0x00FFFFFF; |
307 | 316 |
pgidx = (virtual >> 12) & 0xFFFF; |
308 |
sdr = env->spr[SDR1];
|
|
309 |
hash = ((vsid ^ pgidx) & 0x07FFFF) << 6; |
|
317 |
sdr = env->sdr1;
|
|
318 |
hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
|
|
310 | 319 |
mask = ((sdr & 0x000001FF) << 16) | 0xFFC0; |
311 | 320 |
pg_addr = get_pgaddr(sdr, hash, mask); |
312 | 321 |
ptem = (vsid << 7) | (pgidx >> 10); |
313 | 322 |
#if defined (DEBUG_MMU) |
314 |
printf("0 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%07x " |
|
315 |
"pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); |
|
323 |
if (loglevel > 0) { |
|
324 |
fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x " |
|
325 |
"hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, |
|
326 |
pg_addr); |
|
327 |
} |
|
316 | 328 |
#endif |
317 | 329 |
/* Primary table lookup */ |
318 | 330 |
ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw); |
... | ... | |
321 | 333 |
hash = (~hash) & 0x01FFFFC0; |
322 | 334 |
pg_addr = get_pgaddr(sdr, hash, mask); |
323 | 335 |
#if defined (DEBUG_MMU) |
324 |
printf("1 sdr1=0x%08x vsid=0x%06x api=0x%04x hash=0x%05x " |
|
325 |
"pg_addr=0x%08x\n", sdr, vsid, pgidx, hash, pg_addr); |
|
336 |
if (virtual != 0xEFFFFFFF && loglevel > 0) { |
|
337 |
fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x " |
|
338 |
"hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx, |
|
339 |
hash, pg_addr); |
|
340 |
} |
|
326 | 341 |
#endif |
327 | 342 |
ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw); |
328 | 343 |
if (ret2 != -1) |
329 | 344 |
ret = ret2; |
330 | 345 |
} |
331 |
if (ret != -1) |
|
332 |
*real |= (virtual & 0x00000FFF); |
|
333 |
if (ret == -2 && type == ACCESS_CODE && (sr & 0x10000000)) |
|
334 |
ret = -3; |
|
335 | 346 |
} else { |
336 | 347 |
#if defined (DEBUG_MMU) |
337 |
printf("No access allowed\n"); |
|
348 |
if (loglevel > 0) |
|
349 |
fprintf(logfile, "No access allowed\n"); |
|
338 | 350 |
#endif |
351 |
ret = -3; |
|
339 | 352 |
} |
340 | 353 |
} else { |
341 | 354 |
#if defined (DEBUG_MMU) |
342 |
printf("direct store...\n"); |
|
355 |
if (loglevel > 0) |
|
356 |
fprintf(logfile, "direct store...\n"); |
|
343 | 357 |
#endif |
344 | 358 |
/* Direct-store segment : absolutely *BUGGY* for now */ |
345 | 359 |
switch (type) { |
... | ... | |
393 | 407 |
if (loglevel > 0) { |
394 | 408 |
fprintf(logfile, "%s\n", __func__); |
395 | 409 |
} |
410 |
|
|
396 | 411 |
if ((access_type == ACCESS_CODE && msr_ir == 0) || msr_dr == 0) { |
397 | 412 |
/* No address translation */ |
398 |
*physical = address; |
|
413 |
*physical = address & ~0xFFF;
|
|
399 | 414 |
*prot = PROT_READ | PROT_WRITE; |
400 | 415 |
ret = 0; |
401 | 416 |
} else { |
... | ... | |
406 | 421 |
ret = get_segment(env, physical, prot, address, rw, access_type); |
407 | 422 |
} |
408 | 423 |
} |
424 |
if (loglevel > 0) { |
|
425 |
fprintf(logfile, "%s address %08x => %08x\n", |
|
426 |
__func__, address, *physical); |
|
427 |
} |
|
409 | 428 |
|
410 | 429 |
return ret; |
411 | 430 |
} |
... | ... | |
448 | 467 |
NULL, it means that the function was called in C code (i.e. not |
449 | 468 |
from generated code or from helper.c) */ |
450 | 469 |
/* XXX: fix it to restore all registers */ |
451 |
void tlb_fill(unsigned long addr, int is_write, int flags, void *retaddr)
|
|
470 |
void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
|
|
452 | 471 |
{ |
453 | 472 |
TranslationBlock *tb; |
454 |
int ret, is_user; |
|
455 |
unsigned long pc; |
|
456 | 473 |
CPUState *saved_env; |
474 |
unsigned long pc; |
|
475 |
int ret; |
|
457 | 476 |
|
458 | 477 |
/* XXX: hack to restore env in all cases, even if not called from |
459 | 478 |
generated code */ |
460 | 479 |
saved_env = env; |
461 | 480 |
env = cpu_single_env; |
462 |
is_user = flags & 0x01; |
|
463 | 481 |
{ |
464 | 482 |
unsigned long tlb_addrr, tlb_addrw; |
465 | 483 |
int index; |
... | ... | |
474 | 492 |
tlb_addrr & (TARGET_PAGE_MASK | TLB_INVALID_MASK)); |
475 | 493 |
#endif |
476 | 494 |
} |
477 |
ret = cpu_handle_mmu_fault(env, addr, is_write, flags, 1);
|
|
495 |
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
|
478 | 496 |
if (ret) { |
479 | 497 |
if (retaddr) { |
480 | 498 |
/* now we have a real cpu fault */ |
... | ... | |
506 | 524 |
env = saved_env; |
507 | 525 |
} |
508 | 526 |
|
509 |
void cpu_ppc_init_mmu(CPUPPCState *env)
|
|
527 |
void cpu_ppc_init_mmu(CPUState *env) |
|
510 | 528 |
{ |
511 | 529 |
/* Nothing to do: all translation are disabled */ |
512 | 530 |
} |
... | ... | |
514 | 532 |
|
515 | 533 |
/* Perform address translation */ |
516 | 534 |
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, |
517 |
int flags, int is_softmmu)
|
|
535 |
int is_user, int is_softmmu)
|
|
518 | 536 |
{ |
519 | 537 |
uint32_t physical; |
520 | 538 |
int prot; |
521 | 539 |
int exception = 0, error_code = 0; |
522 |
int is_user, access_type;
|
|
540 |
int access_type; |
|
523 | 541 |
int ret = 0; |
524 | 542 |
|
525 | 543 |
// printf("%s 0\n", __func__); |
526 |
is_user = flags & 0x01; |
|
527 | 544 |
access_type = env->access_type; |
528 | 545 |
if (env->user_mode_only) { |
529 | 546 |
/* user mode only emulation */ |
530 | 547 |
ret = -1; |
531 | 548 |
goto do_fault; |
532 | 549 |
} |
550 |
/* NASTY BUG workaround */ |
|
551 |
if (access_type == ACCESS_CODE && rw) { |
|
552 |
// printf("%s: ERROR WRITE CODE ACCESS\n", __func__); |
|
553 |
access_type = ACCESS_INT; |
|
554 |
} |
|
533 | 555 |
ret = get_physical_address(env, &physical, &prot, |
534 | 556 |
address, rw, access_type); |
535 | 557 |
if (ret == 0) { |
536 |
ret = tlb_set_page(env, address, physical, prot, is_user, is_softmmu); |
|
558 |
ret = tlb_set_page(env, address & ~0xFFF, physical, prot, |
|
559 |
is_user, is_softmmu); |
|
537 | 560 |
} else if (ret < 0) { |
538 | 561 |
do_fault: |
539 | 562 |
#if defined (DEBUG_MMU) |
540 |
printf("%s 5\n", __func__); |
|
541 |
printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x TBL=0x%08x\n", |
|
542 |
env->nip, env->lr, env->ctr, /*msr*/0, env->tb[0]); |
|
543 |
{ |
|
544 |
int i; |
|
545 |
for (i = 0; i < 32; i++) { |
|
546 |
if ((i & 7) == 0) |
|
547 |
printf("GPR%02d:", i); |
|
548 |
printf(" %08x", env->gpr[i]); |
|
549 |
if ((i & 7) == 7) |
|
550 |
printf("\n"); |
|
551 |
} |
|
552 |
printf("CR: 0x"); |
|
553 |
for (i = 0; i < 8; i++) |
|
554 |
printf("%01x", env->crf[i]); |
|
555 |
printf(" ["); |
|
556 |
for (i = 0; i < 8; i++) { |
|
557 |
char a = '-'; |
|
558 |
if (env->crf[i] & 0x08) |
|
559 |
a = 'L'; |
|
560 |
else if (env->crf[i] & 0x04) |
|
561 |
a = 'G'; |
|
562 |
else if (env->crf[i] & 0x02) |
|
563 |
a = 'E'; |
|
564 |
printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); |
|
565 |
} |
|
566 |
printf(" ] "); |
|
567 |
} |
|
568 |
printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); |
|
569 |
printf("SRR0 0x%08x SRR1 0x%08x\n", env->spr[SRR0], env->spr[SRR1]); |
|
563 |
if (loglevel > 0) |
|
564 |
cpu_ppc_dump_state(env, logfile, 0); |
|
570 | 565 |
#endif |
571 | 566 |
if (access_type == ACCESS_CODE) { |
572 | 567 |
exception = EXCP_ISI; |
... | ... | |
580 | 575 |
error_code = EXCP_ISI_PROT; |
581 | 576 |
break; |
582 | 577 |
case -3: |
578 |
/* No execute protection violation */ |
|
583 | 579 |
error_code = EXCP_ISI_NOEXEC; |
584 | 580 |
break; |
585 | 581 |
case -4: |
586 | 582 |
/* Direct store exception */ |
587 | 583 |
/* No code fetch is allowed in direct-store areas */ |
588 |
exception = EXCP_ISI; |
|
589 |
error_code = EXCP_ISI_NOEXEC; |
|
584 |
error_code = EXCP_ISI_DIRECT; |
|
590 | 585 |
break; |
591 | 586 |
} |
592 | 587 |
} else { |
... | ... | |
612 | 607 |
/* lwarx, ldarx or srwcx. */ |
613 | 608 |
exception = EXCP_DSI; |
614 | 609 |
error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT; |
615 |
if (rw) |
|
616 |
error_code |= EXCP_DSI_STORE; |
|
617 | 610 |
break; |
618 | 611 |
case ACCESS_EXT: |
619 | 612 |
/* eciwx or ecowx */ |
620 | 613 |
exception = EXCP_DSI; |
621 |
error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | EXCP_ECXW; |
|
614 |
error_code = EXCP_DSI_NOTSUP | EXCP_DSI_DIRECT | |
|
615 |
EXCP_DSI_ECXW; |
|
622 | 616 |
break; |
623 | 617 |
default: |
618 |
printf("DSI: invalid exception (%d)\n", ret); |
|
624 | 619 |
exception = EXCP_PROGRAM; |
625 | 620 |
error_code = EXCP_INVAL | EXCP_INVAL_INVAL; |
626 | 621 |
break; |
... | ... | |
628 | 623 |
} |
629 | 624 |
if (rw) |
630 | 625 |
error_code |= EXCP_DSI_STORE; |
631 |
/* Should find a better solution: |
|
632 |
* this will be invalid for some exception if more than one |
|
633 |
* exception occurs for one instruction |
|
634 |
*/ |
|
635 |
env->spr[DSISR] = 0; |
|
636 |
if (error_code & EXCP_DSI_DIRECT) { |
|
637 |
env->spr[DSISR] |= 0x80000000; |
|
638 |
if (access_type == ACCESS_EXT || |
|
639 |
access_type == ACCESS_RES) |
|
640 |
env->spr[DSISR] |= 0x04000000; |
|
641 |
} |
|
642 |
if ((error_code & 0xF) == EXCP_DSI_TRANSLATE) |
|
643 |
env->spr[DSISR] |= 0x40000000; |
|
644 |
if (error_code & EXCP_DSI_PROT) |
|
645 |
env->spr[DSISR] |= 0x08000000; |
|
646 |
if (error_code & EXCP_DSI_STORE) |
|
647 |
env->spr[DSISR] |= 0x02000000; |
|
648 |
if ((error_code & 0xF) == EXCP_DSI_DABR) |
|
649 |
env->spr[DSISR] |= 0x00400000; |
|
650 |
if (access_type == ACCESS_EXT) |
|
651 |
env->spr[DSISR] |= 0x00100000; |
|
626 |
/* Store fault address */ |
|
627 |
env->spr[DAR] = address; |
|
652 | 628 |
} |
653 | 629 |
#if 0 |
654 | 630 |
printf("%s: set exception to %d %02x\n", |
... | ... | |
656 | 632 |
#endif |
657 | 633 |
env->exception_index = exception; |
658 | 634 |
env->error_code = error_code; |
659 |
/* Store fault address */ |
|
660 |
env->spr[DAR] = address; |
|
661 | 635 |
ret = 1; |
662 | 636 |
} |
663 | 637 |
|
664 | 638 |
return ret; |
665 | 639 |
} |
666 | 640 |
|
667 |
uint32_t _load_xer (void)
|
|
641 |
uint32_t _load_xer (CPUState *env)
|
|
668 | 642 |
{ |
669 | 643 |
return (xer_so << XER_SO) | |
670 | 644 |
(xer_ov << XER_OV) | |
... | ... | |
672 | 646 |
(xer_bc << XER_BC); |
673 | 647 |
} |
674 | 648 |
|
675 |
void _store_xer (uint32_t value) |
|
649 |
void _store_xer (CPUState *env, uint32_t value)
|
|
676 | 650 |
{ |
677 | 651 |
xer_so = (value >> XER_SO) & 0x01; |
678 | 652 |
xer_ov = (value >> XER_OV) & 0x01; |
... | ... | |
680 | 654 |
xer_bc = (value >> XER_BC) & 0x1f; |
681 | 655 |
} |
682 | 656 |
|
683 |
uint32_t _load_msr (void)
|
|
657 |
uint32_t _load_msr (CPUState *env)
|
|
684 | 658 |
{ |
685 | 659 |
return (msr_pow << MSR_POW) | |
686 | 660 |
(msr_ile << MSR_ILE) | |
... | ... | |
699 | 673 |
(msr_le << MSR_LE); |
700 | 674 |
} |
701 | 675 |
|
702 |
void _store_msr (uint32_t value) |
|
676 |
void _store_msr (CPUState *env, uint32_t value)
|
|
703 | 677 |
{ |
678 |
if (((T0 >> MSR_IR) & 0x01) != msr_ir || |
|
679 |
((T0 >> MSR_DR) & 0x01) != msr_dr) { |
|
680 |
/* Flush all tlb when changing translation mode or privilege level */ |
|
681 |
do_tlbia(); |
|
682 |
} |
|
704 | 683 |
msr_pow = (value >> MSR_POW) & 0x03; |
705 | 684 |
msr_ile = (value >> MSR_ILE) & 0x01; |
706 | 685 |
msr_ee = (value >> MSR_EE) & 0x01; |
... | ... | |
729 | 708 |
/* Dequeue PPC exceptions */ |
730 | 709 |
if (excp < EXCP_PPC_MAX) |
731 | 710 |
env->exceptions &= ~(1 << excp); |
732 |
msr = _load_msr(); |
|
711 |
msr = _load_msr(env);
|
|
733 | 712 |
#if defined (DEBUG_EXCEPTIONS) |
734 |
if (excp != EXCP_DECR && excp == EXCP_PROGRAM && excp < EXCP_PPC_MAX)
|
|
713 |
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1)
|
|
735 | 714 |
{ |
736 | 715 |
if (loglevel > 0) { |
737 | 716 |
fprintf(logfile, "Raise exception at 0x%08x => 0x%08x (%02x)\n", |
738 | 717 |
env->nip, excp << 8, env->error_code); |
739 |
} else { |
|
740 |
printf("Raise exception at 0x%08x => 0x%08x (%02x)\n", |
|
741 |
env->nip, excp << 8, env->error_code); |
|
742 |
} |
|
743 |
printf("nip=0x%08x LR=0x%08x CTR=0x%08x MSR=0x%08x DECR=0x%08x\n", |
|
744 |
env->nip, env->lr, env->ctr, msr, env->decr); |
|
745 |
{ |
|
746 |
int i; |
|
747 |
for (i = 0; i < 32; i++) { |
|
748 |
if ((i & 7) == 0) |
|
749 |
printf("GPR%02d:", i); |
|
750 |
printf(" %08x", env->gpr[i]); |
|
751 |
if ((i & 7) == 7) |
|
752 |
printf("\n"); |
|
753 |
} |
|
754 |
printf("CR: 0x"); |
|
755 |
for (i = 0; i < 8; i++) |
|
756 |
printf("%01x", env->crf[i]); |
|
757 |
printf(" ["); |
|
758 |
for (i = 0; i < 8; i++) { |
|
759 |
char a = '-'; |
|
760 |
if (env->crf[i] & 0x08) |
|
761 |
a = 'L'; |
|
762 |
else if (env->crf[i] & 0x04) |
|
763 |
a = 'G'; |
|
764 |
else if (env->crf[i] & 0x02) |
|
765 |
a = 'E'; |
|
766 |
printf(" %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); |
|
767 | 718 |
} |
768 |
printf(" ] "); |
|
769 |
} |
|
770 |
printf("TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); |
|
771 |
printf("XER 0x%08x SRR0 0x%08x SRR1 0x%08x\n", |
|
772 |
_load_xer(), env->spr[SRR0], env->spr[SRR1]); |
|
719 |
if (loglevel > 0) |
|
720 |
cpu_ppc_dump_state(env, logfile, 0); |
|
773 | 721 |
} |
774 | 722 |
#endif |
775 | 723 |
/* Generate informations in save/restore registers */ |
... | ... | |
812 | 760 |
/* data location address has been stored |
813 | 761 |
* when the fault has been detected |
814 | 762 |
*/ |
815 |
goto store_current; |
|
763 |
msr &= ~0xFFFF0000; |
|
764 |
env->spr[DSISR] = 0; |
|
765 |
if (env->error_code & EXCP_DSI_TRANSLATE) |
|
766 |
env->spr[DSISR] |= 0x40000000; |
|
767 |
else if (env->error_code & EXCP_DSI_PROT) |
|
768 |
env->spr[DSISR] |= 0x08000000; |
|
769 |
else if (env->error_code & EXCP_DSI_NOTSUP) { |
|
770 |
env->spr[DSISR] |= 0x80000000; |
|
771 |
if (env->error_code & EXCP_DSI_DIRECT) |
|
772 |
env->spr[DSISR] |= 0x04000000; |
|
773 |
} |
|
774 |
if (env->error_code & EXCP_DSI_STORE) |
|
775 |
env->spr[DSISR] |= 0x02000000; |
|
776 |
if ((env->error_code & 0xF) == EXCP_DSI_DABR) |
|
777 |
env->spr[DSISR] |= 0x00400000; |
|
778 |
if (env->error_code & EXCP_DSI_ECXW) |
|
779 |
env->spr[DSISR] |= 0x00100000; |
|
780 |
#if defined (DEBUG_EXCEPTIONS) |
|
781 |
if (loglevel) { |
|
782 |
fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n", |
|
783 |
env->spr[DSISR], env->spr[DAR]); |
|
784 |
} else { |
|
785 |
printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n", |
|
786 |
env->spr[DSISR], env->spr[DAR], env->nip); |
|
787 |
} |
|
788 |
#endif |
|
789 |
goto store_next; |
|
816 | 790 |
case EXCP_ISI: |
817 | 791 |
/* Store exception cause */ |
792 |
msr &= ~0xFFFF0000; |
|
818 | 793 |
if (env->error_code == EXCP_ISI_TRANSLATE) |
819 | 794 |
msr |= 0x40000000; |
820 | 795 |
else if (env->error_code == EXCP_ISI_NOEXEC || |
821 |
env->error_code == EXCP_ISI_GUARD) |
|
796 |
env->error_code == EXCP_ISI_GUARD || |
|
797 |
env->error_code == EXCP_ISI_DIRECT) |
|
822 | 798 |
msr |= 0x10000000; |
823 | 799 |
else |
824 | 800 |
msr |= 0x08000000; |
801 |
#if defined (DEBUG_EXCEPTIONS) |
|
802 |
if (loglevel) { |
|
803 |
fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n", |
|
804 |
msr, env->nip); |
|
805 |
} else { |
|
806 |
printf("ISI exception: msr=0x%08x, nip=0x%08x tbl:0x%08x\n", |
|
807 |
msr, env->nip, env->spr[V_TBL]); |
|
808 |
} |
|
809 |
#endif |
|
825 | 810 |
goto store_next; |
826 | 811 |
case EXCP_EXTERNAL: |
827 | 812 |
if (msr_ee == 0) { |
828 | 813 |
#if defined (DEBUG_EXCEPTIONS) |
829 | 814 |
if (loglevel > 0) { |
830 | 815 |
fprintf(logfile, "Skipping hardware interrupt\n"); |
831 |
} else { |
|
832 |
printf("Skipping hardware interrupt\n"); |
|
833 | 816 |
} |
834 | 817 |
#endif |
818 |
/* Requeue it */ |
|
819 |
do_queue_exception(EXCP_EXTERNAL); |
|
835 | 820 |
return; |
836 | 821 |
} |
837 | 822 |
goto store_next; |
... | ... | |
863 | 848 |
env->fpscr[7] |= 0x4; |
864 | 849 |
break; |
865 | 850 |
case EXCP_INVAL: |
851 |
printf("Invalid instruction at 0x%08x\n", env->nip); |
|
866 | 852 |
msr |= 0x00080000; |
867 | 853 |
break; |
868 | 854 |
case EXCP_PRIV: |
... | ... | |
888 | 874 |
goto store_next; |
889 | 875 |
case EXCP_SYSCALL: |
890 | 876 |
#if defined (DEBUG_EXCEPTIONS) |
891 |
printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", |
|
892 |
env->gpr[0], env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); |
|
877 |
if (msr_pr) { |
|
878 |
if (loglevel) { |
|
879 |
fprintf(logfile, "syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", |
|
880 |
env->gpr[0], env->gpr[3], env->gpr[4], |
|
881 |
env->gpr[5], env->gpr[6]); |
|
882 |
} else { |
|
883 |
printf("syscall %d from 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", |
|
884 |
env->gpr[0], env->nip, env->gpr[3], env->gpr[4], |
|
885 |
env->gpr[5], env->gpr[6]); |
|
886 |
} |
|
887 |
} |
|
893 | 888 |
#endif |
894 | 889 |
goto store_next; |
895 | 890 |
case EXCP_TRACE: |
... | ... | |
898 | 893 |
goto store_next; |
899 | 894 |
case EXCP_MTMSR: |
900 | 895 |
/* Nothing to do */ |
901 |
#if defined (DEBUG_EXCEPTIONS) |
|
902 |
printf("%s: escape EXCP_MTMSR\n", __func__); |
|
903 |
#endif |
|
904 | 896 |
return; |
905 | 897 |
case EXCP_BRANCH: |
906 | 898 |
/* Nothing to do */ |
907 |
#if defined (DEBUG_EXCEPTIONS) |
|
908 |
printf("%s: escape EXCP_BRANCH\n", __func__); |
|
909 |
#endif |
|
910 | 899 |
return; |
911 | 900 |
case EXCP_RFI: |
912 | 901 |
/* Restore user-mode state */ |
902 |
tb_flush(env); |
|
913 | 903 |
#if defined (DEBUG_EXCEPTIONS) |
914 |
printf("%s: escape EXCP_RFI\n", __func__); |
|
904 |
if (msr_pr == 1) |
|
905 |
printf("Return from exception => 0x%08x\n", (uint32_t)env->nip); |
|
915 | 906 |
#endif |
916 | 907 |
return; |
917 | 908 |
store_current: |
Also available in: Unified diff