欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载
     

    《核心模组》PPT课件.ppt

    • 资源ID:5584779       资源大小:251KB        全文页数:72页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    《核心模组》PPT课件.ppt

    Driver,核心模組 vs 應用程式,應用程式啟動後從頭到尾都只執行同一件任務.模組被載入核心之後必須先向核心註冊它自己.init_module()函式(模組的入口點)任務是將模組的功能準備好 以便事後可被invocation(調用).cleanup_module()在模組離開之前必須要被呼叫.模組只能與核心連結所以模組只能呼叫核心所提供的程式 ex:printfk().由於上一點,模組的原始碼不能引入一般的標頭檔.有關核心相關事物放在/usr/src/linux下的 include/linux 與 include/asm/目錄下的標頭檔.,使用者空間與核心空間,模組存活在kernel space(核心空間)而應用程式存在user space(使用者空間).作業系統必須負責讓程式得以獨立運作並保護系統資源避免非授權的存取.由CPU來保護系統軟體所以CPU本身提供了不同層級的作業模式(operating modality).Unix系統提供兩個層級而現在CPU也至少有兩種層級,故Unix系統只使用最高與最低層級,Unix核心運作在最高層級(supervisor mode)應用程式運作在最低層級(user mode).execution mode:包括kernel-space 與user-space分別有各自的memory mapping(記憶體對應關係)的關係與各自的address space(定址空間).,insmod,載入 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移到 預先配置的核心空間.系統呼叫大略表:kernel/目錄執行 egrep“sys_.*)$”*.c,版本依存性,模組與連結對象核心息息相關每當升級何新版本時模組就必須再新版本核心下重新編譯一次.編譯器會在ELF(executable Linking and Format).的.modifo(chap 11)區定義_module_kernel_version符號insmod會依照此符號與當時的核心作比較.定義在.可使用insmod f來略過版本檢查.針對特定版本的核心來編譯模組必須引入該版本核心的標頭檔再Makefile定義一個KERNELDIR環境變數讓他指另一個不同的位置.,核心符號表,模組化驅動程式所需的核心全域項目(函式與變數)的位置都紀錄在符號表裡 可從/proc/ksyms取的此表.若模組能被順利載入核心,模組所釋放的符號也會成為核心符號的一部分.模組所釋出的符號可以被新模組使用新模組可以疊在其他模組之上.ex:msdos檔案系統得仰賴fat模組所釋出的符號,模組的生與死,init_module()會註冊模組所提供的任何facility(功能性).模組可以註冊許多不同類型的facility,對於每一個facility都有一個特定的核心函式來完成其註冊程序.傳給核心註冊函式的引數:facility註冊名稱,指標(指向此facility的資料結構).facility種類:序列阜,雜項裝置,/proc檔案,作業領域(executable domain),管制線路(line discipline).,Init_module的錯誤處置,註冊失敗:系統沒有足夠空間或某資源已被其他驅動程式佔用模組自己要負責回復(undo)到註冊失敗之前的狀態,如果init_module()在中途失敗,模組必須自己主動註銷(unregister)那些已經註冊成功的facility.不能藉由重新載入模組來重新註冊facility,也不太可能註銷他們,因為需要當初註冊所用的相同指標.使用goto解決.,卸載模組,使用rmmod可卸載(unload)沒用的模組.原理:rmmod觸發delete_module()system call,如果模組的用量為零,則delete_module()會呼叫模組本身的cleanup_module();否則回傳作錯誤代碼.cleanup_module()必須負責註銷該模組的每一項facility.,實際的初始化與清理函式,命名模組函式,須引入 module_init(my_init);module_exit(my_cleanup);my_init取代init_module(),my_cleanup取代cleanup_module();所以可使每個初始函式與清理函式都有自己專屬的名稱,以方便除錯.,資源的運用,大部分驅動程式的工作大概就在讀寫I/O port或I/O memory(統稱 I/O region)核心都應該保證驅動程式能獨占存取其I/O port以免受到其他驅動程式的干擾/proc/ioports與/proc/iomem檔案可取得以註冊的系統資源,User-space驅動程式(1/2),優點 可使用完整的c函式庫.可使用傳統的debugger.若user-space driver當掉,直接kill就可以.user-space記憶體可被“置換(swappable)”,而kernel-space不可能,因此較大的程式不會排擠其他程式所使用的RAM,除非此裝置正在使用.user-space driver也能容許目標裝置同時被多個行程所存取.,User-space驅動程式(2/2),缺點:在user-space內無法使用”中斷”.不能直接存取I/O memory.必須先呼叫ioperm()或iopl()才能存取I/O port.回應時間較緩慢,因為應用程式要傳輸資料給硬體而硬體也要回應應用程式(context switch)若驅動程式已被“置換(swap)”到磁碟上,那回應時間就更長了 大部分重要裝置不能在user-space上予以有效控制,ex:網路介面,I/O memory(1/3),int check_region(unsigned long start,unsigned long len);用來檢查某段範圍的I/O位址是否被佔用.struct resource*request_region(unsigned long start,unsigned long len,char*nam);要求註冊該位址區.若核心同意,此函式會回傳一個non-NULL指標.,I/O memory(2/3),void release_region(unsigned long start.unsigned long len);將取得的I/O 位址歸還給系統.,I/O memory(3/3),取得,釋放特定一段的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),驅動程式所需的某些參數會因系統而異,ex:I/O 位址,記憶區範圍有時候必須傳遞參數給驅動程式,才能幫助他找到目標裝置或啟動,關閉特定功能.對於某些裝置,如裝置品牌,型號等也有可能影響驅動程式的行為.將正確的參數傳遞給驅動程式(configuring),是驅動程式在初始化期間必須完成的工作.參數值可在載入期間由insmod或modprobe傳給模組,決定組態參數(2/4),modprobe可從一各組態檔(/etc/modules.conf)讀入參數值.使用者可在命令列指定參數值ex:#insmod skull skull_ival=666 skull_sval=“beast”在insmod能夠改變模組參數之前,模組本身必須以MODULE_PARM()巨集(定義在linux/module.h)宣告可被修改的參數.MODULE_PARM()需要兩個引數,一是變數名稱,二是變數型別.,決定組態參數(3/4),int skull_ival=0;char*skull_sval;MODULE_PARM(skull_ival,“I”);MODULE_PARM(skull_sval,“s”);參數型別有五種:b(1-byte),h(2-byte短整數),i(整數),l(長整數),s(字串).,決定組態參數(4/4),MODULE_PARM_DESC()巨集,可讓程式設計師用來描述模組參數的意義.static int skull_port_bse=0 x300;MODULE_PARM(skull_port_base,”i”);MODULE_DESC(skull_port_base,”skull I/O base(default 0 x300);可使用objdump,modinfo指令來檢視參數指令.,訊息除錯法(1/4),printk()函式通用的除錯技巧,對應用程式而言使用printf();對於核心程式而言則使用printk().printk()能讓你指定訊息的loglevel(等級),共分為八纇.定義在裡.KERN_EMERG:緊急訊息,出現在系統崩潰前.KERN_ALERT:危險通知,發生在需要立即採 取行動的事件.KERN_CRIT:嚴重狀況,涉及硬體或軟體故障,訊息除錯法(2/4),KERN_ERR:錯誤狀況回報,通常回報硬體上的困難.KERN_WARNING:緊急訊息,程度上不影響系統.NERN_NOTICE:通知,意料中會發生且值得注意的 狀況.KERN_INFO:資訊性訊息,driver在啟動階段所印出 的硬體資訊.KERN_DEBUG:供除錯用途的訊息.,訊息除錯法(3/4),上述代號展開後分別成為:,之類的字串,括弧內數字越低表示等級越高.ex:printk(KERN_DEBUG“HI”);不同等級的訊息會被輸出到不同的地點,有可能是目前的操控台(console)或者是某種文字終端機(Xterm視窗,Telnet或SSH連線).任何等值低於console_loglevel的變數訊息都會被顯示在操控台上(console).不過若系統上同時執行klogd與syslogd不管console_loglevel的值為何,所有核心訊息都會被加入/var/log/messages.,訊息除錯法(4/4),如果沒跑klogd,則訊息不會流入user-space,除非主動讀取/proc/kmsg.修改console_loglevel的值 使用sys_syslog()利用klogd的 c選項.本書範例:misc-progs/setlevel.c,2.1.31版本開始,可以直接透/proc/sys/kernel/printk檔案來修改或檢視console_levle的值.#echo 8/proc/sys/kernel/printk,核心訊息的輸出流程(1/2),printk()會將訊息寫入一個環型queue,長度為LOG_BUF_LEN(定義在kernel/printk.c),且喚醒 正在等待訊息的行程(使用syslog().正在讀取/proc/kmesg的行程.在環型queue被填滿時,printk()將會繞回原點,將新訊息覆蓋在最就訊息上,其優點:固定記憶體,既使沒跑日誌紀錄引擎(klogd,syslogd)也不至於消耗所有的記憶體.核心內部到處都可以直接呼叫printk().,核心訊息的輸出流程(2/2),klogd所取得的核心訊息會被轉交給syslogd,由它依據/etc/syslog.conf來決定如何處裡收到的訊息.若系統沒跑klogd,核心訊息將會一值留在環型佇列,直到有人讀取它或者是被新訊息蓋掉.若不希望driver所發出得訊息擾亂的系統的日誌檔,可以用-f選項來從新啟動klogd並將其訊息寫入特定檔案.,kernel,/proc/kmsg,klogd,/dev/log,syslogd,syslog.conf,查詢除錯法(1/6)(使用/proc檔案系統),/proc是靠軟體模擬出來的特殊檔案系統,並不實際存在於硬碟上,而是核心提供給user-space的資訊窗口.在proc/下的每一個檔案,接聯繫到核心內的專屬函式,這些函式在使用者讀取檔案時,及時產生檔案的內容.ex:以/proc/modules為例,當你讀取它時它會顯示目前載入哪些模組,但此檔案系統的長度都為0.,查詢除錯法(2/6)(使用/proc檔案系統),Linux許多系統工具,如ps,top,uptime等都是從/proc取得它們所需要的資訊.建立/proc檔案:driver必須製作一備查程式,讓它在檔案被存取時,及時供應資料,核心也會配置一記憶頁給它備查程式介面:int(*read_proc)(char*page,char*start,off_t offset,int count,int*eof,void*data);,read(),/proc,備查函式,記憶頁,User-space,查詢除錯法(3/6)(使用/proc檔案系統),page指標:指向核心預先配置的記憶頁*start與offset:若檔案超過一記憶頁大小,可利用分批傳輸的方式,先將*start指向page再利用offset指向下一各位元組.skcull程式中有對read_proc的實作:,查詢除錯法(4/6)(使用/proc檔案系統),定義好read_proc作業方式後,必須為它在/proc下設置一個入口點,使用create_proc_read_entry().若希望使用者能透過/proc/scullmem取得該函式提供的資料,則driver需宣告如下:,static void scull_create_proc()create_proc_read_entry(“scullmem”,0/*預設模式(0 x444)*/,NULL/*上層目錄(*proc_dir_entry)*/,scull_read_procmem,NULL/*提供給read_proc使用的資料*/);,/proc入口點名稱,檔案權限,入口點上層目錄,read_proc作業方法的指標,傳給read_proc的資料的指標,查詢除錯法(5/6)(使用/proc檔案系統),第三參數的說明:在/proc檔案系統下的每一個子目錄,都有各自 專屬的proc_dir_entry結構來描述.ex:描述/proc/driver子目錄的結構為 proc_root_driver,描述/proc/bus子目錄的結 構為proc_bus.若此引數設定為NULL代表入口點設置在/proc 目錄下.,查詢除錯法(6/6)(使用/proc檔案系統),在模組被載卸之前必須先移除相關的/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);,觀測除錯法,strace,檢驗位於kernel-space的程式碼.能顯示出由user-space程式所發出的所有system call.#strace ls/dev/dev/scull0,排除重大系統錯誤(1/2),除了監視,除錯技術,驅動程式可能還是意料之外的bug存在,嚴重可能造成system fault.fault(失誤)不等於panic(死當),失誤通常會摧毀目前的行程,系統本身能正常.若fault發生在process context之外,或是破壞系統的關鍵部分,即有可能早成panic.oops訊息:往往發生在不當的操作指標所引起,如dereference(提領)或者是誤用指標的值.,排除重大系統錯誤(2/2),page fault:在protect mode(保護模式)下,所使用的是virtual address(虛擬記憶體),藉由page table換算出physical address(實體位置),若程式提領一個無效指標,分頁機制則沒有辦法算出實體位置,因而發生page fault.若在user-space發生提領無效,後果頂多是無法”page in“該位址.若發生在kernel則迫使核心發出oops訊息.,Ksymoops用法,ksymoops用法:systme.map檔(-v)/usr/src/linux/system.map模組清單(-l):/proc/modules核心符號表(-k):/proc/ksyms映像檔(-v):模組object檔存放位置(-o):,gdb使用,gdb使用:指令:gdb/usr/src/linux/vmlinux/proc/kcore(gdb)x/i Ex:(gdb)x/20i 0 xc8002060參考網址:http:/es-sun2.fernuni-hagen.de/cgi-bin/info2html?(gdb)Top,其他核心除錯器,kdbkgdb,核心的計時間隔,中斷CPU暫停目前工作,然後執行ISR來處理中斷.(CH9)計時器中斷,固定間隔觸發的中斷事件,核心依據HZ(定義在)的值來設定間隔長度,硬體平台不同,值也不同.每次發生計時器中斷,jiffies變數的值就會被遞增一次,宣告在,型別為unsigned long volatile,核心確保溢位之後還能正確運作,不必擔心,只須注意.,處理器特有的暫存器,量測指令本身執行時間 unsigned long ini,end;rdtscl(ini);rdtscl(end);printk(“time lapse:%lin”,end-ini);與平台無關的函式用來替代rdstc()#include cycles_t get_cycles(void);/無時脈計數,則回傳永0,32bit如何內插組語指令(iniline assembly)for MIPS#define rdtscl(dest)_asm_ _volatile_(“mfc0%0,$9;nop”:“=r”(dest)內插組語的語法相當有威力,但是有點複雜,特別是在那些會限定暫存器用途的平台上(x86系列).完整語法請參考gcc的說明文件.,取得目前時間(1/2),jiffies從開機到至今的時間,與驅動程式生命期無關,也不可能跨越開關機時間.驅動程式可利用jiffies的現值來估算兩事件之間的間隔時間,如mouse驅動程式不需要知道牆鐘時刻(wall-clock time),若真的需要靠自己處理當時的時刻,do_gettimeofday()或許可派上用場.此函式並非直接告知今天是星期幾,而是將一般的秒與微秒填入一個struct timeval,原型如下#include void do_gettimeofday(struct timeval*tv);,取得目前時間(2/2),從xtime變數同樣也可取得目前時刻,但這是不被鼓勵的行為,因為無法連動取得timevalue,結構內的tv_sec與tv_usec欄位值,除非暫停掉中斷.不太講求精準度,2.2版核心提供一個快又安全的函式來取得目前時刻:void get_fast_time(struct timeval*tv);範例 jit(Just In Time)模組,他不會產生裝置節點,而是直接將它取得的時刻資訊透過/proc/currentime傳到user-space.,cat/proc/currentime/proc/currentime/proc/currentime,延遲執行,延遲通常是為了讓硬體有足夠充裕的時間完成某些工作需要考慮的重點之一,是延遲時間是否超過一個時脈單位較長的延遲,可以利用系統時鐘來計時,較短的延遲,則通常以軟體迴圈來應付,長期延遲(1/4),最簡單也是最蠢的做法,稱為忙著等待(busy waiting):unsigned long j=jiffies+jit_delay*HZ;while(jiffies j)/*發呆*/;因為jiffies是volatile變數,使得C編譯器會落實每次的讀取動作(不使用快取技術).在延遲期間,處理器是被鎖死的,因為這是核心裡的回圈,排程器不會岔斷進入核心行程.若中斷失效時進入迴圈,jiffies不會更新,迴圈無法終止,只能使用reset按鈕.,長期延遲(2/4),busy-wait範例,讀取/proc/jitbusy,每當它的read作業方法被呼叫一次,其內部的忙碌迴圈就會延遲一秒.如果使用dd if=/proc/jitbusy bs=1命令,就可以看到每秒讀出一個字元的效果.這種做法會嚴重拖累系統效能,因為其他行程每隔一秒才有機會執行一次,比較合理的做法是:while(jiffies j)schedule();但還不夠理想,倘若它是整個系統上唯一的可跑行程,它真的會動作(呼叫schedule(),然後立刻被排程器選中,然後再呼叫schedule()所以說,機器負載程度將至少等於1,而idle行程將沒機會上線.(省電 降溫 生命年)若在一個非常忙碌的系統上,呼叫排程器的做法,反而有可能造成驅動程式等待了超過原本預期的時間.,time cat/proc/jitsched,長期延遲(3/4),排程迴圈提供一個觀測驅動程式工作程序的速成工具.(printk()之後一點點延遲,讓klogd有機會盡忠職守,以免不知如何死當)最佳的延遲方式,是要求核心代勞,核心提供兩種執行短程延遲的機制,看你的驅動程式是否要等待其他事件而定.sleep_on_timeout(wait_queue_head_t*q,unsigned long timeout);interruptible_sleep_on_timeout(wait_queue_head_t*q,unsigned long timeout);兩種版本都會讓行程待在指定的待命佇列裡休眠,但一定會在指定期限內返回.timeout值是要等待的jiffies個數,而非jiffies絕對值.,長期延遲(4/4),範例/proc/jitqueue wait_queue_head_t wait;init_waitqueue_head(但實際延遲時間,有可能略為超過你原本預期的時間.,time cat/proc/jitqueue,time cat/proc/jitself,短期延遲,在計算非常短暫的延遲,jiffies無法達成,所以核心提供udelay()和mdelay()函式,原型如下:#include void udelay(unsigned long usecs);/inline void mdelay(unsigned long msecs);udelay()以當地系統的BogoMips(開機所計算出的系統常數)值來決定迴圈的圈數,其值大約是CPU時脈數的兩倍左右.mdelay()是含有udelay()的迴圈所構成兩者都是busy-waiting函式,因此除非沒有其它辦法,否則應該儘量避免使用mdelay(),核心內建的工作佇列,要延遲特定工作的開始執行時間,最簡便的辦法是利用核心所維護的佇列.其中有三個可供驅動程式運用(宣告在),分別是:排程器佇列(scheduler queue)在行程環境內運作,所以限制較寬鬆.2.4是以專用的 kernel thread來執行的,稱為keventd,並且必須透過 schedule_task()來存取.計時器佇列(tq_timer)由計時器時脈訊號觸發的佇列.必須遵守中斷模式規則 即期佇列(tq_immediate)可能再系統呼叫返回之前或是排程器介入時,看何者先 到.會在中斷期被消化掉.,kmalloc的來龍去脈(1/3),定義在,其函式的速度很快,因為它不會清理所配置到的記憶體.void*kmalloc(size_t size,int flags);size引數:核心只能以頁為單位來整塊配置,並且採用一種特殊的分頁配置技術,以充分利用系統的RAM.Linux處理記憶體配置的方法,是製作一組記憶體物件集散區,同一集散區的記憶物件都有固定容量.核心只能配置幾種預定容量的位元組陣列,如果沒有剛好你要的容量,你就必須選擇大一級的容量.如你要配置一個2000bytes的緩衝區,最好選擇2000而不要選擇2048.kmalloc()一次可配置的容量上限是128KBytes.,kmalloc的來龍去脈(2/3),flags引數:GFP_KERNEL 平常的核心記憶體配置,配置到的記憶空間屬於current行程.有可能休眠.GFP_BUFFER 用於管理快取暫存區,容許配置者可以休眠.不同於GFP_KERNEL之處,在於它是藉由出清髒頁到磁碟,以換取可用的記憶空間.GFP_ATOMIC 供interrupt handler以及任何在行程外部的程式來配置記憶體.絕不會休眠.,kmalloc的來龍去脈(3/3),GFP_USER 代替user-process配置記憶體,有可能休眠,而且是屬於低優先度的要求.GFP_HIGHUSER 類似GFP_USER,但是從高址劃分區取得可用空間._GFP_DMA 配置可供DMA傳輸使用的記憶體.可搭配GFP_KERNEL或GFP_ATOMIC的其中之一_GFP_HIGHMEM 要求配置高址劃分區.在沒有高址劃分區的平台上,此旗標沒有作用.它是GFP_HIGHUSER遮罩的一部分,除此之外幾乎沒有作用.,前瞻快取(Lookaside Caches)(1/2),驅動程式經常需要一次又一次配置許多同樣大小的物件,為此核心提供一些特殊的集散區,稱之為前瞻快取.Linux記憶快取的型別為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可存取的記憶體.物件快取產生之後,呼叫kmem_cache_alloc(kmem_*cache,int flags)來配置物件 cache:先前建立的快取 flags:和kmalloc()相同使用void kmem_cache_free(kmem_cache_t*cache,const void*obj)釋放物件使用int kmem_cache_destory(kmem_cache_t*cache)釋放空間,get_free_page()與其相關函式(1/3),如果模組需要比較大塊的記憶體,通常最好使用分頁配置技術.下列函式用來配置記憶頁: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),上述原型如下這裡的flags,意義與kmalloc()一樣,而且同樣以GFP_KERNEL或GFP_ATOMIC最常用,頂多是在搭配_GFP_DMA或_GFP_HIGHMEM.order是你要配置或釋放頁數的2的對數.如值為0則為三頁;8頁則其值為3.在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),當程式不再需要先前配置的記憶頁時,就應該以下列函式將它們釋回.void free_pages(unsigned long addr,unsigned long order);如果你釋放的頁數,不等於先前要求配置的頁數,則記憶表將會損毀,而系統很快就會遇到大麻煩.由於核心會盡力滿足配置的要求,所以,要把系統搞垮,使其反應遲鈍,時在是輕而易舉 只要配置夠多的記憶體就成了.(癱瘓服務 DoS的原理),vmalloc()與其相關函式(1/3),另一種的記憶體配置函式,這是讓你可以在虛擬位址空間(virtual address space)配置一個連續記憶區的vmalloc()函式.請注意,構成連續虛擬位址的實體記憶體,不見得是連續的,而只是被核心是為一段連續的位址範圍而已.vmalloc()與其親戚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),kmalloc()和get_free_pages()所傳的位址,也是虛擬位址,而非真正用於定位實際記憶晶片的實體位址.CPU內部的MMU會自動將虛擬位址轉換成實體位址.vmalloc()和ioremap所用的位址範圍,則是完全靠人工虛構出來的,每一次的配置動作,都必須適當修改分頁表,才能建構出(虛擬的)記憶區.它們之間的差異在某些平台上(x86),vmalloc()傳回的位址,只是高於kmalloc所傳回的位址.vmalloc()的位址範圍從VMALLOC_START到VMALLOC_END,定義在利用vmalloc()配置的位址,不能用於CPU之外(如DMA),因為只有MMU才能處理這類位址.所以可使用vmalloc()的正確時機,是當你需要配置一大塊僅供軟體使用的連續緩衝區時.,vmalloc()與其相關函式(3/3),ioremap()也會建構新的分頁表,和vmalloc()相同;不同的是它實際上並不配置任何記憶體.它所傳回的值,是一個特殊的虛擬位址,可用來存取指定的實體位址範圍.ioremap()最有用之處,是可用來將PCI緩衝區的(實體)位址映射到kernel-space(虛擬)位址.例如,讓驅動程式用來存取PCI顯示卡的視訊記憶體.基於相容性考量,不要將ioremap()傳回的位址當成記憶體的指標,就是不要直接存取該位址.這個工作應交給readb()和CH8的I/O函式來達成.(Alpha沒有這項能力,和PCI不相容)vmalloc()能配置的容量,以及ioremap()可映射到CPU位址空間的記憶體範圍,可說是幾乎沒有限制.兩者都是分頁導向技術(透過修改分頁表來達成要求).vmalloc()有個小缺點,它不能用於中斷期,因為它內部使用了kmalloc(GFP_KERNEL)來取得分頁表的儲存空間,因此有休眠的可能.,I/O 埠 v.s I/O 記憶體,I/O 暫存器&傳統記憶體(RAM)最大差別:I/O 操作有副作用,記憶體操作沒有記憶體存取速度對CPU 效能影響致為關鍵(ex:Cache,重新安排read/write 指令順序)for 傳統記憶體:最佳化存取速度是有益的 for I/O暫存器:干擾到I/O指令的副作用,可能發生錯誤 Solution:設 memory barrier,讓compiler知道這段程式 不要最佳化,Memory barrier,#include void barrier(void);/宣告一個 memory barrier/#include void rmb(void);/保證在barrier前的read動作都完成/void wmb(void);/保證在barrier前的write動作都完成/void mb(void);P.S memory barrier會影響效率,真正需要才使用,Memory barrier的用法,writel(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),驅動程式用I/O埠前,必須先配置他們,才可讀or寫埠定義用來存取I/O埠的內插函式#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),For 1 byte 埠 unsigned inb(unsigned port);void outb(unsigned char byte,unsigned port);For 16bits埠(word寬度)unsigned inw(unsigned port);void outw(unsigned short word,unsigned port);For 32bits埠(longword寬度)unsigned inl(unsigned port);void outl(unsigned longword,unsigned port);,使用I/O 埠(3/3),String instruction 有些processor 有提供字串指令,讓一連串同大小的bytes,words,long 讀or寫到I/O埠,達到迴圈效果暫停I/O 舊裝置如ISA跟不上處理器的傳輸速度,需要暫停函式,如:inb_p(),outb_p()

    注意事项

    本文(《核心模组》PPT课件.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开