Linuxのカーネルの起動ルーチン

カーネルの起動ルーチン(start_kernel)は、メモリ管理などのOSの核を成す機能の起動を行う処理を行う。
ここが真のLinuxカーネルの入口と言える。

Linuxの起動において、これまでのフェーズはアセンブラで書かれていたが、ここからはアーキテクチャに依存しないC言語で書かれている。
カーネルの初期化ルーチンからインタフェース「start_kernel」の呼び出しにより制御を受け取る。

以下、Linux2.6ベースでそのプロセスについて、start_kernelに絞って説明を行う。
また、前提としてx86の32ビット版で処理が進むものとする。
(例のソースコードは、linux-2.6.31/init/main.c)


 470  asmlinkage void __init start_kernel(void)


__initは一度しか実行されないことを表しており、実行後初期化が行われたタイミングでメモリ上から削除することを表す。arch/x86/mm/init.c内に定義されたfree_initmem()によって開放される。

 471  {
  472          char * command_line;
  473          extern struct kernel_param __start___param[], __stop___param[];


変数の定義であるため、ここは割愛する。

 474          smp_setup_processor_id();
【ヘッダ】./include/linux/smp.h:
【実 装】無し
まず初めに、SMPの場合を想定し、初期化を行っているが、MIPS環境ではその処理実装が存在しない。
SPARCには実装が存在するが、x86が前提であるため割愛する。

 475          /*
  476           * Need to run as early as possible, to initialize the
  477           * lockdep hash:
  478           */
  479          lockdep_init();
【ヘッダ】./include/linux/lockdep.h
【実 装】./kernel/lockdep.c
lockdepは、Runtime locking correctness validatorという名称が与えられており、このメソッドは実行環境下でロックが正常に行われているかを確認する管理するモジュールを初期化するものであると考えられる。

 480          debug_objects_early_init();
【ヘッダ】./include/linux/debugobjects.h
【実 装】./lib/debugobjects.c
名前からデバッグ用のオブジェクトを管理するモジュールを初期化するものであると考えられる。

 481          /*
  482           * Set up the the initial canary ASAP:
  483           */
  484          boot_init_stack_canary();
【ヘッダ】./arch/x86/include/asm/stackprotector.h
【実 装】./arch/x86/kernel/process_32.c: boot_init_stack_canary();
名前からカナリアコードを管理するモジュールの初期化を行っているものであると考えられる。
カナリアコードとは、C言語により作成されたコードのセキュリティを高めるための技術である。
コメントにもある通り、これは実行コードの脆弱性を無くすための処理であるため、できる限り早い実行(ASAP:As Soon As Possible)を要求している。

 485          cgroup_init_early();
【ヘッダ】./include/linux/cgroup.h
【実 装】./kernel/cgroup.c
名前からcgroup(Control Group)と呼ばれるリソース管理のモジュールを初期化するものであると考えられる。
リソースをひとつのプロセスが占有しないよう制限を行う仕組みである。
初期化成功時に、以下のようにdmesgへ出力される。
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpu

 486          local_irq_disable();
【ヘッダ】
【実 装】
。(実装の目的が理解でき次第掲載)

 487          early_boot_irqs_off();
【ヘッダ】./include/linux/lockdep.h
【実 装】./kernel/trace/trace_irqsoff.c
。(実装の目的が理解でき次第掲載)

 488          early_init_irq_lock_class();
【ヘッダ】./include/linux/lockdep.h
【実 装】./kernel/irq/handle.c
。(実装の目的が理解でき次第掲載)

 489  /*
  490   * Interrupts are still disabled. Do necessary setups, then
  491   * enable them
  492   */
割り込みの禁止はかかっている状態のままであることを示している。
ブートイメージの初期化ルーチンにて、その処理は行われている。

 493          lock_kernel();
【ヘッダ】./include/linux/smp_lock.h
【実 装】./lib/kernel_lock.c
名前から、カーネルロック(ジャイアントロック)の取得、つまりこの後の処理で他からの制御を受け付けない。

 494          tick_init();
【ヘッダ】./include/linux/tick.h
【実 装】./kernel/time/tick-common.c
名前から、時間関連モジュールの初期化を行っていると考えられる。

 495          boot_cpu_init();
【ヘッダ】自ファイル内
【実 装】自ファイル内
名前から、CPU・またそれを管理する情報の初期化を行っていると考えられる。
(実装の目的が理解でき次第掲載)

 496          page_address_init();
【ヘッダ】./include/linux/mm.h
【実 装】./mm/highmem.c
名前から、メモリ管理のモジュールを初期化するのが目的であると考えられる。
しかし、現状は実装で何の処理も行っていない。

 497          printk(KERN_NOTICE "%s", linux_banner);
画面上にLinuxのバージョン等の情報を出力する。Fedora10では、以下の文字列が出力された。
Linux version 2.6.31.5-127.fc12.i686.PAE (mockbuild@x86-3.fedora.phx.redhat.com) (gcc ver・・・(略)

 498          setup_arch(&command_line);
【ヘッダ】./include/linux/init.h
【実 装】./arch/x86/kernel/setup.c
(実装の目的が理解でき次第掲載)
恐らく、以下の出力はこのメソッドが行ったものと思われる。
KERNEL supported cpus:
  Intel GenuineIntel
  AMD AuthenticAMD
  ・・・(略)
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
  ・・・(略)
DMI present.
AMI BIOS detected: BIOS may corrupt low RAM, working around it.
e820 update range: 0000000000000000 - 0000000000010000 (usable) ==> (reserved)
last_pfn = 0x3f7a0 max_arch_pfn = 0x1000000
MTRR default type: uncachable
MTRR fixed ranges enabled:
00000-9FFFF write-back
 A0000-DFFFF uncachable
 E0000-E3FFF write-protect
 E4000-EFFFF write-through
 F0000-FFFFF write-protect
MTRR variable ranges enabled:
0 base 000000000 mask 0C0000000 write-back
 1 base 03F800000 mask 0FF800000 uncachable
 2 disabled
 3 disabled
 4 disabled
 5 disabled
 6 disabled
 7 disabled

 499          mm_init_owner(&init_mm, &init_task);
【ヘッダ】./include/linux/sched.h
【実 装】./kernel/fork.c



 500          setup_command_line(command_line);
【ヘッダ】
【実 装】

 501          setup_nr_cpu_ids();
【ヘッダ】
【実 装】

 502          setup_per_cpu_areas();
【ヘッダ】
【実 装】

 503          smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
【ヘッダ】
【実 装】


 504          build_all_zonelists();
【ヘッダ】
【実 装】

 505          page_alloc_init();
【ヘッダ】
【実 装】


 506          printk(KERN_NOTICE "Kernel command line: %s
", boot_command_line);
【ヘッダ】
【実 装】

 507          parse_early_param();
【ヘッダ】
【実 装】

 508          parse_args("Booting kernel", static_command_line, __start___param,
【ヘッダ】
【実 装】

 509                     __stop___param - __start___param,
【ヘッダ】
【実 装】

 510                     &unknown_bootoption);
【ヘッダ】
【実 装】

 511          /*
  512           * These use large bootmem allocations and must precede
  513           * kmem_cache_init()
  514           */
【ヘッダ】
【実 装】

 515          pidhash_init();
【ヘッダ】
【実 装】

 516          vfs_caches_init_early();
【ヘッダ】
【実 装】

 517          sort_main_extable();
【ヘッダ】
【実 装】

 518          trap_init();
【ヘッダ】
【実 装】

 519          mm_init();
【ヘッダ】
【実 装】

 520          /*
  521           * Set up the scheduler prior starting any interrupts (such as the
  522           * timer interrupt). Full topology setup happens at smp_init()
  523           * time - but meanwhile we still have a functioning scheduler.
  524           */
  525          sched_init();
【ヘッダ】
【実 装】

 526          /*
  527           * Disable preemption - early bootup scheduling is extremely
  528           * fragile until we cpu_idle() for the first time.
  529           */
  530          preempt_disable();
【ヘッダ】
【実 装】

 531          if (!irqs_disabled()) {
  532                  printk(KERN_WARNING "start_kernel(): bug: interrupts were "
  533                                  "enabled *very* early, fixing it
");
 534                  local_irq_disable();
  535          }
【ヘッダ】
【実 装】

 536          rcu_init();
【ヘッダ】
【実 装】

 537          /* init some links before init_ISA_irqs() */
  538          early_irq_init();
【ヘッダ】
【実 装】

 539          init_IRQ();
【ヘッダ】
【実 装】

 540          prio_tree_init();
【ヘッダ】
【実 装】

 541          init_timers();
【ヘッダ】
【実 装】

 542          hrtimers_init();
【ヘッダ】
【実 装】

 543          softirq_init();
【ヘッダ】
【実 装】

 544          timekeeping_init();
【ヘッダ】
【実 装】

 545          time_init();
【ヘッダ】
【実 装】

 546          sched_clock_init();
【ヘッダ】
【実 装】

 547          profile_init();
【ヘッダ】
【実 装】

 548          if (!irqs_disabled())
【ヘッダ】
【実 装】

 549                  printk(KERN_CRIT "start_kernel(): bug: interrupts were "
【ヘッダ】
【実 装】

 550                                   "enabled early
");
【ヘッダ】
【実 装】

 551          early_boot_irqs_on();
【ヘッダ】
【実 装】

 552          local_irq_enable();
【ヘッダ】
【実 装】


 553          /* Interrupts are enabled now so all GFP allocations are safe. */
【ヘッダ】
【実 装】

 554          set_gfp_allowed_mask(__GFP_BITS_MASK);

【ヘッダ】
【実 装】

 555          kmem_cache_init_late();

【ヘッダ】
【実 装】

 556          /*
  557           * HACK ALERT! This is early. We're enabling the console before
  558           * we've done PCI setups etc, and console_init() must be aware of
  559           * this. But we do want output early, in case something goes wrong.
  560           */
  561          console_init();
【ヘッダ】
【実 装】

 562          if (panic_later)
  563                  panic(panic_later, panic_param);
【ヘッダ】
【実 装】


 564          lockdep_info();
【ヘッダ】
【実 装】


 565          /*
  566           * Need to run this when irqs are enabled, because it wants
  567           * to self-test [hard/soft]-irqs on/off lock inversion bugs
  568           * too:
  569           */
  570          locking_selftest();
【ヘッダ】
【実 装】


 571  #ifdef CONFIG_BLK_DEV_INITRD
  572          if (initrd_start && !initrd_below_start_ok &&
  573              page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  574                  printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
  575                      "disabling it.
",
 576                      page_to_pfn(virt_to_page((void *)initrd_start)),
  577                      min_low_pfn);
  578                  initrd_start = 0;
  579          }
  580  #endif
【ヘッダ】
【実 装】

 581          page_cgroup_init();
【ヘッダ】
【実 装】

 582          enable_debug_pagealloc();
【ヘッダ】
【実 装】

 583          kmemtrace_init();
【ヘッダ】
【実 装】

 584          kmemleak_init();
【ヘッダ】
【実 装】

 585          debug_objects_mem_init();
【ヘッダ】
【実 装】

 586          idr_init_cache();
【ヘッダ】
【実 装】

 587          setup_per_cpu_pageset();
【ヘッダ】
【実 装】

 588          numa_policy_init();
【ヘッダ】
【実 装】

 589          if (late_time_init)
  590                  late_time_init();
【ヘッダ】
【実 装】

 591          calibrate_delay();
【ヘッダ】
【実 装】

 592          pidmap_init();
【ヘッダ】
【実 装】

 593          anon_vma_init();
【ヘッダ】
【実 装】

 594  #ifdef CONFIG_X86
  595          if (efi_enabled)
  596                  efi_enter_virtual_mode();
  597  #endif
【ヘッダ】
【実 装】

 598          thread_info_cache_init();
【ヘッダ】
【実 装】

 599          cred_init();
【ヘッダ】
【実 装】

 600          fork_init(num_physpages);
【ヘッダ】
【実 装】

 601          proc_caches_init();
【ヘッダ】
【実 装】

 602          buffer_init();
【ヘッダ】
【実 装】

 603          key_init();
【ヘッダ】
【実 装】

 604          security_init();
【ヘッダ】
【実 装】

 605          vfs_caches_init(num_physpages);
【ヘッダ】
【実 装】

 606          radix_tree_init();
【ヘッダ】
【実 装】

 607          signals_init();
【ヘッダ】
【実 装】

 608          /* rootfs populating might need page-writeback */
  609          page_writeback_init();
【ヘッダ】
【実 装】

 610  #ifdef CONFIG_PROC_FS
  611          proc_root_init();
  612  #endif
【ヘッダ】
【実 装】

 613          cgroup_init();
【ヘッダ】
【実 装】

 614          cpuset_init();
【ヘッダ】
【実 装】

 615          taskstats_init_early();
【ヘッダ】
【実 装】

 616          delayacct_init();
【ヘッダ】
【実 装】


 617          check_bugs();
【ヘッダ】
【実 装】


 618          acpi_early_init(); /* before LAPIC and SMP init */
【ヘッダ】
【実 装】


 619          ftrace_init();
【ヘッダ】
【実 装】


 620          /* Do the rest non-__init'ed, we're now alive */
  621          rest_init();
【ヘッダ】
【実 装】

 622  }

構築・インストール

(後日掲載)

設定・調整

(後日掲載)

  • 最終更新:2009-12-06 22:56:10

このWIKIを編集するにはパスワード入力が必要です

認証パスワード