early_fixmap_init:
dtb进行映射,通过设备树文件和membloc模块让内核了解更为广阔的内存世界。Uboot将dtb拷贝到内存中,且通过传递相关参数将dtb的物理地址告知内核。但是内核必须将dtb的相关物理地址映射到虚拟地址上,通过虚拟地址间接访问dtb文件。由于此时物理地址映射并没有完成。为了解决该问题提出了fixed map机制。
内核访问DTB物理地址,先将DTB所在的物理地址映射到内核虚拟地址空间的Fixed map区域,然后通过该虚拟地址区域间接访问DTB文件。系统对dtb的大小有限制,不能大于2MB,这样要求主要是为了保证创建地址映射的时候不会分配其它的 translation table page(可以从setup_machine_fdt中有描述,必须要8字节对齐且不能超过2M)。该机制是通过early_fixmap_init函数来完成。
init/main.c中
start_kernel
--setup_arch
---early_fixmap_init
---early_ioremap_init
---setup_machine_fdt
---arm64_memblock_init
early_ioremap_init:

会调用early_ioremap_setup-->内核启动初期需要通过early_ioremap机制让设备寄存器对内存进行访问。一些硬件需要在内存管理系统运行起来之前就需要工作,内核采early_ioremap机制来映射内存给这些硬件驱动使用。并且这些硬件驱动在使用完early_ioremap的地址后需要尽快的释放掉这些内存,这样才能保证其他硬件模块继续使用。因此early_ioremap采用的是Fixed map的temporary fixmap段虚拟地址。ioremap的空间为7 * 256K的区域,保存在slot_vir[]数组中,当需要进行IO操作的时候,最终会调用到__early_ioremap函数,在该函数中去填充对应的pte entry,从而完成最终的虚拟地址和物理地址的映射。
setup_machine_fdt:
返回dtb所在的虚拟地址dt_virt void *dt_virt = fixmap_remap_fdt(dt_phys) fixmap_remap_fdt传入dtb所在的物理地址dt_phys返回其虚拟地址dt_virt,此时运行内核cpu已经开启了MMU。下面是其实现代码细节和调用流程:
1.//arc/arm64/mm/mmu.c2.void *__init fixmap_remap_fdt(phys_addr_t dt_phys)3.{4. void *dt_virt;5. int size;6. //完成fdt PTE表entry的内容填写,返回fdt起始虚拟地址dt_virt和空间大小size7. dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);8. if (!dt_virt)9. return NULL;10. /*把DTB所占的内存添加到memblock管理模块的reserve模块里,这样后续内存分配不会使用这段内存。在后面 11. *会使用memblock_free()把该内存释放 12. */13. memblock_reserve(dt_phys, size);14. return dt_virt;13.}1.//arc/arm64/mm/mmu.c2.void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)3.{//为dtb提供虚拟地址的base,静态定义事先预留15. const u64 dt_virt_base = __fix_to_virt(FIX_FDT);16. int offset; de17. void *dt_virt;18.19. BUILD_BUG_ON(MIN_FDT_ALIGN < 8);//检查物理地址的对齐,必须MIN_FDT_ALIGN对齐20. if (!dt_phys || dt_phys % MIN_FDT_ALIGN)21. return NULL;22. //检查虚拟地址的对齐,必须SZ_2M对齐23. BUILD_BUG_ON(dt_virt_base % SZ_2M);24. /* 25. *保证FDT所在的虚拟地址范围落在early_fixmap_init函数建立的PMD范围内以为在early_fixmap_init已经建 26. *立了PUD和PMD,不能让其额外浪费PMD内存 */27. BUILD_BUG_ON(__fix_to_virt(FIX_FDT_END) >> SWAPPER_TABLE_SHIFT !=28. __fix_to_virt(FIX_BTMAP_BEGIN) >> SWAPPER_TABLE_SHIFT);29. //物理地址偏移(2M空间范围,末尾21位)30. offset = dt_phys % SWAPPER_BLOCK_SIZE;31. //偏移后实际的虚拟地址32. dt_virt = (void *)dt_virt_base + offset;33.34. //根据提供的物理地址和虚拟地址设置页表的entry35. create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),dt_virt_base, SWAPPER_BLOCK_SIZE, prot);36.37. //根据实际的虚拟地址访问物理地址空间内容,即FDT文件内容,此处检测DTB文件首部内容是否是DTB魔数38. if (fdt_magic(dt_virt) != FDT_MAGIC)39. return NULL;40. //获取dtb文件大小41. *size = fdt_totalsize(dt_virt);42. //DTB大小不能超过2M43. if (*size > MAX_FDT_SIZE)44. return NULL;45. //如果dtb文件结尾的地址空间超过了上面建立的2M地址范围,需要紧接着再映射2M地址空间46. if (offset + *size > SWAPPER_BLOCK_SIZE)47. create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,48. round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot);50. return dt_virt;38.}
early_init_dt_scan
-----early_init_dt_verify(对dtb头进行检查) 使用crc校验 scripts/dtc/libfdt中
-----early_init_dt_scan_nodesof_scan_flat_dt:
of_scan_flat_dt对dtb里面的所有节点进行扫描,
//向系统注册该memory node内存区域,通过memblock_add完成添加
early_init_dt_add_memory_arch(base, size);
下一章节介绍设备驱动根据dts信息如何进行内存映射。











![[QT编程系列-3]:C++图形用户界面编程,QT框架快速入门培训 - 2- QT程序的运行框架:HelloWorld、常见控件、对象树原理](https://img-blog.csdnimg.cn/e216baa460f448a7b7c476831bbba6fa.png)
![[综述] Generative AI meets 3D: A Survey on Text-to-3D in AIGC Era](https://img-blog.csdnimg.cn/db18f97164fe45c3900d7eac95c7f2dc.png)






