下面这段时间,我要好好分析一下内核启动过程的源代码,怎么来分析,而且更好的和网友们进行交流,我想,最好的方式莫过于采用赵炯博士编著的《linux内核完全注释》一书的编写规范。将中文注释夹杂在代码中是最好的方式了吧。我将采用分段注释,以免代码太长导致读了后面的忘记了前面的,在其中会有些重要的知识点也是我们要好好学习的。
要找到第一个源代码文件不是太困难,它就是始源,注意我们这里全是在x86机器上,内核版本为2.6.36.2。那么arch/x86/boot目录则是我们的入口点,看看里面的Makefile。
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o
setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o
setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o
setup-y += video-mode.o version.o
setup-$(CONFIG_X86_APM_BOOT) += apm.o
# The link order of the video-*.o modules can matter. In particular,
# video-vga.o *must* be listed first, followed by video-vesa.o.
# Hardware-specific drivers should follow in the order they should be
# probed, and video-bios.o should typically be last.
setup-y += video-vga.o
setup-y += video-vesa.o
setup-y += video-bios.o
可以看见setup-y目标,就是我们前面那篇说的setup.elf,我们可以发现header.o,可以想到,就是我们要找的始源。它是由header.S汇编文件产生的,顺便说一下,x86的汇编是AT&T,如果不晓得最好自己把这块学习一下。
来自:arch/x86/boot/header.S:
/*
* header.S
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Based on bootsect.S and setup.S
* modified by more people than can be counted
*
* Rewritten as a common file by H. Peter Anvin (Apr 2007)
*
* BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
* addresses must be multiplied by 16 to obtain their respective linear
* addresses. To avoid confusion, linear addresses are written using leading
* hex while segment addresses are written as segment:offset.
*
*/
#include <asm/segment.h>
#include <generated/utsrelease.h>
#include <asm/boot.h>
#include <asm/e820.h>
#include <asm/page_types.h>
#include <asm/setup.h>
#include "boot.h"
#include "voffset.h"
#include "zoffset.h"
BOOTSEG = 0x07C0 /* original address of boot-sector */
SYSSEG = 0x1000 /* historical load address >> 4 */
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef RAMDISK
#define RAMDISK 0
#endif
#ifndef ROOT_RDONLY
#define ROOT_RDONLY 1
#endif
.code16
.section ".bstext", "ax"
.global bootsect_start
bootsect_start:
# Normalize the start address
ljmp $BOOTSEG, $start2
start2:
movw %cs, %ax #现在的cs=0x7c00
movw %ax, %ds #初始化段寄存器
movw %ax, %es
movw %ax, %ss #注意堆栈段为0x7c00
xorw %sp, %sp
sti #开中断
cld #di,si ++
movw $bugger_off_msg, %si #bugger_off_msg在下面
msg_loop: #打印信息
lodsb #将ds:si处的字节读入al
andb %al, %al
jz bs_die #如果al==0,则跳转到bs_die
movb $0xe, %ah
movw $7, %bx
int $0x10 #INT0x10是BIOS视频中断,打印字符。功能号 AH= 0x0e,表示在Teletype模式下显示字符,
#AL=字符, BH=页码, BL=前景色 (图形模式 )
jmp msg_loop
bs_die:
# Allow the user to press a key, then reboot
xorw %ax, %ax
int $0x16 #键盘中断,接收一个字符
int $0x19
# int 0x19 should never return. In case it does anyway,
# invoke the BIOS reset code...
要找到第一个源代码文件不是太困难,它就是始源,注意我们这里全是在x86机器上,内核版本为2.6.36.2。那么arch/x86/boot目录则是我们的入口点,看看里面的Makefile。
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o
setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o
setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o
setup-y += video-mode.o version.o
setup-$(CONFIG_X86_APM_BOOT) += apm.o
# The link order of the video-*.o modules can matter. In particular,
# video-vga.o *must* be listed first, followed by video-vesa.o.
# Hardware-specific drivers should follow in the order they should be
# probed, and video-bios.o should typically be last.
setup-y += video-vga.o
setup-y += video-vesa.o
setup-y += video-bios.o
可以看见setup-y目标,就是我们前面那篇说的setup.elf,我们可以发现header.o,可以想到,就是我们要找的始源。它是由header.S汇编文件产生的,顺便说一下,x86的汇编是AT&T,如果不晓得最好自己把这块学习一下。
来自:arch/x86/boot/header.S:
/*
* header.S
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Based on bootsect.S and setup.S
* modified by more people than can be counted
*
* Rewritten as a common file by H. Peter Anvin (Apr 2007)
*
* BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
* addresses must be multiplied by 16 to obtain their respective linear
* addresses. To avoid confusion, linear addresses are written using leading
* hex while segment addresses are written as segment:offset.
*
*/
#include <asm/segment.h>
#include <generated/utsrelease.h>
#include <asm/boot.h>
#include <asm/e820.h>
#include <asm/page_types.h>
#include <asm/setup.h>
#include "boot.h"
#include "voffset.h"
#include "zoffset.h"
BOOTSEG = 0x07C0 /* original address of boot-sector */
SYSSEG = 0x1000 /* historical load address >> 4 */
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef RAMDISK
#define RAMDISK 0
#endif
#ifndef ROOT_RDONLY
#define ROOT_RDONLY 1
#endif
.code16
.section ".bstext", "ax"
.global bootsect_start
bootsect_start:
# Normalize the start address
ljmp $BOOTSEG, $start2
start2:
movw %cs, %ax #现在的cs=0x7c00
movw %ax, %ds #初始化段寄存器
movw %ax, %es
movw %ax, %ss #注意堆栈段为0x7c00
xorw %sp, %sp
sti #开中断
cld #di,si ++
movw $bugger_off_msg, %si #bugger_off_msg在下面
msg_loop: #打印信息
lodsb #将ds:si处的字节读入al
andb %al, %al
jz bs_die #如果al==0,则跳转到bs_die
movb $0xe, %ah
movw $7, %bx
int $0x10 #INT0x10是BIOS视频中断,打印字符。功能号 AH= 0x0e,表示在Teletype模式下显示字符,
#AL=字符, BH=页码, BL=前景色 (图形模式 )
jmp msg_loop
bs_die:
# Allow the user to press a key, then reboot
xorw %ax, %ax
int $0x16 #键盘中断,接收一个字符
int $0x19
# int 0x19 should never return. In case it does anyway,
# invoke the BIOS reset code...