本文是基于韦东山视频的学习笔记
u-boot是什么
嵌入式系统,最终目的,是执行用户APP。
开发板的系统怎么运行,谁引导? 引导的就是bootloader。
简单来说,bootlodaer有两种作用。
- 最终目的就是引导Linux内核
- 其次,他还要初始化板子的各种设备,包括系统时钟,外设
厉害一点的bootloader就是u-boot,他是裸机程序的集大成者(老生常谈了),他可以把所有外设都初始化,供给内核使用。
那么怎么玩呢?
首先得到u-boot和补丁(有些时候u-boot不一定适用于特定的板子,这时候就会有特定板子的补丁,让u-boot适配板子),“u-boot-1.1.6.tar.bz2” 和 “u-boot-1.1.6_jz2440.patch”,然后解压缩,然后打补丁
tar -xjf u-boot-1.1.6.tar.bz2
cd u-boot-1.1.6
patch -p1 < ../u-boot-1.1.6_jz2440.patch
再然后,配置编译
make 100ask24x0_config //百问网的补丁,所以用百问网的配置命令
make
硬件相关
uboot干什么。首先是为引导内核做准备,这个流程和写裸机程序差不多的,这是关于s3c2440的uboot,我们写具体一点。
- 设置为svc模式
- 关看门狗
- 屏蔽中断
- 初始化sdram
- 设置栈
- 初始化时钟
- 代码重定位
- 清除bss段
- 调用start_armboot函数
要在uboot初始化串口
为什么要在bootloader初始化呢,虽然在内核都有初始化,但是在启动内核前也要用到,所以启动前也初始化咯。
重定位
问题是从哪里读,读到哪里去。
在韦老师提供的u-boot里,内核的分区是从0x60000开始,但前面是u-image。
在jz2440里,内核分区基本上是0x30008000。大小是2m。
引导内核
给内核传参
setup_start_tag();
setup_memory_tags();
setup_commandline_tag( "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
setup_end_tag();
入口函数
theKernel = (void (*)(int, int, unsigned int))0x30008000;
theKernel(0, 362, 0x30000100);
main函数
int main(void)
{
void (*theKernel)(int zero, int arch, unsigned int params);
volatile unsigned int *p = (volatile unsigned int *)0x30008000;
/* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */
uart0_init();
/* 1. 从NAND FLASH里把内核读入内存 */
puts("Copy kernel from nand\n\r");
nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
puthex(0x1234ABCD);
puts("\n\r");
puthex(*p);
puts("\n\r");
/* 2. 设置参数 */
puts("Set boot params\n\r");
setup_start_tag();
setup_memory_tags();
setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
setup_end_tag();
/* 3. 跳转执行 */
puts("Boot kernel\n\r");
theKernel = (void (*)(int, int, unsigned int))0x30008000;
theKernel(0, 362, 0x30000100);
/*
* mov r0, #0
* ldr r1, =362
* ldr r2, =0x30000100
* mov pc, #0x30008000
*/
puts("Error!\n\r");
/* 如果一切正常, 不会执行到这里 */
return -1;
}
strcpy
Copy Kernal from Nand…
Setting Parm for Kernal…
Booting Kernal…
Uncompressing Linux… done, booting the kernel.
原来是自己的strcpy函数写错了
void strcpy(unsigned char *src, unsigned char *dest) //这里函数src和dest位置写反了...
{
while ((*dest++ = *src++) != '\0');
}
以后程序不动了多查查循环的语句,不然真的难查