例如,假设我有一个PageTable值并将其物理地址注册到 CR3 寄存器中。
#![no_std]
use {
spinning_top::{const_spinlock, Spinlock},
x86_64::structures::paging::PageTable,
};
// The physical address of `PML4` is registered with CR3 register.
static PML4: Spinlock<PageTable> = const_spinlock(PageTable::new());
Run Code Online (Sandbox Code Playgroud)
PML4如果页面被访问,处理器会更改条目的已访问位。恐怕优化后的代码可能会使用存储在 CPU 寄存器或堆栈之一中的缓存值而不是内存中的实际值,从而导致使用该位的旧值。
在这种情况下,影响应该很小,我不在乎 Accessed 位。但是,一般来说,拥有一个处理器可能会意外更改的值(如 MMIO 和 DMA 缓冲区)或对此类值的引用是否安全?或者我应该每次通过带有read_volatile和的原始指针执行读-修改-写循环write_volatile?
由于您特别询问了“对此类值的引用”:如果您有&T, 并且在引用处于活动状态时T因任何原因发生变异,则程序将显示未定义的行为。
据我所知,Reference 中的文档在这一点上还没有最终确定,但原理是明确的。来自以下文档UnsafeCell:
如果您有引用 &T,那么通常在 Rust 中,编译器会根据 &T 指向不可变数据的知识执行优化。改变该数据,例如通过别名或通过将 &T 转换为 &mut T,被视为未定义行为。
和(编辑长度):
如果您创建一个生命周期为 'a 的安全引用(一个 &T 或 &mut T 引用)并且可由安全代码访问,那么您不得以任何与 'a 的其余部分的引用相矛盾的方式访问数据。例如,这意味着如果您从 UnsafeCell 中获取 *mut T 并将其强制转换为 &T,则T 中的数据必须保持不可变,直到该引用的生命周期到期。
实际上,如果有&PML4或&mut PML4,则 的“易失性”属性PML4可以被视为通过“隐藏”别名的突变。
根据您的需要,您要么需要PML4通过 a通道访问read_volatile(这是安全的,因为read_volatile 总是将底层内存复制到不可变内存中);然后你可以自由地给出对该副本的引用。或者你包装的东西成UnsafeCell<PML4>,在这种情况下访问仍然需要通过读取内部指针(挥发性与否)的值来实现,但至少你可以通过周围&UnsafeCell<PML4>。
| 归档时间: |
|
| 查看次数: |
142 次 |
| 最近记录: |