qemu
1/*
2* QEMU 64-bit address ranges
3*
4* Copyright (c) 2015-2016 Red Hat, Inc.
5*
6* This program is free software; you can redistribute it and/or
7* modify it under the terms of the GNU General Public
8* License as published by the Free Software Foundation; either
9* version 2 of the License, or (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14* General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program; if not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "qemu/osdep.h"21#include "qemu/range.h"22
23int range_compare(Range *a, Range *b)24{
25assert(!range_is_empty(a) && !range_is_empty(b));26
27/* Careful, avoid wraparound */28if (b->lob && b->lob - 1 > a->upb) {29return -1;30}31if (a->lob && a->lob - 1 > b->upb) {32return 1;33}34return 0;35}
36
37/* Insert @data into @list of ranges; caller no longer owns @data */
38GList *range_list_insert(GList *list, Range *data)39{
40GList *l;41
42assert(!range_is_empty(data));43
44/* Skip all list elements strictly less than data */45for (l = list; l && range_compare(l->data, data) < 0; l = l->next) {46}47
48if (!l || range_compare(l->data, data) > 0) {49/* Rest of the list (if any) is strictly greater than @data */50return g_list_insert_before(list, l, data);51}52
53/* Current list element overlaps @data, merge the two */54range_extend(l->data, data);55g_free(data);56
57/* Merge any subsequent list elements that now also overlap */58while (l->next && range_compare(l->data, l->next->data) == 0) {59GList *new_l;60
61range_extend(l->data, l->next->data);62g_free(l->next->data);63new_l = g_list_delete_link(list, l->next);64assert(new_l == list);65}66
67return list;68}
69
70static inline71GList *append_new_range(GList *list, uint64_t lob, uint64_t upb)72{
73Range *new = g_new0(Range, 1);74
75range_set_bounds(new, lob, upb);76return g_list_append(list, new);77}
78
79
80void range_inverse_array(GList *in, GList **rev,81uint64_t low, uint64_t high)82{
83Range *r, *rn;84GList *l = in, *out = *rev;85
86for (l = in; l && range_upb(l->data) < low; l = l->next) {87continue;88}89
90if (!l) {91out = append_new_range(out, low, high);92goto exit;93}94r = (Range *)l->data;95
96/* first range lob is greater than min, insert a first range */97if (range_lob(r) > low) {98out = append_new_range(out, low, MIN(range_lob(r) - 1, high));99}100
101/* insert a range in between each original range until we reach high */102for (; l->next; l = l->next) {103r = (Range *)l->data;104rn = (Range *)l->next->data;105if (range_lob(r) >= high) {106goto exit;107}108if (range_compare(r, rn)) {109out = append_new_range(out, range_upb(r) + 1,110MIN(range_lob(rn) - 1, high));111}112}113
114/* last range */115r = (Range *)l->data;116
117/* last range upb is less than max, insert a last range */118if (range_upb(r) < high) {119out = append_new_range(out, range_upb(r) + 1, high);120}121exit:122*rev = out;123}
124