Linux操作系统内核引导程序详细剖析
2009-06-30 03:24:00 来源:WEB开发网核心提示:这段程序是Linux操作系统启动boot程序,其思想原理可参看本人翻译的《Linux内核 漫游》一篇,Linux操作系统内核引导程序详细剖析, 中文注释:赵炯 gohigh@shtdu.edu.cn www.freedove.com ! bootsect.s (c) 1991, 1992 Linus Torvalds
这段程序是Linux操作系统启动boot程序,其思想原理可参看本人翻译的《Linux内核
漫游》一篇。
中文注释:赵炯 gohigh@shtdu.edu.cn www.freedove.com
! bootsect.s (c) 1991, 1992 Linus Torvalds 版权所有
! Drew Eckhardt修改过
! Bruce Evans (bde)修改过
!
! bootsect.s 被bios-启动子程序加载至0x7c00 (31k)处,并将自己
! 移到了地址0x90000 (576k)处,并跳转至那里。
!
! bde - 不能盲目地跳转,有些系统可能只有512k的低
! 内存。使用中断0x12来获得(系统的)最高内存、等。
!
! 它然后使用BIOS中断将setup直接加载到自己的后面(0x90200)(576.5k),
! 并将系统加载到地址0x10000处。
!
! 注意! 目前的内核系统最大长度限制为(8*65536-4096)(508k)字节长,即使是在
! 将来这也是没有问题的。我想让它保持简单明了。这样508k的最大内核长度应该
! 是足够了,尤其是这里没有象minix中一样包含缓冲区高速缓冲(而且尤其是现在
! 内核是压缩的 :-)
!
! 加载程序已经做的尽量地简单了,所以持续的读出错将导致死循环。只能手工重启。
! 只要可能,通过一次取得整个磁道,加载过程可以做的很快的。
#include /* 为取得CONFIG_ROOT_RDONLY参数 */
!! config.h中(即autoconf.h中)没有CONFIG_ROOT_RDONLY定义!!!?
#include
.text
SETUPSECS = 4 ! 默认的setup程序扇区数(setup-sectors)的默认值;
BOOTSEG = 0x7C0 ! bootsect的原始地址;
INITSEG = DEF_INITSEG ! 将bootsect程序移到这个段处(0x9000) - 避开;
SETUPSEG = DEF_SETUPSEG ! 设置程序(setup)从这里开始(0x9020);
SYSSEG = DEF_SYSSEG ! 系统加载至0x1000(65536)(64k)段处;
SYSSIZE = DEF_SYSSIZE ! 系统的大小(0x7F00): 要加载的16字节为一节的数;
!! 以上4个DEF_参数定义在boot.h中:
!! DEF_INITSEG 0x9000
!! DEF_SYSSEG 0x1000
!! DEF_SETUPSEG 0x9020
!! DEF_SYSSIZE 0x7F00 (=32512=31.75k)*16=508k
! ROOT_DEV & SWAP_DEV 现在是由"build"中编制的;
ROOT_DEV = 0
SWAP_DEV = 0
#ifndef SVGA_MODE
#define SVGA_MODE ASK_VGA
#endif
#ifndef RAMDISK
#define RAMDISK 0
#endif
#ifndef CONFIG_ROOT_RDONLY
#define CONFIG_ROOT_RDONLY 1
#endif
! ld86 需要一个入口标识符,这和通常的一样;
.globl _main
_main:
#if 0 /* 调试程序的异常分支,除非BIOS古怪(比如老的HP机)否则是无害的 */
int 3
#endif
mov ax,#BOOTSEG !! 将ds段寄存器置为0x7C0;
mov ds,ax
mov ax,#INITSEG !! 将es段寄存器置为0x9000;
mov es,ax
mov cx,#256 !! 将cx计数器置为256(要移动256个字, 512字节);
sub si,si !! 源地址 ds:si=0x07C0:0x0000;
sub di,di !! 目的地址es:di=0x9000:0x0000;
cld !! 清方向标志;
rep !! 将这段程序从0x7C0:0(31k)移至0x9000:0(576k)处;
movsw !! 共256个字(512字节)(0x200长);
jmpi go,INITSEG !! 间接跳转至移动后的本程序go处;
! ax和es现在已经含有INITSEG的值(0x9000);
go: mov di,#0x4000-12 ! 0x4000(16k)是>=bootsect + setup 的长度 +
! + 堆栈的长度 的任意的值;
! 12 是磁盘参数块的大小 es:di=0x94000-12=592k-12;
! bde - 将0xff00改成了0x4000以从0x6400处使用调试程序(bde)。如果
! 我们检测过最高内存的话就不用担心这事了,还有,我的BIOS可以被配置为将wini驱动
表
! 放在内存高端而不是放在向量表中。老式的堆栈区可能会搞乱驱动表;
mov ds,ax ! 置ds数据段为0x9000;
mov ss,ax ! 置堆栈段为0x9000;
mov sp,di ! 置堆栈指针INITSEG:0x4000-12处;
/*
* 许多BIOS的默认磁盘参数表将不能
* 进行扇区数大于在表中指定
* 的最大扇区数( - 在某些情况下
* 这意味着是7个扇区)后面的多扇区的读操作。
*
* 由于单个扇区的读操作是很慢的而且当然是没问题的,
* 我们必须在RAM中(为第一个磁盘)创建新的参数表。
* 我们将把最大扇区数设置为36 - 我们在一个ED 2.88驱动器上所能
* 遇到的最大值。
*
* 此值太高是没有任何害处的,但是低的话就会有问题了。
*
* 段寄存器是这样的: ds=es=ss=cs - INITSEG,(=0X9000)
* fs = 0, gs没有用到。
*/
! 上面执行重复操作(rep)以后,cx为0;
mov fs,cx !! 置fs段寄存器=0;
mov bx,#0x78 ! fs:bx是磁盘参数表的地址;
push ds
seg fs
lds si,(bx) ! ds:si是源地址;
!! 将fs:bx地址所指的指针值放入ds:si中;
mov cl,#6 ! 拷贝12个字节到0x9000:0x4000-12开始处;
cld
push di !! 指针0x9000:0x4000-12处;
rep
movsw
pop di !! di仍指向0x9000:0x4000-12处(参数表开始处);
pop si !! ds => si=INITSEG(=0X9000);
movb 4(di),*36 ! 修正扇区计数值;
seg fs
mov (bx),di !! 修改fs:bx(0000:0x0078)处磁盘参数表的地址为0x9000:0x4000-12;
seg fs
mov 2(bx),es
! 将setup程序所在的扇区(setup-sectors)直接加载到boot块的后面。!! 0x90200开始处
;
! 注意,es已经设置好了。
! 同样经过rep循环后cx为0
load_setup:
xor ah,ah ! 复位软驱(FDC);
xor dl,dl
int 0x13
xor dx,dx ! 驱动器0, 磁头0;
mov cl,#0x02 ! 从扇区2开始,磁道0;
mov bx,#0x0200 ! 置数据缓冲区地址=es:bx=0x9000:0x200;
! 在INITSEG段中,即0x90200处;
mov ah,#0x02 ! 要调用功能号2(读操作);
mov al,setup_sects ! 要读入的扇区数SETUPSECS=4;
! (假释所有数据都在磁头0、磁道0);
int 0x13 ! 读操作;
jnc ok_load_setup ! ok则继续;
push ax ! 否则显示出错信息。保存ah的值(功能号2);
call print_nl !! 打印换行;
mov bp,sp !! bp将作为调用print_hex的参数;
call print_hex !! 打印bp所指的数据;
pop ax
jmp load_setup !! 重试!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!INT 13 - DISK - READ SECTOR(S) INTO MEMORY
!! AH = 02h
!! AL = number of sectors to read (must be nonzero)
!! CH = low eight bits of cylinder number
!! CL = sector number 1-63 (bits 0-5)
!! high two bits of cylinder (bits 6-7, hard disk only)
!! DH = head number
!! DL = drive number (bit 7 set for hard disk)
!! ES:BX -> data buffer
!! Return: CF set on error
!! if AH = 11h (corrected ECC error), AL = burst length
!! CF clear if successful
!! AH = status (see #00234)
!! AL = number of sectors transferred (only valid if CF set for some
!! BIOSes)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ok_load_setup:
! 取得磁盘驱动器参数,特别是每磁道扇区数(nr of sectors/track);
#if 0
! bde - Phoenix BIOS手册中提到功能0x08只对硬盘起作用。
! 但它对于我的一个BIOS(1987 Award)不起作用。
! 不检查错误码是致命的错误。
- ››linux下两台服务器文件实时同步方案设计和实现
- ››Linux文件描述符中的close on exec标志位
- ››Linux下管道使用的一些限制
- ››Linux 误删/usr/bin 解决方法
- ››linux 添加新用户并赋予sudo执行权限
- ››linux常用软件安装方法
- ››Linux的分区已经被你从Windows中删除,系统启动后...
- ››linux enable命令大全
- ››Linux实现基于Loopback的NVI(NAT Virtual Interfa...
- ››Linux远程访问windows时,出现"连接被对端重...
- ››linux中使用head命令和tail命令查看文件中的指定行...
- ››linux swap 分区调控(swap分区 lvm管理)
更多精彩
赞助商链接