Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RK瑞芯微_Rockchip
GICV3
GIC
rt-thread 中添加cortex-a gicv3中断控制器代码
5.00
发布于 2021-05-09 22:33:59 浏览:1863
订阅该版
[tocm] ## 前言 * 最近有个活,需要验证ARM GICV3中断控制器的功能。GICV3是GIC的第三个版本,前面还有V1(已经弃用)、V2这些,GICV2一般用在32位处理器上,最多支持8个核心(ARM的一个CPU簇最多4个核,8核心一般是4+4的组合),这几年ARM在手机和服务器上发展很快,原来的GICV2已经不能满足需求了,所以GICV3横空出世。可能细心的小伙伴联想到了STM32的NVIC中断控制器,NVIC主要是针对单片机这种处理器,所有的外设中断都有一个地址,这个地址组成的表叫做中断向量表,cortex-a的GIC中也有这样一个向量表,只不过是针对不同异常模式的,所有的外设中断会进入到统一的异常入口,一般是IRQ或者FIQ这两个异常入口。 * 要验证就必须有板子,市面上好买的GICV3的板子只有瑞芯微的RK3399,其他Cortex-A72的板子用的是GICV2(可能是节约成本吧),这款芯片在2018年就已经铺货,小黄鱼上面便宜的才200出头,4+16的配置真香,想怎么玩就怎么玩。 ## 准备工作 * 开发板: Firefly-RK3399 (4+16) * 操作系统: rt-thread 在rtos验证会快很多,linux有点复杂。 * 编译器: [gcc-arm-10.2-2020.11-mingw-w64-i686-aarch64-none-elf](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads) 这是windos版本的编译器,rthread编译请使用bare-metal target这种版本,其他版本可能会报错。 * 瑞芯微工具:[开发板官网](https://www.t-firefly.com/doc/download/page/id/3.html) * 串口: TTL电平 1.5M波特率 * 数据线: type-c ## 代码理论基础 上面的是硬件和编译环境准备,到抡代码时候了,需要整点干货。rt-thread是一个rtos,不同于linux这种操作系统,跟rtos接近的是u-boot这种裸机程序,所以我们需要从u-boot中获取几个东西。 1. u-boot代码的链接地址0x200000,以此来替换rt-thread中的链接地址(使用的是树莓派4B那个bsp),这样编译后,烧写到u-boot代码的位置后就能启动了。 2. 串口外设寄存器地址,需要这打印输出,方便调试。 3. GIC中断控制器地址,这个每个厂家的CPU都不同,需要在代码中指定。 有了上面的几个东西,加入到代码中编译后,应该就能启动了。 ## 实战操作 * 复制一下树莓派4B的bsp raspi4-32改名为rk3399-32,打算在aarch32模式下开发,arm 64位处理器有aarch64与aarch32两种模式,其中aarch32是为了兼容32位。 * RK3399上电默认是aarch64模式,需要生成aarch64切换到aarch32的代码,这段代码我肯定想不出来,直接去u-boot撸过来,上干货。 ``` mrs x0, cnthctl_el2 // Counter-timer Hypervisor Control register orr x0, x0, #3 msr cnthctl_el2, x0 msr cntvoff_el2, xzr /* Initialize MPID/MPIDR registers */ mrs x0, midr_el1 mrs x1, mpidr_el1 msr vpidr_el2, x0 msr vmpidr_el2, x1 /* Disable coprocessor traps */ mov x0, #0x33ff msr cptr_el2, x0 /* Disable coprocessor traps to EL2 */ msr hstr_el2, xzr /* Disable coprocessor traps to EL2 */ mov x0, #3 << 20 msr cpacr_el1, x0 /* Enable FP/SIMD at EL1 */ /* Initialize HCR_EL2 */ mov x0, #(0 << 31) /* 32位模式为0,64模式为1*/ orr x0, x0, #(1 << 29) /* Disable HVC */ msr hcr_el2, x0 mrs x0, hcr_el2 mov x0, #0x800 movk x0, #0x30d0, lsl #16 msr sctlr_el1, x0 /* Return to AArch32 Supervisor mode */ mov x0, sp msr sp_el1, x0 /* Migrate SP */ mrs x0, vbar_el2 msr vbar_el1, x0 /* Migrate VBAR */ mov x0, #0x1d3 msr spsr_el2, x0 //这里是设置aarch32的spsr寄存器,很关键 adr x0, .aarch32_code //将aarch32_code的地址赋值给x0 msr elr_el2, x0 //将X0赋值给异常返回地址寄存器 eret // exception return. from EL2. continue from .aarch32_code .aarch32_code: .word 0xe3a00032 //这里是随便填,到时候用aarch32模式的汇编进行替换,目的是为了在aarhc64编译器下生成正确跳转指令 .word 0xe5820000 ``` 这段代码的作用是将处理器从el2切换到el1, elx是arm64的异常模式,其中el3是等级最高的,el0最低,os一般工作在el1模式。因为rk3339经ATF可信固件引导启动后就是el2模式,ATF固件大家可以查一下,我就不啰嗦了,这不是这篇文章的主题。切换模式一般是在从高等级切换到低等级时,现在要从el2的aarch64切换到el1的aarch32模式。相关手册`SysReg_xml_v87A-2020-12.pdf`请看网盘. * 修改编译器路径,树莓派4B 64位中的编译器用的是linux版本的,我个人还是喜欢在windows下开发,没办法顺手的工具太多。在文件rtconfig.py中,修改这两项实际的路径与名称,下面是根据我实际的情况修改. ``` EXEC_PATH = r'E:\Program Files (x86)\gcc-arm-10.2-2020.11-mingw-w64-i686-aarch64-none-elf\bin' PREFIX = 'aarch64-none-elf-' ``` * 将link.lds中的`. = 0x80000;`修改为u-boot中获取到的RK3399链接地址,不知道这个地址作用的,肯定使用MDK习惯了,被IDE毒害的程序猿。 ``` . = 0x200000; ``` * 在`libcpu\aarch64\cortex-a72\entry_point.S` 中添加上面的汇编代码,放到_start:的下面, 这样这段代码就在链接地址的最前面了。 ``` // This symbol is set to 0x80000 in ld script. That is the address that raspi3's firmware // loads 'kernel8.img' file in. _start: // enable CNTP for EL1 mrs x0, cnthctl_el2 // Counter-timer Hypervisor Control register orr x0, x0, #3 msr cnthctl_el2, x0 msr cntvoff_el2, xzr /* Initialize MPID/MPIDR registers */ mrs x0, midr_el1 mrs x1, mpidr_el1 msr vpidr_el2, x0 msr vmpidr_el2, x1 /* Disable coprocessor traps */ mov x0, #0x33ff msr cptr_el2, x0 /* Disable coprocessor traps to EL2 */ msr hstr_el2, xzr /* Disable coprocessor traps to EL2 */ mov x0, #3 << 20 msr cpacr_el1, x0 /* Enable FP/SIMD at EL1 */ /* Initialize HCR_EL2 */ mov x0, #(0 << 31) /* 32bit EL1 */ orr x0, x0, #(1 << 29) /* Disable HVC */ msr hcr_el2, x0 mrs x0, hcr_el2 mov x0, #0x800 movk x0, #0x30d0, lsl #16 msr sctlr_el1, x0 /* Return to AArch32 Supervisor mode */ mov x0, sp msr sp_el1, x0 /* Migrate SP */ mrs x0, vbar_el2 msr vbar_el1, x0 /* Migrate VBAR */ mov x0, #0x1d3 msr spsr_el2, x0 adr x0, .aarch32_code msr elr_el2, x0 eret // exception return. from EL2. continue from .L__in_el1 .aarch32_code: .word 0xe3a00032 .word 0xe5820000 // read cpu id, stop slave cores mrs x1, mpidr_el1 // MPIDR_EL1: Multi-Processor Affinity Register and x1, x1, #3 cbz x1, .L__cpu_0 // .L prefix is the local label in ELF ``` * 打开env,执行scons -c (换了工具链需要清除一下,避免干扰,然后在进行scons -j16(`我的cpu是锐龙3700x,16核心的编译贼带劲`). * 对rtthread.elf elf文件进行反汇编, 将elf文件移动到编译器的bin目录,打开shell,执行命令`.\aarch64-none-elf-objdump.exe -d .\rtthread.elf > .\rtthread.asm`,就可以得到以下汇编代码。 ``` 0000000000200000 <_start>: 200000: d53ce100 mrs x0, cnthctl_el2 200004: b2400400 orr x0, x0, #0x3 200008: d51ce100 msr cnthctl_el2, x0 20000c: d51ce07f msr cntvoff_el2, xzr 200010: d5380000 mrs x0, midr_el1 200014: d53800a1 mrs x1, mpidr_el1 200018: d51c0000 msr vpidr_el2, x0 20001c: d51c00a1 msr vmpidr_el2, x1 200020: d2867fe0 mov x0, #0x33ff // #13311 200024: d51c1140 msr cptr_el2, x0 200028: d51c117f msr hstr_el2, xzr 20002c: d2a00600 mov x0, #0x300000 // #3145728 200030: d5181040 msr cpacr_el1, x0 200034: d2800000 mov x0, #0x0 // #0 200038: b2630000 orr x0, x0, #0x20000000 20003c: d51c1100 msr hcr_el2, x0 200040: d53c1100 mrs x0, hcr_el2 200044: d2810000 mov x0, #0x800 // #2048 200048: f2a61a00 movk x0, #0x30d0, lsl #16 20004c: d5181000 msr sctlr_el1, x0 200050: 910003e0 mov x0, sp 200054: d51c4100 msr sp_el1, x0 200058: d53cc000 mrs x0, vbar_el2 20005c: d518c000 msr vbar_el1, x0 200060: d2803a60 mov x0, #0x1d3 // #467 200064: d51c4000 msr spsr_el2, x0 200068: 10000060 adr x0, 200074 <.aarch32_code> 20006c: d51c4020 msr elr_el2, x0 200070: d69f03e0 eret 0000000000200074 <.aarch32_code>: 200074: e3a00032 .word 0xe3a00032 //这些后面使用32位的汇编填充 200078: e5820000 .word 0xe5820000 //这些后面使用32位的汇编填充 ``` * 在rk3399-32中添加aarch64切换到aarch32的代码,因为32位编译器不能编译64位指令,以`.word`的形式插入,新建一个entry_point.S文件,填入一下内容,加入到代码中编译。 ``` .section ".text.entrypoint" .globl system_vectors @这个很重要,lds脚本中将这个段放在最开始的位置了 .word 0xd53ce100 @mrs x0, cnthctl_el2 .word 0xb2400400 @orr x0, x0, #0x3 .word 0xd51ce100 @msr cnthctl_el2, x0 .word 0xd51ce07f @msr cntvoff_el2, xzr .word 0xd5380000 @mrs x0, midr_el1 .word 0xd53800a1 @mrs x1, mpidr_el1 .word 0xd51c0000 @msr vpidr_el2, x0 .word 0xd51c00a1 @msr vmpidr_el2, x1 .word 0xd2867fe0 @mov x0, #0x33ff // #13311 .word 0xd51c1140 @msr cptr_el2, x0 .word 0xd51c117f @msr hstr_el2, xzr .word 0xd2a00600 @mov x0, #0x300000 // #3145728 .word 0xd5181040 @msr cpacr_el1, x0 .word 0xd2800000 @mov x0, #0x0 // #0 .word 0xb2630000 @orr x0, x0, #0x20000000 .word 0xd51c1100 @msr hcr_el2, x0 .word 0xd53c1100 @mrs x0, hcr_el2 .word 0xd2810000 @mov x0, #0x800 // #2048 .word 0xf2a61a00 @movk x0, #0x30d0, lsl #16 .word 0xd5181000 @msr sctlr_el1, x0 .word 0x910003e0 @mov x0, sp .word 0xd51c4100 @msr sp_el1, x0 .word 0xd53cc000 @mrs x0, vbar_el2 .word 0xd518c000 @msr vbar_el1, x0 .word 0xd2803a60 @mov x0, #0x1d3 // #467 .word 0xd51c4000 @msr spsr_el2, x0 .word 0x10000060 @adr x0, 200074 <_start> .word 0xd51c4020 @msr elr_el2, x0 .word 0xd69f03e0 @eret ldr pc, =system_vectors @执行aarch32的入口代码,这句汇编的地址正好是0x200074,aarch64从el2切换到el1后就能执行aarch32代码。 ``` * 修改rk3339-32 lds中的链接地址为`. = 0x200000;`,然后执行scons -j16编译,最后就生成可以在RK3399运行的32位代码,但是现在还远远不够,因为没有对接串口,啥都看不到,后面慢慢道来,休息一会, 后面再续。
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
小鳄鱼
rt-thread脑残粉
文章
8
回答
45
被采纳
7
关注TA
发私信
相关文章
1
GICV2 IGROUP 初始化
2
GIC 默认使用group0,需要处理器进入secure状态才可以访问么?
3
qemu-virt64-aarch64能不能支持gic-version3
4
rk3399移植遇到的问题
5
RK2108的ADC问题
6
RK2108的低功耗问题
7
RT-Thread系统休眠唤醒之后线程活动异常
8
在studio中建立rk3568的rt-thread工程?
9
RK3568的BSP 如何导入rthread-stduio
10
rk3568 rt-thread bsp 包中 ETH 驱动咨询
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部