/* * QEMU ReservedRegion helpers * * Copyright (c) 2023 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include "qemu/osdep.h" #include "qemu/range.h" #include "qemu/reserved-region.h" GList *resv_region_list_insert(GList *list, ReservedRegion *reg) { ReservedRegion *resv_iter, *new_reg; Range *r = ®->range; Range *range_iter; GList *l; for (l = list; l ; ) { resv_iter = (ReservedRegion *)l->data; range_iter = &resv_iter->range; /* Skip all list elements strictly less than range to add */ if (range_compare(range_iter, r) < 0) { l = l->next; } else if (range_compare(range_iter, r) > 0) { return g_list_insert_before(list, l, reg); } else { /* there is an overlap */ if (range_contains_range(r, range_iter)) { /* new range contains current item, simply remove this latter */ GList *prev = l->prev; g_free(l->data); list = g_list_delete_link(list, l); if (prev) { l = prev->next; } else { l = list; } } else if (range_contains_range(range_iter, r)) { /* new region is included in the current region */ if (range_lob(range_iter) == range_lob(r)) { /* adjacent on the left side, derives into 2 regions */ range_set_bounds(range_iter, range_upb(r) + 1, range_upb(range_iter)); return g_list_insert_before(list, l, reg); } else if (range_upb(range_iter) == range_upb(r)) { /* adjacent on the right side, derives into 2 regions */ range_set_bounds(range_iter, range_lob(range_iter), range_lob(r) - 1); l = l->next; } else { uint64_t lob = range_lob(range_iter); /* * the new range is in the middle of an existing one, * split this latter into 3 regs instead */ range_set_bounds(range_iter, range_upb(r) + 1, range_upb(range_iter)); new_reg = g_new0(ReservedRegion, 1); new_reg->type = resv_iter->type; range_set_bounds(&new_reg->range, lob, range_lob(r) - 1); list = g_list_insert_before(list, l, new_reg); return g_list_insert_before(list, l, reg); } } else if (range_lob(r) < range_lob(range_iter)) { range_set_bounds(range_iter, range_upb(r) + 1, range_upb(range_iter)); return g_list_insert_before(list, l, reg); } else { /* intersection on the upper range */ range_set_bounds(range_iter, range_lob(range_iter), range_lob(r) - 1); l = l->next; } } /* overlap */ } return g_list_append(list, reg); }