xref: /openbmc/qemu/include/system/ram_addr.h (revision 4705a71db5909ac5586e87397b2dece132b9e330)
1*4705a71dSRichard Henderson /*
2*4705a71dSRichard Henderson  * Declarations for cpu physical memory functions
3*4705a71dSRichard Henderson  *
4*4705a71dSRichard Henderson  * Copyright 2011 Red Hat, Inc. and/or its affiliates
5*4705a71dSRichard Henderson  *
6*4705a71dSRichard Henderson  * Authors:
7*4705a71dSRichard Henderson  *  Avi Kivity <avi@redhat.com>
8*4705a71dSRichard Henderson  *
9*4705a71dSRichard Henderson  * This work is licensed under the terms of the GNU GPL, version 2 or
10*4705a71dSRichard Henderson  * later.  See the COPYING file in the top-level directory.
11*4705a71dSRichard Henderson  *
12*4705a71dSRichard Henderson  */
13*4705a71dSRichard Henderson 
14*4705a71dSRichard Henderson /*
15*4705a71dSRichard Henderson  * This header is for use by exec.c and memory.c ONLY.  Do not include it.
16*4705a71dSRichard Henderson  * The functions declared here will be removed soon.
17*4705a71dSRichard Henderson  */
18*4705a71dSRichard Henderson 
19*4705a71dSRichard Henderson #ifndef SYSTEM_RAM_ADDR_H
20*4705a71dSRichard Henderson #define SYSTEM_RAM_ADDR_H
21*4705a71dSRichard Henderson 
22*4705a71dSRichard Henderson #include "system/xen.h"
23*4705a71dSRichard Henderson #include "system/tcg.h"
24*4705a71dSRichard Henderson #include "exec/cputlb.h"
25*4705a71dSRichard Henderson #include "exec/ramlist.h"
26*4705a71dSRichard Henderson #include "exec/ramblock.h"
27*4705a71dSRichard Henderson #include "exec/exec-all.h"
28*4705a71dSRichard Henderson #include "system/memory.h"
29*4705a71dSRichard Henderson #include "exec/target_page.h"
30*4705a71dSRichard Henderson #include "qemu/rcu.h"
31*4705a71dSRichard Henderson 
32*4705a71dSRichard Henderson #include "exec/hwaddr.h"
33*4705a71dSRichard Henderson #include "exec/cpu-common.h"
34*4705a71dSRichard Henderson 
35*4705a71dSRichard Henderson extern uint64_t total_dirty_pages;
36*4705a71dSRichard Henderson 
37*4705a71dSRichard Henderson /**
38*4705a71dSRichard Henderson  * clear_bmap_size: calculate clear bitmap size
39*4705a71dSRichard Henderson  *
40*4705a71dSRichard Henderson  * @pages: number of guest pages
41*4705a71dSRichard Henderson  * @shift: guest page number shift
42*4705a71dSRichard Henderson  *
43*4705a71dSRichard Henderson  * Returns: number of bits for the clear bitmap
44*4705a71dSRichard Henderson  */
45*4705a71dSRichard Henderson static inline long clear_bmap_size(uint64_t pages, uint8_t shift)
46*4705a71dSRichard Henderson {
47*4705a71dSRichard Henderson     return DIV_ROUND_UP(pages, 1UL << shift);
48*4705a71dSRichard Henderson }
49*4705a71dSRichard Henderson 
50*4705a71dSRichard Henderson /**
51*4705a71dSRichard Henderson  * clear_bmap_set: set clear bitmap for the page range.  Must be with
52*4705a71dSRichard Henderson  * bitmap_mutex held.
53*4705a71dSRichard Henderson  *
54*4705a71dSRichard Henderson  * @rb: the ramblock to operate on
55*4705a71dSRichard Henderson  * @start: the start page number
56*4705a71dSRichard Henderson  * @size: number of pages to set in the bitmap
57*4705a71dSRichard Henderson  *
58*4705a71dSRichard Henderson  * Returns: None
59*4705a71dSRichard Henderson  */
60*4705a71dSRichard Henderson static inline void clear_bmap_set(RAMBlock *rb, uint64_t start,
61*4705a71dSRichard Henderson                                   uint64_t npages)
62*4705a71dSRichard Henderson {
63*4705a71dSRichard Henderson     uint8_t shift = rb->clear_bmap_shift;
64*4705a71dSRichard Henderson 
65*4705a71dSRichard Henderson     bitmap_set(rb->clear_bmap, start >> shift, clear_bmap_size(npages, shift));
66*4705a71dSRichard Henderson }
67*4705a71dSRichard Henderson 
68*4705a71dSRichard Henderson /**
69*4705a71dSRichard Henderson  * clear_bmap_test_and_clear: test clear bitmap for the page, clear if set.
70*4705a71dSRichard Henderson  * Must be with bitmap_mutex held.
71*4705a71dSRichard Henderson  *
72*4705a71dSRichard Henderson  * @rb: the ramblock to operate on
73*4705a71dSRichard Henderson  * @page: the page number to check
74*4705a71dSRichard Henderson  *
75*4705a71dSRichard Henderson  * Returns: true if the bit was set, false otherwise
76*4705a71dSRichard Henderson  */
77*4705a71dSRichard Henderson static inline bool clear_bmap_test_and_clear(RAMBlock *rb, uint64_t page)
78*4705a71dSRichard Henderson {
79*4705a71dSRichard Henderson     uint8_t shift = rb->clear_bmap_shift;
80*4705a71dSRichard Henderson 
81*4705a71dSRichard Henderson     return bitmap_test_and_clear(rb->clear_bmap, page >> shift, 1);
82*4705a71dSRichard Henderson }
83*4705a71dSRichard Henderson 
84*4705a71dSRichard Henderson static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset)
85*4705a71dSRichard Henderson {
86*4705a71dSRichard Henderson     return (b && b->host && offset < b->used_length) ? true : false;
87*4705a71dSRichard Henderson }
88*4705a71dSRichard Henderson 
89*4705a71dSRichard Henderson static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset)
90*4705a71dSRichard Henderson {
91*4705a71dSRichard Henderson     assert(offset_in_ramblock(block, offset));
92*4705a71dSRichard Henderson     return (char *)block->host + offset;
93*4705a71dSRichard Henderson }
94*4705a71dSRichard Henderson 
95*4705a71dSRichard Henderson static inline unsigned long int ramblock_recv_bitmap_offset(void *host_addr,
96*4705a71dSRichard Henderson                                                             RAMBlock *rb)
97*4705a71dSRichard Henderson {
98*4705a71dSRichard Henderson     uint64_t host_addr_offset =
99*4705a71dSRichard Henderson             (uint64_t)(uintptr_t)(host_addr - (void *)rb->host);
100*4705a71dSRichard Henderson     return host_addr_offset >> TARGET_PAGE_BITS;
101*4705a71dSRichard Henderson }
102*4705a71dSRichard Henderson 
103*4705a71dSRichard Henderson bool ramblock_is_pmem(RAMBlock *rb);
104*4705a71dSRichard Henderson 
105*4705a71dSRichard Henderson /**
106*4705a71dSRichard Henderson  * qemu_ram_alloc_from_file,
107*4705a71dSRichard Henderson  * qemu_ram_alloc_from_fd:  Allocate a ram block from the specified backing
108*4705a71dSRichard Henderson  *                          file or device
109*4705a71dSRichard Henderson  *
110*4705a71dSRichard Henderson  * Parameters:
111*4705a71dSRichard Henderson  *  @size: the size in bytes of the ram block
112*4705a71dSRichard Henderson  *  @max_size: the maximum size of the block after resizing
113*4705a71dSRichard Henderson  *  @mr: the memory region where the ram block is
114*4705a71dSRichard Henderson  *  @resized: callback after calls to qemu_ram_resize
115*4705a71dSRichard Henderson  *  @ram_flags: RamBlock flags. Supported flags: RAM_SHARED, RAM_PMEM,
116*4705a71dSRichard Henderson  *              RAM_NORESERVE, RAM_PROTECTED, RAM_NAMED_FILE, RAM_READONLY,
117*4705a71dSRichard Henderson  *              RAM_READONLY_FD, RAM_GUEST_MEMFD
118*4705a71dSRichard Henderson  *  @mem_path or @fd: specify the backing file or device
119*4705a71dSRichard Henderson  *  @offset: Offset into target file
120*4705a71dSRichard Henderson  *  @grow: extend file if necessary (but an empty file is always extended).
121*4705a71dSRichard Henderson  *  @errp: pointer to Error*, to store an error if it happens
122*4705a71dSRichard Henderson  *
123*4705a71dSRichard Henderson  * Return:
124*4705a71dSRichard Henderson  *  On success, return a pointer to the ram block.
125*4705a71dSRichard Henderson  *  On failure, return NULL.
126*4705a71dSRichard Henderson  */
127*4705a71dSRichard Henderson typedef void (*qemu_ram_resize_cb)(const char *, uint64_t length, void *host);
128*4705a71dSRichard Henderson 
129*4705a71dSRichard Henderson RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
130*4705a71dSRichard Henderson                                    uint32_t ram_flags, const char *mem_path,
131*4705a71dSRichard Henderson                                    off_t offset, Error **errp);
132*4705a71dSRichard Henderson RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, ram_addr_t max_size,
133*4705a71dSRichard Henderson                                  qemu_ram_resize_cb resized, MemoryRegion *mr,
134*4705a71dSRichard Henderson                                  uint32_t ram_flags, int fd, off_t offset,
135*4705a71dSRichard Henderson                                  bool grow,
136*4705a71dSRichard Henderson                                  Error **errp);
137*4705a71dSRichard Henderson 
138*4705a71dSRichard Henderson RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
139*4705a71dSRichard Henderson                                   MemoryRegion *mr, Error **errp);
140*4705a71dSRichard Henderson RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags, MemoryRegion *mr,
141*4705a71dSRichard Henderson                          Error **errp);
142*4705a71dSRichard Henderson RAMBlock *qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t max_size,
143*4705a71dSRichard Henderson                                     qemu_ram_resize_cb resized,
144*4705a71dSRichard Henderson                                     MemoryRegion *mr, Error **errp);
145*4705a71dSRichard Henderson void qemu_ram_free(RAMBlock *block);
146*4705a71dSRichard Henderson 
147*4705a71dSRichard Henderson int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp);
148*4705a71dSRichard Henderson 
149*4705a71dSRichard Henderson void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length);
150*4705a71dSRichard Henderson 
151*4705a71dSRichard Henderson /* Clear whole block of mem */
152*4705a71dSRichard Henderson static inline void qemu_ram_block_writeback(RAMBlock *block)
153*4705a71dSRichard Henderson {
154*4705a71dSRichard Henderson     qemu_ram_msync(block, 0, block->used_length);
155*4705a71dSRichard Henderson }
156*4705a71dSRichard Henderson 
157*4705a71dSRichard Henderson #define DIRTY_CLIENTS_ALL     ((1 << DIRTY_MEMORY_NUM) - 1)
158*4705a71dSRichard Henderson #define DIRTY_CLIENTS_NOCODE  (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))
159*4705a71dSRichard Henderson 
160*4705a71dSRichard Henderson static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
161*4705a71dSRichard Henderson                                                  ram_addr_t length,
162*4705a71dSRichard Henderson                                                  unsigned client)
163*4705a71dSRichard Henderson {
164*4705a71dSRichard Henderson     DirtyMemoryBlocks *blocks;
165*4705a71dSRichard Henderson     unsigned long end, page;
166*4705a71dSRichard Henderson     unsigned long idx, offset, base;
167*4705a71dSRichard Henderson     bool dirty = false;
168*4705a71dSRichard Henderson 
169*4705a71dSRichard Henderson     assert(client < DIRTY_MEMORY_NUM);
170*4705a71dSRichard Henderson 
171*4705a71dSRichard Henderson     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
172*4705a71dSRichard Henderson     page = start >> TARGET_PAGE_BITS;
173*4705a71dSRichard Henderson 
174*4705a71dSRichard Henderson     WITH_RCU_READ_LOCK_GUARD() {
175*4705a71dSRichard Henderson         blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
176*4705a71dSRichard Henderson 
177*4705a71dSRichard Henderson         idx = page / DIRTY_MEMORY_BLOCK_SIZE;
178*4705a71dSRichard Henderson         offset = page % DIRTY_MEMORY_BLOCK_SIZE;
179*4705a71dSRichard Henderson         base = page - offset;
180*4705a71dSRichard Henderson         while (page < end) {
181*4705a71dSRichard Henderson             unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
182*4705a71dSRichard Henderson             unsigned long num = next - base;
183*4705a71dSRichard Henderson             unsigned long found = find_next_bit(blocks->blocks[idx],
184*4705a71dSRichard Henderson                                                 num, offset);
185*4705a71dSRichard Henderson             if (found < num) {
186*4705a71dSRichard Henderson                 dirty = true;
187*4705a71dSRichard Henderson                 break;
188*4705a71dSRichard Henderson             }
189*4705a71dSRichard Henderson 
190*4705a71dSRichard Henderson             page = next;
191*4705a71dSRichard Henderson             idx++;
192*4705a71dSRichard Henderson             offset = 0;
193*4705a71dSRichard Henderson             base += DIRTY_MEMORY_BLOCK_SIZE;
194*4705a71dSRichard Henderson         }
195*4705a71dSRichard Henderson     }
196*4705a71dSRichard Henderson 
197*4705a71dSRichard Henderson     return dirty;
198*4705a71dSRichard Henderson }
199*4705a71dSRichard Henderson 
200*4705a71dSRichard Henderson static inline bool cpu_physical_memory_all_dirty(ram_addr_t start,
201*4705a71dSRichard Henderson                                                  ram_addr_t length,
202*4705a71dSRichard Henderson                                                  unsigned client)
203*4705a71dSRichard Henderson {
204*4705a71dSRichard Henderson     DirtyMemoryBlocks *blocks;
205*4705a71dSRichard Henderson     unsigned long end, page;
206*4705a71dSRichard Henderson     unsigned long idx, offset, base;
207*4705a71dSRichard Henderson     bool dirty = true;
208*4705a71dSRichard Henderson 
209*4705a71dSRichard Henderson     assert(client < DIRTY_MEMORY_NUM);
210*4705a71dSRichard Henderson 
211*4705a71dSRichard Henderson     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
212*4705a71dSRichard Henderson     page = start >> TARGET_PAGE_BITS;
213*4705a71dSRichard Henderson 
214*4705a71dSRichard Henderson     RCU_READ_LOCK_GUARD();
215*4705a71dSRichard Henderson 
216*4705a71dSRichard Henderson     blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
217*4705a71dSRichard Henderson 
218*4705a71dSRichard Henderson     idx = page / DIRTY_MEMORY_BLOCK_SIZE;
219*4705a71dSRichard Henderson     offset = page % DIRTY_MEMORY_BLOCK_SIZE;
220*4705a71dSRichard Henderson     base = page - offset;
221*4705a71dSRichard Henderson     while (page < end) {
222*4705a71dSRichard Henderson         unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
223*4705a71dSRichard Henderson         unsigned long num = next - base;
224*4705a71dSRichard Henderson         unsigned long found = find_next_zero_bit(blocks->blocks[idx], num, offset);
225*4705a71dSRichard Henderson         if (found < num) {
226*4705a71dSRichard Henderson             dirty = false;
227*4705a71dSRichard Henderson             break;
228*4705a71dSRichard Henderson         }
229*4705a71dSRichard Henderson 
230*4705a71dSRichard Henderson         page = next;
231*4705a71dSRichard Henderson         idx++;
232*4705a71dSRichard Henderson         offset = 0;
233*4705a71dSRichard Henderson         base += DIRTY_MEMORY_BLOCK_SIZE;
234*4705a71dSRichard Henderson     }
235*4705a71dSRichard Henderson 
236*4705a71dSRichard Henderson     return dirty;
237*4705a71dSRichard Henderson }
238*4705a71dSRichard Henderson 
239*4705a71dSRichard Henderson static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr,
240*4705a71dSRichard Henderson                                                       unsigned client)
241*4705a71dSRichard Henderson {
242*4705a71dSRichard Henderson     return cpu_physical_memory_get_dirty(addr, 1, client);
243*4705a71dSRichard Henderson }
244*4705a71dSRichard Henderson 
245*4705a71dSRichard Henderson static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
246*4705a71dSRichard Henderson {
247*4705a71dSRichard Henderson     bool vga = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_VGA);
248*4705a71dSRichard Henderson     bool code = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_CODE);
249*4705a71dSRichard Henderson     bool migration =
250*4705a71dSRichard Henderson         cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
251*4705a71dSRichard Henderson     return !(vga && code && migration);
252*4705a71dSRichard Henderson }
253*4705a71dSRichard Henderson 
254*4705a71dSRichard Henderson static inline uint8_t cpu_physical_memory_range_includes_clean(ram_addr_t start,
255*4705a71dSRichard Henderson                                                                ram_addr_t length,
256*4705a71dSRichard Henderson                                                                uint8_t mask)
257*4705a71dSRichard Henderson {
258*4705a71dSRichard Henderson     uint8_t ret = 0;
259*4705a71dSRichard Henderson 
260*4705a71dSRichard Henderson     if (mask & (1 << DIRTY_MEMORY_VGA) &&
261*4705a71dSRichard Henderson         !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA)) {
262*4705a71dSRichard Henderson         ret |= (1 << DIRTY_MEMORY_VGA);
263*4705a71dSRichard Henderson     }
264*4705a71dSRichard Henderson     if (mask & (1 << DIRTY_MEMORY_CODE) &&
265*4705a71dSRichard Henderson         !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE)) {
266*4705a71dSRichard Henderson         ret |= (1 << DIRTY_MEMORY_CODE);
267*4705a71dSRichard Henderson     }
268*4705a71dSRichard Henderson     if (mask & (1 << DIRTY_MEMORY_MIGRATION) &&
269*4705a71dSRichard Henderson         !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION)) {
270*4705a71dSRichard Henderson         ret |= (1 << DIRTY_MEMORY_MIGRATION);
271*4705a71dSRichard Henderson     }
272*4705a71dSRichard Henderson     return ret;
273*4705a71dSRichard Henderson }
274*4705a71dSRichard Henderson 
275*4705a71dSRichard Henderson static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
276*4705a71dSRichard Henderson                                                       unsigned client)
277*4705a71dSRichard Henderson {
278*4705a71dSRichard Henderson     unsigned long page, idx, offset;
279*4705a71dSRichard Henderson     DirtyMemoryBlocks *blocks;
280*4705a71dSRichard Henderson 
281*4705a71dSRichard Henderson     assert(client < DIRTY_MEMORY_NUM);
282*4705a71dSRichard Henderson 
283*4705a71dSRichard Henderson     page = addr >> TARGET_PAGE_BITS;
284*4705a71dSRichard Henderson     idx = page / DIRTY_MEMORY_BLOCK_SIZE;
285*4705a71dSRichard Henderson     offset = page % DIRTY_MEMORY_BLOCK_SIZE;
286*4705a71dSRichard Henderson 
287*4705a71dSRichard Henderson     RCU_READ_LOCK_GUARD();
288*4705a71dSRichard Henderson 
289*4705a71dSRichard Henderson     blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
290*4705a71dSRichard Henderson 
291*4705a71dSRichard Henderson     set_bit_atomic(offset, blocks->blocks[idx]);
292*4705a71dSRichard Henderson }
293*4705a71dSRichard Henderson 
294*4705a71dSRichard Henderson static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
295*4705a71dSRichard Henderson                                                        ram_addr_t length,
296*4705a71dSRichard Henderson                                                        uint8_t mask)
297*4705a71dSRichard Henderson {
298*4705a71dSRichard Henderson     DirtyMemoryBlocks *blocks[DIRTY_MEMORY_NUM];
299*4705a71dSRichard Henderson     unsigned long end, page;
300*4705a71dSRichard Henderson     unsigned long idx, offset, base;
301*4705a71dSRichard Henderson     int i;
302*4705a71dSRichard Henderson 
303*4705a71dSRichard Henderson     if (!mask && !xen_enabled()) {
304*4705a71dSRichard Henderson         return;
305*4705a71dSRichard Henderson     }
306*4705a71dSRichard Henderson 
307*4705a71dSRichard Henderson     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
308*4705a71dSRichard Henderson     page = start >> TARGET_PAGE_BITS;
309*4705a71dSRichard Henderson 
310*4705a71dSRichard Henderson     WITH_RCU_READ_LOCK_GUARD() {
311*4705a71dSRichard Henderson         for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
312*4705a71dSRichard Henderson             blocks[i] = qatomic_rcu_read(&ram_list.dirty_memory[i]);
313*4705a71dSRichard Henderson         }
314*4705a71dSRichard Henderson 
315*4705a71dSRichard Henderson         idx = page / DIRTY_MEMORY_BLOCK_SIZE;
316*4705a71dSRichard Henderson         offset = page % DIRTY_MEMORY_BLOCK_SIZE;
317*4705a71dSRichard Henderson         base = page - offset;
318*4705a71dSRichard Henderson         while (page < end) {
319*4705a71dSRichard Henderson             unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE);
320*4705a71dSRichard Henderson 
321*4705a71dSRichard Henderson             if (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) {
322*4705a71dSRichard Henderson                 bitmap_set_atomic(blocks[DIRTY_MEMORY_MIGRATION]->blocks[idx],
323*4705a71dSRichard Henderson                                   offset, next - page);
324*4705a71dSRichard Henderson             }
325*4705a71dSRichard Henderson             if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) {
326*4705a71dSRichard Henderson                 bitmap_set_atomic(blocks[DIRTY_MEMORY_VGA]->blocks[idx],
327*4705a71dSRichard Henderson                                   offset, next - page);
328*4705a71dSRichard Henderson             }
329*4705a71dSRichard Henderson             if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) {
330*4705a71dSRichard Henderson                 bitmap_set_atomic(blocks[DIRTY_MEMORY_CODE]->blocks[idx],
331*4705a71dSRichard Henderson                                   offset, next - page);
332*4705a71dSRichard Henderson             }
333*4705a71dSRichard Henderson 
334*4705a71dSRichard Henderson             page = next;
335*4705a71dSRichard Henderson             idx++;
336*4705a71dSRichard Henderson             offset = 0;
337*4705a71dSRichard Henderson             base += DIRTY_MEMORY_BLOCK_SIZE;
338*4705a71dSRichard Henderson         }
339*4705a71dSRichard Henderson     }
340*4705a71dSRichard Henderson 
341*4705a71dSRichard Henderson     if (xen_enabled()) {
342*4705a71dSRichard Henderson         xen_hvm_modified_memory(start, length);
343*4705a71dSRichard Henderson     }
344*4705a71dSRichard Henderson }
345*4705a71dSRichard Henderson 
346*4705a71dSRichard Henderson #if !defined(_WIN32)
347*4705a71dSRichard Henderson 
348*4705a71dSRichard Henderson /*
349*4705a71dSRichard Henderson  * Contrary to cpu_physical_memory_sync_dirty_bitmap() this function returns
350*4705a71dSRichard Henderson  * the number of dirty pages in @bitmap passed as argument. On the other hand,
351*4705a71dSRichard Henderson  * cpu_physical_memory_sync_dirty_bitmap() returns newly dirtied pages that
352*4705a71dSRichard Henderson  * weren't set in the global migration bitmap.
353*4705a71dSRichard Henderson  */
354*4705a71dSRichard Henderson static inline
355*4705a71dSRichard Henderson uint64_t cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
356*4705a71dSRichard Henderson                                                 ram_addr_t start,
357*4705a71dSRichard Henderson                                                 ram_addr_t pages)
358*4705a71dSRichard Henderson {
359*4705a71dSRichard Henderson     unsigned long i, j;
360*4705a71dSRichard Henderson     unsigned long page_number, c, nbits;
361*4705a71dSRichard Henderson     hwaddr addr;
362*4705a71dSRichard Henderson     ram_addr_t ram_addr;
363*4705a71dSRichard Henderson     uint64_t num_dirty = 0;
364*4705a71dSRichard Henderson     unsigned long len = (pages + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
365*4705a71dSRichard Henderson     unsigned long hpratio = qemu_real_host_page_size() / TARGET_PAGE_SIZE;
366*4705a71dSRichard Henderson     unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
367*4705a71dSRichard Henderson 
368*4705a71dSRichard Henderson     /* start address is aligned at the start of a word? */
369*4705a71dSRichard Henderson     if ((((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) &&
370*4705a71dSRichard Henderson         (hpratio == 1)) {
371*4705a71dSRichard Henderson         unsigned long **blocks[DIRTY_MEMORY_NUM];
372*4705a71dSRichard Henderson         unsigned long idx;
373*4705a71dSRichard Henderson         unsigned long offset;
374*4705a71dSRichard Henderson         long k;
375*4705a71dSRichard Henderson         long nr = BITS_TO_LONGS(pages);
376*4705a71dSRichard Henderson 
377*4705a71dSRichard Henderson         idx = (start >> TARGET_PAGE_BITS) / DIRTY_MEMORY_BLOCK_SIZE;
378*4705a71dSRichard Henderson         offset = BIT_WORD((start >> TARGET_PAGE_BITS) %
379*4705a71dSRichard Henderson                           DIRTY_MEMORY_BLOCK_SIZE);
380*4705a71dSRichard Henderson 
381*4705a71dSRichard Henderson         WITH_RCU_READ_LOCK_GUARD() {
382*4705a71dSRichard Henderson             for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
383*4705a71dSRichard Henderson                 blocks[i] =
384*4705a71dSRichard Henderson                     qatomic_rcu_read(&ram_list.dirty_memory[i])->blocks;
385*4705a71dSRichard Henderson             }
386*4705a71dSRichard Henderson 
387*4705a71dSRichard Henderson             for (k = 0; k < nr; k++) {
388*4705a71dSRichard Henderson                 if (bitmap[k]) {
389*4705a71dSRichard Henderson                     unsigned long temp = leul_to_cpu(bitmap[k]);
390*4705a71dSRichard Henderson 
391*4705a71dSRichard Henderson                     nbits = ctpopl(temp);
392*4705a71dSRichard Henderson                     qatomic_or(&blocks[DIRTY_MEMORY_VGA][idx][offset], temp);
393*4705a71dSRichard Henderson 
394*4705a71dSRichard Henderson                     if (global_dirty_tracking) {
395*4705a71dSRichard Henderson                         qatomic_or(
396*4705a71dSRichard Henderson                                 &blocks[DIRTY_MEMORY_MIGRATION][idx][offset],
397*4705a71dSRichard Henderson                                 temp);
398*4705a71dSRichard Henderson                         if (unlikely(
399*4705a71dSRichard Henderson                             global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) {
400*4705a71dSRichard Henderson                             total_dirty_pages += nbits;
401*4705a71dSRichard Henderson                         }
402*4705a71dSRichard Henderson                     }
403*4705a71dSRichard Henderson 
404*4705a71dSRichard Henderson                     num_dirty += nbits;
405*4705a71dSRichard Henderson 
406*4705a71dSRichard Henderson                     if (tcg_enabled()) {
407*4705a71dSRichard Henderson                         qatomic_or(&blocks[DIRTY_MEMORY_CODE][idx][offset],
408*4705a71dSRichard Henderson                                    temp);
409*4705a71dSRichard Henderson                     }
410*4705a71dSRichard Henderson                 }
411*4705a71dSRichard Henderson 
412*4705a71dSRichard Henderson                 if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
413*4705a71dSRichard Henderson                     offset = 0;
414*4705a71dSRichard Henderson                     idx++;
415*4705a71dSRichard Henderson                 }
416*4705a71dSRichard Henderson             }
417*4705a71dSRichard Henderson         }
418*4705a71dSRichard Henderson 
419*4705a71dSRichard Henderson         if (xen_enabled()) {
420*4705a71dSRichard Henderson             xen_hvm_modified_memory(start, pages << TARGET_PAGE_BITS);
421*4705a71dSRichard Henderson         }
422*4705a71dSRichard Henderson     } else {
423*4705a71dSRichard Henderson         uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE;
424*4705a71dSRichard Henderson 
425*4705a71dSRichard Henderson         if (!global_dirty_tracking) {
426*4705a71dSRichard Henderson             clients &= ~(1 << DIRTY_MEMORY_MIGRATION);
427*4705a71dSRichard Henderson         }
428*4705a71dSRichard Henderson 
429*4705a71dSRichard Henderson         /*
430*4705a71dSRichard Henderson          * bitmap-traveling is faster than memory-traveling (for addr...)
431*4705a71dSRichard Henderson          * especially when most of the memory is not dirty.
432*4705a71dSRichard Henderson          */
433*4705a71dSRichard Henderson         for (i = 0; i < len; i++) {
434*4705a71dSRichard Henderson             if (bitmap[i] != 0) {
435*4705a71dSRichard Henderson                 c = leul_to_cpu(bitmap[i]);
436*4705a71dSRichard Henderson                 nbits = ctpopl(c);
437*4705a71dSRichard Henderson                 if (unlikely(global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE)) {
438*4705a71dSRichard Henderson                     total_dirty_pages += nbits;
439*4705a71dSRichard Henderson                 }
440*4705a71dSRichard Henderson                 num_dirty += nbits;
441*4705a71dSRichard Henderson                 do {
442*4705a71dSRichard Henderson                     j = ctzl(c);
443*4705a71dSRichard Henderson                     c &= ~(1ul << j);
444*4705a71dSRichard Henderson                     page_number = (i * HOST_LONG_BITS + j) * hpratio;
445*4705a71dSRichard Henderson                     addr = page_number * TARGET_PAGE_SIZE;
446*4705a71dSRichard Henderson                     ram_addr = start + addr;
447*4705a71dSRichard Henderson                     cpu_physical_memory_set_dirty_range(ram_addr,
448*4705a71dSRichard Henderson                                        TARGET_PAGE_SIZE * hpratio, clients);
449*4705a71dSRichard Henderson                 } while (c != 0);
450*4705a71dSRichard Henderson             }
451*4705a71dSRichard Henderson         }
452*4705a71dSRichard Henderson     }
453*4705a71dSRichard Henderson 
454*4705a71dSRichard Henderson     return num_dirty;
455*4705a71dSRichard Henderson }
456*4705a71dSRichard Henderson #endif /* not _WIN32 */
457*4705a71dSRichard Henderson 
458*4705a71dSRichard Henderson static inline void cpu_physical_memory_dirty_bits_cleared(ram_addr_t start,
459*4705a71dSRichard Henderson                                                           ram_addr_t length)
460*4705a71dSRichard Henderson {
461*4705a71dSRichard Henderson     if (tcg_enabled()) {
462*4705a71dSRichard Henderson         tlb_reset_dirty_range_all(start, length);
463*4705a71dSRichard Henderson     }
464*4705a71dSRichard Henderson 
465*4705a71dSRichard Henderson }
466*4705a71dSRichard Henderson bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
467*4705a71dSRichard Henderson                                               ram_addr_t length,
468*4705a71dSRichard Henderson                                               unsigned client);
469*4705a71dSRichard Henderson 
470*4705a71dSRichard Henderson DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
471*4705a71dSRichard Henderson     (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client);
472*4705a71dSRichard Henderson 
473*4705a71dSRichard Henderson bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
474*4705a71dSRichard Henderson                                             ram_addr_t start,
475*4705a71dSRichard Henderson                                             ram_addr_t length);
476*4705a71dSRichard Henderson 
477*4705a71dSRichard Henderson static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
478*4705a71dSRichard Henderson                                                          ram_addr_t length)
479*4705a71dSRichard Henderson {
480*4705a71dSRichard Henderson     cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_MIGRATION);
481*4705a71dSRichard Henderson     cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_VGA);
482*4705a71dSRichard Henderson     cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_CODE);
483*4705a71dSRichard Henderson }
484*4705a71dSRichard Henderson 
485*4705a71dSRichard Henderson 
486*4705a71dSRichard Henderson /* Called with RCU critical section */
487*4705a71dSRichard Henderson static inline
488*4705a71dSRichard Henderson uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
489*4705a71dSRichard Henderson                                                ram_addr_t start,
490*4705a71dSRichard Henderson                                                ram_addr_t length)
491*4705a71dSRichard Henderson {
492*4705a71dSRichard Henderson     ram_addr_t addr;
493*4705a71dSRichard Henderson     unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS);
494*4705a71dSRichard Henderson     uint64_t num_dirty = 0;
495*4705a71dSRichard Henderson     unsigned long *dest = rb->bmap;
496*4705a71dSRichard Henderson 
497*4705a71dSRichard Henderson     /* start address and length is aligned at the start of a word? */
498*4705a71dSRichard Henderson     if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) ==
499*4705a71dSRichard Henderson          (start + rb->offset) &&
500*4705a71dSRichard Henderson         !(length & ((BITS_PER_LONG << TARGET_PAGE_BITS) - 1))) {
501*4705a71dSRichard Henderson         int k;
502*4705a71dSRichard Henderson         int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
503*4705a71dSRichard Henderson         unsigned long * const *src;
504*4705a71dSRichard Henderson         unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE;
505*4705a71dSRichard Henderson         unsigned long offset = BIT_WORD((word * BITS_PER_LONG) %
506*4705a71dSRichard Henderson                                         DIRTY_MEMORY_BLOCK_SIZE);
507*4705a71dSRichard Henderson         unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
508*4705a71dSRichard Henderson 
509*4705a71dSRichard Henderson         src = qatomic_rcu_read(
510*4705a71dSRichard Henderson                 &ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION])->blocks;
511*4705a71dSRichard Henderson 
512*4705a71dSRichard Henderson         for (k = page; k < page + nr; k++) {
513*4705a71dSRichard Henderson             if (src[idx][offset]) {
514*4705a71dSRichard Henderson                 unsigned long bits = qatomic_xchg(&src[idx][offset], 0);
515*4705a71dSRichard Henderson                 unsigned long new_dirty;
516*4705a71dSRichard Henderson                 new_dirty = ~dest[k];
517*4705a71dSRichard Henderson                 dest[k] |= bits;
518*4705a71dSRichard Henderson                 new_dirty &= bits;
519*4705a71dSRichard Henderson                 num_dirty += ctpopl(new_dirty);
520*4705a71dSRichard Henderson             }
521*4705a71dSRichard Henderson 
522*4705a71dSRichard Henderson             if (++offset >= BITS_TO_LONGS(DIRTY_MEMORY_BLOCK_SIZE)) {
523*4705a71dSRichard Henderson                 offset = 0;
524*4705a71dSRichard Henderson                 idx++;
525*4705a71dSRichard Henderson             }
526*4705a71dSRichard Henderson         }
527*4705a71dSRichard Henderson         if (num_dirty) {
528*4705a71dSRichard Henderson             cpu_physical_memory_dirty_bits_cleared(start, length);
529*4705a71dSRichard Henderson         }
530*4705a71dSRichard Henderson 
531*4705a71dSRichard Henderson         if (rb->clear_bmap) {
532*4705a71dSRichard Henderson             /*
533*4705a71dSRichard Henderson              * Postpone the dirty bitmap clear to the point before we
534*4705a71dSRichard Henderson              * really send the pages, also we will split the clear
535*4705a71dSRichard Henderson              * dirty procedure into smaller chunks.
536*4705a71dSRichard Henderson              */
537*4705a71dSRichard Henderson             clear_bmap_set(rb, start >> TARGET_PAGE_BITS,
538*4705a71dSRichard Henderson                            length >> TARGET_PAGE_BITS);
539*4705a71dSRichard Henderson         } else {
540*4705a71dSRichard Henderson             /* Slow path - still do that in a huge chunk */
541*4705a71dSRichard Henderson             memory_region_clear_dirty_bitmap(rb->mr, start, length);
542*4705a71dSRichard Henderson         }
543*4705a71dSRichard Henderson     } else {
544*4705a71dSRichard Henderson         ram_addr_t offset = rb->offset;
545*4705a71dSRichard Henderson 
546*4705a71dSRichard Henderson         for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
547*4705a71dSRichard Henderson             if (cpu_physical_memory_test_and_clear_dirty(
548*4705a71dSRichard Henderson                         start + addr + offset,
549*4705a71dSRichard Henderson                         TARGET_PAGE_SIZE,
550*4705a71dSRichard Henderson                         DIRTY_MEMORY_MIGRATION)) {
551*4705a71dSRichard Henderson                 long k = (start + addr) >> TARGET_PAGE_BITS;
552*4705a71dSRichard Henderson                 if (!test_and_set_bit(k, dest)) {
553*4705a71dSRichard Henderson                     num_dirty++;
554*4705a71dSRichard Henderson                 }
555*4705a71dSRichard Henderson             }
556*4705a71dSRichard Henderson         }
557*4705a71dSRichard Henderson     }
558*4705a71dSRichard Henderson 
559*4705a71dSRichard Henderson     return num_dirty;
560*4705a71dSRichard Henderson }
561*4705a71dSRichard Henderson 
562*4705a71dSRichard Henderson #endif
563