1个人开发操作系统之GDT和IDT的初始化

内存管理时,不让多进程的程序出现内存冲突的一解决方案是Segmentation4GB的内存可以任何分割,每块的初始地址都是0。另外还有一种复杂的内存管理方案,既Paging,目前主流的操作系统都是采用这种方式。本文的OS为了实现简单,只采用Segmentation方案。

我们规定1Segmentation的信息有:

l Size

l 初始地址

l 属性(读写权限等)。

每个Segementation信息占8Byte,既64bit。我们把所有的Segment编号,并把编号保存在CPU内的16segment register里。Segment register可以处理08191segment 本来16位的register应该可以处理065535segment,但是因为register的低3为不能使用,所以最多只到8191。为了保存8192segment(每个8bytes),需要64KB的容量,CPU是无法保存这么多数据的,因此需要内存的帮助。GDT[gobal (segment) descriptor table]的缩写,它保存所有segment的信息。Segment的初始地址和有效设定个数保存在CPUGDTR寄存器内。另外一个IDT[interrupt descriptor table]的缩写,用来处理一些内部或外部的中断。例如键盘,鼠标,软驱,硬盘,CDROM,网卡等。IDT可以处理0255编号的中断,例如当123号中断发生时,调用XXX函数。IDT的信息和GDT相似,也是每个8bytes。本系统的GDT分配在内存的0x270000x27ffffIDT0x<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="26" unitname="F">26f</chmetcnv>8000x26ffff,占2KB

我们将Segment定义为:

struct SEGMENT_DESCRIPTOR {

short limit_low, base_low;

char base_mid, access_right;

char limit_high, base_high;

};

Segment信息的初始地址由32bit组成,成为Base地址,分为3个部分,low2byte),mid1byte),high1byte),如此分割是为了兼容80286 CPU

Segment信息的大小成为LimitLimit最大可以为4GB,当然是在32位机。这样就需要4Byte,和Base地址一共需要8byte,但这样就没有保存属性的位置。为了留给属性空间,只能给Limit 20bit,最大能表示1MB,当然这样是不能满足目前主流的32bit机的。Intel为了解决这个问题,规定了在属性里留有1位称为G bitG表示granularity,粒度),limit的单位不是Byte,而是PagePCCPU1Page表示4KB。这样4KB*1MB=4GB。为了能表示20bitLimit,我们使用2Byte。其中多出的4bit用来表示属性。

Segment的属性由Limit多出的4bit加上剩下的8bit表示,也称访问权限。访问权限的构成:

XXXX0000XXXXXXXXX代表01

4bit386以后使用的扩张访问属性,由[GD00]构成,G表示上面提到的粒度,D表示Segment mode1表示32位机,0表示16位机。下8bit继承80286时代的Segement属性。8bit的属性内容非常多,在这里,我们常用的有如下几个:

000000000x00):未使用的Descriptor table

100100100x92):系统专用,可读写,不能执行

100110100x<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="9" unitname="a">9a</chmetcnv>):系统专用,可执行,可读,不可写

111100100xf2):应用程序使用,可读写,不可执行。

111110100xfa):应用程序可用,可执行,可读,不可写。

属性规定了系统和应用程序使用的读写执行权限。系统模式称为Ring0,应用程序模式称为Ring3,中间的Ring1Ring2模式是系统服务。Ring0管理Ring3,例如,Ring3的应用程序在请求Load LGDT时,操作系统将否决该请求,以保证系统的安全性。下面是新增加的源代码文件。

/*boot.h*/

#define AR_DATA32_RW 0x4092

#define AR_CODE32_ER 0x<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="409" unitname="a">409a</chmetcnv>

#define ADR_BOTPAK 0x00280000

#define LIMIT_BOTPAK 0x0007ffff

#define LIMIT_GDT 0x0000ffff

#define ADR_IDT 0x<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="26" unitname="F">0026f</chmetcnv>800

#define LIMIT_IDT 0x000007ff

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;

};

void init_gdtidt(void);

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);

/*gldt.c*/

#include "boot.h"

void init_gdtidt(void)

{

struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;

struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT;

int i;

/*GDT Init*/

for (i = 0; i <= LIMIT_GDT / 8; i++) {

set_segmdesc(gdt + i, 0, 0, 0);

}

/*set all memory into data segement*/

set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW);

/*set this segemnt to code segment that can be executed by system*/

set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);

load_gdtr(LIMIT_GDT, ADR_GDT);

/*IDT Init*/

for (i = 0; i <= LIMIT_IDT / 8; i++) {

set_gatedesc(idt + i, 0, 0, 0);

}

/*implemented in func.s*/

load_idtr(LIMIT_IDT, ADR_IDT);

return;

}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)

{

if (limit > 0xfffff) {

ar |= 0x8000; /* G_bit = 1 */

limit /= 0x1000;

}

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) & 0x<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="0" unitname="F">0f</chmetcnv>) | ((ar >> 8) & 0xf0);

sd->base_high = (base >> 24) & 0xff;

return;

}

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;

}

;func.s

;Colimas Simple OS

[BITS 32]

GLOBAL _io_hlt, _io_cli, _io_sti, io_stihlt

GLOBAL _io_in8, _io_in16, _io_in32

GLOBAL _io_out8, _io_out16, _io_out32

GLOBAL _io_load_eflags, _io_store_eflags

GLOBAL _load_gdtr, _load_idtr

segment .text

_io_hlt: ; void io_hlt(void);

HLT

RET

_io_cli: ; void io_cli(void);

CLI

RET

_io_sti: ; void io_sti(void);

STI

RET

_io_stihlt: ; void io_stihlt(void);

STI

HLT

RET

_io_in8: ; int io_in8(int port);

MOV EDX,[ESP+4] ; port

MOV EAX,0

IN AL,DX

RET

_io_in16: ; int io_in16(int port);

MOV EDX,[ESP+4] ; port

MOV EAX,0

IN AX,DX

RET

_io_in32: ; int io_in32(int port);

MOV EDX,[ESP+4] ; port

IN EAX,DX

RET

_io_out8: ; void io_out8(int port, int data);

MOV EDX,[ESP+4] ; port

MOV AL,[ESP+8] ; data

OUT <place w:st="on"><city w:st="on">DX</city>,<state w:st="on">AL</state></place>

RET

_io_out16: ; void io_out16(int port, int data);

MOV EDX,[ESP+4] ; port

MOV EAX,[ESP+8] ; data

OUT DX,AX

RET

_io_out32: ; void io_out32(int port, int data);

MOV EDX,[ESP+4] ; port

MOV EAX,[ESP+8] ; data

OUT DX,EAX

RET

_io_load_eflags: ; int io_load_eflags(void);

PUSHFD ; PUSH EFLAGS

POP EAX

RET

_io_store_eflags: ; void io_store_eflags(int eflags);

MOV EAX,[ESP+4]

PUSH EAX

POPFD ; POP EFLAGS

RET

;09/03

_load_gdtr: ; void load_gdtr(int limit, int addr);

MOV AX,[ESP+4] ; limit

MOV [ESP+6],AX

LGDT [ESP+6]

RET

_load_idtr: ; void load_idtr(int limit, int addr);

MOV AX,[ESP+4] ; limit

MOV [ESP+6],AX

LIDT [ESP+6]

RET

_load_gdtr函数的参数是LimitBase地址,GDTR48位寄存器,不能直接使用Mov指令,这个寄存器的后16bit,也就是内存的最初2byte表示Limit,剩下的4byte表示Base地址。[ESP+4]表示limit[ESP+8]表示base地址。因为我们不需要Limit[ESP+4][ESP+6]的值,只需要将[ESP+6]代入LGDT_load_idtr_load_gdtr相同。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值