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

 

posted on 2019-12-09 15:55  zsben  阅读(867)  评论(0编辑  收藏  举报

导航