target-alpha: Implement cpu_alpha_handle_mmu_fault for system mode.

Reads the page table how PALcode would, except that the virtual
page table base register is not used.

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2011-04-18 15:59:21 -07:00 committed by Richard Henderson
parent 2ace7e55a2
commit a3b9af1624
2 changed files with 138 additions and 4 deletions

View File

@ -320,6 +320,19 @@ enum {
#define CPU_INTERRUPT_SMP CPU_INTERRUPT_TGT_EXT_1
#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2
/* OSF/1 Page table bits. */
enum {
PTE_VALID = 0x0001,
PTE_FOR = 0x0002, /* used for page protection (fault on read) */
PTE_FOW = 0x0004, /* used for page protection (fault on write) */
PTE_FOE = 0x0008, /* used for page protection (fault on exec) */
PTE_ASM = 0x0010,
PTE_KRE = 0x0100,
PTE_URE = 0x0200,
PTE_KWE = 0x1000,
PTE_UWE = 0x2000
};
/* Hardware interrupt (entInt) constants. */
enum {
INT_K_IP,

View File

@ -200,14 +200,135 @@ void swap_shadow_regs(CPUState *env)
env->shadow[7] = i7;
}
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
/* Returns the OSF/1 entMM failure indication, or -1 on success. */
static int get_physical_address(CPUState *env, target_ulong addr,
int prot_need, int mmu_idx,
target_ulong *pphys, int *pprot)
{
return -1;
target_long saddr = addr;
target_ulong phys = 0;
target_ulong L1pte, L2pte, L3pte;
target_ulong pt, index;
int prot = 0;
int ret = MM_K_ACV;
/* Ensure that the virtual address is properly sign-extended from
the last implemented virtual address bit. */
if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
goto exit;
}
/* Translate the superpage. */
/* ??? When we do more than emulate Unix PALcode, we'll need to
determine which superpage is actually active. */
if (saddr < 0 && (saddr >> (TARGET_VIRT_ADDR_SPACE_BITS - 2) & 3) == 2) {
/* User-space cannot access kseg addresses. */
if (mmu_idx != MMU_KERNEL_IDX) {
goto exit;
}
phys = saddr & ((1ull << 40) - 1);
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
ret = -1;
goto exit;
}
/* Interpret the page table exactly like PALcode does. */
pt = env->ptbr;
/* L1 page table read. */
index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
L1pte = ldq_phys(pt + index*8);
if (unlikely((L1pte & PTE_VALID) == 0)) {
ret = MM_K_TNV;
goto exit;
}
if (unlikely((L1pte & PTE_KRE) == 0)) {
goto exit;
}
pt = L1pte >> 32 << TARGET_PAGE_BITS;
/* L2 page table read. */
index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
L2pte = ldq_phys(pt + index*8);
if (unlikely((L2pte & PTE_VALID) == 0)) {
ret = MM_K_TNV;
goto exit;
}
if (unlikely((L2pte & PTE_KRE) == 0)) {
goto exit;
}
pt = L2pte >> 32 << TARGET_PAGE_BITS;
/* L3 page table read. */
index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
L3pte = ldq_phys(pt + index*8);
phys = L3pte >> 32 << TARGET_PAGE_BITS;
if (unlikely((L3pte & PTE_VALID) == 0)) {
ret = MM_K_TNV;
goto exit;
}
#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
# error page bits out of date
#endif
/* Check access violations. */
if (L3pte & (PTE_KRE << mmu_idx)) {
prot |= PAGE_READ | PAGE_EXEC;
}
if (L3pte & (PTE_KWE << mmu_idx)) {
prot |= PAGE_WRITE;
}
if (unlikely((prot & prot_need) == 0 && prot_need)) {
goto exit;
}
/* Check fault-on-operation violations. */
prot &= ~(L3pte >> 1);
ret = -1;
if (unlikely((prot & prot_need) == 0)) {
ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
prot_need & PAGE_WRITE ? MM_K_FOW :
prot_need & PAGE_READ ? MM_K_FOR : -1);
}
exit:
*pphys = phys;
*pprot = prot;
return ret;
}
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
target_ulong phys;
int prot, fail;
fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
return (fail >= 0 ? -1 : phys);
}
int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
int mmu_idx, int is_softmmu)
{
target_ulong phys;
int prot, fail;
fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
if (unlikely(fail >= 0)) {
env->exception_index = EXCP_MMFAULT;
env->trap_arg0 = addr;
env->trap_arg1 = fail;
env->trap_arg2 = (rw == 2 ? -1 : rw);
return 1;
}
tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
#endif /* USER_ONLY */