zoukankan      html  css  js  c++  java
  • linux kernel 0.11 setup

     

    setup作用

    ①读取参数放在0x90000处。

    ②将原本在0x10000处的system模块移至0x00000处

    ③加载中断描述符表,全局描述符表,进入32位保护模式。

    概念

    关于实模式和保护模式区别及寻址方式,该博客已经很详尽:http://blog.csdn.net/rosetta/article/details/8933200,只是有个别信息没有。

    IDT:Interrupt Descriptor Table--中断描述表

    GDT:Global Descriptor Table   --全局描述表

    LDT:Local Descriptor Table    --局部描述表

        在Intel架构中,更准确的说是保护模式下,大部分内存管理和中断服务例程都通过描述符表来控制。每个描述符存储了CPU随时可能需要获取的一个单个对象(例如服务例程、任务、一段代码或数据等)的信息。如果试图装载一个数据到一个段寄存器中,CPU需要进行安全性和访问控制检查,来确认是否获得了访问该内存区域的许可。一旦检查结束,一些有用的信息(例如最低和最高地址)被缓存在CPU中的几个不可见的寄存器中。

        Intel定义了3种类型的描述符表:中断描述符表IDT(用以替换中断向量表IVT)、全局描述符表GDT和局部描述符表LDT。每个表分别通过LIDT、LGDT、LLDT指令以(size, linear address)的形式定义(注:是载入描述符表的指令,这里就是说表包含了大小和基址组成。)。大多数情况下,操作系统中启动期指定这些表的位置,然后通过一个指针直接读写这些表。

      1. 全局描述符表GDT:
     
    全局描述符表在系统中只能有一个,且可以被每一个任务所共享.任何描述符都可以放在GDT中,但中断门和陷阱门放在GDT中是不会起作用的.能被多个任务共享的内存区就是通过GDT完成的,
     
      2. 局部描述符表LDT:
     
    局部描述符表在系统中可以有多个,通常情况下是与任务的数量保持对等,但任务可以没有局部描述符表.任务间不相干的部分也是通过LDT实现的.这里涉及到地址映射的问题.和GDT一样,中断门和陷阱门放在LDT中是不会起作用的.
     
      3. 中断描述符表IDT:
     
    和GDT一样,中断描述符表在系统最多只能有一个,中断描述符表内可以存放256个描述符,分别对应256个中断.因为每个描述符占用8个字节,所以IDT的长度可达2K.中断描述符表中可以有任务门、中断门、陷阱门三个门描述符,其它的描述符在中断描述符表中无意义。
     
      4. 段选择子
    在保护模式下,段寄存器的内容已不是段值,而称其为选择子.该选择子指示描述符在上面这三个表中的位置,所以说选择子即是索引值。
    当我们把段选择子装入寄存器时不仅使该寄存器值,同时CPU将该选择子所对应的GDT或LDT中的描述符装入了不可见部分。这样只要我们不进行代码切换(不重新装入新的选择子)CPU就会不会对不可见部分存储的描述符进行更新,可以直接进行访问,加快了访问速度。一旦寄存器被重新赋值,不可见部分也将被重新赋值。

      setup源代码注释

     

    !
    !    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.
    !
    
    ! 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.
                                !    input:
                                !    BH = page number.
                                !    return:
                                !    DH = row.
                                !    DL = column.
                                !    CH = cursor start line.
                                !    CL = cursor bottom line.
        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    VGA和配置参数
    
        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:
    
    ! now we want to move to protected mode ...开始我们要保护模式方面的工作了。
    
        cli            ! no interrupts allowed !cli是关中断,防止有些硬件中断对程序的干扰 sti是开中断,允许硬件中断
    
    ! first we move the system to it's rightful place
    
        mov    ax,#0x0000
        cld            ! 'direction'=0, movs moves forward  cld即告诉程序si,di向前移动,std指令为设置方向,告诉程序si,di向后移动
    do_move:    !    0x1000=64k 循环移动ds:si->es:di数据,总共移动cx=(0x9000-0x1000)=0x8000的数据
        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 指令以(size=0, linear address=0)的形式加载中断描述符表
        lgdt    gdt_48        ! load gdt with whatever appropriate
                                        !    指令以(size=0x800, linear address=512+gdt,0x9)的形式加载全局描述符表
    
    ! 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
    
    ! 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.
    
        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
    
    ! 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!
        jmpi    0,8        ! jmp offset 0 of segment 8 (cs)
    
    ! 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:
        .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
        
    .text
    endtext:
    .data
    enddata:
    .bss
    endbss:
  • 相关阅读:
    有没有用户体验+UI+前端集于一身的人
    ruby array.count
    ruby subset
    向李刚同学道歉
    rails3转载
    RVM and Capistrano
    paperclip自定制文件名
    ruby爬虫
    rails3已经内置subdomain
    摘录
  • 原文地址:https://www.cnblogs.com/cz-blog/p/4755364.html
Copyright © 2011-2022 走看看