从零开始操作系统-03:装载GDT

这一节主要装载GDT。

所需要的文件在Github:https://github.com/yongkangluo/Ubuntu20.04OS/tree/main/Files/Lec3-GDT

基本概念

1. GDT && GDTR && Segment Descriptor

全局描述符表GDT(Global Descriptor Table)在整个系统中,全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何位置,但CPU必须知道GDT的入口,也就是基地址放在哪里,Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。GDTR中存放的是GDT在内存中的基地址和其表长界限。
“The Global Descriptor Table (GDT) is a binary data structure specific to the IA-32 and x86-64 architectures. It contains entries telling the CPU about memory segments. A similar Interrupt Descriptor Table exists containing task and interrupt descriptors.”+

GDT 由 GDTR 寄存器中的值指向。这是使用 LGDT 汇编指令加载的,该指令的参数是指向 GDT 描述符结构的指针。
在这里插入图片描述
其中GDT里装的东西是 段描述符 (Segment Descriptor)
在这里插入图片描述
Segment Descriptor:
在这里插入图片描述

2. 具体配置

gdt.h:主要是对一些初始参数的设定和配置。
gdt.c:

//gdt.c:
#include <lunaix/arch/gdt.h>
#include <stdint.h>

#define GDT_ENTRY 5

uint64_t _gdt[GDT_ENTRY];
uint16_t _gdt_limit = sizeof(_gdt);

void _set_gdt_entry(uint32_t index, uint32_t base, uint32_t limit, uint32_t flags){
    _gdt[index] = SEG_BASE_H(base) | flags | SEG_LIM_H(limit) | SEG_BASE_M(base);
    _gdt[index] <<= 32;
    _gdt[index] |= SEG_BASE_L(base) | SEG_LIM_L(limit);
}
void _init_gdt(){
    _set_gdt_entry(0, 0, 0, 0);
    _set_gdt_entry(1, 0, 0xfffff, SEG_R0_CODE);
    _set_gdt_entry(2, 0, 0xfffff, SEG_R0_DATA);
    _set_gdt_entry(3, 0, 0xfffff, SEG_R3_CODE);
    _set_gdt_entry(4, 0, 0xfffff, SEG_R3_DATA);
}

这里初始化了四块段地址。这是构造GDT表的过程,包括段描述符的生成。下面就要把GDT的地址加载到GDTR中。boot.S相关代码如下:

        call _kernel_init
        
        subl $0x6, %esp
        // 因为 GDTR 是 48 bit,所以在栈上先分配 6 字节
        movl $_gdt, 2(%esp)
        // 先加载地址偏移量
        movw _gdt_limit, %ax
        movw %ax, (%esp) 
        // 再加载size
        lgdt (%esp)
        addl $0x6, %esp
		// 栈回复
		
        movw $0x10, %cx 
        movw %cx, %es
        movw %cx, %ds
        movw %cx, %fs
        movw %cx, %gs
        movw %cx, %ss
        // 初始化段寄存器
        
        pushw $0x08
        pushl $_after_gdt
        retf
		// 这里进行的是跳转
    _after_gdt:
        pushl %ebx
        call _kernel_main

具体的代码在github都用,其中文件目录如下所示。

.
├── arch
│   ├── boot.S
│   ├── gdt.c
│   ├── multiboot.h
│   └── x86
├── bochs.cfg
├── config-grub.sh
├── dump
├── GRUB_TEMPLATE
├── hal
├── includes
│   ├── libc
│   └── lunaix
│       ├── arch
│       │   └── gdt.h![请添加图片描述](https://img-blog.csdnimg.cn/0e16d0c2e97644d4b5ae17faa810a78f.jpeg)

│       └── tty
│           └── tty.h
├── kernel
│   ├── kernel.c
│   └── tty
│       └── tty.c
├── libs
├── linker.ld
└── makefile

之后利用make all生成文件,然后make run 或者 make debug-bochs c 即可运行成功。
在这里插入图片描述

方法主要跟着B站Up主做的,B站视频链接在:https://www.bilibili.com/video/BV1jL4y1s7X6/?spm_id_from=333.788&vd_source=72ce864f895f9fbf22b81450817f2875

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值