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

来源:互联网 发布:韦德生涯数据 编辑:程序博客网 时间:2024/05/17 19:20

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

typedefunsigned intu32;typedefunsigned shortu16;typedefunsigned charu8;typedef struct Descriptor/* ???8 ??a?-?è??*/{u16limit_low;/* Limit */u16base_low;/* Base */u8base_mid;/* Base */u8attr1;/* P(1) DPL(2) DT(1) TYPE(4) */u8limit_high_attr2;/* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */u8base_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")