1. 程式人生 > >嵌入式Linux編譯內核步驟 / 重點解決機器碼問題

嵌入式Linux編譯內核步驟 / 重點解決機器碼問題

fig 否則 可謂 .... boot 實驗 燒寫 min lin

嵌入式系統更新內核

1. 前言

手裏有一塊Friendly ARM的MINI2451的板子,這周試著編譯內核,然後更新一下這個板子的Linux內核,想要更新Linux Kernel 4.1版本,但是種種原因實在是沒有更新成功;於是使用Friendly ARM板子提供的3.6版本的內核,但是他們的內核全都配置好了,你只需要按照常規的方法進行編譯就好了,貌似不能更深入的理解內核, 後來我從kernel.org官網上下載原版內核,然後一點點的把2451這個板子需要文件移植過去,可謂是問題百出啊,也學習到了很多東西。

2. 準備材料

  • FriendlyARM 的mini2451板子一塊
  • 使用的bootloader是FriendARM提供的閉源
    Superboot2451.bin
  • Linux3.6內核源代碼(在官網下的,純凈的)
  • mini2451提供的.config文件

3. 燒寫內核的幾個重點

3.1 拿到全新內核的幾個步驟

我們拿到全新內核的時候,一定要註意幾個步驟,好像並沒有幾個書上由我寫的這麽詳細的,基本上都是給一個大體的思路,但是到了真刀真槍上場的時候,真的是問題百出。以下講圍繞這幾個方面進行討論。

a) 修改頂層Makefile

b) Machine ID的處理( 在arch/arm/ 的mach中增加C文件 -> 修改Kconfig -> 修改Makefile文件 )

c) 在arch/arm/tools/mach-types 文件中增加Machine ID

3.1.1 修改頂層的Makefile

Makefile一共要修改2個地方即可:

  • 修改arch架構: ARCH ?= arm 註意,arm這幾個後面不要打空格啊,要不然make的時候不識別。

  • 修改cross_compile 路徑:CROSS_COMPILE?= /home/user/toolchian/arm-linux-

註意1,CROSS_COMPILE的表述,我這裏給的是全路徑,而不是像書籍和網絡博客上給的 arm-linux- ,這裏為什麽呢?因為你的電腦裏面可能裝了不是一個交叉編譯環境的工具鏈,所以這裏強烈推薦使用交叉編譯環境的絕對路徑,絕對不會出錯,可以放心大膽的使用。

註意2,arm-linux- 後面不要加空格,否則不會識別的,和ARCH那個選項一樣,都不要有空格。

否則就會拋出:“ make: ** /home/delvis/work/linux-3.6/arch/arm: 是一個目錄。 停止。”的錯誤。

Makefile只需要改這兩個位置就可以了,大可保存。

3.1.2 為了Machine ID準備之修改C文件

路徑就是 -> ./arch/arm/ 裏面關於mach-"各種型號",你在教學視頻或者書上經常看見如下的說明:

找一個和你板子型號相近的c文件然後復制一份出來。

我使用的是Linux3.2內核且,我的板子的型號是S3C2451的,所以很理所應當的找到mach-s3c24xx這個文件夾, ! 但是我發現在Linux4.1和Linux2.4版本的內核中沒有mach-s3c24xx這個文件夾,其實沒有什麽關系,只要找到和你板子芯片型號相近的就可以的。

我這裏是復制FriendlyARM提供的mach-mini2451.c這個文件,在這個文件需要註意幾個地方,我現在還不是很明白這個文件是做什麽的,看裏面很多初始化的程序包括GPIO、時鐘、定時器、中斷等等,應該是對2451板子進行初始化的。暫時我還不會寫,靠移植吧。

  • 文件末尾MACHINE_START( USER_DEFINE_STRING, "USER_DEFINE_STRING" ) { .... } 這個就是MACHINE id 的位置
  • 還有其中定義的函數,需要依賴很多頭文件,原生內核裏面沒有,缺什麽我就從FriendlyARM裏面拷貝到相應的目錄。

文件末尾的MACHINE_START傳遞的參數的USER_DEFINE_STRING就是我們一會兒要寫入machine id的宏定義,我這裏宏定義的字符串是MACH_MINI2451

3.1.3 修改mach-xxxx中的Kconfig文件

剛才剛剛添加了新的mach-mini2451.c的文件,就要在和這個文件同一個目錄下的Kconfig中加入這個的配置項,我給出我的配置項:

config MACH_MINI2451
        bool "MINI2451BYDELVIS"
        #select S3C24XX_SMDK
        select S3C_DEV_FB
        select S3C_DEV_HSMMC
        select S3C_DEV_HSMMC1
        select S3C_DEV_NAND
        select S3C_DEV_USB_HOST
        select S3C2416_SETUP_SDHCI
        select WIRELESS_EXT
        select WEXT_SPY
        select WEXT_PRIV
        select AVERAGE
        help
          Say Y here if you are using an FriendlyARM MINI2451

在Kconfig中增加這個字符串,在頂層進行make menuconfig的時候,這個選項就會出來,我們在make menuconfig的時候,最先應該的就是選擇板子的架構

1) System Type --> ARM sytem type( Samsung S3C24XX Socs ) --> Samsung S3C24XX SoCs

選擇後返回上一層

2)SASUNG S3C24XX SoCs Support ---> 先選上 SASUNG S3C2416/S3C2450 ---> 下面自動出 MINI2451BYDELVIS 一會兒說這個菜單的顯示邏輯如何的

3)Exit 並且 Save 成為.config

這些菜單的邏輯和歸屬主要是Kconfig決定的,我們的config MACH_MINI2451這個條目要放到正確的位置,不是隨便放一個位置就行,我們的每一個子菜單對於.config來說都是一項配置。

技術分享圖片

看圖,首先註意兩個畫紅圈的位置,我們講config MACH_MINI2451這一坨放在了 if CPU_S3C2416 ..... endif這個裏面,也就是說我們在make menuconfig中選擇了”MINI2451BYDELVIS“這個選項的時候,MACH_MINI2451默認在.config文件CPU為S3C2416,(也可見,我們的mach-mini2451.c文件是復制mach-s3c2416.c文件改裝而來了)

在make menuconfig菜單中,也只有選擇S3C2416這個CPU型號,我們的這個選項才會出現

3.1.3 修改mach-s3c24xx文件下的Makefile文件

我們平白無故的增加了mach-mini2451.c文件,如果進行全局編譯的時候,是不會進行編譯的,因為沒有makefile進行指導編譯,所以我們需要修改這一層的Makefile,當我進行全局編譯的時候,就有規則指導編譯器進行編譯。

# add by Carlos 2017.12.6
obj-$(CONFIG_MACH_MINI2451)             += mach-mini2451.o mini2451-lcds.o

在這一層的Makefile文件中隨便找一個位置,然後按照這個格式輸出文件。

3.1.4 增加機器碼

說到機器碼,我真的不得不吐槽一下Friendly ARM,在購買Friendly ARM的時候,購買的宣傳界面,大篇幅的說他們花了重金開發了Superboot2451.bin企業級的bootloader,重點是閉源,bootloader還是不錯的,從SD卡引導,支持串口,驅動支持的挺全的,還有一個他們獨創的可視化界面miniTools的USBMODE一鍵安裝系統,一鍵下載程序。但是好歹閉源的同時,把bootloader的關鍵參數給出啊!!!!我找了他們的Wiki,找了官網,手冊,就是沒有知道Superboot2451.bin的Machine ID,好歹把ID值給出來啊。

恩,後來經過實驗輸出,得到強大的閉源Superboot2451.bin的 機器碼 machine id 是: 0x00000695

好了,吐槽到此為止,我還是建議自己開發uboot,這樣方便。

只有bootloader和kernel中的機器碼一樣,內核才能正常啟動,否則將會拋出:

Error: unrecognized/unsupported machine ID (r1 = 0x33f60264).

我們要麽改正uboot中的ID,要麽改正kernel中的ID,總之,無論數字是什麽,要一樣。

好了,Superboot2451.bin的既然是閉源的就沒辦法進行改正了,那麽我們只能改正Kernel中的ID了,那麽Kernel中的ID該怎麽改正呢?

切換到: arch/arm/tools/文件夾,裏面有個mach-types文件,我們在後面追加一個:

mini2451 MACH_MINI2451 MINI2451 0x695

細心的朋友已經發現了,在上面的章節中,零零散散的文件用的也是這些字符,也就是mini2451、MACH_MINI2451、MINI2451這個宏定義都是這個ID值。

到此我們的的內核配置完畢了。

3.2 make menuconfig配置

切換到最後一步,進行make menuconfig進行.config的配置,在韋東山老師的視頻裏面,提到這個.config文件來源於三個部分

  1. 進行make menuconfig配置後的,你需要一條條的進行配置。
  2. 使用默認配置,在上面修改
  3. 使用廠家提供的

我這裏,使用廠家提供的mini2451_linux_config文件,在上面進行修改,首先就把運行把這個config文件復制過來,並且名字改為.config覆蓋原有的.config文件,然後進行make menucofig,在system type中如同上面講述的選擇正確的板子的型號。如果你沒有選擇,就會出現這樣的異常,在內核編譯到最後的時候,出現編譯kernel出現no machine record defined 錯誤。然後一些鬼一樣的網站給出餿主意,還被大量的博客轉載,簡直就是誤導人,你經過google或者百度,會有一個這樣的解決方案

這裏給一個!反!面!教!材!:

放狗搜後,按照如下方法可以解決。將arch/arm/kernel/vmlinux.lds的最後兩行(如下),給註釋起來,但都沒說是為了什麽
ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support"),
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")

反面教材來源:uncompressing linux .................................................後沒反應解決辦法 前半部分

簡直是神一樣的操作,出錯了,註釋起來就可以維持了,什麽邏輯,簡直是對技術的侮辱!!!我嘗試過了,的確內核編譯通過了,可以把內核傳輸到ARM上面,到Load Kernel的下一步,就拋出了Error: unrecognized/unsupported machine ID (r1 = 0x33f60264). 的異常,顯然是沒有機器碼沒有定義。

註釋這個鬼方法根本就不能用好嗎?誰出的餿主意!!

正確的解法是:

按照我們上面的章節進行配置,順理成章的解決Machine ID的問題: ->

1) Machine ID的處理( 在arch/arm/ 的mach中增加C文件 -> 修改Kconfig -> 修改Makefile文件 )

2) 在arch/arm/tools/mach-types 文件中增加Machine ID

3) 在make menuconfig的menu中選擇system type,選擇正確的型號,會自動配置到.config

3.3 make

然後開始make就可以了,編譯內核,我一般都喜歡用make -j8 多線程編程,速度快,但是很燒CPU。。。

技術分享圖片

基本上都是這樣的狀態。。。看溫度。

編譯完成之後,按照Friendly ARM提供的文檔,把zImage文件拷到SD卡正確的路徑,然後從SD卡啟動正常燒寫就好了。

4 總結

看到這樣的輸出的時候,真的很激動,終於內核開始正常解壓了。磨了人好幾天。

技術分享圖片
第15周主要搞內核的搞完了,最近要忙著復習考試,內核事情可能要稍微緩緩了。以後再慢慢研究。

參考文獻:

[1] 貴氣的博客著.Error: unrecognized/unsupported machine ID (r1 = 0x33f60264)..新浪博客.2011-03-20.

[2]韋東山著.《嵌入式Linux完全開發手冊-應用開發》書籍.

[3]FriendlyARM著.2451開發手冊. 用戶手冊.


版權聲明:

1. 本文為MULTIBEANS團隊研發跟隨文章,未經允許不得轉載。

2· 文中涉及的內容若有侵權行為,請與本人聯系,本人會及時刪除。

3· 尊重成果,本文將用的參考文獻全部給出,向無私的工程師,愛好者致敬。


嵌入式Linux編譯內核步驟 / 重點解決機器碼問題