]>
Commit | Line | Data |
---|---|---|
0987d735 PB |
1 | #ifndef RAMLIST_H |
2 | #define RAMLIST_H | |
3 | ||
4 | #include "qemu/queue.h" | |
5 | #include "qemu/thread.h" | |
6 | #include "qemu/rcu.h" | |
7 | ||
8 | typedef struct RAMBlockNotifier RAMBlockNotifier; | |
9 | ||
10 | #define DIRTY_MEMORY_VGA 0 | |
11 | #define DIRTY_MEMORY_CODE 1 | |
12 | #define DIRTY_MEMORY_MIGRATION 2 | |
13 | #define DIRTY_MEMORY_NUM 3 /* num of dirty bits */ | |
14 | ||
15 | /* The dirty memory bitmap is split into fixed-size blocks to allow growth | |
16 | * under RCU. The bitmap for a block can be accessed as follows: | |
17 | * | |
18 | * rcu_read_lock(); | |
19 | * | |
20 | * DirtyMemoryBlocks *blocks = | |
21 | * atomic_rcu_read(&ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION]); | |
22 | * | |
23 | * ram_addr_t idx = (addr >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE; | |
24 | * unsigned long *block = blocks.blocks[idx]; | |
25 | * ...access block bitmap... | |
26 | * | |
27 | * rcu_read_unlock(); | |
28 | * | |
29 | * Remember to check for the end of the block when accessing a range of | |
30 | * addresses. Move on to the next block if you reach the end. | |
31 | * | |
32 | * Organization into blocks allows dirty memory to grow (but not shrink) under | |
33 | * RCU. When adding new RAMBlocks requires the dirty memory to grow, a new | |
34 | * DirtyMemoryBlocks array is allocated with pointers to existing blocks kept | |
35 | * the same. Other threads can safely access existing blocks while dirty | |
36 | * memory is being grown. When no threads are using the old DirtyMemoryBlocks | |
37 | * anymore it is freed by RCU (but the underlying blocks stay because they are | |
38 | * pointed to from the new DirtyMemoryBlocks). | |
39 | */ | |
40 | #define DIRTY_MEMORY_BLOCK_SIZE ((ram_addr_t)256 * 1024 * 8) | |
41 | typedef struct { | |
42 | struct rcu_head rcu; | |
43 | unsigned long *blocks[]; | |
44 | } DirtyMemoryBlocks; | |
45 | ||
46 | typedef struct RAMList { | |
47 | QemuMutex mutex; | |
48 | RAMBlock *mru_block; | |
49 | /* RCU-enabled, writes protected by the ramlist lock. */ | |
50 | QLIST_HEAD(, RAMBlock) blocks; | |
51 | DirtyMemoryBlocks *dirty_memory[DIRTY_MEMORY_NUM]; | |
52 | uint32_t version; | |
53 | QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers; | |
54 | } RAMList; | |
55 | extern RAMList ram_list; | |
56 | ||
57 | void qemu_mutex_lock_ramlist(void); | |
58 | void qemu_mutex_unlock_ramlist(void); | |
59 | ||
60 | struct RAMBlockNotifier { | |
61 | void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size); | |
62 | void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size); | |
63 | QLIST_ENTRY(RAMBlockNotifier) next; | |
64 | }; | |
65 | ||
66 | void ram_block_notifier_add(RAMBlockNotifier *n); | |
67 | void ram_block_notifier_remove(RAMBlockNotifier *n); | |
68 | void ram_block_notify_add(void *host, size_t size); | |
69 | void ram_block_notify_remove(void *host, size_t size); | |
70 | ||
71 | ||
72 | #endif /* RAMLIST_H */ |