Dir:init.h #define __setup(str, fn) \ __setup_param(str, fn, fn, 0) #define __setup_param(str, unique_id, fn, early) \ static char __setup_str_##unique_id[] __initdata = str; \ static struct obs_kernel_param __setup_##unique_id \ __attribute_used__ \ __attribute__((__section__(".init.setup"))) \ __attribute__((aligned((sizeof(long))))) \ = { __setup_str_##unique_id, fn, early }
在init.h文件里,定义__setup等于__setup_param。那么在__setup_param的宏定义里,我们可以知道:它先定义了一个字符串,然后定义了一个结构体类型obs_kernel_param __setup。这个结构体的段属性为.init.setup,内容为一个字符串,一个函数,还有early。具备这个属性的结构体被链接脚本文件放到一起,从__setup_start到 __setup_end搜索调用。在vmlinux.lds中
__setup_start = .;
*(.init.setup)
__setup_end = .;
但是在Flash里没有分区,只能和uboot一样,将分区在代码里写死。一般在启动Linux的时候,Linux会自动打印出分区的信息。这里我的分区是这样的:
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit": 0x00000000-0x00040000 : "bootloader" 0x00040000-0x00060000 : "params" 0x00060000-0x00260000 : "kernel" 0x00260000-0x10000000 : "root"
我们搜索这个分区名 grep "\"bootloader\"" * -nR。在arch/arm/plat-s3c24xx中找到分区代码:
static struct mtd_partition smdk_default_nand_part[] = { [0] = { .name = "bootloader", .size = 0x00040000, .offset = 0, }, [1] = { .name = "params", .offset = MTDPART_OFS_APPEND, .size = 0x00020000, }, [2] = { .name = "kernel", .offset = MTDPART_OFS_APPEND, .size = 0x00200000, }, [3] = { .name = "root", .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, } };
就是这样,在处理完uboot传递的参数,进行CPU和单板的校验,挂载根文件系统等一系列操作后,最终内核执行init_post()中的应用程序。内核启动流程讲解完毕^_^
题外话:最近博主在自学Linux kernel和Linux device driver,感觉有难度。但是还是很有意义的,因为能够看到前辈的代码,心里真的很高兴。我就希望自己也能够修改Linux源代码,写出适合自己硬件的Linux系统。不仅如此,我还希望能够将自己的代码开源,分享给更多的人。完善Linux内核,让它变得更快更方便是博主的最终目标。博主会继续学习,然后把知识更好的分享给大家!