xqemu/include/exec/ramlist.h
Matt Borgerson 95503c6608 v3.0.0 release
-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJbcveDAAoJEDwlJe0UNgzen9QP/jEa9I1aN6ylYJHF7R9NI8Yh
 06k+dXCIK51ETRVXbWDnNa5KHxa1pYdBOVlBt/TtHq1sqJL0B3eAaNyeoRkuehvk
 LE+72CxEm4M+D+cw8Mnq3NEND1dCu3PVXykHUWaoLck3hLwS4gvD/J0veht72GId
 Ifv+wlAObtCijnJ9z5/K54bliPMt/c3HWXQegJ5Z6/aBiha+fYTairu9x3qBht56
 yHHc0cPnqMOR710vzB93u8HGP5jbtbqYmQZGyFXheUFLpEdQhzXfGlNeZsE3FRPb
 4CCRhSDp0a7sfhNQ29eYI4kTmpadnXLFtrDYeoKnzcrfe6VXwhAZotU1iAmAUCVA
 86Z3UI96PeGNwmyuFRAxomtKD5fdilG+IBSrv9WPFHbUzT4OsdldobjAaabGjtvk
 Lt+MG758/GWgRRldNjozi7YfGukctryMYoJcqv6v8o3sXlahId2CffDCGOxUQgWJ
 C4u4zgWDMrZVR7Iqcnn044Q4DCb7pSLnaGd7mpG1sW5MDCEhJKbDBBKzwjsuzGRZ
 YFjAzZ3pCaYrJ2foFteobc43Y0wdugR1AyDNoRY+aaK2qn0EG4gv+NCtlF9ZJlm3
 UCYdAFQuevXFJQ5ZO2nHYNkWUMw0xGUG7CXYMXAxRePk8urLY/tC3g0CySJYnBe1
 BBEbaX+pR3eT5xnEWPL0
 =rchV
 -----END PGP SIGNATURE-----

Merge tag 'v3.0.0' into merge_3_0_0

v3.0.0 release
2018-09-02 13:17:13 -07:00

81 lines
2.8 KiB
C

#ifndef RAMLIST_H
#define RAMLIST_H
#include "qemu/queue.h"
#include "qemu/thread.h"
#include "qemu/rcu.h"
#include "qemu/rcu_queue.h"
typedef struct RAMBlockNotifier RAMBlockNotifier;
#define DIRTY_MEMORY_VGA 0
#define DIRTY_MEMORY_CODE 1
#define DIRTY_MEMORY_MIGRATION 2
#define DIRTY_MEMORY_NV2A 3
#define DIRTY_MEMORY_NUM 4 /* num of dirty bits */
/* The dirty memory bitmap is split into fixed-size blocks to allow growth
* under RCU. The bitmap for a block can be accessed as follows:
*
* rcu_read_lock();
*
* DirtyMemoryBlocks *blocks =
* atomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]);
*
* ram_addr_t idx = (addr >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE;
* unsigned long *block = blocks.blocks[idx];
* ...access block bitmap...
*
* rcu_read_unlock();
*
* Remember to check for the end of the block when accessing a range of
* addresses. Move on to the next block if you reach the end.
*
* Organization into blocks allows dirty memory to grow (but not shrink) under
* RCU. When adding new RAMBlocks requires the dirty memory to grow, a new
* DirtyMemoryBlocks array is allocated with pointers to existing blocks kept
* the same. Other threads can safely access existing blocks while dirty
* memory is being grown. When no threads are using the old DirtyMemoryBlocks
* anymore it is freed by RCU (but the underlying blocks stay because they are
* pointed to from the new DirtyMemoryBlocks).
*/
#define DIRTY_MEMORY_BLOCK_SIZE ((ram_addr_t)256 * 1024 * 8)
typedef struct {
struct rcu_head rcu;
unsigned long *blocks[];
} DirtyMemoryBlocks;
typedef struct RAMList {
QemuMutex mutex;
RAMBlock *mru_block;
/* RCU-enabled, writes protected by the ramlist lock. */
QLIST_HEAD(, RAMBlock) blocks;
DirtyMemoryBlocks *dirty_memory[DIRTY_MEMORY_NUM];
uint32_t version;
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
} RAMList;
extern RAMList ram_list;
/* Should be holding either ram_list.mutex, or the RCU lock. */
#define INTERNAL_RAMBLOCK_FOREACH(block) \
QLIST_FOREACH_RCU(block, &ram_list.blocks, next)
/* Never use the INTERNAL_ version except for defining other macros */
#define RAMBLOCK_FOREACH(block) INTERNAL_RAMBLOCK_FOREACH(block)
void qemu_mutex_lock_ramlist(void);
void qemu_mutex_unlock_ramlist(void);
struct RAMBlockNotifier {
void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size);
void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size);
QLIST_ENTRY(RAMBlockNotifier) next;
};
void ram_block_notifier_add(RAMBlockNotifier *n);
void ram_block_notifier_remove(RAMBlockNotifier *n);
void ram_block_notify_add(void *host, size_t size);
void ram_block_notify_remove(void *host, size_t size);
void ram_block_dump(Monitor *mon);
#endif /* RAMLIST_H */