OpenWrt Learning Notes (IV.)--system boot up __openwrt

Source: Internet
Author: User
Tags dropbear
1. Kernel boot
Bootloader will kernel from flash to ram, Bootloader will quit the stage and give the stage to kernel. Some of the details of the handover process, here do not repeat, we directly from the start of the kernel analysis.

When the kernel of different platforms start, the first part of the assembly script will be somewhat different, but from the assembly jump to the C language code in the process of most of the Start_kernel function, such as the ARM platform, it assembly code the last jump is "b start_kernel "(Linux-3.14/arch/arm/kernel/head-common. S), then executes the Start_kernel function (LINUX-3.14/INIT/MAIN.C), which completes some CPUs, memory, and so on, and then executes the Rest_init (linux-3.14/init/ MAIN.C) function, which creates two kernel threads after Init and kthreadd into the dead loop, the so-called No. 0 process.

The Kenrel_init () (INIT/MAIN.C) function, which, in the Kernel_init function, first invokes kernel_init_freeable, which mainly completes the following tasks:

1. Open/dev/console, and the file descriptor for the open handle is 0 (standard output), then transfer sys_dup copy two file descriptors, 1 and 2 respectively, for standard input and standard error. Because it is the first file to open, the file descriptor is 0, and if the other file is open, the standard output is 0.

2. The second thing is to see if the following Uboot have the command to start RAMDisk, if not, to determine whether the/init file exists, if there is a call to the Prepare_namespace function, this function will complete the root file system mount work.

Because from the boot log you can see the launch command from Uboot [0.000000] Kernel command line:rootwait rootfsname=rootfs rootwait clk_ignore_unused,

So Saved_root_name=rootfs, then Prepare_namespace () will call name_to_dev_t () to get the primary and secondary equipment number and store it in Root_dev (31:12),


Get the primary and secondary device number will call Mount_root, the function will call Mount_block_root ("/dev/root", root_mountflags);

Mount_block_root First call Get_fs_names to get the type of the root file system (usually specified by rootfstype=), and then call Do_mount_root, which invokes Sys_mount to complete the task, and the root file system After mount to/root, call chroot to switch the root directory to the/root directory so that its root file system becomes the real root. And the original root is just a virtual memory root.

Successful log:[1.681344] vfs:mounted root (SQUASHFS filesystem) readonly on device 31:12.

31:12 is Mtd12 's primary and secondary equipment number, we can use the following command to confirm:

root@test:/dev# file/dev/mtdblock12
/dev/mtdblock12:block Special (31/12)

In the case of a flash partition, it is possible to know that the partition is ROOTFS and the partition table is as follows:

[1.453252] Creating MTD partitions on "spi0.0":
[1.458100] 0x000000000000-0x000000040000: "0:SBL1"//No. No. 0 partition
[1.464274] 0x000000040000-0x000000060000: "0:mibib"
[1.469425] 0x000000060000-0x0000000c0000: "0:qsee"
[1.474479] 0x0000000c0000-0x0000000d0000: "0:CDT"
[1.479346] 0x0000000d0000-0x0000000e0000: "0:ddrparams"
[1.484785] 0x0000000e0000-0x0000000f0000: "0:appsblenv"
[1.490212] 0x0000000f0000-0x000000170000: "0:APPSBL"
[1.495430] 0x000000170000-0x000000180000: "0:art"
[1.500384] 0x000000180000-0x000000190000: "Config"
[1.505436] 0x000000190000-0x0000001a0000: "Pot"
[1.510249] 0x0000001a0000-0x0000001b0000: "Data"
[1.515434] 0x0000001b0000-0x000001fc0000: "0:hlos"
[1.520486] 0x000000540000-0x000001fc0000: "Rootfs"//No. 12th partition
[1.525471] Mtd:device (ROOTFS) set to is root filesystem
[1.530832] 1 squashfs-split partitions found on MTD device Rootfs
[1.536393] 0x000001130000-0x000001fc0000: "Rootfs_data"

After executing the above code, returns the Kernel_init function, followed by the following code, which first checks to see if the init parameter is set in the kernel's startup parameters and, if so, uses the program specified by the parameter as the INIT program, otherwise it will attempt to start in the order shown in the following code. If you cannot start, you will kernel panic.

If no parameters are passed to init, the system starts from "/etc/preinit" and starts the file system. 2. "/etc/preinit"

(OPENWRT/PACKAGE/BASE-FILES/FILES/ETC)

    #!/bin/sh # Copyright (c) 2006 Openwrt.org # Copyright (c) Vertical Communications [Z  
    "$PREINIT"] && exec/sbin/init export Path=/bin:/sbin:/usr/bin:/usr/sbin pi_ifname=  
    pi_ip=192.168.1.1 pi_broadcast=192.168.1.255 pi_netmask=255.255.255.0 fs_failsafe_ifname=  
      
    fs_failsafe_ip=192.168.1.1 fs_failsafe_broadcast=192.168.1.255 fs_failsafe_netmask=255.255.255.0 fs_failsafe_wait_timeout=2 pi_suppress_stderr= "y" pi_init_suppress_stderr= "y" pi_init_path= "/bi N:/sbin:/usr/bin:/usr/sbin "pi_init_cmd="/sbin/init ". /lib/functions.sh boot_hook_init preinit_essential boot_hook_init preinit_main boot_hook_init FAI Lsafe boot_hook_init Initramfs boot_hook_init preinit_mount_root for Pi_source_file In/lib/prein it/*; Do. $pi _source_file Done Boot_run_hoOK preinit_essential pi_mount_skip_next=false Pi_jffs2_mount_success=false Pi_failsafe_net_messag   E=false Boot_run_hook Preinit_main
This initialization process follows the following main lines:

Here's a step-by-step analysis of this process.
In the/etc/preinit script, the first command is as follows:
[-Z "$PREINIT"] && exec/sbin/init

When this script is executed from the kernel, it is not defined when preinit the variable, so the/sbin/init is executed directly. /sbin/init program mainly do some initialization work, such as environment variable settings, file system mount, kernel module loading, and then create two processes, respectively, the implementation of/etc/preinit and/SBIN/PROCD, the implementation of/etc/ PreInit sets the variable Preinit,/sbin/procd with the-h argument, and when ProCD exits, exec execution/sbin/proc is invoked to replace the current INIT process (see the PROCD package for Init and PROCD programs). This is when the system boot is complete, the PS command shows the process number 1 of the process name is ultimately the origin of/SBIN/PROCD, there are several changes in the middle.

Continue to look at the/etc/preinit script, out of the variable settings, followed by the execution of three shell scripts:

. /lib/functions.sh

. /lib/functions/preinit.sh

. /lib/functions/system.sh

Note "." and "/" there is a space between the dots here rather with the souce command, but the souce is specific to bash, not in the POSIX standard, "." is the common usage. Use the "." is run in the current shell environment and does not run in a child shell. These shell scripts primarily define the shell functions, especially in preinit.sh, where the hook-related operations are defined.

The following five hook nodes are defined using Boot_hook_init:
Boot_hook_init preinit_essential
Boot_hook_init Preinit_main
Boot_hook_init failsafe
Boot_hook_init Initramfs
Boot_hook_init Preinit_mount_root

The hook function is then added to these nodes. After that is a loop that executes the script in the/lib/preinit/directory under the current shell in turn,
For Pi_source_file in/lib/preinit/*; Todo
. $pi _source_file

Done


These scripts include: 02_default_set_state
10_indicate_failsafe
10_indicate_preinit
10_sysinfo
30_failsafe_wait
40_run_failsafe_hook
50_indicate_regular_preinit
70_initramfs_test

80_mount_root//This will mount the overlay directory


99_10_failsafe_login
99_10_run_init
Because of the number of scripts, OpenWrt's designers divided these scripts into the following categories:
Preinit_essential
Preinit_main
Failsafe
Initramfs
Preinit_mount_root
Each type of function runs in the order of the beginning number of the script.
Directories are used to install the real root.
The script in the/lib/preinit/directory is a similar format, defines the function to add to the hook node, and then adds the function to the corresponding hook node by Boot_hook_add.
Finally, the/etc/preinit performs the function of the Boot_run_hook function that corresponds to the hook node. Only functions on the preinit_essential and Preinit_main nodes are executed in the current environment, as follows:
Boot_run_hook preinit_essential
Boot_run_hook Preinit_main

In this,/etc/preinit execution completes and exits. If you need to track and debug these scripts, you can add a command set-x at the beginning of the/etc/preinit, which will print out the process of executing the command when it is not actually executed.


#####################################
The last script executed by PreInit is 99_10_run_init, running
EXEC env-path= $pi _init_path $pi _init_env $pi _init_cmd
Pi_init_cmd for
Pi_init_cmd= "/sbin/init"

So start running the busybox init command

##########################################

These are the implementations below the old OpenWrt, and there is no such command in the new OpenWrt as Pi_init_cmd, which is implemented in PROCD. Because the last function of the/sbin/init process PreInit () function creates two new processes, one is PROCD, one is/etc/preinit, the following is a careful analysis:

The/sbin/init process comes from PROCD, the package, no longer uses busybox, and it is called from the kernel, so its PID is 1,pid 0 is the kernel itself. Fork create a parent-child process, the child process to do some PROCD after the configuration exit, note that this time PROCD is not really up, its PID is not 1; the parent process continues to create a parent-child process, and the child process exits after calling/etc/preinit. In the process of/sbin/init PID is 1, has never given way.

When the child process is created to execute the/etc/preinit script, the PREINIT environment variable is set to 1, and the main process (pid=1) uses Uloop_process_add () to add/etc/preinit to the Uloop to monitor the/etc/ PreInit the callback PLUGD_PROC_CB () function at the end of execution sets the PID property in the monitor/etc/preinit process counterpart to 0, indicating that the/etc/preinit has completed
The/sbin/procd-h/etc/hotplug-preinit.json is created, and the main process uses uloop_process_add () to monitor the/sbin/procd subprocess by joining Uloop when/sbin/ ProCD the SPAWN_PROCD () function at the end of the process, the SPAWN_PROCD () function reproduces the/SBIN/PROCD process that is actually used, at which point the PROCD process number will be 1.

The following function replaces the/sbin/init process with PROCD, thereby procd the process number 1:



From/tmp/debuglevel read out debug level and set to environment variable DBGLVL, set watchdog FD to environment variable WDTFD, finally call EXECVP () multiply/SBIN/PROCD process

3. "/sbin/init" (the following is mainly from the network)

This process was previously implemented by busy box, but is now implemented by PROCD, and don't look for the wrong location when looking for code.

int main (int argc, char **argv) {pid_t pid;  
    Sigaction (Sigterm, &sa_shutdown, NULL);  
    Sigaction (SIGUSR1, &sa_shutdown, NULL);  
  
    Sigaction (SIGUSR2, &sa_shutdown, NULL);  
    Early ();//-------->early.c cmdline (); Watchdog_init (1); -------.  
    /watchdog.c pid = fork ();  
  
        if (!pid) {char *kmod[] = {"/sbin/kmodloader", "/etc/modules-boot.d/", NULL};  
  
            if (Debug < 3) {int fd = open ("/dev/null", O_RDWR);  
                if (fd >-1) {dup2 (fd, Stdin_fileno);  
                Dup2 (FD, Stdout_fileno);  
                Dup2 (FD, Stderr_fileno);  
            if (fd > Stderr_fileno) Close (FD);  
        } EXECVP (Kmod[0], kmod);  
        ERROR ("Failed to start kmodloader\n");  
    Exit (-1);  
    } if (PID <= 0) ERROR ("Failed to start Kmodloader instance\n");  
 Uloop_init ();   PreInit ();  
  
    -------------->watchdog.c Uloop_run ();  
return 0;   }
early ()Mount/proc/sys/tmp/dev/dev/pts directory (early_mount) Create device nodes and/dev/null file node (EARLY_DEV) Set PATH environment variable (EARLY_ENV) initialization/dev/ Console cmdline ()Determine the debug level according to the/proc/cmdline content init_debug= ([0-9]+) Watchdog_init ()Initialize kernel watchdog (/dev/watchdog) Load kernel moduleTo create a subprocess/sbin/kmodloader load a kernel module in the/etc/modules-boot.d/directory PreInit ()

Create a subprocess to execute the/etc/preinit script, at which point the PREINIT environment variable is set to 1, and the main process uses Uloop_process_add () to add/etc/preinit child processes to the Uloop for monitoring when/etc/ PreInit the callback PLUGD_PROC_CB () function at the end of execution sets the PID property in the monitor/etc/preinit process counterpart to 0, indicating that the/etc/preinit has completed

The/sbin/procd-h/etc/hotplug-preinit.json is created, and the main process uses uloop_process_add () to monitor the/sbin/procd subprocess by joining Uloop when/sbin/ Callback Spawn_procd () function at end of PROCD process

The SPAWN_PROCD () function reproduces the/SBIN/PROCD process that is actually used, reads the debug level from/tmp/debuglevel and sets it to the environment variable DBGLVL, and sets the watchdog FD to the environment variable WDTFD. Last Call EXECVP () multiply/SBIN/PROCD process watchdog

If a/dev/watchdog device is present, setting the watchdog timeout equals 30 seconds, and if the kernel does not receive any data within 30 seconds, it will reboot the system. The user-like process uses the Uloop timer to set a 5-second cycle to write some data notification kernel to the/dev/wathdog device, indicating that the user process is working properly

/**
 * Initialize watchdog/
void watchdog_init (int preinit)

/**
 * Device notification kernel/dev/watchdog frequency (default 5 seconds)
 * Return the old frequency value *
/int watchdog_frequency (int frequency)

/**
 * Device kernel/dev/watchdog timeout
 * when parameter timeout< When =0, represents a stop user-like notification timer from the return value of the current timeout *
/int watchdog_timeout (int timeout)

/**
 * val to True means the system will reboot
/void watchdog_set_stopped in 30 seconds (bool Val)
Signal

Information processing, the following is PROCD for different information processing methods Sigbus, SIGSEGV signal will call Do_reboot () Rb_autoboot reboot system Sighup, SIGKILL, sigstop signal will be ignored sigterm signal use Rb_ Autoboot Event Restart System SIGUSR1, SIGUSR2 signal shutdown system using Rb_power_off event ProCD

The PROCD has 5 states, state_early, State_init, state_running, State_shutdown, State_halt, and the 5 states will change in order, and the current state is saved in the global variable states. Can be changed by using the Procd_state_next () functionstate_early Status-pre-init preparation workInitialization watchdog the "/etc/hotplug.json" rule to monitor hotplug Procd_coldplug () function processing, mount/dev to Tmpfs, fork udevtrigger process to produce cold plug events, To allow HotPlug listener to process Udevstrigger the callback Procd_state_next () function converts the state from state_early to state_init after processing completesState_init State-initialization workConnection UBUSD, the UBUSD does not exist at this time, so the Procd_connect_ubus function uses a timer to reconnect, and Uloop_run () is not really running until the initialization work is completed. When UBUSD is successfully connected, the Servicemain_object object, System_object object, Watch_event object (Procd_connect_ubus () function) is registered. Initializing services (services) and validators (Service verifier) Global AVL tree adds UBUSD service to the Server Management object (service_start_early) according to the/etc/inittab content of the cmd, Handler corresponds to the script that executes Inittab in the global linked list actions from
Package/base-files/files/etc/inittab
:: Sysinit:/etc/init.d/rcs S Boot
:: Shutdown:/etc/init.d/rcs K stop
Tts/0::askfirst:/bin/ash--login
Ttys0::askfirst:/bin/ash--login
Tty1::askfirst:/bin/ash--login
Sysinit/etc/init.d/rcs S Boot script for system initialization
Shutdown scripts for system reboot or shutdown
The first TTY is that if the user logs in via a serial port or Telnet, then run/bin/ash--login

Askfirst and respawn are the same, just before running prompt "Please press Enter to activate this console."
Sequentially load the respawn, Askconsole, Askfirst, sysinit Command sysinit command to bring back the callback/etc/rc.d/() function after all the startup scripts in the Rcdone directory have been executed to the state from State_ Initl turned into state_running
Current boot go to run/etc/init.d/rcs S boot, the script from
Package/base-files/files/etc/init.d/rcs
Similar to PreInit, RCS is also the entry point for a series of scripts that run the/ETC/RC.D directory at the beginning of
Script (if you run RCS K stop, run all scripts starting with K)
K50dropbear S02nvram s40network s50dropbear s96led
K90network s05netconfig s41wmacfixup s50telnet S97watchdog
K98boot s10boot S45firewall s60dnsmasq s98sysntpd
K99umount S39usb S50cron S95done s99sysctl
The script file above comes from:
Package/base-files/files/etc/init.d
Target/linux/brcm-2.4/base-files/etc/init.d
There are also scripts from various modules that are copied to the Rootfs when install, such as dropbear modules
Package/dropbear/files/dropbear.init
These scripts are copied to the/ETC/INIT.D, and then through the/etc/rc.common script, link the init.d script to the/ETC/RC.D directory and add k${stop} and s${according to the start and STOP keywords in those scripts. The prefix of START}, which determines the order in which the scripts are run.
state_running StateProCD run Uloop_run () main loop after entering State_running stateTrigger Task Queues Data Structure

struct Trigger {
    struct list_head list;

    char *type;

    int pending;
    int remove;
    int timeout;

    void *id;

    struct blob_attr *rule;
    struct blob_attr *data;
    struct uloop_timeout delay;

    struct Json_script_ctx jctx;

struct cmd {
    char *name;
    void (*handler) (struct job *job, struct blob_attr *exec, struct blob_attr *env);

struct Job {
    struct runqueue_process proc;
    struct cmd *cmd;
    struct trigger *trigger;
    struct blob_attr *exec;
    struct blob_attr *env;

Interface Description
/**
 * Initialize trigger task queue
/void Trigger_init (void)

/**
 * Add service and Service rules to trigger task queue
 * *
void Trigger_add (struct blob_attr *rule, void *id)

/**
 * Remove the service from the trigger task queue */
void Trigger _del (void *id)

/**
 * 
 *
/void trigger_event (const char *type, struct blob_attr)
Service
Name Handler blob_msg Policy
Set Service_handle_set Service_set_attrs
Add Service_handle_set Service_set_attrs
List Service_handle_list Service_attrs
Delete Service_handle_delete Service_del_attrs
Update_start Service_handle_update Service_attrs
Update_complete Service_handle_update Service_attrs
Event Service_handle_event Event_policy
Validate Service_handle_validate Validate_policy
system
Name Handler blob_msg Policy
Board System_board
Info System_info
Upgrade System_upgrade
Watchdog Watchdog_set Watchdog_policy
Signal Proc_signal Signal_policy
Nandupgrade Nand_set Nand_policy
Shell Invoke Interface

Code base path: package/system/procd/files/procd.sh on device path:/lib/functions/procd.sh

/etc/init.d/daemon

#!/bin/sh/etc/rc.common

start=80
stop=20

use_procd=1

start_service ()
{
    Procd_open_ Instance
    procd_set_param Command/sbin/daemon
    procd_set_param respawn
    procd_close_instance
}


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.