写一个简单的BootLoader(一)——Start.S分析笔记

韦东山嵌入式视频第三期,讲解了如何自己写一个简单的BootLoader。本篇是学习笔记,开发板是JZ2440:


一 什么是BootLoader?

装过系统的朋友应该知道在电脑的操作系统启动之前,需要先运行一个名为BIOS的程序,之后操作系统才开始启动。这个所谓的BIOS全称为“Basic Input Output System”,是“基本输入输出系统”的意思。它保存着计算机最重要的基本输入输出的程序、开机后自检程序和系统自启动程序。其主要功能是为计算机提供最底层的、最直接的硬件设置和控制。类似于PC的BIOS,在嵌入式设备中也有这样一个程序,这就是BootLoader了(PS:这个应该叫启动加载器吗?差不多是这个意思吧)。这个程序起到了初始化硬件和启动操作系统的作用。

二 Start.S分析笔记

在JZ2440中,一个最简单的BootLoader需要做这些工作——关看门狗、设置时钟、初始化SDRAM、重定位、为内核设置串口、从Flash中将内核读入内存、设置启动参数、跳转到内核。能够完成这些工作,就能够称得上是一个“最小型”的BootLoader。

关看门狗

    ldr r0, =0x53000000
    mov r1, #0
    str r1, [r0]

首先关看门狗,这个是常识,如果不关掉的话,就需要每隔一段时间喂狗,否则芯片就会复位。JZ2440的看门狗控制寄存器的地址是0x53000000,这个可以在芯片手册上查到,然后将每一位都置零就可以关闭了。

设置时钟

尽早设置时钟可以提高芯片的工作频率,虽然这个对于启动速度来说几乎没有什么影响,U-Boot中也没有将此步骤放在非常靠前的位置,但是强迫症韦老师还是将这一步骤放在前面。在这边也可以顺带将指令缓存ICACHE启动,这可以肉眼可见的幅度提高启动速度。

CLKDIVN寄存器

    ldr r0, =0x4c000014  
    //CLKDIVN寄存器的地址
    mov r1, #0x05;       
    //FCLK:HCLK:PCLK=1:4:8
    str r1, [r0]

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
    //HDIVN 是否是 0 ,这个条件主要判断的是 “FCLK:HCLK:PCLK=”。
    //当 HDIVN == 0 的时候,FCLK:HCLK:PCLK = 111 ,这就是
    //说,如果不是这个比例,HCLK和PCLK的频率就要降低,这个时候我们总
    //线上的频率和CPU的频率就不一样了,所以我们要把总线模式改为异步总
    //线模式
    mrc p15, 0, r1, c1, c0, 0       /* 读出控制寄存器 */ 
    orr r1, r1, #0xc0000000         /* 设置为“asynchronous bus mode” */
    mcr p15, 0, r1, c1, c0, 0       /* 写入控制寄存器 */

    //MPLLCON = S3C2440_MPLL_400MHZ
    //S3C2440_MPLL_400MHZ =
    //((0x5c<<12)|(0x01<<4)|(0x01))
    ldr r0, =0x4c000004
    ldr r1, =S3C2440_MPLL_400MHZ
    str r1, [r0]

    // 启动ICACHE
    mrc p15, 0, r0, c1, c0, 0   @ read control reg
    orr r0, r0, #(1<<12)
    mcr p15, 0, r0, c1, c0, 0   @ write it back
    //启动速度大幅度提升,大概提升两三倍的样子

初始化SDRAM

初试化SDRAM其实很简单,就是把13个寄存器设置好就可以了。

    ldr r0, =MEM_CTL_BASE   
    //SDRAM控制寄存器的起始地址
    adr r1, sdram_config 
    //(sdram_config)的当前地址
    add r3, r0, #(13*4)    
    //r3=r0+52,之所以为13,是因为有13个控制寄存器
    //每个长度为4,所以为13*4
    1:
    ldr r2, [r1], #4    
    //将r1的值加载到r2,同时r1加4。取出寄存器将要被设置的值
    str r2, [r0], #4    
    //将r2的值存储到r0,同时r0加4。将要设置的值赋给对应的寄存器
    cmp r0, r3          
    //如果r0小于r3,那么就跳回到标签1处
    bne 1b              
    //b是back的意思,结束之后,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

重定位

为了完成比较复杂的工作,不能仅仅使用汇编代码。我们需要使用C语言来编写一些功能,在使用C语言代码之前一定要设置栈。

    ldr sp, =0x34000000 
    //JZ2440的SDRAM大小为64M,并且起始地址为0x30000000。
    //这里指向最高的内存,因为栈是向低地址走的。
    //这里0x04000000为64M(每个地址对应一个字节)
    //所以设为0x30000000+0x04000000

    bl nand_init    
    //跳转到C语言程序中的NAND FLASH初始化函数

    mov r0, #0  
    //copy_code_to_sdram的第一个参数
    ldr r1, =_start        
    //链接脚本起始地址,这是copy_code_to_sdram的第二个参数
    ldr r2, =__bss_start
    //bss段的起始地址
    //BSS(Block Started by Symbol)
    sub r2, r2, r1
    //第三个参数,copy_code_to_sdram的len参数

    bl copy_code_to_sdram   
    //开始从flash中复制代码到SDRAM
    bl clear_bss 
    //清除bss段

这就是使用的链接脚本代码

SECTIONS {
    . = 0x33f80000;代码段的起始地址
    .text : { *(.text) }

    . = ALIGN(4);这句是用来取整的
    .rodata : {*(.rodata*)} 

    . = ALIGN(4);
    .data : { *(.data) }

    . = ALIGN(4);
    __bss_start = .;bss段的起始地址
    .bss : { *(.bss)  *(COMMON) }
    __bss_end = .;
}
最后的bss段用于存储未定义的变量的,是不存储在程序中
的,所以其实程序大小是__bss_end减去0x33f80000的值
这里的0x33f80000就是start.S中的_star

执行main

到这里汇编代码的工作就全部结束了,开始进入C语言程序

    ldr lr, =halt       //返回地址
    ldr pc, =main
halt:
    b halt          //死循环,避免开发板随便跑飞
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值