新手学linux之二————setup.S

!
!    setup.s        (C) 1991 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! both setup.s and system has been loaded by the bootblock.
!
! This code asks the bios for memory/disk/other parameters, and
! puts them in a "safe" place: 0x90000-0x901FF, ie where the
! boot-block used to be. It is then up to the protected mode
! system to read them from there before the area is overwritten
! for buffer-blocks.
!
;setup.S功能描述
;1.把system模块移至0x0处
;2.加载GDT IDT 打开A20
;3.重设中断号
;4.进入保护模式
! NOTE! These had better be the same as in bootsect.s!

INITSEG  = 0x9000    ! we move boot here - out of the way
SYSSEG   = 0x1000    ! system loaded at 0x10000 (65536).
SETUPSEG = 0x9020    ! this is the current segment

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

entry start
start:

! ok, the read went well so we get current cursor position and save it for
! posterity.
;功能03H
;功能描述:在文本坐标下,读取光标各种信息
;入口参数:AH=03H
;BH=显示页码
;出口参数:CH=光标的起始行
;CL=光标的终止行
;DH=行(Y坐标)
;DL=列(X坐标)
    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
    ;在bootset.S中已经设置过了相关寄存器  
    ;将光标行列信息保存至0x9000:0处
    mov    [0],dx        ! it from 0x90000.    

! Get memory size (extended mem, kB)
;功能88H
;功能描述:读取扩展内存大小
;入口参数:AH=88H
;出口参数:AX=扩展内存字节数(以K为单位)
    mov    ah,#0x88
    int    0x15
    mov    [2],ax

! Get video-card data:
;功能0FH
;功能描述:读取显示器模式
;入口参数:AH=0FH
;出口参数:AH=屏幕字符的列数
;AL=显示模式(参见功能00H中的说明)
;BH=页码
    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
;功能12H
;功能描述:显示器的配置中断。其子功能说明如下:
;功能号 功能名称              功能号 功能名称
;10H — 读取配置信息            20H — 选择屏幕打印
;30H — 设置扫描行            31H — 允许/禁止装入缺省调色板
;32H — 允许/禁止显示        33H — 允许/禁止灰度求和
;34H — 允许/禁止光标模拟    35H — 切换活动显示
;36H — 允许/禁止屏幕刷新
    mov    ah,#0x12
    mov    bl,#0x10
    int    0x10
    mov    [8],ax
    mov    [10],bx
    mov    [12],cx

! Get hd0 data
;直接从中断向量表中获取硬盘的参数
;中断向量是作为IDT的索引号,这里*4是代表向量0x41的线性地址(0x0000:0x104)
;从本内存地址复制到0x9000:0x0080处
    mov    ax,#0x0000
    mov    ds,ax
    lds    si,[4*0x41]        ;请参考 http://www.cnblogs.com/motadou/archive/2009/01/16/1376717.html
    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 :-)
;On entry:      AH         15h
;               DL         Drive number
;Returns:       CF         Set if error, else cleared
; AH         Disk type (see below)
; Status of operation if error (see Service 01)
;CX:DX      If no error and AH <> 0, then 4-byte integer
;with number of sectors.
 //Disk Type
                              AH        Meaning
                              00h       Drive not present
                              01h       Diskette, no change line available
                              02h       Diskette, change line available
                              03h       Fixed Disk                /
                              
    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:

! now we want to move to protected mode ...

    cli            ! no interrupts allowed !    ;关中断 EFLAGS IF置0
                                            ;深入思考为什么关中断  在构建idt的时候为 实模式到保护模式的转换

! first we move the system to it's rightful place

    mov    ax,#0x0000
    cld            ! 'direction'=0, movs moves forward
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

! then we load the segment descriptors

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

! that was painless, now we enable A20 为了能访问1M以上的内存空间 得开启A20地址线

    call    empty_8042
    mov    al,#0xD1        ! command write
    out    #0x64,al        ;out只能al ax
    call    empty_8042
    mov    al,#0xDF        ! A20 on
    out    #0x60,al
    call    empty_8042

! well, that went ok, I hope. Now we have to reprogram the interrupts :-(
! we put them right after the intel-reserved hardware interrupts, at
! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
! messed this up with the original PC, and they haven't been able to
! rectify(改正) it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
! which is used for the internal hardware interrupts as well. We just
! have to reprogram the 8259's, and it isn't fun.

;对于这一段的理解 请参考  http://snower.blog.51cto.com/2918921/557678
;附加 http://blog.csdn.net/zxvf/article/details/1245761
;默认情况下,IRQ对应的中断号是由BIOS初始化的,IRQ0~IRQ7对应着中断号0x8~0xF。
;而可编程表现在,我们可以将IRQ0对应的中断号修改成0~255中的任意一个数,
;我们设为INT_NUM,然后IRQ1~IRQ7对应的中断号就跟着变成INT_NUM+1~INT_NUM+7了。
;举个例子,我们将IRQ0对应的中断号改到0x10,那么IRQ1对应的中断号就是0x11、IRQ2的是0x12……IR7的是0x17。
;我们可以通过4个ICW1~ICW4可配置8259A,IRQ与中断号的对应就是通过ICW2(一个8位的数)来完成的。
;ICW2用来指示出IRQ0使用的中断号是什么,因为最后三位均是零,因此要求IRQ0的中断号必须是8的倍数,
;这又是一个很巧妙的设计。因为IRQ1的中断号就是IRQ0的中断号+1,IRQ2的中断号就是IRQ0的中断号+2,
;刚好填满一个8个的中断向量号空间。

//ICW1:发送到0x20(主片)及0xa0(从片)端口
//7 6 5 4 3 2 1 0//
//0 0 0 1 M 0 C I//
//I位:若置位,表示ICW4会被发送。(ICW4等下解释)
//C位:若清零,表示工作在级联环境下。
//M位:指出中断请求的电平触发模式,在PC机中,它应当被置零,表示采用“边沿触发模式”。
//ICW2:发送到0x21(主片)及0xa1(从片)端口
//7 6 5 4 3 2 1 0
//A7 A6 A5 A4 A3 0 0 0
//ICW3:发送到0x21(主片)及0xa1(从片)端口
//ICW3只有在级联工作的时候才会被发送,它主要用来建立两个PIC之间的连接,对于主片与从片,它结构是不一样的。
//(主片结构:)
//7 6 5 4 3 2 1 0
//IRQ7 IRQ6 IRQ5 IRQ4 IRQ3 IRQ2 IRQ1 IRQ0
//上面,如果相应的位被置1,则相应的IRQ线就被用于与从片连接,若清零则表示被连接到外围设备。
//(从片结构:)
//7 6 5 4 3 2 1 0
//0 0 0 0 0 IRQ
//上面的IRQ位指出了是主片的哪一个IRQ连到了从片,这需要同主片上发送的上面的主片结构字一致。

//ICW4:发送到0x21(主片)及0xa1(从片)端口
//7 6 5 4 3 2 1 0
//0 0 0 0 0 0 EOI 80x86
//80x86位:若置位则表示工作在80x86架构下。
//EOI位:若置位则表示自动清除中断请求信号。在PC上这位需要被清零。


//注意:只有在级联的方式的情况下才需要设置ICW3

    mov    al,#0x11        ! initialization sequence 表示中断请求边沿触发,多片级联并且租后需要发送ICW4
    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

! well, that certainly wasn't fun :-(. Hopefully it works, and we don't
! need no steenking BIOS anyway (except for the initial loading :-).
! The BIOS-routine wants lots of unnecessary data, and it's less
! "interesting" anyway. This is how REAL programmers do it.
!
! Well, now's the time to actually move into protected mode. To make
! things as simple as possible, we do no register set-up or anything,
! we let the gnu-compiled 32-bit programs do that. We just jump to
! absolute address 0x00000, in 32-bit protected mode.

    mov    ax,#0x0001    ! protected mode (PE) bit
已经进入保护模式//
    lmsw    ax        ! This is it!    (建议使用 mov ax,cr0为了兼容以前的80286才使用lmsw)
    ;注意此处的cs=0x8已为保护模式下的段选择子
    ;这里使用的是GDT中的第二个段描述符
    jmpi    0,8        ! jmp offset 0 of segment 8 (cs) 刷新当前的cpu列队
//setup.S完///

! This routine(程序) checks that the keyboard command queue is empty
! No timeout is used - if this hangs there is something wrong with
! the machine, and we probably couldn't proceed anyway.
empty_8042:
    .word    0x00eb,0x00eb
    in    al,#0x64    ! 8042 status port
    test    al,#2        ! is input buffer full?
    jnz    empty_8042    ! yes - loop
    ret


gdt:
    ;第一个段描述符 为全0 (规定)
    .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:                    ;(16*3=48)
    .word    0            ! idt limit=0    idt的限长值
    .word    0,0            ! idt base=0L    IDT的基地址

gdt_48:                    
    .word    0x800        ! gdt limit=2048, 256 GDT entries
    .word    512+gdt,0x9    ! gdt base = 0X9xxxx
    
.text
endtext:
.data
enddata:
.bss
endbss:



转载于:https://my.oschina.net/lngligelang/blog/221771

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值