Linux 相关学习记录

  自己学习的备忘,从笔记转移过来,后面每一项写一篇对应的理解文章

内核线程和用户进程异同记录

  • 所有进程的内核地址空间则都是一样的。对于内核进程,由于其始终运行在内核态,所以没有用户地址空间,其对应的tast_struct结构体中的mm域也就被赋值为NULL。而堆的概念应该是只存在于进程的用户地址空间中,所以内核进程是没有堆一说的。
  • 内核线程只工作在内核态中;而用户线程则既可以运行在内核态,也可以运行在用户态; 内核线程没有用户空间,所以对于一个内核线程来说,它的0-3G的内存空间是空白的,它的current->mm是空的,与内核使用同一张页表;而用户线程则可以看到完整的0-4G内存空间。
  • 杀死内核线程:将该task_struct的状态标志位改为 KTHREAD_SHOULD_STOP (调kthread_stop函数),内核线程忽略信号,可见 http://lzz5235.github.io/2015/06/23/how-to-kill-a-kthread.html
  • 守护进程可被信号杀死,父进程ID为1,内核进程父进程ID为2(kthreadd)

内核空间分布和寻址

  • 这里写得挺详细:https://www.cnblogs.com/wuchanming/p/4360277.html

    1. 分 ZONE_DMA(16M), ZONE_NORMAL(16M-896M), ZONE_HIGHMEN(896M-1G)(32位机器), ZONE_NORMAL 和 ZONE_DMA 直接映射物理内存,ZONE_HIGHMEM 通过内核PTE页面建立映射,临时用,用完后归还
    2. 进程寻址空间0-4G,进程只有进入内核态才能访问3G-4G
    3. 进程通过系统调用进入内核态
    4. 每个进程虚拟空间的3G~4G部分是相同的
    5. 进程从用户态进入内核态不会引起CR3的改变但会引起堆栈的改变
  • 从用户态进入内核态过程(门的判断)

    • 图参考这里:https://blog.csdn.net/drshenlei/article/details/4265101
    • CPU特权级切换(CPL):是取的CS寄存器的低两位,在任何时候,不管CPU内部正在发生什么,只要看一眼cs中的CPL,你就可以知道此刻的特权级了。
    • 防止用户态访问内核态空间
      • 通过分段保护机制,当 RPL 和 CPL 都大于 DPL 时候才可以访问对应地址的内存
        • CPL是当前进程的权限级别(Current Privilege Level),是当前正在执行的代码所在的段的特权级,存在于cs寄存器的低两位。
        • DPL:描述符特权(Descriptor Privilege Level) 存储在描述符中的权限位,用于描述代码的所属的特权等级,也就是代码本身真正的特权级。一个程序可以使用多个段(Data,Code,Stack)也可以只用一个code段等。正常的情况下,当程序的环境建立好后,段描述符都不需要改变——当然DPL也不需要改变,因此每个段的DPL值是固定。
        • RPL:请求特权级RPL(Request Privilege Level) ,RPL保存在选择子的最低两位。RPL说明的是进程对段访问的请求权限,意思是当前进程想要的请求权限。RPL的值由程序员自己来自由的设置,并不一定RPL>=CPL,但是当RPL<CPL时,实际起作用的就是CPL了,因为访问时的特权检查是判断:EPL=max(RPL,CPL)<=DPL是否成立,所以RPL可以看成是每次访问时的附加限制,RPL=0时附加限制最小,RPL=3时附加限制最大。所以你不要想通过来随便设置一个rpl来访问一个比cpl更内层的段。
  • 用户态到内核态切换途径

    1. 系统调用
    2. 中断
    3. 异常
  • 用户态进入内核态后进程栈如何切换

    • 详细代码参考这里:https://www.cnblogs.com/justcxtoworld/p/3155741.html
    • 读取TSS段(保存有用户栈顶指针和内核栈顶指针)读取 sp0, ss0
      // TSS 结构定义(参考)
      
      #ifdef CONFIG_X86_32
      /* This is the TSS defined by the hardware. */
      struct x86_hw_tss {
          unsigned short          back_link, __blh;
          unsigned long           sp0;              //当前进程的内核栈顶指针
          unsigned short          ss0, __ss0h;       //当前进程的内核栈段描述符
          unsigned long           sp1;
          /* ss1 caches MSR_IA32_SYSENTER_CS: */
          unsigned short          ss1, __ss1h;
          unsigned long           sp2;
          unsigned short          ss2, __ss2h;
          unsigned long           __cr3;
          unsigned long           ip;
          unsigned long           flags;
          unsigned long           ax;
          unsigned long           cx;
          unsigned long           dx;
          unsigned long           bx;
          unsigned long           sp;            //当前进程用户态栈顶指针
          unsigned long           bp;
          unsigned long           si;
          unsigned long           di;
          unsigned short          es, __esh;
          unsigned short          cs, __csh;
          unsigned short          ss, __ssh;
          unsigned short          ds, __dsh;
          unsigned short          fs, __fsh;
          unsigned short          gs, __gsh;
          unsigned short          ldt, __ldth;
          unsigned short          trace;
          unsigned short          io_bitmap_base;
      } __attribute__((packed));
原文地址:https://www.cnblogs.com/varXinYuan/p/10865443.html