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

来源:互联网 发布:淘宝鼠标滑动效果代码 编辑:程序博客网 时间:2024/04/27 17:29

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

    • 一 什么是BootLoader
    • 二 StartS分析笔记
      • 关看门狗
      • 设置时钟
      • 初始化SDRAM
      • 重定位
      • 执行main


一 什么是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, =mainhalt:    b halt          //死循环,避免开发板随便跑飞
0 0
原创粉丝点击