OK6410A 开发板 (八) 50 linux-5.11 OK6410A 基于VMA的sys_mmap与sys_brk

前提
mmap 和 brk 通过封装 A 和 B , 完成了  对 用户空间虚拟物理内存的管理

代码流程

mm/mmap.c:190:SYSCALL_DEFINE1(brk, unsigned long, brk)
mm/mmap.c:1641:SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
mm/mmap.c:2953:SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len)

可以这么讲, brk 类似于 	mmap数据流中的一种:"私有匿名映射"
而mmap共有 四种用途


mmap 的过程1
  • 主体流程
// 以mmap文件映射举例
// 用户空间的mmap 从进入到返回,并没有发生访存异常
// 当用户空间读写mmap中返回的指针时,才会发生访存异常

// 也就是说 sys_mmap 过程中 不会处理 访存异常
SYSCALL_DEFINE6(mmap_pgoff
	ksys_mmap_pgoff
		vm_mmap_pgoff
			do_mmap
				// A .得到 虚拟地址空间
				addr = get_unmapped_area
					A.1 针对文件xx映射   get_area = file->f_op->get_unmapped_area
					A.2 针对匿名共享映射  get_area = shmem_get_unmapped_area;
					A.3 针对匿名私有映射  get_area = current->mm->get_unmapped_area;
					A.4 return addr = get_area(file, addr, len, pgoff, flags);
					// get_area 函数中 得到 虚拟地址空间
					// 得到 固定虚拟地址空间的方法
					// 参数 addr 以页为单位,即4KB对其
					// MAP_FIXED 会得到固定的虚拟地址空间. // 如果调用前被占用,则解占用
					// MAP_FIXED_NOREPLACE 也会得到固定的虚拟地址空间// 如果调用前辈占用,则return fail
				
				// B C 得到物理地址空间 并 建立虚拟地址空间到物理地址空间的映射
				addr = mmap_region
					* populate = 0; 
					vma_merge
					vma = kmem_cache_zalloc
						//... vma 成员的填充
					
					// mmap 的 四种流程 中都没有 建立页表项.
					// 访存时都会产生异常,都会满足 mm/memory.c 4383 行的 if (!vmf->pte)
					if(file){ // 针对文件xx映射 
						call_mmap(file, vma);//即file->f_op->mmap(file, vma);
							// B. 得到物理地址空间
							// C. 建立虚拟地址空间到物理地址空间的映射
							// 一般会延时到 访存的异常中 做 B和C
					
					}else if (VM_SHARED){ // 针对匿名共享映射
						shmem_zero_setup(vma); // 共享匿名映射 , 读写共享匿名映射的区域不会产生异常
							// B. 得到物理地址空间
							// C. 建立虚拟地址空间到物理地址空间的映射
							// 一般会延时到 访存的异常中 做 B和C
							
					}else{ // 针对匿名私有映射
						vma_set_anonymous(vma);
							// B. 得到物理地址空间
							// C. 建立虚拟地址空间到物理地址空间的映射
							// 一般会延时到 访存的异常中 做 B和C
					
					}
					
					vma_link(mm, vma, prev, rb_link, rb_parent);


			----------------------------------------------------以下是 马上申请物理地址空间和建立映射的情况
				if (!IS_ERR_VALUE(addr) && ((vm_flags & VM_LOCKED) || (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
				*populate = len;
			if (populate) mm_populate 
				__mm_populate
					populate_vma_page_range
						__get_user_pages
							find_extend_vma
							follow_page_mask
							faultin_page
							handle_mm_fault

  • 分体流程 针对文件xx映射
get_area = file->f_op->get_unmapped_area
file->f_op->mmap 按道理应该完成以下事情
	// B. 得到物理地址空间
	// C. 建立虚拟地址空间到物理地址空间的映射
但是实际上分为以下三种情况
	1.在file->f_op->mmap前已经分配了物理内存,file->f_op->mmap 只做了映射
		// MAP_SHARED 不会引起异常
		// MAP_PRIVATE 导致 映射的物理页没有 写权限,写内存会导致异常
	2.file->f_op->mmap 申请了物理内存, 并做了映射
		// MAP_SHARED 不会引起异常
		// MAP_PRIVATE 导致 映射的物理页没有 写权限,写内存会导致异常
	3.file->f_op->mmap 没有申请物理内存,没有做映射,而是在 file->f_op->mmap 中设置了 vma->vm_ops= &my_file_mmap
																				// vm_ops 中有个成员为 fault
																				// 该成员会做
																					1. 申请物理地址空间
																					2. 建立虚拟地址空间到物理地址空间的映射
																			
		
		// MAP_SHARED
		// 在访问地址时会导致内存访问异常, 流程中会回调vma->ops//即 my_file_mmap
		// my_file_mmap 中 完成 申请 物理内存
		// 异常其他流程中 会 做 映射
		
		// MAP_PRIVATE
		// 在访问地址时会导致内存访问异常, 流程中会调用 do_anonymous_page

  • 分体流程 匿名共享映射
get_area = shmem_get_unmapped_area;
	current->mm->get_unmapped_area(file, uaddr, len, pgoff, flags);
shmem_zero_setup(vma);
	shmem_kernel_file_setup("dev/zero", size, vma->vm_flags);
	vma->vm_ops = &shmem_vm_ops; // 类似 文件xx映射 中 mmap 的 第三种情况
  • 分体流程 匿名私有映射
get_area = current->mm->get_unmapped_area;
vma_set_anonymous(vma);
	vma->vm_ops = NULL;
mmap 的过程2 访存异常
  • 主体流程
VM_LOCKED 设置后,也会到调用 异常流程中调用的主要函数
handle_mm_fault -> __handle_mm_fault -> handle_pte_fault -> do_anonymous_page

缺页异常 并不对应 一种异常(armv6有7个异常)
而是 对应 几种因为访问内存的产生的错误 // 是一种软件上的叫法,架构无关
这种错误会让 cpu(对应armv6) 产生 data abort 异常


访存(访问存储器) 时发生异常,armv6 会
	1.设置 FSR // Fault Status Register	存储失效的相关信息(包括存储访问所属区域和访问类型)
	2.设置 FAR // Fault Address Register 存储访问失效的虚拟地址
	3.进入 data abort 异常
		3.1 设置处理器模式为 ABT异常模式

__vectors_start
	vector_dabt
		__dabt_usr/__dabt_svc
			dabt_helper
				v7_early_abort
					mrc c5 // 读 c5
					mrc c6 // 读 c6
					do_DataAbort
						fsr_info[0...4]
							do_page_fault // 缺页异常 的 核心函数,架构相关函数
								__do_page_fault
									handle_mm_fault // 第一个架构无关的函数,mm/memory.c
										__handle_mm_fault
											handle_pte_fault
												
handle_pte_fault
	if (!vmf->pte) { // 页表项为空 // 1. 页表项还没建立 2.页表项的内容被清空
		if (vma_is_anonymous(vmf->vma)) // vma 的 vm_ops 成员为 NULL   , 针对 mmap 的 一种用途 "匿名私有映射"
			return do_anonymous_page(vmf);
		else							// vma 的 vm_ops 成员不为 NULL , 针对 mmap 的 三种用途 "文件私有映射" "文件共享映射" "匿名共享映射"
			return do_fault(vmf);   
	}

	if (!pte_present(vmf->orig_pte)) // 页表项不为空,其成员 pte_present 为 0,说明页面不在内存中,被swap出去了
		return do_swap_page(vmf);

	if (pte_protnone(vmf->orig_pte) && vma_is_accessible(vmf->vma)) // // 页表项不为空,其成员 pte_protnone 为 0,说明页面被设置成NUMA调度的页面
		return do_numa_page(vmf);
		
	if (vmf->flags & FAULT_FLAG_WRITE) { // 页表项不为空,处理器因为写内存而触发异常,
		if (!pte_write(entry)) // 并且PTE为只读属性
			return do_wp_page(vmf);
		entry = pte_mkdirty(entry);
	}

handle_pte_fault 解析

	A 针对 匿名页面缺页异常 do_anonymous_page
		有虚拟地址,没有映射,没有物理地址
		应用场景 : malloc // 匿名页面(没有关联到文件映射的页面)
	B 针对 文件映射缺页异常 do_fault (下分 do_read_fault do_cow_fault do_shared_fault,三个函数都调用 __do_fault,__do_fault中调用vma->vm_ops->fault)
		有虚拟地址,没有映射,没有物理地址
		mmap(驱动mmap中没有申请物理空间和映射)之后,访存 发生异常
		应用场景:mmap读文件内容 // 用于关联到文件映射的页面(这种页面又名页高速缓存)
				动态库映射
				
	C 针对 写时复制缺页异常 do_wp_page
		有虚拟地址,有映射(页表为只读),有物理地址
		应用场景:fork的COW
				
	D 针对 swap   缺页异常 do_swap_page
		有虚拟地址,  有映射,有物理地址,物理页被换出
		应用场景:为了节省内存,物理页面从内存被换出到硬盘,现在需要换入 // 换出到硬盘的时候需要 将哪些内存页换出,有很多算法
	
	针对 ...    缺页异常 do_numa_page
									

  • 分体流程 文件xx映射
do_fault 
	do_read_fault  // 针对 读 私有&共享
		__do_fault
			vma->vm_ops->fault()
	do_cow_fault // 针对 写 私有
		__do_fault
			vma->vm_ops->fault()
	do_shared_fault // 针对 写 共享
		__do_fault
			vma->vm_ops->fault()
  • 分体流程 匿名共享映射
do_fault 
	do_read_fault 
	do_cow_fault 
	do_shared_fault
  • 分体流程 匿名私有映射
do_anonymous_page
	// 第一次为读
	// A.1 填充0页
	pte_mkspecial(pfn_pte(my_zero_pfn(vmf->address),vma->vm_page_prot));
	// A.2
	set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);// 第一次为写
	// B.1. 申请物理地址空间
	page = alloc_zeroed_user_highpage_movable
	// B.2. 做映射
	pte_alloc
	set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);

	// 第一次为读,第二次为写
	// 读的时候执行 A.1 和 A.2
	// 写的时候,处于写时复制, 走 do_wp_page


do_wp_page
	针对写时复制, wp_page_copy
	针对可写并且共享的普通映射页面,wp_page_shared
	针对可写并且共享的特殊映射页面,wp_pfn_shared
	针对可以复用的页面,wp_page_resume
brk 的过程1
SYSCALL_DEFINE1(brk
	if (brk <= mm->brk) {mm->brk = brk;}
	
	find_vma
	do_brk_flags
		get_unmapped_area
		vma_merge
		vma = vm_area_alloc
		vma_set_anonymous // 该函数的调动决定了访存异常时进入 "分体流程 匿名私有映射"
		vma_link(mm, vma, prev, rb_link, rb_parent);

			----------------------------------------------------以下是 马上申请物理地址空间和建立映射的情况
	mm_populate
		__mm_populate
			populate_vma_page_range
				__get_user_pages
					find_extend_vma
					follow_page_mask
					faultin_page
					handle_mm_fault

其中会(申请的话,增加)(释放的话,降低) mm_struct 的 brk 成员的值


brk 的过程2
mmap 的过程2 访存异常 中的
	1. 主体流程
	2. 分体流程 匿名私有映射
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值