--------------------/arch/arm/Makefile-----------------
# Convert bzImage to zImage
bzImage: zImage
zImage Image xipImage bootpImage uImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
------------------./Makefile------------------
# The all: target is the default when no target is given on the
# command line.
# This allow a user to issue only 'make' to build a kernel including modules
# Defaults vmlinux but it is usually overridden in the arch makefile
all: vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
vmlinux-init := $(head-y) $(init-y)
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o #这里 $(MMUEXT) 是个空的
init-y := init/
init-y := $(patsubst %/, %/built-in.o, $(init-y)) #这里返回 init/build-in.o .就是说init下所有的文件会编译成build-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/build-in.o kernel/build-in.o mm/build-in.o fs/build-in.o ipc/build-in.o
# security/build-in.o crypto/build-in.o block/build-in.o
libs-y := lib/
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2) #返回 lib/built-in.o lib/lib.a
drivers-y := drivers/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) #返回 drivers/built-in.o sound/built-in.o
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
-------------------------------------------------------------------------------
-----------------/arch/arm/Makefil---------------------------------------
生成vmlinux命令查看方法:make uImage V=1:
链接的顺序是由.o文件在命令中出现的顺序决定.
查看命令知道 第一个文件 是arch/arm/kernel/head.s
各个段的排放顺序是由链接脚本arch/arm/kernel/vmlinux.lds 决定.
首先放置.text.head段.然后是 .init.text段
arch/arm/kernel/vmlinux.lds 是自动生成的
放置文件的顺序 放置.离LD命令越近的越放在前面.第一个文件是head.s
第二个文件是arch/arm/kernel/init_task.o
--------------------------------------
#启动过程:
1:处理 uboot传入的参数.
2:挂载根文件系统
3.....
a:判断是否是这个cpu
b:判断是否机器号是否和启动参数匹配.
c:建立页表,启动mmu,程序是连接地址是从0xc000 8000开始的.
d:__mmap_switched 函数 :复制数据段,清楚bss段,设置栈,
d:跳转到init/main.c:start_kernel函数 #内核的第一个c函数.
-------------------------------
#head.o分析
是怎么处理启动参数的:
{
3: .long .
.long __arch_info_begin
.long __arch_info_end
.type __lookup_machine_type, %function
__lookup_machine_type:
adr r3, 3b #3b就是前面3那里,物理地址.. r3值,因为lds文件中定义的是虚拟地址.所以这里是虚拟地址.
ldmia r3, {r4, r5, r6} #r4 valtual addr of '3' r5=__arch_info_begin r6=__arch_info_end
sub r3, r3, r4 @ get offset between virt&phys r3=r3-r4
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
__arch_info_begin是定义在lds文件中标号.是在段 *(.arch.info.init)中
那么这个段有些什么内容呢,Arch.h (include\asm-arm\mach):
#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 \
};
#Mach-smdk2440.c (arch\arm\mach-s3c2440):
static const struct machine_desc __mach_desc_S3C2440
/* Maintainer: Ben Dooks <ben@fluff.org> */
.nr = MACH_TYPE_S3C2440,
.name = "SMDK2440",
.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,
};
-----------------------------------
#start_kernel函数分析
#问题:printk是怎么初始化的?
#解析从uboot传递过来的启动参数.
启动参数就通过 setup_arch() setup_command_line()初始化的.
|| ||
|| ||
|| bootargs字符参数 ||
|| tag:0x5441 0009 ||
|| size : ... ||
||
|| start:0x3000 0000 ||
|| size:0x400 0000 ||
|| tag:0x5441 0002 ||
|| sieze 4 ||
||
|| rootdev:0 ||
|| pagesize :0 ||
|| flag :0 ||
|| tag :0x5441 0001 ||
|| size 5 ||
-------------------------
start_kernel()
setup_arch() #解析从uboot传递过来的启动参数.
setup_command_line() #解析从uboot传递过来的启动参数.
parase_early_param
do_early_param
从__setup_start到__setup_end 调用early函数
unknown_bootoption
obsolete_checksetup函数
从__setup_start到__setup_end 调用非early函数
reset_init()
kernel_thread() //内核线程,他会调用kernel_init函数.
kernel_init()
prepare_namespace()
mount_root //挂载根文件系统.
init_post()
//打开/dev/console ,
执行应用程序./sbin/init 等
--------------------------机器号判断过程
-------------------------------------------
内核是怎么知道在哪里挂载文件系统的?
bootargs = noinitrd root=dev/mtdblock3 init=/linuxrc console=ttySAC0
prepare_namespace()
savred_root_name[0] //该变量在 root_dev_setup()中初始化
ROOT_DEV= Root_RAM0;
宏 __setup("root=", root_dev_setup) 会去解析命令行参数找到"root="后,
会保存后面的字符到变量savred_root_name[0]
宏__setup 位于include/linux/init.h中
# Convert bzImage to zImage
bzImage: zImage
zImage Image xipImage bootpImage uImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
------------------./Makefile------------------
# The all: target is the default when no target is given on the
# command line.
# This allow a user to issue only 'make' to build a kernel including modules
# Defaults vmlinux but it is usually overridden in the arch makefile
all: vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
vmlinux-init := $(head-y) $(init-y)
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o #这里 $(MMUEXT) 是个空的
init-y := init/
init-y := $(patsubst %/, %/built-in.o, $(init-y)) #这里返回 init/build-in.o .就是说init下所有的文件会编译成build-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/build-in.o kernel/build-in.o mm/build-in.o fs/build-in.o ipc/build-in.o
# security/build-in.o crypto/build-in.o block/build-in.o
libs-y := lib/
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2) #返回 lib/built-in.o lib/lib.a
drivers-y := drivers/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) #返回 drivers/built-in.o sound/built-in.o
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
-------------------------------------------------------------------------------
-----------------/arch/arm/Makefil---------------------------------------
生成vmlinux命令查看方法:make uImage V=1:
链接的顺序是由.o文件在命令中出现的顺序决定.
查看命令知道 第一个文件 是arch/arm/kernel/head.s
各个段的排放顺序是由链接脚本arch/arm/kernel/vmlinux.lds 决定.
首先放置.text.head段.然后是 .init.text段
arch/arm/kernel/vmlinux.lds 是自动生成的
放置文件的顺序 放置.离LD命令越近的越放在前面.第一个文件是head.s
第二个文件是arch/arm/kernel/init_task.o
--------------------------------------
#启动过程:
1:处理 uboot传入的参数.
2:挂载根文件系统
3.....
a:判断是否是这个cpu
b:判断是否机器号是否和启动参数匹配.
c:建立页表,启动mmu,程序是连接地址是从0xc000 8000开始的.
d:__mmap_switched 函数 :复制数据段,清楚bss段,设置栈,
d:跳转到init/main.c:start_kernel函数 #内核的第一个c函数.
-------------------------------
#head.o分析
是怎么处理启动参数的:
{
3: .long .
.long __arch_info_begin
.long __arch_info_end
.type __lookup_machine_type, %function
__lookup_machine_type:
adr r3, 3b #3b就是前面3那里,物理地址.. r3值,因为lds文件中定义的是虚拟地址.所以这里是虚拟地址.
ldmia r3, {r4, r5, r6} #r4 valtual addr of '3' r5=__arch_info_begin r6=__arch_info_end
sub r3, r3, r4 @ get offset between virt&phys r3=r3-r4
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
__arch_info_begin是定义在lds文件中标号.是在段 *(.arch.info.init)中
那么这个段有些什么内容呢,Arch.h (include\asm-arm\mach):
#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 \
};
#Mach-smdk2440.c (arch\arm\mach-s3c2440):
static const struct machine_desc __mach_desc_S3C2440
/* Maintainer: Ben Dooks <ben@fluff.org> */
.nr = MACH_TYPE_S3C2440,
.name = "SMDK2440",
.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,
};
-----------------------------------
#start_kernel函数分析
#问题:printk是怎么初始化的?
#解析从uboot传递过来的启动参数.
启动参数就通过 setup_arch() setup_command_line()初始化的.
|| ||
|| ||
|| bootargs字符参数 ||
|| tag:0x5441 0009 ||
|| size : ... ||
||
|| start:0x3000 0000 ||
|| size:0x400 0000 ||
|| tag:0x5441 0002 ||
|| sieze 4 ||
||
|| rootdev:0 ||
|| pagesize :0 ||
|| flag :0 ||
|| tag :0x5441 0001 ||
|| size 5 ||
-------------------------
start_kernel()
setup_arch() #解析从uboot传递过来的启动参数.
setup_command_line() #解析从uboot传递过来的启动参数.
parase_early_param
do_early_param
从__setup_start到__setup_end 调用early函数
unknown_bootoption
obsolete_checksetup函数
从__setup_start到__setup_end 调用非early函数
reset_init()
kernel_thread() //内核线程,他会调用kernel_init函数.
kernel_init()
prepare_namespace()
mount_root //挂载根文件系统.
init_post()
//打开/dev/console ,
执行应用程序./sbin/init 等
--------------------------机器号判断过程
-------------------------------------------
内核是怎么知道在哪里挂载文件系统的?
bootargs = noinitrd root=dev/mtdblock3 init=/linuxrc console=ttySAC0
prepare_namespace()
savred_root_name[0] //该变量在 root_dev_setup()中初始化
ROOT_DEV= Root_RAM0;
宏 __setup("root=", root_dev_setup) 会去解析命令行参数找到"root="后,
会保存后面的字符到变量savred_root_name[0]
宏__setup 位于include/linux/init.h中