src目录下有一个配置文件,内核下有一个配置文件,第二个文件并不是动态生成的,根据Makefile的规则,当编译内核时,如果找不到.config文件,会从congfigs目录下把其中一个config文件拷贝出来使用。
src目录下make clean时会把kernel下的.config文件一并清理掉。所以,如果在kernel上自己做了特殊配置,在src下make clean后,内核需要重新配置。
在编译的后期,常会遇到LD(链接)错误,这往往是因为某个源文件中用到了某个外部函数,此函数没有被实现。
include\linux\autoconf.h 里面是配置宏的汇总,是系统自动生成的文件。
/*
* Automatically generated C config: don't edit
* Linux kernel version: 2.6.29
* Tue May 18 23:52:27 2010
*/
#define AUTOCONF_INCLUDED
#define CONFIG_PANIC_DUMP 1
#define CONFIG_VIDEO_V4L1_COMPAT 1
#define CONFIG_HID_CHERRY 1
#define CONFIG_MTD_NAND_PXA3xx_DMA 1
#define CONFIG_FRAME_WARN 1024
#define CONFIG_COMPAT_BRK 1
#define CONFIG_JFFS2_CMODE_PRIORITY 1
#define CONFIG_FB_PXA_DOUBLE_BUFFER 1
在嵌入式系统中我们通常所使用的Linux内核镜像是由两部分组成的:
一部分是经过压缩的真正linux内核,另一部分是用来进行解压缩的代码(head.S、misc.c)。
在Bootloader将内核镜像加载到内存后,跳转到内核运行的入口点是在linux\arch\arm\boot\compressed\Head.S,
Head.S中调用了解压缩内核的操作,启用虚拟内存等操作,最后跳转到 init\main.c kernel_init函数开始真正启动内核。
如果在kernel_init中在控制台还未初始化之前就出现问题,那log就会打不出来,即printk函数无法成功输出log(一般是输出到串口),
此问题可以通过linux目录下make menuconfig,启用kernel hacking - Kernel low-level debugging functions/enable boot log for system bring up解决。
其实质是启用了宏CONFIG_DEBUG_EARLY_PRINTK,也可以直接在代码中将此宏启用。
kernel/printk.c中vprink函数中有如下代码:
#ifdef CONFIG_DEBUG_EARLY_PRINTK
/* It can be used when some module's init does not work */
extern void printascii(const char *);
if (!disable_early_printk)
printascii(printk_buf);
#endif
在kernel_init -> init_post 中调用run_init_process(ramdisk_execute_command) 转到ramdisk中的/init程序执行,即Linux kernel的第一个进程。
init会解析init.rc,创建设备驱动等一系列动作。
移植一般需要注意下面几部分:
(1)开发板描述信息
例如:arch\arm\mach-pxa\g80a.c中
MACHINE_START(G80, "AMUNDSEN handheld Platform (G80 Rev C)")
.phys_io = 0x40000000,
.boot_params = 0xa0000100,
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.map_io = pxa_map_io,
.init_irq = pxa3xx_init_irq,
.timer = &pxa_timer,
.init_machine = kt850_init,
MACHINE_END
kt850_init中对GPIO、I2C、LCD、irq、nand等进行了初始化。
(2)修改NandFlash分区信息
例如:include\asm-arm\arch-pxa\part_table.h
static struct mtd_partition __attribute__((unused))
Android_512m_v75_partitions[] = {
[0] = {
.name = "Bootloader",
.offset = 0,
.size = 0x100000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
[1] = {
.name = "NVM",
.offset = 0x100000,
.size = 0x020000,
},
[2] = {
.name = "Arbel and Greyback Image",
.offset = 0x120000,
.size = 0x800000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
[3] = {
.name = "Kernel",
.offset = 0x920000,
.size = 0x300000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
[4] = {
.name = "system",
.offset = 0x0c20000,
.size = 0x4000000, /* mount 64M fs */
},
[5] = {
.name = "userdata",
.offset = 0x04c20000,
.size = 0x1ad60000, /* mount 432.375M fs */
},
[6] = {
.name = "reserved",
.offset = 0x1f980000,
.size = 0x00100000, /* 1M */
},
};
(3)make menuconfig进行定制
其中包含检查Boot Options
console=ttyS0,115200 mem=240M comm_v75 uart_dma lpj=2416640
(4)修改相关Makefile
顶层makefile:交叉编译器及Arch修改
ARCH = arm,CROSS_COMPILER = arm-liunx-
arch\arm\Makefile
arch\arm\mach-pxa\Makefile
arch\arm\boot\Makefile
arch\arm\boot\compressed\Makefile
在arch/arm/boot/Makefile中
ZRELADDR是指kernel要被解压缩到哪里,解压缩完成后会跳转到ZRELADDR。
arch\arm\mach-pxa\Makefile.boot中定义了zreladdr-y
zreladdr-y := 0x80008000