本文共 4070 字,大约阅读时间需要 13 分钟。
instruction fetch memory abortdata access memory abort
在 内存访问流程中 ,ARM处理器可能会发生异常异常的原因是中止(异常的访问),中止分为三种: MMU faults(4种) MMU检测到限制并向处理器发送信号。 Debug abort 监视器调试模式已启用,并且检测到断点或监视点。 External abort(三种) 外部内存系统发出非法或错误的内存访问信号。
MMU faults 如果中止的内存请求是指令获取,则当处理器尝试执行与中止的访问对应的指令时,将引发预取中止异常。 如果中止的访问是数据访问或缓存维护操作,则会引发数据中止异常。 Debug event 当启用监视调试模式时 , 可以由于 指令访问上的breakpoint 而执行中止, 产生 预取中止异常 当启用监视调试模式时 , 可以由于 数据访问上的watchpoint 而执行中止, 产生 数据中止异常 External abort 指令获取时的外部中止 , 可能会产生 预取中止异常(依据是否执行) 数据读/写时外部中止 , 会产生 数据中止异常 硬件页表遍历上的外部中止 , 会产生 数据中止异常
本次案例是匿名缺页,会产生 MMU faults 中的 下面哪一种? (alignment fault/translation fault/domain fault/permission fault) 因为 没有做映射,所以应该是 translation fault ,// TODO此时是访问数据,从而导致 数据中止异常
// mmap (因为mmap比malloc简单)// A1. 私有匿名映射 : 用于 分配大块内存(128KB及以上)// fd = -1 flags=MAP_ANONYMOUS|MAP_PRIVATE#include#include #include int main(int argc, char *argv[]) { char *m; size_t s = 256 * 1024; // 此时会进入 系统调用 mmap // 做 虚拟内存的申请 m = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS , -1, 0); if (m == MAP_FAILED) { perror("map mem"); m = NULL; return 1; } printf("mmap alloc memory ok, press ENTER to acess memory!\n"); getchar(); // 此时会 进入异常 data abort // 每访问一页,就会进入一次异常 // 进入的时候 , 会调用 do_anonymous_page 为 4KB 虚拟地址 // 1. 做 物理页的申请 alloc_zeroed_user_highpage_movable // 2. 做 虚拟内存与物理内存的映射 set_pte_at memset(m, 0, s); printf("mmap acess memory ok, press ENTER to quit!\n"); getchar(); munmap(m, s); return 0;}
file->f_op->mmap 没有申请物理内存,没有做映射,而是在 file->f_op->mmap 中设置了 vma->ops = &my_file_mmap
访存的动作 是 在用户空间做的例如 *p 就是访存动作这个动作做完之后,就会产生一个 data abort 异常
访存(访问存储器) 时发生异常,armv6 会 1.设置 FSR // Fault Status Register 存储失效的相关信息(包括存储访问所属区域和访问类型) 2.设置 FAR // Fault Address Register 存储访问失效的虚拟地址 R14_abt = address of the aborted instruction + 8 SPSR_abt = CPSR CPSR[4:0] = 0b10111 /* Enter Abort mode */ CPSR[5] = 0 /* Execute in ARM state */ /* CPSR[6] is unchanged */ CPSR[7] = 1 /* Disable normal interrupts */ CPSR[8] = 1 /* Disable Imprecise Data Aborts (v6 only) */ CPSR[9] = CP15_reg1_EEbit /* Endianness on exception entry */ if high vectors configured then PC = 0xFFFF0010 else PC = 0x00000010
__vectors_start vector_dabt __dabt_usr/__dabt_svc dabt_helper CPU_DABORT_HANDLER/v7_early_abort
v7_early_abort mrc c5 // 读 c5 mrc c6 // 读 c6 do_DataAbort fsr_info[0...4] // exceptions_init 注册了 do_translation_fault // hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR, "I-cache maintenance fault"); do_translation_fault
do_translation_fault do_page_fault // 缺页异常 的 核心函数 __do_page_fault handle_mm_fault __handle_mm_fault handle_pte_fault do_anonymous_page __do_user_fault // 用户空间访问 0地址时会出现这种情况 __do_kernel_fault // 内核空间访问 0地址是会出现这种情况 A 针对 匿名页面缺页异常 do_anonymous_page 有虚拟地址,没有映射,没有物理地址 应用场景 : malloc // 匿名页面(没有关联到文件映射的页面)在访问地址时会导致内存访问异常, 流程中会调用 do_anonymous_page
// 每一次进入do_anonymous_page 做 一页的映射// 多次 进入之后,发现// 同一个进程,同一个vma,虚拟地址地址越来越高,page地址越来越低(物理地址越来越低) // 此时无法用 page_to_phys(page) 打印物理地址,但是 struct page 的地址 都是间隔 0x20,说明 物理地址是连续的// pmd 是一样的,pmd 中是 页表基址寄存器 的值// page_table 是 一级页表的地址do_anonymous_page (mm=0xee11e540, vma=0xeeb02738, address=3069333504, page_table=0xee13c494, pmd=0xedc0edb8, flags=85) page = alloc_zeroed_user_highpage_movable(vma, address); (struct page *) 0xef019cc0 // 物理地址 : TODOdo_anonymous_page (mm=0xee11e540, vma=0xeeb02738, address=3069337600, page_table=0xee13c498, pmd=0xedc0edb8, flags=85) page = alloc_zeroed_user_highpage_movable(vma, address); (struct page *) 0xef019ca0 do_anonymous_page (mm=0xee11e540, vma=0xeeb02738, address=3069341696, page_table=0xee13c49c, pmd=0xedc0edb8, flags=85) page = alloc_zeroed_user_highpage_movable(vma, address); (struct page *) 0xef019c80
转载地址:http://ajigi.baihongyu.com/