从头写一个操作系统 07 (create an OS from scratch 07)
你需要自己去查: 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位保护模式的跳转,并且测试今天的代码。
这个简直是神级了🤣
Posted using Partiko Android
嘿嘿,太夸张啦!