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 }
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 }
咱们需要知道的东西如下:
在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进程启动的主要内容,如果未能解决你的问题,请参考以下文章