• 操作系统--用户空间和内核空间,用户态和内核态


    内核空间和用户空间,内核态和用户态(转载)

    内核空间和用户空间
    Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的空间分为两部分。将最高的1G字节(从虚拟地址 0xC0000000到0xFFFFFFFF),供内核使用,称为“内核空间”。而将较低的 3G字节(从虚拟地址 0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间)。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。每个进程有各自的私有用户空间( 0~3G),这个空间对系统中的其他进程是不可见的。最高的1GB字节虚拟内核空间则为所有进程以及内核所共享。

    1.虚拟内核空间到物理空间的映射
    内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。不管是内核空间还是用户空间,它们都处于虚拟空间中。可能有人会问,系统启动时,内核的代码和数据不是被装入到物理内存吗?它们为什么也处于虚拟内存中呢?这和编译程序有关,后面我们通过具体讨论就会明白这一点。
    虽然内核空间占据了每个虚拟空间中的最高1GB字节,但映射到物理内存却总是从最低地址(0x00000000)开始。对内核空间来说,其地址映射是很简单的线性映射,0xC0000000就是物理地址与线性地址之间的位移量,在Linux代码中就叫做PAGE_OFFSET。
    内核的虚拟地址空间到物理地址空间的映射我们可以在 include/asm/i386/page.h中看到对内核空间中地址映射的说明及定义: /*
    143 /*
    144 * This handles the memory map.. We could make this a config
    145 * option, but too many people screw it up, and too few need
    146 * it.
    147 *
    148 * A __PAGE_OFFSET of 0xC0000000 means that the kernel has
    149 * a virtual address space of one gigabyte, which limits the
    150 * amount of physical memory you can use to about 950MB.
    151 *
    152 * If you want more physical memory than this then see the CONFIG_HIGHMEM4G
    153 * and CONFIG_HIGHMEM64G options in the kernel configuration.
    154 */
    ...
    173 #define __PAGE_OFFSET CONFIG_PAGE_OFFSET
    ...
    #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
    #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
    源代码的注释中说明,如果你的物理内存大于950MB,那么在编译内核时就需要加CONFIG_HIGHMEM4G和CONFIG_HIGHMEM64G选项,这种情况我们暂不考虑。如果物理内存小于950MB,则对于内核空间而言,给定一个虚地址x,其物理地址为 “x-PAGE_OFFSET”,给定一个物理地址 x,其虚地址为“ x+ PAGE_OFFSET”。
    需要注意的是,宏 __pa()仅仅把一个内核空间的虚地址映射到物理地址,而决不适用于用户空间,用户空间的地址映射要复杂得多。
    2.内核映像
    在下面的描述中,把内核的代码和数据就叫内核映像( kernel image)。当系统启动时, Linux内核映像被安装在物理地址 0x00100000开始的地方,即 1MB开始的区间 (第1M留作它用)。然而,在正常运行时,整个内核映像应该在虚拟内核空间中,因此,连接程序在连接内核映像时,在所有的符号地址上加一个偏移量 PAGE_OFFSET,这样,内核映像在内核空间的起始地址就为 0xC0100000。
    例如,进程的页目录 PGD(属于内核数据结构)就处于内核空间中。在进程切换时,要将寄存器 CR3设置成指向新进程的页目录 PGD,而该目录的起始地址在内核空间中是虚地址,但 CR3所需要的是物理地址,这时候就要用 __pa()进行地址转换。在 mm_context.h中就有这么一行语句:
    asm volatile(“movl %0,%%cr3”: :”r” (__pa(next->pgd));
    这是一行嵌入式汇编代码,其含义是将下一个进程的页目录起始地址 next_pgd,通过__pa()转换成物理地址,存放在某个寄存器中,然后用 mov指令将其写入CR3寄存器中。经过这行语句的处理, CR3就指向新进程 next的页目录表 PGD了。



    内核态和用户态区别
    当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。


    1、用系统调用时进入核心态。Linux对硬件的操作只能在核心态,这可以通过写驱动程序来控制。在用户态操作硬件会造成core    dump.   
     2、要注意区分系统调用和一般的函数。系统调用由内核提供,如read()、write()、open()等。而一般的函数由软件包中的函数库提供,如sin()、cos()等。在语法上两者没有区别。   
     3、一般情况:系统调用运行在核心态,函数运行在用户态。但也有一些函数在内部使用了系统调用(如fopen),这样的函数在调用系统调用是进入核心态,其他时候运行在用户态。

    大概是    当用户程序调用系统的API时,就产生中断,进入内核态的API,处理完成后,用中断再退出,返回用户态的调用函数。   
       user    api    -->    interrupt    -->    kernel    api    -->    interrupt
    ---------------------------------------------------------------------

    简单来讲一个进程由于执行系统调用而开始执行内核代码,我们称该进程处于内核态中. 一个进程执行应用程序自身代码则称该进程处于用户态.


    intel x86 架构的 CPU 分为好几个运行级别,从 0--3 , 0 为最高级别, 3 为最低级别


    针对不同的级别,有很多的限制,比如说传统的 in ,out 指令,就是端口的输入输出指令,在 0 级下是可以用的,但在 3 级下就不能用,你用就产生陷阱,告诉你出错了,当然限制还有很多了,不只是这一点


    操作系统下是利用这个特点,当操作系统自己的代码运行时, CPU 就切成 0 级,当用户的程序运行是就只让它在 3 级运行,这样如果用户的程序想做什么破坏系统的事情的话,也没办法做到


    当然,低级别的程序是没法把自己升到高级别的,也就是说用户程序运行在 3 级,他想把自己变成 0 级自己是做不到的,除非是操作系统帮忙,利用这个特性,操作系统就可以控制所有的程序的运行,确保系统的安全了. 平时把操作系统运行时的级别就叫内核态(因为是操作系统内核运行时的状态),而且普通用户程序运行时的那个级别叫用户态...
    当操作系统刚引导时, CPU 处于实模式,这时就相当于是 0 级,于是操作系统就自动得到最高权限,然后切到保护模式时就是 0 级,这时操作系统就占了先机,成为了最高级别的运行者,由于你的程序都是由操作系统来加载的,所以当它把你加载上来后,就把你的运行状态设为 3 级,即最低级,然后才让你运行,所以没办法,你只能在最低级运行了,因为没办法把自己从低级上升到高级, 这就是操作系统在内核态可以管理用户程序,杀死用户程序的原因.

  • 相关阅读:
    代码坏味道
    外包对程序员发展有什么弊端?
    前端接口神器
    使用Autofac
    在 WASI 上运行 .NET 7 应用程序
    在非k8s 环境下 的应用 使用 Dapr Sidekick for .NET
    一个简单的模拟实例说明Task及其调度问题
    xxljob 小结
    [LeetCode] 1291. Sequential Digits 顺次数
    [LeetCode] 1289. Minimum Falling Path Sum II 下降路径最小和之二
  • 原文地址:https://www.cnblogs.com/cane/p/3978343.html
Copyright © 2020-2023  润新知