Преглед на файлове

feat(mm): add mm_list class

greatbridf преди 2 години
родител
ревизия
a3602de618
променени са 6 файла, в които са добавени 226 реда и са изтрити 199 реда
  1. 157 61
      include/kernel/mm.hpp
  2. 2 2
      include/kernel/process.hpp
  3. 5 5
      src/kernel/interrupt.cpp
  4. 51 109
      src/kernel/mem.cpp
  5. 8 19
      src/kernel/process.cpp
  6. 3 3
      src/kernel/syscall.cpp

+ 157 - 61
include/kernel/mm.hpp

@@ -29,20 +29,6 @@ struct page {
     } attr;
 };
 
-struct mm;
-
-// map the page to the end of the mm_area in pd
-int k_map(
-    mm* mm_area,
-    page* page,
-    int read,
-    int write,
-    int priv,
-    int cow);
-
-// unmap a whole mem area, making sure that we will never use it again
-int k_unmap(mm* mm_area);
-
 // private memory mapping
 // changes won't be neither written back to file nor shared between processes
 // TODO: shared mapping
@@ -58,7 +44,15 @@ int mmap(
 
 using page_arr = types::vector<page, types::kernel_ident_allocator>;
 
-using mm_list = types::list<mm, types::kernel_ident_allocator>;
+// allocate n raw page(s)
+// @return the id of the first page allocated
+page_t alloc_n_raw_pages(size_t n);
+void free_n_raw_pages(page_t start_pg, size_t n);
+
+// forward declaration
+namespace kernel {
+class mm_list;
+} // namespace kernel
 
 struct mm {
 public:
@@ -71,62 +65,177 @@ public:
             uint32_t system : 1;
         } in;
     } attr;
-    pd_t pd;
-    page_arr* pgs = types::kernel_ident_allocator_new<page_arr>();
+    kernel::mm_list* owner;
+    page_arr* pgs = nullptr;
     fs::inode* mapped_file = nullptr;
     size_t file_offset = 0;
 
 public:
-    static constexpr int mirror_mm_area(mm_list* dst, const mm* src, pd_t pd)
+    constexpr void* end(void) const
+    {
+        return (char*)this->start + this->pgs->size() * PAGE_SIZE;
+    }
+
+    inline bool is_ident(void) const
+    {
+        return this->end() <= (void*)0x40000000U;
+    }
+
+    constexpr bool is_avail(void* start, void* end) const
+    {
+        void* m_start = this->start;
+        void* m_end = this->end();
+
+        return (start >= m_end || end <= m_start);
+    }
+
+    int append_page(page* pg, bool present, bool write, bool priv, bool cow);
+};
+
+namespace kernel {
+
+class mm_list {
+public:
+    using list_type = ::types::list<mm, types::kernel_ident_allocator>;
+    using iterator_type = list_type::iterator_type;
+    using const_iterator_type = list_type::const_iterator_type;
+
+private:
+    list_type m_areas;
+
+public:
+    pd_t m_pd;
+
+public:
+    explicit mm_list(pd_t pd);
+    mm_list(const mm_list& v);
+    constexpr mm_list(mm_list&& v)
+        : m_areas(::types::move(v.m_areas))
+        , m_pd(v.m_pd)
+    {
+        v.m_pd = nullptr;
+    }
+    ~mm_list();
+
+    constexpr iterator_type begin(void)
+    {
+        return m_areas.begin();
+    }
+    constexpr iterator_type end(void)
+    {
+        return m_areas.end();
+    }
+    constexpr const_iterator_type begin(void) const
+    {
+        return m_areas.begin();
+    }
+    constexpr const_iterator_type end(void) const
+    {
+        return m_areas.end();
+    }
+    constexpr const_iterator_type cbegin(void) const
     {
-        mm new_nn {
-            .start = src->start,
-            .attr { src->attr.v },
-            .pd = pd,
-            .mapped_file = src->mapped_file,
-            .file_offset = src->file_offset,
-        };
-
-        for (auto iter = src->pgs->begin(); iter != src->pgs->end(); ++iter) {
-            // TODO: preserve dirty flag, clear accessed flag
-            if (k_map(&new_nn, &*iter,
-                    src->attr.in.read, src->attr.in.write, src->attr.in.system, 1)
+        return m_areas.cbegin();
+    }
+    constexpr const_iterator_type cend(void) const
+    {
+        return m_areas.cend();
+    }
+
+    constexpr iterator_type addarea(void* start, bool w, bool system)
+    {
+        return m_areas.emplace_back(mm {
+            .start = start,
+            .attr {
+                .in {
+                    .read = 1,
+                    .write = w,
+                    .system = system,
+                },
+            },
+            .owner = this,
+            .pgs = ::types::kernel_ident_allocator_new<page_arr>(),
+        });
+    }
+
+    constexpr void clear_user()
+    {
+        for (auto iter = this->begin(); iter != this->end();) {
+            if (iter->is_ident())
+                ++iter;
+
+            // TODO:
+            // k_unmap(iter.ptr());
+            iter = m_areas.erase(iter);
+        }
+    }
+
+    constexpr int mirror_area(mm& src)
+    {
+        auto area = this->addarea(
+            src.start, src.attr.in.write, src.attr.in.system);
+        if (src.mapped_file) {
+            area->mapped_file = src.mapped_file;
+            area->file_offset = src.file_offset;
+        }
+
+        for (auto& pg : *src.pgs) {
+            if (area->append_page(&pg,
+                    true,
+                    src.attr.in.write,
+                    src.attr.in.system,
+                    true)
                 != GB_OK) {
                 return GB_FAILED;
             }
         }
 
-        dst->emplace_back(types::move(new_nn));
         return GB_OK;
     }
-};
 
-inline constexpr void unmap_user_space_memory(mm_list& mms)
-{
-    // skip kernel heap
-    for (auto iter = ++mms.begin(); iter != mms.end();) {
-        k_unmap(iter.ptr());
-        types::kernel_ident_allocator_delete(iter->pgs);
-        iter = mms.erase(iter);
+    constexpr void unmap(iterator_type area)
+    {
+        for (auto& pg : *area->pgs) {
+            if (*pg.ref_count == 1) {
+                ki_free(pg.ref_count);
+                free_n_raw_pages(pg.phys_page_id, 1);
+            } else {
+                --*pg.ref_count;
+            }
+
+            pg.phys_page_id = 0;
+            pg.attr.v = 0;
+            pg.pte->v = 0;
+        }
+        area->attr.v = 0;
+        area->start = 0;
     }
-}
 
-// in mem.cpp
-extern mm_list* kernel_mms;
-extern page empty_page;
+    constexpr iterator_type find(void* lp)
+    {
+        for (auto iter = this->begin(); iter != this->end(); ++iter)
+            if (lp >= iter->start && lp < iter->end())
+                return iter;
+
+        return this->end();
+    }
+};
+
+} // namespace kernel
+
+// global variables
+inline kernel::mm_list* kernel_mms;
+inline page empty_page;
+// --------------------------------
 
 // translate physical address to virtual(mapped) address
 void* ptovp(pptr_t p_ptr);
 
-// @return the pointer to the mm_area containing l_ptr
-//         nullptr if not
-mm* find_mm_area(mm_list* mms, void* l_ptr);
-
 inline constexpr size_t vptrdiff(void* p1, void* p2)
 {
     return (uint8_t*)p1 - (uint8_t*)p2;
 }
-inline constexpr page* lto_page(const mm* mm_area, void* l_ptr)
+inline constexpr page* lto_page(mm* mm_area, void* l_ptr)
 {
     size_t offset = vptrdiff(l_ptr, mm_area->start);
     return &mm_area->pgs->at(offset / PAGE_SIZE);
@@ -159,10 +268,6 @@ inline constexpr pte_t* to_pte(pt_t pt, page_t pg)
 {
     return *pt + to_pti(pg);
 }
-inline pd_t mms_get_pd(const mm_list* mms)
-{
-    return mms->begin()->pd;
-}
 inline void* to_vp(page_t pg)
 {
     return ptovp(to_pp(pg));
@@ -199,15 +304,6 @@ inline pte_t* to_pte(pde_t* pde, page_t pg)
 {
     return to_pte(to_pt(pde), pg);
 }
-inline constexpr void* mmend(const mm* mm_area)
-{
-    return (char*)mm_area->start + mm_area->pgs->size() * PAGE_SIZE;
-}
-
-// allocate n raw page(s)
-// @return the id of the first page allocated
-page_t alloc_n_raw_pages(size_t n);
-void free_n_raw_pages(page_t start_pg, size_t n);
 
 // allocate a raw page
 inline page_t alloc_raw_page(void)

+ 2 - 2
include/kernel/process.hpp

@@ -32,7 +32,7 @@ struct thread {
 
 class process {
 public:
-    mm_list mms;
+    kernel::mm_list mms;
     types::list<thread> thds;
     // TODO: allocate a kernel stack for EVERY THREAD
     void* k_esp;
@@ -43,7 +43,7 @@ public:
 public:
     process(process&& val);
     process(const process&) = delete;
-    process(const process& proc, const thread& main_thread);
+    process(process& proc, const thread& main_thread);
 
     // only used for system initialization
     process(void* start_eip);

+ 5 - 5
src/kernel/interrupt.cpp

@@ -165,18 +165,18 @@ static inline void _int14_panic(void* eip, void* cr2, struct page_fault_error_co
 // page fault
 extern "C" void int14_handler(int14_data* d)
 {
-    mm_list* mms = nullptr;
+    kernel::mm_list* mms = nullptr;
     if (current_process)
         mms = &current_process->mms;
     else
         mms = kernel_mms;
 
-    mm* mm_area = find_mm_area(mms, d->l_addr);
-    if (unlikely(!mm_area))
+    auto mm_area = mms->find(d->l_addr);
+    if (unlikely(mm_area == mms->end()))
         _int14_panic(d->v_eip, d->l_addr, d->error_code);
 
-    pte_t* pte = to_pte(mms_get_pd(mms), d->l_addr);
-    page* page = lto_page(mm_area, d->l_addr);
+    pte_t* pte = to_pte(mms->m_pd, d->l_addr);
+    page* page = lto_page(mm_area.ptr(), d->l_addr);
 
     if (unlikely(d->error_code.present == 0 && !mm_area->mapped_file))
         _int14_panic(d->v_eip, d->l_addr, d->error_code);

+ 51 - 109
src/kernel/mem.cpp

@@ -9,16 +9,11 @@
 #include <kernel/task.h>
 #include <kernel/vga.h>
 #include <kernel_main.h>
+#include <types/allocator.hpp>
 #include <types/bitmap.h>
 #include <types/size.h>
 #include <types/status.h>
 
-// global objects
-
-mm_list* kernel_mms;
-
-// ---------------------
-
 // constant values
 
 #define EMPTY_PAGE_ADDR ((pptr_t)0x0000)
@@ -391,46 +386,54 @@ static inline void init_mem_layout(void)
     }
 }
 
-mm* find_mm_area(mm_list* mms, void* l_ptr)
+using kernel::mm_list;
+mm_list::mm_list(pd_t pd)
+    : m_pd(pd)
 {
-    for (auto iter = mms->begin(); iter != mms->end(); ++iter)
-        if (l_ptr >= iter->start && l_ptr < mmend(iter.ptr()))
-            return iter.ptr();
-    return nullptr;
 }
 
-static inline void map_raw_page_to_pte(
+mm_list::mm_list(const mm_list& v)
+    : m_areas(v.m_areas)
+{
+    pd_t pd = alloc_pd();
+    memcpy(pd, v.m_pd, PAGE_SIZE);
+    m_pd = pd;
+}
+
+mm_list::~mm_list()
+{
+    if (!m_pd)
+        return;
+
+    this->clear_user();
+    dealloc_pd(m_pd);
+}
+
+inline void map_raw_page_to_pte(
     pte_t* pte,
     page_t page,
-    int present,
-    int rw,
-    int priv)
+    bool present,
+    bool write,
+    bool priv)
 {
     // set P bit
     pte->v = 0;
     pte->in.p = present;
-    pte->in.rw = (rw == 1);
-    pte->in.us = (priv == 0);
+    pte->in.rw = write;
+    pte->in.us = !priv;
     pte->in.page = page;
 }
 
-// map page to the end of mm_area in pd
-int k_map(
-    mm* mm_area,
-    page* page,
-    int read,
-    int write,
-    int priv,
-    int cow)
+int mm::append_page(page* pg, bool present, bool write, bool priv, bool cow)
 {
-    void* addr = mmend(mm_area);
-    pde_t* pde = to_pde(mm_area->pd, addr);
+    void* addr = this->end();
+    pde_t* pde = to_pde(this->owner->m_pd, addr);
     // page table not exist
     if (unlikely(!pde->in.p)) {
         // allocate a page for the page table
         pde->in.p = 1;
         pde->in.rw = 1;
-        pde->in.us = (priv == 0);
+        pde->in.us = 1;
         pde->in.pt_page = alloc_raw_page();
 
         memset(to_pt(pde), 0x00, PAGE_SIZE);
@@ -438,51 +441,21 @@ int k_map(
 
     // map the page in the page table
     pte_t* pte = to_pte(pde, addr);
-    map_raw_page_to_pte(pte, page->phys_page_id, read, (write && !cow), priv);
+    map_raw_page_to_pte(pte, pg->phys_page_id, present, (write && !cow), priv);
 
-    if (unlikely(cow && !page->attr.in.cow)) {
-        page->attr.in.cow = 1;
-        page->pte->in.rw = 0;
-        page->pte->in.a = 0;
+    if (unlikely(cow && !pg->attr.in.cow)) {
+        pg->attr.in.cow = 1;
+        pg->pte->in.rw = 0;
+        pg->pte->in.a = 0;
         invalidate_tlb(addr);
     }
-    ++*page->ref_count;
+    ++*pg->ref_count;
 
-    auto iter = mm_area->pgs->emplace_back(*page);
+    auto iter = this->pgs->emplace_back(*pg);
     iter->pte = pte;
     return GB_OK;
 }
 
-int k_unmap(mm* mm_area)
-{
-    for (auto iter = mm_area->pgs->begin(); iter != mm_area->pgs->end(); ++iter) {
-        if (*iter->ref_count == 1) {
-            ki_free(iter->ref_count);
-            free_page(iter->phys_page_id);
-        } else {
-            --*iter->ref_count;
-        }
-
-        iter->phys_page_id = 0;
-        iter->attr.v = 0;
-        iter->pte->v = 0;
-    }
-    mm_area->attr.v = 0;
-    mm_area->start = 0;
-    return GB_OK;
-}
-
-bool check_addr_range_avail(const mm* mm_area, void* start, void* end)
-{
-    void* m_start = mm_area->start;
-    void* m_end = mmend(mm_area);
-
-    if (start >= m_end || end <= m_start)
-        return true;
-    else
-        return false;
-}
-
 static inline int _mmap(
     mm_list* mms,
     void* hint,
@@ -501,25 +474,17 @@ static inline int _mmap(
     size_t n_pgs = len >> 12;
 
     for (const auto& mm_area : *mms)
-        if (!check_addr_range_avail(&mm_area, hint, (char*)hint + len)) {
+        if (!mm_area.is_avail(hint, (char*)hint + len)) {
             errno = EEXIST;
             return GB_FAILED;
         }
 
-    auto iter_mm = mms->emplace_back(mm {
-        .start = hint,
-        .attr { .in {
-            .read = 1,
-            .write = static_cast<uint32_t>(write),
-            .system = static_cast<uint32_t>(priv),
-        } },
-        .pd = mms_get_pd(&current_process->mms),
-    });
-    iter_mm->mapped_file = file;
-    iter_mm->file_offset = offset;
+    auto mm = mms->addarea(hint, write, priv);
+    mm->mapped_file = file;
+    mm->file_offset = offset;
 
     for (size_t i = 0; i < n_pgs; ++i)
-        k_map(iter_mm.ptr(), &empty_page, 0, write, priv, 1);
+        mm->append_page(&empty_page, false, write, priv, true);
 
     return GB_OK;
 }
@@ -570,8 +535,6 @@ static inline void init_paging_map_low_mem_identically(void)
     }
 }
 
-page empty_page;
-
 void init_mem(void)
 {
     init_mem_layout();
@@ -579,28 +542,8 @@ void init_mem(void)
     // map the 16MiB-768MiB identically
     init_paging_map_low_mem_identically();
 
-    kernel_mms = types::kernel_ident_allocator_new<mm_list>();
-    auto heap_mm = kernel_mms->emplace_back(mm {
-        .start = KERNEL_HEAP_START,
-        .attr { .in {
-            .read = 1,
-            .write = 1,
-            .system = 1,
-        } },
-        .pd = KERNEL_PAGE_DIRECTORY_ADDR,
-    });
-
-    page heap_first_page {
-        .phys_page_id = alloc_raw_page(),
-        .pte = nullptr,
-        .ref_count = types::kernel_ident_allocator_new<size_t>(0),
-        .attr = { 0 },
-    };
-
-    k_map(heap_mm.ptr(), &heap_first_page, 1, 1, 1, 0);
-    memset(KERNEL_HEAP_START, 0x00, PAGE_SIZE);
-    kernel_heap_allocator = types::kernel_ident_allocator_new<brk_memory_allocator>(KERNEL_HEAP_START,
-        vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
+    kernel_mms = types::kernel_ident_allocator_pnew(kernel_mms, KERNEL_PAGE_DIRECTORY_ADDR);
+    auto heap_mm = kernel_mms->addarea(KERNEL_HEAP_START, true, true);
 
     // create empty_page struct
     empty_page.attr.in.cow = 0;
@@ -610,13 +553,12 @@ void init_mem(void)
     empty_page.pte->in.rw = 0;
     invalidate_tlb(0x00000000);
 
-    // TODO: improve the algorithm SO FREAKING SLOW
-    // while (kernel_mm_head->len < 256 * 1024 * 1024 / PAGE_SIZE) {
-    while (heap_mm->pgs->size() < 256 * 1024 * 1024 / PAGE_SIZE) {
-        k_map(
-            heap_mm.ptr(), &empty_page,
-            1, 1, 1, 1);
-    }
+    // 0x30000000 to 0x40000000 or 768MiB to 1GiB
+    while (heap_mm->pgs->size() < 256 * 1024 * 1024 / PAGE_SIZE)
+        heap_mm->append_page(&empty_page, true, true, true, true);
+
+    kernel_heap_allocator = types::kernel_ident_allocator_pnew(kernel_heap_allocator,
+        KERNEL_HEAP_START, vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));
 }
 
 void create_segment_descriptor(

+ 8 - 19
src/kernel/process.cpp

@@ -47,7 +47,7 @@ process::process(process&& val)
     val.attr.system = 0;
 }
 
-process::process(const process& val, const thread& main_thd)
+process::process(process& val, const thread& main_thd)
     : mms(*kernel_mms)
     , attr { .system = val.attr.system }
     , pid { ++max_pid }
@@ -70,14 +70,12 @@ process::process(const process& val, const thread& main_thd)
         iter_thd->regs.esp -= orig_k_esp;
         iter_thd->regs.esp += (uint32_t)k_esp;
     } else {
-        pd_t pd = alloc_pd();
-        memcpy(pd, mms_get_pd(kernel_mms), PAGE_SIZE);
+        for (auto& area : val.mms) {
+            if (area.is_ident())
+                continue;
 
-        mms.begin()->pd = pd;
-
-        // skip kernel heap since it's already copied above
-        for (auto iter_src = ++val.mms.cbegin(); iter_src != val.mms.cend(); ++iter_src)
-            mm::mirror_mm_area(&mms, iter_src.ptr(), pd);
+            mms.mirror_area(area);
+        }
     }
 }
 
@@ -124,15 +122,6 @@ void NORETURN _kernel_init(void)
     if (unlikely(ret != GB_OK))
         syscall(0x03);
 
-    pd_t new_pd = alloc_pd();
-    memcpy(new_pd, mms_get_pd(kernel_mms), PAGE_SIZE);
-
-    asm_cli();
-
-    current_process->mms.begin()->pd = new_pd;
-
-    asm_sti();
-
     interrupt_stack intrpt_stack {};
     intrpt_stack.eflags = 0x200; // STI
     const char* argv[] = { "/mnt/INIT.ELF", nullptr };
@@ -212,7 +201,7 @@ void NORETURN init_scheduler()
     tss.ss0 = KERNEL_DATA_SEGMENT;
     tss.esp0 = (uint32_t)init->k_esp;
 
-    asm_switch_pd(mms_get_pd(&current_process->mms));
+    asm_switch_pd(current_process->mms.m_pd);
 
     is_scheduler_ready = true;
 
@@ -249,7 +238,7 @@ void process_context_load(interrupt_stack*, process* proc)
 {
     if (!proc->attr.system)
         tss.esp0 = (uint32_t)proc->k_esp;
-    asm_switch_pd(mms_get_pd(&proc->mms));
+    asm_switch_pd(proc->mms.m_pd);
     current_process = proc;
 }
 

+ 3 - 3
src/kernel/syscall.cpp

@@ -69,7 +69,7 @@ void _syscall_exec(interrupt_stack* data)
     const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
     const char** argv = reinterpret_cast<const char**>(data->s_regs.esi);
 
-    unmap_user_space_memory(current_process->mms);
+    current_process->mms.clear_user();
 
     types::elf::elf32_load(exec, argv, data, current_process->attr.system);
 }
@@ -93,8 +93,8 @@ void _syscall_exit(interrupt_stack* data)
 
     // TODO: write back mmap'ped files and close them
 
-    // unmap all memory areas except kernel heap
-    unmap_user_space_memory(current_process->mms);
+    // unmap all user memory areas
+    current_process->mms.clear_user();
 
     // make child processes orphans (children of init)
     auto children = idx_child_processes->find(current_process->pid);