1 /* 2 * QEMU Hyper-V Dynamic Memory Protocol driver 3 * 4 * Copyright (C) 2020-2023 Oracle and/or its affiliates. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #ifndef HW_HYPERV_HV_BALLOON_PAGE_RANGE_TREE_H 11 #define HW_HYPERV_HV_BALLOON_PAGE_RANGE_TREE_H 12 13 14 /* PageRange */ 15 typedef struct PageRange { 16 uint64_t start; 17 uint64_t count; 18 } PageRange; 19 20 /* return just the part of range before (start) */ 21 static inline void page_range_part_before(const PageRange *range, 22 uint64_t start, PageRange *out) 23 { 24 uint64_t endr = range->start + range->count; 25 uint64_t end = MIN(endr, start); 26 27 out->start = range->start; 28 if (end > out->start) { 29 out->count = end - out->start; 30 } else { 31 out->count = 0; 32 } 33 } 34 35 /* return just the part of range after (start, count) */ 36 static inline void page_range_part_after(const PageRange *range, 37 uint64_t start, uint64_t count, 38 PageRange *out) 39 { 40 uint64_t end = range->start + range->count; 41 uint64_t ends = start + count; 42 43 out->start = MAX(range->start, ends); 44 if (end > out->start) { 45 out->count = end - out->start; 46 } else { 47 out->count = 0; 48 } 49 } 50 51 static inline void page_range_intersect(const PageRange *range, 52 uint64_t start, uint64_t count, 53 PageRange *out) 54 { 55 uint64_t end1 = range->start + range->count; 56 uint64_t end2 = start + count; 57 uint64_t end = MIN(end1, end2); 58 59 out->start = MAX(range->start, start); 60 out->count = out->start < end ? end - out->start : 0; 61 } 62 63 static inline uint64_t page_range_intersection_size(const PageRange *range, 64 uint64_t start, uint64_t count) 65 { 66 PageRange trange; 67 68 page_range_intersect(range, start, count, &trange); 69 return trange.count; 70 } 71 72 static inline bool page_range_joinable_left(const PageRange *range, 73 uint64_t start, uint64_t count) 74 { 75 return start + count == range->start; 76 } 77 78 static inline bool page_range_joinable_right(const PageRange *range, 79 uint64_t start, uint64_t count) 80 { 81 return range->start + range->count == start; 82 } 83 84 static inline bool page_range_joinable(const PageRange *range, 85 uint64_t start, uint64_t count) 86 { 87 return page_range_joinable_left(range, start, count) || 88 page_range_joinable_right(range, start, count); 89 } 90 91 /* PageRangeTree */ 92 /* type safety */ 93 typedef struct PageRangeTree { 94 GTree *t; 95 } PageRangeTree; 96 97 static inline bool page_range_tree_is_empty(PageRangeTree tree) 98 { 99 guint nnodes = g_tree_nnodes(tree.t); 100 101 return nnodes == 0; 102 } 103 104 void hvb_page_range_tree_init(PageRangeTree *tree); 105 void hvb_page_range_tree_destroy(PageRangeTree *tree); 106 107 bool hvb_page_range_tree_intree_any(PageRangeTree tree, 108 uint64_t start, uint64_t count); 109 110 bool hvb_page_range_tree_pop(PageRangeTree tree, PageRange *out, 111 uint64_t maxcount); 112 113 void hvb_page_range_tree_insert(PageRangeTree tree, 114 uint64_t start, uint64_t count, 115 uint64_t *dupcount); 116 117 #endif 118