分享
 
 
 

linux内核分析----初始化

王朝system·作者佚名  2008-05-18
窄屏简体版  字體: |||超大  

参考我提供的三个文件: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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有