原文作者:feiyunw 和 raoxianhong
---------------------------------------------------------------------------
feiyunw 的开场篇:
---------------------------------------------------------------------------
应lucian_yao的建议,我把我写的初始化分析的文章重贴到文档版。
(原先贴在内核技术版,现在又做了一些修改)
写这些东西是因为当时看程序时找不到类似的东西,干脆就自己写了:
bootsect.txt linux/arch/i386/boot/bootsect.S
setup.txt linux/arch/i386/boot/setup.S
head.txt linux/arch/i386/kernel/head.S
希望对大家学习Linux有帮助。
基于Linux 2.2.17是因为我用Redhat7.0。
当时Redhat7.0用Linux2.2.16,我想17和16的差别比较小,就用了17做分析。
关于版权说明:还不知道使用什么声明比较合适,所以就把Copyright留在文件里了。
我认为GPL适合free software,对这种文档性质的东西可能不太合适。
不过可以参照GPL的“free software”使用这些“free document”。
---------------------------------------------------------------------------
读代码前先看看 raoxianhong 的中文版bootsect.txt :
---------------------------------------------------------------------------
看程序太累,请看中文版的bootsect.txt
1.将自己移动到0x9000:0x0000处,为内核调入留出地址空间;
2.建立运行环境(ss=ds=es=cs=0x9000, sp=0x4000-12),保证起动程序运行;
3.BIOS初始化0x1E号中断为软盘参数表,将它取来保存备用;
4.将setup读到0x9000:0x0200处;
5.测试软盘参数一个磁道有多少个扇区(也没有什么好办法,只能试试36, 18, 15, 9对不对了);
6.打印“Loading”;
7.读入内核到0x1000:0000(如果是bzImage, 则将每个64K移动到0x100000处,在实模式下,只能调用0x15号中断了,这段代码无法放在bootsect中所以只能放在setup中,幸好此时setup已经读入了);
8.到setup去吧
---------------------------------------------------------------------------
下面是 feiyunw 的代码分析:
---------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////
// 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 {
//
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
//
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
// int10h/AH=13h
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
阅读(525) | 评论(0) | 转发(0) |