作家
登录

Java开发操作系统内核:实现进程的优先级切换

作者: 来源: 2017-07-18 09:18:42 阅读 我要评论

【技巧沙龙】AI开辟者拭魅战营-7分钟打造1个定制技能。7月22号,我们等你一路!


为了保护体系内核不受恶意法度榜样的破坏,我们本来的做法是专门为应用法度榜样分派零丁应用的内存,使得应用法度榜样对数据的读写都限制在内核给他分派的内存段内。法度榜样对内存段的读写,美满是由DS存放器指向的全局描述符决定的,如不雅恶意法度榜样经由过程修改DS存放器的值,使得它在运行时,让DS存放器指向内核数据段的全局描述符,那么恶意法度榜样就可以读写内核的数据了,为了防备出现这种情况,我们要做的是让应用法度榜样没有读写段存放器的权力,是以我们就必须设定应有法度榜样的优先级。

在X86架构下,法度榜样可以分为4个等级,分别是0,1,2,3.级别数越低,它的权限就越高,体系内核是权限最高的,是以它运行的优先级为0,为了防止应用法度榜样作乱,我们在启动它之前,必须把它的优先级设定为最初级,也就是3.

为了让应用法度榜样运行在低特权级上,内核在启动应用法度榜样前,必须把应用法度榜样代码地点的内存段的级别设置为3,在一个级别为3的代码段上运行指令时,如不雅指令的优先级高于3,例如读写段存放器等,那么就会触发CPU缺点,根据上篇文┞仿讲过的内核异常处理机制,内核就会把应用法度榜样的杀掉落。于是我们修改内核启动应用法度榜样的相干代码,在write_vga_desktop.c中:

void cmd_hlt() {file_loadfile("abc.exe", &buffer);    struct SEGMENT_DESCRIPTOR *gdt =(struct SEGMENT_DESCRIPTOR *)get_addr_gdt();    set_segmdesc(gdt+11, 0xfffff, buffer.pBuffer, 0x409a + 0x60);    //new memory     char *q = memman_alloc_4k(memman, 64*1024);    set_segmdesc(gdt+12, 64 * 1024 - 1, q ,0x4092 + 0x60);    struct TASK *task = task_now();    start_app(0, 11*8,64*1024, 12*8, &(task->tss.esp0));    memman_free_4k(memman, buffer.pBuffer, buffer.length);    memman_free_4k(memman, q, 64 * 1024);}

膳绫擎代码跟以前比拟,差别在于set_segmdesc调用中,设置内存段属性时,我们多加了0x60,加上0x60的目标是,把该描述符所指向的内存其优先级设置为3.如许一来,应用法度榜样一旦指向高优先级的CPU指令,例如move ds, ax这种读写段存放器的指令时,就会激发CPU异常。

同时我们经由过程调用task_now()获合适前正在运行的过程对象,每个过程对象都含有一个TSS数据构造,其内容如下(在multi_task.h中):

struct TSS32 {    int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;    int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;    int es, cs, ss, ds, fs, gs;    int ldtr, iomap;};

TSS构造我们在早前讲到过程切换的┞仿节里有过对它的具体解读,这里我们须要留意它的几个变量:esp0, ss0, esp1, ss1, esp2, ss2。一个过程在运行时,它可以运行在不合优先级下,在不合优先级下运行时,它必须应用不合的客栈,这些变量就是用于存储不合优先级下对应的客栈段和客栈指针的。如不雅过程要切换到优先级0,那么CPU会主动大年夜esp0和ss0中攫取客栈指针和客栈内存段的全局描述符,如不雅过程要大年夜优先级0切换到优先级1,那么我们内核须要本身把对应优先级0的客栈指针和客栈段描述符的值存入到esp0和ss0。也就是说如不雅过程大年夜低优先级切换到高优先级时,CPU会主动帮我们大年夜TSS中攫取对应的客栈段全局描述符和客栈指针,实现响应的客栈切换。如不雅过程大年夜高优先级切换到低优先级时,须要过程本身把高优先级的客栈段描述符和客栈指针存储到TSS中的响应地位。

这也是为何我们调用start_app时,要把TSS对应的esp0变量的地址传入,因为start_app要启动一个优先级为3的应用法度榜样,一旦应用法度榜样运行起来时,过程的优先级会大年夜0变为3,是以我们须要把切换前的客栈指针和客栈段存储到TSS构造的esp0和ss0中。我们再看看start_app的实现:

start_app:  ;void start_app(int eip, int cs,int esp, int ds, &(task->tss.esp0))    pushad    mov eax, [esp+52]    mov [eax], esp    mov [eax+4], ss    mov eax, [esp+36]  ;eip    mov ecx, [esp+40]  ;cs    mov edx, [esp+44]  ;esp    mov ebx, [esp+48]  ;ds    mov  ds,  bx    mov  es,  bx    or ecx,3    or ebx, 3    push ebx    push edx    push ecx    push eax    retf

esp+52对应的┞俘好是start_app的最后一个参数,也就是&(task->tss.esp0),也就是当前过程含有的TSS构造中,esp0变量的地址。我们把它的地址赋值给存放器eax, 指令mov [eax], esp 它的感化就是把当前客栈指针存入TSS构造里的esp0变量,指令mov [eax+4], ss, 它的感化是把当前客栈段描述符存储到TSS构造的ss0变量。

膳绫擎代铝闼楝有两条指令特别值得我们留意,他们是:

or ecx, 3or ebx, 3
00000001  ->  00001000

左移三位后会在右边空出3个0,这三个0是有专门感化的,前两个0用于表示对应内存段的优先级,也叫请求优先级,当内核要运行应用法度榜样的代码时,我们须要把应用法度榜样代码段赋值给存放器cs,把应用法度榜样的内存段赋值给ds,如不雅要把优先级大年夜0切换成3时,我们须要把请求优先级也设置为3,这就是前面两条指令的感化:

or ecx, 3or ebx, 3

ecx存放器存储的是应用法度榜样的代码段,ebx存放器存储的是应有法度榜样的内存段。我们以前讲过,在把全局描述符赋值给段存放器时,须要把该描述符对应在全局描述符表中的下标乘以8后再传给段存放器,为何要乘以8呢?假设某个全局描述符它的下标是1,乘以8相当于左移三位:


膳绫擎两条指令运行后,最右边的两个0都邑变成1,也就是把请求优先级设置成了3。还值得留意的是,以前我们把CPU控制器交给应用法度榜样时,应用的指令是call far,但如不雅跳转时带有优先级切换,那么CPU就不许可应用call far 或者是jmp far 这两种指令,我也不知道英特尔为何这么设计,要实现大年夜优先级0跳转到优先级3,必须先把优先级3对应的客栈和客栈指针压入当前客栈,然后把优先级3的代码段描述符和IP指针压入客栈,然后再履行retf敕令,这几个步调对应的┞俘好是最后几条指令:


  推荐阅读

  大咖头脑风暴:智能互联网时代会发生什么?

【技巧沙龙】AI开辟者拭魅战营-7分钟打造1个定制技能。7月22号,我们等你一路!无论是生活在一线都会,照样栖身在偏远山村,今天中国的绝大年夜多半处所,互联网都已经如同水与电一样,渗入渗出进人们的>>>详细阅读


本文标题:Java开发操作系统内核:实现进程的优先级切换

地址:http://www.17bianji.com/lsqh/36255.html

关键词: 探索发现

乐购科技部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与乐购科技进行文章共享合作。

网友点评
自媒体专栏

评论

热度

精彩导读
栏目ID=71的表不存在(操作类型=0)