diff --git a/core/uaddrspace.c b/core/uaddrspace.c index aefd404..d41d955 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -317,6 +317,17 @@ free_ppage: return -1; } +static struct uAddrVirtualReg *uAddrSpaceMergeVr(struct uAddrVirtualReg *prev, + struct uAddrVirtualReg *next) +{ + if (prev && next && prev->addr + prev->size == next->addr && prev->right == next->right && + prev->res == next->res && prev->flags == next->flags && prev->offset == next->offset) { + prev->size += next->size; + return next; + } else + return NULL; +} + int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, struct mappedRessource *res, uint32_t offset ) { @@ -363,27 +374,48 @@ int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t reg->right = rights; reg->res = res; reg->offset = offset; - // TODO merge it with prev/next one // keep the AddrSpace list sorted struct uAddrVirtualReg *prev = findVirtualRegionBeforeAddr(as, hint_uaddr); - if (prev) - list_insert_after_named(as->listVirtualReg, prev, reg, prevInAddrSpace, - nextInAddrSpace); - else + bool_t regIsNew = TRUE; + if (prev) { + struct uAddrVirtualReg *toFree = uAddrSpaceMergeVr(prev, reg); + if (toFree) { + pr_devel("Merge VR with prev\n"); + reg = prev; + regIsNew = FALSE; + free(toFree); + } + toFree = uAddrSpaceMergeVr(reg, prev->nextInAddrSpace); + if (toFree) { + pr_devel("Merge VR with next\n"); + regIsNew = FALSE; + if (toFree->res && toFree->res->ops && toFree->res->ops->close) + toFree->res->ops->close(toFree); + list_delete_named(as->listVirtualReg, toFree, prevInAddrSpace, nextInAddrSpace); + list_delete_named(toFree->res->listVirtualReg, toFree, prevInMappedRes, + nextInMappedRes); + free(toFree); + } + if (regIsNew) + list_insert_after_named(as->listVirtualReg, prev, reg, prevInAddrSpace, + nextInAddrSpace); + } else list_add_tail_named(as->listVirtualReg, reg, prevInAddrSpace, nextInAddrSpace); - list_add_tail_named(reg->res->listVirtualReg, reg, prevInMappedRes, nextInMappedRes); - if (res->onResMapped) { - int cbret = res->onResMapped(reg); - if (cbret) { - pr_devel("Call back failed on ressource mmaped\n"); - ret = uAddrSpaceUnmap(as, reg->addr, reg->size); + if (regIsNew) { + list_add_tail_named(reg->res->listVirtualReg, reg, prevInMappedRes, nextInMappedRes); + if (res->onResMapped) { + int cbret = res->onResMapped(reg); + if (cbret) { + pr_devel("Call back failed on ressource mmaped\n"); + ret = uAddrSpaceUnmap(as, reg->addr, reg->size); + } } - } - if (res->ops->open) - res->ops->open(reg); + if (res->ops->open) + res->ops->open(reg); + } *uaddr = hint_uaddr;