博客 / 詳情

返回

Cubieboard2(四) 系統構建 —— 基於 mainline

1 環境準備

1.1 編譯環境準備

  • 1)配置編譯環境的幾大要素:

    • (1)OS 平台選擇基於微軟的 WSL(Windows Subsystem for Linux)的 Ubuntu 22.04(見其它文章);
    • (2)讀卡器+內存卡識別採用 usbipd(見其它文章);
    • (3)交叉編譯工具鏈採用 arm-linux-gnueabihf-gcc;
  • 2)WSL 和 usbipd 見其它文章,這裏僅記錄交叉編譯工具鏈的配置:

    # 安裝其它工具庫
    apt-get install build-essential libncurses5-dev u-boot-tools qemu-user-static \
                  debootstrap git binfmt-support libusb-1.0-0-dev pkg-config
    
    # (1)卸載原來的工具鏈
    apt-get remove gcc-arm-linux-gnueabi*
    
    # (2)下載工具鏈(可任選一個下載)
    wget https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
    wget https://releases.linaro.org/components/toolchain/binaries/5.5-2017.10/arm-linux-gnueabihf/gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabihf.tar.xz
    wget https://releases.linaro.org/components/toolchain/binaries/6.5-2018.12/arm-linux-gnueabihf/gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xz
    wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
    # (3)解壓
    mkdir /usr/local/arm
    tar -xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz -C /usr/local/arm
    tar -xvf gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabihf.tar.xz -C /usr/local/arm
    tar -xvf gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xz -C /usr/local/arm
    tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /usr/local/arm
    # (4)配置環境變量,在 /root/.bashrc 文件中添加:
    #export PATH=$PATH:gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin
    #export PATH=$PATH:gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabihf/bin
    #export PATH=$PATH:gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf/bin
    export PATH=$PATH:gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
    # (5)使工具鏈的環境變量生效
    cd && source ~/.bashrc
    
    # (6)測試
    arm-linux-gnueabihf-gcc -v
    Using built-in specs.
    COLLECT_GCC=arm-linux-gnueabihf-gcc
    ......
    gcc version 7.5.0 (Linaro GCC 7.5-2019.12)
    
  • 上面分別列出了 gcc 的 4.9、5.5、6.5、7.5 版本,根據自己要編譯的源碼選擇對應的版本,
    比如 linux-sunxi 基於 linux-3.4 所以要選擇 gcc 4.9 版本,而這裏我們要編譯 linux 的
    主線版本,所以選擇 gcc 的最新版本 7.5
  • 通過修改 .bashrc 切換 gcc 版本時可能會遇到不生效的情況。原因是 $PATH 的內容會被繼
    承,我們可以通過將 /usr/local/arm 下的舊 gcc 換個名字,然後重啓下系統解決。

  • 3)配置結果:

    [root@Chris] [2024-09-13 14:44:07] # [~] :
    -> cat /etc/os-release
    PRETTY_NAME="Ubuntu 22.04.4 LTS"
    NAME="Ubuntu"
    VERSION_ID="22.04"
    VERSION="22.04.4 LTS (Jammy Jellyfish)"
    ......
    
    [root@Chris] [2024-09-13 14:44:16] # [~] :
    -> lsusb
    Bus 002 Device 002: ID 067b:2731 Prolific Technology, Inc. USB SD Card Reader
    
    [root@Chris] [2024-09-13 14:44:19] # [~] :
    -> lsblk
    NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
    ......
    sdd      8:48   1  29.1G  0 disk
    ├─sdd1   8:49   1    64M  0 part
    └─sdd2   8:50   1  29.1G  0 part
    
    [root@Chris] [2024-09-13 14:44:20] # [~] :
    -> arm-linux-gnueabihf-gcc -v
    Using built-in specs.
    COLLECT_GCC=arm-linux-gnueabihf-gcc
    ......
    gcc version 7.5.0 (Linaro GCC 7.5-2019.12)

1.2 主線源碼準備

源碼可以從其官方網站下載壓縮包,但是我更推薦通過 git 倉庫下載。原因有兩個:
一個是方便切換源碼版本;另外就是方便隨時查看修改內、還原錯誤修改。

1.2.1 linux 源碼

  • 1)linux 源碼:3 個倉庫任選其一

    # linux 源碼倉庫在 gitlab、github 上由 Linus Torvalds 維護
    git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    git clone https://github.com/torvalds/linux.git
    
    # 由於 github 連接不穩定等原因,我們可以通過其它方式獲取源碼 —— 由 Gitee 官方
    # 提供的 Linux 源碼的鏡像倉庫,每天同步一次。
    git clone https://gitee.com/mirrors/Linux.git
    
    
    # 由於這次編譯主要是為了支持 Tenda 的 aic8800 無線網卡,其支持的內核版本為 V3.10-V6.2,
    # 目前(2024.9.13)最新的 v6.1 版本為 v6.1-rc8,所以這裏選擇 v6.1-rc8 版本。
    
    # 查看內核版本分支
    git branch -a       # 查看所有分支
    git fetch --tags    # 獲取最新標籤
    git tag | grep v6   # 查看並篩選標籤名
    # 根據標籤創建分支
    git checkout tags/v6.1-rc8
    
    # 已經做了修改,又需要在內核源碼分支間切換時,可以使用 git stash,如:
    # git stash [save "message"]    # 將未提交的更改保存到暫存區,並指定名稱為 message(可省略)
    # git stash pop                 # 恢復暫存區的更改

1.2.2 U-Boot 源碼

  • 1)u-boot 源碼:2 個倉庫任選其一

    # 同理,u-boot 源碼也提供兩個倉庫地址,任選一個即可
    # github 倉庫
    git clone https://github.com/u-boot/u-boot.git
    # gitee 鏡像倉庫
    git clone https://gitee.com/mirrors/u-boot.git

1.2.3 啓動文件 boot.scr

  • 1)新建 boot.cmd 文件,並輸入以下內容:

    setenv stdout serial,hdmi
    setenv stderr serial,hdmi
    fatload mmc 0 0x46000000 uImage
    fatload mmc 0 0x49000000 sun7i-a20-cubieboard2.dtb
    setenv bootargs console=ttyS0,115200 rw [earlyprintk] root=/dev/mmcblk0p2 rootwait panic=10 ${extra}
    bootm 0x46000000 - 0x49000000
  • 2)在上述內容的設置 bootargs 時,沒有添加 rw,會導致 “Read-only file system” 的錯誤。
  • 3)編譯出 boot.scr:

    mkimage -C none -A arm -T script -d boot.cmd boot.scr

1.2.4 根文件系統 rootfs

這裏我們使用 debootstrap 製作從鏡像網站下載的根文件系統包。
  • 1)生成 rootfs:

    ## man debootstrap :
     # --no-check-gpg :Disables checking gpg signatures of retrieved Release files.
     #
     # 從 man 的示例 “debootstrap stretch ./stretch-chroot http://deb.debian.org/debian” 可知:
     # 這裏允許自定義下載源,官方的地址已經不支持 wheezy 版本,這裏通過指定阿里源來指定 debian 版本為 fullseye 或 bookworm
     # 
    debootstrap --foreign --no-check-gpg --arch armhf bookworm . http://mirrors.aliyun.com/debian/
    debootstrap --foreign --no-check-gpg --arch armhf bullseye . http://mirrors.aliyun.com/debian/
    
    # 如果要製作 ubuntu 根文件系統,則需要指定 ubuntu 的源
    debootstrap --foreign --no-check-gpg --arch armhf noble . https://mirrors.aliyun.com/ubuntu-ports/
    debootstrap --foreign --no-check-gpg --arch armhf jammy . https://mirrors.aliyun.com/ubuntu-ports/
    
    cp /usr/bin/qemu-arm-static usr/bin/
    LC_ALL=C LANGUAGE=C LANG=C chroot . /debootstrap/debootstrap --second-stage
至此,所有的環境我們準備就緒,使用 tree 命令查看一下:

2 內核編譯

2.1 添加 tenda aic8800 驅動(可選)

linux-sunxi 基於 linux-3.4 內核修改,而 Tenda U2 V5.0(基於 aic8800 芯片)支持的 linux 內核版本為 V3.10-V6.2。
嘗試在升級內核後的 Cubieboard2 上安裝 .deb 驅動包,但報錯 linux-headers 問題以及 Invalid module format 問題,因此選擇直接編譯到內核中。
# 複製內核源碼(來自其驅動的 deb 包解壓)
cp ~/aic8800/drivers/aic8800/ -r drivers/net/wireless/

# 打開 drivers/net/wireless/Makefile 文件,添加:
obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/

# 打開 drivers/net/wireless/Kconfig 文件,添加:
source "drivers/net/wireless/aic8800/Kconfig"
  • 查看修改結果:

2.2 編譯 linux 內核

  • 1)以 sunxi_defconfig 為基礎,生成 .config 配置文件:

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sunxi_defconfig
    
    ......
    #
    # configuration written to .config
    #
    在 arch/arm/configs/ 目錄下有許多開發板的預定義配置文件,這裏我們選擇 Allwinner Cubieboard2 的 sunxi_defconfig
  • 2)編譯菜單項配置(這是一個需要不斷調試的枯燥工作):

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
    輸入上述命令後,會彈出編譯菜單項的窗口,根據自己的需求修改。我這裏需要無線網卡 AIC8800、USB 大容量設備(用來接 USB 轉 SSD)等。
    *,表示該驅動將作為內核的一部分被編譯進內核映像中,鍵入 “Y” 生效;M,則表示該驅動將作為一個獨立的模塊編譯,並且可以在需要時通過 insmod 或 modprobe 加載,鍵入 “M” 生效;鍵入 “N” 表示不選中。

image.png

  • 3)開始編譯(i7-9750 12 核心花費 5 分鐘):

    make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage dtbs
    ......
    OBJCOPY arch/arm/boot/zImage
    Kernel: arch/arm/boot/zImage is ready
    
    # 把 zImage 轉換為 uImage 
    cd ~/mainline/linux
    mkimage -A arm -O linux -T kernel -C none -a 0x46000000 -e 0x46000000 -n "Linux kernel uImage" -d arch/arm/boot/zImage ../uImage
  • 4)複製 dtc(編譯與反編譯設備樹文件)到 /usr/bin 目錄備用:

    cp ./scripts/dtc/dtc /usr/bin

3 U-Boot 編譯

  • 1)查看 Cubieboard2 配置文件:

  • 2)編譯生成 u-boot-sunxi-with-spl.bin 文件:

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- Cubieboard2_defconfig
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
    
    ......
    OBJCOPY spl/u-boot-spl-nodtb.bin
    COPY    spl/u-boot-spl.bin
    SYM     spl/u-boot-spl.sym
    MKIMAGE spl/sunxi-spl.bin
    MKIMAGE u-boot.img
    COPY    u-boot.dtb
    MKIMAGE u-boot-dtb.img
    BINMAN  .binman_stamp
    OFCHK   .config

4 分區與燒錄

4.1 sdcard 分區

  • 1)讀卡器插入主機後,查看:

    [root@Chris] [2024-09-13 18:00:33] # [~] :
    -> lsblk
    NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
    .....
    sdd      8:48   1  29.1G  0 disk
    └─sdd1   8:49   1  29.1G  0 part
  • 2)創建 DOS 分區表:

  • 3)創建 2 個分區:

  • 4)格式化:

    mkfs.vfat ${card}1
    mkfs.ext4 ${card}2

4.2 燒錄 SPL

  • 1)SPL(Second Program Loader,可以認為是 uboot 的 bootloader,用來加載完整 uboot 到 SDRAM 中)燒錄:

    dd if=u-boot-sunxi-with-spl.bin of=$card bs=1024 seek=8
    sync

4.3 燒錄第 1 分區

  • 2)燒錄鏡像、dtb、啓動文件 boot.scr 到 sdcard 的第一分區中:

    cd ~/mainline/
    mkdir /mnt/h
    
    # 掛載分區 1
    mount ${card}1                /mnt/h
    cp linux/arch/arm/boot/dts/sun7i-a20-cubieboard2.dtb /mnt/h
    cp linux/arch/arm/boot/zImage /mnt/h
    cp boot.scr                   /mnt/h
    
    # 卸載分區 1
    sync && sudo umount /mnt/h

    image.png

4.3 燒錄第 2 分區

第二分區主要燒錄根文件系統 rootfs。
  • 1)配置根文件系統 rootfs:

    cd ~/rootfs/chroot-armhf-bullseye/
    chroot . passwd
    
    echo "Cubieboard2"            > etc/hostname && cat etc/hostname
    echo "127.0.0.1 Cubieboard2" >> etc/hosts && cat etc/hosts
    
    # 安裝內核驅動模塊
    cd ~/mainline/linux
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=~/rootfs/chroot-armhf-bullseye/ modules modules_install
    
    cd ~/rootfs/chroot-armhf-bullseye/
    
    # 初始化 inittab 文件
    echo T0:2345:respawn:/sbin/getty -L ttyS0 115200 vt100 >> etc/inittab && cat etc/inittab
    
    # 掛載 SSD
    chroot . mkdir /data
    echo UUID=8612ea26-f6a4-4b2e-b9bc-775a662b0dea /data ext2 defaults,noatime,nofail 0 0 >> etc/fstab
    
    # 初始化 sources.list 文件
    # vi etc/apt/sources.list
    
    chroot . apt-get update
    chroot . apt-get upgrade
    chroot . apt-get install openssh-server locales wireless-tools wpasupplicant vim lrzsz net-tools ntpdate
    echo "*/60 * * * * /usr/sbin/ntpdate ntp.sjtu.edu.cn" >> /var/spool/cron/crontabs/root
    
    echo "export LC_ALL=\"zh_CN.UTF-8\""
    echo "en_US.UTF-8 UTF-8" > etc/locale.gen
    echo "zh_CN.UTF-8 UTF-8" >> etc/locale.gen
    chroot . locale-gen
    
    
    
    # 備份 rootfs。
    cd ../ && tar -czvf chroot-armhf-bullseye-`date +%Y%m%d_%H%M%S`.tar.gz chroot-armhf-bullseye/
  • 2)燒錄到第 2 分區:

    # 掛載分區 2
    mount ${card}2 /mnt/h
    # 燒錄 rootfs
    mv ~/rootfs/chroot-armhf-bullseye/* /mnt/h/
    # 卸載分區 2
    sync && umount /mnt/h

附錄:基於 AIC8800 的 Tenda U2 V5 USB WIFI

  • 參考:

    • 驅動編譯:https://cloud-atlas.readthedocs.io/zh-cn/latest/linux/ubuntu_...
    • 內核驅動移植:https://www.cnblogs.com/weidongshan/articles/18367372
    • AIC8800D Wi-Fi6/BT5.0 SoC USB移植手冊:https://bbs.16rd.com/thread-586140-1-1.html
    • RK3568 Debian AIC8800移植:https://blog.csdn.net/zyaaaac/article/details/133947137
    • A20網絡機頂盒移植4.5內核+U-Boot+rootfs:https://www.csdndocs.com/article/7504314
  • 1)添加驅動程序:以基於 aic8800 的 USB WIFI 為例

    • (1)將內核文件複製到 drivers/net/wireless 目錄下
    • (2)修改 drivers/net/wireless/Kconfig 文件,添加下面一行內容:

      source "drivers/net/wireless/aic8800/Kconfig"
    • (3)修改 drivers/net/wireless/Makefile 文件,添加下面一行內容:

      obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/
    • (4)通過 make menuconfig 修改配置文件時,進行如下選擇:

      Device Drivers  --->
      [*] Network device support  --->
          [*]   Wireless LAN  --->
              [*]   AIC wireless Support
              <M>     AIC8800 wlan Support
              <M>     AIC8800 bluetooth Support (UART)
  • 2)Linux 內核編譯參考:

    # 安裝工具鏈
    apt-get install build-essential bc bison flex libncurses5-dev libssl-dev \
        gcc-arm-linux-gnueabihf arm-linux-gnueabihf-g++
    
    # 下載內核
    git clone -b v5.4 https://github.com/torvalds/linux.git
    cd linux
    
    # 生成默認的內核配置文件
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig  
    # 啓動一個基於文本的交互式菜單,允許用户手動配置內核
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig 
    
    # 主要用於在現有配置基礎上進行增量更新,以適應新的內核版本或更新的默認配置
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- olddefconfig
    # 編譯內核鏡像
    make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules
    # 僅編譯內核驅動
    make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=drivers/net/wireless/aic8800 modules
    
    # 清理
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- clean
    
  • 3)Tenda U2 V5 最小內核版本支持 3.10,在 3.18.140 版本編譯成功
  • 4)問題處理(編譯 linux-3.11 版本時出現):ERROR: Kernel configuration is invalid.

    現象:
    ERROR: Kernel configuration is invalid.
         include/generated/autoconf.h or include/config/auto.conf are missing.
         Run 'make oldconfig && make prepare' on kernel src to fix it.
    
    處理:
    # 清理編譯失敗的文件
    make mrproper 
    
    # 生成默認的內核配置文件
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig  
    # 啓動一個基於文本的交互式菜單,允許用户手動配置內核
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig 
    # 主要用於在現有配置基礎上進行增量更新,以適應新的內核版本或更新的默認配置
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- olddefconfig
    
    # 準備內核源碼樹,生成一些必要的頭文件和其他輔助文件。
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- prepare
    # 生成內核編譯過程中需要用到的腳本文件
    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- scripts 
    ...
  • 5)問題處理:

    WARNING: Symbol version dump /root/linux-3.10.1/Module.symvers
           is missing; modules will have no dependencies and modversions.
    
    先編譯內核鏡像,再編譯內核驅動即可
    make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules
    make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=drivers/net/wireless/aic8800 modules
  • 6)問題處理:

    # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sunxi_defconfig
    
    drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig:4: syntax error
    drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig:3: unknown statement "---help---"
    drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig:4:warning: ignoring unsupported character '.'
    drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig:4: unknown statement "This"
    make[1]: *** [scripts/kconfig/Makefile:94: sunxi_defconfig] Error 1
    make: *** [Makefile:697: sunxi_defconfig] Error 2
    
    通過 make mrproper 命令清理舊的編譯緩存文件。
    
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.