zoukankan      html  css  js  c++  java
  • linux0.11-----从启动程序开始

      今天终于鼓起勇气在博客园开博,博客是个分享经验、交流知识的地方,最近在研究linux0.11内核,想把自己的所学记录下来,以备后用。欢迎大家留言批评指正或联系 islandscape@163.com,也欢迎大家一起学习、一起进步。

      当我们按下计算机电源键后发生了什么呢?主板接收到一个启动信号,启动供电系统后BIOS进行自检,若发现某个部件不能正常工作系统将进入死循环。所有硬件都通过自检后,系统将控制权交给BIOS。BIOS按照配置顺序读驱动器,将驱动器的第一个扇区(512B)加载到物理地址0x7c00地址,找到启动扇区后从0x7c00这个地址执行启动程序。为什么BIOS会把第一个扇区加载到0x7c00?这是早期设计者们约定的。

      下面看一段启动程序,这段程序开机后会显示“hello world”字样。

        mov ax,0x7c0
        mov ds,ax
        mov es,ax
        jmp go
    go:                      
        mov   cx,11                                    
        mov   dx,0x1004                                 
        mov   bx,0x000c                        
        mov   bp,msg                                   
        mov   ax,0x1301                                
        int    0x10  
    loop:
        jmp loop                                     
    msg:
        DB "hello world"	
    times 510-($-$$) db 0 
    boot_flag:
        DW 0xAA55 

      mov ax,0x7c0,将寄存器ax赋值为立即数0x7c0。之后将段寄存器ds、es赋值为0x7c0。不直接赋值ds、es为0x7c0的原因是所有段寄存器(cs、ds、es、ss)都是对用户不可见的,不能直接对段寄存器操作,只能通过通用寄存器间接赋值。

      为什么是把0x7c0赋值给段寄存器而不是别的值?最早的处理器8086 CPU数据总线是16位的(CPU寄存器是16位的),而地址总线是20位的。16位的寄存器只能寻址到64k(1^16B)远远小于20位地址线能够表示的寻址范围(1--1^20B(1M))。采用单个寄存器寻址总会有4位地址线是浪费的,于是大牛们想出了一种方法:由两个寄存器组成一个寻址单元,一个寄存器的值左移四位(这就变成20位了)再加上另一个寄存器的值就得到了真正寻址地址。这样很像把1M物理地址分成了2^4=16个段,每个段大小是2^16B=64k。偏移四位的寄存器叫做段寄存器,段寄存器有CS、DS、SS、ES、FS、GS六个,另一个寄存器表示段内偏移,一般用通用寄存器表示。这就是大名鼎鼎的实模式寻址,也被写做seg:off,seg为段寄存器、off是段内偏移。常见的寄存器寻址组合有cs:ip 、ss:sp、es:di、ds:bx、ds:ax、ds:cx等。计算机上电后进入实模式,采用上述寻址方式,前面提到bios将该程序加载到0x7c00地址并执行。0x7c0<<4 = 0x7c00,这正是将段寄存器设为0x7c0的原因。

      jmp指令是段内转跳指令,段内转跳的意思是跳到该段的另一个偏移地址。对应的段间转跳(jmpi seg,off)是跳到不同段的不同偏移地址执行。jmp go表示执行标记为go的代码。go在汇编中是一个标识,它会被编译器翻译成一个偏移地址0xyyyy,而jmp go运行时为jmp 0xyyyy。有了这个标识,编译器会帮我们算好这个偏移地址,我们可以把心思放在程序上面。

      从go标识到loop这段代码把“hello world”采用BIOS 0x10号中断输出到屏幕上,之后程序陷入死循环(jmp loop)。

      BIOS中断在实模式中很重要,很多操作如读磁盘、屏幕输出都是通过它完成的。0x10号中断使用方法如下:

    1. ------------------------------------------------------------------  
    2.             INT 0x10功能0x13  
    3. ------------------------------------------------------------------
    4. 描述:  
    5.     以电传打字机的方式显示字符串  
    6. 接受参数:  
    7.     AH          0x13  
    8.     AL          显示模式  
    9.     BH          视频页  
    10.     BL          属性值(如果AL=0x00或0x01)  
    11.     CX          字符串的长度  
    12.     DH,DL     屏幕上显示起始位置的行、列值  
    13.     ES:BP     字符串的段:偏移地址  
    14. 返回值:  
    15.     无  
    16. 显示模式(AL):  
    17.     0x00:字符串只包含字符码,显示之后不更新光标位置,属性值在BL中  
    18.     0x01:字符串只包含字符码,显示之后更新光标位置,属性值在BL中  
    19.     0x02:字符串包含字符码及属性值,显示之后不更新光标位置  
    20.     0x03:字符串包含字符码及属性值,显示之后更新光标位置  
    21. ------------------------------------------------------------------- 

      $意为当前地址、$$是程序起始地址,($-$$)表示程序的长度,times 510-($-$$) db 0将程序末尾到地址510全部填充0。DW 0xAA55将程序的511、512字节填充为0xAA55。为什么要这样做? BIOS依次将驱动器上磁盘第一个扇区(512B)加载到地址0x7c00,若该扇区最后两个字节为0xAA55,则被认为是启动扇区,如果不是则继续寻找下一个驱动器。故谢煜波将引导程序特点归结为三点:1、必须有不多不少512个字节。2、必须放在第一个扇区。3、最后两字节必须为0xAA55。

    参考资料:

      0x10号BIOS中断使用方法摘自:http://blog.csdn.net/guzhou_diaoke/article/details /8397658

      谢煜波,《操作系统引导探究》

      赵炯, 《linux内核完全注释》

  • 相关阅读:
    HDU 2001 计算亮点间的距离
    HDU 1003 Max Sum
    HDU 2091 空心三角形
    HDU 2021 发工资咯:)
    HDU 2028Lowest Common Multiple Plus
    asp.net面试题
    BSD socket
    循环添加textbox的数据
    总结一下网站注入与防范的方法
    net生成12位随机数
  • 原文地址:https://www.cnblogs.com/islandscape/p/3415537.html
Copyright © 2011-2022 走看看