zoukankan      html  css  js  c++  java
  • linux0.11内核源码——boot和setup部分

      https://blog.csdn.net/KLKFL/article/details/80730131

      https://www.cnblogs.com/joey-hua/p/5528228.html

    参考的两篇博客

    x86系统在刚开机时CPU处于实模式

     计算机在刚打开电源时 :CS=0xFFFF,IP=0x0000

    即寻址为0xFFFF0(ROM BIOS映射区)

    然后将 0磁道0扇区 的512个字节读入0x7c00处

    然后设置   CS=0x07c0,IP=0x0000

    此时0x7c00出存放的代码就是从磁盘的引导扇区读入的那512个字节bootsect

    此时一些宏的定义:

     BOOTSEG = 0x07c0

     INITSEG = 0x9000

     SETUPSEG = 0x9020

     SYSSEG = 0x1000

    表示bootsect先被加载到了0x07c0段,然后bootsect的512个字节会被移动到0x9000段,紧跟着的setup段就从0x9020段开始,system段从0x1000开始

    bootsect做的事就是把setup加载到内存上,然后显示logo

     1 entry _start !程序的入口是_start 
     2 
     3 _start:
     4     !下面是调用0x10中断,显示光标操作 
     5     mov ah,#0x03        
     6     xor bh,bh
     7     int 0x10
     8      
     9     mov cx,#36       !字符串msg的长度 
    10     mov bx,#0x0007   !调用0x10中断时,bx寄存器=0x0007表示显示树形 
    11     mov bp,#msg1      
    12     mov ax,#0x07c0
    13     mov es,ax         !es:bp表示要显示的字符串的地址,当前段(bootsect)就是0x07c0,字符串的地址已经赋值给bp 
    14     mov ax,#0x1301        
    15     int 0x10         !调用中断显示logo 
    16 
    17 !设置一个死循环保证不退出 
    18 inf_loop:
    19     jmp inf_loop  
    20     
    21     
    22 !这就是要显示的logo 
    23 msg1:
    24     .byte   13,10                     
    25     .ascii  "Hello OS world, my name is LZJ"
    26     .byte   13,10,13,10               
    27 
    28 
    29 !boot_flag是设置引导扇区的标记,必须由这个才能进行引导,且必须放在最后两个字节
    30 !bootsect的大小是512个字节,所以boot_flag得放在第510个字节处 
    31 .org 510
    32 boot_flag:
    33     .word   0xAA55      

    然后用bootsect读取setup

    先把setup.s编写好

     1 entry _start
     2 _start:
     3     mov ah,#0x03        
     4     xor bh,bh
     5     int 0x10
     6     
     7     mov cx,#25              
     8     mov bx,#0x0007     
     9     mov bp,#msg2
    10     mov ax,cs 
    11     mov es,ax    !此时已经将setup加载到了0x9020处,所以字符串的断地址直接设置为cs即可 
    12     mov ax,#0x1301   
    13     int 0x10    !调用中断
    14      
    15 inf_loop:        !死循环防止退出 
    16     jmp inf_loop   
    17 msg1:
    18     .byte   13,10                     
    19     .ascii  "Hello OS world, my name is LZJ"
    20     .byte   13,10,13,10        
    21            
    22 .org 510        !这里还是和bootsect一样 
    23 boot_flag:
    24     .word   0xAA55      

    然后对上面的bootsect.s进行修改让bootsect能够读入setup

     1 SETUPLEN=2            !自定义的setup段的长度为2个扇区 
     2 SETUPSEG=0x07e0        !因为自定仪的代码没有将bootsect移到0x9000出,所以setup段的开始地址在磁盘的的0x07e0处 
     3 entry _start        
     4 _start:        
     5     mov ah,#0x03        
     6     xor bh,bh
     7     int 0x10
     8     
     9     mov cx,#36            
    10     mov bx,#0x0007     
    11     mov bp,#msg1
    12     mov ax,#0x07c0
    13     mov es,ax
    14     mov ax,#0x1301   
    15     int 0x10
    16     
    17 load_setup:                    !从这里开始进行载入setup
    18  
    19     !0x13号中断是BIOS读磁盘扇区的中断 
    20     mov dx,#0x0000          !dh=磁头号,dl=驱动器号 
    21     mov cx,#0x0002            !ch=柱面号,cl=开始扇区 
    22     mov bx,#0x0200            !表示将读取的内容放在内存es:bp处,es是0x7c0,bp是0x200(前200字节) 
    23     mov ax,#0x0200+SETUPLEN !ah=0x02表示读磁盘,al=扇区数量,本来应该是4,但是自己写的setup只占用了2个扇区(512字节)  
    24     int 0x13                !调用中断读取setup 
    25     
    26     jnc ok_load_setup        !读入成功则跳转 
    27     
    28     mov dx,#0x0000             !读入失败则调用0x13中断进行复位重启,再次进行读入 
    29     mov ax,#0x0000        
    30     int 0x13
    31     jmp load_setup            !再次进行读写
    32      
    33 ok_load_setup:
    34     jmpi    0,SETUPSEG        !cs:ip跳转到0x07e0:0x0000处,即跳转到setup执行 
    35     
    36     
    37 msg1:
    38     .byte   13,10                     
    39     .ascii  "Hello OS world, my name is LZJ"
    40     .byte   13,10,13,10    
    41     
    42 !自己写的setup.s只占用了512个字节(两个扇区),实际上linux0.11用了4个扇区        
    43 .org 510
    44 boot_flag:
    45     .word   0xAA55     

     然后用makefile进行编译,可能要修改下build.c

    make BootImage

    实际上,bootsect在读完setup后还会读入system,其地址为0x10000-0x8ffff

    然后是setup需要完成的工作:

      完成os启动前的设置,使系统进入保护模式:

    首先读入的就是硬件信息:光标,扩展内存数,显卡参数,跟设备号

    然后将system模块向下移动到0地址

      但是,0地址处本来有重要内容,比如int中断,如何避免冲突?

        此时setup让硬件进入保护模式,即int和cs:ip的寻址电路被改变,igt(中断描述符表:用来查中断)和gdt(全局描述符表:用来查cs值对应的段的地址)就是改变后的寻址方式

        cs在保护模式中也称为选择子,表示段的编号

      具体的实现:

        在system移动结束(end_move)后,新建一张临时的gdt表,其内容设置为

        

        下面是gdt表的格式

        

         有一个寄存器叫做cr0,其末尾PE=1为启动保护模式,

        所以先把cr0的末尾置为1来进入保护模式,然后执行指令

    jmpi 0,8 !cs=0x0008,ip=0x0000

         cs=8,对应的gdt从第8个字节开始后的内容恰好为0,所以要跳转的地址为0x0000:0x0000

        即system的开头head.s文件

    到此为止setup也完成了任务,系统开始执行head.s

     参考了一张图片,表示的是在每个阶段每个块的位置

    模仿linux0.11的代码

     1 mov    ax,#INITSEG    
     2 ! 设置 ds = 0x9000
     3 mov    ds,ax 
     4 mov    ah,#0x03
     5 ! 读入光标位置    
     6 xor    bh,bh
     7 ! 调用 0x10 中断
     8 int    0x10
     9 ! 将光标位置写入 0x90000.        
    10 mov    [0],dx        
    11 
    12 ! 读入内存大小位置
    13 mov    ah,#0x88
    14 int    0x15
    15 mov    [2],ax
    16 
    17 ! 从 0x41 处拷贝 16 个字节(磁盘参数表)
    18 mov    ax,#0x0000
    19 mov    ds,ax
    20 lds    si,[4*0x41]    !把内存记录磁盘参数的值赋值给si
    21 mov    ax,#INITSEG    
    22 mov    es,ax        !INITSEG赋值给es
    23 mov    di,#0x0004     !
    24 mov    cx,#0x10          !
    25 ! 重复16次
    26 rep            
    27 movsb

    最后是setup.s的全代码

      1 INITSEG  = 0x9000
      2 entry _start
      3 _start:
      4 ! Print "NOW we are in SETUP"
      5     mov ah,#0x03  
      6     xor bh,bh
      7     int 0x10
      8     mov cx,#25
      9     mov bx,#0x0007   
     10     mov bp,#msg2
     11     mov ax,cs
     12     mov es,ax
     13     mov ax,#0x1301  
     14     int 0x10 
     15 
     16     mov ax,cs
     17     mov es,ax
     18 ! init ss:sp
     19     mov ax,#INITSEG
     20     mov ss,ax
     21     mov sp,#0xFF00
     22 
     23 ! Get Params
     24     mov ax,#INITSEG 
     25     mov ds,ax
     26     mov ah,#0x03  
     27     xor bh,bh
     28     int 0x10      
     29     mov [0],dx    
     30     mov ah,#0x88
     31     int 0x15
     32     mov [2],ax
     33     mov ax,#0x0000
     34     mov ds,ax
     35     lds si,[4*0x41]
     36     mov ax,#INITSEG
     37     mov es,ax
     38     mov di,#0x0004
     39     mov cx,#0x10
     40     rep
     41     movsb
     42 
     43 ! Be Ready to Print
     44     mov ax,cs
     45     mov es,ax
     46     mov ax,#INITSEG 
     47     mov ds,ax
     48 
     49 ! Cursor Position 
     50     mov ah,#0x03   
     51     xor bh,bh
     52     int 0x10
     53     mov cx,#18
     54     mov bx,#0x0007     
     55     mov bp,#msg_cursor
     56     mov ax,#0x1301   
     57     int 0x10 
     58     mov dx,[0]
     59     call    print_hex 
     60 ! Memory Size
     61     mov ah,#0x03      
     62     xor bh,bh
     63     int 0x10
     64     mov cx,#14
     65     mov bx,#0x0007      
     66     mov bp,#msg_memory
     67     mov ax,#0x1301      
     68     int 0x10 
     69     mov dx,[2]
     70     call    print_hex 
     71 ! Add KB
     72     mov ah,#0x03    
     73     xor bh,bh
     74     int 0x10
     75     mov cx,#2
     76     mov bx,#0x0007 
     77     mov bp,#msg_kb
     78     mov ax,#0x1301  
     79     int 0x10 
     80 ! Cyles
     81     mov ah,#0x03  
     82     xor bh,bh
     83     int 0x10
     84     mov cx,#7
     85     mov bx,#0x0007 
     86     mov bp,#msg_cyles
     87     mov ax,#0x1301    
     88     int 0x10 
     89     mov dx,[4]
     90     call    print_hex 
     91 ! Heads
     92     mov ah,#0x03    
     93     xor bh,bh
     94     int 0x10
     95     mov cx,#8
     96     mov bx,#0x0007    
     97     mov bp,#msg_heads
     98     mov ax,#0x1301  
     99     int 0x10 
    100     mov dx,[6]
    101     call    print_hex 
    102 ! Secotrs
    103     mov ah,#0x03    
    104     xor bh,bh
    105     int 0x10
    106     mov cx,#10
    107     mov bx,#0x0007    
    108     mov bp,#msg_sectors
    109     mov ax,#0x1301   
    110     int 0x10 
    111     mov dx,[12]
    112     call    print_hex 
    113 
    114 inf_loop:
    115     jmp inf_loop
    116 
    117 print_hex:       
    118     mov    cx,#4        
    119 print_digit:
    120     rol    dx,#4        
    121     mov    ax,#0xe0f  
    122     and    al,dl  
    123     add    al,#0x30 
    124     cmp    al,#0x3a
    125     jl     outp  
    126     add    al,#0x07  
    127 outp: 
    128     int    0x10
    129     loop   print_digit
    130     ret
    131 print_nl:
    132     mov    ax,#0xe0d     ! CR
    133     int    0x10
    134     mov    al,#0xa     ! LF
    135     int    0x10
    136     ret
    137 
    138 msg2:
    139     .byte 13,10
    140     .ascii "NOW we are in SETUP"
    141     .byte 13,10,13,10
    142 msg_cursor:
    143     .byte 13,10
    144     .ascii "Cursor position:"
    145 msg_memory:
    146     .byte 13,10
    147     .ascii "Memory Size:"
    148 msg_cyles:
    149     .byte 13,10
    150     .ascii "Cyls:"
    151 msg_heads:
    152     .byte 13,10
    153     .ascii "Heads:"
    154 msg_sectors:
    155     .byte 13,10
    156     .ascii "Sectors:"
    157 msg_kb:
    158     .ascii "KB"
    159 
    160 .org 510
    161 boot_flag:
    162     .word 0xAA55
  • 相关阅读:
    Java多线程模式(二)
    HDU 1232 畅通工程
    跨平台实现wchar_t转成char
    小学生玩ACM----优先队列
    JSTL标签急速秒杀jsp页面中的java代码(一)---Core标签库
    项目沟通技术和技巧
    自己写一个strcmp函数(C++)
    Linux Makefile文件编写详细步骤与实践
    JAVA之数组查询binarySearch()方法详解
    系统调用与标准库调用的区别
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12011502.html
Copyright © 2011-2022 走看看