linux内存管理(一)源码解析之内核虚拟内存布局

本文分析了基于linux-4.14.159和64bit架构的Linux内核内存管理,重点讨论内核虚拟地址空间。内容包括:内核虚拟地址空间的大小、KASAN内存错误检测工具、内核模块的虚拟地址空间、VMALLOC区域以及FIXADDR、PCI_IO和VMEMMAP的用途。通过对源码的解析,展示了ARM64架构下内核虚拟内存布局的细节,并与设备日志进行了对比验证。
摘要由CSDN通过智能技术生成

本文kernel代码分析基于以下
1.linux-4.14.159
2.64bit代码处理逻辑

linux内存管理非常复杂及庞大,这节我们看下内核虚拟内存布局,理解内核内存布局对认识内存管理至关重要,我们从源码来进行解析,这样通过理解记忆的话比较牢固。

在linux系统中,内核的虚拟地址空间对所有进程共享的,然而每一个进程存在自己的用户虚拟地址空间和共享的内核虚拟地址空间,此节我们仅研究内核虚拟地址空间。

arm v8架构可以支持32~48位的物理寻址,最大可以寻找256TB的物理地址空间,64位支持64位寻址,为什么最大48位呢?因为48位对目前的应用已经够用,就无需进行64位的物理寻址,太大势必会增加硬件的设计复杂度。

针对arm64的硬件体系结构,如果page大小位4KB,使用3级或4级转换表,内核虚拟地址空间支持39位(512G)或48位(256TB)的寻址空间。

先看地址空间大小:

arch\arm64\include\asm\memory.h
#define VA_BITS			(CONFIG_ARM64_VA_BITS)	

//.config中查看CONFIG_ARM64_VA_BITS=39,

VA_BITS虚拟地址宽度,最大支持48位,不同系统看具体配置的值。如我这边config中配置的时39位,即64位系统配置为39位,值为0x7F FFFF FFFF,这个换算过来即位512G。

0x0000_0000_0000_0000~0x0000_007f_ffff_ffff 512GB user
0xffff_ff80_0000_0000~0xffff_ffff_ffff_ffff 512GB kernel

如之前阐述,linux在arm架构上虚拟地址分位用户虚拟地址空间和内核虚拟地址空间这两个空间,如上每个空间支持512GB寻址。

内核虚拟地址空间起始地址

#define VA_START		(UL(0xffffffffffffffff) - \
	(UL(1) << VA_BITS) + 1)

//展开0xFFFF_FFFF_FFFF_FFFF-0x0000_0080_0000_0000+1=0xFFFF_FF80_0000_ 0000
//也就是说kernel虚拟地址空间起始地址为0xFFFF_FF80_0000_ 0000

内核线性映射的起始地址

#define PAGE_OFFSET		(UL(0xffffffffffffffff) - \
	(UL(1) << (VA_BITS - 1)) + 1)

///计算下来为0xFFFF_FFC0_0000_ 0000

KASAN和MODULE区域
KASAN(KernelAddressSANitizer)是一个动态检测内存错误的工具,主要解决use-after-free和out-of-bounds问题,其原理是利用额外的内存标记可用内存的状态。这部分额外的内存被称作shadow memory(影子区),KASAN将1/8的内存用作shadow memory,详细的内容请百度了解。

MODULE:是内核模块使用的虚拟地址空间,其大小为128MB

/*KIMAGE_VADDR - the virtual address of the start of the kernel image*/
#define KIMAGE_VADDR (MODULES_END)
#define MODULES_END (MODULES_VADDR + MODULES_VSIZE) 
#define MODULES_VADDR (VA_START + KASAN_SHADOW_SIZE)
// 0xFFFF_FF90 0000 0000
#define MODULES_VSIZE (SZ_128M)

#ifdef CONFIG_KASAN
#define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - 3)) 
// 0x10_0000_0000 :64G
#define KASAN_THREAD_SHIFT 1
#else

我们可以看到MODULES_VADDR ,等于VA_START + KASAN_SHADOW_SIZE,而KASAN_SHADOW_SIZE计算下来为64G,
因此MODULES_VADDR 地址为 0xFFFF_FF90 0000 0000
MODULES_END 地址为0xFFFF_FF90_0800_0000

///已确认的内存布局如下:
0xFFFF_FF80_0000_0000 ------ VA_START 

Kasan大小64G  

0xFFFF_FF90_0000_0000 ------ MODULES_VADDR 

MODULE大小为128M

0xFFFF_FF90_0800_0000 ------ MODULES_END 

64G为512G的1/8,因此符合kasan的定义。

再看VMALLOC区域
此区域为vmalloc函数使用的虚拟地址空间,注意因为linux kernel更新很快,笔者研究的代码kernel image映射区域已经从从原来的线性映射区域搬移到了VMALLOC区域

#define PUD_SIZE (_AC(1, UL) << PUD_SHIFT) 

#if CONFIG_PGTABLE_LEVELS > 3
#define PUD_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(1)
#endif

page_SHIFT=12 //(4K)
#define SZ_64K				0x00010000

#define ARM64_HW_PGTABLE_L
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值