3

根据一些教程,我们将在 bootlaoder 开始时禁用 MMU 和 I/D-Caches。如果我理解正确,它旨在直接在程序中使用物理地址,所以如果我错了,请纠正我。谢谢!

其次,我们这样做是为了禁用 MMU 和缓存:

mrc P15, 0, R0, C1, C0, 0

bic R0, R0, #0x00002300 @ 清除位 13, 9:8

bic R0, R0, #0x00000087 @ 清除位 7, 2:0

orr R0, R0, #0x00000002 @ 设置位 2 (A) 对齐

orr R0, R0, #0x00001000 @ 设置位 12 (I) I-Cache

mcr P15, 0, R0, C1, C0, 0

D-Cache、MMU 和数据地址对齐故障检查已被清除位 2:0 禁用,但为什么我们在下面的仪器中立即启用位 2?确保这种操作是有效的?

最后一个问题是为什么 D-cache 被禁用但 I-caches 能够?加快仪器进程?

4

2 回答 2

10

最后一个问题是为什么 D-cache 被禁用但 I-caches 能够?加快仪器进程?

MMU 具有确定哪些内存区域可缓存或不可缓存的设置。如果您没有打开 mmu,但打开了数据缓存(如果可能),那么您无法安全地与外围设备通信。例如,如果您读取 uart 状态寄存器,该寄存器就像任何其他数据操作一样通过缓存,则无论该状态是什么,都将保留在缓存中以供后续读取,直到该缓存行被逐出并且您再获得一次实际镜头登记。例如,假设您有一些代码轮询 uart 状态寄存器以等待 rx 缓冲区中的字符。如果第一次读取显示没有字符,则该状态进入缓存,您将永远留在循环中,因为您将永远无法再次与状态寄存器交谈,您将只获得寄存器的缓存副本。如果那里有一个字符,那么该状态也会被缓存,您读取 rx 寄存器,并且可能做一些事情,如果当您再次返回时,如果该状态尚未从数据缓存中清除,那么您将获得陈旧状态,它显示有一个字符,您读取的 rx 缓冲区可能会或可能不会被缓存,因此您可能会在缓存中获得陈旧值,您可能会获得陈旧值或外围设备在您读取时执行的任何操作并且没有新值,或者您可能获得一个新值,但在这些情况下您没有获得的是对外围设备的正确访问。当 mmu 打开时,您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。也许做点什么,如果当你再次回来时,如果状态没有从数据缓存中清除,那么你会得到陈旧的状态,表明有一个字符,你的 rx 缓冲区读取可能会也可能不会被缓存,所以你可能会得到缓存中的陈旧值,您可能会获得陈旧值或外围设备在您读取并且没有新值时执行的任何操作,或者您可能会获得新值,但在这些情况下您没有得到的是对外围设备的正确访问。当 mmu 打开时,您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。也许做点什么,如果当你再次回来时,如果状态没有从数据缓存中清除,那么你会得到陈旧的状态,表明有一个字符,你的 rx 缓冲区读取可能会也可能不会被缓存,所以你可能会得到缓存中的陈旧值,您可能会获得陈旧值或外围设备在您读取并且没有新值时执行的任何操作,或者您可能会获得新值,但在这些情况下您没有得到的是对外围设备的正确访问。当 mmu 打开时,您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。您读取的 rx 缓冲区可能会或可能不会被缓存,因此您可能会在缓存中获得陈旧的值,您可能会获得陈旧的值或外围设备在您读取时执行的任何操作并且没有新值,或者您可能会获得新值,但是在这些情况下您无法正确访问外围设备。当 mmu 打开时,您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。您读取的 rx 缓冲区可能会或可能不会被缓存,因此您可能会在缓存中获得陈旧的值,您可能会获得陈旧的值或外围设备在您读取时执行的任何操作并且没有新值,或者您可能会获得新值,但是在这些情况下您无法正确访问外围设备。当 mmu 打开时,您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。您使用 mmu 将该外围设备使用的地址空间标记为不可(数据)缓存,并且您没有这个问题。关闭 mmu 后,您需要关闭 arm 系统的数据缓存。

保持 I-cache 处于打开状态是可以的,因为指令只获取读取指令......好吧,对于一个可以的裸机应用程序来说,它会有所帮助,例如,如果您使用的闪存可能会产生读取干扰(spi 或 i2c 闪存) . 问题是这个应用程序是一个引导加载程序,所以你必须格外小心。例如,您的引导加载程序在地址 0x8000 有一些代码至少运行一次,然后您选择将其用作引导加载程序,引导加载程序可能位于地址 0x10000000,允许您在 0x8000 加载新程序,此加载使用数据访问,因此它不会通过指令缓存。因此,指令缓存有可能包含您上次在 0x8000 区域时的部分或全部代码,当你跳转到 0x8000 处的引导加载代码时,你会从缓存中获取旧程序,或者是旧程序和新程序的令人讨厌的混合,用于缓存和未缓存的部分。因此,如果您的引导加载程序允许 i-cache 处于打开状态,则您需要在分支到引导加载代码之前使缓存无效。

最后,如果您或使用此引导加载程序的任何人想要使用 jtag,那么您会遇到同样的问题,但更糟糕的是,当您告诉 jtag 调试器时,会使用不通过 i-cache 的数据周期将新程序写入 ram然后运行新程序,您将获得 1)仅新程序,2)新程序和缓存中的旧程序片段的混合 3)缓存中的旧程序。

因此,没有 mmu 的 d-cache 很糟糕,因为内存、外围设备等中没有的东西。i-cache 是一种使用风险自负的事情,除了 jtag 用于调试的时间之外,您可以减轻这种风险.

如果您有疑虑或已确认(外部)闪存中有读取干扰,那么我建议打开 i-cache,使用紧密循环将您的应用程序复制到 ram,分支到 ram 副本并在那里运行,关闭i-cache(或使用风险自负)并且不要再次触摸闪存,当然不会对小区域进行大量读取访问。像命令行解析器那样紧凑的 uart 轮询循环是一个非常适合读取干扰的好地方。

于 2014-01-22T01:24:31.040 回答
2

您没有指定您在哪个 ARM 上工作。不同的 ARM 的功能可能会有所不同(ARM9 和 ARM Cortex A15 之间存在巨大差距)。

在给定的代码中,位 2 被清除然后设置,但这并不重要,因为这些更改是在 R0 中完成的。在写入 CP15 寄存器(由指令完成)之前,ARM 行为没有变化mcr P15, 0, R0, C1, C0, 0

关于 d-cache/i-cache 启用,这只是一个选择问题,没有要求。在我工作的产品上,引导加载程序启用 L1 I-cache、D-cache、L2 缓存和 MMU(它会在启动 Linux 之前禁用所有这些东西)。如果您在引导加载程序中使用缓存和 MMU,请务必遵循有关缓存失效和内存屏障的 ARM 文档(根据您的实际 ARM 内核)。

于 2014-01-21T18:46:10.130 回答