Sfoglia il codice sorgente

Merge branch 'ata' into special-device-file

greatbridf 2 anni fa
parent
commit
0638ea3bec
3 ha cambiato i file con 142 aggiunte e 100 eliminazioni
  1. 16 38
      include/kernel/mm.hpp
  2. 56 55
      src/kernel/interrupt.cpp
  3. 70 7
      src/kernel/mem.cpp

+ 16 - 38
include/kernel/mm.hpp

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <kernel/mem.h>
+#include <kernel/vfs.h>
 #include <types/allocator.hpp>
 #include <types/list.hpp>
 #include <types/types.h>
@@ -32,6 +33,8 @@ public:
     struct mm_attr attr;
     page_directory_entry* pd;
     page_arr* pgs;
+    struct inode* mapped_file;
+    size_t file_offset;
 
 public:
     mm(const mm& val);
@@ -53,10 +56,9 @@ phys_ptr_t l_ptr_to_p_ptr(const mm_list* mms, linr_ptr_t v_ptr);
 // translate virtual(mapped) address to physical address
 phys_ptr_t v_ptr_to_p_ptr(void* v_ptr);
 
-// check if the l_ptr is contained in the area
-// @return GB_OK if l_ptr is in the area
-//         GB_FAILED if not
-int is_l_ptr_valid(const mm_list* mms, linr_ptr_t l_ptr);
+// @return the pointer to the mm_area containing l_ptr
+//         nullptr if not
+mm* find_mm_area(mm_list* mms, linr_ptr_t l_ptr);
 
 // find the corresponding page the l_ptr pointing to
 // @return the pointer to the struct if found, NULL if not found
@@ -97,40 +99,6 @@ static inline page_directory_entry* mms_get_pd(const mm_list* mms)
     return mms->begin()->pd;
 }
 
-static inline page_directory_entry* lptr_to_pde(const mm_list* mms, linr_ptr_t l_ptr)
-{
-    return mms_get_pd(mms) + linr_addr_to_pd_i((phys_ptr_t)l_ptr);
-}
-
-static inline page_table_entry* lptr_to_pte(const mm_list* mms, linr_ptr_t l_ptr)
-{
-    page_directory_entry* pde = lptr_to_pde(mms, l_ptr);
-    page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
-    return pte + linr_addr_to_pt_i((phys_ptr_t)l_ptr);
-}
-
-static inline page_directory_entry* lp_to_pde(const mm_list* mms, linr_ptr_t l_ptr)
-{
-    phys_ptr_t p_ptr = l_ptr_to_p_ptr(mms, l_ptr);
-    page_directory_entry* pde = mms_get_pd(mms) + linr_addr_to_pd_i(p_ptr);
-    return pde;
-}
-
-// get the corresponding pte for the linear address
-// for example: l_ptr = 0x30001000 will return the pte including the page it is mapped to
-static inline page_table_entry* lp_to_pte(const mm_list* mms, linr_ptr_t l_ptr)
-{
-    phys_ptr_t p_ptr = l_ptr_to_p_ptr(mms, l_ptr);
-
-    page_directory_entry* pde = lp_to_pde(mms, l_ptr);
-    phys_ptr_t p_pt = page_to_phys_addr(pde->in.pt_page);
-
-    page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(p_pt);
-    pte += linr_addr_to_pt_i(p_ptr);
-
-    return pte;
-}
-
 // map the page to the end of the mm_area in pd
 int k_map(
     mm* mm_area,
@@ -140,6 +108,16 @@ int k_map(
     int priv,
     int cow);
 
+// @param len is aligned to 4kb boundary automatically, exceeding part will
+// be filled with '0's and not written back to the file
+int mmap(
+    void* hint,
+    size_t len,
+    struct inode* file,
+    size_t offset,
+    int write,
+    int priv);
+
 // allocate a raw page
 page_t alloc_raw_page(void);
 

+ 56 - 55
src/kernel/interrupt.cpp

@@ -11,8 +11,11 @@
 #include <kernel/stdio.h>
 #include <kernel/syscall.hpp>
 #include <kernel/tty.h>
+#include <kernel/vfs.h>
 #include <kernel/vga.h>
 #include <kernel_main.h>
+#include <types/size.h>
+#include <types/stdint.h>
 
 static struct IDT_entry IDT[256];
 
@@ -137,9 +140,6 @@ extern "C" void int13_handler(
     asm_hlt();
 }
 
-// TODO: remove debug variable
-static size_t page_fault_times;
-
 struct PACKED int14_data {
     linr_ptr_t l_addr;
     struct regs_32 s_regs;
@@ -149,74 +149,75 @@ struct PACKED int14_data {
     uint32_t eflags;
 };
 
+static inline void _int14_panic(void* eip, linr_ptr_t cr2, struct page_fault_error_code error_code)
+{
+    char buf[256] {};
+    snprintf(
+        buf, 256,
+        "\nkilled: segmentation fault (eip: %x, cr2: %x, error_code: %x)\n", eip, cr2, error_code);
+    tty_print(console, buf);
+    MAKE_BREAK_POINT();
+    asm_cli();
+    asm_hlt();
+}
+
 // page fault
-extern "C" void int14_handler(struct int14_data* d)
+extern "C" void int14_handler(int14_data* d)
 {
-    char buf[512];
     mm_list* mms = nullptr;
     if (current_process)
         mms = &current_process->mms;
     else
         mms = kernel_mms;
 
-    // TODO: remove debug variable
-    ++page_fault_times;
+    mm* mm_area = find_mm_area(mms, d->l_addr);
+    if (!mm_area)
+        _int14_panic(d->v_eip, d->l_addr, d->error_code);
 
-    // not present page, possibly mapped but not loaded
-    // or invalid address or just invalid address
-    // TODO: mmapping and swapping
-    if (d->error_code.present == 0) {
-        goto kill;
-    }
-
-    // kernel code
-    if (d->cs == KERNEL_CODE_SEGMENT) {
-        if (is_l_ptr_valid(mms, d->l_addr) != GB_OK) {
-            goto kill;
-        }
-        struct page* page = find_page_by_l_ptr(mms, d->l_addr);
-
-        // copy on write
-        if (d->error_code.write == 1 && page->attr.cow == 1) {
-            page_directory_entry* pde = mms_get_pd(mms) + linr_addr_to_pd_i(d->l_addr);
-            page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
-            pte += linr_addr_to_pt_i(d->l_addr);
-
-            // if it is a dying page
-            if (*page->ref_count == 1) {
-                page->attr.cow = 0;
-                pte->in.a = 0;
-                pte->in.rw = 1;
-                return;
-            }
-            // duplicate the page
-            page_t new_page = alloc_raw_page();
-            void* new_page_data = p_ptr_to_v_ptr(page_to_phys_addr(new_page));
-            memcpy(new_page_data, p_ptr_to_v_ptr(page_to_phys_addr(page->phys_page_id)), PAGE_SIZE);
-
-            pte->in.page = new_page;
-            pte->in.rw = 1;
-            pte->in.a = 0;
+    page_directory_entry* pde = mms_get_pd(mms) + linr_addr_to_pd_i(d->l_addr);
+    page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
+    pte += linr_addr_to_pt_i(d->l_addr);
+    struct page* page = find_page_by_l_ptr(mms, d->l_addr);
 
-            --*page->ref_count;
+    if (d->error_code.present == 0 && !mm_area->mapped_file)
+        _int14_panic(d->v_eip, d->l_addr, d->error_code);
 
-            page->ref_count = (size_t*)k_malloc(sizeof(size_t));
-            *page->ref_count = 1;
+    // copy on write
+    if (page->attr.cow == 1) {
+        // if it is a dying page
+        if (*page->ref_count == 1) {
             page->attr.cow = 0;
-            page->phys_page_id = new_page;
+            pte->in.a = 0;
+            pte->in.rw = mm_area->attr.write;
             return;
         }
-    }
+        // duplicate the page
+        page_t new_page = alloc_raw_page();
 
-kill:
-    snprintf(
-        buf, 512,
-        "\nkilled: segmentation fault (eip: %x, cr2: %x, error_code: %x)\n", d->v_eip, d->l_addr, d->error_code);
-    tty_print(console, buf);
+        // memory mapped
+        if (d->error_code.present == 0)
+            pte->in.p = 1;
 
-    MAKE_BREAK_POINT();
-    asm_cli();
-    asm_hlt();
+        char* new_page_data = (char*)p_ptr_to_v_ptr(page_to_phys_addr(new_page));
+        memcpy(new_page_data, p_ptr_to_v_ptr(page_to_phys_addr(page->phys_page_id)), PAGE_SIZE);
+
+        pte->in.page = new_page;
+        pte->in.rw = mm_area->attr.write;
+        pte->in.a = 0;
+
+        --*page->ref_count;
+
+        page->ref_count = (size_t*)k_malloc(sizeof(size_t));
+        *page->ref_count = 1;
+        page->attr.cow = 0;
+        page->phys_page_id = new_page;
+
+        // memory mapped
+        if (d->error_code.present == 0) {
+            size_t offset = d->l_addr - mm_area->start;
+            vfs_read(mm_area->mapped_file, new_page_data, 4096, mm_area->file_offset + offset, PAGE_SIZE);
+        }
+    }
 }
 
 extern "C" void irq0_handler(struct interrupt_stack* d)

+ 70 - 7
src/kernel/mem.cpp

@@ -4,11 +4,13 @@
 #include <kernel/errno.h>
 #include <kernel/mem.h>
 #include <kernel/mm.hpp>
+#include <kernel/process.hpp>
 #include <kernel/stdio.h>
 #include <kernel/task.h>
 #include <kernel/vga.h>
 #include <kernel_main.h>
 #include <types/bitmap.h>
+#include <types/status.h>
 
 // global objects
 
@@ -390,12 +392,12 @@ static inline void init_mem_layout(void)
     }
 }
 
-int is_l_ptr_valid(const mm_list* mms, linr_ptr_t l_ptr)
+mm* find_mm_area(mm_list* mms, linr_ptr_t l_ptr)
 {
-    for (const auto& item : *mms)
-        if (l_ptr >= item.start && l_ptr < item.start + item.pgs->size() * PAGE_SIZE)
-            return GB_OK;
-    return GB_FAILED;
+    for (auto iter = mms->begin(); iter != mms->end(); ++iter)
+        if (l_ptr >= iter->start && l_ptr < iter->start + iter->pgs->size() * PAGE_SIZE)
+            return iter.ptr();
+    return nullptr;
 }
 
 struct page* find_page_by_l_ptr(const mm_list* mms, linr_ptr_t l_ptr)
@@ -414,11 +416,13 @@ struct page* find_page_by_l_ptr(const mm_list* mms, linr_ptr_t l_ptr)
 static inline void map_raw_page_to_pte(
     page_table_entry* pte,
     page_t page,
+    int present,
     int rw,
     int priv)
 {
     // set P bit
-    pte->v = 0x00000001;
+    pte->v = 0;
+    pte->in.p = present;
     pte->in.rw = (rw == 1);
     pte->in.us = (priv == 0);
     pte->in.page = page;
@@ -449,7 +453,7 @@ int k_map(
     // map the page in the page table
     page_table_entry* pte = (page_table_entry*)p_ptr_to_v_ptr(page_to_phys_addr(pde->in.pt_page));
     pte += linr_addr_to_pt_i(addr);
-    map_raw_page_to_pte(pte, page->phys_page_id, (write && !cow), priv);
+    map_raw_page_to_pte(pte, page->phys_page_id, read, (write && !cow), priv);
 
     mm_area->pgs->push_back(*page);
     mm_area->pgs->back()->attr.cow = cow;
@@ -457,6 +461,61 @@ int k_map(
     return GB_OK;
 }
 
+bool check_addr_range_avail(const mm* mm_area, void* start, void* end)
+{
+    void* m_start = (void*)mm_area->start;
+    void* m_end = (void*)(mm_area->start + PAGE_SIZE * mm_area->pgs->size());
+
+    if (start >= m_end || end <= m_start)
+        return true;
+    else
+        return false;
+}
+
+static inline int _mmap(
+    mm_list* mms,
+    void* hint,
+    size_t len,
+    struct inode* file,
+    size_t offset,
+    int write,
+    int priv)
+{
+    if (!file->flags.file) {
+        errno = EINVAL;
+        return GB_FAILED;
+    }
+
+    len = (len + PAGE_SIZE - 1) & 0xfffff000;
+    size_t n_pgs = len >> 12;
+
+    for (const auto& mm_area : *mms)
+        if (!check_addr_range_avail(&mm_area, hint, (char*)hint + len)) {
+            errno = EEXIST;
+            return GB_FAILED;
+        }
+
+    auto iter_mm = mms->emplace_back((linr_ptr_t)hint, mms_get_pd(&current_process->mms), write, priv);
+    iter_mm->mapped_file = file;
+    iter_mm->file_offset = offset;
+
+    for (size_t i = 0; i < n_pgs; ++i)
+        k_map(iter_mm.ptr(), &empty_page, 0, write, priv, 1);
+
+    return GB_OK;
+}
+
+int mmap(
+    void* hint,
+    size_t len,
+    struct inode* file,
+    size_t offset,
+    int write,
+    int priv)
+{
+    return _mmap(&current_process->mms, hint, len, file, offset, write, priv);
+}
+
 // map a page identically
 // this function is only meant to be used in the initialization process
 // it checks the pde's P bit so you need to make sure it's already set
@@ -558,6 +617,8 @@ mm::mm(linr_ptr_t start, page_directory_entry* pd, bool write, bool system)
       })
     , pd(pd)
     , pgs(types::kernel_ident_allocator_new<page_arr>())
+    , mapped_file(nullptr)
+    , file_offset(0)
 {
 }
 
@@ -570,5 +631,7 @@ mm::mm(const mm& val)
       })
     , pd(val.pd)
     , pgs(val.pgs)
+    , mapped_file(nullptr)
+    , file_offset(0)
 {
 }