精华内容
下载资源
问答
  • 进程内核空间共享

    千次阅读 2012-06-15 15:46:28
    在2.6内核中,所有进程内核空间(3G-4G)都是共享的。  LINUX内核在初始化过程中,内核页表的初始化在保护模式下,但是此时尚未开启分页机制。内核填充PGD表(静态数组),使得(3G-4G)的虚拟地址映射到物理...

    在2.6内核中,所有进程的内核空间(3G-4G)都是共享的。
      LINUX内核在初始化过程中,内核页表的初始化在保护模式下,但是此时尚未开启分页机制。内核填充PGD表(静态数组),使得(3G-4G)的虚拟地址映射到物理地址(0-1G),确切的讲,是(3G -3G+896M)的虚拟地址映射到物理地址(0-896M),因为剩下的(3G+896M--4G)虚拟空间可以用来映射物理存储器的高端地址(大于896M)。然后内核将PGD基地址加载到CR3中,将CR0的PG位置1,正式开启分页机制。此时,(3G-3G+896M)的虚拟地址正式映射到物理地址(0-896M)。
      内核页表PGD将作为进程SWAPPER(PID=0)的页表,SWAPPER是系统中的第一个进程,除了SWAPPER,内核还创建INIT进程。
      INIT进程的页表跟内核页表是一致的,系统中的其它所有用户进程都是INIT进程的儿子或后代。
      而在LINUX中,用户进程的创建都是父进程通过FORK()函数实现,创建的子进程有两种情形:1)子进程与父进程完全共享地址空间,此时它们共享PGD以及PTE;2)子进程不与父进程共享地址空间,此时它们有各自的PGD与PTE,但是(在创建之初)子进程的PGD与PTE是父进程的拷贝。
      在各个进程的运行过程中,他们的页表可能会发生变化,比如发生缺页异常,或者执行EXEC()系列函数,但是所有这些页表项的变化都属于用户空间(0--3G)。内核空间的页表几乎不变,确切的讲,(3G-3G+896M)之间的页表项不变(也就是说,所有进程的3G--3G+896M的虚拟地址都映射到物理地址0--896M)。相反,(3G+896M--4G)之间的页表可能会变,比如内核执行VMALLOC()函数,可能就会修改(3G+896M--4G)之间的页表,为了使所有进程的内核空间(3G--4G)都保持一致,原则上必须修改每个进程的(3G+896M--4G)之间的页表,这样做的效率比较低下。LINUX内核通过PAGE FAULT机制保持所有进程的(3G+896M--4G)之间的页表一致。
      比如在vmalloc分配了一块内存,如何通知所有的进程修改其页表呢?遍历修改?vmalloc先在kernel virtual space找出一段空间,分配出物理页,然后更新到init_mm.pgd所指的page table中。但是当前进程的page table中kernel virtual space那段还是要通过page fault来更新。当发生page fault时,内核通过读取cr2来判断异常的类型,异常发生时cpu会将3位的error_code压入到栈中。如果发生了由于内核访问不存在的页框引起的异常,就跳转去执行vmalloc_fault标记处的代码。这部分代码负责从主内核页表中取出相应信息并更新当前进程的页表。

    来源:http://blog.csdn.net/billbeggar/article/details/5733057

    展开全文
  • 内核空间!=内核进程

    千次阅读 2012-04-12 13:25:01
    #:没有内核进程和用户进程之分; #:每个进程可以在用户态运行和内核态运行; #:每个进程可以认为是一个指令运行路线+背景信息(如:打开文件),这些指令沿着路线的执行会影响到进程的信息(进程的路线是由CPU...
    #:没有内核进程和用户进程之分;
    #:每个进程可以在用户态运行和内核态运行;
    #:每个进程可以认为是一个指令运行路线+背景信息(如:打开文件),这些指令沿着路线的执行会影响到进程的信息(进程的路线是由CPU的eip决定的);

    #:进程的切换:进程的切换需要由当前正在运行的进程准备好“切换到的进程”的相关信息的设置(如:current_proc),然后在执行一个CPU指令(如:ljmp可以通过TSS完成相关寄存器的设置),在这之后,地址空间变了,且CPU按照新的的eip执行了,也就是说新的进程得到了运行。


    进程不分内核进程和用户进程,对于处理器差别在于:优先级的大小和时间片的长短,以及进程的地址空间(3G和1G)

    http://www.perfgeeks.com/

    http://www.embedu.org/Column/Column240.htm


    从android 启动文章看

    init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,
    并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,
    完成引导进程。init始终是第一个进程。

    个人分析:内核空间是指1G内的内存地址在启动后始终加载这驱动等共各个动态启动的用户进程来调用,他是共享静态始终在内存1G范围内的

    而用户进程调用驱动并没新开进程,还在统一进程,不过CPU执行的代码由用户内存空间转移到内核所在的1G范围内了,这样就会有增加的权限等

    等来区分所谓的用户和内核。

    展开全文
  • linux进程内核地址空间

    千次阅读 2011-02-11 21:20:00
    linux进程内核地址空间

      一、 Linux采用了虚拟内存管理技术,使得每个进程都有独立的进程地址空间,该空间是大小为3G,用户看到和接触到的都是虚拟地址。利用这虚拟地址,不但能保护操作系itongde作用,更重要的是用户程序可使用比实际物理地址内存更大的地址空间。

        l二、inux将4G的虚拟地址空间划分为2部分---用户空间与内核空间用户空间从0到0xbfffffff,内核空间从3G到4G,用户进程通常情况下只能访问用户空间的虚拟地址,不能访问啮合空间。例外请款情况是用户进程通过系统调用访问内核空间。

        三、用户空间对应进程,每当进程切换,用户空间就会跟着变化。

        catr/proc/<pid>/maps下查看每个进程运行的用户空间。

        创建进程fork(),程序载入execve(),动态分配内存malloc()等进程相关的操作都需要分配内存给进程。进程申请和获得的不是物理地址,仅仅是虚拟地址。

        实际的物理内存只有当进程真的去访问新获得的虚拟地址时候,才会由“请页机制”产生“缺页”异常,从而进入分配实际页框的程序。该异常是虚拟内存机制赖以存在的基本保证---它会个哦阿苏内核去为进程分配物理页,并建立对应的页表,这之后虚拟地址才实实在在的映射到物理地址上。

      四、Linux内核中内存分配

    1、   #include <linux/slab.h>

    void *kmalloc(size_t size,int flags)  

     参数: size :要分配的内存大小。flags:分配的标志,它控制kmalloc的行为。

     flags如下:

      GFP-ATOMIC  用来在进程上下文之外的代码(包括中断处理)中分配内存,从不睡眠。

    GFP_KERNEL  进程上下文中的分配,可能睡眠  (16M--896M)

    __GFP_DMA  这个标志要求分配能够DMA的内存取(物理地址在16M一下的页帧)

    __GFP_HIGHMEM  表示分配的内存位于搞内存

    2、按页分配:使用模块需要分配大块的内存。

      get_zeroed_page(unsigned int flasgs)  返回指向新页面的指针,并将页面清零

     __get_freee_page(unsigned int flags)  fan返回指向新页面的指针,但不清零页面

    __get_free_pages(unsigned int flags,unsigned int order)

    分配若干个连续的页面,返回指向该内存区域的指针,但是不清零这段内存区域。

    当程序用完这些页后,可以释放他们:

     void free_page(unsigned long addr)

    void free_pages(unsigned long adrr,unsigned  long order)

    如果释放的和先前分配数目不等的页面,会导致系统错误。

     

     五:内核地址空间:固定的,不会随着进程变化而改变

     六:高端内存:物理内存896M以上部分。

        内核空间分布

     直接映射区 8M        动态映射区 8K           KMAP区(永久内存映射区)     固定映射区4K

        896M(MAX)               120M(MIN)                  4M                 4M

    七:直接映射区

          从3G开始,最大896M的线性地址区间,我们称作直接内存映射区,这是因为该区域的线性地址和物理地址之间存在线性转换关系:    线性地3G+物理地址    kmallloc是直接内存映射区分配的,分配的是物理内存

      物理地址区间0x100000  - ---   0x200000映射到线性地址空间就是3G+0x100000     -----    3G+0x200000

    八、动态内存映射区

      该区域的地址由内核函数vmalloc来进行分配,其特点是线性空间连续,但对应的物理空间不连续。vmalloc分配的线性地址所对应的物理页可能处于低端内存,也可能处于高端内存。

    九、永久内存映射区

      对于896MB以上的高端内存,可使用该区域来访问,访问方法:

     1、使用alloc_page(__GFP_HIGNMEM)fenpei gaodua分配高端内存页。

    2、使用kmap函数将分配到的高端内存映射到该区域。

    十、固定映射区

      有4M的线性空间,被成为固定映射区,它和4G顶端只有4K的隔离带,固定映射区中每个地址项都服务于特定的用途,如ACPI_BASE等。通常硬件会映射到这里来。

    展开全文
  • 进程地址空间的隔离 是现代操作系统的一个显著特征。这也是区别于 “古代”操作系统 的显著特征。 进程地址空间隔离意味着进程P1无法以随意的方式访问进程P2的内存,除非这块内存被声明是共享的。 这非常容易理解...

    进程地址空间的隔离 是现代操作系统的一个显著特征。这也是区别于 “古代”操作系统 的显著特征。

    进程地址空间隔离意味着进程P1无法以随意的方式访问进程P2的内存,除非这块内存被声明是共享的。

    这非常容易理解,我举个例子。

    我们知道,在原始野人社会,是没有家庭的观念的,所有的资源都是部落内共享的,所有的野人都可以以任意的方式在任意时间和任何其他野人交互。类似Dos这样的操作系统就是这样的,内存地址空间并没有隔离。进程可以随意访问其它进程的内存。

    后来有了家庭的观念,家庭的资源被隔离,人们便不能私闯民宅了,人们无法以随意的方式进入别人的家用别人的东西,除非这是主人允许的。操作系统进入现代模式后,进程也有了类似家庭的概念。

    但家庭的概念是虚拟的,人们只是遵守约定而不去破坏别人的家庭。房子作为一个物理基础设施,保护着家庭。在操作系统中,家庭类似于虚拟地址空间,而房子就是页表。

    邻居不能闯入你的房子,但警察可以,政府公务人员以合理的理由也可以。所谓的特权管理机构只要理由充分,就可以进入普通人家的房子,touch这家人的东西。对于操作系统而言,这就是内核可以做的事,内核可以访问任意进程的地址空间。

    当然了,内核并不会无故私闯民宅,就像警察不会随意闯入别人家里一样。

    但是,你可以让内核故意这么做,做点无赖的事情。

    我们来试一下,先看一个程序:

    // test.c
    // gcc test.c -o test
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/mman.h>
    
    int main()
    {
        char* addr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        strcpy(addr, "Zhejiang wenzhou pixie shi");
    
        printf("addr: %lu   pid:%d\n", addr, getpid());
    
        printf("before:%s  \n", addr);
    
    	getchar();
    
        printf("after:%s\n", addr);
    
        return 0;
    }
    

    这个程序的输出非常简单,before和after都会输出 “Zhejiang wenzhou pixie shi”,但是我们想把这句话给改了,怎么办呢?显然,test进程如果自己不改它,那就没辙…但是可以让内核强制改啊,让内核私闯民宅就是了。

    接下来我写一个内核模块:

    // test.c
    // make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd` modules
    #include <linux/mm.h>
    #include <linux/sched.h>
    #include <linux/module.h>
    
    static int pid = 1;
    module_param(pid, int, 0644);
    
    static unsigned long addr = 0;
    module_param(addr, long, 0644);
    
    // 根据一个进程的虚拟地址找到它的页表,相当于找到这家人的房子地址,然后闯入!
    static pte_t* get_pte(struct task_struct *task, unsigned long address)
    {
    	pgd_t* pgd;
    	pud_t* pud;
    	pmd_t* pmd;
    	pte_t* pte;
    	struct mm_struct *mm = task->mm;
    
    	pgd = pgd_offset(mm, address);
    	if(pgd_none(*pgd) || pgd_bad(*pgd))
    		return NULL;
    
    	pud = pud_offset(pgd, address);
    	if(pud_none(*pud) || pud_bad(*pud))
    		return NULL;
    
    	pmd = pmd_offset(pud, address);
    	if(pmd_none(*pmd) || pmd_bad(*pmd))
    		return NULL;
    
    	pte = pte_offset_kernel(pmd, address);
    	if(pte_none(*pte))
    		return NULL;
    
    	return pte;
    }
    
    static int test_init(void)
    {
    	struct task_struct  *task;
    	pte_t* pte;
    	struct page* page;
    
    	// 找到这家人
    	task = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);
    	// 找到这家人住在哪里
    	if(!(pte = get_pte(task, addr)))
    		return -1;
    
    	page = pte_page(*pte);
    	// 强行闯入
    	addr = page_address(page);
    	// sdajgdoiewhgikwnsviwgvwgvw
    	strcpy(addr, (char *)"rain flooding water will not get fat!");
    	// 事了拂衣去,深藏功与名
    	return 0;
    }
    
    static void test_exit(void)
    {
    }
    
    module_init(test_init);
    module_exit(test_exit);
    MODULE_LICENSE("GPL");
    

    来来来,我们来试一下:

    [root@10 page_replace]# ./test
    addr: 140338535763968   pid:9912
    before:Zhejiang wenzhou pixie shi
    
    

    此时,我们加载内核模块test.ko

    [root@10 test]# insmod test.ko pid=9912 addr=140338535763968
    [root@10 test]#
    

    在test进程拍入回车:

    [root@10 page_replace]# ./test
    addr: 140338535763968   pid:9912
    before:Zhejiang wenzhou pixie shi
    
    after:rain flooding water will not get fat!
    [root@10 page_replace]#
    

    显然,“浙江温州皮鞋湿”被改成了“下雨进水不会胖”。


    仔细看上面那个内核模块的 get_pte 函数,这个函数要想写对,你必须对你想蹂躏的进程所在的机器的MMU有一定的了解,比如是32位系统还是64位系统,是3级页表还是4级页表或者5级?这…

    Linux的可玩性在于你可以自己动手,又可以让人代劳。比如,获取一个进程的虚拟地址的页表项指示的物理页面,就可以直接得到。

    有这样的API吗?有啊,别忘了一切皆文件,恰好在proc文件系统中,就有这么一个文件:

    • /proc/$pid/pagemap

    读取这个文件,得到的就是进程虚拟地址的页表项,下图截自内核Doc:
    Documentation/vm/pagemap.txt
    在这里插入图片描述


    虚拟地址空间是每进程的,而物理地址空间则是所有进程共享的。换句话说,物理地址是全局的。

    现在,根据Documentation/vm/pagemap.txt的解释,写一个程序,获取任意进程任意虚拟地址的全局物理地址:

    // getphys.c
    // gcc getphys -o getphys
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv)
    {
    	int fd;
    	int pid;
    	unsigned long pte;
    	unsigned long addr;
    	unsigned long phy_addr;
    	char procbuf[64] = {0};
    
    	pid = atoi(argv[1]);
    	addr = atol(argv[2]);
    
    	sprintf(procbuf, "/proc/%d/pagemap", pid);
    
    	fd = open(procbuf, O_RDONLY);
    	size_t offset = (addr/4096) * sizeof(unsigned long);
    	lseek(fd, offset, SEEK_SET);
    
    	read(fd, &pte, sizeof(unsigned long));
    
    	phy_addr = (pte & ((((unsigned long)1) << 55) - 1))*4096 + addr%4096;
    	printf("phy addr:%lu\n", phy_addr);
    
    	return 0;
    }
    

    随后,我们修改内核模块:

    #include <linux/module.h>
    
    static unsigned long addr = 0;
    module_param(addr, long, 0644);
    
    static int test_init(void)
    {
    	strcpy(phys_to_virt(addr), (char *)"rain flooding water will not get fat!");
    	return 0;
    }
    
    static void test_exit(void)
    {
    }
    
    module_init(test_init);
    module_exit(test_exit);
    
    MODULE_LICENSE("GPL");
    

    先运行test,然后根据test的输出作为getphys的输入,再根据getphys的输出作为内核模块test.ko的输入,就成了。还记得吗?这不就是管道连接多个程序的风格吗?

    输入一个物理地址,然后把它改了,仅此而已。通过虚拟地址获取页表的操作已经由用户态的pagemap文件的读取并解析代劳了。


    浙江温州皮鞋湿,下雨进水不会胖。

    展开全文
  • 《LKD2》P21对于进程上下文的解释是:当程序执行系统调用或触发了某个异常,陷入内核空间。此时我们称“内核代表进程执行”并处于进程上下文。  对于此段我的理解是进程的程序代码只能运行于用户空间,只有当执行...
  • 内核地址空间分布和进程地址空间 内核地址空间分布 直接映射区 (Direct Memory Region) 8M 动态内存映射区(Vmalloc Region) 8K 永久内存映射区(PKMap Region) ...
  • 进程地址空间的隔离 是现代操作系统的一个显著特征。这也是区别于 “古代”操作系统 的显著特征。进程地址空间隔离意味着进程P1无法以随意的方式访问进程P2的内存,除非这块内...
  • Linux内核-进程内核栈、用户栈

    千次阅读 2013-07-07 10:35:04
    1.进程的堆栈  内核在创建进程的时候,在创建task_struct的同事,会为进程创建相应的堆栈。...当进程内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。 2.进程用户栈和内核栈的切换
  • 进程地址空间(Linux内核源码分析)

    千次阅读 2017-07-23 11:02:55
    进程地址空间简单的说就是用户空间进程的内存,我们叫这内存为进程地址空间。本篇博客借助linux源码大体分析进程地址空间的相关知识。进程控制块既然我们要聊一聊进程地址空间,那么不可避免的就要先聊一下进程...
  • 进程内核栈、用户栈

    千次阅读 2013-06-24 21:43:27
    每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程内核空间时,cpu堆栈指针寄存器里面的...
  • linux内核--进程地址空间(一)

    千次阅读 2013-09-26 16:11:16
    引言:现代操作系统提供了一种对内存的抽象概念,叫做虚拟存储器,它为每个进程提供了一个大的,一致的,和私有的地址空间。通过一个很清晰的机制,虚拟存储器提供了3个重要的能力: 1)它将主存看成是一个存储在...
  • linux内核--进程空间(二)

    千次阅读 2013-09-26 19:11:43
    内核处理管理本身的内存外,还必须管理用户空间进程的内存。我们称这个内存为进程地址空间,也就是系统中每个用户空间进程所看到的内存。linux操作系统采用虚拟内存技术,因此,系统中的所有进程之间虚拟方式共享...
  • 进程系统资源的使用原理 大部分进程通过glibc申请使用内存,但是glibc也是一个应用程序库,它最终也是要调用操作系统的内存管理接口来使用内存。大部分情况下,glibc对用户和操作系统是透明的,所以直接观察操作...
  • 每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可见的。最高的1GB字节虚拟内核空间则为所有进程以及内核所共享
  • 内核空间与用户空间

    千次阅读 2016-03-01 15:20:03
    内核空间与用户空间 内核空间主要是指操作系统运行时所使用的用于程序调度、虚拟内存的使用或者连接硬件资源等的程序逻辑。为何需要内存空间和用户空间的划分呢?很显然和前面所说的每 个进程都独立使用属于自己的...
  •  最近在学习linux内核方面的知识,经常会看到用户空间与内核空间进程上下文与中断上下文。看着很熟悉,半天又说不出到底是怎么回事,有什么区别。看书过程经常被感觉欺骗,似懂非懂的感觉,很是不爽,今天好好...
  • 可重入内核,是指多个进程可以同时处于内核态下,也就是说可以多个进程可以并发的执行内核代码。对于但处理器来说某一时刻只能有一个进程被CPU处理,其他处于内核态的进程处于阻塞或者挂起等待状态。 对于linux来说...
  • 用户空间栈 & 内核空间

    千次阅读 2014-07-16 16:35:23
    以下简称用户栈、内核栈 1、用户栈和内核栈的区别 ... 内核在创建进程的时候,在创建task_struct的同时,会为进程创建相应的堆栈。每个进程会有两个栈,一个用户栈, ...当进程内核空间时,c
  • 日期 内核版本 架构 作者 GitHub CSDN 2016-06-03 Linux-4.5 X86 & arm gatieme ...进程内核态运行时需要自己的堆栈信息, 因此linux内核为每个进程都提供了一个内核栈kernel stack, struct
  • linux之用户空间和内核空间

    千次阅读 2018-10-25 10:02:20
    linux驱动程序一般工作在内核空间,但也可以工作在用户空间。下面我们将详细解析,什么是内核空间,什么是用户空间,以及如何判断他们。 Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟...
  • linux驱动程序一般工作在内核空间,但也可以工作在用户空间。下面我们将详细解析,什么是内核空间,什么是用户空间,以及如何判断他们。  Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的...
  • Linux用户空间和内核空间

    万次阅读 2019-01-31 21:07:21
    为保证内核的安全,用户进程是不能直接操作内核的,所以Linux将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。 二、 用户空间和内核空间的内存分配 linux操作系统而言,将最高的1G字节(从虚拟地址0xC...
  • 每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程内核空间时,cpu堆栈指针寄存器里面的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 269,263
精华内容 107,705
关键字:

不同进程的内核空间