📄 armmmu.cpp
字号:
case MMU_TRANSLATION_TABLE_BASE: data = translation_table_base; break; case MMU_DOMAIN_ACCESS_CONTROL: data = domain_access_control; break; case MMU_FAULT_STATUS: data = fault_status; break; case MMU_FAULT_ADDRESS: data = fault_address; break; case MMU_PID: data = process_id; break; //no break in Skyeye default: data = 0; fprintf (stderr, "cp15_mrc read UNKNOWN - reg %d, pc 0x\n", creg); exit (-1); break; } return data;}void arm_mmu::invalidate_tlb(word_t opcode_2,word_t CRm,word_t value) { if (opcode_2 == 0 && CRm == 0x7) { FLUSH_MMU_PAGE_TABLE(i_table); FLUSH_MMU_PAGE_TABLE(d_table); i_tlb->invalidate_all (); d_tlb->invalidate_all (); } else if (opcode_2 == 0 && CRm == 0x5) { FLUSH_MMU_PAGE_TABLE(i_table); i_tlb->invalidate_all (); } else if (opcode_2 == 1 && CRm == 0x5) { FLUSH_MMU_PAGE_TABLE(i_table); i_tlb->invalidate_entry (value); } else if (opcode_2 == 0 && CRm == 0x6) { FLUSH_MMU_PAGE_TABLE(d_table); d_tlb->invalidate_all (); } else if (opcode_2 == 1 && CRm == 0x6) { FLUSH_MMU_PAGE_TABLE(d_table); d_tlb->invalidate_entry (value); } else { fprintf (stderr,"Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x\n", opcode_2, CRm); exit (-1); }}void arm_mmu::mcr(word_t instr, word_t value){ unsigned opcode_2 = (instr>>5)&7; unsigned CRm = (instr>>0)&15; unsigned creg = (instr>>16)&15; switch (creg) { case MMU_CONTROL: set_control((value | 0x70) & 0xFFFD); break; case MMU_TRANSLATION_TABLE_BASE: translation_table_base = value & 0xFFFFC000; FLUSH_MMU_PAGE_TABLE(i_table); FLUSH_MMU_PAGE_TABLE(d_table); break; case MMU_DOMAIN_ACCESS_CONTROL: set_domain_access_control(value); break; case MMU_FAULT_STATUS: fault_status = value & 0xFF; break; case MMU_FAULT_ADDRESS: fault_address = value; break; case MMU_CACHE_OPS: /*cache is not implemented*/ //xscale_cp15_cache_ops (state, instr, value); break; case MMU_TLB_OPS: invalidate_tlb(opcode_2,CRm,value); break; case MMU_SA_RB_OPS: // no read buffer break; case MMU_SA_DEBUG: break; case MMU_SA_CP15_R15: break; case MMU_PID: set_process_id(value); break; default: fprintf(stderr, "cp15_mcr wrote UNKNOWN - reg %d, reg15 0x\n", creg); break; }}int arm_mmu::check_perms (int ap, mmu_access_t read) const{ static const byte_t perms[] = { // !u !u !u !u 0, 0, 0, 0, 0, 0, 0, 0, //ap == 0 0, 0, 0, 1, 1, 1, 1, 1, //ap == 0 read 0, 1, 0, 1, 0, 1, 0, 1, //ap == 1 0, 1, 0, 1, 0, 1, 0, 1, //ap == 1 read 0, 1, 0, 1, 0, 1, 0, 1, //ap == 2 1, 1, 1, 1, 1, 1, 1, 1, //ap == 2 read 1, 1, 1, 1, 1, 1, 1, 1, //ap == 3 1, 1, 1, 1, 1, 1, 1, 1 //ap == 3 read // r r r r // s s s s }; /* ap:read:rs_flag:user */ int pack = ap | read | rs_flag | emu->is_privilege_mode(); return perms[pack]; }mmu_fault_t arm_mmu::check_access (word_t virt_addr, tlb_entry_t * tlb_e, mmu_access_t read){ int access; access = domain_access_array[tlb_e->domain]; if(access == 1) { /* client access - check perms */ int subpage, ap; switch (tlb_e->mapping) { case TLB_ESMALLPAGE: //xj ap = tlb_e->perms & 48; break; case TLB_TINYPAGE: ap = tlb_e->perms & 48; break; case TLB_SMALLPAGE: ap = (tlb_e->perms >> ((virt_addr >> 9) & 6)) & 48; break; case TLB_LARGEPAGE: ap = (tlb_e->perms >> ((virt_addr >> 13) & 6)) & 48; break; case TLB_SECTION: ap = (tlb_e->perms >> 6 ) & 48; break; default: assert (0); subpage = 0; /* cleans a warning */ } if (!check_perms (ap, read)) { last_domain= tlb_e->domain; if (tlb_e->mapping == TLB_SECTION) { return SECTION_PERMISSION_FAULT; } else { return SUBPAGE_PERMISSION_FAULT; } } return NO_FAULT; } if (access == 3) { /* access == 3 */ /* manager access - don't check perms */ return NO_FAULT; }// 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;// }}mmu_fault_t arm_mmu::translation_walk (word_t virt_addr, tlb_entry_t *tlb_e){ /* walk the translation tables */ int ap[4]; int fast_access = 1; word_t L1addr, L1desc; tlb_entry_t entry = *tlb_e; L1addr = translation_table_base & 0xFFFFC000; L1addr = (L1addr | (virt_addr >> 18)) & ~3; MEM_READ_WORD (L1addr, &L1desc); switch (L1desc & 3) { case 0: //SBZ { return PAGE_TRANSLATION_FAULT; } case 3: /* fine page table */ { word_t L2addr, L2desc; L2addr = L1desc & 0xFFFFF000; L2addr = (L2addr | ((virt_addr & 0x000FFC00) >> 8)) & ~3; MEM_READ_WORD (L2addr, &L2desc); entry.virt_addr = virt_addr; entry.phys_addr = L2desc; entry.perms = L2desc & 0x00000FFC; entry.domain = (L1desc >> 5) & 0x0000000F; ap[3]=(entry.perms>>10) & 3; ap[2]=(entry.perms>>8) & 3; ap[1]=(entry.perms>>6) & 3; ap[0]=(entry.perms>>4) & 3; switch (L2desc & 3) { case 0: last_domain = entry.domain; return PAGE_TRANSLATION_FAULT; case 3: entry.mapping = TLB_TINYPAGE; break; case 1: entry.mapping = TLB_LARGEPAGE; /*check every sub-page ap-bit in order to group into one ap-bit*/ if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) { fast_access =0; } break; case 2: entry.mapping = TLB_SMALLPAGE; /*check every sub-page ap-bit in order to group into one ap-bit*/ if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) { fast_access =0; } break; } } break; case 1: /* coarse page table */ { word_t L2addr, L2desc; L2addr = L1desc & 0xFFFFFC00; L2addr = (L2addr | ((virt_addr & 0x000FF000) >> 10)) & ~3; MEM_READ_WORD (L2addr, &L2desc); entry.virt_addr = virt_addr; entry.phys_addr = L2desc; entry.perms = L2desc & 0x00000FFC; entry.domain = (L1desc >> 5) & 0x0000000F; ap[3]=(entry.perms>>10) & 3; ap[2]=(entry.perms>>8) & 3; ap[1]=(entry.perms>>6) & 3; ap[0]=(entry.perms>>4) & 3; switch (L2desc & 3) { case 0: last_domain = entry.domain; return PAGE_TRANSLATION_FAULT; case 3: if (emu->is_xscale()) { entry.mapping = TLB_ESMALLPAGE; //xj break; } else { last_domain = entry.domain; return PAGE_TRANSLATION_FAULT; } case 1: entry.mapping = TLB_LARGEPAGE; /*check every sub-page ap-bit in order to group into one ap-bit*/ if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) { fast_access =0; } break; case 2: entry.mapping = TLB_SMALLPAGE; /*check every sub-page ap-bit in order to group into one ap-bit*/ if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) { fast_access =0; } break; } } break; case 2: /* section */ entry.virt_addr = virt_addr; entry.phys_addr = L1desc; entry.perms = L1desc & 0x00000C0C; entry.domain = (L1desc >> 5) & 0x0000000F; entry.mapping = TLB_SECTION; break; } entry.mask = tlb_masks[entry.mapping]; /* Masking bits for both physical address and virtual address consumes more time. The better way is to subtract physical page-base with virtual page-base before hand and the time to convert address will be less The non-optimized function should be like this code. entry.nmask = ~tlb_masks[entry.mapping]; entry.phys_addr &= entry.mask; */ entry.phys_addr = (entry.phys_addr & entry.mask) - (entry.virt_addr & entry.mask); /* Compute the memory access permision of this tlb entry(page entry) for both read access and write access */ evaluate_access_entry(fast_access,&entry); /* commit the change */ *tlb_e = entry; return NO_FAULT;}void arm_mmu::evaluate_access_all(void){ int fast_access; tlb_entry_t *tlb_e; FLUSH_MMU_PAGE_TABLE(i_table); FLUSH_MMU_PAGE_TABLE(d_table); /*Compute the memory access permision of all entries in ITLB*/ for(int i=0;i< MMU_ITLB_SIZE;i++) { tlb_e =i_tlb->get_entry(i); fast_access =1; if (tlb_e->mapping == TLB_INVALID) continue; else if (tlb_e->read_fault == SLOW_ACCESS_CHECKING) fast_access = 0; evaluate_access_entry(fast_access,tlb_e); } /*Compute the memory access permision of all entries in ITLB*/ for(int i=0;i< MMU_DTLB_SIZE ;i++) { tlb_e =d_tlb->get_entry(i); fast_access =1; if (tlb_e->mapping == TLB_INVALID) continue; else if (tlb_e->read_fault == SLOW_ACCESS_CHECKING) fast_access = 0; evaluate_access_entry(fast_access,tlb_e); }}void arm_mmu::evaluate_access_entry (int fast_access,tlb_entry_t *tlb_e){ if (tlb_e->mapping == TLB_INVALID) return; if (fast_access) { /*fast access checking means that this page has one ap-bit or same ap-bit for each sub-page*/ tlb_e->read_fault = check_access(0,tlb_e,MMU_READ); tlb_e->write_fault = check_access(0,tlb_e,MMU_WRITE); } else{ /*slow access checking means that this page has difference ap-bit for each sub-page*/ tlb_e->read_fault = SLOW_ACCESS_CHECKING; tlb_e->write_fault = SLOW_ACCESS_CHECKING; }}word_t arm_mmu::xscale_mrc (word_t instr){ word_t data; unsigned creg = (instr>>16)&15; unsigned opcode_2 = (instr>>5)&7; //unsigned CRm = (instr>>0)&15; switch (creg) { case MMU_ID: data = (opcode_2 ? cache_type : emu->get_cpu_id()); break; case MMU_CONTROL: data = (opcode_2 ? aux_control : control); break; case MMU_TRANSLATION_TABLE_BASE: data = translation_table_base; break; case MMU_DOMAIN_ACCESS_CONTROL: data = domain_access_control; break; case MMU_FAULT_STATUS: data = fault_status; break; case MMU_FAULT_ADDRESS: data = fault_address; break; case MMU_PID: data = process_id; break; //no break in Skyeye case XSCALE_CP15_COPRO_ACCESS: //printf("xscale cp15 read coprocessor access\n"); data = copro_access; break; default: data = 0; fprintf (stderr, "cp15_mrc read UNKNOWN - reg %d, pc 0x\n", creg); exit (-1); break; } return data;}void arm_mmu::xscale_mcr(word_t instr, word_t value){ unsigned opcode_2 = (instr>>5)&7; unsigned CRm = (instr>>0)&15; unsigned creg = (instr>>16)&15; switch (creg) { case MMU_CONTROL: set_control(opcode_2 ? (value & 0x33) : (value & 0x3FFF)); break; case MMU_TRANSLATION_TABLE_BASE: translation_table_base = value & 0xFFFFC000; FLUSH_MMU_PAGE_TABLE(i_table); FLUSH_MMU_PAGE_TABLE(d_table); break; case MMU_DOMAIN_ACCESS_CONTROL: set_domain_access_control(value); break; case MMU_FAULT_STATUS: fault_status = value & 0x6FF; break; case MMU_FAULT_ADDRESS: fault_address = value; break; case MMU_CACHE_OPS: /*cache is not implemented*/ //xscale_cp15_cache_ops (state, instr, value); break; case MMU_TLB_OPS: invalidate_tlb(opcode_2,CRm,value); break; case MMU_PID: set_process_id(value); break; case XSCALE_CP15_COPRO_ACCESS: //printf("xscale cp15 write coprocessor access val 0x %x\n",value); copro_access = value & 0x3ff; break; default: fprintf(stderr, "cp15_mcr wrote UNKNOWN - reg %d, reg15 0x\n", creg); break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -