系列文章目录
Exynos4412 移植Linux-6.1过程记录(一)下载、配置、编译Linux-6.1
项目 | 说明 |
---|---|
宿主机操作系统 | Ubuntu 20.04 LTS x86_64 |
宿主机Linux内核版本 | 5.4.0-126-generic |
目标机linux内核版本 | Linux-6.1 |
目标机硬件 | CBT4412(类似:tiny4412) |
MPU | Exynos4412(Cortex-A9) |
U-Boot | u-boot-2022.01-rc4 |
arm-none-linux-gnueabihf-gcc | gcc version 10.2.1 20201103 (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16)) |
一、下载针对Samsung的Linux内核
在选择Linux内核时,首先要知道有哪些个人或团体在维护针对目标机架构的内核。
在The Linux Kernel官网中,有针对Samsung SoC的Linux内核。目前已经在维护Linux-6.2.0-rc1版本了。网址如下:
kernel/git/krzk/linux.git - Linux Samsung SoC tree
1、下载Linux-6.1
本文下载Linux-6.1。下载地址:
https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git/snapshot/linux-6.1.tar.gz
- Linux-6.1和Linux-6.2.0-rc1:支持Cortex-A系列的CPU,包括Samsung的exynos4。
二、交叉编译工具链
1、交叉编译工具链的选择
访问Arm Developer 官网,根据gcc和glibc的版本,选择针对 Cortex-A系列的交叉编译工具链gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf。该版本包括以下工具:
2、GNU 10.2 cross-toolchain的安装
- 下载gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
cd /opt
wget https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz.asc
- 解压
sudo tar -xJf gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
sudo md5sum --check gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz.asc
如果显示
gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz: OK
表明 XZ 压缩包正常。
- 配置用户环境变量
Ubuntu用户分为root用户、系统用户和普通用户。为了方便使用,将/opt/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/bin/路径添加到root和普通用户变量的PATH中。实现方法是:
- 修改/root/.bashrc文件。这个文件修改的是root用户环境变量。在文件最后面新增加一行代码,内容如下:
export PATH=$PATH:/opt/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/bin/ - 修改~/.bashrc文件。这个文件修改的是当前用户环境变量。在文件最后面新增加一行代码,内容如下:
export PATH=$PATH:/opt/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/bin/
重启终端,让环境变量立即生效。 - 测试交又工具链
检测交叉工具链是否安装成功,命令如下:
$ arm-none-linux-gnueabihf-gcc -v
如果没有报错,并能够显示编译器的相关信息,则说明交叉工具链安装成功。
2、修改顶层目录下的Makefile
cd ~/linux-6.1
vim Makefile
把
ARCH ?= $(SUBARCH)
修改、并增加为
ARCH := arm
CROSS_COMPILE := arm-none-linux-gnueabihf-
CROSS_COMPILE修改为自己的交叉编译工具链。
二、为Exynos4412移植内核
3、导入默认配置
make exynos_defconfig
4、配置内核
make menuconfig
- Kernel hacking —>
[*] Panic on Oops
(5) panic timeout
[*] Kernel low-level debugging functions (read help!)
Kernel low-level debugging port (Use Samsung S3C UART 0 for low-level debug) —>
[ ] Enable decompressor debugging via DEBUG_LL output
[*] Early printk
Kernel low-level debugging port
根据自己开发板的串口来选择。我的是串口0。
5、修改arch/arm/tools/mach-types
u-boot的机器码和linux内核的要一致。我在移植U-Boot时,配置CONFIG_MACH_TYPE为MACH_TYPE_EXYNOS4412。
查找U-Boot中arch/arm/include/asm/mach-types.h,存在
#define MACH_TYPE_TINY4412 4608
#define MACH_TYPE_EXYNOS4412 5030
所以,在内核源码的arch/arm/tools/mach-types中仿照origen添加exynos4412对应的机器码。如下:
origen MACH_ORIGEN ORIGEN 3455
exynos4412 MACH_EXYNOS4412 EXYNOS4412 5030
6、编译设备树
(1)将内核源文件中的设备树文件/arch/arm/boot/dts/exynos4412-origen.dts拷贝一份,改文件名为exynos4412-cbt4412.dts并修改
cp ./arch/arm/boot/dts/exynos4412-origen.dts ./arch/arm/boot/dts/exynos4412-cbt4412.dts
gedit ./arch/arm/boot/dts/exynos4412-cbt4412.dts
保留串口、内存、时钟等配置,添加网卡的基本配置:
// SPDX-License-Identifier: GPL-2.0
/*
* Insignal's Exynos4412 based Origen board device tree source
*
* Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Device tree source file for Insignal's Origen board which is based on
* Samsung's Exynos4412 SoC.
*/
/dts-v1/;
#include "exynos4412.dtsi"
#include "exynos4412-pinctrl.dtsi"
#include <dt-bindings/clock/samsung,s2mps11.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include "exynos-mfc-reserved-memory.dtsi"
/ {
model = "CBt4412 board based on Exynos4412";
compatible = "samsung,exynos4412";
chosen {
stdout-path = &serial_0;
};
memory-controller@12570000 {
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x04000000 0x20000 // Bank0
1 0 0x05000000 0x20000 // Bank1
2 0 0x06000000 0x20000 // Bank2
3 0 0x07000000 0x20000>; // Bank3
};
memory@40000000 {
device_type = "memory";
reg = <0x40000000 0x40000000>;
};
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
clock-frequency = <0>;
};
xusbxti {
compatible = "samsung,clock-xusbxti";
clock-frequency = <24000000>;
};
};
};
&cpu_thermal {
cooling-maps {
cooling_map0: map0 {
/* Corresponds to 800MHz at freq_table */
cooling-device = <&cpu0 7 7>, <&cpu1 7 7>,
<&cpu2 7 7>, <&cpu3 7 7>;
};
cooling_map1: map1 {
/* Corresponds to 200MHz at freq_table */
cooling-device = <&cpu0 13 13>, <&cpu1 13 13>,
<&cpu2 13 13>, <&cpu3 13 13>;
};
};
};
&serial_0 {
status = "okay";
};
&serial_1 {
status = "okay";
};
&serial_2 {
status = "okay";
};
&serial_3 {
status = "okay";
};
(2)修改/arch/arm/boot/dts/Makefile文件,添加上我们新创的设备树文件exynos4412-cbt4412.dts
dtb-$(CONFIG_ARCH_EXYNOS4) += \
exynos4210-i9100.dtb \
exynos4210-origen.dtb \
exynos4210-smdkv310.dtb \
exynos4210-trats.dtb \
exynos4210-universal_c210.dtb \
exynos4412-i9300.dtb \
exynos4412-i9305.dtb \
exynos4412-itop-elite.dtb \
exynos4412-n710x.dtb \
exynos4412-odroidu3.dtb \
exynos4412-odroidx.dtb \
exynos4412-odroidx2.dtb \
exynos4412-origen.dtb \
exynos4412-cbt4412.dtb \
(3)在linu源码目录下编译设备树
$ make dtbs
DTC arch/arm/boot/dts/exynos4412-cbt4412.dtb
此时,在arch/arm/boot/dts/目录中生成exynos4412-cbt4412.dtb。
7、解决fatal error: gmp.h: No such file or director问题
编译内核,报错
make uImage
报错:error: gmp.h 没有这个文件或目录
通过360搜索,找到解决方案如下:
sudo apt-get install libgmp3-dev
8、解决error: mpc.h: No such file or director
编译内核,报错fatal error: gmp.h: 没有那个文件或目录。解决方法:
sudo apt-get install libmpc-dev
9、解决multiple (or no) load addresses错误
make uImage编译内核,报错multiple (or no) load addresses。表明没有定义宏LOADADDR。具体分析可参见博文Linux内核移植 part3:Exynos4412内核编译1
编辑arch/arm/boot/Makefile,直接添加
LOADADDR := 0x40008000
由于找不到mkimage工具,复制在uboot根目录tools目录的mkimage,放到/usr/local/bin即可。
sudo cp ~/u-boot-2022.01-rc4-cbt4412/tools/mkimage /usr/local/bin
准备就绪,make uImage编译内核,显示如下信息:
$ make uImage
10、解决gcc: error: unrecognized argument in option ‘-mabi=aapcs-linux’
CC scripts/mod/empty.o
gcc: error: unrecognized argument in option ‘-mabi=aapcs-linux’
gcc: note: valid arguments to ‘-mabi=’ are: ms sysv
gcc: error: unrecognized command line option ‘-mlittle-endian’
gcc: error: unrecognized command line option ‘-mtp=cp15’
gcc: error: unrecognized command line option ‘-mfpu=vfp’
make[1]: *** [scripts/Makefile.build:252: scripts/mod/empty.o] Error 1
make: *** [Makefile:1288: prepare0] Error 2
-mabi=aapcs-linux
、-mlittle-endian
等等这些是arm-none-linux-gnueabihf-gcc的编译选项,gcc 9是支持的。出现这个问题,是因为CC代表的编译器不正确。我采用以下命令可以继续编译。
make ARCH=arm && make CROSS_COMPILE=arm-none-linux-gnueabihf- && make
虽然我在顶层目录的Makefile中,增加了ARCH :=arm
和CROSS_COMPILE :=arm-none-linux-gnueabihf-
,但是仍然会出现这个问题。然后,我有安装了lib32z1,问题仍然存在。但是再捣鼓了make distclean;make exynos_defconfig;make menuconfig
一阵之后,就没有出现这个问题了。我分析问题的解决可能是2个方面:一是安装了lib32z1;二是Makefile中,ARCH和 CROSS_COMPILE的赋值要用:=
,而不能用?=
。:= 、?=、 +=、 =
四者的区别可以百度。
$ sudo apt-get install lib32z1
11、编译内核
准备就绪,make uImage编译内核,显示如下信息:
$ make uImage
[...]
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
UIMAGE arch/arm/boot/uImage
Image Name: Linux-6.1.0
Created: Fri Jan 6 15:21:59 2023
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 7682528 Bytes = 7502.47 KiB = 7.33 MiB
Load Address: 40008000
Entry Point: 40008000
Kernel: arch/arm/boot/uImage is ready
后续添加SD卡、NandFlash、DM9000网卡驱动,挂载跟文件系统,可以启动linux。初步结果如下:
Starting kernel ...
[ 0.000000][ T0] Booting Linux on physical CPU 0xa00
[ 0.000000][ T0] Linux version 6.1.0-gff8c1029068e-dirty (lighthouse@VM-4-13-ubuntu) (arm-none-linux-gnueabihf-gcc () 10.2.1 20201103, GNU ld (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16)) 2.35.1.20201028) #9 SMP
[ 0.000000][ T0] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=10c5387d
[ 0.000000][ T0] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000][ T0] OF: fdt: Machine model: CBT4412 board based on Exynos4412
[......]
[ 2.506876][ T1] EXT4-fs (mmcblk0p3): recovery complete
[ 2.515380][ T1] EXT4-fs (mmcblk0p3): mounted filesystem with ordered data mode. Quota mode: disabled.
[ 3.150269][ T1] VFS: Mounted root (ext4 filesystem) on device 179:51.
[ 3.151647][ T1] devtmpfs: mounted
[ 3.153105][ T1] Freeing unused kernel image (initmem) memory: 1024K
[ 3.153671][ T1] Run /linuxrc as init process
can't run '/etc/init.d/rcS': No such file or directory
Please press Enter to activate this console.
/ # reboot
umount: can't open '/proc/mounts'
swapoff: can't open '/etc/fstab': No such file or directory
The system is going down NOW!
Sent SIGTERM to all processes
Terminated
Sent SIGKILL to all processes
Requesting system reboot
后记
:后续移植SD卡、NandFlash和DM9000网卡都成功了,虽然有些波折。但是,在执行ifconfig指令时,出现了以下错误,实在无法调试内核和驱动,无奈只能止步于此。望后来者能够给出解决方案。
/ # ifconfig eth0 192.168.1.230 netmask 255.255.255.0 up
[ 67.621272][ T91] dm9000 5000000.ethernet: dm9000 did not respond to first reset
[ 67.621640][ T91] dm9000 5000000.ethernet: dm9000 did not respond to second reset
[ 83.037857][ C3] mmc0: Timeout waiting for hardware interrupt.
[ 83.038126][ C3] mmc0: sdhci: ============ SDHCI REGISTER DUMP ===========
[ 83.038218][ C3] mmc0: sdhci: Sys addr: 0x7ac8b400 | Version: 0x00002401
[ 83.038304][ C3] mmc0: sdhci: Blk size: 0x00007200 | Blk cnt: 0x00000000
[ 83.043178][ C3] mmc0: sdhci: Argument: 0x3c500400 | Trn mode: 0x00000027
[ 83.050295][ C3] mmc0: sdhci: Present: 0x01fa3000 | Host ctl: 0x00000013
[ 83.057413][ C3] mmc0: sdhci: Power: 0x0000000e | Blk gap: 0x00000000
[ 83.064530][ C3] mmc0: sdhci: Wake-up: 0x00000000 | Clock: 0x0000000f
[ 83.071647][ C3] mmc0: sdhci: Timeout: 0x0000000e | Int stat: 0x00000003
[ 83.078765][ C3] mmc0: sdhci: Int enab: 0x03ff000b | Sig enab: 0x03ff000b
[ 83.085882][ C3] mmc0: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000001
[ 83.093000][ C3] mmc0: sdhci: Caps: 0x05e80080 | Caps_1: 0x00000000
[ 83.100118][ C3] mmc0: sdhci: Cmd: 0x0000193a | Max curr: 0x00000000
[ 83.107235][ C3] mmc0: sdhci: Resp[0]: 0x00000900 | Resp[1]: 0x00000000
[ 83.114353][ C3] mmc0: sdhci: Resp[2]: 0x00000000 | Resp[3]: 0x00000c00
[ 83.121470][ C3] mmc0: sdhci: Host ctl2: 0x00000000
[ 83.126591][ C3] mmc0: sdhci: ADMA Err: 0x00000400 | ADMA Ptr: 0x74c41208
[ 83.133709][ C3] mmc0: sdhci: ============================================
[ 93.697611][ C3] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
[ 93.697793][ C3] rcu: 0-...0: (1 GPs behind) idle=73fc/1/0x40000002 softirq=77/78 fqs=1290
[ 93.698138][ C3] (detected by 3, t=2602 jiffies, g=-1075, q=16 ncpus=4)
[ 93.698235][ C3] Sending NMI from CPU 3 to CPUs 0:
[ 103.705129][ C3] rcu: rcu_preempt kthread timer wakeup didn't happen for 991 jiffies! g-1075 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402
[ 103.705261][ C3] rcu: Possible timer handling issue on cpu=3 timer-softirq=1322
[ 103.705347][ C3] rcu: rcu_preempt kthread starved for 992 jiffies! g-1075 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x402 ->cpu=3
[ 103.713494][ C3] rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
[ 103.723302][ C3] rcu: RCU grace-period kthread stack dump:
[ 103.729032][ C3] task:rcu_preempt state:I stack:0 pid:14 ppid:2 flags:0x00000000