如何剪裁操作系統(tǒng)源碼
本文面向的需求場景是,為缺乏標準庫實現(xiàn)的處理器IP移植內(nèi)存管理模塊,即為裸片部署C標準庫中的 malloc()
和 free()
函數(shù)。
具體做法是——從操作系統(tǒng)的內(nèi)存管理組件中剪裁出必要的源碼,適配到目標處理器的開發(fā)環(huán)境(SDK/IDE/CMAKE工程子目錄)中。
1 定需求——理解內(nèi)存管理/堆管理
1.1 C標準庫中的內(nèi)存管理方案
C標準庫提供了一組內(nèi)存管理函數(shù),用于在C程序中進行動態(tài)內(nèi)存分配和釋放操作。這些函數(shù)主要包括malloc、calloc、realloc和free。
malloc函數(shù): malloc函數(shù)用于分配指定大小的內(nèi)存塊,并返回指向該內(nèi)存塊的指針。其函數(shù)原型為:
void* malloc(size_t size);
它接受一個參數(shù)size,表示需要分配的內(nèi)存空間的大?。ㄒ宰止?jié)為單位)。malloc函數(shù)在堆內(nèi)存中分配了一塊連續(xù)的內(nèi)存,并返回指向該內(nèi)存塊起始地址的指針。
calloc函數(shù): calloc函數(shù)也用于分配指定數(shù)量和大小的內(nèi)存塊,并返回指向該內(nèi)存塊的指針。與malloc不同的是,calloc會將分配的內(nèi)存塊中的每個字節(jié)都初始化為0。其函數(shù)原型為:
void* calloc(size_t num, size_t size);
num參數(shù)表示需要分配的元素個數(shù),而size參數(shù)表示每個元素的大?。ㄒ宰止?jié)為單位)。calloc函數(shù)在堆內(nèi)存中分配了大小為num * size的內(nèi)存塊,并返回指向該內(nèi)存塊起始地址的指針。
realloc函數(shù): realloc函數(shù)用于調(diào)整先前分配的內(nèi)存塊的大小。其函數(shù)原型為:
void* realloc(void* ptr, size_t size);
ptr參數(shù)是指向先前通過malloc或calloc分配的內(nèi)存塊的指針,而size參數(shù)表示需要調(diào)整的大?。ㄒ宰止?jié)為單位)。realloc函數(shù)根據(jù)新的大小重新分配內(nèi)存塊,并返回指向重新分配后內(nèi)存塊起始地址的指針。如果內(nèi)存塊不能被重新分配,realloc函數(shù)可能會創(chuàng)建新的內(nèi)存塊,并將原內(nèi)存塊的數(shù)據(jù)復制到新內(nèi)存塊中。
free函數(shù): free函數(shù)用于釋放先前通過malloc、calloc或realloc函數(shù)分配的內(nèi)存塊。其函數(shù)原型為:
void free(void* ptr);
ptr參數(shù)是指向先前分配的內(nèi)存塊的指針。通過調(diào)用free函數(shù),該內(nèi)存塊將被標記為空閑,并可以被再次分配給其他內(nèi)存需求。
1.2 需求剪裁
裸片程序受限于內(nèi)存資源,一般是使用靜態(tài)分配方法設(shè)計得到的,只在移植某些外設(shè)的驅(qū)動時需要提供基本的動態(tài)內(nèi)存管理方法,很少有新增預分配的動態(tài)內(nèi)存的需求。所以 realloc
和 calloc
函數(shù)可以略去,這樣咱的任務量就減少了一半啦。
2 找輪子——向操作系統(tǒng)學習
操作系統(tǒng)是對硬件的抽象,裸片上的絕大部分需求都可以在操作系統(tǒng)的源碼中找到較為通用的實現(xiàn),那么何必再造輪子呢,直接逮著操作系統(tǒng)的薅羊毛吧。
2.1 FreeRTOS中的內(nèi)存管理方案
FreeRTOS 提供了幾種堆管理方案,這些方案的復雜性和功能各不相同,分別適用于不同的需求場景,具體見下圖。
總結(jié)性地說,F(xiàn)reeRTOS在源碼目錄 Source/Portable/MemMang 中為咱們提供了 5 種可選的內(nèi)存管理模塊的實現(xiàn):
- heap_1:極簡版,不支持內(nèi)存釋放(沒有 free 函數(shù))
- heap_2:支持釋放,但不合并釋放的內(nèi)存塊
- heap_3:支持線程安全的 malloc 和 free 函數(shù)
- heap_4:合并釋放的內(nèi)存塊,避免內(nèi)存碎片
- heap_5:在 4 的基礎(chǔ)上支持跨多個內(nèi)存塊進行分配
這兒咱們根據(jù)自己的需求選,本文選擇 heap_2 移植,因為基本功能全面,且足夠簡單。
2.2 拉取源碼
在源碼樹中找到 Source/Portable/MemMang/heap2.c,如下圖。
打開就看到分配和釋放函數(shù)觸手可及,分別命名為 pvPortMalloc
和 vPortFree
, 添加到咱的工程里,然后細看這個源文件的依賴,把依賴項從源碼樹里摳出來,舍棄不需要的文件,也就把內(nèi)存管理模塊從操作系統(tǒng)中剝離出來了。
2.3 剝離依賴項
heap_2.c包含了兩個FreeRTOS相關(guān)的頭文件—— FreeRTOS.h 和 task.h,后者是任務調(diào)度器相關(guān)的聲明,咱們顯然不需要,直接剔除。FreeRTOS是一些配置項的宏定義,咱們把與內(nèi)存管理相關(guān)的剪切過來,不需要保留FreeRTOS.h整個文件。
然后是一個用于讓管理的內(nèi)存空間大小符合內(nèi)存對齊需求的宏定義:
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
configTOTAL_HEAP_SIZE 和 portBYTE_ALIGNMENT 都需要我們手動 #define
heap_2.c 還用到一個宏定義 portBYTE_ALIGNMENT_MASK
:
原先在FreeRTOS.h里,我們加到portmacro.h里:
剩下的就是一些基本的類型替換了,我們統(tǒng)一放到 portmacro.h 文件中:
projdefs.h 也是需要的,里面有 true
和 false
的宏:
2.4 可用源碼
Github倉庫:memManPort文章來源:http://www.zghlxwxcb.cn/news/detail-638065.html
3 測試
可以用下面這個demo來測試移植結(jié)果的可用性,只要pb和pc值結(jié)果一致,那就基本正確了。文章來源地址http://www.zghlxwxcb.cn/news/detail-638065.html
到了這里,關(guān)于如何剪裁操作系統(tǒng)源碼——移植FreeRTOS的內(nèi)存管理模塊到ARMV8裸片的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!