x86系统引导(1)

来源:互联网 发布:nero burn for mac 编辑:程序博客网 时间:2024/05/18 03:10

1、bzImage的生成过程

上图是内核镜像bzimage的构建过程,包括如下过程:

1、构建内核镜像vmlinux,根据在内核配置阶段生成的.config将系统核心和built-in的系统组件进行编译,最后根据指定的链接脚本arch/i386/kernel/vmLinux.lds生成vmLinux文件。

2、对vmlinux进行瘦身并进行压缩,通过gzip对vmlinux.bin进行压缩。

3、构建包含解压缩代码的vminux镜像,使用连接器ld将包含压缩的系统核心的文件piggy.o与head.o,misc.o链接生成新的文件boot/compressed/vmLinux.

4、对新生成的vmlinux再次瘦身。

5、构建内核镜像bzImage,利用内核镜像构建工具build将bootsect,setup,vmLinux.bin三个文件依次放到bzImage文件中去。bootsect是一个引导扇区,一般情况下是512字节,最后两个字节为55AA.然后填充setup部分,补足512字节。

2、内核引导过程中涉及的文件

(1)arch/i386/boot/bootsect.S

(2)arch/i386/boot/setup.S

(3)arch/i386/boot/compressed/head.S

(4)arch/i386/boot/compressed/misc.c

(5)arch/i386/kernel/head.S

(6)init/main.c

3、第一个文件(1)arch/i386/boot/bootsect.S,在另一篇i386的引导协议中说过,这一部分,不再具有引导能力,主要就是传递一些参数。所以只看一小部分源码,如下:

SETUPSECTS= 4/* default nr of setup-sectors */
BOOTSEG = 0x07C0/* original address of boot-sector */
INITSEG = DEF_INITSEG/* we move boot here - out of the way */
SETUPSEG = DEF_SETUPSEG/* setup starts here */
SYSSEG = DEF_SYSSEG/* system loaded at 0x10000 (65536) */
SYSSIZE = DEF_SYSSIZE/* system size: # of 16-byte clicks */
/* to be loaded */
ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */


setup_sects:.byte SETUPSECTS
root_flags: .word ROOT_RDONLY
syssize: .word SYSSIZE
swap_dev: .word SWAP_DEV
ram_size: .word RAMDISK
vid_mode: .word SVGA_MODE
root_dev: .word ROOT_DEV
boot_flag: .word 0xAA55必须以此结尾

4、第二个文件(2)arch/i386/boot/setup.S,主要是探测系统的资源。在引导程序如GRUB装载完内核后,系统的控制全就交给此文件。此文件的主要工作是通过BIOS获得系统的配置信息,并将信息存到对应的内存位置,等待系统初始化时使用。

所做工作如下:

(1)、探测系统配置信息,并将探测的信息存到相应的内存单元中,

(2)、设置系统的全局描述表和中断描述符表。

(3)、进入保护模式

(4)、跳转到__BOOT_DS:0x100000,该地址对应于物理地址0x100000。此处正是经过压缩的内核的位置。

源码就不列出了,但列出下面这段本文件开头的注释,这段注释已经把此文件要做的工作,详细说明了。

/*
 * setup.S Copyright (C) 1991, 1992 Linus Torvalds
 *
 * setup.s is responsible for getting the system data from the BIOS,
 * and putting them into the appropriate places in system memory.

 * both setup.s and system has been loaded by the bootblock.
 *
 * This code asks the bios for memory/disk/other parameters, and
 * puts them in a "safe" place: 0x90000-0x901FF, ie where the
 * boot-block used to be. It is then up to the protected mode
 * system to read them from there before the area is overwritten
 * for buffer-blocks.
 *
 * Move PS/2 aux init code to psaux.c
 * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
 *
 * some changes and additional features by Christoph Niemann,
 * March 1993/June 1994 (Christoph.Niemann@linux.org)
 *
 * add APM BIOS checking by Stephen Rothwell, May 1994
 * (sfr@canb.auug.o
 rg.au)
 *
 * High load stuff, initrd support and position independency
 * by Hans Lermen & Werner Almesberger, February 1996
 * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
 *
 * Video handling moved to video.S by Martin Mares, March 1996
 * <mj@k332.feld.cvut.cz>*
 * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
 * parsons) to avoid loadlin confusion, July 1997
 *
 * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
 * <stiker@northlink.com>
 *
 * Fix to work around buggy BIOSes which dont use carry bit correctly
 * and/or report extended memory in CX/DX for e801h memory size detection 
 * call.  As a result the kernel got wrong figures.  The int15/e801h docs
 * from Ralf Brown interrupt list seem to indicate AX/BX should be used
 * anyway.  So to avoid breaking many machines (presumably there was a reason
 * to orginally use CX/DX instead of AX/BX), we do a kludge to see
 * if CX/DX have been changed in the e801 call and if so use AX/BX .

5、此两个文件主要是压缩内核镜像的解压缩。这两个文件调用gnuzip解压缩内核piggy.o解压缩并释放到逻辑地址__BOOT_DS:_PHYSICAL_START处,并跳转到该地址开始系统的初始化过程。

(3)arch/i386/boot/compressed/head.S

(4)arch/i386/boot/compressed/misc.c

6、(5)arch/i386/kernel/head.S本文件为系统建立一个初步的页表,启用分页机制;装载了新的GDT、IDT,设置栈指针寄存器指向0号进程init_task内核态的栈底。最后跳到位于文件/init/main.c的系统初始化函数start_kernel,继续进行系统的初始化工作。列出其中一段源码:

/*
 * Initialize page tables.  This creates a PDE and a set of page
 * tables, which are located immediately beyond _end.  The variable
 * init_pg_tables_end is set up to point to the first "safe" location.
 * Mappings are created both at virtual address 0 (identity mapping)
 * and PAGE_OFFSET for up to _end+sizeof(page tables)+INIT_MAP_BEYOND_END.
 *
 * Warning: don't use %esi or the stack in this code.  However, %esp
 * can be used as a GPR if you really need it...
 */
page_pde_offset = (__PAGE_OFFSET >> 20);


movl $(pg0 - __PAGE_OFFSET), %edi
movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
movl $0x007, %eax/* 0x007 = PRESENT+RW+USER */
10:
leal 0x007(%edi),%ecx/* Create PDE entry */
movl %ecx,(%edx)/* Store identity PDE entry */
movl %ecx,page_pde_offset(%edx)/* Store kernel PDE entry */
addl $4,%edx
movl $1024, %ecx
11:
stosl
addl $0x1000,%eax
loop 11b
/* End condition: we must map up to and including INIT_MAP_BEYOND_END */
/* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */
leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp
cmpl %ebp,%eax
jb 10b
movl %edi,(init_pg_tables_end - __PAGE_OFFSET)


#ifdef CONFIG_SMP
xorl %ebx,%ebx/* This is the boot CPU (BSP) */
jmp 3f

7、(6)init/main.c

该函数完成绝大多数的初始化,然后有0好进程init_task负责初始化过程中的全任务,包括内存管理、终端等。完成系统的初始化,将控制权交给1号进程init,该进程负责对系统剩余部分的初始化。


x86系统引导(2)的链接







原创粉丝点击