[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH v2 8/8] plat/kvm: x86: Retrieve initrd location from Multiboot



Inspects Multiboot modules information to retrieve the location of an
loaded initramdisk. It will most likely be placed by Multiboot within the
region that we announce as usable for heap. In such a case, we cut out
the initrd from the heap range and report two heap regions: one before the
initrd, one after the initrd.

Signed-off-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
---
 plat/kvm/memory.c    |  31 +++++++++-
 plat/kvm/x86/setup.c | 143 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/plat/kvm/memory.c b/plat/kvm/memory.c
index d8293293..7f2fb46a 100644
--- a/plat/kvm/memory.c
+++ b/plat/kvm/memory.c
@@ -27,7 +27,9 @@
 
 int ukplat_memregion_count(void)
 {
-       return 9;
+       return (9
+               + ((_libkvmplat_cfg.initrd.len > 0) ? 1 : 0)
+               + ((_libkvmplat_cfg.heap2.len  > 0) ? 1 : 0));
 }
 
 int ukplat_memregion_get(int i, struct ukplat_memregion_desc *m)
@@ -131,6 +133,33 @@ int ukplat_memregion_get(int i, struct 
ukplat_memregion_desc *m)
                m->name  = "bstack";
 #endif
                break;
+       case 9: /* initrd */
+               if (_libkvmplat_cfg.initrd.len) {
+                       m->base  = (void *) _libkvmplat_cfg.initrd.start;
+                       m->len   = _libkvmplat_cfg.initrd.len;
+                       m->flags = (UKPLAT_MEMRF_INITRD |
+                                   UKPLAT_MEMRF_WRITABLE);
+#if CONFIG_UKPLAT_MEMRNAME
+                       m->name  = "initrd";
+#endif
+                       ret = 0;
+                       break;
+               }
+               /* fall-through */
+       case 10: /* heap2
+                *  NOTE: heap2 could only exist if initrd was there,
+                *  otherwise we fall through */
+               if (_libkvmplat_cfg.initrd.len && _libkvmplat_cfg.heap2.len) {
+                       m->base  = (void *) _libkvmplat_cfg.heap2.start;
+                       m->len   = _libkvmplat_cfg.heap2.len;
+                       m->flags = UKPLAT_MEMRF_ALLOCATABLE;
+#if CONFIG_UKPLAT_MEMRNAME
+                       m->name  = "heap";
+#endif
+                       ret = 0;
+                       break;
+               }
+               /* fall-through */
        default:
                m->base  = __NULL;
                m->len   = 0;
diff --git a/plat/kvm/x86/setup.c b/plat/kvm/x86/setup.c
index c3959c40..e4becaaa 100644
--- a/plat/kvm/x86/setup.c
+++ b/plat/kvm/x86/setup.c
@@ -115,6 +115,142 @@ static inline void _mb_init_mem(struct multiboot_info *mi)
        _libkvmplat_cfg.bstack.len   = __STACK_SIZE;
 }
 
+static inline void _mb_init_initrd(struct multiboot_info *mi)
+{
+       multiboot_module_t *mod1;
+       uintptr_t heap0_start, heap0_end;
+       uintptr_t heap1_start, heap1_end;
+       size_t    heap0_len,   heap1_len;
+
+       /*
+        * Search for initrd (called boot module according multiboot)
+        */
+       if (mi->mods_count == 0) {
+               uk_pr_debug("No initrd present\n");
+               goto no_initrd;
+       }
+
+       /*
+        * NOTE: We are only taking the first boot module as initrd.
+        *       Initrd arguments and further modules are ignored.
+        */
+       UK_ASSERT(mi->mods_addr);
+
+       mod1 = (multiboot_module_t *)((uintptr_t) mi->mods_addr);
+       UK_ASSERT(mod1->mod_end >= mod1->mod_start);
+
+       if (mod1->mod_end == mod1->mod_start) {
+               uk_pr_debug("Ignoring empty initrd\n");
+               goto no_initrd;
+       }
+
+       _libkvmplat_cfg.initrd.start = (uintptr_t) mod1->mod_start;
+       _libkvmplat_cfg.initrd.end = (uintptr_t) mod1->mod_end;
+       _libkvmplat_cfg.initrd.len = (size_t) (mod1->mod_end - mod1->mod_start);
+
+       /*
+        * Check if initrd is part of heap
+        * In such a case, we figure out the remaining pieces as heap
+        */
+       if (_libkvmplat_cfg.heap.len == 0) {
+               /* We do not have a heap */
+               goto out;
+       }
+       heap0_start = 0;
+       heap0_end   = 0;
+       heap1_start = 0;
+       heap1_end   = 0;
+       if (RANGE_OVERLAP(_libkvmplat_cfg.heap.start,
+                         _libkvmplat_cfg.heap.len,
+                         _libkvmplat_cfg.initrd.start,
+                         _libkvmplat_cfg.initrd.len)) {
+               if (IN_RANGE(_libkvmplat_cfg.initrd.start,
+                            _libkvmplat_cfg.heap.start,
+                            _libkvmplat_cfg.heap.len)) {
+                       /* Start of initrd within heap range;
+                        * Use the prepending left piece as heap */
+                       heap0_start = _libkvmplat_cfg.heap.start;
+                       heap0_end   = ALIGN_DOWN(_libkvmplat_cfg.initrd.start,
+                                                __PAGE_SIZE);
+               }
+               if (IN_RANGE(_libkvmplat_cfg.initrd.start,
+
+                            _libkvmplat_cfg.heap.start,
+                            _libkvmplat_cfg.heap.len)) {
+                       /* End of initrd within heap range;
+                        * Use the remaining left piece as heap */
+                       heap1_start = ALIGN_UP(_libkvmplat_cfg.initrd.end,
+                                              __PAGE_SIZE);
+                       heap1_end   = _libkvmplat_cfg.heap.end;
+               }
+       } else {
+               /* Initrd is not overlapping with heap */
+               heap0_start = _libkvmplat_cfg.heap.start;
+               heap0_end   = _libkvmplat_cfg.heap.end;
+       }
+       heap0_len = heap0_end - heap0_start;
+       heap1_len = heap1_end - heap1_start;
+
+       /*
+        * Update heap regions
+        * We make sure that in we start filling left heap pieces at
+        * `_libkvmplat_cfg.heap`. Any additional piece will then be
+        * placed to `_libkvmplat_cfg.heap2`.
+        */
+       if (heap0_len == 0) {
+               /* Heap piece 0 is empty, use piece 1 as only */
+               if (heap1_len != 0) {
+                       _libkvmplat_cfg.heap.start = heap1_start;
+                       _libkvmplat_cfg.heap.end   = heap1_end;
+                       _libkvmplat_cfg.heap.len   = heap1_len;
+               } else {
+                       _libkvmplat_cfg.heap.start = 0;
+                       _libkvmplat_cfg.heap.end   = 0;
+                       _libkvmplat_cfg.heap.len   = 0;
+               }
+                _libkvmplat_cfg.heap2.start = 0;
+                _libkvmplat_cfg.heap2.end   = 0;
+                _libkvmplat_cfg.heap2.len   = 0;
+       } else {
+               /* Heap piece 0 has memory */
+               _libkvmplat_cfg.heap.start = heap0_start;
+               _libkvmplat_cfg.heap.end   = heap0_end;
+               _libkvmplat_cfg.heap.len   = heap0_len;
+               if (heap1_len != 0) {
+                       _libkvmplat_cfg.heap2.start = heap1_start;
+                       _libkvmplat_cfg.heap2.end   = heap1_end;
+                       _libkvmplat_cfg.heap2.len   = heap1_len;
+               } else {
+                       _libkvmplat_cfg.heap2.start = 0;
+                       _libkvmplat_cfg.heap2.end   = 0;
+                       _libkvmplat_cfg.heap2.len   = 0;
+               }
+       }
+
+       /*
+        * Double-check that initrd is not overlapping with previously allocated
+        * boot stack. We crash in such a case because we assume that multiboot
+        * places the initrd close to the beginning of the heap region. One need
+        * to assign just more memory in order to avoid this crash.
+        */
+       if (RANGE_OVERLAP(_libkvmplat_cfg.heap.start,
+                         _libkvmplat_cfg.heap.len,
+                         _libkvmplat_cfg.initrd.start,
+                         _libkvmplat_cfg.initrd.len))
+               UK_CRASH("Not enough space at end of memory for boot stack\n");
+out:
+       return;
+
+no_initrd:
+       _libkvmplat_cfg.initrd.start = 0;
+       _libkvmplat_cfg.initrd.end   = 0;
+       _libkvmplat_cfg.initrd.len   = 0;
+       _libkvmplat_cfg.heap2.start  = 0;
+       _libkvmplat_cfg.heap2.end    = 0;
+       _libkvmplat_cfg.heap2.len    = 0;
+       return;
+}
+
 static void _libkvmplat_entry2(void *arg __attribute__((unused)))
 {
        ukplat_entry_argp(NULL, cmdline, sizeof(cmdline));
@@ -138,9 +274,16 @@ void _libkvmplat_entry(void *arg)
         */
        _mb_get_cmdline(mi);
        _mb_init_mem(mi);
+       _mb_init_initrd(mi);
 
+       if (_libkvmplat_cfg.initrd.len)
+               uk_pr_info("        initrd: %p\n",
+                          (void *) _libkvmplat_cfg.initrd.start);
        uk_pr_info("    heap start: %p\n",
                   (void *) _libkvmplat_cfg.heap.start);
+       if (_libkvmplat_cfg.heap2.len)
+               uk_pr_info(" heap start (2): %p\n",
+                          (void *) _libkvmplat_cfg.heap2.start);
        uk_pr_info("     stack top: %p\n",
                   (void *) _libkvmplat_cfg.bstack.start);
 
-- 
2.20.1


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.