从linux0.11学习linux内核设计之模式转换:实模式-保护模式(1)

来源:互联网 发布:linux samba rpm 下载 编辑:程序博客网 时间:2024/05/22 09:48

作者:朱克锋

转载请注明出处:http://blog.csdn.net/linux_zkf

 

    在上篇文章中bootsec已经把所有程序都加载到计算机的内存中的一定位置,下面接着上篇文章的结尾

 

jmpi   0,SETUPSEG开始要进入setup程序开始执行。

 

    看一下这行代码:

    jmpi   0,SETUPSEG

    这行代码的作用就是跳转到SETUPSEG出开始执行,就是setup程序加载的位置,OK,此时setup接着bootsec开始继续执行.

 

    在setup开始执行做的第一件事就是读取计算机系统数据,具体代码如下:

 

entry start

start:

 

! ok, the read went well so we get current cursor position and save it for

! posterity.

 

   mov ax,#INITSEG ! this is done in bootsect already, but...

   mov ds,ax

   mov ah,#0x03    ! read cursor pos

   xor bh,bh

   int 0x10        ! save it in known place, con_init fetches

   mov [0],dx      ! it from 0x90000.

 

! Get memory size (extended mem, kB)

 

   mov ah,#0x88

   int 0x15

   mov [2],ax

 

! Get video-card data:

 

   mov ah,#0x0f

   int 0x10

   mov [4],bx      ! bh = display page

   mov [6],ax      ! al = video mode, ah = window width

 

! check for EGA/VGA and some config parameters

 

   mov ah,#0x12

   mov bl,#0x10

   int 0x10

   mov [8],ax

   mov [10],bx

   mov [12],cx

 

! Get hd0 data

 

   mov ax,#0x0000

   mov ds,ax

   lds si,[4*0x41]

   mov ax,#INITSEG

   mov es,ax

   mov di,#0x0080

   mov cx,#0x10

   rep

   movsb

 

! Get hd1 data

 

   mov ax,#0x0000

   mov ds,ax

   lds si,[4*0x46]

   mov ax,#INITSEG

   mov es,ax

   mov di,#0x0090

   mov cx,#0x10

   rep

   movsb

 

! Check that there IS a hd1 :-)

 

   mov ax,#0x01500

   mov dl,#0x81

   int 0x13

   jc  no_disk1

   cmp ah,#3

   je  is_disk1

no_disk1:

   mov ax,#INITSEG

   mov es,ax

   mov di,#0x0090

   mov cx,#0x10

   mov ax,#0x00

   rep

   stosb

is_disk1:

 

    从代码中可以看到读取的数据覆盖了bootsec的程序!!!!对头,bootsec已经使用完了,使命已经完成,留着无用,干掉吧,呵呵呵,过河拆桥啊,不过正是这种过河拆桥的做法合理的利用了计算机的内存,bootsec所占的内存位512字节,读取的机器系统数据占510字节,仅仅只有2个字节没有被覆盖!!!利用率非常之高。

 

    接下来就是见证历史的时刻了:系统将由实模式转换到保护模式!现代操作系统由此产生!

    读取机器系统数据之后紧接着就是:

         cli

    可不要小看了这个mini代码,他的作用就是关闭中断,从此时开始无论系统是否产生中断,系统都不会响应此中断,直到后来的main函数打开中断,不过那时系统响应的不再是BIOS的中断了,而是由系统自己提供的了。

 

    在setup中,关闭中断之后就是把system从开始的SYSSEG移到0x00000处,代码如下:

do_move:

   mov es,ax       ! destination segment

   add ax,#0x1000

   cmp ax,#0x9000

   jz  end_move

   mov ds,ax       ! source segment

   sub di,di

   sub si,si

   mov     cx,#0x8000

   rep

   movsw

   jmp do_move

 

    在0x00000处原来存放的是BIOS的一些东西,中断向量表,数据等等,这样的移动和前面一样,原来的数据全被新数据覆盖了。

 

    紧接着setup执行如下代码:

 

end_move:

   mov ax,#SETUPSEG    ! right, forgot this at first. didn't work :-)

   mov ds,ax

   lidt    idt_48      ! load idt with 0,0

   lgdt    gdt_48      ! load gdt with whatever appropriate

 

。。。。。

gdt:

   .word   0,0,0,0     ! dummy

 

   .word   0x07FF      ! 8Mb - limit=2047 (2048*4096=8Mb)

   .word   0x0000      ! base address=0

   .word   0x9A00      ! code read/exec

   .word   0x00C0      ! granularity=4096, 386

 

   .word   0x07FF      ! 8Mb - limit=2047 (2048*4096=8Mb)

   .word   0x0000      ! base address=0

   .word   0x9200      ! data read/write

   .word   0x00C0      ! granularity=4096, 386

 

idt_48:

   .word   0           ! idt limit=0

   .word   0,0         ! idt base=0L

 

gdt_48:

   .word   0x800       ! gdt limit=2048, 256 GDT entries

   .word   512+gdt,0x9 ! gdt base = 0X9xxxx

   

    这段代码的作用就是setup利用自己的数据信息对中断描述符表寄存器IDTR和全局描述符表寄存器GDTR进行初始化。

 

    初始化中断描述符表寄存器IDTR和全局描述符表寄存器GDTR之后执行到这里:

 

! that was painless, now we enable A20

 

   call    empty_8042

   mov al,#0xD1        ! command write

   out #0x64,al

   call    empty_8042

   mov al,#0xDF        ! A20 on

   out #0x60,al

   call    empty_8042

打开A20!!!!

 

    前面说过实模式的中断机制已经被关闭和破坏,但是又不能没有中断机制,所以要为保护模式下建立中断机制,在setup中将对可编程的终端控制器进行重新编程,代码如下:

 

moval,#0x11        ! initialization sequence

   out #0x20,al        ! send it to 8259A-1

   .word   0x00eb,0x00eb       ! jmp $+2, jmp $+2

   out #0xA0,al        ! and to 8259A-2

   .word   0x00eb,0x00eb

   mov al,#0x20        ! start of hardware int's (0x20)

   out #0x21,al

   .word   0x00eb,0x00eb

   mov al,#0x28        ! start of hardware int's 2 (0x28)

   out #0xA1,al

   .word   0x00eb,0x00eb

   mov al,#0x04        ! 8259-1 is master

   out #0x21,al

   .word   0x00eb,0x00eb

   mov al,#0x02        ! 8259-2 is slave

   out #0xA1,al

   .word   0x00eb,0x00eb

   mov al,#0x01        ! 8086 mode for both

   out #0x21,al

   .word   0x00eb,0x00eb

   out #0xA1,al

   .word   0x00eb,0x00eb

   mov al,#0xFF        ! mask off all interrupts for now

   out #0x21,al

   .word   0x00eb,0x00eb

   out #0xA1,al

 

    搞定这些之后,即进入以下代码:

   mov ax,#0x0001  ! protected mode (PE) bit

   lmsw    ax      ! This is it!

   jmpi    0,8     ! jmp offset 0 of segment 8 (cs)

 

    注意这行代码:

    jmpi   0,8

    这里就跳到head程序了。

 

    到此呢,setup程序执行完毕,后面就由head继续来完成。

    在下一篇文章中我将继续head程序分析、学习linux。加油

原创粉丝点击