Chinaunix首页 | 论坛 | 博客
  • 博客访问: 682372
  • 博文数量: 66
  • 博客积分: 2418
  • 博客等级: 大尉
  • 技术积分: 1659
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-28 10:04
个人简介

keep moving

文章分类

全部博文(66)

文章存档

2015年(2)

2014年(6)

2013年(7)

2011年(7)

2010年(42)

2009年(2)

分类: 嵌入式

2010-04-07 11:51:20

操作系统:	ubuntu9.04
交叉编译工具:	arm-linux-gcc-4.1.1
开发板:		2410-S(s3c2410s)
注意:蓝色为命令,橘红色为要添加或修改的代码和脚步,浅绿色是对mdev的支持,红色为要注意的地方
本文使用mdev(udev的BusyBox简化版),并且不再额外添加代码使内核能够支持devfs(devfs是linux-2.6.12及其以前版本的设备文件系统,但是在linux-2.6.13及其以后的版本中用的是udev。既然已经淘汰了,就不要再添加回来了)。使内核能够支持devfs,主要目的是使内核启动后并在/sbin/init运行之前能自动挂载/dev为devfs文件系统。这样可以避免没有控制台(控制台设备文件)可供init用来按照inittab 的指示开一个shell。本人使用了另一种方法来避免这一问题:直接将串口0/devs3c2410_serial0当/dev/console,这样在mdev -s还没执行前(mdev -s通过扫描/sys/class目录下,所有的dev属性文件,并从这些dev属性文件获取到设备的主次设备号,再为其在/dev目录下创建相应的设备节点。mdev -s还没执行前,/dev目录下一般只有/dev/console、 /dev/null。这两个设备文件是init至少要用到的)init就可以直接使用/dev/console作为控制台开一个shell。因此,本文制作的内核可能需要有一定根文件系统的特殊要求,可参考本人另一篇文章《使用BusyBox制作linux根文件系统(CramFS+mdev》:http://blog.chinaunix.net/u3/109117/showart_2209123.html
若你还是想用devfs,可参考另一篇文章《移植Linux2.6.24.7到博创2410-S(s3c2410s),包括AX88796移植》:http://blog.csdn.net/lingdxuyan/archive/2009/12/22/5057717.aspx

一、下载并解压Linux2.6.24.7内核源码
从网上下载linux-2.6.24.7内核源码到/arm2410s目录下,并解压
lingd@ubuntu:~/arm2410s$ tar xzvf linux2.6.24.7.tar.gz
lingd@ubuntu:~/arm2410s$ cd linux2.6.24.7
进入内核解压后的目录
注:以后示例中,只要是相对路径全部是相对于~/arm2410s/linux2.6.24.7/此目录
内核下载地址:二、修改内核源码根目录下的Makefile文件
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ vi Makefile

修改Makefile中的ARCH和CROSS_COMPILE变量,修改为

ARCH        = arm
CROSS_COMPILE    = arm-linux-                                 //该值是交叉编译器的前缀,具体值因人而异

注:arm和arm-linux-后面不能有空格,否则make menuconfig时会出现“/arm2410s/linux-2.6.24.7/arch/arm: 是一个目录”错误。

三、设置nand flash分区信息
修改arch/arm/plat-s3c24xx/common-smdk.c文件,修改Nand Flash的分区信息和Nand Flash的硬件信息(这部分信息应该与vivi中的flash(mtd)分区对应起来,不可随便设置)。
 (LED 器件的初始化也在这个文件里,但是博创的平台没有那四个LED管,所以要不要那些程序都无所谓。我就把它们放在那里,反正启动时不会有影响,也没有出错信息。)
修改的内容如下:

static struct mtd_partition smdk_default_nand_part[] = {
	[0] = {
		.name = "vivi",
		.size = SZ_128K,
		.offset = 0,
	},

	[1] = {
		.name = "param",
		.offset = SZ_128K,
		.size = SZ_1M-SZ_128K,
	},

	[2] = {
		.name = "kernel",
		.offset = SZ_1M,
		.size = SZ_1M * 3,
	},

	[3] = {
		.name = "root",
		.offset = SZ_4M,
		.size = SZ_4M * 5,
	},

	[4] = {
		.name = "user",
		.offset = SZ_4M * 6,
		.size = SZ_4M * 10,
	},
};


注意:请不要画蛇添足地在进行自定义nand flash分区时仍然按照以前内核的移植步骤,在devs.c中自己添加分区信息,不然系统启动时会有出错信息:

kobject_add failed for s3c2410-nand with -EEXIST, don't try to register things with the same name in the same directory.
[] (dump_stack+0x0/0x14) from [] (kobject_shadow_add+0x160/0x1a8)
[] (kobject_shadow_add+0x0/0x1a8) from [] (kobject_add+0x14/0x18)
[] (kobject_add+0x0/0x18) from [] (device_add+0xa0/0x568)
[] (device_add+0x0/0x568) from [] (platform_device_add+0x100/0x150)
[] (platform_device_add+0x0/0x150) from [] (platform_device_register+0x20/0x24)
 r7:c0022a10 r6:c0020a1c r5:00000000 r4:c02cab30
[] (platform_device_register+0x0/0x24) from [] (platform_add_devices+0x24/0x6c)
 r4:00000000
[] (platform_add_devices+0x0/0x6c) from [] (smdk_machine_init+0x84/0x98)
 r8:c03b8000 r7:00000000 r6:c0020a1c r5:00000000 r4:c0021404
[] (smdk_machine_init+0x0/0x98) from [] (smdk2410_init+0x1c/0x24)
[] (smdk2410_init+0x0/0x24) from [] (customize_machine+0x20/0x2c)
[] (customize_machine+0x0/0x2c) from [] (kernel_init+0xb8/0x284)
[] (kernel_init+0x0/0x284) from [] (do_exit+0x0/0x76c)

我一开始就犯了这个毛病。具体情况请参阅:http://blog.chinaunix.net/u/17218/showart_262438.html以及/arch/arm/plat-s3c24xx文件夹下的common-smdk.c和devs.c。


四、 禁止nand flash的ECC校验
修改文件drivers/mtd/nand/s3c2410.c文件,查找函数s3c2410_nand_init_chip(),在函数的最后一行,添加chip->ecc.mode=NAND_ECC_NONE;

五、增加yaffs2文件系统的支持  
1、下载Yaffs2到~/arm2410s目录下
下载地址:
2、解压Yaffs2并将其加入Linux内核(打补丁的方式)
lingd@ubuntu:~/arm2410s$ tar xzvf yaffs2.tar.gz      
lingd@ubuntu:~/arm2410s$ cd yaffs2
lingd@ubuntu:~/arm2410s/yaffs2$ ./patch-ker.sh c ~/arm2410s/linux-2.6.24.7/

六、博创2410-S所配网卡AX88796(NE2000兼容网卡)驱动的移植。
1、修改arch/arm/Kconfig文件,增加ISA总线支持,使其在make menuconfig 时出现NE2000的网卡配置选项。

config ARCH_S3C2410
bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
select GENERIC_GPIO
select ISA       #lingd
help
	Samsung S3C2410X CPU based systems, such as the Simtec Electronics
	BAST (<), the IPAQ 1940 or
	the Samsung SMDK2410 development board (and derivatives).

2、修改include/asm-arm/arch-s3c2410/map.h文件。加入AX88796的地址映射。

/**********************lingd********************/ 
#define S3C2410_VA_ISA_NET   S3C2410_ADDR(0x02100000)
#define S3C2410_PA_ISA_NET   __phys_to_pfn(0x10000000)
#define S3C2410_SZ_ISA_NET   SZ_1M
/**********************lingd********************/

    说明:
    a、根据网上的资料,“#define S3C2410_VA_ISA_NET   S3C2410_ADDR(0x02100000)”的地址可以自己修改,只要不和别的虚拟地址冲突就行。我有试过将起改成“#define S3C2410_VA_ISA_NET   (0xd1000000)”,也就是博创的2.4.18的定义,也可以正常启动。
    b、“#define S3C2410_PA_ISA_NET   __phys_to_pfn(0x10000000)”这句困扰了我很久。一开始我的定义是“#define S3C2410_PA_ISA_NET   (0x10000000)”,所以启动后系统就死在了网卡的初始化上,出现“Unable to handle kernel paging request at virtual address ”的错误。后来我上网查找资料,才知道:原来实地址与虚地址的映射结构 smdk2410_iodesc 里有所变化。第二个参数从原来的 unsigned long physical 变为 unsigned long pfn (Page Frame Number 页帧号)。而从 smdk2410_iodesc 传入的S3C2410_PA_ISA_NET 仍然是一个 physical 值,因此出现以上的错误。只要在物理地址前加上“__phys_to_pfn”就可以解决这个问题。较详细的讲解请看我的参考资料

3、修改arch/arm/mach-s3c2410/mach-smdk2410.c文件。在smdk2410_iodesc 中加入AX88796的地址信息。
static struct map_desc smdk2410_iodesc[] __initdata = {
	/* nothing here yet */

/**********************lingd********************/
        {
                .virtual        = S3C2410_VA_ISA_NET,
                .pfn          = S3C2410_PA_ISA_NET,
                .length        = S3C2410_SZ_ISA_NET,
                .type          = MT_DEVICE,
        }
/**********************lingd********************/

};

 
4、修改网卡驱动的主要文件drivers/net/ne.c
(1)、添加头文件和定义

#include 
#include 

/**********************lingd********************/
#include 
#include 
#include 
#include 
#include 
#include 

#define AX88796_BASE   (vAX88796_BASE+0x200)
#define AX88796_IRQ    IRQ_EINT2
#define pAX88796_BASE    S3C2410_PA_ISA_NET
#define vAX88796_BASE    S3C2410_VA_ISA_NET
#define EXTINT_OFF  (IRQ_EINT4 - 4)
/**********************lingd********************/

......

 在static struct { const char *name8, *name16; unsigned char SAprefix[4];}
bad_clone_list[] __initdata 中增加AX88796 的MAC地址前三位(不一定需要):
	{"AX88796", "NE2000-compatible", {0x08, 0x08, 0x08}},       //lingd

 

(2)、确保定义总线宽度为16位。
 将

#if defined(CONFIG_PLAT_MAPPI)
#  define DCR_VAL 0x4b
#elif defined(CONFIG_PLAT_OAKS32R)  || \
   defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
#  define DCR_VAL 0x48      /* 8-bit mode */
#else
#  define DCR_VAL 0x49
#endif

修改为

#if 0
#if defined(CONFIG_PLAT_MAPPI)
#  define DCR_VAL 0x4b
#elif defined(CONFIG_PLAT_OAKS32R)  || \
   defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
#  define DCR_VAL 0x48      /* 8-bit mode */
#else
#endif
#endif
#  define DCR_VAL 0x49

    

(3)、在do_ne_probe函数中增加配置总线参数、基地址和中断的语句(其参数参考 刘淼 的书)

static int __init do_ne_probe(struct net_device *dev)
{
	unsigned long base_addr = dev->base_addr;
#ifdef NEEDS_PORTLIST
	int orig_irq = dev->irq;
#endif
/**********************lingd********************/
	static int once=0;
		if (once) {
			return -ENXIO;
		}

	unsigned int value;

	value = __raw_readl(S3C2410_BWSCON);
	value &= ~(S3C2410_BWSCON_WS2|S3C2410_BWSCON_ST2|S3C2410_BWSCON_DW2_32);
	value |= (S3C2410_BWSCON_ST2|S3C2410_BWSCON_DW2_16);
	__raw_writel(value, S3C2410_BWSCON);
	value=0;
	value = (S3C2410_BANKCON_Tacs4|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|S3C2410_BANKCON_Tcoh4|S3C2410_BANKCON_Tcah4|S3C2410_BANKCON_Tacp6|S3C2410_BANKCON_PMCnorm);
	__raw_writel(value,S3C2410_BANKCON2);
	set_irq_type(AX88796_IRQ,IRQ_TYPE_LEVEL_LOW );
	s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
	s3c2410_gpio_pullup(S3C2410_GPF2, 0);

	if(base_addr==0){
		dev->base_addr = base_addr = AX88796_BASE ;
		dev->irq = AX88796_IRQ;
		once++;
	}
/**********************lingd********************/

     SET_MODULE_OWNER(dev);


     /* First check any supplied i/o locations. User knows best.  */
     if (base_addr > 0x1ff) /* Check a single specified location. */
         return ne_probe1(dev, base_addr);
     else if (base_addr != 0)    /* Don't probe at all. */
         return -ENXIO;

......

(4)、修改ne_probe1函数
增加自定义的网卡MAC地址(这个地址可以自行修改,但是MAC也有一定的规则,最重要的是千万不要把它配置为广播或组播地址,请参考网络的相关书籍):

static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
{
 	int i;
	unsigned char ne_defethaddr[]={0x08,0x08,0x08,0x08,0x12,0x27,0};   //lingd
	unsigned char SA_prom[32];
	int wordlength = 2;

......
     增加网卡MAC地址的配置语句,屏蔽通过EEPROM配置网卡的语句
......

	struct {unsigned char value, offset; } program_seq[] =
	{
		{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
		{0x48,   EN0_DCFG},    /* Set byte-wide (0x48) access. */
		{0x00,   EN0_RCNTLO},  /* Clear the count regs. */
		{0x00,   EN0_RCNTHI},
		{0x00,   EN0_IMR}, /* Mask completion irq. */
		{0xFF,   EN0_ISR},
		{E8390_RXOFF, EN0_RXCR},    /* 0x20  Set to monitor */
		{E8390_TXOFF, EN0_TXCR},    /* 0x02  and loopback mode. */
		{32, EN0_RCNTLO},
		{0x00,   EN0_RCNTHI},
		{0x00,   EN0_RSARLO},  /* DMA starting at 0x0000. */
		{0x00,   EN0_RSARHI},
		{E8390_RREAD+E8390_START, E8390_CMD},
	};

	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
		outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
	}

/**********************lingd********************/
	{
		unsigned char *ep;
		ep = (unsigned char * ) &ne_defethaddr[0];
		ne_defethaddr[5]++;

		for(i=0;i<6;i++) {
			SA_prom[i] = ep[i];
	}

	SA_prom[14] = SA_prom[15]=0x57;
	wordlength =2;
	}
/**********************lingd********************/
#if 0    //lingd

	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
		if (SA_prom[i] != SA_prom[i+1])
		wordlength = 1;
	}

#endif   //lingd

     if (wordlength == 2)
     {
#if 0   //lingd

	for (i = 0; i < 16; i++)
		SA_prom[i] = SA_prom[i+i];

	/* We must set the 8390 for word mode. */
	outb_p(DCR_VAL, ioaddr + EN0_DCFG);
	start_page = NESM_START_PG;

	/*
	* Realtek RTL8019AS datasheet says that the PSTOP register
	* shouldn't exceed 0x60 in 8-bit mode.
	* This chip can be identified by reading the signature from
	* the  remote byte count registers (otherwise write-only)...
	*/

	if ((DCR_VAL & 0x01) == 0 &&         /* 8-bit mode */
	     inb(ioaddr + EN0_RCNTLO) == 0x50 &&
	     inb(ioaddr + EN0_RCNTHI) == 0x70)
		stop_page = 0x60;
	else
		stop_page = NESM_STOP_PG;

#endif   //lingd

/**********************lingd********************/
	outb_p(0x49, ioaddr + EN0_DCFG);
	start_page = NESM_START_PG;
	stop_page = NESM_STOP_PG;
/**********************lingd********************/
	} else {
		start_page = NE1SM_START_PG;
		stop_page  = NE1SM_STOP_PG;
	}

......
屏蔽自定检测中断号的语句(参考 刘淼 的书):
......

#if 0  //lingd

	if (dev->irq < 2)
	{
		unsigned long cookie = probe_irq_on();
		outb_p(0x50, ioaddr + EN0_IMR);  /* Enable one interrupt. */
		outb_p(0x00, ioaddr + EN0_RCNTLO);
		outb_p(0x00, ioaddr + EN0_RCNTHI);
		outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
		mdelay(10);        /* wait 10ms for interrupt to propagate */
		outb_p(0x00, ioaddr + EN0_IMR);      /* Mask it again. */
		dev->irq = probe_irq_off(cookie);
		if (ei_debug > 2)
			printk(" autoirq is %d\n", dev->irq);
	} else if (dev->irq == 2)
	/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
	or don't know which one to set. */
		dev->irq = 9;

#endif   //lingd

	if (! dev->irq) {
		printk(" failed to detect IRQ line.\n");
		ret = -EAGAIN;
		goto err_out;
	}

     

 
七、配置内核
1、载入s3c2410的默认配置文件,以简化配置过程
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ cp arch/arm/configs/s3c2410_defconfig .config
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make menuconfig
2、手动配置内核,在s3c2410_defconfig基础上,增加以下配置选项:
General setup  --->     
[*] Configure standard kernel features (for small systems) --->  
选上这项,否则文件系统中的一些选项不会出现
		[*] Enable full-sized data structures for core     
[*] Enable futex support      
[*] Enable eventpoll support    
[*] Enable signalfd() system call         
[*] Enable eventfd() system call    
[*] Use full shmem filesystem
[*] Enable loadable module support ---> [*] Automatic kernel module loading System Type ---> [*] S3C2410 DMA support Boot options ---> Default kernel command string:noinitrd root=31:03 init=/linuxrc console=ttySAC0,115200 mem=64M
注意:udev需要内核提供sysfs和tmpfs支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件提供存放空间,也就是说,在上电之前系统上是没有足够的设备文件可用的,我们需要一些技巧让kernel先引导起来。由于在kernel启动未完成以前我们的设备文件不可用,如果使用mtd设备作为rootfs的挂载点,这个时候/dev/mtdblock 是不存在的,我们无法让kernel找到rootfs,kernel只好停在那里惊慌(panic)。
这个问题我们可以通过给kernel传递设备号的方式来解决,在linux系统中,mtdblock的主设备号是31,part号 从0开始,那么以前的/dev/mtdblock/3就等同于31:03,以次类推,所以我们只需要修改bootloader传给kernel的cmd line参数,使root=31:03,就可以让kernel在udevd未起来之前成功的找到rootfs。
 
Networking  --->
	Networking options  --->  
		<*> Packet socket 
		[*]   Packet socket: mmapped IO
Floating point emulation  --->
	[*] NWFPE math emulation 
Device Drivers  --->
	<*> Memory Technology Devices (MTD  --->
		[*] MTD partitioning support
		[*] Command line partition table parsing
		RAM/ROM/Flash chip drivers  --->
			<*> Detect flash chips by Common Flash Interface (CFI) probe
			<*> Detect nonCFI AMD/JEDECcompatible flash chips
			<*> Support for Intel/Sharp flash chips
			<*> Support for AMD/Fujitsu flash chips
			<*> Support for ROM chips in bus mapping
		<*> NAND Device Support  --->
			<*> NAND Flash support for S3C2410/S3C2440 SoC
	Network device support  --->
		[*] Ethernet (10 or 100Mbit)  --->
			“N”掉< > DM9000 support和< >   Generic Media Independent Interface device support
-------以下一定要选上,是AX88796的驱动------
			[*] Other ISA cards      
			<*> NE2000/NE1000 support
	Character devices  --->
		[*] Nonstandard serial port support
File systems  --->
	<> Second extended fs support #去除对ext2的支持

Pseudo filesystems --->   
udev依赖sysfs,同时他还要求/dev目录可写,因此我们可以把/dev 挂载成tmpfs。所以在配置内核时,我们需要同时支持sysfs和tmpfs:      
[*] /proc file system support         
[*]   Sysctl support (/proc/sys)                 
[*] sysfs file system support         
[*] Virtual memory file system support (former shm fs)         
[*]   Tmpfs POSIX Access Control Lists         
[*] Userspace-driven configuration filesystem
	Miscellaneous filesystems  --->            
		<*> YAFFS2 file system support                  #支持yaffs2
		[*] Lets Yaffs do its own ECC
		<*> Compressed ROM file system support (cramfs) 
	[*]Network File Systems  --->
		<*> NFS file system support
--以下最好选上,因为在挂载NFS时可能出现protocol不支持的情况--
		[*]Provide NFSv3 client support
		[*]Provide client support for the NFSv3 ACL protocol extension
		[*]   Provide NFSv4 client support (EXPERIMENTAL)
		[*]   Allow direct I/O on NFS files
------------------------------------------------------------------------- 
		[ ] NFS server support 
		[*] Root file system on NFS 
 
保存退出,产生.config文件。
八、编译内核
内核的编译操作
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make menuconfig       配置编译选项
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make dep              提供变量依赖关系信息
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make clean            删除生成的模块和目标文件
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make zImage           编译内核生成压缩的映像
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make modules          编译模块
lingd@ubuntu:~/arm2410s/linux-2.6.24.7$ make modules_install  安装编译完成的模块

至此,内核的编译工作完成,在arch/arm/boot目录下生成了zImage文件,即为压缩的内核映像。
最后,将内核镜像烧写到博创arm2410s开发板上,启动正常,网卡也正常
参考文献:
移植Linux2.6.22.2到博创2410-S
http://blog.chinaunix.net/u1/34474/showart_369449.html
Linux 2.6.16 udev问题http://www.eefocus.com/chenzhufly/blog/09-03/166560_5e277.html
阅读(2417) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~