版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
嵌入式Linux驅(qū)動開發(fā)及內(nèi)核原理內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存硬件通訊塊設(shè)備驅(qū)動中斷處理內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動設(shè)備驅(qū)動簡介
驅(qū)動是什么Driverisasoftwarelayerthatliesbetweentheapplicationsandtheactualdevice驅(qū)動程序的角色提供機(jī)制(方法),而不是策略(怎么用)隱藏在UNIX中的哲學(xué)mechanism:Whatcapabilitiesareprovided.policy:Howthesecapabilitiescanbeused.Kernel的作用Kernel可劃分為下列功能單元進(jìn)程管理:進(jìn)程調(diào)度,資源分配,進(jìn)程間通信.內(nèi)存管理:其實(shí)也算是資源分配的一部分文件系統(tǒng):管理,組織物理媒介上數(shù)據(jù)的方法設(shè)備控制:設(shè)備驅(qū)動(linux驅(qū)動開發(fā)所關(guān)注的)網(wǎng)絡(luò):實(shí)質(zhì)上是進(jìn)程間通信.但它不局限于一個(gè)特定的進(jìn)程.它關(guān)注收/發(fā)packets,路由,地址解析...
Kernel的結(jié)構(gòu)模塊可加載模塊(lodablemodules)module:可實(shí)時(shí)加載到內(nèi)核中的代碼,它可動態(tài)連接到內(nèi)核(insmod,rmmod)設(shè)備驅(qū)動就是module的代表,但module還包括文件系統(tǒng)等等.
設(shè)備和模塊的分類模塊分為這些類型,每種類型的模塊驅(qū)動對應(yīng)類型的設(shè)備charactermodule,blockmodule,networkinterfaceothermodule
字符設(shè)備和塊設(shè)備字符設(shè)備:以字節(jié)流的形式被訪問的設(shè)備。e.g:/dev/console:文本控制臺./dev/ttyS0:串口它通過文件系統(tǒng)節(jié)點(diǎn)被訪問.e.g:/dev/tty1,/dev/lp0字符設(shè)備與一般文件(regularfile)的區(qū)別可以在一般文件中前后移動(lseek),但只能順序訪問字符設(shè)備.當(dāng)然,也有特例:framegrabbers.塊設(shè)備:能支持文件系統(tǒng)的設(shè)備傳統(tǒng)的UNIX:只能以block(512B)為單位訪問塊設(shè)備 Linux:能以訪問字符設(shè)備的方式訪問塊設(shè)備,即以字節(jié)文單位訪問塊設(shè)備.Linux中字符設(shè)備與塊設(shè)備的區(qū)別內(nèi)核內(nèi)部對數(shù)據(jù)的組織和管理不同,對驅(qū)動開發(fā)者來說透明接口不同:使用兩套不同的interface網(wǎng)絡(luò)設(shè)備網(wǎng)絡(luò)接口:能與其他主機(jī)通信的設(shè)備它可以是硬件設(shè)備,也可以是軟件設(shè)備,比如lo.(參考TCP/IP詳解p26)網(wǎng)絡(luò)接口只管收發(fā)數(shù)據(jù)包,而不管這些數(shù)據(jù)包被什么協(xié)議所使用不同于字符設(shè)備和塊設(shè)備,網(wǎng)絡(luò)接口沒有對應(yīng)的文件系統(tǒng)節(jié)點(diǎn).雖然可以通過類似eth0這樣的"文件名"來訪問網(wǎng)絡(luò)接口,但文件系統(tǒng)節(jié)點(diǎn)中卻沒有針對網(wǎng)絡(luò)接口的節(jié)點(diǎn)內(nèi)核與網(wǎng)絡(luò)接口之間的通信也不同于內(nèi)核與字符/塊設(shè)備之間的通信(read,write),它們之間使用特定的傳輸數(shù)據(jù)包的函數(shù)調(diào)用其他設(shè)備也有一些module不能嚴(yán)格地劃分類型.USBmodule:它工作在內(nèi)核的USB子系統(tǒng)之上實(shí)際的USB設(shè)備可以是字符設(shè)備,塊設(shè)備,也可以是網(wǎng)絡(luò)接口在設(shè)備驅(qū)動之外,別的功能,不論硬件和軟件,在內(nèi)核中都是模塊化的例如文件系統(tǒng)內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動建立和運(yùn)行模塊建立開發(fā)環(huán)境ldd3例子開發(fā)環(huán)境linux驅(qū)動開發(fā)需要預(yù)先安裝內(nèi)核源碼源碼需要從官方下載或者其他發(fā)行版的官方下載直接解壓到/usr/src目錄下版本影響內(nèi)核官方版本注意注意發(fā)行版的內(nèi)部版本最新內(nèi)核版本linux2.6.20/21工作隊(duì)列接口變化小版本變動不會對驅(qū)動的架構(gòu)造成太大影響對于不同發(fā)行版,不同內(nèi)核版本要做少量移植和測試內(nèi)核模塊VS應(yīng)用程序執(zhí)行機(jī)制不同模塊初始化模塊退出類似事件編程使用庫不一樣無法使用標(biāo)準(zhǔn)庫只能調(diào)用內(nèi)核提供的函數(shù)用戶空間VS內(nèi)核空間用戶空間VS內(nèi)核空間應(yīng)用程序運(yùn)行在用戶空間設(shè)備模塊運(yùn)行在內(nèi)核空間運(yùn)行模式不一樣內(nèi)存地址映射也不一樣用戶空間和內(nèi)核空間的轉(zhuǎn)換可能發(fā)生在進(jìn)程中的系統(tǒng)調(diào)用時(shí)或者硬件中斷系統(tǒng)調(diào)用雖然在內(nèi)核中執(zhí)行,但是依然是在進(jìn)程的上下文中進(jìn)行的,所以可以訪問到進(jìn)程中的數(shù)據(jù)。中斷處理和進(jìn)程是異步的了,而且不和任何進(jìn)程有關(guān)系模塊跨越兩個(gè)空間,有兩個(gè)觸發(fā)入口一些函數(shù)作為系統(tǒng)調(diào)用的一部分執(zhí)行一些函數(shù)負(fù)責(zé)中斷處理內(nèi)核中的并發(fā)應(yīng)用程序很多時(shí)候是按照順序來執(zhí)行的內(nèi)核處于并發(fā)的執(zhí)行環(huán)境當(dāng)中內(nèi)核當(dāng)中有并發(fā)的進(jìn)程中斷需要響應(yīng)和處理內(nèi)核中的服務(wù)也在運(yùn)行對稱多處理器導(dǎo)致并行模塊的加載卸載和查看加載使用insmod卸載使用rmmod查看使用lsmod模塊代碼staticint__initinitialization_function(void){
/*initializationcodehere*/}module_init(initialization_function);模塊代碼staticvoid__exitcleanup_function(void){
/*Cleanupcodehere*/}module_exit(cleanup_function);如何處理加載中的失敗int__initmy_init_function(void){interr;/*registrationtakesapointerandaname*/err=register_this(ptr1,"skull");if(err)gotofail_this;err=register_that(ptr2,"skull");if(err)gotofail_that;err=register_those(ptr3,"skull");if(err)gotofail_those;return0;/*success*/fail_those:unregister_that(ptr2,"skull");fail_that:unregister_this(ptr1,"skull");fail_this:returnerr;/*propagatetheerror*/}如何編寫清理函數(shù)void__exitmy_cleanup_function(void){unregister_those(ptr3,"skull");unregister_that(ptr2,"skull");unregister_this(ptr1,"skull");return;}內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動主次設(shè)備號字符設(shè)備可以通過文件系統(tǒng)來存取字符設(shè)備一般位于/dev下有c標(biāo)志的是字符設(shè)備有b標(biāo)志的是塊設(shè)備設(shè)備號文檔Documentation/devices.txt主設(shè)備號決定驅(qū)動的種類次設(shè)備號決定使用哪個(gè)設(shè)備設(shè)備編號的內(nèi)部表達(dá)dev_t類型(在<linux/types.h>中定義)用來持有設(shè)備編號--主次部分都包括獲得一個(gè)dev_t的主或者次編號,使用MAJOR(dev_tdev);MINOR(dev_tdev);轉(zhuǎn)換為一個(gè)dev_t,使用:MKDEV(intmajor,intminor);分配和釋放設(shè)備編號分配指定的主設(shè)備號intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);動態(tài)分配主設(shè)備號intalloc_chrdev_region(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);釋放
voidunregister_chrdev_region(dev_tfirst,unsignedintcount);字符驅(qū)動中重要的數(shù)據(jù)結(jié)構(gòu)file_operationsfileinode字符設(shè)備的注冊在Linux2.6下使用“structcdev”記錄字符設(shè)備的信息。結(jié)構(gòu)定義如下:
structcdev{
…
structmodule*owner;
structfile_operations*ops;
dev_tdev;
…
};voidcdev_init(structcdev*,structfile_operations*);structcdev*cdev_alloc(void);intcdev_add(structcdev*,dev_t,unsigned)voidcdev_del(structcdev*);
…
Open方法檢查設(shè)備的特定錯誤如果設(shè)備是首次打開,則對其進(jìn)行初始化如有必要,更新f_op指針分配且填寫filp->private_data里的數(shù)據(jù)結(jié)構(gòu)Release方法釋放由open分配的,保存在filp->private中的所有內(nèi)容在最后一次關(guān)閉操作時(shí)關(guān)閉設(shè)備內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動通過打印調(diào)試通過宏可以定義日志級別KERN_EMERG用于緊急消息,常常是那些崩潰前的消息.KERN_ALERT需要立刻動作的情形.KERN_CRIT嚴(yán)重情況,常常與嚴(yán)重的硬件或者軟件失效有關(guān).KERN_ERR用來報(bào)告錯誤情況;設(shè)備驅(qū)動常常使用KERN_ERR來報(bào)告硬件故障.KERN_WARNING有問題的情況的警告,這些情況自己不會引起系統(tǒng)的嚴(yán)重問題.KERN_NOTICE正常情況,但是仍然值得注意.在這個(gè)級別一些安全相關(guān)的情況會報(bào)告.KERN_INFO信息型消息.在這個(gè)級別,很多驅(qū)動在啟動時(shí)打印它們發(fā)現(xiàn)的硬件的信息.KERN_DEBUG用作調(diào)試消息.printk語句缺省是DEFAULT_MESSAGE_LOGLEVEL(KERN_WARNING)通過打印調(diào)試如果開啟Klogd及Syslogd則輸出到日志日志文件參考/var/log/message在printk當(dāng)中打印設(shè)備編號Print_dev_tFormat_dev_t內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動并發(fā)和管理并發(fā)源很多多個(gè)進(jìn)程運(yùn)行SMP多個(gè)CPU并行設(shè)備中斷延遲機(jī)制(工作隊(duì)列,定時(shí)器,Tasklet)并發(fā)和競爭兩個(gè)或多個(gè)進(jìn)程讀寫某些共享數(shù)據(jù),而最后的結(jié)果取決于進(jìn)程運(yùn)行的精確時(shí)序,就稱為競爭條件(RaceConditions)。競爭情況來自對資源的共享存取的結(jié)果.存取管理的常用技術(shù)是加鎖或者互斥其次常用的技術(shù)是引用計(jì)數(shù)臨界區(qū)把對共享內(nèi)存進(jìn)行訪問的程序片段稱作臨界區(qū)(criticalregion),或臨界段(criticalsection)。如果我們能夠適當(dāng)?shù)匕才攀沟脙蓚€(gè)進(jìn)程不可能同時(shí)處于臨界區(qū),則就能夠避免競爭條件。臨界區(qū)四要素任何兩個(gè)進(jìn)程不能同時(shí)處于臨界區(qū)臨界區(qū)外的進(jìn)程不能阻塞其他進(jìn)程不能使進(jìn)程在臨界區(qū)外無限等待不應(yīng)對CPU的速度和數(shù)目做假設(shè)PV操作解決同步互斥PV原語的含義
P操作和V操作是不可中斷的程序段,稱為原語。PV原語及信號量的概念都是由荷蘭科學(xué)家E.W.Dijkstra提出的。信號量sem是一整數(shù),sem大于等于零時(shí)代表可供并發(fā)進(jìn)程使用的資源實(shí)體數(shù),但sem小于零時(shí)則表示正在等待使用臨界區(qū)的進(jìn)程數(shù)。
P原語操作的動作是:
(1)sem減1;
(2)若sem減1后仍大于或等于零,則進(jìn)程繼續(xù)執(zhí)行;
(3)若sem減1后小于零,則該進(jìn)程被阻塞后進(jìn)入與該信號相對應(yīng)的隊(duì)列中,然后轉(zhuǎn)進(jìn)程調(diào)度。
V原語操作的動作是:
(1)sem加1;
(2)若相加結(jié)果大于零,則進(jìn)程繼續(xù)執(zhí)行;
(3)若相加結(jié)果小于或等于零,則從該信號的等待隊(duì)列中喚醒一等待進(jìn)程,然后再返回原進(jìn)程繼續(xù)執(zhí)行或轉(zhuǎn)進(jìn)程調(diào)度。
PV操作對于每一個(gè)進(jìn)程來說,都只能進(jìn)行一次,而且必須成對使用。在PV原語執(zhí)行期間不允許有中斷的發(fā)生。
解決互斥用PV原語實(shí)現(xiàn)進(jìn)程的互斥由于用于互斥的信號量sem與所有的并發(fā)進(jìn)程有關(guān),所以稱之為公有信號量。公有信號量的值反映了公有資源的數(shù)量。只要把臨界區(qū)置于P(sem)和V(sem)之間,即可實(shí)現(xiàn)進(jìn)程間的互斥。就象火車中的每節(jié)車廂只有一個(gè)衛(wèi)生間,該車廂的所有旅客共享這個(gè)公有資源:衛(wèi)生間,所以旅客間必須互斥進(jìn)入衛(wèi)生間,只要把衛(wèi)生間放在P(sem)和V(sem)之間,就可以到達(dá)互斥的效果。
解決同步用PV原語實(shí)現(xiàn)進(jìn)程的同步與進(jìn)程互斥不同,進(jìn)程同步時(shí)的信號量只與制約進(jìn)程及被制約進(jìn)程有關(guān)而不是與整組并發(fā)進(jìn)程有關(guān),所以稱該信號量為私有信號量。利用PV原語實(shí)現(xiàn)進(jìn)程同步的方法是:首先判斷進(jìn)程間的關(guān)系為同步的,且為各并發(fā)進(jìn)程設(shè)置私有信號量,然后為私有信號量賦初值,最后利用PV原語和私有信號量規(guī)定各進(jìn)程的執(zhí)行順序。Linux信號量實(shí)現(xiàn)voidsema_init(structsemaphore*sem,intval);DECLARE_MUTEX(name);DECLARE_MUTEX_LOCKED(name);voidinit_MUTEX(structsemaphore*sem);voidinit_MUTEX_LOCKED(structsemaphore*sem);voiddown(structsemaphore*sem);intdown_interruptible(structsemaphore*sem);intdown_trylock(structsemaphore*sem);voidup(structsemaphore*sem);內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動ioctl接口大部分驅(qū)動需要通過設(shè)備驅(qū)動進(jìn)行各種硬件控制的能力.大部分設(shè)備可進(jìn)行超出簡單的數(shù)據(jù)傳輸之外的操作;例如,設(shè)備鎖上它的門,彈出它的介質(zhì),報(bào)告錯誤信息,改變波特率,或者自我銷毀.這些操作常常通過ioctl方法來支持,它通過相同名字的系統(tǒng)調(diào)用來實(shí)現(xiàn).阻塞I/O數(shù)據(jù)操作可能會遇到read的調(diào)用時(shí)可能沒有數(shù)據(jù)時(shí)Write的調(diào)用時(shí)設(shè)備沒有準(zhǔn)備好接受數(shù)據(jù)當(dāng)驅(qū)動不能立刻滿足要求怎么辦程序員希望調(diào)用read或write并且使調(diào)用返回驅(qū)動應(yīng)當(dāng)(缺省地)阻塞進(jìn)程,使它進(jìn)入睡眠直到請求可繼續(xù).進(jìn)程的休眠進(jìn)程被置為睡眠,從調(diào)度器的運(yùn)行隊(duì)列移除睡眠的進(jìn)程被擱置一邊,等待以后發(fā)生事件睡眠注意安全編程在原子上下文時(shí)不能睡眠休眠醒來,無法確定休眠時(shí)間和時(shí)序休眠的進(jìn)程必須有時(shí)機(jī)被喚醒與休眠相關(guān)的數(shù)據(jù)結(jié)構(gòu)和函數(shù)等待隊(duì)列等待-喚醒函數(shù)wait_event(queue,condition)wait_event_interruptible(queue,condition)wait_event_timeout(queue,condition,timeout)wait_event_interruptible_timeout(queue,condition,timeout)voidwake_up(wait_queue_head_t*queue);voidwake_up_interruptible(wait_queue_head_t*queue);阻塞操作的推薦用法阻塞操作標(biāo)準(zhǔn)語法:如果一個(gè)進(jìn)程調(diào)用read但是沒有數(shù)據(jù)可用(尚未),這個(gè)進(jìn)程必須阻塞.這個(gè)進(jìn)程在有數(shù)據(jù)達(dá)到時(shí)被立刻喚醒,并且那個(gè)數(shù)據(jù)被返回給調(diào)用者,即便小于在給方法的count參數(shù)中請求的數(shù)量.如果一個(gè)進(jìn)程調(diào)用write并且在緩沖中沒有空間,這個(gè)進(jìn)程必須阻塞,并且它必須在一個(gè)與用作read的不同的等待隊(duì)列中.當(dāng)一些數(shù)據(jù)被寫入硬件設(shè)備,并且在輸出緩沖中的空間變空閑,這個(gè)進(jìn)程被喚醒并且寫調(diào)用成功,盡管數(shù)據(jù)可能只被部分寫入,這時(shí)緩沖內(nèi)沒有足夠空間給被請求的count字節(jié).非阻塞I/O,poll和select可以實(shí)現(xiàn)非阻塞讀寫多個(gè)文件三者的區(qū)別和聯(lián)系select在BSDUnix中引入poll是SystemV的解決方案epoll擴(kuò)展到幾千個(gè)文件描述符,提高了性能內(nèi)部實(shí)現(xiàn)
unsignedint(*poll)(structfile*filp,poll_table*wait);內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動測量時(shí)間流失內(nèi)核通過定時(shí)器中斷來跟蹤時(shí)間的流動定時(shí)器中斷由系統(tǒng)定時(shí)硬件以規(guī)律地間隔產(chǎn)生每次發(fā)生一個(gè)時(shí)鐘中斷,一個(gè)內(nèi)核計(jì)數(shù)器的值遞增.這個(gè)計(jì)數(shù)器在系統(tǒng)啟動時(shí)初始化為0,因此它代表從最后一次啟動以來的時(shí)鐘嘀噠的數(shù)目這個(gè)計(jì)數(shù)器是一個(gè)64-位變量(即便在32-位的體系上)并且稱為jiffies_64獲知當(dāng)前時(shí)間voiddo_gettimeofday(structtimeval*tv);延后執(zhí)行長延時(shí)技術(shù)忙等待讓出處理器超時(shí)短延時(shí)技術(shù)voidndelay(unsignedlongnsecs);voidudelay(unsignedlongusecs);voidmdelay(unsignedlongmsecs);
內(nèi)核定時(shí)器structtimer_list{/*...*/unsignedlongexpires;void(*function)(unsignedlong);unsignedlongdata;};voidinit_timer(structtimer_list*timer);structtimer_listTIMER_INITIALIZER(_function,_expires,_data);voidadd_timer(structtimer_list*timer);intdel_timer(structtimer_list*timer);Tasklets機(jī)制structtasklet_struct{/*...*/void(*func)(unsignedlong);unsignedlongdata;};voidtasklet_init(structtasklet_struct*t,void(*func)(unsignedlong),unsignedlongdata);DECLARE_TASKLET(name,func,data);DECLARE_TASKLET_DISABLED(name,func,data);Tasklet特性一個(gè)tasklet能夠被禁止并且之后被重新使能;它不會執(zhí)行直到它被使能與被禁止相同的的次數(shù).如同定時(shí)器,一個(gè)tasklet可以注冊它自己.一個(gè)tasklet能被調(diào)度來執(zhí)行以正常的優(yōu)先級或者高優(yōu)先級.后一組一直是首先執(zhí)行.taslet可能立刻運(yùn)行,如果系統(tǒng)不在重載下,但是從不會晚于下一個(gè)時(shí)鐘嘀噠.一個(gè)tasklet可能和其他tasklet并發(fā),但是對它自己是嚴(yán)格地串行的--同樣的tasklet從不同時(shí)運(yùn)行在超過一個(gè)處理器上.同樣,如已經(jīng)提到的,一個(gè)tasklet常常在調(diào)度它的同一個(gè)CPU上運(yùn)行.工作隊(duì)列工作隊(duì)列表面類似于tasketstasklet在軟件中斷上下文中運(yùn)行的結(jié)果是所有的tasklet代碼必須是原子的.相反,工作隊(duì)列函數(shù)在一個(gè)特殊內(nèi)核進(jìn)程上下文運(yùn)行;結(jié)果,它們有更多的靈活性.特別地,工作隊(duì)列函數(shù)能夠睡眠.tasklet常常在它們最初被提交的處理器上運(yùn)行.工作隊(duì)列以相同地方式工作內(nèi)核代碼可以請求工作隊(duì)列函數(shù)被延后一個(gè)明確的時(shí)間間隔.工作隊(duì)列structworkqueue_struct*create_workqueue(constchar*name);structworkqueue_struct*create_singlethread_workqueue(constchar*name);
內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作內(nèi)存管理與硬件通訊中斷處理塊設(shè)備驅(qū)動內(nèi)存分配內(nèi)存分配的最常用接口.#include<linux/slab.h>void*kmalloc(size_tsize,intflags);voidkfree(void*obj);內(nèi)存管理功能程序在尋址過程中使用的是虛擬地址,該地址由段和偏移值該地址并不能直接用。為了能尋址物理內(nèi)存,就需要一種地址變換機(jī)制將虛擬地址映射或變換到物理內(nèi)存中,這種地址變換機(jī)制就是內(nèi)存管理的主要功能之一(內(nèi)存管理的另外一個(gè)主要功能是內(nèi)存的尋址保護(hù)機(jī)制。由于時(shí)間有限限,本次不對其進(jìn)行討論)。內(nèi)存管理機(jī)制1.無內(nèi)存管理,直接尋址,也稱為實(shí)地址模式(內(nèi)存不受保護(hù))2.段式管理,也稱為保護(hù)模式(可分段記錄內(nèi)存的使用情況)3.分頁式管理,目前操作系統(tǒng)使用的模式(可提高管理效率)分頁式管理(一)內(nèi)存分頁管理是通過頁目錄表和內(nèi)存頁表所組成的二級表進(jìn)行的。其中頁目錄表和頁表的結(jié)構(gòu)是一樣的,表項(xiàng)結(jié)構(gòu)也相同。頁目錄表中的每個(gè)表項(xiàng)(簡稱頁目錄項(xiàng))(4字節(jié))用來尋址一個(gè)頁表,而每個(gè)頁表項(xiàng)(4字節(jié))用來指定一頁物理內(nèi)存頁。因此,當(dāng)指定了一個(gè)頁目錄項(xiàng)和一個(gè)頁表項(xiàng),我們就可以唯一地確定所對應(yīng)的物理內(nèi)存頁。頁目錄表占用一頁內(nèi)存,因此最分頁式管理(二)頁目錄表有1024個(gè)表項(xiàng),每個(gè)表項(xiàng)占用4個(gè)字節(jié),所以一個(gè)頁目錄表剛好占用一頁內(nèi)存(4X1024),因此最多可以尋址1024個(gè)頁表。而每個(gè)頁表也同樣占用一頁內(nèi)存,因此一個(gè)頁表可以尋址最多1024個(gè)物理內(nèi)存頁面。這樣一個(gè)頁目錄表所尋址的所有頁表共可以尋址1024X1024X4096=4G的內(nèi)存空間頁目錄表和頁表結(jié)構(gòu)線性地址內(nèi)存分配所獲取的都是線性地址;一個(gè)32位的線性地址被分成了三個(gè)部分第一部分(10位):指定一個(gè)頁目錄項(xiàng)第二部分(10位):指定一個(gè)頁表項(xiàng)第三部分(12位):指定物理內(nèi)存頁上的偏移地址線性地址結(jié)構(gòu)(一)Typededstruct{ unsignedintdir:10/*用作頁面表目錄中的下標(biāo),該目錄項(xiàng)指向一個(gè)頁面表*/ unsignedintpage:10/*用作頁面表中的下標(biāo),該表項(xiàng)指向一個(gè)物理頁面*/unsignedintoffset:12/*用作4k字節(jié)物理頁面內(nèi)的偏移量*/}線性地址線性地址結(jié)構(gòu)(二)在頁面目錄中共有210
=1024個(gè)目錄項(xiàng),每個(gè)目錄項(xiàng)指向一個(gè)頁面表,每個(gè)頁面表共有1024個(gè)頁面描述項(xiàng)。線性地址的位31-22共10個(gè)比特用來確定頁目錄中的目錄項(xiàng),位21-12用來尋址頁目錄項(xiàng)指定的頁表中的頁表項(xiàng),最后的12個(gè)比特正好用作頁表項(xiàng)指定的一頁物理內(nèi)存中的偏移地址線性地址到物理地址映射(一)有專門的寄存器CR3存儲當(dāng)前頁面目錄的地址1.從寄存器CR3中取得頁面目錄的基地址2.以線性地址中的dir位段為下標(biāo),在目錄中取得相應(yīng)也表的基地址3.以線性地址中的page位段為下標(biāo),在所得到的頁面表中取得相應(yīng)的頁面描述項(xiàng)4.將頁面描述項(xiàng)中給出的頁面基地址與線性地址中的offset位段相加得到實(shí)際的物理地址線性地址到物理地址映射(二)線性地址到物理地址映射(三)線性地址到物理地址映射(四)對于第一個(gè)進(jìn)程(任務(wù)0),其頁表是在頁目錄表之后,共4頁。對于應(yīng)用程序的進(jìn)程,其頁表所使用的內(nèi)存是在進(jìn)程創(chuàng)建時(shí)向內(nèi)存管理程序申請的,因此是在主內(nèi)存區(qū)中表項(xiàng)結(jié)構(gòu)(一)頁框地址(PAGEFRAMEADDRESS)指定了一頁內(nèi)存的物理起始地址。因?yàn)閮?nèi)存頁是位于4K邊界上的,這些指針的低12位都永遠(yuǎn)是0。這樣,在目錄項(xiàng)和頁表項(xiàng)中都只要有20位用于指針就夠了,而余下的12位則可以用于控制或其他的目的用。表項(xiàng)結(jié)構(gòu)(二)每個(gè)表項(xiàng)由頁框地址、訪問標(biāo)志位、臟(已改寫)標(biāo)志位和存在標(biāo)志位等構(gòu)成表項(xiàng)結(jié)構(gòu)(三)表項(xiàng)結(jié)構(gòu)(四)頁框地址(PAGEFRAMEADDRESS)指定了一頁內(nèi)存的物理起始地址存在位(PRESENT–P)確定了一個(gè)頁表項(xiàng)是否可以用于地址轉(zhuǎn)換。P=1可用,P=0不能用于地址轉(zhuǎn)換,相應(yīng)的頁面或頁面表不在內(nèi)存.CPU會產(chǎn)生缺頁中斷,內(nèi)核中表項(xiàng)結(jié)構(gòu)(五)P=0表示相應(yīng)的頁面或頁面表不在內(nèi)存.CPU會產(chǎn)生缺頁中斷,內(nèi)核中的有關(guān)異常服務(wù)程序就可根據(jù)從磁盤上的頁面交換區(qū)將相應(yīng)的頁面讀入內(nèi)存,并且相應(yīng)的設(shè)置表現(xiàn)中的基地址,并將P位設(shè)置為1,供后續(xù)訪問使用。相反也可將內(nèi)存中暫時(shí)不使用的內(nèi)存頁面寫入到磁盤的交換區(qū),然后將相應(yīng)的頁面表項(xiàng)的P位設(shè)置為0。這就實(shí)現(xiàn)虛擬內(nèi)存功能表項(xiàng)結(jié)構(gòu)(六)當(dāng)P=0時(shí),表項(xiàng)中的其余各位均無意義,所以可以被用來臨時(shí)存儲其他信息,如被換出的頁面在磁盤上的位置等等信息PS=0時(shí)表示包含在由該目錄項(xiàng)所指的頁面面表中所有頁面的大小都是4K字節(jié),這也是目前在Linux內(nèi)核中所采用的頁面大小。但從Pentium處理器開始,intel引入了PSE頁面大小擴(kuò)充機(jī)制。即當(dāng)PS=1,頁面的大小就成了4M字節(jié),而頁面表就不足使用。表項(xiàng)結(jié)構(gòu)(七)Ps=1時(shí)線性地址中的低22位就全部用在4M字節(jié)的頁面中的位移,這樣總的尋址能力不變1024X4M=4G,但映射過程減少了一層。提高訪問速度(主要是由于內(nèi)存容量和磁盤的容量的日益增加,磁盤訪問速度的顯著提高,以及對圖像處理要求的日益增加,4M頁面可能成為主流)表項(xiàng)結(jié)構(gòu)(八)已訪問(Accessed–A)和已修改(Dirty–D)比特位用于提供有關(guān)頁使用的信息。除了頁目錄項(xiàng)中的已修改位,這些比特位將由硬件置位,但不復(fù)位。在對一頁內(nèi)存進(jìn)行讀或?qū)懖僮髦?,CPU將設(shè)置相關(guān)的目錄和二級頁表項(xiàng)的已訪問位。在向一個(gè)二級頁表項(xiàng)所涵蓋的地址進(jìn)行寫操作之前,處理器將設(shè)置該二級頁表項(xiàng)的已修改位,而頁目錄項(xiàng)中的已修改位是不用的。當(dāng)所需求的內(nèi)存超出實(shí)際物理內(nèi)存量時(shí),內(nèi)存管理程序就可以使用這些位來確定那些頁可以從內(nèi)存中取走,以騰出空間。內(nèi)存管理程序還需負(fù)責(zé)檢測和復(fù)位這些比特位表項(xiàng)結(jié)構(gòu)(九)讀/寫位(Read/Write–R/W)和用戶/超級用戶位(User/Supervisor–U/S)并不用于地址轉(zhuǎn)換,但用于分頁級的保護(hù)機(jī)制,是由CPU在地址轉(zhuǎn)換過程中同時(shí)操作的。Linux中物理內(nèi)存的管理和分配物理地址0處存放了一個(gè)頁目錄表,緊隨其后是4個(gè)頁表。這4個(gè)頁表將被用于任務(wù)0,其它的派生進(jìn)程將在主內(nèi)存區(qū)申請內(nèi)存頁來存放自己的頁表控制內(nèi)存分配如何進(jìn)行的標(biāo)志,從最少限制的到最多的.GFP_USER和GFP_KERNEL優(yōu)先級允許當(dāng)前進(jìn)程被置為睡眠來滿足請求.GFP_NOFS和GFP_NOIO禁止文件系統(tǒng)操作和所有的I/O操作,分別地,而GFP_ATOMIC分配根本不能睡眠.#include<linux/mm.h>GFP_USERGFP_KERNELGFP_NOFSGFP_NOIOGFP_ATOMIC內(nèi)存分配標(biāo)志這些標(biāo)志分配內(nèi)存時(shí)修改內(nèi)核的行為__GFP_DMA__GFP_HIGHMEM__GFP_COLD__GFP_NOWARN__GFP_HIGH__GFP_REPEAT__GFP_NOFAIL__GFP_NORETRYslab緩存創(chuàng)建和銷毀一個(gè)slab緩存.這個(gè)緩存可被用來分配幾個(gè)相同大小的對象.#include<linux/malloc.h>kmem_cache_t*kmem_cache_create(char*name,size_tsize,size_toffset,unsignedlongflags,constructor(),destructor());intkmem_cache_destroy(kmem_cache_t*cache);緩存標(biāo)志在創(chuàng)建一個(gè)緩存時(shí)可指定的標(biāo)志.SLAB_CTOR_ATOMICSLAB_CTOR_CONSTRUCTOR緩存中分配釋放單個(gè)對象從緩存中分配和釋放一個(gè)單個(gè)對象./proc/slabinfo一個(gè)包含對slab緩存使用情況統(tǒng)計(jì)的虛擬文件.void*kmem_cache_alloc(kmem_cache_t*cache,intflags);voidkmem_cache_free(kmem_cache_t*cache,constvoid*obj);內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動硬件讀寫屏障硬件內(nèi)存屏障.它們請求CPU(和編譯器)來檢查所有的跨這個(gè)指令的內(nèi)存讀,寫#include<asm/system.h>voidrmb(void);voidread_barrier_depends(void);voidwmb(void);voidmb(void);I/O讀寫用來讀和寫I/O端口的函數(shù).它們還可以被用戶空間程序調(diào)用,如果它們有正當(dāng)?shù)臋?quán)限來存取端口.#include<asm/io.h>unsignedinb(unsignedport);voidoutb(unsignedcharbyte,unsignedport);unsignedinw(unsignedport);voidoutw(unsignedshortword,unsignedport);unsignedinl(unsignedport);voidoutl(unsigneddoubleword,unsignedport);延時(shí)讀寫函數(shù)如果在一次I/O操作后需要一個(gè)小延時(shí),你可以使用在前一項(xiàng)中介紹的這些函數(shù)的6個(gè)暫停對應(yīng)部分;這些暫停函數(shù)以_p結(jié)尾unsignedinb_p(unsignedport);字串函數(shù)這些"字串函數(shù)"被優(yōu)化為傳送數(shù)據(jù)從一個(gè)輸入端口到一個(gè)內(nèi)存區(qū),或者其他的方式.這些傳送通過讀或?qū)懙酵欢丝赾ount次來完成.voidinsb(unsignedport,void*addr,unsignedlongcount);voidoutsb(unsignedport,void*addr,unsignedlongcount);voidinsw(unsignedport,void*addr,unsignedlongcount);voidoutsw(unsignedport,void*addr,unsignedlongcount);voidinsl(unsignedport,void*addr,unsignedlongcount);voidoutsl(unsignedport,void*addr,unsignedlongcount);I/O端口資源分配I/O端口的資源分配器.這個(gè)檢查函數(shù)成功返回0并且在錯誤時(shí)小于0#include<linux/ioport.h>structresource*request_region(unsignedlongstart,unsignedlonglen,char*name);voidrelease_region(unsignedlongstart,unsignedlonglen);intcheck_region(unsignedlongstart,unsignedlonglen);I/O地址映射ioremap重映射一個(gè)物理地址范圍到處理器的虛擬地址空間,使它對內(nèi)核可用.iounmap釋放映射當(dāng)不再需要它時(shí).#include<asm/io.h>void*ioremap(unsignedlongphys_addr,unsignedlongsize);void*ioremap_nocache(unsignedlongphys_addr,unsignedlongsize);voidiounmap(void*virt_addr);內(nèi)存區(qū)處理資源分配為內(nèi)存區(qū)處理資源分配的函數(shù)structresource*request_mem_region(unsignedlongstart,unsignedlonglen,char*name);voidrelease_mem_region(unsignedlongstart,unsignedlonglen);intcheck_mem_region(unsignedlongstart,unsignedlonglen);I/O內(nèi)存存取函數(shù)用來使用I/O內(nèi)存的存取者函數(shù).#include<asm/io.h>unsignedintioread8(void*addr);unsignedintioread16(void*addr);unsignedintioread32(void*addr);voidiowrite8(u8value,void*addr);voidiowrite16(u16value,void*addr);voidiowrite32(u32value,void*addr);
I/O內(nèi)存函數(shù).舊的,類型不安全的存取I/O內(nèi)存的函數(shù).unsignedreadb(address);unsignedreadw(address);unsignedreadl(address);voidwriteb(unsignedvalue,address);voidwritew(unsignedvalue,address);voidwritel(unsignedvalue,address);memset_io(address,value,count);memcpy_fromio(dest,source,nbytes);memcpy_toio(dest,source,nbytes);內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動注冊注銷中斷處理調(diào)用這個(gè)注冊和注銷一個(gè)中斷處理.#include<linux/interrupt.h>intrequest_irq(unsignedintirq,請求中斷號irqreturn_t(*handler)(),中斷服務(wù)程序unsignedlongflags,是否共享constchar*dev_name,設(shè)備名稱/proc/interrupts來顯示中斷的擁有者
void*dev_id);用戶數(shù)據(jù)voidfree_irq(unsignedintirq,void*dev_id);中斷介紹
硬中斷是外部設(shè)備對CPU的中斷,軟中斷通常是硬中斷服務(wù)程序?qū)?nèi)核的中斷,信號則是由內(nèi)核(或其他進(jìn)程)對某個(gè)進(jìn)程的中斷。軟中斷的一種典型應(yīng)用就是所謂的“下半部”(bottomhalf),它的得名來自于將硬件中斷處理分離成“上半部”和“下半部”兩個(gè)階段的機(jī)制:上半部在屏蔽中斷的上下文中運(yùn)行,用于完成關(guān)鍵性的處理動作;而下半部則相對來說并不是非常緊急的,通常還是比較耗時(shí)的,因此由系統(tǒng)自行安排運(yùn)行時(shí)機(jī),不在中斷服務(wù)上下文中執(zhí)行軟中斷,用軟件方式進(jìn)行模擬,實(shí)現(xiàn)宏觀上的異步執(zhí)行效果。很多情況下,軟中斷和"信號"有些類似
注冊注銷中斷處理調(diào)用這個(gè)注冊和注銷一個(gè)中斷處理.#include<linux/interrupt.h>intrequest_irq(unsignedintirq,請求中斷號irqreturn_t(*handler)(),中斷服務(wù)程序unsignedlongflags,是否共享constchar*dev_name,設(shè)備名稱/proc/interrupts來顯示中斷的擁有者
void*dev_id);用戶數(shù)據(jù)voidfree_irq(unsignedintirq,void*dev_id);中斷申請標(biāo)志給request_irq的標(biāo)志.SA_INTERRUPT當(dāng)置位了,這表示一個(gè)"快速"中斷處理.快速處理在當(dāng)前處理器上禁止中斷來執(zhí)行
SA_SHIRQ安裝一個(gè)共享的處理者#include<asm/signal.h>SA_INTERRUPTSA_SHIRQSA_SAMPLE_RANDOM中斷的文件系統(tǒng)節(jié)點(diǎn)報(bào)告硬件中斷和安裝的處理者的文件系統(tǒng)節(jié)點(diǎn).可以獲取當(dāng)前系統(tǒng)得中斷號和每個(gè)中斷產(chǎn)生的中斷次數(shù)等信息/proc/interrupts/proc/stat驅(qū)動使用探測函數(shù)驅(qū)動使用的函數(shù),探測決定哪個(gè)中斷線被設(shè)備在使用.probe_irq_on這個(gè)函數(shù)返回一個(gè)未安排的中斷的位掩碼.驅(qū)動必須保留返回的位掩碼,并且在后面?zhèn)鬟f給probe_irq_off.在這個(gè)調(diào)用之后,驅(qū)動應(yīng)當(dāng)安排它的設(shè)備產(chǎn)生至少一次中斷供探測使用probe_irq_off的返回值是被探測的中斷號.中斷處理匯編語言文件處理很多機(jī)器級別的工作.,匯編代碼被安排到每個(gè)可能的中斷.在每個(gè)情況下,這個(gè)代碼將中斷號壓棧并且跳轉(zhuǎn)到一個(gè)通用段,稱為do_IRQ,在irq.c中定義.do_IRQ做的第一件事是確認(rèn)中斷以便中斷控制器能夠繼續(xù)其他事情.它接著獲取給定IRQ號的一個(gè)自旋鎖,因此阻止任何其他CPU處理這個(gè)IRQ.它清除幾個(gè)狀態(tài)位(包括稱為IRQ_WAITING的一個(gè),我們很快會看到它)并且接著查看這個(gè)特殊IRQ的處理者.如果沒有處理者,什么不作;自旋鎖釋放,任何掛起的軟件中斷被處理,最后do_IRQ返回.使能和禁止中斷可以使能和禁止中斷。共享處理不使用這個(gè)函數(shù).voiddisable_irq(intirq);voiddisable_irq_nosync(intirq);voidenable_irq(intirq);禁止中斷使用local_irq_save來禁止本地處理器的中斷并且記住它們之前的狀態(tài)voidlocal_irq_save(unsignedlongflags);voidlocal_irq_restore(unsignedlongflags);使能和禁止中斷在當(dāng)前處理器無條件禁止和使能中斷的函數(shù).voidlocal_irq_disable(void);voidlocal_irq_enable(void);內(nèi)容提要設(shè)備驅(qū)動簡介建立和運(yùn)行模塊字符驅(qū)動調(diào)試技術(shù)并發(fā)和競爭高級字符驅(qū)動操作時(shí)間,延時(shí)和延后工作分配內(nèi)存與硬件通訊中斷處理塊設(shè)備驅(qū)動塊設(shè)備注冊register_blkdev注冊一個(gè)塊驅(qū)動到內(nèi)核,并且,可選地,獲得一個(gè)主編號.一個(gè)驅(qū)動可被注銷,使用unregister_blkdev.#include<linux/fs.h>intregister_blkdev(unsignedintmajor,constchar*name);intunregister_blkdev(unsignedintmajor,constchar*name);塊設(shè)備相關(guān)數(shù)據(jù)結(jié)構(gòu)塊設(shè)備驅(qū)動的數(shù)據(jù)結(jié)構(gòu).structblock_device_operations描述內(nèi)核中單個(gè)塊設(shè)備的結(jié)構(gòu).#include<linux/genhd.h>structgendisk;分配gendisk結(jié)構(gòu)的函數(shù),并且返回它們到系統(tǒng).structgendisk*alloc_disk(intminors);voidadd_disk(structgendisk*gd); 塊設(shè)備相關(guān)函數(shù)voidset_capacity(structgendisk*gd,sector_tsectors);存儲設(shè)備能力(以512-字節(jié))在gendisk結(jié)構(gòu)中.voidadd_disk(structgendisk*gd);添加一個(gè)磁盤到內(nèi)核.一旦調(diào)用這個(gè)函數(shù),你的磁盤的方法可被內(nèi)核調(diào)用.intcheck_disk_change(structblock_device*bdev);一個(gè)內(nèi)核函數(shù),檢查在給定磁盤驅(qū)動器中的介質(zhì)改變,并且采取要求的清理動作當(dāng)檢測到這樣一個(gè)改變.請求隊(duì)列相關(guān)函數(shù)#include<linux/blkdev.h>request_queue_tblk_init_queue(request_fn_proc*request,spinlock_t*lock);voidblk_cleanup_queue(request_queue_t*);處理塊請求隊(duì)列的創(chuàng)建和刪除的函數(shù).structrequest*elv_next_request(request_queue_t*queue);voidend_request(structrequest*req,intsuccess);elv_next_request從一個(gè)請求隊(duì)列中獲得下一個(gè)請求;end_request可用在每個(gè)簡單驅(qū)動器中來標(biāo)識一個(gè)(或部分)請求完成.voidblkdev_dequeue_request(structrequest*req);voidelv_requeue_request(request_queue_t*queue,structrequest*req);從隊(duì)列中除去一個(gè)請求,并且放回它的函數(shù)如果需要.voidblk_stop_queue(request_queue_t*queue);voidblk_start_queue(request_queue_t*queue);如果你需要阻止對你的請求函數(shù)的進(jìn)一步調(diào)用,調(diào)用blk_stop_queue來完成.調(diào)用blk_start_queue來使你的請求方法被再次調(diào)用.請求隊(duì)列參數(shù)控制函數(shù)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 鋁金屬行業(yè)運(yùn)營情況跟蹤及展望 202412 -大公國際
- 中小企業(yè)融資新模式以知識產(chǎn)權(quán)為抵押的貸款
- 兒童獨(dú)立行動能力的實(shí)踐與探索
- 創(chuàng)新型實(shí)驗(yàn)室管理團(tuán)隊(duì)的構(gòu)建
- 從兒童心理發(fā)展看家庭教育的價(jià)值與挑戰(zhàn)
- 全民健體戰(zhàn)略下校園食品健康規(guī)劃邁向標(biāo)準(zhǔn)化和國際化的探求之路
- 企業(yè)風(fēng)險(xiǎn)管理與金融安全的關(guān)聯(lián)性分析
- 健身餐家庭制作全攻略
- 創(chuàng)新教育模式下的學(xué)校招生策略
- 護(hù)理學(xué)院慶祝護(hù)士節(jié)的詳細(xì)活動規(guī)劃
- 鈴木教學(xué)法在我國鋼琴教學(xué)中的應(yīng)用研究 開題
- 掘進(jìn)迎頭預(yù)防冒頂片幫安全技術(shù)措施
- 【MOOC】操作系統(tǒng)及Linux內(nèi)核-西安郵電大學(xué) 中國大學(xué)慕課MOOC答案
- 全新危險(xiǎn)廢物運(yùn)輸安全協(xié)議(2024版)3篇
- 混凝土輸送泵車安全操作規(guī)程(4篇)
- 【MOOC】模擬電子技術(shù)基礎(chǔ)-華中科技大學(xué) 中國大學(xué)慕課MOOC答案
- 2024年網(wǎng)格員考試題庫完美版
- 北京市矢量地圖-可改顏色
- 2020年度圖書館中級職稱專業(yè)技術(shù)資格考試題庫
- 南京工業(yè)大學(xué)甲醇制氫工藝設(shè)計(jì)(反應(yīng)器)
- 農(nóng)業(yè)氣象學(xué)-作業(yè)3-國開(ZJ)-參考資料
評論
0/150
提交評論