+ {
+ printf("ERROR: module target [%llx-%llx) overlaps\n",
+ to->begin(), to->end());
+ overlap->vprint();
+ regions.dump();
+ panic("cannot move module");
+ }
+ }
+ memmove((void *)to->begin(), (void *)start, size);
+ unsigned long x = to->end() + 1;
+ memset((char *)x, 0, l4_round_page(x) - x);
+
+ (L4_MB_MOD_PTR(mbi->mods_addr))[i].mod_start = to->begin();
+ (L4_MB_MOD_PTR(mbi->mods_addr))[i].mod_end = to->end() + 1;
+ from->begin(to->begin());
+ from->end(to->end());
+}
+
+static inline
+unsigned long mbi_mod_start(l4util_mb_info_t *mbi, int i)
+{ return (L4_MB_MOD_PTR(mbi->mods_addr))[i].mod_start; }
+
+static inline
+unsigned long mbi_mod_end(l4util_mb_info_t *mbi, int i)
+{ return (L4_MB_MOD_PTR(mbi->mods_addr))[i].mod_end; }
+
+static inline
+unsigned long mbi_mod_size(l4util_mb_info_t *mbi, int i)
+{ return mbi_mod_end(mbi, i) - mbi_mod_start(mbi, i); }
+
+/**
+ * Move modules to another address.
+ *
+ * Source and destination regions may overlap.
+ */
+static void
+move_modules(l4util_mb_info_t *mbi, unsigned long modaddr)
+{
+ printf(" Moving up to %d modules behind %lx\n", mbi->mods_count, modaddr);
+
+ Region *ramr = ram.find(Region(modaddr, modaddr));
+ Region module_area(modaddr, ramr->end(), "ram for modules");
+
+ unsigned long firstmodulestart = ~0UL, lastmoduleend = 0;
+ for (unsigned i = 0; i < mbi->mods_count; ++i)
+ {
+ if (lastmoduleend < mbi_mod_end(mbi, i))
+ lastmoduleend = mbi_mod_end(mbi, i);
+ if (firstmodulestart > mbi_mod_start(mbi, i))
+ firstmodulestart = mbi_mod_start(mbi, i);
+ }
+ lastmoduleend = l4_round_page(lastmoduleend);
+ if (firstmodulestart < modaddr)
+ {
+ Region s(lastmoduleend, ramr->end());
+ unsigned long sz = modaddr - firstmodulestart;
+ lastmoduleend = regions.find_free(s, sz, L4_PAGESHIFT) + sz;
+ }
+
+ for (unsigned i = 0; i < mbi->mods_count; ++i)
+ {
+ unsigned long start = mbi_mod_start(mbi, i);
+ unsigned long end = mbi_mod_end(mbi, i);
+ unsigned long size = mbi_mod_size(mbi, i);
+
+ if (start == end)
+ continue;
+
+ Region from(start, end - 1);
+ Region *this_module = regions.find(from);
+ assert(this_module->begin() == from.begin()
+ && this_module->end() == from.end());
+
+ if (i < 3)
+ {
+ if (start < lastmoduleend)
+ {
+ Region to(lastmoduleend, lastmoduleend + (end - start) - 1);
+ if (module_area.contains(to))
+ {
+ move_module(mbi, i, this_module, &to, true);
+ lastmoduleend = l4_round_page(this_module->end());
+ }
+ }
+ continue;
+ }
+
+ if (start >= modaddr)
+ continue;
+
+ unsigned long long to = regions.find_free(module_area, size, L4_PAGESHIFT);
+ assert(to);
+
+ Region m_to = Region(to, to + size - 1);
+ move_module(mbi, i, this_module, &m_to, true);
+ }
+
+ // now everything is behind modaddr -> pull close to modaddr now
+ // this is optional but avoids holes and gives more consecutive memory
+
+ if (Verbose_load)
+ printf(" Compactifying\n");
+
+ regions.sort();
+ unsigned long lastend = modaddr;
+
+ // Now check whether modaddr is ok or if some non-modules are still above
+ // modaddr, so that we need to have lastend higher
+ {
+ unsigned long end_last_pre_module = 0;
+ bool seen_modules = false;
+
+ for (Region *i = regions.begin(); i < regions.end(); ++i)
+ {
+ if (strcmp(i->name(), ".Module"))
+ {
+ unsigned long mod_end = l4_round_page(i->end());
+ if (!seen_modules && end_last_pre_module < mod_end)
+ end_last_pre_module = mod_end;
+ }
+ else
+ seen_modules = true;
+ }
+
+ if (end_last_pre_module > lastend)
+ lastend = end_last_pre_module;
+ }
+
+ if (Verbose_load)
+ printf(" Moving modules down to %lx\n", lastend);
+
+ for (Region *i = regions.begin(); i < regions.end(); ++i)
+ {
+ if (i->begin() < modaddr)
+ continue;
+
+ // find in mbi
+ unsigned mi = 0;
+ for (; mi < mbi->mods_count; ++mi)
+ if (i->begin() == mbi_mod_start(mbi, mi))
+ break;
+
+ if (mi < 3 || mbi->mods_count == mi)
+ continue;
+
+ unsigned long start = mbi_mod_start(mbi, mi);
+ unsigned long end = mbi_mod_end(mbi, mi);
+
+ if (start > lastend)
+ {
+ Region to(lastend, end - 1 - (start - lastend));
+ move_module(mbi, mi, i, &to, false);
+ end = i->end();
+ }
+ lastend = l4_round_page(end);