ARMv8-A 那些事 - 使能MMU之后的一些怪事

By: Ailson Jack
Date: 2024.12.05
个人博客:http://www.only2fire.com/

微信公众号:嵌入式那些事

前述

前几年自己写的一个OS一直是运行在STM32等Cortex-M系列处理器上的,由于我对Cortex-A系列处理器不是很了解也没有将OS移植到Cortex-A系列处理器上。后面自己学习了ARMv7A指令集的一些知识,于是就将自己写的OS移植到了ZYNQ7020芯片上,算是熟悉了OS在ARMv7A架构处理器的移植过程,后面将lwip和fatfs移植到了OS中,丰富了OS的功能。

最近自己看了些ARMv8A指令集的一些知识,就考虑将OS移植到ARMv8A架构的处理器上,目前系统能够正常的运行到第一个任务,但是一使能MMU系统就挂了。因为启动MMU之后系统马上就挂了,也没法打印具体的错误信息,因此这个问题还是比较难排查的。

下面简单的记录下解决这些问题的过程,给遇到类似问题的伙伴一个排查方向吧。

怪事1:使能MMU导致系统死机

由于OS在使能MMU之后就死机了,无法通过打印关键寄存器知道死机的真实原因。这里我就换个方向排查,因为我的MMU代码在裸机下是能够正常工作的,我就只需要找出裸机和OS之间的差异,这里我主要排查3个方向:

  • 更换裸机的交叉编译器;
  • 对比OS的启动配置和裸机的启动配置;
  • 对比Makefile的配置;

更换裸机的交叉编译器

在将裸机的交叉编译器更换为OS使用的交叉编译器编译裸机代码之后,运行裸机镜像,在使能MMU之后,裸机的后续功能正常,暂时排除交叉编译器不一致的影响。

对比OS的启动配置和裸机的启动配置

对比汇编入口代码到调用MMU使能之间的一些关键寄存器配置,我这里主要对比了OS和裸机在启动过程中下述寄存器的值:

  • SCR_EL3
  • SPSR_EL3
  • HCR_EL2
  • SPSR_EL2
  • SCTLR_EL1

将裸机中上述寄存器的值配置得和OS一样,然后编译裸机代码,运行裸机镜像,在使能MMU之后,裸机的后续功能正常,暂时排除启动配置不一致的影响。

对比Makefile的配置

在更换裸机的交叉编译器和对比启动时的一些寄存器配置之后,裸机镜像都没有出现使能MMU之后就死机的问题,这个时候其实我也没有太多的思路了,想着这个问题与代码和编译器都没有关系了,那还有什么会造成这个问题呢。当时思考了下,还剩下Makefile和链接脚本没有去对比了,于是我对比了下OS和裸机的链接脚本,并没有太大的区别,那么只剩下对比Makefile的配置了。

通过对比Makefile,发现只要裸机的Makefile添加上-ffunction-sections编译选项之后,重新编译裸机代码,运行裸机镜像,使能MMU之后就会出现死机问题。

裸机链接脚本对代码段的描述如下:

/* text.boot代码段 */
_text_boot = .;
.text.boot : { *(.text.boot) }
_etext_boot = .;

/*
 * text代码段
 */
_text = .;
.text :
{
    *(.text)
}
_etext = .;

根据链接脚本的规则,所有的代码段应该都要在_text_boot_etext之间,没有添加-ffunction-sections编译选项时,所有的代码段也确实都在_text_boot_etext之间,_etext之后就是数据段了,如下图所示:

在这里插入图片描述
根据map文件可知,所有的函数都在.text段和.text.boot段。

添加-ffunction-sections编译选项之后,重新编译裸机代码,分析map文件发现_etext并不是代码段的结尾,如下图所示:

在这里插入图片描述
_etext之后还有以各个函数命名的代码段,包括使能MMU的函数也在_etext之后。然而在MMU配置时,设置代码段的范围为_text_boot_etext之间,MMU配置_etext之后的一段空间为数据段,此时由于使能MMU的函数在数据段了,因此一使能MMU程序就导致系统死机。

解决这个问题其实也比较简单了,不需要去掉-ffunction-sections编译选项,只需要修改下裸机链接脚本让代码段都处于_text_boot_etext之间,修改后的裸机链接脚本对代码段的描述如下:

/* text.boot代码段 */
_text_boot = .;
.text.boot : { *(.text.boot) }
_etext_boot = .;

/*
 * text代码段
 */
_text = .;
.text :
{
    /* 确保所有函数都在代码段 */
    *(.text*)
}
_etext = .;

此时重新编译裸机代码,所有的代码段都在_text_boot_etext之间了,使能MMU之后程序也能正常运行。

将OS中链接脚本修改之后,系统能够正常运行了,开心。

这个问题的根本原因还是在于链接脚本中对代码段范围的设定存在缺陷,导致本该处于代码段范围的函数,却被划到了数据段中。

怪事2:执行某个函数导致系统死机

在解决了怪事1之后,本以为OS能够正常的进行一些测试,没想到在调用某一个函数时出现系统死机,现象和怪事1一样,不过由于此时MMU已经正常工作了,OS的异常提示信息也给出了一些提示:大致意思就是指令异常,感觉还是MMU配置有些bug导致出现这个问题的。我将MMU配置的区间打印出来,MMU配置了3个区间,代码段,数据段和设备地址空间段:

va:0x00080000 pa:0x00080000 size:0x00007000 // 代码段
va:0x00086000 pa:0x00086000 size:0x1ff7a000 // 数据段
va:0xfe000000 pa:0xfe000000 size:0x02000000 // 设备地址空间

可以看出,代码段的0x860000x87000被重新配置成了数据段,调用处于该区间的函数时就会出现系统死机的情况。这个问题是代码段的结尾没有4KB对齐,而配置数据段时是以代码段的结尾作为数据段的起始地址,导致MMU配置时被划分到了数据段。分析map文件,也可以看出确实是调用了处于0x860000x87000代码段的armv8a_int_enable()函数之后,出现了异常信息:

在这里插入图片描述
这里有两个方法来解决这个问题(下面两个方法任选一个即可)。

方法1

修改链接脚本,将代码段的结尾进行4KB对齐,这样配置MMU时,数据段的起始地址就不会和代码段的结尾重合了。

修改后的链接脚本对代码段的描述如下:

/* text.boot代码段 */
_text_boot = .;
.text.boot : { *(.text.boot) }
_etext_boot = .;

/*
 * text代码段
 */
_text = .;
.text :
{
    /* 确保所有函数都在代码段 */
    *(.text*)
}
. = ALIGN(4096);
_etext = .;

修改链接脚本后,OS终于能够正常运行了,map文件对应如下:

在这里插入图片描述
_etext是0x87000,是4KB对齐的。

方法2

将链接脚本中数据段的起始地址进行4KB对齐,配置MMU的数据段空间时,以链接脚本中的数据段起始地址作为参数进行配置。

后记

-ffunction-sections编译选项介绍

查询了下-ffunction-sections编译选项的说明:GCC链接器的链接操作是以section作为最小的处理单元,只要一个section中的某个符号被引用,那么该section就会被链接进可执行程序。使用GCC编译代码时,可以使用-ffunction-sections-fdata-sections将每个函数或者符号生成为一个section,每个section名与function或data名保持一致。在链接阶段,-Wl,--gc-sections链接选项指示链接器将没有使用到的section去掉,从而减小最终可执行程序的大小。

我们可以使用下面的编译链接选项来启用section优化功能:

C_FLAGS += -ffunction-sections -fdata-sections
LD_FLAGS += -Wl,--gc-sections

欢迎关注博主的公众号(微信搜索公众号:嵌入式那些事),可以扫描下面的公众号二维码:

在这里插入图片描述
如果文中有什么问题欢迎指正,毕竟博主的水平有限。

如果这篇文章对你有帮助,记得点赞和关注博主就行了^_^。

欢迎关注博主的博客和微信公众号。

注:转载请注明出处,谢谢!^_^

# 学习对象在全民造车、造芯的大时代,在努力去解决卡脖子的时代,ASIC硬件、SOC底层软件、Linux Kernel等操作系统软件(内核/驱动)、软硬件方面的系统架构师等的岗位需求也越来越明显,社会一直都是非常缺人的,缺的是核心的那一小撮、领头的那一小撮,社会所缺的更是能够软硬件融合的那一小撮人……总之,要想在这个时代,站稳自己的脚跟,能够在大公司或行业上拥有一席之地,就必需深入学习底层技术原理,核心技术才是您的看家本领。本课程设计之初,主要针对SOC底层软件开发的者、系统开发者,或者励志成为这样的人。既适合资深/高级工程师来查缺补漏,又适合初级工程师入门。(理论上该课程和ASIC硬件电路设计无关,该课程偏软件,但实购买该课程的做ASIC的同学已然超过了15%)适用人群1、芯片开发者(包括底层软件、或做ASIC硬件的)。不限行业,例如车、云、物联网、移动端等领域;2、汽车行业开发者(主机厂、tier1、SOC厂家、各级供应商);3、嵌入式开发者、kernel开发者、驱动、软件工程师;4、学生。既适合学生从入门到精通,也适合资深工程师查缺补漏;您的收益:1、全体系的掌握ARMv8/ARMv9的核心知识点(ARM基础、异常中断GIC、MMU/Cache、architecture...);2、掌握ARM架构、掌握SOC架构、掌握常规IP(gic、smmu、timer、AXI/ACE/CHI、TZC400...);3、快速熟悉常规系统软件(bootrom、spl、ATF、TEE、bootloader、kernel...), Secureboot安全启动...4、技术水平提升N个level, 掌握快速的学习方法;# 学习什么在ARM蓬勃发展的年代,不仅仅涉及到物联网IOT、移动领域(如手机)、汽车电子领域,现在还涉及到PC、服务器的,简直就是各行各业。ARMv8出来已经有10年了,ARMv9也2年时间了。在技术不断更新迭代的背景下,此时再去学习十五年前的ARMv7、二十年前的ARMv5/v6显然不是明智的选择。本课程主要基于当前最新的架构,ARMv8的aarch64和ARMv9,如涉及具体的ARM Core IP主要还是以最新的ARM Core IP为主,软件架构也是以当前最主流的/未来所趋势的架构来讲解。以下也给大家列举初了一个ARM产品的timeline的总结(在本课程中有着大量的这种总结),从这张图中,您是可以清晰的看到本课程拥有独具一格的风格、拥有全网最新(且唯一)的资料总结或学习路线。# 本课程大纲和规划(课程持续更新中,课程总量统计:2022/10/02  当前是 61节课, 22小时)第一章:主要是快速学习: ARM简介、指令集、寄存器总结等。第二章:本系列视频的一大亮点,系统全面地讲解了arm异常中断gic等相关的软硬件知识,本人一直在倡导“学arm安全其实就是学arm架构,学arm架构其实就是学习arm的异常和中断”,异常中断是领着你进入架构的入门,是让你变成系统软硬件架构师的必走之路。第三章:安全专题,这也是本视频最核心的东西。因为你无论买书还是看博客等,你都很难找到讲解安全的教程,这里就是有和无的区别。本人系统的整理的安全的知识,带领你快速入门。第四章:mmu专题,透过务看本质的讲解,白话式的演讲。在所有模块中,mmu也算是相对较简单模块。相信人人听得懂,人人学得会。第五章:cache专题,一切追求实求是,不人云亦云,一切知识点都有迹可循,推翻了网络的很多观念。在众多模块中,cache算是一个比较难的模块。了解了cache后,才能算真正了解系统的软硬件架构。第六章:虚拟化,本人不擅长,会啥就随便讲点啥。(以后学会了再来补)第七章:architecture,就是零散和零碎的系统架构知识,如exclusive、arch timer、reset、系统启动、SOC设计、AMBA/AXI/ACE、DSU、WFE/WFI这样的。第八章: 新增的ARMv9 CCA/RME安全架构专题第九章:主要放置一些直播课。# 课程收益1、知道我学习什么,我要怎么去学习,从此之后有了一个明确的学习路线。2、认识一些共同目标的人,相互讨论问题,共同进步。勤学、共学、助学。3、ARM不再神秘,SOC不在神秘,让您短期内就能cover住全局4、熟悉ARM Architecture架构知识5、熟悉SOC架构知识6、熟悉主流的系统软件框架7、熟悉各项硬件原理和机制,如异常中断、MMU、cache、TLB、VMSA、Trustzone6、深入了解当前的系统架构、软硬件架构,能够看懂这些大家,将来也能够自己设计。7、熟悉系统的启动流程、Secureboot等8、熟悉各类标准和规范9、能够进入芯片厂商干活、能够在非芯片产生成为技术担当。10、学习资料的获取方法,会看11500多页的ARM手册,会看数以百计的ARM各项参考手册。 本课程会持续更新。也希望通过本课程的学习,能够让大家的ARMv8/ARMv9开发技术能有质的飞越,能找到自己心仪的工作。在购买之前,也建议大家看一看第一章第一节的课程介绍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackailson

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值