MMU简单处理TLB例外

MMU简单处理TLB例外

TLB是translation lookaside buffer的简称,也可称为快表,页表的Cache。
首先,我们知道MMU的作用是把虚拟地址转换成物理地址。虚拟地址和物理地址的映射关系存储在页表中,而现在页表又是分级的。64位系统一般都是3~5级, 常见的配置是4级页表,就以4级页表为例说明: 分别是PGD、PUD、PMD、PTE四级页表。在硬件上会有一个叫做页表基地址寄存器,它存储PGD页表的首地址。MMU就是根据页表基地址寄存器从PGD页表一路查到PTE,最终找到物理地址(PTE页表中存储物理地址)。
这就像在地图上显示你的家在哪一样,我为了找到你家的地址,先确定你是中国,再确定你是某个省,继续往下某个市,最后找到你家是一样的原理。一级一级找下去。这个过程非常繁琐;如果第一次查到你家的具体位置,我如果记下来你的姓名和你家的地址。下次查找时,是不是只需要跟我说你的姓名是什么,我就直接能够告诉你地址,而不需要一级一级查找。四级页表查找过程需要四次内存访问, 延时可想而知,非常影响性能, 而记下来本次查找页表命中的数据就可以称为缓存到TLB.

本章节的内容主要是通过TlbRefill来将一个VA映射成PA,即VA有效.

TLB Miss

在固件下我们没有实现页表的操作,地址都是通过窗口命中来转换成物理地址, 所以我们有了0x8000000000000000(uncache) 和 0x9000000000000000(cache) 两个窗口地址,并且将窗口下的地址进一步划分;
比如:CPU->Chipset 间HT空间的地址 0x80000e0000000000 -> 0x0e0000000000 (HT1_LO的物理地址空间).
基本上在高位的窗口命中下划分的VA->PA都按照1-1做了映射关系.

正因为有了以上的窗口地址,我们的代码中的有效地址基本上都是以0x8000000000000000 和 0x9000000000000000来划分,即Mem空间通过Cache窗口,非Mem通过Uncache窗口进行访问; 但如果我们访问的地址不落在窗口命中范围,就会去TLB表项内查找是否存在映射关系(MTLB & STLB),由于我们没有增加任何Table Entry,所以其余地址必定TLB Miss, 从而触发TLB 例外, 下面以一个VA为例:
在这里插入图片描述
下面在不静态添加TLB表项的前提下,就TLBRefill来动态实现VA有效。

TLB Refill

我们目前的 Exception Entry在内存的0地址,故异常初始化的时候将Exception Section拷贝到了0地址,作为软件入口点。

简谈TLB Refill执行逻辑:

  • 1 保存上下文,即所有寄存器的状态,为了灵活架构提供了TLB时可以作为暂存的寄存器在这里插入图片描述
  • 2 检测触发例外是中断还是异常, 我们以TLB重填例外为例 0x8a Bit0 置1在这里插入图片描述
  • 3 重填TLB表项: TLBRELO0、 TLBRELO1 、 TLBREHI.
  • 4 开中断恢复寄存器状态.
  • 5 ERTN返回:在这里插入图片描述

重填TLB入口点

Exception_Handler ( 保存上文数据 ) -> { la t1, mException; jirl zero, t1, 0;} (跳转异常具体处理).

0x00: 当前模式信息 (CRMD)
0x01: 例外当前模式信息 (PRMD)
0x04: 例外配置 (ECTL)
0x05: 例外状态 (ESTAT)
0x06: 例外程序计数器 (EPC)
0x07: 出错虚地址 (BADV)
0x08: 出错指令 (BADI)
0x10: TLB索引 (TLBIDX):
0x11: TLB表项高位 (TLBEHI)
0x12: TLB表项低位0 (TLBELO0)
0x13: TLB表项低位1 (TLBELO1)
0x1b: 全局目录基址 (PGD)
0x1e: STLB页大小 (STLBPS)
0x30 + n (0->15): 数据保存 (SAVEn)
0x88 : TLB重填例外入口地址 TLBRENTRY :填写异常入口点,即0地址异常处理函数.
0x89 : TLB重填例外出错虚地址 TLBRBADV : 触发TLB例外时,出错虚拟地址(读写出错BadV为读写无效地址,加载执行出错为pc无效地址).
0x8a : TLB重填例外程序计数器 TLBREPC : 触发TLB例外时, 当前PC已跳入异常,EPC记录触发异常前的PC.
0x8b : TLB重填例外数据保存 TLBRSAVE 暂存上下文数据
0x8c : TLB重填例外表项低位0 (TLBRELO0) TLB表项的奇偶页:PPN0(物理页号)
0x8d : TLB重填例外表项低位1 (TLBRELO1) TLB表项的奇偶页:PPN1(物理页号)
0x8e : TLB重填例外表项高位 (TLBREHI) TLB表项的虚页号VPN
以上这些CSR寄存器都是调试必须了解的,关于本章节的所有寄存器的信息都可参考 龙芯架构参考手册 卷一:基础架构
相关手册文档已开源github,附下载地址: https://github.com/loongson/LoongArch-Documentation,欢迎有兴趣的小伙伴收藏转发学习 !

单个TLB表项的比较部分:

在这里插入图片描述

TLBRefill Code实例:

   150 VOID                                                                                                                                                                                                  
   151 AddTlbEntry (                                                                                                                                                                                         
   152   IN TLB_REGS *Regs                                                                                                                                                                                   
   153   )                                                                                                                                                                                                   
   154 {                                                                                                                                                                                                     
   155   DbgPrint (DEBUG_INFO, "Add TLB Entry:\n");                                                                                                                                                          
   156   DbgPrint (DEBUG_INFO, "\tTLBELO0  = 0x%lx\n", Regs->TLBELO0);                                                                                                                                       
   157   DbgPrint (DEBUG_INFO, "\tTLBELO1  = 0x%lx\n", Regs->TLBELO1);                                                                                                                                       
   158 //  Csrxchg (Regs->PageSize << 24, 0x3f000000, 0x10); // CSR.TLBRERA.IsTLBR = 0, is not tlbrefill                                                                                                     
   159   Csrxchg (Regs->Index, 0xfff, 0x10); // Index                                                                                                                                                        
   160 //  Csrxchg (0, 0x80000000, 0x10);  // NP CSR.TLBRERA.IsTLBR = 0,bit = 1;                                                                                                                             
   161   CsrWrite (Regs->PageSize, 0x1e);  // PS                                                                                                                                                             
   162   CsrWrite (Regs->TLBEHI, 0x8e);  // TLBEHI                                                                                                                                                           
   163   CsrWrite (Regs->TLBELO0, 0x8c); // TLBELO0                                                                                                                                                          
   164   CsrWrite (Regs->TLBELO1, 0x8d); // TLBELO1                                                                                                                                                          
   165   TlbWr();                                                                                                                                                                                            
   166 }                                                                                                                                                                                                     
   167                                                                                                                                                                                                       
   168 #define VTLB_INDEX_BASE 2048U                                                                                                                                                                         
   169                                                                                                                                                                                                       
   170 static int num = 1;                                                                                                                                                                                   
   171                                                                                                                                                                                                       
   172 VOID                                                                                                                                                                                                  
   173 TlbRefill (                                                                                                                                                                                           
   174     VOID                                                                                                                                                                                              
   175   )                                                                                                                                                                                                   
   176 {                                                                                                                                                                                                     
   177   TLB_REGS Regs;                                                                                                                                                                                      
   178                                                                                                                                                                                                       
   179   Regs.PageSize = 0xc; // PageSize: 4k                                                                                                                                                                
   180   Regs.TLBEHI   = CsrRead64(0x89);  // BadV                                                                                                                                                           
   181   UINT64 Tmp = CsrRead64(0x89);                                                                                                                                                                       
   182   if (Tmp & 0x0e0000000000) {                                                                                                                                                                         
   183     Tmp |= 0x43; //uncache attribute                                                                                                                                                                  
   184   } else {                                                                                                                                                                                            
   185     Tmp |= 0x53; //cache attribute                                                                                                                                                                    
   186   }                                                                                                                                                                                                   
   187   Regs.TLBELO0  = Tmp ;                                                                                                                                                                               
   188   Regs.TLBELO1  = Tmp | (1ULL << Regs.PageSize); //Single PageSize                                                                                                                                    
   189                                                                                                                                                                                                       
   190   Regs.Index = VTLB_INDEX_BASE + num;                                                                                                                                                                 
   191   num++;                                                                                                                                                                                              
   192                                                                                                                                                                                                       
   193   AddTlbEntry (&Regs);                                                                                                                                                                                
   194                                                                                                                                                                                                       
   195 }             

Code execution:

在这里插入图片描述

Kernel TlbRefill

关于内核下发生TlbRefill的情况:用户态地址都是通过页表映射后的地址,当创建进程时,都为每个进城增加了页表的对应关系。
假设进程A和进程B都需要物理内存PM的资源,而增加的页表AT就是A通往内存PM的通道,增加的BT就是B通往内存PM的通道,同一块物理内存资源,代码中的有效地址确实多对一的关系,这样我们可以保证每个进程都可以访问更多的资源,当然少不了PGD的参与,保证每个进程都存储整个空间。

简单梳理了下内核,发现如果发生TLB 例外来Refill时,重填的页大小与内存分配的最小页一致,4K or 16K or 64K, 当然也为了保证对齐,内核下的对应关系挺复杂的,我们以上固件下只简单介绍了VA->PA 1-1映射的关系。

以上关于LoongArch架构的资源均来自https://github.com/loongson/,欢迎有需要的小伙伴下载学习,共同交流 !

03-14
### MMUTLB 的基本概念 内存管理单元 (Memory Management Unit, MMU) 是计算机体系结构中的一个重要组件,负责将虚拟地址映射到物理地址。它通过分页机制来支持操作系统的虚拟内存功能[^1]。 转换后备缓冲区 (Translation Lookaside Buffer, TLB) 是一种高速缓存,用于存储最近使用的虚拟地址到物理地址的映射关系。当处理器访问内存时,TLB 可以快速提供所需的物理地址,从而减少每次都需要查询页表的时间开销[^2]。 ### 实现细节 #### 1. 虚拟地址到物理地址的转换过程 MMU 使用分页技术将进程的虚拟地址空间划分为固定大小的页面 (Page),并将这些页面映射到实际的物理内存帧 (Frame) 中。此过程中涉及的主要数据结构包括: - **页目录 (Page Directory)**:指向多个页表项的指针数组。 - **页表 (Page Table)**:包含具体页框号和其他控制位的信息。 每当 CPU 需要解析一个虚拟地址时,会先检查 TLB 是否存在对应的条目。如果命中,则直接返回相应的物理地址;如果没有找到匹配项(即发生 TLB 缺失),则需要逐级遍历页目录和页表完成地址翻译并更新 TLB 记录。 ```c // 假设简单的两级页表结构 struct PageDirectoryEntry { unsigned int present : 1; // 页面是否存在标志 unsigned int rw : 1; // 读写权限标记 unsigned int user : 1; // 用户模式可访问标志 unsigned int pwt : 1; // 写通属性 unsigned int pcd : 1; // 缓存禁用属性 unsigned int accessed: 1; // 已访问标志 unsigned int dirty : 1; // 修改过的内容标志 unsigned int page_table_base_address; }; struct PageTableEntry { unsigned int present : 1; unsigned int rw : 1; unsigned int user : 1; unsigned int pwt : 1; unsigned int pcd : 1; unsigned int accessed: 1; unsigned int dirty : 1; unsigned int frame_number; }; ``` #### 2. TLB 替换策略 为了提高性能,在有限容量下如何有效替换旧有记录成为关键问题之一。常见的算法包括 FIFO(先进先出), LRU(最近最少使用)以及随机选择等方式。 --- ### 总结 综上所述,MMU 结合 TLB 提供了一种高效且灵活的方法来进行虚实地址之间的转化工作,这对于现代操作系统来说至关重要。同时需要注意的是不同架构可能还会引入更多特性比如大页支持或者多层页表设计等进一步优化效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来杯清咖_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值