Linux内核ARM转换表基础(TTB0和TTB1)

问题描述 投票:7回答:4

针对ARMv7编译的Linux内核2.6.34.3(Cortex-a8)

我查看了内核代码,看起来Linux内核为TTB1(转换表基础)上的内核地址空间(一切都超过0xC0000000)和ttb0上的用户进程(0xC0000000下的所有内容)设置了硬件页表,进程上下文切换。它是否正确?我仍然很困惑MMU如何知道翻译的哪个ttb?

我读到TTBCR(转换表基本控制寄存器)确定在找不到MVA时要走哪个ttb寄存器,但是寄存器总是读为0,这意味着始终在ARM体系结构参考手册中使用TTBR0。怎么可能?任何人都可以向我解释Linux内核如何使用这两个ttbs?

我读了ttb如何从这个站点https://www.cs.rutgers.edu/~pxk/416/notes/10-paging.html工作,但我仍然不明白内核如何使用这两个ttbs

(仔细检查了内核代码,由于某种原因ttb0和ttb1都已设置,但似乎从未使用过ttb1,我将TTB1寄存器设置为0并且Linux内核继续照常运行)

linux-kernel operating-system arm
4个回答
14
投票

TTBR寄存器一起用于确定完整32位或40位地址空间的寻址。哪个寄存器用于通过TTBCR中的tXsz位控制的地址范围。对应于TTBR0的t0sz和TTBR1的t1sz有一个条目。

每个TTBRx寄存器寻址的页表是独立的,但您通常会发现大多数Linux实现只使用TTBR0。 Linux希望能够使用3G / 1G地址空间分区方案,ARM不支持该方案。如果查看“ARMv7体系结构参考手册”的B3-1345页,您会看到t0sz和t1sz的值分别决定了TTBR0和TTBR1支持的地址范围。为了增加对迷失方向的困惑,甚至可能有脱离的地址空间,其中TTBR0和TTBR1支持不连续的范围,从而导致系统地址空间中的漏洞。美好时光!

但是,为了回答您的主要问题,ARM建议使用TTBR0将偏移量存储到USER进程使用的页表中,并使用TTBR1将偏移量存储到KERNEL使用的页表中。我还没有看到实际执行此操作的单个实现。在所有情况下都使用TTBR0,TTBR1包含L1表的副本。

那么这是如何工作的呢? TTBR的值存储为过程状态的一部分,并且每次切换过程时都会简单地恢复。这就是它的工作方式。最初,TTBR1将为内核表保持一个常量值,永远不会被替换或换出,而每次在进程之间进行上下文切换时,TTBR0都会被更改。显然,ARM的大多数Linux实现都决定基本上消除TTBR1的使用并坚持使用TTBR0来实现一切。

如果你想在你的设备上测试这个理论,试试whacking TTBR1并注意什么都没发生。然后尝试敲击TTBR0并观察系统崩溃。我还没有遇到一个没有产生完全相同结果的实例。简而言之,TTBR1对于Linux来说是无用的,而且TTBR0几乎只用于交换。

现在,一旦你获得LPAE支持,抛弃所有这些并重新开始。这是一个实现,你将开始看到t0sz和t1sz的值不是零,因此也是N.


1
投票

我对ARM体系结构知之甚少,但是从我在附带的链接中读到的内容,我想Linux实现了它的虚拟内存管理:

虚拟地址的高位确定使用哪一个。表的基数存储在两个基址寄存器(TTBR0或TTBR1)中的一个中,具体取决于虚拟地址的最高n位是否为0(使用TTBR0)(使用TTBR1)。 n的值由转换表基本控制寄存器(TTBCR)定义。

寄存器TTBCR告诉我们将从TTBR0TTBR1指向的页表中翻译哪些地址。如果TTBCR包含0xc000000,那么从00xbfffffff的任何地址都由TTBR0指向的页面表翻译,而0xc00000000xffffffff的任何地址都由TTBR1指向的页面表翻译。这与用户进程的3GB内存分配相匹配,内核为1GB。

这样就可以实现一种设计,其中操作系统和内存映射I / O位于地址空间的上部,并由TTBR1中的页表管理,用户进程位于内存的下半部分,由TTB0中的页表。在上下文切换时,操作系统必须将TTBR0更改为指向新进程的第一级表。 TTBR1仍将包含操作系统和内存映射I / O的内存映射。

因此,TTBR1的值永远不会改变,因为你希望内核被永久映射(想想当引发中断时会发生什么)。另一方面,TTBR0在每个进程切换时都被修改,它包含当前进程的页表。


1
投票

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/Bihgfcgf.html

对于ARM5及更低版本,TTB表的大小和对齐方式是固定的(至16k)。每个1级条目代表1MB。表项是32位(16k * 1M /(32位/ 8)= 4GB)。 TTBCR控制TTBR0表格大小。从上面的URL,

选择使用哪个转换表基址寄存器 翻译表基址寄存器选择如下: 如果N = 0,则始终使用转换表基址寄存器0。 - 这是重置时的默认情况。它向后兼容ARMv5或更早的处理器。 如果N大于0,则: - 如果虚拟地址的位[31:32-N]都为0,则使用转换表基址寄存器0,否则使用转换表基址寄存器1。

因此TTBR0的大小也设置了内存分割。为一个 传统 Linux的 3G / 1G 1G / 3G,应选择值2。 4kB表== 1G内存==位31..30为零。对于值6,表是256byte == 64MB ==位31..26是零。

在Linux用语中,这些是页面全局条目(这将拆分此页面全局目录)。条目可以指向另一个表或只是一个1MB的段。下一个表条目是页面中间Linux目录,然后是最终页表条目。我认为ARM中没有使用页面中间条目。

MMU硬件每次都不会走路。有一个TLB(翻译旁观缓冲区)。它就像MMU表的缓存。当操作系统更新这些表时,必须刷新TLB或处理器将使用陈旧的条目。类似地,ARM缓存是虚拟标记的,因此更改映射也可能意味着必须刷新缓存。出于这些原因,您永远不想在上下文切换上更改内容。共享库文本(比如libc.so)在上下文切换中应该是相同的。希望每个进程都有libc.so映射到同一个虚拟地址。这样做有很大的好处;较低的内存使用率和良好的I-cache使用率。

域和PID寄存器以及管理员/用户模式也可以控制存储器访问。这些是可以在上下文切换上切换的单个寄存器。

有关ARMV5上PID和域使用的信息,请参阅http://lwn.net/images/conf/rtlws11/papers/proc/p01.pdf。当前的Linux源代码与本文描述的完全不同。完全有可能Linux不需要使用此机制并将TTBCR设置为零,以便ARM子架构的VM代码类似。

编辑:我不相信TTBCR功能可用于实现3G / 1G分割。我认为Rutger的页面一般是在讨论TTBCR,而不是在Linux环境中。此外,至少2.6.38 Linux使用域或DACR,但不使用pid或fcse,因为它支持有限数量的进程。

http://lwn.net/Articles/106177/ - 也在Rutgers页面上引用。


0
投票

TTBR0保存转换表0的基址,以及它占用的内存信息。

这是从Hyp模式以外的模式进行存储器访问的第1阶段转换的转换表之一

© www.soinside.com 2019 - 2024. All rights reserved.