linux内核的编译过程:
uImage:
进入顶层目录的Makefile文件中:
504 include $(srctree)/arch/$(SRCARCH)/Makefile ====》 arch/arm/Makefile
||
\/
进入arch/arm/Makefile中
必备变量:
machine-$(CONFIG_ARCH_EXYNOS) += exynos ===》 machine-y += exynos
plat-$(CONFIG_ARCH_EXYNOS) += samsung ===> plat-y += samsung
MACHINE := arch/arm/mach-$(word 1,$(machine-y))/
===》MACHINE := arch/arm/mach-exynos/
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
===> machdirs :=arch/arm/mach-exynos/
platdirs := $(patsubst %,arch/arm/plat-%/,$(plat-y))
===> platdirs := arch/arm/mach-samsung
291 boot := arch/arm/boot
BOOT_TARGETS = zImage Image xipImage bootpImage uImage
$(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
===> @ make -C $(build)=arch/arm/boot MACHINE=arch/arm/mach-exynos/ arch/arm/boot/uImage
||
\/
进入arch/arm/boot/Makefile中
14 ifneq ($(MACHINE),)
15 include $(srctree)/$(MACHINE)/Makefile.boot ====》include arch/arm/mach-exynos/Makefile.boot
16 endif
arch/arm/mach-exynos/Makefile.boot文件内容:
zreladdr-y += 0x40008000 就是内核的入口地址
params_phys-y := 0x40000100 uboot传递参数的地址
22 ZRELADDR := $(zreladdr-y)
23 PARAMS_PHYS := $(params_phys-y)
export ZRELADDR INITRD_PHYS PARAMS_PHYS 到处为全局变量
$(obj) == 当前Makeifle的路径
78 $(obj)/uImage: $(obj)/zImage FORCE
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE ===》arch/arm/boot/compressed/vmlinux |3| 5
$(call if_changed,objcopy)
||
\/
进入arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/vmlinux.lds 链接脚本
25 HEAD = head.o
86 suffix_$(CONFIG_KERNEL_GZIP) = gzip ==》 suffix_y = gzip
$(obj)/piggy.$(suffix_y).o ===》arch/arm/boot/compressed/piggy.gzip.o
26 OBJS += misc.o decompress.o 他们是用来解压内核的代码
148 lib1funcs = $(obj)/lib1funcs.o ==》arch/arm/boot/compressed/lib1funcs.o
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) $(bswapsdi2) FORCE
195 $(obj)/piggy.$(suffix_y).o: $(obj)/piggy.$(suffix_y) FORCE
192 $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE ==>arch/arm/boot/Image
||
\/
退回arch/arm/boot/Makefile文件
47 $(obj)/Image: vmlinux FORCE ===》 依赖于源码顶层目录下的vmlinux文件
48 $(call if_changed,objcopy)
||
\/
退回Makefile文件
802 export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
803 export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y)
804 export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
809 vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)
817 vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
Linux内核的启动流程:
arch/arm/kernel/vmlinux.lds 链接脚本
arch/arm/kernel/head.S 内核启动的第一段代码
safe_svcmode_maskall r9
设置cpu的工作模式,关闭中断
||
\/
94 mrc p15, 0, r9, c0, c0 @ get processor id
95 bl __lookup_processor_type @ r5=procinfo r9=cpuid
获得处理器的id,然后对比内核是否支持?
||
\/
bl __vet_atags
判断uboot给内核传递参数的方式是taglist或者 dtb?
bl __create_page_tables 创建页表, 为开启MMU做准备
||
\/
参考 arch/arm/mm/proc-v7.S 查看对TLB cache的初始化
ldr r13, =__mmap_switched 赋值个sp寄存器
||
\/
b __enable_mmu 使能mmu
||
\/
b __turn_mmu_on 开启MMU
||
\/
b __mmap_switched
拷贝相关数据
清空BSS段
||
\/
b start_kernel 进入C语言代码
setup_arch(&command_line); 就是获得uboot传递过来的参数
setup_command_line(command_line); 获得bootargs参数
console_init(); 尤其注意的函数。
rest_init();
||
\/
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
||
\/
kernel_init
||
\/
kernel_init_freeable(); 挂载文件系统相关的函数
||
\/
prepare_namespace(); 挂载文件系统
567 if (strncmp(root_device_name, "/dev/", 5) == 0)
568 root_device_name += 5;
mount_root(); 执行挂载
||
\/
510 if (mount_nfs_root())
511 return;
||
\/
执行init程序,内核完全启动。
平台代码,设备树:
设备树:Device Tree
/{
node1 {
属性
child_1 {
};
child_2 {
};
};
node {
属性
};
};
设备树文件:
dts 设备树的原文件。
dtb 设备树二进制文件
dtsi :类似于头文件
属性:
model :表示具体某一个machine
compatible 用来将驱动和设备绑定
#address-cells = <1> 表示起始地址
#size-cells = <1> 表示范围
reg:可寻址设备用来表示编码地址信息,是一个列表
reg = <0x0203F000 0x1000>;
参考Documentation/devicetree/bindings 有例子