精华内容
下载资源
问答
  • 操作系统虚拟地址转换物理地址

    千次阅读 2020-01-03 20:08:27
    十进制转换为二进制 0000 0 0001 1 0010 2 0011 3 0100 4 0101 5 0110 6 0111 7 1000 8 1001 9 1010 10 1011 11 1100 12 11...

    十进制转换为二进制

    0000    0

    0001    1

    0010   20011   3
    0100    4   0101      50110   60111     7
    1000     81001      9 1010   101011     11

     

    1100     121101      131110    141111     15

     

    展开全文
  • 虚拟地址空间那篇文章中我们通过虚拟地址空间简单地介绍了虚拟地址空间,知道了应用程序中使用的是虚拟地址,需要通过MMU转换物理地址,本文将详细介绍虚拟地址如何转换物理地址。 页、页框、页表 linux操作...

    在虚拟地址空间那篇文章中我们简单地介绍了虚拟地址空间,知道了应用程序中使用的是虚拟地址,需要通过MMU转换成物理地址,本文将详细介绍虚拟地址如何转换成物理地址。

    页、页框、页表

    linux操作系统以页为单位管理虚拟内存,通常一页为4k,而物理内存是以块为单位管理的,物理内存被分成很多与页大小相同的块,被称为页框,每个页地址与页框对应,这种对应关系被记录在页表中,页表是MMU中的数据结构,下图是页表中较为常见的几个属性。
    在这里插入图片描述
    页框存在于物理内存上,而页可以放置在任意的页框中,这是能够进行地址转换的基础。

    缺页异常

    页表结构图中,p(存在位)表示虚拟地址对应的物理地址是否已经加载到内存中,如果虚拟地址没有被使用过,物理地址就不会加载到内存中,当需要使用虚拟地址时,操作系统先检查存在位,如果存在位为1则地址转换后可以直接访问,如果存在位为0,会引发缺页异常,操作系统将加载页框到内存中,然后继续访问。与普通中断不同的是,缺页异常返回后会再次执行陷入中断的那条指令,而普通中断会执行跳过该指令,执行下一条指令。

    换页

    操作系统通常使用页面缓存算法来管理已经加载的页,当操作系统通过缺页异常准备加载新页面时,如果缓存已满,就需要先删除一页,再加载新页,删除页时,需要检查D(脏位),如果D为1,说明该页被修改过,需要先写入磁盘,再删除。linux操作系统中,名为pdflush的守护进程会周期性地刷脏页。
    换页时选择被删除的页通过页面缓存置换算法来实现,常见的算法包括先进先出算法(FIFO)、最佳置换算法(OPT)和最近最少使用算法(LRU)。linux使用LRU算法实现页面置换,这里提供一种LRU的简单实现。

    
    //双向链表,也可以使用stl的list
    struct linkedlist{
        linkedlist* prev;
        linkedlist* next;
        int value;
        int key;
    
        linkedlist():prev(nullptr),next(nullptr),key(0),value(0){};
        linkedlist(int p1,int p2):prev(nullptr),next(nullptr),key(p1),value(p2){};
        linkedlist(linkedlist* p1, linkedlist* p2, int q1,int q2):prev(p1), next(p2),key(q1),value(q2) {};
    };
    
    class LRUCache {
    public:
        LRUCache(int capacity) {
            _capacity = capacity;
            size = 0;
            head = new linkedlist(0, 0);
            tail = new linkedlist(head, nullptr, 0, 0);
            head->next = tail;
        }
        
        //获取页面时,更新该页面位置到最前
        int get(int key) {                       
            if(mp.find(key)==mp.end())return -1;
            moveToHead(mp[key]);
            return mp[key]->value;
        }
        
        //添加页面时,删除最后一个页面
        void put(int key, int value) {
            if(mp.find(key)==mp.end()){
                if(size==_capacity) {
                    delTail();
                    --size;
                }
                linkedlist* node = new linkedlist(key,value);
                mp[key] = node;
                addToHead(node);
                ++size;
            }
            else{
                mp[key]->value = value;
                moveToHead(mp[key]);
            }
            return;
        }
    private:
        linkedlist* head;
        linkedlist* tail;
        unordered_map<int,linkedlist*> mp;
        int size;
        int _capacity;
    
        void moveToHead(linkedlist* node){
            node = delNode(node);
            addToHead(node);
        }
    
        void addToHead(linkedlist* node){
            linkedlist* tmp = head->next;
            head->next = node;
            node->prev = head;
            node->next = tmp;
            tmp->prev = node;
        }
    
        linkedlist* delNode(linkedlist* node){
            linkedlist* p = node->prev;
            linkedlist* n = node->next;
    
            p->next = n;
            n->prev = p;
            node->next = nullptr;
            node->prev = nullptr;
            return node;
        }
    
        void delTail(){
            linkedlist* node = tail->prev;
            node = delNode(node);
            mp.erase(node->key);
            delete node;
            node = nullptr;
        }
    };
    
    

    OPT算法被称为完美但无法实现的页面置换算法,限于篇幅(困了)我们后续再介绍。

    多级页表

    使用段页式管理内存的操作系统将虚拟地址先通过段表转换为线性地址,再通过页表将线性地址转换为物理地址。Linux操作系统使用页式管理,虚拟地址就是线性地址,我们仅详细介绍线性地址到物理地址的转换。

    在这里插入图片描述

    如上图,在32位操作系统中,页目录表的基址被记录在CR3寄存器中,地址的高10位为页目录表的偏移,通过基址和偏移可以找到页表基址,地址中间10为页表的偏移,通过基址和偏移可以找到对应的页,地址低12位记录了页中的偏移,就能够查找到对应的物理地址了。

    快表(TLB)

    上面介绍的多级页表中包括一张页目录表和一张页表,需要多次跳转才能访问到物理地址,并且Linux的实际实现中,页目录表的数量还要更多。为了减少跳转带来的消耗,MMU引入了快表(TLB),快表个人理解就是一种缓存,将经常使用的页面及其页框直接记录在快表中,当需要访问物理地址时,先从TLB中寻找,如果命中TLB,则直接取出页框地址访问。
    快表实际上是一个单独的高速缓存寄存器,其大小通常受到限制,因此快表只能访问有限个表项。当虚拟地址空间切换时,快表也会切换,此时页面转换的消耗将大大增加。

    总结

    本文较为深入地讨论了虚拟地址和物理地址的转换,相信大家都这个过程已经比较清楚,后续将对异常和中断进行介绍,帮助大家理解缺页异常的实际工作过程。

    展开全文
  • 虚拟地址到物理地址转换步骤

    千次阅读 2020-08-24 14:52:14
    已知一个虚拟地址0x01AF5518, 则转换的过程如下: 注意: 这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况 1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:  -> 0000 0001...

    已知一个虚拟地址0x01AF5518, 则转换的过程如下:

    注意: 这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况

    1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:
      -> 0000 0001 1010 1111 0101 0101 0001 1000

    按照10, 10, 12的位数重新排列后
      -> (页目录索引)00 000 00110, (页表项索引)10 1111 0101, (偏移)0101 0001 1000

    换算成十六进制后可以得到如下结果
      页目录索引 = 6, 页表项索引 = 0x2f5 , 偏移 = 0x518

    1. 根据当前的CR3寄存器中的物理地址定位页目录表基址
        Cr3中存放的是物理地址, 这个物理地址指向进程的页目录表基址, 由此可以得到
        页目录表基址(PDE) = Cr3 = 0xAA0E5000

    2. 计算页表项的地址
        页表地址存放在页目录表(PDE)中的第6个项目中, 也就是
        [0xAA0E5000 + 4 * 6] = [0xAA0E5018] = 0x3D955867, 其中0x00000867为该页表属性值, PTE = 0x3D955000

    3. 计算页面物理地址
        我们要找的页面在这个页表中的第0x2f5项, 所以虚拟地址所在的页的物理地址为
        [0x3D955000 + 0x2f5 * 4] = [0x3D955BD4] =
        假设[0x3D955BD4] = 0x7095e847, 页面的物理地址 x0x7095e000, 0x00000847表示的是页面属性

    4. 计算最终的物理地址
        由虚拟地址分离的偏移可以计算出最终的物理地址为
        0x7095E000 + 0x00000518 = 0x7095E518.

    展开全文
  • 谈起内存管理,首先我们就要搞清楚虚拟地址和物理地址的...虚拟地址,就是就是一种逻辑意义上的地址,而当我们想要访问这个虚拟地址时,是需要转换物理地址才能够真实的访问到,比如我一个2G的内存,那么虚拟地...

    谈起内存管理,首先我们就要搞清楚虚拟地址和物理地址的关系。本文就是简单介绍下这两个基础概念。

    物理地址

    物理地址指实际存在的物理内存地址,比我有一个2G的内存芯片,那么系统的物理内存就是2G,我要访问该内存中的一个地址,那就需要对应的物理内存。

    虚拟地址

    虚拟地址,就是就是一种逻辑意义上的地址,而当我们想要访问这个虚拟地址时,是需要转换到物理地址才能够真实的访问到,比如我一个2G的内存,那么虚拟地址可能会超过2G的范围,那么直接去物理内存中寻找该地址是根本不存在的,因此我们需要一个虚实的转换,这个动作是由MMU内存管理单元来做的。

    虚拟地址和物理地址映射

    ARM32 Linux系统中每个进程都享有4G大小的虚拟地址空间,而物理地址大小要看设备配置了多大的物理内存,这个是实际存在的物理内存,比如2G。那么这就存在一个冲突,每个进程4G虚拟地址,怎么映射到仅仅只有2G的物理内存上去呢?这就是人类聪明才智体现的地方。MMU的设计就是为了解决这种虚实映射关系的,当然MMU并非单纯靠硬件即可完成关系的映射,它需要软件的参与和配合。MMU通过页表来对我们的地址进行转换,那么我们需要在MMU使能之前,把需要访问的地址转换页表配置完成并告知MMU,这样MMU就可以按照配置的页表来自动进行地址转换了这一点是最终靠硬件完成。

    32 bit的Linux内核软件最大支持3级映射,而ARM32硬件上最大只支持2级映射关系,Linux内核是完全可以支持的,还是以它为例,:

     +-----------+------------+----------+
     |31       20|19        12|11       0|
     +-----------+------------+----------+
              |         |         |       
              |         |         |        
              |         |         |        
              |         |         |         
              |         |         +-----------> [0:11] in-page offset
              |         +---------------------> [19:12] 二级 index
              +-------------------------------> [31:20] 一级 index
      
    TTBRx寄存器存放页表基地址
    

    首先我们需要创建一级页表到一块内存区域内,每个页表项4Byte,12个bit寻址,那么这块内存区域大小不能超过16K。那么一个虚拟地址的[31:20]这12个bit就可以直接找到对应的一级页表项(PGD)

    TTBRx
    存放PGD页表基地址,4096个一级PGD页表项,虚拟地址的[31:20] 12 bit一共能寻址4096个PGD页表项

    +------+
    |4 byte| PGD entry
    +------+
    |4 byte| PGD entry
    +------+
    |4 byte| PGD entry
    +------+
    

    PGD页表项
    存放二级PTE页表基地址,一个二级页表中存放有256个二级PTE页表项,可以通过虚拟地址的[19:12]来进行寻址二级页表项。

     +-----------+------------+----------+
     |31                    10|9        0|           PGD entry
     +-----------+------------+----------+
                |                  |       
                |                  |        
                |                  |        
                |                  |         
                |                  +-----------> [9:0] 各种标志位
                |         
                +-------------------------------> [31:10] 二级页表基地址(二级页表页存放的物理地址范围是12个bit)
                                                                          +------+
                                                                          |4 byte| PTE entry
                                         虚拟地址的[19:12] offset--------> +------+
                                                                          |4 byte| PTE entry
                                                                          +------+
                                                                          |4 byte| PTE entry
                                                                          +------+
    
    

    PTE页表项
    存放4KB物理页的基地址,这里是最终要访问的物理页。

     +-----------+------------+----------+
     |31                    12|11        0|           PTE entry
     +-----------+------------+----------+
                |                  |       
                |                  |        
                |                  |        
                |                  |         
                |                  +-----------> [11:0] 各种标志位
                |         
                +-------------------------------> [31:12] 物理内存页基地址
    

    由于我们配置的是4KB大小的物理页面,那么一个4K大小的内存页,寻址特定的地址就需要12个bit,恰好我们的虚拟内存,剩余[11:0]是用来寻址最后物理内存页中的offset的。

    通过这种转换后,可以看到最后访问的物理内存地址也是一个32 bit大小的地址,所以在这种平台,最大支持4G的物理访问地址空间。但是这种转换带来的好处时,我们的虚拟地址和实际的物理地址,并不是相等的,我们可以通过这种页表的映射来把不同的物理地址映射到虚拟地址上,这样通过内核的内存管理机制,我们可以给每个进程分配4G的虚拟内存,并且只在对应虚拟地址需要访问时才进行实际的映射,这样就能保证各个进程感觉自己真有4G的内存一样。

    如何把4G虚拟地址映射到2G的内存上来

    这个问题我想肯定困扰过很多刚刚接触内存管理的技术人员,笔者当初也是百思不得其解,经过后来的逐渐深入才见的真章。
    缺页异常
    一个是4G,一个是2G,怎么算都不会相等,其实内核的内存管理机制并不会立刻对这些地址进行映射,有基础的人应该都听说过直接映射和动态映射的概念,内核中是会划分一部分物理内存作为直接映射区,这部分是会在系统启动时直接映射到虚拟内存区域中,比如我们的kernel代码运行区域,除此之外,其余的物理内存都会保留下来供内核统一管理,这些同一个管理的内存只会在需要的时候才会进行映射,比如当我们的进程访问一个虚拟地址,而此时该虚拟地址恰好没有映射,那么就会产生缺页异常,此异常会被内核接收到,然后内存管理机制就开始进行处理,把需要访问的虚拟地址进行映射,映射到实际的物理内存上去。
    swap机制
    除了这个之外还有一个问题,系统中运行了那么多的进程,如果不停的访问不存在的虚拟内存,触发内核的缺页异常进行动态映射,那么总有一刻,2G的内存都被映射完了,那么此时还要继续访问更多虚拟地址,那么改怎么办呢?此时就涉及到内核的另一个内存管理机制,那就是swap机制,我们知道当安装一个Linux系统时,我们都要制定一个swap分区,这个分区就是在此时时候的,内核会把一些不常使用的内存页置换出来,数据保存到我们的硬盘上,这样就会有空余出来的内存继续被系统映射了,那么当其他进程要访问被置换的数据时,系统同样再从swap分区把对应数据恢复到内存中来。就是利用这种方式实现了2G物理内存当4G使用的目的。

    不同进程4G的虚拟地址空间如何切换

    前面我们介绍,MMU进行虚拟地址到物理地址转换时需要页表的,那么不同进程都有各自的4G虚拟地址空间,那么这些不同的区间如何划分和切换呢?实际上针对不同的进程,内核会维护各自进程的内存页表,我们内核代码是通过配置不同进程的内存页表来完成不同进程虚拟地址切换的。当我们的CPU在进行进程调度的时候,有一个节点就是要重新设置对应进程的页表。这样切换到不同的进程运行不用的程序时,就能保证各自空间的独立性。

    展开全文
  • 分页内存管理——虚拟地址到物理地址转换

    万次阅读 多人点赞 2018-08-10 23:30:57
    此篇博客内容在于着重帮助读者明白在分页内存管理下,虚拟地址和物理地址转换计算是怎么进行的。 有关分页内存管理的其他知识请事先参阅有关资料。^_^ 一、在计算之前需要了解如下知识: 1.对每个程序而言,...
  • 页表就是用于将虚拟地址转换物理地址转换关系表。访问虚拟地址时,计算机通过页表找到对应的实际物理地址访问。 我们在上一节介绍了内存管理模块概图, 怎么完成从pgd 到 page的转化呢? linux 内核code是...
  • Linux虚拟地址和物理地址转换

    千次阅读 2018-06-27 23:46:43
  • MMU的主要作用:虚拟地址到物理地址转换;访问权限控制;设置虚拟存储空间的缓冲。 虚拟存储器:程序一般存于掉电不丢失的硬盘中,但是硬盘读写速度慢。所以系统上电后一般只在ROM中完成小部分硬件初始化程序,并...
  • 说明: GDT:全局描述符表 LDT:局部描述符表 TI:标志位,为0表示描述符在GDT,为1表示描述符在LDT
  • 操作系统虚拟地址计算物理地址

    万次阅读 多人点赞 2018-12-05 18:39:21
    有关计算机操作系统中虚拟地址转换物理地址的计算 笔者以具体题目加以说明: 在一个分页虚拟存储系统中,用户编程空间为32个页,页长为1 KB,内存空间为16 KB。如果应用程序有10页长,若已知虚页0、1、2、3,已...
  • linux虚拟地址转物理地址

    千次阅读 2018-06-21 07:06:00
    80386虚拟地址和物理地址转换CPU的发展之前在看malloc内存分配函数的原理时,有涉及到分配虚拟内存,然后再映射到物理内存,当初也是看得一头雾水,因为对虚拟内存和物...
  • Linux 内核 虚拟地址 物理地址 转换

    千次阅读 2015-12-12 15:10:02
    剩下的1G-896=128M范围的虚拟地址可以映射到任意物理地址.称为内核虚拟地址.当实际内存大于1G时(实际上是> 896M时),用这块地址空间做映射. 实际的计算机体系结构有硬件的制约,这限制了页框可以使用的方式。尤其
  • 已知一个虚拟地址0x01AF5518, 则转换的过程如下:  注意: *这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况* 1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:  -&...
  • 操作系中分页式管理总的逻辑地址到物理地址的映射转换算法 C语言
  • Linux 虚拟地址到物理地址转换

    千次阅读 2019-03-08 13:58:14
    CPU通过地址来访问内存中的单元,地址有虚拟地址和物理地址之分,如果CPU没有MMU(Memory Management Unit,内存管理单元),或者有MMU但没有启用,CPU核在取指令或访问内存时发出的地址将直接传到CPU芯片的外部地址...
  • 一直以来感觉虚拟地址和物理地址之间的相互转换非常麻烦,虚拟地址到物理地址转换由CPU硬件完成,但物理地址虚拟地址怎么转换啊?况且有时候在软件上也希望通过一个物理地址得到虚拟地址,这时候自然不能依赖CPU...
  • 逻辑地址是CPU在执行过程中生成的地址,而物理地址是指存储单元(已加载到内存中的单元)中的位置。请注意,用户仅处理逻辑地址(虚拟地址)。逻辑地址尤其由MMU或地址转换单元进行转换。该过程的输出是适当的物理...
  • 仿照书上的例子,试着手工把虚拟地址转换物理地址。 由于书中的例子是针对未开启PAE的情况,而我的XP SP2默认开启了PAE,所以白白浪费了大半天时间。话说以前还真不知道启动参数里面/noexecute=optin也会开启PAE...
  • 计算机中的存储层次结构都是在考虑性价比的前提条件下尽量满足程序员的这一需求,其中虚拟地址的产生在其中起到了至关重要的作用:它允许程序员不用考虑物理内存的使用情况而任意使用整个内存空间(CPU地址总线决定...
  • 初试将虚拟地址转换物理地址

    千次阅读 2013-06-16 17:40:17
    背景:最近学习张银奎的《软件调试》,看到 2.7.5 节 使用WinDBG观察分页机制,终于看到第一个可以操作的例子,但始终不能按书上的方式正确的将虚拟地址转换物理地址,google一下,终于解决,放到这里记录一下。...
  • 虚拟地址物理地址转换
  • CPU将一个虚拟内存空间中的地址(虚拟地址)转换物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将这个逻辑地址转换成一个线程地址...
  • 用户态进程的虚拟地址如何转换物理地址用户态进程的虚拟地址如何转换物理地址?mmapmmap基础概念mmap内存映射原理mmap详解UMA和NUMA:mmap优点总结mmap相关函数 用户态进程的虚拟地址如何转换物理地址? 区分...
  • ,通过MMU将虚拟地址转换物理地址发送到cpu芯片引脚上。 虚拟地址转换物理地址的过程 cr3:页目录基地址寄存器 CR3含有存放页目录表页面的物理地址(注意,是物理地址!!!) 以下为32位系统二级页表: ...
  • 对于这些地址,内核通过宏__pa()找到这些虚拟地址对应的物理地址。或者通过__va()找到物理地址对应 的虚拟地址。 arch/arm64/include/asm/memory.h #define __pa(x) __virt_to_phys((unsigned long)(x)) #define ...
  • 项目中经常需要把内存数据dump出来看看是否与自己设想的一样,dump之前我们需要把内核的虚拟地址先转换物理地址才能借助工具dump出来。废话不多说,直接说正题。1. 内核里的地址是从3G开始算的,即起始地址为:0xc...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 126,984
精华内容 50,793
关键字:

虚拟地址转换物理地址