xref: /openbmc/qemu/include/qemu/range.h (revision b439595a)
1fec0fc0aSEric Blake /*
2fec0fc0aSEric Blake  * QEMU 64-bit address ranges
3fec0fc0aSEric Blake  *
4fec0fc0aSEric Blake  * Copyright (c) 2015-2016 Red Hat, Inc.
5fec0fc0aSEric Blake  *
6e361a772SThomas Huth  * This program is free software; you can redistribute it and/or
7fec0fc0aSEric Blake  * modify it under the terms of the GNU General Public
8fec0fc0aSEric Blake  * License as published by the Free Software Foundation; either
9fec0fc0aSEric Blake  * version 2 of the License, or (at your option) any later version.
10fec0fc0aSEric Blake  *
11e361a772SThomas Huth  * This program is distributed in the hope that it will be useful,
12fec0fc0aSEric Blake  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fec0fc0aSEric Blake  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e361a772SThomas Huth  * General Public License for more details.
15fec0fc0aSEric Blake  *
16e361a772SThomas Huth  * You should have received a copy of the GNU General Public License
17e361a772SThomas Huth  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18fec0fc0aSEric Blake  */
19fec0fc0aSEric Blake 
201de7afc9SPaolo Bonzini #ifndef QEMU_RANGE_H
211de7afc9SPaolo Bonzini #define QEMU_RANGE_H
221de7afc9SPaolo Bonzini 
23620ac82eSMichael S. Tsirkin /*
24620ac82eSMichael S. Tsirkin  * Operations on 64 bit address ranges.
25620ac82eSMichael S. Tsirkin  * Notes:
266dd726a2SMarkus Armbruster  * - Ranges must not wrap around 0, but can include UINT64_MAX.
27620ac82eSMichael S. Tsirkin  */
28620ac82eSMichael S. Tsirkin 
29620ac82eSMichael S. Tsirkin struct Range {
306dd726a2SMarkus Armbruster     /*
316dd726a2SMarkus Armbruster      * Do not access members directly, use the functions!
326dd726a2SMarkus Armbruster      * A non-empty range has @lob <= @upb.
336dd726a2SMarkus Armbruster      * An empty range has @lob == @upb + 1.
346dd726a2SMarkus Armbruster      */
356dd726a2SMarkus Armbruster     uint64_t lob;        /* inclusive lower bound */
366dd726a2SMarkus Armbruster     uint64_t upb;        /* inclusive upper bound */
37620ac82eSMichael S. Tsirkin };
38620ac82eSMichael S. Tsirkin 
range_invariant(const Range * range)39d56978f4SDavid Hildenbrand static inline void range_invariant(const Range *range)
40a0efbf16SMarkus Armbruster {
416dd726a2SMarkus Armbruster     assert(range->lob <= range->upb || range->lob == range->upb + 1);
42a0efbf16SMarkus Armbruster }
43a0efbf16SMarkus Armbruster 
44a0efbf16SMarkus Armbruster /* Compound literal encoding the empty range */
456dd726a2SMarkus Armbruster #define range_empty ((Range){ .lob = 1, .upb = 0 })
46a0efbf16SMarkus Armbruster 
47a0efbf16SMarkus Armbruster /* Is @range empty? */
range_is_empty(const Range * range)48d56978f4SDavid Hildenbrand static inline bool range_is_empty(const Range *range)
49a0efbf16SMarkus Armbruster {
50a0efbf16SMarkus Armbruster     range_invariant(range);
516dd726a2SMarkus Armbruster     return range->lob > range->upb;
52a0efbf16SMarkus Armbruster }
53a0efbf16SMarkus Armbruster 
54a0efbf16SMarkus Armbruster /* Does @range contain @val? */
range_contains(const Range * range,uint64_t val)55d56978f4SDavid Hildenbrand static inline bool range_contains(const Range *range, uint64_t val)
56a0efbf16SMarkus Armbruster {
576dd726a2SMarkus Armbruster     return val >= range->lob && val <= range->upb;
58a0efbf16SMarkus Armbruster }
59a0efbf16SMarkus Armbruster 
60a0efbf16SMarkus Armbruster /* Initialize @range to the empty range */
range_make_empty(Range * range)61a0efbf16SMarkus Armbruster static inline void range_make_empty(Range *range)
62a0efbf16SMarkus Armbruster {
63a0efbf16SMarkus Armbruster     *range = range_empty;
64a0efbf16SMarkus Armbruster     assert(range_is_empty(range));
65a0efbf16SMarkus Armbruster }
66a0efbf16SMarkus Armbruster 
67a0efbf16SMarkus Armbruster /*
68a0efbf16SMarkus Armbruster  * Initialize @range to span the interval [@lob,@upb].
69a0efbf16SMarkus Armbruster  * Both bounds are inclusive.
70a0efbf16SMarkus Armbruster  * The interval must not be empty, i.e. @lob must be less than or
71a0efbf16SMarkus Armbruster  * equal @upb.
72a0efbf16SMarkus Armbruster  */
range_set_bounds(Range * range,uint64_t lob,uint64_t upb)73a0efbf16SMarkus Armbruster static inline void range_set_bounds(Range *range, uint64_t lob, uint64_t upb)
74a0efbf16SMarkus Armbruster {
756dd726a2SMarkus Armbruster     range->lob = lob;
766dd726a2SMarkus Armbruster     range->upb = upb;
77a0efbf16SMarkus Armbruster     assert(!range_is_empty(range));
78a0efbf16SMarkus Armbruster }
79a0efbf16SMarkus Armbruster 
80a0efbf16SMarkus Armbruster /*
81a0efbf16SMarkus Armbruster  * Initialize @range to span the interval [@lob,@upb_plus1).
82a0efbf16SMarkus Armbruster  * The lower bound is inclusive, the upper bound is exclusive.
83a0efbf16SMarkus Armbruster  * Zero @upb_plus1 is special: if @lob is also zero, set @range to the
84a0efbf16SMarkus Armbruster  * empty range.  Else, set @range to [@lob,UINT64_MAX].
85a0efbf16SMarkus Armbruster  */
range_set_bounds1(Range * range,uint64_t lob,uint64_t upb_plus1)86a0efbf16SMarkus Armbruster static inline void range_set_bounds1(Range *range,
87a0efbf16SMarkus Armbruster                                      uint64_t lob, uint64_t upb_plus1)
88a0efbf16SMarkus Armbruster {
896dd726a2SMarkus Armbruster     if (!lob && !upb_plus1) {
906dd726a2SMarkus Armbruster         *range = range_empty;
916dd726a2SMarkus Armbruster     } else {
926dd726a2SMarkus Armbruster         range->lob = lob;
936dd726a2SMarkus Armbruster         range->upb = upb_plus1 - 1;
946dd726a2SMarkus Armbruster     }
95a0efbf16SMarkus Armbruster     range_invariant(range);
96a0efbf16SMarkus Armbruster }
97a0efbf16SMarkus Armbruster 
98a0efbf16SMarkus Armbruster /* Return @range's lower bound.  @range must not be empty. */
range_lob(Range * range)99a0efbf16SMarkus Armbruster static inline uint64_t range_lob(Range *range)
100a0efbf16SMarkus Armbruster {
101a0efbf16SMarkus Armbruster     assert(!range_is_empty(range));
1026dd726a2SMarkus Armbruster     return range->lob;
103a0efbf16SMarkus Armbruster }
104a0efbf16SMarkus Armbruster 
105a0efbf16SMarkus Armbruster /* Return @range's upper bound.  @range must not be empty. */
range_upb(Range * range)106a0efbf16SMarkus Armbruster static inline uint64_t range_upb(Range *range)
107a0efbf16SMarkus Armbruster {
108a0efbf16SMarkus Armbruster     assert(!range_is_empty(range));
1096dd726a2SMarkus Armbruster     return range->upb;
110a0efbf16SMarkus Armbruster }
111a0efbf16SMarkus Armbruster 
112a0efbf16SMarkus Armbruster /*
113f3b0b626SDavid Hildenbrand  * Initialize @range to span the interval [@lob,@lob + @size - 1].
114f3b0b626SDavid Hildenbrand  * @size may be 0. If the range would overflow, returns -ERANGE, otherwise
115f3b0b626SDavid Hildenbrand  * 0.
116f3b0b626SDavid Hildenbrand  */
117c0840179SMarc-André Lureau G_GNUC_WARN_UNUSED_RESULT
range_init(Range * range,uint64_t lob,uint64_t size)118c0840179SMarc-André Lureau static inline int range_init(Range *range, uint64_t lob, uint64_t size)
119f3b0b626SDavid Hildenbrand {
120f3b0b626SDavid Hildenbrand     if (lob + size < lob) {
121f3b0b626SDavid Hildenbrand         return -ERANGE;
122f3b0b626SDavid Hildenbrand     }
123f3b0b626SDavid Hildenbrand     range->lob = lob;
124f3b0b626SDavid Hildenbrand     range->upb = lob + size - 1;
125f3b0b626SDavid Hildenbrand     range_invariant(range);
126f3b0b626SDavid Hildenbrand     return 0;
127f3b0b626SDavid Hildenbrand }
128f3b0b626SDavid Hildenbrand 
129f3b0b626SDavid Hildenbrand /*
130f3b0b626SDavid Hildenbrand  * Initialize @range to span the interval [@lob,@lob + @size - 1].
131f3b0b626SDavid Hildenbrand  * @size may be 0. Range must not overflow.
132f3b0b626SDavid Hildenbrand  */
range_init_nofail(Range * range,uint64_t lob,uint64_t size)133f3b0b626SDavid Hildenbrand static inline void range_init_nofail(Range *range, uint64_t lob, uint64_t size)
134f3b0b626SDavid Hildenbrand {
135f3b0b626SDavid Hildenbrand     range->lob = lob;
136f3b0b626SDavid Hildenbrand     range->upb = lob + size - 1;
137f3b0b626SDavid Hildenbrand     range_invariant(range);
138f3b0b626SDavid Hildenbrand }
139f3b0b626SDavid Hildenbrand 
140f3b0b626SDavid Hildenbrand /*
141f3b0b626SDavid Hildenbrand  * Get the size of @range.
142f3b0b626SDavid Hildenbrand  */
range_size(const Range * range)143f3b0b626SDavid Hildenbrand static inline uint64_t range_size(const Range *range)
144f3b0b626SDavid Hildenbrand {
145f3b0b626SDavid Hildenbrand     return range->upb - range->lob + 1;
146f3b0b626SDavid Hildenbrand }
147f3b0b626SDavid Hildenbrand 
148f3b0b626SDavid Hildenbrand /*
149f3b0b626SDavid Hildenbrand  * Check if @range1 overlaps with @range2. If one of the ranges is empty,
150f3b0b626SDavid Hildenbrand  * the result is always "false".
151f3b0b626SDavid Hildenbrand  */
range_overlaps_range(const Range * range1,const Range * range2)152f3b0b626SDavid Hildenbrand static inline bool range_overlaps_range(const Range *range1,
153f3b0b626SDavid Hildenbrand                                         const Range *range2)
154f3b0b626SDavid Hildenbrand {
155f3b0b626SDavid Hildenbrand     if (range_is_empty(range1) || range_is_empty(range2)) {
156f3b0b626SDavid Hildenbrand         return false;
157f3b0b626SDavid Hildenbrand     }
158f3b0b626SDavid Hildenbrand     return !(range2->upb < range1->lob || range1->upb < range2->lob);
159f3b0b626SDavid Hildenbrand }
160f3b0b626SDavid Hildenbrand 
161f3b0b626SDavid Hildenbrand /*
162f3b0b626SDavid Hildenbrand  * Check if @range1 contains @range2. If one of the ranges is empty,
163f3b0b626SDavid Hildenbrand  * the result is always "false".
164f3b0b626SDavid Hildenbrand  */
range_contains_range(const Range * range1,const Range * range2)165f3b0b626SDavid Hildenbrand static inline bool range_contains_range(const Range *range1,
166f3b0b626SDavid Hildenbrand                                         const Range *range2)
167f3b0b626SDavid Hildenbrand {
168f3b0b626SDavid Hildenbrand     if (range_is_empty(range1) || range_is_empty(range2)) {
169f3b0b626SDavid Hildenbrand         return false;
170f3b0b626SDavid Hildenbrand     }
171f3b0b626SDavid Hildenbrand     return range1->lob <= range2->lob && range1->upb >= range2->upb;
172f3b0b626SDavid Hildenbrand }
173f3b0b626SDavid Hildenbrand 
174f3b0b626SDavid Hildenbrand /*
175a0efbf16SMarkus Armbruster  * Extend @range to the smallest interval that includes @extend_by, too.
176a0efbf16SMarkus Armbruster  */
range_extend(Range * range,Range * extend_by)177c5a22c43SMichael S. Tsirkin static inline void range_extend(Range *range, Range *extend_by)
178c5a22c43SMichael S. Tsirkin {
179a0efbf16SMarkus Armbruster     if (range_is_empty(extend_by)) {
180c5a22c43SMichael S. Tsirkin         return;
181c5a22c43SMichael S. Tsirkin     }
182a0efbf16SMarkus Armbruster     if (range_is_empty(range)) {
183c5a22c43SMichael S. Tsirkin         *range = *extend_by;
184c5a22c43SMichael S. Tsirkin         return;
185c5a22c43SMichael S. Tsirkin     }
1866dd726a2SMarkus Armbruster     if (range->lob > extend_by->lob) {
1876dd726a2SMarkus Armbruster         range->lob = extend_by->lob;
188c5a22c43SMichael S. Tsirkin     }
1896dd726a2SMarkus Armbruster     if (range->upb < extend_by->upb) {
1906dd726a2SMarkus Armbruster         range->upb = extend_by->upb;
191c5a22c43SMichael S. Tsirkin     }
1926dd726a2SMarkus Armbruster     range_invariant(range);
193c5a22c43SMichael S. Tsirkin }
194c5a22c43SMichael S. Tsirkin 
1951de7afc9SPaolo Bonzini /* Get last byte of a range from offset + length.
1961de7afc9SPaolo Bonzini  * Undefined for ranges that wrap around 0. */
range_get_last(uint64_t offset,uint64_t len)1971de7afc9SPaolo Bonzini static inline uint64_t range_get_last(uint64_t offset, uint64_t len)
1981de7afc9SPaolo Bonzini {
1991de7afc9SPaolo Bonzini     return offset + len - 1;
2001de7afc9SPaolo Bonzini }
2011de7afc9SPaolo Bonzini 
2021de7afc9SPaolo Bonzini /* Check whether a given range covers a given byte. */
range_covers_byte(uint64_t offset,uint64_t len,uint64_t byte)2031de7afc9SPaolo Bonzini static inline int range_covers_byte(uint64_t offset, uint64_t len,
2041de7afc9SPaolo Bonzini                                     uint64_t byte)
2051de7afc9SPaolo Bonzini {
2061de7afc9SPaolo Bonzini     return offset <= byte && byte <= range_get_last(offset, len);
2071de7afc9SPaolo Bonzini }
2081de7afc9SPaolo Bonzini 
2091de7afc9SPaolo Bonzini /* Check whether 2 given ranges overlap.
2101de7afc9SPaolo Bonzini  * Undefined if ranges that wrap around 0. */
ranges_overlap(uint64_t first1,uint64_t len1,uint64_t first2,uint64_t len2)2111de7afc9SPaolo Bonzini static inline int ranges_overlap(uint64_t first1, uint64_t len1,
2121de7afc9SPaolo Bonzini                                  uint64_t first2, uint64_t len2)
2131de7afc9SPaolo Bonzini {
2141de7afc9SPaolo Bonzini     uint64_t last1 = range_get_last(first1, len1);
2151de7afc9SPaolo Bonzini     uint64_t last2 = range_get_last(first2, len2);
2161de7afc9SPaolo Bonzini 
2171de7afc9SPaolo Bonzini     return !(last2 < first1 || last1 < first2);
2181de7afc9SPaolo Bonzini }
2191de7afc9SPaolo Bonzini 
22043f04cbeSEric Auger /*
22143f04cbeSEric Auger  * Return -1 if @a < @b, 1 @a > @b, and 0 if they touch or overlap.
22243f04cbeSEric Auger  * Both @a and @b must not be empty.
22343f04cbeSEric Auger  */
22443f04cbeSEric Auger int range_compare(Range *a, Range *b);
22543f04cbeSEric Auger 
2267c47959dSEric Blake GList *range_list_insert(GList *list, Range *data);
2277f8f9ef1SHu Tao 
228*b439595aSEric Auger /*
229*b439595aSEric Auger  * Inverse an array of sorted ranges over the [low, high] span, ie.
230*b439595aSEric Auger  * original ranges becomes holes in the newly allocated inv_ranges
231*b439595aSEric Auger  */
232*b439595aSEric Auger void range_inverse_array(GList *in_ranges,
233*b439595aSEric Auger                          GList **out_ranges,
234*b439595aSEric Auger                          uint64_t low, uint64_t high);
235*b439595aSEric Auger 
2361de7afc9SPaolo Bonzini #endif
237