注意:該博客基於由crosstool-ng製作的交叉編譯器編譯出armLinux內核。交叉編譯器的具體制作請參考我上兩篇博客。
1.fl2440簡介
FL2440開發板是飛凌公司使用三星的ARM9 S3C2440 CPU做的一個ARM Linux學習開發板,該CPU是使用armv4t指令集的ARM920T核,工作主頻最高在400MHz。每個CPU廠商在研發並生產出CPU時並不是直接將該CPU推給客戶讓客戶自己研究該CPU特性後再做硬件設計(因爲客戶不懂這些具體的CPU使用細節,而研發該CPU的公司會更懂它),而會先使用該CPU設計出母板(demo板,如SMDK2440),在母板上儘可能將該CPU的硬件使用信息展示給客戶,客戶再參考母板根據實際的功能、市場需求來高度定製自己的硬件,例如產品不需要顯示則可以把母板中的LCD硬件部分去掉、CS8900網卡供貨存在問題那就換成DM9000等等。
相應的CPU廠商在開發出相應的硬件demo板後,也不是直接丟給客戶來開發相應的軟件,而是會安排軟件研發人員針對母板硬件完成u-boot和Linux內核的開發,以支持相應硬件。因爲我們的硬件是參考母板來定製開發的,所以我們的軟件移植(u-boot和linux內核)也可以在相關源碼裏的母板代碼上做針對硬件的修改來支持我們的產品。
在FL2440開發板的移植過程中,我們將以SMDK2440爲模版在它的基礎上做些修改來支持我們相應的硬件。在開始移植之前,我們先創建FL2440整個項目的目錄框架:
zhanghang@ubuntu:~$ mkdir fl2440
zhanghang@ubuntu:~$ cd fl2440/
zhanghang@ubuntu:~/fl2440$ mkdir -p {crosstool,bootloader,linux/{kernel,rootfs},driver,3rdparty,program,images}
zhanghang@ubuntu:~/fl2440$ tree
.
├── 3rdparty
├── bootloader
├── crosstool
├── driver
├── images
├── linux
│ ├── kernel
│ └── rootfs
└── program
9 directories, 0 files
2.源碼修改
Linux 是一個源碼開放的操作系統,無論是普通用戶還是企業用戶都可以編寫自己的內核代碼,再加上對標準內核的裁剪從而製作出適合自己的操作系統。Linux操作系統有很多發行版本,如Redhat, CentOS, Ubuntu等等,但所有的這些Linux操作系統都是選擇一個Linux內核穩定版本,外加不同的C基礎庫和應用程序構建的一個操作系統。嵌入式Linux系統開發其本質就是我們拿到源碼並進行修改DIY(Do It Yourself)一個屬於我們自己的操作系統,這個過程包括Booloader和Linux內核(裁剪)移植、驅動模塊編寫、根文件系統製作、第三方應用程序移植等,這個工作叫做BSP(Board Support Packet,板級支持包)開發,這裏面需要相應的硬件協議、操作系統、以及C語言和數據結構等知識,難度較高。
zhanghang@ubuntu:~$ cd fl2440/linux/
zhanghang@ubuntu:~/fl2440/linux$ wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.0.tar.bz2 //下載內核
zhanghang@ubuntu:~/fl2440/linux$ tar -xjf linux-3.0.tar.bz2 //解壓
zhanghang@ubuntu:~/fl2440/linux$ cd linux-3.0/
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ ls
arch Documentation init lib README sound
block drivers ipc MAINTAINERS REPORTING-BUGS tools
COPYING firmware Kbuild Makefile samples usr
CREDITS fs Kconfig mm scripts virt
crypto include kernel net security
修改1:
SMDK2440上使用的是16MHz的晶振,而FL2440上使用的是12MHz的晶振,所以開發板相應代碼要做修改,linux-3.0/arch/arm/mach-s3c2440/下支持很多使用S3C2440 CPU做的開發板(大家可以使用ls命令看看具體有哪些開發板,今後驅動添加我們可以參考其他開發板如mini2440的信息),我們以mach-smdk2440.c爲原型來進行修改:
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ vim arch/arm/mach-s3c2440/mach-smdk2440.c
160 static void __init smdk2440_map_io(void)
161 {
162 s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
163 // s3c24xx_init_clocks(16934400);
164 s3c24xx_init_clocks(12000000);
165 s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
166 }
167
修改2:
我們的u-boot給Linux內核傳的machine ID值爲1999,而Linux內核裏smdk2440開發板對應的machine ID是362,所以我們要修改內核代碼讓smdk2440的machine ID與u-boot裏的保持一致,這裏我們在源碼中將兩個machine ID值互換:
enp2611 ARCH_ENP2611 ENP2611 356
s3c2440 ARCH_S3C2440 S3C2440 1999
gumstix ARCH_GUMSTIX GUMSTIX 373
...
exeda MACH_EXEDA EXEDA 1994
mini2440 MACH_MINI2440 MINI2440 362
colibri300 MACH_COLIBRI300 COLIBRI300 2000
修改3:
samsung的串口驅動設備名字默認叫ttySAC,而我們一般使用ttyS,所以將源碼中的設備名改掉:
55 /* UART name and device definitions */
56
57 //#define S3C24XX_SERIAL_NAME "ttySAC"
58 #define S3C24XX_SERIAL_NAME "ttyS"
59 #define S3C24XX_SERIAL_MAJOR 204
60 #define S3C24XX_SERIAL_MINOR 64
修改4:
修改頂層Makefile的ARCH爲arm, CROSS_COMPILE爲我們自己相應的交叉編譯器:
zhanghang@ubuntu:~$ cd /opt/xtools/arm920t/bin/
zhanghang@ubuntu:/opt/xtools/arm920t/bin$ ls
arm-arm920t-linux-gnueabi-addr2line arm-arm920t-linux-gnueabi-gprof
arm-arm920t-linux-gnueabi-ar arm-arm920t-linux-gnueabi-ld
arm-arm920t-linux-gnueabi-as arm-arm920t-linux-gnueabi-ldd
arm-arm920t-linux-gnueabi-c++ arm-arm920t-linux-gnueabi-nm
arm-arm920t-linux-gnueabi-cc arm-arm920t-linux-gnueabi-objcopy
arm-arm920t-linux-gnueabi-c++filt arm-arm920t-linux-gnueabi-objdump
arm-arm920t-linux-gnueabi-cpp arm-arm920t-linux-gnueabi-populate
arm-arm920t-linux-gnueabi-ct-ng.config arm-arm920t-linux-gnueabi-ranlib
arm-arm920t-linux-gnueabi-g++ arm-arm920t-linux-gnueabi-readelf
arm-arm920t-linux-gnueabi-gcc arm-arm920t-linux-gnueabi-size
arm-arm920t-linux-gnueabi-gcc-4.6.0 arm-arm920t-linux-gnueabi-strings
arm-arm920t-linux-gnueabi-gcov arm-arm920t-linux-gnueabi-strip
195 #ARCH ?= $(SUBARCH)
196 #CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
197 ARCH ?= arm
198 CROSS_COMPILE ?= /opt/xtools/arm920t/bin/arm-arm920t-linux-gnueabi- //這裏改成大家自己的交叉編譯器,注意arm-arm920t-linux-gnueabi- 後面應該緊跟回車,不能有其他任何字符
下面是我的交叉編譯器位置:
zhanghang@ubuntu:~$ cd /opt/xtools/arm920t/bin/
zhanghang@ubuntu:/opt/xtools/arm920t/bin$ ls
arm-arm920t-linux-gnueabi-addr2line arm-arm920t-linux-gnueabi-gprof
arm-arm920t-linux-gnueabi-ar arm-arm920t-linux-gnueabi-ld
arm-arm920t-linux-gnueabi-as arm-arm920t-linux-gnueabi-ldd
arm-arm920t-linux-gnueabi-c++ arm-arm920t-linux-gnueabi-nm
arm-arm920t-linux-gnueabi-cc arm-arm920t-linux-gnueabi-objcopy
arm-arm920t-linux-gnueabi-c++filt arm-arm920t-linux-gnueabi-objdump
arm-arm920t-linux-gnueabi-cpp arm-arm920t-linux-gnueabi-populate
arm-arm920t-linux-gnueabi-ct-ng.config arm-arm920t-linux-gnueabi-ranlib
arm-arm920t-linux-gnueabi-g++ arm-arm920t-linux-gnueabi-readelf
arm-arm920t-linux-gnueabi-gcc arm-arm920t-linux-gnueabi-size
arm-arm920t-linux-gnueabi-gcc-4.6.0 arm-arm920t-linux-gnueabi-strings
arm-arm920t-linux-gnueabi-gcov arm-arm920t-linux-gnueabi-strip
修改5:
添加DM9000網卡的支持,沒有網卡驅動,開發板只能通過串口進行連接,更不能上網,通過ssh或dropbear遠程登陸。
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ vim arch/arm/mach-s3c2440/mach-smdk2440.c
#include <linux/dm9000.h>//add
//並添加如下代碼
#define DM9000_BASE (S3C2410_CS4 + 0x300)
static struct resource s3c_dm9000_resource[] = {
[0] = {
.start = DM9000_BASE,
.end = DM9000_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = DM9000_BASE + 4,
.end = DM9000_BASE + 7,
.flags = IORESOURCE_MEM
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
static struct dm9000_plat_data s3c_dm9000_pdata = {
.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
};
static struct platform_device s3c_device_dm9000 = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_dm9000_resource),
.resource = s3c_dm9000_resource,
.dev = {
.platform_data = &s3c_dm9000_pdata,
},
};
//在結構體static struct platform_device *smdk2440_devices[] __initdata中添加dm9000網卡支持
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_dm9000,//add
};
2.內核配置和編譯
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ find -name *.c | wc -l
16198
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ find -name *.S | wc -l
1223
Linux-3.0內核有16198個C文件和1223個彙編文件,就這一份源碼支持了不同體系結構CPU, 並且包含了絕大部分硬件的驅動源碼。那麼根據不同的硬件設計和功能需求,定製化編譯生成一個具有特定用途的嵌入式Linux系統image將是一場災難,好在Linux的源碼編譯系統有一個非常巧妙的鐵三角關係,導致這個過程顯得沒那麼複雜。這個鐵三角分別是Kconfig、.config和Makefile文件,他們三者之間的關係簡單來說就是去飯店點菜:Kconfig是菜單,.config就是你點的菜,Makefile是做法。
**Kconfig:**一個文本形式的文件,存在內核源碼中的每一個文件夾下,內核配置命令make menuconfig讀取相應的Konfig文件生成菜單界面;
**.config:**隱藏文件存放在內核源碼頂層目錄中,make menuconfig命令配置的結果,裏面的每個選項用來指導Makefile哪些C文件需要編譯,哪些不需要編譯;
**Makefile:**一個文本形式的文件,存在內核源碼中的每一個文件夾下,用來控制編譯該目錄下的源碼編譯;
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ make s3c2410_defconfig
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ export TERM=vt100
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ make menuconfig
我們是使用S3C2440做的SMDK2440開發板,所有其他的開發板都不應該選擇
System Type --->
S3C2400 Machines ---> 裏面全部不選
S3C2410 Machines ---> 裏面全部不選
S3C2412 Machines ---> 裏面全部不選
S3C2416 Machines ---> 裏面全部不選
S3C2440 and S3C2442 Machines --->
[*] SMDK2440
[*] SMDK2440 with S3C2440 CPU module
其它全部不選
S3C2443 Machines --->
裏面全部不選
... ...
我們的交叉編譯器使用的是EABI接口,所以這裏一定要修改配置,否則跑不起來。
Kernel Features --->
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel (EXPERIMENTAL) (NEW)
爲防止爲串口驅動衝突:
Device Drivers --->
Character devices --->
Serial drivers --->
把<> 8250/16550 and compatible serial support取消
<*> Samsung SoC serial support
[ ] Samsung SoC serial debug
[*] Support for console on Samsung SoC serial port
<*> Samsung S3C2440/S3C2442/S3C2416 Serial port support
寫個shell腳本完成這些相應命令
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ vim build.sh
#!/bin/bash
make
mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d arch/arm/boot/zImage linuxroms3c2440.bin
chmod a+x linuxrom-s3c2440.bin
Shell腳本解釋說明:
make命令是編譯Linux內核源碼,編譯完成後將生產arch/arm/boot/zImage內核啓動文件。
zImage並不能被u-boot的bootm命令啓動,而需要使用mkimage工具在其前面加上bootm命令啓動內核所需要的64字節(0x40)頭信息方可啓動,處
理後的文件一般叫做uImage。
mkimage命令是由u-boot編譯產生(u-boot-2010.09/tools/mkimage),在編譯完成u-boot後我們需要將它以root權限拷貝到系統/bin路徑下。
mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n “Linux Kernel” -d arch/arm/boot/zImage linuxrom- s3c2440.bin
-A arm 指定ARCH爲arm
-O linux 指定操作系統(OS)爲Linux
-T kernel 指定類型(Type)爲內核
-C none 指定壓縮類型爲未壓縮,zImage裏有自解壓的代碼;
-a 30008000 指定Image加載的地址, u-boot下使用tftp命令下載linux內核到內存的相應地址
-e 30008040 指定Linux內核的入口地址, uImage的地址在30008000,uImage是在zImage前面加了64字節(0x40)頭,所以內核
zImage入口地址爲30008040。
-n “Linux Kernel” 指定Image的名字
-d arch/arm/boot/zImage 指定zImage文件所在位置
linuxrom-s3c2440.bin 指定生成的uImage文件名
chmod a+x linuxrom-s3c2440.bin 將生成的uImage文件(linuxrom-s3c2440.bin)變成綠色顯眼。
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ ./build.sh
...//編譯過程可能出現錯誤,由於我是用全新的ubuntu14.04去做的,出現如下錯誤:
...
IHEX2FW firmware/emi26/loader.fw
IHEX2FW firmware/emi26/firmware.fw
IHEX2FW firmware/emi26/bitstream.fw
IHEX2FW firmware/emi62/loader.fw
IHEX2FW firmware/emi62/bitstream.fw
IHEX2FW firmware/emi62/spdif.fw
IHEX2FW firmware/emi62/midi.fw
./build.sh: line 3: mkimage: command not found
chmod: cannot access ‘linuxrom-s3c2440.bin’: No such file or directory
解決辦法:
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ sudo apt-get install u-boot-tools
...//最後編譯結束,整個過程時常大約20分鐘
KSYM .tmp_kallsyms2.S
AS .tmp_kallsyms2.o
LD vmlinux
SYSMAP System.map
SYSMAP .tmp_System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy.gzip
AS arch/arm/boot/compressed/piggy.gzip.o
SHIPPED arch/arm/boot/compressed/lib1funcs.S
AS arch/arm/boot/compressed/lib1funcs.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
Building modules, stage 2.
MODPOST 360 modules
LD [M] kernel/configs.ko
Image Name: Linux Kernel
Created: Sun Apr 28 07:06:03 2019
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2277412 Bytes = 2224.04 kB = 2.17 MB
Load Address: 30008000
Entry Point: 30008040//編譯結束
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ ls
arch firmware lib net tools
block fs linuxrom-s3c2440.bin README usr
build.sh include MAINTAINERS REPORTING-BUGS virt
COPYING init Makefile samples vmlinux
CREDITS ipc mm scripts vmlinux.o
crypto Kbuild modules.builtin security
Documentation Kconfig modules.order sound
drivers kernel Module.symvers System.map
zhanghang@ubuntu:~/fl2440/linux/linux-3.0$ du -h linuxrom-s3c2440.bin
2.2M linuxrom-s3c2440.bin
編譯完成後將會生成linuxrom-s3c2440.bin(約2.2M),該文件即爲u-boot裏bootm命令能識別的uImage文件。
此時,該文件就可以移植到開發板上。但是由於沒有根文件系統,啓動會停止並提示沒有根文件系統。
下一節我會講根文件系統的製作。