Kernel Life Cycle
When uboot finishes printing the Starting kernel..., it completes its mission and gives control to the first instruction of the kernel, which is the function below
init/main.c
asmlinkage __visible void __init start_kernel(void) { ... rest_init(); }
Start_ Kenel is equivalent to the main function of the kernel, and the life cycle of the kernel begins with the first statement that executes the function and ends with the last function, reset_init(), the kernel will no longer return from this function, but will fall into a while(1) dead loop inside this function, which is treated as an idle process, or process 0.
So the life cycle of the kernel is a complete start_kernel function. Start_ The first statement of the kernel function stays in the final dead loop.
init process
Kernel creates a number of kernel threads to keep working on memory, disk, and CPU management. Two of them are more important and need to be highlighted: the Number 1 kernel thread, kernel_init and kernel thread 2 kthreadd. Kernel thread number 1 will eventually be replaced by the user's first process init, which is also process number 1. The following:
# 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 is a column in which the kernel thread is enclosed and the user process is not enclosed. As you can see from the uniform PID address, they are in the same position.
Let's take a closer look at starting_ What happened to kernel s until they finally ran the init process
Adding printing is a good way to analyze the process.
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"); }
At first, I tried to add printk printing at the beginning of the function, and found that the kernel didn't start after adding printk, and conservatively at 131 lines console_init(); Then start adding prints.
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() // Printing of 132 lines
However, found in console_init() has been printed a lot before, and this place is still a bit confusing. Guess is either in console_init() was ready to print before; Either in console_init() caches the prints before initializing them. Let's study this later. Insert an eye first 👁.
Next to Print
[ 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()
From 133 to 206 lines, there is a lot of code, but only 5 lines are printed. Less is less important, then no analysis, haha 😁.
Look at the code below, you're good, there's only one sentence left:rest_init();, And line 210 printk waits until the system is completely unprinted, indicating rest_init() does not return. It looks like a handlebarrel.
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"); }
Corresponding prints are as follows:
[ 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
Printed kernel_init(), because schedule_was called Preempt_ Disabled(), which calls schedule() internally to perform process switching and go to sleep. Of course, when the current process wakes up, the program starts from this breakpoint.
void __sched schedule_preempt_disabled(void) { sched_preempt_enable_no_resched(); schedule(); preempt_disable(); }
After process switching, kernel_init() has the opportunity to run
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."); }
Corresponding prints are as follows:
[ 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.
You can see how many functions from lines 5 to 12 are printed, and how many driver-related prints are available, such as usb, Console, Key, io, pinctrl, Serial, CAN, RTC, input, mmc, mdio_bus, the driver we developed all day long, was initialized at this stage. Here I'm going to give the call directly, and you can see that the drive-related printing is in do_ Generated in 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_ The initcalls() function loop calls the initialization functions of the kernel module compiled into the kernel one after the other. These initialization functions are also hierarchical, with a total of seven levels 1-7. The higher the number, the lower the level, the later it will be called. The module_that we use the longest Init() is level 6, the level is relatively low, the call will be late, think about it, many external modules are using module_init(), they are all installed manually after the kernel is fully booted, even later.
This phase prints a lot of log s, indicating that most of the code in the kernel is driven and that a lot of functions initialized by kernel modules are written in the kernel.
When the driver is initialized, the kernel is close to the end
[ 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:
- Mount the root file system
- Kernel End Work
- kernel_init kernel thread calls do_execve function to execute the init program, resulting in the init process (process 1). The kernel thread terminated.
Rest_ Cpu_last sentence of init() function Startup_ Entry (CPUHP_ONLINE); It eventually becomes the idle process (process 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(); }
In kernel_ The kthreadd kernel thread that init created later in the same period persists and becomes process 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] ...