非线性编辑是什么意思地址中x的意思

span在线性代数中是什么意思_百度知道ubuntu(19)
《Linux内核完全剖析—基于0.12内核》第5章Linux内核体系结构,本章首先概要介绍了Linux内核的编制模式和体系结构,然后详细描述了Linux 内核源代码目录的组织形式以及子目录中各个代码文件的主要功能以及基本调用的层次关系。本节为大家介绍的是虚拟地址、线性地址和物理地址之间的关系。
5.3.6& 虚拟地址、线性地址和物理地址之间的关系
前面我们根据内存分段和分页机制详细说明了CPU的内存管理方式。现在我们以Linux 0.12系统为例,详细说明内核代码和数据以及各任务的代码和数据在虚拟地址空间、线性地址空间和物理地址空间中的对应关系。由于任务0和任务1的生成或创建过程比较特殊,我们将对它们分别进行描述。
1.内核代码和数据的地址
对于Linux 0.12内核代码和数据来说,在head.s程序的初始化操作中已经把内核代码段和数据段都设置成为长度为16MB的段。在线性地址空间中这两个段的范围重叠,都是从线性地址0开始到地址0xFFFFFF共16MB地址范围。在该范围中含有内核所有的代码、内核段表(GDT、IDT、TSS)、页目录表和内核的二级页表、内核局部数据以及内核临时堆栈(将被用作第1个任务,即任务0的用户堆栈)。其页目录表和二级页表已设置成把0~16MB的线性地址空间一一对应到物理地址上,占用了4个目录项,即4个二级页表。因此对于内核代码或数据的地址来说,我们可以直接把它们看做物理内存中的地址。此时内核的虚拟地址空间、线性地址空间和物理地址空间三者之间的关系可用图5-14来表
图5-14& 内核代码和数据段在三种地址空间中的关系
因此,默认情况下Linux 0.12内核最多可管理16MB的物理内存,共有4096个物理页面(页帧),每个页面4KB。通过上述分析可以看出:①内核代码段和数据段区域在线性地址空间和物理地址空间中是一样的。这样设置可以大大简化内核的初始化操作。②GDT和IDT在内核数据段中,因此它们的线性地址也同样等于它们的物理地址。在实模式下的setup.s程序初始化操作中,我们曾经设置过临时的GDT和IDT,这是进入保护模式之前必须设置的。由于这两个表当时处于物理内存大约0x90200处,而进入保护模式后内核系统模块处于物理内存0开始位置,并且0x90200处的空间将被挪作他用(用于高速缓冲),因此在进入保护模式后,在运行的第1个程序head.s中我们需要重新设置这两个表。即设置GDTR和IDTR指向新的GDT和IDT,描述符也需要重新加载。但由于开启分页机制时这两个表的位置没有变动,因此无须重新建立或移动表位置。③除任务0以外,所有其他任务使用的物理内存页面与线性地址中的页面至少有部分不同,因此内核需要动态地在主内存区中为它们作映射操作,动态地建立页目录项和页表项。虽然任务1的代码和数据也在内核中,但由于其需要另行分配获得内存,因此也需要自己的映射表项。
虽然Linux 0.12默认可管理16MB物理内存,但是系统中并不是一定要有这些物理内存。机器中只要有4MB(甚至2MB)物理内存就完全可以运行Linux 0.12系统了。若机器只有4MB物理内存,那么此时内核4MB~16MB地址范围就会映射到不存在的物理内存地址上。但这并不妨碍系统的运行。因为在初始化时内核内存管理程序会知道机器中所含物理内存量的确切大小,因而不会让CPU分页机制把线性地址页面映射到不存在的4MB~16MB中去。内核中这样的默认设置主要是为了便于系统物理内存的扩展,实际并不会用到不存在的物理内存区域。如果系统有多于16MB的物理内存,由于在init/main.c程序中初始化时限制了对16MB以上内存的使用,并且这里内核也仅映射了0~16MB的内存范围,因此在16MB之上的物理内存将不会用到。
通过在这里为内核增加一些页表,并且对init/main.c程序稍作修改,我们可以对此限制进行扩展。例如在系统中有32MB物理内存的情况下,我们就需要为内核代码和数据段建立8个二级页表项来把32MB的线性地址范围映射到物理内存上。
2.任务0的地址对应关系
任务0是系统中人工启动的第1个任务。它的代码段和数据段长度被设置为640KB。该任务的代码和数据直接包含在内核代码和数据中,是从线性地址0开始的640KB内容,因此它可以直接使用内核代码已经设置好的页目录和页表进行分页地址变换。同样,它的代码和数据段在线性地址空间中也是重叠的。对应的任务状态段TSS0也是手工预设置好的,并且位于任务0数据结构信息中,参见include/linux/sched.h第156行开始的数据。TSS0段位于内核sched.c程序的代码中,长度为104字节,具体位置可参见图5-24中&任务0结构信息&一项所示。3个地址空间中的映射对应关系如图5-15所示。
(点击查看大图)图5-15& 任务0在3个地址空间中的相互关系
由于任务0直接被包含在内核代码中,因此不需要为其再另外分配内存页。它运行时所需要的内核态堆栈和用户态堆栈空间也都在内核代码区中,并且由于在内核初始化时(head.s)这些内核页面在页表项中的属性都已经被设置成了0b111,即对应页面用户可读写并且存在,因此用户堆栈user_stack[]空间虽然在内核空间中,但任务0仍然能对其进行读写操作。
3.任务1的地址对应关系
与任务0类似,任务1也是一个特殊的任务。它的代码也在内核代码区域中。与任务0不同的是在线性地址空间中,系统在使用fork()创建任务1(init进程)时为存放任务1的二级页表而在主内存区申请了一页内存来存放,并复制了父进程(任务0)的页目录和二级页表项。因此任务1有自己的页目录和页表表项,它把任务1占用的线性空间范围64~128MB(实际上是64MB~64MB+640KB)也同样映射到了物理地址0~640KB处。此时任务1的长度也是640KB,并且其代码段和数据段相重叠,只占用一个页目录项和一个二级页表。另外,系统还会为任务1在主内存区域中申请一页内存用来存放它的任务数据结构和用作任务1的内核堆栈空间。任务数据结构(也称进程控制块PCB)信息中包括任务1的TSS段结构信息,如图5-16所示。
(点击查看大图)图5-16& 任务1在3种地址空间中的关系
任务1的用户态堆栈空间将直接共享使用处于内核代码和数据区域(线性地址0~640KB)中任务0的用户态堆栈空间user_stack[](参见kernel/sched.c,第82~87行),因此这个堆栈需要在任务1实际使用之前保持&干净&,以确保被复制用于任务1的堆栈不含有无用数据。在刚开始创建任务1时,任务0的用户态堆栈user_stack[]与任务1共享使用,但当任务1开始运行时,由于任务1映射到user_stack[]处的页表项被设置成只读,使得任务1在执行堆栈操作时将会引起写页面异常,从而由内核另行分配主内存区页面作为堆栈空间使用。
4.其他任务的地址对应关系
对于被创建的从任务2开始的其他任务,它们的父进程都是init(任务1)进程。我们已经知道,在Linux 0.12系统中共可以有64个进程同时存在。下面我们以任务2为例来说明其他任何任务对地址空间的使用情况。
从任务2开始,如果任务号以nr来表示,那么任务nr在线性地址空间中的起始位置将被设定在nr×64MB处。例如任务2的开始位置= nr×64MB = 2×64MB = 128MB。任务代码段和数据段的最大长度被设置为64MB,因此任务2占有的线性地址空间范围是128MB~192MB,共占用64MB/4MB = 16个页目录项。虚拟空间中任务代码段和数据段都被映射到线性地址空间相同的范围,因此它们也完全重叠。图显示出了任务2的代码段和数据段在3种地址空间中的对应关系。
在任务2被创建出来之后,将在其中运行execve()函数来执行shell程序。当内核通过复制任务1刚创建任务2时,除了占用线性地址空间范围不同外(128MB~128MB+640KB),此时任务2的代码和数据在3种地址空间中的关系与任务1的类似。当任务2的代码(init())调用execve()系统调用开始加载并执行shell程序时,该系统调用会释放掉从任务1复制的页目录和页表表项及相应内存页面,然后为新的执行程序shell重新设置相关页目录和页表表项。图给出的是任务2中开始执行shell程序时的情况,即任务2原先复制任务1的代码和数据被shell程序的代码段和数据段替换后的情况。图中显示出已经映射了一页物理内存页面的情况。这里请注意,在执行execve()函数时,系统虽然在线性地址空间为任务2分配了64MB的空间范围,但是内核并不会立刻为其分配和映射物理内存页面。只有当任务2开始执行时由于发生缺页而引起异常时才会由内存管理程序为其在主内存区中分配并映射一页物理内存到其线性地址空间中。这种分配和映射物理内存页面的方法称为需求加载(load
on demand),请参见第13章中的相关描述。
(点击查看大图)图5-17& 其他任务地址空间中的对应关系
从Linux内核0.99版以后,对内存空间的使用方式发生了变化。每个进程可以单独享用整个4GB的地址空间范围。如果我们能理解本节说描述的内存管理概念,那么对于现在所使用的Linux 2.x内核中所使用的内存管理原理也能立刻明白。由于篇幅所限,这里对此不再说明。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:10362次
排名:千里之外
原创:19篇
转载:17篇
(2)(4)(3)(2)(1)(12)(14)线性代数中,‖x‖是什么意思
小乙wan1199
代表矩阵的范数,可以参看百度百科范数词条
为您推荐:
其他类似问题
是表示范数吗?
扫描下载二维码转: linux的物理内存与线性地址空间布局 - Fangzhen - 博客园
随笔 - 367, 文章 - 174, 评论 - 108, 引用 - 0
在支持MMU的32位处理器平台上,Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0xxFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同。Linux运行在虚拟存储空间,并负责把系统中实际存在的远小于4GB的物理内存根据不同需求映射到整个4GB的虚拟存储空间中。博客访问: 96589
博文数量: 77
博客积分: 80
博客等级: 民兵
技术积分: 420
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
原文地址: 作者:
这两天一直看到uc论坛上关于系统中几种地址概念的讨论,加上这一块自己一直没有理解,索性就在网上多找了些资料,下面是自己的一些浅薄的理解。
设计平台为x86,如果是其它平台,不保证能一一对号入座,但应该也是可以举一反三的吧。
&& 在硬件工程师和普通用户看来,内存就是插在或固化在主板上的内存条,他们有一定的容量,比如512MB。但应用程序员并不过度关心内存容量,而是关心可以使用的内存空间。比如,他们可以开发一个占用1GB内存的程序,让其在操作系统下运行,哪怕实际内存不足1G。操作系统开发者则是介于二者之间,即需要知道物理内存的地址,也需要提供一套机制,为应用程序提供另一个内存空间,这个空间的大小可以与实际内存大小没有直接关系。
&& 这里将主板上的物理内存条所提供的内存空间定义为物理内存空间,把内存看成一个从0字节一直到最大空量逐字节的编号的大数组,然后把这个数组叫做物理地址。
将应用程序员看到的内存定义为虚拟地址,它是相对于物理内存来讲的,可以直接理解成“不直实的”,“假的”内存,例如,一个0x内存地址,它并不对就物理地址上那个大数组中0x - 1那个地址元素;之所以是这样,是因为现代操作都提供了一种内存管理的抽像,即虚拟内存(virtual memory)。使用虚拟内存中的地址,由操作系统协助相关硬件,把它“转换”成真正的物理地址。这个“转换”,是所有问题讨论的关键。
&& Intel为了兼容,将远古时代的段式内存管理方式保留了下来。逻辑地址指的是机器语言指令中,用来指定一个操作数或者是一条指令的地址。以上例,我们说的连接器为A分配的0x这个地址就是逻辑地址。——不过不好意思,这样说,好像又违背了Intel中段式管理中,对逻辑地址要求,“一个逻辑地址,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量],也就是说,上例中那个0x,应该表示为[A的代码段标识符: 0x],这样,才完整一些”。
线性地址空间是指一段连续的、不分段的、范围为0~4GB的地址空间。一个线性地址就是线性地址空间的一个绝对地址。
&& x86平台下的系统采用分段机制与分页机制对地址进行转换,其中分段机制把一个虚拟地址转换成线性地址;接着,分页机制把一个线性地址转换成物理地址。
&& 段是虚拟地址空间的基本单位,分段机制必须把虚拟地址空间的一个地址转换为线性地址空间的一个线性地址。为了实现这种映射,仅仅用段寄存器来确定一个基址是不够的,至少还有描述段的长度,所以这里需要一个数据结构,这个结构包括以下内容:1)段的基地址;2)段的界限;3)段的保护属性。此时对于虚拟地址的每一个索引,都对应着索引:基地址:界限:属性的对应关系,这种对应关系组成一个表就叫做段描述符表,其中的表项叫做段描述符,而此时在段寄存器中存放的内容就是段描述表中的索引,由索引可以确定段描述符在描述符表中的位置,因此,段寄存器也叫选择符,结构如下:
500)this.width=500;" border=0>
&&&此时对于每一个虚拟地址“选择符:偏移量”,就能够先通过段选择符找到对应的段描述符中的基地址,加上偏移量即可得其在系统中的线性地址,这个对应关系如下图所示:
&Linux中的段
&&& 在IA32上任意地址都是一个虚拟地址,即任意地址都是以“选择符:偏移量”的方式给出的,这是分段机制内存访问模式的基本特点。但是,由于绝大多数硬件平台都不支持分段机制,只支持分页机制,所以为了让Linux有更好的可移植性,需要去掉分段机制。
&&& 不幸的是,IA32规定分段机制是不可禁止的,因此,Linux的开发人员干脆让段的基地址为0,而段的界限为4GB,这是对于任意偏移量,则等式为“0+偏移量=线性地址”,即偏移量等于线性地址。另外由于分段机制规定偏移量<4GB,所以偏移量的范围为0H~FFFFFFFFH,这恰好是线性地址空间范围,也就是说虚拟地址直接映射到了线性地址,所以在Linux下虚拟逻辑地址与线性地址是一致的(而不是相同),即虚拟地址中的逻辑偏移量总是等于线性地址的。
&&& 因此,Linux在系统中分别为内核和用户程序创建了基地址为0,段界限为4GB的代码段描述符与数据段描述符。
&& CPU的页式内存管理单元,负责把一个线性地址,最终为一个物理地址。从管理和效率的角度出发,线性地址被分为以固定长度为单位的组,称为页(page),例如一个32位的机器,线性地址最大可为4G,可以用4KB为一个页来划分,这页,整个线性地址就被划分为一个tatol_page[2^20]的大数组,共有2的20个次方个页。这个大数组我们称之为页。目录中的每一个目录项,就是一个地址——对应的页的地址。&& 另一类“页”,我们称之为物理页,或者是页框、页桢的。是分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与内存页是一一对应的。&& 这里注意到,这个total_page数组有2^20个成员,每个成员是一个地址(32位机,一个地址也就是4字节),那么要单单要表示这么一个数组,就要占去4MB的内存空间。为了节省空间,引入了一个二级管理模式的机器来组织分页单元。文字描述太累,看图直观一些:
(23.21 KB)
如上图,1、分页单元中,页目录是唯一的,它的地址放在CPU的cr3寄存器中,是进行地址转换的开始点。万里长征就从此长始了。2、每一个活动的进程,因为都有其独立的对应的虚似内存(页目录也是唯一的),那么它也对应了一个独立的页目录地址。——运行一个进程,需要将它的页目录地址放到cr3寄存器中,将别个的保存下来。3、每一个32位的线性地址被划分为三部份,面目录索引(10位):页表索引(10位):偏移(12位)依据以下步骤进行转换:1、从cr3中取出进程的页目录地址(操作系统负责在调度进程的时候,把这个地址装入对应寄存器);2、根据线性地址前十位,在数组中,找到对应的索引项,因为引入了二级管理模式,页目录中的项,不再是页的地址,而是一个页表的地址。(又引入了一个数组),页的地址被放到页表中去了。3、根据线性地址的中间十位,在页表(也是数组)中找到页的起始地址;4、将页的起始地址与线性地址中最后12位相加,得到最终我们想要的葫芦;&& 这个转换过程,应该说还是非常简单地。全部由硬件完成,虽然多了一道手续,但是节约了大量的内存,还是值得的。那么再简单地验证一下:1、这样的二级模式是否仍能够表示4G的地址;页目录共有:2^10项,也就是说有这么多个页表每个目表对应了:2^10页;每个页中可寻址:2^12个字节。还是2^32 = 4GB<FONT color=#、这样的二级模式是否真的节约了空间按中的解释,二级模式空间的节约是从两个方面实现的:A、如果一级页表中的一个页表条目为空,那么那所指的二级页表就根本不会存在。这表现出一种巨大的潜在节约,因为对于一个典型的程序,4GB虚拟地址空间的大部份都会是未分配的;B、只有一级页表才需要总是在主存中。虚拟存储器系统可以在需要时创建,并页面调入或调出二级页表,这就减少了主存的压力。只有最经常使用的二级页表才需要缓存在主存中。——不过Linux并没有完全享受这种福利,它的页表目录和与已分配页面相关的页表都是常驻内存的。&& 值得一提的是,虽然页目录和页表中的项,都是4个字节,32位,但是它们都只用高20位,低12位屏蔽为0——把页表的低12屏蔽为0,是很好理解的,因为这样,它刚好和一个页面大小对应起来,大家都成整数增加。计算起来就方便多了。但是,为什么同时也要把页目录低12位屏蔽掉呢?因为按同样的道理,只要屏蔽其低10位就可以了,不过我想,因为12>10,这样,可以让页目录和页表使用相同的数据结构,方便。Linux中的页管理
原理上来讲,Linux只需要为每个进程分配好所需数据结构,放到内存中,然后在调度进程的时候,切换寄存器cr3,剩下的就交给硬件来完成了(呵呵,事实上要复杂得多,不过偶只分析最基本的流程)。前面说了i386的二级页管理架构,不过有些CPU,还有三级,甚至四级架构,Linux为了在更高层次提供抽像,为每个CPU提供统一的界面。提供了一个四层页管理架构,来兼容这些二级、三级、四级管理架构的CPU。这四级分别为:页全局目录PGD(对应刚才的页目录)页上级目录PUD(新引进的)页中间目录PMD(也就新引进的)页表PT(对应刚才的页表)。整个转换依据硬件转换原理,只是多了二次数组的索引罢了,如下图:
那么,对于使用二级架构32位的硬件,现在又是四级转换了,它们怎么能够协调地工作起来呢?嗯,来看这种情况下,怎么来划分线性地址吧!从硬件的角度,32位地址被分成了三部份——也就是说,不管理软件怎么做,最终落实到硬件,也只认识这三位老大。从软件的角度,由于多引入了两部份,,也就是说,共有五部份。——要让二层架构的硬件认识五部份也很容易,在地址划分的时候,将页上级目录和页中间目录的长度为0就可以了。这样,操作系统见到的是五部份,硬件还是按它死板的三部份划分,也不会出错,也就是说大家共建了和谐计算机系统。这样,虽说是多此一举,但是考虑到64位地址,使用四层转换架构的CPU,我们就不再把中间两个设为0了,这样,软件与硬件再次和谐——抽像就是强大呀!!!例如,一个逻辑地址已经被转换成了线性地址,0x,换成二制进,也就是:
内核对这个地址进行划分PGD = PUD = 0PMD = 0PT = offset = 现在来理解Linux针对硬件的花招,因为硬件根本看不到所谓PUD,PMD,所以,本质上要求PGD索引,直接就对应了PT的地址。而不是再到PUD和PMD中去查数组(虽然它们两个在线性地址中,长度为0,2^0 =1,也就是说,它们都是有一个数组元素的数组),那么,内核如何合理安排地址呢?从软件的角度上来讲,因为它的项只有一个,32位,刚好可以存放与PGD中长度一样的地址指针。那么所谓先到PUD,到到PMD中做映射转换,就变成了保持原值不变,一一转手就可以了。这样,就实现了“逻辑上指向一个PUD,再指向一个PDM,但在物理上是直接指向相应的PT的这个抽像,因为硬件根本不知道有PUD、PMD这个东西”。然后交给硬件,硬件对这个地址进行划分,看到的是:页目录 = PT = offset = 嗯,先根据(32),在页目录数组中索引,找到其元素中的地址,取其高20位,找到页表的地址,页表的地址是由内核动态分配的,接着,再加一个offset,就是最终的物理地址了。
&& 综上所述,也就是在Linux系统中,只需要考虑分页机制,而对于系统中使用的地址来说,则只需要区分逻辑地址与物理地址即可~~~
阅读(1774) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。}

我要回帖

更多关于 非线性编辑是什么意思 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信