ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

arm64内存-fdt的映射和setup_machine_fdt

2022-03-26 19:31:54  阅读:240  来源: 互联网

标签:phys virt setup machine init fdt dt size


调用顺序

arch/arm64/kernel/setup.c

setup_arch -> setup_machine_fdt

setup_machine_fdt

 171static void __init setup_machine_fdt(phys_addr_t dt_phys)
 172{
 173        int size;
 174        void *dt_virt = fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL);
 175        const char *name;
 176
 177        if (dt_virt)
 178                memblock_reserve(dt_phys, size);
 179
 180        if (!dt_virt || !early_init_dt_scan(dt_virt)) {
 181                pr_crit("\n"
 182                        "Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
 183                        "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
 184                        "\nPlease check your bootloader.",
 185                        &dt_phys, dt_virt);
 186
 187                while (true)
 188                        cpu_relax();
 189        }
 190
 191        /* Early fixups are done, map the FDT as read-only now */
 192        fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
 193
 194        name = of_flat_dt_get_machine_name();
 195        if (!name)
 196                return;
 197
 198        pr_info("Machine model: %s\n", name);
 199        dump_stack_set_arch_desc("%s (DT)", name);
 200}
 201

 

174  使用fixmap_remap_fdt 在 arch/arm64/mm/mmu.c,  将物理地址 dt_phys 映射到虚拟地址 dt_virt , 并且 得到 fdt 的长度 size  (下面会有介绍)

177 ~ 178 如果映射成功,即 dt_virt 不为 0 , 使用memblock 模块的 reserve 函数,将  dt_phys 开始 size 大小的这块内存,在 memblock 模块中 预留下来。

180 在保证 dt_virt 不为0 的前提下面,调用 early_init_dt_scan ( dt_virt )   drivers/of/fdt.c 中, 给 fdt 模块填入输入 dt_virt ,并初始化fdt模块,后面就可以调用 fdt 模块的函数,从里面取属性了。 (下面会有介绍)

181 ~ 188 如果 early_init_dt_scan 返回false了,表示 dt_virt 指向区域的 设备树 格式有问题,报错。

192 将 dt_phys  开始 size 大小 的这块内存设置为 只读。

192 调用 fdt 模块的 函数,获取属性值, machine_name

199 给 dump stack 模块,设置 arch desc ,也就是 machine name 。

 

fixmap_remap_fdt

arch/arm64/mm/mmu.c

1265void *__init fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
1266{
1267        const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
1268        int offset;
1269        void *dt_virt;

1297        offset = dt_phys % SWAPPER_BLOCK_SIZE;
1298        dt_virt = (void *)dt_virt_base + offset;
1299
1300        /* map the first chunk so we can read the size from the header */
1301        create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
1302                        dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
1303
1304        if (fdt_magic(dt_virt) != FDT_MAGIC)
1305                return NULL;
1306
1307        *size = fdt_totalsize(dt_virt);
1308        if (*size > MAX_FDT_SIZE)
1309                return NULL;
1310
1311        if (offset + *size > SWAPPER_BLOCK_SIZE)
1312                create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
1313                               round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot);
1314
1315        return dt_virt;
1316}

1267 调用 fixmap 模块的函数,得到 FIX_FDT 这个 idx 对应的 VA 地址,放在dt_virt_base 里面。

1270 ~ 1296 跳过一些参数检查

1297  计算 dt_phys 这个物理地址,以  swapper_block 大小对齐后,在一个swapper_block 中的偏移。

1298 由 dt_virt_base 和 offset 得到 dt_phys 映射后的 VA 地址。 这个地址在 1307 行,作输入给fdt模块的 fdt_totalsize 函数使用,取得 设备树 占内存大小。 1315 行返回值。

 

1301 使用 create_mapping_noalloc 函数,建立 dt_virt_base 到  round_down ( dt_phys, SWAPPER_BLOCK_SIZE ) 之间的 映射关系。

        create_mapping_noalloc 函数 也在  arch/arm64/mm/mmu.c 中,是 static 声明,相当于一个 建立映射的 辅助函数。

        这个辅助函数会 修改 已经存在  (不会新建)  的 pgd pud pmd pte 表, 表里面的表项内容,完成 phys 和 virt 之间的映射。

        前提是 fixmap 模块,已经 初始化了,所以 fixmap start  ~  fixmap_top 这段 VA 地址 对应的 pgd pud pmd pte 表 都已经存在了。dt_virt_base 就是处在fixmap start  ~  fixmap_top 这段 VA 地址 之间。

         为什么使用 本模块中的 static 辅助函数,不使用 fixmap 模块的函数?

        各个软件模块  归根到底,都是为了管理 操作   设备; 各个软件模块都  都遵从     从设备读->算->写入设备 的方式,修改设备的状态即可,不必太多耦合,一个调用另外一个。

 

1034 ~ 1035 检查  fdt magic 标识。

 

1037~ 1039 取 size ,并对size 进行检查。

 

1311 ~ 1313 ,发现 offset + size 超过了 一个 swapper block 的大小,则需要映射后面的一个 swapper block ,这样,才能访问完整的 设备树。

 

early_init_dt_scan

drivers/of/fdt.c

1201bool __init early_init_dt_scan(void *params)
1202{
1203        bool status;
1204
1205        status = early_init_dt_verify(params);
1206        if (!status)
1207                return false;
1208
1209        early_init_dt_scan_nodes();
1210        return true;
1211}

1205  调用 early_init_dt_verify 进行 校验 检查, 检查失败,返回false

1209 调用 early_init_dt_scan_nodes 解析 设备树的节点。

 

标签:phys,virt,setup,machine,init,fdt,dt,size
来源: https://www.cnblogs.com/zhangzhiwei122/p/16060453.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有