This chapter is OS dependent. We chose to follow the kernel initialization process in the linear order in which it occurs. We begin with a discussion of what happens on power-on through to the call to the first architecture-independent function, start_kernel(), and follow the process up to the invocation of /sbin/init. The figure below illustrates the order of events from system power on to power off.
We begin with a discussion of BIOS and Open Firmware, which is the first code that runs in the x86 upon power on. This is followed by a discussion of bootloaders commonly used with Linux and how they load the kernel and pass execution control to it. We then discuss in detail the step known as kernel initialization, where all the subsystems are initialized. The end of the kernel initialization is marked by the call to /sbin/init by process 1. The init program continues on with what is known as system initialization by enabling processes that need to be running before users can log in.
1. BIOS
For x86 systems, this is where the system BIOS resides. The Basic Input Output System (BIOS) is a block of hardware-specific system initialization code that boots the system. In x86 systems, the boot loader and, in turn Linux, depend on BIOS to bring the system to a known state. The interface to BIOS is a uniform set of functions known as interrupts. At load time, Linux uses these interrupts to query available system resources. After BIOS completes its initialization, it copies the first 512 bytes from the boot device (which is discussed in the next section) to address 0x7c00 and jumps to it. Although in some installations, BIOS loads the operating system over a network connection, this discussion is confined to the process when loading Linux from the hard drive. When Linux is loaded, BIOS is still in memory and its functions are accessible and called by way of interrupts.
2. Boot Loaders
Boot loaders are programs that reside on the boot device of a computer. The first boot device is usually the first hard disk in the system. A boot loader is called by BIOS (x86) after enough system initialization has occurred to support the memory, interrupts, and I/O required to load the kernel. Once loaded, the kernel initializes and configures the operating system.
Master Boot Record (MBR), which resides in the first sector (sector 0, cylinder 0, head 0) of the boot device. The MBR contains a small program and a four-entry partition table. The end of the boot sector has a hex marker 0xAA55 at location 510. The Table below shows the components of the MBR.
The MBR's partition table holds information pertinent to each of the hard disk primary partitions. The following table shows what each 16-byte entry of the MBR's partition table looks like:
At the end of BIST and hardware identification, the system initialization code (BIOS) accesses the hard drive controller to read the MBR. After the type of boot drive is identified, one can follow a documented interface (for example, on an IDE drive) to access head 0, cylinder 0, and sector 0.
After the boot device is located, the MBR is copied to memory address 0x7c00 and executed. The small program at the head of the MBR moves itself out of the way and searches its partition table for the location of the active boot partition. The MBR then copies the code from the active boot partition to address 0x7c00 and begins executing it. From this point, DOS is usually booted on an x86 system. However, the active boot partition can have a bootloader that, in turn, loads the operating system. We now discuss some of the most common bootloaders that Linux uses. Here, a Figure shows what memory looks like at bootup time.
2.1 Common Bootloader—GRUB(Grand Unified Bootloader)
GRUB is an x86-based bootloader that's used to load Linux.
GRUB recognizes filesystems on the boot drives, and the kernel can be loaded by specifying the filename, drive, and partition where the kernel resides. GRUB is a two-stage bootloader. Stage 1 is installed in the MBR and is called by BIOS. Stage 2 is partially loaded by Stage 1 and then finishes loading itself from the filesystem. The breakdown of events ocurring in each of the stages is the following:
This configuration specifies that Linux boots and loads the executable image to linear address 0x9000 and jumps to 0x9020. At this point, the uncompressed part of the Linux kernel decompresses the compressed portion to address 0x10000 and kernel initialization begins.
3 Intel x86 based hardware memory management
Memory management is one of the first subsystems to be initialized and begins prior to the execution of start_kernel() because of its highly architecture-dependent nature.
In real address mode, the processor can execute a program written for the 8086 and 8088 processors using the same instructions and, more importantly, the same method of addressing or address translation. The end result of address translation is how the processor accesses the system memory. The early Intel processors had a 20-bit address bus, which accessed approximately 64K bytes of memory
The code in setup.S performs several important functions with respect to memory initialization:
# method E820H:
# the memory map from hell. e820h returns memory classified into
# a whole bunch of different types, and allows memory holes and
# everything. We scan through this memory map and build a list
# of the first 32 memory areas, which we return at [E820MAP].
# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
#define SMAP 0x534d4150
meme820:
xorl %ebx, %ebx # continuation counter
movw $E820MAP, %di # point into the whitelist
# so we can have the bios
# directly write into it.
jmpe820:
movl $0x0000e820, %eax # e820, upper word zeroed
movl $SMAP, %edx # ascii 'SMAP'
movl $20, %ecx # size of the e820rec
pushw %ds # data record.
popw %es
int $0x15 # make the call
jc bail820 # fall to e801 if it fails
cmpl $SMAP, %eax # check the return is `SMAP'
jne bail820 # fall to e801 if it fails
# cmpl $1, 16(%di) # is this usable memory?
# jne again820
# If this is usable memory, we save it by simply advancing %di by
# sizeof(e820rec).
#
good820:
movb (E820NR), %al # up to 128 entries
cmpb $E820MAX, %al
jae bail820
incb (E820NR)
movw %di, %ax
addw $20, %ax
movw %ax, %di
again820:
cmpl $0, %ebx # check to see if
jne jmpe820 # %ebx is set to EOF
bail820:
the memory map can be obtained by three methods: 0xe820, 0xe801, and 0x88. All three methods have to do with compatibility with existing BIOS distributions and their platforms.
# Now we move the system to its rightful place ... but we check if we have a
# big-kernel. In that case we *must* not move it ...
testb $LOADED_HIGH, %cs:loadflags
jz do_move0 # .. then we have a normal low
# loaded zImage
# .. or else we have a high
# loaded bzImage
jmp end_move # ... and we skip moving
do_move0:
movw $0x100, %ax # start of destination segment
movw %cs, %bp # aka SETUPSEG
subw $DELTA_INITSEG, %bp # aka INITSEG
movw %cs:start_sys_seg, %bx # start of source segment
cld
do_move:
movw %ax, %es # destination segment
incb %ah # instead of add ax,#0x100
movw %bx, %ds # source segment
addw $0x100, %bx
subw %di, %di
subw %si, %si
movw $0x800, %cx
rep
movsw
cmpw %bp, %bx # assume start_sys_seg > 0x200,
# so we will perhaps read one
# page more than needed, but
# never overwrite INITSEG
# because destination is a
# minimum one page below source
jb do_move
end_move:
对CPU、定时器、DMA控制器、中断控制器、内存中的RAM和ROM、键盘、磁盘驱动器、异步通信接口、打印机配置等内容进行测试,这个过程叫做POST(上电自检),Intel称为BIST过程。
加电:
初始化寄存器;CS:EIP=0xfffffff0,in ROM(CPU要执行的第一条指令) 在0x0000位置设置中断向量表,这样后面还可以接着使用BIOS功能该地址中有一条JMP指令,跳转地址通常是BIOS的入口地址
BIOS:
--POST
--初始化硬件设备
--搜索启动操作系统的设备(U盘、硬盘、CD-ROM)
--并把MBR读到内存绝对地址0x7c00处同时将控制权交出。
Main Ref:
Kernel Primer- A Top Down Approach for x86 and PowerPC architectures