Эх сурвалжийг харах

Merge branch 'master' into assert-checks

greatbridf 2 жил өмнө
parent
commit
f4b2f9707d

+ 40 - 1
include/kernel/mm.hpp

@@ -2,6 +2,7 @@
 
 #include <kernel/mem.h>
 #include <kernel/vfs.hpp>
+#include <stdint.h>
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
 #include <types/list.hpp>
@@ -34,6 +35,7 @@ struct page {
 // TODO: shared mapping
 // @param len is aligned to 4kb boundary automatically, exceeding part will
 // be filled with '0's and not written back to the file
+// @param offset MUST be aligned to 4kb
 int mmap(
     void* hint,
     size_t len,
@@ -60,6 +62,30 @@ namespace kernel {
 class mm_list;
 } // namespace kernel
 
+template <uint32_t base, uint32_t expo>
+inline constexpr uint32_t pow()
+{
+    if constexpr (expo == 0)
+        return 1;
+    if constexpr (expo == 1)
+        return base;
+    if constexpr (expo % 2 == 0)
+        return pow<base, expo / 2>() * pow<base, expo / 2>();
+    else
+        return pow<base, expo / 2>() * pow<base, expo / 2 + 1>();
+}
+
+template <int n>
+inline constexpr uint32_t align_down(uint32_t v)
+{
+    return v & ~(pow<2, n>() - 1);
+}
+template <int n>
+inline constexpr uint32_t align_up(uint32_t v)
+{
+    return align_down<n>(v + pow<2, n>() - 1);
+}
+
 struct mm {
 public:
     void* start;
@@ -215,7 +241,7 @@ public:
     {
         int i = 0;
 
-        // TODO: 
+        // TODO:
         // if there are more than 4 pages, calling invlpg
         // should be faster. otherwise, we use movl cr3
         // bool should_invlpg = (area->pgs->size() > 4);
@@ -247,6 +273,19 @@ public:
 
         return this->end();
     }
+
+    bool is_avail(void* start, size_t len)
+    {
+        start = (void*)align_down<12>((uint32_t)start);
+        len = align_up<12>((uint32_t)start + len)
+            - (uint32_t)start;
+        for (const auto& area : *this) {
+            if (!area.is_avail(start, (char*)start + len))
+                return false;
+        }
+
+        return true;
+    }
 };
 
 } // namespace kernel

+ 13 - 2
src/kernel/interrupt.cpp

@@ -221,8 +221,19 @@ extern "C" void int14_handler(int14_data* d)
 
         // memory mapped
         if (d->error_code.present == 0) {
-            size_t offset = vptrdiff(d->l_addr, mm_area->start) & 0xfffff000;
-            vfs_read(mm_area->mapped_file, new_page_data, PAGE_SIZE, mm_area->file_offset + offset, PAGE_SIZE);
+            size_t offset = align_down<12>((uint32_t)d->l_addr);
+            offset -= (uint32_t)mm_area->start;
+
+            int n = vfs_read(
+                mm_area->mapped_file,
+                new_page_data,
+                PAGE_SIZE,
+                mm_area->file_offset + offset,
+                PAGE_SIZE);
+
+            // TODO: send SIGBUS if offset is greater than real size
+            if (n != PAGE_SIZE)
+                memset(new_page_data + n, 0x00, PAGE_SIZE - n);
         }
     }
 }

+ 11 - 7
src/kernel/mem.cpp

@@ -9,6 +9,7 @@
 #include <kernel/task.h>
 #include <kernel/vga.hpp>
 #include <kernel_main.hpp>
+#include <stdint.h>
 #include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/bitmap.h>
@@ -451,14 +452,17 @@ static inline int _mmap(
         return GB_FAILED;
     }
 
-    len = (len + PAGE_SIZE - 1) & 0xfffff000;
-    size_t n_pgs = len >> 12;
+    // TODO: find another address
+    assert(((uint32_t)hint & 0xfff) == 0);
+    // TODO: return failed
+    assert((offset & 0xfff) == 0);
 
-    for (const auto& mm_area : *mms)
-        if (!mm_area.is_avail(hint, (char*)hint + len)) {
-            errno = EEXIST;
-            return GB_FAILED;
-        }
+    size_t n_pgs = align_up<12>(len) >> 12;
+
+    if (!mms->is_avail(hint, len)) {
+        errno = EEXIST;
+        return GB_FAILED;
+    }
 
     auto mm = mms->addarea(hint, write, priv);
     mm->mapped_file = file;

+ 29 - 7
src/types/elf.cpp

@@ -2,6 +2,7 @@
 #include <kernel/errno.h>
 #include <kernel/mem.h>
 #include <kernel/process.hpp>
+#include <kernel/vfs.hpp>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -75,17 +76,38 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     current_process->mms.clear_user();
 
     for (int i = 0; i < hdr.phnum; ++i) {
-        if (phents->type != types::elf::elf32_program_header_entry::PT_LOAD)
+        if (phents[i].type != types::elf::elf32_program_header_entry::PT_LOAD)
             continue;
 
-        auto ret = mmap((void*)phents->vaddr, phents->memsz, ent_exec->ind, phents->offset, 1, d->system);
-        if (ret != GB_OK) {
-            k_free(phents);
-
-            kill_current(-1);
+        auto ret = mmap(
+            (char*)phents[i].vaddr,
+            phents[i].filesz,
+            ent_exec->ind,
+            phents[i].offset,
+            1,
+            d->system);
+
+        if (ret != GB_OK)
+            goto error;
+
+        if (phents[i].memsz > align_up<12>(phents[i].filesz)) {
+            ret = mmap(
+                (char*)phents[i].vaddr + align_up<12>(phents[i].filesz),
+                align_up<12>(phents[i].memsz) - align_up<12>(phents[i].filesz),
+                fs::vfs_open("/dev/null")->ind,
+                phents[i].offset + align_up<12>(phents[i].filesz),
+                1,
+                d->system);
+
+            if (ret != GB_OK)
+                goto error;
         }
 
-        ++phents;
+        continue;
+
+    error:
+        k_free(phents);
+        kill_current(-1);
     }
 
     // map stack area