gdb跟踪调试内核从start_kernel到init进程启动

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gdb跟踪调试内核从start_kernel到init进程启动相关的知识,希望对你有一定的参考价值。

顾涛原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

如果我写的不好或者有误的地方请留言

  • 题目自拟,内容围绕Linux内核的启动过程,即从start_kernel到init进程启动;
  • 博客中需要使用实验截图
  • 博客内容中需要仔细分析start_kernel函数的执行过程
  • 总结部分需要阐明自己对“Linux系统启动过程”的理解,尤其是idle进程、1号进程是怎么来的。

实验报告:

在实验楼里跑了一下gdb 没有多大印象 印象就是卡 这是卡吗 下面分析换自己的虚拟机

技术分享

先来个宏观认识:

从start_kernel()中可以看到最后一条语句是rest_init();

技术分享
  1 asmlinkage __visible void __init start_kernel(void)
  2 {
  3     char *command_line;
  4     char *after_dashes;
  5 
  6     /*
  7      * Need to run as early as possible, to initialize the
  8      * lockdep hash:
  9      */
 10     lockdep_init();
 11     set_task_stack_end_magic(&init_task);
 12     smp_setup_processor_id();
 13     debug_objects_early_init();
 14 
 15     /*
 16      * Set up the the initial canary ASAP:
 17      */
 18     boot_init_stack_canary();
 19 
 20     cgroup_init_early();
 21 
 22     local_irq_disable();
 23     early_boot_irqs_disabled = true;
 24 
 25 /*
 26  * Interrupts are still disabled. Do necessary setups, then
 27  * enable them
 28  */
 29     boot_cpu_init();
 30     page_address_init();
 31     pr_notice("%s", linux_banner);
 32     setup_arch(&command_line);
 33     mm_init_cpumask(&init_mm);
 34     setup_command_line(command_line);
 35     setup_nr_cpu_ids();
 36     setup_per_cpu_areas();
 37     smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */
 38 
 39     build_all_zonelists(NULL, NULL);
 40     page_alloc_init();
 41 
 42     pr_notice("Kernel command line: %s\n", boot_command_line);
 43     parse_early_param();
 44     after_dashes = parse_args("Booting kernel",
 45                   static_command_line, __start___param,
 46                   __stop___param - __start___param,
 47                   -1, -1, &unknown_bootoption);
 48     if (!IS_ERR_OR_NULL(after_dashes))
 49         parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
 50                set_init_arg);
 51 
 52     jump_label_init();
 53 
 54     /*
 55      * These use large bootmem allocations and must precede
 56      * kmem_cache_init()
 57      */
 58     setup_log_buf(0);
 59     pidhash_init();
 60     vfs_caches_init_early();
 61     sort_main_extable();
 62     trap_init();
 63     mm_init();
 64 
 65     /*
 66      * Set up the scheduler prior starting any interrupts (such as the
 67      * timer interrupt). Full topology setup happens at smp_init()
 68      * time - but meanwhile we still have a functioning scheduler.
 69      */
 70     sched_init();
 71     /*
 72      * Disable preemption - early bootup scheduling is extremely
 73      * fragile until we cpu_idle() for the first time.
 74      */
 75     preempt_disable();
 76     if (WARN(!irqs_disabled(),
 77          "Interrupts were enabled *very* early, fixing it\n"))
 78         local_irq_disable();
 79     idr_init_cache();
 80     rcu_init();
 81     context_tracking_init();
 82     radix_tree_init();
 83     /* init some links before init_ISA_irqs() */
 84     early_irq_init();
 85     init_IRQ();
 86     tick_init();
 87     rcu_init_nohz();
 88     init_timers();
 89     hrtimers_init();
 90     softirq_init();
 91     timekeeping_init();
 92     time_init();
 93     sched_clock_postinit();
 94     perf_event_init();
 95     profile_init();
 96     call_function_init();
 97     WARN(!irqs_disabled(), "Interrupts were enabled early\n");
 98     early_boot_irqs_disabled = false;
 99     local_irq_enable();
100 
101     kmem_cache_init_late();
102 
103     /*
104      * HACK ALERT! This is early. We‘re enabling the console before
105      * we‘ve done PCI setups etc, and console_init() must be aware of
106      * this. But we do want output early, in case something goes wrong.
107      */
108     console_init();
109     if (panic_later)
110         panic("Too many boot %s vars at `%s‘", panic_later,
111               panic_param);
112 
113     lockdep_info();
114 
115     /*
116      * Need to run this when irqs are enabled, because it wants
117      * to self-test [hard/soft]-irqs on/off lock inversion bugs
118      * too:
119      */
120     locking_selftest();
121 
122 #ifdef CONFIG_BLK_DEV_INITRD
123     if (initrd_start && !initrd_below_start_ok &&
124         page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
125         pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
126             page_to_pfn(virt_to_page((void *)initrd_start)),
127             min_low_pfn);
128         initrd_start = 0;
129     }
130 #endif
131     page_cgroup_init();
132     debug_objects_mem_init();
133     kmemleak_init();
134     setup_per_cpu_pageset();
135     numa_policy_init();
136     if (late_time_init)
137         late_time_init();
138     sched_clock_init();
139     calibrate_delay();
140     pidmap_init();
141     anon_vma_init();
142     acpi_early_init();
143 #ifdef CONFIG_X86
144     if (efi_enabled(EFI_RUNTIME_SERVICES))
145         efi_enter_virtual_mode();
146 #endif
147 #ifdef CONFIG_X86_ESPFIX64
148     /* Should be run before the first non-init thread is created */
149     init_espfix_bsp();
150 #endif
151     thread_info_cache_init();
152     cred_init();
153     fork_init(totalram_pages);
154     proc_caches_init();
155     buffer_init();
156     key_init();
157     security_init();
158     dbg_late_init();
159     vfs_caches_init(totalram_pages);
160     signals_init();
161     /* rootfs populating might need page-writeback */
162     page_writeback_init();
163     proc_root_init();
164     cgroup_init();
165     cpuset_init();
166     taskstats_init_early();
167     delayacct_init();
168 
169     check_bugs();
170 
171     sfi_init_late();
172 
173     if (efi_enabled(EFI_RUNTIME_SERVICES)) {
174         efi_late_init();
175         efi_free_boot_services();
176     }
177 
178     ftrace_init();
179 
180     /* Do the rest non-__init‘ed, we‘re now alive */
181     rest_init();
182 }
start_kernel
技术分享
 1 static noinline void __init_refok rest_init(void)
 2 {
 3     int pid;
 4 
 5     rcu_scheduler_starting();
 6     /*
 7      * We need to spawn init first so that it obtains pid 1, however
 8      * the init task will end up wanting to create kthreads, which, if
 9      * we schedule it before we create kthreadd, will OOPS.
10      */
11     kernel_thread(kernel_init, NULL, CLONE_FS);
12     numa_default_policy();
13     pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
14     rcu_read_lock();
15     kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
16     rcu_read_unlock();
17     complete(&kthreadd_done);
18 
19     /*
20      * The boot idle thread must execute schedule()
21      * at least once to get things moving:
22      */
23     init_idle_bootup_task(current);
24     schedule_preempt_disabled();
25     /* Call into cpu_idle with preempt disabled */
26     cpu_startup_entry(CPUHP_ONLINE);
27 }
rest_init

咱们需要知道的东西如下:

在start_kernel中:

init_task:手工创建的PCB 0号进程即最终的idle进程
trap_init:初始化中断管理模块
mm_init:初始化内存管理模块
sched_init:初始化调度模块

在rest_init中:

run_init_process:linux系统中的1号进程 第一个用户态进程

注意:

1.我们需要首先初始化获得pid=1的进程 如果初始化最终创建了ktheads

我们在创建kthreadd之前调度它 Linux系统将会OOPS

2.启动空闲线程必须至少执行一次schedule()

 

以上是关于gdb跟踪调试内核从start_kernel到init进程启动的主要内容,如果未能解决你的问题,请参考以下文章

跟踪调试Linux内核的启动过程

构建调试Linux内核网络代码的环境MenuOS系统

实验三:跟踪分析Linux内核的启动过程 ----- 20135108 李泽源

跟踪分析Linux内核的启动过程

Linux内核的启动过程分析

构建调试Linux内核网络代码的环境MenuOS系统