Linux内核的启动简述

来源:互联网 发布:cf最新刷枪软件 编辑:程序博客网 时间:2024/05/22 15:53

原创作品转载请注明出处 

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

回顾知识:

操作系统法宝:堆栈中断上下文切换进程上下文切换


Linux源代码目录 linux-3.18.6


主要目录介绍:

arch不同的CPU体系结构相关的代码,主要研究x86目录Documentation相关文档drivers驱动相关代码fs文件系统相关代码init内核启动相关代码,其中main.c的start_kernel是系统启动的入口Kernel内核相关代码mm内存管理相关代码net网络相关代码


gdb命令

c 继续执行(continue)

list 查看代码

break 设置断点


调试内核

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S # 关于-s和-S选项的说明:# -S freeze CPU at startup (use ’c’ to start execution)# -s shorthand for -gdb tcp::1234 若不想使用1234端口,则可以使用-gdb tcp:xxxx来取代-s选项



gdb(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行(gdb)break start_kernel # 断点的设置可以在target remote之前,也可以在之后





kernel_init中完成初始化操作

9500asmlinkage __visible void __init start_kernel(void)501{502char *command_line;503char *after_dashes;504505/*506 * Need to run as early as possible, to initialize the507 * lockdep hash:508 */509lockdep_init();510set_task_stack_end_magic(&init_task);511smp_setup_processor_id();512debug_objects_early_init();513514/*515 * Set up the the initial canary ASAP:516 */517boot_init_stack_canary();518519cgroup_init_early();520521local_irq_disable();522early_boot_irqs_disabled = true;523524/*525 * Interrupts are still disabled. Do necessary setups, then526 * enable them527 */528boot_cpu_init();529page_address_init();530pr_notice("%s", linux_banner);531setup_arch(&command_line);532mm_init_cpumask(&init_mm);533setup_command_line(command_line);534setup_nr_cpu_ids();535setup_per_cpu_areas();536smp_prepare_boot_cpu();/* arch-specific boot-cpu hooks */537538build_all_zonelists(NULL, NULL);539page_alloc_init();540541pr_notice("Kernel command line: %s\n", boot_command_line);542parse_early_param();543after_dashes = parse_args("Booting kernel",544  static_command_line, __start___param,545  __stop___param - __start___param,546  -1, -1, &unknown_bootoption);547if (!IS_ERR_OR_NULL(after_dashes))548parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,549   set_init_arg);550551jump_label_init();552553/*554 * These use large bootmem allocations and must precede555 * kmem_cache_init()556 */557setup_log_buf(0);558pidhash_init();559vfs_caches_init_early();560sort_main_extable();561trap_init();562mm_init();563564/*565 * Set up the scheduler prior starting any interrupts (such as the566 * timer interrupt). Full topology setup happens at smp_init()567 * time - but meanwhile we still have a functioning scheduler.568 */569sched_init();570/*571 * Disable preemption - early bootup scheduling is extremely572 * fragile until we cpu_idle() for the first time.573 */574preempt_disable();575if (WARN(!irqs_disabled(),576 "Interrupts were enabled *very* early, fixing it\n"))577local_irq_disable();578idr_init_cache();579rcu_init();580context_tracking_init();581radix_tree_init();582/* init some links before init_ISA_irqs() */583early_irq_init();584init_IRQ();585tick_init();586rcu_init_nohz();587init_timers();588hrtimers_init();589softirq_init();590timekeeping_init();591time_init();592sched_clock_postinit();593perf_event_init();594profile_init();595call_function_init();596WARN(!irqs_disabled(), "Interrupts were enabled early\n");597early_boot_irqs_disabled = false;598local_irq_enable();599600kmem_cache_init_late();601602/*603 * HACK ALERT! This is early. We're enabling the console before604 * we've done PCI setups etc, and console_init() must be aware of605 * this. But we do want output early, in case something goes wrong.606 */607console_init();608if (panic_later)609panic("Too many boot %s vars at `%s'", panic_later,610      panic_param);611612lockdep_info();613614/*615 * Need to run this when irqs are enabled, because it wants616 * to self-test [hard/soft]-irqs on/off lock inversion bugs617 * too:618 */619locking_selftest();620621#ifdef CONFIG_BLK_DEV_INITRD622if (initrd_start && !initrd_below_start_ok &&623    page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {624pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",625    page_to_pfn(virt_to_page((void *)initrd_start)),626    min_low_pfn);627initrd_start = 0;628}629#endif630page_cgroup_init();631debug_objects_mem_init();632kmemleak_init();633setup_per_cpu_pageset();634numa_policy_init();635if (late_time_init)636late_time_init();637sched_clock_init();638calibrate_delay();639pidmap_init();640anon_vma_init();641acpi_early_init();642#ifdef CONFIG_X86643if (efi_enabled(EFI_RUNTIME_SERVICES))644efi_enter_virtual_mode();645#endif646#ifdef CONFIG_X86_ESPFIX64647/* Should be run before the first non-init thread is created */648init_espfix_bsp();649#endif650thread_info_cache_init();651cred_init();652fork_init(totalram_pages);653proc_caches_init();654buffer_init();655key_init();656security_init();657dbg_late_init();658vfs_caches_init(totalram_pages);659signals_init();660/* rootfs populating might need page-writeback */661page_writeback_init();662proc_root_init();663cgroup_init();664cpuset_init();665taskstats_init_early();666delayacct_init();667668check_bugs();669670sfi_init_late();671672if (efi_enabled(EFI_RUNTIME_SERVICES)) {673efi_late_init();674efi_free_boot_services();675}676677ftrace_init();678679/* Do the rest non-__init'ed, we're now alive */680rest_init();681}

trap_init : 中断向量的初始化工作

set_intr_gate : 设置中断门

set_system_trap_gate : 系统调用中断

393static noinline void __init_refok rest_init(void)394{395int pid;396397rcu_scheduler_starting();398/*399 * We need to spawn init first so that it obtains pid 1, however400 * the init task will end up wanting to create kthreads, which, if401 * we schedule it before we create kthreadd, will OOPS.402 */403kernel_thread(kernel_init, NULL, CLONE_FS);404numa_default_policy();405pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);406rcu_read_lock();407kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);408rcu_read_unlock();409complete(&kthreadd_done);410411/*412 * The boot idle thread must execute schedule()413 * at least once to get things moving:414 */415init_idle_bootup_task(current);416schedule_preempt_disabled();417/* Call into cpu_idle with preempt disabled */418cpu_startup_entry(CPUHP_ONLINE);419}

reset_init : 0进程初始化工作

kernel_init : 1号进程(用户态)初始化


Linux中1号进程是由0号进程来创建的,因此必须要知道的是如何创建0号进程,由于在创建进程时,程序一直运行在内核态,而进程运行在用户态,因此创建0号进程涉及到特权级的变化,即从特权级0变到特权级3,Linux是通过模拟中断返回来实现特权级的变化以及创建0号进程,通过将0号进程的代码段选择子以及程序计数器EIP直接压入内核态堆栈,然后利用iret汇编指令中断返回跳转到0号进程运行。

0 0
原创粉丝点击