操作系统真象还原_访问vaddr对应的pte

2023-09-21 12:57:17
须知:只要开启了分页机制,不管物理地址还是虚拟地址在CPU面前都按照分页处理,也就是即便给出物理地址CPU也按虚拟地址对待。

先访问到页表自己 + 再用页目录项pde(页目录表中页表的索引)做为pte的索引访问到页表 + 再用pte的索引做为页内偏移

代码

\boot\loader6_3.s

;第二步:
;将页目录表物理地址赋值给cr3寄存器,分页机制打开前要将页表地址加载到控制寄存器cr3中
mov eax, PAGE_DIR_TABLE_POS              ; PAGE_DIR_TABLE_POS = 0x100000
mov cr3, eax

\kernel\memory.c

/** 
 * 功能:
 *      得到参数vaddr所在的pte指针,指针的值也就是虚拟地址。
 *      通过vaddr构造一个新的虚拟地址new_vaddr,该新地址能够访问到vaddr所在pte。
 * 参数:
 *      vaddr          虚拟地址,分为三个部分,0000_0000_00|0000_0000_00|0000_0000_0000
 *                                            pde_num      pte_num      p_add
 * 说明:
 *      这里面临一个问题:如何通过虚拟地址访问到页目录表本身?
 *      1. MMU会把寄存器cr3的地址+pde_num*4获得pde地址。
 *      2. 再从pde中取出页表地址+pte_num*4获得pte地址。
 *      3. 再从pde中取出普通页地址+p_add获得最终地址。
 * 
 *      (1)pte_ptr和pde_ptr这两个函数返回的是能够访问到vaddr所在pte及pde的新虚拟地址new_vaddr,
 *      new_vaddr经过处理器处理32位地址的三个步骤,最终指向vaddr的pte及pde所在的物理地址。
 *      因此,这两个函数的功能等同于:给我一个新的虚拟地址new_vaddr,让它指向vaddr所在的pde及pte,
 *      也就是让new_vaddr指向pde及pte所在的物理地址。
 *      (2)这两个函数中的参数vaddr,可以是已经分配、在页表中存在的,也可以是尚未分配,
 *      目前页表中不存在的虚拟地址,pte_ptr和pde_ptr这两个函数只是根据虚拟地址转换的规则计
 *      算出vaddr对应的pte及pde的虚拟地址,与vaddr所在的pte及pde是否存在无关。
 *      
 *      处理器第一次当成页目录表处理,第二次当成页表处理,第三次当成普通页处理
 * 
 *      分三步:
 *          第一步,CPU将页目录表当成页目录表
 *          第二步,CPU将页目录表当成页表
 *          第三步,CPU将页目录表当成页(也就是页帧)
 */
uint31_t *pte_ptr(uint32_t vaddr)
{
    // 0xffc00000 = 1111 1111 1100 0000 0000 0000 0000 0000 
    // 1111_1111_11b=0x3ff=1023 
    uint32_t *pte = (uint32_t *)(0xffc00000  // new_vaddr的页目录项下标,只是为了获得页目录表的物理地址
                    + ((vaddr & 0xffc00000) >> 10)  // 真正的页目录项下标,在cpu眼里是页表项下标
                    + PTE_IDX(vaddr) * 4);  // 真正页表项下标,在cpu眼里是普通页中的地址
    
    // 得到一个新的地址,新地址高10位必定是0xffc;中间10位是vaddr的高10位;低12位中的高10位是vaddr的中间10位。
    return pte;
}

/** 
 * 功能:
 *      根据vaddr来构造一个新的32位地址new_vaddr。
 * 参数:
 *      vaddr                   虚拟地址                
 * 说明:
 *      new_vaddr为虚拟地址vaddr对应的pde的指针得到虚拟地址vaddr所在pde的指针,也就
 *      是返回能够访问该pde的虚拟地址。
 */
uint32_t *pde_ptr(uint32_t vaddr)
{
    /* 0xfffff是用来访问到页表本身所在的地址,如果new_vaddr的低12位为0,则访问到的是页表的起始虚拟地址 */
    uint32_t *pde = (uint32_t *)((0xfffff000) + PDE_IDX(vaddr) * 4);
    return pde;
}

MMU机制

页目录表物理地址已经存放在cr3寄存器,只要开启了分页机制,任何地址在CPU眼里都要cr3+pde_num*4找到页目录项,从页目录项中取出页表的地址;再用页表地址+pte_num*4找到页表项,再从页表项中找到页框地址;再用p_add在该页框中定位具体地址。

示例

假如vaddr = 0x7ffdac7f = (0111 1111 11)(11 1101 1010) 1100 0111 1111
             pde_num   pte_num   p_add

正常虚拟地址访问

请添加图片描述

  • 第一步:
    • 1:MMU从cr3中取出页目录表的物理地址。
    • 2:MMU用cr3中的页目录表的物理地址+511*4定位到页目录项的物理地址。
  • 第二步:
    • 1:MMU从下标为511的页目录项中取出页表的物理地址。
    • 2:MMU用页表的物理地址+986*4,定位到对应的页表项的物理地址。
  • 第三步:
    • 1:MMU从下标为986的页表项中取出普通页框的物理地址。
    • 2:MMU用普通页框的物理地址+ 3199,从而定位到了真正的物理地址。

构造虚拟地址vaddr对应的pte指针

要构造一个新的虚拟地址new_vaddr,该新地址要能够访问到vaddr所在pte。也就是得到虚拟地址 vaddr 对应的 pte 指针。

将vaddr作为参数,调用pte_ptr()得到:

*pte = (uint32_t *)(0xffc00000 + ((0x7ffdac7f & 0xffc00000) >> 10) 
                    + ((0x7ffdac7f & 0x003ff000) >> 12) * 4); 

0x7ffdac7f = 0111 1111 1111 1101 1010 1100 0111 1111
0xffc00000 = 1111 1111 1100 0000 0000 0000 0000 0000

(0x7ffdac7f & 0xffc00000) = 0x7fc00000 = 0111 1111 1100 0000 0000 0000 0000 0000
= (uint32_t *)(0xffc00000 + (0x7fc00000 >> 10) + ((0x7ffdac7f & 0x003ff000) >> 12) * 4)

0x7fc00000 >> 10 = 0111 1111 1100 0000 0000 00 = 0x1ff000
= (uint32_t *)(0xffc00000 + 0x1ff000 + ((0x7ffdac7f & 0x003ff000) >> 12) * 4)

(0x7ffdac7f & 0x003ff000) = 0x3DA000 = 0011 1101 1010 0000 0000 0000
= (uint32_t *)(0xffc00000 + 0x1ff000 + (0x3DA000 >> 12) * 4)

0x3DA000 >> 12 = 0011 1101 1010 00 = 0x3da
0x3da * 4 = 0xf68

= (uint32_t *)(0xffc00000 + 0x1ff000 + 0xf68)

0xffc00000 = 1111 1111 1100 0000 0000 0000 0000 0000
0x1ff000 = 0000 0000 0001 1111 1111 0000 0000 0000
0xf68 = 0000 0000 0000 0000 0000 1111 0110 1000

0xffc00000 + 0x1ff000 + 0xf68 = 0xFFDFFF68
= (1111 1111 11)(01 1111 1111) (1111 0110 1000)
pde_num    pte_num    p_add

= (uint32_t *)(0xFFDFFF68)

因此得到:

  • pde_num = 0x3ff
  • pte_num = 0x1ff
  • p_add = 0xf68

访问vaddr对应的pte

由于页目录表中的最后一个页目录项(也就是下标为1023的页目录项)中存储的是页目录表的物理地址,所以只要给出的虚拟地址new_vaddr的高十位是0x3ff,那么,原本new_vaddr的中间10位访问的是别的页表中的页表项就不会发生,相反,new_vaddr的中间10位(原本作为页表项的下标)仍然访问的页目录项的物理地址。new_vaddr的低12位访问的才是别的页表的页表项。

  • 第一步:
    • 1:MMU从cr3中取出页目录表的物理地址。
    • 2:MMU用cr3中的页目录表的物理地址+1023*4定位到页目录项的物理地址。
  • 第二步:
    • 1:MMU从下标为1023的页目录项中再次取出页目录表的物理地址。
    • 2:MMU用下标为1023的页目录项中存储的页目录表的物理地址+511*4,再次定位到对应页目录项的物理地址。
  • 第三步:
    • 1:MMU从下标为511的页目录项中取出页表的物理地址。
    • 2:MMU用下标为511的页目录项中存储的页表的物理地址+3944,从而定位到vaddr对应的pte的物理地址。

总结

当正常访问vaddr时,页目录表访问一次,页表访问一次,普通页框访问一次。
当访问vaddr对应的pte时,页目录表访问次,页表访问一次。

更多推荐

【LeetCode每日一题合集】2023.9.11-2023.9.17(⭐反悔贪心&拓扑排序&Floyd)

文章目录630.课程表III解法——反悔贪心⭐⭐⭐⭐⭐1462.课程表IV⭐解法1——拓扑排序预处理解法2——Floyd算法判断是否存在路径2596.检查骑士巡视方案(方向模拟)1222.可以攻击国王的皇后(方向模拟)LCP50.宝石补给(简单模拟)198.打家劫舍(经典线性DP)213.打家劫舍II(循环打家劫舍)代

成功入选 2023 谷歌出海创业加速器,Tapdata 乘势远航

9月6日,2023Google开发者大会的收官之行于上海拉开帷幕。会间,官方正式公布了最新一期谷歌出海创业加速器入营名单,Tapdata成功入选:长期以来,Google开发者大会为开发者提供了一个独一无二的学习和合作机会,这是一场汇聚全球创新者的聚会,鼓励创新思维。从中能够深入了解最新的技术趋势、工具和平台,与行业内顶

Linux学习-HIS系统部署(2)

GitLab服务器搭建使用rpm包本地部署GitLab服务器#确认GitLab主机硬件配置,注GitLab服务器至少要有4G内存,关闭SWAP分区[root@gitlab~]#free-mtotalusedfreesharedbuff/cacheavailableMem:40211163786161183720Swap

【文末送书】计算机网络编程 | epoll详解

欢迎关注博主Mindtechnist或加入【智能科技社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。关注公粽号《机器和智能》回复关键词“python项目实战”即可获取美哆商城视频资源

【无公网IP】安装Wnmp并结合内网穿透,实现灵活可靠的外网访问内网服务!

文章目录前言1.Wnmp下载安装2.Wnmp设置3.安装cpolar内网穿透3.1注册账号3.2下载cpolar客户端3.3登录cpolarwebui管理界面3.4创建公网地址4.固定公网地址访问前言WNMP是Windows系统下的绿色Nginx+Mysql+PHP环境集成套件包,安装完成后即可得到一个Nginx+My

erlang练习题(二)

题目一替换元组或列表中指定位置的元素,新元素作为参数和列表或元组一起传入函数内解答replaceIdx(List,Index,Val)->replaceIdx(List,Index,Val,1,[]).replaceIdx([],_,_,_,Acc)->lists:reverse(Acc);%%到达替换位置的处理rep

期权如何交易?期权如何做模拟交易?

买卖期权的第一步就是要有期权账户,国内的期权品种有商品期权和ETF期权以及股指期权,每种的开户方式和要求都不同,下文为大家介绍期权如何交易?期权如何做模拟交易?一、期权交易需要开立一个期权账户,可以交易期权的平台有证券/期货公司、三方的期权平台。期权交易从方向上可以分为看涨期权和看跌期权,对于这两种期权在交易上又都可以

排序算法:归并排序(递归和非递归)

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关排序算法的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!C语言专栏:C语言:从入门到精通数据结构专栏:数据结构个人主页:stackY、​目录1.归并排序1.1递归版本代码演示:1.2非递归版本代码演示:测试排序:改正代码1:测试排序:

慢查询SQL如何优化

一.什么是慢SQL?慢SQL指的是Mysql中执行比较慢的SQL,排查慢SQL最常用的方法是通过慢查询日志来查找慢SQL。Mysql的慢查询日志是Mysql提供的一种日志记录,它用来记录Mysql中响应时间超过long_query_time值的sql,long_query_time的默认时间为10s.二.查看慢SQL是

工控机通过Profinet转Modbus RTU网关连接变频器与电机通讯案例

在工业自动化系统中,工控机扮演着重要的角色,它是数据采集、处理和控制的中心。工控机通过Profinet转ModbusRTU网关连接变频器与电机通讯,为工业自动化系统中的设备之间的通信提供了解决方案。工控机通过Profinet转ModbusRTU网关的方式,将Profinet协议转换为ModbusRTU协议,从而实现了工

使用API接口获取商品数据:从入门到实践

一、引言随着电子商务的飞速发展,许多电商平台提供了API接口,允许开发者获取商品数据,以创建各种创新的应用。本文将详细介绍如何使用API接口获取商品数据,并通过代码示例进行演示。二、API接口概述1.API接口定义API(ApplicationProgrammingInterface)接口是一种协议,允许不同的应用程序

热文推荐