ARM仿真器-foxICE 设为首页   |   加入收藏夹   |   网站地图         
  站内搜索:
 
http://www.foxice.net
最新下载_foxICE
ARM7TDMI R3内核
ARM7EJS内核
ARM946E-S内核
ARM966E-S内核
ARM9TDMI内核
ARM940T内核
ARM指令集速查卡
ARM925T内核(TI925T)

更多 >> 

 技术专栏RSS订阅

   首页>技术专栏>Redboot >ARM Bootloader的实现 ---C和ASM混合编程

ARM Bootloader的实现 ---C和ASM混合编程

作者:Gavin Li ver 1  2  3  4  5  6

Cirrus Logic 的 clps7111~Ep9312 系列 ARM core 的 CPU 内置 128 字节的 boot 程序。这个 boot 程序为把操作系统下载到裸机提供了极大的方便。这样再焊接电路板之前不用把操作系统预先写入 Flash ,而且日后升级操作系统也非常方便。 这个 boot 程序的功能是:

1. 设置串行口的参数为: 9600 , 8N1 , No FlowControl 。
2. 然后送出一个 < 字符
3. 开始接收 2K 字节程序( Bootloader )
4. 送出一个 > 字符
5. 跳转去执行这 2K 的程序。

烧写操作系统的过程是 :
1. 连接 ARM target 的产性口和 PC 的串行口
ARM PC
RX ------------------- TX
TX ------------------- RX
GND ---------------- GND

2. 从 BOOT 程序引导 ARM target
3. 在 Windows NT4.0 的 console 中 , 设置串行口的参数 9600 8N1

C:>mode COM2: baud=9600 data=8 parity=n stop=1

4. 在 console 中把 bootloader 送到串行口。 /b 表示以二进制方式

C:>copy /b bootldr.bin COM1:

5. 在 console 中 , 根据 bootloader 的设置来调整串行口的参数 115200 8N1

C:>mode COM2: baud=115200 data=8 parity=n stop=1

6. 在 console 中把 vxworks image 送到串行口。 /b 表示以二进制方式

C:>copy /b vxworks COM1:

7. Power off ARM target ,设置其从 Flash 启动。

8. reboot ,进入 VxWorks

这 2K 字节的程序就是我们说的 ARM Bootloader ,它的任务一般是:

1. 必要的硬件初始化
2. 从串行口接收 VxWorks 的二进制文件,并写入 Flash
3. 在这过程中,显示一些提示信息。
像 Bootloader 这样底层的程序一般认为是要用纯汇编来写的。但是用汇编写的程序可读性肯定没有用C写的程序好。汇编程序不宜维护,没办法向其它类型的 CPU 去移植。这些方面 C 的程序是没有问题的! _

那么Bootloader能否用纯C语言去写呢?不可能。因为有些操作特殊寄存器的指令也是特殊指令,用C是实现不了的。有些功能用C也是不能实现的。用C不能作的有:
1. 操作 CP15 寄存器的指令
2. 中断使能
3. 堆栈地址的设定

所以,只要知道这几条汇编指令可以了,不必学习所有的汇编指令。是不是上手很快呀。下面来看看我们在Bootloader 中所用到的汇编部分:
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x 1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");

简单吧,比看几十K的汇编程序感觉好得多吧。也许你会问:硬件的初始化怎么办?那是要操作寄存器的。我说:看看这段 C 的代码:
*((DWORD*)(dwHardwareBase + HW1_SYSCON1)) = SYSCON1_VALUE;

明白了吧, ARM 中把寄存器映射在内存中了,就跟读写内存没有区别。现在编写程序的问题已经全部解决了,但是否就没有问题了呢?不是。你的程序应该写成什么样呢?怎么编译生成二进制文件呢?让我们先写一个程序试一下吧:
#define DWORD unsigned int
int main(void)
{
register DWORD dwHardwareBase;
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x 1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");
dwHardwareBase = (DWORD)0x80000000;
return 0;
}

编译一下:
C:>ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc –static sam1.c
C:>ldarm -o sam1.out -Ttext 10000000 sam1.o
ldarm: warning: cannot find entry symbol _start; defaulting to 10000000
sam1.o(.text+0xc):fake: undefined reference to `__gccmain'
sam1.o(.text+0xc):fake: relocation truncated to fit: ARM_26 __gccmain
我们发现应该把 main 定义成 _start
#define DWORD unsigned int
void start(void) //gcc 需要把它定义成 _start , vxworks 的 egcs 要把它定义成 start 。
{
register DWORD dwHardwareBase;
asm ("_my_start:
mov r14, #0x70
mcr p15, 0, r14, c1, c0, 0 /* MMU disabled, 32 Bit mode, Little endian */
mrs r14, cpsr
bic r14, r14, #0x 1f /* Mask */
orr r14, r14, #0xc0 + 0x13 /* Diasble IRQ and FIQ, SVC32 Mode */
msr cpsr, r14
ldr r13, =0xc0020000 /* Setup Stack */
");
dwHardwareBase = (DWORD)0x80000000;
}

编译一下:
C:>ccarm -c -O2 -mcpu=arm710 -mlittle-endian -nostdlib -fvolatile -nostdinc –static
sam1.c
C:>ldarm -o sam1.out -Ttext 10000000 sam1.o
C:>objdumparm -d sam1.out > sam1.asm

1  2  3  4  5  6

立即下载:
点击下载
相关文档
 
下载说明:
  1. 未经本站明确许可,任何网站不得非法盗链及抄袭本站资源!
 

首页 | 产品介绍 | 技术支持 | 下载中心 | 技术专栏 | 关于我们 | 联系我们
电话:86-755-82798083   82796301   传真:86-755-82799007    Email:sales@foxice.net   sales6@foxice.net
在线咨询:QQ:346466907   MSN:sales6@foxice.net   ini3000@msn.com

© 2006 Foxice.net 版权所有