版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第8章
內(nèi)存和I/O管理
18.1內(nèi)存管理
內(nèi)存管理機(jī)制內(nèi)存保護(hù)2不同實(shí)時(shí)內(nèi)核所采用的內(nèi)存管理方式不同,有的簡(jiǎn)單,有的復(fù)雜。實(shí)時(shí)內(nèi)核所采用的內(nèi)存管理方式與應(yīng)用領(lǐng)域和硬件環(huán)境密切相關(guān)。在強(qiáng)實(shí)時(shí)應(yīng)用領(lǐng)域,內(nèi)存管理方法比較簡(jiǎn)單,甚至不提供內(nèi)存管理功能。一些實(shí)時(shí)性要求不高,可靠性要求比較高,且系統(tǒng)比較復(fù)雜的應(yīng)用在內(nèi)存管理上就相對(duì)復(fù)雜些,可能需要實(shí)現(xiàn)對(duì)操作系統(tǒng)或是任務(wù)的保護(hù)。3嵌入式實(shí)時(shí)操作系統(tǒng)在內(nèi)存管理方面需要考慮如下因素:快速而確定的內(nèi)存管理
不使用內(nèi)存管理:最快速和最確定的內(nèi)存管理方式,適用于那些小型的嵌入式系統(tǒng),系統(tǒng)中的任務(wù)比較少,且數(shù)量固定。通常的操作系統(tǒng)都至少具有基本的內(nèi)存管理方法:提供內(nèi)存分配與釋放的系統(tǒng)調(diào)用。4不使用虛擬存儲(chǔ)技術(shù)
虛擬存儲(chǔ)技術(shù):為用戶提供一種不受物理存儲(chǔ)器結(jié)構(gòu)和容量限制的存儲(chǔ)管理技術(shù),是桌面/服務(wù)器操作系統(tǒng)為在所有任務(wù)中使用有限物理內(nèi)存的通常方法,每個(gè)任務(wù)從內(nèi)存中獲得一定數(shù)量的頁(yè)面,并且,當(dāng)前不訪問的頁(yè)面將被置換出去,為需要頁(yè)面的其他任務(wù)騰出空間。置換是一種具有不確定性的操作:當(dāng)任務(wù)需要使用當(dāng)前被置換出去的頁(yè)面中的代碼和數(shù)據(jù)時(shí),將不得不從磁盤中獲取頁(yè)面,而在內(nèi)存中另外的頁(yè)面又可能不得不需要先被置換出去。在嵌入式實(shí)時(shí)操作系統(tǒng)中一般不使用虛擬存儲(chǔ)技術(shù),以避免頁(yè)面置換所帶來的開銷。
5內(nèi)存保護(hù)
平面內(nèi)存模式:應(yīng)用程序和系統(tǒng)程序能夠?qū)φ麄€(gè)內(nèi)存空間進(jìn)行訪問。平面內(nèi)存模式比較簡(jiǎn)單,易于管理,性能也比較高。適合于程序簡(jiǎn)單、代碼量小和實(shí)時(shí)性要求比較高的領(lǐng)域。內(nèi)存保護(hù):應(yīng)用比較復(fù)雜、程序量比較大的情況;防止應(yīng)用程序破壞操作系統(tǒng)或是其他應(yīng)用程序的代碼和數(shù)據(jù)。6
內(nèi)存保護(hù)包含兩個(gè)方面的內(nèi)容:防止地址越界:每個(gè)應(yīng)用程序都有自己獨(dú)立的地址空間,當(dāng)應(yīng)用程序要訪問某個(gè)內(nèi)存單元時(shí),由硬件檢查該地址是否在限定的地址空間之內(nèi),只有在限定地址空間之內(nèi)的內(nèi)存單元訪問才是合法的,否則需要進(jìn)行地址越界處理;防止操作越權(quán):對(duì)于允許多個(gè)應(yīng)用程序共享的存儲(chǔ)區(qū)域,每個(gè)應(yīng)用程序都有自己的訪問權(quán)限,如果一個(gè)應(yīng)用程序?qū)蚕韰^(qū)域的訪問違反了權(quán)限規(guī)定,則進(jìn)行操作越權(quán)處理。78.1.2內(nèi)存管理機(jī)制
靜態(tài)分配系統(tǒng)在啟動(dòng)前,所有的任務(wù)都獲得了所需要的所有內(nèi)存,運(yùn)行過程中將不會(huì)有新的內(nèi)存請(qǐng)求。在強(qiáng)實(shí)時(shí)系統(tǒng)中,減少內(nèi)存分配在時(shí)間上可能帶來的不確定性。不需要操作系統(tǒng)進(jìn)行專門的內(nèi)存管理操作。系統(tǒng)使用內(nèi)存的效率比較低下,只適合于那些強(qiáng)實(shí)時(shí),且應(yīng)用比較簡(jiǎn)單,任務(wù)數(shù)量可以靜態(tài)確定的系統(tǒng)。
8內(nèi)存管理機(jī)制
動(dòng)態(tài)分配堆(heap):應(yīng)用通過分配(malloc)與釋放(free)操作來使用內(nèi)存。
堆會(huì)帶來碎片:內(nèi)存被逐漸劃分為位于已被使用區(qū)域之間的越來越小的空閑區(qū)域。垃圾回收:對(duì)內(nèi)存堆進(jìn)行重新排列,把碎片組織成為大的連續(xù)可用內(nèi)存空間。但垃圾回收的時(shí)間長(zhǎng)短不確定:不適合于處理實(shí)時(shí)應(yīng)用。在實(shí)時(shí)系統(tǒng)中,避免內(nèi)存碎片的出現(xiàn),而不是在出現(xiàn)內(nèi)存碎片時(shí)進(jìn)行回收。9內(nèi)存管理機(jī)制
常用管理方式:固定大小存儲(chǔ)區(qū):在指定邊界的一塊地址連續(xù)的內(nèi)存空間中,實(shí)現(xiàn)固定大小內(nèi)存塊的分配。
可變大小存儲(chǔ)區(qū):在指定邊界的一塊地址連續(xù)的內(nèi)存空間中,實(shí)現(xiàn)可變大小內(nèi)存塊的分配。應(yīng)用根據(jù)需要從固定大小存儲(chǔ)區(qū)或者可變大小存儲(chǔ)區(qū)中獲得一塊內(nèi)存空間,用完后將該內(nèi)存空間釋放回相應(yīng)的存儲(chǔ)區(qū)。101.固定大小存儲(chǔ)區(qū)管理
可供使用的一段連續(xù)的內(nèi)存空間被稱為是一個(gè)分區(qū);分區(qū)由大小固定的內(nèi)存塊構(gòu)成,且分區(qū)的大小是內(nèi)存塊大小的整數(shù)倍數(shù)。一個(gè)大小為512字節(jié)的分區(qū),內(nèi)存塊為128個(gè)字節(jié)的分區(qū)
內(nèi)存塊1內(nèi)存塊2內(nèi)存塊3內(nèi)存塊4128字節(jié)512字節(jié)11typedef
struct
{
PartitionID ID; /*分區(qū)的ID*/
PartitionName Name; /*分區(qū)的名字*/void *starting_address; /*分區(qū)的起始地址*/
int length; /*分區(qū)的長(zhǎng)度*/
int
buffer_size; /*內(nèi)存塊的大小*/
PartitionAttribute attribute; /*屬性*/
int
number_of_used_blocks;/*剩余內(nèi)存塊數(shù)*/
MemoryChain memory; /*內(nèi)存塊鏈*/}Partition;分區(qū)的數(shù)據(jù)結(jié)構(gòu)
ID表示分區(qū)的標(biāo)識(shí);starting_address表示分區(qū)的起始地址;
length表示分區(qū)的存儲(chǔ)單元的數(shù)量;buffer_size表示分區(qū)中每個(gè)內(nèi)存塊的大??;
attribute表示分區(qū)的屬性;number_of_used_blocks表示分區(qū)中已使用內(nèi)存塊的數(shù)量;
memory為一個(gè)指針,指向分區(qū)中由空閑內(nèi)存塊組成的雙向空閑內(nèi)存塊鏈表的頭結(jié)點(diǎn)。12空閑內(nèi)存塊鏈表
13固定大小存儲(chǔ)區(qū)管理
分區(qū)的操作創(chuàng)建分區(qū)刪除分區(qū)從分區(qū)得到內(nèi)存塊把內(nèi)存塊釋放到分區(qū)獲取分區(qū)ID獲取當(dāng)前創(chuàng)建的分區(qū)的數(shù)量獲取當(dāng)前所有分區(qū)的ID獲取分區(qū)信息
14固定大小存儲(chǔ)區(qū)管理
如果內(nèi)存塊處于空閑狀態(tài),將使用內(nèi)存塊中的幾個(gè)字節(jié)作為控制結(jié)構(gòu),用來存放用于雙向鏈接的前向指針和后向指針。在使用內(nèi)存塊時(shí),內(nèi)存塊中原有的控制信息不再有效,其中的所有存儲(chǔ)空間都可以被使用。固定大小存儲(chǔ)區(qū)管理的系統(tǒng)開銷對(duì)用戶的影響為零。由于內(nèi)存塊的大小固定,不存在碎片的問題。152.可變大小存儲(chǔ)區(qū)管理
可變大小存儲(chǔ)區(qū)管理為基于堆的管理方式。堆為一段連續(xù)的、大小可配置的內(nèi)存空間,用來提供可變內(nèi)存塊的分配??勺儍?nèi)存塊稱為段,最小分配單位稱為頁(yè),即段的大小是頁(yè)的大小的整數(shù)倍。如果申請(qǐng)段的大小不是頁(yè)的倍數(shù),實(shí)時(shí)內(nèi)核將會(huì)對(duì)段的大小進(jìn)行調(diào)整,調(diào)整為頁(yè)的倍數(shù)。如,從頁(yè)大小為256個(gè)字節(jié)的堆中分配一個(gè)大小為350字節(jié)的段,實(shí)時(shí)內(nèi)核實(shí)際分配的段大小為512個(gè)字節(jié)。
16typedef
struct{
HeapID ID; /*堆的ID*/
HeadName name; /*堆的名字*/
TaskQueue
waitQueue; /*等待隊(duì)列*/void *starting_address; /*內(nèi)存空間起始地址*/
int length; /*內(nèi)存空間長(zhǎng)度/字節(jié)*/
int
page_size; /*頁(yè)長(zhǎng)度(字節(jié))*/
int
maximum_segment_size; /*最大可用段大小*/
RegionAttribute attribute; /*堆的屬性*/
int
number_of_used_blocks; /*分配的塊數(shù)*/
HeapMemoryChain memory; /*堆頭控制結(jié)構(gòu)*/}Heap;堆的數(shù)據(jù)結(jié)構(gòu)
waitQueue用來表示任務(wù)等待隊(duì)列,如果任務(wù)從堆中申請(qǐng)段不能得到滿足,將被阻塞在堆的等待隊(duì)列上;starting_address用來表示堆在內(nèi)存中的起始地址;length表示堆的大??;page_size為頁(yè)的大??;maximum_segment_size表示堆中當(dāng)前最大可用段的大?。籥ttribute表示堆的屬性;number_of_used_blocks表示已分配使用的內(nèi)存塊的數(shù)量;memory表示空閑段鏈表。17可變大小存儲(chǔ)區(qū)管理
可變大小存儲(chǔ)區(qū)中的空閑段通過雙向鏈表鏈接起來,形成一個(gè)空閑段鏈。在創(chuàng)建堆時(shí),只有一個(gè)空閑段,其大小為整個(gè)存儲(chǔ)區(qū)的大小減去控制結(jié)構(gòu)的內(nèi)存開銷。從存儲(chǔ)區(qū)中分配段時(shí),可依據(jù)首次適應(yīng)算法,查看空閑鏈中是否存在合適的段。當(dāng)把段釋放回存儲(chǔ)區(qū)時(shí),該段將被掛在空閑段鏈的鏈尾。如果空閑鏈中有與該段相鄰的段,則將其合并成一個(gè)更大的空閑段。由于對(duì)申請(qǐng)的內(nèi)存的大小作了一些限制,避免了內(nèi)存碎片的產(chǎn)生。18可變大小存儲(chǔ)區(qū)管理
堆的空閑段鏈
在段的控制塊中設(shè)置了一個(gè)標(biāo)志位,表示段被使用的情況:1表示該段正被使用,0表示該段空閑。在固定大小存儲(chǔ)區(qū)管理方式中,只有在空閑狀態(tài)下,內(nèi)存塊才擁有控制信息。在可變大小存儲(chǔ)區(qū)管理方式中,無論段空閑或是正在被使用,段的控制結(jié)構(gòu)都始終存在。
19可變大小存儲(chǔ)區(qū)管理
堆的操作創(chuàng)建堆從堆中得到內(nèi)存塊釋放內(nèi)存塊到堆中擴(kuò)展堆獲得已分配內(nèi)存塊的實(shí)際可用空間大小刪除堆獲得堆的ID獲得在堆上等待的任務(wù)數(shù)量獲得等待任務(wù)的ID列表獲得堆的數(shù)量獲得堆列表獲得堆信息20C/OS中的存儲(chǔ)管理C/OS中是實(shí)模式存儲(chǔ)管理不劃分內(nèi)核空間和用戶空間,整個(gè)系統(tǒng)只有一個(gè)地址空間,即物理內(nèi)存空間,應(yīng)用程序和內(nèi)核程序都能直接對(duì)所有的內(nèi)存單元進(jìn)行訪問;系統(tǒng)中的“任務(wù)”,實(shí)際上都是線程–––只有運(yùn)行上下文和棧是獨(dú)享的,其他資源都是共享的。內(nèi)存布局代碼段(text)、數(shù)據(jù)段(data)、bss段、堆空間、??臻g;內(nèi)存管理,管的是誰?堆!21什么是bss段?一個(gè)程序本質(zhì)上都是由
bss段、data段、text段三個(gè)組成的。在當(dāng)前的計(jì)算機(jī)程序設(shè)計(jì)中是很重要的一個(gè)基本概念。而且在嵌入式系統(tǒng)的設(shè)計(jì)中也非常重要,牽涉到嵌入式系統(tǒng)運(yùn)行時(shí)的內(nèi)存大小分配,存儲(chǔ)單元占用空間大小的問題。
在采用段式內(nèi)存管理的架構(gòu)中(比如intel的80x86系統(tǒng)),bss段(BlockStartedbySymbolsegment)通常是指用來存放程序中未初始化的全局變量的一塊內(nèi)存區(qū)域,一般在初始化時(shí)bss段部分將會(huì)清零。bss段屬于靜態(tài)內(nèi)存分配,即程序一開始就將其清零了。
比如,在C語言之類的程序編譯完成之后,已初始化的全局變量保存在.data段中,未初始化的全局變量保存在.bss段中。
在《Programminggroundup》里對(duì).bss的解釋為:Thereisanothersectioncalledthe.bss.Thissectionislikethedatasection,exceptthatitdoesn’ttakeupspaceintheexecutable.
text和data段都在可執(zhí)行文件中(在嵌入式系統(tǒng)里一般是固化在鏡像文件中),由系統(tǒng)從可執(zhí)行文件中加載;而bss段不在可執(zhí)行文件中,由系統(tǒng)初始化。22malloc/free?在ANSIC中可以用malloc()和free()兩個(gè)函數(shù)動(dòng)態(tài)地分配內(nèi)存和釋放內(nèi)存。在嵌入式實(shí)時(shí)操作系統(tǒng)中,容易產(chǎn)生碎片。由于內(nèi)存管理算法的原因,malloc()和free()函數(shù)執(zhí)行時(shí)間是不確定的。μC/OS-II對(duì)malloc()和free()函數(shù)進(jìn)行了改進(jìn),使得它們可以分配和釋放固定大小的內(nèi)存塊。這樣一來,malloc()和free()函數(shù)的執(zhí)行時(shí)間也是固定的了
3Kb堆初始狀態(tài)A(1Kb)B(1Kb)C(1Kb)3個(gè)申請(qǐng)1KbB(1Kb)1Kb釋放A,C23C/OS中的存儲(chǔ)管理C/OS采用的是固定分區(qū)的存儲(chǔ)管理方法μC/OS把連續(xù)的大塊內(nèi)存按分區(qū)來管理,每個(gè)分區(qū)包含有整數(shù)個(gè)大小相同的塊;在一個(gè)系統(tǒng)中可以有多個(gè)內(nèi)存分區(qū),這樣,用戶的應(yīng)用程序就可以從不同的內(nèi)存分區(qū)中得到不同大小的內(nèi)存塊。但是,特定的內(nèi)存塊在釋放時(shí)必須重新放回它以前所屬于的內(nèi)存分區(qū);采用這樣的內(nèi)存管理算法,上面的內(nèi)存碎片問題就得到了解決。24內(nèi)存分區(qū)示意圖分區(qū)1分區(qū)2分區(qū)3分區(qū)4內(nèi)存塊25內(nèi)存控制塊為了便于管理,在μC/OS中使用內(nèi)存控制塊MCB(MemoryControlBlock)來跟蹤每一個(gè)內(nèi)存分區(qū),系統(tǒng)中的每個(gè)內(nèi)存分區(qū)都有它自己的MCB。typedef
struct{void*OSMemAddr; /*分區(qū)起始地址*/void*OSMemFreeList;//下一個(gè)空閑內(nèi)存塊
INT32UOSMemBlkSize;/*內(nèi)存塊的大小*/INT32UOSMemNBlks; /*內(nèi)存塊數(shù)量*/INT32UOSMemNFree; /*空閑內(nèi)存塊數(shù)量*/}OS_MEM;26內(nèi)存管理初始化如果要在μC/OS-II中使用內(nèi)存管理,需要在OS_CFG.H文件中將開關(guān)量OS_MEM_EN設(shè)置為1。這樣μC/OS-II在系統(tǒng)初始化OSInit()時(shí)就會(huì)調(diào)用OSMemInit(),對(duì)內(nèi)存管理器進(jìn)行初始化,建立空閑的內(nèi)存控制塊鏈表。OSMemAddrOSMemFreeListOSMemBlkSizeOSMemNBlksOSMemNFreeOSMemAddrOSMemFreeListOSMemBlkSizeOSMemNBlksOSMemNFreeOSMemAddrOSMemFreeListOSMemBlkSizeOSMemNBlksOSMemNFreeOSMemFreeList0OS_MAX_MEM_PART…27創(chuàng)建一個(gè)內(nèi)存分區(qū)OSMemCreate()OS_MEM*OSMemCreate(
void*addr,//內(nèi)存分區(qū)的起始地址
INT32Unblks,//分區(qū)內(nèi)的內(nèi)存塊數(shù)
INT32Ublksize,//每個(gè)內(nèi)存塊的字節(jié)數(shù)
INT8U*err);//指向錯(cuò)誤碼的指針例子OS_MEM*CommTxBuf;INT8UCommTxPart[100][32];CommTxBuf=OSMemCreate(CommTxPart,
100,32,&err);28OSMemCreate()從系統(tǒng)的空閑內(nèi)存控制塊中取得一個(gè)MCB;將這個(gè)內(nèi)存分區(qū)中的所有內(nèi)存塊鏈接成一個(gè)單向鏈表;在對(duì)應(yīng)的MCB中填寫相應(yīng)的信息。MCB29分配一個(gè)內(nèi)存塊void*OSMemGet(OS_MEM*pmem,
INT8U*err);功能:從已經(jīng)建立的內(nèi)存分區(qū)中申請(qǐng)一個(gè)內(nèi)存塊。該函數(shù)的唯一參數(shù)是指向特定內(nèi)存分區(qū)的指針。如果沒有空閑的內(nèi)存塊可用,返回NULL指針。應(yīng)用程序必須知道內(nèi)存塊的大小,并且在使用時(shí)不能超過該容量。30釋放一個(gè)內(nèi)存塊INT8UOSMemPut(OS_MEM*pmem,
void*pblk);功能:將一個(gè)內(nèi)存塊釋放并放回到相應(yīng)的內(nèi)存分區(qū)中。注意:用戶應(yīng)用程序必須確認(rèn)將內(nèi)存塊放回到了正確的內(nèi)存分區(qū)中,因?yàn)镺SMemPut()并不知道一個(gè)內(nèi)存塊是屬于哪個(gè)內(nèi)存分區(qū)的。31等待一個(gè)內(nèi)存塊如果沒有空閑的內(nèi)存塊,OSMemGet()立即返回NULL。能否在沒有空閑內(nèi)存塊的時(shí)候讓任務(wù)進(jìn)入等待狀態(tài)?μC/OS-II本身在內(nèi)存管理上并不支持這項(xiàng)功能,如果需要的話,可以通過為特定內(nèi)存分區(qū)增加信號(hào)量的方法,來實(shí)現(xiàn)此功能?;舅悸罚寒?dāng)應(yīng)用程序需要申請(qǐng)內(nèi)存塊時(shí),首先要得到一個(gè)相應(yīng)的信號(hào)量,然后才能調(diào)用OSMemGet()函數(shù)。32OS_EVENT*SemaphorePtr;OS_MEM*PartitionPtr;INT8UPartition[100][32];OS_STKTaskStk[1000];voidmain(void){INT8Uerr;
OSInit();...
SemaphorePtr=OSSemCreate(100);
PartitionPtr=OSMemCreate(Partition,100,32,&err);
OSTaskCreate(Task,(void*)0,&TaskStk[999],&err);
OSStart();}33voidTask(void*pdata){INT8Uerr;
INT8U*pblock;
for(;;){
OSSemPend(SemaphorePtr,0,&err);
pblock=OSMemGet(PartitionPtr,&err);
/*使用內(nèi)存塊*/...
OSMemPut(PartitionPtr,pblock);
OSSemPost(SemaphorePtr);}}34/*MEMORYCONTROLBLOCK*/typedef
struct{
/*Pointertobeginningofmemorypartition*/
void*OSMemAddr;
/*Pointertolistoffreememoryblocks*/
void*OSMemFreeList;
/*Size(inbytes)ofeachblockofmemory*/INT32UOSMemBlkSize;
/*Totalnumberofblocksinthispartition*/
INT32UOSMemNBlks;
/*Numberofmemoryblocksremaininginthispartition*/
INT32UOSMemNFree;}OS_MEM;
Memorycontrolblockdatastructure
35/*Max.numberofmemorypartitions...*/#defineOS_MAX_MEM_PART32/*Storageformemorypartitionmanager*/OS_MEMOSMemTbl[OS_MAX_MEM_PART];voidOS_MemInit(void){OS_MEM*pmem;INT16Ui;
pmem=(OS_MEM*)&OSMemTbl[0];/*Pointtomemorycontrolblock(MCB)*/for(i=0;i<(OS_MAX_MEM_PART-1);i++){/*Init.listoffreememorypartitions*//*Chainlistoffreepartitions*/
pmem->OSMemFreeList=(void*)&OSMemTbl[i+1];/*Storestartaddressofmemorypartition*/
pmem->OSMemAddr=(void*)0;
pmem->OSMemNFree=0;/*Nofreeblocks*/
pmem->OSMemNBlks=0;/*Noblocks*/
pmem->OSMemBlkSize=0;/*Zerosize*/
pmem++;}
pmem->OSMemFreeList=(void*)0;/*Initializelastnode*/
pmem->OSMemAddr=(void*)0;/*Storestartaddressofmemorypartition*/
pmem->OSMemNFree=0;/*Nofreeblocks*/
pmem->OSMemNBlks=0;/*Noblocks*/
pmem->OSMemBlkSize=0;/*Zerosize*//*Pointtobeginningoffreelist*/
OSMemFreeList=(OS_MEM*)&OSMemTbl[0];}OS_MemInit
36可變大小存儲(chǔ)區(qū)管理
OS_MEM*OSMemCreate(void*addr,INT32Unblks,INT32Ublksize,INT8U*err){
OS_MEM*pmem;INT8U*pblk;void**plink;INT32Ui;OS_ENTER_CRITICAL();
pmem=OSMemFreeList;/*Getnextfreememorypartition*/if(OSMemFreeList!=(OS_MEM*)0){/*Seeifpooloffreepartitionswasempty*/
OSMemFreeList=(OS_MEM*)OSMemFreeList->OSMemFreeList;}OS_EXIT_CRITICAL();if(pmem==(OS_MEM*)0){/*Seeifwehaveamemorypartition*/*err=OS_MEM_INVALID_PART;return((OS_MEM*)0);}plink=(void**)addr;/*Createlinkedlistoffreememoryblocks*/
pblk=(INT8U*)addr+blksize;for(i=0;i<(nblks-1);i++){*plink=(void*)pblk;plink=(void**)pblk;
pblk=pblk+blksize;}*plink=(void*)0;/*LastmemoryblockpointstoNULL*/
pmem->OSMemAddr=addr;/*Storestartaddressofmemorypartition*/
pmem->OSMemFreeList=addr;/*Initializepointertopooloffreeblocks*/
pmem->OSMemNFree=nblks;/*StorenumberoffreeblocksinMCB*/
pmem->OSMemNBlks=nblks;
pmem->OSMemBlkSize=blksize;/*Storeblocksizeofeachmemoryblocks*/*err=OS_NO_ERR;return(pmem);}OSMemCreate37可變大小存儲(chǔ)區(qū)管理
void*OSMemGet(OS_MEM*pmem,INT8U*err){void*pblk;OS_ENTER_CRITICAL();if(pmem->OSMemNFree>0){/*Seeifthereareanyfreememoryblocks*/
pblk=pmem->OSMemFreeList;/*Yes,pointtonextfreememoryblock*/
pmem->OSMemFreeList=*(void**)pblk;/*Adjustpointertonewfreelist*/
pmem->OSMemNFree--;/*Onelessmemoryblockinthispartition*/OS_EXIT_CRITICAL();*err=OS_NO_ERR;/*Noerror*/return(pblk);/*Returnmemoryblocktocaller*/}OS_EXIT_CRITICAL();*err=OS_MEM_NO_FREE_BLKS;/*No,Notifycallerofemptymemorypartition*/return((void*)0);/*ReturnNULLpointertocaller*/}OSMemGet
38可變大小存儲(chǔ)區(qū)管理
INT8UOSMemPut(OS_MEM*pmem,void*pblk){OS_ENTER_CRITICAL();if(pmem->OSMemNFree>=pmem->OSMemNBlks){/*Makesureallblocksnotalreadyreturned*/OS_EXIT_CRITICAL();return(OS_MEM_FULL);}/*Insertreleasedblockintofreeblocklist*/*(void**)pblk=pmem->OSMemFreeList;
pmem->OSMemFreeList=pblk;
pmem->OSMemNFree++;/*Onemorememoryblockinthispartition*/OS_EXIT_CRITICAL();return(OS_NO_ERR);/*Notifycallerthatmemoryblockwasreleased*/}OSMemPut
393.內(nèi)存保護(hù)
內(nèi)存保護(hù)可通過硬件提供的MMU(memorymanagementunit)來實(shí)現(xiàn)。目前,大多數(shù)處理器都集成了MMU:大幅度降低那些通過在處理器外部添加MMU模塊的處理方式所存在的內(nèi)存訪問延遲。MMU現(xiàn)在大都被設(shè)計(jì)作為處理器內(nèi)部指令執(zhí)行流水線的一部分,使得使用MMU不會(huì)降低系統(tǒng)性能,相反,如果系統(tǒng)軟件不使用MMU,還會(huì)導(dǎo)致處理器的性能降低。在某些情況下,不使能MMU,跳過處理器的相應(yīng)流水線,可能導(dǎo)致處理器的性能降低80%左右。40內(nèi)存保護(hù)
早期的嵌入式操作系統(tǒng)大都沒有采用MMU:一方面是出于對(duì)硬件成本的考慮;另一方面是出于實(shí)時(shí)性的考慮。嵌入式系統(tǒng)發(fā)展到現(xiàn)在,硬件成本越來越低,MMU所帶來的成本因素基本上可以不用考慮原來的嵌入式CPU的速度較慢,采用MMU通常會(huì)造成對(duì)時(shí)間性能的不滿足,而現(xiàn)在CPU的速度也越來越快,并且采用新技術(shù)后,已經(jīng)將MMU所帶來的時(shí)間代價(jià)降低到比較低的程度嵌入式CPU具有MMU的功能已經(jīng)是一種必要的趨勢(shì)。41內(nèi)存保護(hù)
由于采用MMU后對(duì)應(yīng)用的運(yùn)行模式甚至開發(fā)模式都會(huì)有一些影響,大量嵌入式操作系統(tǒng)都沒有使用MMU。對(duì)于安全性、可靠性要求高的應(yīng)用來講如果不采用MMU,則幾乎不可能達(dá)到應(yīng)用的要求。如果沒有MMU的功能,將無法防止程序的無意破壞,無法截獲各種非法的訪問異常,當(dāng)然更不可能防止應(yīng)用程序的蓄意破壞了。采用MMU后,便于發(fā)現(xiàn)更多的潛在問題,并且也便于問題的定位。未采用MMU時(shí),內(nèi)存模式一般都是平面模式,應(yīng)用可以任意訪問任何內(nèi)存區(qū)域、任何硬件設(shè)備,程序中出現(xiàn)非法訪問時(shí),開發(fā)人員是無從知曉的,也非常難于定位。42內(nèi)存保護(hù)
MMU通常具有如下功能:內(nèi)存映射;檢查邏輯地址是否在限定的地址范圍內(nèi),防止頁(yè)面地址越界;檢查對(duì)內(nèi)存頁(yè)面的訪問是否違背特權(quán)信息,防止越權(quán)操作內(nèi)存頁(yè)面;在必要的時(shí)候(頁(yè)面地址越界或是頁(yè)面操作越權(quán))產(chǎn)生異常。
43通過MMU進(jìn)行內(nèi)存映射內(nèi)存映射把應(yīng)用程序使用的地址集合(邏輯地址)翻譯為實(shí)際的物理內(nèi)存地址(物理地址)44內(nèi)存保護(hù)
大多數(shù)處理器的典型頁(yè)面大小為4K字節(jié),有些處理器也可能使用大于4K字節(jié)的頁(yè)面,但頁(yè)面大小總是2的冪,以對(duì)發(fā)生在MMU中的地址映射行為流水線化。當(dāng)頁(yè)放置到物理內(nèi)存時(shí),頁(yè)面將放置到頁(yè)框架(pageframe)中。頁(yè)框架是物理內(nèi)存的一部分,具有與頁(yè)面同樣的大小,且開始地址為頁(yè)面大小的整數(shù)倍。45內(nèi)存保護(hù)
MMU包含著能夠把邏輯地址映射為物理地址的表,稱為頁(yè)表。操作系統(tǒng)能夠在需要的時(shí)候?qū)@種映射關(guān)系進(jìn)行改變:應(yīng)用程序?qū)?nèi)存的需求發(fā)生變化或是添加或刪除應(yīng)用程序的時(shí)候。在應(yīng)用程序中的任務(wù)發(fā)生上下文切換時(shí)。
46內(nèi)存保護(hù)
基于頁(yè)表的內(nèi)存映射過程例如,一個(gè)系統(tǒng)具有32位的地址空間和4K字節(jié)的頁(yè)面,32位的地址空間由20位的頁(yè)號(hào)和12位的頁(yè)內(nèi)偏移量構(gòu)成。MMU將檢查20位的頁(yè)號(hào),并為該頁(yè)面提供(根據(jù)MMU表進(jìn)行映射)頁(yè)框架地址。47內(nèi)存保護(hù)
每個(gè)內(nèi)存頁(yè)還具有一些特權(quán)和狀態(tài)信息。MMU提供二進(jìn)制位來標(biāo)識(shí)每個(gè)頁(yè)面的特權(quán)或狀態(tài)信息。這些二進(jìn)制位用來確定頁(yè)面中的內(nèi)容是否:可被處理器指令所使用(執(zhí)行特權(quán))可寫(寫特權(quán))可讀(讀特權(quán))已被回寫(臟位)當(dāng)前在物理內(nèi)存中(有效位)48內(nèi)存保護(hù)
在操作系統(tǒng)的支持下,MMU還提供虛擬存儲(chǔ)功能,即在任務(wù)所需要的內(nèi)存空間超過能夠從系統(tǒng)中獲得的物理內(nèi)存空間的情況下,也能夠得到正常運(yùn)行。當(dāng)需要的頁(yè)面被添加到邏輯地址空間時(shí),任務(wù)對(duì)內(nèi)存頁(yè)面的合法訪問,將自動(dòng)訪問到物理內(nèi)存。頁(yè)面當(dāng)前不在物理內(nèi)存中時(shí),將導(dǎo)致頁(yè)面故障異常,然后操作系統(tǒng)負(fù)責(zé)從后援存儲(chǔ)器(如硬盤或是FLASH存儲(chǔ)設(shè)備)中獲取需要的頁(yè)面,并從產(chǎn)生頁(yè)面故障的機(jī)器指令處重新執(zhí)行。49內(nèi)存保護(hù)
MMU通常具有如下不同功能程度的使用方式:0級(jí),內(nèi)存的平面使用模式?jīng)]有使用MMU,應(yīng)用程序和系統(tǒng)程序能夠?qū)φ麄€(gè)內(nèi)存空間進(jìn)行訪問。采用該模式的系統(tǒng)比較簡(jiǎn)單、性能也比較高,適合于程序簡(jiǎn)單、代碼量小和實(shí)時(shí)性要求比較高的領(lǐng)域。大多數(shù)傳統(tǒng)的嵌入式操作系統(tǒng)都采用該模式;50內(nèi)存保護(hù)
1級(jí),用來處理具有MMU和內(nèi)存緩存的嵌入式處理器通常只是打開MMU,并通過創(chuàng)建一個(gè)域(domain,為內(nèi)存保護(hù)的基本單位,每個(gè)域?qū)?yīng)一個(gè)頁(yè)表)的方式來使用內(nèi)存,并對(duì)每次內(nèi)存訪問執(zhí)行一些必要的地址轉(zhuǎn)換操作。該模式仍然只是擁有MMU打開特性的平面內(nèi)存模式;51內(nèi)存保護(hù)
2級(jí),內(nèi)存保護(hù)模式
MMU被打開,且創(chuàng)建了靜態(tài)的域(應(yīng)用程序的邏輯地址同應(yīng)用程序在物理內(nèi)存中的物理地址之間的映射關(guān)系在系統(tǒng)運(yùn)行前就已經(jīng)確定),以保護(hù)應(yīng)用和操作系統(tǒng)在指針試圖訪問其他程序的地址空間時(shí)不會(huì)被非法操作。通常使用消息傳送機(jī)制實(shí)現(xiàn)數(shù)據(jù)在被MMU保護(hù)起來的各個(gè)域之間的移動(dòng)。52內(nèi)存保護(hù)
3級(jí),虛擬內(nèi)存使用模式
通過操作系統(tǒng)使用CPU提供的內(nèi)存映射機(jī)制,內(nèi)存頁(yè)被動(dòng)態(tài)地分配、釋放或是重新分配。從內(nèi)存映射到基于磁盤的虛擬內(nèi)存頁(yè)的過程是透明的。53內(nèi)存保護(hù)
0級(jí)模式為大多數(shù)傳統(tǒng)嵌入式實(shí)時(shí)操作系統(tǒng)的使用模式,同1級(jí)模式一樣,都是內(nèi)存的平面使用模式,不能實(shí)現(xiàn)內(nèi)存的保護(hù)功能。
2級(jí)模式是目前大多數(shù)嵌入式實(shí)時(shí)操作系統(tǒng)所采用的內(nèi)存管理模式,既能實(shí)現(xiàn)內(nèi)存保護(hù)功能,又能通過靜態(tài)域的使用方式保證系統(tǒng)的實(shí)時(shí)特性。
3級(jí)模式適合于應(yīng)用比較復(fù)雜、程序量比較大,并不要求實(shí)時(shí)性的應(yīng)用領(lǐng)域。
54內(nèi)存保護(hù)
基于靜態(tài)域的MMU使用方式也稱為是一一對(duì)應(yīng)的使用方式。在這種一一對(duì)應(yīng)的使用方式中,應(yīng)用程序的邏輯地址同應(yīng)用程序在物理內(nèi)存中的物理地址相同,簡(jiǎn)化了內(nèi)存管理的實(shí)現(xiàn)方式。55內(nèi)存保護(hù)
在嵌入式實(shí)時(shí)操作系統(tǒng)中,MMU通常被用來進(jìn)行內(nèi)存保護(hù):實(shí)現(xiàn)操作系統(tǒng)與應(yīng)用程序的隔離應(yīng)用程序和應(yīng)用程序之間的隔離防止應(yīng)用程序破壞操作系統(tǒng)的代碼、數(shù)據(jù)以及應(yīng)用程序?qū)τ布闹苯釉L問。對(duì)于應(yīng)用程序來講,也可以防止別的應(yīng)用程序?qū)ψ约旱姆欠ㄈ肭?,從而破壞?yīng)用程序自身的運(yùn)行。
56內(nèi)存保護(hù)
在內(nèi)存保護(hù)方面,MMU提供了以下措施:防止地址越界通過限長(zhǎng)寄存器檢查邏輯地址,確保應(yīng)用程序只能訪問邏輯地址空間所對(duì)應(yīng)的、限定的物理地址空間,MMU將在邏輯地址超越限長(zhǎng)寄存器所限定的范圍時(shí)產(chǎn)生異常;防止操作越權(quán)
根據(jù)內(nèi)存頁(yè)面的特權(quán)信息控制應(yīng)用程序?qū)?nèi)存頁(yè)面的訪問,如果對(duì)內(nèi)存頁(yè)面的訪問違背了內(nèi)存頁(yè)面的特權(quán)信息,MMU將產(chǎn)生異常。57內(nèi)存保護(hù)
簡(jiǎn)單的MMU保護(hù)模式應(yīng)用程序之間要通信就只能通過操作系統(tǒng)提供的通信服務(wù),如:信號(hào)量、管道、消息、共享內(nèi)存等,而不能直接訪問彼此的地址空間。MMU通常還提供權(quán)限等級(jí),不同的權(quán)限等級(jí)對(duì)硬件訪問的權(quán)限不一樣。操作系統(tǒng)一般運(yùn)行在核心態(tài),具有所有的特權(quán),而應(yīng)用則一般運(yùn)行在用戶態(tài),具有一般權(quán)限,以防止應(yīng)用程序的故意破壞。58內(nèi)存保護(hù)
基于域的內(nèi)存管理方式
59內(nèi)存保護(hù)
一個(gè)域可以包含多個(gè)任務(wù)、內(nèi)存頁(yè)、系統(tǒng)對(duì)象(信號(hào)量、隊(duì)列等)和各種共享區(qū)域等,代表了一個(gè)執(zhí)行環(huán)境,是一個(gè)隔離的空間,與進(jìn)程的概念類似??梢哉J(rèn)為域是資源分配的單位,任務(wù)則是內(nèi)核調(diào)度的單位。在基于域的管理方式中,域就是一個(gè)獨(dú)立的空間,共享庫(kù)、內(nèi)核等部分的代碼和數(shù)據(jù)空間直接映射到域空間中,在每個(gè)域中都是獨(dú)立的。應(yīng)用和應(yīng)用之間,應(yīng)用和嵌入式實(shí)時(shí)操作系統(tǒng)內(nèi)核之間通過域的方式進(jìn)行了相互隔離,互不侵犯;共享庫(kù)(如文件系統(tǒng),網(wǎng)絡(luò)協(xié)議,圖形用戶接口等)采用非受限訪問方式,以提高應(yīng)用的運(yùn)行速度。但可能由于沒有對(duì)共享庫(kù)采用任何的保護(hù)機(jī)制,容易造成系統(tǒng)崩潰的現(xiàn)象。如果要實(shí)現(xiàn)全面的保護(hù),共享庫(kù)也應(yīng)該通過域的方式進(jìn)行管理,并按照客戶/服務(wù)器的方式提供服務(wù);操作系統(tǒng)內(nèi)核可通過TRAP(自陷)的機(jī)制提供服務(wù);堆是域私有的,進(jìn)一步提高了安全性。608.2I/O管理
I/O管理的功能I/O實(shí)現(xiàn)的考慮61
在通用操作系統(tǒng)中,I/O管理采用層次結(jié)構(gòu)的思想(如四個(gè)層次的結(jié)構(gòu):中斷處理程序,設(shè)備驅(qū)動(dòng)程序,與設(shè)備無關(guān)的操作系統(tǒng)軟件,用戶層軟件):較低層的軟件要使較高層的軟件獨(dú)立于硬件的特性,較高層軟件則要向用戶提供一個(gè)友好、清晰、規(guī)范的界面。在I/O管理的層次結(jié)構(gòu)中,主要通過設(shè)備獨(dú)立的I/O系統(tǒng)和設(shè)備驅(qū)動(dòng)程序來共同完成I/O操作。設(shè)備驅(qū)動(dòng)程序通過一組例程來提供比較低級(jí)的I/O功能,比如把字節(jié)序列輸入或輸出到面向字符的設(shè)備中。高級(jí)協(xié)議(如面向字符設(shè)備的通信協(xié)議)則由與設(shè)備無關(guān)的I/O系統(tǒng)來實(shí)現(xiàn)。62
在實(shí)時(shí)內(nèi)核的I/O系統(tǒng)中,用戶I/O請(qǐng)求在到達(dá)設(shè)備驅(qū)動(dòng)程序之前,通常都只進(jìn)行非常少量的處理。實(shí)時(shí)內(nèi)核的I/O系統(tǒng)的作用就像一個(gè)轉(zhuǎn)換表,把用戶對(duì)I/O的請(qǐng)求轉(zhuǎn)換到相應(yīng)的驅(qū)動(dòng)程序例程。驅(qū)動(dòng)程序就能夠獲得最原始的用戶I/O請(qǐng)求,并對(duì)設(shè)備進(jìn)行操作。為滿足標(biāo)準(zhǔn)設(shè)備處理的需要,I/O系統(tǒng)通常也提供一些高級(jí)的例程庫(kù),便于實(shí)現(xiàn)設(shè)備的標(biāo)準(zhǔn)通信協(xié)議。I/O系統(tǒng)既便于實(shí)現(xiàn)能夠滿足大多數(shù)設(shè)備要求的、標(biāo)準(zhǔn)的驅(qū)動(dòng)程序;也能在需要的時(shí)候,方便地實(shí)現(xiàn)非標(biāo)準(zhǔn)的設(shè)備驅(qū)動(dòng)程序,以滿足實(shí)時(shí)性或是其他的特殊需要。
638.2.1I/O管理的功能
I/O管理在系統(tǒng)中的體系結(jié)構(gòu)64I/O管理的功能
I/O系統(tǒng)主要提供以下功能:管理設(shè)備驅(qū)動(dòng)程序;實(shí)現(xiàn)設(shè)備命名;向用戶提供統(tǒng)一的調(diào)用。
65I/O管理的功能
管理設(shè)備驅(qū)動(dòng)程序通過驅(qū)動(dòng)程序地址表來實(shí)現(xiàn)。驅(qū)動(dòng)程序地址表中存放了設(shè)備驅(qū)動(dòng)程序的入口地址,可以通過此表實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)的動(dòng)態(tài)安裝與卸載的管理。驅(qū)動(dòng)程序地址表通常可以通過雙向循環(huán)鏈表或是數(shù)組的方式來實(shí)現(xiàn)。
66I/O管理的功能
應(yīng)用層可以通過設(shè)備名來使用設(shè)備,I/O系統(tǒng)和驅(qū)動(dòng)程序內(nèi)部則采用主/次設(shè)備號(hào)來操作設(shè)備。用主設(shè)備號(hào)區(qū)別不同的驅(qū)動(dòng)程序,由于一個(gè)驅(qū)動(dòng)程序可能管理多個(gè)同類設(shè)備,驅(qū)動(dòng)程序內(nèi)部再用次設(shè)備號(hào)區(qū)別不同設(shè)備。比如,一個(gè)串行通信設(shè)備的驅(qū)動(dòng)程序可以用來處理多個(gè)獨(dú)立串行通道,這些通道之間只存在參數(shù)方面的差異,如設(shè)備地址。I/O系統(tǒng)還需要提供將設(shè)備名映射到主/次設(shè)備號(hào)的方法??梢酝ㄟ^設(shè)備名表來實(shí)現(xiàn)設(shè)備名到主/次設(shè)備號(hào)的映射方法。有了設(shè)備名,通過設(shè)備名表就能得到設(shè)備的主/次設(shè)備號(hào)。67I/O管理的功能
應(yīng)用層如果每次都通過設(shè)備名使用設(shè)備并不方便。I/O系統(tǒng)可采用文件描述符的機(jī)制簡(jiǎn)化這一過程。用戶打開設(shè)備后獲得該設(shè)備的文件描述符,以后對(duì)設(shè)備的操作都通過這個(gè)文件描述符來進(jìn)行。68I/O管理的功能
I/O系統(tǒng)可采用主/次設(shè)備號(hào)、設(shè)備名表和文件描述符等三方面的內(nèi)容共同完成設(shè)備命名,即設(shè)備識(shí)別。I/O系統(tǒng)的統(tǒng)一接口主要實(shí)現(xiàn)以下對(duì)設(shè)備的操作:設(shè)備初始化;打開設(shè)備;關(guān)閉設(shè)備;讀設(shè)備;寫設(shè)備;設(shè)備控制。698.2.2I/O系統(tǒng)的實(shí)現(xiàn)考慮
I/O系統(tǒng)主要通過文件描述符表、設(shè)備名表和驅(qū)動(dòng)程序地址表實(shí)現(xiàn)I/O的管理功能。I/O系統(tǒng)內(nèi)部主要機(jī)制之間的層次關(guān)系
701.主設(shè)備號(hào)
I/O系統(tǒng)內(nèi)部最下層是主設(shè)備號(hào)機(jī)制,通過主設(shè)備號(hào)來區(qū)分不同的驅(qū)動(dòng)程序。I/O系統(tǒng)內(nèi)部不使用次設(shè)備號(hào),次設(shè)備號(hào)僅在驅(qū)動(dòng)程序內(nèi)部有用。主設(shè)備號(hào)機(jī)制的實(shí)現(xiàn)主要體現(xiàn)在驅(qū)動(dòng)程序地址表數(shù)據(jù)結(jié)構(gòu)上,實(shí)現(xiàn)了I/O系統(tǒng)對(duì)驅(qū)動(dòng)程序的統(tǒng)一管理。主設(shè)備號(hào)是訪問驅(qū)動(dòng)程序地址表的索引;通過主設(shè)備號(hào)訪問驅(qū)動(dòng)程序地址表可以獲得驅(qū)動(dòng)程序提供的關(guān)于設(shè)備的六個(gè)標(biāo)準(zhǔn)操作的函數(shù)調(diào)用的入口地址。71主設(shè)備號(hào)
若驅(qū)動(dòng)程序地址表組織為數(shù)組的形式,需要在I/O系統(tǒng)初始化時(shí)為驅(qū)動(dòng)程序地址表分配存儲(chǔ)空間,以容納各個(gè)設(shè)備的驅(qū)動(dòng)程序的入口地址。若驅(qū)動(dòng)程序地址表組織為雙向循環(huán)鏈表的形式,則在安裝設(shè)備的時(shí)候動(dòng)態(tài)分配容納該設(shè)備驅(qū)動(dòng)程序入口地址的存
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 工作服選購(gòu)合同范本
- 長(zhǎng)期醫(yī)藥配送合同
- 幼兒園物資選購(gòu)協(xié)議范本
- 柴油購(gòu)銷合同范本示例
- 焊錫絲采購(gòu)合同簽訂后的履行
- 乳膠漆產(chǎn)品代理協(xié)議
- 地方特色月餅銷售合同
- 標(biāo)準(zhǔn)投資理財(cái)合同樣本
- 地址租賃協(xié)議
- 小學(xué)生科學(xué)繪本故事解讀
- 2021-2022學(xué)年北京市西城區(qū)六年級(jí)(上)期末英語試卷
- 香菇購(gòu)銷合同
- 54張管理用財(cái)務(wù)報(bào)表模板(帶釋義和公式)
- 個(gè)別化教育實(shí)施方案
- 人大代表“鄉(xiāng)村振興戰(zhàn)略”調(diào)研報(bào)告
- 白血病病例討論
- (新版)高級(jí)茶藝師資格考試題庫(kù)(含答案)
- SB/T 10952-2012實(shí)木復(fù)合門
- 大洋洲-澳大利亞(區(qū)域課件)【知識(shí)精講+備課精研】 高中區(qū)域地理教學(xué) 課件 (世界地理、中國(guó)地理)
- GB/T 917-2017公路路線標(biāo)識(shí)規(guī)則和國(guó)道編號(hào)
- 《學(xué)法-知法-守法》PPT-完美版
評(píng)論
0/150
提交評(píng)論