--- trunk/src/cpus/memory_arm.c 2007/10/08 16:18:51 14 +++ trunk/src/cpus/memory_arm.c 2007/10/08 16:19:11 18 @@ -25,24 +25,12 @@ * SUCH DAMAGE. * * - * $Id: memory_arm.c,v 1.23 2005/10/07 15:19:48 debug Exp $ + * $Id: memory_arm.c,v 1.27 2005/10/23 14:24:13 debug Exp $ * * - * TODO/NOTE: There are probably two solutions to the subpage access - * permission problem: - * - * a) the obvious (almost trivial) solution is to decrease the native page - * size from 4 KB to 1 KB. That would ruin the rest of the translation - * system though. (It would be infeasible to hold the entire address - * space in 1-level tables.) - * - * b) to return something else than just 0, 1, or 2 from arm_memory_rw(). - * Perhaps |4, which would indicate that the vaddr => paddr conversion - * was done, but that it should not be entered into the cache. This could - * also be used in combination with the B and C bits (which are currently - * ignored). - * - * b would probably be the best solution. + * TODO/NOTE: The B and/or C bits could also cause the return value to + * be MEMORY_NOT_FULL_PAGE, to make sure it doesn't get entered into the + * translation arrays. TODO: Find out if this is a good thing to do. */ #include @@ -59,6 +47,19 @@ /* + * arm_translate_address(): + * + * Address translation with the MMU disabled. + */ +int arm_translate_address(struct cpu *cpu, uint64_t vaddr64, + uint64_t *return_addr, int flags) +{ + *return_addr = vaddr64 & 0xffffffff; + return 2; +} + + +/* * arm_check_access(): * * Helper function. Returns 0 for no access, 1 for read-only, and 2 for @@ -99,7 +100,7 @@ /* - * arm_translate_address(): + * arm_translate_address_mmu(): * * Don't call this function is userland_emul is non-NULL, or cpu is NULL. * @@ -107,13 +108,15 @@ * 0 Failure * 1 Success, the page is readable only * 2 Success, the page is read/write + * + * If this is a 1KB page access, then the return value is ORed with + * MEMORY_NOT_FULL_PAGE. */ -int arm_translate_address(struct cpu *cpu, uint64_t vaddr64, +int arm_translate_address_mmu(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_addr, int flags) { - unsigned char descr[4]; - uint32_t addr, d, d2 = (uint32_t)(int32_t)-1, ptba, vaddr = vaddr64; - int d2_in_use = 0, d_in_use = 1; + unsigned char *q; + uint32_t addr, d=0, d2 = (uint32_t)(int32_t)-1, ptba, vaddr = vaddr64; int instr = flags & FLAG_INSTR; int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0; int useraccess = flags & MEMORY_USER_ACCESS; @@ -121,30 +124,35 @@ int user = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32; int domain, dav, ap0,ap1,ap2,ap3, ap = 0, access = 0; int fs = 2; /* fault status (2 = terminal exception) */ - - if (!(cpu->cd.arm.control & ARM_CONTROL_MMU)) { - *return_addr = vaddr; - return 2; - } + int subpage = 0; if (useraccess) user = 1; - addr = cpu->cd.arm.ttb + ((vaddr & 0xfff00000ULL) >> 18); - if (!cpu->memory_rw(cpu, cpu->mem, addr, &descr[0], - sizeof(descr), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { - fatal("arm_translate_address(): huh?\n"); - exit(1); + addr = ((vaddr & 0xfff00000ULL) >> 18); + + if (cpu->cd.arm.translation_table == NULL || + cpu->cd.arm.ttb != cpu->cd.arm.last_ttb) { + uint32_t ofs; + cpu->cd.arm.translation_table = memory_paddr_to_hostaddr( + cpu->mem, cpu->cd.arm.ttb & 0x0fffffff, 0); + if (cpu->cd.arm.translation_table != NULL) { + ofs = cpu->cd.arm.ttb & ((1 << BITS_PER_MEMBLOCK) - 1); + cpu->cd.arm.translation_table += ofs; + } + cpu->cd.arm.last_ttb = cpu->cd.arm.ttb; } - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) - d = descr[0] + (descr[1] << 8) + (descr[2] << 16) - + (descr[3] << 24); - else - d = descr[3] + (descr[2] << 8) + (descr[1] << 16) - + (descr[0] << 24); - /* fatal("vaddr=0x%08x ttb=0x%08x addr=0x%08x d=0x%08x\n", - vaddr, cpu->cd.arm.ttb, addr, d); */ + if (cpu->cd.arm.translation_table != NULL) { + d = *(uint32_t *)(cpu->cd.arm.translation_table + addr); +#ifdef HOST_LITTLE_ENDIAN + if (cpu->byte_order == EMUL_BIG_ENDIAN) +#else + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) +#endif + d = ((d & 0xff) << 24) | ((d & 0xff00) << 8) | + ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24); + } /* Get the domain from the descriptor, and the Domain Access Value: */ domain = (d >> 5) & 15; @@ -152,26 +160,31 @@ switch (d & 3) { - case 0: d_in_use = 0; - domain = 0; + case 0: domain = 0; fs = FAULT_TRANS_S; goto exception_return; case 1: /* Course Pagetable: */ + if (dav == 0) { + fs = FAULT_DOMAIN_P; + goto exception_return; + } ptba = d & 0xfffffc00; addr = ptba + ((vaddr & 0x000ff000) >> 10); - if (!cpu->memory_rw(cpu, cpu->mem, addr, &descr[0], - sizeof(descr), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { - fatal("arm_translate_address(): huh 2?\n"); + + q = memory_paddr_to_hostaddr(cpu->mem, addr & 0x0fffffff, 0); + if (q == NULL) { + printf("arm memory blah blah adfh asfg asdgasdg\n"); exit(1); } + d2 = *(uint32_t *)(q + (addr & ((1 << BITS_PER_MEMBLOCK) - 1))); +#ifdef HOST_LITTLE_ENDIAN + if (cpu->byte_order == EMUL_BIG_ENDIAN) +#else if (cpu->byte_order == EMUL_LITTLE_ENDIAN) - d2 = descr[0] + (descr[1] << 8) + (descr[2] << 16) - + (descr[3] << 24); - else - d2 = descr[3] + (descr[2] << 8) + (descr[1] << 16) - + (descr[0] << 24); - d2_in_use = 1; +#endif + d2 = ((d2 & 0xff) << 24) | ((d2 & 0xff00) << 8) | + ((d2 & 0xff0000) >> 8) | ((d2 & 0xff000000) >> 24); switch (d2 & 3) { case 0: fs = FAULT_TRANS_P; @@ -197,38 +210,28 @@ case 0x800: ap = ap2; break; default: ap = ap3; } -#if 0 - if ((ap0 != ap1 || ap0 != ap2 || ap0 != ap3) && - !no_exceptions) - fatal("WARNING: vaddr = 0x%08x, small page, but" - " different access permissions for the sub" - "pages! This is not really implemented " - "yet.\n", (int)vaddr); -#endif + if (ap0 != ap1 || ap0 != ap2 || ap0 != ap3) + subpage = 1; *return_addr = (d2 & 0xfffff000) | (vaddr & 0x00000fff); break; case 3: /* 1KB page: */ - fatal("WARNING: 1 KB page! Not implemented yet.\n"); + subpage = 1; ap = (d2 >> 4) & 3; *return_addr = (d2 & 0xfffffc00) | (vaddr & 0x000003ff); break; } - if (dav == 0) { - fs = FAULT_DOMAIN_P; - goto exception_return; - } access = arm_check_access(cpu, ap, dav, user); if (access > writeflag) - return access; + return access | (subpage? MEMORY_NOT_FULL_PAGE : 0); fs = FAULT_PERM_P; goto exception_return; case 2: /* Section descriptor: */ - *return_addr = (d & 0xfff00000) | (vaddr & 0x000fffff); if (dav == 0) { fs = FAULT_DOMAIN_S; goto exception_return; } + *return_addr = (d & 0xfff00000) | (vaddr & 0x000fffff); ap = (d >> 10) & 3; access = arm_check_access(cpu, ap, dav, user); if (access > writeflag) @@ -249,11 +252,7 @@ fatal("{ arm memory fault: vaddr=0x%08x domain=%i dav=%i ap=%i " "access=%i user=%i", (int)vaddr, domain, dav, ap, access, user); - if (d_in_use) - fatal(" d=0x%08x", d); - if (d2_in_use) - fatal(" d2=0x%08x", d2); - fatal(" }\n"); + fatal(" d=0x%08x d2=0x%08x }\n", d, d2); } if (instr)