Linux内核开发
为了说清楚要修改的地方,下面会比较啰嗦
Linux系统内核的源代码是开放的,因此我们可以从官网上下载Linux内核。
下载地址:https://www.kernel.org
解压之后进入内核会看到一下一下目录:
arch COPYING crypto drivers fs init Kbuild kernel MAINTAINERS mm README samples security tools virt block CREDITS Documentation firmware include ipc Kconfig lib Makefile net REPORTING-BUGS scripts sound usr
其中每个目录的表示如下:
arch(cpu) COPYING crypto(加密算法) drivers(驱动) fs(file system) init(init进程) Kbuild(内核编译时使用的) kernel(Linux内核核心相关的) MAINTAINERS(Linux内核的维护人员信息) mm(内存管理) README samples(Linux内核使用的示例) security tools(工具) virt(虚拟机) block(块设备) CREDITS(感谢谁) Documentation(文档) firmware(系统固件) include(头文件) ipc(进程间相互通信) Kconfig(make menuconfig时使用的) lib(Linux要使用的相关的库) Makefile net(网络相关的) REPORTING-BUGS scripts(Linux内核编译的脚本) sound(声卡相关的) usr(用户)
内核要修改的地方其实很少,只需要改一下arch/arm/目录下我们要用的cpu的源代码就可以了。当我们要用到某个驱动时就修改一下driver目录下的驱动的代码。
在这里要把Linux内核烧录到基于Samsung S3C2440处理器的fl2440开发板上,Linux内核适用于很多架构的内核,可以在arch目录下看到:
alpha avr32 cris h8300 Kconfig m68k mips parisc s390 sh tile unicore32 xtensa arm blackfin frv ia64 m32r microblaze mn10300 powerpc score sparc um x86
在这里显示的并不是一种型号的CPU而是一种架构的CPU,我们要进入到arm架构里面去:
boot mach-at91 mach-footbridge mach-ixp23xx mach-mv78xx0 mach-pnx4008 mach-s3c2443 mach-spear3xx mach-w90x900 plat-orion vfp common mach-bcmring mach-gemini mach-ixp4xx mach-mx5 mach-pxa mach-s3c24a0 mach-spear6xx Makefile plat-pxa configs mach-clps711x mach-h720x mach-kirkwood mach-mxs mach-realview mach-s3c64xx mach-tcc8k mm plat-s3c24xx include mach-cns3xxx mach-imx mach-ks8695 mach-netx mach-rpc mach-s5p64x0 mach-tegra nwfpe plat-s5p Kconfig mach-davinci mach-integrator mach-l7200 mach-nomadik mach-s3c2400 mach-s5pc100 mach-u300 oprofile plat-samsung Kconfig.debug mach-dove mach-iop13xx mach-loki mach-nuc93x mach-s3c2410 mach-s5pv210 mach-ux500 plat-iop plat-spear Kconfig-nommu mach-ebsa110 mach-iop32x mach-lpc32xx mach-omap1 mach-s3c2412 mach-sa1100 mach-versatile plat-mxc plat-tcc kernel mach-ep93xx mach-iop33x mach-mmp mach-omap2 mach-s3c2416 mach-shark mach-vexpress plat-nomadik plat-versatile lib mach-exynos4 mach-ixp2000 mach-msm mach-orion5x mach-s3c2440 mach-shmobile mach-vt8500 plat-omap tools
惯例,第一步要改的是Makefile文件
[wangchengcheng@centos6 linux-3.0]$ vim Makefile
修改要编译的内核与交叉编译器:
1 @@ -192,8 +192,8 @@ 2 # Default value for CROSS_COMPILE is not to prefix executables 3 # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile 4 export KBUILD_BUILDHOST := $(SUBARCH) 5 -ARCH ?= $(SUBARCH) 6 -CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) 7 +ARCH ?= arm 8 +CROSS_COMPILE ?= /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-
其次要修改编译完成之后自动调用mkimage,这里的mkimage内核源代码并没有给提供,在编译好的u-boot的tools文件夹中,我们可以把它拷贝到当前目录下或者/bin/目录下或者/usr/bin/目录下。在这里我把它拷贝到了当前目录下。然后修改Makefile文件:
1 @@ -557,6 +557,9 @@ 2 # This allow a user to issue only 'make' to build a kernel including modules 3 # Defaults to vmlinux, but the arch makefile usually adds further targets 4 all: vmlinux 5 + cp arch/arm/boot/zImage . -f 6 + mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d zImage linuxrom-s3c2440.bin 7 + rm -f zImage
注:mkimage命令的作用是将内核编译出来的二进制文件转换为u-boot能够识别的二进制文件。
接下来改的地方是make distclean,当我们make distclean时我们希望把可执行文件linuxrom-s3c2440.bin文件给删掉:
1 @@ -1201,6 +1204,7 @@ 2 -o -name '.*.rej' -o -size 0 \ 3 -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ 4 -type f -print | xargs rm -f 5 + @rm -f linuxrom-*.bin
到此,Makefile文件就修改完成了!要开始修改内核源代码了!
[wangchengcheng@centos6 linux-3.0]$ vim arch/arm/mach-s3c2440/mach-smdk2440.c
根据f2440开发板的原理图可知,其晶振频率为12MHZ因此要修改晶振频率:
1 @@ -155,12 +196,13 @@ 2 &s3c_device_wdt, 3 &s3c_device_i2c0, 4 &s3c_device_iis, 5 }; 6 7 static void __init smdk2440_map_io(void) 8 { 9 s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); 10 - s3c24xx_init_clocks(16934400); 11 + s3c24xx_init_clocks(12000000); 12 s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); 13 }
接下来改串口,因为Linux的所有设备都是文件,文件的匹配需要用到name域来匹配。而Samsung公司串口的默认名字为"ttySAC"所以我们要把串口名字改成“ttyS”
1 @@ -54,7 +54,7 @@ 2 3 /* UART name and device definitions */ 4 5 -#define S3C24XX_SERIAL_NAME "ttySAC" 6 +#define S3C24XX_SERIAL_NAME "ttyS" 7 #define S3C24XX_SERIAL_MAJOR 204 8 #define S3C24XX_SERIAL_MINOR 64
最后修改machine id设备编号
由于将s3c2440的machine id与mini2440的machine id互换:
[wangchengcheng@centos6 linux-3.0]$ vim arch/arm/tools/mach-types
1 @@ -85,7 +85,7 @@ 2 bast ARCH_BAST BAST 331 3 h1940 ARCH_H1940 H1940 347 4 enp2611 ARCH_ENP2611 ENP2611 356 5 -s3c2440 ARCH_S3C2440 S3C2440 362 6 +s3c2440 ARCH_S3C2440 S3C2440 1999 7 gumstix ARCH_GUMSTIX GUMSTIX 373 8 omap_h2 MACH_OMAP_H2 OMAP_H2 382 9 e740 MACH_E740 E740 384 10 @@ -356,7 +356,7 @@ 11 snapper_9260 MACH_SNAPPER_9260 SNAPPER_9260 1987 12 dsm320 MACH_DSM320 DSM320 1988 13 exeda MACH_EXEDA EXEDA 1994 14 -mini2440 MACH_MINI2440 MINI2440 1999 15 +mini2440 MACH_MINI2440 MINI2440 362 16 colibri300 MACH_COLIBRI300 COLIBRI300 2000 17 linkstation_ls_hgl MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL 2005 18 cpuat9g20 MACH_CPUAT9G20 CPUAT9G20 2031
到此内核源代码最基本的修改就告一段落了,内核的编译主要依赖于.config这个文件。内核用这个文件来指导编译器要编译的与不要编译的。由于直接修改.config文件过于复杂,就像修改u-boot一样繁琐效率又很低。在这里人们人性化的设计了图形化界面:make menuconfig
首先我们要在最高目录下创建一个.config文件,这里的.config文件参考mini2440的config文件:
[wangchengcheng@centos6 linux-3.0]$ cp arch/arm/configs/mini2440_defconfig .config
[wangchengcheng@centos6 linux-3.0]$ make menuconfig
我们将看到:
选择System Type ---> S3C2440 and S3C2442 Machines ---> 不选[ ] MINI2440 development board,选择[*] SMDK2440与[*] SMDK2440 with S3C2440 CPU module
此时Linux内核已经初步修改完成,但是一些基本的驱动都没有加载。所以我们还是不能用它来做事情的。
添加硬盘分区:
[wangchengcheng@centos6 linux-3.0]$ vim arch/arm/plat-s3c24xx/common-smdk.c
1 /* NAND parititon from 2.4.18-swl5 */ 2 3 static struct mtd_partition smdk_default_nand_part[] = { 4 [0] = { 5 .name = "bootloader", 6 .size = SZ_1M, 7 .offset = 0, 8 }, 9 [1] = { 10 .name = "linux", 11 .offset = MTDPART_OFS_NXTBLK, 12 .size = SZ_1M*15, 13 }, 14 [2] = { 15 .name = "rootfs", 16 .offset = MTDPART_OFS_NXTBLK, 17 .size = SZ_1M*40, 18 }, 19 [3] = { 20 .name = "apps", 21 .offset = MTDPART_OFS_NXTBLK, 22 .size = SZ_1M*50, 23 }, 24 [4] = { 25 .name = "data", 26 .offset = MTDPART_OFS_NXTBLK, 27 .size = SZ_1M*50, 28 }, 29 [5] = { 30 .name = "backup", 31 .size = SZ_1M * 100, 32 .size = MTDPART_OFS_NXTBLK, 33 }, 34 }; 35 36 static struct s3c2410_nand_set smdk_nand_sets[] = { 37 [0] = {
开发板上的nandflash是256M的,bootleader启动需要1M,内核需要15M,根文件系统需要40M,其他的自由分配。
注:此时要在进行分区就要选择相应的文件系统。nandflash常用的文件系统有:yaffs2,ubifs,cramfs已经initramfs等。
添加initramfs文件系统:
initramfs是最简单的文件系统的添加方式:make menuconfig ---> General setup ---> 选中[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support,并且在() Initramfs source file(s)中指定根文件目录树的路径(相对路径或者绝对路径都可以。)
添加DM9000网卡
修改arch/arm/mach-s3c2440/mach-smdk2440.c
#include <linux/dm9000.h>//添加DM9000网卡的头文件
添加如下代码
/* add DM9000 ethernet drivers ,whitch is modify by xiaohe */
#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,
}
};
/*
* The DM9000 has no eeprom, and it's MAC address is set by
* the bootloader before starting the kernel.
*/
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,
},
};
/* modify end */
修改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,
};
重新make之后,内核就可以支持DM9000网络了,这时我们就可以用tftp下载文件到内核里去。
这时输入ifconfig:
>: ifconfig
eth0 Link encap:Ethernet HWaddr 6A:C6:F1:ED:0D:F7
inet addr:192.168.1.111 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:138 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:13167 (12.8 KiB) TX bytes:0 (0.0 B)
Interrupt:51 Base address:0x4300
添加U盘驱动
一、添加U盘支持
FL2440添加u盘的挂载比较简单,大部分的内容都是在内核里面做make menuconfig,配置内核。
Device Drivers --->
Generic Driver Options --->
(/sbin/hotplug) path to uevent helper //配置u盘的热插拔
[*] Block devices --->
<*> Low Performance USB Block driver //低性能USB块设备驱动
SCSI device support --->
<*> SCSI device support //SCSI设备的支持
<*> SCSI generic support //SCSI通用的支持
[*] Probe all LUNs on each SCSI device //所有在每个SCSI LUN探针装置
[*] USB support --->
<*> Support for Host-side USB //主机端USB支持
[*] USB device filesystem (DEPRECATED) //USB设备文件系统(不推荐使用)
[*] USB device class-devices (DEPRECATED) / /USB设备类设备(不推荐使用)
<*> USB Monitor //USB监控
<*> OHCI HCD support //支持OHCI标准
<*> USB Mass Storage support //支持USB海量存储
File systems ---> //配置u盘的文件系统
DOS/FAT/NT Filesystems --->
<*> MSDOS fs support
<*> VFAT (Windows-95) fs support
(936) Default codepage for FAT //默认代码页
(cp936) Default iocharset for FAT //默认字符集
-*- Native language support ---> //配置u盘的语言格式支持,不过感觉着个配置没什么用,中文也支持不了,也许是因为linux对中文的支持并不好吧
<*> Simplified Chinese charset (CP936, GB2312)
<*> ASCII (United States)
<*> NLS UTF-8
二、添加USB结构体变量,加厂商ID和设备ID
diff -Nuar linux-3.0/drivers/usb/serial/option.c linux-3.0-s3c2440/drivers/usb/serial/option.c
--- linux-3.0/drivers/usb/serial/option.c 2011-07-22 10:17:23.000000000 +0800
+++ linux-3.0-s3c2440/drivers/usb/serial/option.c 2015-12-07 16:31:30.555485473 +0800
@@ -51,6 +51,13 @@
static void option_instat_callback(struct urb *urb);
/* Vendor and product IDs */
+static int vendor = 0; /* Add by guowenxue */
+static int product = 0; /* Add by guowenxue */
+
+/* Vendor and product IDs */
+#define OPTION_VENDOR_RESERVED 0xFFFF /* Add by guowenxue */
+#define OPTION_RESERVED_DEVICE 0xFFFF /* Add by guowenxue */
+
#define OPTION_VENDOR_ID 0x0AF0
#define OPTION_PRODUCT_COLT 0x5000
#define OPTION_PRODUCT_RICOLA 0x6000
@@ -446,7 +453,8 @@
.reason = OPTION_BLACKLIST_SENDSETUP
};
-static const struct usb_device_id option_ids[] = {
+static struct usb_device_id option_ids[] = {
+ { USB_DEVICE(OPTION_VENDOR_RESERVED, OPTION_RESERVED_DEVICE) }, /* Add by guowenxue */
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
@@ -1079,6 +1087,15 @@
static int __init option_init(void)
{
int retval;
+
+ if ((vendor>0) && (product>0))
+ {
+ option_ids[0].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ option_ids[0].idVendor = vendor;
+ option_ids[0].idProduct = product;
+ printk("Register option drvier for modem vendor=0x%04x product=0x%04x\n", vendor, product);
+ }
+
三、加宏和USB进程
diff -Nuar linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c linux-3.0-s3c2440/arch/arm/mach-s3c2440/mach-smdk2440.c
--- linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c 2011-07-22 10:17:23.000000000 +0800
+++ linux-3.0-s3c2440/arch/arm/mach-s3c2440/mach-smdk2440.c 2015-12-07 16:31:30.532734715 +0800
@@ -23,6 +23,13 @@
#include <linux/platform_device.h>
#include <linux/io.h>
+/* add by guowenxue for norflash */
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -44,6 +51,11 @@
#include <plat/clock.h>
#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/ts.h> /*Add by guowenxue to support Touch screen, 2011.09.06*/
+#include <mach/regs-clock.h> /*Add by guowenxue 2012.07.15, for usb_s3c2440_init() */
+#include <linux/i2c.h> /*Add by guowenxue 2012.10.22, for AT24C512 driver */
+#include <linux/i2c/at24.h> /* Add by guowenxue 2012.10.22, for AT24C512 driver */
+#include <linux/delay.h>
加USB的init进程:
+int usb_s3c2440_init(void)
+{
+ /* Input Frequency is 12.0000MHz, and MDEV=0x38 PDIV=2 SDIV=2, so output frequency 48.00MHz */
+ unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x02);
+ while (upllvalue != __raw_readl(S3C2410_UPLLCON))
+ {
+ __raw_writel(upllvalue, S3C2410_UPLLCON);
+ mdelay(1);
+ }
+
+ return 0;
+}
+
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
- s3c24xx_init_clocks(16934400);
+ s3c24xx_init_clocks(12000000); /*Modify by guowenxue, 2011.08.30*/
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
+ usb_s3c2440_init(); /* Add by guowenxue, 2012.07.15 */
}
配置好之后,插上U盘就可以看到如下信息:
usb 1-1.1: new full speed USB device number 3 using s3c2410-ohci
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: new full speed USB device number 3 using s3c2410-ohci
usb 1-1.1: New USB device found, idVendor=048d, idProduct=1234
usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1.1: Product:
usb 1-1.1: Manufacturer:
usb 1-1.1: SerialNumber: 袎
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: New USB device found, idVendor=048d, idProduct=1234
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: Product:
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: Manufacturer:
Dec 31 17:44:35 root kern.info kernel: usb 1-1.1: SerialNumber: 袎
uba:
Dec 31 17:44:35 root kern.info kernel: uba:
表示USB驱动uba已经装载成功,这时可能会出现一个问题,我们查看/mnt/usb/并没有U盘里的信息。
这是因为U盘没有挂载上去,将U盘挂载到/mnt/usb/下就可以了:
>: mount -t vfat /dev/uba /mnt/usb/
为什么U盘没有自动挂载上去呢?
查看自动挂载的配置文件/etc/mdev.conf:
>: vi mdev.conf
sd[a-z][0-9] 0:0 0777 @(mount /dev/$MDEV /mnt/usb)
sd[a-z] 0:0 0777 $(umount /mnt/usb)
ub[a-z][0-9] 0:0 0777 @(mount /dev/$MDEV /mnt/usb)
ub[a-z] 0:0 0777 $(umount /mnt/usb)
mmcblk[0-9]p[0-9] 0:0 0777 @(mount /dev/$MDEV /mnt/sdc)
mmcblk[0-9] 0:0 0777 $(umount /mnt/sdc)
原来是第三行的ub[a-z][0-9]的原因,因为我的U盘的驱动挂载上去之后只有uba没有后面的数字,而配置文件里后面有0-9的数字,所以没办法匹配,也就没办法挂载,在这里添加一行:
ub[a-z] 0:0 0777 @(mount /dev/$MDEV /mnt/usb)
ub[a-z] 0:0 0777 $(umount /mnt/usb)
这样就可以实现自动挂载了。