diff --git a/usr.sbin/bhyve/amd64/e820.c b/usr.sbin/bhyve/amd64/e820.c --- a/usr.sbin/bhyve/amd64/e820.c +++ b/usr.sbin/bhyve/amd64/e820.c @@ -156,6 +156,7 @@ { struct e820_element *new_element; struct e820_element *element; + struct e820_element *sib_element; struct e820_element *ram_element; assert(end >= base); @@ -222,6 +223,20 @@ * [ 0x1000, 0x2000] Reserved * [ 0x2000, 0x4000] RAM <-- element */ + + /* + * If the previous element has the same type and ends at our + * base boundary, we can merge both entries. + */ + sib_element = TAILQ_PREV(element, e820_table, chain); + if (sib_element != NULL && + sib_element->type == new_element->type && + sib_element->end == new_element->base) { + new_element->base = sib_element->base; + TAILQ_REMOVE(&e820_table, sib_element, chain); + free(sib_element); + } + TAILQ_INSERT_BEFORE(element, new_element, chain); /* @@ -232,6 +247,19 @@ if (end != element->end) { element->base = end; } else { + /* + * If the next element has the same type and starts at + * our end boundary, we can merge both entries. + */ + sib_element = TAILQ_NEXT(element, e820_table, chain); + if (sib_element != NULL && + sib_element->type == new_element->type && + sib_element->base == new_element->end) { + new_element->end = sib_element->end; + TAILQ_REMOVE(&e820_table, sib_element, chain); + free(sib_element); + } + TAILQ_REMOVE(&e820_table, element, chain); free(element); } @@ -247,6 +275,21 @@ * [ 0x1000, 0x3000] RAM <-- element * [ 0x3000, 0x4000] Reserved */ + + /* + * If the previous element has the same type and ends at our + * base boundary, we can merge both entries. + */ + sib_element = TAILQ_NEXT(element, chain); + if (sib_element != NULL && + sib_element->type == new_element->type && + sib_element->base == new_element->end) { + /* Merge new element into subsequent one. */ + new_element->end = sib_element->end; + TAILQ_REMOVE(&e820_table, sib_element, chain); + free(sib_element); + } + TAILQ_INSERT_AFTER(&e820_table, element, new_element, chain); element->end = base; } else {