Cache Memory Region in QEMU
[Qemu-devel] [PULL 04/25] exec: introduce MemoryRegionCache - Paolo Bonzini
struct MemoryRegionCache
(QEMU)
In QEMU, MemoryRegionCache
is a data structure that optimizes memory access for virtual devices by caching translation results.
Introduce a new data structure to cache the result of address_space_translate()
without forcing usage of a host address like address_space_map()
does.
我的理解是, address_space_map()
函数看起来好像只是 j
目前好像只在 virtio 中用到了,因为只在 virtio 中看到了相关的代码。请看 virtio_init_region_cache()
。
MemoryRegion
是描述一片内存区,MemoryRegionCache
是真的要用的内存,Hypervisor 根据需要动态申请,后面简称 MRC。
为甚不用 RAMBlock 了呢?
struct MemoryRegionCache {
// 真实 hold 着这片区域的内存,也就是这片区域的虚拟地址(HVA)
void *ptr;
// [] linear address translation?
// 这片区域表示的地址空间的起始地址
// 可以看 address_space_map 来印证这一点
hwaddr xlat;
hwaddr len;
// address space 对应的 flatview
FlatView *fv;
MemoryRegionSection mrs;
bool is_write;
};
address_space_cache_init()
QEMU
初始化一个 MemoryRegionCache
^。
传入的参数包含一个在 AddressSpace 中的 (addr, len),我们要做的就是把这片地址映射到 MemoryRegionCache
中去。
int64_t address_space_cache_init(MemoryRegionCache *cache,
AddressSpace *as,
hwaddr addr,
hwaddr len,
bool is_write)
{
AddressSpaceDispatch *d;
hwaddr l;
MemoryRegion *mr;
Int128 diff;
//...
l = len;
cache->fv = address_space_get_flatview(as);
d = flatview_to_dispatch(cache->fv);
cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true);
/*
* cache->xlat is now relative to cache->mrs.mr, not to the section itself.
* Take that into account to compute how many bytes are there between
* cache->xlat and the end of the section.
*/
diff = int128_sub(cache->mrs.size, int128_make64(cache->xlat - cache->mrs.offset_within_region));
l = int128_get64(int128_min(diff, int128_make64(l)));
mr = cache->mrs.mr;
memory_region_ref(mr);
if (memory_access_is_direct(mr, is_write)) {
/* We don't care about the memory attributes here as we're only
* doing this if we found actual RAM, which behaves the same
* regardless of attributes; so UNSPECIFIED is fine.
*/
// 得到 addr(所在 AddressSpace 里的偏移)对应的 xlat(所在 MR 里的偏移)
// 并缓存到 cache 里
l = flatview_extend_translation(cache->fv, addr, len, mr,
cache->xlat, l, is_write,
MEMTXATTRS_UNSPECIFIED);
// 还是从 RAMBlock 里取 ptr。
// addr 是 cache->xlat,其实就是 offset,加上 ram_block->host
// 就变成 ptr 了。
cache->ptr = qemu_ram_ptr_length(mr->ram_block, cache->xlat, &l, true);
} else {
cache->ptr = NULL;
}
cache->len = l;
cache->is_write = is_write;
return l;
}
address_space_write_cached()
QEMU
Write to a cached RAM region.
/**
* address_space_write_cached: write to a cached RAM region
*
* @cache: Cached region to be addressed
* @addr: address relative to the base of the RAM region
* @buf: buffer with the data transferred
* @len: length of the data transferred
*/
static inline MemTxResult
address_space_write_cached(MemoryRegionCache *cache, hwaddr addr,
const void *buf, hwaddr len)
{
assert(addr < cache->len && len <= cache->len - addr);
// 如果之前 cache 已经缓存过了
if (likely(cache->ptr)) {
memcpy(cache->ptr + addr, buf, len);
return MEMTX_OK;
} else {
return address_space_write_cached_slow(cache, addr, buf, len);
}
}
🗞️ Recent Posts