笔记第10课内核启动流程
2013-07-23 02:21
225 查看
pc机上建立查看内核文档的source insight工程:
1、建立新工程:
1、在内核目录下新建一个”si“的文件夹,source insight工程数据全部存放在里面。
E:\colin weidongshan\colin_kernel\transplant\linux-2.6.22.6_jz2440\linux-2.6.22.6\si
2、添加文件到SI工程
1、点击"Add All",选中“Include top level sub-directories”和“Recursively add lower sub-directories”点击“OK”
2、选中“Arch”目录,点击“Remove Tree”,去掉总个目录
进入“Arch\Arm\选中"Boot"、"Common"、"Configs"、"Kernel"、"Lib"、"Mm"、"Nwfpe"、"Oprofile"、"Plat-s3c24xx"、"Tools"、"Vfp"目录,点击"Add Tree"
进入“Arch\Arm\Mach-s3c2440\”,点击"Add All",也可以加“Arch\Arm\Mach-s3c2410\”
3、选中“Include”目录,点击“Remove Tree”,去掉总个目录
进入“Include\”,单击选中"Acpi"、"Asm-generic"、"Config"、"Crypto"、"Keys"、"Linux"、"Math-emu"、"Media"、"Mtd"、"Net"、"Pcmcia"、"Rdma"、"Rxrpc"、"Scsi"、"Sound"、"Video",点击"Add Tree"
进入“Include\Asm-arm\”,点击"Add All",去掉“Include top level sub-directories”和“Recursively add lower sub-directories”前面的勾,表示只加顶层目录的文件
进入“Include\Asm-arm\”,单击选中"Hardware"、"Mach"、"Plat-s3c24xx",点击"Add Tree"
进入“Include\Asm-arm\Arch-s3c2410\”,点击"Add All"
4、同步文件,完成
第10课第1节 内核启动流程分析之编译体验
首先通过cuteftp把”linux-2.6.22.6_jz2440.patch“和”linux-2.6.22.6.tar.bz2“拷贝到/work/system目录下
解压缩: book@book-desktop:/work/system$ tar xjf linux-2.6.22.6.tar.bz2
book@book-desktop:/work/system$ cd linux-2.6.22.6/
打补丁: book@book-desktop:/work/system/linux-2.6.22.6$ patch -p1 < ../linux-2.6.22.6_jz2440.patch
编译之前:把文件拷出来按上面的方法建立查看内核文档的source insight工程,方便查看内核文件;
book@book-desktop:/work/system/linux-2.6.22.6$ make clean
book@book-desktop:/work/system/linux-2.6.22.6$ cd ..
book@book-desktop:/work/system$ tar cjf linux-2.6.22.6_jz2440.tar.bz2 linux-2.6.22.6
然后用cuteftp把”linux-2.6.22.6_jz2440.tar.bz2“文件拖到windows下面来,接下来就是在windows下面建立source insight工程了
配置: 有3种方法--->a、make menuconfig b、使用默认的配置在上面修改 c、使用厂家提供的配置文件
对于b:
1、book@book-desktop:/work/system/linux-2.6.22.6$ find -name "*defconfig*" 查找默认配置可以发现默认配置在././arch/arm/configs/下
2、在该目录下找到相似的配置文件xxx_defconfig,执行make xxx_defconfig,执行的结果保存在.config下面
3、然后再执行make menuconfig,这里就是读出上面的.config
对于c:厂家提供的配置文件是config_ok
book@book-desktop:/work/system/linux-2.6.22.6$ cp config_ok .config
book@book-desktop:/work/system/linux-2.6.22.6$ make menuconfig
编译: 编译直接make就行了,但是我们想生成uImage,我们要用make uImage
book@book-desktop:/work/system/linux-2.6.22.6$ make uImage
编译成功后会在:/work/system/linux-2.6.22.6/arch/arm/boot下面生成”uImage“,用cuteftp把”uImage“拷贝到windows进行烧写。
烧写内核: 条件是已经烧写了好u-boot,以前移植好的可以烧写进mini2440的文件在E:\colin weidongshan\colin_kernel\transplant下
1、启动u-boot,接上USB线,会发现新设备,安装驱动程序(\百问网JZ2440v2主光盘\windows\drivers\dnw)
安装完后会在设备管理器”通用串行总线控制器“里面看到:100ASK eBlocks SEC SOC Test Board
2、输入k后,打开dnw软件,发送编译好的内核
Enter your selection: k
USB host is connected. Waiting a download.
启动内核: Enter your selection: b
补充技巧:
1、删掉根文件系统:OpenJTAG> nand erase rootfs
2、如果要删掉uboot的启动参数,用:OpenJTAG> nand erase 。这条命令会把整个NAND Flash都擦除掉
刚刚那个问题解决了,就是用nand erase这个命令把整个nandflash都擦除掉,因为环境参数是存储在nandflash里面,
下载的uboot可能是先去读nandflash里面的参数,而不是先使用默认的参数,所以uboot重新烧写的话,
烧写内核之前一定要先擦除nandflash,可能这个uboot里面没有擦掉存储环境变量的部分
第10课第2节 内核启动流程分析之配置
一:配置的结果是生成了".config"文件
book@book-desktop:/work/system/linux-2.6.22.6$ vi .config
下面以一个配置项为例:CONFIG_DM9000=y或=M
book@book-desktop:/work/system/linux-2.6.22.6$ grep "CONFIG_DM9000" * -nwR
1、C源码:里面有“CONFIG_DM9000” :肯定是宏--->来源于下面第4点include/linux/autoconf.h
2、子目录makefile:drivers/net/Makefile :子目录下面的"CONFIG_DM9000"是由下面第3点include/config/auto.conf 定义的
3、include/config/auto.conf :这个里面的内容来源于".config"文件,make机制根据".config"文件自动生成的。“include/config/auto.conf”文件是被顶层的makefile包含的
4、include/linux/autoconf.h :这个里面的内容来源于".config"文件,make机制根据".config"文件自动生成的
对于第4点查看一下:
book@book-desktop:/work/system/linux-2.6.22.6$ vi include/linux/autoconf.h
可以看到在这个头文件里面:#define CONFIG_DM9000 1
对于第2点查看一下:
book@book-desktop:/work/system/linux-2.6.22.6$ vi drivers/net/Makefile
可以看到在这个makefile文件里面:obj-$(CONFIG_DM9000) += dm9dev9000c.o
插讲一下子目录makefile:由此可以看见y和m的差别就是在上面第2条子目录下体现的
obj-y += xxx.o --->表示xxx.c的文件最后会编译进内核里面
obj-m += yyy.o --->表示yyy.c的文件最后会编译成可加载的模块yyy.ko
对于第3点查看一下:
book@book-desktop:/work/system/linux-2.6.22.6$ vi include/config/auto.conf
可以看到在这个文件里面: CONFIG_DM9000=y
总结:
a、当我们配置的时候生成了".config"文件
b、当我们make uImage是有哪些事情发生:
1、.config自动生成了autoconf.h,而“autoconf.h”文件是被源代码使用的
2、.config自动生成了auto.conf,而“auto.conf”文件是被顶层makefile包含的,子目录下面的makefile用得着“auto.conf”
这一段的流程分析:由".config"文件生成了“include/linux/autoconf.h”(内容:#define CONFIG_DM9000 1),即就是说不管".config"文件里面的配置项
CONFIG_DM9000=y还是CONFIG_DM9000=M,在“include/linux/autoconf.h”这里全部变成了#define CONFIG_DM9000 1,定义为1之后我们的c
语言源文件就可以使用这个宏#define CONFIG_DM9000 1。
那么".config"文件里面的配置项CONFIG_DM9000=y还是CONFIG_DM9000=M这个差别在哪里体现呢?既然在c语言源文件里面体现不出来,则就是
在子目录makefile里面体现,如在drivers/net/Makefile里面有obj-$(CONFIG_DM9000) += dm9dev9000c.o
那么子目录makefile里面如:obj-$(CONFIG_DM9000) += dm9dev9000c.o里面的CONFIG_DM9000是由谁来定义的呢?显然是由include/config/auto.conf里面
CONFIG_DM9000=y 来定义
而include/config/auto.conf也是来源于".config"文件。include/config/auto.conf是被顶层的makefile包含的
第10课第3节 内核启动流程分析之Makefile
二:分析Makefile:第一个文件、链接脚本
1、子目录下面的makefile:
obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
obj-m += s3c24xx_leds.o
2、make uImage,发现uImage位于:linux-2.6.22.6_jz2440\linux-2.6.22.6\arch\arm\makefile
可以肯定上面的这个makefile会被包含在顶层的makefile里面,我们搜索顶层makefile发现里面有:include $(srctree)/arch/$(ARCH)/Makefile
在上一节的分析中,我们看到.config文件生成了autoconf.h和auto.conf
我们搜索一下顶层的makefile:-include include/config/auto.conf
在linux-2.6.22.6_jz2440\linux-2.6.22.6\arch\arm\makefile下可以看到uImage有关的一行:zImage Image xipImage bootpImage uImage: vmlinux,所以uImage依赖于vmlinux
在顶层makefile里面linux-2.6.22.6_jz2440\linux-2.6.22.6\makefile搜索vmlinux可以看到:all: vmlinux
zImage Image xipImage bootpImage uImage: vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
vmlinux-init := $(head-y) $(init-y)
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
init-y := init/
init-y := $(patsubst %/, %/built-in.o, $(init-y))即=init/built-in.o
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-y))
=usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o
libs-y := lib/
llibs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
=lib/lib.a lib/built-in.o
drivers-y := drivers/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
=drivers/built-in.o sound/built-in.o
net-y := net/
net-y := $(patsubst %/, %/built-in.o, $(net-y))
=net/built-in.o
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
走捷径分析linux:
book@book-desktop:/work/system/linux-2.6.22.6$ rm vmlinux
book@book-desktop:/work/system/linux-2.6.22.6$ make uImage V=1
arm-linux-ld -EL -p --no-undefined -X -o vmlinux
-T arch/arm/kernel/vmlinux.lds //链接脚本
arch/arm/kernel/head.o arch/arm/kernel/init_task.o //第一个文件,下面的都是原材料
init/built-in.o
--start-group usr/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o
arch/arm/mach-s3c2410/built-in.o arch/arm/mach-s3c2400/built-in.o arch/arm/mach-s3c2412/built-in.o arch/arm/mach-s3c2440/built-in.o
arch/arm/mach-s3c2442/built-in.o arch/arm/mach-s3c2443/built-in.o arch/arm/nwfpe/built-in.o arch/arm/plat-s3c24xx/built-in.o
kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o
arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o
第10课第4节 内核启动流程分析之内核启动
一、创建si工程,按前面讲的
二、内核:
A、处理u-boot传入的参数,从arch/arm/kernel/head.s开始跟踪进来
0、判断是否支持这个cpu
1、判断是否支持这个单板,uboot启动内核时传人的机器ID(theKernel (0, bd->bi_arch_number, bd->bi_boot_params);)
在arch/arm/kernel/head.s下:
bl __lookup_machine_type @ r5=machinfo
进入__lookup_machine_type由此引出了
在arch/arm/kernel/vmlinux.lds //链接脚本
__arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;
在内核里面搜索:
book@book-desktop:/work/system/linux-2.6.22.6$ grep ".arch.info.init" * -nR
在arch.h里面有:
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
展开宏
static const struct machine_desc __mach_desc_S3C2440 \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_S3C2440, \
.name = "SMDK2440",
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
};
2、建立页表
3、使能MMU
4、跳到我们内核的第一个c函数:start_kernel,这个函数会处理(theKernel (0, bd->bi_arch_number, bd->bi_boot_params);)里面的启动参数
B、挂接根文件系统
C、最终目的:运行应用程序
内核的启动流程:
arch/arm/kernel/head.s
start_kernel
setup_arch(&command_line); //解析uboot传入的参数
setup_command_line(command_line); //解析uboot传入的参数
parse_early_param
do_early_param
从__setup_start到__setup_end,调用early函数
unknown_bootoption
obsolete_checksetup
从__setup_start到__setup_end,调用非early函数
rest_init();
kernel_init
prepare_namespace();
mount_root();//挂接根文件系统
init_post();
//执行应用程序
三、Uboot传入的命令行参数的处理
1、说明:对于下面两个函数只不过是把Uboot传入的命令行参数记录下来而已
setup_arch(&command_line); //解析uboot传入的参数
setup_command_line(command_line); //解析uboot传入的参数
我们在prepare_namespace();这个函数的时候它肯定得先确定你挂接的是哪一个文件系统:命令行参数root=/dev/mtdblock3指定
在这个函数里面可以看到ROOT_DEV = name_to_dev_t(root_device_name);
由于if (saved_root_name[0]) {
root_device_name = saved_root_name;
if (!strncmp(root_device_name, "mtd", 3)) {
mount_block_root(root_device_name, root_mountflags);
goto out;
}
ROOT_DEV = name_to_dev_t(root_device_name);
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5;
}
在SI里面全局查找saved_root_name在哪里定义,可以搜索到一个函数和一个宏:
static int __init root_dev_setup(char *line)
{
strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
__setup("root=", root_dev_setup);
由这个宏我们可以大胆的估计,在解析命令行的时候发现了root=***,然后以它找到root_dev_setup这个函数,然后调用这个
函数,这个函数把root=***后面的***保存到变量saved_root_name里面去。
2、下面再分析__setup("root=", root_dev_setup);怎么执行:
在SI里面全局查找__setup在哪里定义,技巧先查找,再在结果里面搜索define
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
再搜索__setup_param
#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 }
我们把__setup("root=", root_dev_setup)展开,可以分析这个就是定义了如同上面的结构体,这个结构体里面有3个重要的成员
①名字"root=" ②函数root_dev_setup③early
而且__setup("root=", root_dev_setup)定义的结构体有一个特殊的属性:__attribute__((__section__(".init.setup"))),显然
".init.setup"在链接脚本里面
__setup_start = .;
*(.init.setup)
__setup_end = .;
搜索一下__setup_start就可以知道命令行是怎么调用的了,在两个函数里面被调用:
①函数obsolete_checksetup
②函数do_early_param,这个应该就是对应上面的__setup_str_##unique_id, fn, early 里面的early了。
再找一下do_early_param是谁调用:
parse_early_param
由于我们传入的参数early是0.很显然我们用的是①函数obsolete_checksetup
如下调用过程:
parse_early_param
do_early_param
从__setup_start到__setup_end,调用early函数
①函数obsolete_checksetup它被unknown_bootoption调用,搜索这个函数得:它被start_kernel函数调用。
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
如下调用过程:
unknown_bootoption
obsolete_checksetup
从__setup_start到__setup_end,调用非early函数
四、分区表
如果启动参数不是下面这个,则要设置启动参数:
set bootargs noinitrd root=/dev/mtdblock3 rootfstype=jffs2 init=/linuxrc console=ttySAC0
启动linux后,可以看到启动时会显示分区表:
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
book@book-desktop:/work/system/linux-2.6.22.6$ grep ".arch.info.init" * -nR
分区应该在arch/arm/plat-s3c24xx/common-smdk.c里面
/* NAND parititon from 2.4.18-swl5 */
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,
}
};
1、建立新工程:
1、在内核目录下新建一个”si“的文件夹,source insight工程数据全部存放在里面。
E:\colin weidongshan\colin_kernel\transplant\linux-2.6.22.6_jz2440\linux-2.6.22.6\si
2、添加文件到SI工程
1、点击"Add All",选中“Include top level sub-directories”和“Recursively add lower sub-directories”点击“OK”
2、选中“Arch”目录,点击“Remove Tree”,去掉总个目录
进入“Arch\Arm\选中"Boot"、"Common"、"Configs"、"Kernel"、"Lib"、"Mm"、"Nwfpe"、"Oprofile"、"Plat-s3c24xx"、"Tools"、"Vfp"目录,点击"Add Tree"
进入“Arch\Arm\Mach-s3c2440\”,点击"Add All",也可以加“Arch\Arm\Mach-s3c2410\”
3、选中“Include”目录,点击“Remove Tree”,去掉总个目录
进入“Include\”,单击选中"Acpi"、"Asm-generic"、"Config"、"Crypto"、"Keys"、"Linux"、"Math-emu"、"Media"、"Mtd"、"Net"、"Pcmcia"、"Rdma"、"Rxrpc"、"Scsi"、"Sound"、"Video",点击"Add Tree"
进入“Include\Asm-arm\”,点击"Add All",去掉“Include top level sub-directories”和“Recursively add lower sub-directories”前面的勾,表示只加顶层目录的文件
进入“Include\Asm-arm\”,单击选中"Hardware"、"Mach"、"Plat-s3c24xx",点击"Add Tree"
进入“Include\Asm-arm\Arch-s3c2410\”,点击"Add All"
4、同步文件,完成
第10课第1节 内核启动流程分析之编译体验
首先通过cuteftp把”linux-2.6.22.6_jz2440.patch“和”linux-2.6.22.6.tar.bz2“拷贝到/work/system目录下
解压缩: book@book-desktop:/work/system$ tar xjf linux-2.6.22.6.tar.bz2
book@book-desktop:/work/system$ cd linux-2.6.22.6/
打补丁: book@book-desktop:/work/system/linux-2.6.22.6$ patch -p1 < ../linux-2.6.22.6_jz2440.patch
编译之前:把文件拷出来按上面的方法建立查看内核文档的source insight工程,方便查看内核文件;
book@book-desktop:/work/system/linux-2.6.22.6$ make clean
book@book-desktop:/work/system/linux-2.6.22.6$ cd ..
book@book-desktop:/work/system$ tar cjf linux-2.6.22.6_jz2440.tar.bz2 linux-2.6.22.6
然后用cuteftp把”linux-2.6.22.6_jz2440.tar.bz2“文件拖到windows下面来,接下来就是在windows下面建立source insight工程了
配置: 有3种方法--->a、make menuconfig b、使用默认的配置在上面修改 c、使用厂家提供的配置文件
对于b:
1、book@book-desktop:/work/system/linux-2.6.22.6$ find -name "*defconfig*" 查找默认配置可以发现默认配置在././arch/arm/configs/下
2、在该目录下找到相似的配置文件xxx_defconfig,执行make xxx_defconfig,执行的结果保存在.config下面
3、然后再执行make menuconfig,这里就是读出上面的.config
对于c:厂家提供的配置文件是config_ok
book@book-desktop:/work/system/linux-2.6.22.6$ cp config_ok .config
book@book-desktop:/work/system/linux-2.6.22.6$ make menuconfig
编译: 编译直接make就行了,但是我们想生成uImage,我们要用make uImage
book@book-desktop:/work/system/linux-2.6.22.6$ make uImage
编译成功后会在:/work/system/linux-2.6.22.6/arch/arm/boot下面生成”uImage“,用cuteftp把”uImage“拷贝到windows进行烧写。
烧写内核: 条件是已经烧写了好u-boot,以前移植好的可以烧写进mini2440的文件在E:\colin weidongshan\colin_kernel\transplant下
1、启动u-boot,接上USB线,会发现新设备,安装驱动程序(\百问网JZ2440v2主光盘\windows\drivers\dnw)
安装完后会在设备管理器”通用串行总线控制器“里面看到:100ASK eBlocks SEC SOC Test Board
2、输入k后,打开dnw软件,发送编译好的内核
Enter your selection: k
USB host is connected. Waiting a download.
启动内核: Enter your selection: b
补充技巧:
1、删掉根文件系统:OpenJTAG> nand erase rootfs
2、如果要删掉uboot的启动参数,用:OpenJTAG> nand erase 。这条命令会把整个NAND Flash都擦除掉
刚刚那个问题解决了,就是用nand erase这个命令把整个nandflash都擦除掉,因为环境参数是存储在nandflash里面,
下载的uboot可能是先去读nandflash里面的参数,而不是先使用默认的参数,所以uboot重新烧写的话,
烧写内核之前一定要先擦除nandflash,可能这个uboot里面没有擦掉存储环境变量的部分
第10课第2节 内核启动流程分析之配置
一:配置的结果是生成了".config"文件
book@book-desktop:/work/system/linux-2.6.22.6$ vi .config
下面以一个配置项为例:CONFIG_DM9000=y或=M
book@book-desktop:/work/system/linux-2.6.22.6$ grep "CONFIG_DM9000" * -nwR
1、C源码:里面有“CONFIG_DM9000” :肯定是宏--->来源于下面第4点include/linux/autoconf.h
2、子目录makefile:drivers/net/Makefile :子目录下面的"CONFIG_DM9000"是由下面第3点include/config/auto.conf 定义的
3、include/config/auto.conf :这个里面的内容来源于".config"文件,make机制根据".config"文件自动生成的。“include/config/auto.conf”文件是被顶层的makefile包含的
4、include/linux/autoconf.h :这个里面的内容来源于".config"文件,make机制根据".config"文件自动生成的
对于第4点查看一下:
book@book-desktop:/work/system/linux-2.6.22.6$ vi include/linux/autoconf.h
可以看到在这个头文件里面:#define CONFIG_DM9000 1
对于第2点查看一下:
book@book-desktop:/work/system/linux-2.6.22.6$ vi drivers/net/Makefile
可以看到在这个makefile文件里面:obj-$(CONFIG_DM9000) += dm9dev9000c.o
插讲一下子目录makefile:由此可以看见y和m的差别就是在上面第2条子目录下体现的
obj-y += xxx.o --->表示xxx.c的文件最后会编译进内核里面
obj-m += yyy.o --->表示yyy.c的文件最后会编译成可加载的模块yyy.ko
对于第3点查看一下:
book@book-desktop:/work/system/linux-2.6.22.6$ vi include/config/auto.conf
可以看到在这个文件里面: CONFIG_DM9000=y
总结:
a、当我们配置的时候生成了".config"文件
b、当我们make uImage是有哪些事情发生:
1、.config自动生成了autoconf.h,而“autoconf.h”文件是被源代码使用的
2、.config自动生成了auto.conf,而“auto.conf”文件是被顶层makefile包含的,子目录下面的makefile用得着“auto.conf”
这一段的流程分析:由".config"文件生成了“include/linux/autoconf.h”(内容:#define CONFIG_DM9000 1),即就是说不管".config"文件里面的配置项
CONFIG_DM9000=y还是CONFIG_DM9000=M,在“include/linux/autoconf.h”这里全部变成了#define CONFIG_DM9000 1,定义为1之后我们的c
语言源文件就可以使用这个宏#define CONFIG_DM9000 1。
那么".config"文件里面的配置项CONFIG_DM9000=y还是CONFIG_DM9000=M这个差别在哪里体现呢?既然在c语言源文件里面体现不出来,则就是
在子目录makefile里面体现,如在drivers/net/Makefile里面有obj-$(CONFIG_DM9000) += dm9dev9000c.o
那么子目录makefile里面如:obj-$(CONFIG_DM9000) += dm9dev9000c.o里面的CONFIG_DM9000是由谁来定义的呢?显然是由include/config/auto.conf里面
CONFIG_DM9000=y 来定义
而include/config/auto.conf也是来源于".config"文件。include/config/auto.conf是被顶层的makefile包含的
第10课第3节 内核启动流程分析之Makefile
二:分析Makefile:第一个文件、链接脚本
1、子目录下面的makefile:
obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
obj-m += s3c24xx_leds.o
2、make uImage,发现uImage位于:linux-2.6.22.6_jz2440\linux-2.6.22.6\arch\arm\makefile
可以肯定上面的这个makefile会被包含在顶层的makefile里面,我们搜索顶层makefile发现里面有:include $(srctree)/arch/$(ARCH)/Makefile
在上一节的分析中,我们看到.config文件生成了autoconf.h和auto.conf
我们搜索一下顶层的makefile:-include include/config/auto.conf
在linux-2.6.22.6_jz2440\linux-2.6.22.6\arch\arm\makefile下可以看到uImage有关的一行:zImage Image xipImage bootpImage uImage: vmlinux,所以uImage依赖于vmlinux
在顶层makefile里面linux-2.6.22.6_jz2440\linux-2.6.22.6\makefile搜索vmlinux可以看到:all: vmlinux
zImage Image xipImage bootpImage uImage: vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
vmlinux-init := $(head-y) $(init-y)
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
init-y := init/
init-y := $(patsubst %/, %/built-in.o, $(init-y))即=init/built-in.o
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-y))
=usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o
libs-y := lib/
llibs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
=lib/lib.a lib/built-in.o
drivers-y := drivers/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
=drivers/built-in.o sound/built-in.o
net-y := net/
net-y := $(patsubst %/, %/built-in.o, $(net-y))
=net/built-in.o
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
走捷径分析linux:
book@book-desktop:/work/system/linux-2.6.22.6$ rm vmlinux
book@book-desktop:/work/system/linux-2.6.22.6$ make uImage V=1
arm-linux-ld -EL -p --no-undefined -X -o vmlinux
-T arch/arm/kernel/vmlinux.lds //链接脚本
arch/arm/kernel/head.o arch/arm/kernel/init_task.o //第一个文件,下面的都是原材料
init/built-in.o
--start-group usr/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o
arch/arm/mach-s3c2410/built-in.o arch/arm/mach-s3c2400/built-in.o arch/arm/mach-s3c2412/built-in.o arch/arm/mach-s3c2440/built-in.o
arch/arm/mach-s3c2442/built-in.o arch/arm/mach-s3c2443/built-in.o arch/arm/nwfpe/built-in.o arch/arm/plat-s3c24xx/built-in.o
kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o
arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in.o net/built-in.o --end-group .tmp_kallsyms2.o
第10课第4节 内核启动流程分析之内核启动
一、创建si工程,按前面讲的
二、内核:
A、处理u-boot传入的参数,从arch/arm/kernel/head.s开始跟踪进来
0、判断是否支持这个cpu
1、判断是否支持这个单板,uboot启动内核时传人的机器ID(theKernel (0, bd->bi_arch_number, bd->bi_boot_params);)
在arch/arm/kernel/head.s下:
bl __lookup_machine_type @ r5=machinfo
进入__lookup_machine_type由此引出了
在arch/arm/kernel/vmlinux.lds //链接脚本
__arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;
在内核里面搜索:
book@book-desktop:/work/system/linux-2.6.22.6$ grep ".arch.info.init" * -nR
在arch.h里面有:
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
展开宏
static const struct machine_desc __mach_desc_S3C2440 \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_S3C2440, \
.name = "SMDK2440",
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
};
2、建立页表
3、使能MMU
4、跳到我们内核的第一个c函数:start_kernel,这个函数会处理(theKernel (0, bd->bi_arch_number, bd->bi_boot_params);)里面的启动参数
B、挂接根文件系统
C、最终目的:运行应用程序
内核的启动流程:
arch/arm/kernel/head.s
start_kernel
setup_arch(&command_line); //解析uboot传入的参数
setup_command_line(command_line); //解析uboot传入的参数
parse_early_param
do_early_param
从__setup_start到__setup_end,调用early函数
unknown_bootoption
obsolete_checksetup
从__setup_start到__setup_end,调用非early函数
rest_init();
kernel_init
prepare_namespace();
mount_root();//挂接根文件系统
init_post();
//执行应用程序
三、Uboot传入的命令行参数的处理
1、说明:对于下面两个函数只不过是把Uboot传入的命令行参数记录下来而已
setup_arch(&command_line); //解析uboot传入的参数
setup_command_line(command_line); //解析uboot传入的参数
我们在prepare_namespace();这个函数的时候它肯定得先确定你挂接的是哪一个文件系统:命令行参数root=/dev/mtdblock3指定
在这个函数里面可以看到ROOT_DEV = name_to_dev_t(root_device_name);
由于if (saved_root_name[0]) {
root_device_name = saved_root_name;
if (!strncmp(root_device_name, "mtd", 3)) {
mount_block_root(root_device_name, root_mountflags);
goto out;
}
ROOT_DEV = name_to_dev_t(root_device_name);
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5;
}
在SI里面全局查找saved_root_name在哪里定义,可以搜索到一个函数和一个宏:
static int __init root_dev_setup(char *line)
{
strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
__setup("root=", root_dev_setup);
由这个宏我们可以大胆的估计,在解析命令行的时候发现了root=***,然后以它找到root_dev_setup这个函数,然后调用这个
函数,这个函数把root=***后面的***保存到变量saved_root_name里面去。
2、下面再分析__setup("root=", root_dev_setup);怎么执行:
在SI里面全局查找__setup在哪里定义,技巧先查找,再在结果里面搜索define
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
再搜索__setup_param
#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 }
我们把__setup("root=", root_dev_setup)展开,可以分析这个就是定义了如同上面的结构体,这个结构体里面有3个重要的成员
①名字"root=" ②函数root_dev_setup③early
而且__setup("root=", root_dev_setup)定义的结构体有一个特殊的属性:__attribute__((__section__(".init.setup"))),显然
".init.setup"在链接脚本里面
__setup_start = .;
*(.init.setup)
__setup_end = .;
搜索一下__setup_start就可以知道命令行是怎么调用的了,在两个函数里面被调用:
①函数obsolete_checksetup
②函数do_early_param,这个应该就是对应上面的__setup_str_##unique_id, fn, early 里面的early了。
再找一下do_early_param是谁调用:
parse_early_param
由于我们传入的参数early是0.很显然我们用的是①函数obsolete_checksetup
如下调用过程:
parse_early_param
do_early_param
从__setup_start到__setup_end,调用early函数
①函数obsolete_checksetup它被unknown_bootoption调用,搜索这个函数得:它被start_kernel函数调用。
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
如下调用过程:
unknown_bootoption
obsolete_checksetup
从__setup_start到__setup_end,调用非early函数
四、分区表
如果启动参数不是下面这个,则要设置启动参数:
set bootargs noinitrd root=/dev/mtdblock3 rootfstype=jffs2 init=/linuxrc console=ttySAC0
启动linux后,可以看到启动时会显示分区表:
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
book@book-desktop:/work/system/linux-2.6.22.6$ grep ".arch.info.init" * -nR
分区应该在arch/arm/plat-s3c24xx/common-smdk.c里面
/* NAND parititon from 2.4.18-swl5 */
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,
}
};
相关文章推荐
- 学习笔记:内核启动流程
- 第10课第3节 内核启动流程分析之Makefile
- Linux内核启动流程笔记
- Yocto开发笔记之《U-boot启动内核流程》(QQ交流群:519230208)
- 第10课第1节 内核启动流程分析之编译体验
- Linux系统启动流程、内核及模块管理
- uboot启动流程及内核参数传递
- Android启动流程分析之三:内核启动过程2--start_kernel
- 内核启动学习笔记
- ARM-Linux内核移植之(一)——内核启动流程分析 .
- arm-linux内核启动学习笔记(二)(废弃)
- 嵌入式Linux内核启动流程
- linux+shell编程 笔记 启动关机的流程与加载程序
- 深入学习JVM笔记一JVM启动流程与基本结构
- 国嵌视频学习---linux内核启动流程
- 韦东山视频---内核启动流程之编译体验学习
- 【内核】linux内核启动流程详细分析
- IMX6Solo启动流程-Linux 内核启动 七
- 学习笔记3-跟踪分析Linux内核的启动过程
- [转载] linux启动流程分析(2)---内核启动地址的确定