学习笔记: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上kernel这个地址区读写到0x30007FC0地址上去,然后从0x30007FC0上启动内核
3、u-boot的配置
执行
相当于执行Makefile中的
即相当于执行下面的脚本文件
因此,创建了顶层Makefile包含的文件
里面的内容是:
创建开发板相关的头文件
里面的内容是:
4、分析Makefile
u-boot.bin:
u-boot:
其中,LDFLAGS:
执行make命令,通过结果分析目标u-boot的规则
这些文件如何组成u-boot.bin,如何排序,哪个是第一个运行的文件,从链接文件u-boot-1.1.6/board/100ask24x0/u-boot.lds可以看到,start.o放在起始运行地址,因此,cpu/arm920t/start.S是第一个运行的源程序
其中,u-boot.lds:
5、分析start.S,运行流程:
①、设置svc模式
②、关看门狗
③、屏蔽中断
④、初始化SDRAM
⑤、设置栈
⑥、时钟
⑦、重定位:将代码从Flash拷贝到SDRAM中
⑧、清BSS段
⑨、调用start_armboot
6、start.S最后一步调用start_armboot函数,进入board.c中的start_armboot函数
7、start_armboot函数最后调用main_loop函数,进入main.c中的main_loop函数
如果在bootdelay时间段内没有按空格则,执行
8、启动内核或按空格进入u-boot菜单都会从main_loop函数进入run_command函数
run_command函数会根据cmd参数按照include\command.h中的如下代码找到对应的函数执行
9、NOR FLASH、NAND FLASH启动选择:
10、从NAND FLASH里读出内核
Flash上的 uImage=头部+真正的内核,头部:
头部里关键参数是:
in_load:加载地址
in_eq:入口地址
如果发现内核不在加载地址就把内核移到加载地址,再跳到入口地址。
11、启动内核前的准备
do_bootm函数功能:
-根据头部移动内核到加载地址
-调用do_bootm_linux函数启动linux内核
12、启动内核
设置启动参数:在某个地址按某种格式保存参数
跳到入口地址:
bi_boot_params:启动参数所存的地址
bi_arch_number:机器ID
- 关看门狗
- 设置栈
- 初始化时钟
- 初始化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
相关文章推荐
- Linux 自检和 SystemTap
- U-Boot源码分析及移植-fs2410
- 一张图看尽 Linux 内核运行原理
- Linux内核链表实现过程
- PHP内核探索之解释器的执行过程
- 深入理解PHP内核(二)之SAPI探究
- C++中Semaphore内核对象用法实例
- 一张图看尽Linux内核运行原理
- 深入理解PHP内核(一)
- PHP内核探索之变量
- 深入php内核之php in array
- 浅谈Linux内核创建新进程的全过程
- 修改内核 内存分配 root、文件系统和内核镜像的位置
- 移植linux-2.6.30.4到S3C2440
- 看《Linux0.11内核完全注释2.01》的方法
- 升级LINUX内核(支持8G内存)的命令
- FreeBSD系统优化部分内核参数调整中文注释
- Linux2.6X内核中文件相关结构体总结
- 内核的主要配置文件的详细说明
- redhat AS4内核配置更改再编译