Linux可以将根文件系统编译进内核,称作initramfs。加载内核的时候,真实的内核和根文件系统都加载到内存。这在嵌入式系统中非常普遍,我们通常制作一个最小根文件系统initramfs,并把他编译进内核。而把其他的内容制作成其他的文件系统,系统启动时再挂载到根文件系统的某个根目录下。initramfs另外一个好处是,其可以和内核一起加载到内存,方便早期的调试。由于在内存中,所以一般只需要实现中断,时钟和串口就可以正常启动系统。
本文基于EasyLinux平台移植Linux系统到GT2440开发板上,EasyLinux平台是基于Buildroot定制的编译系统,详情可以参见《嵌入式Linux编译系统的设计》一文,我的内核版本为Linux3.18.6。
首先进行package的配置,在buildroot目录下:
make O=build/gt2440 menuconfig
选中cpio和initial ram filesystem linked into linux kernel。可以在cpio中定制根文件系统,这里暂不说明如何定制文件系统,只讲解如何制作一个initramfs。
然后配置内核:
make O=build/gt2440 linux-menuconfig
同样选中initramfs,至此,相关配置已经完成。只需要完成内核移植,即可以启动系统。要启动initramfs,需要至少实现中断,时钟和串口驱动。我用的GT2440实际上内核已经完全支持(mach-smdk2440),因此所做的工作非常少,只需要把时钟源修改成12MHz就好了。在mach-smdk2440.c中
static void __init smdk2440_init_time(void) { //s3c2440_init_clocks(16934400); s3c2440_init_clocks(12000000); samsung_timer_init(); }
此外,还需要把串口驱动编译进内核,我刚开始就是这里坑了一下:
这里说明一下如何确定console=xxxx名字,在drivers/tty/serial/samsung.c中s3c24xx_serial_probe函数
if (!s3c24xx_uart_drv.state) { ret = uart_register_driver(&s3c24xx_uart_drv); if (ret < 0) { pr_err("Failed to register Samsung UART driver\n"); return ret; } }这里注册了串口驱动,而驱动的名字在s3c24xx_uart_drv中
static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .driver_name = "s3c2410_serial", .nr = CONFIG_SERIAL_SAMSUNG_UARTS, .cons = S3C24XX_SERIAL_CONSOLE, .dev_name = S3C24XX_SERIAL_NAME, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, };S3C24XX_SERIAL_NAME为字符串ttySAC,则第一个串口为ttySAC0。
接下来就是编译了,事实上内核支持直接编译出uImage镜像,但本人测试发现,编出来的uImage镜像虽然可以正常启动系统,但是启动时打印内核是不压缩的,明明配置了内核是gzip压缩,原因不明。嵌入式系统通常需要节约flash空间,内核是必须要压缩的。因此,我决定先编译出普通的Image镜像,即不压缩的内核。然后自己压缩内核制作uImage镜像。
配置:
make O=build/gt2440 menuconfig
选custom内核镜像,名字为Image。即编译内核的时候target为Image。
编译:make O=build/gt2440
制作uImage镜像:
make O=build/gt2440 easylinux-mkimage
easylinux-mkimage: rm -rf $(TOPDIR)/image/* cp -rf $(BINARIES_DIR)/* $(TOPDIR)/image ./easylinux_mkimage.sh $(HOST_DIR) $(TOPDIR)/image
#!/bin/sh echo "gzip -9 Image" gzip -9 $2/Image $1/usr/bin/mkimage -A arm -O linux -T kernel -C gzip -a 0x30008000 -e 0x30008000 -n "easylinux" -d $2/Image.gz $2/uImageuboot启动参数设置:
bootargs=console=ttySAC0,115200n8 mem=62M
下载内核:
启动系统,注意这里,内核是gzip压缩的。
成功启动系统:
至此,我们只需要download到内存就完全启动了系统。
大家可以跳过uImage镜像的自己制作,直接编译出uImage镜像,也是可以启动的。我这里不知道什么原因,内核总是不会压缩,知道的朋友可以告诉我。
附一个我自己直接编译uImage镜像的截图,内核是非压缩的。(内核是有配置CONFIG_KERNEL_GZIP的)