u-boot分析-课堂笔记

参考《嵌入式linux应用开发完全手册》

目录

一.编译体验

1.将镜像文件及源码放入ubuntu

2.解压u-boot-1.1.6.tar.bz2

 3.进入u-boot-1.1.6/

4.打补丁

5.配置

6.编译

二、makefile结构分析

 三、分析编译过程

 四、源码

 4.1、u-boot第一阶段代码分析

4.2、 u-boot第二阶段代码分析

4.3、u-boot命令格式

 4.4、启动内核


一.编译体验

1.将镜像文件及源码放入ubuntu

2.解压u-boot-1.1.6.tar.bz2

tar xjf u-boot-1.1.6.tar.bz2

 3.进入u-boot-1.1.6/

cd u-boot-1.1.6/

4.打补丁

patch -p1 < ../u-boot-1.1.6_jz2440.patch

 查看这个补丁文件,在开头的地方可以看到补丁打入的地方,即

--- u-boot-1.1.6/board/100ask24x0/100ask24x0.c   

意思是打入u-boot-1.1.6/board/100ask24x0/100ask24x0.c  ,而我们已经在u-boot-1.1.6/这个目录下了,所以命令前面p1的意思是忽略u-boot-1.1.6/。

5.配置

make 100ask24x0_config

6.编译

make

 这里会提示没有安装arm-linux-gcc,需要去安装,这里不讲述如何安装

然后就可以烧写生成的u-boot.bin文件。

 pc机一上电,BIOS引导操作系统windows识别c、d盘。嵌入式系统上电后bootloader引导linux内核,挂载根文件系统。bootloader的最终目的就是要启动内核

 启动内核之前要从flash中读出内核,之前还有硬件相关的初始化,在这一系列环节中可以完成开发功能,比如烧写flash,网卡,usb和串口等等。

二、makefile结构分析

参考“嵌入式Linux应用开发完全手册"

分析配置过程-make 100ask24x0_config

 MKCONFIG    := $(SRCTREE)/mkconfig

100ask24x0_config    :    unconfig
    @$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0

相当于执行:

MKCONFIG 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0

 p252

 三、分析编译过程

总结编译过程

 四、源码

这是u-boot内存使用情况图

 4.1、u-boot第一阶段代码分析

硬件设备初始化,将cpu工作模式设置为管理模式,关闭看门狗。

为加载bootloader的第二阶段代码准备ram空间

复制bootloader的第二阶段代码到ram空间中

设置好栈,栈的灵活性很大,只要让sp寄存器指向一段没有使用的内存即可

跳转到第二阶段的c入口点,在跳转之前还要清除bss段

4.2、 u-boot第二阶段代码分析

第二阶段从lib_arm/board.c中的start_armboot函数开始,程序流程图如下

u-boot启动内核,先从flash中读出内核,然后启动它

 读出内核:nand read.jffs2 0x30007FC0 kernel,从nandFlash把内核读到0x30007FC0

启动内核:bootm 0x30007FC0,从0x30007FC0启动内核

u-boot的核心是命令

4.3、u-boot命令格式

即使是内核的启动,也是通过u-boot命令来实现的,u-boot中每个命令都通过U_BOOT_CMD宏来定义

宏U_BOOT_CMD在include/command.h中定义:

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

Struct_Section也是在include/command.h中定义:

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

对于每个使用U_BOOT_CMD宏来定义的命令,都在.u_boot_cmd段中定义一个cmd_tbl_t结构。

总之,内核的复制和启动,可以通过如下命令来完成:bootm从内存、ROM、NOR FLASH中启动内核,bootp则通过网络来启动,而nboot从NAND Flash启动内核。他们都是先将内核映像从各种媒介中读出,存放在指定的位置,然后设置标记列表以给内核传递参数,最后跳到内核的入口点去执行。

做一个简单的测试,在common文件夹内添加一个cmd_hello.c文件

代码如下

#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <asm/byteorder.h>

int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    int i;
    printf ("hello world!!,%d\n",argc);
    for(i =0;i<argc;i++)
    {
        printf("argv[%d]: %s\n",i,argv[i]);
    }
    return 0;
}
U_BOOT_CMD(
 	hello,	CFG_MAXARGS,	1,	do_hello,
 	"hello   - just for test\n",
 	"hello, long help ................\n"
);

 然后修改Makefile,最后make,启动开发板

 4.4、启动内核

介绍一下分区,PC每个硬盘都有分区表,但是对于嵌入式linux,flash没有分区表,所以这些分区是在源码里写死的,所以我们不关系这些分区的名字,只关心这些分区的地址

 所以上面读出内核的这条命令:nand read.jffs2 0x30007FC0 kernel,也可以写成nand read.jffs2 0x30007FC0   0x00200000      0x00060000

 u-boot要告诉内核一些参数,也就是为内核设置启动参数,然后再跳到入口地址启动内核

对于ARM架构的CPU,都是通过lib_arm/armlinux.c中的do_bootm_linux函数来启动内核。这个函数中,设置标记列表,最后通过"theKernel (0, bd->bi_arch_number, bd->bi_boot_params);"调用内核。其中theKenel指向内核存放的地址(对于ARM架构的CPU,通常是0x30008000),bi_arch_number是前面board_init函数设置的机器类型ID,而bi_boot_params就是标记列表的开始地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值