Commit cf7055bdfbd3e1b5f33e11b2f9aede0046a18578

Authored by aurel32
1 parent 4e7ed2d1

target-sh4: fix TLB/MMU emulation

Based on a patch from Vladimir Prus and comments from Shin-ichiro KAWASAKI.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5770 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 29 additions and 36 deletions
target-sh4/helper.c
@@ -43,13 +43,14 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, @@ -43,13 +43,14 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
43 env->exception_index = 0; 43 env->exception_index = 0;
44 switch (rw) { 44 switch (rw) {
45 case 0: 45 case 0:
46 - env->tea = address;  
47 env->exception_index = 0x0a0; 46 env->exception_index = 0x0a0;
48 break; 47 break;
49 case 1: 48 case 1:
50 - env->tea = address;  
51 env->exception_index = 0x0c0; 49 env->exception_index = 0x0c0;
52 break; 50 break;
  51 + case 2:
  52 + env->exception_index = 0x0a0;
  53 + break;
53 } 54 }
54 return 1; 55 return 1;
55 } 56 }
@@ -72,6 +73,9 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) @@ -72,6 +73,9 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
72 #define MMU_DTLB_VIOLATION_WRITE (-8) 73 #define MMU_DTLB_VIOLATION_WRITE (-8)
73 #define MMU_DTLB_MULTIPLE (-9) 74 #define MMU_DTLB_MULTIPLE (-9)
74 #define MMU_DTLB_MISS (-10) 75 #define MMU_DTLB_MISS (-10)
  76 +#define MMU_IADDR_ERROR (-11)
  77 +#define MMU_DADDR_ERROR_READ (-12)
  78 +#define MMU_DADDR_ERROR_WRITE (-13)
75 79
76 void do_interrupt(CPUState * env) 80 void do_interrupt(CPUState * env)
77 { 81 {
@@ -353,20 +357,19 @@ int find_utlb_entry(CPUState * env, target_ulong address, int use_asid) @@ -353,20 +357,19 @@ int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
353 Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE, 357 Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
354 MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ, 358 MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
355 MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS, 359 MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
356 - MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION 360 + MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
  361 + MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
357 */ 362 */
358 static int get_mmu_address(CPUState * env, target_ulong * physical, 363 static int get_mmu_address(CPUState * env, target_ulong * physical,
359 int *prot, target_ulong address, 364 int *prot, target_ulong address,
360 int rw, int access_type) 365 int rw, int access_type)
361 { 366 {
362 - int use_asid, is_code, n; 367 + int use_asid, n;
363 tlb_t *matching = NULL; 368 tlb_t *matching = NULL;
364 369
365 use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0; 370 use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
366 - is_code = env->pc == address; /* Hack */  
367 371
368 - /* Use a hack to find if this is an instruction or data access */  
369 - if (env->pc == address && !(rw & PAGE_WRITE)) { 372 + if (rw == 2) {
370 n = find_itlb_entry(env, address, use_asid, 1); 373 n = find_itlb_entry(env, address, use_asid, 1);
371 if (n >= 0) { 374 if (n >= 0) {
372 matching = &env->itlb[n]; 375 matching = &env->itlb[n];
@@ -382,13 +385,13 @@ static int get_mmu_address(CPUState * env, target_ulong * physical, @@ -382,13 +385,13 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
382 switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) { 385 switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) {
383 case 0: /* 000 */ 386 case 0: /* 000 */
384 case 2: /* 010 */ 387 case 2: /* 010 */
385 - n = (rw & PAGE_WRITE) ? MMU_DTLB_VIOLATION_WRITE : 388 + n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE :
386 MMU_DTLB_VIOLATION_READ; 389 MMU_DTLB_VIOLATION_READ;
387 break; 390 break;
388 case 1: /* 001 */ 391 case 1: /* 001 */
389 case 4: /* 100 */ 392 case 4: /* 100 */
390 case 5: /* 101 */ 393 case 5: /* 101 */
391 - if (rw & PAGE_WRITE) 394 + if (rw == 1)
392 n = MMU_DTLB_VIOLATION_WRITE; 395 n = MMU_DTLB_VIOLATION_WRITE;
393 else 396 else
394 *prot = PAGE_READ; 397 *prot = PAGE_READ;
@@ -396,18 +399,18 @@ static int get_mmu_address(CPUState * env, target_ulong * physical, @@ -396,18 +399,18 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
396 case 3: /* 011 */ 399 case 3: /* 011 */
397 case 6: /* 110 */ 400 case 6: /* 110 */
398 case 7: /* 111 */ 401 case 7: /* 111 */
399 - *prot = rw & (PAGE_READ | PAGE_WRITE); 402 + *prot = (rw == 1)? PAGE_WRITE : PAGE_READ;
400 break; 403 break;
401 } 404 }
402 } else if (n == MMU_DTLB_MISS) { 405 } else if (n == MMU_DTLB_MISS) {
403 - n = (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : 406 + n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
404 MMU_DTLB_MISS_READ; 407 MMU_DTLB_MISS_READ;
405 } 408 }
406 } 409 }
407 if (n >= 0) { 410 if (n >= 0) {
408 *physical = ((matching->ppn << 10) & ~(matching->size - 1)) | 411 *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
409 (address & (matching->size - 1)); 412 (address & (matching->size - 1));
410 - if ((rw & PAGE_WRITE) & !matching->d) 413 + if ((rw == 1) & !matching->d)
411 n = MMU_DTLB_INITIAL_WRITE; 414 n = MMU_DTLB_INITIAL_WRITE;
412 else 415 else
413 n = MMU_OK; 416 n = MMU_OK;
@@ -426,8 +429,12 @@ int get_physical_address(CPUState * env, target_ulong * physical, @@ -426,8 +429,12 @@ int get_physical_address(CPUState * env, target_ulong * physical,
426 && (address < 0xe0000000 || address > 0xe4000000)) { 429 && (address < 0xe0000000 || address > 0xe4000000)) {
427 /* Unauthorized access in user mode (only store queues are available) */ 430 /* Unauthorized access in user mode (only store queues are available) */
428 fprintf(stderr, "Unauthorized access\n"); 431 fprintf(stderr, "Unauthorized access\n");
429 - return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :  
430 - MMU_DTLB_MISS_READ; 432 + if (rw == 0)
  433 + return MMU_DADDR_ERROR_READ;
  434 + else if (rw == 1)
  435 + return MMU_DADDR_ERROR_WRITE;
  436 + else
  437 + return MMU_IADDR_ERROR;
431 } 438 }
432 if (address >= 0x80000000 && address < 0xc0000000) { 439 if (address >= 0x80000000 && address < 0xc0000000) {
433 /* Mask upper 3 bits for P1 and P2 areas */ 440 /* Mask upper 3 bits for P1 and P2 areas */
@@ -465,27 +472,6 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, @@ -465,27 +472,6 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
465 target_ulong physical, page_offset, page_size; 472 target_ulong physical, page_offset, page_size;
466 int prot, ret, access_type; 473 int prot, ret, access_type;
467 474
468 - switch (rw) {  
469 - case 0:  
470 - rw = PAGE_READ;  
471 - break;  
472 - case 1:  
473 - rw = PAGE_WRITE;  
474 - break;  
475 - case 2: /* READ_ACCESS_TYPE == 2 defined in softmmu_template.h */  
476 - rw = PAGE_READ;  
477 - break;  
478 - default:  
479 - /* fatal error */  
480 - assert(0);  
481 - }  
482 -  
483 - /* XXXXX */  
484 -#if 0  
485 - fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n",  
486 - __func__, env->pc, address, rw, mmu_idx, is_softmmu);  
487 -#endif  
488 -  
489 access_type = ACCESS_INT; 475 access_type = ACCESS_INT;
490 ret = 476 ret =
491 get_physical_address(env, &physical, &prot, address, rw, 477 get_physical_address(env, &physical, &prot, address, rw,
@@ -517,6 +503,13 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, @@ -517,6 +503,13 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
517 case MMU_DTLB_VIOLATION_WRITE: 503 case MMU_DTLB_VIOLATION_WRITE:
518 env->exception_index = 0x0c0; 504 env->exception_index = 0x0c0;
519 break; 505 break;
  506 + case MMU_IADDR_ERROR:
  507 + case MMU_DADDR_ERROR_READ:
  508 + env->exception_index = 0x0c0;
  509 + break;
  510 + case MMU_DADDR_ERROR_WRITE:
  511 + env->exception_index = 0x100;
  512 + break;
520 default: 513 default:
521 assert(0); 514 assert(0);
522 } 515 }
@@ -537,7 +530,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) @@ -537,7 +530,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
537 target_ulong physical; 530 target_ulong physical;
538 int prot; 531 int prot;
539 532
540 - get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0); 533 + get_physical_address(env, &physical, &prot, addr, 0, 0);
541 return physical; 534 return physical;
542 } 535 }
543 536