三、GDT和IDT的配置
在bootsector.S中我们就打开了CR0寄存器的第0位(设置为1),即打开了保护模式。接下来进入今天的主题GDT(全局描述符表)的设置。首先来看下intel手册中是如何规定gdt的。
intel内置48位的GDTR寄存器,低16位代表描述符的数量,最大可有8192个描述符,基地址则规定了GDT表的地址。那么GDT表中的段描述符长啥样呢?可以从下图中窥见一斑。
那么根据这个段描述符的描述,总共8个字节,我们可以设定一个结构体来描述一个段描述符。本文主要借鉴ucore的GDT设置方法,如下所示:
gdt.h
gdt.c
到这里的时候其实已经完成gdt表的设置,但为了看到段描述符的变化,我们写一个打印函数来证明cs、ds等确实发生了变化。
到这里,GDT的设置就基本完成了,接下来进行IDT的配置。首先来看IDT表的结构,和GDT表的结构十分相似。
出现以下错误:
主要原因是.S文件中使用了.h中的一个变量,所以加了其头文件,但在编译的时候无法按.S格式解析.h文件中的结构体等,所以报错,改正如下
人为输入int 0x1中断,可以看到系统调用了1号中断服务程序,运行成功。至此,GDT和IDT的配置基本完成,代码如下:
gdt.c
#include "gdt.h"
/* *
* Global Descriptor Table:
*
* The kernel and user segments are identical (except for the DPL). To load
* the %ss register, the CPL must equal the DPL. Thus, we must duplicate the
* segments for the user and the kernel. Defined as follows:
* - 0x0 : unused (always faults -- for trapping NULL far pointers)
* - 0x8 : kernel code segment
* - 0x10: kernel data segment
* - 0x18: user code segment
* - 0x20: user data segment
* - 0x28: defined for tss, initialized in gdt_init
* */
static struct segdesc gdt[] = {
SEG_NULL, //null
SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_KERNEL), //kernel text
SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_KERNEL), //kernel data
SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_USER), //user text
SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_USER), //user data
SEG_NULL, //tss
};
/* *
* Interrupt descriptor table:
*
* Must be built at run time because shifted function addresses can't
* be represented in relocation records.
* */
static struct gatedesc idt[256] = {{0}};
//set gdt's info
static struct dtdesc gdtinfo={sizeof(gdt)-1,(unsigned int)gdt};
//set idt's info
static struct dtdesc idtinfo = {sizeof(idt) - 1, (unsigned int)idt};
/* *
* lgdt - load the global descriptor table register and reset the
* data/code segement registers for kernel.
* */
static inline void lgdt(struct dtdesc *dt)
{
asm volatile ("lgdt (%0)" :: "r" (dt));
asm volatile ("movw %%ax, %%gs" :: "a" (USER_DS));
asm volatile ("movw %%ax, %%fs" :: "a" (USER_DS));
asm volatile ("movw %%ax, %%es" :: "a" (KERNEL_DS));
asm volatile ("movw %%ax, %%ds" :: "a" (KERNEL_DS));
asm volatile ("movw %%ax, %%ss" :: "a" (KERNEL_DS));
// reload cs
asm volatile ("ljmp %0, $1f\n 1:\n" :: "i" (KERNEL_CS));
}
static inline void lidt(struct dtdesc *dt)
{
asm volatile ("lidt (%0)" :: "r" (dt) : "memory");
}
void gdt_init()
{
//load gdtinfo
lgdt(&gdtinfo);
}
void idt_init()
{
extern unsigned int __vectors[];
int i;
for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
}
SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);
lidt(&idtinfo);
}
gdt.h
/* Application segment type bits */
#define STA_X 0x8 // Executable segment
#define STA_E 0x4 // Expand down (non-executable segments)
#define STA_C 0x4 // Conforming code segment (executable only)
#define STA_W 0x2 // Writeable (non-executable segments)
#define STA_R 0x2 // Readable (executable segments)
#define STA_A 0x1 // Accessed
/* global descrptor numbers */
#define GD_KTEXT ((1) << 3) // kernel text
#define GD_KDATA ((2) << 3) // kernel data
#define GD_UTEXT ((3) << 3) // user text
#define GD_UDATA ((4) << 3) // user data
#define GD_TSS ((5) << 3) // task segment selector
#define DPL_KERNEL (0)
#define DPL_USER (3)
//global descriptor selector
#define KERNEL_CS (GD_KTEXT|DPL_KERNEL)
#define KERNEL_DS (GD_KDATA|DPL_KERNEL)
#define USER_CS (GD_UTEXT|DPL_USER)
#define USER_DS (GD_UDATA|DPL_USER)
/* System segment type bits */
#define STS_CG32 0xC // 32-bit Call Gate
#define STS_IG32 0xE // 32-bit Interrupt Gate
#define STS_TG32 0xF // 32-bit Trap Gate
#define SEG_NULL \
(struct segdesc) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define SEG(type, base, lim, dpl) \
(struct segdesc) { \
((lim) >> 12) & 0xffff, (base) & 0xffff, \
((base) >> 16) & 0xff, type, 1, dpl, 1, \
(unsigned)(lim) >> 28, 0, 0, 1, 1, \
(unsigned) (base) >> 24 \
}
#define SEGTSS(type, base, lim, dpl) \
(struct segdesc) { \
(lim) & 0xffff, (base) & 0xffff, \
((base) >> 16) & 0xff, type, 0, dpl, 1, \
(unsigned) (lim) >> 16, 0, 0, 1, 0, \
(unsigned) (base) >> 24 \
}
#define T_SYSCALL 0x80
/* *
* Set up a normal interrupt/trap gate descriptor
* - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate
* - sel: Code segment selector for interrupt/trap handler
* - off: Offset in code segment for interrupt/trap handler
* - dpl: Descriptor Privilege Level - the privilege level required
* for software to invoke this interrupt/trap gate explicitly
* using an int instruction.
* */
#define SETGATE(gate, istrap, sel, off, dpl) { \
(gate).gd_off_15_0 = (unsigned int)(off) & 0xffff; \
(gate).gd_ss = (sel); \
(gate).gd_args = 0; \
(gate).gd_rsv1 = 0; \
(gate).gd_type = (istrap) ? STS_TG32 : STS_IG32; \
(gate).gd_s = 0; \
(gate).gd_dpl = (dpl); \
(gate).gd_p = 1; \
(gate).gd_off_31_16 = (unsigned int)(off) >> 16; \
}
/* segment descriptors */
//bit field
struct segdesc{
unsigned sd_lim_15_0 : 16; // low bits of segment limit
unsigned sd_base_15_0 : 16; // low bits of segment base address
unsigned sd_base_23_16 : 8; // middle bits of segment base address
unsigned sd_type : 4; // segment type (see STS_ constants)
unsigned sd_s : 1; // 0 = system, 1 = application
unsigned sd_dpl : 2; // descriptor Privilege Level
unsigned sd_p : 1; // present
unsigned sd_lim_19_16 : 4; // high bits of segment limit
unsigned sd_avl : 1; // unused (available for software use)
unsigned sd_rsv1 : 1; // reserved
unsigned sd_db : 1; // 0 = 16-bit segment, 1 = 32-bit segment
unsigned sd_g : 1; // granularity: limit scaled by 4K when set
unsigned sd_base_31_24 : 8; // high bits of segment base address
};
/* Gate descriptors for interrupts and traps */
struct gatedesc {
unsigned gd_off_15_0 : 16; // low 16 bits of offset in segment
unsigned gd_ss : 16; // segment selector
unsigned gd_args : 5; // # args, 0 for interrupt/trap gates
unsigned gd_rsv1 : 3; // reserved(should be zero I guess)
unsigned gd_type : 4; // type(STS_{TG,IG32,TG32})
unsigned gd_s : 1; // must be 0 (system)
unsigned gd_dpl : 2; // descriptor(meaning new) privilege level
unsigned gd_p : 1; // Present
unsigned gd_off_31_16 : 16; // high bits of offset in segment
};
//describe the gdt/ldt/idt,remember struct's member is first member in low address
struct dtdesc{
unsigned short dt_size;
unsigned int dt_base;
}__attribute__((packed));
static inline void lgdt(struct dtdesc *dt);
static inline void lidt(struct dtdesc *dt);
void lidt(struct dtdesc *dt);
void gdt_init();
void idt_init();
trap.h
/* Trap Numbers */
/* Processor-defined: */
#define T_DIVIDE 0 // divide error
#define T_DEBUG 1 // debug exception
#define T_NMI 2 // non-maskable interrupt
#define T_BRKPT 3 // breakpoint
#define T_OFLOW 4 // overflow
#define T_BOUND 5 // bounds check
#define T_ILLOP 6 // illegal opcode
#define T_DEVICE 7 // device not available
#define T_DBLFLT 8 // double fault
// #define T_COPROC 9 // reserved (not used since 486)
#define T_TSS 10 // invalid task switch segment
#define T_SEGNP 11 // segment not present
#define T_STACK 12 // stack exception
#define T_GPFLT 13 // general protection fault
#define T_PGFLT 14 // page fault
// #define T_RES 15 // reserved
#define T_FPERR 16 // floating point error
#define T_ALIGN 17 // aligment check
#define T_MCHK 18 // machine check
#define T_SIMDERR 19 // SIMD floating point error
/* Hardware IRQ numbers. We receive these as (IRQ_OFFSET + IRQ_xx) */
#define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET
#define IRQ_TIMER 0
#define IRQ_KBD 1
#define IRQ_COM1 4
#define IRQ_IDE1 14
#define IRQ_IDE2 15
#define IRQ_ERROR 19
#define IRQ_SPURIOUS 31
/* *
* These are arbitrarily chosen, but with care not to overlap
* processor defined exceptions or interrupt vectors.
* */
#define T_SWITCH_TOU 120 // user/kernel switch
#define T_SWITCH_TOK 121 // user/kernel switch
/* registers as pushed by pushal */
struct pushregs {
unsigned int reg_edi;
unsigned int reg_esi;
unsigned int reg_ebp;
unsigned int reg_oesp; /* Useless */
unsigned int reg_ebx;
unsigned int reg_edx;
unsigned int reg_ecx;
unsigned int reg_eax;
};
struct trapframe {
struct pushregs tf_regs;
unsigned short tf_gs;
unsigned short tf_padding0;
unsigned short tf_fs;
unsigned short tf_padding1;
unsigned short tf_es;
unsigned short tf_padding2;
unsigned short tf_ds;
unsigned short tf_padding3;
unsigned int tf_trapno;
/* below here defined by x86 hardware */
unsigned int tf_err;
unsigned int tf_eip;
unsigned short tf_cs;
unsigned short tf_padding4;
unsigned int tf_eflags;
/* below here only when crossing rings, such as from user to kernel */
unsigned int tf_esp;
unsigned short tf_ss;
unsigned short tf_padding5;
} __attribute__((packed));
static void trap_dispatch(struct trapframe *tf);
void trap(struct trapframe *tf);
trap.h
#include "trap.h"
#include "vga.h"
/* *
* trap - handles or dispatches an exception/interrupt. if and when trap() returns,
* the code in kern/trap/trapentry.S restores the old CPU state saved in the
* trapframe and then uses the iret instruction to return from the exception.
* */
/* trap_dispatch - dispatch based on what type of trap occurred */
static void trap_dispatch(struct trapframe *tf)
{
char c;
switch (tf->tf_trapno) {
case 1:
print_string("interrupt 1!\n",black,green);
break;
case IRQ_OFFSET + IRQ_TIMER:
break;
case IRQ_OFFSET + IRQ_COM1:
break;
case IRQ_OFFSET + IRQ_KBD:
break;
case T_SWITCH_TOU:
break;
case T_SWITCH_TOK:
break;
case IRQ_OFFSET + IRQ_IDE1:
case IRQ_OFFSET + IRQ_IDE2:
/* do nothing */
break;
default:
// in kernel, it must be a mistake
print_string("unexpected trap in kernel!\n",black,green);
}
}
void trap(struct trapframe *tf)
{
// dispatch based on what type of trap occurred
trap_dispatch(tf);
}
运行结果:
参考资料:
1.ucore操作系统
2.http://wiki.0xffffff.org/posts/hurlex-7.html
三、GDT和IDT的配置相关推荐
- CPU实模式和保护模式、全局描述符表GDT、Linux内核中GDT和IDT的结构定义
一 计算机实模式和保护模式 实模式 在实模式下,内存被限制为仅有1M字节(220 字节).有效的地址从00000到FFFFF (十六进制). 这些地址需要用20位的数来表示.一个20位的数不适合任何一 ...
- DB数据源之SpringBoot+MyBatis踏坑过程(三)手工+半自动注解配置数据源与加载Mapper.xml扫描...
DB数据源之SpringBoot+MyBatis踏坑过程(三)手工+半自动注解配置数据源与加载Mapper.xml扫描 liuyuhang原创,未经允许禁止转载 系列目录连接 DB数据源之Spr ...
- Kinect开发学习笔记之(三)Kinect开发环境配置
Kinect开发学习笔记之(三)Kinect开发环境配置 zouxy09@qq.com http://blog.csdn.net/zouxy09 我的Kinect开发平台是: Win7 x86 + V ...
- [独孤九剑]持续集成实践(三)- Jenkins安装与配置(Jenkins+MSBuild+GitHub)
本系列文章包含: [独孤九剑]持续集成实践(一)- 引子 [独孤九剑]持续集成实践(二)– MSBuild语法入门 [独孤九剑]持续集成实践(三)- Jenkins安装与配置(Jenkins+MSBu ...
- 华三H3C交换机路由器如何配置dhcp中继
华三H3C交换机路由器如何配置dhcp中继(dhcp relay) 华三交换机路由器如何配置dhcp中继(dhcp relay) 具体环境如上图,内网有专门的dhcp服务器(此处用华三路由器代替)连接 ...
- 计算机网络与协议实验VLAN配置,计算机网络实验三虚拟局域网vlan划分与配置
计算机网络实验三虚拟局域网vlan划分与配置 (5页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 计算机网络原理计算机网络原理 实验报告 ...
- 华三模拟器HCL安装与配置-关联piped、SecureCRT、Wireshark
华三模拟器HCL安装与配置-关联piped.SecureCRT.Wireshark 目录 一. 华三模拟器介绍- 2 1.1 概述- 2 1.2 HCL简介- 2 1.3 HCL模拟器 V2.1.1说 ...
- win7 x64驱动开发经验(三)windbg 双机调试配置 、问题及解决办法
win7 x64驱动开发经验(三)windbg 双机调试配置 .问题及解决办法 http://www.cnblogs.com/witty/archive/2012/04/23/2466024.html ...
- steam游戏上架流程三: 游戏的发布配置与测试
参考: steamworks.net 官方文档的说明 http://steamworks.github.io/gettingstarted/ steam游戏上架流程一:使用官方SDK上传游戏 htt ...
- mysql配置数据库连接池_三种数据库连接池的配置
三种数据库连接池的配置及使用(For JDBC) 连接池的优缺点 优点 使用连接池的最主要的优点是性能.创建一个新的数据库连接所耗费的时间主要取决于网络的速 度以及应用程序和数据库服务器的 ( 网络 ...
最新文章
- keras构建前馈神经网络(feedforward neural network)进行分类模型构建基于早停法(Early stopping)
- 工资高低由什么决定?(面试时如何谈工资?工作中怎样做才能不断涨工资?)...
- 【 MATLAB 】信号处理工具箱之波形产生函数 rectpuls
- Salesforce - soql 多字段多值过滤查询思路
- Activity中与ListActivity中使用listview区别
- 用nodejs搭建最简单、轻量化的http server
- 【渝粤题库】国家开放大学2021春1080工程数学(本)题目
- UBUNTU下双显示器设置
- C++经典问题:如果对象A中有对象成员B,对象B没有默认构造函数,那么对象A必须在初始化列表中初始化对象B?
- 乐山市计算机学校太坑,乐山市计算机学校小规矩成就大素养
- 百度UEditor编辑器使用(二)
- Modbus RTU CRC校验码计算方法
- IDL 读取葵花8(Himawari-8)HSD数据
- 《禅者的初心》读书笔记(2)
- linux下检查磁盘是否有坏道,badblocks 检查硬盘是否有坏道
- 【USACO3-4-2】电网 皮克定理
- 增量迭代模型,瀑布模型,螺旋模型,快速原型模型
- 八大常用基础电路保护器件作用
- 解决:win10下修改mac地址的方法
- 三种求平方根的算法——C/C++