Linux內核學習總結

張瑜
原創作品轉載請註明出處
《Linux內核分析》MOOC課  http://mooc.study.163.com/course/USTC-1000029000 

自從上學期學了孟寧老師的網絡程序設計的課程,覺得老師翻轉課堂,注重實踐與理論相結合的教學方式特別棒,這學期又看見孟寧老師的Linux內核課程,毫不猶豫的選了。線上視頻課程與實驗樓的在線實驗,還有線下老師的手把手教學輔導,讓我受益匪淺。此課程的收穫不只是對Linux內核的學習,對Linux的操作也是加深了熟練,對Linux內核加深了了解。

一、博客目錄:

  1. Linux內核分析——簡單分析彙編代碼
  2. Linux內核分析——操作系統的工作原理
  3. Linux內核分析——跟蹤分析Linux內核的啓動過程
  4. Linux內核分析——扒開系統調用的三層皮(上)
  5. Linux內核分析——扒開系統調用的三層皮(下)
  6. Linux內核分析——分析Linux內核創建一個新進程的過程
  7. Linux內核分析——Linux內核如何裝載和啓動一個可執行程序
  8. Linux內核分析——進程的切換和系統的一般執行過程

二:課程內容總結

  1. 簡單分析彙編代碼
    馮諾依曼體系結構的計算機,又叫存儲程序計算機,從硬件的角度來看,其工作模型是CPU依次讀取內存中的指令來完成工作。這節課詳細介紹了CPU計算模塊、寄存器和內存是如何配合工作的。

  2. 基於mykernel的一個簡單的時間片輪轉多道程序內核代碼分析
    mykernel是由老師建立的一個用於開放自己的操作系統的內核平臺。
    Linux操作系統的正常工作可以說有三個非常重要的部分,就是我們的存儲程序原理、堆棧以及中斷的支持。 操作系統對進程的管理主要就是進程的管理和調度,我們爲每個進程維護一個進程描述和以及進程間的關係。我們的內核的工作主要有兩部分組成,首先運行有一個內核線程,然後就是一些中斷處理程序的集合,我們在中斷處理程序中要就行進程的調度。Linux操作系統由內核來實現具體工作的,一個進程是通過系統調用fork()函數來創建的,先是將先前CPU正在運行的進程的進程上下文保存在內核態堆棧中,包括有eip,esp,ebp,cs等寄存器的數據;然後加載創建的進程的上下文信息到相應的寄存器中,運行當前新建進程;運行完畢後根據系統的調度繼續執行相應的進程。Linux操作系統是多進程的操作系統,不同的進程就是基於以上的方式有操作系統實現調度運行的。同時,操作系統以一種中斷的機制實現與用戶的交互。操作系統中的IDT描述好各個中斷對應的處理程序,當發生相對應的中斷時,由硬件來實現中斷信號的傳遞,CPU接收到相應的IRQ信號後,由操作系統如調度進程那樣調度相應的處理程序,來完成相應的中斷請求,實現與用戶的交互。

  3. 使用gdb跟蹤Linux內核啓動過程
    道生一(start_kernel–>cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三個進程),三生萬物(1號進程是所有用戶態進程的祖先,2號進程是所有內核線程的祖先)。
    start_kernel()是內核的彙編與C語言的交接點,在該函數以前,內核的代碼都是用匯編寫的,完成一些最基本的初始化與環境設置工作。start_kernel就像是c代碼中的main函數。不管你關注Linux的內核模塊,總是離不開start_kernel函數的,因爲大部分模塊的初始化工作都是在start_kernel中完成的。按照這節課的實驗步驟,跟蹤Linux內核的啓動過程。通過自己編譯內核源碼,並且調試了啓動過程,瞭解到內核在啓動時經歷了哪些初始化。內核幾乎所有的初始化都是在start_kernel進行的,在start_kernel之前主要是彙編代碼完成的一些操作。在start_kernel中會初始化中斷向量,內存管理模塊,調度模塊等一系列初始化。在最後的rest_init()中會初始化0號進程和1號用戶態進程,然後最終啓動系統。

  4. 使用庫函數API和C代碼中嵌入彙編代碼兩種方式使用同一個系統調用
    系統調用的三層皮:xyz(API)、system_ call(中斷向量)、sys_xyz(中斷向量對應的中斷服務程序)。當用戶態進程調用一個系統調用時,CPU切換到內核態並開始執行一個內核函數,在Linux中是通過執行int $0x80來執行系統調用的, 這條彙編指令產生向量爲128的編程異常。 中斷向量0x80與system_call綁定起來。 系統調用號將xyz和sys_xyz關聯起來了。

  5. 分析system_call中斷處理過程
    系統調用在內核代碼中的工作機制和初始化
    int 0x80——>system call:通過中斷向量匹配
    system call——>sys_xyz():通過系統調用號匹配
    一旦執行int 0x80後立刻跳轉到system_call執行
    通過gdb我們可以給系統調用內核處里程序如sys_write, sys_time設置斷點,並讓程序停在斷點處,進行斷點跟蹤系統調用處裏過程。由於system_call是完全用匯編寫就一個的函數,雖然我們也可以在system_call處設置斷點,但卻無法讓系統停在system_call處,所以也無法通過單步跟蹤學習其處裏流程。這裏寫圖片描述

  6. 進程的描述和進程的創建
    爲了管理進程,內核必須對每個進程進行清晰的描述,進程描述符提供了內核所需瞭解的進程信息。在Linux應用程序的開發中,可以通過fork、vfork和clone等API來創建一個子進程,它們在Linux內核中對應的系統調用分別爲sys_fork、sys_vfork和sys_clone函數,而這些函數最終都會調用do_fork完成子進程的創建。do_fork主要是複製了父進程的task_struct,然後修改必要的信息,從而得到子進程的task_struct。

  7. Linux內核如何裝載和啓動一個可執行程序
    Linux系統可以通過execve API啓動一個新進程,該API又呼叫sys_execve系統調用,負責將新的程序代碼和數據替換到新的進程中,打開可執行 文件,載入依賴的庫文件,申請新的內存空間,最後執行 start_thread(regs, elf_entry, bprm->p) ,設置 new_ip, new_sp ,完成新進程的代碼和數據替換,然後返回,接下來就是執行新的進程代碼了。

  8. Linux中進程調度與進程切換過程
    Linux系統的一般執行過程,最一般的情況是:正在運行的用戶態進程X切換到運行用戶態進程Y的過程要經過以下步驟

    1). 正在運行的用戶態進程X

    2). 發生中斷:save cs:eip/esp/eflags(current) to kernel stack, then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).

    3). SAVE_ALL //保存現場,這裏是已經進入內核中斷處裏過程

    4). 中斷處理過程中或中斷返回前調用了schedule(),其中的switch_to做了關鍵的進程上下文切換

    5). 標號1之後開始運行用戶態進程Y(這裏Y曾經通過以上步驟被切換出去過因此可以從標號1繼續執行)

    6). restore_all //恢復現場

    7). iret - pop cs:eip/ss:esp/eflags from kernel stack

    8). 繼續運行用戶態進程Y

三、學習總結

這學期選了Linux課程,對於翻轉課堂的混合式教學,我自己受益匪淺,線上課程可以重複觀看,觀看時間也很靈活,進行思考後跟隨實驗樓的在線實驗進行實驗,文檔寫的特別詳細。然後線下還可以找老師進行答疑,解決一些困惑,同時老師也會問一些自己沒有想到的問題。還有一個每一週的測試,可以讓自己及時的總結和衡量自己一週學習的內容和知識。我的自學能力也得到了提升。
當然,對這門課程我還是有很多做的不夠,比如有些問題沒有進行很深入的思考,“不求甚解”,同時也有很多函數沒有被我追蹤到,是一個遺憾。
再次強調,孟寧老師的教學方法特別適合軟件工程這種重實踐的課程。下半學期我還選了孟寧老師的高級軟件工程課程,希望自己能得到進一步提升。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章