当前位置: 技术问答>linux和unix
高分请教MMU的问题!!!!!!!!!!!!!!!!!
来源: 互联网 发布时间:2016-05-08
本文导语: 课本上讲的MMU原理我都明白,我想问的是实际应用的问题. 我们知道,系统刚开始启动时BOOT会把操作系统内核加载到RAM固定的地址(一般是高地址), 然后内核初始化MMU,建立页表(假设是分页方式),然后就启动了MMU.然后所有...
课本上讲的MMU原理我都明白,我想问的是实际应用的问题.
我们知道,系统刚开始启动时BOOT会把操作系统内核加载到RAM固定的地址(一般是高地址),
然后内核初始化MMU,建立页表(假设是分页方式),然后就启动了MMU.然后所有的寻址必须经过MMU转换成物理地址.
我想知道的是:
1.内核是不是不入页表?如果不入,内核内部的代码和数据寻址那就不用MMU做地址转换?还是虚拟地址就是物理地址?
页表中是怎样表示内核区域呢?还是内核占用的那块RAM区域不在页表中体现?
2.页表是存放在RAM中的,页表的寻址肯定不能再使用MMU寻址?寻找页表时是不是使用页表基址寄存器之类的寄存器?
3.页表是CPU建立的还是操作系统建立的?如果是CPU建立的,是哪个相关的寄存器?如果是操作系统建立,是不是每个表项都需要初始化?
4.页表的基地址是手工指定的还是CPU决定的?如果是手工指定的,一般位于RAM的哪个位置?内核一般位于高地址,是不是页表的地址紧接内核的地址?
5.malloc动态分配一块内存,在页表中是怎么处理的?
请高手们帮忙解答一下,如果你懒得回答,请推荐一本书我自己看.但是让我自己看linux的内核就太过于复杂了.
我们知道,系统刚开始启动时BOOT会把操作系统内核加载到RAM固定的地址(一般是高地址),
然后内核初始化MMU,建立页表(假设是分页方式),然后就启动了MMU.然后所有的寻址必须经过MMU转换成物理地址.
我想知道的是:
1.内核是不是不入页表?如果不入,内核内部的代码和数据寻址那就不用MMU做地址转换?还是虚拟地址就是物理地址?
页表中是怎样表示内核区域呢?还是内核占用的那块RAM区域不在页表中体现?
2.页表是存放在RAM中的,页表的寻址肯定不能再使用MMU寻址?寻找页表时是不是使用页表基址寄存器之类的寄存器?
3.页表是CPU建立的还是操作系统建立的?如果是CPU建立的,是哪个相关的寄存器?如果是操作系统建立,是不是每个表项都需要初始化?
4.页表的基地址是手工指定的还是CPU决定的?如果是手工指定的,一般位于RAM的哪个位置?内核一般位于高地址,是不是页表的地址紧接内核的地址?
5.malloc动态分配一块内存,在页表中是怎么处理的?
请高手们帮忙解答一下,如果你懒得回答,请推荐一本书我自己看.但是让我自己看linux的内核就太过于复杂了.
|
支持1楼。由于本人仅仅熟悉一点点基于x86的Linux,且是2.4内核的,因此就以此为例说一说。
1)系统刚开始启动时BOOT会把操作系统内核加载到RAM固定的地址(一般是高地址),
现在比较常见的是各种bootloader,如grub,lilo之类的
以基于x86的Linux2.4内核为例,Linux内核被解压缩在物理地址1MB的位置。(这个地址不算是高地址吧)
2)然后内核初始化MMU,建立页表(假设是分页方式),然后就启动了MMU.然后所有的寻址必须经过MMU转换成物理地址.
OK
以基于x86的Linux2.4内核为例,小于896MB的物理内存都被页表机制映射到线性地址3GB以上的地址空间中
(这个地址算是高地址吧,呵呵)
1.内核是不是不入页表?如果不入,内核内部的代码和数据寻址那就不用MMU做地址转换?还是虚拟地址就是物理地址?
页表中是怎样表示内核区域呢?还是内核占用的那块RAM区域不在页表中体现?
以基于x86的Linux2.4内核为例,内核也是通过MMU寻址的。
但是在内核中线性地址和物理地址之间还存在一种比较规范的映射关系:比如 线性地址-3GB=物理地址
所以一方面可以通过MMU寻址,另一方面可以通过简单的计算获得物理地址
关于如何映射到的这个问题,你只要想象一下,页表就是一个数组,这个数组存放了一些物理地址
数组的序号,就是线性页号,物理地址就是物理页号
这个数组是内核填写的,内核想怎么填就怎么填,想填成恰好映射关系满足 线性地址-3G=物理地址 就可以填
你可以自己试一试
2.页表是存放在RAM中的,页表的寻址肯定不能再使用MMU寻址?寻找页表时是不是使用页表基址寄存器之类的寄存器?
对的。x86中,使用cr3寄存器来记录页表的起始地址,这个起始地址是物理地址。
3.页表是CPU建立的还是操作系统建立的?如果是CPU建立的,是哪个相关的寄存器?如果是操作系统建立,是不是每个表项都需要初始化?
在基于x86的Linux中,页表是操作系统建立的。建立的方法就是:做好一个数组(页表,填写映射到的物理页起始地址,和其他一些信息), 然后通过cr3告诉系统页表在物理地址的哪里
关于是否每个表项都需要初始化:在基于x86的Linux中不必每个表项都初始化,用户程序可以使用按需调页的方法,在用到才填写。内核的页表大家可以共享。
4.页表的基地址是手工指定的还是CPU决定的?如果是手工指定的,一般位于RAM的哪个位置?内核一般位于高地址,是不是页表的地址紧接内核的地址?
在基于x86的Linux2.4中,大多数页表所占用的内存是动态分配出来的。创建一个进程就分配,按需调页的时候需要就分配;不需要的时候就释放。不固定。
5.malloc动态分配一块内存,在页表中是怎么处理的?
在基于x86的Linux2.4中,内核中没有malloc,而使用内核中专门的内存分配函数,如kmalloc。
malloc仅仅是用户程序使用的,是C库中的接口。它管理用户空间中的堆。你可以理解为分配的是线性地址,但不是物理地址。
从页表的角度上看,当访问到malloc分配的线性地址时,若MMU发现相应线性页已经被映射到一个物理页时,就顺利访问;
若没有映射,则内核会分配一个页面,填写页表,再次访问就可以顺利访问了
1)系统刚开始启动时BOOT会把操作系统内核加载到RAM固定的地址(一般是高地址),
现在比较常见的是各种bootloader,如grub,lilo之类的
以基于x86的Linux2.4内核为例,Linux内核被解压缩在物理地址1MB的位置。(这个地址不算是高地址吧)
2)然后内核初始化MMU,建立页表(假设是分页方式),然后就启动了MMU.然后所有的寻址必须经过MMU转换成物理地址.
OK
以基于x86的Linux2.4内核为例,小于896MB的物理内存都被页表机制映射到线性地址3GB以上的地址空间中
(这个地址算是高地址吧,呵呵)
1.内核是不是不入页表?如果不入,内核内部的代码和数据寻址那就不用MMU做地址转换?还是虚拟地址就是物理地址?
页表中是怎样表示内核区域呢?还是内核占用的那块RAM区域不在页表中体现?
以基于x86的Linux2.4内核为例,内核也是通过MMU寻址的。
但是在内核中线性地址和物理地址之间还存在一种比较规范的映射关系:比如 线性地址-3GB=物理地址
所以一方面可以通过MMU寻址,另一方面可以通过简单的计算获得物理地址
关于如何映射到的这个问题,你只要想象一下,页表就是一个数组,这个数组存放了一些物理地址
数组的序号,就是线性页号,物理地址就是物理页号
这个数组是内核填写的,内核想怎么填就怎么填,想填成恰好映射关系满足 线性地址-3G=物理地址 就可以填
你可以自己试一试
2.页表是存放在RAM中的,页表的寻址肯定不能再使用MMU寻址?寻找页表时是不是使用页表基址寄存器之类的寄存器?
对的。x86中,使用cr3寄存器来记录页表的起始地址,这个起始地址是物理地址。
3.页表是CPU建立的还是操作系统建立的?如果是CPU建立的,是哪个相关的寄存器?如果是操作系统建立,是不是每个表项都需要初始化?
在基于x86的Linux中,页表是操作系统建立的。建立的方法就是:做好一个数组(页表,填写映射到的物理页起始地址,和其他一些信息), 然后通过cr3告诉系统页表在物理地址的哪里
关于是否每个表项都需要初始化:在基于x86的Linux中不必每个表项都初始化,用户程序可以使用按需调页的方法,在用到才填写。内核的页表大家可以共享。
4.页表的基地址是手工指定的还是CPU决定的?如果是手工指定的,一般位于RAM的哪个位置?内核一般位于高地址,是不是页表的地址紧接内核的地址?
在基于x86的Linux2.4中,大多数页表所占用的内存是动态分配出来的。创建一个进程就分配,按需调页的时候需要就分配;不需要的时候就释放。不固定。
5.malloc动态分配一块内存,在页表中是怎么处理的?
在基于x86的Linux2.4中,内核中没有malloc,而使用内核中专门的内存分配函数,如kmalloc。
malloc仅仅是用户程序使用的,是C库中的接口。它管理用户空间中的堆。你可以理解为分配的是线性地址,但不是物理地址。
从页表的角度上看,当访问到malloc分配的线性地址时,若MMU发现相应线性页已经被映射到一个物理页时,就顺利访问;
若没有映射,则内核会分配一个页面,填写页表,再次访问就可以顺利访问了
|
1.有的处理器可以disable MMU,但有的处理器不能。如果不能的那种,那么一切操作都需要通过MMU,那么内核当然也要入页表。实际上对于Linux来说,内核的页表项跟用户空间的页表项的处理方法上有些不同。(有些复杂,暂时没有看到有书讲这个讲得很透的,推荐一个站点吧:www.linuxforum.net)
2. 这好比一个“先有蛋还是先有鸡”的问题,实际上我所见过的X86平台和MIPS平台上,用于标明页目录所在位置是通过寄存器来指定的,寄存器就可以绕过MMU了啊。
3. 准确的说,应该是操作系统建立起来的,当然每个表项都需要手工初始化。CPU只是提供了一个页表机制而已,其中的内容需要软件来管理。
4.请见回答2.在内存中的位置和所在平台有关系。因为平台不一样,实现方式都不一样,在存放位置上就大相径庭了。
5. malloc的问题跟页表处理,那是隔得太远了。从底层操作系统的角度看来,malloc不过是应用程序为了提高内存使用效率而实现的一个方法而已,连操作系统的功能都说不上,只能算应用层的东东。比如一般Linux使用Glibc,那么malloc就是Glibc实现的一个算法。(Glibc就是为我们实现C库函数调用的东东)
说一下malloc吧:Glibc从维护了一个pool, 每次malloc时,Glibc都会先检查pool中是否有足够的空间,如果有,那么直接从pool总分配,如果空间不够了,就会先去操作系统的heap区域中申请一大块内存来放在pool中,然后划一块給当前的malloc请求;反之,free的时候回去检查pool中空闲区域是不是太多,如果是,就释放掉某一大块的内存。(具体内核提供这个操作的函数名字忘记了。你可以看看毛德操的,不过注意他是机遇X86平台的,某些假设对其他平台是不适用的)
2. 这好比一个“先有蛋还是先有鸡”的问题,实际上我所见过的X86平台和MIPS平台上,用于标明页目录所在位置是通过寄存器来指定的,寄存器就可以绕过MMU了啊。
3. 准确的说,应该是操作系统建立起来的,当然每个表项都需要手工初始化。CPU只是提供了一个页表机制而已,其中的内容需要软件来管理。
4.请见回答2.在内存中的位置和所在平台有关系。因为平台不一样,实现方式都不一样,在存放位置上就大相径庭了。
5. malloc的问题跟页表处理,那是隔得太远了。从底层操作系统的角度看来,malloc不过是应用程序为了提高内存使用效率而实现的一个方法而已,连操作系统的功能都说不上,只能算应用层的东东。比如一般Linux使用Glibc,那么malloc就是Glibc实现的一个算法。(Glibc就是为我们实现C库函数调用的东东)
说一下malloc吧:Glibc从维护了一个pool, 每次malloc时,Glibc都会先检查pool中是否有足够的空间,如果有,那么直接从pool总分配,如果空间不够了,就会先去操作系统的heap区域中申请一大块内存来放在pool中,然后划一块給当前的malloc请求;反之,free的时候回去检查pool中空闲区域是不是太多,如果是,就释放掉某一大块的内存。(具体内核提供这个操作的函数名字忘记了。你可以看看毛德操的,不过注意他是机遇X86平台的,某些假设对其他平台是不适用的)