通过memblock已经有了内存布局的信息,接下来就要完成内存的映射。映射的过程位于paging_init函数中
1. /*
2. * paging_init() sets up the page tables, initialises the zone memory
3. * maps and sets up the zero page.
4. */
5. void __init paging_init(void)
6. {
7. phys_addr_t pgd_phys = early_pgtable_alloc();
8. pgd_t *pgd = pgd_set_fixmap(pgd_phys);
9.
10. map_kernel(pgd);
11. map_mem(pgd);
12.
13. /*
14. * We want to reuse the original swapper_pg_dir so we don't have to
15. * communicate the new address to non-coherent secondaries in
16. * secondary_entry, and so cpu_switch_mm can generate the address with
17. * adrp+add rather than a load from some global variable.
18. *
19. * To do this we need to go via a temporary pgd.
20. */
21. cpu_replace_ttbr1(__va(pgd_phys));
22. memcpy(swapper_pg_dir, pgd, PGD_SIZE);
23. cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
24.
25. pgd_clear_fixmap();
26. memblock_free(pgd_phys, PAGE_SIZE);
27.
28. /*
29. * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
30. * allocated with it.
31. */
32. memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
33. SWAPPER_DIR_SIZE - PAGE_SIZE);
34. }
映射的过程如下图所示:
在map_kernel和map_mem中,最终都会通过__create_pgd_mapping将指定地址和大小进行一一映射,流程如下。
其实在dtb中映射中,最终也会走到__create_pgd_mapping,映射kernel和mem和映射dtb的区别在于,此时可以通过memblock模块进行物理内存的分配了,并且,这里我们又看到了fixmap的使用pte_set_fixmap,用来获取刚刚分配的物理地址对应的虚拟地址,然后对这个page清零,之后再解除这段映射。在系统映射的时候我们会看到很多类似的步骤,通过fixmap建立刚刚分配PGD/PMD/PTE对应的映射,使用完毕之后再解除映
35. static phys_addr_t __init early_pgtable_alloc(void)
36. {
37. phys_addr_t phys;
38. void *ptr;
39. /*****1****/
40. phys = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
41.
42. /*
43. * The FIX_{PGD,PUD,PMD} slots may be in active use, but the FIX_PTE
44. * slot will be free, so we can (ab)use the FIX_PTE slot to initialise
45. * any level of table.
46. */
47. /*****2*****
48. ptr = pte_set_fixmap(phys);
49. /******3****/
50. memset(ptr, 0, PAGE_SIZE);
51.
52. /*
53. * Implicit barriers also ensure the zeroed page is visible to the page
54. * table walker
55. */
56. /*****4*****/
57. pte_clear_fixmap();
58.
59. return phys;
60. }
- (1)分配4k大小区域
- (2)利用fixmap区域建立与刚分配的一块物理地址的映射
- (3)对分配的区域清零
- (4)解除映射