xref: /qemu/system/ram-block-attributes.c (revision 5d6483edaa9232d8f3709f68c8eab4bc2033fb70)
1*5d6483edSChenyi Qiang /*
2*5d6483edSChenyi Qiang  * QEMU ram block attributes
3*5d6483edSChenyi Qiang  *
4*5d6483edSChenyi Qiang  * Copyright Intel
5*5d6483edSChenyi Qiang  *
6*5d6483edSChenyi Qiang  * Author:
7*5d6483edSChenyi Qiang  *      Chenyi Qiang <chenyi.qiang@intel.com>
8*5d6483edSChenyi Qiang  *
9*5d6483edSChenyi Qiang  * SPDX-License-Identifier: GPL-2.0-or-later
10*5d6483edSChenyi Qiang  */
11*5d6483edSChenyi Qiang 
12*5d6483edSChenyi Qiang #include "qemu/osdep.h"
13*5d6483edSChenyi Qiang #include "qemu/error-report.h"
14*5d6483edSChenyi Qiang #include "system/ramblock.h"
15*5d6483edSChenyi Qiang #include "trace.h"
16*5d6483edSChenyi Qiang 
17*5d6483edSChenyi Qiang OBJECT_DEFINE_SIMPLE_TYPE_WITH_INTERFACES(RamBlockAttributes,
18*5d6483edSChenyi Qiang                                           ram_block_attributes,
19*5d6483edSChenyi Qiang                                           RAM_BLOCK_ATTRIBUTES,
20*5d6483edSChenyi Qiang                                           OBJECT,
21*5d6483edSChenyi Qiang                                           { TYPE_RAM_DISCARD_MANAGER },
22*5d6483edSChenyi Qiang                                           { })
23*5d6483edSChenyi Qiang 
24*5d6483edSChenyi Qiang static size_t
25*5d6483edSChenyi Qiang ram_block_attributes_get_block_size(const RamBlockAttributes *attr)
26*5d6483edSChenyi Qiang {
27*5d6483edSChenyi Qiang     /*
28*5d6483edSChenyi Qiang      * Because page conversion could be manipulated in the size of at least 4K
29*5d6483edSChenyi Qiang      * or 4K aligned, Use the host page size as the granularity to track the
30*5d6483edSChenyi Qiang      * memory attribute.
31*5d6483edSChenyi Qiang      */
32*5d6483edSChenyi Qiang     g_assert(attr && attr->ram_block);
33*5d6483edSChenyi Qiang     g_assert(attr->ram_block->page_size == qemu_real_host_page_size());
34*5d6483edSChenyi Qiang     return attr->ram_block->page_size;
35*5d6483edSChenyi Qiang }
36*5d6483edSChenyi Qiang 
37*5d6483edSChenyi Qiang 
38*5d6483edSChenyi Qiang static bool
39*5d6483edSChenyi Qiang ram_block_attributes_rdm_is_populated(const RamDiscardManager *rdm,
40*5d6483edSChenyi Qiang                                       const MemoryRegionSection *section)
41*5d6483edSChenyi Qiang {
42*5d6483edSChenyi Qiang     const RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
43*5d6483edSChenyi Qiang     const size_t block_size = ram_block_attributes_get_block_size(attr);
44*5d6483edSChenyi Qiang     const uint64_t first_bit = section->offset_within_region / block_size;
45*5d6483edSChenyi Qiang     const uint64_t last_bit =
46*5d6483edSChenyi Qiang         first_bit + int128_get64(section->size) / block_size - 1;
47*5d6483edSChenyi Qiang     unsigned long first_discarded_bit;
48*5d6483edSChenyi Qiang 
49*5d6483edSChenyi Qiang     first_discarded_bit = find_next_zero_bit(attr->bitmap, last_bit + 1,
50*5d6483edSChenyi Qiang                                            first_bit);
51*5d6483edSChenyi Qiang     return first_discarded_bit > last_bit;
52*5d6483edSChenyi Qiang }
53*5d6483edSChenyi Qiang 
54*5d6483edSChenyi Qiang typedef int (*ram_block_attributes_section_cb)(MemoryRegionSection *s,
55*5d6483edSChenyi Qiang                                                void *arg);
56*5d6483edSChenyi Qiang 
57*5d6483edSChenyi Qiang static int
58*5d6483edSChenyi Qiang ram_block_attributes_notify_populate_cb(MemoryRegionSection *section,
59*5d6483edSChenyi Qiang                                         void *arg)
60*5d6483edSChenyi Qiang {
61*5d6483edSChenyi Qiang     RamDiscardListener *rdl = arg;
62*5d6483edSChenyi Qiang 
63*5d6483edSChenyi Qiang     return rdl->notify_populate(rdl, section);
64*5d6483edSChenyi Qiang }
65*5d6483edSChenyi Qiang 
66*5d6483edSChenyi Qiang static int
67*5d6483edSChenyi Qiang ram_block_attributes_notify_discard_cb(MemoryRegionSection *section,
68*5d6483edSChenyi Qiang                                        void *arg)
69*5d6483edSChenyi Qiang {
70*5d6483edSChenyi Qiang     RamDiscardListener *rdl = arg;
71*5d6483edSChenyi Qiang 
72*5d6483edSChenyi Qiang     rdl->notify_discard(rdl, section);
73*5d6483edSChenyi Qiang     return 0;
74*5d6483edSChenyi Qiang }
75*5d6483edSChenyi Qiang 
76*5d6483edSChenyi Qiang static int
77*5d6483edSChenyi Qiang ram_block_attributes_for_each_populated_section(const RamBlockAttributes *attr,
78*5d6483edSChenyi Qiang                                                 MemoryRegionSection *section,
79*5d6483edSChenyi Qiang                                                 void *arg,
80*5d6483edSChenyi Qiang                                                 ram_block_attributes_section_cb cb)
81*5d6483edSChenyi Qiang {
82*5d6483edSChenyi Qiang     unsigned long first_bit, last_bit;
83*5d6483edSChenyi Qiang     uint64_t offset, size;
84*5d6483edSChenyi Qiang     const size_t block_size = ram_block_attributes_get_block_size(attr);
85*5d6483edSChenyi Qiang     int ret = 0;
86*5d6483edSChenyi Qiang 
87*5d6483edSChenyi Qiang     first_bit = section->offset_within_region / block_size;
88*5d6483edSChenyi Qiang     first_bit = find_next_bit(attr->bitmap, attr->bitmap_size,
89*5d6483edSChenyi Qiang                               first_bit);
90*5d6483edSChenyi Qiang 
91*5d6483edSChenyi Qiang     while (first_bit < attr->bitmap_size) {
92*5d6483edSChenyi Qiang         MemoryRegionSection tmp = *section;
93*5d6483edSChenyi Qiang 
94*5d6483edSChenyi Qiang         offset = first_bit * block_size;
95*5d6483edSChenyi Qiang         last_bit = find_next_zero_bit(attr->bitmap, attr->bitmap_size,
96*5d6483edSChenyi Qiang                                       first_bit + 1) - 1;
97*5d6483edSChenyi Qiang         size = (last_bit - first_bit + 1) * block_size;
98*5d6483edSChenyi Qiang 
99*5d6483edSChenyi Qiang         if (!memory_region_section_intersect_range(&tmp, offset, size)) {
100*5d6483edSChenyi Qiang             break;
101*5d6483edSChenyi Qiang         }
102*5d6483edSChenyi Qiang 
103*5d6483edSChenyi Qiang         ret = cb(&tmp, arg);
104*5d6483edSChenyi Qiang         if (ret) {
105*5d6483edSChenyi Qiang             error_report("%s: Failed to notify RAM discard listener: %s",
106*5d6483edSChenyi Qiang                          __func__, strerror(-ret));
107*5d6483edSChenyi Qiang             break;
108*5d6483edSChenyi Qiang         }
109*5d6483edSChenyi Qiang 
110*5d6483edSChenyi Qiang         first_bit = find_next_bit(attr->bitmap, attr->bitmap_size,
111*5d6483edSChenyi Qiang                                   last_bit + 2);
112*5d6483edSChenyi Qiang     }
113*5d6483edSChenyi Qiang 
114*5d6483edSChenyi Qiang     return ret;
115*5d6483edSChenyi Qiang }
116*5d6483edSChenyi Qiang 
117*5d6483edSChenyi Qiang static int
118*5d6483edSChenyi Qiang ram_block_attributes_for_each_discarded_section(const RamBlockAttributes *attr,
119*5d6483edSChenyi Qiang                                                 MemoryRegionSection *section,
120*5d6483edSChenyi Qiang                                                 void *arg,
121*5d6483edSChenyi Qiang                                                 ram_block_attributes_section_cb cb)
122*5d6483edSChenyi Qiang {
123*5d6483edSChenyi Qiang     unsigned long first_bit, last_bit;
124*5d6483edSChenyi Qiang     uint64_t offset, size;
125*5d6483edSChenyi Qiang     const size_t block_size = ram_block_attributes_get_block_size(attr);
126*5d6483edSChenyi Qiang     int ret = 0;
127*5d6483edSChenyi Qiang 
128*5d6483edSChenyi Qiang     first_bit = section->offset_within_region / block_size;
129*5d6483edSChenyi Qiang     first_bit = find_next_zero_bit(attr->bitmap, attr->bitmap_size,
130*5d6483edSChenyi Qiang                                    first_bit);
131*5d6483edSChenyi Qiang 
132*5d6483edSChenyi Qiang     while (first_bit < attr->bitmap_size) {
133*5d6483edSChenyi Qiang         MemoryRegionSection tmp = *section;
134*5d6483edSChenyi Qiang 
135*5d6483edSChenyi Qiang         offset = first_bit * block_size;
136*5d6483edSChenyi Qiang         last_bit = find_next_bit(attr->bitmap, attr->bitmap_size,
137*5d6483edSChenyi Qiang                                  first_bit + 1) - 1;
138*5d6483edSChenyi Qiang         size = (last_bit - first_bit + 1) * block_size;
139*5d6483edSChenyi Qiang 
140*5d6483edSChenyi Qiang         if (!memory_region_section_intersect_range(&tmp, offset, size)) {
141*5d6483edSChenyi Qiang             break;
142*5d6483edSChenyi Qiang         }
143*5d6483edSChenyi Qiang 
144*5d6483edSChenyi Qiang         ret = cb(&tmp, arg);
145*5d6483edSChenyi Qiang         if (ret) {
146*5d6483edSChenyi Qiang             error_report("%s: Failed to notify RAM discard listener: %s",
147*5d6483edSChenyi Qiang                          __func__, strerror(-ret));
148*5d6483edSChenyi Qiang             break;
149*5d6483edSChenyi Qiang         }
150*5d6483edSChenyi Qiang 
151*5d6483edSChenyi Qiang         first_bit = find_next_zero_bit(attr->bitmap,
152*5d6483edSChenyi Qiang                                        attr->bitmap_size,
153*5d6483edSChenyi Qiang                                        last_bit + 2);
154*5d6483edSChenyi Qiang     }
155*5d6483edSChenyi Qiang 
156*5d6483edSChenyi Qiang     return ret;
157*5d6483edSChenyi Qiang }
158*5d6483edSChenyi Qiang 
159*5d6483edSChenyi Qiang static uint64_t
160*5d6483edSChenyi Qiang ram_block_attributes_rdm_get_min_granularity(const RamDiscardManager *rdm,
161*5d6483edSChenyi Qiang                                              const MemoryRegion *mr)
162*5d6483edSChenyi Qiang {
163*5d6483edSChenyi Qiang     const RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
164*5d6483edSChenyi Qiang 
165*5d6483edSChenyi Qiang     g_assert(mr == attr->ram_block->mr);
166*5d6483edSChenyi Qiang     return ram_block_attributes_get_block_size(attr);
167*5d6483edSChenyi Qiang }
168*5d6483edSChenyi Qiang 
169*5d6483edSChenyi Qiang static void
170*5d6483edSChenyi Qiang ram_block_attributes_rdm_register_listener(RamDiscardManager *rdm,
171*5d6483edSChenyi Qiang                                            RamDiscardListener *rdl,
172*5d6483edSChenyi Qiang                                            MemoryRegionSection *section)
173*5d6483edSChenyi Qiang {
174*5d6483edSChenyi Qiang     RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
175*5d6483edSChenyi Qiang     int ret;
176*5d6483edSChenyi Qiang 
177*5d6483edSChenyi Qiang     g_assert(section->mr == attr->ram_block->mr);
178*5d6483edSChenyi Qiang     rdl->section = memory_region_section_new_copy(section);
179*5d6483edSChenyi Qiang 
180*5d6483edSChenyi Qiang     QLIST_INSERT_HEAD(&attr->rdl_list, rdl, next);
181*5d6483edSChenyi Qiang 
182*5d6483edSChenyi Qiang     ret = ram_block_attributes_for_each_populated_section(attr, section, rdl,
183*5d6483edSChenyi Qiang                                     ram_block_attributes_notify_populate_cb);
184*5d6483edSChenyi Qiang     if (ret) {
185*5d6483edSChenyi Qiang         error_report("%s: Failed to register RAM discard listener: %s",
186*5d6483edSChenyi Qiang                      __func__, strerror(-ret));
187*5d6483edSChenyi Qiang         exit(1);
188*5d6483edSChenyi Qiang     }
189*5d6483edSChenyi Qiang }
190*5d6483edSChenyi Qiang 
191*5d6483edSChenyi Qiang static void
192*5d6483edSChenyi Qiang ram_block_attributes_rdm_unregister_listener(RamDiscardManager *rdm,
193*5d6483edSChenyi Qiang                                              RamDiscardListener *rdl)
194*5d6483edSChenyi Qiang {
195*5d6483edSChenyi Qiang     RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
196*5d6483edSChenyi Qiang     int ret;
197*5d6483edSChenyi Qiang 
198*5d6483edSChenyi Qiang     g_assert(rdl->section);
199*5d6483edSChenyi Qiang     g_assert(rdl->section->mr == attr->ram_block->mr);
200*5d6483edSChenyi Qiang 
201*5d6483edSChenyi Qiang     if (rdl->double_discard_supported) {
202*5d6483edSChenyi Qiang         rdl->notify_discard(rdl, rdl->section);
203*5d6483edSChenyi Qiang     } else {
204*5d6483edSChenyi Qiang         ret = ram_block_attributes_for_each_populated_section(attr,
205*5d6483edSChenyi Qiang                 rdl->section, rdl, ram_block_attributes_notify_discard_cb);
206*5d6483edSChenyi Qiang         if (ret) {
207*5d6483edSChenyi Qiang             error_report("%s: Failed to unregister RAM discard listener: %s",
208*5d6483edSChenyi Qiang                          __func__, strerror(-ret));
209*5d6483edSChenyi Qiang             exit(1);
210*5d6483edSChenyi Qiang         }
211*5d6483edSChenyi Qiang     }
212*5d6483edSChenyi Qiang 
213*5d6483edSChenyi Qiang     memory_region_section_free_copy(rdl->section);
214*5d6483edSChenyi Qiang     rdl->section = NULL;
215*5d6483edSChenyi Qiang     QLIST_REMOVE(rdl, next);
216*5d6483edSChenyi Qiang }
217*5d6483edSChenyi Qiang 
218*5d6483edSChenyi Qiang typedef struct RamBlockAttributesReplayData {
219*5d6483edSChenyi Qiang     ReplayRamDiscardState fn;
220*5d6483edSChenyi Qiang     void *opaque;
221*5d6483edSChenyi Qiang } RamBlockAttributesReplayData;
222*5d6483edSChenyi Qiang 
223*5d6483edSChenyi Qiang static int ram_block_attributes_rdm_replay_cb(MemoryRegionSection *section,
224*5d6483edSChenyi Qiang                                               void *arg)
225*5d6483edSChenyi Qiang {
226*5d6483edSChenyi Qiang     RamBlockAttributesReplayData *data = arg;
227*5d6483edSChenyi Qiang 
228*5d6483edSChenyi Qiang     return data->fn(section, data->opaque);
229*5d6483edSChenyi Qiang }
230*5d6483edSChenyi Qiang 
231*5d6483edSChenyi Qiang static int
232*5d6483edSChenyi Qiang ram_block_attributes_rdm_replay_populated(const RamDiscardManager *rdm,
233*5d6483edSChenyi Qiang                                           MemoryRegionSection *section,
234*5d6483edSChenyi Qiang                                           ReplayRamDiscardState replay_fn,
235*5d6483edSChenyi Qiang                                           void *opaque)
236*5d6483edSChenyi Qiang {
237*5d6483edSChenyi Qiang     RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
238*5d6483edSChenyi Qiang     RamBlockAttributesReplayData data = { .fn = replay_fn, .opaque = opaque };
239*5d6483edSChenyi Qiang 
240*5d6483edSChenyi Qiang     g_assert(section->mr == attr->ram_block->mr);
241*5d6483edSChenyi Qiang     return ram_block_attributes_for_each_populated_section(attr, section, &data,
242*5d6483edSChenyi Qiang                                             ram_block_attributes_rdm_replay_cb);
243*5d6483edSChenyi Qiang }
244*5d6483edSChenyi Qiang 
245*5d6483edSChenyi Qiang static int
246*5d6483edSChenyi Qiang ram_block_attributes_rdm_replay_discarded(const RamDiscardManager *rdm,
247*5d6483edSChenyi Qiang                                           MemoryRegionSection *section,
248*5d6483edSChenyi Qiang                                           ReplayRamDiscardState replay_fn,
249*5d6483edSChenyi Qiang                                           void *opaque)
250*5d6483edSChenyi Qiang {
251*5d6483edSChenyi Qiang     RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(rdm);
252*5d6483edSChenyi Qiang     RamBlockAttributesReplayData data = { .fn = replay_fn, .opaque = opaque };
253*5d6483edSChenyi Qiang 
254*5d6483edSChenyi Qiang     g_assert(section->mr == attr->ram_block->mr);
255*5d6483edSChenyi Qiang     return ram_block_attributes_for_each_discarded_section(attr, section, &data,
256*5d6483edSChenyi Qiang                                             ram_block_attributes_rdm_replay_cb);
257*5d6483edSChenyi Qiang }
258*5d6483edSChenyi Qiang 
259*5d6483edSChenyi Qiang static bool
260*5d6483edSChenyi Qiang ram_block_attributes_is_valid_range(RamBlockAttributes *attr, uint64_t offset,
261*5d6483edSChenyi Qiang                                     uint64_t size)
262*5d6483edSChenyi Qiang {
263*5d6483edSChenyi Qiang     MemoryRegion *mr = attr->ram_block->mr;
264*5d6483edSChenyi Qiang 
265*5d6483edSChenyi Qiang     g_assert(mr);
266*5d6483edSChenyi Qiang 
267*5d6483edSChenyi Qiang     uint64_t region_size = memory_region_size(mr);
268*5d6483edSChenyi Qiang     const size_t block_size = ram_block_attributes_get_block_size(attr);
269*5d6483edSChenyi Qiang 
270*5d6483edSChenyi Qiang     if (!QEMU_IS_ALIGNED(offset, block_size) ||
271*5d6483edSChenyi Qiang         !QEMU_IS_ALIGNED(size, block_size)) {
272*5d6483edSChenyi Qiang         return false;
273*5d6483edSChenyi Qiang     }
274*5d6483edSChenyi Qiang     if (offset + size <= offset) {
275*5d6483edSChenyi Qiang         return false;
276*5d6483edSChenyi Qiang     }
277*5d6483edSChenyi Qiang     if (offset + size > region_size) {
278*5d6483edSChenyi Qiang         return false;
279*5d6483edSChenyi Qiang     }
280*5d6483edSChenyi Qiang     return true;
281*5d6483edSChenyi Qiang }
282*5d6483edSChenyi Qiang 
283*5d6483edSChenyi Qiang static void ram_block_attributes_notify_discard(RamBlockAttributes *attr,
284*5d6483edSChenyi Qiang                                                 uint64_t offset,
285*5d6483edSChenyi Qiang                                                 uint64_t size)
286*5d6483edSChenyi Qiang {
287*5d6483edSChenyi Qiang     RamDiscardListener *rdl;
288*5d6483edSChenyi Qiang 
289*5d6483edSChenyi Qiang     QLIST_FOREACH(rdl, &attr->rdl_list, next) {
290*5d6483edSChenyi Qiang         MemoryRegionSection tmp = *rdl->section;
291*5d6483edSChenyi Qiang 
292*5d6483edSChenyi Qiang         if (!memory_region_section_intersect_range(&tmp, offset, size)) {
293*5d6483edSChenyi Qiang             continue;
294*5d6483edSChenyi Qiang         }
295*5d6483edSChenyi Qiang         rdl->notify_discard(rdl, &tmp);
296*5d6483edSChenyi Qiang     }
297*5d6483edSChenyi Qiang }
298*5d6483edSChenyi Qiang 
299*5d6483edSChenyi Qiang static int
300*5d6483edSChenyi Qiang ram_block_attributes_notify_populate(RamBlockAttributes *attr,
301*5d6483edSChenyi Qiang                                      uint64_t offset, uint64_t size)
302*5d6483edSChenyi Qiang {
303*5d6483edSChenyi Qiang     RamDiscardListener *rdl;
304*5d6483edSChenyi Qiang     int ret = 0;
305*5d6483edSChenyi Qiang 
306*5d6483edSChenyi Qiang     QLIST_FOREACH(rdl, &attr->rdl_list, next) {
307*5d6483edSChenyi Qiang         MemoryRegionSection tmp = *rdl->section;
308*5d6483edSChenyi Qiang 
309*5d6483edSChenyi Qiang         if (!memory_region_section_intersect_range(&tmp, offset, size)) {
310*5d6483edSChenyi Qiang             continue;
311*5d6483edSChenyi Qiang         }
312*5d6483edSChenyi Qiang         ret = rdl->notify_populate(rdl, &tmp);
313*5d6483edSChenyi Qiang         if (ret) {
314*5d6483edSChenyi Qiang             break;
315*5d6483edSChenyi Qiang         }
316*5d6483edSChenyi Qiang     }
317*5d6483edSChenyi Qiang 
318*5d6483edSChenyi Qiang     return ret;
319*5d6483edSChenyi Qiang }
320*5d6483edSChenyi Qiang 
321*5d6483edSChenyi Qiang int ram_block_attributes_state_change(RamBlockAttributes *attr,
322*5d6483edSChenyi Qiang                                       uint64_t offset, uint64_t size,
323*5d6483edSChenyi Qiang                                       bool to_discard)
324*5d6483edSChenyi Qiang {
325*5d6483edSChenyi Qiang     const size_t block_size = ram_block_attributes_get_block_size(attr);
326*5d6483edSChenyi Qiang     const unsigned long first_bit = offset / block_size;
327*5d6483edSChenyi Qiang     const unsigned long nbits = size / block_size;
328*5d6483edSChenyi Qiang     const unsigned long last_bit = first_bit + nbits - 1;
329*5d6483edSChenyi Qiang     const bool is_discarded = find_next_bit(attr->bitmap, attr->bitmap_size,
330*5d6483edSChenyi Qiang                                             first_bit) > last_bit;
331*5d6483edSChenyi Qiang     const bool is_populated = find_next_zero_bit(attr->bitmap,
332*5d6483edSChenyi Qiang                                 attr->bitmap_size, first_bit) > last_bit;
333*5d6483edSChenyi Qiang     unsigned long bit;
334*5d6483edSChenyi Qiang     int ret = 0;
335*5d6483edSChenyi Qiang 
336*5d6483edSChenyi Qiang     if (!ram_block_attributes_is_valid_range(attr, offset, size)) {
337*5d6483edSChenyi Qiang         error_report("%s, invalid range: offset 0x%" PRIx64 ", size "
338*5d6483edSChenyi Qiang                      "0x%" PRIx64, __func__, offset, size);
339*5d6483edSChenyi Qiang         return -EINVAL;
340*5d6483edSChenyi Qiang     }
341*5d6483edSChenyi Qiang 
342*5d6483edSChenyi Qiang     trace_ram_block_attributes_state_change(offset, size,
343*5d6483edSChenyi Qiang                                             is_discarded ? "discarded" :
344*5d6483edSChenyi Qiang                                             is_populated ? "populated" :
345*5d6483edSChenyi Qiang                                             "mixture",
346*5d6483edSChenyi Qiang                                             to_discard ? "discarded" :
347*5d6483edSChenyi Qiang                                             "populated");
348*5d6483edSChenyi Qiang     if (to_discard) {
349*5d6483edSChenyi Qiang         if (is_discarded) {
350*5d6483edSChenyi Qiang             /* Already private */
351*5d6483edSChenyi Qiang         } else if (is_populated) {
352*5d6483edSChenyi Qiang             /* Completely shared */
353*5d6483edSChenyi Qiang             bitmap_clear(attr->bitmap, first_bit, nbits);
354*5d6483edSChenyi Qiang             ram_block_attributes_notify_discard(attr, offset, size);
355*5d6483edSChenyi Qiang         } else {
356*5d6483edSChenyi Qiang             /* Unexpected mixture: process individual blocks */
357*5d6483edSChenyi Qiang             for (bit = first_bit; bit < first_bit + nbits; bit++) {
358*5d6483edSChenyi Qiang                 if (!test_bit(bit, attr->bitmap)) {
359*5d6483edSChenyi Qiang                     continue;
360*5d6483edSChenyi Qiang                 }
361*5d6483edSChenyi Qiang                 clear_bit(bit, attr->bitmap);
362*5d6483edSChenyi Qiang                 ram_block_attributes_notify_discard(attr, bit * block_size,
363*5d6483edSChenyi Qiang                                                     block_size);
364*5d6483edSChenyi Qiang             }
365*5d6483edSChenyi Qiang         }
366*5d6483edSChenyi Qiang     } else {
367*5d6483edSChenyi Qiang         if (is_populated) {
368*5d6483edSChenyi Qiang             /* Already shared */
369*5d6483edSChenyi Qiang         } else if (is_discarded) {
370*5d6483edSChenyi Qiang             /* Completely private */
371*5d6483edSChenyi Qiang             bitmap_set(attr->bitmap, first_bit, nbits);
372*5d6483edSChenyi Qiang             ret = ram_block_attributes_notify_populate(attr, offset, size);
373*5d6483edSChenyi Qiang         } else {
374*5d6483edSChenyi Qiang             /* Unexpected mixture: process individual blocks */
375*5d6483edSChenyi Qiang             for (bit = first_bit; bit < first_bit + nbits; bit++) {
376*5d6483edSChenyi Qiang                 if (test_bit(bit, attr->bitmap)) {
377*5d6483edSChenyi Qiang                     continue;
378*5d6483edSChenyi Qiang                 }
379*5d6483edSChenyi Qiang                 set_bit(bit, attr->bitmap);
380*5d6483edSChenyi Qiang                 ret = ram_block_attributes_notify_populate(attr,
381*5d6483edSChenyi Qiang                                                            bit * block_size,
382*5d6483edSChenyi Qiang                                                            block_size);
383*5d6483edSChenyi Qiang                 if (ret) {
384*5d6483edSChenyi Qiang                     break;
385*5d6483edSChenyi Qiang                 }
386*5d6483edSChenyi Qiang             }
387*5d6483edSChenyi Qiang         }
388*5d6483edSChenyi Qiang     }
389*5d6483edSChenyi Qiang 
390*5d6483edSChenyi Qiang     return ret;
391*5d6483edSChenyi Qiang }
392*5d6483edSChenyi Qiang 
393*5d6483edSChenyi Qiang RamBlockAttributes *ram_block_attributes_create(RAMBlock *ram_block)
394*5d6483edSChenyi Qiang {
395*5d6483edSChenyi Qiang     const int block_size  = qemu_real_host_page_size();
396*5d6483edSChenyi Qiang     RamBlockAttributes *attr;
397*5d6483edSChenyi Qiang     MemoryRegion *mr = ram_block->mr;
398*5d6483edSChenyi Qiang 
399*5d6483edSChenyi Qiang     attr = RAM_BLOCK_ATTRIBUTES(object_new(TYPE_RAM_BLOCK_ATTRIBUTES));
400*5d6483edSChenyi Qiang 
401*5d6483edSChenyi Qiang     attr->ram_block = ram_block;
402*5d6483edSChenyi Qiang     if (memory_region_set_ram_discard_manager(mr, RAM_DISCARD_MANAGER(attr))) {
403*5d6483edSChenyi Qiang         object_unref(OBJECT(attr));
404*5d6483edSChenyi Qiang         return NULL;
405*5d6483edSChenyi Qiang     }
406*5d6483edSChenyi Qiang     attr->bitmap_size =
407*5d6483edSChenyi Qiang         ROUND_UP(int128_get64(mr->size), block_size) / block_size;
408*5d6483edSChenyi Qiang     attr->bitmap = bitmap_new(attr->bitmap_size);
409*5d6483edSChenyi Qiang 
410*5d6483edSChenyi Qiang     return attr;
411*5d6483edSChenyi Qiang }
412*5d6483edSChenyi Qiang 
413*5d6483edSChenyi Qiang void ram_block_attributes_destroy(RamBlockAttributes *attr)
414*5d6483edSChenyi Qiang {
415*5d6483edSChenyi Qiang     g_assert(attr);
416*5d6483edSChenyi Qiang 
417*5d6483edSChenyi Qiang     g_free(attr->bitmap);
418*5d6483edSChenyi Qiang     memory_region_set_ram_discard_manager(attr->ram_block->mr, NULL);
419*5d6483edSChenyi Qiang     object_unref(OBJECT(attr));
420*5d6483edSChenyi Qiang }
421*5d6483edSChenyi Qiang 
422*5d6483edSChenyi Qiang static void ram_block_attributes_init(Object *obj)
423*5d6483edSChenyi Qiang {
424*5d6483edSChenyi Qiang     RamBlockAttributes *attr = RAM_BLOCK_ATTRIBUTES(obj);
425*5d6483edSChenyi Qiang 
426*5d6483edSChenyi Qiang     QLIST_INIT(&attr->rdl_list);
427*5d6483edSChenyi Qiang }
428*5d6483edSChenyi Qiang 
429*5d6483edSChenyi Qiang static void ram_block_attributes_finalize(Object *obj)
430*5d6483edSChenyi Qiang {
431*5d6483edSChenyi Qiang }
432*5d6483edSChenyi Qiang 
433*5d6483edSChenyi Qiang static void ram_block_attributes_class_init(ObjectClass *klass,
434*5d6483edSChenyi Qiang                                             const void *data)
435*5d6483edSChenyi Qiang {
436*5d6483edSChenyi Qiang     RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_CLASS(klass);
437*5d6483edSChenyi Qiang 
438*5d6483edSChenyi Qiang     rdmc->get_min_granularity = ram_block_attributes_rdm_get_min_granularity;
439*5d6483edSChenyi Qiang     rdmc->register_listener = ram_block_attributes_rdm_register_listener;
440*5d6483edSChenyi Qiang     rdmc->unregister_listener = ram_block_attributes_rdm_unregister_listener;
441*5d6483edSChenyi Qiang     rdmc->is_populated = ram_block_attributes_rdm_is_populated;
442*5d6483edSChenyi Qiang     rdmc->replay_populated = ram_block_attributes_rdm_replay_populated;
443*5d6483edSChenyi Qiang     rdmc->replay_discarded = ram_block_attributes_rdm_replay_discarded;
444*5d6483edSChenyi Qiang }
445