您的位置:首页 > 其它

笔记第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,

}

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: