1. 程式人生 > >2018-2019-1 20189203《Linux核心原理與分析》第四周作業

2018-2019-1 20189203《Linux核心原理與分析》第四周作業

第一部分 課本學習

  • 核心版本號:Linux核心自2013年12月起,就以A.B.C.D的方式命名。A和B變得無關緊要,C是核心的真實版本。每一個版本的變化都會帶來新的特性,如內部API的變化等,改動的程式碼數量常常上萬行。D是安全補丁和bug修復。
  • 幾個關鍵的目錄:
    Arch:與體系結構相關的子目錄列表。
    Block:存放Linux儲存體系中關於塊裝置管理的程式碼。
    Crypto:存放常見的加密演算法的C語言程式碼。
    Documentation:存放一些文件。
    Drivers:驅動目錄,裡面分門別類地存放了Linux核心支援的所有硬體裝置的驅動原始碼。
    Firmware:韌體。
    Fs:檔案系統,裡面列出了Linux支援的各種檔案系統的實現。
    Include:標頭檔案目錄,存放公共的標頭檔案。
    Init:init是初始化的意思,存放Linux核心啟動時的初始化程式碼。
    Ipc:裡面是Linux支援的IPC的程式碼實現。
    Kernel:存放核心本身需要的一些核心程式碼檔案。其中有很多關鍵程式碼,包括pid--程序號等。
    Lib:公用的庫檔案,裡面是一些公用的庫函式。
    Mm:存放LInux的記憶體管理程式碼。
    Net:該目錄下是網路相關的程式碼,譬如TCP/IP協議棧等。
  • 編譯配置Linux核心的關鍵步驟:
    1、編譯安裝步驟
    安裝開發組包>下載原始碼檔案>.config: 準備配置檔案>make menuconfig: 配置核心選項>make[-j#]>make modules_install: 安裝模組>make install:安裝核心相關檔案>安裝bzImage 為 /boot/vmlinuz-VERSION-RELEASE>生成initramfs>編輯grub的配置檔案。
    2、編譯配置選項
    (1)配置核心選項
    (2)支援“更新”模式進行配置:make help
    Make config:基於命令列以遍歷的方式去配置核心中可配置的每個選項。
    Make menuconfig:基於命令列以遍歷的方式去配置核心中可配置的每個選項。
    Make gconfig:基於GTK(GNOME)環境視窗介面。
    Make xconfig: 基於QT(KDE)環境的視窗介面。
    (3)支援“全新配置”模式進行配置
    Make defconfig:基於核心為目標平臺提供的“預設”配置進行配置。
    Make allyesconfig:所有選項均回答為“yes”。
    Make allnoconfig:所有選項均回答為“no”。
    3.編譯
    全編譯:make[-j#]

第二部分 實驗操作

  • 在實驗樓環境下輸入:
cd LinuxKernel/
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img

完成啟動核心的操作,如下圖:

  • 幾個指令的含義:
    qemu :相當於開啟一個虛擬機器
    kernel:啟動一個核心,位置由其後的檔名指定。
    bzImage是vmLinux經過gzip壓縮後的檔案,是壓縮的核心映像。vmLinux是編譯出來的最原始的核心ELF檔案。
    initrd是“initial ramdisk”的簡寫,普通linux使用者一般感受不到這個記憶體根檔案系統的存在,核心啟動先訪問initrd檔案系統,然後在切換到磁碟檔案系統。
  • 使用gdb跟蹤除錯核心
(gdb)file linux-3.18.6/vmlinux # 在gdb介面中targe remote之前載入符號表
(gdb)target remote:1234 # 建立gdb和gdbserver之間的連線,按c 讓qemu上的Linux繼續執行
(gdb)break start_kernel # 斷點的設定可以在target remote之前,也可以在之後
  • 操作如下:
    載入符號表:

    連結gdbserver:

    設定一個斷點

    檢視start_kernel函式的上下文

    第三部分 分析從start_kernel到init程序啟動的過程

    1、start_kernel()

    程式碼如下:
  • main.c中沒有main函式,start_kernel()相當於C語言中的main函式。Start_kernel是一切的起點,在此函式被呼叫之前,核心程式碼主要是用匯編語言寫的,用於完成硬體系統的初始化工作,為C程式碼的執行設定環境。

    2、init_task()

    程式碼如下:
  • init_task(0號程序)是task_struct型別,是程序描述符,使用巨集INIT_TASK對其進行初始化。接下來就是對各模組的初始化。

    3.rest_init()

    程式碼如下:
  • rest_init()這個函式呼叫系統函式 kernel_thread() 建立 1 號程序,即 init 程序,是使用者態所有程序的祖先。然後,新建 kthreadd 程序,是核心態所有程序的祖先。最後,通過 cpu_startup_entry 函式啟動 0 號程序。
    Init_task()(PID為0)在建立了init程序後,呼叫cpu_idle()演變成idle程序,執行一次排程後,init程序執行。1號核心執行緒負責執行核心的部分初始化工作及進行系統配置,最後呼叫do_execve載入init程式,演變成init程序(使用者態1號程序),init程序是核心啟動的第一個使用者態程序。Kthreadd(PID為2)程序由0號程序建立,始終執行在核心空間,負責所有核心執行緒的排程和管理。