在系统地址空间中,如何寻址?

fxyj2008 2007-01-25 07:08:45
1. 当用户进程通过系统调用进入系统空间后,如何寻址
2. 用户进程在运行的时候,我们知道每个地址需要MMU映射成物理地址,因此需要将存放该进程页面目录的地址放到 cr3 寄存器中.
当一个中断发生时,发生了调度,调度程序选择了一个新的用户进程投入运行,在用户进程能够运行之前,需要做一些初始化工作,比如将该进程的页面目录地址装载到cr3寄存器中,类似应有如下代码:
movl 新的页面地址,cr3;
在运行上述代码后,此时cr3中装的是调度后待运行的进程的页面目录地址了,接下来由于在系统地址空间中的代码还没有运行完,因此需要继续运行,但此时如果还是使用MMU映射的话会出现问题,造成地址不连续了,因此我想问一下,在系统空间中代码运行的时候,寻址是否通过MMU映射,如果不是,那么是通过什么方式寻址的,难道将MMU关闭了?
...全文
991 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
lauxp 2007-02-14
  • 打赏
  • 举报
回复
其实呢,看一下:
/usr/src/linux-2.4.21-4.EL/arch/i386/vmlinux.lds.in

#define __ASSEMBLY__
#include <asm/page.h>

/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
ENTRY(_start)
SECTIONS
{
#if CONFIG_X86_4G_VM_LAYOUT
. = 0x02000000 + 0x100000;
#else
. = 0xc0000000 + 0x100000; << ================ .text开始于此

编译的时候就把vmlinux的地址映射到PAGE_OFFSET+0x10000。

还有: /usr/src/linux-2.4.21-4.EL/arch/i386/kernel

92 /*
93 * Enable paging
94 */
95 3:
96 movl $swapper_pg_dir-__PAGE_OFFSET,%eax
97 movl %eax,%cr3 /* set the page table pointer.. */
98 movl %cr0,%eax
99 orl $0x80000000,%eax
100 movl %eax,%cr0 /* ..and set paging (PG) bit */
101 jmp 1f /* flush the prefetch-queue */ <<======== 排空流水线的数据,确保保护模式的寻址
102 1:
103 movl $1f,%eax
104 jmp *%eax /* make sure eip is relocated */
blue_yxt 2007-02-11
  • 打赏
  • 举报
回复
fxyj2008(超级黑客):
不如你看一下<LINUX内核情景分析>这本书的下册(系统启动在章节)

在内核启动时,已经对内核地址空间做好了映射,页表相关的数据结构被0号进程的INIT_MM所指向

好好分析一下这段代码,我相信你会相信系统地址空间也是由页表,通过MMU来寻址的(和用户空间的寻址并没有什么两样:)
fxyj2008 2007-02-09
  • 打赏
  • 举报
回复
to:aria(*nix learner)
讨论确实不错,可以看到大家的思路和看法
lauxp 2007-02-07
  • 打赏
  • 举报
回复
设置了%cr0之后,就开启分页功能,任何寻址工作都会通过%cr3,也就是进入保护模式;
内核态不同于用户态的地方在于:
内核态的线性地址=物理地址+PAGE_OFFSET







aria 2007-02-06
  • 打赏
  • 举报
回复
hehe,只要打开MMU页表就是省不了的,这和操作系统没有关系。

这一点估计是和 fxyj2008(超级黑客) 兄台最大的分歧所在了。不过也无必要再继续讨论下去了,如果没有大虾出来指点的话恐怕也没有结果。

不管怎么说,有讨论总是好的。
fxyj2008 2007-02-06
  • 打赏
  • 举报
回复
本想结帖的,但看大家讨论的这么热烈,不忍心啊
我觉得需要从下面几个方面思考:
1.在内核空间运行的时候是否一定需要页表?我们知道,在用户空间运行的时候,用的都是虚拟地址,因此需要页表来做映射,当初引入虚拟地址的概念也就是为了多个进程运行而不互相干扰,并且有自己独立的空间.而在系统空间中运行的时候,没有页表好象会工作的更好,直接用物理寻址,不知道大家是否会同意我的观点?
blue_yxt 2007-02-06
  • 打赏
  • 举报
回复
我认为楼上兄弟的阐述是正解

我投他一票!
blue_yxt 2007-02-05
  • 打赏
  • 举报
回复
我觉得问题的关键就是把《情景分析》中的这句话解释清楚,并给予代码证明!!!

“所有进程的页面目录中与系统空间相对应的目录项都指向相同的页面表,所以,不管换上哪一个进程的页面目录都一样,受影响的只是用户空间,系统空间的映射则永远不变。”

1.进程进入核态,肯定是要通过页表来访问;
2.而这个页表一定不是在进程的mm_struct->pgd指向的位置;
3.那么.....既然要用到页表,那么谁将这3G以上的系统空间页表赋给CR3呢????
aria 2007-02-05
  • 打赏
  • 举报
回复
我的一点理解:

不管是哪个进程,其pgd(task_struct-->mm_struct->pgd)的768-1023表项的内容都是一样的,也即系统空间部分的页目录内容是一样的。

这部分的内容可以参考:do_fork()/copy_mm()/mm_init() [kernel/fork.c], 以及get_pgd_fast()/get_pgd_slow(),在get_pgd_slow()中可以看到将swapper_pg_dir+USER_PTRS_PER_PGD开始的,长度为(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)的内容复制到到进程的pgd中。

swapper_pg_dir是init task的pgd,在初始化时会设置(参见pagetable_init() [arch/i386/mm/init.c]),而实际上会设置的也是3G以上的空间。这一部分的设置会在fork其他进程的时候直接复制过去。

因此每个进程的pgd的768-1023项是3G以上空间(也即内核空间)的页表映射,而且都是一样的(因为都是从swapper_pg_dir复制过来的)。

总的来说,在内核空间访问地址一样都要通过MMU,在Linux/x86情况下,每个进程的pgd(也即页面目录)的地址一般都不一样,但是其内容中关于内核空间的页面映射部分都是一样的。因此在切换进程的时候并不需要特别的处理。
闻思修 2007-02-03
  • 打赏
  • 举报
回复
如果不用页表,直接用物理地址,那高端地址怎么映射啊。。。
闻思修 2007-02-03
  • 打赏
  • 举报
回复
肯定要有页表啊。。。。
虽然NORMAL内存的虚拟地址和物理地址是一一对应的,但是有一个偏移量。。。。
江南一书生 2007-02-01
  • 打赏
  • 举报
回复
无论是用户空间还是内核空间,程序所使用的都是虚拟地址而不是物理地址,并且都要经过MMU的转换。所不同的是,内核空间的地址会直接映射,不会用页表查询映射的。
fxyj2008 2007-01-31
  • 打赏
  • 举报
回复
我是这样理解的:

系统空间虽然占据了虚拟空间的最高1G内存,但在物理内存中是从最低的地址(0)开始,所以,对于系统空间而言,对于一个虚地址x,其物理地址就是x-PAGE_OFFSET

但是CPU只有通过两种方式寻址地址,一个是通过页表映射,另一个就是直接物理地址寻址,很显然,在系统空间中是直接物理地址寻址,系统并没有页表

但为什么要提出PAGE_OFFSET这个概念呢?还有为什么要有x-PAGE_OFFSET这个计算呢?

那是在切换进程的时候,系统需要装入新进程的页面目录到cr2寄存器中,但cr2 里必须放物理地址,因此需要知道这个待装入新进程的页面目录的物理地址,这时就用到了上面的x-PAGE_OFFSET计算,在系统空间中运行时,一直用的都是物理寻址

一般在创建新进程的时候,会生成一个 task_struct 这个数据结构来描述这个进程,当这个进程被调度并投入运行时,需要用到页表,因此为这个进程分配了一个物理内存,用于描述这个进程要到的页面,以可以映射,这个用于描述的数据结构就是页面目录,

struct task_struct
{
....
该进程的页面目录地址;
....

}
那么这个页面目录地址到底放的是什么呢? 应该是虚拟地址,如果为这个页面目录分配的物理地址是x,那么这边的值存放的就是x+PAGE_OFFSET,也就是所谓的这个系统空间的虚拟地址,也就是系统空间占据的进程虚拟空间的最高1G内存中的地址

PAGE_OFFSET 只是在程序中转化系统的虚拟地址到物理地址的(记住,只是在系统的虚拟地址中是这样做的,因为在描述这个进程的task_struct结构中存放的其他地址都是虚拟地址,如页面目录地址,需要进行x-PAGE_OFFSET转换),是代码运行时由软件实现的,具体的CPU并不这样做,CPU只有页面映射和直接物理寻址两种,很显然,系统是直接运行在物理寻址模式下的
fxyj2008 2007-01-30
  • 打赏
  • 举报
回复
多谢大家的参与讨论!

好象没有全局的变量mm_***吧

个人认为 如果 系统空间也使用虚拟地址是没有必要的,引入虚拟地址的一个目的就是保证各个用户进程能够独立运行,并且彼此不干扰,所有调度由系统来做

下面是摘自David A Rusling 写的 Linux Kernel 上的一段话,翻译后的中文如下,与大家分享:

操作系统自身也运行在虚拟内存中的意义不大,如果操作系统被迫维护自身的页表那
将是一个令人恶心的方案,多数通用处理器同时支持物理寻址和虚拟寻址模式物理寻址
模式,无需页表的参与且处理器不会进行任何地址转换,Linux 核心直接运行在物理地址空
间上
aria 2007-01-30
  • 打赏
  • 举报
回复
hnhbdss(阿蒙)说的mm_*** 可能指的是init_mm,也即init task的mm_struct,具体的页表映射关系应在init_mm.pgd(实际上会指向swapper_pg_dir)。

在Linux Kernel实现中,核态中用到的内存地址都是在PAGE_OFFSET(3G)以上,这也是为什么System.map中地址都是cxxxxxxx,而PAGE_OFFSET开始的内核地址的页表初始化在arch/i386/mm/init.c中的pagetable_init()中可以看到。如果手头有2.6内核,可参考init.c中的kernel_physical_mapping_init()。

核态的地址并非不用页表,而只是初始化时设置好,另一个很重点的内容是核态的地址实际上物理地址和虚拟地址刚好是差PAGE_OFFSET,这实际上是初始化时有意设置为此以便简化实现的。
fxyj2008 2007-01-29
  • 打赏
  • 举报
回复
多谢老兄的回复

后来我查了相关的资料,在系统空间中(既核态),是不需要页表的,也就是说在系统空间中给出的地址就是物理地址,如果系统运行的空间也是虚拟地址空间的,那设计不可想象了,也没那个必要

MMU在内核启动后是不会关闭的。另外按我的理解和系统空间相对应的目录都一样(包括init task),而init task的内核空间对应的目录项会在系统页表初始化时指定的。

在用户进程中,确实需要MMU,因为他们用的是虚拟的地址,当一个用户进程通过系统调用进入系统空间后,cr3中的内容还是指象该用户进程的页面目录,但是此时,在系统空间的代码寻址并不需要做地址映射了,给出的就是物理地址,所以即使将其他进程的页面目录装入cr3 寄存器中,对在系统空间中寻址也没有影响,因为他根本就没有用到cr3寄存器,不需要做映射

hnhbdss 2007-01-29
  • 打赏
  • 举报
回复
对于系统空间,它的物理地址和虚拟地址之间相差的是一个固定的数目,就是3G,
3G以上是系统空间,这对于所有的应用程序的地址空间都是一样的,而且是单独的放置,就是在全局的变量mm_***中,因此当进行切换页目录时,内核的映射还是一样的,所以程序会连续执行!不会因为改变cr3而无法执行.而用户空间的地址映射就是随意了!
aria 2007-01-29
  • 打赏
  • 举报
回复
呵呵,不是很确定你查的是什么资料,不过我仍然是坚持在核态肯定会用到页表,而且也是虚拟地址,因为CPU肯定不会区分你是用户态还是核态的,MMU机制与用户态/核态并没有关系,只要启用了MMU访问的就不会是物理地址。
aria 2007-01-26
  • 打赏
  • 举报
回复
1. 不太清楚你这里所说的寻址具体是指什么,是内存地址?外设?还是其他?一般来说实际上核态和用户态的寻址最终均需要通过MMU处理(只要CPU有MMU)。
2. x86在进程切换*前*确实会有类似 movl 新的页表地址,cr3 的处理,新的页表地址即是新的进程的页表基地址。这一点不会有问题,因为此时CPU仍然在系统空间运行,而所有进程的页面目录中与系统空间相对应的目录项都指向相同的页面表,所以,不管换上哪一个进程的页面目录都一样,受影响的只是用户空间,系统空间的映射则永远不变。
<- 前面这一段是从《情景分析》中摘录的

MMU在内核启动后是不会关闭的。另外按我的理解和系统空间相对应的目录都一样(包括init task),而init task的内核空间对应的目录项会在系统页表初始化时指定的。

4,465

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 内核源代码研究区
社区管理员
  • 内核源代码研究区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧