# 启用init\_level4\_pgt

内核启动阶段，使用的页表是early\_level4\_pgt。（有可能不是，大部分情况下是的。）

early\_level4\_pgt的设置可以看[head\_64.S设置的段页](http://blog.csdn.net/richardysteven/article/details/52629731#t16)

看这个名字就能猜出来，这个页表仅仅是初始的时候使用的。那什么时候内核第一次更改的呢？

## 成功上位

```
void __init init_mem_mapping(void)
{

	load_cr3(swapper_pg_dir);
	__flush_tlb_all();

}
```

然后呢？ 咱来做个实验吧～

给出补丁～ 4.7上的

```
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index 2ee7811..f6dc1ed 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -21,6 +21,7 @@ extern pmd_t level2_fixmap_pgt[512];
 extern pmd_t level2_ident_pgt[512];
 extern pte_t level1_fixmap_pgt[512];
 extern pgd_t init_level4_pgt[];
+extern pgd_t early_level4_pgt[];

 #define swapper_pg_dir init_level4_pgt

diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 372aad2..ba19480 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -577,7 +577,7 @@ static void __init memory_map_bottom_up(unsigned long map_start,

 void __init init_mem_mapping(void)
 {
-	unsigned long end;
+	unsigned long end, pgd;

 	probe_page_size_mask();

@@ -619,7 +619,13 @@ void __init init_mem_mapping(void)
 	early_ioremap_page_table_range_init();
 #endif

+	printk(KERN_ERR "%s: early_level4_pgt is %lx\n", __func__, __pa_symbol(early_level4_pgt ));
+	printk(KERN_ERR "%s: init_level4_pgt  is %lx\n", __func__, __pa_symbol(init_level4_pgt ));
+	pgd = read_cr3();
+	printk(KERN_ERR "%s: current cr3 is %lx\n", __func__, pgd);
 	load_cr3(swapper_pg_dir);
+	pgd = read_cr3();
+	printk(KERN_ERR "%s: cr3 is set  to %lx\n", __func__, pgd);
 	__flush_tlb_all();

 	early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
```

其实很简单，就是打印了一下early\_level4\_pgt, init\_level4\_pgt，用来对比一下cr3中，原有的值和更改后的值。

简单吧，然后看一下这次输出的结果，看看我们的猜想对不对～

```
[    0.000000] init_mem_mapping: early_level4_pgt is 1fca000
[    0.000000] init_mem_mapping: init_level4_pgt  is 1e06000

[    0.000000] init_mem_mapping: current cr3 is 1fca000
[    0.000000] init_mem_mapping: cr3 is set  to 1e06000
```

好了，内核页表切换完成。进入到init\_level4\_pgt统治的时代了。

## 补充细节

之前内核都是使用early\_level4\_pgt这个页表的，那和init\_level4\_pgt有什么关系呢？

来来看看这段代码。

```
asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
{
	...

	clear_page(init_level4_pgt);

	...

	/* set init_level4_pgt kernel high mapping*/
	init_level4_pgt[511] = early_level4_pgt[511];

	...
}
```

在这段代码中，init\_level4\_pgt\[511]设置成了early\_level4\_pgt一样的值。

好了这下清楚了，从本质上讲，这两个页表没有什么区别，本次的页表和之前的页表样子没有变。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://richardweiyang.gitbook.io/kernel-exploring/nei-cun-guan-li/00-evolution_of_kernel_pagetable/05-switch_to_init_level4_pgt.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
