嵌入式培訓(xùn)-課件及_第1頁
嵌入式培訓(xùn)-課件及_第2頁
嵌入式培訓(xùn)-課件及_第3頁
嵌入式培訓(xùn)-課件及_第4頁
嵌入式培訓(xùn)-課件及_第5頁
已閱讀5頁,還剩51頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

LINUX內(nèi)核啟動分析FrancHE內(nèi)核啟動流程分析內(nèi)核啟動控制腳本本章小結(jié)內(nèi)核啟動流程分析PARTI:內(nèi)核自引導(dǎo)過程這個首先必須分析linux的Makefile系統(tǒng),因為燒到板子上的linux內(nèi)核是壓縮過的,所以在引導(dǎo)時必須有一個解壓縮過程。這就是所謂的linux內(nèi)核自引導(dǎo)過程編譯結(jié)束后,系統(tǒng)將產(chǎn)生一個zImage文件,它的產(chǎn)生過程是這樣的: pressed/Makefile: piggy.o:$(SYSTEM)$(OBJCOPY)-Obinary-R.note-Rment-S$(SYSTEM)piggygzip$(GZFLAGS)<piggy>piggy.gz$(LD)-r-o$@-bbinarypiggy.gzrm-fpiggypiggy.gz vmlinux:$(HEAD)$(OBJS)piggy.ovmlinux.lds$(LD)$(ZLDFLAGS)$(HEAD)$(OBJS)piggy.o$(LIBGCC)-ovmlinux/arch/arm/boot/Makefile: zImage:$(CONFIGURE)compressed/vmlinux$(OBJCOPY)-Obinary-R.note-Rment-Scompressed/vmlinux$@從這里我們可以很容易的看出,在zImage中可以運行的有效代碼只有$(HEAD),也就是pressed/head.Spressed/head.S將完成解壓,最后跳到vmlinux的入口問題:請通過pressed/vmlinux.lds找到head.S的入口點(函數(shù))?其次,我們將分析這里幾個比較主要的文件,以幫助我們理解整個內(nèi)核自引導(dǎo)流程.首先分析內(nèi)核預(yù)引導(dǎo)程序head.S其次分析misc.c中的press_kernel函數(shù)。最后分析call_kernel函數(shù)head.S: 次序大致是: start->wont_overwrite->press_kernel->call_kernelpress_kernel: 次序大致是: 設(shè)置內(nèi)核解壓后的入口地址:out_data; 調(diào)用gunzip->inflate來解壓kernel; 返回解壓后的kernel入口指令地址output_ptr。Call_kernel函數(shù): 大致的流程是:

cache_clean_flush->cache_off->mov pc,r4 注意:跳過去以后,帶了兩個參數(shù): r0=0 r1=architecturenumberPARTII:內(nèi)核引導(dǎo)過程到這里,我們已經(jīng)完成了內(nèi)核的解壓,程序已經(jīng)到了vmlinux的入口。Vmlinux是為解壓的linux內(nèi)核文件這個階段,我們首先分析arm-headv.S然后我們將分析start_kernel函數(shù)arm-headv.S:

這個文件的執(zhí)行流程大致是這樣的:

stext是它的作為入口 __lookup_processor_type->__lookup_architecture_type->__create_page_tables->__arm920_setup->start_kernel(Cfunction)Start_kernel函數(shù)分析: 1)這個函數(shù)放在.init段中 2)由第一條可知,這個函數(shù)在初始化時運行,而且只運行一次。問題1:為什么在/arch/arm/kernel/setup.c中:函數(shù)setup_machine中的__arch_info_begin全局結(jié)構(gòu)會已經(jīng)有定義?它是在何處定義的?問題2:/include/asm-arm/mach/arch.h中:

machine_desc結(jié)構(gòu)的填值是什么時候完成的,為什么?在預(yù)編譯過程中已經(jīng)定義了(smdk.c):

MACHINE_START(SMDK2410,"Samsung-SMDK2410") BOOT_MEM(0x30000000,0x48000000,0xe8000000) BOOT_PARAMS(0x30000100) FIXUP(fixup_smdk) MAPIO(smdk_map_io) INITIRQ(s3c2410_init_irq)start_kernel過程分析: *setup_arch函數(shù):它將設(shè)置處理器類型,CPU類型,初始化啟動命令行,初始化bootmem,頁表,標準資源。

parse_cmdline(&meminfo,cmdline_p,from): 這個函數(shù)將初始化cmdline,它的具體做法是:將從from得到的命令行賦給cmdline_p,同時寫入meminfo的首地址(也就是內(nèi)存的初始地址)

#bootmem_init: Thebootmemallocatorisusedonlyduringboot,toallocatepagesforpermanentkerneldata.thebootmemallocatorprovidespagesforkernelinitialization,andthosepagesarepermanentlyreservedforkernelpurposes,almostasiftheywereloadedwiththekernelimage;theydonotparticipateinanyMMactivityafterboot. #paging_init:這將初始化整個內(nèi)存頁表,這里再一次使用了技巧:用匯編(proc-arm920.S)填充了/include/asm-arm/cpu-multi32.h:structprocessor,從而完成了對設(shè)置TLB和cache的操作。重建頁表的原因是內(nèi)核使用的調(diào)用空間是在(0xc0000000(3G))以后。頁表一共有兩級,一級(section)是以1M為單位,二級(page)是以4K為單位。這里將會初始化所有在3G以后可以訪問到的內(nèi)存空間PGD(pagedirectory),PMD(pagemiddledirectory),PTE(pagetableentry),在ARMlinux中,只有PMD和PTE,沒有PGD,或者說PMD=PGD關(guān)于paging_init的背景知識: PGD=以兆為單位的頁目錄

PMD=以4k為單位的頁目錄 但是由于在ARM機器上,PGD和PMD是合而為一的,也就是說PGD就是PMD。

一個PGD就是一個4K大小的表,每一個process只有一個頁目錄,以4字節(jié)為一個表項,分成1024個表項。 由于系統(tǒng)內(nèi)存不可能做到PMD對齊,也就是說必定有起始和最后的未對齊部分,所以還需要把它們映射到系統(tǒng)中來。很明顯,我們將使用直接對PTE的操作完成這個過程。 函數(shù)create_mapping將得出整個內(nèi)存映射到0xc0000000為起始地址的頁表,起始的小于1M的空間將有頁地址,中間將使用section(1M)地址(自然可以獲得頁地址),最后1M將又只有頁地址。 #request_standard_resources: 這個函數(shù)是為創(chuàng)建第一個進程作準備的,主要申請代碼存放空間和頁表. *trap_init: 它將重新初始化向量表到0x200的位置,并設(shè)置新的內(nèi)部exception處理函數(shù)。他還將設(shè)置各種SWI(包括系統(tǒng)調(diào)用)的行為 *irq_init:

它將設(shè)置初始化中斷控制數(shù)據(jù)結(jié)構(gòu)irqdesc,設(shè)置默認的mask和unmask回調(diào)函數(shù),接下來調(diào)用在setup_arch中注冊的init_arch_irq(s3c2410_init_irq)來最終初始化s3c2410的中斷控制結(jié)構(gòu)。 *sched_init(為調(diào)度程序的運行設(shè)置環(huán)境): 它將調(diào)用init_timervecs:初始化定時器隊列(一共有5個隊列) 它還將初始化basichandler中:TIMER_BH,TQUEUE_BH,IMMEDIATE_BH的回調(diào)函數(shù)。

*softirq_init:主旨:CPU將通過觸發(fā)定時器完成一系列的操作,系統(tǒng)稱他們?yōu)閟oftirq。初始化定時器到期和HI_SOFTIRQ,TASKLET_SOFTIRQ發(fā)生時的行為。這種行為的發(fā)生將要通過顯式調(diào)用mark_bh來實現(xiàn)。

*time_init: 完整定義定時器的行為,這將通過setup_timer來實現(xiàn)。 注意:這里有兩件事:A軟中斷,B硬中斷。因為:定時器是一個硬中斷,它的處理函數(shù)將是清掉計數(shù)器,使得時鐘可以重新計數(shù),這個是硬中斷中斷;而由于定時器的目的是要觸發(fā)一系列的事件(函數(shù)),所以它需要激發(fā)很多處理函數(shù),這個是軟中斷。具體針對我們的板子:do_set_rtc是硬中斷處理函數(shù),do_timer則是處理軟中斷到期的函數(shù)。 *console_init: 初始化串口,從而可以盡早實現(xiàn)debug功能。 *init_modules: 實現(xiàn)module動態(tài)加載機制。 *kmem_cache_init: 初始化cacheentry的管理結(jié)構(gòu)。 *sti():

使能中斷。

*calibrate_delay: 通過CPU空轉(zhuǎn)得到大致的運行指令速度。 *mem_init():

初始化剩余(去掉text段,data段和init段的Memory)。 *kmem_cache_sizes_init():

初始化cache的大小和對齊情況(這里值的是在內(nèi)存中的內(nèi)核緩存。 *pgtable_cache_init():

頁表在內(nèi)存中的緩存。

*fork_init:

這將設(shè)置系統(tǒng)能創(chuàng)建的進程的最大數(shù)量。 問題:為什么這個程序一直在設(shè)置thread的數(shù)量,而不是process的數(shù)量? *proc_caches_init:

設(shè)置進程的緩存。 *vfs_caches_init: 設(shè)置文件讀寫(虛擬文件系統(tǒng)接口)的緩存 *buffer_init: 創(chuàng)建內(nèi)存的哈希表,從而方便tlbmiss時的查找。 *page_cache_init: 頁面的緩存,也是為了加快查找的速度。 *signals_init: 創(chuàng)建信號隊列。 *check_bugs: 查找有沒有FIRQ產(chǎn)生。 *smp_init: 我們不是對稱多處理器,這個是空函數(shù)。

*rest_init: 這個是系統(tǒng)最后的一個調(diào)用,它將完成讓CPU進入IDLE狀態(tài)的之前的工作。 這主要通過調(diào)用: kernel_thread(init,NULL,CLONE_FS|CLONE_FILES|CLONE_SIGNAL);/*啟動init系統(tǒng)線程,它的入口函數(shù)是init*/

unlock_kernel();/*我們是單核,沒有意義*/

current->need_resched=1;/*在系統(tǒng)調(diào)用shedule()函數(shù)時,使能調(diào)度功能*/

cpu_idle();/*CPU空閑進入函數(shù),它將定時的調(diào)用schdule()函數(shù)*/

PARTIII:內(nèi)核第一個進程的啟動內(nèi)核的第一個進程init將啟動它的第一個線程,這個線程的主函數(shù)是init。我們接下來主要是要分析這個函數(shù),它將會完成掛接根文件系統(tǒng),初始化設(shè)備驅(qū)動和啟動用戶空間的init進程等重要工作。Init函數(shù)的主要流程是這樣的:

init->do_basic_setup->prepare_namespace->free_initmem->最后啟動sh(shell)函數(shù)do_basic_setup分析: *sock_init 這個函數(shù)主要是初始化網(wǎng)絡(luò)環(huán)境,它將首先初始化系統(tǒng)所支持的協(xié)議族全局數(shù)組為NULL,調(diào)用sk_init初始化sock鏈表的內(nèi)存空間,調(diào)用skb_init初始化sk_buff的內(nèi)存空間。最后將sock_fs_type注冊入文件系統(tǒng)。(問題:“注冊入文件系統(tǒng)”一般是什么意思?) *start_context_thread:

它將調(diào)用sys_clone系統(tǒng)調(diào)用創(chuàng)建內(nèi)核線程,入口程序是context_thread。

這里使用了一個技巧,在等待內(nèi)核線程創(chuàng)建完畢前,系統(tǒng)為了禁止調(diào)度,使用了spin_lock_irq(禁止中斷)的方法。 問題:為什么禁止中斷可以停止調(diào)度?

*do_initcalls: 這里有一個重要技巧,這種和編譯器協(xié)調(diào)完成系統(tǒng)編程的方法是提高效率和系統(tǒng)性的武器。 具體做法是在lds文件中定義一個__initcall段(section),在以后的程序中將一些要在初始時執(zhí)行的代碼放到這個段里,然后在do_initcalls時統(tǒng)一一次執(zhí)行。 舉例如下: 在arch/arm/mach-s3c2410/dma.c中,有__initcall(s3c2410_init_dma),由于__initcall是一個宏,它將在預(yù)編譯時執(zhí)行,這也就完成了在執(zhí)行前就將s3c2410_init_dma填充到initcall段的任務(wù)。 注意:當do_basic_setup結(jié)束時,系統(tǒng)中已經(jīng)有一個系統(tǒng)進程在運行了。 *prepare_namespace: 這個函數(shù)主要是用來掛根文件系統(tǒng)的。由于在我們的系統(tǒng)中大部分的功能已經(jīng)被注釋掉,所以真正有用的只有mount_root()和mount_devfs_fs()。

我們在vivi階段已經(jīng)設(shè)置了root=/dev/bon/2,也就是說這里我們將把這個分區(qū)組織起來,建立一個真正的linux文件系統(tǒng)。后面那個函數(shù)mount_devfs_fs()沒有用處。

*free_initmem:

linux中,__init段有一個特點,就是在初始化時執(zhí)行一次,以后不再執(zhí)行,所以我們把它清空。

*if(open("/dev/console",O_RDWR,0)<0) printk("Warning:unabletoopenaninitialconsole.\n"); (void)dup(0); (void)dup(0); 以上這段話將通過sys_open和sys_dup系統(tǒng)調(diào)用實現(xiàn)三個文件描述符為0,1,2的輸入輸出設(shè)備,他們分別是標準輸入(STDIN),標準輸出(STDOUT)和標準錯誤(STDERR)的文件描述符(指針)。 問題:上面這段話結(jié)束后,標準輸入,標準輸出和標準錯誤這三種信息將分別打向哪里? *接下來,系統(tǒng)將調(diào)用一系列的execve來完成運行初始化腳本的工作。

#includeintexecve(constchar*filename,constchar*argv[],constchar*envp[;]); execve()運行由指針filename指向的程序,filename定位的程序必須是一個二進制可執(zhí)行代碼或者是一個可以運行的腳本程序。

execve()如果成功調(diào)用的話,是沒有返回值的,調(diào)用這個函數(shù)的進程的text,data,bss和stack都將被新加載的函數(shù)的相應(yīng)的代碼和數(shù)據(jù)段覆蓋。被新加載的程序變成了執(zhí)行態(tài)的進程,它繼承了調(diào)用者的PID,還有其他打開的文件描述符如果在exec的時候沒有指明要關(guān)閉的話也都一一繼承。發(fā)給父進程的信號(signal)此時被清零。 到此為止,linux的內(nèi)核啟動已經(jīng)結(jié)束,我們看到它已經(jīng)啟動過context_thread這唯一的一個內(nèi)核線程(進程)內(nèi)核啟動控制腳本完成前面的第一部分后,ARMlinux將開始通過引導(dǎo)一系列腳本來完成其余的初始化部分。首先在文件/init/main.c中:Init函數(shù)的最后判斷:mand在同一文件中的parse_option函數(shù)對它進行過賦值,它的內(nèi)容是由vivi定義的init=/linuxrc,也就是說/linuxrc是ARMlinux執(zhí)行的第一個腳本。以下是/linuxrc的內(nèi)容:

#!/bin/sh echo"mount/etcasramfs" /bin/mount-n-tramfsramfs/etc /bin/cp-a/mnt/etc/*/etc echo"re-createthe/etc/mtabentries" #re-createthe/etc/mtabentries /bin/mount-f-tcramfs-oremount,ro/dev/mtdblock/3/ /bin/mount-f-tramfsramfs/etc exec/sbin/init問題:#!/bin/sh是什么意思?很顯然,這里/bin/mount,/bin/cp

等都是用戶進程,也就是說,系統(tǒng)在運行這些程序時是在用戶態(tài)的。/etc目錄將會被掛載成ramfs,這里因為有-n選項,它將不會更新/etc/mtab(mounttable)。Cp這句話的原因是要把mtab這個文件準備好,下面的操作要寫這個文件。以下的兩條將要做這樣的事:

/

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論