文章總列表

回憶青春往事,編譯Raspberry Pi核心,讓WiFi網卡不要一閃一閃亮晶晶

我與Linux Kernel

我大概讀高中接觸RedHat Linux 6.0的年代,編譯Linux Kernel算是滿重要的技能,比如某個硬體沒有預設支援,就要編譯Kernel才能用。後來的Kernel支援module,其實大多的driver都會以modules的方式先弄好,而且RedHat這些package都弄得很好,幾乎是裝好就會動,也不大需要再手工編譯核心。而且現在的電腦記憶體只有多,自己編譯核心讓記憶體少個1MB,除非是做產品,不然毫無意義。多年過去,這項技能我也不再使用。


講完歷史,接下來聊一下為什麼又要自己編譯核心。我在兒子房間放了一片Raspberry Pi,上面插了WiFi USB,像下面這張圖(出處)。WiFI Dongle有個藍光會閃啊閃,兒子有時候晚上睡不著,會盯著他看。我在網路上查了很久,發現要搞定他的唯一手法是重新編譯RTL8192CU的驅動程式,看起來沒什麼好辦法,只好重拾手工技能。



一些步驟和心得

我無法把自己嘗試錯誤的心路歷程都寫下來,這樣會顯得我很笨(笑)。但是起碼這題,我可以整理一些步驟給自己和偶然經過這裡的人參考。


先抓一份Raspberry Pi Source Code

Raspberry Pi基金會其實有給一份怎麼build Kernel的文件。但是我想說,這邊其實會有個陷阱:比如我的kernel是4.4.27+,用他建議的命令抓到的source code是最新版,比我當前的4.4.27+還要更新。這點其實不會怎樣,如果您想要把整個Kernel重新build過,包括modules都自己來,這樣是沒問題的。但我不想整份Kernel都重來,我只想抓當前Kernel版本的RTL8192 driver小改一下,讓他不要一閃一閃亮晶晶,我真的不想動整份Kernel...

git clone --depth=1 https://github.com/raspberrypi/linux

這邊聊一下Linux Kernel有囉嗦的地方,隨便拿個module還不能拿來用。我做完整個project大概發現有這些條件:
  • Kernel版本要完全一樣
  • Compiler版本要完全一樣 (比如最新版Kernel用gcc4.9,但我的RPi只有4.6...)
  • ARM instruction set要完全一樣
  • 其他奇怪的條件...

先在RPi3做實驗

使用Raspberry Pi這種大牌子的硬體,最大的好處是很多問題都有人解過了。上面那題其實已經有人解過,答案是rpi-source這個script,只要到他網頁照著跑安裝命令,再執行rpi-source就會給您一份當前kernel版本的source code。我先在新買的RPi3做實驗,很順利的取得source code。

然後照著這篇文章的說明修改RTL8192 driver。只是改改header file重新編譯,這一定超簡單的!

// linux/driver/net/wireless/rtl8192cu/include/autoconf.h

// #define CONFIG_LED           // <-- comment this line out to disable LED
#ifdef CONFIG_LED
    #define CONFIG_SW_LED
    #ifdef CONFIG_SW_LED
        //#define CONFIG_LED_HANDLED_BY_CMD_THREAD
    #endif

#endif // CONFIG_LED
我找到了這篇,有些步驟可以只編譯modules,加上本來RPi的文件。重要的步驟寫在下面
  1. For RPI 1
    make bcmrpi_defconfig      (the file is located in arch/arm/config/)

    For RPI 2/3
    make bcm2709_defconfig    (the file is located in arch/arm/config/)

    這個步驟其實不會真的編譯kernel,只是幫你把RPI需要的Kernel options填到.config這個檔案給後面用
  2. 然後要做點準備步驟,後面才可以編譯
    make prepare
    make modules_prepare
  3. 第三步就是編譯
    make -j4 SUBDIRS=drivers/net/wireless/realtek/rtl8192cu/modules
  4. 如果一切順利,就可以取貨以及覆蓋本來的driver。當然可以直接覆蓋,優雅一點是把原本的備份下來,或著建個symbolic link之類的
    貨:drivers/net/wireless/realtek/rtl8192cu/8192cu.ko
    本來的driver:/lib/modules/4.4.27-v7+/kernel/drivers/net/wireless/realtek/rtl8192cu/8192cu.ko

  5. 在RPi上頭插上USB dongle,使用lsmod/ rmmod/ insmod載入新舊版本的driver,並且觀察是否ifconfig有出現wlan1這個介面。

事情很順利,很快我的RPi3插上USB dongle就不會一閃一閃亮晶晶,我也覺得這題也不過就這樣而已。到了RPi 1一定也輕鬆解決。


RPi 1的苦難

先回答一題更基本的問題:為什麼不直接把RPi3拿去兒子房間?是這樣的,因為還有一些service移植不過去,而且會動的東西不要動它其實永遠比較好...

前面我列出Linux Kernel module囉嗦之處,其實是在這裡感受到的,這邊簡單列一下

  1. 在RPi1呼叫rpi-source確實可以拿到kernel source code,但是他抱怨我的gcc版本太舊(v4.6)。還好他可以用--skip-gcc硬抓一份source code回來。
  2. 照上面的步驟做,想說放到安裝目錄作完收工。結果因為gcc版本不一樣(人家用v4.9),開機不會動,沒網路。
  3. 該死,我是遠端作業,兒子還在裡面睡覺沒辦法拿出來修。
  4. 隔天拿出來看開機畫面,是kernel panic,還沒有safe mode能用。還好SD卡拿到RPi3能讀,把driver還原就回復正常。
  5. 試著在RPi3上面build,不知道為什麼用的是ARMv7指令(但是我要ARMv6)
  6. 把整份source code拷貝到RPi3,整個重做,還是不會動。使用modinfo看新舊版本的driver,發現我編出來的少了底下兩列
  7. 其實已經快絕望了,因為我不只測上面幾個步驟。最後我決定整份kernel重build,命令如下。這次弄出來的driver總算上圖兩行都有了,也會動了!
    make -j4 zImage modules

結語

寫到這裡,您可能會問,那幹嘛不一開始就build整份kernel?因為我用的RPi3內建的CPU只有Cortex-A53,雖然號稱4核,但是效能孱弱無比。編譯整份kernel大概要2hr,我是剛好出門,死馬當活馬醫剛好矇到。不然就要設定cross compile環境,這樣我可以用Intel Core-I5來弄就快得多。但是設定這些toolchain弄完頭髮都白了,還是別折騰了。

再呼應一開始講的,手工編譯核心這項技能大概已經在Linux Users失傳,現在只有Kernel開發者會用。回來玩一下,讓我想起17年前美好的時光,想起我的初戀女友(有關連嗎?),原來我唸高中是這麼久以前的事了。今天去合興車站等Kernel building,原來這裡是當年學長期末考睡過頭追火車的現場。

很多年後,偶爾手編Linux Kernel,回憶青春往事。

留言

北極熊小江寫道…
看來我們都是7年級前段班, 我也是coder不過是php, 沒看到這篇文章都已經快忘掉了自己編kernel 的東西了....以前還要選自己要編哪些驅動進去到kernel, 現在都不大需要管了. 最近在搞車子的OBDII 才找到你的網站, 沒想到EML372有這麼多故事可以看..這是不曉得位什麼缺了一段中間人那篇的文章似乎那篇消失了.
lihgong寫道…
同是七年級生,我很高興能看到電子業巨大的進展。當年200Mhz的處理器就要上萬台幣,現在樹莓派給了1Ghz,四核心只要35美金。他也成為我實現夢想的工具之一

如後面文章,我製作了一個產品,這些攻擊的技術其實是產品的基礎,於是我把文章都下架了。如果有興趣,我相信你可以聯繫得到我

使用ELM327和車子OBD2打交道很方便,但這個工具有他侷限之處。後來我的實驗工具都改用底下這個模組,他可以在Linux/Windows 使用,在走上各種歪路後,這是我暫時的選擇
https://m.tb.cn/h.eD0vLdZ?sm=ef1de8

這個網誌中的熱門文章

STM32 UART + DMA,使用HAL實作TX/RX,以及不定長度接收

幼犬書桌椅選擇心得 升降桌 兒童桌椅

CANON G3000 廢墨瓶改裝