linux最新内核的一些变化以及我的一些想法

自从2.6内核放出以后,对于内核爱好者来说,每天都有享不尽的大餐,太令人激动了,每个版本都会推出新东西,本文就很简单的两个方面来讨论一下,一个是2.6内核以后在进入系统空间SAVE_ALL的时候,将ds寄存器设置为了__USER_DS
#define SAVE_ALL /
         cld; /
         pushl %es; /
         pushl %ds; /
         pushl %eax; /
         pushl %ebp; /
         pushl %edi; /
         pushl %esi; /
         pushl %edx; /
         pushl %ecx; /
         pushl %ebx; /
         movl $(__USER_DS), %edx; /
         movl %edx, %ds; /
         movl %edx, %es;
这 里将ds和es设置成了__USER_DS,这岂不是胡闹吗?记住,linux之所以设置什么ds,cs段选择符也是例行公事,完全没有必要,要明白为什 么这里将ds设置成__USER_DS,还要先看看ds是干什么用的,ds是数据段寄存器,cs是代码段寄存器(涉及到intel寄存器的可见部分和不可 见部分,这个不谈),ds的保护作用是:如果你访问的段,要求的访问级别高于当前进程的代码段级别的话,访问会导致GP异常。现在进入了内核,当前代码段 的访问级别为0,处于最高级别,它访问任何段都不会出错,再者,linux为了减少复杂性,只用了2个级别,那么就没有任何问题了,如果要像intel规 定的那样将ds寄存器设置成 __KERNEL_DS,那么看看从内核返回的时候:恢复CS,EIP的值,此时CS的CPL是3.因为DS,ES被设为了__KERNEL_DS,所以其DPL是0,所以要将DS,ES中的值清除.这样就要一个清除动作,损失了效率,因此就先将ds段寄存器设置成__USER_DS,这么做的一切都是 intel的什么狗屁分段机制造成的,汗!另外在创建内核线程的时候还有一处诡异也是这个道理:

int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)

{

         struct pt_regs regs;

         memset(&regs, 0, sizeof(regs));

         regs.ebx = (unsigned long) fn;

         regs.edx = (unsigned long) arg;

         regs.xds = __USER_DS;//一会ret_from_fork的时候要RESTORE_ALL

         regs.xes = __USER_DS;

         regs.orig_eax = -1;

         regs.eip = (unsigned long) kernel_thread_helper;

         regs.xcs = __KERNEL_CS;

         regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;

         /* Ok, create the new process.. */

         return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);

}

ENTRY(ret_from_fork)

         pushl %eax

         call schedule_tail

         GET_THREAD_INFO(%ebp)

         popl %eax

         jmp syscall_exit

...

syscall_exit:

         cli                      # make sure we don't miss an interrupt

                                     # setting need_resched or sigpending

                                       # between sampling and the iret

         movl TI_flags(%ebp), %ecx

         testw $_TIF_ALLWORK_MASK, %cx   # current->work

         jne syscall_exit_work

restore_all:

         RESTORE_ALL

#define RESTORE_ALL     /               #这里RESTORE_ALL的正是上面伪造的regs现场

         RESTORE_REGS    /

         addl $4, %esp;  /

1:      iret;           /

#define RESTORE_REGS    /

         RESTORE_INT_REGS; /

1:      popl %ds;       /

2:      popl %es;       /

.section .fixup,"ax";   /

3:      movl $0,(%esp); /

         jmp 1b;         /

4:      movl $0,(%esp); /

         jmp 2b;         /

.previous;              /

.section __ex_table,"a";/

         .align 4;       /

         .long 1b,3b;    /

         .long 2b,4b;    /

.previous

上面就是说2.6内核已经不再用__KERNEL_DS了,因为没有任何意义。(传统的intel段寄存器里面会有一些“门”,linux包括windows并没有用那么
多复杂的专为老式系统设计的“门”)
说完了这个再说说内核线程的创建,以前都是直接调用kernel_thread就完事了,最新的2.6.26和27内核倒好,专门为创建内核线程在系统保 留了一个内核守护线程,这下好了,你要创建一个内核线程也要向这个守护线程请求,然后排队,唤醒这个守护线程,这样这个守护线程会替你把内核线程创建出来,linux对进程/线程真是情有独钟啊!重要的是,进程/线程拥有上下文,于是它就可以接受系统的管理,这样就不会有那么多的限制,管理起来更方便, 毕竟将创建内核线程这件事情给统一管理了,但是我担心的是。这会不会出现单点故障。唉,分离和统一,一对矛盾啊,当你觉得不能再进一步统一时,就尝试分离吧!前面的博客还说windows喜欢将一切纳入自己的“管理器”,现在linux也差不多了,但是不同的是,windows钟情于自己设计的对象,一切 都是对象,所以管理器都是对象管理器,而linux更钟情于一个古老的概念----进程,实际上,linux能进程/线程化的都进程/线程化了。
设计上的东西,说起来没完,就此打住,且待下回!

原文链接: https://blog.csdn.net/dog250/article/details/5303223

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    linux最新内核的一些变化以及我的一些想法

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/410489

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 下午12:03
下一篇 2023年4月26日 下午12:03

相关推荐