u-boot之内核是怎么启动的

发布者:RadiantBreeze最新更新时间:2024-08-29 来源: cnblogs关键字:u-boot  内核  启动 手机看文章 扫描二维码
随时随地手机看文章

在u-boot之start_armboot函数分析已经分析过了整个程序框架,但只是说了下什么时候运行内核,并没有具体说明是怎么执行内核的。内核启动分以下几个步骤说明:


1、启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0说明


2、run_command函数是怎么执行命令的


3、u-boot给内核传递的参数说明


4、内核启动流程


1、启动参数bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0说明


这个参数分了两条uboot命令首先从kernel区拷贝相应大小的内核到内存0x30007FC0 处;然后执行 bootm 0x30007FC0命令,这条命令后面会详细解释流程。执行了这条命令后就可以从0x30007FC0处启动内核了。这里需要再说明一下其实真正的内核位于0x30008000处,因为前面64字节是内核的一些信息,具体定义如下:


typedef struct image_header {

    uint32_t    ih_magic;    /* Image Header Magic Number    *///内核的编号 

    uint32_t    ih_hcrc;    /* Image Header CRC Checksum    */      //内核头部数据的CRC校验

    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    */   //内核数据的CRC校验

    uint8_t        ih_os;        /* Operating System        *///内核是什么操作系统

    uint8_t        ih_arch;    /* CPU architecture        */      //内核的CPU架构

    uint8_t        ih_type;    /* Image Type            */     //内核映像文件类型

    uint8_t        ih_comp;    /* Compression Type        *///压缩类型

    uint8_t        ih_name[IH_NMLEN];    /* Image Name        *///内核映像文件名称

} image_header_t;


2、run_command函数是怎么执行命令的


 run_command函数在Main.c (common)中,这个函数是整个U-BOOT命令的核心函数。uboot的链接文件中存在着.u_boot_cmd段,这个段的内容就是存放的所有的UBOOT命令


这个段的定义在command.h(include)中,如下:其中


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


#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}

//分解为=>U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) cmd_tbl_t __u_boot_cmd_name __attribute__ ((unused,section ('.u_boot_cmd'))) = {name, maxargs, rep, cmd, usage, help}

//name为命令的名字

//maxargs为命令的最大数量

//rep为命令是否可以重复,表示按下回车是否可以运行上一次的命令

//cmd表示具体命令的执行函数指针,这个函数不在.u_boot_cmd这个段内,只是函数的指针存放在.u_boot_cmd这个段内

//usage表示简短的用法说明

//help表示长的说明

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 *[]);

char    *usage;    /* Usage message    (short)    */

#ifdef    CFG_LONGHELP

char    *help;    /* Help message    (long)    */

#endif

#ifdef CONFIG_AUTO_COMPLETE

/* do auto completion on the arguments */

int    (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);

#endif

};


举个例子以bootm这个命令为例子,在u-boot控制台输入bootm命令后,u-boot代码会执行run_command(bootm, 0);这个函数。然后调用do_bootm函数。


U_BOOT_CMD(

     bootm,    CFG_MAXARGS,    1,    do_bootm,

     'bootm   - boot application image from memoryn',

     '[addr [arg ...]]n    - boot application image stored in memoryn'

     'tpassing arguments 'arg ...'; when booting a Linux kernel,n'

     't'arg' can be the address of an initrd imagen'

#ifdef CONFIG_OF_FLAT_TREE

    'tWhen booting a Linux kernel which requires a flat device-treen'

    'ta third argument is required which is the address of the of then'

    'tdevice-tree blob. To boot that kernel without an initrd image,n'

    'tuse a '-' for the second argument. If you do not pass a thirdn'

    'ta bd_info struct will be passed insteadn'

#endif

);


照着执行bootm命令继续下去,run_command(bootm, 0)函数首先做一些参数的检查


clear_ctrlc();        /* forget any previous Control C *///清除前一条命令 


    if (!cmd || !*cmd) {//检查cmd命令是否存在

        return -1;    /* empty command */

    }


    if (strlen(cmd) >= CFG_CBSIZE) {//检查参数个数是否超过最大限制

        puts ('## Command too long!n');

        return -1;

    }


    strcpy (cmdbuf, cmd);//将cmd全部拷贝到cmdbuf中


run_command(bootm, 0)继续运行,一直循环寻找str中的命令。str在初始化的时候就已经被赋为cmdbuf了。大致说明一下程序的流程:


a、首先就查询命令有几条


b、展开调用环境变量的命令


c、取得参数的个数


d、查找命令,从.u_boot_cmd段中找出符合的命令


e、执行命令的运行函数


while (*str) {//从输入的字符中取出有效命令  by andy


        /*

         * Find separator, or string end

         * Allow simple escape of ';' by writing ';'

         */

        for (inquotes = 0, sep = str; *sep; sep++) {//一直查询到最后一个字节为结束符

            if ((*sep==''') &&     //查找连接符合  

                (*(sep-1) != '\'))

                inquotes=!inquotes;  //如果是连接符的话


            if (!inquotes &&

                (*sep == ';') &&    /* separator        *///说明是多个连续的命令

                ( sep != str) &&    /* past string start    */

                (*(sep-1) != '\'))    /* and NOT escaped    */

                break;

        }


        /*

         * Limit the token to data between separators

         */

        token = str;

        if (*sep) {//如果不止一条命令 by andy

            str = sep + 1;    /* start of command for next pass *///指向下一条命令的开头,当前seq指向的是;

            *sep = '';

        }

        else

            str = sep;    /* no more commands for next pass */

#ifdef DEBUG_PARSER

        printf ('token: '%s'n', token);

#endif


        /* find macros in this token and replace them */

        process_macros (token, finaltoken);//展开环境变量  by andy,以$()或${}取得变量最终得到finaltoken


        /* Extract arguments */

        if ((argc = parse_line (finaltoken, argv)) == 0) {//取得变量个数以及变量的值存放在argv中,变量个数包括命令,所以应该大于0  by andy

            rc = -1;    /* no command at all */

            continue;

        }


        /* Look up command in command table */

        if ((cmdtp = find_cmd(argv[0])) == NULL) {//查找命令,找到后返回的是cmd_tbl_t结构体指针  by andy

            printf ('Unknown command '%s' - try 'help'n', argv[0]);

            rc = -1;    /* give up after bad command */

            continue;

        }


        /* found - check max args */

        if (argc > cmdtp->maxargs) {//验证参数的个数是否超过限制  by andy

            printf ('Usage:n%sn', cmdtp->usage);

            rc = -1;

            continue;

        }


#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)

        /* avoid 'bootd' recursion */

        if (cmdtp->cmd == do_bootd) {

#ifdef DEBUG_PARSER

            printf ('[%s]n', finaltoken);

#endif

            if (flag & CMD_FLAG_BOOTD) {

                puts (''bootd' recursion detectedn');

                rc = -1;

                continue;

            } else {

                flag |= CMD_FLAG_BOOTD;

            }

        }

#endif    /* CFG_CMD_BOOTD */


        /* OK - call function to do the command */

        if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {//调用命令函数执行  by andy

            rc = -1;

        }


        repeatable &= cmdtp->repeatable;


        /* Did the user stop this? */

        if (had_ctrlc ())//是否有crtl+c按键按下,按下的话就结束下一条命令的处理  by andy

            return 0;    /* if stopped then not repeatable */

    }


对从.u_boot_cmd段中找出符合的命令的代码做一下注释


cmd_tbl_t *find_cmd (const char *cmd)

{

    cmd_tbl_t *cmdtp;

    cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;    /*Init value */

[1] [2] [3]
关键字:u-boot  内核  启动 引用地址:u-boot之内核是怎么启动的

上一篇:u-boot之怎么实现分区
下一篇:u-boot之start_armboot函数分析

推荐阅读最新更新时间:2026-03-23 10:33

U-boot内核移植步骤
Linux 3.3.5系统移植 将arch/arm/mach-s3c6410/下的,mach-smdk6410.c cp为mach-my6410.c; 打开arch/arm/mach-s3c6410/下的Kconfig,仿照MACH_SMDK6410做一个菜单项: config MACH_MY6410 bool MY6410 select CPU_S3C6410 select SAMSUNG_DEV_ADC select S3C_DEV_HSMMC select S3C_DEV_HSMMC1 select S3C_DEV_I2C1 select SAMSUNG_DEV_IDE select
[单片机]
第十四章、TIny4412 U-BOOT移植十四 编译产生内核
一、修改过文件说明 由于前面好几章,每一个文件修改的地方都很多,一一记录太费时间,所以都说了很多原理性的东西,这里将我修改过的文件作一个总结,这里所说的修改过的文件是相对于第一章创建完的u-boot平台代码。 1、/makefile 2、sd_fuse整个文件夹,我整个复制了FriendlyARM所提供的uboot下的sd_fuse文件夹,因为这个文件是用来烧写SD卡的,所以我直接复制使用了。 3、/include/configs/zthtiny4412.h 4、/board/Samsung/zthtiny4412 5、/arch/arm/lib/board.c 6、/arch/arm/include/asm/arch-exy
[单片机]
第十四章、TIny4412 <font color='red'>U-BOOT</font>移植十四 编译产生<font color='red'>内核</font>
【IMX6ULL学习笔记】六、U-BOOT环境变量与Linux启动
一、环境变量 bootcmd bootcmd 和 bootagrs 是采用类似 shell 脚本语言编写的,里面很多的变量引用,这些变量都是环境变量,很多是 NXP 定义的。文件mx6ull_alientek_emmc.h 中的宏 CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值,内容如下: #if defined(CONFIG_SYS_BOOT_NAND) #define CONFIG_EXTRA_ENV_SETTINGS CONFIG_MFG_ENV_SETTINGS panel=TFT43AB fdt_addr=0x83000000 fdt_high=0xffff
[单片机]
【IMX6ULL学习笔记】六、<font color='red'>U-BOOT</font>环境变量与Linux<font color='red'>启动</font>
Samsung_tiny4412(驱动笔记01)----linux 3.5,U-Boot,Busybox,SD卡启动环境搭建
/*********************************************************************************** * * linux 3.5,U-Boot,Busybox,SD卡启动环境搭建 * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 以下所有的shell命令都是在root权限下运行的; * 3. minicom(U-Boot)指的是用minicom连接开发板做为U-Boot的终端; * 4. 文中在需
[单片机]
TQ2440 学习笔记—— 30、移植U-BootU-Boot启动过程第一阶段源码分析】
使用u-boot 从NOR Flash 启动,前面说过u-boot 属于两个阶段的Bootloader ,第一阶段的文件为cpu/arm920t/start.S 和 board/EmbedSky/lowlevel_init.S, 前者是平台相关的,后者是开发板相关的。 一、u-boot 第一阶段代码分析 (1)硬件设备初始化 依次完成如下设置:将CPU 的工作模式设为管理模式(svc),关闭WATCHDOG ,设置FCLK、HCLK、PCLK 的比例(即设置CLKDIVN寄存器),关闭MMU、CACHE。部分代码如下: (2)为加载Bootloader 的第二阶段代码准备RAM 空间 所谓准备RAM 空间,就
[单片机]
TQ2440 学习笔记—— 30、移植<font color='red'>U-Boot</font>【<font color='red'>U-Boot</font> 的<font color='red'>启动</font>过程第一阶段源码分析】
如何在Ubuntu下使用TF/SD 卡制作Exynos 4412 u-boot启动
/** ****************************************************************************** * @author Maoxiao Hu * @version V1.0.1 * @date Feb-2015 ****************************************************************************** * COPYRIGHT 2015 ISE of SHANDONG UNIVERSITY **************************************************
[单片机]
如何在Ubuntu下使用TF/SD 卡制作Exynos 4412 <font color='red'>u-boot</font><font color='red'>启动</font>盘
基于S3C6410处理器的U-Boot SD卡启动的移植分析与功能
通用Bootloader(Universal Bootloader,U-Boot)是系统上电后执行的第一段代码,其作用主要包括初始化硬件环境以及加载执行操作系统内核。在进行系统安装时,U-Boot通常需要使用专用工具烧写到FLASH中,内核及文件系统则通过U-Boot命令进行烧写,该过程操作繁琐,并且容易出错,不适宜系统的大量安装。 S3C6410是三星公司生产的一款基于ARM11架构的通用嵌入式处理器,其启动方式除了传统的Flash启动模式外,还支持从SD 卡中启动系统。本文基于S3C6410处理器,分析了从SD卡启动系统的原理,并对U-Boot源码进行修改以支持该启动方式,在此基础上进一步扩展了U-Boot的功能,使其
[单片机]
基于S3C6410处理器的<font color='red'>U-Boot</font> SD卡<font color='red'>启动</font>的移植分析与功能
Linux内核启动流程-迅为IMX6ULL开发板(一)
在前面的章节介绍了uboot和Linux内核的一些相关内容。在来看Linux内核的大致启动流程,Linux内核的启动流程要比uboot复杂的多,涉及到的内容也更多,因此在本章节大致简单的了解一下Linux内核的启动流程。有兴趣的用户可以参考其他书籍或资料进行深入了解。 嵌入式linux内核的启动全过程主要分为三个阶段。第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式、使能MMU、设置一级页表等,而第三阶段则主要为C代码,包括内核初始化的全部工作。下面分别进行简单介绍。 基于迅为-IMX6ULL开发板 30.1 Linux内核启动(一):Linux内核自解压过程 Linux内核有两种映像格式:一种是非压缩
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved