From: Marco Schlumpp Date: Mon, 13 Feb 2023 15:58:19 +0000 (+0100) Subject: plat/common: Extract non-multiboot specific memory region helpers X-Git-Tag: RELEASE-0.13.0~43 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=7190449a7a0bdd0ffcd90c37fa0a8d2fc287c804;p=unikraft%2Funikraft.git plat/common: Extract non-multiboot specific memory region helpers The multiboot entry point had a few internal functions that are also useful for other entry points. Signed-off-by: Marco Schlumpp Reviewed-by: Sergiu Moga Approved-by: Marc Rittinghaus Tested-by: Unikraft CI GitHub-Closes: #760 --- diff --git a/include/uk/plat/memory.h b/include/uk/plat/memory.h index bd7c444f3..9c06beade 100644 --- a/include/uk/plat/memory.h +++ b/include/uk/plat/memory.h @@ -84,6 +84,27 @@ struct ukplat_memregion_desc { #endif /* CONFIG_UKPLAT_MEMRNAME */ } __packed __align(__SIZEOF_LONG__); +/** + * Check whether the memory region descriptor overlaps with [pstart, pend) in + * the physical address space. + * + * @param mrd + * Pointer to the memory region descriptor to check against + * @param pstart + * Start of the physical memory region + * @param pend + * End of the physical memory region + * @return + * Zero if the two specified regions have no overlap, a non-zero value + * otherwise + */ +static inline int +ukplat_memregion_desc_overlap(const struct ukplat_memregion_desc *mrd, + __paddr_t pstart, __paddr_t pend) +{ + return RANGE_OVERLAP(mrd->pbase, mrd->len, pstart, pend - pstart); +} + /** * Returns the number of available memory regions */ diff --git a/plat/common/include/uk/plat/common/memory.h b/plat/common/include/uk/plat/common/memory.h index 90d363b7e..599e21cba 100644 --- a/plat/common/include/uk/plat/common/memory.h +++ b/plat/common/include/uk/plat/common/memory.h @@ -112,6 +112,88 @@ ukplat_memregion_list_insert(struct ukplat_memregion_list *list, return (int)i; } +/** + * Insert a new region into the memory region list. This extends + * ukplat_memregion_list_insert to carve out the area of any pre-existing + * overlapping regions. The virtual addresses will leave out any carved out + * region. + * If there is not enough space for all resulting regions, the function will + * insert as many as possible and then return an error. + * @param list + * The memory region list to insert the range into + * @param mrd + * The memory range to insert + * @param min_size + * The minimum size an inserted region has to have. Regions smaller than this + * size won't be added. Setting this parameter to zero will disable this + * behavior. + * @returns + * Zero if the operation was successful, a negative errno otherwise + */ +static inline int +ukplat_memregion_list_insert_split_phys(struct ukplat_memregion_list *list, + const struct ukplat_memregion_desc *mrd, + const __sz min_size) +{ + struct ukplat_memregion_desc *mrdp; + struct ukplat_memregion_desc mrdc; + __paddr_t pstart, pend; + __vaddr_t voffset; + int i; + int rc; + + voffset = mrd->vbase - mrd->pbase; + pstart = mrd->pbase; + pend = mrd->pbase + mrd->len; + + mrdc = *mrd; + + /* TODO: The following code does not make use of the tracked iteration + * index to insert elements at the correct location and instead uses the + * generic insertion routine. For large memory region lists this could + * be potentially slow. + */ + for (i = 0; i < (int)list->count; i++) { + mrdp = &list->mrds[i]; + if (!ukplat_memregion_desc_overlap(mrdp, pstart, pend)) + continue; + if (pend <= mrdp->pbase) + break; + + if (!mrdp->type) + continue; + + if (pstart < mrdp->pbase) { + /* Some part of the inserted region is before the + * overlapping region. Try to insert that part if it's + * large enough. + */ + mrdc.pbase = pstart; + mrdc.vbase = pstart + voffset; + mrdc.len = mrdp->pbase - pstart; + + if (mrdc.len >= min_size) { + rc = ukplat_memregion_list_insert(list, &mrdc); + if (unlikely(rc < 0)) + return rc; + } + } + + pstart = mrdp->pbase + mrdp->len; + } + + if (pend - pstart < min_size) + return 0; + + mrdc.pbase = pstart; + mrdc.vbase = pstart + voffset; + mrdc.len = pend - pstart; + + /* Add the remaining region */ + rc = ukplat_memregion_list_insert(list, &mrdc); + return rc < 0 ? rc : 0; +} + /** * Delete the specified region from the memory list. * diff --git a/plat/kvm/x86/multiboot.c b/plat/kvm/x86/multiboot.c index f2994aa5f..30ea74ac4 100644 --- a/plat/kvm/x86/multiboot.c +++ b/plat/kvm/x86/multiboot.c @@ -22,12 +22,6 @@ void _ukplat_entry(struct lcpu *lcpu, struct ukplat_bootinfo *bi); -static inline int mrd_overlap(__paddr_t pstart, __paddr_t pend, - const struct ukplat_memregion_desc *mrd) -{ - return ((pend > mrd->pbase) && (pstart < mrd->pbase + mrd->len)); -} - static inline void mrd_insert(struct ukplat_bootinfo *bi, const struct ukplat_memregion_desc *mrd) { @@ -50,12 +44,12 @@ void multiboot_entry(struct lcpu *lcpu, struct multiboot_info *mi) { struct ukplat_bootinfo *bi; struct ukplat_memregion_desc mrd = {0}; - struct ukplat_memregion_desc *mrdp; multiboot_memory_map_t *m; multiboot_module_t *mods; __sz offset, cmdline_len; __paddr_t start, end; __u32 i; + int rc; bi = ukplat_bootinfo_get(); if (unlikely(!bi)) @@ -133,33 +127,20 @@ void multiboot_entry(struct lcpu *lcpu, struct multiboot_info *mi) if (end <= start) continue; + mrd.pbase = start; + mrd.vbase = start; /* 1:1 mapping */ + mrd.len = end - start; + if (m->type == MULTIBOOT_MEMORY_AVAILABLE) { mrd.type = UKPLAT_MEMRT_FREE; mrd.flags = UKPLAT_MEMRF_READ | UKPLAT_MEMRF_WRITE; - for (i = 0; i < bi->mrds.count; i++) { - ukplat_memregion_get(i, &mrdp); - if (!mrd_overlap(start, end, mrdp)) - continue; - - if (!mrdp->type) - continue; - - if (start < mrdp->pbase) { - mrd.pbase = start; - mrd.vbase = start; /* 1:1 map */ - mrd.len = mrdp->pbase - start; - - if (mrd.len >= PAGE_SIZE) - mrd_insert(bi, &mrd); - } - - start = mrdp->pbase + mrdp->len; - } - - if (end - start < PAGE_SIZE) - continue; + rc = ukplat_memregion_list_insert_split_phys( + &bi->mrds, &mrd, __PAGE_SIZE); + if (unlikely(rc < 0)) + multiboot_crash("Unable to add region", + rc); } else { mrd.type = UKPLAT_MEMRT_RESERVED; mrd.flags = UKPLAT_MEMRF_READ | @@ -168,13 +149,8 @@ void multiboot_entry(struct lcpu *lcpu, struct multiboot_info *mi) /* We assume that reserved regions cannot * overlap with loaded modules. */ + mrd_insert(bi, &mrd); } - - mrd.pbase = start; - mrd.vbase = start; /* 1:1 mapping */ - mrd.len = end - start; - - mrd_insert(bi, &mrd); } }