linux内核分析----初始化
2004-04-23 15:18 pm
作者:e4gle
来自:Linux知识宝库
联系方式:无名

参考我提供的三个文件:bootsect.txt,head.txt,setup.txt
至于x86的引导无非如下步骤:
1,cpu初始化自身,在固定位置执行一条指令。
2,这条指令条转到bios中。
3,bios找到启动设备并获取mbr,该mbr指向我们的lilo
4,bios装载并把控制权交给lilo
5,压缩内核自解压,并把控制权转交给解压内核。
简单点讲,就是cpu成为内核引导程序的引导程序的引导程序的引导程序,西西。
这时内核将跳转到start_kernel是/init/main.c的重点函数,main.c函数很多定义都是为此函数服务的,这里我简要介绍一下这个函数的初始化流程。

初始化内核:
从start_kernel函数(/init/main.c)开始系统初始化工作,好,我们首先分析这个函数:
函数开始首先:
#ifdef __SMP__
static int boot_cpu = 1;
/* "current" has been set up, we need to load it now *//*定义双处理器用*/
if (!boot_cpu)
initialize_secondary();
boot_cpu = 0;
#endif

定义双处理器。

printk(linux_banner); /*打印linux banner*/
打印内核标题信息。

开始初始化自身的部分组件(包括内存,硬件终端,调度等),我来逐个分析其中的函数:
setup_arch(&command_line, &memory_start, &memory_end);/*初始化内存*/
返回内核参数和内核可用的物理地址范围
函数原型如下:
setup_arch(char **, unsigned long *, unsigned long *);
返回内存起始地址:
memory_start = paging_init(memory_start,memory_end);
看看paging_init的定义,是初始化请求页:
paging_init(unsigned long start_mem, unsigned long end_mem)(会在以后的内存管理子系统分析时详细介绍)
{
int i;
struct memclust_struct * cluster;
struct memdesc_struct * memdesc;

/* initialize mem_map[] */
start_mem = free_area_init(start_mem, end_mem);/*遍历查找内存的空闲页*/

/* find free clusters, update mem_map[] accordingly */
memdesc = (struct memdesc_struct *)
(hwrpb->mddt_offset + (unsigned long) hwrpb);
cluster = memdesc->cluster;
for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
unsigned long pfn, nr;

/* Bit 0 is console/PALcode reserved. Bit 1 is
non-volatile memory -- we might want to mark
this for later */
if (cluster->usage & 3)
continue;
pfn = cluster->start_pfn;
if (pfn >= MAP_NR(end_mem)) /* if we overrode mem size */
continue;
nr = cluster->numpages;
if ((pfn + nr) > MAP_NR(end_mem)) /* if override in cluster */
nr = MAP_NR(end_mem) - pfn;

while (nr--)
clear_bit(PG_reserved, &mem_map[pfn++].flags);
}

memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);

return start_mem;
}

trap_init(); 初始化硬件中断
/arch/i386/kernel/traps.c文件里定义此函数

sched_init() 初始化调度
/kernel/sched.c文件里有详细的调度算法(这些会在以后进程管理和调度的结构分析中详细介绍)

parse_options(command_line) 分析传给内核的各种选项(随后再详细介绍)

memory_start = console_init(memory_start,memory_end) 初始化控制台

memory_start = kmem_cache_init(memory_start, memory_end) 初始化内核内存cache(同样,在以后的内存管理分析中介绍此函数)

sti();接受硬件中断

kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
current->need_resched = 1; need_resched标志增加,调用schedule(调度里面会详细说明)
cpu_idle(NULL) 进入idle循环以消耗空闲的cpu时间片

已经基本完成内核初始化工作,已经把需要完成的少量责任传递给了init,所身于地工作不过是进入idle循环以消耗空闲的cpu时间片。所以在这里调用了cpu_idle(NULL),它从不返回,所以当有实际工作好处理时,该函数就会被抢占。

parse_options函数:
static void __init parse_options(char *line)/*参数收集在一条长命令行中,内核被赋给指向该命令行头部的指针*/
{
char *next;
char *quote;
int args, envs;

if (!*line)
return;
args = 0;
envs = 1;/* TERM is set to 'linux' by default */
next = line;
while ((line = next) != NULL) {

quote = strchr(line,'"');
next = strchr(line, ' ');
while (next != NULL && quote != NULL && quote < next) {

next = strchr(quote+1, '"');
if (next != NULL) {
quote = strchr(next+1, '"');
next = strchr(next+1, ' ');
}
}
if (next != NULL)
*next++ = 0;
/*
* check for kernel options first..
*/
if (!strcmp(line,"ro")) {
root_mountflags |= MS_RDONLY;
continue;
}
if (!strcmp(line,"rw")) {
root_mountflags &= ~MS_RDONLY;
continue;
}
if (!strcmp(line,"debug")) {
console_loglevel = 10;
continue;
}
if (!strcmp(line,"quiet")) {
console_loglevel = 4;
continue;
}
if (!strncmp(line,"init=",5)) {
line += 5;
execute_command = line;
args = 0;
continue;
}
if (checksetup(line))
continue;

if (strchr(line,'=')) {
if (envs >= MAX_INIT_ENVS)
break;
envp_init[++envs] = line;
} else {
if (args >= MAX_INIT_ARGS)
break;
argv_init[++args] = line;
}
}
argv_init[args+1] = NULL;
envp_init[envs+1] = NULL;
}



[这个贴子最后由e4gle在 2002/08/25 06:30pm 编辑]

////////////////////////////////////////////////////////////////////
// setup.txt
// Copyright(C) 2001, Feiyun Wang
////////////////////////////////////////////////////////////////////
// analysis on linux/arch/i386/boot/setup.S (for linux 2.2.17)
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// export the margin tags for .text, .data and .bss
{
.text
begtext:

.data
begdata:

.bss
begbss:
}

////////////////////////////////////////////////////////////////////
.text
start()
SYSSEG = 0x1000
SETUPSEG = 0x9020
modelist = end of .text:
{
// if loaded by bootsect.S,
// you can assume CS=SETUPSEG (=0x9020), otherwise...
goto start_of_setup();

/*
http://lxr.linux.no/source/Documentation/i386/boot.txt
Offset/Size Proto Name Meaning
01F1/1 ALL setup_sects The size of the setup in sectors
01F2/2 ALL root_flags If set, the root is mounted readonly
01F4/2 ALL syssize DO NOT USE - for bootsect.S use only
01F6/2 ALL swap_dev DO NOT USE - obsolete
01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only
01FA/2 ALL vid_mode Video mode control
01FC/2 ALL root_dev Default root device number
01FE/2 ALL boot_flag 0xAA55 magic number
0200/2 2.00+ jump Jump instruction
0202/4 2.00+ header Magic signature "HdrS"
0206/2 2.00+ version Boot protocol version supported
0208/4 2.00+ realmode_swtch Boot loader hook
020C/4 2.00+ start_sys_seg Points to kernel version string
0210/1 2.00+ type_of_loader Boot loader identifier
0211/1 2.00+ loadflags Boot protocol option flags
0212/2 2.00+ setup_move_size Move to high memory size (used with hooks)
0214/4 2.00+ code32_start Boot loader hook
0218/4 2.00+ ramdisk_image initrd load address (set by boot loader)
021C/4 2.00+ ramdisk_size initrd size (set by boot loader)
0220/4 2.00+ bootsect_kludge DO NOT USE - for bootsect.S use only
0224/4 2.01+ heap_end_ptr Free memory after setup end
0226/2 N/A pad1 Unused
0228/4 2.02+ cmd_line_ptr 32-bit pointer to the kernel command line
*/
.ascii "HdrS"
.word 0x0201
realmode_swtch: // boot loader hook
.word 0, 0
start_sys_seg: // pointer to kernel version string
.word SYSSEG
.word kernel_version
type_of_loader:
.byte 0
loadflags:
#ifndef __BIG_KERNEL__
.byte 0x00
#else
.byte LOADED_HIGH = 1
#endif
setup_move_size:
.word 0x8000
code32_start: // boot loader hook
#ifndef __BIG_KERNEL__
.long 0x1000
#else
.long 0x100000
#endif
ramdisk_image: // initrd load address (set by boot loader)
.long 0
ramdisk_size: // initrd size (set by boot loader)
.long 0
bootsect_kludge: // DO NOT USE - for bootsect.S use only
.word bootsect_helper(), SETUPSEG
heap_end_ptr: // free memory after setup end
.word modelist+1024
}

////////////////////////////////////////////////////////////////////
// check signature to see if all code loaded
start_of_setup()
{
// get disk type, bootlin depends on this
// http://www.ctyme.com/intr/rb-0639.htm
int13h/AH=15h(AL=0, DL=0x81);

#ifdef SAFE_RESET_DISK_CONTROLLER
int13h/AH=0(AL=0, DL=0x80); // reset hd0
#endif

// check signature at the end of setup code
if (setup_sig1!=SIG1 || setup_sig2!=SIG2) {
// since size of setup may > 4 sectors,
// the rest code may be loaded at SYSSEG
goto bad_sig;
}
goto goodsig1;
}

////////////////////////////////////////////////////////////////////
// some small functions
prtstr() { /* ... print ASCIIz string at DS:SI */}
prtsp2() { /* ... print double space */ }
prtspc() { /* ... print single space */ }
prtchr() { /* ... print ASCII AL */ }
beep() { /* ... beep */ }

////////////////////////////////////////////////////////////////////
goodsig1() { goto goodsig; } // making near jumps

////////////////////////////////////////////////////////////////////
// move rest setup code from SYSSEG:0 to CS:0800
// TODO: it won't work if image loaded at 0x100000?
bad_sig()
DELTA_INITSEG = 0x0020 (= SETUPSEG - INITSEG)
SYSSEG = 0x1000
{
BX = (CS-DELTA_INITSEG):[497]; // i.e. setup_sects
// first 4 sectors have been loaded
CX = (BX - 4) << 8; // rest code in words
start_sys_seg = (CX >> 3) + SYSSEG; // real system code start

move SYSSEG:0 to CS:0800 (CX*2 bytes);

if (setup_sig1!=SIG1 || setup_sig2!=SIG2) {
prtstr("No setup signature found ...");
halt;
}
}

////////////////////////////////////////////////////////////////////
// check if loader compatible with image
good_sig()
LOADHIGH = 1
{
if ((loadflags & LOADHIGH) && (!type_of_loader)) {
// Nope, old loader want to load big kernel
prtstr("Wrong loader: giving up.");
halt;
}
}

////////////////////////////////////////////////////////////////////
// get memory size
// set the keyboard repeat rate to max
// check video adapter
// get hd0 & hd1 data
// check for Micro Channel (MCA) bus
// check for PS/2 pointing device
// check for APM BIOS
// move code to INITSEG/SETUPSEG
// load IDT and GDT
// enable and test A20
// reset coprocessor
// reprogram the interrupts
// switch to protected mode
// goto KERNEL
loader_ok()
SETUPSET = 0x9020
INITSEG = 0x9000
DELTA_INITSEG = 0x20
{
// DS = CS - DELTA_INITSEG when entering this function

// get memory size
#ifndef STANDARD_MEMORY_BIOS_CALL
(double word)DS:[0x1E0] = 0;
try {
// get memory size for >64M configurations
// http://www.ctyme.com/intr/rb-1739.htm
int15h/AX=E801h;
// AX = extended memory between 1M and 16M, in KB
// BX = extended memory above 16M, in 64K blocks
(double word)DS:[0x1E0] = ((EBX & 0xFFFF) << 6)
+ (EAX & 0xFFFF);
}
#else
(double word)DS:[0x1E0] = 0;
#endif

// get extended memory size
// http://www.ctyme.com/intr/rb-1529.htm
int15h/AH=88h;
DS:[2] = AX; // KB of contiguous memory from 100000h

// set the keyboard repeat rate to max
// http://www.ctyme.com/intr/rb-1757.htm
int16h/AX=0305h(BX=0);

// check video adapter and its parameters, see video.S
video();

// get hd0 & hd1 data
// http://www.ctyme.com/intr/rb-6135.htm
// http://www.ctyme.com/intr/rb-6184.htm
// pointers in 0:0104 & 0:0118 respectively
move hd0 data to CS-DELTA_INITSEG:0080 (16 bytes);
move hd1 data to CS-DELTA_INITSEG:0090 (16 bytes);

// get disk type, check if hd1 exists
// http://www.ctyme.com/intr/rb-0639.htm
int13h/AH=15h(AL=0, DL=0x81);
if (failed || AH!=03h) { // AH=03h if is a hard disk
clear CS-DELTA_INITSEG:0090 (16 bytes);
}

// check for Micro Channel (MCA) bus
DS:[0xA0] = 0; // set table length to 0
try {
// get system configuration
// http://www.ctyme.com/intr/rb-1594.htm
int15h/AH=C0h; // ES:BX = ROM configuration table
move ROM configuration table to CS-DELTA_INITSEG:00A0;
// first 16 bytes only
}

// check PS/2 pointing device
DS:[0x1FF] = 0;
// get equipment list
// http://www.ctyme.com/intr/rb-0575.htm
int11h();
if (has psmouse) {
DS:[0x1FF] = 0xAA;
}

#ifdef CONFIG_APM
// check for APM BIOS

DS:[0x40] = 0;
// Advanced Power Management v1.0+ - installation check
// http://www.ctyme.com/intr/rb-1394.htm
int15h/AX=5300h(BX=0);
// check both CF and BX for APM support
if (APM && 32-bit protected mode interface supported) {
int15h/AX=5304h(BX=0); // disconnect interface
try {
// clear return values first
clear EBX, CX, DX, ESI, DI;
// connect 32bit protect mode APM interface
// http://www.ctyme.com/intr/rb-1397.htm
int15h/AX=5303h(BX=0);
if (supported) {
DS:[0x42] = 32-bit code segment base address;
DS:[0x44] = offset of entry point;
DS:[0x48] = 16-bit code segment base address;
DS:[0x4A] = 16-bit data segment base address;
DS:[0x4E] = APM BIOS code segment length;
DS:[0x52] = APM BIOS data segment length;
int15h/AX=5300h(BX=0); // check again
if (APM supported) {
INITSET:[0x40] = APM version;
INITSET:[0x4C] = APM flags;
}
else { // should not happen
// disconnect interface
int15h/AX=5304h(BX=0);
}
}
else {
// clear 32bit support
INITSET:[0x4C] &= ~0x0002;
}
}
}
#endif

// call mode switch
if (realmode_swtch) {
far realmode_swtch(); // mode switch hook
}
else {
far default_switch(); // see below
}

// set code32: 0x100000 for big kernel, otherwise 0x1000
(double word) code32 = code32_start;
if (!(loadflags & LOADED_HIGH)) {
// normal low loaded zImage
move start_sys_seg:0 to (0100:0 ... CS-DELTA_INITSEG:0);
// move 0x1000 bytes each time
}
if (CS!=SETUPSEG) {
cli; // disable interrupts

// store new SS in DX
DX = SS;
AX = CS - DELTA_INITSEG;
if (DX>=AX) {
DX = DX + INITSEG - AX; // i.e. SS-CS+SETUPSEG
}

// move CS-DELTA_INITSEG:0 to INITSEG:0 (setup_move_size bytes)
// TODO: why not do this in one step?
ES = INITSEG;
move _DOWNWARD_ from CS-DELTA_INITSEG:setup_move_size-1 to
(INITSEG:setup_move_size-1
... INITSEG:move_self_here+0x200);
// setup_move_size-move_self_here-0x200 bytes
// INITSEG:move_self_here+0x200 = SETUPSEG:move_self_here
goto SETUPSEG:move_self_here;
move_self_here:
move the rest to INITSEG:move_self_here+0x200-1 ... INITSEG:0;
// move_self_here+0x200 bytes
DS = SETUPSEG;
SS = DX;
}
// CS==SETUPSEG is true now

// Protected Mode Basics
// http://x86.ddj.com/articles/pmbasics/tspec_a1_doc.htm

lidt idt_48; // load idt with 0, 0;
// new code added here in linux 2.4
lgdt gdt_48; // load gdt with whatever appropriate;

// enable A20
empty_8042();
outportb(0x64, 0xD1); // command write
empty_8042();
outportb(0x60, 0xDF); // A20 on
empty_8042();

#define TEST_ADDR 0x7C

// test A20
GS = AX = 0xFFFF;
BX = 0:[TEST_ADDR];
do {
0:[TEST_ADDR] = ++AX;
} while (AX==GS:[TEST_ADDR+0x10]);
0:[TEST_ADDR] = BX;

// reset coprocessor
outportb(0xF0, 0);
delay();
outportb(0xF1, 0);
delay();

// reprogram the interrupts
outportb(0x20, 0x11); // initialize 8259A-1
delay();
outportb(0xA0, 0x11); // initialize 8259A-2
delay();
outportb(0x21, 0x20); // start of hardware int's (0x20)
delay();
outportb(0xA1, 0x28); // start of hardware int's 2 (0x28)
delay();
outportb(0x21, 0x04); // 8259-1 is master
delay();
outportb(0xA1, 0x02); // 8259-2 is slave
delay();
outportb(0x21, 0x01); // 8086 mode
delay();
outportb(0xA1, 0x01); // 8086 mode
delay();
outportb(0xA1, 0xFF); // mask off all interrupts for now
delay();
outportb(0x21, 0xFB); // mask all irq's but irq2, which is cascaded

// protected mode!
mov ax, #1;
lmsw ax;
jmp flush_instr;
flush_instr:
xor bx, bx;
}

////////////////////////////////////////////////////////////////////
{
db 0x66, 0xea
code32:
dd 0x1000
dw __KERNEL_CS // 0x10, defined in asm-i386/segment.h
// goto 10:1000 or 10:100000

kernel_version:
.ascii UTS_RELEASE // defined in makefile
.ascii "("
.ascii LINUX_COMPILE_BY
.ascii "@"
.ascii LINUX_COMPILE_HOST
.ascii ")"
.ascii UTS_VERSION
db 0
}

////////////////////////////////////////////////////////////////////
// default real mode switch routine
far default_switch()
{
cli;
outportb(0x70, 0x80); // disable NMI
}

////////////////////////////////////////////////////////////////////
// get called when using bootsect loader _AND_ have bzImage to load
far bootsect_helper(ES)
{
if (bootsect_es==0) {
type_of_loader = 0x20; // bootsect-loader, version 0
AX = ES >> 4;
CS:[bootsect_src_base+2] = AH;
bootsect_es = ES;
AX = ES - SYSSEG;
}
else {
if (BX==0) { // 64K aligned
// copy extended memory
// http://www.ctyme.com/intr/rb-1527.htm
try {
int15h/AX=87h(CX=0x8000,
ES:SI=CS:bootsect_gdt);
}
catch {
bootsect_panic:
prtstr("INT15 refuses to access high memory."
" Giving up.");
halt;
}
ES = bootsect_es;
CS:[bootsect_dst_base+2]++;
}
AH = CS:[bootsect_dst_base+2] << 4;
AL = 0;
}
}

////////////////////////////////////////////////////////////////////
{
bootsect_gdt:
.word 0, 0, 0, 0
.word 0, 0, 0, 0
bootsect_src:
.word 0xFFFF
bootsect_src_base:
.byte 0, 0, 1 ! base = 0x010000
.byte 0x93 ! typbyte
.word 0 ! limit16, base24 =0
bootsect_dst:
.word 0xFFFF
bootsect_dst_base:
.byte 0, 0, 0x10 ! base = 0x100000
.byte 0x93 ! typbyte
.word 0 ! limit16, base24 =0
.word 0, 0, 0, 0 ! used by BIOS
.word 0, 0, 0, 0
bootsect_es:
.word 0
}

////////////////////////////////////////////////////////////////////
// check that the keyboard command queue is empty
empty_8042()
{
timeout = 0xFFFFFF; // local variable
for (; {
if (--timeout==0) return;
delay();
inportb(0x64, AL); // 8042 status port
if (AL & 1) { // output buffer
delay();
inportb(0x60, .);
continue;
}
if (!(AL & 2)) return; // input buffer
}
}

////////////////////////////////////////////////////////////////////
// read the CMOS clock, return the seconds in AL
gettime()
{
// get real-time clock time
// http://www.ctyme.com/intr/rb-2273.htm
int1Ah/AH=02h(); // DH = seconds (in BCD)
AL = DH & 0x0F;
AH = DH >> 4;
AAD;
}

////////////////////////////////////////////////////////////////////
delay() { /* needed after doing I/O */ }

////////////////////////////////////////////////////////////////////
{
gdt:
.word 0,0,0,0 ! dummy
.word 0,0,0,0 ! unused

.word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)

.word 0xFFFF ! 4Gb - (0x100000*0x1000 = 4Gb)
.word 0x0000 ! base address=0
.word 0x9200 ! data read/write
.word 0x00CF ! granularity=4096, 386 (+5th nibble of limit)
idt_48:
.word 0 ! idt limit=0
.word 0, 0 ! idt base=0L
gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
.word 512+gdt, 0x9 ! gdt base = 0x9XXXX
// +512 because of bootsect
}

////////////////////////////////////////////////////////////////////
// Included video setup & detection code "video.S"
/*
Positions of various video parameters passed to the kernel
(see also include/linux/tty.h)
CS-DELTA_INITSEG segment
#define PARAM_CURSOR_POS 0x00
#define PARAM_VIDEO_PAGE 0x04
#define PARAM_VIDEO_MODE 0x06
#define PARAM_VIDEO_COLS 0x07
#define PARAM_VIDEO_EGA_BX 0x0a
#define PARAM_VIDEO_LINES 0x0e
#define PARAM_HAVE_VGA 0x0f
#define PARAM_FONT_POINTS 0x10
#define PARAM_LFB_WIDTH 0x12
#define PARAM_LFB_HEIGHT 0x14
#define PARAM_LFB_DEPTH 0x16
#define PARAM_LFB_BASE 0x18
#define PARAM_LFB_SIZE 0x1c
#define PARAM_LFB_LINELENGTH 0x24
#define PARAM_LFB_COLORS 0x26
#define PARAM_VESAPM_SEG 0x2e
#define PARAM_VESAPM_OFF 0x30
#define PARAM_LFB_PAGES 0x32
*/
video()
{
FS = DS;
DS = ES = CS;
GS = 0;
basic_detect();

#ifdef CONFIG_VIDEO_SELECT
if (FS:[0x1FA]!=ASK_VGA) {
// ASK_VGA=0xFFFD, defined in asm-i386/boot.h
mode_set();
if (failed) {
prtstr("You passed an undefined mode number.");
}
}
else {
mode_menu();
}

#ifdef CONFIG_VIDEO_RETAIN
restore_screen();
#endif

#endif

mode_params();
}

////////////////////////////////////////////////////////////////////
SIG1 = 0xAA55
SIG2 = 0x5A5A
{
setup_sig1: .word SIG1
setup_sig2: .word SIG2
modelist:

.text
endtext:

.data
enddata:

.bss
endbss:
}

////////////////////////////////////////////////////////////////////
// end of file







WSS(http://www.whitecell.org)
一个非营利性民间技术组织
致力于各种系统安全技术的研究
坚持传统的hacker精神
追求技术的精纯

编辑  发贴时间2002/08/25 06:23pm 此 IP 为代理服务器IP: 已设置保密
该用户目前不在线 e4gle
 帅哥 此人为版主
头衔: 论坛版主 午马 天秤座



级别: 精灵
魅力: 2286
经验: 1824
金钱: 5165 幽妮石
来自: WSS 
总发贴数: 232 篇
注册日期: 2002/08/14
消息 查看 搜索 好友 邮件 主页 复制 引用 回复贴子回复 

[这个贴子最后由e4gle在 2002/08/25 06:30pm 编辑]

////////////////////////////////////////////////////////////////////
// bootsect.txt
////////////////////////////////////////////////////////////////////
// Copyright(C) 2001, Feiyun Wang
// analysis on linux/arch/i386/boot/bootsect.S (linux 2.2.17)
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
#if 0
int 3;// for debugger
#endif

_main()
BOOTSEG = 0x07C0
INITSEG = 0x9000
{
move BOOTSEG:0 to INITSEG:0 (512 bytes);
goto INITSEG:go; // CS:IP = INITSEG:go
}

////////////////////////////////////////////////////////////////////
// prepare disk parameter table
go()
INITSEG = 0x9000
{
set SS:SP to INITSEG:3FF4;// 0x4000-0x0C
copy disk parameter table (pointer in 0:0078)
to INITSEG:3FF4 (12 bytes);
patch sector count to 36 (offset 4 in parameter table, 1 byte);
set disk parameter table pointer (0:0078) to INITSEG:3FF4;
}

////////////////////////////////////////////////////////////////////
// load the setup-sectors directly after the bootblock
load_setup()
setup_sects = SETUPSECS = 4
INITSEG = 0x9000
{
for(; {
int13h/AH=0(DL=0); // reset FDC
try {
// http://www.ctyme.com/intr/rb-0607.htm
int13h/AH=02h(AL=setup_sects,
ES:BX=INITSEG:0200,
CX=2, DX=0);
break;
}
catch (disk error) {
print_nl();
print_hex(SP);
}
}
}

////////////////////////////////////////////////////////////////////
// get disk drive parameters, specifically sectors#/track
ok_load_setup()
global variables: disksizes, sectors
{
#if 0
// get disk drive parameters
// http://www.ctyme.com/intr/rb-0621.htm
int13h/AH=08h(DL=0);
CH = 0;
// seems not completed yet
#else
// probe sectors with disksize[] = {36, 18, 15, 9}
SI = &disksizes;
for (; {
sectors = DS:[SI++];
if (SI>=disksizes+4) break;
try {
int13h/AH=02h(AL=1,
ES:BX=INITSEG(setup_sects+1)<<9),
CX=sectors, DX=0);
break;
}
catch {
}
}
#endif
}

////////////////////////////////////////////////////////////////////
// print out "Loading"
// load the system image
// set root_dev
// jump to the setup-routine loaded directly after the bootblock
got_sectors()
INITSEG = 0x9000
SYSSEG = 0x1000
SETUPSEG = 0x9020
global variable: root_dev
{
// int10h/AH=03h http://www.ctyme.com/intr/rb-0088.htm
// int10h/AH=13h http://www.ctyme.com/intr/rb-0210.htm
print out "Loading";

read_it(ES=SYSSEG);
kill_motor();
print_nl();

if (!root_dev) {
switch (sectors) {
case 15: root_dev = 0x0208;// /dev/ps0 - 1.2Mb
break;
case 18: root_dev = 0x021C;// /dev/PS0 - 1.44Mb
break;
case 36: root_dev = 0x0220;// /dev/fd0H2880 - 2.88Mb
break;
default: root_dev = 0x0200;// /dev/fd0 - autodetect
break;
}
}

goto SETUPSEG:0;
// see linux/arch/i386/boot/setup.S
}

word sread = 0; // sectors read of current track
word head = 0; // current head
word track = 0; // current track
////////////////////////////////////////////////////////////////////
// load the system image
read_it(ES)
setup_sects = SETUPSECS = 4
SYSSEG = 0x1000
syssize = SYSSIZE = 0x7F00
{
sread = setup_sects + 1; // plus 1 bootsect
if (ES & 0x0fff) halt; // not 64KB aligned
BX = 0;

for (; {
rp_read:
#ifdef __BIG_KERNEL__
.word 0x1eff, 0x220;
// call far * bootsect_kludge, see setup.S
#else
AX = ES - SYSSEG;
#endif
if (AX>syssize) return;

ok1_read:
// get proper AL (sectors to read),
// not to across tracks or make BX overflow
AX = sectors - sread;
CX = BX + (AX << 9);
// TODO: I think CX!=0 can be omitted
if (CX overflow && CX!=0) {
AX = (-BX) >> 9;
}
ok2_read:
read_track(AL, ES:BX);
CX = AX;
AX += sread;
if (AX==sectors) {
if (head==1) track++;
head = 1 - head;
AX = 0;
}
ok3_read:
sread = AX;
BX += CX << 9;
if (BX overflow) {
ES += 0x1000;
BX = 0;
}
}
}

////////////////////////////////////////////////////////////////////
// read disk with (sread, track, head)
read_track(AL, ES:BX)
{
for (; {
printf(".");

// set CX, DX according to (sread, track, head)
DX = track;
CX = sread + 1;
CH = DL;

DX = head;
DH = DL;
DX &= 0x0100;

try {
int13h/AH=02h(AL, ES:BX, CX, DX);
return;
}
catch (disk error) {
bad_rt:
print_all();
int13h/AH=0h(DL=0); // reset FDC
}
}
}

////////////////////////////////////////////////////////////////////
// some small functions
print_all() { /* ... print out error, AX, BX, CX, DX */ }
print_nl() { /* ... print CR LF */ }
print_hex() { /* ... print the word pointed by SS:BP in hex */ }
kill_motor() { outportb(0x3F2, 0); /* turn off floppy drive motor */}

////////////////////////////////////////////////////////////////////
// global variables for bootsect.S
{
sectors:
.word 0
disksizes:
.byte 36, 18, 15, 9
msg1:
.byte 13, 10
.ascii "Loading"

/*
http://lxr.linux.no/source/Documentation/i386/boot.txt
Offset/Size Proto Name Meaning
01F1/1 ALL setup_sects The size of the setup in sectors
01F2/2 ALL root_flags If set, the root is mounted readonly
01F4/2 ALL syssize DO NOT USE - for bootsect.S use only
01F6/2 ALL swap_dev DO NOT USE - obsolete
01F8/2 ALL ram_size DO NOT USE - for bootsect.S use only
01FA/2 ALL vid_mode Video mode control
01FC/2 ALL root_dev Default root device number
01FE/2 ALL boot_flag 0xAA55 magic number
*/
.org 497
setup_sects:
.byte SETUPSECS
root_flags:
.word CONFIG_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
}

////////////////////////////////////////////////////////////////////
// end of file




[这个贴子最后由e4gle在 2002/08/25 06:30pm 编辑]

////////////////////////////////////////////////////////////////////
// head.txt
// Copyright(C) 2001, Feiyun Wang
////////////////////////////////////////////////////////////////////
// analysis on linux/arch/i386/kernel/head.S (for linux 2.2.17)
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
startup_32()
__KERNEL_DS = 0x18;
CL_MAGIC = 0xA33F;
CL_MAGIC_ADDR = 0x90020;
CL_BASE_ADDR = 0x90000;
CL_OFFSET = 0x90022;
{
cld;
DS = ES = FS = GS = __KERNEL_DS (= 0x18);

#ifdef __SMP__
if (BX) {
CR4 |= mmu_cr4_features-__PAGE_OFFSET;
// mmu_cr4_features defined in arch/i386/mm/init.c
// __PAGE_OFFSET defined in include/asm-i386/page.h
}
#endif

CR3 = 0x101000;// page table pointer
CR0 |= 0x80000000;// set PG bit

SS:ESP = stack_start;

#ifdef __SMP__
if (BX) {
EFLAG = 0;
goto checkCPUtype;
}
#endif

clear BSS (__bss_start .. _end);
setup_idt();
EFLAGS = 0;
move 0x90000 to empty_zero_page (i.e. 0x5000) (2 KByte);
clear empty_zero_page+2K (2 KByte);

if (CL_MAGIC==*(CL_MAGIC_ADDR)) {
move *(CL_OFFSET)+CL_BASE_ADDR to empty_zero_page+2K (2 KByte);
}
}

////////////////////////////////////////////////////////////////////
checkCPUtype()
global variables: ready
// see include/asm-i386/processor.h struct cpuinfo_x86
// boot_cpu_data defined in arch/i386/kernel/setup.c
struct cpuinfo_x86 boot_cpu_data;
__KERNEL_DS = 0x18;
{
X86_CPUID = -1;

X86 = 3;
save original EFLAGS;
check AC bit in EFLAGS;
if (AC bit not changed) goto is386;

X86 = 4;
check ID bit in EFLAGS;
restore original EFLAGS;
if (ID bit not changed) goto is486;

// get CPU info,
// <> Vol.2 P.3-110
CPUID(EAX=0);
X86_CPUID = EAX;
X86_VENDOR_ID = EBX;
*((&X86_VENDOR_ID)+4) = ECX;
*((&X86_VENDOR_ID)+8) = EDX;
if (!EAX) goto is486;

CPUID(EAX=1);
CL = AL;
X86 = AH & 0x0f;// family
X86_MODEL = (AL & 0xf0) >> 4;// model
X86_MASK = AL & 0x0f;// stepping id
X86_CAPABILITY = EDX;// feature

is486:
// save PG, PE & ET, set AM, WP, NE & MP
EAX = (CR0 & 0x80000011) | 0x50022;
goto 2f;
is386:
restore original EFLAGS;
// save PG, PE & ET, set MP
EAX = (CR0 & 0x80000011) | 0x02;
2f:
CR0 = EAX;
check_x87();

#ifdef __SMP__
if (ready) {
CR4 |= 0x10;// set PSE, turn on 4 MByte pages
CR3 = CR3;
}
ready++;
#endif;

lgdt gdt_descr;
lidt idt_descr;
DS = ES = FS = GS = __KERNEL_DS (= 0x18);

#ifdef __SMP__
SS = __KERNEL_DS (= 0x18);
#else
SS:ESP = stack_start;
#endif

lldt 0;
cld;
start_kernel();
halt;
}

////////////////////////////////////////////////////////////////////
{
#ifdef __SMP__
ready:.byte 0;
#endif
}

////////////////////////////////////////////////////////////////////
check_x87()
{
X86_HARD_MATH = 0;
clts;
fninit;
fstsw ax;
if (al) {
// no coprocessor, set EM;
// TODO; why not use |=?
cr0 ^= 0x04;
}
else {
X86_HARD_MATH = 1;
fsetpm;// 0xDB, 0xE4
}
}

////////////////////////////////////////////////////////////////////
setup_idt()
{
edx = &ignore_int;
eax = __KERNEL_CS << 16;
ax = dx;
dx = 0x8E00;// interrupt gate, dpl = 0, present

set all entries in idt_table to eax:edx;// 256*8 Bytes
}

////////////////////////////////////////////////////////////////////
{
stack_start:
.long init_task_union+8192;
.long __KERNEL_DS;
}

////////////////////////////////////////////////////////////////////
ignore_init()
{
printk("Unknown interrupt ");
}

////////////////////////////////////////////////////////////////////
{
NR_TASKS = 512;// defined in include/linux/tasks.h
IDT_ENTRIES = 256;
GDT_ENTRIES = 12+2*NR_TASKS;

.word 0;
idt_descr:
.word IDT_ENTRIES*8-1;
idt:
.long idt_table;

.word 0;
gdt_descr:
.word GDT_ENTRIES*8-1;
gdt:
.long gdt_table;
}

////////////////////////////////////////////////////////////////////
{
.org 0x1000;
swapper_pg_dir:
.long 0x00102007;
.fill __USER_PGD_PTRS-1, 4, 0;// 767 entries
.long 0x00102007;
.fill __KERNEL_PGD_PTRS-1, 4, 0;// 255 entries

.org 0x2000;
pg0:
// ...

.org 0x3000;
empty_bad_page:

.org 0x4000;
empty_bad_page_table:

.org 0x5000;
empty_zero_page:

.org 0x6000;
.data
gdt_table:
.quad 0x0000000000000000;// null
.quad 0x0000000000000000;// not used
.quad 0x00cf9a000000ffff;// 0x10 kernel 4GB code at 0x00000000
.quad 0x00cf92000000ffff;// 0x18 kernel 4GB data at 0x00000000
.quad 0x00cffa000000ffff;// 0x20 user 4GB code at 0x00000000
.quad 0x00cff2000000ffff;// 0x28 user 4GB data at 0x00000000
.quad 0x0000000000000000;// not used
.quad 0x0000000000000000;// not used

.quad 0x0040920000000000;// 0x40 APM setup for bad BIOS
.quad 0x00409a0000000000;// 0x48 APM CS code
.quad 0x00009a0000000000;// 0x50 APM CS 16 code (16 bit)
.quad 0x0040920000000000;// 0x58 APM DS data
.fill 2*NR_TASKS, 8, 0;

.section .text.lock
stext_lock:
}

////////////////////////////////////////////////////////////////////
// end of file





全文结束


所有分类
1: 非技术类

2: 基础知识

3: 指令大全

4: shell

5: 安装启动

6: xwindow

7: kde

8: gnome

9: 输入法类

10: 美化汉化

11: 网络配置

12: 存储备份

13: 杂项工具

14: 编程技术

15: 网络安全

16: 内核技术

17: 速度优化

18: apache

19: email

20: ftp服务

21: cvs服务

22: 代理服务

23: samba

24: 域名服务

25: 网络过滤

26: 其他服务

27: nfs

28: oracle

29: dhcp

30: mysql

31: php

32: ldap
posted on 2005-07-04 19:30 【Z&Y】幸福小筑 阅读(1045) 评论(3)  编辑 收藏 引用 所属分类: Linux源码分析

评论:
# re: linux内核分析----初始化 2010-06-18 17:34 | StantonLisa
Wow, superb research referring to this topic. Can wish to tell me how long time that would take? Because I am willing to create some thesis project or may be that will be better to detect the <a href="http://www.topthesis.com">thesis writing</a>. Thnx.   回复  更多评论
  
# re: linux内核分析----初始化 2010-06-18 23:39 | thesis writing service
If you want to enlarge your knowledge about this post, look for thesis writing service or buy dissertation service and buy professional phd thesis over there.   回复  更多评论
  
# re: linux内核分析----初始化 2013-04-02 10:00 | BuyEssay rewiew
Have a desire to get to know about essay paper services? Searching for reliable company to get aid from? MarvelousEssays rewiew "best-writing-services.com" will give you a register of companies from which pupils can choose the most reliable ones to buy essay from.  回复  更多评论
  
只有注册用户登录后才能发表评论。