资料分类
硬件内存 |主板 |CPU |硬盘 |显卡 |网卡 |声卡 |光驱 | 笔记本专区 | 刻录机| 鼠标| 键盘 |病毒专题

办公:打印机|扫描仪|复印机 网络ADSL|局域网| 防火墙 | 路由器 | 无线网络 | 系统winxp win2003 winvisa 服务器

常用维修软件: GHOST | DM | PC3000 | NDD | PQMagic | 效率源 | 还原精灵 电子基础: 电子元件 | 工具应用 | 电路基础
您现在的位置: 龙腾电脑维修网 >> 技术资料 >> 软件专栏 >> linux >> 文章正文

剖析Linux内核引导程序

剖析Linux内核引导程序


剖析Linux内核引导程序:
这段程序是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)不起作用。 
  
  ! 不检查错误码是致命的错误。 
   
  • 上一篇文章:

  • 下一篇文章:

  • 如果您发现该文章有错误,请通知管理员,谢谢!
    作者:佚名
    点击数:
    更新时间:2006-12-13 16:56:37
    我要发表评论
    本站论坛
    返回文章首页
    我要发表文章
    评论内容只代表网友观点,与本站立场无关!

    公司简介 - 联系方法 - 合作伙伴 - RSS订阅 - 意见反馈 - Dragon computer(龙腾电脑英文站) - 版权声明
    @ 2006-2008龙腾电脑 版权所有. ALL RIGHTS RESERVED. 浙ICP备05046531号
    友情连接QQ:42738612 本站QQ群:28651784 26926005