Bladeren bron

refactor(mm): some tweaks of mm and mm_list

greatbridf 1 jaar geleden
bovenliggende
commit
4ee526a1aa
5 gewijzigde bestanden met toevoegingen van 181 en 188 verwijderingen
  1. 92 141
      include/kernel/mm.hpp
  2. 1 1
      include/kernel/process.hpp
  3. 9 9
      src/kernel/interrupt.cpp
  4. 75 25
      src/kernel/mem.cpp
  5. 4 12
      src/kernel/process.cpp

+ 92 - 141
include/kernel/mm.hpp

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <list>
+#include <set>
 #include <vector>
 #include <bit>
 #include <cstddef>
@@ -33,7 +33,7 @@ struct page {
     // 0 :11 : pte_index
     // 12:31 : pt_page
     uint32_t pg_pteidx;
-    uint32_t attr;
+    mutable uint32_t attr;
 };
 
 // private memory mapping
@@ -50,14 +50,6 @@ int mmap(
     int write,
     int priv);
 
-using page_arr = std::vector<page,
-    types::allocator_adapter<page, types::kernel_ident_allocator>>;
-
-// forward declaration
-namespace kernel {
-class mm_list;
-} // namespace kernel
-
 template <uint32_t base, uint32_t expo>
 constexpr uint32_t pow()
 {
@@ -116,44 +108,6 @@ void free_page(page* pg);
 page_t __alloc_raw_page(void);
 void __free_raw_page(page_t pg);
 
-struct mm {
-public:
-    void* start;
-    union {
-        uint32_t v;
-        struct {
-            uint32_t read : 1;
-            uint32_t write : 1;
-            uint32_t system : 1;
-        } in;
-    } attr;
-    kernel::mm_list* owner;
-    page_arr* pgs = nullptr;
-    fs::inode* mapped_file = nullptr;
-    size_t file_offset = 0;
-
-public:
-    constexpr void* end(void) const
-    {
-        return (char*)this->start + this->pgs->size() * PAGE_SIZE;
-    }
-
-    constexpr bool is_kernel_space(void) const
-    {
-        return this->start >= std::bit_cast<void*>(0xc0000000);
-    }
-
-    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, uint32_t attr, bool priv);
-};
-
 namespace kernel {
 
 void* pmap(page_t pg);
@@ -184,120 +138,113 @@ public:
     }
 };
 
+namespace memory {
+
+struct mm {
+public:
+    using pages_vector = std::vector<page,
+        types::allocator_adapter<page, types::kernel_ident_allocator>>;
+
+public:
+    void* start {};
+    struct mm_attr {
+        uint32_t write : 1;
+        uint32_t system : 1;
+        uint32_t mapped : 1;
+    } attr {};
+    pages_vector* pgs {};
+    fs::inode* mapped_file {};
+    size_t file_offset {};
+
+public:
+    constexpr void* end() const noexcept
+    { return vptradd(start, pgs->size() * PAGE_SIZE); }
+    constexpr bool is_kernel_space() const noexcept
+    { return start >= std::bit_cast<void*>(0xc0000000); }
+    constexpr bool is_avail(void* ostart, void* oend) const noexcept
+    {
+        void* m_start = start;
+        void* m_end = end();
+
+        return (ostart >= m_end || oend <= m_start);
+    }
+
+    void append_page(pd_t pd, const page& pg, uint32_t attr, bool priv);
+};
+
 class mm_list {
+private:
+    struct comparator {
+        constexpr bool operator()(const mm& lhs, const mm& rhs) const noexcept
+        { return lhs.start < rhs.start; }
+        constexpr bool operator()(const mm& lhs, void* rhs) const noexcept
+        { return lhs.end() <= rhs; }
+        constexpr bool operator()(void* lhs, const mm& rhs) const noexcept
+        { return lhs < rhs.start; }
+    };
+
 public:
-    using list_type = std::list<mm,
+    using list_type = std::set<mm, comparator,
         types::allocator_adapter<mm, types::kernel_ident_allocator>>;
-    using iterator_type = list_type::iterator;
-    using const_iterator_type = list_type::const_iterator;
+    using iterator = list_type::iterator;
+    using const_iterator = list_type::const_iterator;
+
+public:
+    static inline mm_list* s_kernel_mms;
 
 private:
     list_type m_areas;
-
-public:
     page_t m_pd;
 
 public:
+    // for system initialization only
     explicit constexpr mm_list(page_t pd)
-        : m_pd(pd)
-    {
-    }
-    mm_list(const mm_list& v);
+        : m_pd(pd) { }
+
+    // default constructor copies kernel_mms
+    explicit mm_list();
+    // copies kernel_mms and mirrors user space
+    explicit mm_list(const mm_list& other);
+
     constexpr mm_list(mm_list&& v)
         : m_areas(std::move(v.m_areas))
-        , m_pd(v.m_pd)
-    {
-        v.m_pd = 0;
-        for (auto& area : m_areas)
-            area.owner = this;
-    }
-    ~mm_list()
-    {
-        if (!m_pd)
-            return;
-
-        this->clear_user();
-        dealloc_pd(m_pd);
-    }
+        , m_pd(std::exchange(v.m_pd, 0)) { }
 
-    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
-    {
-        return m_areas.cbegin();
-    }
-    constexpr const_iterator_type cend(void) const
-    {
-        return m_areas.cend();
-    }
+    ~mm_list();
+    void switch_pd() const;
 
     constexpr mm& addarea(void* start, bool w, bool system)
     {
-        return m_areas.emplace_back(mm {
+        auto [ iter, inserted ] = m_areas.emplace(mm {
             .start = start,
             .attr {
-                .in {
-                    .read = 1,
-                    .write = w,
-                    .system = system,
-                },
+                .write = w,
+                .system = system,
+                .mapped = 0,
             },
-            .owner = this,
-            .pgs = types::_new<types::kernel_ident_allocator, page_arr>(),
+            .pgs = types::_new<types::kernel_ident_allocator, mm::pages_vector>(),
         });
+        assert(inserted);
+        return *iter;
     }
 
+    mm& add_empty_area(void* start, std::size_t page_count,
+        uint32_t page_attr, bool w, bool system);
+
     constexpr void clear_user()
     {
-        for (auto iter = this->begin(); iter != this->end();) {
+        for (auto iter = m_areas.begin(); iter != m_areas.end(); ) {
             if (iter->is_kernel_space()) {
                 ++iter;
                 continue;
             }
 
             this->unmap(iter);
-
             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,
-                    PAGE_COW | (pg.attr & PAGE_MMAP),
-                    src.attr.in.system)
-                != GB_OK) {
-                return GB_FAILED;
-            }
-        }
-
-        return GB_OK;
-    }
-
-    inline void unmap(iterator_type area)
+    inline void unmap(iterator area)
     {
         int i = 0;
 
@@ -318,36 +265,40 @@ public:
             invalidate_tlb((uint32_t)area->start + (i++) * PAGE_SIZE);
         }
         types::pdelete<types::kernel_ident_allocator>(area->pgs);
-        area->attr.v = 0;
-        area->start = 0;
     }
 
-    constexpr iterator_type find(void* lp)
+    constexpr mm* find(void* lp)
     {
-        for (auto iter = this->begin(); iter != this->end(); ++iter)
-            if (lp >= iter->start && lp < iter->end())
-                return iter;
-
-        return this->end();
+        auto iter = m_areas.find(lp);
+        if (iter == m_areas.end())
+            return nullptr;
+        return &*iter;
+    }
+    constexpr const mm* find(void* lp) const
+    {
+        auto iter = m_areas.find(lp);
+        if (iter == m_areas.end())
+            return nullptr;
+        return &*iter;
     }
 
-    constexpr bool is_avail(void* start, size_t len)
+    constexpr bool is_avail(void* start, size_t len) const noexcept
     {
         start = align_down<12>(start);
         len = vptrdiff(align_up<12>(vptradd(start, len)), start);
-        for (const auto& area : *this) {
-            if (!area.is_avail(start, (char*)start + len))
+        for (const auto& area : m_areas) {
+            if (!area.is_avail(start, vptradd(start, len)))
                 return false;
         }
-
         return true;
     }
 };
 
+} // namespace memory
+
 } // namespace kernel
 
 // global variables
-inline kernel::mm_list* kernel_mms;
 inline page empty_page;
 // --------------------------------
 

+ 1 - 1
include/kernel/process.hpp

@@ -278,7 +278,7 @@ public:
     };
 
 public:
-    mutable kernel::mm_list mms;
+    kernel::memory::mm_list mms {};
     std::set<kernel::tasks::thread> thds;
     kernel::cond_var cv_wait;
     std::list<wait_obj> waitlist;

+ 9 - 9
src/kernel/interrupt.cpp

@@ -164,14 +164,14 @@ static inline void NORETURN _int14_kill_user(void)
 // page fault
 extern "C" void int14_handler(int14_data* d)
 {
-    kernel::mm_list* mms = nullptr;
-    if (current_process)
+    kernel::memory::mm_list* mms = nullptr;
+    if (current_process) [[likely]]
         mms = &current_process->mms;
     else
-        mms = kernel_mms;
+        mms = kernel::memory::mm_list::s_kernel_mms;
 
-    auto mm_area = mms->find(d->l_addr);
-    if (unlikely(mm_area == mms->end())) {
+    auto* mm_area = mms->find(d->l_addr);
+    if (!mm_area) [[unlikely]] {
         if (d->error_code.user) {
             // user access of address that does not exist
             _int14_kill_user();
@@ -179,10 +179,10 @@ extern "C" void int14_handler(int14_data* d)
             _int14_panic(d->v_eip, d->l_addr, d->error_code);
         }
     }
-    if (unlikely(d->error_code.user && mm_area->attr.in.system))
+    if (d->error_code.user && mm_area->attr.system)
         _int14_kill_user();
 
-    page* page = &mm_area->pgs->at(vptrdiff(d->l_addr, mm_area->start) / PAGE_SIZE);
+    page* page = &(*mm_area->pgs)[vptrdiff(d->l_addr, mm_area->start) / PAGE_SIZE];
     kernel::paccess pa(page->pg_pteidx >> 12);
     auto pt = (pt_t)pa.ptr();
     assert(pt);
@@ -197,7 +197,7 @@ extern "C" void int14_handler(int14_data* d)
             page->attr &= ~PAGE_COW;
             pte->in.p = 1;
             pte->in.a = 0;
-            pte->in.rw = mm_area->attr.in.write;
+            pte->in.rw = mm_area->attr.write;
             return;
         }
         // duplicate the page
@@ -212,7 +212,7 @@ extern "C" void int14_handler(int14_data* d)
         }
 
         pte->in.page = new_page;
-        pte->in.rw = mm_area->attr.in.write;
+        pte->in.rw = mm_area->attr.write;
         pte->in.a = 0;
 
         --*page->ref_count;

+ 75 - 25
src/kernel/mem.cpp

@@ -198,24 +198,77 @@ static inline void init_mem_layout(void)
     }
 }
 
-using kernel::mm_list;
-mm_list::mm_list(const mm_list& v)
-    : m_areas(v.m_areas)
+using kernel::memory::mm_list;
+using kernel::memory::mm;
+
+mm_list::mm_list()
+    : m_areas(s_kernel_mms->m_areas)
 {
     m_pd = __alloc_raw_page();
-    kernel::paccess pdst(m_pd), psrc(v.m_pd);
+    kernel::paccess pdst(m_pd), psrc(s_kernel_mms->m_pd);
     auto* dst = pdst.ptr();
     auto* src = psrc.ptr();
     assert(dst && src);
     memcpy(dst, src, PAGE_SIZE);
 }
 
-inline void map_raw_page_to_pte(
-    pte_t* pte,
-    page_t page,
-    bool present,
-    bool write,
-    bool priv)
+mm_list::mm_list(const mm_list& other)
+    : mm_list()
+{
+    for (auto& src : other.m_areas) {
+        if (src.is_kernel_space() || src.attr.system)
+            continue;
+
+        auto& area = this->addarea(
+            src.start, src.attr.write, src.attr.system);
+
+        if (src.attr.mapped) {
+            area.attr.mapped = 1;
+            area.mapped_file = src.mapped_file;
+            area.file_offset = src.file_offset;
+        }
+
+        paccess pa(m_pd);
+        pd_t pd = (pd_t)pa.ptr();
+
+        for (const auto& pg : *src.pgs) {
+            area.append_page(pd, pg,
+                    PAGE_COW | (pg.attr & PAGE_MMAP),
+                    src.attr.system);
+        }
+    }
+}
+
+mm_list::~mm_list()
+{
+    if (!m_pd)
+        return;
+
+    clear_user();
+    dealloc_pd(m_pd);
+}
+
+void mm_list::switch_pd() const
+{
+    asm_switch_pd(m_pd);
+}
+
+mm& mm_list::add_empty_area(void *start, std::size_t page_count,
+    uint32_t page_attr, bool w, bool system)
+{
+    auto& area = addarea(start, w, system);
+    kernel::paccess pa(m_pd);
+    pd_t pd = (pd_t)pa.ptr();
+
+    while (page_count--)
+        area.append_page(pd, empty_page, page_attr, system);
+
+    return area;
+}
+
+constexpr void map_raw_page_to_pte(
+    pte_t* pte, page_t page,
+    bool present, bool write, bool priv)
 {
     // set P bit
     pte->v = 0;
@@ -225,18 +278,17 @@ inline void map_raw_page_to_pte(
     pte->in.page = page;
 }
 
-int mm::append_page(page& pg, uint32_t attr, bool priv)
+void mm::append_page(pd_t pd, const page& pg, uint32_t attr, bool priv)
 {
-    void* addr = this->end();
-    kernel::paccess pa(this->owner->m_pd);
-    auto pd = (pd_t)pa.ptr();
     assert(pd);
+
+    void* addr = this->end();
     pde_t* pde = *pd + v_to_pdi(addr);
 
     page_t pt_pg = 0;
     pte_t* pte = nullptr;
     // page table not exist
-    if (unlikely(!pde->in.p)) {
+    if (!pde->in.p) [[unlikely]] {
         // allocate a page for the page table
         pt_pg = __alloc_raw_page();
         pde->in.p = 1;
@@ -285,8 +337,6 @@ int mm::append_page(page& pg, uint32_t attr, bool priv)
     auto& emplaced = this->pgs->back();
     emplaced.pg_pteidx = (pt_pg << 12) + pti;
     emplaced.attr = attr;
-
-    return GB_OK;
 }
 
 int mmap(
@@ -316,13 +366,12 @@ int mmap(
         return GB_FAILED;
     }
 
-    auto& mm = mms.addarea(hint, write, priv);
+    auto& mm = mms.add_empty_area(hint, n_pgs, PAGE_MMAP | PAGE_COW, write, priv);
+
+    mm.attr.mapped = 1;
     mm.mapped_file = file;
     mm.file_offset = offset;
 
-    for (size_t i = 0; i < n_pgs; ++i)
-        mm.append_page(empty_page, PAGE_MMAP | PAGE_COW, priv);
-
     return GB_OK;
 }
 
@@ -332,8 +381,9 @@ void init_mem(void)
     init_mem_layout();
 
     // TODO: replace early kernel pd
-    kernel_mms = types::pnew<types::kernel_ident_allocator>(kernel_mms, EARLY_KERNEL_PD_PAGE);
-    auto& heap_mm = kernel_mms->addarea(KERNEL_HEAP_START, true, true);
+    auto* __kernel_mms = types::_new<types::kernel_ident_allocator,
+            kernel::memory::mm_list>(EARLY_KERNEL_PD_PAGE);
+    kernel::memory::mm_list::s_kernel_mms = __kernel_mms;
 
     // create empty_page struct
     empty_page.attr = 0;
@@ -342,8 +392,8 @@ void init_mem(void)
     empty_page.pg_pteidx = 0x00002000;
 
     // 0xd0000000 to 0xd4000000 or 3.5GiB, size 64MiB
-    while (heap_mm.pgs->size() < 64 * 1024 * 1024 / PAGE_SIZE)
-        heap_mm.append_page(empty_page, PAGE_COW, true);
+    __kernel_mms->add_empty_area(KERNEL_HEAP_START,
+        64 * 1024 * 1024 / PAGE_SIZE, PAGE_COW, true, true);
 
     types::__allocator::init_kernel_heap(KERNEL_HEAP_START,
         vptrdiff(KERNEL_HEAP_LIMIT, KERNEL_HEAP_START));

+ 4 - 12
src/kernel/process.cpp

@@ -126,24 +126,16 @@ int filearr::open(const process &current, const char *filename, uint32_t flags)
 }
 
 process::process(const process& parent, pid_t pid)
-    : mms { *kernel_mms }
-    , attr { parent.attr } , pwd { parent.pwd }
+    : mms { parent.mms }, attr { parent.attr } , pwd { parent.pwd }
     , signals { parent.signals } , pid { pid }
     , ppid { parent.pid } , pgid { parent.pgid } , sid { parent.sid }
     , control_tty { parent.control_tty }, root { parent.root }
 {
-    for (auto& area : parent.mms) {
-        if (area.is_kernel_space() || area.attr.in.system)
-            continue;
-
-        mms.mirror_area(area);
-    }
-
     this->files.dup_all(parent.files);
 }
 
 process::process(pid_t pid, pid_t ppid)
-    : mms(*kernel_mms) , attr { .system = true }
+    : attr { .system = true }
     , pwd { "/" } , pid { pid } , ppid { ppid } { }
 
 void proclist::kill(pid_t pid, int exit_code)
@@ -380,7 +372,7 @@ void NORETURN init_scheduler(void)
     tss.ss0 = KERNEL_DATA_SEGMENT;
     tss.esp0 = current_thread->pkstack;
 
-    asm_switch_pd(current_process->mms.m_pd);
+    current_process->mms.switch_pd();
 
     asm volatile(
         "movl %0, %%esp\n"
@@ -423,7 +415,7 @@ bool schedule()
 
     proc = &procs->find(thd->owner);
     if (current_process != proc) {
-        asm_switch_pd(proc->mms.m_pd);
+        proc->mms.switch_pd();
         current_process = proc;
     }