s3c2440 ARM9 Linux-3.0最小系统移植

s3c2440 ARM9 Linux-3.0最小系统移植

注:本文基于Ubuntu14.04下crosstool-ng 交叉编译器制作
文章架构:
一、创建Linux内核目录框架
二、Linux源码修改
三、内核配置及编译
四、Linux内核启动

一、创建Linux内核目录框架
FL2440开发板由三星ARM9 S3C2440 做CPU,该CPU使用arm4t指令集的ARM920T核,工作主频最高400MHz。
CPU厂商在开发出相应的demo板后,会由相应的软件研发人员针对母版硬件完成u-boot和Linux内核开发,以支持相应硬件。所以在FL2440开发板的移植过程中,我们将以SMDK2440为模板做出相应修改以支持我们相应的硬件。在开始移植之前,我们首先创建整个项目的目录框架:
在这里插入图片描述
二、Linux源码修改
Linux是源码开放的操作系统,任何人都可以编写个人的内核代码,再加上对标准内核的裁剪从而制作适合自己的操作系统。在选择Linux版本时,建议选择长期支持版本。
在这里插入图片描述
嵌入式Linux系统开发其本质是修改Linux内核源码,使之适合我们个人的操作系统,即BSP(Board Support Packet)开发。这个过程包括Boot loader和Linux内核裁剪、移植、驱动模块编写、根文件系统制作、第三方应用程序移植等等。
1.Linux内核下载并解压到相应目录文件夹下
Linux内核下载地址: https://www.kernel.org/pub/linux/kernel/v3.x/

命令行:wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.0.tar.bz2
命令行:tar -xjf linux-3.0.tar.bz2

2.修改源码
修改1:SMDK2440上使用的是16MHz的晶振,而FL2440上使用的是12MHz晶振。在linux-3.0/arch/arm/mach-s3c2440/ 下支持很多使用s3c2440CPU做的开发板。我们以mach-smdk2440.c为原型修改:

命令行:vim linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c

static void __init smdk2440_map_io(void)
{
 s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
// s3c24xx_init_clocks(16934400);
 s3c24xx_init_clocks(12000000);
 s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
}

修改2:u-boot给Linux内核传的machine ID为1999,而smdk2440开发板对应的machine ID 为362.所以我们要修改内核代码让smdk2440的machine ID与u-boot里的保持一致,这里我们在源码中将两个machine ID值互换:

命令行:vim arch/arm/tools/mach-types

... ...
#s3c2440 ARCH_S3C2440 S3C2440 362
s3c2440 ARCH_S3C2440 S3C2440 1999
... ...
#mini2440 MACH_MINI2440 MINI2440 1999
mini2440 MACH_MINI2440 MINI2440 362
... ...

修改3:修改串口设备默认名字

命令行:vim drivers/tty/serial/samsung.c

//#define S3C24XX_SERIAL_NAME "ttySAC"
#define S3C24XX_SERIAL_NAME "ttyS

修改4:修改makefile

命令行:vim makefile

扫描二维码关注公众号,回复: 10414168 查看本文章
#ARCH ?= $(SUBARCH)
#CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
ARCH ?= arm
CROSS_COMPILE ?= /opt/xtools/arm920t/bin/arm-linux- 
//这里改成大家自己的交叉编译器,注意arm-linux-后面应该紧跟回车,不能有其他任何字符

修改5:添加DM9000网卡设备支持

1.vim arch/arm/mach-s3c2440/mach-smdk2440.c

static struct platform_device *smdk2440_devices[] __initdata = {
 	&s3c_device_wdt,
 	&s3c_device_i2c0,
 	&s3c_device_iis,
 +	&s3c_device_dm9000, /* 添加DM9000网卡的设备,告诉Linux内核现在有这个硬件连上来了 */
};

2.vim arch/arm/plat-s3c24xx/devs.c //在该C文件中定义结构体变量 s3c_device_dm9000

EXPORT_SYMBOL(s3c_device_iis);
+#ifdef CONFIG_DM9000 /* DM9000 network device support add by guowenxue 2011.08.30*/
+#include <linux/dm9000.h>
+static struct resource s3c_dm9000_resource[] = {
	+ [0] = {
	+ .start = S3C2410_CS4 + 0x300, // DM9000网卡的CS片选管脚连接的是CS4
	+ .end = S3C2410_CS4 + 0x300 + 0x3,
	+ .flags = IORESOURCE_MEM
	+ }, 
	+ [1]={
	+ .start = S3C2410_CS4 + 0x300 + 0x4, //CMD pin is A2
	+ .end = S3C2410_CS4 + 0x300 + 0x4 + 0x7c,
	+ .flags = IORESOURCE_MEM
	+ }, 
	+ [2] = {
	+ .start = IRQ_EINT7, // DM9000网卡的中断管脚连的是 EINT7这个Pin
	+ .end = IRQ_EINT7,
	+ .flags = IORESOURCE_IRQ
	+ }, 
+};
+
+static struct dm9000_plat_data s3c_device_dm9000_platdata = {
	+ .flags= DM9000_PLATF_16BITONLY, // DM9000网卡的使用LDATA0~15 16位模式
	+};
	+
	+struct platform_device s3c_device_dm9000 = {
	+ .name= "dm9000",
	+ .id= 0,
	+ .num_resources= ARRAY_SIZE(s3c_dm9000_resource),
	+ .resource= s3c_dm9000_resource,
	+ .dev= {
	+ .platform_data = &s3c_device_dm9000_platdata,
	+ } 
+};
+#endif
+
/* RTC */
  1. vim arch/arm/plat-samsung/include/plat/devs.h //在该头文件中导出s3c_device_dm9000的声明
extern struct platform_device s3c_device_hsmmc1;
extern struct platform_device s3c_device_hsmmc2;
extern struct platform_device s3c_device_hsmmc3;
extern struct platform_device s3c_device_cfcon;
+extern struct platform_device s3c_device_dm9000; /* 声明devs.c中定义的结构体变量s3c_device_dm9000 */
extern struct platform_device s3c_device_spi0;

4.vim drivers/net/dm9000.c //修改dm9000.c的驱动代码,添加中断的初始化

... ... ...
static int
dm9000_open(struct net_device *dev)
{
	 board_info_t *db = netdev_priv(dev);
	- unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
	+ unsigned long irqflags = (db->irq_res->flags|IRQ_TYPE_EDGE_RISING) & IRQF_TRIGGER_MASK;
	+
	+ irq_set_irq_type(dev->irq, IRQ_TYPE_EDGE_RISING);
	 if (netif_msg_ifup(db))
	 dev_dbg(db->dev, "enabling %s\n", dev->name);
 }
... ... ...

三、内核配置及编译

命令行:find -name *.c | wc -l
命令行:find -name *.S | wc -l

通过上面两个命令可以查看,Linux内核由16198个C文件和1223个汇编文件,这份源码支持不同体系结构的CPU,并包含了绝大部分硬件的驱动源码。而在Linux源码编译系统中有一个非常巧妙的三个文件 Kconfig.config\Makefile。
Kconfig:一个文本形式的文件,存在内核源码中的每一个文件夹下,内核配置命令make menuconfig读取相应的Kconfig文件生成菜单界面;
.config:隐藏文件存放在内核源码顶层目录中,make menuconfig命令配置结果,里面的每个选项用来指导Makefile哪些文件需要编译,哪些不需要编译。
Makefile:一个文本形式的文件,存在内核源码中的每一个文件夹下,用来控制编译该目录下的源码编译;
1.配置Kconfig,生成.config

命令行:export TERM=vt100
命令行: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 --->
	[*] Network device support --->
		[*] Ethernet (10 or 100Mbit) ---> 
			<*> DM9000 support
			(4) DM9000 maximum debug level
			所有其他选项都不要选
		[ ] Ethernet (1000 Mbit) ---> DM9000是100M网卡,1000M的网卡就不要选
		[ ] Ethernet (10000 Mbit) ---> DM9000是100M网卡, 10000M的网卡都不要选

2.编写shell脚本,实现部分常用命令

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 linuxrom-s3c2440.bin
chmod a+x linuxrom-s3c2440.bin

Shell脚本解释说明:
Make 编译Linux内核源码。编译完成后将产生arch/arm/boot/zImage内核启动文件。

zImage并不能被u-boot命令启动,而需要使用mkimage工具在其前面加上bootm命令启动内核所需要的64字节头信息方可启动,处理后的文件一般叫做uImage。

mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n “Linux Kernel” -d arch/arm/boot/zImage linuxroms3c2440.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)变成绿色显眼。

命令行:chmod a+x linuxrom-s3c2440.bin
命令行:./build.sh
编译完成生成Linuxrom-s3c2440.bin,该文件即为u-bootzhong bootm命令可识别的uImage文件。

四、Linux内核启动
将Linux内核烧入s3c2440,在u-boot下启动,通过tftpd工具传输。

命令行: set tb ‘tftp 30008000 linuxrom-s3c2440.bin; bootm 30008000’
命令行:save
命令行:run tb

Linux内核自举启动完成之后,最后将创建init进程并执行根文件系统中的/init或/initrc程序,该程序解析并执行根文件系统中的/etc/inittab配置文件,在此文件中配置了init进程在系统启动要启动哪些应用程序。这时候我们并没有提供根文件系统,所以系统会死掉。

关于根文件制作请看下篇。

发布了6 篇原创文章 · 获赞 0 · 访问量 553

猜你喜欢

转载自blog.csdn.net/qq_29973657/article/details/93658097