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