initramfs 在什么时候被调用

     看了王伯生大牛的书,但是我没得到一个清晰的说明或者流程图: initramfs 到底在什么时候调用?

     在什么时候被调用,这是个相对的概念, 我需要得到相对于我已经存在的一些知识概念,initramfs调用的时间点, 比如      它相对于模块加载应该是在更前面哦?sys_open好像已经能用了? udevd是在initramfs里调用的还是在真实文件系统里调用的 ?/dev/下大部分的设备是udevd创建的还是tmpfs创建的?


没完待续。。。


1   它相对于模块加载应该是在更前面哦?

196 #define pure_initcall(fn)               __define_initcall(fn, 0)
197
198 #define core_initcall(fn)               __define_initcall(fn, 1)
199 #define core_initcall_sync(fn)          __define_initcall(fn, 1s)
200 #define postcore_initcall(fn)           __define_initcall(fn, 2)
201 #define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
202 #define arch_initcall(fn)               __define_initcall(fn, 3)
203 #define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
204 #define subsys_initcall(fn)             __define_initcall(fn, 4)
205 #define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
206 #define fs_initcall(fn)                 __define_initcall(fn, 5)
207 #define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
208 #define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
209 #define device_initcall(fn)             __define_initcall(fn, 6)

210 #define device_initcall_sync(fn)        __define_initcall(fn, 6s)
211 #define late_initcall(fn)               __define_initcall(fn, 7)
212 #define late_initcall_sync(fn)          __define_initcall(fn, 7s)
213 

214 #define __initcall(fn) device_initcall(fn)   

268 #define module_init(x)  __initcall(x);      

我们看到 rootfs_initcall 在前面 module_init  前面,所以是文件系统先加载。


2  sys_open好像已经能用了?

之所以有这问是因为: mount_root 里调用了 sys_open().  sys_open就是个函数,它调用的一些东西在fs/目录下都能找到,

而fs_initcall() 的确在  rootfs 调用前已经调用了。


以下看下sys_open怎么定义的。

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)

SYSCALL_DEFINE3 在何处定义?

 

#define SYSCALL_DEFINE3(name, ...)       SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

#define SYSCALL_DEFINEx(x, sname, ...)              __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

#define __SYSCALL_DEFINEx(x, name, ...)              asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

  include/linux/syscalls.h, line 228

#define __SYSCALL_DEFINEx
(x
, name
, ...)                                 /

    asmlinkage
 long sys
##name(__SC_DECL##x(__VA_ARGS__))


#define __SC_DECL3
(t3
, a3
, ...) t3
 a3
, __SC_DECL2
(__VA_ARGS__)
所以对函数定义 SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) 就等于
 SYSCALL_DEFINEx(3, _##socket, __VA_ARGS__)
= asmlinkage long sys_socket(__SC_DECL3(__VA_ARGS__))
= asmlinkage long sys_socket(int family, __SC_DECL2(__VA_ARGS__))
最终得到
asmlinkage long sys_socket(int family, int type, int protocol)



3 udevd是在initramfs里调用的还是在真实文件系统里调用的 ?









# This is a very simple, default initramfs

    dir /dev 0755 0 0
    nod /dev/console 0600 0 0 c 5 1
    nod /dev/tty 0666 0 0 c 5 0
    nod /dev/null 0600 0 0 c 1 3
    nod /dev/mem 0600 0 0 c 1 1
    nod /dev/kmem 0600 0 0 c 1 2
    nod /dev/zero 0600 0 0 c 1 5
    nod /dev/random 0600 0 0 c 1 8
    nod /dev/urandom 0600 0 0 c 1 9

    dir /dev/pts 0755 0 0
    nod /dev/ptmx 0666 0 0 c 5 2

    nod /dev/ttyS0 0666 0 0 c 4 64
    nod /dev/ttyS1 0666 0 0 c 4 65
    nod /dev/ttyS2 0666 0 0 c 4 66

    dir /bin 755 0 0
    dir /proc 755 0 0

    file /bin/hello ${INSTALL_ROOT}/projects/${SAMPLE}/hello/hello 755 0 0
    slink /bin/init hello 777 0 0

This file is an input file for thegen_init_cpio program in the kernel source tree.

It generates a cpio archive which is suitable for initramfs with the files/dirs/devices(=nodes)/... listed in the input file.

The syntax is(语法)

file <name> <location> <mode> <uid> <gid> [<hard links>]
dir <name> <mode> <uid> <gid>\n
nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>
slink <name> <target> <mode> <uid> <gid>

etc.

Which programs are actually run on boot, depends on the init program in the initramfs. Here theinit program is asymlink tohello.

==================

先来看下面的文章:

一、从哪里到哪里
本文旨在描述linux中内核如何调用启动,然后如何从img的文件系统切换到硬盘的过程。
描述起于:linux-2.6.11/init/main.c中函数static intinit(void *unused)
描述止于:/etc/rc.d/rc.sysinit文件的被调用
二、描写流程
linux代码linux-2.6.11/init/main.cinit这个函数被调用时,初始启动的文件
系统镜像:/boot/initrd-2.6.11.12.img(以2.6.11.12内核为例)已被grub加载到
内存中,并已挂载到根目录上("/")。
1
、我们先来看看initrd-2.6.11.12.img到底是个什么东西:
[root@wj-server1tmp]# cd /tmp
[root@wj-server1 tmp]# cp /boot/initrd-2.6.11.12.img/tmp/initrd-2.6.11.12.gz
[root@wj-server1 tmp]# gunzipinitrd-2.6.11.12.gz
解压缩后的文件为:
[root@wj-server1tmp]# ls -l initrd-2.6.11.12
-rw-r--r--  1 root root846848  7
31 17:01initrd-2.6.11.12
是一个CPIO格式的文件,该文件格式是种文件镜像让我们将它解开到一个目录中看看
其中的具体内容:
[root@wj-server1tmp]# mkdir initrd
[root@wj-server1 tmp]# cd initrd
[root@wj-server1 initrd]# cpio -i  ../initrd-2.6.11.12
1654blocks
[root@wj-server1 initrd]# gzip../initrd-2.6.11.12
[root@wj-server1 initrd]# mv../initrd-2.6.11.12.gz../initrd-2.6.11.12.img
2
、回到内核init函数中,看看如何调用/boot/initrd-2.6.11.12.img/init脚本的
  ....
//
这里判断在grub装载的/boot/initrd-2.6.11.12.img中是否有"/init"这个文件?
if(sys_access((const char __user *) "/init", 0) == 0)
   execute_command = "/init"
else
   ....
//
如果有"/init"这个文件就先运行它。
if(execute_command)
   run_init_process(execute_command);
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("Noinit found. Try passing init= option tokernel");
由代码我们看到kernel会先判断并运行/boot/initrd-2.6.11.12.img中的/init文件,我们
来看看该/boot/initrd-2.6.11.12.img/init文件的内容,我们上面已将该文件展开到目录/tmp/initrd中:
[root@wj-server1initrd]# cat ./init
#!/bin/nash     #
该文件是个nash的脚本文件
#
挂接proc文件系统
mount-t proc /proc /proc
#
不输出nash调试信息,由/proc/cmdline决定,cat/proc/cmdline我的启动参数
#
输出roroot=/dev/hda3 vga=791 splash=silent,如果该命令行中带了quiet
#
数,则不输出nash提示信息。
setquiet
#
提示信息(这里提示因该放到上面去,mkinitrd-4.2.17-2mgc.rpm包中原来如是,
#
笔误?为什么这里牵涉到mkinitrd这个包类?因为:/boot/initrd-2.6.11.12.img
#
文件由下面命令生成:mkinitrd/boot/initrd-2.6.11.12.img 2.6.11.12
echoMounted /proc filesystem
#
挂接sys文件系统
echoMounting sysfs
mount -t sysfs /sys /sys
#
创建/dev临时目录
echoCreating /dev
mount -o mode=0755 -t tmpfs /dev /dev
#
创建设备文件(这些设备文件在切换到硬盘后,由/etc/rc.sysinitstart_udev
#
重新创建)
mknod/dev/console c 5 1
mknod /dev/null c 1 3
mknod /dev/zero c 15
#
新建伪终端目录
mkdir/dev/pts
#
新建共享内存目录
mkdir/dev/shm
#
这里是调用的nash中的makedevs指令装载硬盘等块设备,不装载其他设备只装载
#
硬盘等块设备
echoStarting udev
#
告诉内核当发现新拔插设备时用"/sbin/hotplug"程序来处理
echo-n "/sbin/hotplug" >/proc/sys/kernel/hotplug
makedevs
makedevs #
这里多搞一次没必要
echoCreating root device
#
grub启动命令行root=/dev/hda3来联接设备/dev/rootroot变量所指定的启动
#
设备,见下面我的grub启动参数:
#kernel /boot/vmlinuz-2.6.11.12  ro root=/dev/hda3 vga=791splash=silent
mkrootdev /dev/root
#
挂接/dev/root目录
echoMounting root filesystem
mount -o defaults --ro -t ext3 /dev/root/sysroot
echo Switching to new root
#
切换根目录到设备/dev/root目录,运行完该命令根目录"/"->"/dev/hda3"
switchroot--movedev/sysroot
由上面的注释我们大概能够明白./init脚本的基本运行流程:
a
、装载基本的内核系统文件和设备文件
b
、根据grub的启动命令行参数,判断root根文件设备,参看/boot/grub/grub.conf文件中制定
的参数,该参数在内核启动后可有cat/proc/cmdline显示出来,nash和其他的一些程序也是通
过读该系统文件来去内核启动参数的。
c
、在将从grub启动参数中获得根设备并将其与/dev/root设备联接以后,通过nashswitchroot
指令将/dev/root设备挂接到根目录上("/"
看看这样操作后,留下的痕迹:
[root@wj-server1initrd]# ls -l /dev/root
lrwxrwxrwx  1 root root 9  7
31 12:06/dev/root -> /dev/hda3
[root@wj-server1 initrd]#mount
/dev/hda3 on / type ext3(rw)
到此为止,已将硬盘设备装载到根目录下了,从而取代了原来有initrd.img文件的根位置。
3
、再回头看看内核中main.cinit函数,看看如何调用/sbin/init处理/etc/inittab文件
   ....
//
如果有"/init"这个文件就先运行它。
if(execute_command)
   run_init_process(execute_command);
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("Noinit found. Try passing init= option tokernel");
我们已经运行完run_init_process(execute_command);这里了,然后继续运行:
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
/sbin/init
这个文件在SysVinit-2.85-34mgc.rpm这个包中,该程序的主要处理代码在文件:
sysvinit-2.85/src/init.c
中,该文件主要查找和处理/etc/inittab文件,按照该文件的内容
依次做处理。
[root@wj-server1initrd]# cat /etc/inittab
#
# inittab      This file describes how the INIT process should set up
#              the system in a certainrun-level.
#
# Author:       Miquel vanSmoorenburg,
#              Modified for RHS Linux by Marc Ewing and Donnie Barnes
#
#Default runlevel. The runlevels used by RHS are:
#   0 -halt (Do NOT set initdefault to this)
#   1 - Singleuser mode
#   2 - Multiuser, without NFS (The same as 3,if you do not have networking)
#   3 - Full multiusermode
#   4 - unused
#   5 - X11
#  6 - reboot (Do NOT set initdefault tothis)
#
id:5:initdefault:                          #/sbin/init
根据这里判断启动的级别
#System initialization.
si::sysinit:/etc/rc.d/rc.sysinit           # /sbin/init
会最先运行这个系统配置文件
l0:0:wait:/etc/rc.d/rc0                   # /sbin/init
根据上面取得的级别运行相应
l1:1:wait:/etc/rc.d/rc1                   #
目录下的启动脚本
l2:2:wait:/etc/rc.d/rc2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
# TrapCTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now   #
设置关机热键
#When our UPS tells us power has failed, assume we have a fewminutes
# of power left.  Schedule a shutdown for 2minutes from now.
# This does, of course, assume you have powerdinstalled and your
# UPS connected and workingcorrectly.
pf::powerfail:/sbin/shutdown -f -h +2 "PowerFailure; System Shutting Down"
# If power was restored beforethe shutdown kicked in, cancelit.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored;Shutdown Cancelled"
# Run gettys in standardrunlevels
1:2345:respawn:/sbin/mingetty tty1         #
建立6个登陆控制终端可以通过CTRL-ALT-F?
2:2345:respawn:/sbin/mingettytty2          #
切换,'?'表示第几个登陆控制台,比如第1
3:2345:respawn:/sbin/mingettytty3          #
个为F1,第2个为F2依次类推。F7X11控制
4:2345:respawn:/sbin/mingettytty4          #
台,后面就没有了,所以在X下可以很灵活
5:2345:respawn:/sbin/mingettytty5          #
的切换到控制台下面操作。
6:2345:respawn:/sbin/mingettytty6
# Run xdm in runlevel 5
x:5

nce:/etc/X11/prefdm-nodaemon
通过内核中对/sbin/init的调用现在已经执行/etc/rc.d/rc.sysinit操作了。

============================

文章二:


在移植nand flash驱动之前先学习一下linux的驱动加载过程:(这是我看过的一个博客,但不记得在哪里了 :( )

1. bootloader跳转到内核的起始位置后,压缩过的kernel入口在arch/arm/boot/compressed/head.S,它将调用函数decompress_kernel()(arch/arm/boot/compressed/misc.c)解压,打印“Uncompressing Linux...”,调用gunzip(),打印"done, booting the kernel."

2. 然后call_kernel,执行解压后的kernel,最后调用start_kernel() (init/main.c)转入体系结构无关的通用C代码,在start_kernel()中完成了一系 列系统初始化,并启动了调度器;最后调用函数rest_init()将创建第一个核心线程kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND),调用kernel_init()函数。

3. kernel_init()中先调用kernel_init_freeable();再调用free_initmem();最后执行根文件系统的配置init。
        if (!run_init_process("/sbin/init") ||
            !run_init_process("/etc/init") ||
            !run_init_process("/bin/init") ||
            !run_init_process("/bin/sh"))
                return 0;

4. 在上面的kernel_init_freeable()中,主要有三个函数。
        do_basic_setup();

        /* Open the /dev/console on the rootfs, this should never fail */
        if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
            pr_err("Warning: unable to open an initial console.\n");
    
        load_default_modules();

5.
        static void __init do_basic_setup(void)
        {
            cpuset_init_smp();
            usermodehelper_init();
            shmem_init();
            driver_init();
            init_irq_proc();
            do_ctors();
            usermodehelper_enable();
            do_initcalls();
        }
6.
        /*
         * This function requests modules which should be loaded by default and is
         * called twice right after initrd is mounted and right before init is
         * exec'd.  If such modules are on either initrd or rootfs, they will be
         * loaded before control is passed to userland.
         */
        void __init load_default_modules(void)
        {
                load_default_elevator_module();    
        }
        在include/linux/elevator.h中,什么也没有做:
        static inline void load_default_elevator_module(void) { }

7. driver_init()在drivers/base/init.c,主要实现了/sys的设备模型,还有platform初始化:
    /**
    * driver_init - initialize driver model.
    *
    * Call the driver model init functions to initialize their
    * subsystems. Called early from init/main.c.
    */
    void __init driver_init(void)
    {
        /* These are the core pieces */
        devtmpfs_init();
        devices_init();
        buses_init();
        classes_init();
        firmware_init();
        hypervisor_init();

        /* These are also core pieces, but must come after the
         * core core pieces.
         */
        platform_bus_init();
        cpu_dev_init();
        memory_dev_init();
    }

8. do_initcalls()在init/main.c中,加载8个优先级函数,这些函数主要是一些驱动核心,模块,有一定顺序的代码:
    static void __init do_initcalls(void)
    {
        int level;

        for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
        do_initcall_level(level);
    }
                
        static initcall_t *initcall_levels[] __initdata =
    {
        __initcall0_start,
        __initcall1_start,
        __initcall2_start,
        __initcall3_start,
        __initcall4_start,
        __initcall5_start,
        __initcall6_start,
        __initcall7_start,
        __initcall_end,
    };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值