linux 内核页表初始化源码分析2.4.22

一 静态页表初始化

空间布局

如下图,swapper_pg_dir 代表着一级页表,pg0,pg1,则是内核起始的两个pte页表,包含1~9m 的8m空间,存储内核镜像,
由于vmlinux 的编译基址址是PAGE_OFFSET + 1MiB,所以,这里这三个虚拟地址分别为

swapper_pg_dir:PAGE_OFFSET + 1MiB +0x1000
pg0:PAGE_OFFSET + 1MiB +0x2000
pg1:PAGE_OFFSET + 1MiB +0x3000
线性映射,物理地址 = 虚拟地址-PAGE_OFFSET
这里还有个empty_zero_page 紧随其后,用于存放boot 传递给内核的参数,

arch/i386/kernel/head.S
在这里插入图片描述
而内核映像 实际的位置从 text 才开始,即1m+0x5000

在这里插入图片描述

swapper_pg_dir页表的初始化

二.内核页表初始化

static void __init pagetable_init (void)
{
	unsigned long vaddr, end;
	pgd_t *pgd, *pgd_base;
	int i, j, k;
	pmd_t *pmd;
	pte_t *pte, *pte_base;

	/*
	 * This can be zero as well - no problem, in that case we exit
	 * the loops anyway due to the PTRS_PER_* conditions.
	 */
	end = (unsigned long)__va(max_low_pfn*PAGE_SIZE); //页表初始化范围,结束地址max_low_pfn,即低端内存结束地址

	pgd_base = swapper_pg_dir; //pgd一级页表基址
...
	i = __pgd_offset(PAGE_OFFSET);//页表初始化范围,起始地址,--page_offset 
	pgd = pgd_base + i;

	for (; i < PTRS_PER_PGD; pgd++, i++) {
		vaddr = i*PGDIR_SIZE;
		if (end && (vaddr >= end)) 
			break;
#if CONFIG_X86_PAE
		...
#else
		pmd = (pmd_t *)pgd; 
#endif
		if (pmd != pmd_offset(pgd, 0))
			BUG();
		for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
			vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
			if (end && (vaddr >= end))
				break;
...
			//从页帧分配一页用于pte 页表
			pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);

			for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
				vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
				if (end && (vaddr >= end))
					break;
				//设置pte页表项
				*pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
			}
			//设置pmd即pgd页表项
			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
			if (pte_base != pte_offset(pmd, 0))
				BUG();

		}
	}

	/*
	 * Fixed mappings, only the page table structure has to be
	 * created - mappings will be set by set_fixmap():
	 */
	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
	fixrange_init(vaddr, 0, pgd_base); //从vaddr 到最大空间结束(0)

#if CONFIG_HIGHMEM
	/*
	 * Permanent kmaps:
	 */
	vaddr = PKMAP_BASE;
	fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);//为highmmem 初始化页表结构,同样未建立页表映射(pte 页表项未设置)

	pgd = swapper_pg_dir + __pgd_offset(vaddr);
	pmd = pmd_offset(pgd, vaddr);
	pte = pte_offset(pmd, vaddr);
	pkmap_page_table = pte;//pte页表基址,最大1024 只需一页
#endif

...
}

fixrange_init

为fixrange 建立 gpd,和pmd页表,注意pte 页表并未建立


```c

static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
{
	pgd_t *pgd;
	pmd_t *pmd;
	pte_t *pte;
	int i, j;
	unsigned long vaddr;

	vaddr = start;//fixrange 的起始线性地址
	i = __pgd_offset(vaddr);
	j = __pmd_offset(vaddr);
	pgd = pgd_base + i;

	for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
#if CONFIG_X86_PAE
...
#else
		pmd = (pmd_t *)pgd;
#endif
		for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
			if (pmd_none(*pmd)) {
				pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
				set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
				if (pte != pte_offset(pmd, 0))
					BUG();
			}
			vaddr += PMD_SIZE;
		}
		j = 0;
	}
}






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值