启动文件,其实也就是裸机编程文件

关于这个问题,三种解决方法:

  • 自己找博客、github、技术手册等,看看a9的启动文件,然后买块a9的开发板,自己烧录下载,运行。缺点:需要买板子,而且没有好用的IDE支撑(虽然eclipse经过一定的配置后也能行),下载程序很困难(可能需要sd卡反复插拔),调试可能更困难了,还需要买个jlink调试器,还只能gdb命令行调试(当然也有一些gdb前端调试软件,比如ozone等)。我这个博客也有写这个windows上运行qemu仿真stm32板子a9板子实例_标biao的博客
  • Linux的bootloader,一般是uboot是最为通用的bootloader,里面就有这样的代码。缺点:太复杂,扒拉出来学习成本太高。嵌入式杂记(uboot启动流程,简单易懂!!!)_标biao的博客
  • 通过虚拟机qemu仿真a9板子。优点:程序的下载和调试都方便了;缺点:可能下载调试运行等操作比较慢,毕竟是仿真嘛,依赖于电脑性能。

三者我都尝试过,这里我建议选第三种方法吧。(而且我现在是在windows系统上搞这个,网上大部分教程都是在Ubuntu系统,对初学者不友好)

没必要重复造轮子,我们直接找现成的,国产嵌入式实时操作系统 rtthread 这方面就做得比较好,在各种处理器体系都有适配。

rtthread 官网:​​RT-Thread, RTOS, 物联网操作系统 - RT-Thread物联网操作系统​

  1. 去下载它们的免费IDE,RT-Thread Studio
  2. 新建一个基于开发板的项目,开发板选择 VExpress-A9,这个是arm官方做产品测试搞出来的开发板,这里是对它进行了qemu的模拟,还能看到启动qemu用了哪些命令,自己命令行就可以借鉴使用了。

    下载命令:
    qemu-system-arm.exe -M vexpress-a9 -nographic        -kernel Debug/rtthread.bin

    调试命令:
    qemu-system-arm.exe -M vexpress-a9 -nographic -S -s       -kernel Debug/rtthread.elf

    关于每个选项什么意思,大家自己百度一下吧。

    注:经过RT-Thread Studio的github主页介绍,以及我的测试,rthread确实只支持a9这个板子的qemu仿真模拟(而且只能是单核,尽管我们可以在debug设置界面设置为多核,调试就会报错了,其它的,比如stm32f4这些都不支持(虽然有些地方说支持,是假的)。究其原因,RT-Thread Studio后台调用的是qemu-system-arm.exe这个软件,而不是qemu-system-guneclipse.exe这个(可以参考我的博客qemu的详细资料大全(入门必看!!!)_标biao的博客)。
  3. arm cortex-a9的qemu仿真与启动文件解释_ide

  4. 傻瓜式的构建项目,下载,调试就行。这也说明这个IDE做得真不错
  5. 启动文件在这儿
  6. arm cortex-a9的qemu仿真与启动文件解释_嵌入式硬件_02


  7. a9的启动文件,rtthread封装得挺好,注释写得很清楚
    (1)设置处理器模式
    (2)设置FPU
    (3)设置一个栈
    (4)初始化bss段
    (5)设置是否适用多核的配置
    (6)设置mmu
    (7)跳入C语言函数

    自己可以打个断点,在这个IDE里调试运行一下,就全部明白了。

    同理其它处理器的启动文件如何搞(比如stm32,sparc等处理器的启动文件),也通过这个IDE新建工程就能看啦,但是不支持qemu仿真了。
_reset:
/* set the cpu to SVC32 mode and disable interrupt */
cps #Mode_SVC

#ifdef RT_USING_FPU
mov r4, #0xfffffff
mcr p15, 0, r4, c1, c0, 2
#endif

/* disable the data alignment check */
mrc p15, 0, r1, c1, c0, 0
bic r1, #(1<<1)
mcr p15, 0, r1, c1, c0, 0

/* setup stack */
bl stack_setup

/* clear .bss */
mov r0,#0 /* get a zero */
ldr r1,=__bss_start /* bss start */
ldr r2,=__bss_end /* bss end */

bss_loop:
cmp r1,r2 /* check if data to clear */
strlo r0,[r1],#4 /* clear 4 bytes */
blo bss_loop /* loop until done */

#ifdef RT_USING_SMP
mrc p15, 0, r1, c1, c0, 1
mov r0, #(1<<6)
orr r1, r0
mcr p15, 0, r1, c1, c0, 1 //enable smp
#endif

/* initialize the mmu table and enable mmu */
ldr r0, =platform_mem_desc
ldr r1, =platform_mem_desc_size
ldr r1, [r1]
bl rt_hw_init_mmu_table
bl rt_hw_mmu_init

/* call C++ constructors of global objects */
ldr r0, =__ctors_start__
ldr r1, =__ctors_end__

ctor_loop:
cmp r0, r1
beq ctor_end
ldr r2, [r0], #4
stmfd sp!, {r0-r1}
mov lr, pc
bx r2
ldmfd sp!, {r0-r1}
b ctor_loop
ctor_end:

/* start RT-Thread Kernel */
ldr pc, _rtthread_startup
_rtthread_startup:

/* 这里就是把rtthread_startup这个函数地址放在这儿了,实现上面的跳入C语言函数了 */
.word rtthread_startup