版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、3項(xiàng)技術(shù):1,mmap系統(tǒng)調(diào)用可以實(shí)現(xiàn)將設(shè)備內(nèi)存映射到用戶進(jìn)程的地址空間。2,使用get_user_pages,可以把用戶空間內(nèi)存映射到內(nèi)核中。3,DMA的I/O操作,使得外設(shè)具有直接訪問(wèn)系統(tǒng)內(nèi)存的能力。內(nèi)存管理內(nèi)核用來(lái)管理內(nèi)存的數(shù)據(jù)結(jié)構(gòu)地址內(nèi)型Linux是一個(gè)虛擬內(nèi)存系統(tǒng),即用戶程序使用的地址與硬件使用的物理地址是不等同的。虛擬內(nèi)存引入了一個(gè)間接層,使得許多操作成為可能:*有了虛擬內(nèi)存,系統(tǒng)中運(yùn)行的程序可以分配比物理內(nèi)存更多的內(nèi)存。*虛擬地址還能讓程序在進(jìn)程的地址空間內(nèi)使用更多的技巧,包括將程序的內(nèi)存映射到設(shè)備內(nèi)存上。地址內(nèi)型列表*用戶虛擬地址 每個(gè)進(jìn)程都有自己的虛擬地址空間。*物理地址 處
2、理器訪問(wèn)系統(tǒng)內(nèi)存時(shí)使用的地址。*總線地址 在外圍總線和內(nèi)存之間使用。MMU可以實(shí)現(xiàn)總線和主內(nèi)存之間的重新映射。 當(dāng)設(shè)置DMA操作時(shí),編寫(xiě)MMU相關(guān)的代碼是一個(gè)必需的步驟。*內(nèi)核邏輯地址 內(nèi)核邏輯地址組成了內(nèi)核的常規(guī)地址空間,該地址映射了部分(或全部)內(nèi)存, 并經(jīng)常被視為物理地址。在大多數(shù)體系架構(gòu)中,邏輯地址與其相關(guān)聯(lián)的物理地址 的不同,僅僅在于它們之間存在一個(gè)固定的偏移量。kmalloc返回的內(nèi)存就是 內(nèi)核邏輯地址。*內(nèi)核虛擬地址 內(nèi)核虛擬地址與邏輯地址相同之處在于,都將內(nèi)核空間的地址映射到物理地址上。 不同之處在于,內(nèi)核虛擬地址與物理地址的映射不是線性的和一對(duì)一的。 vmalloc返回一個(gè)虛
3、擬地址,kmap函數(shù)也返回一個(gè)虛擬地址。物理地址和頁(yè)物理地址被分為離散的單元,稱之為頁(yè)。系統(tǒng)內(nèi)部許多對(duì)內(nèi)存的操作都是基于單個(gè)頁(yè)的。大多數(shù)系統(tǒng)都使用每頁(yè)4096個(gè)字節(jié),PAGE_SIZE 給出指定體系架構(gòu)下的頁(yè)大小。觀察內(nèi)存地址,無(wú)論是虛擬的還是物理的,它們都被分為頁(yè)號(hào)和一個(gè)頁(yè)內(nèi)的偏移量。如果每頁(yè)4096個(gè)字節(jié),那么最后的12位就是偏移量,剩余的高位則指定頁(yè)號(hào)。頁(yè)幀數(shù):將除去偏移量的剩余位移到右端,稱該結(jié)果為頁(yè)幀數(shù)。高端與低端內(nèi)存內(nèi)核(在x86架構(gòu)中)將4GB的虛擬地址空間分割為用戶空間和內(nèi)核空間。一個(gè)典型的分割是將3GB分配給用戶空間,1GB分配給內(nèi)核空間。占用內(nèi)核地址空間最大的部分是物理內(nèi)存
4、的虛擬映射,內(nèi)核無(wú)法直接操作沒(méi)有映射到內(nèi)核地址空間的內(nèi)存。低端內(nèi)存: 只有內(nèi)存的低端部分擁有邏輯地址。內(nèi)核的數(shù)據(jù)結(jié)構(gòu)必須放置在低端內(nèi)存中。高端內(nèi)存: 除去低端內(nèi)存的剩余部分沒(méi)有邏輯地址。它們處于內(nèi)核虛擬地址之上。內(nèi)存映射和頁(yè)結(jié)構(gòu)內(nèi)核使用邏輯地址來(lái)引用物理內(nèi)存中的頁(yè)。為解決在高端內(nèi)存中無(wú)法使用邏輯地址的問(wèn)題,內(nèi)核中處理內(nèi)存的函數(shù)趨向于使用指向page結(jié)構(gòu)的指針。page結(jié)構(gòu)用來(lái)保存內(nèi)核需要知道的所有物理內(nèi)存信息,對(duì)系統(tǒng)中的每個(gè)物理頁(yè),都有一個(gè)page結(jié)構(gòu)相對(duì)應(yīng)。page結(jié)構(gòu)的幾個(gè)成員:atomic_t count; 對(duì)該頁(yè)的訪問(wèn)計(jì)數(shù)。void *virtual; 如果頁(yè)面被映射,則指向頁(yè)的內(nèi)核虛
5、擬地址; 如果未被映射,則為NULL。 低端內(nèi)存頁(yè)總是被映射,而高端內(nèi)存頁(yè)通常不被映射。unsigned long flags; 描述頁(yè)狀態(tài)的一系列標(biāo)志。 PG_locked表示內(nèi)存中的頁(yè)已經(jīng)被鎖住, 而PG_reserved表示禁止內(nèi)存管理系統(tǒng)訪問(wèn)該頁(yè)。內(nèi)核維護(hù)了一個(gè)或者多個(gè)page結(jié)構(gòu)的數(shù)組,用來(lái)跟蹤系統(tǒng)中的物理內(nèi)存。有一些函數(shù)和宏用來(lái)在page結(jié)構(gòu)指針與虛擬地址之間進(jìn)行轉(zhuǎn)換:struct page *virt_to_page(void *kaddr); 將內(nèi)核邏輯地址轉(zhuǎn)換為響應(yīng)的page結(jié)構(gòu)指針。struct page *pfn_to_page(int pfn);針對(duì)給定的頁(yè)幀號(hào),返回p
6、age結(jié)構(gòu)指針。void *page_address(struct page *page); 如果地址存在的話,則返回頁(yè)的內(nèi)核虛擬地址。void *kmap(struct page *page); 為系統(tǒng)中的頁(yè)返回內(nèi)核虛擬地址。對(duì)于低端內(nèi)存頁(yè),它只返回頁(yè)的邏輯地址;對(duì)于高端內(nèi)存頁(yè),kmap在專用的內(nèi)核地址空間創(chuàng)建特殊的映射。void kunmap(struct page *page);釋放由kmap創(chuàng)建的映射。void *kmap_atomic(struct page *page,enum km_type type);void kunmap_atomic(void *addr,enum km_
7、type type);,是kmap的高性能版本。頁(yè)表在任何現(xiàn)代的系統(tǒng)中,處理器必須使用某種機(jī)制,將虛擬地址轉(zhuǎn)化為響應(yīng)的物理地址,這種機(jī)制成為頁(yè)表。虛擬內(nèi)存區(qū)虛擬內(nèi)存區(qū)(VMA)用于管理進(jìn)程地址空間中不同區(qū)域的內(nèi)核數(shù)據(jù)結(jié)構(gòu)??梢詫⑵涿枋鰹椤皳碛凶陨韺傩缘膬?nèi)存對(duì)象”。進(jìn)程的內(nèi)存映射包含下面這些區(qū)域:*可執(zhí)行代碼區(qū)域*多個(gè)數(shù)據(jù)區(qū):初始化數(shù)據(jù),非初始化數(shù)據(jù)(BSS),程序堆棧。*與每個(gè)活動(dòng)的內(nèi)存映射對(duì)應(yīng)的區(qū)域#cat /proc/1/maps可以了解進(jìn)程的內(nèi)存區(qū)域。/proc/self始終指向當(dāng)前進(jìn)程。每行都是用下面的形式表示的:start-end perm offset major:minor in
8、ode image在/proc/*/maps中的每個(gè)成員(除映像名外)都與vm_area_struct結(jié)構(gòu)中的一個(gè)成員對(duì)應(yīng):startend該內(nèi)存區(qū)域的起始處和結(jié)束處的虛擬地址。perm讀、寫(xiě)和執(zhí)行權(quán)限,最后一位若是p表示私有,s表示共享。offset內(nèi)存區(qū)域在映射文件中的起始位置。majorminor擁有映射文件的設(shè)備的主設(shè)備號(hào)和次設(shè)備號(hào)。inode被映射的文件的索引節(jié)點(diǎn)號(hào)。image被映射文件的名稱。vm_area_struct結(jié)構(gòu)當(dāng)用戶空間進(jìn)程調(diào)用mmap,將設(shè)備內(nèi)存映射到它的地址空間時(shí),系統(tǒng)通過(guò)創(chuàng)建一個(gè)表示該映射的新VMA作為響應(yīng)。支持mmap的驅(qū)動(dòng)程序需要幫助進(jìn)城完成VMA的初始化。
9、vm_area_struct結(jié)構(gòu)是在中定義的。VMA的主要成員如下:unsigned long vm_start;unsigned long vm_end;該VMA所覆蓋的虛擬地址范圍。struct file *vm_file;指向與該區(qū)域相關(guān)聯(lián)的file結(jié)構(gòu)指針。unsigned long vm_pgoff;以頁(yè)為單位,文件中該區(qū)域的偏移量。unsigned long vm_flags;描述該區(qū)域的一套標(biāo)志。struct vm_operations_struct *vm_ops;內(nèi)核能調(diào)用的一套函數(shù),用來(lái)對(duì)該內(nèi)存區(qū)進(jìn)行操作。它的存在表示內(nèi)存區(qū)域是一個(gè)內(nèi)核“對(duì)象”。void *vm_priva
10、te_data;驅(qū)動(dòng)程序用來(lái)保存自身信息的成員。vm_operations_struct結(jié)構(gòu)的幾個(gè)成員:void (*open)(struct vm_area_struct *vma);void (*close)(struct vm_area_struct *vma);struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address,int *type);int (*populate)(struct vm_area_struct *vm, unsigned long address,unsigned long le
11、n, pgprot_t prot,unsigned long pgoff,int nonblock);內(nèi)存映射處理在系統(tǒng)中的每個(gè)進(jìn)程都擁有一個(gè)struct mm_struct結(jié)構(gòu),其中包含了虛擬內(nèi)存區(qū)域鏈表、頁(yè)表以及其他大量?jī)?nèi)存管理信息,還包含一個(gè)信號(hào)燈(mmap_sem)和一個(gè)自旋鎖(page_table_lock)。mmap設(shè)備操作對(duì)于驅(qū)動(dòng)程序來(lái)說(shuō),內(nèi)存映射可以提供給用戶程序直接訪問(wèn)設(shè)備內(nèi)存的能力。映射一個(gè)設(shè)備意味著將用戶空間的一段內(nèi)存與設(shè)備內(nèi)存關(guān)聯(lián)起來(lái)。無(wú)論何時(shí)當(dāng)程序在分配的地址范圍內(nèi)讀寫(xiě)時(shí),實(shí)際上訪問(wèn)的就是設(shè)備。要注意:像串口和其它面向流的設(shè)備不能進(jìn)行mmap抽象。必須以PAGE_SI
12、ZE為單位進(jìn)行映射。rmpap_pfn_range和io_remap_page_range為一段物理地址建立新的頁(yè)表。int remap_pfn_range(struct vm_area_struct *vm, unsigned long virt_addr,unsigned long pfn, unsigned long size,pgprot_t prot);int io_remap_page_range(struct vm_area_struct *vma, unsigned long virt_addr,unsigned long phys_addr, unsigned long si
13、ze,pgprot_t prot);vma:虛擬內(nèi)存區(qū)域,在一定范圍內(nèi)的頁(yè)將被映射到該區(qū)域內(nèi)。virt_addr:重新映射時(shí)的起始用戶虛擬地址。該函數(shù)為處于virt_addr和virt_addr+size 之間的虛擬地址建立頁(yè)表。pfn:與物理內(nèi)存對(duì)應(yīng)的頁(yè)幀號(hào),虛擬內(nèi)存將要被映射到該物理內(nèi)存上。size:以字節(jié)為單位,被重新映射的區(qū)域大小。prot:新VMA要求的保護(hù)屬性。一個(gè)簡(jiǎn)單的實(shí)現(xiàn)static int simple_remap_mmap(struct file *filp,struct vm_area_struct *vma)if(remap_pfn_range(vma,vma-vm_s
14、tart,vma-vm_pgoff, vma-vm_end-vma-vm-vm_start,vma-vm_page_prot) return -EAGAIN;vma-vm_ops = &simple_remap_vm_ops;simple_vma_open(vma);return 0;可見(jiàn),重新映射內(nèi)存就是調(diào)用remap_pfn_range函數(shù)創(chuàng)建所需的頁(yè)表。為VMA添加操作vm_area_struct結(jié)構(gòu)包含了一系列針對(duì)VMA的操作。void simple_vma_open(struct vm_area_struct *vma)printk(KERN_NOTICE Simple VMA op
15、en,virt %lx,phys %lxn, vma-vm_start,vma-vm_pgoff PAGE_SHIFT);void simple_vma_close(struct vm_area_struct *vma)printk(KERN_NOTICE Simple VMA close.n);static struct vm_operations_struct simple_remap_vm_ops = .open = simple_vma_open,.close = simple_vma_close,;使用nopage映射內(nèi)存有時(shí)驅(qū)動(dòng)程序?qū)map的實(shí)現(xiàn)必須具有更好的靈活性,在這種情況下
16、,提倡使用VMA的nopage方法實(shí)現(xiàn)內(nèi)存映射。如果要支持mremap系統(tǒng)調(diào)用,就必須實(shí)現(xiàn)nopage函數(shù)。struct page *(*nopage)(struct vm_area_struct *vma, unsigned long address,int *type);重映射特定的I/O區(qū)域一個(gè)典型的驅(qū)動(dòng)程序只映射與其外圍設(shè)備相關(guān)的一小段地址,而不是映射全部地址。重新映射RAM-使用nopage方法重映射RAM-重新映射內(nèi)核虛擬地址執(zhí)行直接I/O訪問(wèn)實(shí)現(xiàn)直接I/O的關(guān)鍵是get_user_pages()函數(shù):int get_user_pages(struct task_struct *t
17、sk,struct mm_struct *mm, unsigned long start,int len,int write,int force, struct page *pages,struct vm_area_struct *vmas);異步I/Ossize_t (*aio_read)(),ssize_t (*aio_write)(),ssize_t (*aio_fsync)()直接內(nèi)存訪問(wèn) DMADMA是一種硬件機(jī)制,它允許外圍設(shè)備和主內(nèi)存之間直接傳輸它們的I/O數(shù)據(jù),而不需要系統(tǒng)處理器的參與。DMA數(shù)據(jù)傳輸概覽有兩種方式引發(fā)數(shù)據(jù)傳輸:1,軟件對(duì)數(shù)據(jù)的請(qǐng)求,比如通過(guò)read函數(shù)。2,硬
18、件異步地將數(shù)據(jù)傳遞給系統(tǒng)。第一種情況的步驟如下:1)當(dāng)進(jìn)程調(diào)用read,驅(qū)動(dòng)程序分配一個(gè)DMA緩沖區(qū),并讓硬件將數(shù)據(jù)傳輸?shù)竭@個(gè)緩沖區(qū)中。進(jìn)程處于睡眠狀態(tài)。2)硬件將數(shù)據(jù)寫(xiě)入到DMA緩沖區(qū)中,當(dāng)寫(xiě)入完畢,產(chǎn)生一個(gè)中斷。3)中斷處理程序獲得輸入的數(shù)據(jù),應(yīng)答中斷,并且喚醒進(jìn)程,該進(jìn)程即可讀取數(shù)據(jù)。第二種情況發(fā)生在異步使用DMA時(shí)。比如對(duì)于一個(gè)數(shù)據(jù)采集設(shè)備,即使沒(méi)有進(jìn)程讀取數(shù)據(jù),它也不斷地寫(xiě)入數(shù)據(jù)。此時(shí),驅(qū)動(dòng)程序應(yīng)該維護(hù)一個(gè)緩沖區(qū),其后的read調(diào)用將返回所有積累的數(shù)據(jù)給用戶空間。這種傳輸方式的步驟如下:1)硬件產(chǎn)生中斷,宣告新數(shù)據(jù)的到來(lái)。2)中斷處理程序分配一個(gè)緩沖區(qū),并且告訴硬件向哪里傳輸數(shù)據(jù)。3
19、)外圍設(shè)備將數(shù)據(jù)寫(xiě)入緩沖區(qū),完成后產(chǎn)生另外一個(gè)中斷。4)處理程序分發(fā)新數(shù)據(jù),喚醒任何相關(guān)進(jìn)程,然后執(zhí)行清理工作。高效的DMA處理依賴于中斷報(bào)告!分配DMA緩沖區(qū)使用DMA緩沖區(qū)的主要問(wèn)題是:當(dāng)大于一頁(yè)時(shí),它們必須占據(jù)連續(xù)的物理頁(yè),這是因?yàn)槭褂肐SA或者PCI系統(tǒng)總線傳輸數(shù)據(jù),而這兩種方式使用的都是物理地址。驅(qū)動(dòng)程序作者必須謹(jǐn)慎地為DMA操作分配正確的內(nèi)存類型,因?yàn)椴⒉皇撬袃?nèi)存區(qū)間都適合DMA操作。在實(shí)際操作中,一些設(shè)備和一些系統(tǒng)中的高端內(nèi)存不能用于DMA,這是因?yàn)橥鈬O(shè)備不能使用高端內(nèi)存的地址。對(duì)于有限制的設(shè)備,應(yīng)使用GFP_DMA標(biāo)志調(diào)用kmalloc或者get_free_pages從DM
20、A區(qū)間分配內(nèi)存。另外,還可以通過(guò)使用通用DMA層來(lái)分配緩沖區(qū)??偩€地址使用DMA的設(shè)備驅(qū)動(dòng)程序?qū)⑴c連接到總線接口上的硬件通信,硬件使用的是物理地址,而程序代碼使用的是虛擬地址。實(shí)際上,基于DMA的硬件使用總線地址,而非物理地址。的一些函數(shù)提供了可移植的方案:unsigned long virt_to_bus(volatile void *address);void *bus_to_virt(unsigned long address);這些函數(shù)在內(nèi)核邏輯地址和總線地址間執(zhí)行了簡(jiǎn)單的轉(zhuǎn)換。通用DMA層DMA操作最終會(huì)分配緩沖區(qū),并將總線地址傳遞給設(shè)備。內(nèi)核提供了一個(gè)與總線體系架構(gòu)無(wú)關(guān)的DMA層,
21、它會(huì)隱藏大多數(shù)問(wèn)題。在編寫(xiě)驅(qū)動(dòng)程序時(shí),為DMA操作使用該層。device結(jié)構(gòu)該結(jié)構(gòu)是在Linux設(shè)備模型中用來(lái)表示設(shè)備底層的,驅(qū)動(dòng)程序通常不直接使用該結(jié)構(gòu),但是,在使用通用DMA層時(shí),需要使用它。該結(jié)構(gòu)內(nèi)部隱藏了描述設(shè)備的總線細(xì)節(jié)。 處理復(fù)雜的硬件是否給定的設(shè)備在當(dāng)前主機(jī)上具備執(zhí)行DMA操作的能力?因?yàn)橛械脑O(shè)備受限于24位尋址??梢杂胐ma_set_mask()函數(shù)解決。DMA映射一個(gè)DMA映射是要分配的DMA緩沖區(qū)與為該緩沖區(qū)生成的、設(shè)備可訪問(wèn)地址的組合。DMA映射建立了一個(gè)新的結(jié)構(gòu)類型dma_addr_t來(lái)表示總線地址。dma_addr_t類型的變量對(duì)驅(qū)動(dòng)程序是不透明的,唯一允許的操作是將
22、它們傳遞給DMA支持例程以及設(shè)備本身。根據(jù)DMA緩沖區(qū)期望保留的時(shí)間長(zhǎng)短,PCI代碼有兩種DMA映射:1)一致性映射2)流式DMA映射(推薦)建立一致性DMA映射void *dma_alloc_coherent(struct device *dev,size_t size, dma_addr_t *dma_handle,int flag);該函數(shù)處理了緩沖區(qū)的分配和映射。前兩個(gè)參數(shù)是device結(jié)構(gòu)和所需緩沖區(qū)的大小。函數(shù)在兩處返回結(jié)果:1)函數(shù)的返回值時(shí)緩沖區(qū)的內(nèi)核虛擬地址,可以被驅(qū)動(dòng)程序使用。2)相關(guān)的總線地址則保存在dma_handle中。向系統(tǒng)返回緩沖區(qū)void dma_free_co
23、herent(struct device *dev,size_t size, void *vaddr,dma_addr_t dma_handle);DMA池DMA池是一個(gè)生成小型、一致性DMA映射的機(jī)制。調(diào)用dma_alloc_coherent函數(shù)獲得的映射,可能其最小大小為單個(gè)頁(yè)。如果設(shè)備需要的DMA區(qū)域比這還小,就要用DMA池了。struct dma_pool *dma_pool_create(const char *name,struct device *dev, size_t size,size_t align, size_t allocation);name是DMA池的名字,dev是
24、device結(jié)構(gòu),size是從該池中分配的緩沖區(qū)大小,align是該池分配操作所必須遵守的硬件對(duì)齊原則。銷毀DMA池void dma_pool_destroy(struct dma_pool *pool);DMA池分配內(nèi)存void *dma_pool_alloc(struct dma_pool *pool,int mem_flags, dma_addr_t *handle);釋放內(nèi)存void dma_pool_free(struct dma_pool *pool,void *vaddr,dma_addr_t addr);建立流式DMA映射流式映射具有比一致性映射更為復(fù)雜的接口。這些映射希望能與
25、已經(jīng)由驅(qū)動(dòng)程序分配的緩沖區(qū)協(xié)同工作,因而不得不處理那些不是它們選擇的地址。當(dāng)建立流式映射時(shí),必須告訴內(nèi)核數(shù)據(jù)流動(dòng)的方向。枚舉類型dma_data_direction:DMA_TO_DEVICE 數(shù)據(jù)發(fā)送到設(shè)備(如write系統(tǒng)調(diào)用)DMA_FROM_DEVICE 數(shù)據(jù)被發(fā)送到CPUDMA_BIDIRECTIONAL 數(shù)據(jù)可雙向移動(dòng)DMA_NONE 出于調(diào)試目的。當(dāng)只有一個(gè)緩沖區(qū)要被傳輸?shù)臅r(shí)候,使用dma_map_single函數(shù)映射它:dma_addr_t dma_map_single(struct device *dev,void *buffer,size_t size, enum dma_
26、data_direction direction);返回值是總線地址,可以把它傳遞給設(shè)備。當(dāng)傳輸完畢后,使用dma_unmap_single函數(shù)刪除映射:void dma_unmap_single(struct device *dev,dma_addr_t dma_addr,size_t size, enum dma_data_direction direction);流式DMA映射的幾條原則:*緩沖區(qū)只能用于這樣的傳送,即其傳送方向匹配于映射時(shí)給定的方向。*一旦緩沖區(qū)被映射,它將屬于設(shè)備,而不是處理器。直到緩沖區(qū)被撤銷映射前,驅(qū)動(dòng)程序不能以任何方式訪問(wèn)其中的內(nèi)容。*在DMA處于活動(dòng)期間內(nèi),不
27、能撤銷對(duì)緩沖區(qū)映射,否則會(huì)嚴(yán)重破壞系統(tǒng)的穩(wěn)定性。驅(qū)動(dòng)程序需要不經(jīng)過(guò)撤銷映射就訪問(wèn)流式DMA緩沖區(qū)的內(nèi)容,有如下調(diào)用:void dma_sync_single_for_cpu(struct device *dev,dma_handle_t bus_addr, size_t size,enum dma_data_direction direction);將緩沖區(qū)所有權(quán)交還給設(shè)備:void dma_sync_single_for_device(struct device *dev,dma_handle_t bus_addr, size_t size,enum dma_data_direction d
28、irection);單頁(yè)流式映射有時(shí)候,要為page結(jié)構(gòu)指針指向的緩沖區(qū)建立映射,比如為get_user_pages獲得的用戶空間緩沖區(qū)。dma_addr_t dma_map_page(struct device *dev,struct page *page, unsigned long offset,size_t size, enum dma_data_direction direction);void dma_unmap_page(struct device *dev,dma_addr_t dma_address, size_t size,enum dma_data_direction d
29、irection);分散/聚集映射有幾個(gè)緩沖區(qū),它們需要與設(shè)備雙向傳輸數(shù)據(jù)。可以簡(jiǎn)單地依次映射每一個(gè)緩沖區(qū)并且執(zhí)行請(qǐng)求的操作,但是一次映射整個(gè)緩沖區(qū)表還是很有利的。映射分散表的第一步是建立并填充一個(gè)描述被傳輸緩沖區(qū)的scatterlist結(jié)構(gòu)的數(shù)組。scatterlist結(jié)構(gòu)的成員:struct page *page;unsigned int length;unsigned int offset;映射int dma_map_sg(struct device *dev,struct scatterlist *sg,int nents, enum dma_data_direction direct
30、ion);解除void dma_unmap_sg(struct device *dev,struct scatterlsit *list, int nents,enum dma_data_direction direction);PCI雙重地址周期映射通用DMA支持層使用32位總線地址,然而PCI總線還支持64位地址模式,即雙重地址周期(DAC)。通用DMA層并不支持該模式。要使用PCI總線的DAC,必須設(shè)置一個(gè)單獨(dú)的DMA掩碼:int pci_dac_set_dma_mask(struct pci_dev *pdev,u64 mask);建立映射dma64_addr_t pci_dac_pa
31、ge_to_dma(struct pci_dev *pdev,struct page *page, unsigned long offset,int direction);一個(gè)簡(jiǎn)單的PCI DMA例子這里提供了一個(gè)PCI設(shè)備的DMA例子dad(DMA Acquisition Device)的一部分,說(shuō)明如何使用DMA映射:int dad_transfer(struct dad_dev *dev,int write,void *buffer,size_t count)dma_addr_t bus_addr;dev-dma_dir = (write ? DMA_TO_DEVICE : DMA_FR
32、OM_DEVICE);dev-dma_size = count;/*映射DMA需要的緩沖區(qū)*/bus_addr = dma_map_single(&dev-pci_dev-dev,buffer,count,dev-dma_dir);writeb(dev-mand,DAD_CMD_DISABLEDMA);writeb(dev-mand,write ? DAD_CMD_WR : DAD_CMD_RD);writeb(dev-registers.addr,cpu_to_le32(bus_addr); /*設(shè)置*/writeb(dev-registers.len,cpu_to_le32(count);
33、/*開(kāi)始操作*/writeb(dev-mand,DAD_CMD_ENABLEDMA);return 0;該函數(shù)映射了準(zhǔn)備進(jìn)行傳輸?shù)木彌_區(qū)并且啟動(dòng)設(shè)備操作。另一半工作必須在中斷服務(wù)例程中完成,如:void dad_interrupt(int irq,void *dev_id,struct pt_regs *regs)struct dad_dev *dev = (struct dad_dev *)dev_id;/* 確定中斷是由對(duì)應(yīng)的設(shè)備發(fā)來(lái)的*/dma_unmap_single(dev-pci_dev-dev,dev-dma_addr, dev-dma_size,dev-dma_dir);/*
34、釋放之后,才能訪問(wèn)緩沖區(qū),把它拷貝給用戶 */.ISA設(shè)備的DMAISA總線允許兩種DMA傳輸:本地DMA和ISA總線控制DMA。只討論本地(native)DMA。*非常重要!本地DMA使用主板上的標(biāo)準(zhǔn)DMA控制器電路來(lái)驅(qū)動(dòng)ISA總線上的信號(hào)線。本地DMA,要關(guān)注三種實(shí)體:*8237 DMA控制器(DMAC) 控制器保存了有關(guān)DMA傳輸?shù)男畔ⅲ绶较?、?nèi)存地址、傳輸數(shù)據(jù)量大小等。 還包含了一個(gè)跟蹤傳送狀態(tài)的計(jì)數(shù)器。 當(dāng)控制器接收到一個(gè)DMA請(qǐng)求信號(hào)時(shí),它將獲得總線控制權(quán)并驅(qū)動(dòng)信號(hào)線, 這樣設(shè)備就能讀寫(xiě)數(shù)據(jù)了。*外圍設(shè)備 當(dāng)設(shè)備準(zhǔn)備傳送數(shù)據(jù)時(shí),必須激活DMA請(qǐng)求信號(hào)。 DMAC負(fù)責(zé)管理實(shí)際的傳輸
35、工作;當(dāng)控制器選通設(shè)備后, 硬件設(shè)備就可以順序地讀/寫(xiě)總線上的數(shù)據(jù)。 當(dāng)傳輸結(jié)束時(shí),設(shè)備通常會(huì)產(chǎn)生一個(gè)中斷。*設(shè)備驅(qū)動(dòng)程序 設(shè)備驅(qū)動(dòng)程序完成的工作很少, 它只是負(fù)責(zé)提供DMA控制器的方向、總線地址、傳輸量的大小等。 它還與外圍設(shè)備通信,做好傳輸數(shù)據(jù)的準(zhǔn)備,當(dāng)DMA傳輸完畢后,響應(yīng)中斷。在PC中使用的早期DMA控制器能夠管理四個(gè)“通道”,每個(gè)通道都與一套DMA寄存器相關(guān)聯(lián)。DMA控制器是系統(tǒng)資源,因此,內(nèi)核協(xié)助處理這一資源。內(nèi)核使用DMA注冊(cè)表為DMA通道提供了請(qǐng)求/釋放機(jī)制,并且提供了一組函數(shù)在DMA控制器中配置通道信息。注冊(cè)DMAint request_dma(unsigned int ch
36、annel,const char *name);void free_dma(unsigned int channel);在open操作時(shí)請(qǐng)求通道,比在模塊初始化函數(shù)中請(qǐng)求通道要好一些。注意:使用DMA的每個(gè)設(shè)備需要一根IRQ線,否則它將無(wú)法通知數(shù)據(jù)已經(jīng)傳輸完畢。openint dad_open(struct inode *inode,struct file *filp)sturct dad_device *my_device;.if(error = request_irq(my_device.irq,dad_interrupt, SA_INTERRUPT,dad,NULL) return er
37、ror;if(error = request_dma(my_device.dma,dad) free_irq(my_device.irq,NULL); return error;.return 0;closevoid dad_close(struct inode *inode,struct file *filp)struct dad_device *my_device;.free_dma(my_device.dma);free_irq(my_device.irq,NULL);.與DMA控制器通信注冊(cè)之后,驅(qū)動(dòng)程序的主要任務(wù)包括為適當(dāng)?shù)牟僮髋渲肈MA控制器。幸運(yùn)的是,內(nèi)核導(dǎo)出了驅(qū)動(dòng)程序所需要的所
38、有函數(shù)。當(dāng)read或者write函數(shù)被調(diào)用時(shí),或者準(zhǔn)備異步傳輸時(shí),驅(qū)動(dòng)程序都要對(duì)DMA控制器進(jìn)行配置。unsigned long claim_dma_lock(); 獲得DMA自旋鎖void release_dma_lock(unsigned long flags); 返回DMA自旋鎖void set_dma_mode(unsigned int channel,char mode);表明是從設(shè)備讀入通道(DMA_MODE_READ),還是向設(shè)備寫(xiě)入數(shù)據(jù)(DMA_MODE_WRITE)。void set_dma_addr(unsigned int channel,unsigned int add
39、r);為DMA緩沖區(qū)分配地址。該函數(shù)將addr的最低24位存儲(chǔ)到控制器中。addr參數(shù)必須是總線地址。void set_dma_count(unsigned int channel,unsigned int count);為傳輸?shù)淖止?jié)量賦值。void disable_dma(unsigned int channel);控制器內(nèi)的DMA通道可以被禁用。void enable_dma(unsigned int channel);該函數(shù)告訴控制器,DMA通道包含了合法的數(shù)據(jù)。int get_dma_residue(unsigned int channel);驅(qū)動(dòng)程序有時(shí)需要知道DMA傳輸是否已經(jīng)結(jié)束
40、。該函數(shù)返回還未傳輸?shù)淖止?jié)數(shù)。void clear_dma_ff(unsigned int channel);該函數(shù)清除了DMA的觸發(fā)器。使用這些函數(shù),驅(qū)動(dòng)程序可以實(shí)現(xiàn)如下函數(shù),為DMA傳輸做準(zhǔn)備:int dad_dma_prepare(int channel,int mode,unsigned int buf, unsigned int count)unsigned long flags;flags = claim_dma_lock();disable_dma(channel);clear_dma_ff(channel);set_dma_mode(channel,mode);set_dma_
41、addr(channel,virt_to_bus(buf);set_dma_count(channel,count);enable_dma(channel);release_dma_lock(flags);return 0;下面代碼用來(lái)檢驗(yàn)是否完成DMA:int dad_dma_isdone(int channel)int residue;unsigned long flags = claim_dma_lock();residue = get_dma_residue(channel);release_dma_lock(flags);return (residue = 0);剩下需要做的事情是配
42、置設(shè)備板卡,硬件手冊(cè)是程序員唯一的朋友。附錄資料:不需要的可以自行刪除CentOS網(wǎng)絡(luò)設(shè)置這里介紹一下Linux下的網(wǎng)絡(luò)設(shè)置文件,這是網(wǎng)絡(luò)計(jì)算機(jī)服務(wù)器的前提條件。1網(wǎng)絡(luò)的基本設(shè)置我們?cè)谠O(shè)置網(wǎng)絡(luò)環(huán)境的時(shí)候,提前要弄清楚以下的相關(guān)信息。IP IP地址 Netmak 子網(wǎng)掩碼Gateway 默認(rèn)網(wǎng)關(guān)HostName 主機(jī)名稱DomainName 域名DNS DNS的IP2網(wǎng)絡(luò)設(shè)置文件無(wú)論是通過(guò)網(wǎng)絡(luò)配置命令(下文將提到)來(lái)配置網(wǎng)絡(luò),還是通過(guò)圖形化的配置界面,最終的配置信息都將寫(xiě)入到某某的文件中,也就是說(shuō)一旦我們知道了這些信息都寫(xiě)到了什么文件中或哪兒個(gè)文件中,我們就可以通過(guò)直接的修改某某文件來(lái)直接進(jìn)行配
43、置,下面就說(shuō)明一下網(wǎng)絡(luò)設(shè)置將要涉及到的幾個(gè)主要的文件。不光是 CentOS,其他的UNIX系的OS都可以通過(guò)這個(gè)方法來(lái)配置網(wǎng)絡(luò),不過(guò)系統(tǒng)的不同定義也不同,比如說(shuō)有些系統(tǒng)會(huì)說(shuō)到通過(guò)直接修改文件的方法配置網(wǎng)絡(luò)信息會(huì)導(dǎo)致網(wǎng)絡(luò)環(huán)境的不穩(wěn)定,提倡使用圖形界面或配置命令的形式來(lái)配置網(wǎng)絡(luò),這里要特別的注意。(1)文件 /etc/sysconfig/network這個(gè)/etc/sysconfig/network文件是定義hostname和是否利用網(wǎng)絡(luò)的不接觸網(wǎng)絡(luò)設(shè)備的對(duì)系統(tǒng)全體定義的文件。設(shè)定形式:設(shè)定值=值/etc/sysconfig/network的設(shè)定項(xiàng)目如下:NETWORKING 是否利用網(wǎng)絡(luò) GAT
44、EWAY 默認(rèn)網(wǎng)關(guān)IPGATEWAYDEV 默認(rèn)網(wǎng)關(guān)的接口名HOSTNAME 主機(jī)名DOMAIN 域名(2)文件 /etc/sysconfig/network-scripts/ifcfg-eth0/etc/sysconfig/network-scripts在這個(gè)目錄下面,存放的是網(wǎng)絡(luò)接口(網(wǎng)卡)的制御腳本文件(控制文件),ifcfg- eth0是默認(rèn)的第一個(gè)網(wǎng)絡(luò)接口,如果機(jī)器中有多個(gè)網(wǎng)絡(luò)接口,那么名字就將依此類推ifcfg-eth1,ifcfg-eth2,ifcfg- eth3(這里面的文件是相當(dāng)重要的,涉及到網(wǎng)絡(luò)能否正常工作)設(shè)定形式:設(shè)定值=值設(shè)定項(xiàng)目項(xiàng)目如下:DEVICE 接口名(設(shè)備,
45、網(wǎng)卡)BOOTPROTO IP的配置方法(static:固定IP, dhcpHCP, none:手動(dòng)) HWADDR MAC地址ONBOOT 系統(tǒng)啟動(dòng)的時(shí)候網(wǎng)絡(luò)接口是否有效(yes/no)TYPE 網(wǎng)絡(luò)類型(通常是Ethemet)NETMASK 網(wǎng)絡(luò)掩碼IPADDR IP地址IPV6INIT IPV6是否有效(yes/no)GATEWAY 默認(rèn)網(wǎng)關(guān)IP地址這里有一個(gè)例子:CODE:rootlinux # cat -n /etc/sysconfig/network-scripts/ifcfg-eth0 1 DEVICE=eth0 2 BOOTPROTO=static 3 BROADCAST=55
46、 4 HWADDR=00:0C:2x:6x:0 x:xx 5 IPADDR=3 6 NETMASK= 7 NETWORK= 8 ONBOOT=yes 9 TYPE=Ethernet(3)文件 /etc/resolv.conf這個(gè)文件是用來(lái)配置主機(jī)將用的DNS服務(wù)器信息。在這個(gè)文件中如果不設(shè)置DNS服務(wù)器的IP地址,那么在通信的時(shí)候,將無(wú)法指定像 HYPERLINK /./ t _blank url=/url/url這樣的域名。(DNS是Domain NameSystem的簡(jiǎn)稱,中文名稱域名解析服務(wù)器,主要是IP和域名轉(zhuǎn)換功能)/etc/resolv.conf的設(shè)定項(xiàng)目:domain 定義本地域
47、名search 定義域名和搜索列表nameserver定義被參照的DNS服務(wù)器的IP地址(最多可指定3個(gè))一般來(lái)說(shuō)最重要的是第三個(gè)nameserver項(xiàng)目,沒(méi)有這項(xiàng)定義,用域名將無(wú)法訪問(wèn)網(wǎng)站,并且yum等服務(wù)將無(wú)法利用(4)文件 /etc/hosts/etc/hosts這個(gè)文件是記載LAN內(nèi)接續(xù)的各主機(jī)的對(duì)應(yīng)HostName和IP用的。在LAN內(nèi),我們各個(gè)主機(jī)間訪問(wèn)通信的時(shí)候,用的是內(nèi)網(wǎng)的IP地址進(jìn)行訪問(wèn)(例:2,3),從而確立連接進(jìn)行通信。除了通過(guò)訪問(wèn)IP來(lái)確立通信訪問(wèn)之外,我們還可以通過(guò)HostName進(jìn)行訪問(wèn),我們?cè)诎惭b機(jī)器的時(shí)候都會(huì)給機(jī)器起一個(gè)名字,這個(gè)名字就是這臺(tái)機(jī)器的HostNam
48、e,通過(guò)上圖可以看到,HostA的 hostname是centos1,HostB的hostname是centos2那我們?cè)趺茨懿坏ㄟ^(guò)IP確立連接,通過(guò)這個(gè)IP對(duì)應(yīng)的 HostName進(jìn)行連接訪問(wèn)呢?解決的辦法就是這個(gè)/etc/hosts這個(gè)文件,通過(guò)把LAN內(nèi)的各主機(jī)的IP地址和HostName的一一對(duì)應(yīng)寫(xiě)入這個(gè)文件的時(shí)候,就可以解決問(wèn)題。要在HostA上用ssh訪問(wèn)HostB的時(shí)候,在命令行下做這樣的操作: - CODE:rootcentos1 # ssh 3email=root3sroot3s/email password:Last login: Mon Dec 25 15:04:58
49、2006 from centos1rootcentos2 #訪問(wèn)成功后,我們看到hostname的地方變化了。那么我們用hostname試試看: - CODE:rootcentos1 # ssh centos2ssh:centos2: Name or service not known 提示錯(cuò)誤,不知道主機(jī)rootcentos1 #那么我們編輯/etc/hosts文件,將HostB的IP和hostname的對(duì)應(yīng)關(guān)系寫(xiě)入這個(gè)文件,如果主機(jī)有域名,可以將域名寫(xiě)在IP地址之后hostname之前,并且用空格隔開(kāi),形式如第三行的設(shè)置。 - CODE:rootcentos1 # cat -n /etc/
50、hosts 1 # Do not remove the following line, or various programs 2 # that require network functionality will fail. 3 localhost.localdomain localhost 4 3 centos2rootcentos2 #然后我們?cè)購(gòu)膹?fù)#ssh centos2的操作 - CODE:rootcentos1 # ssh centos2email=rootcentos2srootcentos2s/email password:Last login: Mon Dec 25 15:0
51、5:07 2006 from centos1rootcentos2 #可以看到訪問(wèn)成功了,這個(gè)文件就是這樣的,倘若你要用windowsXP訪問(wèn)局域網(wǎng)中的linux你也可以用上面的方法,只不過(guò)在 windowsXP下面你也要修改hosts這個(gè)文件,文件路徑:C:WINDOWSsystem32driversetchosts,在這個(gè)文件中添加你要訪問(wèn)的局域網(wǎng)中的主機(jī)的IP和hostname,就能通過(guò)主機(jī)名訪問(wèn)主機(jī)了。3網(wǎng)絡(luò)基本命令(1)network service的制御網(wǎng)絡(luò)接口配置信息改動(dòng)后,網(wǎng)絡(luò)服務(wù)必須從新啟動(dòng),來(lái)激活網(wǎng)絡(luò)新配置的使得配置生效,這部分操作和從新啟動(dòng)系統(tǒng)時(shí)時(shí)一樣的作用。制御(控制)
52、是/etc/init.d/network這個(gè)文件,可以用這個(gè)文件后面加上下面的參數(shù)來(lái)操作網(wǎng)絡(luò)服務(wù)。例如:rootlinux #/etc/init.d/networkrestart同樣也可以用service這個(gè)命令來(lái)操作網(wǎng)絡(luò)服務(wù)例如:rootlinux #service network restartstart 啟動(dòng)stop 停止restart 再啟動(dòng)reload 和再啟動(dòng)一樣(.)status 狀態(tài)表示如果服務(wù)器軟件采用rpm的方式安裝,以上的內(nèi)容大多數(shù)都對(duì)應(yīng)。(2)network管理命令網(wǎng)絡(luò)管理還有一些常用的命令,下面介紹幾個(gè)常用的命令。ifconfignetstathostnameping
53、tracerouteifconfig這個(gè)命令可以用于,網(wǎng)絡(luò)接口的啟動(dòng)/停止,更改設(shè)置和表示網(wǎng)絡(luò)狀態(tài),在不添加任何參數(shù)的情況下,這個(gè)ifconfig可以表示網(wǎng)絡(luò)接口的狀態(tài)。例如:rootlinux # ifconfigeth0 Link encap:Ethernet HWaddr00:xx:xx:xx:04:45 inet addr:1 Bcast:55 Mask: inet6 addr: fe80:20c:29ff:fe61:445/64 Scopeink UPBROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RXpackets:472 errors:
54、0 dropped:0 overruns:0 frame:0 TXpackets:445 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RXbytes:35804 (34.9 KiB) TX bytes:53012(51.7 KiB) Interrupt:185 Base address:0 x1080lo Link encapocal Loopback inet addr: Mask: inet6 addr: :1/128 Scope:Host UPLOOPBACK RUNNING MTU:16436
55、 Metric:1 RXpackets:8 errors:0 dropped:0 overruns:0 frame:0 TXpackets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RXbytes:560 (560.0 b) TX bytes:560 (560.0b)rootlinux #看看ifconfig的輸出內(nèi)容1. Link encap 2. HWaddr MAC地址 3.inet addr IP地址(IPV4) 4. Bcast 廣播地址 5. Mask 衍碼 6. inet6 addr I
56、P地址(IPV6) 7. UP 啟動(dòng)中 8. BROADCAST 廣播地址有效 9. RUNNING 動(dòng)作10. MTU 網(wǎng)絡(luò)接口的MTU(MaximumTransfer Unit:Ethernet最大傳送frame值)11. Metric 12. RX packets 受信包數(shù)13. TX packets 送信包數(shù)14. collisions 15. interrupt IRQ號(hào)碼16. Baseaddress I/O地址通過(guò)這個(gè)命令還可以u(píng)p(開(kāi)啟)和down(關(guān)閉)某個(gè)網(wǎng)絡(luò)接口(網(wǎng)卡),例如我們關(guān)閉eth0可以用下面的命令:rootlinux #ifconfigeth0 down相反的開(kāi)
57、啟如下:rootlinux #ifconfigeth0 up通過(guò)這個(gè)命令還可以設(shè)置網(wǎng)絡(luò)接口(網(wǎng)卡),例如我們將eth0的IP設(shè)置成1,子網(wǎng)衍碼設(shè)置成如下:rootlinux #ifconfigetho inet 1 netmask 假如有多個(gè)網(wǎng)絡(luò)接口的情況下,ethX的X部分用網(wǎng)絡(luò)接口碼(數(shù)字,例如eth0,eth1,eth2代替)。netstat這條命令是顯示網(wǎng)絡(luò)各種情況的命令,在不跟隨任何參數(shù)被執(zhí)行的情形下,將表示Active Internet connections和ActiveUNIX domain sockets的情報(bào)??纯聪旅娴妮敵鲂畔ⅲ哼@里是6正在通過(guò)ssh連接1的情形rootl
58、inux #netstatActive Internetconnections (w/o servers)Proto Recv-Q Send-QLocal Address ForeignAddress State tcp 0 0 :ffff:1:ssh :ffff:6:4757 ESTABLISHEDActive UNIX domainsockets (w/o servers)Proto RefCntFlags Type State I-Node Pathunix 11 DGRAM 5202 /dev/logunix 2 DGRAM 5997 /var/run/hal/hotplug_socketunix 2 DGRAM 2536 udevdunix 2 DGRAM 7474unix 3 STREAM CONNECTED 5995 /var/run/dbus/system_bus_socketunix 3 STREAM CONNECTED 5994unix 3 STREAM CONNECTED 5974
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年智能工廠環(huán)境下EMC電磁兼容問(wèn)題深度解析培訓(xùn)
- 2024屆山西省昔陽(yáng)縣中學(xué)高考仿真模擬化學(xué)試卷含解析
- 2024年春季教材更新:20以內(nèi)加減法課件全新解讀
- 數(shù)控編程零件加工理論題
- 2024年教育技術(shù)新篇章:《童心是小鳥(niǎo)》課件的崛起
- 2023年中醫(yī)內(nèi)科學(xué)主治醫(yī)師考試真題及答案解析
- 整改5s通知單空白模板
- 2020年一級(jí)建造師《建筑工程》各章節(jié)考點(diǎn):流水施工方法的應(yīng)用-68
- 2024-2025學(xué)年高中數(shù)學(xué)第三章概率3.1.3概率的基本性質(zhì)作業(yè)含解析新人教A版必修3
- 2025屆中考?xì)v史一輪復(fù)習(xí)考點(diǎn)強(qiáng)化練6遼宋夏金元時(shí)期民族關(guān)系發(fā)展和社會(huì)變化
- 心臟驟停急救-課件
- XX醫(yī)院康復(fù)科建設(shè)方案
- 出差申請(qǐng)表(模板)
- 中藥材技術(shù)創(chuàng)新中心的可行性研究報(bào)告
- 有機(jī)合成化學(xué)(山東聯(lián)盟)知到章節(jié)答案智慧樹(shù)2023年青島科技大學(xué)
- 商標(biāo)法題庫(kù)1(答案)
- TMF自智網(wǎng)絡(luò)白皮書(shū)4.0
- 電視劇《國(guó)家孩子》觀影分享會(huì)PPT三千孤兒入內(nèi)蒙一段流淌著民族大愛(ài)的共和國(guó)往事PPT課件(帶內(nèi)容)
- 所水力除焦設(shè)備介紹
- 改革開(kāi)放英語(yǔ)介紹-課件
- pet考試歷屆真題和答案
評(píng)論
0/150
提交評(píng)論