Chinaunix首页 | 论坛 | 博客
  • 博客访问: 34875
  • 博文数量: 16
  • 博客积分: 1425
  • 博客等级: 上尉
  • 技术积分: 135
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-06 15:00
文章分类

全部博文(16)

文章存档

2011年(1)

2010年(5)

2009年(4)

2008年(6)

我的朋友

分类: LINUX

2008-07-15 23:37:44

原文作者: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  的代码分析:
---------------------------------------------------------------------------

CODE:
////////////////////////////////////////////////////////////////////
// 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


阅读(507) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~