mirror of https://github.com/xqemu/xqemu.git
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
This commit is contained in:
parent
4e7ed2d1d3
commit
cf7055bdfb
|
@ -43,13 +43,14 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
|
||||||
env->exception_index = 0;
|
env->exception_index = 0;
|
||||||
switch (rw) {
|
switch (rw) {
|
||||||
case 0:
|
case 0:
|
||||||
env->tea = address;
|
|
||||||
env->exception_index = 0x0a0;
|
env->exception_index = 0x0a0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
env->tea = address;
|
|
||||||
env->exception_index = 0x0c0;
|
env->exception_index = 0x0c0;
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
env->exception_index = 0x0a0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -72,6 +73,9 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
|
||||||
#define MMU_DTLB_VIOLATION_WRITE (-8)
|
#define MMU_DTLB_VIOLATION_WRITE (-8)
|
||||||
#define MMU_DTLB_MULTIPLE (-9)
|
#define MMU_DTLB_MULTIPLE (-9)
|
||||||
#define MMU_DTLB_MISS (-10)
|
#define MMU_DTLB_MISS (-10)
|
||||||
|
#define MMU_IADDR_ERROR (-11)
|
||||||
|
#define MMU_DADDR_ERROR_READ (-12)
|
||||||
|
#define MMU_DADDR_ERROR_WRITE (-13)
|
||||||
|
|
||||||
void do_interrupt(CPUState * env)
|
void do_interrupt(CPUState * env)
|
||||||
{
|
{
|
||||||
|
@ -353,20 +357,19 @@ int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
|
||||||
Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
|
Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
|
||||||
MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
|
MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
|
||||||
MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
|
MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
|
||||||
MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION
|
MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION,
|
||||||
|
MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
|
||||||
*/
|
*/
|
||||||
static int get_mmu_address(CPUState * env, target_ulong * physical,
|
static int get_mmu_address(CPUState * env, target_ulong * physical,
|
||||||
int *prot, target_ulong address,
|
int *prot, target_ulong address,
|
||||||
int rw, int access_type)
|
int rw, int access_type)
|
||||||
{
|
{
|
||||||
int use_asid, is_code, n;
|
int use_asid, n;
|
||||||
tlb_t *matching = NULL;
|
tlb_t *matching = NULL;
|
||||||
|
|
||||||
use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
|
use_asid = (env->mmucr & MMUCR_SV) == 0 || (env->sr & SR_MD) == 0;
|
||||||
is_code = env->pc == address; /* Hack */
|
|
||||||
|
|
||||||
/* Use a hack to find if this is an instruction or data access */
|
if (rw == 2) {
|
||||||
if (env->pc == address && !(rw & PAGE_WRITE)) {
|
|
||||||
n = find_itlb_entry(env, address, use_asid, 1);
|
n = find_itlb_entry(env, address, use_asid, 1);
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
matching = &env->itlb[n];
|
matching = &env->itlb[n];
|
||||||
|
@ -382,13 +385,13 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
|
||||||
switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) {
|
switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) {
|
||||||
case 0: /* 000 */
|
case 0: /* 000 */
|
||||||
case 2: /* 010 */
|
case 2: /* 010 */
|
||||||
n = (rw & PAGE_WRITE) ? MMU_DTLB_VIOLATION_WRITE :
|
n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE :
|
||||||
MMU_DTLB_VIOLATION_READ;
|
MMU_DTLB_VIOLATION_READ;
|
||||||
break;
|
break;
|
||||||
case 1: /* 001 */
|
case 1: /* 001 */
|
||||||
case 4: /* 100 */
|
case 4: /* 100 */
|
||||||
case 5: /* 101 */
|
case 5: /* 101 */
|
||||||
if (rw & PAGE_WRITE)
|
if (rw == 1)
|
||||||
n = MMU_DTLB_VIOLATION_WRITE;
|
n = MMU_DTLB_VIOLATION_WRITE;
|
||||||
else
|
else
|
||||||
*prot = PAGE_READ;
|
*prot = PAGE_READ;
|
||||||
|
@ -396,18 +399,18 @@ static int get_mmu_address(CPUState * env, target_ulong * physical,
|
||||||
case 3: /* 011 */
|
case 3: /* 011 */
|
||||||
case 6: /* 110 */
|
case 6: /* 110 */
|
||||||
case 7: /* 111 */
|
case 7: /* 111 */
|
||||||
*prot = rw & (PAGE_READ | PAGE_WRITE);
|
*prot = (rw == 1)? PAGE_WRITE : PAGE_READ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (n == MMU_DTLB_MISS) {
|
} else if (n == MMU_DTLB_MISS) {
|
||||||
n = (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
|
n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
|
||||||
MMU_DTLB_MISS_READ;
|
MMU_DTLB_MISS_READ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
*physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
|
*physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
|
||||||
(address & (matching->size - 1));
|
(address & (matching->size - 1));
|
||||||
if ((rw & PAGE_WRITE) & !matching->d)
|
if ((rw == 1) & !matching->d)
|
||||||
n = MMU_DTLB_INITIAL_WRITE;
|
n = MMU_DTLB_INITIAL_WRITE;
|
||||||
else
|
else
|
||||||
n = MMU_OK;
|
n = MMU_OK;
|
||||||
|
@ -426,8 +429,12 @@ int get_physical_address(CPUState * env, target_ulong * physical,
|
||||||
&& (address < 0xe0000000 || address > 0xe4000000)) {
|
&& (address < 0xe0000000 || address > 0xe4000000)) {
|
||||||
/* Unauthorized access in user mode (only store queues are available) */
|
/* Unauthorized access in user mode (only store queues are available) */
|
||||||
fprintf(stderr, "Unauthorized access\n");
|
fprintf(stderr, "Unauthorized access\n");
|
||||||
return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
|
if (rw == 0)
|
||||||
MMU_DTLB_MISS_READ;
|
return MMU_DADDR_ERROR_READ;
|
||||||
|
else if (rw == 1)
|
||||||
|
return MMU_DADDR_ERROR_WRITE;
|
||||||
|
else
|
||||||
|
return MMU_IADDR_ERROR;
|
||||||
}
|
}
|
||||||
if (address >= 0x80000000 && address < 0xc0000000) {
|
if (address >= 0x80000000 && address < 0xc0000000) {
|
||||||
/* Mask upper 3 bits for P1 and P2 areas */
|
/* 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,
|
||||||
target_ulong physical, page_offset, page_size;
|
target_ulong physical, page_offset, page_size;
|
||||||
int prot, ret, access_type;
|
int prot, ret, access_type;
|
||||||
|
|
||||||
switch (rw) {
|
|
||||||
case 0:
|
|
||||||
rw = PAGE_READ;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rw = PAGE_WRITE;
|
|
||||||
break;
|
|
||||||
case 2: /* READ_ACCESS_TYPE == 2 defined in softmmu_template.h */
|
|
||||||
rw = PAGE_READ;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* fatal error */
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXXXX */
|
|
||||||
#if 0
|
|
||||||
fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n",
|
|
||||||
__func__, env->pc, address, rw, mmu_idx, is_softmmu);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
access_type = ACCESS_INT;
|
access_type = ACCESS_INT;
|
||||||
ret =
|
ret =
|
||||||
get_physical_address(env, &physical, &prot, address, rw,
|
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,
|
||||||
case MMU_DTLB_VIOLATION_WRITE:
|
case MMU_DTLB_VIOLATION_WRITE:
|
||||||
env->exception_index = 0x0c0;
|
env->exception_index = 0x0c0;
|
||||||
break;
|
break;
|
||||||
|
case MMU_IADDR_ERROR:
|
||||||
|
case MMU_DADDR_ERROR_READ:
|
||||||
|
env->exception_index = 0x0c0;
|
||||||
|
break;
|
||||||
|
case MMU_DADDR_ERROR_WRITE:
|
||||||
|
env->exception_index = 0x100;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
@ -537,7 +530,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
|
||||||
target_ulong physical;
|
target_ulong physical;
|
||||||
int prot;
|
int prot;
|
||||||
|
|
||||||
get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0);
|
get_physical_address(env, &physical, &prot, addr, 0, 0);
|
||||||
return physical;
|
return physical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue