您好,欢迎访问一九零五行业门户网

实战 | RISC-V Linux入口地址2M预留内存优化

上篇分析了risc-v linux启动的页表创建,提到risc-v linux入口地址必须2m对齐,今天讲讲如何解决2m对齐的问题,或者说如何优化部分内存。
注意:本文基于linux5.10.111内核
内存占用分析 每颗芯片在出厂时,其bootrom就已经固化在芯片内部,假设bootrom的地址是0x0,即上电后,会从0x0地址处开始运行程序。
在启动risc-v linux之前,需要先运行opensbi,因此应该把opensbi放到地址0x0处,这样芯片上电后,就会从0x0地址处执行opensbi。在opensbi运行完后,会跳转到opensbi运行地址偏移2m的位置去执行下一级boot(这里下一级boot是kernel),即跳转到0x200000地址处运行kernel,因此应该把kernel放到内存的0x200000处。
内存分布示意图如下:
对于kernel来说,在启动时会从自己的kernel加载地址处(即0x200000)开始建立页表映射,只有对物理内存建立了页表映射,后面才能访问这些内存。而kernel加载地址前面的2m内存(即0x0 - 0x200000)将被kernel忽略,不会对这2m内存建立页表,即kernel无法访问这2m内存。
在qemu上risc-v linux的启动信息:
但opensbi实际不需要使用2m这么大的范围,默认是512kb,opensbi的pmp会保护这512kb内存,不让其他程序访问。
因此在kernel和opensbi之间会存在1.5m的内存空隙,并且这部分内存空隙没有程序使用,这就会造成内存浪费,那如何让kernel将前面的一部分内存也利用起来呢?
优化方案 对这2m内存的优化,有两种方案:
方案一:将opensbi放到内存的最后面,kernel入口地址仍然保持2m对齐。
方案二:opensbi仍然放到内存的起始位置,通过修改内核源码,解除2m对齐限制,即可将kernel地址往前挪。
方案一 我们将opensbi放到内存的最后面,kernel入口地址仍然保持2m对齐。
即kernel放到内存的最前面,opensbi放到后面:
例如kernel放到内存的0x0地址处,opensbi放到内存的0x10000000地址处。这样kernel前面就不会有预留内存,只不过这样需要修改bootrom的地址,将地址从0x0修改为0x0x10000000。这种方案只适合芯片还没出厂前,因为用户无法修改bootrom的地址,芯片出厂后,bootrom地址是固定的,假设bootrom地址为0x0,那么芯片上电后,就会从0x0开始运行程序,所以opensbi必须放到0x0地址处,这样必然kernel只能往后偏移2m。
方案二 我们也可以修改risc-v linux的内核源码,解除2m对齐的限制。我们只需要在setup_vm()函数中,将原来的二级页表改为三级页表,这样kernel入口地址只需要4k对齐,因此就能将kernel往前挪,从而利用前面的内存。
修改代码路径:arch/riscv/mm/init.c
注释原来的2m对齐检查:
对kernel的前2m页表映射由二级页表改为三级页表:
//新增一个ptepte_t trampoline_pte[ptrs_per_pte] __page_aligned_bss;create_pgd_mapping(trampoline_pg_dir,page_offset, (uintptr_t)trampoline_pmd,pgdir_size,page_table);create_pmd_mapping(trampoline_pmd,page_offset, (uintptr_t)trampoline_pte,pmd_size,page_table);end_va = page_offset + pmd_size;for (va = page_offset; va < end_va; va += page_size){ create_pte_mapping(trampoline_pte,page_offset, load_pa + (va - page_offset), page_size,page_kernel_exec);}
对整个kernel的页表映射由二级页表改为三级页表:
假设kernel大小为4m+
//定义三个ptepte_t load_sz_pte[ptrs_per_pte] __page_aligned_bss;pte_t load_sz_pte1[ptrs_per_pte] __page_aligned_bss;pte_t load_sz_pte2[ptrs_per_pte] __page_aligned_bss;//=======0-2m======create_pgd_mapping(early_pg_dir,page_offset, (uintptr_t)early_pmd,pgdir_size,page_table);create_pmd_mapping(early_pmd,page_offset, (uintptr_t)load_sz_pte,pmd_size,page_table);end_va = page_offset + pmd_size;for (va = page_offset; va < end_va; va += page_size){ create_pte_mapping(load_sz_pte,page_offset, load_pa + (va - page_offset), page_size,page_kernel_exec);}//=======2-4m==========create_pgd_mapping(early_pg_dir,page_offset + pmd_size, (uintptr_t)early_pmd,pgdir_size,page_table);create_pmd_mapping(early_pmd,page_offset, (uintptr_t)load_sz_pte1,pmd_size,page_table);end_va = page_offset + (pmd_size * 2);for (va = page_offset + pmd_size; va < end_va; va += page_size){ create_pte_mapping(load_sz_pte1,va, load_pa + (va - page_offset), page_size,page_kernel_exec);}//=======4-6m==========create_pgd_mapping(early_pg_dir,page_offset + (pmd_size*2), (uintptr_t)early_pmd,pgdir_size,page_table);create_pmd_mapping(early_pmd,page_offset, (uintptr_t)load_sz_pte2,pmd_size,page_table);end_va = page_offset + (pmd_size * 3);for (va = page_offset + (pmd_size*2); va < end_va; va += page_size){ create_pte_mapping(load_sz_pte2,va, load_pa + (va - page_offset), page_size,page_kernel_exec);}
通过以上的代码修改,就能将kernel入口地址往前挪1.5m,只给opensbi预留512kb,这样risc-v linux启动之后,可用物理内存就会增加。
总结 risc-v linux入口地址2m对齐的操作目前还没看到有人解释,不过应该就是为了给opensbi预留2m,于是kernel只建立了二级页表,使得入口地址必须2m对齐。对这部分内存的优化解决方案,目前也还没人给出,希望本文的优化方案能够帮助到有些人,也希望能够给大家一些启发。
以上就是实战 | risc-v linux入口地址2m预留内存优化的详细内容。
其它类似信息

推荐信息