实战 | 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内存。0x200000
)开始建立页表映射,只有对物理内存建立了页表映射,后面才能访问这些内存。而kernel加载地址前面的2M内存(即0x0 - 0x200000
)将被kernel忽略,不会对这2M内存建立页表,即kernel无法访问这2M内存。
在QEMU上RISC-V Linux的启动信息:

但opensbi实际不需要使用2M这么大的范围,默认是512KB
,opensbi的pmp会保护这512KB
内存,不让其他程序访问。

因此在Kernel和opensbi之间会存在1.5M
但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往前挪,从而利用前面的内存。setup_vm()
函数中,将原来的二级页表改为三级页表,这样kernel入口地址只需要4K对齐,因此就能将kernel往前挪,从而利用前面的内存。
修改代码
路径:arch/riscv/mm/init.c
修改代码

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的页表映射由二级页表改为三级页表:


//定义三个PTE pte_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); }

总结
RISC-V Linux入口地址2M对齐的操作目前还没看到有人解释,不过应该就是为了给opensbi预留2M,于是kernel只建立了二级页表,使得入口地址必须2M对齐。对这部分内存的优化解决方案,目前也还没人给出,希望本文的优化方案能够帮助到有些人,也希望能够给大家一些启发。
以上是实战 | RISC-V Linux入口地址2M预留内存优化的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Linux内核作为操作系统的核心部分,承担着管理硬件资源、提供系统调用等重要功能。本文将深入探讨Linux内核的五大部分,包括进程管理、文件系统、网络通信、设备驱动和内存管理,并提供详细的介绍和代码示例。一、进程管理进程的创建在Linux内核中,进程的创建通过fork()系统调用来实现。下面是一个简单的示例代码:#include

上篇分析了RISC-V Linux启动的页表创建,提到RISC-V Linux入口地址必须2M对齐,今天讲讲如何解决2M对齐的问题,或者说如何优化部分内存。

篇幅长,技术内容多,点击关注不走散。序言:了解Linux内核一个计算机系统是一个硬件和软件的共生体,它们相互依赖,不可分割。计算机的硬件linux内核移植步骤,富含外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的缸体。并且没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部份:储存管理、CPU和进程管理、文件系统、设备管理和驱动、网络通讯linux论坛,以及系

尊敬的读者们,您好!在此,我有幸与您分享我作为资深网络工程师,以其专业的技术在Linux内核TCP协议栈的研发及优化工作中所积累下的宝贵经验与技巧。相信通过此文,我们能互相学习、探讨,为对该领域有着浓厚兴趣或正在进行相关工作的你们带来实际且有益的参考资料。1.TCP连接建立TCP连接建立乃是TCP协议栈关键事务,然而面临诸多连接问题并不少见。经过深思熟虑及详细调试,我挖掘出一些普遍存在且实用的问题及其解决方案,包括防范SYN洪泛攻击(可透过调整系统参数)及应对网络拥塞(亦即运用TCPFastOp

这是一个深度探索Linux内核源代码分布的关于1500字的文章。因为篇幅有限,我们将重点介绍Linux内核源代码的组织结构,并提供一些具体的代码示例,以帮助读者更好地理解。Linux内核是一个开源的操作系统内核,其源代码托管在GitHub上。整个Linux内核源代码分布非常庞大,包含了几十万行代码,涉及到多个不同的子系统和模块。要深入了解Linux内核源代码

论述了Linux内核在计算机操作系统中发挥重要作用的观点linux内核设计和实现,通过深入解析Linux内核设计及实际应用,揭示了它在该领域的显着地位和影响力量。 1.优化的内存管理通过采用虚拟内存管理技术,Linux内核能高效率地完成内存分配与回收。在置换页面算法帮助下linux内核设计和实现,精确处理物理内存至虚拟内存之间的映射关系。依据应用程序具体需求,实现可动调整,从而提升了整个系统性能表现。 2.强大的进程管理内核借助其卓越的多任务处理技术,使多个进程能够和谐共处于单一系统中。精心制定的进

安卓系统与Linux内核是息息相关的两个实体,它们之间的关系紧密而又复杂。在安卓系统中,Linux内核充当着重要的角色,为安卓系统提供了底层的硬件驱动和系统调用支持。本文将探讨安卓系统与Linux内核之间的关系,以及它们是如何交互、协同工作的,同时提供一些具体的代码示例。安卓系统是基于Linux内核开发的移动操作系统,主要用于智能手机、平板电脑等移动设备。L

Linux内核是操作系统的核心,它控制对系统资源(例如:CPU、I/O设备、物理内存和文件系统)的访问。在引导过程中以及系统运行时,内核会将各种消息写入内核环形缓冲区。这些消息包括有关系统操作的各种信息。
