xref: /openbmc/qemu/include/exec/ram_addr.h (revision a23797ef)
1 /*
2  * Declarations for cpu physical memory functions
3  *
4  * Copyright 2011 Red Hat, Inc. and/or its affiliates
5  *
6  * Authors:
7  *  Avi Kivity <avi@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or
10  * later.  See the COPYING file in the top-level directory.
11  *
12  */
13 
14 /*
15  * This header is for use by exec.c and memory.c ONLY.  Do not include it.
16  * The functions declared here will be removed soon.
17  */
18 
19 #ifndef RAM_ADDR_H
20 #define RAM_ADDR_H
21 
22 #ifndef CONFIG_USER_ONLY
23 #include "hw/xen/xen.h"
24 
25 ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
26                                     bool share, const char *mem_path,
27                                     Error **errp);
28 ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
29                                    MemoryRegion *mr, Error **errp);
30 ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp);
31 ram_addr_t qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t max_size,
32                                      void (*resized)(const char*,
33                                                      uint64_t length,
34                                                      void *host),
35                                      MemoryRegion *mr, Error **errp);
36 int qemu_get_ram_fd(ram_addr_t addr);
37 void *qemu_get_ram_block_host_ptr(ram_addr_t addr);
38 void *qemu_get_ram_ptr(ram_addr_t addr);
39 void qemu_ram_free(ram_addr_t addr);
40 void qemu_ram_free_from_ptr(ram_addr_t addr);
41 
42 int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp);
43 
44 #define DIRTY_CLIENTS_ALL     ((1 << DIRTY_MEMORY_NUM) - 1)
45 #define DIRTY_CLIENTS_NOCODE  (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))
46 
47 static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
48                                                  ram_addr_t length,
49                                                  unsigned client)
50 {
51     unsigned long end, page, next;
52 
53     assert(client < DIRTY_MEMORY_NUM);
54 
55     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
56     page = start >> TARGET_PAGE_BITS;
57     next = find_next_bit(ram_list.dirty_memory[client], end, page);
58 
59     return next < end;
60 }
61 
62 static inline bool cpu_physical_memory_all_dirty(ram_addr_t start,
63                                                  ram_addr_t length,
64                                                  unsigned client)
65 {
66     unsigned long end, page, next;
67 
68     assert(client < DIRTY_MEMORY_NUM);
69 
70     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
71     page = start >> TARGET_PAGE_BITS;
72     next = find_next_zero_bit(ram_list.dirty_memory[client], end, page);
73 
74     return next >= end;
75 }
76 
77 static inline bool cpu_physical_memory_get_dirty_flag(ram_addr_t addr,
78                                                       unsigned client)
79 {
80     return cpu_physical_memory_get_dirty(addr, 1, client);
81 }
82 
83 static inline bool cpu_physical_memory_is_clean(ram_addr_t addr)
84 {
85     bool vga = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_VGA);
86     bool code = cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_CODE);
87     bool migration =
88         cpu_physical_memory_get_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
89     return !(vga && code && migration);
90 }
91 
92 static inline uint8_t cpu_physical_memory_range_includes_clean(ram_addr_t start,
93                                                                ram_addr_t length,
94                                                                uint8_t mask)
95 {
96     uint8_t ret = 0;
97 
98     if (mask & (1 << DIRTY_MEMORY_VGA) &&
99         !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_VGA)) {
100         ret |= (1 << DIRTY_MEMORY_VGA);
101     }
102     if (mask & (1 << DIRTY_MEMORY_CODE) &&
103         !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_CODE)) {
104         ret |= (1 << DIRTY_MEMORY_CODE);
105     }
106     if (mask & (1 << DIRTY_MEMORY_MIGRATION) &&
107         !cpu_physical_memory_all_dirty(start, length, DIRTY_MEMORY_MIGRATION)) {
108         ret |= (1 << DIRTY_MEMORY_MIGRATION);
109     }
110     return ret;
111 }
112 
113 static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
114                                                       unsigned client)
115 {
116     assert(client < DIRTY_MEMORY_NUM);
117     set_bit_atomic(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]);
118 }
119 
120 static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
121                                                        ram_addr_t length,
122                                                        uint8_t mask)
123 {
124     unsigned long end, page;
125     unsigned long **d = ram_list.dirty_memory;
126 
127     end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
128     page = start >> TARGET_PAGE_BITS;
129     if (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) {
130         bitmap_set_atomic(d[DIRTY_MEMORY_MIGRATION], page, end - page);
131     }
132     if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) {
133         bitmap_set_atomic(d[DIRTY_MEMORY_VGA], page, end - page);
134     }
135     if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) {
136         bitmap_set_atomic(d[DIRTY_MEMORY_CODE], page, end - page);
137     }
138     xen_modified_memory(start, length);
139 }
140 
141 #if !defined(_WIN32)
142 static inline void cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap,
143                                                           ram_addr_t start,
144                                                           ram_addr_t pages)
145 {
146     unsigned long i, j;
147     unsigned long page_number, c;
148     hwaddr addr;
149     ram_addr_t ram_addr;
150     unsigned long len = (pages + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
151     unsigned long hpratio = getpagesize() / TARGET_PAGE_SIZE;
152     unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
153 
154     /* start address is aligned at the start of a word? */
155     if ((((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) &&
156         (hpratio == 1)) {
157         long k;
158         long nr = BITS_TO_LONGS(pages);
159 
160         for (k = 0; k < nr; k++) {
161             if (bitmap[k]) {
162                 unsigned long temp = leul_to_cpu(bitmap[k]);
163                 unsigned long **d = ram_list.dirty_memory;
164 
165                 atomic_or(&d[DIRTY_MEMORY_MIGRATION][page + k], temp);
166                 atomic_or(&d[DIRTY_MEMORY_VGA][page + k], temp);
167                 if (tcg_enabled()) {
168                     atomic_or(&d[DIRTY_MEMORY_CODE][page + k], temp);
169                 }
170             }
171         }
172         xen_modified_memory(start, pages << TARGET_PAGE_BITS);
173     } else {
174         uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE;
175         /*
176          * bitmap-traveling is faster than memory-traveling (for addr...)
177          * especially when most of the memory is not dirty.
178          */
179         for (i = 0; i < len; i++) {
180             if (bitmap[i] != 0) {
181                 c = leul_to_cpu(bitmap[i]);
182                 do {
183                     j = ctzl(c);
184                     c &= ~(1ul << j);
185                     page_number = (i * HOST_LONG_BITS + j) * hpratio;
186                     addr = page_number * TARGET_PAGE_SIZE;
187                     ram_addr = start + addr;
188                     cpu_physical_memory_set_dirty_range(ram_addr,
189                                        TARGET_PAGE_SIZE * hpratio, clients);
190                 } while (c != 0);
191             }
192         }
193     }
194 }
195 #endif /* not _WIN32 */
196 
197 bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
198                                               ram_addr_t length,
199                                               unsigned client);
200 
201 static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
202                                                          ram_addr_t length)
203 {
204     cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_MIGRATION);
205     cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_VGA);
206     cpu_physical_memory_test_and_clear_dirty(start, length, DIRTY_MEMORY_CODE);
207 }
208 
209 
210 static inline
211 uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
212                                                ram_addr_t start,
213                                                ram_addr_t length)
214 {
215     ram_addr_t addr;
216     unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
217     uint64_t num_dirty = 0;
218 
219     /* start address is aligned at the start of a word? */
220     if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
221         int k;
222         int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
223         unsigned long *src = ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION];
224 
225         for (k = page; k < page + nr; k++) {
226             if (src[k]) {
227                 unsigned long bits = atomic_xchg(&src[k], 0);
228                 unsigned long new_dirty;
229                 new_dirty = ~dest[k];
230                 dest[k] |= bits;
231                 new_dirty &= bits;
232                 num_dirty += ctpopl(new_dirty);
233             }
234         }
235     } else {
236         for (addr = 0; addr < length; addr += TARGET_PAGE_SIZE) {
237             if (cpu_physical_memory_test_and_clear_dirty(
238                         start + addr,
239                         TARGET_PAGE_SIZE,
240                         DIRTY_MEMORY_MIGRATION)) {
241                 long k = (start + addr) >> TARGET_PAGE_BITS;
242                 if (!test_and_set_bit(k, dest)) {
243                     num_dirty++;
244                 }
245             }
246         }
247     }
248 
249     return num_dirty;
250 }
251 
252 #endif
253 #endif
254