linux学习(二)--setup.s

执行过bootsect.s,加载了所有系统代码之后,开始向32位模式转变,为main函数的调用做准备,同样,附上图往下看

 

  1 INITSEG  = 0x9000    ! we move boot here - out of the way
  2 SYSSEG   = 0x1000    ! system loaded at 0x10000 (65536).
  3 SETUPSEG = 0x9020    ! this is the current segment
  4 
  5 .globl begtext, begdata, begbss, endtext, enddata, endbss
  6 .text
  7 begtext:
  8 .data
  9 begdata:
 10 .bss
 11 begbss:
 12 .text
 13 
 14 entry start
 15 start:
 16 
 17 //保存当前光标位置
 18     mov    ax,#INITSEG    
 19     mov    ds,ax            ;ds设置成INITSEG
 20     mov    ah,#0x03        ;int 10读光标功能号3
 21     xor    bh,bh
 22     int    0x10            ;调用中断,读取光标位置
 23     mov    [0],dx            ;光标信息存在dx中,并存入0x90000处
 24     mov    ah,#0x88        ;int 15取扩展内存大小功能号0x88
 25     int    0x15            ;调用中断
 26     mov    [2],ax            ;返回从100000开始的扩展内存大小
 27 
 28 //保存显卡当前显示模式
 29     mov    ah,#0x0f
 30     int    0x10
 31     mov    [4],bx        ; bh = display page
 32     mov    [6],ax        ; al = video mode, ah = window width
 33 
 34 //检查显示方式(EGA/VGA),并选取参数
 35     mov    ah,#0x12    
 36     mov    bl,#0x10
 37     int    0x10
 38     mov    [8],ax        
 39     mov    [10],bx    ;显示内存,显示状态
 40     mov    [12],cx    ;显卡特性参数
 41 
 42 //取第0个硬盘信息
 43     mov    ax,#0x0000
 44     mov    ds,ax
 45     lds    si,[4*0x41];取中断向量,41的值,即硬盘0参数表的地址
 46     mov    ax,#INITSEG
 47     mov    es,ax
 48     mov    di,#0x0080    ;传输向量表到达的目的地址:9000:0080
 49     mov    cx,#0x10    ;取10字节
 50     rep
 51     movsb            ;循环复制
 52 
 53 //取第一个磁盘信息
 54     mov    ax,#0x0000
 55     mov    ds,ax
 56     lds    si,[4*0x46];取中断向量,46的值,即硬盘1参数表的地址
 57     mov    ax,#INITSEG
 58     mov    es,ax
 59     mov    di,#0x0090    ;传输向量表到达的目的地址:9000:0090
 60     mov    cx,#0x10    ;取10字节
 61     rep
 62     movsb
 63 
 64 //检查是否存在第二个硬盘
 65     mov    ax,#0x01500
 66     mov    dl,#0x81
 67     int    0x13
 68     jc    no_disk1    ;如果cf==1,跳转,没有第二个磁盘
 69     cmp    ah,#3        ;判断是否有硬盘
 70     je    is_disk1
 71 //没有则删除第二个硬盘表
 72 no_disk1:
 73     mov    ax,#INITSEGjj
 74     mov    es,ax
 75     mov    di,#0x0090
 76     mov    cx,#0x10
 77     mov    ax,#0x00
 78     rep
 79     stosb
 80 
 81 is_disk1:
 82 
 83 //开始保护模式方面的工作
 84 
 85     cli            ;不允许中断
 86 
 87 //首先我们将系统模块移动到新的目标位置
 88 
 89     mov    ax,#0x0000
 90     cld                ! 'direction'=0, movs moves forward
 91 do_move:
 92     mov    es,ax        ;被复制到的目的地址es:di=>0000:0
 93     add    ax,#0x1000
 94     cmp    ax,#0x9000
 95     jz    end_move
 96     mov    ds,ax        ;原地址ds:si=>1000:0
 97     sub    di,di
 98     sub    si,si
 99     mov     cx,#0x8000    ;移动0x8000字节(64k)
100     rep
101     movsw
102     jmp    do_move
103 
104 //加载段描述符
105 
106 end_move:
107     mov    ax,#SETUPSEG    ! right, forgot this at first. didn't work :-)
108     mov    ds,ax            ;ds指向setup段
109     lidt    idt_48        ;加载中断描述符表寄存器
110     lgdt    gdt_48        ;加载全局描述符表寄存器
111 
112 //开启A20地址线,准备进入32位寻址模式
113 
114     call    empty_8042
115     mov    al,#0xD1        ! command write
116     out    #0x64,al
117     call    empty_8042
118     mov    al,#0xDF        ! A20 on
119     out    #0x60,al
120     call    empty_8042
121 
122 ! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
123 ! we put them right after the intel-reserved hardware interrupts, at
124 ! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
125 ! messed this up with the original PC, and they haven't been able to
126 ! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
127 ! which is used for the internal hardware interrupts as well. We just
128 ! have to reprogram the 8259's, and it isn't fun.
129 
130     mov    al,#0x11        ! initialization sequence
131     out    #0x20,al        ! send it to 8259A-1
132     .word    0x00eb,0x00eb        ! jmp $+2, jmp $+2,$表示当前指令地址
133     out    #0xA0,al        ! and to 8259A-2
134     .word    0x00eb,0x00eb
135     mov    al,#0x20        ! start of hardware int's (0x20)
136     out    #0x21,al
137     .word    0x00eb,0x00eb
138     mov    al,#0x28        ! start of hardware int's 2 (0x28)
139     out    #0xA1,al
140     .word    0x00eb,0x00eb
141     mov    al,#0x04        ! 8259-1 is master
142     out    #0x21,al
143     .word    0x00eb,0x00eb
144     mov    al,#0x02        ! 8259-2 is slave
145     out    #0xA1,al
146     .word    0x00eb,0x00eb
147     mov    al,#0x01        ! 8086 mode for both
148     out    #0x21,al
149     .word    0x00eb,0x00eb
150     out    #0xA1,al
151     .word    0x00eb,0x00eb
152     mov    al,#0xFF        ! mask off all interrupts for now
153     out    #0x21,al
154     .word    0x00eb,0x00eb
155     out    #0xA1,al
156 
157 ! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
158 ! need no steenking BIOS anyway (except for the initial loading :-).
159 ! The BIOS-routine wants lots of unnecessary data, and it's less
160 ! "interesting" anyway. This is how REAL programmers do it.
161 !
162 ! Well, now's the time to actually move into protected mode. To make
163 ! things as simple as possible, we do no register set-up or anything,
164 ! we let the gnu-compiled 32-bit programs do that. We just jump to
165 ! absolute address 0x00000, in 32-bit protected mode.
166 
167     mov    ax,#0x0001    ! protected mode (PE) bit
168     lmsw    ax        ! This is it!
169     jmpi    0,8        ! jmp offset 0 of segment 8 (cs)
170                     ; 跳转到8:0位置,这里的8为实模式下的段选择符,目的地址是0x00000000
171 //关于8的解析,这里的8对应二进制的"1000",这里的后两位0表示内核特权级,倒数第三位的0表示gdt
172 //1表示用全局描述符表的第1项,该项指出代码的基地址是0,也就是接下来执行的head.s
173 
174 ! This routine checks that the keyboard command queue is empty
175 ! No timeout is used - if this hangs there is something wrong with
176 ! the machine, and we probably couldn't proceed anyway.
177 
178 //检查键盘命令队列是否为空,当输入缓冲器为空则可以对其进行写命令
179 empty_8042:
180     .word    0x00eb,0x00eb
181     in    al,#0x64        ! 8042 status port
182     test    al,#2        ! is input buffer full?
183     jnz    empty_8042    ! yes - loop
184     ret
185 //全局描述符表开始处
186 gdt:
187     .word    0,0,0,0    ! dummy//第一描述符,不用
188 
189 //这里在gdt表中的偏移量为08,联系我们上面的jmpi 0,8,也就是调用此处的表内容
190 //加载代码段寄存器时,使用这个偏移
191     .word    0x07FF        ! 8Mb - limit=2047 (2048*4096=8Mb)
192     .word    0x0000        ! base address=0
193     .word    0x9A00        ! code read/exec
194     .word    0x00C0        ! granularity=4096, 386
195 
196 //这里在gdt表中的偏移量是10,当加载数据段寄存器时,使用这个偏移
197     .word    0x07FF        ! 8Mb - limit=2047 (2048*4096=8Mb)
198     .word    0x0000        ! base address=0
199     .word    0x9200        ! data read/write
200     .word    0x00C0        ! granularity=4096, 386
201 
202 idt_48:
203     .word    0            ! idt limit=0
204     .word    0,0            ! idt base=0L
205 
206 gdt_48:
207     .word    0x800            ! gdt limit=2048, 256 GDT entries
208     .word    512+gdt,0x9    ! gdt base = 0X9xxxx
209     
210 .text
211 endtext:
212 .data
213 enddata:
214 .bss
215 endbss:

 

posted @ 2018-11-29 21:13  Taolaw  阅读(768)  评论(0编辑  收藏  举报