openwrt (四)启动(2)

目录

  • 1. 第一次运行procd
  • 2. 第二次运行procd
  • 3. 开机系统服务的启动

1. 第一次运行procd

第一次运行procd,形式为procd -h /etc/hotplug-preinit.json,这是主要是对对uevent的处理。

分析代码完成序列图:

Created with Raphaël 2.1.2 procd(procd.c) procd(procd.c) procd(hotplug.c) procd(hotplug.c) procd(hotplug.c/hotplug()) procd(hotplug.c/hotplug()) ubox(uloop.c) ubox(uloop.c) ubox(json_script.c) ubox(json_script.c) hotplug_run /etc/hotplug-preinit.json uloop_init() hotplug() hotplug_fd json_script_init 注册callback: handle_var handle_error handle_command handle_file queue_proc.cb= queue_proc_cb uloop_fd_add (hotplug_fd, ULOOP_READ) register_kevent uloop_run() uloop_run_events hotplug_handler hotplug_handler: json_script_run json_script_run json_process_cmd handle_command rule_handle_command atomic=1,直接运行handler 否则 创建子进程运行cmd_handler的handler, 主进程运行cmd_handler的start和complete

贴上/etc/hotplug-preinit.json

[
        [ "case", "ACTION", {
                "add": [
                        [ "if",
                                [ "has", "FIRMWARE" ],
                                [
                                        [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ],
                                        [ "load-firmware", "/lib/firmware" ],
                                        [ "return" ]
                                ]
                        ],
                ],
        }, ],
        [ "if",
                [ "and",
                        [ "eq", "SUBSYSTEM", "button" ],
                ],
                [ "exec", "/etc/rc.button/failsafe" ]
        ],
]

可见在preint阶段需要处理安全模式和固件升级两个hotplug.

  1. uevent事件的ACTION为add类型时,如果事件中的包含$FIRMWARE变量则做两件事:

    • 执行/sbin/hotplug-call,识别uevent中的SUBSYSTEM 变量运行/etc/hotplug.d/ 下对应目录中的脚本。
    • 加载/lib/firmware下的对应固件完成模块的固件升级。
  2. 判断uevent事件,如果SUBSYSTEMbutton则通过运行/etc/rc.button/failsafe脚本。该脚本决定是否创建/tmp/failsafe_button判断是否进入安全模式,/tmp/failsafe_button这个文件在lib/preinit/30_failsafe_wait中用到。

附上/etc/rc.button/failsafe如下:

#!/bin/sh

[ "${TYPE}" = "switch" ] || echo ${BUTTON} > /tmp/failsafe_button

注:FAQ一章中贴上来带注释的/etc/hotplug.json。介绍了hotplug的json描述。

2. 第二次运行procd

第二次运行procd,替换了init进程成为1号进程,完成开机的初始化,各种用户态服务的启动。

Created with Raphaël 2.1.2 procd.c procd.c state.c state.c hotplug.c hotplug.c coldplug.c coldplug.c inittab.c inittab.c ubus.c ubus.c procd_state_next() state_enter() STATE_EARLY hotplug("/etc/hotplug.json") procd_coldplug [callback] udevtrigger_complete procd_state_next() STATE_UBUS mrvl_fast_boot() /etc/telinit procd_connect_ubus() ubus_reconnect ubus_connect_cb procd_state_ubus_connect procd_state_next STATE_INIT procd_inittab() procd_inittab_run("respawn"); procd_inittab_run("askconsole"); procd_inittab_run("askfirst"); procd_inittab_run("sysinit"); STATE_RUNNING 到STATE_RUNNING 开机的初始化部分 就结束了

procd中有几个状态:

  • STATE_EARLY,
  • STATE_UBUS,
  • STATE_INIT,
  • STATE_RUNNING,
  • STATE_SHUTDOWN,
  • STATE_HALT,

开机初始化走到STATE_RUNNING就算是结束了,之后procd进程会通过uloop_run驻留系统。

3. 开机系统服务的启动

从上面序列图上可以看到,开机做了几件事情:

  1. STATE_EARLY阶段
    hotplug根据/etc/hotplug.json监听内核的uevent事件
    coldplug mount /dev到tmpfs, 运行udevtrigger主动触发设备uevent,创建设备节点。

  2. STATE_UBUS阶段

    • marvell平台运行mrvl_fast_boot,这是定制的,非标准流程。运行脚本/etc/telinit,主要是modem、rild、usb的一些配置启动。
    • 与ubus建立socket连接,开始时ubus不存在,procd_connect_ubus中定义定时间,定时重连,直到连接上ubus后,向ubus添加对象main_objectsystem_object,然后以服务进程启动ubusd,以提供进程间通信的基础。
  3. STATE_INIT阶段

    • procd_inittab()函数解析配置文件/etc/inittab
      创建了sysinitshutdownaskconsole三个init_action的list。
    • procd_inittab_run依次运行respawnaskconsoleaskfirstsysinit几个action的callback:
static struct init_handler handlers[] = {
        {
                .name = "sysinit",
                .cb = runrc,
        }, {
                .name = "shutdown",
                .cb = runrc,
        }, {
                .name = "askfirst",
                .cb = askfirst,
                .multi = 1,
        }, {
                .name = "askconsole",
                .cb = askconsole,
                .multi = 1,
        }, {
                .name = "respawn",
                .cb = rcrespawn,
                .multi = 1,
        }
};

下面重点看sysinit对应的runrc

Created with Raphaël 2.1.2 inittab.c inittab.c rcS.c rcS.c runrc() if (rcS(a->argv[1], a->argv[2], rcdone)) _rc(&q, "/etc/rc.d", pattern, "*", param) 找到/etc/rc.d目录下所有S开头的文件, 即:/etc/rc.d/S* add_initd,将S*启动脚本加入运行队列,运行脚本中的boot函数

该项目运行下面脚本:

S00sysfixtime
S10boot #/etc/init.d/mrvl_init,/sbin/kmodloader,/etc/uci-defaults,/sbin/reload_config
S19dnsmasq  #空boot,hotplug过程中完成
S19firewall #空boot,hotplug过程中完成
S40fstab  #/sbin/block mount
S95done #/etc/rc.local,/etc/diag.sh

后续就是看具体的启动脚本,模块化调试了。

你可能感兴趣的:(linux驱动,linux,other,openwrt)