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 ", 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)

这样就可以实现自动挂载了。

原文地址:https://www.cnblogs.com/xiaohexiansheng/p/5492885.html