初学者学习Linux系统地址转换时,如果只是学习理论,又或者研读代码,那可能感觉比较枯燥。此时如果可以利用某些工具实际观察一下地址转换的过程,那可能会给枯燥的内核学习带来些微的乐趣。crash tool是一款内核调试工具,常用来分析内核崩溃问题。我们可以手动触发内核崩溃,然后借用该工具来分析当时系统的运行情况,当然也包括内存的运行情况。

本文基于ARMv8 AArch64 (简称ARM64)架构,Linux 4.14内核来讲述。首先回顾一下内存访问的相关知识点。

1、ARM内存访问的硬件架构

ARM有MMU部件,现代操作系统一般都会启用MMU来访问内存。启用MMU之后,多进程就有了可能,每个进程可以维护各自私有的虚拟地址空间,无需关心物理内存布局。

2、虚拟地址空间到物理地址空间的映射

虚拟地址到物理地址的映射是通过查表的机制来实现,下图是一种典型的地址映射布局。内核空间地址的高16位(bit[63:48])为全1,其转换表的基地址存放在TTBR1_EL1寄存器中;用户空间地址的高16位(bit[63:48])为全0,其转换表的基地址存放在TTBR0_EL0寄存器中。

除了高16位外,剩下的48位,也并不全用作虚拟地址空间,使用多少位是可以配置的,比如Linux系统的内核一般做如下配置,表示有39位虚拟地址空间。

CONFIG_ARM64_VA_BITS=39

39位虚拟地址空间,内核空间范围为0xFFFFFF80_00000000 ~ 0xFFFFFFFF_FFFFFFFF,用户空间范围为0x00000000_00000000 ~ 0x0000007F_FFFFFFFF。

3、转换表的格式

转换表有4个级别,level 0 ~ level 3。

如下图所示,当bit[1:0]为2b'11时,表示该表项是Table descriptor,指向下一级转换表的地址。而当 bit[1:0]为2b'01时,表示Block entry,不指向下一级转换表,而是直接输出block address。当表项处于level 3时,即使bit[1:0]为2b'11,也不再指向下一级转换表,而是输出block address。

4、地址转换的过程

如下图所示,以39位虚拟地址为例,来了解地址转换过程。图片是取自ARMv8官方文档,建议放大了看。

内存中维护着三个转换表,从虚拟地址转换成物理地址,要经过三次查表的过程。

39位虚拟地址被分成了4部分,作用如下:

  • bit[38:30] —— 索引第一级表中的表项

  • bit[29:21] —— 索引第二级表中的表项

  • bit[20:12] —— 索引第三级表中的表项

  • bit[11:0] —— 页内偏移

第一步,TTBR寄存器中存放了第一级转换表的起始地址,虚拟地址的bit[38:30]的值表示要查找转换表中的第几项,这个值左移三位(64位地址,每个表项占用8字节),再加上第一级转换表的地址,就是该表项的地址。该表项存放的是第二级转换表的起始地址。

第二步,用第二级转换表的起始地址,再结合虚拟地址的bit[29:21],与第一步计算方法类似,可以计算出第二级表项的地址。第二级表项中存放了第三级转换表的起始地址。

第三步,用第三级转换表的起始地址,再结合虚拟地址的bit[20:12],与第一步计算方法类似,可以计算出第三级表项的地址。第三级表项存放的是最终的页面描述符,有页面的物理地址信息,用这个地址再加上虚拟地址的bit[11:0],就是该虚拟地址对应的物理地址。

5、Linux内核中的关键数据结构

mm_struct结构体是内存描述符,内核用它来维护一个进程的地址空间的所有信息。这个结构体中包含了一个重要成员:pgd指针,pgd的名称是页全局目录,指向的是第一级转换表的的起始地址。

每个进程的task_struct结构体中,都包含了内存描述符。

init_mm全局变量,是内核本身的内存描述符。

有了以上知识点做支撑后,就可以用crash tool来验证自己的理解了。

6、用crash tool观察地址转换

手动触发内核崩溃的shell指令是:

echo "c" > /proc/sysrq-trigger

crash tool使用示例如下:

crash_arm64 vmlinux dumpfile -m phys_offset=0x80000000

进入crash tool环境后,我们选择1号进程,也就是init进程来分析。首先用bt命令看一下1号进程当前的调用栈。

我们选择该进程TASK的地址和SP寄存器指向的地址来进行实际分析。TASK的高位地址全为1,为内核空间的虚拟地址;SP地址高位全为0,为用户空间的地址。

先分析用户空间的虚拟地址 0000007feeac5cb0,将它分解如下:

bit[38:30]    0x1ff ,左移三位是 0xff8

bit[29:21]    0x175,左移三位是 0xba8

bit[20:12]    0x0c5,左移三位是 0x628

bit[11:0]      0xcb0

怎么找到它对应的物理地址呢?首先要找到第一级转换表所在的位置,也就是pgd的位置。我们在前面提到过,进程的内存描述中有pgd指针。所以我们可以先通过crash tool的task命令查看内存描述符的地址,再通过struct命令查看内存描述符中pgd指针的值。

知道了第一级转换表所在的位置,结合虚拟地址的bit[38:30],就可以算出虚拟地址在第一级转换表中所对应的表项位置:0xffffffc01bf60000 + 0xff8 = 0xffffffc01bf60ff8。用rd命令可以读取这个表项的值,这个值里面含有第二级转换表的起始地址信息。

读出的值是99c00003,bit[1:0]=2b'11,表示该表项类型为Table descriptor,指向下一级(第二级)转换表,起始地址是99c00000。结合虚拟地址的bit[29:21],可以算出虚拟地址在第二级转换表中的表项地址:0x99c00000 + 0xba8 = 0x99c00ba8。该地址是物理地址,需要用rd -p命令读取其值,这个值里面含有第三级转换表的起始地址信息。

读出的值是99c04003,表项类型也为Table descriptor。结合虚拟地址的bit[20:12],可以算出虚拟地址在第三级转换表中对应的表项地址:0x99c04000 + 0x628 = 0x99c04628。三级表项存放的是页面描述符信息,不再指向下一级转换表。

从0x99c04628地址读出的值是00e800008594bf53,结合第4节的地址转换过程图,bit[47:12]存放的是地址信息,与虚拟地址的bit[11:0](页内偏移)结合后,就构成了实际的物理地址:0x8594b000 + 0xcb0 = 0x8594bcb0。这个地址就是0x0000007feeac5cb0所对应的物理地址。

上述过程我们手动计算出了物理地址,那如何知道有没有算对呢?其实crash tool提供了vtop这个命令,可以直接显示虚拟地址到物理地址的转换结果,如下图所示。可以看到vtop命令的结果和我们手动计算的结果一致,说明我们对转换过程的理解是正确的。

再来分析内核空间的虚拟地址 ffffffc01bf60000,将它分解如下:

bit[38:30]    0x100,左移三位是 0x800

bit[29:21]    0x0df,左移三位是 0x6f8

bit[20:12]    0x160,左移三位是 0xb00

bit[11:0]     0x000

首先我们要知道内核空间的 pgd,结合前面第4节讲的Linux关键数据结构,内核空间的 pgd 是保存在 init_mm 变量中,用p命令打印变量结果,可以看到pgd指针的值。

每一级表项的计算过程与用户空间例子类似,可以得到如下观察结果:

注意,第二级表项的值是00f800008be00f11,bit[1:0]=2b'01,表示Block entry,不再指向下一级转换表,而是指示物理地址,地址值为9be00000。

两级转换表对应的是虚拟地址的bit[38:30]和bit[29:21],又没有第三级转换表,因此剩下的bit[20:0]都是页内偏移。所以计算出最终物理地址为:0x9be00000 + 0x160000 = 0x9bf60000。也就是说, ffffffc01bf60000的物理地址是9bf60000。

用vtop命令验证,和手动计算的结果一致。

------ END ------

作者:bigfish99

博客:https://www.cnblogs.com/bigfish0506/

公众号:大鱼嵌入式

用crash tool观察ARM64 Linux地址转换的更多相关文章

  1. Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)

    IPv4套接字地址结构 struct sockaddr_in { uint8_t sinlen;(4个字节) sa_family_t sin_family;(4个字节) in_port_t sin_p ...

  2. 操作系统-存储管理(5)IA-32/Linux的地址转换

    IA-32/Linux按字节编址:在保护模式下,IA-32采用段页式虚拟存储管理方式,存储地址采用逻辑地址.线性地址和物理地址来进行描述. 逻辑地址由48位组成,包含16位段选择符(高13位为段表项的 ...

  3. ARM中MMU地址转换理解

    首先,我们要分清ARM CPU上的三个地址:虚拟地址(VA,Virtual Address).变换后的虚拟地址(MVA,Modified Virtual Address).物理地址(PA,Physic ...

  4. Linux网络地址转换分析

    Linux网络地址转换分析 地址转换用来改变源/目的端口,是netfilter的一部分,也是通过hook点上注册相应的结构来工作. Nat注册的hook点和conntrack相同,只是优先级不同,数据 ...

  5. OpenRisc-31-关于在设计具有DMA功能的ipcore时的虚实地址转换问题的分析与解决

    引言 之前,我们在讨论基于ORPSoC的ipcore设计时提到过DMA的问题,当时我们实现DMA的功能时,访问的是local memory,并没有使用主存(即外部的SDRAM),使用的是本地的一块存储 ...

  6. UNIX网络编程——socket概述和字节序、地址转换函数

    一.什么是socket socket可以看成是用户进程与内核网络协议栈的编程接口.socket不仅可以用于本机的进程间通信,还可以用于网络上不同主机的进程间通信. socket API是一层抽象的网络 ...

  7. 套接字编程相关函数(1:套接字地址结构、字节序转换、IP地址转换)

    1. 套接字地址结构 1.1 IPv4套接字地址结构 IPv4套接字地址结构通常也称为“网际套接字地址结构”,它以sockaddr_in命名,定义在<netinet/in.h>头文件中.下 ...

  8. iptables实现网络防火墙及地址转换

    iptables主机防火墙功能及常用命令 FSM:Finite State Machine 有限状态机 客户端:closed -->syn_sent -->established --&g ...

  9. Memory Translation and Segmentation.内存地址转换与分段

    原文标题:Memory Translation and Segmentation 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精 ...

随机推荐

  1. 学习Walle(一)

    一.概述 Walle 一个web部署系统工具,配置简单.功能完善.界面流畅.开箱即用!支持git.svn版本管理,支持各种web代码发布,PHP,Python,JAVA等代码的发布.回滚,可以通过we ...

  2. Spark学习摘记 —— Pair RDD行动操作API归纳

    本文参考 参考<Spark快速大数据分析>动物书中的第四章"键值对操作",本篇是对RDD转化操作和行动操作API归纳的最后一篇 RDD转化操作API归纳:https:/ ...

  3. webstrom Debug 调试vue项目

    第一种,使用vue插件 下载插件:https://chrome.google.com/web... 这样直接run一个vue项目,你就会看见插件标亮了 打开调试模式,你就会看见最后有个vue标记,打开 ...

  4. E-R图转换为关系模型

    E-R模型如何转换成关系模型,这里我们分成三种情况进行讲解,分别是一对一,一对多和多对多. 1.一对一的情况: 有两种方法解决这个问题.第一个方法:可以单独对应一个关系模式,由各实体的主码构成关系模式 ...

  5. EMS创建独立新用户并分配邮箱

    创建新用户"王春海"并分配邮箱. 以Exchange管理员身份登录EMS控制台.在PowerShell命令行提示符下,键入如下命令: [PS] C:\Windows\system3 ...

  6. 自己对kmp算法的理解,借由 28. 实现 strStr() 为例

    做题思路 or 感想 : 就借由这道题来理解一下kmp算法吧 kmp算法的操作过程我觉得有句话很合适 :KMP 算法永不回退 目标字符串 的指针 i,不走回头路(不会重复扫描 目标字符串),而是借助 ...

  7. IDEA小技巧:Debug条件断点

    今天给大家分享一个IDEA调试过程中的一个小技巧. 先来说说场景,你有没有碰到类似的情况,一个循环结构里,中间某一个情况可能会出错.比如下面的代码结果中,可能执行到第27次的时候,会出现问题. for ...

  8. vue3 操作修改数据

    vue2.x改变数据: <template>   <div class="v2">     这是数据展示:     <div v-for=" ...

  9. “浪潮杯”第九届山东省ACM大学生程序设计竞赛 F: Four-tuples容斥定理

    题目 F : Four-tuples  输入 1 1 1 2 2 3 3 4 4 输出 1 题意 给l1, r1, l2, r2, l3, r3,  l4, r4​ , 八个数据, 要求输出在区间[l ...

  10. SpringMVC初学习

    # SpringMVC快速入门 @[TOC](文章目录) --- # 前言 `提示:这里可以添加本文要记录的大概内容:` 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习 ...