Linux内核态的内存分配和内存映射的关系

在内存中,有两种资源。这两种资源都需要申请。

1. 物理内存空间
2. 虚拟地址

像分配内存函数kmalloc 和__get_free_page函数是在低端内存中分配物理内存空间,然后直接返回相对应的内核逻辑地址(低端内存都映射到内核逻辑地址上3G~4G)。

然而vmalloc函数是在高端内存中分配物理内存空间的,因为没有相对应的内核逻辑地址,所以需要再分配内核虚拟地址,然后修改页表,映射内核虚拟地址和物理内存空间,最后返回内核虚拟地址。

假设有一段物理内存是一个page结构数组,用于跟踪系统中的物理内存。设这段起始内存地址是START_ADDR。

struct page *mem_map = (struct page *)START_ADDR;

假如某个struct page *page指针指向这个page结构数组中的某个元素,则可以通过 page – mem_map得到这个元素的下标。而下标跟物理内存页相关联,进而得到物理内存地址。
也就是说根据 struct page的地址,能找到这个page所代表物理页的地址。

kmap()是主要用在高端存储器页框的内核映射中,一般是这么使用的:

  • 使用alloc_pages()在高端存储器区得到struct page结构,然后调用kmap(struct *page)在内核地址空间PAGE_OFFSET+896M之后的地址空间中(PKMAP_BASE到FIXADDR_STAR)建立永久映射(如果page结构对应的是低端物理内存的页,该函数仅仅返回该页对应的虚拟地址)
  • kmap()也可能引起睡眠,所以不能用在中断和持有锁的代码中
  • 不过kmap 只能对一个物理页进行分配,所以尽量少用。

使用kmap的原因:

  • 对于高端物理内存(896M之后),并没有和内核地址空间建立一一对应的关系(即虚拟地址=物理地址+PAGE_OFFSET这样的关系),所以不能使用get_free_pages()这样的页分配器进行内存的分配,而必须使用alloc_pages()这样的伙伴系统算法的接口得到struct *page结构,然后将其映射到内核地址空间,注意这个时候映射后的地址并非和物理地址相差PAGE_OFFSET.

Leave a Reply

Your email address will not be published. Required fields are marked *