




已阅读5页,还剩67页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Driver 核心模組 vs 應用程式 l應用程式啟動後從頭到尾都只執行同一件任務. l模組被載入核心之後必須先向核心註冊它自己. init_module()函式(模組的入口點)任務是將模組的功能準備好 以便事後可被invocation(調用). cleanup_module()在模組離開之前必須要被呼叫. l模組只能與核心連結所以模組只能呼叫核心所提供的程式 ex: printfk(). l由於上一點,模組的原始碼不能引入一般的標頭檔. 有關核心相關事物放在 /usr/src/linux下的 include/linux 與 include/asm/ 目錄下的標頭檔. 使用者空間與核心空間 l模組存活在kernel space(核心空間)而應用程式存在user space(使 用者空間). l作業系統必須負責讓程式得以獨立運作並保護系統資源避免非授 權的存取. l由CPU來保護系統軟體所以CPU本身提供了不同層級的作業模式 (operating modality). lUnix系統提供兩個層級而現在CPU也至少有兩種層級,故Unix系 統只使用最高與最低層級,Unix核心運作在最高層級(supervisor mode)應用程式運作在最低層級(user mode). lexecution mode:包括kernel-space 與user-space分別有各自的 memory mapping(記憶體對應關係)的關係與各自的address space( 定址空間). insmod l載入 insmod對模組的作用:將模組內的任何unresolved symbol(懸置 符號)連結到目前核心(函式庫)的符號表. 核心如何支援insmod? 依賴定義在kernel/module.c的system call函式: 1) sys_create_module():配置一塊可以容納模組的核心記憶空間. 2) sys_get_kernel_syms():傳回核心符號表,解決模組的懸置符號 . 3) sys_init_module():將insmod改好的relocated object code移 到 預先配置的核心空間. l系統呼叫大略表: kernel/ 目錄執行 egrep “sys_.*)$” *.c 版本依存性 l模組與連結對象核心息息相關每當升級何新版本時模組就必須再 新版本核心下重新編譯一次. l編譯器會在ELF(executable Linking and Format).的.modifo(chap 11)區定義_module_kernel_version符號 linsmod會依照此符號與當時的核心作比較. l定義在. l可使用insmod f來略過版本檢查. l針對特定版本的核心來編譯模組必須引入該版本核心的標頭檔 再Makefile定義一個KERNELDIR環境變數讓他指另一個不同 的位置. 核心符號表 l模組化驅動程式所需的核心全域項目(函式與變數)的位 置都紀錄在符號表裡 可從/proc/ksyms取的此表. l若模組能被順利載入核心,模組所釋放的符號也會成為核 心符號的一部分. l模組所釋出的符號可以被新模組使用新模組可以疊在 其他模組之上. ex: msdos檔案系統得仰賴fat模組所釋出的符號 模組的生與死 linit_module()會註冊模組所提供的任何facility(功能性). l模組可以註冊許多不同類型的facility,對於每一個facility 都有一個特定的核心函式來完成其註冊程序. l傳給核心註冊函式的引數:facility註冊名稱,指標(指向此 facility的資料結構). lfacility種類:序列阜,雜項裝置,/proc檔案,作業領域 (executable domain),管制線路(line discipline). Init_module的錯誤處置 l註冊失敗:系統沒有足夠空間或某資源已被其他驅動程式 佔用 l模組自己要負責回復(undo)到註冊失敗之前的狀態,如果 init_module()在中途失敗,模組必須自己主動註銷 (unregister)那些已經註冊成功的facility. l不能藉由重新載入模組來重新註冊facility,也不太可能註 銷他們,因為需要當初註冊所用的相同指標. l使用goto解決. 卸載模組 l使用rmmod可卸載(unload)沒用的模組. l原理: rmmod觸發delete_module() system call,如果模組的 用量為零,則delete_module()會呼叫模組本身的 cleanup_module();否則回傳作錯誤代碼. lcleanup_module()必須負責註銷該模組的每一項facility. 實際的初始化與清理函式 l命名模組函式,須引入 module_init(my_init); module_exit(my_cleanup); l my_init取代init_module(),my_cleanup取代 cleanup_module(); l所以可使每個初始函式與清理函式都有自己專屬的名稱, 以方便除錯. 資源的運用 l大部分驅動程式的工作大概就在讀寫I/O port或I/O memory(統稱 I/O region) l核心都應該保證驅動程式能獨占存取其I/O port以免受到其他驅動 程式的干擾 l/proc/ioports與/proc/iomem檔案可取得以註冊的系統資源 User-space驅動程式(1/2) l優點 可使用完整的c函式庫. 可使用傳統的debugger. 若user-space driver當掉,直接kill就可以. user-space記憶體可被“置換(swappable)”,而kernel-space不 可能,因此較大的程式不會排擠其他程式所使用的RAM, 除非此裝置正在使用. user-space driver也能容許目標裝置同時被多個行程所存 取. User-space驅動程式(2/2) l缺點: 在user-space內無法使用”中斷”. 不能直接存取I/O memory. 必須先呼叫ioperm()或iopl()才能存取I/O port. 回應時間較緩慢,因為應用程式要傳輸資料給硬體而硬體 也要回應應用程式(context switch) 若驅動程式已被“置換(swap)”到磁碟上,那回應時間就更 長了 大部分重要裝置不能在user-space上予以有效控制,ex:網路 介面 I/O memory(1/3) lint check_region(unsigned long start,unsigned long len); 用來檢查某段範圍的I/O位址是否被佔用. lstruct resource *request_region(unsigned long start,unsigned long len , char *nam); 要求註冊該位址區.若核心同意,此函式會回傳一個non- NULL指標. I/O memory(2/3) lvoid release_region(unsigned long start.unsigned long len); 將取得的I/O 位址歸還給系統. I/O memory(3/3) l取得,釋放特定一段的I/O memory region int check_mem_region(usigned long start,unsigned long len); int request_mem_region(unsigned long start,unsigned long len,char *name); int release_mem_region(unsigned long start,unsigned long len); 決定組態參數(1/4) l驅動程式所需的某些參數會因系統而異,ex:I/O 位址, 記憶區範圍有時候必須傳遞參數給驅動程式,才能 幫助他找到目標裝置或啟動,關閉特定功能. l對於某些裝置,如裝置品牌,型號等也有可能影響驅 動程式的行為. l將正確的參數傳遞給驅動程式(configuring),是驅動程 式在初始化期間必須完成的工作. l參數值可在載入期間由insmod或modprobe傳給模組 決定組態參數(2/4) lmodprobe可從一各組態檔(/etc/modules.conf)讀入參 數值. l使用者可在命令列指定參數值ex: #insmod skull skull_ival=666 skull_sval=“beast” l在insmod能夠改變模組參數之前,模組本身必須以 MODULE_PARM()巨集(定義在linux/module.h)宣告 可被修改的參數. lMODULE_PARM()需要兩個引數,一是變數名稱,二 是變數型別. 決定組態參數(3/4) int skull_ival=0; char *skull_sval; MODULE_PARM(skull_ival, “I”); MODULE_PARM(skull_sval, “s”); l參數型別有五種:b(1-byte),h(2-byte短整數),i(整數),l( 長整數),s(字串). 決定組態參數(4/4) lMODULE_PARM_DESC()巨集,可讓程式設計師用來 描述模組參數的意義. static int skull_port_bse=0x300; MODULE_PARM(skull_port_base,”i”); MODULE_DESC(skull_port_base,”skull I/O base(default 0x300); l可使用objdump,modinfo指令來檢視參數指令. 訊息除錯法(1/4) lprintk()函式 l通用的除錯技巧,對應用程式而言使用printf();對 於核心程式而言則使用printk(). lprintk()能讓你指定訊息的loglevel(等級),共分為 八纇.定義在裡. KERN_EMERG:緊急訊息,出現在系統崩潰前. KERN_ALERT:危險通知,發生在需要立即採 取行動的事件. KERN_CRIT:嚴重狀況,涉及硬體或軟體故障 訊息除錯法(2/4) KERN_ERR:錯誤狀況回報,通常回報硬體上的困難. KERN_WARNING:緊急訊息,程度上不影響系統. NERN_NOTICE:通知,意料中會發生且值得注意的 狀況. KERN_INFO:資訊性訊息,driver在啟動階段所印出 的硬體資訊. KERN_DEBUG:供除錯用途的訊息. 訊息除錯法(3/4) l上述代號展開後分別成為:,之類的 字串,括弧內數字越低表示等級越高. ex:printk(KERN_DEBUG “HI”); l不同等級的訊息會被輸出到不同的地點,有可能是目 前的操控台(console)或者是某種文字終端機(Xterm 視窗,Telnet或SSH連線). l任何等值低於console_loglevel的變數訊息都會被顯 示在操控台上(console). l不過若系統上同時執行klogd與syslogd不管 console_loglevel的值為何,所有核心訊息都會被加 入/var/log/messages. 訊息除錯法(4/4) l如果沒跑klogd,則訊息不會流入user-space,除非主 動讀取/proc/kmsg. l修改console_loglevel的值 使用sys_syslog() 利用klogd的 c選項. 本書範例:misc-progs/setlevel.c, l2.1.31版本開始,可以直接透/proc/sys/kernel/ printk檔案來修改或檢視console_levle的值. # echo 8 /proc/sys/kernel/printk 核心訊息的輸出流程(1/2) lprintk()會將訊息寫入一個環型queue,長度為 LOG_BUF_LEN(定義在kernel/printk.c),且喚醒 正在等待訊息的行程(使用syslog(). 正在讀取/proc/kmesg的行程. l在環型queue被填滿時,printk()將會繞回原點,將新 訊息覆蓋在最就訊息上,其優點: 固定記憶體,既使沒跑日誌紀錄引擎 (klogd,syslogd)也不至於消耗所有的記憶體. 核心內部到處都可以直接呼叫printk(). 核心訊息的輸出流程(2/2) lklogd所取得的核心訊息會被轉交給syslogd,由它依 據/etc/syslog.conf來決定如何處裡收到的訊息. l若系統沒跑klogd,核心訊息將會一值留在環型佇列, 直到有人讀取它或者是被新訊息蓋掉. l若不希望driver所發出得訊息擾亂的系統的日誌檔, 可以用-f選項來從新啟動klogd並將其訊息寫入特定 檔案 . kernel/proc/kmsgklogd/dev/logsyslogd syslog.conf 查詢除錯法(1/6)(使用/proc檔案系統) l/proc是靠軟體模擬出來的特殊檔案系統,並不實際存 在於硬碟上,而是核心提供給user-space的資訊窗口. l在proc/下的每一個檔案,接聯繫到核心內的專屬函式 ,這些函式在使用者讀取檔案時,及時產生檔案的內容 . ex: 以/proc/modules為例,當你讀取它時它會顯示目 前載入哪些模組,但此檔案系統的長度都為0. 查詢除錯法(2/6)(使用/proc檔案系統) lLinux許多系統工具,如ps,top,uptime等都是從 /proc取得它們所需要的資訊. l建立/proc檔案:driver必須製作一備查程式,讓它在檔 案被存取時,及時供應資料,核心也會配置一記憶頁給 它 l備查程式介面: int (*read_proc)(char *page,char *start,off_t offset,int count,int *eof ,void *data); read()/proc備查函式記憶頁User-space 查詢除錯法(3/6)(使用/proc檔案系統) lpage指標:指向核心預先配置的記憶頁 l*start與offset:若檔案超過一記憶頁大小,可利用 分批傳輸的方式,先將*start指向page再利用offset 指向下一各位元組. lskcull程式中有對read_proc的實作: 查詢除錯法(4/6)(使用/proc檔案系統) l定義好read_proc作業方式後,必須為它在/proc下設 置一個入口點,使用create_proc_read_entry(). l若希望使用者能透過/proc/scullmem取得該函式提 供的資料,則driver需宣告如下: static void scull_create_proc() create_proc_read_entry(“scullmem”, 0 /* 預設模式(0x444) */, NULL /* 上層目錄(*proc_dir_entry)*/, scull_read_procmem, NULL /* 提供給read_proc使用的資料 */); /proc入口點名稱 檔案權限 入口點上層目錄 read_proc作業 方法的指標 傳給read_proc的資 料的指標 查詢除錯法(5/6)(使用/proc檔案系統) l第三參數的說明: 在/proc檔案系統下的每一個子目錄,都有各自 專屬的proc_dir_entry結構來描述. ex:描述/proc/driver子目錄的結構為 proc_root_driver,描述/proc/bus子目錄的結 構為proc_bus. 若此引數設定為NULL代表入口點設置在/proc 目錄下. 查詢除錯法(6/6)(使用/proc檔案系統) l在模組被載卸之前必須先移除相關的/proc入口點, 使用remove_proc_entry() /移除 /proc/scullmem; remove_pcor_entry(“scullmem”,NULL); /移除 /proc/driver/scullmem; remove_proc_entry(“scullmem”,proc_root_driver); /移除 /proc/scull/scullmem; remove_proc_entry(“scullmem”,scull_procdir); 觀測除錯法 lstrace,檢驗位於kernel-space的程式碼. l能顯示出由user-space程式所發出的所有system call. l#strace ls /dev /dev/scull0 排除重大系統錯誤(1/2) l除了監視,除錯技術,驅動程式可能還是意料之外的 bug存在,嚴重可能造成system fault. lfault(失誤)不等於panic(死當),失誤通常會摧毀目前 的行程,系統本身能正常. l若fault發生在process context之外,或是破壞系統的 關鍵部分,即有可能早成panic. loops訊息:往往發生在不當的操作指標所引起,如 dereference(提領)或者是誤用指標的值. 排除重大系統錯誤(2/2) lpage fault: 在protect mode(保護模式)下,所使用 的是virtual address(虛擬記憶體),藉由page table換算出physical address(實體位置),若程式 提領一個無效指標,分頁機制則沒有辦法算出實體位 置,因而發生page fault. l若在user-space發生提領無效,後果頂多是無法 ”page in “該位址. l若發生在kernel則迫使核心發出oops訊息. Ksymoops用法 lksymoops用法: lsystme.map檔(-v) /usr/src/linux/system.map l模組清單(-l): /proc/modules l核心符號表(-k): /proc/ksyms l映像檔(-v): l模組object檔存放位置(-o): gdb使用 lgdb使用: l指令:gdb /usr/src/linux/vmlinux /proc/kcore l(gdb) x/i lEx: (gdb) x/20i 0xc8002060 l參考網址:http:/es-sun2.fernuni-hagen.de/cgi- bin/info2html?(gdb)Top 其他核心除錯器 lkdb lkgdb 核心的計時間隔 l中斷CPU暫停目前工作,然後執行ISR來處理中斷.(CH9) l計時器中斷,固定間隔觸發的中斷事件,核心依據HZ(定義 在)的值來設定間隔長度,硬體平台不同 ,值也不同. l每次發生計時器中斷,jiffies變數的值就會被遞增一次, 宣告在,型別為unsigned long volatile,核心確保溢位之後還能正確運作,不必擔心,只 須注意. 處理器特有的暫存器 l量測指令本身執行時間 unsigned long ini, end; rdtscl(ini); rdtscl(end); printk(“time lapse: %lin”,end-ini); l與平台無關的函式用來替代rdstc() #include cycles_t get_cycles(void); /無時脈計數,則回傳 永0,32bit l如何內插組語指令(iniline assembly) for MIPS #define rdtscl (dest) _asm_ _volatile_(“mfc0 %0,$9; nop” : “=r” (dest) l內插組語的語法相當有威力,但是有點複雜,特別是在那 些會限定暫存器用途的平台上(x86系列).完整語法請參 考gcc的說明文件. 取得目前時間(1/2) ljiffies從開機到至今的時間,與驅動程式生命期無 關,也不可能跨越開關機時間. l驅動程式可利用jiffies的現值來估算兩事件之間的 間隔時間,如mouse l驅動程式不需要知道牆鐘時刻(wall-clock time), 若真的需要靠自己處理當時的時刻 ,do_gettimeofday()或許可派上用場. l此函式並非直接告知今天是星期幾,而是將一般的秒 與微秒填入一個struct timeval,原型如下 #include void do_gettimeofday(struct timeval *tv); 取得目前時間(2/2) l從xtime變數同樣也可取得目前時刻,但這是不被 鼓勵的行為,因為無法連動取得timevalue,結構 內的tv_sec與tv_usec欄位值,除非暫停掉中斷. l不太講求精準度,2.2版核心提供一個快又安全的 函式來取得目前時刻: void get_fast_time(struct timeval *tv); l範例 jit(Just In Time)模組,他不會產生裝置 節點,而是直接將它取得的時刻資訊透過 /proc/currentime傳到user-space. cat /proc/currentime /proc/currentime /proc/currentime 延遲執行 l延遲通常是為了讓硬體有足夠充裕的時間 完成某些工作 l需要考慮的重點之一,是延遲時間是否超過一 個時脈單位 l較長的延遲,可以利用系統時鐘來計時,較短 的延遲,則通常以軟體迴圈來應付 長期延遲(1/4) l最簡單也是最蠢的做法,稱為忙著等待(busy waiting): unsigned long j = jiffies + jit_delay * HZ; while (jiffies void udelay (unsigned long usecs); /inline void mdelay (unsigned long msecs); ludelay()以當地系統的BogoMips(開機所計算出的系 統常數)值來決定迴圈的圈數,其值大約是CPU時脈數 的兩倍左右. lmdelay()是含有udelay()的迴圈所構成 l兩者都是busy-waiting函式,因此除非沒有其它辦法 ,否則應該儘量避免使用mdelay() 核心內建的工作佇列 l要延遲特定工作的開始執行時間,最簡便的辦法是利用核心 所維護的佇列.其中有三個可供驅動程式運用(宣告在 ),分別是: 排程器佇列(scheduler queue) 在行程環境內運作,所以限制較寬鬆.2.4是以專用的 kernel thread來執行的,稱為keventd,並且必須透過 schedule_task()來存取. 計時器佇列(tq_timer) 由計時器時脈訊號觸發的佇列.必須遵守中斷模式規則 即期佇列(tq_immediate) 可能再系統呼叫返回之前或是排程器介入時,看何者先 到.會在中斷期被消化掉. kmalloc的來龍去脈(1/3) l定義在,其函式的速度很快,因為它不會清理所 配置到的記憶體. lvoid *kmalloc(size_t size, int flags); lsize引數: l核心只能以頁為單位來整塊配置,並且採用一種特殊的分頁配置 技術,以充分利用系統的RAM. lLinux處理記憶體配置的方法,是製作一組記憶體物件集散區,同 一集散區的記憶物件都有固定容量. l核心只能配置幾種預定容量的位元組陣列,如果沒有剛好你要的 容量,你就必須選擇大一級的容量. l如你要配置一個2000bytes的緩衝區,最好選擇2000而不要選擇 2048. lkmalloc()一次可配置的容量上限是128KBytes. kmalloc的來龍去脈(2/3) lflags引數: lGFP_KERNEL 平常的核心記憶體配置,配置到的記憶空間屬於 current行程.有可能休眠. lGFP_BUFFER 用於管理快取暫存區,容許配置者可以休眠.不同 於GFP_KERNEL之處,在於它是藉由出清髒頁到磁碟, 以換取可用的記憶空間. lGFP_ATOMIC 供interrupt handler以及任何在行程外部的程式 來配置記憶體.絕不會休眠. kmalloc的來龍去脈(3/3) lGFP_USER 代替user-process配置記憶體,有可能休眠,而且 是屬於低優先度的要求. lGFP_HIGHUSER 類似GFP_USER,但是從高址劃分區取得可用空間. l_GFP_DMA 配置可供DMA傳輸使用的記憶體.可搭配 GFP_KERNEL或GFP_ATOMIC的其中之一 l_GFP_HIGHMEM 要求配置高址劃分區.在沒有高址劃分區的平台上 ,此旗標沒有作用.它是GFP_HIGHUSER遮罩的一部分, 除此之外幾乎沒有作用. 前瞻快取(Lookaside Caches) (1/2) l驅動程式經常需要一次又一次配置許多同樣大小的物件,為此核 心提供一些特殊的集散區,稱之為前瞻快取. lLinux記憶快取的型別為kmem_cache_t,可藉由呼叫 kmem_cache_create()來產生: kmem_cache_t *kmem_cache_create(const char *name, size_t size, size_t offset, unsigned long flags, void (*constructor)(void *,kmem_cache_t *,unsigned long flags), void (*destructor)(void *,kmem_cache_t *,unsigned long flags); name: 同時代表函式與快取的符號,名稱最長不得超過19個 字元(包含0在內). offset: 第一個物件在記憶頁裡的起始位置,用來確保配置 到的物件一定放在特定的對齊位置上,用0核心會幫你完成. 前瞻快取(Lookaside Caches) (2/2) flags: SLAB_NO_REAP: 保護快取不因系統記憶不足而縮減容量.通常不需要設立. SLAB_HWCACHE_ALIGN: 要求每個資料物件都要對齊一條快取線. SLAB_CACHE_DMA: 要求每個資料物件都配置在DMA可存取的記憶體. l物件快取產生之後,呼叫kmem_cache_alloc(kmem_*cache, int flags) 來配置物件 cache:先前建立的快取 flags:和kmalloc()相同 l使用void kmem_cache_free(kmem_cache_t *cache, const void *obj)釋放物件 l使用int kmem_cache_destory(kmem_cache_t *cache)釋放空間 get_free_page( )與其相關函式(1/3) l如果模組需要比較大塊的記憶體,通常最好使用分頁配置技術. l下列函式用來配置記憶頁: get_free_page() 回傳一指向新記憶頁的指標,內容全清為0. _get_free_page() 類似get_free_page(),但不清除內容. _get_free_pages() 配置一個跨頁的連續記憶區,傳回指向記憶區第一位元組的指 標.內容不被清除. _get_dma_pages() 類似_get_free_pages(),但保證配置到的記憶體可作為DMA 用途.在Linux2.2之後,使用_get_free_pages()搭配_GFP_DMA 也可達到相同效果. get_free_page( )與其相關函式(2/3) l上述原型如下 l這裡的flags,意義與kmalloc()一樣,而且同樣以 GFP_KERNEL或GFP_ATOMIC最常用,頂多是在搭配 _GFP_DMA或_GFP_HIGHMEM. lorder是你要配置或釋放頁數的2的對數.如值為0則 為三頁;8頁則其值為3. l在Linux2.0,order值的上限是5,Linux2.2之後最高 值為9.無論如何,階數越大,配置失敗的機會就越高. unsigned long get_free_page(int flags); unsigned long _get_free_page(int flags); unsigned long _get_free_pages(int flags, unsigned long order); unsigned long _get_dma_pages(int flags, unsigned long order); get_free_page( )與其相關函式(3/3) l當程式不再需要先前配置的記憶頁時,就應該以下列 函式將它們釋回. void free_pages (unsigned long addr, unsigned long order); l如果你釋放的頁數,不等於先前要求配置的頁數,則 記憶表將會損毀,而系統很快就會遇到大麻煩. l由於核心會盡力滿足配置的要求,所以,要把系統搞 垮,使其反應遲鈍,時在是輕而易舉 只要配置夠 多的記憶體就成了.(癱瘓服務 DoS的原理) vmalloc() 與其相關函式(1/3) l另一種的記憶體配置函式,這是讓你可以在虛擬位址空間 (virtual address space)配置一個連續記憶區的 vmalloc()函式. l請注意,構成連續虛擬位址的實體記憶體,不見得是連續 的,而只是被核心是為一段連續的位址範圍而已. lvmalloc()與其親戚ioremap()(不算是配置函式)的原型 如下: #include void *vmalloc(unsigned long size); void vfree(void *addr); void *ioremap(unsigned long offset, unsigned long size); void iounmap(void *addr); vmalloc() 與其相關函式(2/3) lkmalloc()和get_free_pages()所傳的位址,也是虛擬位址,而非 真正用於定位實際記憶晶片的實體位址. lCPU內部的MMU會自動將虛擬位址轉換成實體位址. lvmalloc()和ioremap所用的位址範圍,則是完全靠人工虛構出來 的,每一次的配置動作,都必須適當修改分頁表,才能建構出(虛擬 的)記憶區. l它們之間的差異在某些平台上(x86),vmalloc()傳回的位址,只是 高於kmalloc所傳回的位址.vmalloc()的位址範圍從 VMALLOC_START到VMALLOC_END,定義在 l利用vmalloc()配置的位址,不能用於CPU之外(如DMA),因為只有 MMU才能處理這類位址. 所以可使用vmalloc()的正確時機,是當 你需要配置一大塊僅供軟體使用的連續緩衝區時. vmalloc() 與其相關函式(3/3) lioremap()也會建構新的分頁表,和vmalloc()相同;不同的是它實 際上並不配置任何記憶體.它所傳回的值,是一個特殊的虛擬位址 ,可用來存取指定的實體位址範圍. lioremap()最有用之處,是可用來將PCI緩衝區的(實體)位址映射 到kernel-space(虛擬)位址.例如,讓驅動程式用來存取PCI顯示 卡的視訊記憶體. l基於相容性考量,不要將ioremap()傳回的位址當成記憶體的指標 ,就是不要直接存取該位址.這個工作應交給readb()和CH8的I/O 函式來達成.(Alpha沒有這項能力,和PCI不相容) lvmalloc()能配置的容量,以及ioremap()可映射到CPU位址空間的 記憶體範圍,可說是幾乎沒有限制.兩者都是分頁導向技術(透過 修改分頁表來達成要求). lvmalloc()有個小缺點,它不能用於中斷期,因為它內部使用了 kmalloc(GFP_KERNEL)來取得分頁表的儲存空間,因此有休眠的可 能. I/O 埠 v.s I/O 記憶體 lI/O 暫存器 /宣告一個 memory barrier / l#include void rmb (void); /保證在barrier前的read動作都完 成/ void wmb (void);/保證在barrier前的write動作都完 成/ void mb (void); P.S memory barrier會影響效率,真正需要才使用 Memory barrier的用法 lwritel (dev-registers.addr, io_destination_address); writel (dev-registers.size, io_size); writel (dev-registers.operation, DEV_READ); wmb (); writel (dev-registers.control, DEV_GO); 確認所有動作 皆完成 write memory barrier 使用I/O 埠(1/3) l驅動程式用I/O埠前,必須先配置他們,才可讀or寫埠 l定義用來存取I/O埠的內插函式 l#include int check_region(unsigned long start,unsigned long len); struct resource *request_region(unsigned long start,unsigned long len,char *name); void release_region(unsigned long start,unsigned long len); 使用I/O 埠(2/3) lFor 1 byte 埠 unsigned inb(unsigned port); void outb(unsigned char byte,unsigned port); lFor 16bits埠 (word寬度) unsigned inw(unsigned port); void outw(unsigned short word,unsigned port); lFor 32bits埠 (longword寬度) unsigned inl(unsigned port); void outl(unsigned longword,unsigned port); 使用I/O 埠(3/3) lString instruction 有些processor 有提供字串指令,讓一連串同大小的 bytes,words,long 讀or寫到I/O埠, 達到迴圈效果 l暫停I/O 舊裝置如ISA跟不上處理器的傳輸速度,需要暫停函式, 如: inb_p() ,outb_p() l平台相依性 I/O指令和處理器有高度相依性,必須針對特定平台 (ex: Alpha ,ARM, PowerPC, SPARC) 數位I/O 埠(1/2) l把值寫出到輸出埠,會被轉換成對應輸出腳位的電子信號 l每台PC 都有兩個並列埠,第一個介面從0X378開始;第二 個從0X278開始 l每個並列埠都有三個暫存器: 資料暫存器(bidirectional to pin2pin9) 狀態暫存器(read-only) 控制暫存器(output-only) l唯一與腳位信號無關:控制埠的 bit4 (0x10),可發出irq lSee figure below 數位I/O 埠(2/2) 使用I/O記憶體 lI/O記憶體只是類似RAM的特殊區域,不同的是處理器可從 其匯流排存取特定硬體裝置 lDriver必須要求kernel將實體位址搬入driver的可見範 圍,所以要先呼叫ioremap() l直接映射記憶體 ex: PDA用的MIPS處理器,內有兩段位置範圍(各512 Mb)直接映射到實體位址,在此區MMU不會理會,也無 Cache. l軟體映射I/O記憶體 PCI裝置的位置是由系統軟體指派,每次開機都會不同 ,所以要用ioremap()將虛擬位址指向裝置 y0B3E6I9LdOgRjVmYp!t&w-z1C4G7JaMePhTkWnZr$u*x+A2E5H8KcNfQiUlXp#s%v)y0B3F6IaLdOgSjVmYq!t*w-z1D4G7JbMePhTkWoZr$u(x+A2E5H9KcNfRiUlXp#s&v)y0C3F6IaLdPgSjVnYq!t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlWo#r%v(y+B3E6H9LcOgRjUmYp!s&w)z1C4F7JaMdPhSkWnZq$u*x- A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w)z1C4G7JaMePhSkWnZr$u*x+A2D5H8KcNfQiUlXo#s%v)y0B3F6I9LdOgSjVmYq!t&w-z1D4G7JbMePhTkWoZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVnYq!t*w-z1D4G8JbMeQhTkWoZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D4G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRjUmXp!s&v)z0C4F7IaMdPgSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%v(y+B3E6H9LcOfRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$u*x- A2D5G8KbNfQiTlXo#r%v(y0B3E6I9LcOgRjVmYp!t&w)z1C4G7JaMePhSkWnZq$u*x+A2D5H8KbNfQiUlXo#s%v(y0B3F6I9LdOgRjVmYq!t&w-z1C4G7JbMePhTkWnZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVmYq!t*w-z1D4G7JbMeQhTkWoZr$u(x+B2E5H9KcNfRiUmXp#s&v)y0C3F7IaLdPgSjVnYq$t*w-A1D4G8JbNeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaMdPgSkVnYq$t*x-A1D5G8JbNeQiTlWo#r%u(y+B3E6H9LcOfRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$t*x- A2D5G8KbNeQiTlXo#r%v(y+B3E6I9LcOgRjUmYp!t&w)z1C4F7JaMePhSkWnZq$u*x+A2D5H8KbNfQiUlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w-z1C4G7JaMePhTkWnZr$u*x+A2E5H8KcNfQiUlXp#s%v)y0B3F6IaLdOgSjVmYq!t*w-z1D4G7JbMePhTkWoZr$u(x+A2E5H9KcNfRiUlXp#s&v)y0C3F6IaLdPgSjVnYq!t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjU!t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w- A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%v(y+B3E6H9LcOgRjUmYp!s&w)z1C4F7JaMdPhSkWnZq$u*x-A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LcOgRjVmYp!t&w)z1C4G7JaMePhSkWnZr$u*x+A2D5H8KcNfQiUlXo#s%v)y0B3F6I9LdOgSjVmYq!t&w-z1D4G7JbMePhTkWnZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVnYq!t*w-z1D4G8JbMeQhTkWoZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSjVnYq$t*w- A1D4G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRjUmXp!s&v)z0C4F7IaMdPgSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%u(y+B3E6H9LcOfRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$u*x-A2D5G8KbNfQiTlXo#r%v(y0B3E6I9LcOgRjVmYp!t&w)z1C4G7JaMePhSkWnZq$u*x+A2D5H8KbNfQiUlXo#s%v(y0B3F6I9LdOgRjVmYq!t&w-z1C4G7JbMePhTkWnZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0B3F6IaLdOgSjVmYq!t*w-z1D4G7JbMeQhTkWoZr$u(x+B2E5H9KcNfRiUmXp#s&v)y0C3F7IaLdPgSjVnYq$t*w- A1D4G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaMdPgSkVnYq$t*x-A1D5G8JbNeQiXp#s&v)y0C3F7IaLdPgSjVnYq!t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaMdPgSkVnYq$t*x-A1D5G8JbNeQiTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlXo#r%v(y+B3E6I9LcOgRjUmY*x-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlXo#r%v(y+B3E6I9LcOgRjUmYp!s&w)z1C4F7JaMdPhSkWnZq$u*x- A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w-z1C4G7JaMePhTkWnZr$u*x+A2E5H8KcNfQiUlXo#s%v)y0B3F6I9PhSkWnZq$u*x-A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w-z1C4G7JaMePhSkWnZr$u*x+A2D5H8KcN
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025版广东土地估价师协会职业培训服务合同
- 2025版数字媒体广告资源包租赁合同模板
- 二零二五年度信息技术培训与咨询服务协议
- 二零二五版房产收购项目合作续约合同样本
- 二零二五年度商业地产项目场地转租及投资回报协议
- 二零二五版建筑信息模型(BIM)技术应用合同意向书
- 2025版环保材料消费贷款担保合同
- 2025版城市综合体房地产评估报告合同
- 二零二五版德汉翻译及国际文化交流项目合同
- 二零二五家政洗衣店市场拓展合作协议
- GB/T 748-2005抗硫酸盐硅酸盐水泥
- GB 15763.1-2001建筑用安全玻璃防火玻璃
- 走好群众路线-做好群众工作(黄相怀)课件
- 民间文学(全套课件)
- 专升本00465心理卫生与心理辅导历年试题题库(考试必备)
- 既有重载铁路无缝线路改造及运维技术探索
- 2022年教师副高职称评答辩范文(七篇)
- 高压罗茨风机选型参数表
- 金融控股公司协同模式与实务分析
- 2021-2022年湖南省长沙市第一中学高一(上)入学考试物理试题(解析版)
- 轴类零件的设计ppt课件
评论
0/150
提交评论