2440 (2) -- linux移植

475 阅读8分钟

交叉编译器

s3c2440使用ARM920T内核,v4T架构,因此选择交叉编译器时,需要保证交叉编译器支持v4T架构。比如使用gcc11.3时,是支持该架构的.

官方提供的编译器来自于sourcery,均只能在i386,i686机器上运行,可以在这里查看可用列表,另外经过我比对所有glibc版本,发现没有对armv6以前的任何支持,导致后续编译busybox时依赖有glibc中的libm.a会出现问题。

archlinux直接从aur仓库安装arm-linux-gnueabi-gcc即可,不过我尝试了一下编译失败了,看起来很久没有人维护了。

yaourt -Syy arm-linux-gnueabi-binutils
yaourt -Syy arm-linux-gnueabi-gcc

ARM提供了预编译版本,可以从他们的官网下载。

  • 我的系统是64位系统,所以选择x86_64 Linux hosted cross compilers下面的内容
  • 需要编译 小端,linux内核,所以选择AArch64 GNU/Linux target (aarch64-none-linux-gnu)里的内容
  • 编译的文件要放在32位的2440上运行,所以选择gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz,但是2440是一块比较老的芯片v4T架构,上面没有FPU,所以是不支持hard float的。寻找到之前的 8.3-2019.02 release版本中存在soft float版本,选择gcc-arm-8.3-2019.02-x86_64-arm-linux-gnueabihf.tar.xz
Toolchain Package NameHost OSTarget Description
gcc-arm-10.3-2021.07-aarch64-aarch64-none-elf.tar.xzAArch64 LinuxAArch64 ELF bare-metal target.
gcc-arm-10.3-2021.07-aarch64-arm-none-eabi.tar.xzAArch64 LinuxAArch32 bare-metal target.
gcc-arm-10.3-2021.07-aarch64-arm-none-linux-gnueabihf.tar.xzAArch64 LinuxAArch32 GNU/Linux target with hard float.
gcc-arm-10.3-2021.07-mingw-w64-i686-arm-none-eabi.tar.xzWindowsAArch32 bare-metal target.
gcc-arm-10.3-2021.07-mingw-w64-i686-aarch64-none-elf.tar.xzWindowsAArch64 ELF bare-metal target.
gcc-arm-10.3-2021.07-mingw-w64-i686-arm-none-linux-gnueabihf.tar.xzWindowsAArch32 GNU/Linux target with hard float.
gcc-arm-10.3-2021.07-mingw-w64-i686-aarch64-none-linux-gnu.tar.xzWindowsAArch64 GNU/Linux target.
gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xzx86_64 LinuxAArch64 ELF bare-metal target.
gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xzx86_64 LinuxAArch64 GNU/Linux target.
gcc-arm-10.3-2021.07-x86_64-aarch64_be-none-linux-gnu.tar.xzx86_64 LinuxAArch64 GNU/Linux big-endian target.
gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xzx86_64 LinuxAArch32 bare-metal target.
gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xzx86_64 LinuxAArch32 GNU/Linux target with hard float.

另外选择的版本还要和linux kernel版本匹配,比如在下载的kernel源码中有对应的目录./include/linux/compiler-gccx.h。需要下载对应的gccx版本,否则会出现错误# fatal error: linux/compiler-gcc6.h: No such file or directory

linaro官网可以修改链接中版本号,找到旧版本的arm编译器。2440本身非常古老了,在最新的linux kernel中即将失去支持。

linux kernel

arch wiki参考

linuxkernel参考

  • 下载某个版本kernel至本地,比如某个kernel为https://cdn.kernel.org/pub/linux/kernel/vA.x/linux-A.B.C.tar.xz(不过24xx对应的支持会在2022年之后移除,因此以后的内核应该很难移植到2440上了)
mkdir <路径>/kernelbuild
cd <路径>/kernelbuild
wget https://cdn.kernel.org/pub/linux/kernel/vA.x/linux-A.B.C.tar.xz
  • 解压
unxz linux-A.B.C.tar.xz
tar -xvf linux-A.B.C.tar
  • 清除所有中间target
cd linux-A.B.C
make mrproper
  • 配置kernel,由于2440是32位处理器,arch为ARM,对于Makefile中的ARCH,CROSS_COMPILE需要修改,也可以在make时作为环境变量引入,例如下面(在此之前需要下载交叉编译器确保有arm-linux-xxx编译器能够被调用)
make ARCH=arm CROSS_COMPILE=arm-linux- 

,我选择了直接改Makefile,省得每次输出错

ARCH = arm
CROSS_COMPILE = arm-linux-
  • 修改arch目录下平台配置,由于我使用的TQ2440是12MHz,所以需要手动配置时钟频率,对于我的linux kernel版本,该文件位于linux-5.19.9/arch/arm/mach-s3c/mach-smdk2440.c
// s3c2440_init_clocks(16934400);
s3c2440_init_clocks(12000000);
  • 编译镜像
    make menuconfig
    
    • 选择Load加载arch/arm/configs/s3c2410_defconfig
    • system type选择s3c2440
    • kernel feature选择use the arm eabi
    • save至.config
    • 另外默认的选项对于TQ2440不完全适用,直接编译并下载到板子后会在初始化vfs时出现kernel BUG at fs/sysfs/inode.c,看起来也许是初始某个设备挂了,需要按照TQ官方的config文件关闭大量的选项。
    • 硬件ECC选项需要关闭,否则初始化yaffs时会出错,导致 I/O error, dev mtdblock2, sector 0,Please append a correct "root=" boot option; here are the available partitions
  • 修改机器码:uboot中设定的机器码为168,因此需要改编arch/arm/tools/mach-types中对应s3c2440中342为168
  • 修改perl语法:kernel/timeconst.hdefined(@array)语法在perl中已经过时,需要改为@array
  • include/sound/soc-dai.h中修改union定义
/* parent codec/platform */
// union {
//  struct snd_soc_codec *codec;
//  struct snd_soc_platform *platform;
// };
struct snd_soc_platform *platform;
  • 编译
make zImage

Busybox

官网 下载busybox1.33.2,该版本在我下载时为stable状态。

  • 修改Makefile中ARCH,CROSSCOMPILE的值
  • make
  • make install
  • 新建一个文件夹rootfs,将_install中的内容复制到新文件夹rootfs

报错 storage size of ‘rlimit_fsize’ isn’t knowninclude/libbb.h添加一行#include "sys/resource.h"

YAFFS

因为TQ2440试用NAND作为存储,对于NAND存储介质,通常的文件系统并不适合,YAFFS比较适合这种介质。 官方文档

  • yaffs对新的linuxl内核没有支持,直接编译需要修改部分地方,我改正了部分函数,可以在新版本内核编译通过,仓库

  • 参考 current_kernel_time

  • 参考 ‘MS_RDONLY’ undeclared

  • 参考 为内核大于5.9版本增加bdevname函数

  • 参考 修正proc_create对旧版本依赖

  • 报错

Warning: unable to open an initial console.                                     
Failed to execute /linuxrc.  Attempting defaults...                             
Kernel panic - not syncing: No init found.  Try passing init= option

自己编译的mkyaffs2image不能够被识别,很头疼,需要使用一个版本

  • 报错

     runaway loop modprobe binfmt-464c
    
    • 检查了kernel的menuconfig配置,Kernel support for ELF binaries 已经加入了
    • 检查了BUSYBOX的menuconfig和makefile配置,已经设置了arm-linux前缀
    • 使用自己编译的linux内核和官方提供的文件系统,可以进入;换成自己的文件系统就会报错
    • 使用官方提供的内核和自己的文件系统也会报错,对比说明制作的文件系统有问题
    • 使用官方的文件系统进入后将自己的busybox文件传输过来执行进行检查,报错"line: 1: Syntax error: word unexpected (expecting ")")",使用file检查确认为ELF文件,将官方的busybox拷贝替换,再次制作文件系统,成功启动,说明是busybox这个文件的问题。
    • 使用readelf检查,发现指令集竟然不是armv4T,而我使用的交叉编译器并没有设置march,所以需要手动指定
    # arm-linux-gnueabi-readelf -A _install/bin/busybox
    Attribute Section: aeabi
    File Attributes
      Tag_CPU_name: "7-A"
      Tag_CPU_arch: v7
      Tag_CPU_arch_profile: Application
      Tag_ARM_ISA_use: Yes
      Tag_THUMB_ISA_use: Thumb-2
      Tag_FP_arch: VFPv3
      Tag_Advanced_SIMD_arch: NEONv1
      Tag_ABI_PCS_wchar_t: 4
      Tag_ABI_FP_rounding: Needed
      Tag_ABI_FP_denormal: Needed
      Tag_ABI_FP_exceptions: Needed
      Tag_ABI_FP_number_model: IEEE 754
      Tag_ABI_align_needed: 8-byte
      Tag_ABI_align_preserved: 8-byte, except leaf SP
      Tag_ABI_enum_size: int
      Tag_ABI_HardFP_use: SP and DP
      Tag_CPU_unaligned_access: v6
    

    问题定位是未指定march,之前编译linuxkernel时顺利通过,于是便忽视了这个问题,通过make V=1来检查busybox编译时执行的具体指令,最后发现在link的时候arch会从armv4t转变成armv7,经过几个小时摸索,发现交叉编译器中的libm.a全部是armv7架构,而且是busybox依赖项,因此必须移除该依赖。我找到了一份armv4t架构的libm.a,试图手动引入进busybox的link(make时加入make EXTRA_LDFLAGS="-L."),发现不止这一个依赖是armv7的架构。百般无奈下只能自己动手丰衣足食了。在x86-64机器上编译出支持armv4t的交叉编译器,我上传到这里。太难了使用virtualbox启动ubuntu-i386.iso镜像,使用官方提供的编译器在上面编译即可。

不同的交叉编译器编译出的可执行文件对应的linux版本不同,比如使用gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabi编译得到的bin/busybox的版本信息为

# file _install/bin/busybox
_install/bin/busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=f205bee369809f13870c1c298524503f0ba21175, stripped

而我使用的linux内核是2.6.30,所以不能够执行这个busybox文件,因此降低了编译器版本

  • 自动重启:进入系统,挂载文件系统,回车进入命令行均完成,但是过一段时间开发板自动重启,原因在于make menuconfig中在device driver中开启了看门狗,天嵌官方提供的文件镜像中包含一个喂狗程序,可以使得看门狗不会工作,但是我自制的文件系统还没有做这部分,所以临时的办法是把看门狗选项先关掉。

网卡驱动

TQ2440使用的是DM9000E网卡,在linux内核源码中drivers/net/dm9000.c可以直接使用。

  • BUSYBOX配置中取消静态编译,因为动态编译时libnss无法正常工作,导致域名无法解析;编译后拷贝编译器对应的lib至rootfs文件夹下
  • BUSYBOX对应的/etc/init.d/rcS中加入
ifconfig lo 127.0.0.1 #缺省值
net_set& #调用网络配置文件
  • /sbin加入可执行文件net_set
#!/bin/sh
echo Try to bring eth0 interface up ... > /dev/tq2440_serial0
if [ -f /etc/net.conf ] ; then
source/etc/net.conf
ifconfig eth0 down
ifconfig eth0 hw ether $MAC
echo ifconfig eth0 hw ether $MAC >/dev/tq2440_serial0
ifconfig eth0 $IPADDR netmask $NETMASK up
echo ifconfig eth0 $IPADDR netmask $NETMASK up >/dev/tq2440_serial0
route add default gw $GATEWAY
echo add default gw $GATEWAY >/dev/tq2440_serial0
else
ifconfig eth0 hw ether 10:23:45:67:89:ab
ifconfig eth0 192.168.1.6 netmask 255.255.255.0 up
routeadd default gw 192.168.1.2
echo ifconfig eth0 hw ether 10:23:45:67:89:ab > /dev/tq2440_serial0
echo ifconfig eth0 192.168.1.6 netmask 255.255.255.0 up >/dev/tq2440_serial0
echo routeadd default gw 192.168.1.2 >/dev/tq2440_serial0
fi
echo Done > /dev/tq2440_serial0
  • /etc中创建net.conf
IPADDR=192.168.1.6
NETMASK=255.255.255.0
GATEWAY=192.168.1.2
MAC=10:23:45:67:89:ab

参考