Linux/MIPS啟動分析

來源:互聯網
上載者:User

Linux啟動入口主要代碼在 arch/mips/kernel/head.S檔案中 kernel_entry函數以彙編形式出現

主要幹了以下幾件事:

1.  BSS段清0

2.  從boot傳過來的參數賦值到全域變數

3. clear context register

4. 根據init_thread_union建立$gp寄存器  並設定 
$sp 寄存器,堆棧指標    (PTR_LA      $28, init_thread_union)

5. 做好上述準備後就跳轉到 
/arch/mips/kernel/main.c 中的 start_kernel()初始化硬體平台相關的代碼


主要涉及的資料結構 在arch/mips/kernel/init_task.c 


union thread_union init_thread_union
__init_task_data
__attribute__((__aligned__(THREAD_SIZE))) =
{ INIT_THREAD_INFO(init_task) };

THREAD_SIZE在這裡為8K,__attribute__((__aligned__(THREAD_SIZE)))表示這個資料結構以8K對齊  

struct task_struct
init_task = INIT_TASK(init_task);

union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};

套用linux設計與實現的圖表示Thread_info、stack、task_struct的關係

在mips的head.S的工作就是

這就是傳說中的0號進程

1. 進程0是所有其他進程的祖先, 也稱作idle進程或swapper進程。
2. 進程0是在系統初始化時由kernel自身從無到有建立。(過程集中在start_kernel函數內)
3. 進程0的資料成員大部分是靜態定義的,即由預先定義好的(如上)INIT_TASK, INIT_MM等宏初始化。
 
進程0的描述符init_task定義在arch/arm/kernel/init_task.c,由INIT_TASK宏初始化。 init_mm等結構體定義在include/linux/init_task.h內,為init_task成員的初始值,分別由對應的初始化宏如INIT_MM等初始化

下面是轉載網上大蝦的詳細分析

系統加電起動後,MIPS 處理器預設的程式入口是0xBFC00000,此地址在無緩衝的KSEG1的地址地區內,對應的物理地址是 0x1FC00000,即CPU從0x1FC00000開始取第一條指令,這個地址在硬體上已經確定為FLASH的位置,Bootloader將 Linux 核心映像拷貝到  RAM  中某個空閑地址處,然後一般有個記憶體移動操作,目的地址在 arch/mips/Makefile 內指定:
load-$(CONFIG_MIPS_PB1550) += 0xFFFFFFFF80100000,
則最終bootloader定會將核心移到物理地址   0x00100000  處。

上面Makefile 裡指定的的 load 地址,最後會被編譯系統寫入到 arch/mips/kernel/vmlinux.lds 中:

OUTPUT_ARCH(mips)
ENTRY(kernel_entry)
jiffies = jiffies_64;
SECTIONS
{
. = 0xFFFFFFFF80100000;
/* read-only */
_text = .; /* Text and read-only data */
.text : {
    *(.text)
...

這個檔案最終會以參數 -Xlinker --script -Xlinker vmlinux.lds 的形式傳給 gcc,並最終傳給連結器 ld 來控制其行為。
ld 會將 .text 節的地址連結到 0xFFFFFFFF80100000 處。

關於核心 ELF 檔案的入口地址(Entry point),即 bootloader 移動完核心後,直接跳轉到的地址,由ld 寫入 ELF的頭中,其會依次用下面的方法嘗試設定進入點,當遇到成功時則停止:

a. 命令列選項 -e entry
b. 指令碼中的 ENTRY(symbol)
c. 如果有定義 start 符號,則使用start符號(symbol)
d. 如果存在 .text 節,則使用第一個位元組的地址。
e. 地址0

注意到上面的 ld script 中,用 ENTRY 宏設定了核心的 entry point 是 kernel_entry,因此核心取得控制權後執行的第一條指令是在 kernel_entry 處。
*********************************************

linux  核心啟動的第一個階段是從  /arch/mips/kernel/head.s檔案開始的。
而此處正是核心入口函數kernel_entry(),該函數定義在 /arch/mips/kernel/head.s檔案裡。

kernel_entry()函數是體繫結構相關的組合語言,它首先初始化核心堆棧段,來為建立系統中的第一個進程進行準備,
接著用一段迴圈將核心映像的未初始化資料區段(bss段,在_edata和_end之間)清零,
最後跳轉到  /init/main.c 中的 start_kernel()初始化硬體平台相關的代碼。
*********************************************

NESTED(kernel_entry, 16,sp)            # kernelentry point
聲明函數   kernel_entry,函數的堆棧為 16byte,返回地址儲存在  $sp 寄存器中。
-----------------------------
聲明函數入口
#define NESTED(symbol, framesize,rpc)                 \
        .globl symbol;                        \
        .align 2;                             \
        .type  symbol,@function;              \
        .ent   symbol,0;                      \
symbol:     .frame  sp, framesize, rpc

彙編偽指令  frame 用來聲明堆棧布局。
它有三個參數:
    1)第一個參數  framereg:聲明用於訪問局部堆棧的寄存器,一般為  $sp。
    2)第二個參數  framesize:申明該函數已指派堆棧的大小,應該符合  $sp + framesize = 原來的  $sp。
    3)第三個參數  returnreg:這個寄存器用來儲存返回地址。
----------------------------
   kernel_entry_setup          # cpuspecific setup
----------------------------
這個宏一般為空白的,在 include/asm-mips/mach-generic/kernel-entry-init.h 檔案中定義。

某些MIPS CPU需要額外的設定一些控制寄
存器,和具體的平台相關,一般為空白宏;某些多核MIPS,啟動時所
有的core的入口一起指向   kernel_entry,然後在該宏裡分叉,
boot core 繼續往下,其它的則不停的判斷迴圈,直到boot core 喚醒之
----------------------------

    setup_c0_status_pri
設定   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 是使用多核的 SMTC Linux 時定義的。一般情況下不考慮。
MIPS已經開發出  SMP Linux的改進版,叫做SMTC(線程上下文對稱式多處理) Linux。
SMTC Linux能理解輕量級  TC 的概念,並能因此減少某些與SMP Linux相關的開銷。
----------------------------
    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 傳遞給核心的啟動參數儲存在 fw_arg0,fw_arg1,fw_arg2,fw_arg3 變數中。
變數  fw_arg0 為核心參數的個數,其餘分別為字串指標,為  *** = XXXX  的格式。
----------------------------------
    MTC0        zero,CP0_CONTEXT   # clear context register
清除  CP0 的 context register,這個寄存器用來儲存頁表的起始地址。
----------------------------------
    PTR_LA      $28, init_thread_union
初始化  $gp 寄存器,這個寄存器的地址指向一個  union,
THREAD_SIZE  大小,最低處是一個thread_info 結構
---------------------------------
    PTR_LI      sp, _THREAD_SIZE - 32
    PTR_ADDU    sp, $28
設定  $sp 寄存器,堆棧指標。  $sp = (init_thread_union 的地址) +  _THREAD_SIZE- 32
的得出  $sp 指向這個  union  結構的結尾地址  - 32 位元組地址。
-----------------------------------
    set_saved_sp    sp, t0, t1
把  這個 CPU 核的堆棧地址  $sp 儲存到  kernelsp[NR_CPUS] 數組。
---------------------------------
    如果定義了  CONFIG_SMP 宏,即多  CPU 核。
        .macro  set_saved_sp stackp temptemp2
#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 stackptemp temp2
        LONG_S  \stackp, kernelsp
        .endm

變數  kernelsp 的定義,在 arch/mips/kernel/setup.c 檔案中。
unsigned long kernelsp[NR_CPUS];
把  這個 CPU 核的堆棧地址  $sp 儲存到  kernelsp[NR_CPUS] 數組。
---------------------------------
    PTR_SUBU    sp, 4 *SZREG       # init stack pointer
---------------------------------
    j       start_kernel
    END(kernel_entry)
最後跳轉到  /arch/mips/kernel/main.c 中的 start_kernel()初始化硬體平台相關的代碼。
----------------------------------
******************************************
這個   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) };
******************************************
問題:
    1)這個  init_thread_union 結構體指標是怎麼初始化的?

******************************************

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.