从头写一个操作系统 07 (create an OS from scratch 07)

in #code6 years ago (edited)

lesson 9

你需要自己去查: GDT

本节目标: 编写 GDT

还记得lesson 6的segmentation吗?段地址左移一位,只有16位的寻址总线却达到了20位的寻址能力。

在32位模式下,段地址的使用方法有了变化。现在,偏移量是GDT中段描述符的索引。段描述符定义了基础地址(32位)、地址范围(20位)和其他一些标志位(只读,权限等)。更让人容易迷惑的是GDT的数据结构有点奇怪,打开os-dev看第34页,或者GDT的维基。

编写GDT最简单的方式是定义两个段,一个是代码段,另一是数据段。让它们重叠在一起放弃对内存的保护,今后我们会用c语言来修复这个缺陷。

第一个GDT入口必须是0x00,确保程序员管理内存是没有出错

然后,CPU不能直接加载GDT地址,它需要先取得一个GDT的大小(16bit)、地址(32bit)的数据结构(GDT descriptor)。用lgdt操作符加载GDT descriptor即可。

让我们直接跳转到GDT的汇编代码。这一节的理论比较复杂,最后仔细看看os-dev上的内容。

gdt_start: ; 不要更改这个标签,后面计算gdt大小会用到
    ; GDT以8个字节的空字节开始
    dd 0x0 ; 4 byte
    dd 0x0 ; 4 byte

; code段的GDT. base = 0x00000000, length = 0xfffff
;  os-dev.pdf 的36页有flags的详细介绍
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:
    ;size的取值范围为1到65536,但内存地址0xFFFF == 65535 ,所以1-65536  ->   0 - 65535 这样作为对应,所以减去1。
    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

下一节课,我们会完成32位保护模式的跳转,并且测试今天的代码。

THE ORIGIN ARTICALE IN GITHUB:

Sort:  

这个简直是神级了🤣

Posted using Partiko Android

嘿嘿,太夸张啦!