keep moving
分类: 嵌入式
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 [ 我一开始就犯了这个毛病。具体情况请参阅: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] (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) #include /**********************lingd********************/ #include #include ...... 在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.#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********************/ */ 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