OK6410A 开发板 (八) 47 linux-5.11 OK6410A 物理虚拟内存的管理

物理虚拟内存管理理论
在 mmu 开启之后, 存在了两种内存
	物理内存
	虚拟内存

就需要对 这两种内存 进行管理

我们用内存的时候,需要
	1. 物理内存
	2. 虚拟内存 // 与 物理内存对应的虚拟内存

对物理内存的管理方法有4(根据内存模型不同而不同)
	CONFIG_FLATMEM
	CONFIG_DISCONTIGMEM
	CONFIG_SPARSEMEM_VMEMMAP
	CONFIG_SPARSEMEM
对虚拟内存的管理方法有4,我们关注以下过程
	直接映射区
	vmalloc 动态映射区 
	持久映射区 kmap 
	临时映射区 fixmap (kmap_atomic 临时内核映射)


注意 : 在运行时,
	物理内存的管理方法只有一种,配置哪种就是哪种
	虚拟内存的管理方法有4种

对于内存管理,我们关注
	// 1. 存放
	// 2. 申请
	// 3. 释放

level 1 物理内存的管理
  • 第一种物理内存管理 CONFIG_FLATMEM
1. 初始化
	配置了 CONFIG_FLAT_NODE_MEM_MAP 之后 pglist_data 结构体 中 才会有 node_mem_map 成员
	
	// 为所有的物理内存创建 struct page (每4KB创建一个)
	pg_data_t *pgdat = NODE_DATA(nid); // &contig_page_data
	struct page * map = memblock_alloc_node(size, SMP_CACHE_BYTES, pgdat->node_id);
	pgdat->node_mem_map = map + offset;
	
	
	reserve_bootmem_region
		// 设置 struct page 的 flags 成员
	__free_memory_core
		// 将 struct page 挂到 free_list 成员中
		// 此时 struct page 也在 node_mem_map  中
2. 申请
	get_page_from_freelist
3. 释放
	add_to_free_list
level 1 虚拟内存的管理
  • 第一种 线性映射/直接映射区
1.初始化
	map_lowmem
2.申请/获取
	page_to_virt(page)
	page_address(page);
3.释放
	不需要释放
特点
	1.线性映射关系,管理简单
	2.唯一的lowmemory 映射的区域
	3.映射一旦完成,系统运行期间不会改变.其他的4种都会改变
应用场景
	TODO
  • 第二种 vmalloc 动态映射区
1. 初始化
	vmalloc_init
2. 申请
	__alloc_vmap_area(size, align, vstart, vend);
3. 释放
	va = __find_vmap_area((unsigned long)addr);
	free_unmap_vmap_area(va);
特点
	1.最灵活,其他区不能满足的需求,都由该区满足
	2.返回的虚拟地址空间是连续的(4K 4K的连续)
	3.地址范围固定,VMALLOC_START - VMALLOC_END
应用场景
	TODO
  • 第三种 持久映射区 kmap
1. 初始化
	pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE), PKMAP_BASE, _PAGE_KERNEL_TABLE);
2. 申请
	vaddr = map_new_virtual(page); 
		vaddr = PKMAP_ADDR(last_pkmap_nr);
		set_pte_at(&init_mm, vaddr, &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));
3. 释放
	vaddr = (unsigned long)page_address(page);
	nr = PKMAP_NR(vaddr);
	// 此时有一个等待队列,不知道干啥的
	
特点
	1.一次只能映射一页
	2.可能会引起睡眠
应用场景
	TODO
  • 第四种 临时映射区 fixmap (kmap_atomic)
1. 初始化
	early_pte_alloc(pmd_off_k(FIXADDR_START), FIXADDR_START, _PAGE_KERNEL_TABLE);
2. 申请
	idx = arch_kmap_local_map_idx(kmap_local_idx_push(), pfn);
	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
	pteval = pfn_pte(pfn, prot);
	arch_kmap_local_set_pte(&init_mm, vaddr, kmap_pte - idx, pteval);
3. 释放
	idx = arch_kmap_local_unmap_idx(kmap_local_idx(), addr);
	pte_clear(&init_mm, addr, kmap_pte - idx);

特点
	1. 返回的虚拟地址是固定的,FIXADDR_TOP_START - FIXADDR_TOP 中 偏移量 为 FIX_KMAP_BEGIN - FIX_KMAP_END 的 区间
	2. 每个cpu都有属于自己的临时映射区,大小为 KM_TYPE_NR * 4KB
	3. 临时映射区的区间很小,管理简单
	4. 寻找到空闲的虚拟空间的速度快
	5. 不会睡眠
	6. 临时映射区的使用是有限制的,映射使用完成后必须马上去除映射.// 因为映射中调用 preempt_disable 关闭了内核抢占
应用场景
	TODO
  • 第五种 VMA
1. 初始化
	
2. 申请
	addr = get_unmapped_area(file, addr, len, pgoff, flags);
3. 释放
	vma = find_vma(mm, start); // 类似于 vmalloc 的 va = __find_vmap_area((unsigned long)addr);
	// unmap_region(mm, vma, prev, start, end);
	remove_vma_list(mm, vma); // 类似于 vmalloc 的 free_unmap_vmap_area(va);
	
特点
	1.只有这一种能用于 进程用户空间虚拟地址的管理
	2.地址范围在 0x0000 0000 - 0xC000 0000
应用场景
	TODO
level2 内存管理的实现
在处理 用户需求(申请内存),要处理
	1. 物理内存的申请
	2. 虚拟内存的申请

实现有 buddy vmalloc , 这些实现 是 对 level1虚拟内存的管理 level1物理内存的管理 的封装


在内核配置一定的基础上, buddy管理了 运行时的物理内存管理
	配置 管理了 物理内存 // 设置了管理内存的方式
	buddy 针对这些配置 实现了 不同的 物理内存管理,但在运行时,只有一种 物理内存管理,即 配置确定后的buddy
	
buddy很奇怪,封装了如下,但并不是简单的封装 level1
	第一种 物理内存的管理
		// 管理的物理内存来自于 buddy 管理的 所有的ZONE的 struct page
	没有封装 虚拟内存的管理


buddy 提供的api中
	alloc_pages/alloc_page 				封装了物理内存的管理,没有封装虚拟内存的管理
	__get_free_pages/__get_free_page   	封装了物理内存的管理,并封装了虚拟内存的管理 
		// 通过 page_address(page);封装了 虚拟内存的管理
		// __get_free_page() 分配的是物理地址,而返回的则是虚拟地址(虽然这听上去有些别扭)

可以这么说:
	buddy 实现了对物理内存的管理,并没有实现对虚拟内存的管理
	但在buddy输出的api里面,有些api封装了对虚拟内存的管理
	
但是我们一般说 buddy 管理的仅仅是物理内存,而不包括虚拟内存
vmalloc 封装了
	第一种 物理内存的管理
		// 管理的物理内存来自于 buddy 管理的 ZONE_HIGHMEM 中的 struct page
		// 每次只申请一个 page ,所以 申请出来的多块内存不连续
	第二种 虚拟内存的管理


slab 是 很特殊的,不是 这几种合成的产物
	物理内存的管理
		// 在 buddy(不带封装虚拟内存的buddy)的基础上,将struct page 分成几块 来管理
		// kmalloc会根据申请的大小来选择基于slub分配器或者基于Buddy System来申请连续的物理内存
		// 基于 slub 分配的话, 一个 对象 小于 4KB , 所以在 4KB 内 物理内存是连续的
		// 基于 buddy 分配的化, 由于一次申请多个 4KB块, 所以如果申请成功,则 多个4KB块内 是连续的
	第一种虚拟内存的管理
		// 通过 page_address(page);封装了 虚拟内存的管理 ??? 没有找到代码

kmalloc 基于 slab

其他
  • 物理内存管理还是虚拟内存管理
buddy 属于 物理内存管理还是虚拟内存管理
	物理内存管理

物理内存是什么 : 
	内存中所有的页框
	
物理内存怎么管理
	1个页框 对应 一个 struct page  结构体 , 存储 在 mem_map 数组中.
	
	
	物理地址 在 struct page 中的 体现
		体现在 struct page 的 地址上 : page_to_phys(page)
	
	// 虽然这里说的是物理内存的管理,但是alloc返回的却是虚拟地址.
	// 查找 struct page 对应的 虚拟地址 由 page_address 提供实现
	虚拟地址 在 struct page 中的 体现
		如果是低端内存,体现在 struct page 的 地址上 : page_to_virt(page)
		
		// 高端内存 建立映射的方法有三种,为什么只在 一种(kmap) 中 找 虚拟地址
		如果是高端内存,体现在 在 持久内核映射kmap机制 建立的 数据结构 中查找
			如果之前做了映射(pam->page = page),返回  pam->virtual
			如果之前没做映射,返回 NULL.


虚拟内存是什么
	0G-3G 用户空间
		每个用户进程 有一个
		映射是怎么做的?
		映射关系是怎么保存的?
	3G-4G 内核空间
		内核/用户进程内核态/内核线程 共用一个
		
		分类:
			低端内存
				虚拟地址 C000 0000 - EF80 0000 线性映射 物理地址 (0-760MB) 0000 0000 - 2F80 0000
				映射在页表中,映射关系保存在哪里
			高端内存
				虚拟地址 EF80 0000 - FFFF FFFF (264MB)动态映射 物理地址 (760M-4G)2F80 0000 - FFFF FFFF
				映射在表中(三种机制建立的),映射关系保存在哪里?
					需要在 建立页表的过程中,需要追代码来看映射关系.
					
					1. 持久内核映射 : page_address_htable
					2. 临时内核映射 : 每个cpu有几个?
					3. 非连续内存分配 : 

虚拟内存怎么管理
	

  • 物理内存和虚拟内存的管理
内存的管理

	物理内存管理原理
	// 物理内存 的关系(phy_addr与page)由 固定 一次函数关系 来描述
	// 不同(可选的有四种)的 模型 , 有不同的 函数关系
	// 在 CONFIG_FLATMEM 模型下,函数关系如下
	// phy_addr = (addr_of(page) - addr_of(mem_map) + ARCH_PFN_OFFSET) << PAGE_SHIFT
	// mem_map 为 一个  固定值
	// ARCH_PFN_OFFSET =  __pv_phys_pfn_offset
	
	物理内存管理实现
		1. buddy
			物理地址 在 struct page 中的 体现
				体现在 struct page 的 地址上 : page_to_phys(page)
		2. slab
			slab 没有 对物理内存的管理,完全是 基于 buddy // TODO,基于buddy的物理内存管理,将物理内存管理粒度变的更小
		3. vmalloc
			vmalloc 没有 对物理内存的管理,完全是 基于 buddy
	
	虚拟内存管理原理
	// 虚拟内存 由 以下四种管理
	// 直接映射区								低端内存
	// vmalloc 动态映射区 					内存连续
	// 持久映射区 kmap 						进程空间
	// 临时映射区 基于fixmap (kmap_atomic) 	不会睡眠/快速`
	
	虚拟内存:低端内存实现
		1. buddy
			虚拟地址 在 struct page 中的 体现
				如果是低端内存,体现在 struct page 的 地址上 : page_to_virt(page)	//直接映射区
		2. slab
			slab 没有对虚拟内存的管理,完全是基于 buddy
		3. vmalloc
			在这个维度不存在
	虚拟内存:高端内存实现
		1. buddy
			如果是高端内存,在 持久内核映射kmap机制 建立的 数据结构 page_address_htable 中查找 到的 pam->virtual 变量 体现 // 持久映射区
				如果之前做了映射(pam->page = page),返回  pam->virtual
				如果之前没做映射,返回 NULL.
		2. slab
			slab 没有对虚拟内存的管理,完全是基于 buddy
		3. vmalloc // vmalloc 动态映射区
			虚拟地址在 struct vmap_area 结构体 中的 va_start 成员 体现
			struct vmap_area 结构体被挂载到 vmap_area_root和vmap_area_list
  • 内存模型 对 物理内存管理 的 影响
内存模型
	https://zhuanlan.zhihu.com/p/220068494


#define page_to_pfn __page_to_pfn
#define page_to_phys(page)  (__pfn_to_phys(page_to_pfn(page)))

不同的 memory_model 下 函数关系 不同 , 存在有4个模型,选一个即可



CONFIG_FLATMEM

	#define __page_to_pfn(page)	((unsigned long)((page) - mem_map) + \
					 ARCH_PFN_OFFSET)

CONFIG_DISCONTIGMEM
	#define __page_to_pfn(pg)						\
	({	const struct page *__pg = (pg);					\
		struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg));	\
		(unsigned long)(__pg - __pgdat->node_mem_map) +			\
		 __pgdat->node_start_pfn;					\
	})

CONFIG_SPARSEMEM_VMEMMAP
	#define __page_to_pfn(page)	(unsigned long)((page) - vmemmap)

CONFIG_SPARSEMEM

	#define __page_to_pfn(pg)					\
	({	const struct page *__pg = (pg);				\
		int __sec = page_to_section(__pg);			\
		(unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec)));	\
	})


物理虚拟内存管理实现1:buddy的实现
能直接用 用 alloc_pages 从 ZONE_DMA/ZONE_NORMAL 	返回 struct page
	并能通过 page_to_phys(page) 得到 虚拟地址
能直接  用 alloc_pages 从 ZONE_HIGHMEM 			返回 struct page
	不能通过 page_to_phys(page) 得到 虚拟地址
	因为 page_to_phys(page) 只支持 低端内存(虚拟内存概念) 对应的 物理页
	
	通过 查找 几种方法(A) 建立的映射关系
		如果 查找了映射关系,则返回虚拟地址
		如果 没查到映射关系,则返回NULL
	

此时可以有 几种方法(A) 建立映射
	1. 持久内核映射	: kmap/kunmap				: 利用了与 fixmap 同时建立的 pkmap_page_table // page_address_htable // https://blog.csdn.net/u011011827/article/details/116916526
		// 一级页表 在 0x50007xxx 	
		// 二级页表 在 &(pkmap_page_table[last_pkmap_nr]) // // pkmap_page_table = early_pte_alloc(pmd_off_k(PKMAP_BASE)
		// 虚拟地址 在 memory layout 的 PKMAP 区域 , PKMAP 区域 在 配置了 CONFIG_HIGHMEM 之后 才会存在 ,低于0xc000 0000
		// 虚拟地址范围 PKMAP_BASE - PKMAP_BASE+ LAST_PKMAP*4K
	2. 临时内核映射	: kmap_atomic/kunmap_atomic	: 利用了 fixmap
		// 一级页表 在 0x50007xxx
		// 二级页表 在 kmap_pte - idx  // pte_t *kmap_pte = kmap_get_pte(); // virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
		// 虚拟地址 在 memory layout 的 fixmap 区域
		// 虚拟地址范围 FIXADDR_TOP_START - FIXADDR_TOP
	3. 非连续内存分配	: vmap/vunmap				: 是 vmalloc 相关的函数
		// 一级页表 在 0x50007xxx
		// 二级页表 在 pte = pte_alloc_kernel_track(pmd, addr, mask);
		// 虚拟地址 在 memory layout 的 vmalloc 区域
		// 虚拟地址范围 VMALLOC_START - VMALLOC_END

		// map_kernel_range -> map_kernel_range_noflush -> vmap_p4d_range -> vmap_pud_range -> vmap_pmd_range

		//	vmap_pmd_range
		//		pmd_alloc_track
		//			// 申请写入的 一级页表的地址 (位于 0x50007xxx)
		//		vmap_pte_range
		//			// 处理二级页表
		//	vmap_pte_range
		//		pte_alloc_kernel_track
		//			// 申请写入的 二级页表的地址
		//			// 写入一级页表
		//		set_pte_at
		//			// 写入二级页表

		// 二级页表的申请
		// pte_alloc_kernel_track
			__pte_alloc_kernel
				pte_alloc_one_kernel
					__pte_alloc_one_kernel
						__get_free_page(GFP_PGTABLE_KERNEL);
				pmd_populate_kernel
					__pmd_populate
						pmdp[0] = __pmd(pmdval);
						pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));

虚拟内存管理机制的区别
虚拟内存管理机制分为两大类
	1. linux运行时用的内存管理机制
		vmalloc
			原型:void *vmalloc(unsigned long size);
			虚拟地址 : VMALLOC_START - VMALLOC_END
			典型地址 : vmalloc : 0xf0000000 - 0xff000000   ( 240 MB) // 在arm32-vexpress 平台
			虚拟地址范围 : 0M-1G 范围内,典型为几百M
			特点 : 
				1.可能睡眠 
				2.不需要马上释放 
				3.申请前不需要做准备 
				4.可以申请大于4K的空间,能达到100M 
				5.(需要做三件事) 
				6.返回地址 在 vmalloc 区内
				7.得到的物理地址4K间不连续,4K内连续
			应用场景:
				1.场景必须满足:非中断上下文
				2.场景必须满足:物理地址不必要连续
		kmap
			原型 : void *kmap(struct page *page);
			虚拟地址 : PKMAP_BASE 开始 // kmap_high 
			典型地址 : pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB) //在arm32 中 #define PKMAP_BASE      (PAGE_OFFSET - PMD_SIZE) // 0xc000 0000 - 0x20 0000 = 0xbfe0 0000
			典型地址 : arch/x86/include/asm/pgtable_32_areas.h:42:# define VMALLOC_END  (PKMAP_BASE - 2 * PAGE_SIZE)
			虚拟地址范围 : arm32为 5124KB
			特点 : 
				1.可能睡眠 
				2.不需要马上释放 
				3.申请前需要准备page 
				4.只能申请4K的空间 
				5.(需要做一件事) 
				6.返回地址 在 pkmap 区内
			应用场景:
				1.场景必须满足: 非中断上下文 
				2.场景必须满足: 已经有一个page了,而现在要访问这个page

		kmap_atomic
			原型 : void *kmap_atomic(struct page *page);
			虚拟地址 : fixmap 中的 FIX_KMAP_BEGIN // __kmap_local_pfn_prot
			典型地址 : fixmap  : 0xffc00000 - 0xfff00000   (3072 kB) 中的 FIX_KMAP_BEGIN
			虚拟地址范围 : arm32为 (13 * cpu_number)4KB
			特点 : 
				1.不会睡眠 
				2.需要马上释放(因为申请的api带加锁,所以需要尽快用kunmap_atomic释放锁) 
				3.申请前需要准备page 
				4.只能申请4K的空间 
				5. 更快(需要做一件事) 
				6.返回地址 在 fixmap 区的 FIX_KMAP_BEGIN   内
			应用场景:
				1.场景必须满足: 可以在中断上下文使用,也可以在进程上下文中使用 
				2.场景必须满足: 已经有一个page了,而现在要访问这个page
				3.场景必须满足: 使用一般是访问一次,访问一次后 就释放
	2. linux启动时用的内存管理机制 // 此时内存管理基址还没完全建立
		1. fixmap 永久
			原型1 : void __iomem * __init earlycon_map(resource_size_t paddr, size_t size);
			原型2 :
			虚拟地址 : fixmap 中的 FIX_EARLYCON_MEM_BASE
			典型地址 : fixmap  : 0xffc00000 - 0xfff00000   (3072 kB) 中的 FIX_EARLYCON_MEM_BASE
			虚拟地址范围 : 对于console来说,14KB ; 对于 dtb 来说,?4KB 
			特点 : 
				1.不会睡眠(TODO) 
				2.不需要释放 
				3.申请前需要准备物理地址 
				4.能申请大于4K的空间,但还是比较小 
				5.(需要做一件事) 
				6.对于earlycon来说,返回地址 在 fixmap 区的 FIX_EARLYCON_MEM_BASE 内
			应用场景:
				1.场景必须满足: 在启动时
				2.场景必须满足: 必须是 earlycon 或者 fdt 或者 ... 中 的 一种
		2. fixmap 临时
			原型 : void __init __iomem * early_ioremap(resource_size_t phys_addr, unsigned long size)
			虚拟地址 : fixmap 中的 FIX_BTMAPS_SLOTS
			典型地址 : fixmap  : 0xffc00000 - 0xfff00000   (3072 kB) 中的 FIX_BTMAPS_SLOTS
			虚拟地址范围 : ?4KB 
			特点 : 
				1.不会睡眠(TODO) 
				2.使用完可尽快主动释放,就算不释放也会被early_fixmap_shutdown 释放 
				3.申请前需要准备物理地址 
				4.能申请大于4K的空间,但还是比较小 
				5.(需要做一件事) 
				6.返回地址 在 fixmap 区的 FIX_BTMAPS_SLOTS 内
			应用场景:
				1.场景必须满足: 在启动时
				2.场景必须满足: 没有必要 是 earlycon 或者 fdt 或者 ... 中 的 一种,但是 earlycon 也可以使用这种内存申请方式
				3.场景必须满足: 做好映射页表被clear的准备,在内核运行时不会再去访问映射得到的虚拟地址
  • fixed_addresses & 三种 虚拟内存管理机制
enum fixed_addresses {
	FIX_EARLYCON_MEM_BASE,
	__end_of_permanent_fixed_addresses,

	FIX_KMAP_BEGIN = __end_of_permanent_fixed_addresses,
	FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_MAX_IDX * NR_CPUS) - 1,

	/* Support writing RO kernel text via kprobes, jump labels, etc. */
	FIX_TEXT_POKE0,
	FIX_TEXT_POKE1,

	__end_of_fixmap_region,

	/*
	 * Share the kmap() region with early_ioremap(): this is guaranteed
	 * not to clash since early_ioremap() is only available before
	 * paging_init(), and kmap() only after.
	 */
#define NR_FIX_BTMAPS		32
#define FIX_BTMAPS_SLOTS	7
#define TOTAL_FIX_BTMAPS	(NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)

	FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
	FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
	__end_of_early_ioremap_region
};

fixmap 地址从上到下
	fixmap 永久  : FIX_EARLYCON_MEM_BASE
	kmap_atomic  : FIX_KMAP_BEGIN  - FIX_KMAP_END
	fixmap 临时  : FIX_BTMAP_BEGIN - FIX_BTMAP_END

可见 , "fixmap 永久" kmap_atomic  "fixmap 临时" 都是基于 fixmap 的

------------------

fixed_addresses  中的成员 为 index , 我们要将 index 转换为 虚拟地址,可通过
#define __fix_to_virt(x)    (FIXADDR_TOP - ((x) << PAGE_SHIFT))

  • vmalloc机制与内核高端内存映射机制 与 fixmap(固定映射) 的关系与区别

vmalloc
	vmalloc机制可用于高端内存的临时映射,这里的临时是说,32位系统下,虚拟内存的数量比物理内存的数量小。
	
	vmalloc:什么都没有,可以用vmalloc申请,申请的可以大于2M,甚至可以100M。 特点:慢,需要做物理内存和虚拟内存申请和映射三件事;地址空间大,返回的地址在那VMALLOC(一般大于100M)空间内
	以上两者:kmap过程中可能会睡眠,vmalloc也可能会
kmap
	
	
	kmap可用于高端内存的永久映射,永久是相对于kmap_atomic来说的。
	kmap有512个页表,一个映射4k字节,也就是512*4K,2M的映射空间
	kmap_atomic有13*cpu_number个页表,能映射的空间一般比kmap小
	
	kmap映射的空间,用的页表,是不能被别人占用的。自己将其解除映射后,别人才能申请到。
	kmap_atomic是这么设计的, A申请了一个页表a,A还没释放,B也可以申请a。对于一个页表a来说,A和B不管他是否被占用,直接把自己的内容放进去。但这样会造成静态。所以AB申请a的时候自带对a的加锁,因为所以A申请到a后,得尽快释放a
	
	kmap_atomic用的的FIX_KMAP_BEGIN,基于fixmap
	kmap用的是PKMAP_BASE空间,和fixmap没关系
	
	kmap:以page为输入,可以用kmap申请,申请的为4K,不可更大。
		特点:快,需要做映射一件事。地址空间小,返回的地址就在那2M内。
	以上两者:kmap过程中可能会睡眠,vmalloc也可能会
	
	kmap_atomic,不会睡眠,以page为输入。申请的为4K,特点,快,只需要映射,比kmap还快。地址空间小,比kmap还小

fixmap
	是用来在内存没有完全建立的时候做映射用的
	做完映射的一部分(临时)被清理,一部分保留
	被清理的是公共使用的,被保留的都是私有模块在用的
	私有模块有几种
		dtb
		earlycon
	公共的提供接口early_ioremap
	
	fixmap 的应用时机是启动时(内存机制还没完全建立),虚拟地址是固定(编译时固定)的。空间比较小,物理地址是使用模块(消费者)确定的,映射是使用过程中建立的。分为临时(会被系统启动过程中的shutdown关闭),永久(可以系统启动完成后继续使用)
	
		

fixmap(固定映射)	
	临时的 : 在系统启动过程early_fixmap_shutdown中,创建的映射关系(pte)被会清0
		temporary-fix-map
		temporary fixed address
		在 fixed_addresses 枚举体 中  0 - __end_of_permanent_fixed_addresses 
		例如 FIX_EARLYCON_MEM_BASE 对应的 earlycon / early_ioremap 
			// 有人说 FIX_EARLYCON_MEM_BASE 属于 permanent fixed address
			// 但是 实验结果是 earlycon 做的映射 在 early_fixmap_shutdown 中被 清0 了
	永久的 : 创建好的不会被清0
		permanent-fix-map
		permanent fixed address
		在 fixed_addresses 枚举体 中 __end_of_permanent_fixed_addresses - __end_of_fixed_addresses(__end_of_fixmap_region/或__end_of_early_ioremap_region 哪个大是哪个)
		例如 FIX_KMAP_BEGIN/FIX_KMAP_END

内核高端内存映射机制
	临时的 : 
		kmap_atomic 不会阻塞
		临时映射,一个cpu core只能建立16个映射,一般建立后用完会马上清除,因为空间不够
		基于 fixmap 的 FIX_KMAP_BEGIN/FIX_KMAP_END
		返回地址 : FIXADDR_START - FIXADDR_TOP

		有人把这种方式 成为 固定映射(fixmap) 
		固定映射和临时映射不能等同,严格来说临时映射只是固定映射的一段FIX_KMAP_BEGIN到FIX_KMAP_END区间

	永久/持久的 : 
		persisent-kernel-mapping
		kmap 会阻塞,不能用在中断处理函数和可延迟函数
		长期映射,不会因为空间不够而清0 原来建立的,可以建立很多映射
		基于 与fixmap 几乎同时创建的 pkmap_page_table
		返回地址: PKMAP_BASE - FIXADDR_START
	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值