openwrt (四)启动(1)

目录


1. 1号进程

1号进程的创建
kernel的启动开始于start_kernel()函数,在这里完成各种系统初始化后最后进入rest_init函数,这整个过程都可以称之为0进程:

        asmlinkage void __init start_kernel(void)
        {
            ...
                boot_cpu_init();
                page_address_init();
                pr_notice("%s", linux_banner);
                setup_arch(&command_line);
                mm_init_owner(&init_mm, &init_task);
                mm_init_cpumask(&init_mm);
                setup_command_line(command_line);
                setup_nr_cpu_ids();
                setup_per_cpu_areas();
                smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */

                build_all_zonelists(NULL, NULL);
                page_alloc_init();

                pr_notice("Kernel command line: %s\n", boot_command_line);
                parse_early_param();
            ...
                vfs_caches_init_early();
                sort_main_extable();
                trap_init();
                mm_init();
            ...

                /* Do the rest non-__init'ed, we're now alive */
                rest_init();

        }

rest_init()创建了两个内核线程kernel_init和kthreadd:

        static noinline void __init_refok rest_init(void)
        {
                int pid;

                rcu_scheduler_starting();
                /*
                 * We need to spawn init first so that it obtains pid 1, however
                 * the init task will end up wanting to create kthreads, which, if
                 * we schedule it before we create kthreadd, will OOPS.
                 */
                kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
                numa_default_policy();
                pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
                rcu_read_lock();
                kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
                rcu_read_unlock();
                complete(&kthreadd_done);

                /*
                 * The boot idle thread must execute schedule()
                 * at least once to get things moving:
                 */
                init_idle_bootup_task(current);
                schedule_preempt_disabled();
                /* Call into cpu_idle with preempt disabled */
                cpu_startup_entry(CPUHP_ONLINE);
        }

top命令可以看到kthreadd的pid为2

top.png

kernel_init后面会尝试装载init进程,并完成内核态到用户态的转换,形成用户态的祖先1号进程。

    static int __ref kernel_init(void *unused)
    {
        ...
            if (execute_command) {
                    if (!run_init_process(execute_command))
                            return 0;
                    pr_err("Failed to execute %s.  Attempting defaults...\n",
                            execute_command);
            }
            if (!run_init_process("/etc/preinit") ||
                !run_init_process("/sbin/init") ||
                !run_init_process("/etc/init") ||
                !run_init_process("/bin/init") ||
                !run_init_process("/bin/sh"))
                    return 0;

            panic("No init found.  Try passing init= option to kernel. "
                  "See Linux Documentation/init.txt for guidance.");
    }

execute_command为cmdline传递进来的init进程,不存在或运行失败后依次尝试运行:

    "/etc/preinit",     "/sbin/init",       "/etc/init",        "/bin/init",        "/bin/sh"

2. /etc/preinit 第一阶段

Kernel command line:

root=/dev/mtdblock11 rootfstype=squashfs init=/etc/preinit noinitrd console=ttyS0,115200 panic_debug crashkernel=4k@0x00A00000 RDCA=0x00A00400 rootsize=0x1000000 mem=128M@0x0 cpmem=36M@0x5c00000 ddr_mode=0 APMF=0 PROD=0

可见,用户态起始于/etc/preinit

#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

[ -z "$PREINIT" ] && exec /sbin/init

export PATH=/usr/sbin:/sbin:/usr/bin:/bin

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=0

pi_suppress_stderr="y"
pi_init_suppress_stderr="y"
pi_init_path="/usr/sbin:/sbin:/usr/bin:/bin"
pi_init_cmd="/sbin/init"

. /lib/functions.sh
. /lib/functions/preinit.sh
. /lib/functions/system.sh

boot_hook_init preinit_essential
boot_hook_init preinit_main
boot_hook_init failsafe
boot_hook_init initramfs
boot_hook_init preinit_mount_root

for pi_source_file in /lib/preinit/*; do
        . $pi_source_file
done

boot_run_hook preinit_essential

pi_mount_skip_next=false
pi_jffs2_mount_success=false
pi_failsafe_net_message=false

boot_run_hook preinit_main

/etc/preinit执行两次,如下:

Created with Raphaël 2.1.2 boot /etc/preinit:(1)(2) PREINIT非空?:(1)(2) 脚本启动各种系统服务(2) 结束
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenWrt是一个基于Linux的嵌入式操作系统,主要用于路由器和其他网络设备。它的启动流程如下: 1. 加电启动: 当设备接通电源后,硬件会初始化并自检,然后启动引导加载程序。 2. 引导加载程序(Bootloader): 引导加载程序是嵌入在设备内部存储器中的特殊软件,负责从固定的引导设备(例如闪存)读取并加载操作系统。OpenWrt支持多种引导加载程序,最常用的是u-boot。 3. 内核启动: 一旦引导加载程序启动了内核映像,它就会将控制权交给内核。内核是操作系统的核心,负责设备驱动程序、资源管理和进程调度等功能。OpenWrt使用开源的Linux内核。 4. 设备树(Device Tree)加载: 设备树是一个描述硬件配置和连接性的数据结构,可以在多种硬件平台上重复使用相同的内核映像。OpenWrt使用设备树来识别和配置硬件设备。 5. 根文件系统加载: 内核会加载并挂载根文件系统,根文件系统是包含完整操作系统的文件集合。OpenWrt的根文件系统采用SquashFS格式,其中包含库、配置文件和可执行文件等。 6. 初始化进程(init)启动: 初始化进程是系统启动的第一个进程,它会读取配置文件并启动其他系统组件和服务,例如网络管理、文件共享和Web界面等。 7. 网络服务启动: OpenWrt启动后会配置网络接口,设置IP地址和路由表等,确保设备能够进行网络通信。 8. 用户界面启动: OpenWrt提供Web界面和命令行界面,供用户进行配置和管理。用户可以通过浏览器或SSH等方式访问设备进行设置。 总的来说,OpenWrt启动流程包括硬件初始化、引导加载程序、内核启动、设备树加载、根文件系统加载、初始化进程启动、网络服务启动和用户界面启动等步骤。这些步骤确保系统能够正常启动并提供网络服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值