美文网首页
从头写一个操作系统 09 (create an OS from

从头写一个操作系统 09 (create an OS from

作者: 半步江南 | 来源:发表于2019-04-15 10:10 被阅读0次

    lesson 10

    这一课,不能简单的翻译课文,因为作者并没有写什么内容,一切都在代码里。
    那就让我们把代码拆开,看看16位实模式是如何跳转到32位保护模式的。

    分析代码前,先想象为什么会有16位实模式呢?

    很久以前,大概1985年左右,那时的intel的CPU只有16位,16位就是代表CPU有16根电线接收数据(其实是16根电线发送数据,另外CPU还有32根电线分两组,每组16根各自接受一组数据),DOS就是那个时代的操作系统,很多年过去了,intel的cpu进化成为32位,但intel为了保证硬件的向前兼容,统一计算机启动的第一步是进入16位模式,然后由引导区决定下一步的动作,这样如果是必须16位模式的DOS系统,一样可以在32位机器上工作。如果你玩树莓派,就会发现完全没有16位实模式这个说法,不过树莓派的启动也是很奇怪的,它先启动GPU,让GPU先读两个配置文件,然后才让ARMcpu工作,这是后话,以后讲到树莓派的时候再说。

    32位保护模式与16位实模式是有本质区别的,cpu一次可以寻址32位的地址,也就是最大能够寻址到4G,怎么算的?

    2^16 = 65536  约等于65K
    2^20=1048575  约等于1M
    2^32=4294967295  约等于4G
    

    现在咱们都用64位的操作系统,还记得当年换64位操作系统的原因吗?大概2010年后,电脑内存越来越大,很快超过了8G,可尴尬的是32位操作系统无法寻址超过4G的内存地址,因为就算给CPU的32根电线
    都传递高电平,也只有0XFFFF FFFF 这么几个F,内存是有8G,多出4G的空间,CPU的指头都不够数。64位操作系统是可以调动CPU所有64根电线的,如果让64根电线都是高电平,那么可以寻址到160亿G的内存地址。

    16位与32位的区别就在于寻址的方式,也就是CPU如何把自己要什么地址告诉内存,16位是用段地址*16+偏移地址的方式寻址,能够寻址20位。到了32位CPU,做了另外的选择,更加安全也更加复杂,上一节课已经说过。同一个32位CPU在执行16位模式时,通过调整一个开关,就能进入32位寻址能力的模式,这个开关就是代码中的cr0,当cr0的最低位的bit被置为1时,CPU进入32位保护模式。

    switch_to_pm:
        cli ;                       1. 关闭中断
        lgdt [gdt_descriptor] ;     2. 加载 GDT descriptor
        mov eax, cr0
        or eax, 0x1 ;               3. 将cr0设置为32位模式
        mov cr0, eax
        jmp CODE_SEG:init_pm ;      4. far jump 
    

    lgdt 加载 gdt_descriptor 的作用就是把GDT载入到GDTR寄存器中,其实就是载入了一个地址。
    16位时CS寄存器里存的的段地址,进入32位保护模式后,CS中存的是GDT这个结构中的偏移量,比如本例中的GDT代码为:

    gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
        ; the GDT starts with a null 8-byte
        dd 0x0 ; 4 byte
        dd 0x0 ; 4 byte
    
    ; GDT for code segment. base = 0x00000000, length = 0xfffff
    ; for flags, refer to os-dev.pdf document, page 36
    gdt_code: 
        dw 0xffff    ; segment length, bits 0-15
        dw 0x0       ; segment base, bits 0-15
        db 0x0       ; segment base, bits 16-23
        db 10011010b ; flags (8 bits)
        db 11001111b ; flags (4 bits) + segment length, bits 16-19
        db 0x0       ; segment base, bits 24-31
    
    ; GDT for data segment. base and length identical to code segment
    ; some flags changed, again, refer to os-dev.pdf
    gdt_data:
        dw 0xffff
        dw 0x0
        db 0x0
        db 10010010b
        db 11001111b
        db 0x0
    
    gdt_end:
    
    ; GDT descriptor
    gdt_descriptor:
        dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
        dd gdt_start ; address (32 bit)
    
    ; define some constants for later use
    CODE_SEG equ gdt_code - gdt_start
    DATA_SEG equ gdt_data - gdt_start
    

    可以看到 CODE_SEG 的值是0x08 (gdt-code -gdt_start),所以此时的CS寄存器中就存着0x08
    在保护模式下,CS:IP取指令地址的流程就成为了, CPU计算GDTR+CS 得到code段的真实base地址,然后以IP作为offset,得到最终指令的地址。当然在载入指令前会判断code段的limit是否小于IP,如果小于,则报告段错误,写C语言的人谁没碰到过段错误?当然C语言中的段错误,应该都是超出了LDTR的limit,LDTR中的L是local,GDTR中的G是global。

    一旦进入到32位保护模式,一瞬间便天高地阔,不过首先要初始化所有的寄存器,因为寄存器在实模式时,只用了16位,现在可以让寄存器所有32位的能力都能发挥出来。由far jump 到BEGIN_PM lable执行32位下初始化寄存器的指令。下面就该进入kernel了!

    THE ORIGIN ARTICALE IN GITHUB:[1]

    Concepts you may want to Google beforehand: interrupts, pipelining

    Goal: Enter 32-bit protected mode and test our code from previous lessons

    To jump into 32-bit mode:

    Disable interrupts
    Load our GDT
    Set a bit on the CPU control register cr0
    Flush the CPU pipeline by issuing a carefully crafted far jump
    Update all the segment registers
    Update the stack
    Call to a well-known label which contains the first useful code in 32 bits
    We will encapsulate this process on the file 32bit-switch.asm. Open it and take a look at the code.

    After entering 32-bit mode, we will call BEGIN_PM which is the entry point for our actual useful code (e.g. >kernel code, etc). You can read the code at 32bit-main.asm. Compile and run this last file and you will see >the two messages on the screen.

    Congratulations! Our next step will be to write a simple kernel


    1. https://github.com/cfenollosa/os-tutorial/tree/master/10-32bit-enter

    相关文章

      网友评论

          本文标题:从头写一个操作系统 09 (create an OS from

          本文链接:https://www.haomeiwen.com/subject/dbwrwqtx.html