qemu模拟armv7,裸机运行
学习armv7架构,freertos启动等
基于armv7的设备,在qemu下启动,裸机运行
2024.8.2更新,添加简单的启动,task调度代码
文章目录
文档资料
imx6ull 官方资料链接
Arm官方文档
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
ARM Cortex-A Series Programmer’s Guide for ARMv7-A
Arm A-profile Architecture Registers
Arm A-profile A32/T32 Instruction Set Architecture
Arm A-profile A64 Instruction Set Architecture
arm_compiler_user_guide_100748_6.22_00_en
Arm Architecture Reference Manual for A-profile architecture : (AArch64)
gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz
https://developer.arm.com/downloads/-/gnu-a
gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2
https://developer.arm.com/downloads/-/gnu-rm
qemu环境搭建
- qemu源码下载
- 100ask修改版qemu源码下载
- 100ask 6ullqemu
# 本文运行方式,使用官方的qemu也能正常运行,只使用imx6ull的功能
git clone https://e.coding.net/weidongshan/ubuntu-18.04_imx6ul_qemu_system.git
- 6ull裸机开发资料
git clone https://e.coding.net/weidongshan/01_all_series_quickstart.git
git clone https://e.coding.net/weidongshan/noos/cortexA7_windows_tools.git
git clone https://e.coding.net/weidongshan/hardware/doc_and_source_for_hardware.git
git clone https://e.coding.net/weidongshan/noos/doc_and_source_for_mcu_mpu.git
编译器下载
:arm-none-linux-gnueabihf
# ,用 aria2c 比 wget 实在是快太多了
https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-linux-gnueabihf.tar.xz
armv7架构
寄存器
异常处理
lr的地址调整:关于ARM的PC指针
疑问: armv7进入异常的时候根据规范描述是可以选择进入arm,或者thumb状态的?那么如果可以选择thumb编译的时候要按照thumb的格式编译
A3:Application Level Memory Model
三种属性的设备:
Normal
Device
Strongly-ordered
猜测:和 mmu,或者乱序执行有关?
General Timer
产生timer中断信号必须同时满足以下两个条件:
- CompareValue或者TimerValue计时时间到
- timer必须enable且是unmask
消除timer中断信号只需要满是下面的其中一个条件即可:
- 重新设置CompareValue或TimerValue寄存器,使其两个定时条件都不满足
- 使用timer掩码(CNTP_CTL.IMASK)
- 禁用timer(CNTP_CTL.ENABLE, 不再产出中断信号)
主要操作寄存器:
CNTFRQ:读取设置频率
CNTPCT:读取定时器的计数值(64位的)
CNTP_CTL:控制寄存器(是否使能屏蔽定时器中断,状态指示是否发生中断)
CNTP_CVAL:设置定时器的计时时间(64位,向上加)
用法如:setTimer(getSystemTick()+delayTick)
CNTP_TVAL:设置定时器的计时时间(32位有符号,向下减)
用法如:setTimer(delayTick)
Cortex A7
gic
中断源ID:
Software Generated Interrupts:0-15
Private Peripheral Interrupts:16-31
安全物理定时器ID:29
非安全物理定时器ID:30
Shared Peripheral Interrupts :32-1019,支持480个 (cortexa7,179)
特殊中断ID
GIC memory-map
Memory regions used for these registers must be marked as Device or Strongly-ordered in the translation tables.
Memory regions marked as Normal Memory cannot access any of the GIC registers, instead access caches or external memory as required
??
优先级:32级
GICC_BPR ->0,所有支持抢占,->7,所有非抢占模式
gic寄存器
0x000: RW: GICD_CTLR: 控制寄存器,是否使能 gic distributor
0x004: RO: GICD_TYPER: bit5-7,支持的cpu数量+1,bit0-4,gic支持的中断个数x32
0x008: RO: GICD_IIDR: bit24-31,ProductId,bit16-19,产品编号?bit12-15,revision num, [bit0-6,0x3b,bit7,0,bit8-11,0x4]
0x080: RW: GICD_IGROUPRn: 0,Group0,1,Group1, 0x080+(n>>5)<<2, n&0x1F
0x100: RW: GICD_ISENABLERn: 0,interrupt is disabled, 1,interrupt is enable; 写1->1
0x180: RW: GICD_ICENABLERn: 禁中断 0,disabled, 1,enabled; 写1->0
0x200: RW: GICD_ISPENDRn: 0,no pending,1,ppi/swi pending on this cpu, spi pending any cpu
写1, edge: inactive->pending; acitve->active and pending; pending->pending
level: inactive->pending; active->active and pending; pending->pending
0x280: RW: GICD_ICPENDRn: 0,no pending,1,ppi/swi pending on this cpu, spi pending any cpu
写1, edge: pending->inactive; active and pending->active
level: pending->inactive; active and pending->active ? todo
0x300: RW: GICD_ISACTIVERn: 0, not active, 1,active; 写1->1
0x380: RW: GICD_ICACTIVERn: 0, not active, 1,active; 写1->0
0x400: RW: GICD_IPRIORITYRn: 设置优先级 0, proiority0,1,2,3 0x400+(m>>2)<<2 (m&0x3)*8
0x800: RW: GICD_ITARGETSRn: 绑定cpu,0, target cpu, byte0,1,2,3, each byte:cpu/isr
GICD_ITARGETSR0-7,只读的(id0-31,swi中断)其他spi可写
0xc00: RW: GICD_ICFGRn: low,0,N-N,1,1-N; high, 0,level,1,edge 0xc00+(m>>4)*4 (m&0xf)*2
0xe00: RW: GICD_NSACRn: 0,no-secure
0xf00: RO:GICD_SGIR: 软件参数中断,bit24-25,0,CPUTargeList,1,其他cpu,2,to self,bit16-23,target cpu,bit-cpu;
bit15,0,SGIINTID,Group0,1,Group1;bit0-3,Interrupt id 0-15
0xf10: RW: GICD_CPENDSGIRn: byte0,1,2,3; 0,not pending, 1,pending; write 1, remove pending ?
0xf20: RW: GICD_SPENDSGIRn: byte0,1,2,3; 0,not pending, 1,pending; write 1, add pending ?
0x0000: RW: GICC_CTLR: bit0:0,禁用中断信号,1使能中断信号
0x0004: RW: GICC_PMR: 中断优先级掩码 bit0-7,bit0:128 bit0-1:64 bit0-2:32 bit0-3:16
0x0008: RW: GICC_BPR:中断group分割点 bit0-2
0x000c: RO: GICC_IAR: 响应的中断号,bit10-12,swi请求中断的cpu,bit0-9,中断id
0x0010:WO:GICC_EOIR:中断处理完成,bit10-12,同上,同上
0x0014: RO: GICC_RPR: bit0-7,当前运行的中断优先级
0x0018: RO: GICC_HPPIR: 最高pending的优先级,bit10-12,swi产生中断的cpu,bit0-9:最高pending中断id
0x001c: RW: GICC_ABPR:
0x0020: RO: GICC_AIAR:
0x0024: WO: GICC_AEOIR:
0x0028: RO: GICC_AHPPIR:
0x00d0: RW: GICC_APRn:
0x00e0: RW: GICC_NSAPRn:
0x00fc: RO: GICC_IIDR:读取productid, gic版本
0x1000:WO:GICC_DIR:
操作方法:
- GICD_TYPER:获取支持的中断信息
- GICD_ICENABLERn:禁止中断转发
- GICC_PMR:设置中断掩码
- GICC_BPR:设置group,Subpriority(0,全抢占,7,禁止抢占)
- GICD_CTLR:使能
- GICC_CTLR:使能
MMU相关
多核之间的操作全局变量的问题?
- 如何保证数据是最新的,手动刷缓存?
a . memory type中有三种概念,是不是把全局变量定位到device区域,就不需要考虑缓存的问题了 - 硬件支持,只要写全局变量,自动处理,用户无感?
arm寄存器
cpsr
N, bit[31] Negative condition flag.
Z, bit[30] Zero condition flag.
C, bit[29] Carry condition flag.
V, bit[28] Overflow condition flag.
A, bit[8] Asynchronous abort mask bit.
I, bit[7] IRQ mask bit.
F, bit[6] FIQ mask bit.
0 Exception not masked.
1 Exception masked
T, bit[5] Thumb execution state bit
J T
0 0 ARM
0 1 Thubm
1 0 Jazelle
1 1 ThumbEE
M[4:0], bits[4:0] Mode field
User 10000
FIQ 10001
IRQ 10010
Supervisor 10011
Monitor 10110
Abort 10111
Hyp 11010
Undefined 11011
System 11111
汇编指令
c嵌汇编 ( Mixing C and assembly code )
__asm__ [__volatile__] ( assembler template
: [output operand list] /* optional */
: [input operand list] /* optional */
: [clobbered register list] /* optional */
);
伪指令
global:别的文件可以调用当前汇编文件里的函数
extern:当前汇编可以调用别的文件的函数
thumb: 指令来指明接下来的代码应以 Thumb 模式进行汇编
条件执行
A8.3 Conditional execution
msr
srs
rfe
编译链接
ARM链接脚本详解
linker script ld链接脚本语法简介
GCC Arm 12.2编译提示 LOAD segment with RWX permissions 警告
–start-group 和 --end-group 功能作用
做了哪些工作
- 设置异常向量表
- 设置模式下的sp,关mmu、icache、dcache
- 初始化gic(distribution,cpuifterface)
- 设置arch time
- 初始化串口
- 两个task进行任务切换,实现中。。。
qemu启动,task调度代码
- 使能arch timer
- 初始化 uart,支持printf打印
- 支持添加task,task循环调度,上下文切换,任务栈保存恢复
- 代码结构如下:代码见附件
tree
.
├── build.sh # 编译执行,可能需要调整编译器路径
├── CMakeLists.txt
├── lib
│ ├── gic.c
│ ├── gic.h
│ ├── timer.c
│ ├── timer.h
│ ├── uart.c
│ └── uart.h
├── out
├── qemu.sh # qemu执行脚本
└── src
├── link.ld
├── main.c
├── my_printf.c
├── my_printf.h
├── start.S
└── task_test.c
参考文章
在线脑图工具 processon
qemu嵌入式arm快速体验
QEMU imx6ul开发板环境搭建
百问网资料下载中心
uboot源码
qemu很老的例程
githbub文档语法
【从0学ARM】你不了解的ARM处理异常之道
记录问题
- armv7需要设置异常向量表,即 VBAR 寄存器
在上电reset_handler中调用svc #0无法调转swi_handler,所以才发现需要设置异常向量中断 - arm arch timer
每个核上的timer一直是在计数的,设置中断信号之后,要在中断函数中更新CompareValue或TimeValue的值 - 无法通过通过cp15读取gic基地址 ?, Configuration Base Address Register, (cortexa7,p137)
MRC p15, 4, <Rt>, c15, c0, 0; Read Configuration Base Address Register
- 读取cpuid,MPIDR
MRC p15, 0, <Rt>, c0, c0, 5; Read Multiprocessor Affinity Register
5. 调试阶段发现有些代码执行异常,比如c和汇编相互调用的时候,发现可能是armv7支持thumb造成的,-marm强制arm态
6. task栈切换
- task中添加uint64变量执行异常(Undefined_Handler)
分析汇编代码发现了vmov指令,在编译选项中添加 -mfpu=vfpv3解决,vfpv3和neon的区别是啥呢?
- arm编译器的区别
遇到编译链接问题,注意到编译器不一样,记录一下
9. c 函数库 (newlic 和 glic)
C 函数库 (libc,glibc,uClibc,newlib)
- 遇到一个编译很坑的问题,查了好久发现是 project enable_language 和 设置编译器,先后顺序导致的问题
此案例中,先设置project(IMX6ULL ASM C),后设置编译器即可解决问题
那么是如何发现的问题呢,因为我开始的时候用的是 arm-none-linux-gnueabihf-gcc 编译freertos,测试qemu启动,简单的task切换都没有问题,然后开始加入freertos源码,编译就出现一堆奇怪的问题(undefined reference __gcc_personality_v0 / __aeabi_unwind_cpp_pr0)等一大堆问题,先是问了人工智能改了一大圈也无果
后面我发现其他工程用的编译器是 arm-none-eabi-gcc(上述问题8), 换了之后直接报错 < is not able to compile a simple test program. undefined reference to `_exit’ >, 对我来说有是一个奇怪的问题
根据ai的回答,加上_exit函数也不行,后面我就用cmake写了一个最小编译环境,和我工程交叉测试发现了问题所在,不过根本原因也没深究,也可能只是碰巧解决了问题吧VERBOSE=1,编译详细日志
- CMAKE_EXE_LINKER_FLAGS_xxx 和 CMAKE_BUILD_TYPE
CMAKE_<LANG>_FLAGS_<CONFIG> , 测试发现 CMAKE_BUILD_TYPE (release,debug,或者自定义标签),会决定前面的<CONFIG>,
Cmake笔记
12. xxxx.c.obj 和 xxx.c.o 生成差异
CMAKE_SYSTEM_NAME 变量用于设置目标系统的操作系统。不同的操作系统通常有不同的编译工具链和库路径。通过设置 CMAKE_SYSTEM_NAME,你告诉CMake期望的目标系统是什么,这影响了CMake配置过程中的行为。例如:
Windows、Linux、Darwin(macOS)、Generic(通常用于裸机或嵌入式系统)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm) 测试设置之后会生成obj后缀文件
- gcc 链接 和 ld 链接异同点
- 安装的 arm-none-eabi-gdb 报错:libncurses.so.5: cannot open shared object file: No such file or directory
网上的答案 sudo apt install libncurses5* 搞定,不知道是不是我的最新ubuntu24的问题,找不到下载源,所有就手动下载安装
ubuntu lib库下载地址:https://packages.ubuntu.com/
http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncurses5_6.2-0ubuntu2.1_amd64.deb
http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.2-0ubuntu2.1_amd64.deb
版本:6.2-0ubuntu2.1, 架构:i386,amd6464位电脑只需要 amd64,旧的gdb版本需要libncurses5, Distribution选择any
- 基于imx6ull的sdk,在qemu上实现freertos,编译正常,运行的时候 portYIELD_WITHIN_API 这个就崩了,其实调用svc异常,主要分析定位异常原因
根本原因是问题1,未设置vbar寄存器,如何定位呢,
- 首先肯定可以定位到哪一行的代码执行异常
- 在执行异常代码的时候切换到汇编代码查看,可以分析异常原因,比如此异常时候,跳到了0x000000c8, 这个地址是不正常的(由汇编文件可以分析向量地址0x80002008),就能知道是哪里的异常了
- is not able to compile a simple test program
https://discourse.cmake.org/t/the-c-compiler-is-not-able-to-compile-a-simple-test-program-when-compiling-using-arm-gnu-toolchain/8215
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 即可
话说csdn的vip真的是x,质量还不行,哪里有其文章的平台
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)