- 论坛徽章:
- 0
|
get from http://www.laogu.com/wz_1411.htm
下一次,接着就去看看U-BOOT的源程序了。当然是基于S3C44B0的BOOTLOADER进行的。
上一次说到要学习UBOOT的代码,但在看之前,首先要知道目标机器的编程资源,这里的资源,是指S3C44B0所提供的
运行程序的资源,对任何嵌入式软件开发,都首先要对硬件有一个很好的了解,这跟PC机的编程是大不一样的。因为
PC机都已经发展了30多年,但整个编程的体系是没有很大的变化,就是说现在的PC都是在虚拟机上编写了,跟硬件打
交道的机会很少,所以不用去了解它。但是在嵌入式的软件里,每样硬件都是千差万别的,所以一定要去看原版的
S3C44B0说明手册,一定要看英文原版的,不能看那种中文版的,哈哈,为什么要看英文原版的呢?第一,每个CPU都
有很多特别寄存器,而这些寄存器都是用英文缩写的,看中文,就不知道它是什么意思了,并且还要死记,没有英文
整句好记。第二,中文是经过翻译的,并且都不是三星厂家进行翻译,都是一些业余水平的人来做,很难保证按原文
的意思进行。有一次,我看中文的S3C44B0资料找特别寄存器,就找不到,我说为什么没有呢,原来别人都不翻译那些
,结果在英文原版中,一看就找到了。因此,喜欢看英文原版的。并且只要学习过几个CPU之后,发现嵌入式软件就那
几样东西了。
对开发软件的人来说,最重要的东西是什么呢?哈哈,当然是存储器和寄存器了。每次拿到开发板之后,一定要去了
解存储器是怎么样分配的,是从什么地址开始,存储器有多大。是什么样的存储器,是FLASH的,还是SDRAM的。FLASH
的存储器映射在S3C44B0的什么地址空间呢?SDRAM又是映射在什么地址空间呢?一定要把这些问题搞清楚,否则就很
难对它开发软件。所以看S3C44B0的手册时,就要注意看它的存储管理。目前,S3C44B0的存储器管理,分为很多BANK
的。BANK0一般用来映射FLASH存储器,并且在BANK0后面一段空间里进行特别寄存器映射,它的空间是4M大小。并且一
般的开发板,都是把FLASH存储器映射在0x0000_0000 到 0x001F_FFFF,这里的地址空间,就是2M大小。把SDRAM映射在
BANK6里面,地址空间就是0x0c00_0000 到 0x0c7f_ffff,这里就是8M的SDRAM了。
特别寄存器的地址空间是从 0x01c0_0000到0x0200_0000的4M空间里,这里的寄存器,大多数都是跟IO有关的。比如串
行通讯,DMA,PWM,看门狗,IO口等等。
看懂了存寄器和存储器,就可以进行汇编练习。当然S3C44B0它还有ARM标准的寄存器,共有37个吧。这些是所有ARM的
CPU都具有的。
把CPU和S3C44B0特别的功能深入了解之后,就可以去看UBOOT代码。
目前我的引导程序是在UBOOT1.1.2上修改过来的,大家可以下载UBOOT的源程序,也许你们会问在那里有下呢?这个问
题不用我回答了,用GOOGLE,直接找u-boot,就可以找到了。
由于这个引导程序是从u-boot1.1.2修改过来的,所以还是采用uboot的编译工具,它就是
arm-linux-tools-20031127.tar.gz,这个可以uboot的网站下载,然后在linux下安装好,就可以编译引导程序。
编译命令主要:
make clean 是清空所有临时文件,一般是用来清空目录,用来重新编译程序。
make XXXX_config 是编译本引导程序,XXXX是自己定义的开发板,在board目录下。
make backup 是备份引导程序的源程序。
UBOOT编译环境建立起来,就可以去修改和学习UBOOT的源程序,就可以开发自己的boot。源程序已经下载,就可以解
开压缩包,在目录u-boot-1.1.3,因目前最新的UBOOT是1.1.2,那个1.1.3是我自己的UBOOT源程序,如果自己想改为
1.1.3名称,在LINUX下编译是有点问题的,自己去试试吧。哈哈。。。
接着,我到目录cpu\s3c44b0,这个目录,就是S3C44B0的CPU引导程序,最开始运行的代码就是从这里开始的。那我看
代码,也要从这里开始。
看一下这个目录,包括文件有:
G:\Downloads\lichee\lichee\boot\src\u-boot-1.1.3\cpu\s3c44b0 的目录
2005-07-18 12:47 .
2005-07-18 12:47 ..
2005-07-16 04:35 4,154 .depend
2004-02-24 08:16 1,066 config.mk
2004-10-18 05:12 9,878 cpu.c
2004-02-24 08:16 4,843 interrupts.c
2004-02-24 08:16 1,303 Makefile
2004-10-18 05:12 4,378 serial.c
2005-07-17 23:48 4,820 start.S
2005-07-17 23:47 4,784 start.S.bak
有好几个文件,它们的作用,大家自己先想想,不懂的再问我,目前我要开始看start.S文件,这个最开始运行的文件
。
这个文件是汇编写的,但它是经过c的预处理的,所以像在头文件.h中的宏,也可以使用的,这就是GCC的博大之处。
大家看到我的目录,也许很奇怪,为什么会有“lichee”这个名称?我来告知各位,这个是我起的名称,叫做“荔枝
”,我的BOOT代码和我的uClinux的代号,都叫“荔枝”。吃过“荔枝”的人,都知道外面红红的,里面的肉是白的,
清甜可口。我的BOOT和OS都是外面看起来很好看,里面的功能,就是难看了,但要深入去了解,才会尝到新鲜的味道
。
好了,下面就要开始品尝我的“荔枝”了,第一段代码:
/** S3C44B0 CPU启动代码。* 蔡军生 2005/07/17 **/
/** 包含配置文件。*/
#include /*添加版本说明.2005/07/16*/
#include /** 中断向量表.*/
/* 声明标量是全局函数,CPU加电启动后,就从这里执行代码。 */
.globl _start
_start: b reset /* 跳到复位中断开始位置。 */
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
.balignl 16,0xdeadbeef
上面这段代码,看懂了吗?如果有什么不懂,就发问题过来。
这里用到ARM指令,b指令就是无条件地跳到reset的地方运行,reset是一个标记,并且它是相对量。
add pc, pc, #0x0c000000,这句用到了4G空间跳转技术,因为ARM的CPU下一次值是根据PC的值来进行的。这里
修改了PC的值,就相当跳到对应的地址运行了。又由ARM的指令的宽度是4字节的,所以这里的PC值就是0x0c000004。
如果这里直接用b指令是不行的,因为它不超出32M的寻址空间,只有修改PC值才可以达到目的,因此采用ADD指令来修
改PC值。
.balignl 16,0xdeadbeef
上面这句,就是填充多少字节在后面。
整段代码实现建立中断向量表,这个根据ARM的CPU来编写的。
第一段代码看完了,再接着看第二段代码。
/******************************************************************
* 启动代码。
** 如果不作内存初始化,就只建立堆栈,重新定位代码到RAM位置。
* 然后就可以跳到第二阶段的代码运行了。
**********************************************************************/
/* 保存变量的数据区 */
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/** These are defined in the board-specific linker script.*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
上面这段代码,主要保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者其它的使用。还有一些变量的长度是
通过连接脚本里得到,实际上由编译器算出来的。
看了数据区,这次要看从引导那里跳到这里执行时,运行什么东西了。
/** 实际运行的复位代码。从一开始运行的代码,就跳到这里运行。*/
reset:
/* * 设置cpu运行在SVC32模式。*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0x13
msr cpsr,r0
具体分析如下:
/** 实际运行的复位代码。从一开始运行的代码,就跳到这里运行。*/
reset:
/** 设置cpu运行在SVC32模式。S3C44B0共有7种模式。 */
mrs r0,cpsr
取得当前程序状态寄存器cpsr到r0。
bic r0,r0,#0x1f
这里使用位清除指令,把中断全部清除,只置位模式控制位。
orr r0,r0,#0x13
计算为超级保护模式。
msr cpsr,r0
设置cpsr为超级保护模式。
通过设置ARM的CPSR寄存器,让CPU运行在操作系统模式,为后面进行其它操作作好准备了。后面的代码如下:
/* * 当是从FLASH启动时,就要进行内存测试,当
* 是从RAM启动时,一般就是开发本源程序时,就
* 可以跳过。
*
*/
#ifdef CONFIG_INIT_CRITICAL
bl cpu_init_crit
/*
* 在重新定位之前,要进行RAM访问时间测试,因为每个开发
* 都是不一样的。
* 可以在文件memsetup.S里看到它的说明。
*/
bl memsetup
#endif
/* 进行重定位 */
relocate: /* 重定位Boot代码到RAM内存,比如从FLASH移到RAM */
adr r0, _start /* 把_start的相对地址移到r0 */
ldr r1, _TEXT_BASE /* 把_TEXT_BASE地址,就是BOOT在RAM中运行地址 */
cmp r0, r1 /* 比较两个地址是否相同,如果相同,就已经在RAM运行,否则就是FLASH中运行。*/
beq stack_setup
/* 是在FLASH中运行,要把FLASH中的BOOT代码移到RAM中,然后再运行. */
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2保存引导代码大小 */
add r2, r0, r2 /* r2保存引导代码最后地址 */
copy_loop:
ldmia r0!, {r3-r10} /* 从源地址[r0]读取8个字节到寄存器,每读一个就更新一
次r0地址 */
stmia r1!, {r3-r10} /* 拷贝寄存器r3-r10的值保存到 [r1]指明的地址,每写一
个字节,就增加1. */
cmp r0, r2 /* 判断是否拷贝到[r2]地址,就是引导代码结束位置。 */
ble copy_loop /* 循环拷贝 */
/*拷贝中断向量表,实际是建立起二级中断向量表,当CPU中断时,先运行FLASH中断,接着就转移到实际中向表执行
中断程序。*/
adr r0, real_vectors
add r2, r0, #1024
ldr r1, =0x0c000000
add r1, r1, #0x08
vector_copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble vector_copy_loop
/* 建立起堆栈 */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
ldr pc, _start_armboot /* 已经准备好了堆栈,就可跳到C写的代码里,由于我的代码是ARM,就是
跳到lib_arm\board.c(208):void start_armboot (void)中运行。 */
_start_armboot: .word start_armboot
/**************************************************************************
* CPU_init_critical临界区寄存器
* 设置一些重要的寄存器,并进行内存测试。
*************************************************************************
*/
#define INTCON (0x01c00000+0x200000) /* 中断控制器 */
#define INTMSK (0x01c00000+0x20000c) /* 中断控制屏蔽寄存器 */
#define LOCKTIME (0x01c00000+0x18000c)
#define PLLCON (0x01c00000+0x180000)
#define CLKCON (0x01c00000+0x180004)
#define WTCON (0x01c00000+0x130000)
cpu_init_crit:
/* 关闭看门狗 */
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
/** 清除所有中断位,设置INTMRs实现。*/
ldr r1,=INTMSK
ldr r0, =0x03fffeff
str r0, [r1]
ldr r1, =INTCON
ldr r0, =0x05
str r0, [r1]
/* 设置时钟控制寄存器 */
ldr r1, =LOCKTIME
ldrb r0, =800
strb r0, [r1]
/* 设置锁相环,控制CPU运行速度。 */
ldr r1, =PLLCON
#if CONFIG_S3C44B0_CLOCK_SPEED==66
ldr r0, =0x34031 /* 66MHz (Quartz=11MHz) */
#elif CONFIG_S3C44B0_CLOCK_SPEED==75
ldr r0, =0x610c1 /*B2: Xtal=20mhz Fclk=75MHz */
#else
# error CONFIG_S3C44B0_CLOCK_SPEED undefined
#endif
str r0, [r1]
ldr r1,=CLKCON
ldr r0, =0x7ff8
str r0, [r1]
/* 调用子函数返回 */
mov pc, lr
/*************************************************/
/* 实际的中断向量表 */
/*************************************************/
real_vectors:
b reset
b undefined_instruction
b software_interrupt
b prefetch_abort
b data_abort
b not_used
b irq
b fiq
/*************************************************/
undefined_instruction:
mov r6, #3
b reset
software_interrupt:
mov r6, #4
b reset
prefetch_abort:
mov r6, #5
b reset
data_abort:
mov r6, #6
b reset
not_used:
/* we *should* never reach this */
mov r6, #7
b reset
irq:
mov r6, #8
b reset
fiq:
mov r6, #9
b reset
把引导的汇编看完,已经准备C的运行环境,下面就开始学习C的源程序,从start.S文件里到跳文件lib_arm\board.c里运
行.
/*引导程序从汇编start.S里跳到这里执行。蔡军生 2005/07/19*/
void start_armboot (void)
{
/* 声明一个全局指针,它是指向一个数据结构,用于保存参数。
并且它占用r8寄存器,用它来保存内存地址,达到全局使用目的。
*/
DECLARE_GLOBAL_DATA_PTR;
ulong size;
init_fnc_t **init_fnc_ptr;
char *s;
#if defined(CONFIG_VFD) defined(CONFIG_LCD) unsigned long addr;
#endif
/* gd指针可写,因为已经分配一个寄存器给它作为变量。
这里就相当于把后面算出来的地址保存到r8寄存器.
*/
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* 下面一句是阻止3.4以上版本的GCC进行代码优化,把后面的代码删除掉。 */
__asm__ __volatile__("": : :"memory");
/* 清空gd指向的结构 */
memset ((void*)gd, 0, sizeof (gd_t));
/* */
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;
这一段准备好保存参数的全局变量区.
后面就是一系列的初始化和获取正确的参数.
/* 用循环调用所有初始化函数 */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
{
if ((*init_fnc_ptr)() != 0)
{
/* 当每个函数初始化失败时,就会挂机在这里。 */
hang();
}
}
上次说到在函数指针数组里,不断地调用所有初始化函数进行初始化,下面就来仔细地分析一下,它们到底是做什么
的,做什么样的初始化,怎么样为后面做好运行的准备工作。看到第一个初始化函数,就是CPU初始化(cpu_init),
这个函数是在cpu\s3c44b0\cpu.c里,它的作用就是进行S3C44B0初始化工作。看到这个函数内容如下:
/* CPU初始化。蔡军生 2005/07/23*/
int cpu_init (void)
{
/* 清空缓冲区 */
icache_enable();
return 0;
}
它在里面调用了函数icache_enable(),它就是用来初始化S3C44B0的缓冲区,并且启用CPU缓冲区。因为CPU在加电之
后,它的初始化值是不启用内部的8K缓冲区的,必须由程序进行设置。接着看看那个调用的函数又是怎么样初始化内
部缓存区的呢?
/* CPU内存的缓冲初始化。蔡军生 2005/07/23*/
void icache_enable (void)
{
ulong reg;
/* 清空内存的缓冲区. */
s3c44b0_flush_cache();
/* 初始化缓冲区,设置非缓冲区的起始地址和结束地址。第一个寄存器指明下面的地址不要缓存,低16位是起始地址,高16位是结束地址。并且空间大小都是以4K为界。0x0000:0000 - 0x0C00:0000*/
NCACHBE0 = 0xC0000000;
NCACHBE1 = 0x00000000;
/* 设置SYSCFG寄存器启用8K缓冲区。 */
reg = SYSCFG;
reg = 0x00000006; /* 8kB */
SYSCFG = reg;
}
在这个函数里,第一个先调用函数是进行缓冲区清0的工作,它有一些特别的地方,如下:
/* CPU的内部缓冲初始化。蔡军生 2005/07/23*/
static void s3c44b0_flush_cache(void)
{
volatile int i;
/* 清空缓冲区,每次要按4个32位来读写,所以要加16. */
for( i = 0x10002000; i
它用一个for循环进行内部的缓冲区初始化,由于S3C44B0决定每次读写都是按16字节进行的。因此,这里的i就是不断
地加16个字节。不过,这里为什么不清除0x10000000到0x10001fff区域呢?这个我也没有搞清楚,等我有空试试清除
有没有问题!
到现在为止,缓冲区已经清空,就要设置那些内存区域是不要进行缓存的。因为不是所有内存都需要进行缓冲的,比
如读取外面的IO,就不需要进行缓冲;读取FLASH也不需要。因此,设置第一个非缓冲区的起始地址为NCACHBE0 =
0xC0000000,这个值里的低16位是起始地址0x0000,它的32位地址就是从0x00000000开始。它的高16位是结束地址
0Xc000,它的32位地址就是从0Xc0000000结束。最后就是通过设置SYSCFG寄存器的[2:1]位的值为11,就启用了8K内存
数据和指令缓冲区。到这里为止,就已经设置好CPU的缓冲区初始化和启用。
由于前几次,把编译好的UBOOT写到FLASH老是运行不了。那么怎么办呢?思考了很久,也查看了源程序,还是没有发
现问题。也许那个UBOOT的源程序太大,有很多的编译开关,还有很多驱动程序选择,所以一头雾水,不知怎么办好。
到了这个时候,只有从头开始跟踪了。就是尽可能地跟踪程序运行到那里。因而依次地进行下面的检查:
1. 检查设置的倍频是否对。
2. 检查程序写到FLASH的数据是否对。
3. 检查设置RAM是否对。
4. 检查设置串口的波特率是否对。
一般进行四部份检查就找出大体的问题。我首先查了一下,我的开发板上的晶振是10MHz输入,那么我要倍频到60MHz
,所以就要计算它的倍频系数。当然最快的办法,就是用三星提供的PLLSET.EXE工具,五秒钟就搞定了。经过检查,
发现我的倍频系数不对,所以重新设置倍频系数。一般设置过倍频系后,都要调整串口波特率、SDRAM的刷新频率。设
置好倍频系数后,接着,就要计算串口的波特率,这个三星的S3C44B0的手册有计算公式。比如9600,就是拿60MHz进
行分频得到的。
这次设置好后这些东西之后,就把UBOOT编译后,再写到FLASH运行,还是不行。偶都在痛苦中,为什么还不行呢。后
来我想想,把UBOOT的编译地址改到0x00000000运行,就是在FLASH运行,不拷贝到SDRAM中运行。结果是可以运行一段
,串口有东西输出来,我的设置的LED也可以显示。蜂鸣器也不响。说明这个串口的设置已经对,那么系统的倍频也对
了。但UBOOT的堆栈我没有改,所以只能跑到没有使用到堆栈的代码。接着,我还需要改回到0x0C100000的基地址运行
。经过用ADS中的AXD调试,单步跟踪。又是一件痛苦的事情,发现AXD只能单步跟踪,设置断点,或者其它调试都不行
,如果在后面设置了断点,选择运行,发现到断点,还停不下来的。
呵呵。。。。。。。调试就是这样的,不是样样都顺手。既然只能单步运行,就老老实实地单步调试了,经过30多分
钟的单步运行,F8都已经按得手软。最后才跟踪到出错的地址,发现内存设置不对。主要是SDRAM的设置不对,查看了
加载地址的出错了。发现了这个加载地址出错,偶也没有更好的办法解决之前,就只好把算好的值,依次地用ldr加载
到r1-r13,共13个寄存器里。接着让AXD全速运行,程序就可运行了。原来出错就是没有把SDRAM的参数加载正确,让
我调试了三天。
通过一个多小时的调试,串口可以显示了,UBOOT的很多命令也可运行了。但还没有调通USB口,也没有网络接口。后
面的工作,就是先调通网络接口。我的开发板用的网络芯片是RTL8019AS,这个我也没有怎么看过,得好好找点资料,
了解了解这个IC,然后找一份LINUX的RTL8019的驱动程序出来看看,再决定怎么样调通RTL8019,由于RTL8019要用到
中断,就要先检查S3C44B0设置,否则到最后都没有办法调试。
通过开发板的调试,与SKYEYE相比,主要的区别是在SDRAM的频率,串口的频率,还有中断的功能,都有很大的不同。
因此,在SKYEYE上能运行的,在开发板,就不一定可以运行,就是这个原因
below get from http://www.linuxfans.org/nuke//modules.php?name=News&file=article&sid=2765
基于Atmel at91rm9200的armlinux的bootloader启动代码分析
1.4 u-boot源代码目录结构
board:开发板相关的源码,不同的板子对应一个子目录,内部放着主板相关代码。
at91rm9200dk/at91rm9200.c, config.mk, Makefile, flash.c ,u-boot.lds等都和具体开发板的硬件和地址分配有关。
common:与体系结构无关的代码文件,实现了u-boot所有命令,
其中内置了一个shell脚本解释器(hush.c, a prototype Bourne shell grammar parser), busybox中也使用了它.
cpu:与cpu相关代码文件,其中的所有子目录都是以u-boot所支持的cpu命名.
at91rm9200/at45.c, at91rm9200_ether.c, cpu.c, interrupts.c serial.c, start.S, config.mk, Makefile等.
其中cpu.c负责初始化CPU、设置指令Cache和数据Cache等;
interrupt.c负责设置系统的各种中断和异常,比如快速中断、开关中断、时钟中断、软件中断、
预取中止和未定义指令等;
start.S负责u-boot启动时执行的第一个文件,它主要是设置系统堆栈和工作方式,为跳转到C程序入口点.
disk:设备分区处理代码。
doc:u-boot相关文档。
drivers:u-boot所支持的设备驱动代码, 网卡、支持CFI的Flash、串口和USB总线等。
fs: u-boot所支持支持文件系统访问存取代码, 如jffs2.
include:u-boot head文件,主要是与各种硬件平台相关的头文件,
如include/asm-arm/arch-at91rm9200/, include/asm-arm/proc-armv
net:与网络有关的代码,BOOTP协议、TFTP协议、RARP协议代码实现.
lib_arm:与arm体系相关的代码。(这里我们主要面向的是ARM体系,所以该目录是我们主要研究对象)
tools:编译后会生成mkimage工具,用来对生成的raw bin文件加入u-boot特定的image_header.
1.5 u-boot的功能介绍
u-boot支持SCC/FEC以太网、OOTP/TFTP引导、IP和MAC的功能.
读写Flash、DOC、IDE、IIC、EEROM、RTC
支持串行口kermit和S-record下载代码, 并直接从串口下载并执行。
在我们生成的内核镜像时,要做如下处理.
1. arm-linux-objcopy -O binary -R.note -R.comment -S vmlinux linux.bin
2. gzip -9 linux.bin
3. mkimage -A arm -O linux -T kernel -C gzip -a 0xc0008000 -e 0xc0008000 -n
"Linux-2.4.19-rmk7” -d linux.bin.gz uImage
即在Linux内核镜像vmLinux前添加了一个特殊的头,这个头在include/image.h中定义,
typedef struct image_header
{
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
当u-boot引导时会对这个文件头进行CRC校验,如果正确,才会跳到内核执行.
如果u-boot启动以后会出现
u-boot>
敲入help, 会出现大量的命令提示,Monitor command
go - start application at address 'addr'
run - run commands in an environment variable
bootm - boot application image from memory
bootp - boot image via network using BootP/TFTP protocol
tftpboot- boot image via network using TFTP protocol
and env variables "ipaddr" and "serverip"
(and eventually "gatewayip")
rarpboot- boot image via network using RARP/TFTP protocol
diskboot- boot from IDE devicebootd - boot default, i.e., run 'bootcmd'
loads - load S-Record file over serial line
loadb - load binary file over serial line (kermit mode)
md - memory display
mm - memory modify (auto-incrementing)
nm - memory modify (constant address)
mw - memory write (fill)
cp - memory copy
cmp - memory compare
crc32 - checksum calculation
imd - i2c memory display
imm - i2c memory modify (auto-incrementing)
inm - i2c memory modify (constant address)
imw - i2c memory write (fill)
icrc32 - i2c checksum calculation
iprobe - probe to discover valid I2C chip addresses
iloop - infinite loop on address range
isdram - print SDRAM configuration information
sspi - SPI utility commands
base - print or set address offset
printenv- print environment variables
setenv - set environment variables
saveenv - save environment variables to persistent storage
protect - enable or disable FLASH write protection
erase - erase FLASH memory
flinfo - print FLASH memory information
bdinfo - print Board Info structure
iminfo - print header information for application image
coninfo - print console devices and informations
ide - IDE sub-system
loop - infinite loop on address range
mtest - simple RAM test
icache - enable or disable instruction cache
dcache - enable or disable data cache
reset - Perform RESET of the CPU
echo - echo args to console
version - print monitor version
help - print online help
? - alias for 'help'
u-boot支持大量的命令可用, 这里就不作介绍,大家有兴趣可以看看u-boot 的README文档
3.3 对u-boot-1.0.0的修改和移植
1.6 关于u-boot的移植如下,由于u-boot的软件设计体系非常清晰,它的移植工作并不复杂,
相信各位的代码阅读功力不错的话,参照如下就可以完成。
If the system board that you have is not listed, then you will need
to port U-Boot to your hardware platform. To do this, follow these
steps:
1. Add a new configuration option for your board to the toplevel
"Makefile" and to the "MAKEALL" script, using the existing
entries as examples. Note that here and at many other places
boards and other names are listed in alphabetical sort order. Please
keep this order.
2. Create a new directory to hold your board specific code. Add any
files you need. In your board directory, you will need at least
the "Makefile", a ".c", "flash.c" and "u-boot.lds".
3. Create a new configuration file "include/configs/.h" for
your board
4. If you're porting U-Boot to a new CPU, then also create a new
directory to hold your CPU specific code. Add any files you need.
5. Run "make _config" with your new name.
6. Type "make", and you should get a working "u-boot.srec" file
7. Debug and solve any problems that might arise.
[Of course, this last step is much harder than it sounds.]
为了使u-boot-1.0.0支持新的开发板,一种简便的做法是在u-boot已经支持的开发板中参考选择一种较接近板的进行修改,
幸运的是在u-boot-1.0.0中已经有了at91rm9200的支持。
1.7 与at91rm9200相关的u-boot代码
在include/configs/at91rm9200dk.h 它包括开发板的CPU、系统时钟、RAM、Flash系统及其它相关的配置信息。
在include/asm-arm/AT91RM9200.h, 该文件描述了H9200寄存器的结构及若干宏定义。
具体内容要参考相关处理器手册。
在cpu/at91rm9200/目录下别为cpu.c、interrupts.c和serial.c等文件.
在board/at91rm9200dk/目录下分别为flash.c、at91rm9200dk.c, config.mk, Makefile,u-boot.lds
flash.c : u-boot读、写和删除Flash设备的源代码文件。由于不同开发板中Flash存储器的种类各不相同,
所以,修改flash.c时需参考相应的Flash芯片手册。它包括如下几个函数:
unsigned long flash_init (void ),Flash初始化;
void flash_print_info (flash_info_t *info),打印Flash信息;
int flash_erase (flash_info_t *info, int s_first, int s_last),Flash擦除;
volatile static int write_dword (flash_info_t *info, ulong dest, ulong data),Flash写入;
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt),从内存复制数据。
u-boot.lds :linker scripte, 设置u-boot中各个目标文件的连接地址.
网口设备控制程序
在drivers/目录中网口设备控制程序cs8900, bcm570x等, 还可以添加其他网卡驱动
int eth_init (bd_t *bd) : 初始化网络设备;
void eth_halt (void) : 关闭网络设备;
int eth_send (volatile void *packet,int len) : 发送数据包;
int eth_rx (void) : 接收数据包。
Makefile
在u-boot-1.0.0/Makefile中
at91rm9200dk_config : unconfig
./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk
1.8 编译u-boot
make at91rm9200_config
Configuring for at91rm9200 board...
make all
生成三个文件:u-boot.bin, u-boot, u-boot.srec
u-boot.bin is a raw binary image
u-boot is an image in ELF binary format
u-boot.srec is in Motorola S-Record format (objcopy -O srec -R.note -R.comment -S [inputfile] [outfile]
以上工作完成我们可以通过串口将u-boot.bin下载到主板的SDRAM中,它会自动执行, 并出现uboot>
这里我们可以通过串口把boot.bin, u-boot.bin.gz下载到主板,再用u-boot的提供的写flash功能分别
把boot.bin, u-boot.bin.gz写入到flash中,完成以上工作后,对主板跳线选择片外启动,
板子复位后会自动启动u-boot.
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/45211/showart_404116.html |
|