一、前言
作為一個(gè)多年耕耘在linux 2.6.23內(nèi)核的開發(fā)者,各個(gè)不同項(xiàng)目中各種不同周邊外設(shè)驅(qū)動(dòng)的開發(fā)以及各種瑣碎的、扯皮的俗務(wù)占據(jù)了大部分的時(shí)間。當(dāng)有機(jī)會(huì)下載3.14的內(nèi)核并準(zhǔn)備學(xué)習(xí)的時(shí)候,突然發(fā)現(xiàn)linux kernel對(duì)于我似乎變得非常的陌生了,各種新的機(jī)制,各種framework、各種新的概念讓我感到閱讀內(nèi)核代碼變得舉步維艱。 還好,剖析內(nèi)核的熱情還在,剩下的就交給時(shí)間的。首先進(jìn)入視線的是Device Tree機(jī)制,這是和porting內(nèi)核非常相關(guān)的機(jī)制,如果想讓將我們的硬件平臺(tái)遷移到高版本的內(nèi)核上,Device Tree是一個(gè)必須要掃清的障礙。
我想從下面三個(gè)方面來了解Device Tree:
1、為何要引入Device Tree,這個(gè)機(jī)制是用來解決什么問題的?(這是本文的主題)
2、Device Tree的基礎(chǔ)概念(請(qǐng)參考DT基礎(chǔ)概念)
3、ARM linux中和Device Tree相關(guān)的代碼分析(請(qǐng)參考DT代碼分析)
閱讀linux內(nèi)核代碼就像欣賞冰山,有看得到的美景(各種內(nèi)核機(jī)制及其代碼),也有埋在水面之下看不到的基礎(chǔ)(機(jī)制背后的源由和目的)。沉醉于各種內(nèi)核機(jī)制的代碼固然有無限樂趣,但更重要的是注入更多的思考,思考其背后的機(jī)理,真正理解軟件抽象。這樣才能舉一反三,并應(yīng)用在具體的工作和生活中。
本文主要從下面幾個(gè)方面闡述為何ARM linux會(huì)引入Device Tree:
1、沒有Device Tree的ARM linux是如何運(yùn)轉(zhuǎn)的?
2、混亂的ARM architecture代碼和存在的問題
3、新內(nèi)核的解決之道
二、沒有Device Tree的ARM linux是如何運(yùn)轉(zhuǎn)的?
我曾經(jīng)porting內(nèi)核到兩個(gè)ARM-based的平臺(tái)上。一個(gè)是小的芯片公司的應(yīng)用處理器,公司自己購買了CPU core,該CPU core使用ARM兼容的指令集(但不是ARM)加上各種公司自行設(shè)計(jì)的多媒體外設(shè)整合成公司的產(chǎn)品進(jìn)行銷售。而我的任務(wù)就是porting 2.4.18內(nèi)核到該平臺(tái)上。在黑白屏幕的手機(jī)時(shí)代,那顆AP(application process)支持了彩屏、camera、JPEG硬件加速、2D/3D加速、MMC/SD卡、各種音頻加速(內(nèi)置DSP)等等特性,功能強(qiáng)大到無法直視。另外一次移植經(jīng)歷是讓2.6.23內(nèi)核跑在一個(gè)大公司的冷門BP(baseband processor)上。具體porting的方法是很簡(jiǎn)單的:
1、自己撰寫一個(gè)bootloader并傳遞適當(dāng)?shù)?a target="_blank">參數(shù)給kernel。除了傳統(tǒng)的command line以及tag list之類的,最重要的是申請(qǐng)一個(gè)machine type,當(dāng)拿到屬于自己項(xiàng)目的machine type ID的時(shí)候,當(dāng)時(shí)心情雀躍,似乎自己已經(jīng)是開源社區(qū)的一份子了(其實(shí)當(dāng)時(shí)是有意愿,或者說有目標(biāo)是想將大家的代碼并入到linux kernel main line的)。
2、在內(nèi)核的arch/arm目錄下建立mach-xxx目錄,這個(gè)目錄下,放入該SOC的相關(guān)代碼,例如中斷controller的代碼,時(shí)間相關(guān)的代碼,內(nèi)存映射,睡眠相關(guān)的代碼等等。此外,最重要的是建立一個(gè)board specific文件,定義一個(gè)machine的宏:
MACHINE_START(project name, "xxx公司的xxx硬件平臺(tái)")?
??? .phys_io??? = 0x40000000,?
??? .boot_params??? = 0xa0000100,???
??? .io_pg_offst??? = (io_p2v(0x40000000) >> 18) & 0xfffc,?
??? .map_io??????? = xxx_map_io,?
??? .init_irq??? = xxx_init_irq,?
??? .timer??????? = &xxx_timer,?
??? .init_machine??? = xxx_init,?
MACHINE_END
在xxx_init函數(shù)中,一般會(huì)加入很多的platform device。因此,伴隨這個(gè)board specific文件中是大量的靜態(tài)table,描述了各種硬件設(shè)備信息。
3、調(diào)通了system level的driver(timer,中斷處理,clock等)以及串口terminal之后,linux kernel基本是可以起來了,后續(xù)各種driver不斷的添加,直到系統(tǒng)軟件支持所有的硬件。
綜上所述,在linux kernel中支持一個(gè)SOC平臺(tái)其實(shí)是非常簡(jiǎn)單的,讓linux kernel在一個(gè)特定的平臺(tái)上“跑”起來也是非常簡(jiǎn)單的,問題的重點(diǎn)是如何優(yōu)雅的”跑”。
三、混亂的ARM architecture代碼和存在的問題
每次正式的linux kernel release之后都會(huì)有兩周的merge window,在這個(gè)窗口期間,kernel各個(gè)部分的維護(hù)者都會(huì)提交各自的patch,將自己測(cè)試穩(wěn)定的代碼請(qǐng)求并入kernel main line。每到這個(gè)時(shí)候,Linus就會(huì)比較繁忙,他需要從各個(gè)內(nèi)核維護(hù)者的分支上取得最新代碼并merge到自己的kernel source tree中。Tony Lindgren,內(nèi)核OMAP development tree的維護(hù)者,發(fā)送了一個(gè)郵件給Linus,請(qǐng)求提交OMAP平臺(tái)代碼修改,并給出了一些細(xì)節(jié)描述:
1、簡(jiǎn)單介紹本次改動(dòng)
2、關(guān)于如何解決merge conficts。有些git mergetool就可以處理,不能處理的,給出了詳細(xì)介紹和解決方案
一切都很平常,也給出了足夠的信息,然而,正是這個(gè)pull request引發(fā)了一場(chǎng)針對(duì)ARM linux的內(nèi)核代碼的爭(zhēng)論。我相信Linus一定是對(duì)ARM相關(guān)的代碼早就不爽了,ARM的merge工作量較大倒在其次,主要是他認(rèn)為ARM很多的代碼都是垃圾,代碼里面有若干愚蠢的table,而多個(gè)人在維護(hù)這個(gè)table,從而導(dǎo)致了沖突。因此,在處理完OMAP的pull request之后(Linus并非針對(duì)OMAP平臺(tái),只是Tony Lindgren撞在槍口上了),他發(fā)出了怒吼:
Gaah. Guys, this whole ARM thing is a f*cking pain in the ass.
負(fù)責(zé)ARM linux開發(fā)的Russell King臉上掛不住,進(jìn)行了反駁:事情沒有那么嚴(yán)重,這次的merge conficts就是OMAP和IMX/MXC之間一點(diǎn)協(xié)調(diào)的問題,不能抹殺整個(gè)ARM linux團(tuán)隊(duì)的努力。其他的各個(gè)ARM平臺(tái)維護(hù)者也加入討論:ARM平臺(tái)如何復(fù)雜,如何龐大,對(duì)于arm linux code我們已經(jīng)有一些思考,正在進(jìn)行中……一時(shí)間,討論的氣氛有些尖銳,但總體是坦誠和友好的。
對(duì)于一件事情,不同層次的人有不同層次的思考。這次爭(zhēng)論涉及的人包括:
1、內(nèi)核維護(hù)者(CPU體系結(jié)構(gòu)無關(guān)的代碼)
2、維護(hù)ARM系統(tǒng)結(jié)構(gòu)代碼的人
3、維護(hù)ARM sub architecture的人(來自各個(gè)ARM SOC vendor)
維護(hù)ARM sub architecture的人并沒有強(qiáng)烈的使命感,作為公司的一員,他們最大的目標(biāo)是以最快的速度支持自己公司的SOC,盡快的占領(lǐng)市場(chǎng)。這些人的軟件功力未必強(qiáng),對(duì)linux kernel的理解未必深入(有些人可能很強(qiáng),但是人在江湖身不由己)。在這樣的情況下,很多SOC specific的代碼都是通過copy and paste,然后稍加修改代碼就提交了。此外,各個(gè)ARM vendor的SOC family是一長串的CPU list,每個(gè)CPU多多少少有些不同,這時(shí)候#ifdef就充斥了各個(gè)源代碼中,讓ARM mach-和plat-目錄下的代碼有些不忍直視。
作為維護(hù)ARM體系結(jié)構(gòu)的人,其能力不容置疑。以Russell King為首的team很好的維護(hù)了ARM體系結(jié)構(gòu)的代碼?;旧希薽ach-和plat-目錄,其他的目錄中的代碼和目錄組織是很好的。作為ARM linux的維護(hù)者,維護(hù)一個(gè)不斷有新的SOC加入的CPU architecture code的確是一個(gè)挑戰(zhàn)。在Intel X86的架構(gòu)一統(tǒng)天下的時(shí)候,任何想正面攻擊Intel的對(duì)手都敗下陣來。想要擊倒巨人(或者說想要和巨人并存)必須另辟蹊徑。ARM的策略有兩個(gè),一個(gè)是focus在嵌入式應(yīng)用上,也就意味著要求低功耗,同時(shí)也避免了和Intel的正面對(duì)抗。另外一個(gè)就是博采眾家之長,采用license IP的方式,讓更多的廠商加入ARM建立的生態(tài)系統(tǒng)。毫無疑問,ARM公司是成功的,但是這種模式也給ARM linux的維護(hù)者帶來了噩夢(mèng)。越來越多的芯片廠商加入ARM陣營,越來越多的ARM platform相關(guān)的代碼被加入到內(nèi)核,不同廠商的周邊HW block設(shè)計(jì)又各不相同……
內(nèi)核維護(hù)者是真正對(duì)操作系統(tǒng)內(nèi)核軟件有深入理解的人,他們往往能站在更高的層次上去觀察問題,發(fā)現(xiàn)問題。Linus注意到每次merge window中,ARM的代碼變化大約占整個(gè)ARCH目錄的60%,他認(rèn)為這是一個(gè)很明顯的符號(hào),意味著ARM linux的代碼可能存在問題。其實(shí),60%這個(gè)比率的確很夸張,因?yàn)閡nicore32是在2.6.39 merge window中第一次全新提交,它的代碼是全新的,但是其代碼變化大約占整個(gè)ARCH目錄的9.6%(需要提及的是unicore32是一個(gè)中國芯)。有些維護(hù)ARM linux的人認(rèn)為這是CPU市場(chǎng)占用率的體現(xiàn),不是問題,直到內(nèi)核維護(hù)者貼出實(shí)際的代碼并指出問題所在。內(nèi)核維護(hù)者當(dāng)然想linux kernel支持更多的硬件平臺(tái),但是他們更愿意為linux kernel制定更長遠(yuǎn)的規(guī)劃。例如:對(duì)于各種繁雜的ARM平臺(tái),用一個(gè)kernel image來支持。
經(jīng)過爭(zhēng)論,確定的問題如下:
1、ARM linux缺少platform(各個(gè)ARM sub architecture,或者說各個(gè)SOC)之間的協(xié)調(diào),導(dǎo)致arm linux的代碼有重復(fù)。值得一提的是在本次爭(zhēng)論之前,ARM維護(hù)者已經(jīng)進(jìn)行了不少相關(guān)的工作(例如PM和clock tree)來抽象相同的功能模塊。
2、ARM linux中大量的board specific的源代碼應(yīng)該踢出kernel,否則這些垃圾代碼和table會(huì)影響linux kernel的長期目標(biāo)。
3、各個(gè)sub architecture的維護(hù)者直接提交給Linux并入主線的機(jī)制缺乏層次。
四、新內(nèi)核的解決之道
針對(duì)ARM linux的現(xiàn)狀,最需要解決的是人員問題,也就是如何整合ARM sub architecture(各個(gè)ARM Vendor)的資源。因此,內(nèi)核社區(qū)成立了一個(gè)ARM sub architecture的team,該team主要負(fù)責(zé)協(xié)調(diào)各個(gè)ARM廠商的代碼(not ARM core part),Russell King繼續(xù)負(fù)責(zé)ARM core part的代碼。此外,建立一個(gè)ARM platform consolidation tree。ARM sub architecture team負(fù)責(zé)review各個(gè)sub architecture維護(hù)者提交的代碼,并在ARM platform consolidation tree上維護(hù)。在下一個(gè)merge window到來的時(shí)候,將patch發(fā)送給Linus。
針對(duì)重復(fù)的代碼問題,如果不同的SOC使用了相同的IP block(例如I2C controller),那么這個(gè)driver的code要從各個(gè)arch/arm/mach-xxx中獨(dú)立出來,變成一個(gè)通用的模塊供各個(gè)SOC specific的模塊使用。移動(dòng)到哪個(gè)目錄呢?對(duì)于I2C或者USB OTG而言,這些HW block的驅(qū)動(dòng)當(dāng)然應(yīng)該移動(dòng)到kernel/drivers目錄。因?yàn)?,?duì)于這些外設(shè),可能是in-chip,也可能是off-chip的,但是對(duì)于軟件而言,它們是沒有差別的(或者說好的軟件抽象應(yīng)該掩蓋底層硬件的不同)。對(duì)于那些system level的code呢?例如clock control、interrupt control。其實(shí)這些也不是ARM-specific,應(yīng)該屬于linux kernel的核心代碼,應(yīng)該放到linux/kernel目錄下,屬于core-Linux-kernel frameworks。當(dāng)然對(duì)于ARM平臺(tái),也需要保存一些和framework交互的code,這些code叫做ARM SoC core architecture code。OK,總結(jié)一下:
1、ARM的核心代碼仍然保存在arch/arm目錄下
2、ARM SoC core architecture code保存在arch/arm目錄下
3、ARM SOC的周邊外設(shè)模塊的驅(qū)動(dòng)保存在drivers目錄下
4、ARM SOC的特定代碼在arch/arm/mach-xxx目錄下
5、ARM SOC board specific的代碼被移除,由Device Tree機(jī)制來負(fù)責(zé)傳遞硬件拓?fù)浜陀布Y源信息。
OK,終于來到了Device Tree了。本質(zhì)上,Device Tree改變了原來用hardcode方式將HW 配置信息嵌入到內(nèi)核代碼的方法,改用bootloader傳遞一個(gè)DB的形式。對(duì)于基于ARM CPU的嵌入式系統(tǒng),我們習(xí)慣于針對(duì)每一個(gè)platform進(jìn)行內(nèi)核的編譯。但是隨著ARM在消費(fèi)類電子上的廣泛應(yīng)用(甚至桌面系統(tǒng)、服務(wù)器系統(tǒng)),我們期望ARM能夠象X86那樣用一個(gè)kernel image來支持多個(gè)platform。在這種情況下,如果我們認(rèn)為kernel是一個(gè)black box,那么其輸入?yún)?shù)應(yīng)該包括:
1、識(shí)別platform的信息
2、runtime的配置參數(shù)
3、設(shè)備的拓?fù)浣Y(jié)構(gòu)以及特性
對(duì)于嵌入式系統(tǒng),在系統(tǒng)啟動(dòng)階段,bootloader會(huì)加載內(nèi)核并將控制權(quán)轉(zhuǎn)交給內(nèi)核,此外,還需要把上述的三個(gè)參數(shù)信息傳遞給kernel,以便kernel可以有較大的靈活性。在linux kernel中,Device Tree的設(shè)計(jì)目標(biāo)就是如此。
?
評(píng)論
查看更多