summaryrefslogtreecommitdiff
path: root/src/stem/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/stem/mem')
-rw-r--r--src/stem/mem/paging.c48
-rw-r--r--src/stem/mem/paging.h5
-rw-r--r--src/stem/mem/seg.c73
-rw-r--r--src/stem/mem/seg.h40
4 files changed, 157 insertions, 9 deletions
diff --git a/src/stem/mem/paging.c b/src/stem/mem/paging.c
index 5ce3aae..4cc861c 100644
--- a/src/stem/mem/paging.c
+++ b/src/stem/mem/paging.c
@@ -3,7 +3,9 @@
#include <stdlib.h>
#include <core/monitor.h>
#include "mem.h"
+#include "seg.h"
#include <core/sys.h>
+#include <task/task.h>
static struct bitset frames;
@@ -66,17 +68,45 @@ void pagedir_switch(struct page_directory *pd) {
asm volatile("mov %0, %%cr0" : : "r"(cr0));
}
+struct page_directory *pagedir_new() {
+ uint32_t i;
+
+ struct page_directory *pd = kmalloc(sizeof(struct page_directory));
+ pd->tablesPhysical = kmalloc_page(&pd->physicalAddr);
+
+ for (i = 768; i < 1024; i++) {
+ pd->tables[i] = kernel_pagedir->tables[i];
+ pd->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i];
+ }
+
+ return pd;
+}
+
uint32_t paging_fault(struct registers *regs) {
size_t addr;
+ struct segment_map *seg = 0;
asm volatile("mov %%cr2, %0" : "=r"(addr));
- monitor_write("PageFault ");
- if (regs->err_code & 0x1) monitor_write("present ");
- if (regs->err_code & 0x2) monitor_write("write ");
- if (regs->err_code & 0x4) monitor_write("user ");
- if (regs->err_code & 0x8) monitor_write("rsvd ");
- if (regs->err_code & 0x10) monitor_write("instructionfetch ");
- monitor_write("@"); monitor_writeHex(addr); monitor_write("\n");
- PANIC("Page fault");
+
+ seg = current_pagedir->mappedSegs;
+ while (seg) {
+ if (seg->start >= addr && seg->start + seg->len < addr) break;
+ seg = seg->next;
+ }
+
+ if (seg != 0) {
+ if (seg->seg->handle_fault(seg, addr, (regs->err_code & 0x2)) != 0) seg = 0;
+ }
+
+ if (seg == 0) {
+ monitor_write("PageFault ");
+ if (regs->err_code & 0x1) monitor_write("present ");
+ if (regs->err_code & 0x2) monitor_write("write ");
+ if (regs->err_code & 0x4) monitor_write("user ");
+ if (regs->err_code & 0x8) monitor_write("rsvd ");
+ if (regs->err_code & 0x10) monitor_write("instructionfetch ");
+ monitor_write("@"); monitor_writeHex(addr); monitor_write("\n");
+ return 1;
+ }
return 0;
}
@@ -88,6 +118,8 @@ struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int ma
return &pd->tables[table_idx]->pages[address % 1024];
} else if (make) {
pd->tables[table_idx] = kmalloc_page(pd->tablesPhysical + table_idx);
+ if (table_idx >= 768)
+ tasking_updateKernelPagetable(table_idx, pd->tables[table_idx], pd->tablesPhysical[table_idx]);
memset((uint8_t*)pd->tables[table_idx], 0, 0x1000);
pd->tablesPhysical[table_idx] |= 0x07;
return &pd->tables[table_idx]->pages[address % 1024];
diff --git a/src/stem/mem/paging.h b/src/stem/mem/paging.h
index 72078cf..9ee6c4c 100644
--- a/src/stem/mem/paging.h
+++ b/src/stem/mem/paging.h
@@ -18,10 +18,12 @@ struct page_table {
struct page pages[1024];
};
+struct segment_map;
struct page_directory {
struct page_table *tables[1024]; //Virtual addresses of page tables
uint32_t *tablesPhysical; //Pointer to the virtual address of the page directory (contain phys addr of pt)
uint32_t physicalAddr; //Physical address of info above
+ struct segment_map *mappedSegs;
};
extern struct page_directory *kernel_pagedir;
@@ -32,11 +34,12 @@ void frame_free(uint32_t id);
void paging_init(size_t totalRam);
void paging_cleanup();
void pagedir_switch(struct page_directory *pd);
+struct page_directory *pagedir_new(); //Creates a brand new empty page directory for a process, with kernel pages
struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int make);
void page_map(struct page *page, uint32_t frame, uint32_t user, uint32_t rw);
void page_unmap(struct page *page);
void page_unmapFree(struct page *page);
-uint32_t paging_fault(struct registers *regs); //returns a boolean
+uint32_t paging_fault(struct registers *regs); //returns a boolean : 1 if unhandled, 0 if ok
#endif
diff --git a/src/stem/mem/seg.c b/src/stem/mem/seg.c
new file mode 100644
index 0000000..f340c63
--- /dev/null
+++ b/src/stem/mem/seg.c
@@ -0,0 +1,73 @@
+#include "seg.h"
+#include "mem.h"
+
+struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir) {
+ struct segment_map *sm = seg->map(seg, pagedir);
+ if (sm == 0) return 0;
+ seg->mappings++;
+ sm->seg = seg;
+ sm->pagedir = pagedir;
+ sm->next = pagedir->mappedSegs;
+ pagedir->mappedSegs = sm->next;
+ return sm;
+}
+
+void seg_unmap(struct segment_map *map) {
+ map->seg->unmap(map);
+ if (map->pagedir->mappedSegs == map) {
+ map->pagedir->mappedSegs = map->pagedir->mappedSegs->next;
+ } else {
+ struct segment_map *m = map->pagedir->mappedSegs;
+ while (m->next != 0 && m->next != map) m = m->next;
+ if (m->next == map) m->next = map->next;
+ }
+ map->seg->mappings--;
+ if (map->seg->mappings == 0) {
+ map->seg->delete(map->seg);
+ kfree(map->seg->seg_data);
+ kfree(map->seg);
+ }
+ kfree (map);
+}
+
+// ************************************ SIMPLESEG stuff *************
+
+struct segment* simpleseg_make(size_t start, size_t len, int writable) {
+ struct simpleseg *ss = kmalloc(sizeof(struct simpleseg));
+ struct segment *se = kmalloc(sizeof(struct segment));
+ se->seg_data = ss;
+ se->mappings = 0;
+ se->map = simpleseg_map;
+ se->unmap = simpleseg_unmap;
+ se->delete = simpleseg_delete;
+ se->handle_fault = simpleseg_handleFault;
+ ss->writable = writable; ss->start = start; ss->len = len;
+ return se;
+}
+
+struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir) {
+ struct segment_map *sm = kmalloc(sizeof(struct segment_map));
+ sm->start = ((struct simpleseg*)(seg->seg_data))->start;
+ sm->len = ((struct simpleseg*)(seg->seg_data))->len;
+ return sm;
+}
+
+void simpleseg_unmap(struct segment_map* sm) {
+ size_t i;
+ for (i = sm->start; i < sm->start + sm->len; i += 0x1000) {
+ page_unmapFree(pagedir_getPage(sm->pagedir, i, 0));
+ }
+}
+
+int simpleseg_handleFault(struct segment_map* sm, size_t addr, int write) {
+ struct simpleseg *ss = sm->seg->seg_data;
+ if (write && !ss->writable) return 1;
+ addr &= 0xFFFFF000;
+ struct page *p = pagedir_getPage(sm->pagedir, addr, 1);
+ if (p->frame != 0) return 1;
+ page_map(p, frame_alloc(), 1, ss->writable);
+ return 0;
+}
+
+void simpleseg_delete(struct segment* seg) {
+}
diff --git a/src/stem/mem/seg.h b/src/stem/mem/seg.h
new file mode 100644
index 0000000..022d38e
--- /dev/null
+++ b/src/stem/mem/seg.h
@@ -0,0 +1,40 @@
+#ifndef DEF_SEG_H
+#define DEF_SEG_H
+
+#include "paging.h"
+
+struct segment_map;
+struct segment {
+ void* seg_data;
+ int mappings;
+
+ struct segment_map* (*map)(struct segment* seg, struct page_directory* pagedir);
+ void (*unmap)(struct segment_map*);
+ void (*delete)(struct segment* seg);
+ int (*handle_fault)(struct segment_map* map, size_t addr, int write); //0 if ok, 1 if segfault
+};
+
+struct segment_map {
+ struct segment* seg;
+ struct page_directory* pagedir;
+ size_t start, len;
+ struct segment_map *next;
+};
+
+struct segment_map *seg_map(struct segment* seg, struct page_directory* pagedir);
+void seg_unmap(struct segment_map* map);
+
+/// ************************************* SIMPLESEG stuff *****************
+
+struct simpleseg {
+ int writable;
+ size_t start, len;
+};
+
+struct segment* simpleseg_make(size_t start, size_t len, int writable);
+struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir);
+void simpleseg_unmap(struct segment_map*);
+void simpleseg_delete(struct segment *seg);
+int simpleseg_handleFault(struct segment_map* map, size_t addr, int write);
+
+#endif