在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > arm linux 啟動流程之 進入內(nèi)核

            arm linux 啟動流程之 進入內(nèi)核

            作者: 時間:2016-11-09 來源:網(wǎng)絡(luò) 收藏
            還是從編譯鏈接生成vmlinux的過程來看吧,由一大堆.o文件鏈接而成,第一個就是

            kernel/arch/arm/kernel/head-armv.o ,而且我們還看到了
            lds鏈接文件kernel/arch/arm/vmlinux.lds,先把它分析一下
            ENTRY(stext)//入口點是stext應(yīng)該就在head-armv.s中了
            SECTIONS
            {
            . = 0xC0008000;//基址,是內(nèi)核開始的虛擬地址
            .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 = .;
            }
            關(guān)于虛擬地址和物理地址的:使用MMU后,系統(tǒng)就會使用虛擬地址,通過MMU來指向
            實際物理地址而在這里我們的0xC0008000實際物理地址就是0x30008000,
            具體關(guān)于MMU的介紹參考《ARM體系結(jié)構(gòu)與編程》。
            到head-armv.s找到程序的入口
            .section ".text.init",#alloc,#execinstr
            .typestext, #function
            ENTRY(stext)
            movr12, r0
            movr0, #F_BIT | I_BIT | MODE_SVC@ make sure svc mode
            msrcpsr_c, r0@ and all irqs disabled
            bl__lookup_processor_type
            teqr10, #0@ invalid processor?
            moveqr0, #p@ yes, error p
            beq__error
            bl__lookup_architecture_type
            teqr7, #0@ invalid architecture?
            moveqr0, #a@ yes, error a
            beq__error
            bl__create_page_tables
            adrlr, __ret@ return address
            addpc, r10, #12@ initialise processor
            來看看上一句跳到哪里去了
            去追尋r10的值,是在__lookup_processor_type子函數(shù)中賦的
            __lookup_processor_type:
            adrr5, 2f//r5 標(biāo)號2的地址基址是0x30008000
            ldmiar5, {r7, r9, r10}//r7=__proc_info_end r9=__proc_info_begin
            subr5, r5, r10//r10 標(biāo)號2的鏈接地址 基址是0xc0008000
            addr7, r7, r5@ to our address space
            addr10, r9, r5//r10 變換為基址是0x30008000的__proc_info_begin
            2:.long__proc_info_end
            .long__proc_info_begin
            .long2b
            這樣r10中存放的是__proc_info_begin的地址,因為現(xiàn)在我們還沒有打開MMU
            所以還是需要把基址變換到0x30008000,接著我們就去找__proc_info_begin吧
            注意到在上面的vmlinux.lds中有這個標(biāo)號,下來鏈接的是.proc.info段,
            在kernel/arch/arm/mm/proc-arm920.s的最后找到了這個段
            .section ".proc.info", #alloc, #execinstr

            本文引用地址:http://www.biyoush.com/article/201611/318008.htm

            .type__arm920_proc_info,#object
            __arm920_proc_info:
            .long0x41009200
            .long0xff00fff0
            .long0x00000c1e@ mmuflags
            b__arm920_setup
            ok,這樣我們就知道addpc, r10, #12跳到哪里去了,因為這個地址剛好放了條跳轉(zhuǎn)語句
            注意了b語句用的都是相對地址,所以不需要變換地址,反正是跳到__arm920_setup,而且
            上一條語句是adrlr, __ret,設(shè)定了__arm920_setup的返回地址是__ret,所以執(zhí)行完
            __arm920_setup后回到head-armv.s的__ret標(biāo)號繼續(xù)執(zhí)行.
            __ret:ldrlr, __switch_data
            mcrp15, 0, r0, c1, c0//注意這里了,在這里打開了MMU
            movr0, r0
            movr0, r0
            movr0, r0
            movpc, lr//跳到__mmap_switched,這里已經(jīng)用了虛擬地址了吧
            // 這條指令ldrlr, __switch_data加載的__mmap_switched地址就是虛擬地址啊
            __switch_data:.long__mmap_switched
            從__mmap_switched一路執(zhí)行下來,就要調(diào)到C語言代碼中去了
            bSYMBOL_NAME(start_kernel)//在kernel/init/main.c中
            這個程序不是特別復(fù)雜,細心看看還是能大概看懂,我也不能去一一注釋
            這里有一個流程圖



            到了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();
            就是一大堆初始化工作,追著每個函數(shù)去看好了

            start_kernel最后調(diào)用的一個函數(shù)
            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進程,執(zhí)行的是main.c中的init函數(shù)
            lock_kernel();
            do_basic_setup();
            在do_basic_setup中調(diào)用了do_initcalls函數(shù)
            各種驅(qū)動都是在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
            仔細研究下就發(fā)現(xiàn)這是把初始化函數(shù)的地址放到了.initcall.init段中
            這樣就可以不斷調(diào)用驅(qū)動的初始化函數(shù)了
            如果沒有定義MODULE,那么#define module_init(x)__initcall(x);
            所以如果要把驅(qū)動的編譯進內(nèi)核就很簡單了吧
            init的最后
            if (execute_command)
            execve(execute_command,argv_init,envp_init);
            execute_command與ppcboot傳的命令行參數(shù)是有關(guān)的哦,就是init=/linuxrc
            這樣就要去執(zhí)行根目錄下的linuxrc腳本,這個腳本會去執(zhí)行busybox
            而busybox又去執(zhí)行/etc/init.d/rcS腳本,這個腳本又去執(zhí)行/usr/etc/rc.local
            完了



            關(guān)鍵詞: armlinux啟動流程內(nèi)

            評論


            技術(shù)專區(qū)

            關(guān)閉