国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
linux mips啟動分析 - MIPS技術(shù)及應(yīng)用社區(qū)

linux mips啟動分析更新于2010-11-24 10:19:14文章出處: 嵌入式學(xué)習(xí)網(wǎng)

關(guān)鍵字:linuxmips啟動

系統(tǒng)加電起動后,MIPS處理器默認(rèn)的程序入口是0xBFC00000,此地址在無緩存的KSEG1的地址區(qū)域內(nèi),對應(yīng)的物理地址是0x1FC00000,即CPU從0x1FC00000開始取第一條指令,這個地址在硬件上已經(jīng)確定為FLASH的位置,Bootloader將Linux內(nèi)核映像拷貝到 RAM 中某個空閑地址處,然后一般有個內(nèi)存移動操作,目的地址在arch/mips/Makefile內(nèi)指定:
core-$(CONFIG_MIPS_ADM5120)+= arch/mips/adm5120/
load-$(CONFIG_MIPS_ADM5120)+= 0xffffffff80002000
則最終bootloader定會將內(nèi)核移到物理地址 0x002000 處
上面Makefile里指定的的load地址,最后會被編譯系統(tǒng)寫入到arch/mips/kernel/vmlinux.lds中:
OUTPUT_ARCH(mips)
ENTRY(kernel_entry)
jiffies = jiffies_64;
SECTIONS
{
. = 0xFFFFFFFF80002000;
/* read-only */
_text = .; /* Text and read-only data */
.text : {
    *(.text)
...
這個文件最終會以參數(shù)-Xlinker --script -Xlinkervmlinux.lds的形式傳給gcc,并最終傳給鏈接器ld來控制其行為。ld會將.text節(jié)的地址鏈接到0xFFFFFFFF80002000處。
關(guān)于內(nèi)核ELF文件的入口地址(Entrypoint),即bootloader移動完內(nèi)核后,直接跳轉(zhuǎn)到的地址,由ld寫入ELF的頭中,其會依次用下面的方法嘗試設(shè)置入口點,當(dāng)遇到成功時則停止:
a.命令行選項-e entry
b.腳本中的ENTRY(symbol)
c.如果有定義start符號,則使用start符號(symbol)
d.如果存在.text節(jié),則使用第一個字節(jié)的地址。
e.地址0
注意到上面的ld script中,用ENTRY宏設(shè)置了內(nèi)核的entrypoint是kernel_entry,因此內(nèi)核取得控制權(quán)后執(zhí)行的第一條指令是在kernel_entry處。
linux內(nèi)核啟動的第一個階段是從 /arch/mips/kernel/head.s文件開始的。而此處正是內(nèi)核入口函數(shù)kernel_entry(),該函數(shù)定義在/arch/mips/kernel/head.s文件里。kernel_entry()函數(shù)是體系結(jié)構(gòu)相關(guān)的匯編語言,它首先初始化內(nèi)核堆棧段,來為創(chuàng)建系統(tǒng)中的第一個進程進行準(zhǔn)備,接著用一段循環(huán)將內(nèi)核映像的未初始化數(shù)據(jù)段(bss段,在_edata和_end之間)清零,最后跳轉(zhuǎn)到 /init/main.c中的start_kernel()初始化硬件平臺相關(guān)的代碼。
*********************************************
NESTED(kernel_entry, 16,sp)           # kernel entry point
聲明函數(shù)   kernel_entry,函數(shù)的堆棧為16 byte,返回地址保存在  $sp寄存器中。
-----------------------------
聲明函數(shù)入口
#define NESTED(symbol, framesize,rpc)                 \
        .globl symbol;                        \
        .align 2;                             \
        .type  symbol,@function;              \
        .ent   symbol,0;                      \
symbol:     .frame  sp, framesize, rpc
匯編偽指令  frame用來聲明堆棧布局。
它有三個參數(shù):
    1)第一個參數(shù)  framereg:聲明用于訪問局部堆棧的寄存器,一般為 $sp。
    2)第二個參數(shù)  framesize:申明該函數(shù)已分配堆棧的大小,應(yīng)該符合
$sp+framesize= 原來的  $sp。
    3)第三個參數(shù)  returnreg:這個寄存器用來保存返回地址。
----------------------------
   kernel_entry_setup         # cpu specific setup
----------------------------
這個宏一般為空的,在include/asm-mips/mach-generic/kernel-entry-init.h文件中定義。
某些MIPSCPU需要額外的設(shè)置一些控制寄存器,和具體的平臺相關(guān),一般為空宏;某些多核MIPS,啟動時所有的core的入口一起指向  kernel_entry,然后在該宏里分叉,boot core繼續(xù)往下,其它的則不停的判斷循環(huán),直到boot core喚醒之。
----------------------------
setup_c0_status_pri
設(shè)置   cp0_status寄存器
----------------------------
    .macro  setup_c0_status_pri
#ifdef CONFIG_64BIT
    setup_c0_status ST0_KX 0
#else
    setup_c0_status 0 0
#endif
    .endm
----------------------------
    ARC64_TWIDDLE_PC
除非CONFIG_ARC64,否則為空操作
-----------------------------
#ifdef CONFIG_MIPS_MT_SMTC
    mtc0    zero,CP0_TCCONTEXT__bss_start
    mfc0    t0, CP0_STATUS
    ori t0, t0, 0xff1f
    xori    t0, t0, 0x001e
    mtc0    t0, CP0_STATUS
#endif /* CONFIG_MIPS_MT_SMTC */
宏定義   CONFIG_MIPS_MT_SMTC是使用多核的  SMTCLinux時定義的。一般情況下不考慮。
MIPS已經(jīng)開發(fā)出  SMP Linux的改進版,叫做SMTC(線程上下文對稱多處理) Linux。
SMTC Linux能理解輕量級  TC的概念,并能因此減少某些與SMP Linux相關(guān)的開銷。
----------------------------
    PTR_LA      t0,__bss_start     # clear .bss
    LONG_S      zero, (t0)
    PTR_LA      t1,__bss_stop - LONGSIZE
1:
    PTR_ADDIU   t0, LONGSIZE
    LONG_S      zero, (t0)
    bne     t0, t1, 1b
清除  BSS段,清0。
變量   __bss_start 和  __bss_stop在連接文件arch/mips/kernel/vmlinux.lds中定義。
--------------------------------
    LONG_S      a0,fw_arg0     # firmware arguments
    LONG_S      a1, fw_arg1
    LONG_S      a2, fw_arg2
    LONG_S      a3, fw_arg3
把  bootloader傳遞給內(nèi)核的啟動參數(shù)保存在fw_arg0,fw_arg1,fw_arg2,fw_arg3變量中。
變量  fw_arg0為內(nèi)核參數(shù)的個數(shù),其余分別為字符串指針,為 *** =XXXX 的格式。
----------------------------------
MTC0        zero,CP0_CONTEXT   # clear context register
清除  CP0的context register,這個寄存器用來保存頁表的起始地址。
----------------------------------
 PTR_LA      $28, init_thread_union
初始化  $gp寄存器,這個寄存器的地址指向一個  union,
THREAD_SIZE 大小,最低處是一個thread_info結(jié)構(gòu)
---------------------------------
PTR_LI      sp, _THREAD_SIZE - 32
PTR_ADDU    sp, $28
設(shè)置  $sp寄存器,堆棧指針。  $sp = (init_thread_union的地址)+ _THREAD_SIZE - 32
的得出  $sp指向這個  union 結(jié)構(gòu)的結(jié)尾地址 -32字節(jié)地址。
-----------------------------------
    set_saved_sp    sp, t0, t1
把 這個CPU核的堆棧地址  $sp保存到  kernelsp[NR_CPUS]數(shù)組。
---------------------------------
   如果定義了  CONFIG_SMP宏,即多  CPU核。
        .macro set_saved_sp stackp temp temp2
#ifdef CONFIG_MIPS_MT_SMTC
        mfc0   \temp, CP0_TCBIND
#else
        MFC0   \temp, CP0_CONTEXT
#endif
       LONG_SRL    \temp, PTEBASE_SHIFT
        LONG_S  \stackp,kernelsp(\temp)
        .endm
如果沒有定義  CONFIG_SMP宏,單  CPU核。
        .macro set_saved_sp stackp temp temp2
        LONG_S  \stackp,kernelsp
        .endm

變量  kernelsp的定義,在arch/mips/kernel/setup.c文件中。
unsigned long kernelsp[NR_CPUS];
把 這個CPU核的堆棧地址  $sp保存到  kernelsp[NR_CPUS]數(shù)組。

---------------------------------
    PTR_SUBU    sp, 4 *SZREG       # init stack pointer
---------------------------------
    j      start_kernel
    END(kernel_entry)
最后跳轉(zhuǎn)到  /init/main.c中的start_kernel()初始化硬件平臺相關(guān)的代碼。
----------------------------------
**********************************************
這個   init_thread_union變量在 arch/mips/kernel/init_task.c文件中定義。
union thread_union init_thread_union
    __attribute__((__section__(".data.init_task"),
                  __aligned__(THREAD_SIZE))) =
        {INIT_THREAD_INFO(init_task) };
linux 內(nèi)核啟動的第一個階段是從  /arch/mips/kernel/head.s文件開始的。
而此處正是內(nèi)核入口函數(shù)kernel_entry(),該函數(shù)定義在/arch/mips/kernel/head.s文件里。
kernel_entry()函數(shù)是體系結(jié)構(gòu)相關(guān)的匯編語言,它首先初始化內(nèi)核堆棧段,來為創(chuàng)建系統(tǒng)中的第一個進程進行準(zhǔn)備,接著用一段循環(huán)將內(nèi)核映像的未初始化數(shù)據(jù)段(bss段,在_edata和_end之間)清零,
最后跳轉(zhuǎn)到  /arch/mips/kernel/main.c中的start_kernel()初始化硬件平臺相關(guān)的代碼。
下面講述   start_kernel()函數(shù)。
*******************************************
asmlinkage void __init start_kernel(void)
{
---------------------------------
    char * command_line;
    extern struct kernel_param __start___param[],__stop___param[];
    定義了核的參數(shù)數(shù)據(jù)結(jié)構(gòu)
---------------------------------

    smp_setup_processor_id();
    設(shè)置  SMP多核的  CPU核的ID號,單核不進行任何操作,我們不關(guān)心。
---------------------------------
    unwind_init();
    在  MIPS體系結(jié)構(gòu)中,這個函數(shù)是個空函數(shù)(可能調(diào)用setup_arch,配置核的相關(guān)函數(shù))
---------------------------------
    lockdep_init();
    初始化核依賴關(guān)系哈希表。
---------------------------------
    local_irq_disable();
    關(guān)閉當(dāng)前  CPU核的中斷
---------------------------------
    early_boot_irqs_off();
    通過一個靜態(tài)全局變量   early_boot_irqs_enabled來幫助我們調(diào)試代碼,
    通過這個標(biāo)記可以幫助我們知道是否在“early bootup code”,
    也可以通過這個標(biāo)志警告是否有無效的中斷打開。
    和    early_boot_irqs_on()函數(shù)配置使用,參考下面。
---------------------------------
    early_init_irq_lock_class();
    每一個中斷都有一個    IRQ描述符 (structirq_desc)來進行描述。
    這個函數(shù)的主要作用是設(shè)置所有的   IRQ描述符 (structirq_desc)的鎖是統(tǒng)一的鎖,
    還是每一個    IRQ描述符 (structirq_desc)都有一個小鎖。
---------------------------------
    lock_kernel();
    獲取大內(nèi)核鎖,這種大內(nèi)核鎖鎖定整個內(nèi)核。
---------------------------------
    tick_init();
    如果沒有定義  CONFIG_GENERIC_CLOCKEVENTS宏定義,則這個函數(shù)為空函數(shù),
    如果定義了這個宏,這執(zhí)行初始化  tick控制功能,注冊clockevents的框架。
---------------------------------
    boot_cpu_init();
    對于  CPU核的系統(tǒng)來說,設(shè)置第一個  CPU核為活躍 CPU核。
    對于單  CPU核系統(tǒng)來說,設(shè)置CPU核為活躍  CPU核。
    參考《linux-mips啟動分析(2-1)》。
---------------------------------
    page_address_init();
    當(dāng)定義了CONFIG_HIGHMEM 宏,并且沒有定義  WANT_PAGE_VIRTUAL 宏時,非空函數(shù)。
    其他情況為空函數(shù)。
---------------------------------
    printk(KERN_NOTICE);
    printk(linux_banner);
    輸出打印版本信息。
---------------------------------
    setup_arch(&command_line);
    每種體系結(jié)構(gòu)都有自己的  setup_arch()函數(shù),這些是體系結(jié)構(gòu)相關(guān)的。
    如何確定編譯那個體系結(jié)構(gòu)的    setup_arch()函數(shù)呢?
    主要由  linux源碼樹頂層  Makefile中 ARCH變量來決定的。
    例如:  MIPS體系結(jié)構(gòu)的。
    SUBARCH := mips
    ARCH       ?= $(SUBARCH)
---------------------------------
    setup_command_line(command_line);
    保存未改變的  comand_line 到字符數(shù)組 static_command_line[] 中。
    保存 boot_command_line到字符數(shù)組     saved_command_line[]中。
---------------------------------
    unwind_setup();
    空函數(shù)。
---------------------------------
    setup_per_cpu_areas();
    如果沒有定義  CONFIG_SMP宏,則這個函數(shù)為空函數(shù)。
    如果定義了    CONFIG_SMP宏,
    則這個    setup_per_cpu_areas()函數(shù)給每個CPU分配內(nèi)存,并拷貝   .data.percpu段的數(shù)據(jù)。
---------------------------------
    如果沒有定義  CONFIG_SMP宏,則這個函數(shù)為空函數(shù)。
    如果定義了    CONFIG_SMP宏,這個函數(shù)
    smp_prepare_boot_cpu();
---------------------------------
    sched_init();
    核心進程調(diào)度器初始化,調(diào)度器的初始化優(yōu)先于任何中斷的建立(包括  timer中斷)。
    并且初始化進程0,即  idle進程,但是并沒有設(shè)置idle進程的 NEED_RESCHED標(biāo)志,
    以完成內(nèi)核剩余的啟動部分。
---------------------------------
    preempt_disable();
    進制內(nèi)核的搶占。使當(dāng)前進程的   structthread_info結(jié)構(gòu)  preempt_count成員的值增加1。
---------------------------------
    建立各個節(jié)點的管理區(qū)的  zonelist,便于分配內(nèi)存的  fallback使用。
    這個鏈表的作用: 這個鏈表是為了在一個分配不能夠滿足時可以考察下一個管理區(qū)來設(shè)置了。
    在考察結(jié)束時,分配將從  ZONE_HIGHMEM回退到 ZONE_NORMAL,
    在分配時從  ZONE_NORMAL退回到  ZONE_DMA就不會回退了。
    build_all_zonelists();
---------------------------------
    page_alloc_init();
---------------------------------
    在  MIPS體系結(jié)構(gòu)下,這個函數(shù)已經(jīng)在  arch_mem_init() 函數(shù)中調(diào)用了一次。
    這個函數(shù)的具體分析詳細(xì)分析,請看《linux-mips啟動分析(4)》。
    所以這個函數(shù)直接返回。
    parse_early_param();
---------------------------------
    打印  linux啟動命令行參數(shù)。
    printk(KERN_NOTICE "Kernel command line: %s\n",boot_command_line);
---------------------------------
    這個函數(shù)的意思對  linux啟動命令行參數(shù)進行再分析和處理。
    這兩個變量   __start___param和  __stop___param在
    鏈接腳本  arch/mips/kernel/vmlinux.lds中定義。
    最后一個參數(shù)為,當(dāng)不能夠識別  linux啟動命令行參數(shù)時,調(diào)用的函數(shù)。
    parse_args("Booting kernel",static_command_line, __start___param,
          __stop___param - __start___param, &unknown_bootoption);
---------------------------------
    檢查中斷是否已經(jīng)打開了,如果已將打開了,關(guān)閉中斷。
    if (!irqs_disabled()) {
        local_irq_disable();
         }
---------------------------------
    sort_main_extable();
    這個函數(shù)對內(nèi)核建立的異常處理調(diào)用函數(shù)表(exception table)
    根據(jù)異常的向量號進行堆排序。
---------------------------------
    設(shè)置  CPU的異常處理函數(shù),TLB重填,cache出錯,還有通用異常處理表的初始化。
    trap_init();
---------------------------------
    初始化  RCU機制,這個步驟必須比本地  timer的初始化早。
    rcu_init();
---------------------------------
   用來初始化中斷處理硬件相關(guān)的寄存器和中斷描述符數(shù)組     irq_desc[] 數(shù)組,
    每個中斷號都有一個對應(yīng)的中斷描述符。
    參考《linux-mips啟動分析(11)》。
    init_IRQ();
--------------------------------
    系統(tǒng)在初始化階段動態(tài)的分配了  4  個 hashtable,并把它們的地址存入  pid_hash[] 數(shù)組。
    便于從PID查找 進程描述符地址。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
uClinux在S3C4510上的啟動分析(轉(zhuǎn))
2.6.18-2內(nèi)核中對S3C2440的引導(dǎo)啟動分析 - Arm s3c2440 - Li...
linux內(nèi)核啟動過程分析之內(nèi)核啟動
Linux-Android啟動之Init進程前傳
arm-linux啟動過程
arm-linux 啟動代碼分析——stage1 (2) - linux內(nèi)核與驅(qū)動 - 木椅子
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服