交叉编译器
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 Name | Host OS | Target Description |
|---|---|---|
| gcc-arm-10.3-2021.07-aarch64-aarch64-none-elf.tar.xz | AArch64 Linux | AArch64 ELF bare-metal target. |
| gcc-arm-10.3-2021.07-aarch64-arm-none-eabi.tar.xz | AArch64 Linux | AArch32 bare-metal target. |
| gcc-arm-10.3-2021.07-aarch64-arm-none-linux-gnueabihf.tar.xz | AArch64 Linux | AArch32 GNU/Linux target with hard float. |
| gcc-arm-10.3-2021.07-mingw-w64-i686-arm-none-eabi.tar.xz | Windows | AArch32 bare-metal target. |
| gcc-arm-10.3-2021.07-mingw-w64-i686-aarch64-none-elf.tar.xz | Windows | AArch64 ELF bare-metal target. |
| gcc-arm-10.3-2021.07-mingw-w64-i686-arm-none-linux-gnueabihf.tar.xz | Windows | AArch32 GNU/Linux target with hard float. |
| gcc-arm-10.3-2021.07-mingw-w64-i686-aarch64-none-linux-gnu.tar.xz | Windows | AArch64 GNU/Linux target. |
| gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz | x86_64 Linux | AArch64 ELF bare-metal target. |
| gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz | x86_64 Linux | AArch64 GNU/Linux target. |
| gcc-arm-10.3-2021.07-x86_64-aarch64_be-none-linux-gnu.tar.xz | x86_64 Linux | AArch64 GNU/Linux big-endian target. |
| gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz | x86_64 Linux | AArch32 bare-metal target. |
| gcc-arm-10.3-2021.07-x86_64-arm-none-linux-gnueabihf.tar.xz | x86_64 Linux | AArch32 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
- 下载某个版本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.h中defined(@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的值 makemake install- 新建一个文件夹
rootfs,将_install中的内容复制到新文件夹rootfs中
报错 storage size of ‘rlimit_fsize’ isn’t known
在include/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镜像,使用官方提供的编译器在上面编译即可。 - 检查了kernel的menuconfig配置,
不同的交叉编译器编译出的可执行文件对应的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