vmlinux和bzImage的Makefile部分阅读

vmlinux

vmlinux:$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE

       $(call vmlinux-modpost)

       $(call if_changed_rule, vmlinux__)

       $(Q) rm –f .old_version

quiet_cmd_vmlinux__ ?= LD $@

       cmd_vmlinux__ ?= $(LD) $(LDFLAGS_vmlinux) –o $@ -T $(vmlinux-lds) /

$(vmlinux-init) –( $(vmlinux-main) -) $(filter-out $(vmlinux-lds)) /

$(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE, $^

 

vmlinux-init := $(head-y) $(init-y)

vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)

arch/x86/Makefile下有

head-y := arch/x86/kernel/head_$(BITS).o   <=   head_32.S

a)      初始化段寄存器、clear BSS、将实模式下的boot_params相关数据拷贝到保护模式下

b)      建立临时内核页表、启用分页

c)       建立进程0的内核堆栈stack_start???

d)      setup_idt

e)      识别处理器、建立GDTIDT

f)      i386_start_kernel

head-y += arch/x86/kernel/head$(BITS).o    <=   head32.c

i386_start_kernel => start_kernel

head-y += arch/x86/kernel/head.o                <=   head.c

head-y += arch/x86/kernel/init_task.o          <=   init_task.c

       struct task_struct init_task = INIT_TASK(init_task)

       DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;

 

init-y = init/version.omain.o

其中main.o中定义了start_kernel()

drivers-y =    drivers/ sound/ firmware/

net-y =          net/

libs-y =          lib/ arch/x86/lib

core-y =        usr/ kernel/ mm/ fs/ ipc/ security/ crypto/ block/ arch/x86

 

根据上面列出的vmlinux的构造规则可以看出,源码根目录下的vmlinux就是内核从实模式进入保护模式后将要执行的代码,head-y先于init-y执行,它会启用分页,建立全局描述符表和中断描述符表,并跳转到start_kernel()函数。

start_kernel()函数是定义在init-y中的main.c函数中的。start_kernel()函数完成Linux内核的初始化工作,其中的初始化函数大多定义在core-ylibs-ydrivers-ynet-y中。可见vmlinux包含了内核主要功能并完成了内核初始化。

至此Linux内核完成启动,现在正在运行。

 

bzImage

arch/x86/Makefile

boot := arch/x86/boot/

bzImage: vmlinux

       $(Q) $(MAKE) $(build)=$(boot) $(boot)/bzImage

$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE

       $(call if_changed, image)

quiet_cmd_image = BUILD $@

       cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin /

$(ROOT_DEV) > $@

arch/x86/boot/Makefile

setup.elf: setup.ld $(SETUP_OBJS) FORCE

       $(call if_changed, ld)

OBJCOPYFLAGS_setup.bin := -O binary

setup.bin: setup.elf FORCE

       $(call, if_changed, objcopy)

SET_OBJS即由setup-y组成

setup-y = a20.obioscall.ocmdline.ocopy.ocpu.ocpucheck.o /

early_serial_console.oheader.omain.opm.opumjump.o…

setup-y中的文件组成了内核在实模式下执行的代码。

header.S要做的工作包括为C语言运行建立运行环境,准备好堆和栈;检查setupsignature;清楚BSS段;跳转到main执行。

main.c用来初始化硬件设备并未内核程序的执行建立环境内存检测、键盘、视频、;调用go_to_protected_mode(),设置boot_params

pm.c中定义了go_to_protected_mode

a)      enable_a20 开始20地址线,这样就可以访问2M空间

b)      reset_coprocessor 复位协处理器

c)       mask_all_interrupts() 屏蔽所有中断

d)      setup_idt()setup_gdt()

e)      protected_mode_jump(boot_params.hdr.code32_start, (u32)&boot_params+ds()<<4)

(note:code32_start=0x100000也就是vmlinux.bin所在的位置)

pmjump.S开启保护模式,设置段寄存器,长跳转设置代码段寄存器,最后跳转到code32_start处,在bzImage中,这就是vmlinux.bin的位置,首先进入的是compressed/head_32.S(后面详述)

boot/compressed/head_32.S中的startup_32调用decompress_kernel()解压函数(misc.o)vmlinux解压缩到1M处,jmp*%ebp跳转到解压后的vmlinux入口,就是上面源码根目录下的vmlinux,上面已经描述了后面的工作。

 

根据上面的分析可知,setup.bin的主要工作是为C语言运行建立运行环境,获取启动参数,检测硬件、建立临时全局描述符表,中中断描述符表,从实模式转换到保护模式并加载vmlinux

这个加载不是直接加载,为了使得bzImage(3.1M)尽可能的小,会将vmlinux(19M)进行压缩所以在bzImage中的是vmlinux.bin(3.1M),它包含了vmlinux的压缩版,和解压函数,解压函数就在compressed/目录下。

在编译内核的时候,会把主内核(不包括setup部分)编译成vmlinux,然后makecompressed目录下,在这里会对vmlinux进行打包压缩,并把解压函数一起打包成一个vmlinux.bin

这个过程是:

vmlinux复制为二进制格式,并strip掉调试信息,得到的vmlinux.bin大小为16M

objcopy –R .comment –S vmlinux vmlinux.bin

利用gzip工具压缩vmlinux.bin得到vmlinux.bin.gz大小为3.1M

gzip –c vmlinux.bin > vmlinux.bin.gz

利用mkpiggy内建工具

./mkpiggy vmlinux.bin.gz > piggy.S

最后把解压函数misc.o和其他文件一起链接成compressed/vmlinux(5.1M)

ld –T vmlinux.ldds head_32.o misc.o string.o cmdline.o early_serial_console.o piggy.o –o vmlinux

回到上级目录下,Make将会执行

objcopy –O binary –R .note –R .comment –S compressed/vmlinux vmlinux.bin

这就完成了vmlinux.bin的构造,最终的vmlinux.bin大小为3.1M

setup.bin(15K)vmlinux.bin(3.1M) build在一起就形成了bzImage(3.1M)

LILO调用一个BIOS例程从磁盘装入内核映像的初始部分,即将内核映像的第一个512字节从地址0x00090000开始存入RAM中,偏移0x200处开始的一条短跳转指令跳转到start_of_setup处。调用另一个BIOS例程从磁盘装载剩余的映像,并把内核映像放入从0x00100000开始的RAM中。

你可能感兴趣的:(vmlinux和bzImage的Makefile部分阅读)