嵌入式 uboot引導kernel,kernel引導fs【轉】
轉自:http://www.cnblogs.com/lidabo/p/5383934.html#3639633
1、uboot引導kernel: u-boot中有個bootm命令,它可以引導內存中的應用程序映像(Kernel),bootm命令對應 common/cmd_bootm.c中的do_bootm()函數,此函數實現下面幾個功能: 1)讀flash中的內核映像文件 2)解壓內核 3)校驗內核 4)跳到內核執行(調用do_bootm_linux()函數)
{
1、Stage1 start.S代碼結構 u-boot的stage1代碼通常放在start.S文件中,他用匯編語言寫成,其主要代碼部分如下
(1) 定義入口。:
該工作通過修改連接器腳本來完成。
(2)設置異常向量(Exception Vector)。
(3)設置CPU的速度、時鐘頻率及終端控制寄存器。
(4)初始化內存控制器。
(5)將ROM中的程序復制到RAM中。
(6)初始化堆棧。
(7)轉到RAM中執行,該工作可使用指令ldr pc來完成。
2、Stage2 C語言代碼部分 lib_arm/board.c中的start arm boot是C語言開始的函數也是整個啟動代碼中C語言的主函數,同時還是整個u-boot(armboot)的主函數,該函數只要完成如下操作:
(1)調用一系列的初始化函數。
(2)初始化Flash設備。
(3)初始化系統內存分配函數。
(4)如果目標系統擁有NAND設備,則初始化NAND設備。
(5)如果目標系統有顯示設備,則初始化該類設備。
(6)初始化相關網絡設備,填寫IP、MAC地址等。
(7)進去命令循環(即整個boot的工作循環),接受用戶從串口輸入的命令,然後進行相應的工作。
}
2、kernel引導fs:
1)獲得可運行的Linux內核 2)內核裝載時的內存空間映射 3)內核啟始相關文件分析 4)arch/i386/boot/bootsect.S 5)arch/i386/boot/setup.S 6)arch/i386/boot/compressed/head.S 7)arch/i386/kernel/head.S 8)start_kernel
{
在start_kernel()函數中:
輸出Linux版本信息(printk(_banner))
設置與體系結構相關的環境(setup_arch())
頁表結構初始化(paging_init())
使用"arch/alpha/kernel/entry.S"中的入口點設置系統自陷入口(trap_init())
使用alpha_mv結構和entry.S入口初始化系統IRQ(init_IRQ())
核心進程調度器初始化(包括初始化幾個缺省的Bottom-half,sched_init())
時間、定時器初始化(包括讀取CMOS時鐘、估測主頻、初始化定時器中斷等,time_init())
提取並分析核心啟動參數(從環境變量中讀取參數,設置相應標誌位等待處理,(parse_options())
控制臺初始化(為輸出信息而先於PCI初始化,console_init())
剖析器數據結構初始化(prof_buffer和prof_len變量)
核心Cache初始化(描述Cache信息的Cache,kmem_cache_init())
延遲校準(獲得時鐘jiffies與CPU主頻ticks的延遲,calibrate_delay())
內存初始化(設置內存上下界和頁表項初始值,mem_init())
創建和設置內部及通用cache("slab_cache",kmem_cache_sizes_init())
創建uid taskcount SLAB cache("uid_cache",uidcache_init())
創建文件cache("files_cache",filescache_init())
創建目錄cache("dentry_cache",dcache_init())
創建與虛存相關的cache("vm_area_struct","mm_struct",vma_init())
塊設備讀寫緩沖區初始化(同時創建"buffer_head"cache用戶加速訪問,buffer_init())
創建頁cache(內存頁hash表初始化,page_cache_init())
創建信號隊列cache("signal_queue",signals_init())
初始化內存inode表(inode_init())
創建內存文件描述符表("filp_cache",file_table_init())
檢查體系結構漏洞(對於alpha,此函數為空,check_bugs())
SMP機器其余CPU(除當前引導CPU)初始化(對於沒有配置SMP的內核,此函數為空,smp_init())
啟動init過程(run_init_process() 創建第一個核心線程,調用init()函數,原執行序列調用cpu_idle() 等待調度,init())
至此start_kernel()結束,基本的核心環境已經建立起來了。
} 9)第一個內核線程 - kernel_init
三、start_kernel函數流程:
asmlinkage void __init start_kernel(void) { char * command_line; extern const struct kernel_param __start___param[], __stop___param[]; smp_setup_processor_id();//首先判斷是否是SMP (對稱多處理器)對單核SOC來說,mpidr = 0; /* * Need to run as early as possible, to initialize the * lockdep hash: */ lockdep_init(); //只初始化該哈希表一次 debug_objects_early_init(); /* * Set up the the initial canary ASAP: */ boot_init_stack_canary();//stack_canary的是帶防止棧溢出攻擊保護的堆棧 /** * cgroup_init_early - cgroup initialization at system boot * * Initialize cgroups at system boot, and initialize any * subsystems that request early init. */ cgroup_init_early(); local_irq_disable(); early_boot_irqs_disabled = true; /* * Interrupts are still disabled. Do necessary setups, then * enable them */ //初始化time ticket,時鐘 tick_init(); //用以啟動的CPU進行初始化。也就是初始化CPU0 boot_cpu_init(); //初始化頁面 page_address_init(); printk(KERN_NOTICE "%s", linux_banner); //CPU架構相關的初始化 setup_arch(&command_line); //初始化內存管理 mm_init_owner(&init_mm, &init_task); mm_init_cpumask(&init_mm); //處理啟動命令行 setup_command_line(command_line); //可能多余的初始化可能去判斷cpu的最大支持個數 setup_nr_cpu_ids(); //為每個CPU開辟一塊區域? setup_per_cpu_areas(); //準備boot_cpu.如果是SMP環境,則設置boot CPU的一些數據。在引導過程中使用的CPU稱為boot CPU smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ //Linux將所有物理內存分為三個區,ZONE_DMA, ZONE_NORMAM, ZONE_HIGHMEM build_all_zonelists(NULL); //初始化page allocation相關結構 page_alloc_init(); printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line); //解 析啟動參數 parse_early_param(); parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, &unknown_bootoption); /* * These use large bootmem allocations and must precede * kmem_cache_init() */ setup_log_buf(0); //初始化process ID hash表 pidhash_init(); //文件系統caches預初始化 vfs_caches_init_early(); //初始化exception table sort_main_extable(); //初始化trap,用以處理錯誤執行代碼 trap_init(); //初始化內存管理 mm_init(); /* * Set up the scheduler prior starting any interrupts (such as the * timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. */ //進程調度初始化 sched_init(); /* * Disable preemption - early bootup scheduling is extremely * fragile until we cpu_idle() for the first time. */ // 後當前進程將不能被強搶占 preempt_disable(); /*判斷中斷是否關閉,若打開則關閉中斷*/ if (!irqs_disabled()) { printk(KERN_WARNING "start_kernel(): bug: interrupts were " "enabled *very* early, fixing it\n"); local_irq_disable(); } idr_init_cache(); perf_event_init(); //Read_Copy_Update機制初始 /*初始化互斥機制*/ rcu_init(); radix_tree_init(); /*中斷向量的初始化*/ /* init some links before init_ISA_irqs() */ early_irq_init(); //初始化中斷 init_IRQ(); prio_tree_init(); /*初始化定時器*/ init_timers(); // 初始化高精時鐘 hrtimers_init(); // 初始化軟中斷 softirq_init(); // 初始化時鐘源 timekeeping_init(); /*初始化系統時鐘*/ time_init(); /* 對內核的profile(一個內核性能調式工具)功能進行初始化 */ profile_init(); call_function_init();//??? if (!irqs_disabled()) printk(KERN_CRIT "start_kernel(): bug: interrupts were " "enabled early\n"); early_boot_irqs_disabled = false; /*打開IRQ中斷*/ local_irq_enable(); /* Interrupts are enabled now so all GFP allocations are safe. */ gfp_allowed_mask = __GFP_BITS_MASK; //初始化CPU Cache kmem_cache_init_late(); /* * HACK ALERT! This is early. We‘re enabling the console before * we‘ve done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */ //初始化console console_init(); if (panic_later) panic(panic_later, panic_param); lockdep_info(); /* * Need to run this when irqs are enabled, because it wants * to self-test [hard/soft]-irqs on/off lock inversion bugs * too: */ //自測試鎖 locking_selftest(); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " "disabling it.\n", page_to_pfn(virt_to_page((void *)initrd_start)), min_low_pfn); initrd_start = 0; } #endif //頁面初始 page_cgroup_init(); //頁面分配debug啟用 enable_debug_pagealloc(); debug_objects_mem_init(); //memory leak 偵測初始化 kmemleak_init(); //設置每個CPU的頁面集合 setup_per_cpu_pageset(); numa_policy_init(); if (late_time_init) late_time_init(); //初始化調度時鐘 sched_clock_init(); /*校驗延時函數的精確度*/ calibrate_delay(); /*進程號位圖初始化,一般用一個page來只是所有的進程PID占用情況*/ pidmap_init(); //anonymous page?什麽意思? anon_vma_init(); #ifdef CONFIG_X86 if (efi_enabled) efi_enter_virtual_mode(); #endif //初始化thread info thread_info_cache_init(); //credential cred_init(); //初始化fork fork_init(totalram_pages); //初始化/proc的cache? proc_caches_init(); buffer_init(); key_init(); security_init(); dbg_late_init(); //文件系統cache初始化 vfs_caches_init(totalram_pages); signals_init(); /* rootfs populating might need page-writeback */ page_writeback_init(); #ifdef CONFIG_PROC_FS proc_root_init();//本文件系統?? #endif cgroup_init(); cpuset_init(); taskstats_init_early(); delayacct_init(); check_bugs(); acpi_early_init(); /* before LAPIC and SMP init */ //simple firmware interface sfi_init_late(); ftrace_init(); /* Do the rest non-__init‘ed, we‘re now alive */ rest_init(); }
嵌入式 uboot引導kernel,kernel引導fs【轉】