上篇文章介绍了如何查看内核使用的分页模式,笔者电脑上内核使用的分页模式是 4-level paging,这篇文章讲解 4-level paging分页模式如何将线性地址转换成物理地址.
先思考2个问题:
- 内核初始化时,线性地址0xffffffff8220a000转换成物理地址是多少?
- 内核初始化时,线性地址0xffff88800220a000转换成物理地址是多少?
1. 4-level paging 转换过程
先看一张intel手册上的4-level paging 4KB大小的页的转换图

下面介绍这张图表达的内容:
2. cr3寄存器介绍
CR3寄存器又叫页目录基址寄存器(Page Directory Base Register, PDGR), CR3中存放着当前任务页表目录的物理地址.
3. 内核中线性地址和物理地址转换宏
下面代码使用内核中定义的宏打印物理地址,代码中的宏选自linux5.4.34 arch/x86/include/asm/page.h arch/x86/include/asm/page_64.h
#include <stdio.h>
#define __AC(X,Y) (X##Y)
#define _AC(X,Y) __AC(X,Y)
#define __PAGE_OFFSET_BASE_L4 _AC(0xffff888000000000, UL)
#define __PAGE_OFFSET __PAGE_OFFSET_BASE_L4
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
#define __START_KERNEL_map _AC(0xffffffff80000000, UL)
// __va宏是将物理地址转换成线性地址,直接等于物理地址 + 0xffff888000000000
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
static inline unsigned long __phys_addr_nodebug(unsigned long x)
{
unsigned long y = x - __START_KERNEL_map;
/* use the carry flag to determine if x was < __START_KERNEL_map */
// 笔者电脑上phys_base为0
x = y + ((x > y) ? 0 /* phys_base */ : (__START_KERNEL_map - PAGE_OFFSET));
return x;
}
#define __phys_addr(x) __phys_addr_nodebug(x)
#define __phys_addr_symbol(x) \
((unsigned long)(x) - __START_KERNEL_map + 0 /* phys_base */) // phys_base为0
#define __phys_reloc_hide(x) (x)
// __pa宏是将线性地址转换成物理地址
#define __pa

本文详细解释了内核4-levelpaging模式下,如何通过CR3寄存器、页目录索引和页表查找,将线性地址0xffffffff8220a000和0xffff88800220a000转换成物理地址0x220a000的过程,并揭示了转换规则和Intel手册中的关键细节。
最低0.47元/天 解锁文章
2514

被折叠的 条评论
为什么被折叠?



