目录
一、内核框架介绍及简单修改
linux内核下载地址:https://www.kernel.org/,这里移植linux3.4.2版本,u-boot是bootloader最常用的一种,对于u-boot会先将内核拷贝到内存中,设置TAG参数,然后调用函数启动内核(函数的参数:R0=0 R1=机器ID R2=TAG参数地址),内核过程:
根据R1,判断能否支持该机器,调用机器相关的初始化函数
解析TAG参数
装载驱动程序(网卡、Flash等)
挂接根文件系统
启动应用程序
编译内核步骤
tar xjf linux-3.4.2.tar.bz2
在顶层makefile中修改ARCH
ARCH ?= arm //注意不能加空格 不然编译的时候会提示不认识
CROSS_COMPILE ?= arm-linux-
配置文件在arch/arm/configs中其中有s3c2410_defconfig
make s3c2410_defconfig //会生成.config
make uImage
建立一个source insight工程来查阅内核源码,建立步骤,过程如下
- 对于arch是各种CPU先整个去掉我们只关心里面的arm目录,在arm中boot至lib目录通用的就全部加进去(add tree),添加mach-s3c2410、2440、24xx;Mm到Oprofile目录看起来通用;还有plat-s3c24xx平台;plat-samsung;还有makefile
- 同步
首先在u-boot目录中bootm.c有以下语句,表示在启动参数中设置machid环境变量,内核首先会先判断该机器ID是否被内核支持,不然就会根据默认设置mach ID来启动内核
s = getenv("machid");
对于smdk2440,uboot的默认mach ID在smdk2410.c中,其宏定义为193
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
这些机器ID在内核目录arch/arm中,首先设置环境变量机器ID为随机值,启动内核,内核提示支持的机器ID,其中包含有SMDK2440提示ID为16a,这里后续需要裁减内核,支持的多中机器会导致内核庞大,对于16a对应的文件为内核目录中mach-smdk2440.c,根据ID找到对应的结构体,然后调用里面的初始化函数,在u-boot设置机器ID为16a,同时设置波特率
set machid 16a
bootargs=console=ttySAC0,115200 root=/dev/mtdblock3
用新内核启动发现依然乱码,最后原因是在内核根据机器ID调用各种初始化,其中时钟频率不对应,对于S3C2440,晶振是12M来说,修改arch\arm\mach-s3c24xx\mach-smdk2440.c
s3c24xx_init_clocks(16934400);
改为
s3c24xx_init_clocks(12000000);
二、移植内核
修改分区并且制作根文件系统
启动内核信息提示包含有八个分区,需要进一步修改代码,在内核源码中搜索grep "\"Boot\ Agent\"" * -nR(\:转义,用双引号和空格的本来含义),搜索到common-smdk.c,修改nand分区为之前u-boot分区好的大小,u-boot分区好的大小参考移植新u-boot,其中MTDPART_OFS_APPEND宏表示紧接着,MTDPART_SIZ_FULL宏表示剩下的
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "bootloader",
.size = SZ_256K,
.offset = 0,
},
[1] = {
.name = "params",
.offset = MTDPART_OFS_APPEND,
.size = SZ_128K,
},
[2] = {
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = SZ_4M,
},
[3] = {
.name = "rootfs",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
用yaffs2文件系统进行挂接,在启动内核的信息中时候发现挂接失败,在配置文件.config中搜索YAFFS,发现没有支持yaffs,而搜索jffs2就有
nfs 30000000 192.168.0.106:/work/nfs_root/fs_mini_mdev.yaffs2; nand erase.part rootfs; nand write.yaffs 30000000 260000 $filesize //烧写的时候文件的大小会存放在filesize这个环境变量中对于之前的u-boot需要加上括号,新版u-boot不需要加括号
nfs 32000000 192.168.0.106:/work/nfs_root/uImage_new; bootm 32000000
----------------------------------------------------------------------------------------------------------------------
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,3)
Backtrace:
因此我们尝试用jffs2文件系统来挂接,在内核启动信息中提示没有找到init进程,内核最终目的是去启动应用程序,对于内核启动后只会去启动t第一个应用程序,然后这个应用程序会根据配置文件来启动哪个应用程序
nfs 30000000 192.168.0.106:/work/nfs_root/fs_mini_mdev_new.jffs2; nand erase.part rootfs; nand write.jffs2 30000000 260000 $filesize
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
nfs 32000000 192.168.0.106:/work/nfs_root/uImage_new; bootm 32000000
-----------------------------------------------------------------------------------------
Kernel panic - not syncing: No init found. Try passing init= option to kernel. See Linux Documentation/init.txt for guidance.
自己来构建linux根文件系统
首先安装busybox-1.20.0,在README中解释了用CONFIG_PREFIX来指定安装目录
tar xjf busybox-1.20.0.tar.bz2
cd busybox-1.20.0/
make menuconfig
在编译选项中加上交叉编译的前缀:arm-linux-
Busybox Settings->Build Options->Cross compiler prefix
使用默认的配置make
make install CONFIG_PREFIX=/work/nfs_root/fs_mini_mdev_new
添加C库,从gcc编译器中添加到fs_mini_mdev_new
book:/work/nfs_root/fs_mini_mdev_new$ mkdir lib
book:/work/nfs_root/fs_mini_mdev_new$ mkdir /work/nfs_root/fs_mini_mdev_new/usr/lib -p //这里加上-p选项,usr/lib两个目录一起创建
book:/usr/local/arm/4.3.2$ cd /work/system/busybox-1.20.0/
book:/work/system/busybox-1.20.0$ echo $PATH
/home/book/bin:/home/book/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin:/snap/bin
book:/work/system/busybox-1.20.0$ cd /usr/local/arm/4.3.2/bin
book:/usr/local/arm/4.3.2/bin$ cd ..
book:/usr/local/arm/4.3.2$ find -name lib
./lib
./arm-none-linux-gnueabi/libc/usr/lib
./arm-none-linux-gnueabi/libc/thumb2/usr/lib
./arm-none-linux-gnueabi/libc/thumb2/lib
./arm-none-linux-gnueabi/libc/lib
./arm-none-linux-gnueabi/libc/armv4t/usr/lib
./arm-none-linux-gnueabi/libc/armv4t/lib
./arm-none-linux-gnueabi/lib
book:/usr/local/arm/4.3.2$ cp /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/*so* /work/nfs_root/fs_mini_mdev_new/lib -d
book:/usr/local/arm/4.3.2$ cp /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/usr/lib/*so* /work/nfs_root/fs_mini_mdev_new/usr/lib -d
添加etc目录,内核启动的第一个进程会先打开etc/inittab,根据inittab会执行/etc/init.d/rcS脚本,在rcS脚本中有句mount -a,会根据/etc/fstab的内容来挂接各种根文件系统,而mdev -s会自动创建dev中的内容
book@www.100ask.org:/work/nfs_root/fs_mini_mdev_new/etc$ cat inittab
#/etc/inittab
console::askfirst:-/bin/sh
::sysinit:/etc/init.d/rcS
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
book@www.100ask.org:/work/nfs_root/fs_mini_mdev_new/etc$ cat init.d/rcS
#mount -t proc none /proc
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
if [ | -e /etc/pointercal ]
then
/bin/ts_cal.sh
fi
#/bin/qpe.sh &
book@www.100ask.org:/work/nfs_root/fs_mini_mdev_new/etc$ cat fstab
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
创建dev目录,首先需要创建console和null节点,并且创建其他目录
book:/work/nfs_root/fs_mini_mdev_new/dev$ sudo mknod console c 5 1
book:/work/nfs_root/fs_mini_mdev_new/dev$ sudo mknod null c 1 3
book:/work/nfs_root/fs_mini_mdev_new$ mkdir proc tmp mnt sys root
制作为jffs文件系统
mkfs.jffs2 -n -s 2048 -e 128KiB -d fs_mini_mdev_new -o fs_mini_mdev_new.jffs2
利用新的jffs文件系统,新的uImage启动,在内核信息中提示init进程被杀死
烧写:
nfs 30000000 192.168.0.106:/work/nfs_root/fs_mini_mdev_new.jffs2
nand erase.part rootfs
nand write.jffs2 30000000 260000 $filesize
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
nfs 32000000 192.168.0.106:/work/nfs_root/uImage_new
bootm 32000000
-------------------------------------------------------------
内核启动信息
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
对于arm-linux-gcc的版本中支持eabi接口,对于内核需要配置支持eabi接口,在配置内核中搜索EABI,将其编译进入内核,利用新内核启动就没问题了
修改内核支持yaffs文件系统
yaffs比jffs2更适合nand flash,获得yaffs源码,在git上获得源码,如果没有git,需要先下载git
sudo apt-get install git
git clone git://www.aleph1.co.uk/yaffs2
获得源码后README-linux中有介绍怎么打补丁
cd yaffs-dir
./patch-ker.sh c m linux-tree
在内核目录下打补丁
book:yaffs2$ ./patch-ker.sh c m /work/system/linux-3.4.2
Updating /work/system/linux-3.4.2/fs/Kconfig
Updating /work/system/linux-3.4.2/fs/Makefile
然后再内核中配置yaffs
用mkyaffs2image工具制作之前制作的根文件系统为yaffs2格式的文件系统,在此之前还需要修改u-boot的bug,在u-boot目录drivers/mtd/nand/nand_util.c下修改为以下
518 if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags & WITH_YAFFS_OOB)) {
519 rval = nand_write (nand, offset, length, buffer);
520 if (rval == 0)
521 return 0;
522
内核裁剪制作补丁
一开始有说到内核中有支持很多单板,我们可以根据配置文件.config,在配置内核总取消器编译进内核,还有其他功能的需求,看个人需要是否编译进内核
制作补丁,.config复制为config_ok
make distclean
mv linux-3.4.2 linux-3.4.2_100ask
tar xjf linux-3.4.2.tar.bz2
利用diff工具来生成补丁文件
diff -urN linux-3.4.2 linux-3.4.2_100ask > linux-3.4.2_100ask.patc
利用补丁直接使用新内核
patch -p1 < ../linux-3.4.2_100ask.patch
cp config_ok .config
make uImage
制作了u-boot_new.bin, uImage_new, fs_mini_mdev_new.yaffs,重烧整个系统,使用jtag工具烧u-boot_new.bin或使用uboot来更新自己
tftp 30000000 u-boot_new.bin; nand erase.part u-boot; nand write 30000000 u-boot
启动uboot,用它来烧写内核、FS
tftp 30000000 uImage_new; nand erase.part kernel; nand write 30000000 kernel
tftp 30000000 fs_mini_mdev_new.yaffs2; nand erase.part rootfs; nand write.yaffs 30000000 260000 $filesize
设置参数
set 'nand read 30000000 kernel;bootm 30000000'
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 //可能出现挂接失败就加上rootfstype=yaffs
set machid 16a
save
boot