arm linux 啟動流程之 進入核心

來源:互聯網
上載者:User

Author-------Dansen-----xzd2734@163.com 

還是從編譯連結產生vmlinux的過程來看吧,由一大堆.o檔案連結而成,第一個就是
kernel/arch/arm/kernel/head-armv.o ,而且我們還看到了
lds連結檔案kernel/arch/arm/vmlinux.lds,先把它分析一下
ENTRY(stext) //進入點是stext 應該就在head-armv.s中了
SECTIONS
{
 . = 0xC0008000;  //基址,是核心開始的虛擬位址
 .init : {   /* Init code and data  */
  _stext = .;
  __init_begin = .;
   *(.text.init)
  __proc_info_begin = .;
   *(.proc.info)
  __proc_info_end = .;
  __arch_info_begin = .;
   *(.arch.info)
  __arch_info_end = .;
  __tagtable_begin = .;
   *(.taglist)
  __tagtable_end = .;
   *(.data.init)
  . = ALIGN(16);
  __setup_start = .;
   *(.setup.init)
  __setup_end = .;
  __initcall_start = .;
   *(.initcall.init)
  __initcall_end = .;
  . = ALIGN(4096);
  __init_end = .;
 }
關於虛擬位址和物理地址的:使用MMU後,系統就會使用虛擬位址,通過MMU來指向
實際物理地址而在這裡我們的0xC0008000實際物理地址就是0x30008000,
具體關於MMU的介紹參考《ARM體繫結構與編程》。
到head-armv.s找到程式的入口
  .section ".text.init",#alloc,#execinstr
  .type stext, #function
ENTRY(stext)
  mov r12, r0
  mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
  msr cpsr_c, r0   @ and all irqs disabled
  bl __lookup_processor_type
  teq r10, #0    @ invalid processor?
  moveq r0, #'p'   @ yes, error 'p'
  beq __error
  bl __lookup_architecture_type
  teq r7, #0    @ invalid architecture?
  moveq r0, #'a'   @ yes, error 'a'
  beq __error
  bl __create_page_tables
  adr lr, __ret   @ return address
  add pc, r10, #12   @ initialise processor
來看看上一句跳到哪裡去了
去追尋r10的值,是在__lookup_processor_type子函數中賦的
__lookup_processor_type:
  adr r5, 2f   //r5 標號2的地址 基址是0x30008000
  ldmia r5, {r7, r9, r10} //r7=__proc_info_end  r9=__proc_info_begin
  sub r5, r5, r10  //r10 標號2的連結地址   基址是0xc0008000
  add r7, r7, r5   @ to our address space
  add r10, r9, r5  //r10 變換為基址是0x30008000的__proc_info_begin
2:  .long __proc_info_end
  .long __proc_info_begin
  .long 2b
這樣r10中存放的是__proc_info_begin的地址,因為現在我們還沒有開啟MMU
所以還是需要把基址變換到0x30008000,接著我們就去找__proc_info_begin吧
注意到在上面的vmlinux.lds中有這個標號,下來連結的是.proc.info段,
在kernel/arch/arm/mm/proc-arm920.s的最後找到了這個段
 .section ".proc.info", #alloc, #execinstr

 .type __arm920_proc_info,#object
__arm920_proc_info:
 .long 0x41009200
 .long 0xff00fff0
 .long 0x00000c1e   @ mmuflags
 b __arm920_setup
ok,這樣我們就知道add pc, r10, #12跳到哪裡去了,因為這個地址剛好放了條跳躍陳述式
注意了b語句用的都是相對位址,所以不需要變換地址,反正是跳到__arm920_setup,而且
上一條語句是adr lr, __ret,設定了__arm920_setup的返回地址是__ret,所以執行完
__arm920_setup後回到head-armv.s的__ret標號繼續執行.
__ret:  ldr lr, __switch_data
  mcr p15, 0, r0, c1, c0 //注意這裡了,在這裡開啟了MMU
  mov r0, r0
  mov r0, r0
  mov r0, r0
  mov pc, lr //跳到__mmap_switched,這裡已經用了虛擬位址了吧
 // 這條指令ldr lr, __switch_data載入的__mmap_switched地址就是虛擬位址啊
__switch_data: .long __mmap_switched
從__mmap_switched一路執行下來,就要調到C語言代碼中去了
  b SYMBOL_NAME(start_kernel) //在kernel/init/main.c中
這個程式不是特別複雜,細心看看還是能大概看懂,我也不能去一一注釋
這裡有一個流程圖


到了C語言中就不是很難理解了
 lock_kernel();
 printk(linux_banner);
 setup_arch(&command_line);
 printk("Kernel command line: %s/n", saved_command_line);
 parse_options(command_line);
 trap_init();
 init_IRQ();
 sched_init();
 softirq_init();
 time_init();
就是一大堆初始化工作,追著每個函數去看好了

start_kernel最後調用的一個函數
static void rest_init(void)
{
 kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
 unlock_kernel();
 current->need_resched = 1;
  cpu_idle();
}
用kernel_thread建立了一個init進程,執行的是main.c中的init函數
 lock_kernel();
 do_basic_setup();
在do_basic_setup中調用了do_initcalls函數
各種驅動都是在do_initcalls(void)中完成的
static void __init do_initcalls(void)
{
 initcall_t *call;

 call = &__initcall_start;
 do {
  (*call)();
  call++;
 } while (call < &__initcall_end);

 flush_scheduled_tasks();
}
__initcall_start也是在vmlinux.lds中賦值的,那就需要找到.initcall.ini這個段
在kernel/include/linux/init.h中可以找到
#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
typedef int (*initcall_t)(void);
#define __initcall(fn)        /
 static initcall_t __initcall_##fn __init_call = fn
仔細研究下就發現這是把初始化函數的地址放到了.initcall.init段中
這樣就可以不斷調用驅動的初始化函數了
如果沒有定義MODULE,那麼#define module_init(x) __initcall(x);
所以如果要把驅動的編譯進核心就很簡單了吧
init的最後
 if (execute_command)
  execve(execute_command,argv_init,envp_init);
execute_command與ppcboot傳的命令列參數是有關的哦,就是init=/linuxrc
這樣就要去執行根目錄下的linuxrc指令碼,這個指令碼會去執行busybox
而busybox又去執行/etc/init.d/rcS指令碼,這個指令碼又去執行/usr/etc/rc.local
完了

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.