mirror of
https://github.com/qemu/qemu.git
synced 2026-01-14 03:01:08 +00:00
We have 115 direct inclusions of "system/memory.h", and 91 headers in include/ use it: hundreds of files have to process it. However only one single header really uses the MemoryRegionCache API: "hw/virtio/virtio-access.h". Split it out to a new header, avoiding processing unused inlined functions hundreds of times. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20260109165058.59144-6-philmd@linaro.org>
211 lines
6.6 KiB
C
211 lines
6.6 KiB
C
/*
|
|
* Physical memory management API
|
|
*
|
|
* Copyright 2011 Red Hat, Inc. and/or its affiliates
|
|
*
|
|
* Authors:
|
|
* Avi Kivity <avi@redhat.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#ifndef SYSTEM_MEMORY_CACHED_H
|
|
#define SYSTEM_MEMORY_CACHED_H
|
|
|
|
#include "exec/hwaddr.h"
|
|
#include "system/memory.h"
|
|
|
|
struct MemoryRegionCache {
|
|
uint8_t *ptr;
|
|
hwaddr xlat;
|
|
hwaddr len;
|
|
FlatView *fv;
|
|
MemoryRegionSection mrs;
|
|
bool is_write;
|
|
};
|
|
|
|
/**
|
|
* address_space_ld*_cached: load from a cached #MemoryRegion
|
|
* address_space_st*_cached: store into a cached #MemoryRegion
|
|
*
|
|
* These functions perform a load or store of the byte, word,
|
|
* longword or quad to the specified address. The address is
|
|
* a physical address in the AddressSpace, but it must lie within
|
|
* a #MemoryRegion that was mapped with address_space_cache_init.
|
|
*
|
|
* The _le suffixed functions treat the data as little endian;
|
|
* _be indicates big endian; no suffix indicates "same endianness
|
|
* as guest CPU".
|
|
*
|
|
* The "guest CPU endianness" accessors are deprecated for use outside
|
|
* target-* code; devices should be CPU-agnostic and use either the LE
|
|
* or the BE accessors.
|
|
*
|
|
* @cache: previously initialized #MemoryRegionCache to be accessed
|
|
* @addr: address within the address space
|
|
* @val: data value, for stores
|
|
* @attrs: memory transaction attributes
|
|
* @result: location to write the success/failure of the transaction;
|
|
* if NULL, this information is discarded
|
|
*/
|
|
|
|
#define SUFFIX _cached_slow
|
|
#define ARG1 cache
|
|
#define ARG1_DECL MemoryRegionCache *cache
|
|
#include "system/memory_ldst.h.inc"
|
|
|
|
/* Inline fast path for direct RAM access. */
|
|
static inline
|
|
uint8_t address_space_ldub_cached(MemoryRegionCache *cache, hwaddr addr,
|
|
MemTxAttrs attrs, MemTxResult *result)
|
|
{
|
|
assert(addr < cache->len);
|
|
if (likely(cache->ptr)) {
|
|
return ldub_p(cache->ptr + addr);
|
|
} else {
|
|
return address_space_ldub_cached_slow(cache, addr, attrs, result);
|
|
}
|
|
}
|
|
|
|
static inline
|
|
void address_space_stb_cached(MemoryRegionCache *cache,
|
|
hwaddr addr, uint8_t val,
|
|
MemTxAttrs attrs, MemTxResult *result)
|
|
{
|
|
assert(addr < cache->len);
|
|
if (likely(cache->ptr)) {
|
|
stb_p(cache->ptr + addr, val);
|
|
} else {
|
|
address_space_stb_cached_slow(cache, addr, val, attrs, result);
|
|
}
|
|
}
|
|
|
|
#define ENDIANNESS
|
|
#include "system/memory_ldst_cached.h.inc"
|
|
|
|
#define ENDIANNESS _le
|
|
#include "system/memory_ldst_cached.h.inc"
|
|
|
|
#define ENDIANNESS _be
|
|
#include "system/memory_ldst_cached.h.inc"
|
|
|
|
#define SUFFIX _cached
|
|
#define ARG1 cache
|
|
#define ARG1_DECL MemoryRegionCache *cache
|
|
#include "system/memory_ldst_phys.h.inc"
|
|
|
|
/**
|
|
* address_space_cache_init: prepare for repeated access to a physical
|
|
* memory region
|
|
*
|
|
* @cache: #MemoryRegionCache to be filled
|
|
* @as: #AddressSpace to be accessed
|
|
* @addr: address within that address space
|
|
* @len: length of buffer
|
|
* @is_write: indicates the transfer direction
|
|
*
|
|
* Will only work with RAM, and may map a subset of the requested range by
|
|
* returning a value that is less than @len. On failure, return a negative
|
|
* errno value.
|
|
*
|
|
* Because it only works with RAM, this function can be used for
|
|
* read-modify-write operations. In this case, is_write should be %true.
|
|
*
|
|
* Note that addresses passed to the address_space_*_cached functions
|
|
* are relative to @addr.
|
|
*/
|
|
int64_t address_space_cache_init(MemoryRegionCache *cache,
|
|
AddressSpace *as,
|
|
hwaddr addr,
|
|
hwaddr len,
|
|
bool is_write);
|
|
|
|
/**
|
|
* address_space_cache_init_empty: Initialize empty #MemoryRegionCache
|
|
*
|
|
* @cache: The #MemoryRegionCache to operate on.
|
|
*
|
|
* Initializes #MemoryRegionCache structure without memory region attached.
|
|
* Cache initialized this way can only be safely destroyed, but not used.
|
|
*/
|
|
static inline void address_space_cache_init_empty(MemoryRegionCache *cache)
|
|
{
|
|
cache->mrs.mr = NULL;
|
|
/* There is no real need to initialize fv, but it makes Coverity happy. */
|
|
cache->fv = NULL;
|
|
}
|
|
|
|
/**
|
|
* address_space_cache_invalidate: complete a write to a #MemoryRegionCache
|
|
*
|
|
* @cache: The #MemoryRegionCache to operate on.
|
|
* @addr: The first physical address that was written, relative to the
|
|
* address that was passed to @address_space_cache_init.
|
|
* @access_len: The number of bytes that were written starting at @addr.
|
|
*/
|
|
void address_space_cache_invalidate(MemoryRegionCache *cache,
|
|
hwaddr addr,
|
|
hwaddr access_len);
|
|
|
|
/**
|
|
* address_space_cache_destroy: free a #MemoryRegionCache
|
|
*
|
|
* @cache: The #MemoryRegionCache whose memory should be released.
|
|
*/
|
|
void address_space_cache_destroy(MemoryRegionCache *cache);
|
|
|
|
/*
|
|
* Internal functions, part of the implementation of address_space_read_cached
|
|
* and address_space_write_cached.
|
|
*/
|
|
MemTxResult address_space_read_cached_slow(MemoryRegionCache *cache,
|
|
hwaddr addr, void *buf, hwaddr len);
|
|
MemTxResult address_space_write_cached_slow(MemoryRegionCache *cache,
|
|
hwaddr addr, const void *buf,
|
|
hwaddr len);
|
|
|
|
/**
|
|
* address_space_read_cached: read from 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_read_cached(MemoryRegionCache *cache, hwaddr addr,
|
|
void *buf, hwaddr len)
|
|
{
|
|
assert(addr < cache->len && len <= cache->len - addr);
|
|
fuzz_dma_read_cb(cache->xlat + addr, len, cache->mrs.mr);
|
|
if (likely(cache->ptr)) {
|
|
memcpy(buf, cache->ptr + addr, len);
|
|
return MEMTX_OK;
|
|
} else {
|
|
return address_space_read_cached_slow(cache, addr, buf, len);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
if (likely(cache->ptr)) {
|
|
memcpy(cache->ptr + addr, buf, len);
|
|
return MEMTX_OK;
|
|
} else {
|
|
return address_space_write_cached_slow(cache, addr, buf, len);
|
|
}
|
|
}
|
|
|
|
#endif
|