- UID
- 1029342
- 性别
- 男
|
Uboot移植 代码分析
突然发现自己很久没有弄这块了,自己把uboot翻出来看了一会,感觉想写点什么,大家看看吧,觉得写的有用就顶下,觉得写的不对,就指出来,大家共同进步把。
首先当我们想要移植一个uboot的时候,我们可以利用uboot里面提供的一些原有跟门自己使用芯片一样,只是外围电路不一样的的一些配置,比如我们做说s3c2410的一个uboot移植,我们可以复制一份uboot里面本来提供的smdk2410的原有代码复制一份改成我们自己的名字,比如我的tt2410,这样大部分地方是相同的,只是一些设计到外围硬件的程序需要大家来修改,这样我们对于uboot的移植就很是方便了。不过大部分主要是对uboot的代码进行分析,移植在其次。
当我们打开uboot代码的时候,这个源代码里面有一个board的文件夹,在这个文件夹里面有一个smdk2410的文件夹,这个是源代码对2410 smdk的板子的支持,我们可以建立我们自己板子的支持,我们可以创建一个文件夹命名为tt2410,然后将smdk2410中间的文件全部复制过来,然后将smdk2410.c 这个文件更名为tt2410,然后需要修改一下makefile这个修改比较简单,就不需要我说了。其实我们添加对于我们自己板子支持很多地方的makefile是需要修改的,其实修改的方法很简单,除这个文件夹里面 是直接改名,其他地方的makefile大部分是直接将smdk2410的配置直接复制一份,然后改一个我们自己命名文件夹的对应的编译规则,大家只要打开看看基本上是知道makefile是怎样去修改,所以后面我对makefile的修改基本省略
在我们刚刚建立的文件夹中间有一个名为u-boot.lds的文件,打开这个文件我们可以看到如下代码
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss (NOLOAD) : { *(.bss) }
_end = .;
}
其实这个东西是在我们编译器编译完成之后,连接器使用的一个文件,这个链接文件定义了程序的入口点,代码段、数据段等分配情况,我们主要看到这里有这样的一句话
= 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
这段代码其实就是告诉我们程序最开始运行的代码其实就是cpu/arm920t/start.s 这个文件的程序,很多人不知道问什么要这么做。其实这样做的目的是让cpu上电一定要执行这段代码,第二点就是为么我们uboot工作的第一阶段。其实大家查资料可以知道,在我们芯片内部其实是有一段固化的代码,这段代码可以直接从nor或者nand中间读取程序,就我这个芯片而言,可以直接读取到4k的内容,但是我们的uboot程序不可能只有4k呀,所以我们必须指定在这个4k程序中间要将uboot所有的程序拷贝到ram中间,这样我们的uboot才能完整运行,所以uboot这样做是非常有必要的。
我们先来看看cpu/arm920t/start.s这个代码
首先第一句话_start: b start_code
程序跳转到start_code这个地方,我们去看看这个地方
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
这段代码设置cpu的工作模式为管理模式
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLKCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
然后这段其实很清楚上面因为上面基本上都用英文标出来了,首先我们先关闭看门狗,然后关中断,然后再是设置cpu的分频系数
bl cpu_init_crit 然后调用这个函数
这个函数 mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0
这些主要就是做关闭idcache 然后关闭mmu
bl lowlevel_init 这个函数其实做的就是对ram的一个初始化,这个这个初始化使用汇编的查表来完成的,所以大家看起来不是很好看,但是仔细看看还是看的出来
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
这一段其实是对代码拷贝就是将uboot代码从flast里面拷贝到ram里面去,但是uboot的源码是只对norflash支持的 ,其实我们可以自己添加对nand的支持,很多人会想,我们怎样去区分nor还是nand启动的捏,其实有一个巧妙的方法
在cpu对内部的固化代码虽然可以直接对nor和nand直接读取,但是有一点,nor的写必须要添加代码才能,所以我们这个会发现一点,在前面4k的范围内,我们没有添加对nor写的程序的时候,我们在地址00000000h出写入一个数据再去读出来,如果我们写入数据,再读出来是我们写入的数据的话,那么 这个肯定是从nand启动的,因为nor cpu里面的固化代码是不能写的,只能写nand,所以我们利用这个巧妙的方式可以区分,我们cpu上电是从nor启动还是nand启动的。 |
|