标题:

  Uboot -kerne-root 启动流程

内容:

  ※uboot启动流程

  ※Kernel启动流程

  ※Root启动流程

  ※构建根文件系统

/*********************************

*u-boot:   u-boot2012.04.01

*kernel:    linux-2.6.22

*busybox:    busybox-1.1.6

*********************************/

一、uboot启动流程

1.初始化硬件

2.把内核从NAND读到SDRAM

3.设置内核启动参数

4.跳转执行内核

执行第一个代码:/cpu/arm920t/start.S

第一阶段(start.S)

reset:

  set the cpu to SVC32 mode          //管理模式

  turn off the watchdog               //关看门狗

  mask all IRQs                         //屏蔽中断

   cpu_init_crit

  flush v4 I/D caches              //关闭caches

  disable MMU stuff and caches     //关闭MMU

  lowlevel_init  //配置SDRAM

   Relocate                          //重定位

   stack_setup:                       //设置堆栈

  clear_bss:                         //清楚bss段

  start_armboot                      //跳转执行第二阶段

第二阶段(board.c)

start_armboot (void)

  init_sequence

  cpu_init,                      /* basic cpu dependent setup */

  board_init,                   /* basic board dependent setup */

  interrupt_init,              /* set up exceptions */

  env_init,                      /* initialize environment */

  init_baudrate,               /* initialze baudrate settings */

  serial_init,                   /* serial communications setup */

  console_init_f,             /* stage 1 init of console */

  display_banner,                        /* say that we are here */

  flash_init            初始化NOR

  nand_init()           初始化NAND

  env_relocate ()        将环境变量读入指定位置

  cs8900_get_enetaddr     初始化网络设备

  main_loop ()            死循环

    s = getenv ("bootdelay")

      bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

    s = getenv ("bootcmd");

    Bootcmd=nand read.jffs2 0x30007fc0 kernel;bootm 0x30007fc0  //环境变量

    run_command (s, 0);

    continue;

Uboot命令的实现

①串口输入命令(字符串)

②动作(函数),命令对应于名字

因而根据命令找到对应函数,来执行。Uboot里面有一个结构体

包含1.名

2.函数

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

};

此时run_command函数根据名字匹配该结构体

Run_command

命令的提取

while (*str) {

/*

* 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;

}

parse_line()   //解析命令

Cmdtp=find_cmd()      //匹配命令  cmdtp就是指向上面的结构体cmd_tbl_s

for (cmdtp = &__u_boot_cmd_start;

cmdtp != &__u_boot_cmd_end;

cmdtp++)

以上:

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

比如启动命令:

Bootcmd=nand read.jffs2 0x30007fc0 kernel;bootm 0x30007fc0以bootm 0x30007fc0为例

U_BOOT_CMD(

bootm,  CFG_MAXARGS,         1,         do_bootm,

"bootm   - boot application image from memory\n",

"[addr [arg ...]]\n    - boot application image stored in memory\n"

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

"\t'arg' can be the address of an initrd image\n"

#ifdef CONFIG_OF_FLAT_TREE

"\tWhen booting a Linux kernel which requires a flat device-tree\n"

"\ta third argument is required which is the address of the of the\n"

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

"\tuse a '-' for the second argument. If you do not pass a third\n"

"\ta bd_info struct will be passed instead\n"

#endif

);

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}

以上可以展开为;

cmd_tbl_t __u_boot_cmd_bootm  __attribute__ ((unused,section (".u_boot_cmd")))

= {bootm, CFG_MAXARGS, 1, do_bootm, "bootm   - boot application image from memory\n", help}

以上解释为:bootm命令定义了__u_boot_cmd_bootm结构体,该结构体类型是cmd_tbl_t,并且强制为.u_boot_cmd段属性

Uboot启动内核

内核启动依赖nand read.jffs2 0x30007fc0 kernel;bootm 0x30007fc0

nand read.jffs2 0x30007fc0 kernel把内核读到0x30007fc0

从哪里读? --kernel分区在配置文件里面写死了smdk2410.h

读到哪里? --0x30007fc0

Nand命令分析:

"nand read[.jffs2]     - addr off|partition size\n"

bootm 0x30007fc0从bootm 0x30007fc0启动它

Bootm命令分析:

do_bootm

image_header_t *hdr = &header;

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;

memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

//如果当前地址不是入口地址,移到加载地址0x30008000,由于头部占用64字节,所以此时地址是0x30007fc0

do_bootm_linux  (cmdtp, flag, argc, argv,

addr, len_ptr, verify); //启动内核

setup_start_tag (bd);

setup_memory_tags (bd);

setup_commandline_tag (bd, commandline);

setup_end_tag (bd);

printf ("\nStarting kernel ...\n\n");

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

theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

二、Kernel启动流程

处理uboot传入的参数

①判断是否支持这个CPU

②判断是否支持这个单板

③建立页表

④使能MMU

⑤跳到start_kernel函数

内核执行的第一个代码文件:/arch/arm/kernel/head.S  和 /arch/arm/boot/bootp/init.S

Start_kernel分析

1.输出内核版本信息

2.Setup_arch($command_line)

3.Setup_command_line(command_line)

调用关系:

Start_kernel

printk(linux_banner);   //输出版本信息

setup_arch(&command_line); //匹配ID,arch-type

setup_processor();

list = lookup_processor_type(processor_id);

mdesc = setup_machine(machine_arch_type);

parse_cmdline(cmdline_p, from); //解析命令

setup_command_line(command_line);

strcpy (saved_command_line, boot_command_line);

Rest_init

  Kernel_thread()    //线程

  // kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

    kernel_init()

    Prepare_namespace()

    Mount_root()

    Init_post()

      Run_init_process()  //执行文件系统第一个程序

      ...

三、Root启动流程

init过程

1.读取配置文件

2.解析配置文件

3.执行客户程序

配置文件:1.指定程序;2.何时执行

busybox调用过程

busybox -> init_main

parse_inittab

file = fopen(INITTAB, "r");//打开配置文件/etc/inittab

(没有配置文件时使用默认配置文件)

new_init_action()

#1.创建init_action结构,填充

#2.把这个结构放入init_action_list链表里面

run_actions(SYSINIT);

waitfor(a, 0); //执行程序,等待执行完毕

run(a); //系统调用,创建precess子进程

waitpid(runpid, &status, 0) //等待结束

delete_init_action(a);//在init_action_list里面删掉应用程序

run_actions(WAIT);

waitfor(a, 0);

delete_init_action(a);

run_actions(ONCE);

run(a);//不会等待子进程结束

delete_init_action(a);//在init_action_list里面删

while (1) {

run_actions(RESPAWN);

run(a)

run_actions(ASKFIRST);

run(a)

打印:"\nPlease press Enter to activate this console. ";

等待回车

创建子进程

wpid = wait(NULL);//等待子进程退出

while (wpid > 0) {

a->pid = 0;//退出后,设置pid=0

}

}

init_action_list里面有id,action,process等等

static void new_init_action(int action, const char *command, const char *cons)

struct init_action *new_action, *a, *last;

init_action里面有:

struct init_action *next;

int action;

pid_t pid;    //进程号

char command[INIT_BUFFS_SIZE];  //应用程序

char terminal[CONSOLE_NAME_SIZE];  //终端

new_init_action做了什么

1.创建init_action结构,填充

2.把这个结构放入init_action_list链表里面

现在假设没有配置文件,根据

/* No inittab file -- set up some default behavior */

#endif

/* Reboot on Ctrl-Alt-Del */

new_init_action(CTRLALTDEL, "reboot", "");

/* Umount all filesystems on halt/reboot */

new_init_action(SHUTDOWN, "umount -a -r", "");

/* Swapoff on halt/reboot */

if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");

/* Prepare to restart init when a HUP is received */

new_init_action(RESTART, "init", "");

/* Askfirst shell on tty1-4 */

new_init_action(ASKFIRST, bb_default_login_shell, "");

new_init_action(ASKFIRST, bb_default_login_shell, VC_2);

new_init_action(ASKFIRST, bb_default_login_shell, VC_3);

new_init_action(ASKFIRST, bb_default_login_shell, VC_4);

/* sysinit */

new_init_action(SYSINIT, INIT_SCRIPT, "");

来反推出默认配置项

#inittab格式:(文件在example/inittab文件)

#<id>:<runlevels>:<action>:<process>

#<id>         :/dev/id,最终用作终端:stdin,stdout,stderrer:printf,scanf,err

#<runlevels>  :忽略

#<action>     :何时执行的

<action>: Valid actions include: sysinit, respawn, askfirst, wait, once,

restart, ctrlaltdel, and shutdown.

#<process>    :应用程序或者脚本

new_init_action(ASKFIRST, -/bin/sh, /dev/tty2);

new_init_action(CTRLALTDEL, "reboot", "");

id=null

runlevels=null

action=ctrlaltdel

那么上面就是:

::ctrlaltdel:reboot

同理可知其他的配置项是:

::shutdown:umount -a -r

::restart:init

::askfirst:-/bin/sh

tty2:askfirst:-/bin/sh

tty3:askfirst:-/bin/sh

tty4:askfirst:-/bin/sh

::sysinit:/etc/init.d/rcS

其实:

main里面

signal(SIGHUP, exec_signal);

signal(SIGQUIT, exec_signal);

signal(SIGUSR1, shutdown_signal);

signal(SIGUSR2, shutdown_signal);

signal(SIGINT, ctrlaltdel_signal);

signal(SIGTERM, shutdown_signal);

signal(SIGCONT, cont_handler);

signal(SIGSTOP, stop_handler);

signal(SIGTSTP, stop_handler);

当用户按下 ctrl + alt +del时会产生一个信号,然后执行ctrlaltdel_signal函数

static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED)

{

run_actions(CTRLALTDEL);

}

总结:应用程序所需要的文件

1./dev/console /dev/null

2.配置文件/etc/inittab

3.配置文件里面指定的应用程序

4.库文件

5.init本身,即busybox

以上就是最小根文件系统所需要的项

构建根文件系统

read  INSTALL  rirst.

总结:应用程序所需要的文件

1./dev/console /dev/null

2.配置文件/etc/inittab

3.配置文件里面指定的应用程序

4.库文件

5.init本身,即busybox

以上就是最小根文件系统所需要的项

编译busybox

先阅读install文件可知道如何编译它

make menuconfig

make

make install(这里安装要注意)

安装到我们指定的某个文件里面

使用make CONFIG_PREFIX=/path/from/root install

编译需要在makefile里面加上cross_compiler里面加上arm-linux-

一、创建console

现在上面编译后busybox目录是work/FL_fs/first_fs

在此目录下:ls /dev/console /dev/null -l

crw------- 1 root root 5, 1 2015-01-05 20:57 /dev/console

crw-rw-rw- 1 root root 1, 3 2015-01-05 20:30 /dev/null

那么根据它来创建console null等设备

#mkdir dev

#cd dev

#mknod console c 5 1

#mknod null c 1 3

#ls -l

显示:

crw-r--r-- 1 root root 5, 1 2015-05-06 20:39 console

crw-r--r-- 1 root root 1, 3 2015-05-06 20:40 null

表示创建成功

二、配置项

#cd work/FL_fs/first_fs

#mkdir etc

#vim  etc/inittab

输入:

console::askfirst:-/bin/sh

三、安装c库

#cd lib

#cp /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib *.so* /work/FL_fs/first_fs/lib -d

end

最小根文件系统已经完成。

此时需要制作镜像文件以烧写到硬件。

yaffs2和jffs文件系统

1.制作yaffs2

#cd work/system

yaffs_source_util_large_smmall_page_nand.tar.bz2

#tar xjf  yaffs_source_util_large_small_page_nand.tar.bz2

#cd Developement_util_ok

#cd yaffs2

#cd utils

#make

#cp mkyaffs2image /usr/local/bin

#chmod +x /usr/local/bin/mkyaffs2image

#cd /work/FL_fs

#mkyaffs2image first_fs first_fs.yaffs2

此后烧写到开发板里面。

可以启动,并能使用ls,cd等命令。

如何改进?

#cd ../first_fs

#mkdir proc

单板上有虚拟系统

#mkdir proc

#mount -t proc none /proc

#ps

可以看到哪些程序及其内容

PID TTY          TIME CMD

383 pts/2    00:00:00 ps

30564 pts/2    00:00:00 su

30573 pts/2    00:00:00 bash

383 进程号

#cd 383

如果不想 手动挂载 #mount -t proc none /proc

也可以写到配置文件里面

#vim inittab

++ ::sysinit:/etc/init.d/rcS  需要脚本

#mkdir etc/init.d

#vim rcS

##mount -t proc none /proc

#chmod +x /etc/init.d/rcS

就可以了

上面#mount -t proc none /proc

也可以使用#mount -a

#mount -a是什么意思?

读出/etc/fstab内容来挂载

怎么使用呢?

#mount -a会依赖fstab文件

fstab文件内容有哪些呢?

#device         mount-point    type     options     dump   fsck

proc        /proc        proc defaults    0       0

那么,在/etc/fstab里面输入:

proc   /proc    default 0 0

然后在脚本rcS里面使用#mount -a

然后再制作yaffs镜像文件就和第一种方法是一样的。

可以使用#cat /proc/mounts查看挂载了哪些文件系统

继续

上面的dev是手工创建

那么怎么自动创建dev下面的设备节点呢

方法:使用mdev

怎么使用mdev?  在/

可以查看mdev.txt

[1] mount -t sysfs sysfs /sys

[2] echo /bin/mdev > /proc/sys/kernel/hotplug

[3] mdev -s

[4] mount -t tmpfs mdev /dev

[5] mkdir /dev/pts

[6] mount -t devpts devpts /dev/pts

这6步就可以了。

所以:

1、#cd ../first_fs

#mkdir sys

[1] mount -t sysfs sysfs /sys

[4] mount -t tmpfs mdev /dev

应该怎么做?

#vim /etc/fstab

#device         mount-point    type     options     dump   fsck

proc        /proc        proc defaults    0        0

sysfs           /sys           sysfs    default     0      0

tmpfs           /dev           tmpfs    default     0      0

[2] echo /bin/mdev > /proc/sys/kernel/hotplug

[3] mdev -s

[5] mkdir /dev/pts

[6] mount -t devpts devpts /dev/pts

怎么做呢?

#cd /etc/init.d/rcS

mount -a

mkdir /dev/pts/

mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev -s

u-boot、kernel和filesystem 执行过程分析的更多相关文章

  1. ASP.NET MVC应用程序执行过程分析

    ASP.NET MVC应用程序执行过程分析 2009-08-14 17:57 朱先忠 朱先忠的博客 字号:T | T   ASP.NET MVC框架提供了支持Visual Studio的工程模板.本文 ...

  2. Ansible系列(七):执行过程分析、异步模式和速度优化

    本文目录:1.1 ansible执行过程分析1.2 ansible并发和异步1.3 ansible的-t选项妙用1.4 优化ansible速度 1.4.1 设置ansible开启ssh长连接 1.4. ...

  3. MFC的执行过程分析

    MFC程序的执行细节剖析 MFC程序也是Windows程序,所以它应该也有一个WinMain.可是在程序中看不到它的踪影.事实上在程序进入点之前.另一个(并且仅有一个)全局对象(theApp).这就是 ...

  4. ARM Linux从Bootloader、kernel到filesystem启动流程

    转自:http://www.veryarm.com/1491.html ARM Linux启动流程大致为:bootloader ---->kernel---->root filesyste ...

  5. spring boot mybatis 打成可执行jar包后启动UnsatisfiedDependencyException异常

    我的spring boot + mybatis项目在idea里面执行正常,但发布测试环境打成可执行jar包后就启动失败,提示错误如下: [ ERROR] [2018-08-30 17:23:48] o ...

  6. Linux kernel 之 socket 创建过程分析

    重要结构体 struct socket 结构体 // 普通的 BSD 标准 socket 结构体 // socket_state: socket 状态, 连接?不连接? // type: socket ...

  7. Spring Boot Maven 打包可执行Jar文件!

    Maven pom.xml 必须包含 <packaging>jar</packaging> <build> <plugins> <plugin&g ...

  8. Spring Boot Gradle 打包可执行Jar文件!

    使用Gradle构建项目,继承了Ant的灵活和Maven的生命周期管理,不再使用XML作为配置文件格式,采用了DSL格式,使得脚本更加简洁. 构建环境: jdk1.6以上,此处使用1.8 Gradle ...

  9. 将 Spring boot 项目打成可执行Jar包,及相关注意事项(main-class、缺少 xsd、重复打包依赖)

    最近在看 spring boot 的东西,觉得很方便,很好用.对于一个简单的REST服务,都不要自己部署Tomcat了,直接在 IDE 里 run 一个包含 main 函数的主类就可以了. 但是,转念 ...

随机推荐

  1. git fetch和git pull(转载)

    From:http://www.tech126.com/git-fetch-pull/ Git中从远程的分支获取最新的版本到本地有这样2个命令: 1. git fetch:相当于是从远程获取最新版本到 ...

  2. jsLint配置参数解释

    转自: http://www.cnblogs.com/elementstorm/archive/2013/04/10/3012679.htmlanon :true //匿名函数声明中function关 ...

  3. 对json数据进行类似sql查询

    添加js引用:jsonsql-0.1.js 通过下面列子得到一个json类型的结果 Example: jsonsql.query("select * from json.channel.it ...

  4. AngularJs编写指令

    <!DOCTYPE html> <html ng-app="app"> <head lang="en"> <meta ...

  5. Angularjs路由.让人激动的技术.真给前端长脸了.

    先看文件的摆放 不废话,直接上代码. detail.html: <hr/> <h3>路由 <span style="color: red;">{ ...

  6. Python之几个技巧特点

    今天偶然看到一篇文章<你可能不知道的30个Python语言的提点技巧>,虽然做python有几年了,但中间还是好多不知道或没想到,特在这里做下摘抄. 原文地址: http://soft.c ...

  7. Ext中 get、getDom、getCmp的区别

    getDom方法能够得到文档中的DOM节点,该方法中包含一个参数,该参数可以是DOM节点的id.DOM节点对象或DOM节点对应的Ext元素(Element)等. (与getElementById是一个 ...

  8. FPGA一个博客学习

    FPGA一个博客学习 http://bbs.ednchina.com/BLOG_PERSONALCAT_100185_2001619.HTM

  9. Java: 基类、子类、构造函数、程序块的初始化顺序

    初始化顺序 基类static block 子类static block 基类non-static block 子类non-static block 基类constructor 子类constructo ...

  10. 转载:Cocos2D-x 游戏接入 Windows 设备所需做的六件事

    原文地址:http://msopentech.com/zh-hans/blog/2014/05/09/cocos2d-x-%E6%B8%B8%E6%88%8F%E6%8E%A5%E5%85%A5-wi ...