一个简单的进程----跳到ring3

进程都是工作的特权级ring3下的,如何跳到ring3呢?我们用iret指令,不过在这之前我们要准备好ring3的堆栈,设置ring3的代码段,为了能在ring3模式下能够打印我们还要修改视频段,还记得前面《ring0到ring3》是如何做的吗?我们先写一个函数_set_gdt_desc来修改gdt,代码非常的简单,无非是设置gdt中的描述符。

typedef	unsigned int		u32;
typedef	unsigned short	u16;
typedef	unsigned char		u8;
typedef struct Descriptor		/* ???8 ??a?-?è??*/
{
	u16	limit_low;		/* Limit */
	u16	base_low;		/* Base */
	u8	base_mid;		/* Base */
	u8	attr1;			/* P(1) DPL(2) DT(1) TYPE(4) */
	u8	limit_high_attr2;	/* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
	u8	base_high;		/* Base */
}DESCRIPTOR;
void _set_gdt_desc(struct desc_struct *descriptor_addr,u32 base,u32 limit,u16 attr)
{
 DESCRIPTOR *descriptor = (DESCRIPTOR *)descriptor_addr;
 descriptor->limit_low = limit & 0x0FFFF;
 descriptor->base_low  = base & 0x0FFFF;
 descriptor->base_mid  = (base >> 16) & 0x0FF;
 descriptor->attr1   = attr & 0xFF;
 descriptor->limit_high_attr2= ((limit>>16) & 0x0F) | (attr>>8) & 0xF0;
 descriptor->base_high = (base >> 24) & 0x0FF;
}


 然后分别设置视频段、堆栈段、代码段

#define DA_C     0x98        //存在的只执行代码段属性值
#define DA_32    0x4000  //32 位段
#define DA_DPL3  0x60   //DPL = 3
#define DA_DPL0  0x00   //DPL = 0
#define DA_DRWA  0x93 //存在的已访问可读写数据段类型
#define DA_DRW   0x92  //存在的可读写数据段属性值
#define SA_RPL3   3        //RPL(Requested Privilege Level)=3: 请求特权级,用于特权检查。

//视频段,选择子为0x10
_set_gdt_desc(&gdt[2],0xb8000,0x0ffff,DA_DRW+ DA_DPL3);
//堆栈段,选择子为0x28
_set_gdt_desc(&gdt[5],0,0xffffffff,DA_DRWA + DA_32 + DA_DPL3);
//代码段,选择子为0x30
_set_gdt_desc(&gdt[6],0,0xffffffff,DA_C+DA_32+DA_DPL3);


写一个简单的进程,不停的打印A

void delay(int time)
{
	int i, j, k;
	for (k = 0; k < time; k++) {
		for (i = 0; i < 10; i++) {
			for (j = 0; j < 10000; j++) {}
		}
	}
}
void testA(void)		
{

set_registers();

	while(1){
		disp_str("A");
		delay(2);
	}
}

下面我们该实现跳转了

#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
	"pushl $0x2b\n\t" \
	"pushl %%eax\n\t" \
	"pushfl\n\t"\
	"pushl $0x33\n\t" \
	"pushl $testA\n\t" \
	"iret\n" \
	:::"ax")

第2行将寄存器esp的值放到eax中

第3行设置ss,即堆栈段选择子0x28+3,3是SA_RPL3

第3行设置esp

第4行设置

第5行设置cs,即代码段选择子0x30+3,3是SA_RPL3

第5行设置eip

第6行iret实现跳转

#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \   
 "pushl $0x2b\n\t" \
 "pushl %%eax\n\t" \
 "pushfl\n\t"\
 "pushl $0x33\n\t" \
 "pushl $testA\n\t" \
 "iret\n" \
 :::"ax")

你可能感兴趣的:(一个简单的进程----跳到ring3)