u-boot 2011.09 调用kernel 的流程
这段时候我总是觉得有个问题,u-boot 的存在是不是就是为了调用kernel 而存在的。
所以,粗浅的跟了一下这个流程,还有很多细节上的东西没有做好,往指正。
u-boot-2011.9 调用内核代码跟踪
1. _start board_init_r main_loop.
这个流程是u-boot 的一个整体的流程。
2. main_loop()
这个函数主要执行一些u-boot 最后的一些工作,
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
这里是设置系统的启动延时的时间。
如果在include/configs/ok335x.h 里面设置了宏定义CONFIG_BOOTDELAY大于零
那么在延时期间中断便可进入shell 终端界面。
s = getenv ("bootcmd"); debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); if (bootdelay >= && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(); /* disable Control C checking */
# endif # ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0);
这里面就有关于u-boot 调用kernel 的方法。
Bootcmd 的定义在common/env_common.c 里面。
#ifdef CONFIG_BOOTARGS
"bootargs=" CONFIG_BOOTARGS "\0"
这是关于bootcmd 的定义。
在c语言中一个字符串其实本质上代表的就是的指针。
Bootcmd 指向的是CONFIG_BOOTCOMMAND 这个地址。
CONFIG_BOOTCOMMAND 这个宏的定义在include/configs/ok335x.h 里面。
#define CONFIG_BOOTCOMMAND \
" if test $bootdev = MMC; then " \
"mmc dev ${mmcdev}; mmc rescan;"\
"echo SD/MMC found on device ${mmcdev};" \
"if run loadbootenv; then " \
"echo Loaded environment from ${bootenv};" \
"run importbootenv;" \
"fi;" \
"if test -n $uenvcmd; then " \
"echo Running uenvcmd ...;" \
"run uenvcmd;" \
"fi;" \
"if run loaduimagefat; then " \
"run mmcboot;" \
"elif run loaduimage; then " \
"run mmcboot;" \
"else " \
"echo Could not find ${bootfile} ;" \
"fi;" \
"else " \
"run nandboot;" \
"fi;" \
这边的话我们是直接运行run nandboot ;
"nandboot=echo Booting from nand ...; " \
"run nandargs; " \
"nandecc hw 2;"\
"nand read ${loadaddr} ${nandsrcaddr} ${nandimgsize}; " \
"bootm ${loadaddr}\0" \
最后运行bootm ${loadaddr} ,就可以运行kernel 。
3. run_command() 函数
这个函数的实现在common/main.c 里面。
运行run_command 函数,如果成功运行,返回1或者0,如果没有运行则返回-1。
命令结构体。
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
char *usage; /* Usage message (short) */
#ifdef CONFIG_SYS_LONGHELP
char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *c mdv[]);
#endif
}; typedef struct cmd_tbl_s cmd_tbl_t;
最后运行这条命令。
/* OK - call function to do the command */
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
rc = -;
}
4. bootm 命令分析
在run_command 里面,以及前面的分析可以得出,最终,他会调用
bootm 命令,并且指向kernel 的地址。
bootm 命令的实现是在common/cmd_bootm.c 中实现。
/*******************************************************************/
/* bootm - boot application image from image in memory */
/*******************************************************************/ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
其实这个函数做了三个很重要的功能。
bootm_start : 内核启动前的准备工作,获取内核的信息并检查。
bootm_load_os : 检查内核的文件格式,是否需要解压。
boot_fn : 内核启动函数的调用, 我们调用的是do_bootm_linux 函数。
1) bootm_start
从do_bootm 调用了这一个函数。
if (bootm_start(cmdtp, flag, argc, argv))
return ;
有时候我们加载内核不成功,很多时候会报can’t get kernel image就是在这里报的。
从下可以看到,我们又调用了boot_get_kernel 函数。
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
void *os_hdr;
int ret; memset ((void *)&images, , sizeof (images));
images.verify = getenv_yesno ("verify"); bootm_start_lmb(); /* get kernel image header, start address and length */
os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
&images, &images.os.image_start, &images.os.image_len);
if (images.os.image_len == ) {
puts ("ERROR: can't get kernel image!\n");
return ;
}
这个函数的作用其实是:找到kernel 镜像。
static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] ,
bootm_headers_t *images, ulong *os_data, ulong *os_len)
{
image_header_t *hdr;
ulong img_addr;
} else {
img_addr = simple_strtoul(argv[], NULL, );
debug ("* kernel: cmdline image address = 0x%08lx\n", img_addr);
} show_boot_progress (); /* copy from dataflash if needed */
img_addr = genimg_get_image (img_addr); /* check image type, for FIT images get FIT kernel node */
*os_data = *os_len = ;
switch (genimg_get_format ((void *)img_addr)) {
case IMAGE_FORMAT_LEGACY:
printf ("## Booting kernel from Legacy Image at %08lx ...\n",
img_addr);
hdr = image_get_kernel (img_addr, images->verify);
打印一句调试信息。
然后通过image_get_kernel 获取kernel.
static image_header_t *image_get_kernel (ulong img_addr, int verify)
{
image_header_t *hdr = (image_header_t *)img_addr; if (!image_check_magic(hdr)) {
puts ("Bad Magic Number\n");
show_boot_progress (-);
return NULL;
}
show_boot_progress (); if (!image_check_hcrc (hdr)) {
puts ("Bad Header Checksum\n");
show_boot_progress (-);
return NULL;
} show_boot_progress ();
image_print_contents (hdr); if (verify) {
puts (" Verifying Checksum ... ");
if (!image_check_dcrc (hdr)) {
printf ("Bad Data CRC\n");
show_boot_progress (-);
return NULL;
}
puts ("OK\n");
}
show_boot_progress (); if (!image_check_target_arch (hdr)) {
printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));
show_boot_progress (-);
return NULL;
}
return hdr;
}
void image_print_contents (const void *ptr)
{
const image_header_t *hdr = (const image_header_t *)ptr;
const char *p; #ifdef USE_HOSTCC
p = "";
#else
p = " ";
#endif printf ("%sImage Name: %.*s\n", p, IH_NMLEN, image_get_name (hdr));
#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || defined(USE_HOSTCC)
printf ("%sCreated: ", p);
genimg_print_time ((time_t)image_get_time (hdr));
#endif
printf ("%sImage Type: ", p);
image_print_type (hdr);
printf ("%sData Size: ", p);
genimg_print_size (image_get_data_size (hdr));
printf ("%sLoad Address: %08x\n", p, image_get_load (hdr));
321 printf ("%sEntry Point: %08x\n", p, image_get_ep (hdr)); if (image_check_type (hdr, IH_TYPE_MULTI) ||
image_check_type (hdr, IH_TYPE_SCRIPT)) {
int i;
ulong data, len;
ulong count = image_multi_count (hdr); printf ("%sContents:\n", p);
for (i = ; i < count; i++) {
image_multi_getimg (hdr, i, &data, &len); printf ("%s Image %d: ", p, i);
genimg_print_size (len); if (image_check_type (hdr, IH_TYPE_SCRIPT) && i > ) {
/*
338 * the user may need to know offsets
339 * if planning to do something with
340 * multiple files
341 */
printf ("%s Offset = 0x%08lx\n", p, data);
}
}
}
}
打印内核信息。打印校验和校验是否正确。
OK,到此从image_get_kernel - > boot_get_kernel 回来。
if (!image_check_target_arch (hdr)) {
printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));
show_boot_progress (-);
return NULL;
}
return hdr;
}
返回内核地址。
再从boot_get_kernel 回到bootm_start
/* get image parameters */
switch (genimg_get_format (os_hdr)) {
case IMAGE_FORMAT_LEGACY:
images.os.type = image_get_type (os_hdr);
236 images.os.comp = image_get_comp (os_hdr);
237 images.os.os = image_get_os (os_hdr);
238
239 images.os.end = image_get_image_end (os_hdr);
240 images.os.load = image_get_load (os_hdr);
break;
获取内核的参数并保存。
default:
puts ("ERROR: unknown image format type!\n");
return ;
有时候我们加载内核失败会报这个错误。
/* find kernel entry point */
if (images.legacy_hdr_valid) {
images.ep = image_get_ep (&images.legacy_hdr_os_copy);
找到内核的入口。
if (((images.os.type == IH_TYPE_KERNEL) ||
(images.os.type == IH_TYPE_MULTI)) &&
(images.os.os == IH_OS_LINUX)) {
/* find ramdisk */
ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,
&images.rd_start, &images.rd_end);
if (ret) {
puts ("Ramdisk image is corrupt or invalid\n");
return ;
}
获取虚拟磁盘。
images.os.start = (ulong)os_hdr;
322 images.state = BOOTM_STATE_START; return ;
}
保存内核开启地址,并给开始的状态。
从bootm_start 回到do_bootm.
if (bootm_start(cmdtp, flag, argc, argv))
return ;
正常情况下bootm_start 是返回0,所以不会执行return 1;
2) bootm_load_os 函数
ret = bootm_load_os(images.os, &load_end, );
获取文件类型,打印调试信息。
#define BOOTM_ERR_RESET -1
#define BOOTM_ERR_OVERLAP -2
#define BOOTM_ERR_UNIMPLEMENTED -3
static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress)
{
uint8_t comp = os.comp;
ulong load = os.load;
ulong blob_start = os.start;
ulong blob_end = os.end;
ulong image_start = os.image_start;
ulong image_len = os.image_len;
uint unc_len = CONFIG_SYS_BOOTM_LEN;
#if defined(CONFIG_LZMA) || defined(CONFIG_LZO)
int ret;
#endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */ const char *type_name = genimg_get_type_name (os.type); switch (comp) {
case IH_COMP_NONE:
if (load == blob_start || load == image_start) {
printf (" XIP %s ... ", type_name);
} else {
printf (" Loading %s ... ", type_name);
memmove_wd ((void *)load, (void *)image_start,
image_len, CHUNKSZ);
}
*load_end = load + image_len;
puts("OK\n");
break;
flush_cache(load, (*load_end - load) * sizeof(ulong)); puts ("OK\n");
debug (" kernel loaded at 0x%08lx, end = 0x%08lx\n", load, *load_end);
if (boot_progress)
show_boot_progress (); if ((load < blob_end) && (*load_end > blob_start)) {
debug ("images.os.start = 0x%lX, images.os.end = 0x%lx\n", blob_start, blob_end );
debug ("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end); return BOOTM_ERR_OVERLAP;
} return ;
}
从bootm_load_os 回到do_bootm
ret = bootm_load_os(images.os, &load_end, 1); if (ret < ) {
if (ret == BOOTM_ERR_RESET)
do_reset (cmdtp, flag, argc, argv);
if (ret == BOOTM_ERR_OVERLAP) {
if (images.legacy_hdr_valid) {
if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
puts ("WARNING: legacy format multi component "
"image overwritten\n");
} else {
puts ("ERROR: new format image overwritten - "
"must RESET the board to recover\n");
show_boot_progress (-);
do_reset (cmdtp, flag, argc, argv);
}
}
if (ret == BOOTM_ERR_UNIMPLEMENTED) {
if (iflag)
enable_interrupts();
show_boot_progress (-);
return ;
}
}
如果刚才出错,那么检查错误编号,打印错误信息。
boot_fn = boot_os[images.os.os]; if (boot_fn == NULL) {
if (iflag)
enable_interrupts();
printf ("ERROR: booting os '%s' (%d) is not supported\n",
genimg_get_os_name(images.os.os), images.os.os);
show_boot_progress (-);
return ;
} arch_preboot_os(); boot_fn(0, argc, argv, &images);
其实这一步调用的是do_bootm_linux
static boot_os_fn *boot_os[] = {
#ifdef CONFIG_BOOTM_LINUX
[IH_OS_LINUX] = do_bootm_linux,
#endif
#ifdef CONFIG_BOOTM_NETBSD
[IH_OS_NETBSD] = do_bootm_netbsd,
#endif
#ifdef CONFIG_LYNXKDI
[IH_OS_LYNXOS] = do_bootm_lynxkdi,
#endif
#ifdef CONFIG_BOOTM_RTEMS
[IH_OS_RTEMS] = do_bootm_rtems,
#endif
#if defined(CONFIG_BOOTM_OSE)
[IH_OS_OSE] = do_bootm_ose,
#endif
#if defined(CONFIG_CMD_ELF)
[IH_OS_VXWORKS] = do_bootm_vxworks,
[IH_OS_QNX] = do_bootm_qnxelf,
#endif
#ifdef CONFIG_INTEGRITY
[IH_OS_INTEGRITY] = do_bootm_integrity,
#endif
};
do_bootm_linux 函数其实在arch/arm/lib/bootm.c里面
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
bd_t *bd = gd->bd;
char *s;
int machid = bd->bi_arch_number;
void (*kernel_entry)(int zero, int arch, uint params); #ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs");
#endif if ((flag != ) && (flag != BOOTM_STATE_OS_GO))
return ; s = getenv ("machid");
if (s) {
machid = simple_strtoul (s, NULL, );
printf ("Using machid 0x%x from environment\n", machid);
} show_boot_progress (); #ifdef CONFIG_OF_LIBFDT
if (images->ft_len)
return bootm_linux_fdt(machid, images);
#endif kernel_entry = (void (*)(int, int, uint))images->ep; debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong) kernel_entry);
声明一个函数指针。
把镜像入口给kernel_entry 这个函数指针。
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG)
setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (images->rd_start && images->rd_end)
setup_initrd_tag (bd, images->rd_start, images->rd_end);
#endif
setup_end_tag(bd);
#endif
初始化开始标签。
初始化串口。
初始化版本信息。
初始化内存。
初始化命令行。
End.
announce_and_cleanup(); kernel_entry(0, machid, bd->bi_boot_params);
/* does not return */ return ;
}
正式进入内核。
参考:http://blog.csdn.net/g_salamander/article/details/8463854
u-boot 2011.09 调用kernel 的流程的更多相关文章
- andriod and linux kernel启动流程
虽然这里的Arm Linux kernel前面加上了Android,但实际上还是和普遍Arm linux kernel启动的过程一样的,这里只是结合一下Android的Makefile,讲一下boot ...
- 深入 kernel panic 流程【转】
一.前言 我们在项目开发过程中,很多时候会出现由于某种原因经常会导致手机系统死机重启的情况(重启分Android重启跟kernel重启,而我们这里只讨论kernel重启也就是 kernel panic ...
- http://www.blogjava.net/xzclog/archive/2011/09/29/359789.html
http://www.blogjava.net/xzclog/archive/2011/09/29/359789.html http://bbs.csdn.net/topics/380187593
- http://www.ruanyifeng.com/blog/2011/09/restful
http://www.ruanyifeng.com/blog/2011/09/restful
- Unable to boot : please use a kernel appropriate for your cpu
假设你在virtualbox里得到这种提示信息: Unable to boot - please use a kernel appropriate for your CPU 以下的解决的方法,能够帮你 ...
- JNI NDK (AndroidStudio+CMake )实现C C++调用Java代码流程
JNI/NDK Java调用C/C++前言 通过第三篇文章讲解在实际的开发过程中Java层调用C/C++层的处理流程.其实我们在很大的业务里也需要C/C+ +层去调用Java层,这两层之间的相互调用 ...
- 修复VirtualBox "This kernel requires the following features not present on the CPU: pae Unable to boot – please use a kernel appropriate for your CPU"
异常处理汇总-开发工具 http://www.cnblogs.com/dunitian/p/4522988.html 修复VirtualBox "This kernel requires ...
- u-boot 2011.09 使用自己的board 以及config.h
一个新的方案,用的UBOOT 可能和上一个方案是同一个,但是配置有可能不一样,今天记录一下通过修改配置文件使用新的 board 文件以及 config.h 进入 u-boot 2011.09 // 打 ...
- 修复VirtualBox "This kernel requires the following features not present on the CPU: pae Unable to boot – please use a kernel appropriate for your CPU"(安装深度Linux的时候就需要)
异常处理汇总-开发工具 http://www.cnblogs.com/dunitian/p/4522988.html 修复VirtualBox "This kernel requires ...
随机推荐
- SDK
IOS: iOS Application Life Cycle 应用程序生命周期 http://www.cnblogs.com/chenyg32/p/3873301.html iOS应用程序生命周期( ...
- Django笔记-登陆、注册(利用cookie实现)
1.项目结构: 2.关键代码: settings.py INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'djang ...
- Node.js Tools 1.2 for Visual Studio 2015 released
https://blogs.msdn.microsoft.com/visualstudio/2016/07/28/node-js-tools-1-2-visual-studio-2015/ What ...
- ssh远程连接ubuntu
1. 首先在服务器上安装ssh的服务器端. $ sudo aptitude install openssh-server 2. 启动ssh-server. $ sudo /etc/init.d/ss ...
- 表达式拼接Expression<Func<IEntityMapper, bool>> predicate
/// <summary> /// 重写以筛选出当前上下文的实体映射信息 /// </summary> protected override IEnumerable<IE ...
- Linux 挂载 NFS
NFS(网络文件系统),这是在 Linux 系统上常用的文件共享方式.也可以做为作为一个远程存储使用,比如:我有个网站,用户可以上传文件,但文件慢慢会越来越多,这个时候我们只能把存放上传文件的目录挂在 ...
- [Unity] 2D开发学习教程
豆子先生,据说是官方的一个Demo, 在蛮牛网上有大部分代码的视频讲解. 这个是我学习过程中边看教程边写出来的,功能和原版基本一样,增加了手游的操控. Blog: http://www.cnblogs ...
- 整理一下Entity Framework的查询
整理一下Entity Framework的查询 2012-08-30 13:41:59 标签:Entity Framework 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信 ...
- mysql数据表分表策略(转)
mysql分表方法: 方法一. 做数据库集群! 主从数据库 双向热备份(或一对多的数据库实时备份策略),这样可将数据库查询分摊到几个服务器去(可跟服务器负载均衡结合起来架构) 优点:扩展性好,没有多个 ...
- CF456C Boredom (DP)
Boredom CF#260 div2 C. Boredom Codeforces Round #260 C. Boredom time limit per test 1 second memory ...