/* arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation. Copyright (C) 2003 Skyeye Develop Group for help please send mail to This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "mem_map.h" #include "arm/interpreter/skyeye_defs.h" #include "arm/interpreter/armdefs.h" //#include "bank_defs.h" #if 0 #define TLB_SIZE 1024 * 1024 #define ASID 255 static uint32_t tlb_entry_array[TLB_SIZE][ASID]; static inline void invalidate_all_tlb(ARMul_State *state){ memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID); } static inline void invalidate_by_mva(ARMul_State *state, ARMword va){ memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t)); return; } static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){ int i; for(i = 0; i < TLB_SIZE; i++) memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t)); return; } static uint32_t get_phys_page(ARMul_State* state, ARMword va){ uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF]; //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page); return phys_page; } static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){ //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa); //printf("In %s, insert va=0x%x, va>>12=0x%x, pa=0x%x, pa>>12=0x%x\n", __FUNCTION__, va, va >> 12, pa, pa >> 12); tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12; return; } #endif #define BANK0_START 0x50000000 static void* mem_ptr = NULL; static int exclusive_detect(ARMul_State* state, ARMword addr){ #if 0 for(int i = 0; i < 128; i++){ if(state->exclusive_tag_array[i] == addr) return 0; } #endif if(state->exclusive_tag_array[0] == addr) return 0; else return -1; } static void add_exclusive_addr(ARMul_State* state, ARMword addr){ #if 0 for(int i = 0; i < 128; i++){ if(state->exclusive_tag_array[i] == 0xffffffff){ state->exclusive_tag_array[i] = addr; //printf("In %s, add addr 0x%x\n", __func__, addr); return; } } printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__); #endif state->exclusive_tag_array[0] = addr; return; } static void remove_exclusive(ARMul_State* state, ARMword addr){ #if 0 int i; for(i = 0; i < 128; i++){ if(state->exclusive_tag_array[i] == addr){ state->exclusive_tag_array[i] = 0xffffffff; //printf("In %s, remove addr 0x%x\n", __func__, addr); return; } } #endif state->exclusive_tag_array[0] = 0xFFFFFFFF; } /* This function encodes table 8-2 Interpreting AP bits, returning non-zero if access is allowed. */ static int check_perms (ARMul_State *state, int ap, int read) { int s, r, user; s = state->mmu.control & CONTROL_SYSTEM; r = state->mmu.control & CONTROL_ROM; /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */ // printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read); // printf("mode is %x\n", state->Mode); user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); switch (ap) { case 0: return read && ((s && !user) || r); case 1: return !user; case 2: return read || !user; case 3: return 1; } return 0; } #if 0 fault_t check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb, int read) { int access; state->mmu.last_domain = tlb->domain; access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; if ((access == 0) || (access == 2)) { /* It's unclear from the documentation whether this should always raise a section domain fault, or if it should be a page domain fault in the case of an L1 that describes a page table. In the ARM710T datasheets, "Figure 8-9: Sequence for checking faults" seems to indicate the former, while "Table 8-4: Priority encoding of fault status" gives a value for FS[3210] in the event of a domain fault for a page. Hmm. */ return SECTION_DOMAIN_FAULT; } if (access == 1) { /* client access - check perms */ int subpage, ap; #if 0 switch (tlb->mapping) { /*ks 2004-05-09 * only for XScale * Extend Small Page(ESP) Format * 31-12 bits the base addr of ESP * 11-10 bits SBZ * 9-6 bits TEX * 5-4 bits AP * 3 bit C * 2 bit B * 1-0 bits 11 * */ case TLB_ESMALLPAGE: /* xj */ subpage = 0; /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */ break; case TLB_TINYPAGE: subpage = 0; /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */ break; case TLB_SMALLPAGE: subpage = (virt_addr >> 10) & 3; break; case TLB_LARGEPAGE: subpage = (virt_addr >> 14) & 3; break; case TLB_SECTION: subpage = 3; break; default: assert (0); subpage = 0; /* cleans a warning */ } ap = (tlb->perms >> (subpage * 2 + 4)) & 3; if (!check_perms (state, ap, read)) { if (tlb->mapping == TLB_SECTION) { return SECTION_PERMISSION_FAULT; } else { return SUBPAGE_PERMISSION_FAULT; } } #endif } else { /* access == 3 */ /* manager access - don't check perms */ } return NO_FAULT; } #endif #if 0 fault_t mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr) #endif /* ap: AP bits value. * sop: section or page description 0:section 1:page */ fault_t mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop) { { /* walk the translation tables */ ARMword l1addr, l1desc; if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) { l1addr = state->mmu.translation_table_base1; l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3; } else { l1addr = state->mmu.translation_table_base0; l1addr = (((l1addr >> (14 - state->mmu.translation_table_ctrl)) << (14 - state->mmu.translation_table_ctrl)) | (virt_addr << state->mmu.translation_table_ctrl) >> (18 + state->mmu.translation_table_ctrl)) & ~3; } /* l1desc = mem_read_word (state, l1addr); */ if (state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, l1addr, &l1desc, 4); else l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc); #if 0 if (virt_addr == 0xc000d2bc) { printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); // exit(-1); } #endif switch (l1desc & 3) { case 0: case 3: /* * according to Figure 3-9 Sequence for checking faults in arm manual, * section translation fault should be returned here. */ { return SECTION_TRANSLATION_FAULT; } case 1: /* coarse page table */ { ARMword l2addr, l2desc; l2addr = l1desc & 0xFFFFFC00; l2addr = (l2addr | ((virt_addr & 0x000FF000) >> 10)) & ~3; if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, l2addr, &l2desc, 4); else l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc); /* chy 2003-09-02 for xscale */ *ap = (l2desc >> 4) & 0x3; *sop = 1; /* page */ switch (l2desc & 3) { case 0: return PAGE_TRANSLATION_FAULT; break; case 1: *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF); break; case 2: case 3: *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF); break; } } break; case 2: /* section */ *ap = (l1desc >> 10) & 3; *sop = 0; /* section */ #if 0 if (virt_addr == 0xc000d2bc) { printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); // printf("l2addr is %x l2desc is %x\n", l2addr, l2desc); printf("ap is %x, sop is %x\n", *ap, *sop); printf("mode is %d\n", state->Mode); // exit(-1); } #endif if (l1desc & 0x30000) *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF); else *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF); break; } } return NO_FAULT; } static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, ARMword datatype); static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, ARMword datatype); int arm1176jzf_s_mmu_init (ARMul_State *state) { state->mmu.control = 0x50078; state->mmu.translation_table_base = 0xDEADC0DE; state->mmu.domain_access_control = 0xDEADC0DE; state->mmu.fault_status = 0; state->mmu.fault_address = 0; state->mmu.process_id = 0; state->mmu.context_id = 0; state->mmu.thread_uro_id = 0; //invalidate_all_tlb(state); return No_exp; } void arm1176jzf_s_mmu_exit (ARMul_State *state) { } static fault_t arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) { fault_t fault; int c; /* cache bit */ ARMword pa; /* physical addr */ ARMword perm; /* physical addr access permissions */ int ap, sop; static int debug_count = 0; /* used for debug */ DEBUG_LOG(ARM11, "va = %x\n", va); va = mmu_pid_va_map (va); if (MMU_Enabled) { // printf("MMU enabled.\n"); // sleep(1); /* align check */ if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { DEBUG_LOG(ARM11, "align\n"); return ALIGNMENT_FAULT; } else va &= ~(WORD_SIZE - 1); /* translate tlb */ fault = mmu_translate (state, va, &pa, &ap, &sop); if (fault) { DEBUG_LOG(ARM11, "translate\n"); printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault); return fault; } /* no tlb, only check permission */ if (!check_perms(state, ap, 1)) { if (sop == 0) { return SECTION_PERMISSION_FAULT; } else { return SUBPAGE_PERMISSION_FAULT; } } #if 0 /*check access */ fault = check_access (state, va, tlb, 1); if (fault) { DEBUG_LOG(ARM11, "check_fault\n"); return fault; } #endif } /*if MMU disabled or C flag is set alloc cache */ if (MMU_Disabled) { // printf("MMU disabled.\n"); // sleep(1); pa = va; } if(state->space.conf_obj == NULL) state->space.read(state->space.conf_obj, pa, instr, 4); else *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr); return NO_FAULT; } static fault_t arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data) { /* ARMword temp,offset; */ fault_t fault; fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); return fault; } static fault_t arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr, ARMword *data) { /* ARMword temp,offset; */ fault_t fault; fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); return fault; } static fault_t arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data) { return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); } static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, ARMword datatype) { fault_t fault; ARMword pa, real_va, temp, offset; ARMword perm; /* physical addr access permissions */ int ap, sop; DEBUG_LOG(ARM11, "va = %x\n", va); va = mmu_pid_va_map (va); real_va = va; /* if MMU disabled, memory_read */ if (MMU_Disabled) { // printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va); // sleep(1); /* *data = mem_read_word(state, va); */ if (datatype == ARM_BYTE_TYPE) /* *data = mem_read_byte (state, va); */ if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, va, data, 1); else *data = Memory::Read8(va); //mem_read_raw(8, va, data); else if (datatype == ARM_HALFWORD_TYPE) /* *data = mem_read_halfword (state, va); */ if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, va, data, 2); else *data = Memory::Read16(va); //mem_read_raw(16, va, data); else if (datatype == ARM_WORD_TYPE) /* *data = mem_read_word (state, va); */ if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, va, data, 4); else *data = Memory::Read32(va); //mem_read_raw(32, va, data); else { ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); } return NO_FAULT; } // printf("MMU enabled.\n"); // sleep(1); /* align check */ if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { DEBUG_LOG(ARM11, "align\n"); return ALIGNMENT_FAULT; } /* va &= ~(WORD_SIZE - 1); */ #if 0 uint32_t page_base; page_base = get_phys_page(state, va); if((page_base & 0xFFF) == 0){ pa = (page_base << 12) | (va & 0xFFF); goto skip_translation; } #endif /*translate va to tlb */ #if 0 fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb); #endif fault = mmu_translate (state, va, &pa, &ap, &sop); #if 0 if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){ //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); int i; for(i = 0; i < 16; i++) printf("Reg[%d]=0x%x\t", i, state->Reg[i]); printf("\n"); } #endif if (fault) { DEBUG_LOG(ARM11, "translate\n"); //printf("mmu read fault at %x\n", va); //printf("fault is %d\n", fault); return fault; } // printf("va is %x pa is %x\n", va, pa); /* no tlb, only check permission */ if (!check_perms(state, ap, 1)) { if (sop == 0) { return SECTION_PERMISSION_FAULT; } else { return SUBPAGE_PERMISSION_FAULT; } } #if 0 /*check access permission */ fault = check_access (state, va, tlb, 1); if (fault) return fault; #endif //insert_tlb(state, va, pa); skip_translation: /* *data = mem_read_word(state, pa); */ if (datatype == ARM_BYTE_TYPE) { /* *data = mem_read_byte (state, pa | (real_va & 3)); */ if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1); else *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data); /* mem_read_raw(32, pa | (real_va & 3), data); */ } else if (datatype == ARM_HALFWORD_TYPE) { /* *data = mem_read_halfword (state, pa | (real_va & 2)); */ if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2); else *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data); /* mem_read_raw(32, pa | (real_va & 2), data); */ } else if (datatype == ARM_WORD_TYPE) /* *data = mem_read_word (state, pa); */ if(state->space.conf_obj != NULL) state->space.read(state->space.conf_obj, pa , data, 4); else *data = Memory::Read32(pa); //mem_read_raw(32, pa, data); else { ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); } if(0 && (va == 0x2869c)){ printf("In %s, pa is %x va=0x%x, value is %x pc %x, instr=0x%x\n", __FUNCTION__, pa, va, *data, state->Reg[15], state->CurrInstr); } /* ldrex or ldrexb */ if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) || ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){ int rn = (state->CurrInstr & 0xF0000) >> 16; if(state->Reg[rn] == va){ add_exclusive_addr(state, pa | (real_va & 3)); state->exclusive_access_state = 1; } } #if 0 if (state->pc == 0xc011a868) { printf("pa is %x value is %x size is %x\n", pa, data, datatype); printf("icounter is %lld\n", state->NumInstrs); // exit(-1); } #endif return NO_FAULT; } static fault_t arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data) { return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); } static fault_t arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr, ARMword data) { return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); } static fault_t arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data) { return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); } static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, ARMword datatype) { int b; ARMword pa, real_va; ARMword perm; /* physical addr access permissions */ fault_t fault; int ap, sop; #if 0 /8 for sky_printk debugger.*/ if (va == 0xffffffff) { putchar((char)data); return 0; } if (va == 0xBfffffff) { putchar((char)data); return 0; } #endif DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); va = mmu_pid_va_map (va); real_va = va; if (MMU_Disabled) { /* mem_write_word(state, va, data); */ if (datatype == ARM_BYTE_TYPE) /* mem_write_byte (state, va, data); */ if(state->space.conf_obj != NULL) state->space.write(state->space.conf_obj, va, &data, 1); else Memory::Write8(va, data); else if (datatype == ARM_HALFWORD_TYPE) /* mem_write_halfword (state, va, data); */ if(state->space.conf_obj != NULL) state->space.write(state->space.conf_obj, va, &data, 2); else Memory::Write16(va, data); else if (datatype == ARM_WORD_TYPE) /* mem_write_word (state, va, data); */ if(state->space.conf_obj != NULL) state->space.write(state->space.conf_obj, va, &data, 4); else Memory::Write32(va, data); else { ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype); } goto finished_write; //return 0; } /*align check */ /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */ if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { DEBUG_LOG(ARM11, "align\n"); return ALIGNMENT_FAULT; } va &= ~(WORD_SIZE - 1); #if 0 uint32_t page_base; page_base = get_phys_page(state, va); if((page_base & 0xFFF) == 0){ pa = (page_base << 12) | (va & 0xFFF); goto skip_translation; } #endif /*tlb translate */ fault = mmu_translate (state, va, &pa, &ap, &sop); #if 0 if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){ //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); int i; for(i = 0; i < 16; i++) printf("Reg[%d]=0x%x\t", i, state->Reg[i]); printf("\n"); } #endif if (fault) { DEBUG_LOG(ARM11, "translate\n"); //printf("mmu write fault at %x\n", va); return fault; } // printf("va is %x pa is %x\n", va, pa); /* no tlb, only check permission */ if (!check_perms(state, ap, 0)) { if (sop == 0) { return SECTION_PERMISSION_FAULT; } else { return SUBPAGE_PERMISSION_FAULT; } } #if 0 /* tlb check access */ fault = check_access (state, va, tlb, 0); if (fault) { DEBUG_LOG(ARM11, "check_access\n"); return fault; } #endif #if 0 if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) { printf("pa is %x value is %x size is %x\n", pa, data, datatype); } #endif #if 0 if (state->pc == 0xc011a878) { printf("write pa is %x value is %x size is %x\n", pa, data, datatype); printf("icounter is %lld\n", state->NumInstrs); exit(-1); } #endif //insert_tlb(state, va, pa); skip_translation: /* strex */ if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) || ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){ /* failed , the address is monitord now. */ int dest_reg = (state->CurrInstr & 0xF000) >> 12; if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){ remove_exclusive(state, pa | (real_va & 3)); state->Reg[dest_reg] = 0; state->exclusive_access_state = 0; } else{ state->Reg[dest_reg] = 1; //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa); return NO_FAULT; } } if (datatype == ARM_BYTE_TYPE) { /* mem_write_byte (state, (pa | (real_va & 3)), data); */ if(state->space.conf_obj != NULL) state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1); else Memory::Write8((pa | (real_va & 3)), data); } else if (datatype == ARM_HALFWORD_TYPE) /* mem_write_halfword (state, (pa | (real_va & 2)), data); */ if(state->space.conf_obj != NULL) state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2); else Memory::Write16((pa | (real_va & 3)), data); else if (datatype == ARM_WORD_TYPE) /* mem_write_word (state, pa, data); */ if(state->space.conf_obj != NULL) state->space.write(state->space.conf_obj, pa, &data, 4); else Memory::Write32(pa, data); #if 0 if (state->NumInstrs > 236403) { printf("write memory\n"); printf("pa is %x value is %x size is %x\n", pa, data, datatype); printf("icounter is %lld\n", state->NumInstrs); } #endif finished_write: #if DIFF_WRITE if(state->icounter > state->debug_icounter){ if(state->CurrWrite >= 17 ){ printf("Wrong write array, 0x%x", state->CurrWrite); exit(-1); } uint32 record_data = data; if(datatype == ARM_BYTE_TYPE) record_data &= 0xFF; if(datatype == ARM_HALFWORD_TYPE) record_data &= 0xFFFF; state->WriteAddr[state->CurrWrite] = pa | (real_va & 3); state->WriteData[state->CurrWrite] = record_data; state->WritePc[state->CurrWrite] = state->Reg[15]; state->CurrWrite++; //printf("In %s, pc=0x%x, addr=0x%x, data=0x%x, CFlag=%d\n", __FUNCTION__, state->Reg[15], pa | (real_va & 3), record_data, state->CFlag); } #endif return NO_FAULT; } ARMword arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value) { int creg = BITS (16, 19) & 0xf; int OPC_1 = BITS (21, 23) & 0x7; int OPC_2 = BITS (5, 7) & 0x7; ARMword data; switch (creg) { case MMU_ID: if (OPC_2 == 0) { data = state->cpu->cpu_val; } else if (OPC_2 == 1) { /* Cache type: * 000 0110 1 000 101 110 0 10 000 101 110 0 10 * */ data = 0x0D172172; } break; case MMU_CONTROL: /* * 6:3 read as 1 * 10 read as 0 * 18,16 read as 1 * */ data = (state->mmu.control | 0x50078) & 0xFFFFFBFF; break; case MMU_TRANSLATION_TABLE_BASE: #if 0 data = state->mmu.translation_table_base; #endif switch (OPC_2) { case 0: data = state->mmu.translation_table_base0; break; case 1: data = state->mmu.translation_table_base1; break; case 2: data = state->mmu.translation_table_ctrl; break; default: printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2); break; } break; case MMU_DOMAIN_ACCESS_CONTROL: data = state->mmu.domain_access_control; break; case MMU_FAULT_STATUS: /* OPC_2 = 0: data FSR value * */ if (OPC_2 == 0) data = state->mmu.fault_status; if (OPC_2 == 1) data = state->mmu.fault_statusi; break; case MMU_FAULT_ADDRESS: data = state->mmu.fault_address; break; case MMU_PID: //data = state->mmu.process_id; if(OPC_2 == 0) data = state->mmu.process_id; else if(OPC_2 == 1) data = state->mmu.context_id; else if(OPC_2 == 3){ data = state->mmu.thread_uro_id; } else{ printf ("mmu_mcr read UNKNOWN - reg %d\n", creg); } //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr); //exit(-1); break; default: printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); data = 0; break; } /* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */ *value = data; return data; } static ARMword arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value) { int creg = BITS (16, 19) & 0xf; int CRm = BITS (0, 3) & 0xf; int OPC_1 = BITS (21, 23) & 0x7; int OPC_2 = BITS (5, 7) & 0x7; if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) { switch (creg) { case MMU_CONTROL: /* * 6:3 read as 1 * 10 read as 0 * 18,16 read as 1 * */ if(OPC_2 == 0) state->mmu.control = (value | 0x50078) & 0xFFFFFBFF; else if(OPC_2 == 1) state->mmu.auxiliary_control = value; else if(OPC_2 == 2) state->mmu.coprocessor_access_control = value; else fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2); break; case MMU_TRANSLATION_TABLE_BASE: switch (OPC_2) { /* int i; */ case 0: #if 0 /* TTBR0 */ if (state->mmu.translation_table_ctrl & 0x7) { for (i = 0; i <= state->mmu.translation_table_ctrl; i++) state->mmu.translation_table_base0 &= ~(1 << (5 + i)); } #endif state->mmu.translation_table_base0 = (value); break; case 1: #if 0 /* TTBR1 */ if (state->mmu.translation_table_ctrl & 0x7) { for (i = 0; i <= state->mmu.translation_table_ctrl; i++) state->mmu.translation_table_base1 &= 1 << (5 + i); } #endif state->mmu.translation_table_base1 = (value); break; case 2: /* TTBC */ state->mmu.translation_table_ctrl = value & 0x7; break; default: printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2); break; } //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); //invalidate_all_tlb(state); break; case MMU_DOMAIN_ACCESS_CONTROL: /* printf("mmu_mcr wrote DACR "); */ state->mmu.domain_access_control = value; break; case MMU_FAULT_STATUS: if (OPC_2 == 0) state->mmu.fault_status = value & 0xFF; if (OPC_2 == 1) { printf("set fault status instr\n"); } break; case MMU_FAULT_ADDRESS: state->mmu.fault_address = value; break; case MMU_CACHE_OPS: break; case MMU_TLB_OPS: { switch(CRm){ case 5: /* ITLB */ { switch(OPC_2){ case 0: /* invalidate all */ //invalidate_all_tlb(state); break; case 1: /* invalidate by MVA */ //invalidate_by_mva(state, value); break; case 2: /* invalidate by asid */ //invalidate_by_asid(state, value); break; default: printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); break; } break; } case 6: /* DTLB */ { switch(OPC_2){ case 0: /* invalidate all */ //invalidate_all_tlb(state); break; case 1: /* invalidate by MVA */ //invalidate_by_mva(state, value); break; case 2: /* invalidate by asid */ //invalidate_by_asid(state, value); break; default: printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); break; } break; } case 7: /* Unified TLB */ { switch(OPC_2){ case 0: /* invalidate all */ //invalidate_all_tlb(state); break; case 1: /* invalidate by MVA */ //invalidate_by_mva(state, value); break; case 2: /* invalidate by asid */ //invalidate_by_asid(state, value); break; default: printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); break; } break; } default: printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm); break; } //printf("SKYEYE In %s, write TLB 0x%x OPC_1=%d, OPC_2=%d , CRm=%d instr=0x%x\n", __FUNCTION__, value, OPC_1, OPC_2, CRm, instr); } break; case MMU_CACHE_LOCKDOWN: /* * FIXME: cache lock down*/ break; case MMU_TLB_LOCKDOWN: printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); /* FIXME:tlb lock down */ break; case MMU_PID: //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); //state->mmu.process_id = value; /*0:24 should be zero. */ //state->mmu.process_id = value & 0xfe000000; if(OPC_2 == 0) state->mmu.process_id = value; else if(OPC_2 == 1) state->mmu.context_id = value; else if(OPC_2 == 3){ state->mmu.thread_uro_id = value; } else{ printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); } break; default: printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); break; } } return No_exp; } ///* teawater add for arm2x86 2005.06.19------------------------------------------- */ //static int //arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr, // ARMword *phys_addr) //{ // fault_t fault; // int ap, sop; // // ARMword perm; /* physical addr access permissions */ // virt_addr = mmu_pid_va_map (virt_addr); // if (MMU_Enabled) { // // /*align check */ // if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { // DEBUG_LOG(ARM11, "align\n"); // return ALIGNMENT_FAULT; // } else // virt_addr &= ~(WORD_SIZE - 1); // // /*translate tlb */ // fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop); // if (fault) { // DEBUG_LOG(ARM11, "translate\n"); // return fault; // } // // /* permission check */ // if (!check_perms(state, ap, 1)) { // if (sop == 0) { // return SECTION_PERMISSION_FAULT; // } else { // return SUBPAGE_PERMISSION_FAULT; // } // } //#if 0 // /*check access */ // fault = check_access (state, virt_addr, tlb, 1); // if (fault) { // DEBUG_LOG(ARM11, "check_fault\n"); // return fault; // } //#endif // } // // if (MMU_Disabled) { // *phys_addr = virt_addr; // } // // return 0; //} /* AJ2D-------------------------------------------------------------------------- */ /*arm1176jzf-s mmu_ops_t*/ mmu_ops_t arm1176jzf_s_mmu_ops = { arm1176jzf_s_mmu_init, arm1176jzf_s_mmu_exit, arm1176jzf_s_mmu_read_byte, arm1176jzf_s_mmu_write_byte, arm1176jzf_s_mmu_read_halfword, arm1176jzf_s_mmu_write_halfword, arm1176jzf_s_mmu_read_word, arm1176jzf_s_mmu_write_word, arm1176jzf_s_mmu_load_instr, arm1176jzf_s_mmu_mcr, arm1176jzf_s_mmu_mrc /* teawater add for arm2x86 2005.06.19------------------------------------------- */ /* arm1176jzf_s_mmu_v2p_dbct, */ /* AJ2D-------------------------------------------------------------------------- */ };