FreeRTOS內核解析v0.1-LOVT_第1頁
FreeRTOS內核解析v0.1-LOVT_第2頁
FreeRTOS內核解析v0.1-LOVT_第3頁
FreeRTOS內核解析v0.1-LOVT_第4頁
FreeRTOS內核解析v0.1-LOVT_第5頁
已閱讀5頁,還剩34頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、FreeRTOS內核解析FreeRTOS是一個小型的嵌入式實時系統(tǒng)內核,應用比較廣泛,而且開源,商業(yè)免費。在STM32F4系列上移植FreeRTOS Start System Peripheral Init OS Init TASK A OS Task Scheduler TASK B TASK C 圖1 OS操作流程在FreeRTOS內核中包含的文件: 1. croutine.c 協(xié)線程文件,和任務類似,在系統(tǒng)資源比較缺乏下使用。2. list.c 列表結構描述,在內核整體控制上都使用了列表格式數(shù)據(jù)處理。一切 的數(shù)據(jù)結構基礎。3. queue.c 隊列,任務和任務之間的通訊處理。 4. Ti

2、mers.c 軟定時,以任務形式存在。5. Port.c 硬件與系統(tǒng)內核交互部分。SVC、PENDSC、中斷等設置。匯編與C的結合6. Heap.c 堆棧內存空間。內存空間申請,釋放。在這里我們使用heap_4.c。7. tasks.c 所有任務相關函數(shù)。8. cmsisi_os.c 系統(tǒng)相關接口CMSISI_OS標準化,接口處理。 heap_4.c 實現(xiàn)原理:申請一塊靜態(tài)內存,按照堆的方式處理。包含內存申請,釋放,自動合并相連的空閑內存。 應用API函數(shù): void *pvPortMalloc(size_t xWantedSize); void vPortFree(void *pv); si

3、ze_t xPortGetFreeHeapSize(void); 內部過程函數(shù): static void prvHeapInit(void); static void prvInsertBlockIntoFreeList(xBlockLink *pxBlockToInsert) ; /申請內存空間塊描述 可以看做一個節(jié)點typedef struct A_BLOCK_LINK struct A_BLOCK_LINK *pxNextFreeBlock; /指向下一塊內存 size_t xBlockSize; /空閑塊大小xBlockLink;/指向開始和結尾 xStart是靜態(tài)內存 pxEnd 是

4、個指針 xBlockLink xStart, *pxEnd = NULL節(jié)點數(shù)據(jù)空間。節(jié)點數(shù)據(jù)空間。在系統(tǒng)蛇口中要考慮到字節(jié)對齊的問題。所以在申請一塊內存時,要先進行內存字節(jié)格式對齊。也就是說1-7個字節(jié)格式化后也為8個字節(jié)。#define portBYTE_ALIGNMENT 8 /8字節(jié)對齊#define portBYTE_ALIGNMENT_MASK ( 0x0007 ) /對齊掩碼static const unsigned short heapSTRUCT_SIZE = (sizeof(xBlockLink) + (portBYTE_ALIGNMENT - 1) & portB

5、YTE_ALIGNMENT_MASK);/靜態(tài)內存 作為整個內存空間 configTOTAL_HEAP_SIZE 宏定義設置 根據(jù)需求設置大小static unsigned char ucHeapconfigTOTAL_HEAP_SIZE; #define heapADJUSTED_HEAP_SIZE(configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT) /實際可用大小 在初始化prvHeapInit()函數(shù)中 假設configTOTAL_HEAP_SIZE為1024 (0x400)在實際使用空間中 起碼可以保持 1024 - 8個字節(jié)空間可用pucAlign

6、edHeap 指向了8字節(jié)對齊化了的地址xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;xStart.xBlockSize = (size_t)0;假設ucHeap是一個不對齊的地址 0x00427c58;那么8字節(jié)對齊后為0x00427c600x00427c58 0x00428058。 0x00427c60 pucAlignedHeap 指向該位置xStart可以看做獨立該空間的一個節(jié)點 大小為0 指向空間的開始地址xStart->pxNextFreeBlock 指向pucAlignedHeappucHeapEnd = pucAli

7、gnedHeap + xTotalHeapSize;pucHeapEnd -= heapSTRUCT_SIZE;pxEnd = (void *)pucHeapEnd; 更新pxEnd 指向pxEnd->xBlockSize = 0;pxEnd->pxNextFreeBlock = NULL;0x00428050(pxEnd)。 NULL(pxNextFreeBlock )pxFirstFreeBlock = (void *)pucAlignedHeap;pxFirstFreeBlock->xBlockSize = xTotalHeapSize - heapSTRUCT_SIZ

8、E;pxFirstFreeBlock->pxNextFreeBlock = pxEnd;xFreeBytesRemaining -= heapSTRUCT_SIZE; /更新空閑大小使用標志 高位置1xBlockAllocatedBit = (size_t)1) << (sizeof(size_t) * heapBITS_PER_BYTE) - 1);pxFirstFreeBlock pxFirstFreeBlock->pxNextFreeBlock對齊損失節(jié)點數(shù)據(jù)空間pxEnd申請內存pvPortMalloc(size_t xWantedSize) xWantedSi

9、ze為要申請內存的大小,返回該內存的指針if(pxEnd = NULL)/未初始化 先進行初始化prvHeapInit();xWantedSize += heapSTRUCT_SIZE;/實際使用的空間為節(jié)點+內存xWantedSize設置的大小也要字節(jié)對齊化處理pxPreviousBlock = &xStart;pxBlock = xStart.pxNextFreeBlock;while(pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL) /遍歷全局 查看足

10、夠大的空閑內存pxPreviousBlock = pxBlock;pxBlock = pxBlock->pxNextFreeBlock;pxPreviousBlock 指向 xStartpxBlock 注意:這里的B 數(shù)據(jù)都是空閑內存B空閑B空閑B空閑B。ENDpxPreviousBlock pxBlock B空閑B空閑B空閑B。END pxPreviousBlock pxBlock (該空間足夠大)B空閑B空閑B空閑B。END pvReturn pvReturn 返回空間地址pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNext

11、FreeBlock; pxPreviousBlock pxBlock 這里pxBlock不為空 斷開空閑鏈表B空閑B空閑B數(shù)據(jù)B。END空間大 一分為二pxNewBlockLink = (void *)(unsigned char *)pxBlock) + xWantedSize);pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;pxBlock->xBlockSize = xWantedSize; 這里可以看出節(jié)點中的大小包含節(jié)點所占空間 pxBlock pxNewBlockLink B空閑B要用內

12、存空閑B。ENDprvInsertBlockIntoFreeList(pxNewBlockLink); 把新塊插入空閑列表xFreeBytesRemaining -= pxBlock->xBlockSize; 更新剩余空間pxBlock->xBlockSize |= xBlockAllocatedBit; 節(jié)點長度高位置1pxBlock->pxNextFreeBlock = NULL; 已使用從空閑鏈表中斷開把該塊插入空閑鏈表prvInsertBlockIntoFreeList(xBlockLink *pxBlockToInsert)for(pxIterator = &

13、;xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) 遍歷空閑列表定位pxIterator pxIterator 指向xStartxStart.pxNextFreeBlock 指向第一個空閑 pxBlockToInsertB空閑B要用內存B。ENDpuc = (unsigned char *)pxIterator; 為要插入塊的前一個空閑塊if(puc + pxIterator->xBlockSize) = ( unsigned

14、 char * )pxBlockToInsert)如果pxIterator這塊在插入塊pxBlockToInsert前方相鄰 那么進行合并pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;pxBlockToInsert = pxIterator; 如果pxIterator 與 pxBlockToInsert相鄰 那么合并這2塊空閑 pxIterator pxBlockToInsertB空閑B空閑B。ENDpxIterator (pxBlockToInsert) 合并后 B空閑B。ENDpuc = (unsigned char

15、 *)pxBlockToInsert;if(puc+pxBlockToInsert->xBlockSize)=(unsignedchar*)pxIterator->pxNextFreeBlock)如果pxIterator這塊在插入塊pxBlockToInsert后方相鄰 那么進行合并pxBlockToInsert->xBlockSize+=pxIterator->pxNextFreeBlock->xBlockSize;pxBlockToInsert->pxNextFreeBlock=pxIterator->pxNextFreeBlock->pxN

16、extFreeBlock; pxIterator->pxNextFreeBlock 與 pxBlockToInsert相鄰 pxIterator pxBlockToInsertB空閑B數(shù)據(jù)B空閑B空閑ENDif(pxIterator != pxBlockToInsert) 連接2塊空閑列表pxIterator->pxNextFreeBlock = pxBlockToInsert;pxIterator pxBlockToInsertB空閑B數(shù)據(jù)B空閑B數(shù)據(jù)END釋放內存vPortFree(void *pv)if(pxLink->xBlockSize & xBlockAl

17、locatedBit)!= 0)已使用內存的 塊大小高位都置1判斷pxLink->xBlockSize &= xBlockAllocatedBit 高位清零xFreeBytesRemaining += pxLink->xBlockSize; 更新剩余大小prvInsertBlockIntoFreeList(xBlockLink *)pxLink); 把該塊插入空閑列表List.c 列表結構,含有插入、移除的功能。列表中的項目結構struct xLIST_ITEMconfigLIST_VOLATILE portTickType xItemValue; /項目值struct x

18、LIST_ITEM * configLIST_VOLATILE pxNext;/指向下一個ITEMstruct xLIST_ITEM * configLIST_VOLATILE pxPrevious;/指向前一個ITEMvoid * pvOwner;/可指向任務中TCBvoid * configLIST_VOLATILE pvContainer;/指向所屬列表;typedef struct xLIST_ITEM xListItem;簡化項目結構struct xMINI_LIST_ITEMconfigLIST_VOLATILE portTickType xItemValue;/項目值struct

19、 xLIST_ITEM * configLIST_VOLATILE pxNext; /指向下一個ITEMstruct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /指向上一個ITEM;typedef struct xMINI_LIST_ITEM xMiniListItem;列表結構typedef struct xLISTconfigLIST_VOLATILE unsigned portBASE_TYPE uxNumberOfItems; /項目個數(shù)xListItem * configLIST_VOLATILE pxIndex; /指向最后一個ITE

20、MxMiniListItem xListEnd; /申請一個內存表示列表尾 xList; pxIndex &xListEnd(靜態(tài)內存)ITEM1ITEM2ITEM3ITEM4ITEM5查看list.h中一些宏定義 方便使用,提高效率/設置ITEM的pvOwner #define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )/獲取ITEM的pvOwner#define listGET_LIST_ITEM_OWNER( pxLis

21、tItem ) ( pxListItem )->pvOwner/設置ITEM的VALUE值#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )/獲取ITEM的VALUE值#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )/獲取LIST中第一個ITEM的VALUE值#define listGET_ITEM_VALUE_OF_HEAD_EN

22、TRY( pxList ) ( (&( ( pxList )->xListEnd )->pxNext->xItemValue )/判斷LIST是否為空#define listLIST_IS_EMPTY( pxList ) ( ( portBASE_TYPE ) ( ( pxList )->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0 ) )/獲取LIST中ITEM個數(shù)#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems

23、)/獲取pxIndex指向的下一個pvOwner 并且更新了pxIndex#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) 。/獲取第一個ITEM的pvOwner #define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd )->pxNext->pvOwner )/查看該ITEM的所屬LIST 是否與pxList一致#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( (

24、 portBASE_TYPE ) ( ( pxListItem )->pvContainer = ( void * ) ( pxList ) ) )/獲取ITEM所屬LIST#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )列表初始化vListInitialise( xList * const pxList )pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );pxList->xListEnd.

25、xItemValue = portMAX_DELAY;pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;初始化了pxIndex 指向xListEnd xListEnd 的值為 portMAX_DELAY(0xffffffff)L

26、IST中包含個數(shù)為0 (pxNext ) pxList->pxIndex &( pxList->xListEnd )(靜態(tài)內存) (pxPrevious )ITEM個數(shù)為0插入到末尾vListInsertEnd( xList * const pxList, xListItem * const pxNewListItem )pxIndex = pxList->pxIndex;pxNewListItem->pxNext = pxIndex;pxNewListItem->pxPrevious = pxIndex->pxPrevious;pxIndex-&g

27、t;pxPrevious->pxNext = pxNewListItem;pxIndex->pxPrevious = pxNewListItem;pxNewListItem->pvContainer = ( void * ) pxList;( pxList->uxNumberOfItems )+;LIST的個數(shù)加1 該ITEM所屬pxList (pxNext ) pxList->pxIndex &( pxList->xListEnd )(靜態(tài)內存) (pxPrevious ) (pxPrevious) (pxNext )pxNewListItem(插

28、入的ITEM)如果再插入一次 (pxNext ) pxList->pxIndex &( pxList->xListEnd )(靜態(tài)內存) (pxPrevious ) (pxPrevious) (pxNext )ITEM1pxNewListItemVALUE值插入vListInsert( xList * const pxList, xListItem * const pxNewListItem )if( xValueOfInsertion = portMAX_DELAY ) 插入的值為最大值 與xListEnd一致 指向xListEnd前的一個ITEM pxIterator

29、= pxList->xListEnd.pxPrevious;elsefor( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) 遍歷比較VALUE值 獲取插入位置假設插入值為3 pxIteratorITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5)pxNewListItem->pxNext = pxIter

30、ator->pxNext;pxNewListItem->pxNext->pxPrevious = pxNewListItem;pxNewListItem->pxPrevious = pxIterator;pxIterator->pxNext = pxNewListItem;pxNewListItem->pvContainer = ( void * ) pxList;( pxList->uxNumberOfItems )+; pxIterator pxNewListItemITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5)移除一個ITEM

31、uxListRemove( xListItem * const pxItemToRemove )pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;假設pxItemToRemove為ITEM2 pxIterator 一般情況下指向xListEnd 也有可能指向其中一個 pxItemToRemoveITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5)pxL

32、ist = ( xList * ) pxItemToRemove->pvContainer;if( pxList->pxIndex = pxItemToRemove ) pxList->pxIndex = pxItemToRemove->pxPrevious; (pxIterator) pxItemToRemove 更新pxIterator指向ITEM1(1)ITEM2(2)ITEM3(4)ITEM4(5) Port.c 端口設置,涉及到內核系統(tǒng)。由匯編及C編寫。pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, p

33、dTASK_CODE pxCode, void *pvParameters )堆棧初始化設置,在任務建立時執(zhí)行。每個任務都有一個對應的堆棧,用于任務切換后,寄存器狀態(tài)的保存。 pxTopOfStack 指向堆棧高地址 (ulong類型) 假設0x20000470XPSR(0x01000000)PC(pxCode)LRR12R3R2R1R0(param)RETURN(0xfffffffd)R11R10R9R8R7R6R5R4 返回更新的pxTopOfStack 0x2000042c進入時寄存器狀態(tài)函數(shù)退出后寄存器狀態(tài)堆棧中的數(shù)據(jù)開啟任務調度xPortStartScheduler( void )u

34、lOriginalPriority = *pcFirstUserPriorityRegister; /IP0 中斷0配置的優(yōu)先級*pcFirstUserPriorityRegister = portMAX_8_BIT_VALUE;ucMaxPriorityValue = *pcFirstUserPriorityRegister; /0xffucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; /0101 0000 大于這個中斷優(yōu)先級的中斷不能被響應 /ISR中可以安全調用系統(tǒng)A

35、PIulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; /7 組的最大值while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) = portTOP_BIT_OF_BYTE ) /查看最高位ulMaxPRIGROUPValue-;ucMaxPriorityValue <<= ( unsigned char ) 0x01;優(yōu)先級組76543搶占位數(shù)01234xxxx 0000 使用高4位 廠商只用了4位 15個中斷優(yōu)先級計算出優(yōu)先級組的設定ulMaxPRIGROUPValue <<=

36、 portPRIGROUP_SHIFT; /AIRCR 10:8ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;*pcFirstUserPriorityRegister = ulOriginalPriority; /重設IP0當前優(yōu)先級portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; /0x00F00000 SHP10 portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; /0x0F000000 SHP11 設置了PENDSV STSTICK為最低優(yōu)先級 不影響其他

37、中斷vPortSetupTimerInterrupt(); /SYSTICK設置uxCriticalNesting = 0; /進入臨界區(qū)嵌套計數(shù)清0prvEnableVFP(); /使能FPU *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS; /FPCCR使能自動保存和恢復prvStartFirstTask(); /開啟第一個任務初始化定時中斷vPortSetupTimerInterrupt( void ) portNVIC_SYSTICK_LOAD_REG 重載計數(shù)設置 portNVIC_SYSTICK_CTRL_REG 使能SYSTICK時鐘 使能S

38、YSTICK 使能SYSTICK中斷 使能VFP功能_asm void prvEnableVFP( void )PRESERVE8ldr.w r0, =0xE000ED88 /CPACR中設置ldr r1, r0 /CP11 CP10 23:22 21:20orr r1, r1, #( 0xf << 20 )str r1, r0bx r14nop開啟第一個任務_asm void prvStartFirstTask( void )PRESERVE8ldr r0, =0xE000ED08 /向量表偏移ldr r0, r0 ldr r0, r0 /第一個值為堆棧棧頂msr msp, r0

39、 /存入MSPcpsie i /開啟中斷svc 0 /產(chǎn)生SVC中斷nopSVC指令_asm void vPortSVCHandler( void ) 調用SVC來請求任務切換PRESERVE8 8字節(jié)對齊ldr r3, =pxCurrentTCB ldr r1, r3 獲取當前任務 地址0x20000480ldr r0, r1 獲取當前任務的棧頂?shù)刂?0x2000068Cldmia r0!, r4-r11, r14 POP R4-R11 R14 R0指向地址更新 R0RETURN(0xfffffffd)R11R10R9R8R7R6R5R4如果LR=0xFFFFFFFD明產(chǎn)生異常的時候使用的是

40、PSPmsr psp, r0 更新堆棧地址 R0從0x2000042C 變0x20000450mov r0, #0 清空r0msr basepri, r0 清除basepribx r14PENDSV _asm void xPortPendSVHandler(void)用于上下文切換extern uxCriticalNesting; /進入臨界區(qū)嵌套次數(shù)extern pxCurrentTCB;extern vTaskSwitchContext;PRESERVE8mrs r0, pspldr r3, =pxCurrentTCB /獲取當前TCBldr r2, r3tst r14, #0x10it

41、eqvstmdbeq r0!, s16-s31 /使用FPU PUSH高位VFPstmdb r0!, r4-r11, r14 /保存當前環(huán)境str r0, r2 /把新的堆棧存入pxTopOfStackstmdb sp!, r3mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITYmsr basepri, r0 /設置basepribl vTaskSwitchContext /設置上下文切換 的一些狀態(tài)參數(shù)mov r0, #0msr basepri, r0 /屏蔽baseprildmia sp!, r3 /恢復SP ldr r1, r3 /獲取棧頂ldr r

42、0, r1ldmia r0!, r4-r11, r14 /pop內核寄存器tst r14, #0x10it eqvldmiaeq r0!, s16-s31 /PUSH FPU 高位VFPmsr psp, r0bx r14Task.c 任務相關函數(shù)狀態(tài)及參數(shù):typedef enum 任務的幾個狀態(tài)eRunning = 0, 運行eReady, 就緒eBlocked, 阻塞eSuspended, 掛起eDeleted 刪除 eTaskState;typedef struct xTASK_PARAMTERS 任務的參數(shù)pdTASK_CODE pvTaskCode; 任務函數(shù)const signed

43、 char * const pcName; 任務名unsigned short usStackDepth; 堆棧深度void *pvParameters; 參數(shù)unsigned portBASE_TYPE uxPriority; 優(yōu)先級portSTACK_TYPE *puxStackBuffer; 堆棧指針 xMemoryRegion xRegions portNUM_CONFIGURABLE_REGIONS ; MPU部分 xTaskParameters;typedef struct xMEMORY_REGION MPU內存管理void *pvBaseAddress; 分配的內存地址unsi

44、gned long ulLengthInBytes; 內存長度unsigned long ulParameters; 參數(shù) xMemoryRegion;typedef struct xTASK_STATUS 每個任務在系統(tǒng)中的參數(shù)xTaskHandle xHandle; 任務句柄const signed char *pcTaskName; 任務名unsigned portBASE_TYPE xTaskNumber; 任務號 唯一eTaskState eCurrentState; 任務當前狀態(tài) unsigned portBASE_TYPE uxCurrentPriority; 當前優(yōu)先級 unsigned portBASE_TYPE uxBasePriority; 任務優(yōu)先級 互斥信號量中使用 unsigned long ulRunTimeCounter; 運行TICK計數(shù)unsigned short usStackHighWaterMark; 堆棧當前使用深度 xTaskStatusType;typedef struct tskTask

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論