mirror of
https://git.proxmox.com/git/qemu
synced 2025-07-03 21:59:37 +00:00
use constants for TLB handling (Thiemo Seufer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1978 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
c5d6edc3fc
commit
43057ab127
@ -87,7 +87,7 @@ struct CPUMIPSState {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(MIPS_USES_R4K_TLB)
|
#if defined(MIPS_USES_R4K_TLB)
|
||||||
tlb_t tlb[16];
|
tlb_t tlb[MIPS_TLB_NB];
|
||||||
#endif
|
#endif
|
||||||
uint32_t CP0_index;
|
uint32_t CP0_index;
|
||||||
uint32_t CP0_random;
|
uint32_t CP0_random;
|
||||||
|
@ -28,53 +28,56 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec-all.h"
|
#include "exec-all.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TLBRET_DIRTY = -4,
|
||||||
|
TLBRET_INVALID = -3,
|
||||||
|
TLBRET_NOMATCH = -2,
|
||||||
|
TLBRET_BADADDR = -1,
|
||||||
|
TLBRET_MATCH = 0
|
||||||
|
};
|
||||||
|
|
||||||
/* MIPS32 4K MMU emulation */
|
/* MIPS32 4K MMU emulation */
|
||||||
#ifdef MIPS_USES_R4K_TLB
|
#ifdef MIPS_USES_R4K_TLB
|
||||||
static int map_address (CPUState *env, target_ulong *physical, int *prot,
|
static int map_address (CPUState *env, target_ulong *physical, int *prot,
|
||||||
target_ulong address, int rw, int access_type)
|
target_ulong address, int rw, int access_type)
|
||||||
{
|
{
|
||||||
|
target_ulong tag = address & (TARGET_PAGE_MASK << 1);
|
||||||
|
uint8_t ASID = env->CP0_EntryHi & 0xFF;
|
||||||
tlb_t *tlb;
|
tlb_t *tlb;
|
||||||
target_ulong tag;
|
|
||||||
uint8_t ASID;
|
|
||||||
int i, n;
|
int i, n;
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = -2;
|
|
||||||
tag = address & 0xFFFFE000;
|
|
||||||
ASID = env->CP0_EntryHi & 0xFF;
|
|
||||||
for (i = 0; i < MIPS_TLB_NB; i++) {
|
for (i = 0; i < MIPS_TLB_NB; i++) {
|
||||||
tlb = &env->tlb[i];
|
tlb = &env->tlb[i];
|
||||||
/* Check ASID, virtual page number & size */
|
/* Check ASID, virtual page number & size */
|
||||||
if ((tlb->G == 1 || tlb->ASID == ASID) &&
|
if ((tlb->G == 1 || tlb->ASID == ASID) &&
|
||||||
tlb->VPN == tag && address < tlb->end2) {
|
tlb->VPN == tag && address < tlb->end2) {
|
||||||
/* TLB match */
|
/* TLB match */
|
||||||
n = (address >> 12) & 1;
|
n = (address >> TARGET_PAGE_BITS) & 1;
|
||||||
/* Check access rights */
|
/* Check access rights */
|
||||||
if (!(n ? tlb->V1 : tlb->V0))
|
if (!(n ? tlb->V1 : tlb->V0))
|
||||||
return -3;
|
return TLBRET_INVALID;
|
||||||
if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
|
if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
|
||||||
*physical = tlb->PFN[n] | (address & 0xFFF);
|
*physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK);
|
||||||
*prot = PAGE_READ;
|
*prot = PAGE_READ;
|
||||||
if (n ? tlb->D1 : tlb->D0)
|
if (n ? tlb->D1 : tlb->D0)
|
||||||
*prot |= PAGE_WRITE;
|
*prot |= PAGE_WRITE;
|
||||||
return 0;
|
return TLBRET_MATCH;
|
||||||
}
|
}
|
||||||
return -4;
|
return TLBRET_DIRTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return TLBRET_NOMATCH;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
|
static int get_physical_address (CPUState *env, target_ulong *physical,
|
||||||
target_ulong address, int rw, int access_type)
|
int *prot, target_ulong address,
|
||||||
|
int rw, int access_type)
|
||||||
{
|
{
|
||||||
int user_mode;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* User mode can only access useg */
|
/* User mode can only access useg */
|
||||||
user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
|
int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
|
||||||
|
int ret = TLBRET_MATCH;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (logfile) {
|
if (logfile) {
|
||||||
fprintf(logfile, "user mode %d h %08x\n",
|
fprintf(logfile, "user mode %d h %08x\n",
|
||||||
@ -82,8 +85,7 @@ int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (user_mode && address > 0x7FFFFFFFUL)
|
if (user_mode && address > 0x7FFFFFFFUL)
|
||||||
return -1;
|
return TLBRET_BADADDR;
|
||||||
ret = 0;
|
|
||||||
if (address < 0x80000000UL) {
|
if (address < 0x80000000UL) {
|
||||||
if (!(env->hflags & MIPS_HFLAG_ERL)) {
|
if (!(env->hflags & MIPS_HFLAG_ERL)) {
|
||||||
#ifdef MIPS_USES_R4K_TLB
|
#ifdef MIPS_USES_R4K_TLB
|
||||||
@ -181,7 +183,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||||||
access_type = ACCESS_INT;
|
access_type = ACCESS_INT;
|
||||||
if (env->user_mode_only) {
|
if (env->user_mode_only) {
|
||||||
/* user mode only emulation */
|
/* user mode only emulation */
|
||||||
ret = -2;
|
ret = TLBRET_NOMATCH;
|
||||||
goto do_fault;
|
goto do_fault;
|
||||||
}
|
}
|
||||||
ret = get_physical_address(env, &physical, &prot,
|
ret = get_physical_address(env, &physical, &prot,
|
||||||
@ -190,14 +192,15 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||||||
fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
|
fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
|
||||||
__func__, address, ret, physical, prot);
|
__func__, address, ret, physical, prot);
|
||||||
}
|
}
|
||||||
if (ret == 0) {
|
if (ret == TLBRET_MATCH) {
|
||||||
ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
|
ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
|
||||||
|
physical & TARGET_PAGE_MASK, prot,
|
||||||
is_user, is_softmmu);
|
is_user, is_softmmu);
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
do_fault:
|
do_fault:
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
default:
|
default:
|
||||||
case -1:
|
case TLBRET_BADADDR:
|
||||||
/* Reference to kernel address from user mode or supervisor mode */
|
/* Reference to kernel address from user mode or supervisor mode */
|
||||||
/* Reference to supervisor address from user mode */
|
/* Reference to supervisor address from user mode */
|
||||||
if (rw)
|
if (rw)
|
||||||
@ -205,7 +208,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||||||
else
|
else
|
||||||
exception = EXCP_AdEL;
|
exception = EXCP_AdEL;
|
||||||
break;
|
break;
|
||||||
case -2:
|
case TLBRET_NOMATCH:
|
||||||
/* No TLB match for a mapped address */
|
/* No TLB match for a mapped address */
|
||||||
if (rw)
|
if (rw)
|
||||||
exception = EXCP_TLBS;
|
exception = EXCP_TLBS;
|
||||||
@ -213,14 +216,14 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||||||
exception = EXCP_TLBL;
|
exception = EXCP_TLBL;
|
||||||
error_code = 1;
|
error_code = 1;
|
||||||
break;
|
break;
|
||||||
case -3:
|
case TLBRET_INVALID:
|
||||||
/* TLB match with no valid bit */
|
/* TLB match with no valid bit */
|
||||||
if (rw)
|
if (rw)
|
||||||
exception = EXCP_TLBS;
|
exception = EXCP_TLBS;
|
||||||
else
|
else
|
||||||
exception = EXCP_TLBL;
|
exception = EXCP_TLBL;
|
||||||
break;
|
break;
|
||||||
case -4:
|
case TLBRET_DIRTY:
|
||||||
/* TLB match but 'D' bit is cleared */
|
/* TLB match but 'D' bit is cleared */
|
||||||
exception = EXCP_LTLBL;
|
exception = EXCP_LTLBL;
|
||||||
break;
|
break;
|
||||||
@ -231,7 +234,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
|||||||
env->CP0_Context = (env->CP0_Context & 0xff800000) |
|
env->CP0_Context = (env->CP0_Context & 0xff800000) |
|
||||||
((address >> 9) & 0x007ffff0);
|
((address >> 9) & 0x007ffff0);
|
||||||
env->CP0_EntryHi =
|
env->CP0_EntryHi =
|
||||||
(env->CP0_EntryHi & 0xFF) | (address & 0xFFFFE000);
|
(env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
|
||||||
env->exception_index = exception;
|
env->exception_index = exception;
|
||||||
env->error_code = error_code;
|
env->error_code = error_code;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user