diff -ur qemu-0.9.0/target-arm/helper.c qemu/target-arm/helper.c --- qemu-0.9.0/target-arm/helper.c 2007-07-30 16:48:18.000000000 +0200 +++ qemu/target-arm/helper.c 2007-07-30 16:46:50.000000000 +0200 @@ -278,87 +280,101 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type, int is_user, uint32_t *phys_ptr, int *prot) { - int code; - uint32_t table; - uint32_t desc; - int type; - int ap; - int domain; - uint32_t phys_addr; + int code; + uint32_t pgdp, ptep; + uint32_t pgd, pte = 0; + uint32_t index; + int ap = 0; + int domain = 0; + uint32_t phys_addr = 0; + + /* Fast Context Switch Extension. */ + if (address < 0x02000000) + address += env->cp15.c13_fcse; + + if ((env->cp15.c1_sys & 1) == 0) { + /* MMU disabled. */ + *phys_ptr = address; + *prot = PAGE_READ | PAGE_WRITE; + return 0; + } + + /* Pagetable walk. */ + + /* Lookup l1 descriptor. */ + pgdp = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); + + pgd = ldl_phys(pgdp); + + switch (pgd & 3) { + case 0: /* Section translation fault. */ + code = 5; + goto do_fault; + + case 1: /* Coarse page table. */ + index = (address >> 10) & 0x3fc; + ptep = (pgd & 0xfffffc00) | index; + + pte = ldl_phys(ptep); + break; + + case 2: /* Section. */ + phys_addr = (pgd & 0xfff00000) | (address & 0x000fffff); + + domain = (pgd >> 5) & 0x0f; + ap = (pgd >> 10) & 0x03; + code = 13; + + goto do_check; + + case 3: /* Fine page table. */ + index = (address >> 8) & 0xffc; + ptep = (pgd & 0xfffff000) | index; + + pte = ldl_phys(ptep); + break; + } + + code = 15; + switch (pte & 3) { + case 0: /* Page translation fault. */ + code = 7; + goto do_fault; + + case 1: /* Large page. */ + phys_addr = (pte & 0xffff0000) | (address & 0x0000ffff); + + domain = (pgd >> 5) & 0x0f; + ap = (pte >> (4 + ((address >> 13) & 6))) & 3; + break; + + case 2: /* Small page. */ + phys_addr = (pte & 0xfffff000) | (address & 0x00000fff); + + domain = (pgd >> 5) & 0x0f; + ap = (pte >> (4 + ((address >> 13) & 6))) & 3; + break; + + case 3: /* Tiny page. */ + phys_addr = (pte & 0xfffffc00) | (address & 0x000003ff); + + domain = (pgd >> 5) & 0x0f; + ap = (pte >> 4) & 3; + break; + } + +do_check: + *prot = check_ap(env, ap, domain, access_type, is_user); + if (!*prot) { + /* Access permission fault. */ + goto do_fault; + } - /* Fast Context Switch Extension. */ - if (address < 0x02000000) - address += env->cp15.c13_fcse; - - if ((env->cp15.c1_sys & 1) == 0) { - /* MMU diusabled. */ - *phys_ptr = address; - *prot = PAGE_READ | PAGE_WRITE; - } else { - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc); - desc = ldl_phys(table); - type = (desc & 3); - domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3; - if (type == 0) { - /* Secton translation fault. */ - code = 5; - goto do_fault; - } - if (domain == 0 || domain == 2) { - if (type == 2) - code = 9; /* Section domain fault. */ - else - code = 11; /* Page domain fault. */ - goto do_fault; - } - if (type == 2) { - /* 1Mb section. */ - phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); - ap = (desc >> 10) & 3; - code = 13; - } else { - /* Lookup l2 entry. */ - table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = ldl_phys(table); - switch (desc & 3) { - case 0: /* Page translation fault. */ - code = 7; - goto do_fault; - case 1: /* 64k page. */ - phys_addr = (desc & 0xffff0000) | (address & 0xffff); - ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - break; - case 2: /* 4k page. */ - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - ap = (desc >> (4 + ((address >> 13) & 6))) & 3; - break; - case 3: /* 1k page. */ - if (type == 1) { - /* Page translation fault. */ - code = 7; - goto do_fault; - } - phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); - ap = (desc >> 4) & 3; - break; - default: - /* Never happens, but compiler isn't smart enough to tell. */ - abort(); - } - code = 15; - } - *prot = check_ap(env, ap, domain, access_type, is_user); - if (!*prot) { - /* Access permission fault. */ - goto do_fault; - } *phys_ptr = phys_addr; - } - return 0; + return 0; + do_fault: - return code | (domain << 4); + return code | (domain << 4); } int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, @@ -532,7 +548,7 @@ return; bad_reg: /* ??? For debugging only. Should raise illegal instruction exception. */ - cpu_abort(env, "Unimplemented cp15 register read\n"); + cpu_abort(env, "Unimplemented cp15 register write\n"); } uint32_t helper_get_cp15(CPUState *env, uint32_t insn)