首页 > 代码库 > 【FL2400】Linux3.0 内核移植 一

【FL2400】Linux3.0 内核移植 一

接触arm + Linux已经将近两年了,之前都是站在大神的肩膀上来移植linux内核,对很对要求移植的东西都不是很懂!为了进一步深入对内核的了解,我决定重新从头开始对linux内核进行移植。这次移植完全是从一个新手的角度进行移植,包括可能出现的问题,以及出现的问题如何解决。

环境:

操作系统: CentOS 6.2 

编译环境:gcc version 4.3.6 (Buildroot 2011.11) 

开发板    : 飞凌2440(s3c2440)(arm920t)

u-boot    :u-boot-2010.09(MACHID = 1999)

Linux内核:linux-3.0

【在移植之前,以上环境都是配置好的,包括u-boot-2010.09已经可以在板子上运行的】


linux内核已经给我们提供了许多已经配置好的config文件,在arch/arm/configs/下,我们选一个跟我们比较像s3c2410_defconfig的进行配置;

make menuconfig进入配置模式-->Load an Alternate Configuration File-->在里面输入需要的具体路径:arch/arm/configs/s3c2410_defconfig-->退出并保存

由于里面他自动加载的模块太多了,我们需要去掉大部分,也就是传说中的系统裁剪,接着make menuconfig进入配置模式。这个就自己根据英文意思进行选择,我就说一个地方,在System Type 里面,如果不进行稍微的裁剪,他会编译适合大部分内核,如果你只想编译适合你自己的,在System MMU下面把除S3C2440的选项都去掉!make完成之后,内核已经制作完成了,当然还需要uboot的mkimage工具将内核按照一定格式压缩

mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d zImage uImage-s3c2440.gz
Image Name:   Linux Kernel
Created:      Tue Aug 12 09:26:51 2014
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    1984356 Bytes = 1937.85 kB = 1.89 MB
Load Address: 30008000
Entry Point:  30008040
【注:mkimage工具在uboot编译成功之后,就会在tools文件夹下面生成】

生成的uImage-s3c2440.gz放入tftp服务器里面,然后进入uboot的debug模式,用tftp命令将编译好的内核下载到SRAM上:

tftp 30008000 uImage-s3c2440.gz;bootm 30008000
这里的地址一定要跟上面mkimage的参数一致。我特意测试了一下,如果不一致的效果:

[ fl2440@chenzhenwei ]# tftp 30009000 uImage-s3c2440.gz;bootm 30009000
dm9000 i/o: 0x20000300, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 08:00:3e:26:0a:6b
could not establish link
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.244
Filename 'uImage-s3c2440.gz'.
Load address: 0x30009000
Loading: T #################################################################
         #################################################################
         ######
done
Bytes transferred = 1984420 (1e47a4 hex)
## Booting kernel from Legacy Image at 30009000 ...
   Image Name:   Linux Kernel
   Created:      2014-08-12   1:26:51 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1984356 Bytes = 1.9 MiB
   Load Address: 30008000
   Entry Point:  30008040
   Verifying Checksum ... OK
   Loading Kernel Image from 30009040 to 30008000... OK
OK
OS entry point: 30008040
Image entry point=30008040
这样,下载完成之后,如果你之前的uboot的MACHID跟你LINUX内核的ID是一样的话,那内核就可以正常启动了,当然我没有那么幸运,上面我已经说过了,我UBOOT的MACHID是1999。而内核默认的MACHID为000016a。所以就出现如下后果(提示MACHID不支持):

Starting kernel ...

Uncompressing Linux... done, booting the kernel.

Error: unrecognized/unsupported machine ID (r1 = 0x33edffc4).

Available machine support:

ID (hex)        NAME
0000016a        SMDK2440
0000043c        SMDK2443

Please check your kernel config and/or bootloader.
那么我们需要把mach-type的id改下:

[09:42:50 @ linux-3.0 ]$ vim arch/arm/tools/mach-types

s3c2440         ARCH_S3C2440        S3C2440         362
将362改为1999即可,重新编译,加载内核,这里说个小技巧,由于我们要不停测试内核,如果一个劲的往Nand Flash上不断擦除读写,很麻烦,浪费时间,而且还减少nandflash的使用寿命,所以正确的调试方法是,直接将内核下载到指定的地址空间上,直接运行,我上面就是使用这种方法!

修改完之后,make,make image,下载,运行之后就没有上面那个状况了,但是他就停在这里不输出了:

[ fl2440@chenzhenwei ]# run tb
dm9000 i/o: 0x20000300, id: 0x90000a46 
DM9000: running in 16 bit mode
MAC: 08:00:3e:26:0a:6b
could not establish link
operating at 100M full duplex mode
Using dm9000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.244
Filename 'uImage-s3c2440.gz'.
Load address: 0x30008000
Loading: T #################################################################
         #################################################################
         ######
done
Bytes transferred = 1984424 (1e47a8 hex)
## Booting kernel from Legacy Image at 30008000 ...
   Image Name:   Linux Kernel
   Created:      2014-08-12   1:51:01 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1984360 Bytes = 1.9 MiB
   Load Address: 30008000
   Entry Point:  30008040
   Verifying Checksum ... OK
   XIP Kernel Image ... OK
OK
OS entry point: 30008040
Image entry point=30008040

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
注: 这里的tb是我在uboot里面定义的一个变量,变量内容(tb=tftp 30008000 uImage-s3c2440.gz;bootm 30008000)这样我就不用每次输入那么多了;
但是我惊奇的发现我的班长的lcd已经有一个小企鹅了,虽然小企鹅残缺不全?据目前推测是因为驱动参数没有设置好,后期我们再设置,现在先来说说接下来串口没有打印内核信息了。

uboot的有个bootargs参数,我们先来看看这个参数,这个参数是传给内核使用的,你也可以再make menuconfig里面设置这个参数(Boot options --> ()  Default kernel command string)

bootargs=console=ttyS0,115200 mem=64M initrd=0x30800000,16M root=/dev/ram0 rw loglevel=7

这里的console口ttyS0,内核既然没有输出,那么他创建的console设备名肯定不是他了,所以我们现在就要找到内核里serial的名字。找了半天在drivers/tty/serial/samsung.c里发现了这个驱动,有如下定义:

/* UART name and device definitions */
 
#define S3C24XX_SERIAL_NAME "ttySAC"
#define S3C24XX_SERIAL_MAJOR    204
#define S3C24XX_SERIAL_MINOR    64
说明SERIAL_NAME为ttySAC,那么我们就需要把我们的bootargs参数修改下,改为

bootargs=console=ttySAC0,115200 mem=64M initrd=0x30800000,16M root=/dev/ram0 rw loglevel=7
重新启动内核,你会惊喜的发现,内核有东西输出了,但是是一堆乱码?根据我的常识推断,这肯定是波特率不对,但是波特率在bootargs里面设置的是115200啊,跟我PC上的波特率是一样的啊!那是哪里的问题呢?肯定是那个地方的频率不对,才导致系统出现这个问题!


图一 串口波特率不对,导致内核打印信息为乱码

(有人肯定会问我,你怎么找这么准啊?对,这完全是经验,你要怎么才能拥有这个经验呢?多实践,多了解,多记,首先你要对内核的每个目录是干什么的要了解下吧?然后你要知道linux内核他的设备驱动是个怎么回事吧?具体这些问题,网上说的不计其数。)

这个使我想起了s3c2410跟s3c2440的主频不一样,又因为我使用的是s3c2410的config文件,所以我就需要看看他的主内核是时钟是怎么配置的。一般时钟都在芯片内核初始化的地方,我们就需要去mach-s3c2440的目录下面看看。

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

找到machine_init的地方,这个肯定是系统初始化了,发现有这么一段代码:

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


static void __init smdk2440_machine_init(void)
{
    s3c24xx_fb_set_platdata(&smdk2440_fb_info);
    s3c_i2c0_set_platdata(NULL);


    platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
    smdk_machine_init();
}
有一句s3c24xx_init_clocks(16934400);这个事16.934MHz的晶振,而我板子上的系统晶振为12MHz的,所以我需要把这晶振频率改下:s3c24xx_init_clocks(12000000);

注意:可能你们的板子上的晶振不是12MHz的,所以要自己看下原理图或者开发板上的晶振是多少。
重新make , make image , 下载,bootm。


图二  s3c2440晶振电路图

这次内核成功的打印信息了:

Bytes transferred = 1984424 (1e47a8 hex)
## Booting kernel from Legacy Image at 30008000 ...
   Image Name:   Linux Kernel
   Created:      2014-08-12   2:23:33 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1984360 Bytes = 1.9 MiB
   Load Address: 30008000
   Entry Point:  30008040
   Verifying Checksum ... OK
   XIP Kernel Image ... OK
OK
OS entry point: 30008040
Image entry point=30008040

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
Linux version 3.0.0 (chenzhenwei@localhost.localdomain) (gcc version 4.3.6 (Buildroot 2011.11) ) #3 Tue Aug 12 10:20:31 CST 2014
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
CPU: VIVT data cache, VIVT instruction cache
Machine: SMDK2440
Memory policy: ECC disabled, Data cache writeback
CPU S3C2440A (id 0x32440001)
S3C24XX Clocks, Copyright 2004 Simtec Electronics
S3C244X: core 405.000 MHz, memory 101.250 MHz, peripheral 50.625 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
Kernel command line: console=ttySAC0,115200 mem=64M initrd=0x30800000,16M root=/dev/ram0 rw loglevel=7
PID hash table entries: 256 (order: -2, 1024 bytes)
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 44520k/44520k available, 21016k reserved, 0K highmem
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    DMA     : 0xffc00000 - 0xffe00000   (   2 MB)
    vmalloc : 0xc4800000 - 0xf6000000   ( 792 MB)
    lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
    modules : 0xbf000000 - 0xc0000000   (  16 MB)
      .init : 0xc0008000 - 0xc002b000   ( 140 kB)
      .text : 0xc002b000 - 0xc0399000   (3512 kB)
      .data : 0xc039a000 - 0xc03c5080   ( 173 kB)
       .bss : 0xc03c50a4 - 0xc03e9d84   ( 148 kB)
NR_IRQS:99
系统默认nand flash分区:

Creating 8 MTD partitions on "NAND":
0x000000000000-0x000000004000 : "Boot Agent"
mtd: partition "Boot Agent" doesn't end on an erase block -- force read-only
0x000000000000-0x000000200000 : "S3C2410 flash partition 1"
0x000000400000-0x000000800000 : "S3C2410 flash partition 2"
0x000000800000-0x000000a00000 : "S3C2410 flash partition 3"
0x000000a00000-0x000000e00000 : "S3C2410 flash partition 4"
0x000000e00000-0x000001800000 : "S3C2410 flash partition 5"
0x000001800000-0x000003000000 : "S3C2410 flash partition 6"
0x000003000000-0x000010000000 : "S3C2410 flash partition 7"
但是提示没有文件系统:

List of all partitions:
1f00              16 mtdblock0  (driver?)
1f01            2048 mtdblock1  (driver?)
1f02            4096 mtdblock2  (driver?)
1f03            2048 mtdblock3  (driver?)
1f04            4096 mtdblock4  (driver?)
1f05           10240 mtdblock5  (driver?)
1f06           24576 mtdblock6  (driver?)
1f07          212992 mtdblock7  (driver?)
No filesystem could mount root, tried:  ext2 cramfs vfat msdos iso9660 ntfs romfs
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
Backtrace: 
[<c003b734>] (dump_backtrace+0x0/0x104) from [<c02bb4f0>] (dump_stack+0x18/0x1c)
 r6:c3889000 r5:00008000 r4:c3819f5c
[<c02bb4d8>] (dump_stack+0x0/0x1c) from [<c02bb548>] (panic+0x54/0x1a8)
[<c02bb4f4>] (panic+0x0/0x1a8) from [<c0008ff0>] (mount_block_root+0x264/0x2d0)
 r3:00000000 r2:c3819f5c r1:c3819f5c r0:c034e9e8
[<c0008d8c>] (mount_block_root+0x0/0x2d0) from [<c00090b0>] (mount_root+0x54/0x6c)
[<c000905c>] (mount_root+0x0/0x6c) from [<c00091dc>] (prepare_namespace+0x114/0x1e4)
 r5:c0026600 r4:c03c5120
[<c00090c8>] (prepare_namespace+0x0/0x1e4) from [<c0008490>] (kernel_init+0xe8/0x128)
 r5:c002584c r4:c0025bdc
[<c00083a8>] (kernel_init+0x0/0x128) from [<c0050554>] (do_exit+0x0/0x6e8)
 r6:c0050554 r5:c00083a8 r4:00000000
再具体看下他的List of all partitions,部分分区跟我的内核和文件系统分区重叠了,所以我们要对文件系统分区进行修改;(这里我就不对文件系统进行详细的描述了,因为这次是针对linux内核移植)

【如果存在什么问题,请大家留言并指出】

E-mail: ieczw@qq.com

如果转载请注明出处,谢谢!