Linux3.4.5内核移植到MPC880过程记录
PS一下:我2009年9月份到的目前这家公司,当时看到这里所用的Linux内核版本还是Linux2.4.22版本时,囧!!!都什么年代了,还用这么古老的linux内核版本,太Out了,当时事业部的同事还用的不亦乐乎,让人愈发抓狂!后来事实证明,提前做好Linux内核版本的升级还是非常有必要的。因为后续产品开发对软件平台进行了重构(采用C++开发),把一个用户程序Download到Linux2.4.22平台上运行,使用top命令一看,CPU占用率飙升到98%了,更要命的是当时这个用户程序还只是集成了一部分功能,还有其他用户程序还没有启动,看来不能再继续在Linux2.4.22平台上做开发了,立马开足马力升级Linux操作系统平台!其实当时基于Linux2.6.29内核的移植工作已经完成的差不多了(未详细测试和个别驱动未移植完),将用户程序重新编译然后放到基于Linux2.6.29操作系统平台运行后,使用top命令查看CPU占用率只有4%,接近25倍的性能差异,看来Linux内核开发者平时所作的改进工作不是盖的,在此向Linux内核开发和维护者致敬。从此自己的开发工作开始跨入Linux2.6内核版本了。闲话少说,继续Linux3.4.5版本移植过程。
移植工作第一步:解压内核文件并重新修改顶层的Makefile文件
将linux-3.4.5版本软件拷贝到Fedora12下的工作目录,并直接解压。等待解压完成后,先修改顶层的Makefile文件,指定SUBARCH := powerpc(硬件平台是PowerPC芯片-MPC880芯片)和CROSS_COMPILE :=powerpc-linux-,这一步操作估计问题不大。
然后需要打开一个终端,使用cd命令进入Linux3.4.5内核所在的位置,这时候不要忘记指定交叉编译工具的路径,例如我需要指定的交叉编译工具的路径和交叉编译工具如下:exportPATH=$PATH:/opt/eldk4.2_ppc8xx/usr/bin/
exportCROSS_COMPILE=ppc_8xx-
通过在Linux终端输入上面的命令,就完成了对交叉编译环境的设定。
移植工作第二步:选择内核编译配置
此时由于移植是在全新的Linux内核源码基础上进行的,为了避免频繁手动设定各种Linux内核配置选项,我采用的是ep88xc默认配置。此时可以在终端输入以下命令:
make ep88xc_defconfig
该默认配置信息具体内容大家可以参考/linux-3.4.5/arch/powerpc/configs/ep88xc_defconfig文件。可以看到Linux3.4.5内核编译工作开始了,此时我的电脑上编译内核时会报以下错:
BOOTCC arch/powerpc/boot/treeboot-currituck.o
{standard input}:Assembler messages:
{standardinput}:126: Error: Unrecognized opcode: `mfdcrx' treeboot-currituck.c
出错的地方在arch/powerpc/boot/treeboot-currituck.c文件的第50行,参照以下红色标注处:
static unsignedlong long ibm_currituck_detect_memsize(void)
{
u32 reg;
unsigned i;
unsigned long long memsize = 0;
for(i = 0; i < MAX_RANKS; i++){
reg = mfdcrx(DDR3_MR0CF+ i);
if (!(reg & 1))
continue;
reg &= 0x0000f000;
reg >>= 12;
memsize += (0x800000ULL<< reg);
}
return memsize;
}
文件编译出错的原因是mfdcrx指令无法识别,手头的交叉编译工具可能落伍了,先关不了那么多,修改arch/powerpc/boot/Makefile文件,屏蔽treeboot-currituck相应内容,主要涉及到2个地方,
#$(obj)/treeboot-currituck.o:BOOTCFLAGS += -mcpu=405
$(obj)/virtex405-head.o:BOOTAFLAGS += -mcpu=405
以及:
src-plat:= of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
cuboot-ebony.ccuboot-hotfoot.c epapr.c treeboot-ebony.c \
prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.ctreeboot-bamboo.c cuboot-8xx.c \
cuboot-pq2.c cuboot-sequoia.ctreeboot-walnut.c \
cuboot-bamboo.c cuboot-mpc7448hpc2.ccuboot-taishan.c \
fixed-head.S ep88xc.c ep405.ccuboot-c2k.c \
cuboot-katmai.ccuboot-rainier.c redboot-8xx.c ep8248e.c \
cuboot-warp.ccuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \
virtex405-head.S virtex.credboot-83xx.c cuboot-sam440ep.c \
cuboot-acadia.ccuboot-amigaone.c cuboot-kilauea.c \
gamecube-head.S gamecube.cwii-head.S wii.c treeboot-iss4xx.c
# treeboot-currituck.c
修改完成后继续编译,如果不出意外的话第一次编译顺利完成。此步骤的作用是确保所选用的内核代码可以顺利编译完成,便于后续继续开展移植修改工作。
移植工作第三步:选择芯片的dts配置文件
在Linux2.6内核以来,基于PowerPC芯片的开发引入了dts,相关内容可以自己到网上查找相关资料学习,很多与PowerPC芯片相关(Flash、SOC、中断配置、网口配置)内容都需要在对应的dts文件中进行配置。由于自己手头上有基于Linux2.6.29内核版本下对应芯片的dts文件,可以直接拷贝过来,我直接就修改了/linux-3.4.5/arch/powerpc/boot/dts/ep88xc.dts:
ranges = <
0x0 0x0 0xfc0000000x1000000 //指定Flash起始地址,容量信息 16M
0x4 0x0 0xfa0000000x1000000 //指定SDRAM起始地址,容量信息64M
>;
flash@0,1000000 {
#address-cells= <1>;
#size-cells =<1>;
compatible ="cfi-flash";
reg = <0x00x0000000 0x1000000>; //指定Flash大小
bank-width =<2>;
device-width =<2>;
partition@0 {
label ="uboot";
reg =<0x000000 0x0080000>;
read-only;
};
partition@80000 {
label ="kernel";
reg =<0x0080000 0x0180000>;
read-only;
};
partition@280000 {
label ="initrd";
reg =<0x00200000 0x0480000>;
read-only;
};
partition@700000 {
label ="user";
reg = <0x00680000 0x980000>;
};
};
在该dts文件中指定了Flash的大小,Flash分区信息,其实大家可以阅读下该文件的内容,可以发现网口的信息也需要配置,开发过程中很多驱动需要用到的中断信息也需要在此文件中进行添加,如此就不一一详细列举。
移植工作第四步:修改关于MPC880芯片相关配置内容(具体修改内容要结合实际硬件)
我的移植过程中修改了/linux-3.4.5/arch/powerpc/boot/cuboot-8xx.c文件(时钟控制),/linux-3.4.5/arch/powerpc/platforms/8xx/ep88xc.c(增加内存控制相应内容)、/linux-3.4.5/arch/powerpc/sysdev/cpm1.c(CPM控制器相关配置),修改完成后直接编译完成后下到板上进行测试。
幸运的是此时Linux内核可以正常启动,顺利地看到以下信息:
U-Boot 2010.09(Jul 18 2012 - 12:38:19)
Uboot Version: V4.0.1.
Uboot For Kernel:Linux-3.4.5
CPU: MPC885ZPnn at 132.779 MHz [40.0...133.0 MHz]
8 kB I-Cache 8 kB D-Cache FEC present
DRAM: 64 MB
FLASH: 16 MB
In: serial
Out: serial
Err: serial
Net: FEC, FEC2
autoboot in 2seconds (stop with 'c')...
## Booting kernelfrom Legacy Image at fc080000 ...
Image Name: Linux-3.4.5
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1363256 Bytes = 1.3 MB
Load Address: 00400000
Entry Point: 0040056c
Verifying Checksum ... OK
## Loading initRamdisk from Legacy Image at fc280000 ...
Image Name: Ram disk
Image Type: PowerPC Linux RAMDisk Image (gzip compressed)
Data Size: 4631202 Bytes = 4.4 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Loading Ramdisk to 0373f000, end 03ba9aa2 ... OK
Memory <-<0x0 0x4000000> (64MB)
ENET0:local-mac-address <- 00:30:bf:01:02:d2
ENET1:local-mac-address <- 0f:f0:cf:f0:69:6e
CPUclock-frequency <- 0x7ea0aa1 (133MHz)
CPUtimebase-frequency <- 0x3f5055(4MHz)
zImage starting:loaded at 0x00400000 (sp: 0x03baabb8)
Allocating0x2befec bytes for kernel ...
gunzipping(0x00000000 <- 0x0040d000:0x006f94e8)...done0x2a8f80 bytes
Using loadersupplied ramdisk at 0x3789000-0x3bc7aa2
initrd head: 0x1f8b0808
Linux/PowerPCload: root=/dev/ram0 rw init=/linuxrc
但是接下来的问题又大了:
List of allpartitions:
1f00 512 mtdblock0 (driver?)
1f01 2048 mtdblock1 (driver?)
1f02 4608 mtdblock2 (driver?)
1f03 9216 mtdblock3 (driver?)
No filesystemcould mount root, tried: cramfs
Kernel panic -not syncing: VFS: Unable to mount root fs on unknown-block(31,2)
Call Trace:
[c3027ec0] [c0005a64] show_stack+0x58/0x154 (unreliable)
[c3027f00] [c00236d0] panic+0xc4/0x204
[c3027f50] [c0275d24]mount_block_root+0x274/0x298
[c3027fa0] [c0275f04] prepare_namespace+0x154/0x194
[c3027fc0] [c027536c] kernel_init+0x1a8/0x1c4
[c3027ff0][c000aa18] kernel_thread+0x4c/0x68
Rebooting in 180seconds..
Linux内核无法正常挂载根文件系统,导致Linux内核后续执行出现崩溃。
移植工作第五步:修正根文件系统无法挂载的问题
其实这个问题之前还遇到很多问题,比如说无法正确识别文件分区信息,则只需要在内核配置选项选中以下内容:
DeviceDrivers --- >
Memory Technology Device(MTD)support --- >
Mapping drivers for chipaccess --- >
<*>Flash devicein physical memory map based on OF description
而关于根文件系统无法挂载的问题修改起来很简单,我以前制作的根文件系统是ramdisk,现在只需要实现Linux3.4.5内核从ramdisk根文件系统启动成功就行。首先得看一下我制作根文件系统的脚本:
dd if=/dev/zeroof=mpc880rootfs bs=1k count=16384
mke2fs -m0 -N2000 ./mpc880rootfs
mkdir ramdisk
mount -t ext2 -oloop ./mpc880rootfs ./ramdisk
cp -av rootfSource/*ramdisk
ppc_8xx-strip -sramdisk/lib/lib*
ppc_8xx-strip -sramdisk/lib/security/lib*
ppc_8xx-strip -sramdisk/usr/lib/lib*
umount ramdisk
gzip v9mpc880rootfs
mkimage -n"Ram disk" -A ppc -O linux -T ramdisk -C gzip -d mpc880rootfs.gz rootfs.bin
脚本的具体内容就不做解释了,里面要关注到2个问题,2个问题跟根文件系统挂载有关。问题1:ramdisk是一种内存虚拟磁盘技术,实质上并不是一种文件系统,它使用的文件系统是ext2文件系统,所以我们在配置Linux3.4.5内核配置选项时,一定要选择对ext2文件系统的支持。
File systems --- >
<*>Second extended fs support
问题2:在dd if=/dev/zero of=mpc880rootfs bs=1kcount=16384这个语句中,告诉我们创建的ramdisk文件空间大小是16384*1k,因此我们在配置对Default RAM disk size kbytes时选择的大小应该为16384。
DeviceDrivers --- >
[*]Block devices --- >
<*>RAM block device support
(16384) Default RAM disk size(kbytes)
光解决上述2个问题还是不够的,需要注意到前面的打印信息,uboot需要将Linux内核启动参数传递给Linux内核--Linux/PowerPCload: root=/dev/ram0 rw init=/linuxrc,内核启动打印会上述信息,由于我选择的是ramdisk作为根文件系统启动,因此需要修改uboot软件,重新制定uboot传递的信息内容,具体传递的启动信息内容格式如下:
initrd=xxxx(ramdisk启动地址),zzzz(ramdisk大小) root=/dev/ram rwinit=/linuxrc
ramdisk的启动地址和大小信息,在Linux内核启动时可以看到,修改好uboot软件后重新编译,并将修改编译好的内容下到板上,复位启动,哈哈。。。linux-3.4.5内核移植完成!!
U-Boot 2010.09(Jul 18 2012 - 12:38:19)
Uboot Version: V4.0.1.
Uboot For Kernel:Linux-3.4.5
CPU: MPC885ZPnn at 132.779 MHz [40.0...133.0 MHz]
8 kB I-Cache 8 kB D-Cache FEC present
DRAM: 64 MB
FLASH: 16 MB
In: serial
Out: serial
Err: serial
Net: FEC, FEC2
autoboot in 2seconds (stop with 'c')...
## Booting kernelfrom Legacy Image at fc080000 ...
Image Name: Linux-3.4.5
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1363256 Bytes = 1.3 MB
Load Address: 00400000
Entry Point: 0040056c
Verifying Checksum ... OK
## Loading initRamdisk from Legacy Image at fc280000 ...
Image Name: Ram disk
Image Type: PowerPC Linux RAMDisk Image (gzip compressed)
Data Size: 4631202 Bytes = 4.4 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
Loading Ramdisk to 0373f000, end 03ba9aa2 ... OK
Memory <-<0x0 0x4000000> (64MB)
ENET0:local-mac-address <- 00:30:bf:01:02:d2
ENET1:local-mac-address <- 0f:f0:cf:f0:69:6e
CPUclock-frequency <- 0x7ea0aa1 (133MHz)
CPUtimebase-frequency <- 0x3f5055(4MHz)
zImage starting:loaded at 0x00400000 (sp: 0x03baabb8)
Allocating0x2befec bytes for kernel ...
gunzipping(0x00000000 <- 0x0040d000:0x006f94e8)...done0x2a8f80 bytes
Using loadersupplied ramdisk at 0x3789000-0x3c79aa2
initrd head: 0x1f8b0808
Linux/PowerPCload: initrd=0xC3789000, 0x004677BB root=/dev/ram rw init=/linuxrc
Finalizing devicetree... flat tree at 0x728220
Using EmbeddedPlanet EP88xC machine description
Linux version 3.4.5(root@Kevin Liu) (gcc version 4.2.2) #9 Wed Jul 18 15:41:08 CST 2012
Found initrd at0xc373f000:0xc3ba9aa2
Zone PFN ranges:
DMA 0x00000000 -> 0x00004000
Normal empty
Movable zonestart PFN for each node
Early memory PFNranges
0: 0x00000000 -> 0x00004000
MMU: Allocated 72bytes of context maps for 16 contexts
Built 1 zonelistsin Zone order, mobility grouping on. Total pages: 16256
Kernel commandline: initrd=0xC3789000,0x004677BB root=/dev/ram rw init=/linuxrc
PID hash tableentries: 256 (order: -2, 1024 bytes)
Dentry cache hashtable entries: 8192 (order: 3, 32768 bytes)
Inode-cache hashtable entries: 4096 (order: 2, 16384 bytes)
Memory:57352k/65536k available (2744k kernel code, 8184k reserved, 116k data, 90k bss,108k init)
Kernel virtualmemory layout:
* 0xfffdf000..0xfffff000 : fixmap
* 0xfde00000..0xfe000000 : consistent mem
* 0xfddf6000..0xfde00000 : early ioremap
* 0xc5000000..0xfddf6000 : vmalloc & ioremap
SLUB:Genslabs=14, HWalign=16, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
NR_IRQS:512nr_irqs:512 16
DecrementerFrequency = 0x7ea0aa
clocksource:timebase mult[788054df] shift[24] registered
console [ttyCPM0]enabled
pid_max: default:4096 minimum: 301
Mount-cache hashtable entries: 512
NET: Registeredprotocol family 16
bio: create slab<bio-0> at 0
Switching toclocksource timebase
FS-Cache: Loaded
NET: Registeredprotocol family 2
IP route cachehash table entries: 1024 (order: 0, 4096 bytes)
TCP establishedhash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hashtable entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tablesconfigured (established 2048 bind 2048)
TCP: reno registered
NET: Registeredprotocol family 1
RPC: Registerednamed UNIX socket transport module.
RPC: Registeredudp transport module.
RPC: Registeredtcp transport module.
RPC: Registeredtcp NFSv4.1 backchannel transport module.
Trying to unpackrootfs image as initramfs...
rootfs image is notinitramfs (no cpio magic); looks like an initrd
Freeing initrdmemory: 4524k freed
jffs2: version2.2. (NAND) 漏 2001-2006 RedHat, Inc.
msgmni has beenset to 120
io scheduler noopregistered
io schedulerdeadline registered (default)
fa200a80.serial: ttyCPM0 at MMIO 0xc5064a80 (irq = 19) is a CPM UART
brd: moduleloaded
fc000000.flash:Found 1 x16 devices at 0x0 in16-bit bank. Manufacturer ID 0x000089 Chip ID 0x000018
Intel/SharpExtended Query Table at 0x0031
Intel/SharpExtended Query Table at 0x0031
Using bufferwrite method
cfi_cmdset_0001:Erase suspend on write enabled
4 ofpartpartitions found on MTD device fc000000.flash
Creating 4 MTDpartitions on "fc000000.flash":
0x000000000000-0x000000080000: "uboot"
0x000000080000-0x000000280000: "kernel"
0x000000280000-0x000000700000: "initrd"
0x000000700000-0x000001000000: "user"
eth0: fs_enet:00:30:bf:01:02:d2
eth1: fs_enet:00:3b:f5:21:69:6e
FEC MII Bus:probed
mdio_busfa200e00: error probing PHY at address 2
rtc-genericrtc-generic: rtc core: registered rtc-generic as rtc0
i2c /dev entries driver
TCP: cubicregistered
NET: Registeredprotocol family 17
rtc-genericrtc-generic: setting system clock to 1970-01-28 10:51:28 UTC (2371888)
RAMDISK: gzipimage found at block 0
VFS: Mounted root(ext2 filesystem) on device 1:0.
Freeing unusedkernel memory: 108k freed
Failed to execute/linuxrc. Attempting defaults...
内核移植当天就完成了,似乎很顺利呀,用于驱动也顺便重新编译,下到板上还跑了些用户程序,一切都很OK!