《Linux內核設計與實現》課本第五章學習筆記——20135203齊嶽

《Linux內核設計與實現》課本第五章學習筆記

By20135203齊嶽

與內核通訊

用戶空間進程和硬件設備之間經過系統調用來交互,其主要做用有三個。html

  • 爲用戶空間提供了硬件的抽象接口。
  • 保證了系統的穩定和安全。
  • 實現多任務和虛擬內存。保證良好的穩定性和安全性。

系統調用是用戶空間訪問內核的惟一手段;除異常和陷入外,是內核惟一合法的入口。linux

API、POSIX和C庫

應用程序經過在用戶空間實現的應用編程接口(API)而非直接經過系統調用來編程。程序員

POSIX是應用編程接口的一個國際標準,C庫提供了POSIX的絕大部分API。編程

Unix接口設計的特色:提供機制(須要實現什麼功能)而非策略(怎樣實現這些功能)。Unix系統調用抽象出了用於完成某種肯定的目的的函數,而至於函數是如何實現功能的則並不關心,從程序員的角度來看,只需經過接口即可實現功能。api

系統調用

要訪問系統調用,一般經過C庫定義的函數調用來進行。例如,getpid()系統調用,在內核中的實現爲:安全

SYSCALL_DEFINED0(getpid)
{
    return task_tgid_vnr(current);//return current->tgid
}

SYSCALL _ DEFINED0只是一個宏,定義一個無參數的系統調用,展開後的代碼以下函數

asmlinkage long sys_getpid(void)

asmlinkage爲限定詞,是一個編譯指令,通知編譯器僅從棧中提取該函數的參數。函數返回值在用戶態時爲int,在內核態爲long。性能

系統調用號

在Linux系統中每一個系統調用被賦予一個系統調用號,當用戶空間的進程執行一個系統調用時,系統調用號用來指明執行哪一個系統調用學習

系統調用號一旦分配就不會再更改,被刪除的系統調用號也不準再回收。設計

sys _ ni _ syscall()專門針對無效的系統調用而設立的,只負責返回-ENOSYS。

系統調用號被定義在arch/i386/kernel/syscall_64.c文件中。

指定恰當的系統調用

X86中,系統調用號經過eax寄存器傳遞給內核,system _ call()函數經過將給定的系統調用與NR _syscalls做比較來檢查其有效性,若是大於或等於NR _syscalls就返回-ENOSYS,不然就執行相應的系統調用:

call *sys_call_table(,%eax,8)//基址+偏移量*8

參數傳遞

上一篇博客中有詳細的記錄,這裏再也不贅述。見http://www.cnblogs.com/July0207/p/5277774.html

系統調用的實現

參數驗證

因爲系統調用在內核空間執行,因此必須驗證其參數是否合法有效,並且必須是正確的。

檢查指針是否有效

檢查用戶提供的指針是否有效,在接收這個指針以前,必須保證:

  • 指針所指向的內存區域屬於用戶空間。
  • 指針所指向的內存區域在進程的地址空間以內。
  • 若是是讀,該內存應被標記爲可讀,若是是寫,該內存應被標記爲可寫,若是是可執行,該內存應被標記爲可執行。進程決不能繞過內存訪問限制。
檢查內核空間與用戶空間數據的來回拷貝

內核提供了兩個方法來完成必須的檢查內核空間與用戶空間數據的來回拷貝。

  • 爲了向用戶空間寫數據,內核提供了copy _ to _user(),它須要三個參數,第一個是進程空間中的目的內存地址,第二個是內核空間內的源地址,第三個是須要拷貝的數據長度(字節數)。

  • 爲了從用戶空間讀數據,內核提供了copy _ from _user(),該函數把第二個參數指定位置上的數據拷貝到第一個參數的指定位置,第三個是須要拷貝的數據長度(字節數)。

若是運行成功,則返回0,若是失敗,則返回沒能拷貝成功的字節數。

檢查針對是否有合法權限

調用capable()函數檢查用戶是否有權對指定資源進行操做,返回非0值則有權限,返回0無權限。

<linux/capability.h>中包含一份全部權能和其對應的權限列表。

系統調用上下文

內核在執行系統調用時處於進程上下文。在進程上下文中,內核能夠:

  • 休眠:說明系統調用可使用內核提供的絕大部分功能。
  • 能夠被搶佔:要求保證該系統調用是可重入的。

綁定一個系統調用的最後步驟

  1. 在系統調用表的最後加入一個表項。
  2. 對於所支持的各類體系結構,系統調用號都必須定義於<asm/unistd.h>中。
  3. 系統調用必須被編譯進內核映像,不能被編譯成模塊。只要將其放進kernel/下的一個相關文件中便可,例如sys.c。

從用戶空間訪問系統調用

Linux自己提供了一組宏,用於直接對系統調用進行訪問。他會設置好寄存器並調用陷入指令。該宏必須瞭解到底有多少參數按照怎樣的順序壓入寄存器。

_syscalln()     //n的範圍從0到6,表明須要傳遞給系統調用的參數個數。

例如,open()系統調用的形式是:

long open(const char *filename, int flags, int mode)

等價於

#define NR_open 5
_syscall3(long,open,const char*,filename, int,flags, int,mode)

對於每一個宏來講,都有(2+2xn)個參數:

1.系統調用的返回值類型

2.系統調用的名稱

3及之後是按照系統調用參數的順序排列每一個參數的類型和名稱。

_ NR _open在<asm/unistd.h>中定義。這個宏會被擴展成爲內嵌彙編的C函數。

創建一個新系統調用

好處:

  • 系統調用建立容易而且使用方便
  • linux系統調用的高性能

問題:

  • 佔用系統調用號
  • 固化,不容許改動接口
  • 須要分別註冊到每一個須要支持的體系結構中
  • 腳本中不易調用,文件系統中也不能直接訪問
  • 在主內核樹外難以維護使用

替代方法:

  • 某些接口,例如信號量,用文件描述符表示
  • 把增長的信息做爲一個文件放在sysfs的合適位置。
相關文章
相關標籤/搜索