【正文】
守護進程:在超級用戶下運行的一個用戶進程,與核心建立一個 IPC通道。 Kerneld調用 insmod和 rmmond來裝入和移出模塊。kerneld裝入的 module,一般放在 /lib/modules/kernelversion目錄下。 ? insmod 命令調用 sys_get_kernel_sys()系統(tǒng)調用收集核心中所有符號來解決 module中資源引用問題 。 模塊基礎 ——裝入 ? 符號表的記錄有兩個域:符號的名字( symbol name)和符號的值(一般是符號的地址)。核心提供的符號表在 module 鏈表最尾 module中。 ? insmod調用 sys_create_module(),為新module分配一個 module數據結構,掛在module_list頭上 ,置新 module 狀態(tài)為UNINITIALIZED。 ? 當初始化 module時, insmod調用sys_init_module()系統(tǒng)調用,將 module的初始化和清除函數作為參數傳遞。修改核心的符號表,同時系統(tǒng)需要修改新 module依賴的所有module中的相關指針。 模塊基礎 ——卸載 ? Rmmod命令 ? Kerneld進程自動卸載 自動卸載的機制為:每隔一定的時間, kerneld 調用sys_delete_module()系統(tǒng)調用,將它裝入的且不在被使用的 module從系統(tǒng)中卸載。它遍歷 module_list,檢查被它裝入( AUTOCLEAN)并且不用( VISITED標志)的模塊。 ?內核模塊必須有兩個函數: int init_module(): 為 內核中的某些東西注冊一個句柄,或者把內核中的程序提換成它自己的代碼(通常是進行一些工作以后再調用原來工作的代碼)。 void clean_module():模塊要求撤銷 init_module進行的所有修改,使得模塊可以被安全的卸載。 在 insmod和 rmmod命令中使用這兩個函數。 ? Use count:記錄使用本模塊的進程數或模塊數。 MOD_INC_USE_COUNT:增加 use count MOD_DEC_USE_COUNT:減少 use count MOD_IN_USE:檢查 use count是否是 0 模塊基礎 ——數據結構 ? struct module{ struct module *next。 struct module_ref *ref。 /* 所有引用該模塊的模塊 ,也用鏈表連接 */ struct symbol_table *symtab。 /*符號表 */ const char *name。 /*模塊的名字 , 存放在 module結構后面的 64個字節(jié)里 */ int size。 /* size of module in pages */ void* addr。 /* address of module */ int state。 /*三種狀態(tài):未初始化 , 運行 , 刪除 */ void (*cleanup)(void)。 /* cleanup routine */ }。 struct symbol_table { int size。 /* 包括 string table的總長度 */ int n_symbols。 int n_refs。 struct internal_symbol symbol[0]。 struct module_ref ref[0]。 }。 后面定義的是兩個零大小的數組聲明,便于動態(tài)分配空間。 symbol包含一組字符串指針,指向真正的符號字符串表 struct internal_symbol { /*符號信息 */ void *addr。 const char *name。 /*指向 string table*/ }。 struct module_ref { /*引用信息 */ struct module *module。 struct module_ref *next。 }。 string table的內容是該模塊導出的函數名和變量名 n e x trefs i z en a m es y m b o la d d rc l e a n u ps t a t em o d u l em o d u l e 39。 sc o d es i z en _ s y m b o l sn _ r e f sa d d ra d d rm o d u l en a m en a m en e x tn e x tm o d u l es y m b o l _ t a b l ei n t e r n a l _ s y m b o l 結構m o d u l e _ r e f 結構s t r i n g t a b l en a m e i sh e r e圖 1 m o d u l e 與 s y m b o l _ t a b l e 的 結 構 示意 圖模塊基礎 ——系統(tǒng)調用 ? Sys_create_module 為模塊分配空間 , 將模塊鏈入系統(tǒng)的模塊鏈中 ? Sys_init_module 初始化模塊 , 修正指針使模塊正常工作 ? Sys_delete_module 從系統(tǒng)模塊鏈中刪除模塊 , 釋放內存空間 ? Sys_get_kernel_syms 將系統(tǒng)的所有符號表全部取出到用戶空間 核心空間i n s m o d 用戶進程空間My mo du l e 目標文件ke r ne lmo d ul eke r ne lsy m bo lmo d ul eAsy m bo lAke r ne l_ sy m結構My m od ul eMy m od ul eMy s ym bo l磁盤內存1234圖 i n s m od M y m o d u l e 的過程① insmod先調用系統(tǒng)調用 sys_get_kernel_syms,將當前加到系統(tǒng)中的模塊和核心的符號表全部輸出到 kernel_sym結構中 , 為后面使用 。 這個結構的內容在 insmod用戶進程空間 。 ② 將 Mymodule目標文件讀進 insmod用戶進程空間 , 成為一個映像 。 ③ 根據第一步得到的信息 , 將 Mymodule映像中的地址沒有確定的函數和變量一一修正過來 。 ④調用系統(tǒng)調用 sys_create_module、sys_init_module,將 Mymodule鏈入到系統(tǒng)中去。 ? 內核模塊的編譯 需要用 c選項進行編譯 。 所有的內核模塊都必須包含特定的標志: __KERNEL__:這個標志告訴頭文件此代碼將在內核模塊中運行 , 而不是作為用戶進程 。 MODULE:這個標志告訴頭文件要給出適當的內核模塊的定義 。 LINUX: 從技術上講,這個標志不是必要的。用于比較正規(guī)的內核模塊,在多個操作系統(tǒng)上編譯,這個標志將會使你感到方便。它可以允許你在獨立于操作系統(tǒng)的部分進行常規(guī)的編譯。 例: gcc Wall DMODULE D__KERNEL__ DLINUX D表示加入標志 用戶空間設備驅動程序 ? 有時不需要真正的驅動程序: 沒有兩個以上的應用程序使用設備 并且不需要響應中斷 沒有多個進程訪問 不管理資源 ? 例: vgalib庫 早期的鼠標轉換 設備驅動程序框架 ——接口 ? Linux設備驅動程序與外界的接口 ,通過file_operations(include/linux/)完成。 ,初始化設備。 。與具體設備相關。 驅動程序框架 ——功能 ? 驅動程序的注冊與注銷 ? 設備的打開與釋放 ? 設備的讀寫操作 ? 設備的控制操作 ? 設備的中斷和輪詢處理 初始化函數的調用關系 ? 系統(tǒng)轉入核心 , 調用函數 start_kernel() 。 它調用kernel_thread (init, NULL, 0), 創(chuàng)建 init進程進行系統(tǒng)配置 ( 其中包括所有設備的初始化工作 ) 。 sys_setup() device_setup() chr_dev_init()/blk_dev_init() Kernel_thread() init() setup() 注冊與注銷 ? 注冊和注銷函數: register_*dev() unregister_*dev() //include/linux/ ? 所謂注冊就是在內核的 chrdevs或 blkdevs中添加一項。 struct device_struct { const char * name。 struct file_operations * fops。 }。 相同主設備號的 fops元素內容相同 。 打開與釋放 ? 打開設備: open() 檢查與設備有關的錯誤,如未準備好。 如果是首次打開,則初始化設備。 確定次設備號,根據需要可更新設備的 f_op。 如果需要,分配且設置文件中的 private_data。 遞增設備使用的計數器。 如果只允許一個進程使用設備,則需要設忙標志。 ?釋放設備: release() 遞減設備使用的計數器 釋放設備文件中的私有數據所占空間 如果是獨占設備,則要清除忙標志,使其他進程可以使用 如果是最后一個釋放,則關閉設備 設備的讀寫操作 ? 字符設備: foo_read()和 foo_write() ? 塊設備 block_read和 block_write()——策略規(guī)程,不需要在驅動程序中實現。 通過緩沖區(qū)讀寫,只在數據不在緩沖區(qū)時才真正執(zhí)行數據傳輸,通過 request_fn()完成。 struct blk_dev_struct struct request 設備的控制 ? ioctl() 一般做法是: 首先差錯檢查, 然后用一個大的 switch語句(可能是內嵌的)來處理所有可能的 ioctl命令。 返回: 出錯返回 erro 其他情況由用戶定義 字符設備驅動程序 ? 數據結構 ? 注冊與注銷 ? 輪詢和中斷 對應驅動程序的 “ 三個接口 ” 。 添加一個簡單的字符設備 ? 確定主設備號 ? 編寫 file_operations中的函數以及中斷處理函數。 ? 編寫初始化函數 foo_init() ? 在 chr_dev_init()中添加調用和返回初始化函數的代碼。 ? 修改 drivers/char/Makefile; 假設我們把所以必要的函數寫 , 則在“ L_OBJS := \” 行把“ ” 加到其中 。 ?將該設備私有的 *.c, *.h復制到目錄 drivers/char下 。 ?用命令: make clean。make dep。make zImage重新編譯內核 。 ?用 mknod命令在目錄 /dev下建立相應主設備號的用于讀寫的特殊文件 mknod命令:建立設備特殊文件 格式: mknod 文件名 類型 主設備號 次設備號 類型: c或 b, 代表字符設備或塊設備 塊設備驅動程序 ? 數據結構 ? 注冊與注銷 ? 讀寫請求及其處理 增加一個塊設備的方法和字符設備差不多。 塊設備不需要編寫 file_operations結構里的 read和 write函數,但是也需要 read和 write在request中調用。 需要有請求處理函數,以及中斷處理函數。 嵌入式網絡技術 TCP/IP協(xié)議簡介 ? TCP/IP協(xié)議是一套把因特網上的各種系統(tǒng)互連起來的協(xié)議組,保證因特網上數據的準確快速傳輸 ? 參考開放系統(tǒng)互連 (OSI)模型, TCP/IP通常采用一種簡化的四層模型 : ? 應用層 ? 傳輸層 ? 網絡層 ? 鏈路層 TCP協(xié)議的實現 ? TCP協(xié)議是面向連接的、端對端的可靠通信協(xié)議。 ? 它采用了許多機制來保證可靠傳輸,應用于嵌入式系統(tǒng)顯得過于復雜 ? TCP協(xié)議數據傳輸可分為三個階段:建立連接、傳輸數據和斷開連接。 ? 它的實現過程可以用狀態(tài)機來描述。 TCP連接建立 ? 建立連接有兩