30OS笔记(3)

第五天完成了文字显示与GDT/IDT初始化。

字符是以8*16的长方形点阵实现的,所以一个字符有16B。16个十六进制数便表示出这一个字符。

字库由hankaku.txt提供。

GDT(global (segment) descriptor table)全局段号记录表:

为了解决内存使用范围重叠等问题,可以将内存分为许多块(block),每一块起始地址都看做0来处理。

为了表示一个段,需要有以下信息:

段的大小;

段的起始地址;

段的管理属性;

CPU用8B来表示这些信息,然而用于指定段的寄存器(GDTR)只有16位。因此这里再次用了索引的方法。由于CPU设计的原因,段寄存器的低3位不能使用,因此能够使用的段号只有13位,从0-8191。所对应的内容共有8192B(64KB),这64KB的数据就是GDT。

选择器构成简图:

索引号(13位)|T1(1位)|RPL(2位)

IDT(interrupt descriptor table)中断记录表:和GDT原理差不多。

----------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------

struct SEGMENT_DESCRIPTOR {
	short limit_low, base_low;
	char base_mid, access_right;
	char limit_high, base_high;
};

struct GATE_DESCRIPTOR {
	short offset_low, selector;
	char dw_count, access_right;
	short offset_high;
};

以上两个结构体分别子路了GDT与IDT的内容。
limit_low 段限长的0~15bit base_low 段基址的0~15bit
base_mid 段基址的16~23bit access_right(0~3bit TYPE字段, 4bit S字段 5~6 DPL字段 7bit P字段)
limit_high 段限长的16~19bit+AVL+D/B+G域 base_high 段基址的24~31bit

offset_low 过程偏移地址的低16bit selector 段选择子
dw_count 参数个数, 只是调用门中有效
access_right 0~3bit:TYPE字段, 4bit:S字段, 5~6bit:DPL字段, 7bit:P字段
offset_high 过程偏移地址的高16bit

void init_gdtidt(void)
{
	/* GDT的位置紧随在IDT之后 */
	struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) 0x00270000;
	struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) 0x0026f800;
	
	int i;

	/* GDT初始化 */
	for (i = 0; i < 8192; i++) {
		set_segmdesc(gdt + i, 0, 0, 0);
	}
	/* 编号为0的描述符是空描述符 是Intel要求必须这样设置的 */
	set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);	/* 内核数据段 
				 32位可读写数据段描述符 段限长4G-1 段基址0  DPL = 0*/
	set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);	/* 内核代码段 
				32位可读可执行代码段描述符 段限长512KB  段基址0x280000 DPL = 0*/
	load_gdtr(0xffff, 0x00270000);							/* 加载GDT */

	/* IDT初始化 */
	for (i = 0; i < 256; i++) {
		set_gatedesc(idt + i, 0, 0, 0);
	}
	load_idtr(0x7ff, 0x0026f800);							/* 加载IDT */

	return;
}

/* 设置段描述符 */
/*
	sd 段描述符结构指针	limit 段限长	base 段基址		ar 段描述符属性
 */
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
	if (limit > 0xfffff) {			/* 如果限长大于1M (20bit的段限长若以字节为单位最多只能表示1M的内存)*/
		ar |= 0x8000; /* G_bit = 1 */	/* 描述符中有一个G位, 若G = 1则表示段限长是以4KB为单位
											若G = 0 则表示段限长是以字节为单位的 */
		limit /= 0x1000;				/* 调整段限长的值即除以4K */
	}
	
	/* 将各值填入相应的域中 可参考上面给出的段描述符图 */
	sd->limit_low    = limit & 0xffff;
	sd->base_low     = base & 0xffff;
	sd->base_mid     = (base >> 16) & 0xff;
	sd->access_right = ar & 0xff;
	sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
	sd->base_high    = (base >> 24) & 0xff;
	return;
}

/* 设置门描述符 */
/*
	gd 门描述符结构指针		offset 过程入口偏移
	selector 段选择子		ar 门描述符属性
 */
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
	gd->offset_low   = offset & 0xffff;
	gd->selector     = selector;
	gd->dw_count     = (ar >> 8) & 0xff;
	gd->access_right = ar & 0xff;
	gd->offset_high  = (offset >> 16) & 0xffff;
	return;
}
将0x00270000-0x0027ff00设为GDT是随便设的。
感谢宅的中文注释,这些东西日后再深入理解。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值