上篇分析了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内存。0x200000
)开始建立页表映射,只有对物理内存建立了页表映射,后面才能访问这些内存。而kernel加载地址前面的2M内存(即0x0 - 0x200000
)将被kernel忽略,不会对这2M内存建立页表,即kernel无法访问这2M内存。
在QEMU上RISC-V Linux的启动信息:
但opensbi实际不需要使用2M这么大的范围,默认是512KB
,opensbi的pmp会保护这512KB
内存,不让其他程序访问。
因此在Kernel和opensbi之间会存在1.5M
512KB
,opensbi的pmp会保护这512KB
内存,不让其他程序访问。
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往前挪,从而利用前面的内存。setup_vm()
函数中,将原来的二级页表改为三级页表,这样kernel入口地址只需要4K对齐,因此就能将kernel往前挪,从而利用前面的内存。
路径:arch/riscv/mm/init.c
修改代码
注释原来的2M对齐检查:
对kernel的前2M页表映射由二级页表改为三级页表:
//新增一个PTE pte_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+
以上是实战 | RISC-V Linux入口地址2M预留内存优化的详细内容。更多信息请关注PHP中文网其他相关文章!