您的位置:首页 > 其它

学习笔记:u-boot引导内核启动

2016-04-11 22:32 423 查看
1、u-boot的功能:

- 关看门狗

- 设置栈

- 初始化时钟

- 初始化SDRAM

- 从FLASH读出内核写入SDRAM

- 启动内核

此外,在开发阶段为了方便还额外添加一些其他功能

- 烧写FLASH

- 网卡

- USB

- 串口

2、u-boot主要目的:

1. 从flash上读出内核写到SDRAM中

2. 启动内核(用do_bootm函数)



nand read.jffs2 0x30007FC0 kernel
bootm 0x30007FC0


从nand上kernel这个地址区读写到0x30007FC0地址上去,然后从0x30007FC0上启动内核

3、u-boot的配置

执行

make 100ask24x0_config


相当于执行Makefile中的

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


即相当于执行下面的脚本文件

mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0


因此,创建了顶层Makefile包含的文件

include/config.mk


里面的内容是:

ARCH   = arm
CPU    = arm920t
BOARD  = 100ask24x0
SOC    = s3c24x0


创建开发板相关的头文件

include/config.h


里面的内容是:

/* Automatically generated - do not edit */
#include <configs/100ask24x0.h>


4、分析Makefile

u-boot.bin:

$(obj)u-boot.bin:	$(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@


u-boot:

$(obj)u-boot:		depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot


其中,LDFLAGS:

u-boot-1.1.6/config.mk:189:LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
LDSCRIPT:boot-1.1.6/board/100ask24x0/u-boot.lds
u-boot-1.1.6/board/100ask24x0/config.mk:25:TEXT_BASE = 0x33F80000


执行make命令,通过结果分析目标u-boot的规则

UNDEF_SYM=`arm-linux-objdump -x lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd /home/lvxiao/Ftp/system/u-boot/tmp/u-boot-1.1.6 && arm-linux-ld -Bstatic -T /home/lvxiao/Ftp/system/u-boot/tmp/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000  $UNDEF_SYM cpu/arm920t/start.o \
--start-group lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a --end-group -L /usr/local/arm/gcc-3.4.5-glibc-2.3.6/bin/../lib/gcc/arm-linux/3.4.5 -lgcc \
-Map u-boot.map -o u-boot


这些文件如何组成u-boot.bin,如何排序,哪个是第一个运行的文件,从链接文件u-boot-1.1.6/board/100ask24x0/u-boot.lds可以看到,start.o放在起始运行地址,因此,cpu/arm920t/start.S是第一个运行的源程序

其中,u-boot.lds:

SECTIONS
{
. = 0x00000000;

. = ALIGN(4);
.text      :
{
cpu/arm920t/start.o   (.text)
board/100ask24x0/boot_init.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 : { *(.bss) }
_end = .;
}


5、分析start.S,运行流程:

①、设置svc模式

②、关看门狗

③、屏蔽中断

④、初始化SDRAM

⑤、设置栈

⑥、时钟

⑦、重定位:将代码从Flash拷贝到SDRAM中

⑧、清BSS段

⑨、调用start_armboot

_start_armboot: .word start_armboot


6、start.S最后一步调用start_armboot函数,进入board.c中的start_armboot函数

u-boot-1.1.6\lib_arm\board.c:void start_armboot (void)


7、start_armboot函数最后调用main_loop函数,进入main.c中的main_loop函数

u-boot-1.1.6\common\main.c:void main_loop (void)


s = getenv ("bootcmd");


if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1);    /* disable Control C checking */
# endif

# ifndef CFG_HUSH_PARSER
{
printf("Booting Linux ...\n");
run_command (s, 0);
}
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif

# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev);    /* restore Control C checking */
# endif
}


run_command("menu", 0);


如果在bootdelay时间段内没有按空格则,执行
run_command (s, 0);
命令启动内核,如果按了空格则执行
run_command("menu", 0);
跳转到菜单。

8、启动内核或按空格进入u-boot菜单都会从main_loop函数进入run_command函数

u-boot-1.1.6\common\main.c:int run_command (const char *cmd, int flag)


run_command函数会根据cmd参数按照include\command.h中的如下代码找到对应的函数执行

#define _CMD_REMOVE(_name, _cmd)                    \
int __remove_ ## _name(void)                    \
{                               \
if (0)                          \
_cmd(NULL, 0, 0, NULL);             \
return 0;                       \
}
...
...
...
#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, \
_comp)              \
_CMD_REMOVE(sub_ ## _name, _cmd)

#endif /* CONFIG_CMDLINE */

#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)      \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)


9、NOR FLASH、NAND FLASH启动选择:

u-boot-1.1.6\board\100ask24x0\boot_init.c:int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)


10、从NAND FLASH里读出内核

u-boot-1.1.6\common\cmd_nand.c:int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])


Flash上的 uImage=头部+真正的内核,头部:

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;


头部里关键参数是:

in_load:加载地址

in_eq:入口地址

如果发现内核不在加载地址就把内核移到加载地址,再跳到入口地址。

11、启动内核前的准备

do_bootm函数功能:

-根据头部移动内核到加载地址

-调用do_bootm_linux函数启动linux内核

u-boot-1.1.6\commoncmd_bootm.c:int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])


12、启动内核

u-boot-1.1.6\lib_arm\Armlinux.c:void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],ulong addr, ulong *len_ptr, int verify)


设置启动参数:在某个地址按某种格式保存参数

setup_start_tag (bd);
setup_memory_tags (bd)
setup_commandline_tag (bd, commandline);
setup_end_tag (bd);


跳到入口地址:

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);


bi_boot_params:启动参数所存的地址

bi_arch_number:机器ID
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  u-boot 内核