kernel启动过程详解(梳理流程的工具和方法)

start_kernel相当于内核的main函数,内核的生命周期就是从执行这个函数的第一条语句开始的

大家好,又见面了,我是你们的朋友全栈君。

内核生命周期

uboot 打印完 Starting kernel . . .,就完成了自己的使命,控制权便交给了 kernel 的第一条指令,也就是下面这个函数
init/main.c

asmlinkage __visible void __init start_kernel(void)
{ 
   
	...
	rest_init();
}

start_kernel 相当于内核的 main 函数,内核的生命周期就是从执行这个函数的第一条语句开始的,直到最后一个函数 reset_init(),内核将不再从这个函数中返回,而是陷入这个函数里面的一个 while(1) 死循环,这个死循环被作为 idle 进程,也就是 0 号进程

所以,内核的生命周期,就是一个完整的 start_kernel 函数。始于 start_kernel 函数的第一条语句,停留在最后的死循环。

init 进程

kernel 会创建众多内核线程,来持续致力于内存、磁盘、CPU 的管理,其中有两个内核线程比较重要,需要我们重点讲解,那就是 1 号内核线程 kernel_init 和 2 号内核线程 kthreadd。1 号内核线程最终会被用户的第一个进程 init 代替,也就成了 1 号进程。如下:

# ps
PID   USER     COMMAND
    1 root     init
    2 root     [kthreadd]
    3 root     [rcu_gp]
    4 root     [rcu_par_gp]
    7 root     [kworker/u4:0-ev]
    8 root     [mm_percpu_wq]
    9 root     [ksoftirqd/0]
...

COMMAND 这一列,带中括号的是内核线程,不带中括号的是用户进程。从 PID 统一编址就可以看出,它俩地位是一样的。
下面我们深入分析一下从 start_kernel 到最终运行 init 进程,kernel 都经历了什么

打印

添加打印,是分析流程的好方法。

asmlinkage __visible void __init start_kernel(void)
{ 
   
	char *command_line;
	char *after_dashes;

	set_task_stack_end_magic(&init_task);
	smp_setup_processor_id();
	debug_objects_early_init();

	cgroup_init_early();

	local_irq_disable();
	early_boot_irqs_disabled = true;

	/* * Interrupts are still disabled. Do necessary setups, then * enable them. */
	boot_cpu_init();
	page_address_init();
	pr_notice("%s", linux_banner);
	setup_arch(&command_line);
	/* * Set up the the initial canary and entropy after arch * and after adding latent and command line entropy. */
	add_latent_entropy();
	add_device_randomness(command_line, strlen(command_line));
	boot_init_stack_canary();
	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 */
	boot_cpu_hotplug_init();

	build_all_zonelists(NULL);
	page_alloc_init();

	pr_notice("Kernel command line: %s\n", boot_command_line);
	parse_early_param();
	after_dashes = parse_args("Booting kernel",
				  static_command_line, __start___param,
				  __stop___param - __start___param,
				  -1, -1, NULL, &unknown_bootoption);
	if (!IS_ERR_OR_NULL(after_dashes))
		parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
			   NULL, set_init_arg);

	jump_label_init();

	/* * These use large bootmem allocations and must precede * kmem_cache_init() */
	setup_log_buf(0);
	vfs_caches_init_early();
	sort_main_extable();
	trap_init();
	mm_init();

	ftrace_init();

	/* trace_printk can be enabled here */
	early_trace_init();

	/* * Set up the scheduler prior starting any interrupts (such as the * timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. */
	sched_init();
	/* * Disable preemption - early bootup scheduling is extremely * fragile until we cpu_idle() for the first time. */
	preempt_disable();
	if (WARN(!irqs_disabled(),
		 "Interrupts were enabled *very* early, fixing it\n"))
		local_irq_disable();
	radix_tree_init();

	/* * Set up housekeeping before setting up workqueues to allow the unbound * workqueue to take non-housekeeping into account. */
	housekeeping_init();

	/* * Allow workqueue creation and work item queueing/cancelling * early. Work item execution depends on kthreads and starts after * workqueue_init(). */
	workqueue_init_early();

	rcu_init();

	/* Trace events are available after this */
	trace_init();

	if (initcall_debug)
		initcall_debug_enable();

	context_tracking_init();
	/* init some links before init_ISA_irqs() */
	early_irq_init();
	init_IRQ();
	tick_init();
	rcu_init_nohz();
	init_timers();
	hrtimers_init();
	softirq_init();
	timekeeping_init();
	time_init();
	sched_clock_postinit();
	printk_safe_init();
	perf_event_init();
	profile_init();
	call_function_init();
	WARN(!irqs_disabled(), "Interrupts were enabled early\n");
	early_boot_irqs_disabled = false;
	local_irq_enable();

	kmem_cache_init_late();

	/* * HACK ALERT! This is early. We're enabling the console before * we've done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */
	console_init();
printk("## start_kernel() --> console_init()\n");
	if (panic_later)
		panic("Too many boot %s vars at `%s'", panic_later,
		      panic_param);

	lockdep_info();

	/* * Need to run this when irqs are enabled, because it wants * to self-test [hard/soft]-irqs on/off lock inversion bugs * too: */
	locking_selftest();

	/* * This needs to be called before any devices perform DMA * operations that might use the SWIOTLB bounce buffers. It will * mark the bounce buffers as decrypted so that their usage will * not cause "plain-text" data to be decrypted when accessed. */
	mem_encrypt_init();

#ifdef CONFIG_BLK_DEV_INITRD
	if (initrd_start && !initrd_below_start_ok &&
	    page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { 
   
		pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
		    page_to_pfn(virt_to_page((void *)initrd_start)),
		    min_low_pfn);
		initrd_start = 0;
	}
#endif
	page_ext_init();
	kmemleak_init();
	debug_objects_mem_init();
	setup_per_cpu_pageset();
	numa_policy_init();
	acpi_early_init();
	if (late_time_init)
		late_time_init();
	calibrate_delay();
	pid_idr_init();
	anon_vma_init();
#ifdef CONFIG_X86
	if (efi_enabled(EFI_RUNTIME_SERVICES))
		efi_enter_virtual_mode();
#endif
	thread_stack_cache_init();
	cred_init();
	fork_init();
	proc_caches_init();
	uts_ns_init();
	buffer_init();
	key_init();
	security_init();
	dbg_late_init();
	vfs_caches_init();
	pagecache_init();
	signals_init();
	seq_file_init();
	proc_root_init();
	nsfs_init();
	cpuset_init();
	cgroup_init();
	taskstats_init_early();
	delayacct_init();

	check_bugs();

	acpi_subsystem_init();
	arch_post_acpi_subsys_init();
	sfi_init_late();

	if (efi_enabled(EFI_RUNTIME_SERVICES)) { 
   
		efi_free_boot_services();
	}
printk("## run rest_init()\n");
	/* Do the rest non-__init'ed, we're now alive */
	rest_init();
printk("## after rest_init()\n");
}

一开始尝试在函数刚开始就添加 printk 打印,结果发现添加完 printk 后内核起不来,最后保守起见,在 131 行 console_init(); 后才开始添加打印。


Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.18.12 (liyongjun@Box) (gcc version 9.3.0 (Buildroot 2021.05)) #14 SMP Thu Nov 25 00:37:30 CST 2021
[    0.000000] CPU: ARMv7 Processor [410fc074] revision 4 (ARMv7), cr=10c5387d
[    0.000000] CPU: div instructions available: patching division code
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] OF: fdt: Machine model: LeMaker Banana Pi
[    0.000000] Memory policy: Data cache writealloc
[    0.000000] cma: Reserved 16 MiB at 0x7ec00000
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: Using PSCI v0.1 Function IDs from DT
[    0.000000] random: get_random_bytes called from start_kernel+0xa0/0x430 with crng_init=0
[    0.000000] percpu: Embedded 16 pages/cpu @(ptrval) s34444 r8192 d22900 u65536
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 260202
[    0.000000] Kernel command line: console=ttyS0,57600 earlyprintk root=/dev/mmcblk0p2 rootwait
[    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Memory: 1011460K/1046952K available (6144K kernel code, 418K rwdata, 1524K rodata, 1024K init, 240K bss, 19108K reserved, 16384K cma-reserved, 244136K highmem)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)
[    0.000000]     vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)
[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
[    0.000000]       .text : 0x(ptrval) - 0x(ptrval)   (7136 kB)
[    0.000000]       .init : 0x(ptrval) - 0x(ptrval)   (1024 kB)
[    0.000000]       .data : 0x(ptrval) - 0x(ptrval)   ( 419 kB)
[    0.000000]        .bss : 0x(ptrval) - 0x(ptrval)   ( 241 kB)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
[    0.000000] Hierarchical RCU implementation.
[    0.000000]  RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=2.
[    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
[    0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.000000] GIC: Using split EOI/Deactivate mode
[    0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.000007] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.000021] Switching to timer-based delay loop, resolution 41ns
[    0.000334] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[    0.000586] clocksource: hstimer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 6370868154 ns
[    0.000822] Console: colour dummy device 80x30
[    0.000844] ## start_kernel() --> console_init() // 132 行的打印

可是,发现在 console_init() 之前就有不少打印了,这个地方还是有些不解。猜测要么是在 console_init() 之前就已经可以打印了;要么是在 console_init() 之前先将打印缓存着,等初始化之后再打印。这点以后再研究吧。先插个眼?。

接着看打印

[    0.000844] ## start_kernel() --> console_init()
[    0.000872] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=240000)
[    0.000886] pid_max: default: 32768 minimum: 301
[    0.001054] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
[    0.001070] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
[    0.001727] CPU: Testing write buffer coherency: ok
[    0.001779] ## run rest_init()

从 133 行到 206 行,代码不少,打印却只有寥寥 5 行。少就说明不重要,那就不分析了,哈哈?。
看下面的代码,乖乖,就剩一句了:rest_init();,并且第 210 行的 printk 等到系统完全起来都没有打印,说明 rest_init() 就没返回。看来是个扛把子。

static noinline void __ref rest_init(void)
{ 
   
	struct task_struct *tsk;
	int pid;
printk("## rcu_scheduler_starting()\n");
	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. */
	pid = kernel_thread(kernel_init, NULL, CLONE_FS);
	/* * Pin init on the boot CPU. Task migration is not properly working * until sched_init_smp() has been run. It will set the allowed * CPUs for init to the non isolated CPUs. */
	rcu_read_lock();
	tsk = find_task_by_pid_ns(pid, &init_pid_ns);
	set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));
	rcu_read_unlock();
printk("## bb\n");
	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();
printk("## cc\n");
	/* * Enable might_sleep() and smp_processor_id() checks. * They cannot be enabled earlier because with CONFIG_PREEMPT=y * kernel_thread() would trigger might_sleep() splats. With * CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled * already, but it's stuck on the kthreadd_done completion. */
	system_state = SYSTEM_SCHEDULING;
printk("## dd\n");
	complete(&kthreadd_done);

	/* * The boot idle thread must execute schedule() * at least once to get things moving: */
printk("## ee\n");
	schedule_preempt_disabled();
printk("## ff\n");
	/* Call into cpu_idle with preempt disabled */
	cpu_startup_entry(CPUHP_ONLINE);
// printk("## ff\n");
}

对应打印如下:

[    0.001779] ## run rest_init()
[    0.001786] ## rcu_scheduler_starting()
[    0.002030] ## bb
[    0.002089] ## cc
[    0.002097] ## dd
[    0.002104] ## ee
[    0.002150] ## kernel_init()
[    0.002199] /cpus/cpu@0 missing clock-frequency property
[    0.002214] /cpus/cpu@1 missing clock-frequency property
[    0.002228] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.002799] Setting up static identity map for 0x40100000 - 0x40100060
[    0.002972] Hierarchical SRCU implementation.
[    0.003776] smp: Bringing up secondary CPUs ...
[    0.014335] ## ff

打印了 kernel_init(),是因为调用了 schedule_preempt_disabled(),其内部调用了 schedule() 执行进程切换,进入睡眠。当然,在当前进程被唤醒时,程序也是从这个断点开始运行。

void __sched schedule_preempt_disabled(void)
{ 
   
	sched_preempt_enable_no_resched();
	schedule();
	preempt_disable();
}

执行进程切换后,kernel_init() 才有机会运行

static int __ref kernel_init(void *unused)
{ 
   
	int ret;
printk("## kernel_init()\n");
	kernel_init_freeable();
	/* need to finish all async __init code before freeing the memory */
	async_synchronize_full();

	ftrace_free_init_mem();

	jump_label_invalidate_initmem();
	free_initmem();
printk("## 2.\n");
	mark_readonly();
printk("## 3.\n");
	system_state = SYSTEM_RUNNING;
	numa_default_policy();

	rcu_end_inkernel_boot();
printk("## 4.\n");
	if (ramdisk_execute_command) { 
   
		ret = run_init_process(ramdisk_execute_command);
		if (!ret)
			return 0;
		pr_err("Failed to execute %s (error %d)\n",
		       ramdisk_execute_command, ret);
	}

	/* * We try each of these until one succeeds. * * The Bourne shell can be used instead of init if we are * trying to recover a really broken machine. */
	if (execute_command) { 
   
		ret = run_init_process(execute_command);
		if (!ret)
			return 0;
		panic("Requested init %s failed (error %d).",
		      execute_command, ret);
	}
	if (!try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh")) { 
   
printk("## kernel_init() --> /sbin/init\n");
		return 0;
		}

	panic("No working init found. Try passing init= option to kernel. "
	      "See Linux Documentation/admin-guide/init.rst for guidance.");
}

对应打印如下:

[    0.002150] ## kernel_init()
[    0.002199] /cpus/cpu@0 missing clock-frequency property
[    0.002214] /cpus/cpu@1 missing clock-frequency property
[    0.002228] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.002799] Setting up static identity map for 0x40100000 - 0x40100060
[    0.002972] Hierarchical SRCU implementation.
[    0.003776] smp: Bringing up secondary CPUs ...
[    0.014335] ## ff
[    0.014540] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[    0.014681] smp: Brought up 1 node, 2 CPUs
[    0.014697] SMP: Total of 2 processors activated (96.00 BogoMIPS).
[    0.014704] CPU: All CPU(s) started in HYP mode.
[    0.014709] CPU: Virtualization extensions available.
[    0.015730] devtmpfs: initialized
[    0.015786] ## 11.
[    0.015802] ## 22.
[    0.015811] ## 33.
[    0.015820] ## 44.
[    0.015825] ## 55.
[    0.015918] ## 66.
[    0.015999] ## 77.
[    0.016006] ## 88.
[    0.016058] ## 99.
[    0.021654] ## AA.
[    0.021836] ### AAA.
[    0.022450] VFP support v0.3: implementor 41 architecture 2 part 30 variant 7 rev 4
[    0.022721] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.022747] futex hash table entries: 512 (order: 3, 32768 bytes)
[    0.023540] pinctrl core: initialized pinctrl subsystem
[    0.024726] NET: Registered protocol family 16
[    0.026025] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.027158] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
[    0.027173] hw-breakpoint: maximum watchpoint size is 8 bytes.
[    0.042711] reg-fixed-voltage gmac-3v3: could not find pctldev for node /soc@1c00000/pinctrl@1c20800/gmac_power_pin@0, deferring probe
[    0.043233] SCSI subsystem initialized
[    0.043811] usbcore: registered new interface driver usbfs
[    0.043864] usbcore: registered new interface driver hub
[    0.043933] usbcore: registered new device driver usb
[    0.044199] pps_core: LinuxPPS API ver. 1 registered
[    0.044209] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.044230] PTP clock support registered
[    0.044563] Advanced Linux Sound Architecture Driver Initialized.
[    0.045501] clocksource: Switched to clocksource arch_sys_counter
[    0.046238] simple-framebuffer 7fe79000.framebuffer: framebuffer at 0x7fe79000, 0x178e00 bytes, mapped to 0x(ptrval)
[    0.046258] simple-framebuffer 7fe79000.framebuffer: format=x8r8g8b8, mode=656x536x32, linelength=2880
[    0.052472] Console: switching to colour frame buffer device 82x33
[    0.058369] simple-framebuffer 7fe79000.framebuffer: fb0: simplefb registered!
[    0.066686] NET: Registered protocol family 2
[    0.067281] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes)
[    0.067316] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
[    0.067395] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
[    0.067522] TCP: Hash tables configured (established 8192 bind 8192)
[    0.067655] UDP hash table entries: 512 (order: 2, 16384 bytes)
[    0.067722] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
[    0.067964] NET: Registered protocol family 1
[    0.068567] RPC: Registered named UNIX socket transport module.
[    0.068583] RPC: Registered udp transport module.
[    0.068590] RPC: Registered tcp transport module.
[    0.068596] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.069204] hw perfevents: no interrupt-affinity property for /pmu, guessing.
[    0.069499] hw perfevents: enabled with armv7_cortex_a7 PMU driver, 5 counters available
[    0.071072] workingset: timestamp_bits=30 max_order=18 bucket_order=0
[    0.077754] NFS: Registering the id_resolver key type
[    0.077803] Key type id_resolver registered
[    0.077812] Key type id_legacy registered
[    0.079006] bounce: pool size: 64 pages
[    0.079106] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 248)
[    0.079119] io scheduler noop registered
[    0.079127] io scheduler deadline registered
[    0.079295] io scheduler cfq registered (default)
[    0.079307] io scheduler mq-deadline registered
[    0.079315] io scheduler kyber registered
[    0.080074] sun4i-usb-phy 1c13400.phy: could not find pctldev for node /soc@1c00000/pinctrl@1c20800/usb0_id_detect_pin@0, deferring probe
[    0.083501] sun4i-pinctrl 1c20800.pinctrl: initialized sunXi PIO driver
[    0.140590] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled
[    0.143240] console [ttyS0] disabled
[    0.163431] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 48, base_baud = 1500000) is a U6_16550A
[    1.630962] console [ttyS0] enabled
[    1.661099] 1c28c00.serial: ttyS1 at MMIO 0x1c28c00 (irq = 49, base_baud = 1500000) is a U6_16550A
[    1.702024] 1c29c00.serial: ttyS2 at MMIO 0x1c29c00 (irq = 50, base_baud = 1500000) is a U6_16550A
[    1.723737] sun4i-backend 1e60000.display-backend: Couldn't find matching frontend, frontend features disabled [ 1.744080] sun4i-drm display-engine: bound 1e60000.display-backend (ops 0xc07482cc) [ 1.759592] sun4i-backend 1e40000.display-backend: Couldn't find matching frontend, frontend features disabled
[    1.779827] sun4i-drm display-engine: bound 1e40000.display-backend (ops 0xc07482cc)
[    1.795785] sun4i-drm display-engine: No panel or bridge found... RGB output disabled
[    1.811456] sun4i-drm display-engine: bound 1c0c000.lcd-controller (ops 0xc074724c)
[    1.827130] sun4i-drm display-engine: No panel or bridge found... RGB output disabled
[    1.842825] sun4i-drm display-engine: bound 1c0d000.lcd-controller (ops 0xc074724c)
[    1.858540] sun4i-drm display-engine: bound 1c16000.hdmi (ops 0xc0748cd0)
[    1.872123] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    1.885344] [drm] No driver support for vblank timestamp query.
[    1.897182] fb: switching to sun4i-drm-fb from simple
[    1.907391] Console: switching to colour dummy device 80x30
[    2.418984] [drm] Cannot find any crtc or sizes
[    2.428711] [drm] Initialized sun4i-drm 1.0.0 20150629 for display-engine on minor 0
[    2.545528] ahci-sunxi 1c18000.sata: controller can't do PMP, turning off CAP_PMP [ 2.560532] ahci-sunxi 1c18000.sata: SSS flag set, parallel bus scan disabled [ 2.574817] ahci-sunxi 1c18000.sata: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl platform mode [ 2.592721] ahci-sunxi 1c18000.sata: flags: ncq sntf stag pm led clo only pio slum part ccc [ 2.610642] scsi host0: ahci-sunxi [ 2.617874] ata1: SATA max UDMA/133 mmio [mem 0x01c18000-0x01c18fff] port 0x100 irq 36 [ 2.635546] libphy: Fixed MDIO Bus: probed [ 2.643735] CAN device driver interface [ 2.652152] sun7i-dwmac 1c50000.ethernet: PTP uses main clock [ 2.663680] sun7i-dwmac 1c50000.ethernet: no reset control found [ 2.676345] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver [ 2.689416] ehci-platform: EHCI generic platform driver [ 2.700248] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    2.712647] ohci-platform: OHCI generic platform driver
[    2.725114] sunxi-rtc 1c20d00.rtc: registered as rtc0
[    2.735252] sunxi-rtc 1c20d00.rtc: RTC enabled
[    2.744274] i2c /dev entries driver
[    2.752374] axp20x-i2c 1-0034: AXP20x variant AXP209 found
[    2.778365] input: axp20x-pek as /devices/platform/soc@1c00000/1c2ac00.i2c/i2c-1/1-0034/axp20x-pek/input/input0
[    2.799556] ldo1: supplied by regulator-dummy
[    2.808582] ldo2: supplied by regulator-dummy
[    2.818392] ldo3: supplied by regulator-dummy
[    2.827795] ldo4: supplied by regulator-dummy
[    2.836730] ldo5: supplied by regulator-dummy
[    2.846544] dcdc2: supplied by regulator-dummy
[    2.856093] dcdc3: supplied by regulator-dummy
[    2.866705] axp20x-i2c 1-0034: AXP20X driver loaded
[    2.877918] Registered IR keymap rc-empty
[    2.886099] rc rc0: sunxi-ir as /devices/platform/soc@1c00000/1c21800.ir/rc/rc0
[    2.900854] input: sunxi-ir as /devices/platform/soc@1c00000/1c21800.ir/rc/rc0/input1
[    2.916966] sunxi-ir 1c21800.ir: initialized sunXi IR driver
[    2.930370] sunxi-wdt 1c20c90.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)
[    2.949908] sunxi-mmc 1c0f000.mmc: Got CD GPIO
[    2.957174] ata1: SATA link down (SStatus 0 SControl 300)
[    2.984443] sunxi-mmc 1c0f000.mmc: base:0x(ptrval) irq:30
[    2.996403] sun4i-ss 1c15000.crypto-engine: Die ID 0
[    3.008208] usbcore: registered new interface driver usbhid
[    3.019411] usbhid: USB HID core driver
[    3.028477] random: fast init done
[    3.038082] sun4i-codec 1c22c00.codec: ASoC: Failed to create component debugfs directory
[    3.055988] sun4i-codec 1c22c00.codec: Codec <-> 1c22c00.codec mapping ok
[    3.070975] NET: Registered protocol family 17
[    3.079931] can: controller area network core (rev 20170425 abi 9)
[    3.092458] NET: Registered protocol family 29
[    3.101361] can: raw protocol (rev 20170425)
[    3.109908] can: broadcast manager protocol (rev 20170425 t)
[    3.121240] can: netlink gateway (rev 20170425) max_hops=1
[    3.132444] Key type dns_resolver registered
[    3.141113] Registering SWP/SWPB emulation handler
[    3.155150] mmc0: host does not support reading read-only switch, assuming write-enable
[    3.162888] sun7i-dwmac 1c50000.ethernet: PTP uses main clock
[    3.182777] sun7i-dwmac 1c50000.ethernet: no reset control found
[    3.194864] mmc0: new high speed SDHC card at address 59b4
[    3.206939] mmcblk0: mmc0:59b4 USD00 7.32 GiB
[    3.217882]  mmcblk0: p1 p2
[    3.305735] sun7i-dwmac 1c50000.ethernet: Version ID not available
[    3.318137] sun7i-dwmac 1c50000.ethernet:    DWMAC1000
[    3.328068] sun7i-dwmac 1c50000.ethernet: DMA HW capability register supported
[    3.342498] sun7i-dwmac 1c50000.ethernet: Normal descriptors
[    3.353804] sun7i-dwmac 1c50000.ethernet: Ring mode enabled
[    3.372879] libphy: stmmac: probed
[    3.379711] mdio_bus stmmac-0:00: attached PHY driver [unbound] (mii_bus:phy_addr=stmmac-0:00, irq=POLL)
[    3.398646] mdio_bus stmmac-0:01: attached PHY driver [unbound] (mii_bus:phy_addr=stmmac-0:01, irq=POLL)
[    3.437826] ehci-platform 1c14000.usb: EHCI Host Controller
[    3.449048] ehci-platform 1c14000.usb: new USB bus registered, assigned bus number 1
[    4.445622] [drm] Cannot find any crtc or sizes
[    4.454972] ehci-platform 1c14000.usb: irq 32, io mem 0x01c14000
[    4.495500] ehci-platform 1c14000.usb: USB 2.0 started, EHCI 1.00
[    4.508602] hub 1-0:1.0: USB hub found
[    4.516156] hub 1-0:1.0: 1 port detected
[    4.524842] ehci-platform 1c1c000.usb: EHCI Host Controller
[    4.536034] ehci-platform 1c1c000.usb: new USB bus registered, assigned bus number 2
[    4.551813] ehci-platform 1c1c000.usb: irq 37, io mem 0x01c1c000
[    4.585504] ehci-platform 1c1c000.usb: USB 2.0 started, EHCI 1.00
[    4.598505] hub 2-0:1.0: USB hub found
[    4.606055] hub 2-0:1.0: 1 port detected
[    4.614695] ohci-platform 1c14400.usb: Generic Platform OHCI controller
[    4.627974] ohci-platform 1c14400.usb: new USB bus registered, assigned bus number 3
[    4.643687] ohci-platform 1c14400.usb: irq 33, io mem 0x01c14400
[    4.730281] hub 3-0:1.0: USB hub found
[    4.737832] hub 3-0:1.0: 1 port detected
[    4.746524] ohci-platform 1c1c400.usb: Generic Platform OHCI controller
[    4.759793] ohci-platform 1c1c400.usb: new USB bus registered, assigned bus number 4
[    4.775542] ohci-platform 1c1c400.usb: irq 38, io mem 0x01c1c400
[    4.860311] hub 4-0:1.0: USB hub found
[    4.867876] hub 4-0:1.0: 1 port detected
[    4.876658] usb_phy_generic usb_phy_generic.0.auto: usb_phy_generic.0.auto supply vcc not found, using dummy regulator
[    4.898584] musb-hdrc musb-hdrc.1.auto: MUSB HDRC host driver
[    4.910112] musb-hdrc musb-hdrc.1.auto: new USB bus registered, assigned bus number 5
[    4.926629] hub 5-0:1.0: USB hub found
[    4.934193] hub 5-0:1.0: 1 port detected
[    4.942801] sunxi-rtc 1c20d00.rtc: setting system clock to 1970-01-01 00:00:11 UTC (11)
[    4.959189] vcc3v0: disabling
[    4.965121] vcc5v0: disabling
[    4.971086] usb0-vbus: disabling
[    4.977556] ALSA device list:
[    4.983479]   #0: sun4i-codec
[    4.989417] ### BBB.
[    4.997149] EXT4-fs (mmcblk0p2): INFO: recovery required on readonly filesystem
[    5.011809] EXT4-fs (mmcblk0p2): write access will be enabled during recovery
[    5.029755] EXT4-fs (mmcblk0p2): recovery complete
[    5.090424] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[    5.106669] VFS: Mounted root (ext4 filesystem) readonly on device 179:2.
[    5.121202] devtmpfs: mounted
[    5.127186] ## 111.
[    5.132783] Freeing unused kernel memory: 1024K
[    5.141851] ## 2.

可以看到从第 5 行到第 12 行区区几个函数,竟然打印了那么多,而且还看到了众多驱动相关的打印,如 usbConsoleKeyiopinctrlSerialCANRTCinputmmcmdio_bus,说明我们整天开发的驱动,是在这个阶段初始化的呀。这里我直接给出调用关系,可以看到,驱动相关的打印是在 do_initcalls() 中产生的

kernel_init()
	kernel_init_freeable()
		do_basic_setup()
			printk("### AAA.\n");
			do_initcalls();
			printk("### BBB.\n");
			
static void __init do_initcalls(void)
{ 
   
	int level;

	for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
		do_initcall_level(level);
}

do_initcalls() 函数循环将编译进内核的内核模块的初始化函数依次调用一遍。这些初始化函数也是有等级的,总共有 7 个级别 1-7,数字越大,级别越低,被调用的就越晚。其中我们最长用的 module_init() 为第 6 级,等级算是比较低的了,调用也会较晚,想想也是,好多外部模块都是使用的 module_init(),它们可都是在内核完全启动后,再手动安装的呀,更晚。
这个阶段打印了很多 log,说明内核中大部分的代码都是驱动,内核中写了大量的内核模块初始化的函数。
驱动初始化完,内核也就接近尾声了

[    4.989417] ### BBB.
[    4.997149] EXT4-fs (mmcblk0p2): INFO: recovery required on readonly filesystem
[    5.011809] EXT4-fs (mmcblk0p2): write access will be enabled during recovery
[    5.029755] EXT4-fs (mmcblk0p2): recovery complete
[    5.090424] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[    5.106669] VFS: Mounted root (ext4 filesystem) readonly on device 179:2.
[    5.121202] devtmpfs: mounted
[    5.127186] ## 111.
[    5.132783] Freeing unused kernel memory: 1024K
[    5.141851] ## 2.
[    5.145862] ## 3.
[    5.149703] ## 4.
[    5.162188] ## kernel_init() --> /sbin/init
## init_main()
[    5.232554] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
Starting syslogd: OK
Starting klogd: OK
Running sysctl: OK
Initializing random number generator: OK
Saving random seed: [    5.377468] random: dd: uninitialized urandom read (512 bytes read)
OK
Starting network: OK

Welcome to Bananapi M1
buildroot login:
  • 挂载根文件系统
  • 内核收尾工作
  • kernel_init 内核线程调用 do_execve 函数,去执行 init 程序,产生 init 进程(1 号进程)。该内核线程终结。

rest_init() 函数的最后一句 cpu_startup_entry(CPUHP_ONLINE); 最终变成了 idle 进程(0 号进程)。

void cpu_startup_entry(enum cpuhp_state state)
{ 
   
	/* * This #ifdef needs to die, but it's too late in the cycle to * make this generic (ARM and SH have never invoked the canary * init for the non boot CPUs!). Will be fixed in 3.11 */
#ifdef CONFIG_X86
	/* * If we're the non-boot CPU, nothing set the stack canary up * for us. The boot CPU already has it initialized but no harm * in doing it again. This is a good place for updating it, as * we wont ever return from this function (so the invalid * canaries already on the stack wont ever trigger). */
	boot_init_stack_canary();
#endif
	arch_cpu_idle_prepare();
	cpuhp_online_idle(state);
	while (1)
		do_idle();
}

而在 kernel_init 同期稍晚创建的 kthreadd 内核线程,则一直存在,成为 2 号进程

# ps
PID   USER     COMMAND
    1 root     init
    2 root     [kthreadd]
    3 root     [rcu_gp]
    4 root     [rcu_par_gp]
    7 root     [kworker/u4:0-ev]
    8 root     [mm_percpu_wq]
    9 root     [ksoftirqd/0]
...

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/129312.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月13日 下午4:40
下一篇 2022年4月13日 下午4:40


相关推荐

  • 实测字节版Manus扣子空间6大实用场景,居然还能这么玩!(附扣子空间保姆级教程)

    实测字节版Manus扣子空间6大实用场景,居然还能这么玩!(附扣子空间保姆级教程)

    2026年3月12日
    2
  • html看板娘

    html看板娘DOCTYPE tml html body scriptsrc https eqcn ajz miesnfu com wp content plugins wp 3d pony live2dw lib L2Dwidget min js script L2Dwidget init model jsonPath script scriptsrc https body html

    2026年3月17日
    2
  • Python 数据可视化,常用看这一篇就够了

    Python 数据可视化,常用看这一篇就够了文章目录前言可视化视图分为4类,散点图折线图直方图条形图箱线图饼图热力图蜘蛛图二元变量分布成对关系总结前言如果你想要用Python进行数据分析,就需要在项目初期开始进行探索性的数据分析,这样方便你对数据有一定的了解。其中最直观的就是采用数据可视化技术,这样,数据不仅一目了然,而且更容易被解读。可视化视图分为4类,比较:比较数据间各类别的关系,或者是它们随着时间的变化趋势,比如折线图;联系:查看两个或两个以上变量之间的关系,比如散点图;构成:每个部分占整体的百分比,或者是随着时间的百

    2022年6月29日
    26
  • 2026年win10家庭版升级专业版教程

    2026年win10家庭版升级专业版教程

    2026年3月14日
    2
  • 决策树(分类树、回归树)

    决策树(分类树、回归树)决策树前言 第一篇博客 最近看完决策树 想着归纳一下 也方便自己以后回顾 写的会比较全面一些 可能会有很多不太正确的地方 欢迎大家交流指正 决策树模型 决策树模型是运用于分类以及回归的一种树结构 决策树由节点和有向边组成 一般一棵决策树包含一个根节点 若干内部节点和若干叶节点 决策树的决策过程需要从决策树的根节点开始 待测数据与决策树中的特征节点进行比较 并按照比较结果选

    2026年3月19日
    2
  • SchedulerFactoryBean的问题「建议收藏」

    SchedulerFactoryBean的问题「建议收藏」http://blog.csdn.net/beliefer/article/details/51578546转载于:https://www.cnblogs.com/yangwei20160911/p/6867182.html

    2022年5月10日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号