導讀:如本人在《U-Boot架構淺析》所說,U-Boot具備十大黃金原則:小巧、快速、簡單、可移植、可配置、可調試、易用、可維護、優雅、開源。面對如此精美的做品,如不深究,從提高編程技藝角度而言實爲憾事。故本文試圖觀其形而悟其神,並把所見所思所得記錄與諸君分享。文中觀點或有錯誤疏漏,誠請交流指正,不甚感激!html
說明:git
封面配圖,純爲搞笑
編程文中繪圖採用UML語言,或有不對也請一併指正。微信
代碼分析基於u-boot-2016.09.y架構
代碼見下面app
https://gitlab.denx.de/u-boot/u-boot/-/tree/u-boot-2016.09.y函數
所得之一:封裝思想gitlab
U-boot將幾乎全部信息集總抽象至global_data,歸納而言,大致有如下信息:
spa
bd_info(bd_t*)包含CPU頻率,內存大小,FLASH大小等信息.net
爲實現可移植原則,將不一樣體系結構利用宏進行選編譯。
通用屬性數據:CPU頻率、PCI頻率、內存頻率、環境變量地址、堆信息等雜散參數信息。
驅動設備接口:
struct udevice *dm_root;
驅動程序模型的根指針
struct udevice *dm_root_f;
重定向前驅動程序模型的根指針
struct list_headuclass_root;
uclass鏈表,全部被udevice匹配的uclass都會被掛載到這個雙向鏈表上
struct udevice *timer;
定時器設備指針
struct udevice*cur_serial_dev;
當前串口設備指針
structarch_global_data arch,
各不一樣體系結構屬性。
所得:
可移植:實現接口統一,通用部分實現,多樣性兼顧。
可配置:差別屬性利用宏進行使能與關閉。
所得之二:宏的妙用
jt_funcs 定義了函數跳轉表:
在static int initr_jumptable(void)進行初始化。
#define EXPORT_FUNC(impl, res, func, ...) res(*func)(__VA_ARGS__);
impl,函數名這個參數展開時沒有用到,只是爲了增長可讀性。至關於函數實現名。
res 返回值
__VA_ARGS__ 可變參數列表
如:
EXPORT_FUNC(get_version, unsigned long,get_version, void)
展開爲:
unsigned long (* get_version) (void)
利用該宏定義可變參數函數指針,將一系列不一樣函數原型用一種統一的格式進行定義,並收集在_exports.h中,jt_funcs結構體將該頭文件包含,並封裝而成跳轉表結構體。編譯預處理時自動將定義插入到結構體的定義中了。
<include /_exports.h>包含封裝在EXPOR_FUNC宏中的一系列導出函數,其中一些導出取決於「 CONFIG_XXX」選項。將根據包含此標頭的文件定義宏。例如,在common / exports.c>中,將設置EXPOR_FUNC宏以使用<include /_exports.h>中的函數初始化跳轉表結構。 在<include /exports.h>中,EXPOR_FUNC宏將設置爲包含在跳轉表結構中的函數指針的類型。
這樣作的好處:
可維護性極高,如需添加或修改跳轉表結構體函數,只需修改_exports.h,以及修改對應的實現源文件
定義函數指針進跳轉表另外一個給我啓發是,能夠實現動態加載,以實現統一接口不一樣操做。相似C++的函數重載。
所得之三:環形緩衝區
在分析控制檯模塊部分代碼時發現,其內存緩衝區採用環形緩衝區。
所得之一:將環形緩衝區預留一個字節以判斷滿/空。這樣作程序優雅實現簡便。
環形緩衝I/O:@start +@size - 1
空:若是@head ==@tail 則空
滿:若是在追加一個字節使@head== @tail,則滿
未完待續。。。
本文分享自微信公衆號 - 嵌入式客棧(embInn)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。