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

作者:朱克锋

转载请注明出处: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中将对可编程的终端控制器进行重新编程,代码如下:

 

mov al,#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。加油

你可能感兴趣的:(从linux0.11学习linux内核设计之模式转换:实模式-保护模式(1))