自己写bootloader笔记2---start.S分析

1、框架

(1)关看门狗//对2440来说,看门狗一上电是打开的,不关掉过3秒会复位整个开发板

(2)设置时钟//2440一上电时运行频率是12M,所以要让它能运行更快点

(3)初始化SDRAM (重定位时用到)

(4)重定位(bootloader比较小时,在nor flash上运行就可以了。如果bootloader比较大,要把它重定位到SDRAM)

执行main(其它复杂功能的代码用C函数实现)


2、程序


#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))
#define MEM_CTL_BASE    0x48000000

//.text表示一个代码段

.text

//.global表示标号_start是全局标号

.global _start
_start:


/* 1. 关看门狗 */对2440来说,看门狗一上电是打开的,不关掉过3秒会复位整个开发板

//0x53000000是看门狗定时控制寄存器的地址,ldr是 伪汇编指令,把0x53000000这个地址值赋给r0寄存器。

ldr r0, =0x53000000

//把立即数0赋给r1寄存器

mov r1, #0

//把数据r1保存到地址为r0的内存单元

str r1, [r0]


/* 2. 设置时钟 */2440一上电时系统运行频率是12M,所以要让它能运行更快点

//0x4c000014是时钟分频控制寄存器的地址

ldr r0, =0x4c000014
mov r1, #0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
str r1, [r0]


/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
mrc p15, 0, r1, c1, c0, 0/* 读出控制寄存器 */ 
orr r1, r1, #0xc0000000/* 设置为“asynchronous bus mode” */
mcr p15, 0, r1, c1, c0, 0/* 写入控制寄存器 */


/* MPLLCON = S3C2440_MPLL_200MHZ */

//0x4c000004是MPLL配置寄存器的地址

对应的反汇编33f80024:e59f0084 ldrr0, [pc, #132]; 33f800b0 <sdram_config+0x38>

如果对于ldr伪汇编指令,0x4c000004这个数比较复杂,不能用mov指令表示,会吧这个数存在地址(pc + 132)处,也就是33f800b0处然后从(pc + 132)的存储器地址处取出数据,加载到寄存器r0中。

ldr r0, =0x4c000004


ldr r1, =S3C2440_MPLL_200MHZ
str r1, [r0]


/* 3. 初始化SDRAM */

//吧设置的SDRAM控制器的值赋给SDRAM的控制器里面去,MEM_CTL_BASE是控制器的基址

//MEM_CTL_BASE是控制器的基址,也就是 r0是控制器的基址

ldr r0, =MEM_CTL_BASE

//adr读取相对地址值,也就是r1是 sdram_config的当前地址 

adr r1, sdram_config     /* sdram_config的当前地址 */

//由于用作SDRAM控制器的寄存器有13个,且每个地址的值占4个字节,也就是r3是最后一个寄存器的地址的内容的尾部字节地址。

add r3, r0, #(13*4)

//这里1是局部标签,用于跳转

1:

//将地址为r1的内存单元数据读到r2中,然后r1+4

ldr r2, [r1], #4

//将r2的数据保存到地址为r0的内存单元中,然后r0+4

str r2, [r0], #4

//比较r0和r3的地址值

cmp r0, r3

/*

1: ;A
cmp r0, #0
beq 1f ; r0==0那么向前跳转到B处执行
bne 1b ; 否则向后跳转到A处执行
1: ;B

*/

bne 1b


/* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */

用C语言写代码要先设置栈,让栈指针指向一块空的内存,让其指向SDRAM的最高内存,栈是往下增长的

ldr sp, =0x34000000

//先调用nand flash的初始化函数,因为无论是nor flash启动还是nand flash启动,都会从nand flash读取内核到SDRAM

bl nand_init

传给C函数的参数r0 ,r1,r2

r0对应C函数的第一个参数src,是0地址(从nand flash的0地址或nor flash的0地址复制到SDRAM的链接地址)

mov r0, #0

r1对应dest,也就是链接地址,第一条指令_start的地址

ldr r1, =_start

r2对应len,也就是要拷贝的程序的长度,看链接脚本,_bss_start是bss端的起始地址,二进制文件的大小应为bss端的起始地址减去代码段的起始地址(链接地址)的值

ldr r2, =__bss_start

相当于r2=r2-r1

sub r2, r2, r1
把代码从nand flash 拷贝到SDRAM 

bl copy_code_to_sdram

//把bss段占用的内存清零

bl clear_bss

/* 5. 执行main */ 其他代码使用C函数(初始化nand flash,从nand flash把内核读到内存)

bl main是相对跳转,若从nand flash的0地址开始执行,跳转的时候不能调到SDRAM里面去,因为是根据当前指令地址PC,PC值实际的值是A+8(跳转指令处的地址是A,以当前指令bl的bit[23:0]找到main函数的偏差值,然后跳转到(PC值+偏差值)的地址。

连接寄存器r14(LR),用于保存返回地址,用于main函数执行完后返回

ldr lr, =halt

该指令是从内存中的某个位置(main)读出数据并赋给

PC,同样依

赖当前PC的值,但是偏移量是那个位置(main)的连接地址(运行时的地址),所以

以用它实现从Flash到RAM的程序跳转

把main函数的地址赋给PC ,跳转到main函数执行

ldr pc, =main

//进入死循环,防止程序跑飞

halt:
b halt

//sdram_config标号下是SDRAM的所有寄存器的值

sdram_config:
.long 0x22011110//BWSCON
.long 0x00000700//BANKCON0
.long 0x00000700//BANKCON1
.long 0x00000700//BANKCON2
.long 0x00000700//BANKCON3  
.long 0x00000700//BANKCON4
.long 0x00000700//BANKCON5
.long 0x00018005//BANKCON6
.long 0x00018005//BANKCON7
.long 0x008C04F4// REFRESH
.long 0x000000B1//BANKSIZE
.long 0x00000030//MRSRB6
.long 0x00000030//MRSRB7
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值