|  | /* | 
|  | * 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 <http://www.gnu.org/licenses/>. | 
|  | */ | 
|  |  | 
|  | #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); | 
|  | } | 
|  |  |