| /* | 
 |  * 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); | 
 | } | 
 |  |