aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/memory
diff options
context:
space:
mode:
authorMarvin Borner2020-06-01 23:30:40 +0200
committerMarvin Borner2020-06-01 23:30:40 +0200
commit0b3b63ffdedb2e37e0732c09eb0e967e256f0d71 (patch)
treef92a97a59e15d699b2594d3d313214f241ae8565 /src/kernel/memory
parent5782d6b0c10b322d78c5d1284cbd4199d2e0f7ce (diff)
Very clean mmap approach
Sorry for the previous commit messages, I was kind of frustrated.
Diffstat (limited to 'src/kernel/memory')
-rw-r--r--src/kernel/memory/alloc.c8
-rw-r--r--src/kernel/memory/mmap.c106
-rw-r--r--src/kernel/memory/mmap.h18
-rw-r--r--src/kernel/memory/paging.c241
-rw-r--r--src/kernel/memory/paging.h90
5 files changed, 230 insertions, 233 deletions
diff --git a/src/kernel/memory/alloc.c b/src/kernel/memory/alloc.c
index d1d8b47..4f76080 100644
--- a/src/kernel/memory/alloc.c
+++ b/src/kernel/memory/alloc.c
@@ -1,6 +1,7 @@
#include <io/io.h>
#include <lib/lib.h>
#include <memory/alloc.h>
+#include <memory/mmap.h>
#include <memory/paging.h>
#include <stddef.h>
#include <stdint.h>
@@ -22,13 +23,13 @@ int liballoc_unlock()
void *liballoc_alloc(u32 p)
{
- u32 ptr = paging_alloc_pages((u32)p);
+ u32 ptr = kmalloc_frames((u32)p);
return (void *)ptr;
}
int liballoc_free(void *ptr, u32 p)
{
- paging_set_free((u32)ptr, (u32)p);
+ kfree_frames((u32)ptr, (u32)p);
return 0;
}
@@ -96,8 +97,7 @@ static long long l_possible_overruns = 0;
static void *liballoc_memset(void *s, int c, u32 n)
{
- u32 i;
- for (i = 0; i < n; i++)
+ for (u32 i = 0; i < n; i++)
((char *)s)[i] = c;
return s;
diff --git a/src/kernel/memory/mmap.c b/src/kernel/memory/mmap.c
new file mode 100644
index 0000000..ab021b8
--- /dev/null
+++ b/src/kernel/memory/mmap.c
@@ -0,0 +1,106 @@
+#include <memory/mmap.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <system.h>
+
+#define FRAME_SIZE 0x1000
+#define FRAME_COUNT (total_memory / 4)
+#define FRAME_TABLE_SIZE (FRAME_COUNT / 32)
+
+#define FREE 0x0
+#define USED 0x1
+
+void *kmalloc(u32 size);
+
+extern u32 kernel_end;
+u32 kernel_end_address = (u32)&kernel_end;
+
+u32 total_memory;
+
+u32 *frame_table;
+
+void *kmalloc(u32 size)
+{
+ void *ret;
+
+ ret = (void *)kernel_end_address;
+ kernel_end_address += size;
+
+ return ret;
+}
+
+// TODO: Efficiency
+void *kmalloc_frames(u32 num)
+{
+ u8 found;
+
+ for (u32 i = 0; i < FRAME_COUNT; i++) {
+ found = 1;
+ for (u32 j = 0; j < num; j++) {
+ if (mmap_index_check(i + j) == USED) {
+ found = 0;
+ break;
+ }
+ }
+ if (found) {
+ for (u32 j = 0; j < num; j++) {
+ mmap_index_set_used(i + j);
+ }
+ return (void *)(i * FRAME_SIZE);
+ }
+ }
+
+ warn("Not enough frames");
+ return NULL;
+}
+
+void kfree_frames(void *ptr, u32 num)
+{
+ u32 address = (u32)ptr;
+ u32 i = address;
+
+ while (i < address + (num * FRAME_SIZE)) {
+ mmap_address_set_free(address);
+ i += FRAME_SIZE;
+ }
+}
+
+u8 mmap_index_check(u32 n)
+{
+ return (frame_table[n / 32] >> (n % 32)) & 0x1;
+}
+
+void mmap_init(u32 size)
+{
+ total_memory = size;
+ frame_table = kmalloc(FRAME_TABLE_SIZE);
+}
+
+void mmap_init_finalize()
+{
+ // TODO: Efficiency
+ //memset(frame_table, 0xFF, (&kernel_end / FRAME_SIZE) / 8);
+ for (u32 i = 0; i < kernel_end_address; i += FRAME_SIZE) {
+ mmap_address_set_used(i);
+ }
+}
+
+void mmap_address_set_free(u32 address)
+{
+ frame_table[(address / FRAME_SIZE) / 32] &= ~(1 << ((address / FRAME_SIZE) % 32));
+}
+
+void mmap_address_set_used(u32 address)
+{
+ frame_table[(address / FRAME_SIZE) / 32] |= (1 << ((address / FRAME_SIZE) % 32));
+}
+
+void mmap_index_set_free(u32 n)
+{
+ frame_table[n / 32] &= ~(1 << (n % 32));
+}
+
+void mmap_index_set_used(u32 n)
+{
+ frame_table[n / 32] |= 1 << (n % 32);
+} \ No newline at end of file
diff --git a/src/kernel/memory/mmap.h b/src/kernel/memory/mmap.h
new file mode 100644
index 0000000..1de801f
--- /dev/null
+++ b/src/kernel/memory/mmap.h
@@ -0,0 +1,18 @@
+#ifndef MELVIX_MMAP
+#define MELVIX_MMAP
+
+#include <stdint.h>
+
+void *kmalloc_frames(u32 num);
+void kfree_frames(void *ptr, u32 num);
+
+u8 mmap_check(u32 n);
+void mmap_init(u32 size);
+void mmap_init_finalize();
+void mmap_address_set_free(u32 address);
+void mmap_address_set_used(u32 address);
+u8 mmap_index_check(u32 n);
+void mmap_index_set_free(u32 n);
+void mmap_index_set_used(u32 n);
+
+#endif \ No newline at end of file
diff --git a/src/kernel/memory/paging.c b/src/kernel/memory/paging.c
index 0e2cea4..1d9f6b1 100644
--- a/src/kernel/memory/paging.c
+++ b/src/kernel/memory/paging.c
@@ -1,238 +1,109 @@
+#include <io/io.h>
#include <lib/lib.h>
-#include <memory/alloc.h>
+#include <memory/mmap.h>
#include <memory/paging.h>
#include <stdint.h>
#include <system.h>
-u32 kernel_page_directory[PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN)));
-u32 kernel_page_tables[PAGE_COUNT][PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN)));
-u32 *temp_dir[PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN)));
-
-u32 **page_directory __attribute__((aligned(PAGE_ALIGN)));
-
-void paging_init(u32 **dir)
-{
- //log("%d", paging_get_used_pages());
- for (u32 i = 0; i < PAGE_COUNT; i++) {
- dir[i] = kernel_page_tables[i];
- for (u32 j = 0; j < PAGE_COUNT; j++) {
- dir[i][j] = kernel_page_tables[i][j];
- }
- }
-}
-
-void paging_kernel_init()
-{
- for (u32 i = 0; i < PAGE_COUNT; i++)
- for (u32 j = 0; j < PAGE_COUNT; j++)
- kernel_page_tables[i][j] =
- ((j * PAGE_ALIGN) + (i * PAGE_SIZE)) | PT_RW | PT_USER;
-
- for (u32 i = 0; i < PAGE_COUNT; i++)
- kernel_page_directory[i] =
- ((u32)kernel_page_tables[i]) | PD_RW | PD_PRESENT | PD_USER;
-
- page_directory = temp_dir;
- for (u32 i = 0; i < PAGE_COUNT; i++) {
- page_directory[i] = kernel_page_tables[i];
- for (u32 j = 0; j < PAGE_COUNT; j++) {
- page_directory[i][j] = kernel_page_tables[i][j];
- }
- }
-}
+struct page_dir *kernel_page_directory;
void paging_install()
{
- paging_switch_directory((u32 **)kernel_page_directory);
- paging_kernel_init();
-
- if (!memory_init())
- paging_set_present(0, memory_get_all() >> 3);
- paging_set_used(0, ((u32)&kernel_end >> 12) + 1);
-
- paging_enable();
- log("Installed paging");
-
- // Test!
- u32 *a = malloc(PAGE_ALIGN);
- u32 *b = malloc(PAGE_ALIGN);
- free(b);
- free(a);
- u32 *c = malloc(2048);
- assert(a == c);
- c[42] = 0x4242;
- assert(c[42] == 0x4242);
- free(c);
- info("Malloc test succeeded!");
-}
+ memory_init();
-u32 **paging_make_directory()
-{
- /* u32 **dir = valloc(PAGE_COUNT * sizeof(*dir)); */
- /* dir[0] = malloc(PAGE_COUNT * PAGE_COUNT * sizeof(**dir)); */
- /* for (u32 i = 1; i < PAGE_COUNT; i++) */
- /* dir[i] = dir[0] + i * PAGE_COUNT; */
- u32 **dir = valloc(PAGE_COUNT * sizeof(*dir));
- for (u32 i = 0; i < PAGE_COUNT; i++)
- dir[i] = malloc(PAGE_COUNT + sizeof(**dir));
+ struct page_table *page_table;
+ page_table = kmalloc_frames(1);
+ memset(page_table, 0, sizeof(struct page_table));
for (u32 i = 0; i < PAGE_COUNT; i++) {
- dir[i] = kernel_page_directory[i];
- /* for (u32 j = 0; j < PAGE_COUNT; j++) { */
- /* dir[i][j] = (&kernel_page_directory[i])[j]; */
- /* } */
+ page_table->entries[i].present = 1;
+ page_table->entries[i].writable = 1;
+ page_table->entries[i].address = SHIFT(i * PAGE_SIZE);
}
- paging_switch_directory(dir);
- log("%d", 42);
+ kernel_page_directory = kmalloc_frames(1);
+ memset(kernel_page_directory, 0, sizeof(struct page_dir));
+ kernel_page_directory->entries[0].present = 1;
+ kernel_page_directory->entries[0].writable = 1;
+ kernel_page_directory->entries[0].address = SHIFT((u32)page_table);
- return dir;
-}
-
-void paging_remove_directory(u32 **dir)
-{
- // TODO: Fix freeing of directory by calculating aligned offset
- free(dir[0]);
- free(dir);
+ paging_switch_directory((u32)kernel_page_directory);
+ paging_enable();
+ info("Installed paging");
}
void paging_disable()
{
- u32 cr0;
- asm("mov %%cr0, %0" : "=r"(cr0));
+ u32 cr0 = cr0_get();
cr0 &= 0x7fffffff;
- asm("mov %0, %%cr0" ::"r"(cr0));
+ cr0_set(cr0);
paging_enabled = 0;
}
void paging_enable()
{
- u32 cr0;
- asm("mov %%cr0, %0" : "=r"(cr0));
+ u32 cr0 = cr0_get();
cr0 |= 0x80000000;
- asm("mov %0, %%cr0" ::"r"(cr0));
+ cr0_set(cr0);
paging_enabled = 1;
}
-void paging_switch_directory(u32 **dir)
-{
- page_directory = dir;
- asm("mov %0, %%cr3" ::"r"(dir));
-}
-
-void invlpg(u32 addr)
-{
- asm("invlpg (%0)" ::"r"(addr) : "memory");
-}
-
-void paging_map(u32 phy, u32 virt, u16 flags)
-{
- u32 pdi = virt >> 22;
- u32 pti = virt >> 12 & 0x03FF;
- page_directory[pdi][pti] = phy | flags;
- invlpg(virt);
-}
-
-void paging_map_user(u32 phy, u32 virt)
+void paging_switch_directory(u32 dir)
{
- u32 pdi = virt >> 22;
- /* u32 pti = virt >> 12 & 0x03FF; */
- for (int i = 0; i < 1024; i++) {
- page_directory[pdi][i] = phy | PT_RW | PT_PRESENT | PT_USER;
- phy += 4096;
- }
- invlpg(virt);
+ cr3_set(dir);
}
-u32 paging_get_phys(u32 virt)
+struct page_table_entry *paging_get_page(u32 address, struct page_dir *page_dir)
{
- u32 pdi = virt >> 22;
- u32 pti = (virt >> 12) & 0x03FF;
- return page_directory[pdi][pti] & 0xFFFFF000;
-}
+ struct page_table *page_table;
-u16 paging_get_flags(u32 virt)
-{
- u32 pdi = virt >> 22;
- u32 pti = (virt >> 12) & 0x03FF;
- return page_directory[pdi][pti] & 0xFFF;
-}
+ address /= PAGE_SIZE;
+ u32 n = address / PAGE_COUNT;
-void paging_set_flag_up(u32 virt, u32 count, u32 flag)
-{
- //debug("Setting flag %b for %d tables", flag, count);
- u32 page_n = virt / PAGE_ALIGN;
- for (u32 i = page_n; i < page_n + count; i++) {
- page_directory[i / PAGE_COUNT][i % PAGE_COUNT] |= flag;
- invlpg(i * PAGE_ALIGN);
- }
-}
+ if (page_dir->entries[n].present == 0) {
+ page_table = kmalloc_frames(1);
+ memset(page_table, 0, sizeof(struct page_table));
-void paging_set_flag_down(u32 virt, u32 count, u32 flag)
-{
- u32 page_n = virt / PAGE_ALIGN;
- for (u32 i = page_n; i < page_n + count; i++) {
- page_directory[i / PAGE_COUNT][i % PAGE_COUNT] &= ~flag;
- invlpg(i * PAGE_ALIGN);
+ page_dir->entries[n].address = SHIFT((u32)page_table);
+ page_dir->entries[n].present = 1;
+ page_dir->entries[n].writable = 1;
+ page_dir->entries[n].user = 1;
+ } else {
+ page_table = (void *)UNSHIFT(page_dir->entries[n].address);
}
-}
-void paging_set_present(u32 virt, u32 count)
-{
- paging_set_flag_up(virt, count, PT_PRESENT);
+ return &page_table->entries[address % PAGE_COUNT];
}
-void paging_set_absent(u32 virt, u32 count)
+void paging_frame_alloc(struct page_table_entry *page)
{
- paging_set_flag_down(virt, count, PT_PRESENT);
-}
+ void *ptr = kmalloc_frames(1);
-void paging_set_used(u32 virt, u32 count)
-{
- paging_set_flag_up(virt, count, PT_USED);
+ if (page->address != 0) {
+ warn("Page is already allocated");
+ return;
+ }
+ page->address = SHIFT((u32)ptr);
+ page->present = 1;
+ page->user = 1;
}
-void paging_set_free(u32 virt, u32 count)
+void paging_frame_free(struct page_table_entry *page)
{
- paging_set_flag_down(virt, count, PT_USED);
+ kfree_frames((void *)UNSHIFT(page->address), 1);
+ memset((void *)page, 0, sizeof(struct page_table_entry));
}
-u32 paging_find_pages(u32 count)
+struct page_dir *paging_make_dir()
{
- u32 continuous = 0;
- u32 start_dir = 0;
- u32 start_page = 0;
- for (u32 i = 0; i < PAGE_COUNT; i++) {
- for (u32 j = 0; j < PAGE_COUNT; j++) {
- if (!(page_directory[i][j] & PT_PRESENT) ||
- (page_directory[i][j] & PT_USED)) {
- continuous = 0;
- start_dir = i;
- start_page = j + 1;
- } else {
- if (++continuous == count)
- return (start_dir * PAGE_SIZE) + (start_page * PAGE_ALIGN);
- }
- }
- }
+ struct page_dir *ret = kmalloc_frames(1);
- panic("Out of memory!");
- return 0;
-}
+ memcpy(ret, kernel_page_directory, sizeof(struct page_dir));
-u32 paging_alloc_pages(u32 count)
-{
- u32 ptr = paging_find_pages(count);
- paging_set_used(ptr, count);
- return ptr;
+ return ret;
}
-u32 paging_get_used_pages()
+void paging_free_dir(struct page_dir *page_dir)
{
- u32 n = 0;
- for (u32 i = 0; i < PAGE_COUNT; i++)
- for (u32 j = 0; j < PAGE_COUNT; j++)
- if (page_directory[i][j] & PT_USED)
- n++;
- return n;
+ kfree_frames(page_dir, 1);
} \ No newline at end of file
diff --git a/src/kernel/memory/paging.h b/src/kernel/memory/paging.h
index 29d584c..ac0dbfa 100644
--- a/src/kernel/memory/paging.h
+++ b/src/kernel/memory/paging.h
@@ -3,56 +3,58 @@
#include <stdint.h>
-#define PAGE_ALIGN 4096
+#define PAGE_SIZE 0x1000
#define PAGE_COUNT 1024
-#define PAGE_SIZE PAGE_ALIGN *PAGE_COUNT
-
-#define PD_PRESENT 1 << 0
-#define PD_RW 1 << 1
-#define PD_USER 1 << 2
-#define PD_WRITETHR 1 << 3
-#define PD_CACHE_D 1 << 4
-#define PD_ACCESSED 1 << 5
-#define PD_4M_PAGE 1 << 7
-
-#define PT_PRESENT 1 << 0
-#define PT_RW 1 << 1
-#define PT_USER 1 << 2
-#define PT_WRITETHR 1 << 3
-#define PT_CACHE_D 1 << 4
-#define PT_ACCESSED 1 << 5
-#define PT_DIRTY 1 << 6
-#define PT_GLOBAL 1 << 8
-#define PT_USED 1 << 9
-
-u32 **page_directory __attribute__((aligned(PAGE_ALIGN)));
-u32 kernel_page_tables[PAGE_COUNT][PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN)));
+#define SHIFT(address) ((address) >> 12)
+#define UNSHIFT(address) ((address) << 12)
+
int paging_enabled;
+struct page_table_entry {
+ u32 present : 1;
+ u32 writable : 1;
+ u32 user : 1;
+ u32 write_through : 1;
+ u32 cache_disable : 1;
+ u32 accessed : 1;
+ u32 dirty : 1;
+ u32 attribute : 1;
+ u32 global : 1;
+ u32 available : 3;
+ u32 address : 20;
+} __attribute__((packed));
+
+struct page_table {
+ struct page_table_entry entries[PAGE_COUNT];
+};
+
+struct page_dir_entry {
+ u32 present : 1;
+ u32 writable : 1;
+ u32 user : 1;
+ u32 write_through : 1;
+ u32 cache_disable : 1;
+ u32 accessed : 1;
+ u32 reserved : 1;
+ u32 page_size : 1;
+ u32 global : 1;
+ u32 available : 3;
+ u32 address : 20;
+} __attribute__((packed));
+
+struct page_dir {
+ struct page_dir_entry entries[PAGE_COUNT];
+};
+
void paging_install();
void paging_enable();
void paging_disable();
+void paging_switch_directory(u32 dir);
-u32 **paging_make_directory();
-void paging_remove_directory(u32 **dir);
-void paging_switch_directory(u32 **dir);
-
-void paging_map(u32 phy, u32 virt, u16 flags);
-void paging_map_user(u32 phy, u32 virt);
-u32 paging_get_phys(u32 virt);
-u16 paging_get_flags(u32 virt);
-u32 paging_get_used_pages();
-
-void paging_set_flags(u32 virt, u32 count, u16 flags);
-void paging_set_flag_up(u32 virt, u32 count, u32 flag);
-void paging_set_flag_down(u32 virt, u32 count, u32 flag);
-void paging_set_present(u32 virt, u32 count);
-void paging_set_absent(u32 virt, u32 count);
-void paging_set_used(u32 virt, u32 count);
-void paging_set_free(u32 virt, u32 count);
-void paging_set_user(u32 virt, u32 count);
-
-u32 paging_find_pages(u32 count);
-u32 paging_alloc_pages(u32 count);
+struct page_table_entry *paging_get_page(u32 address, struct page_dir *page_dir);
+void paging_frame_alloc(struct page_table_entry *page);
+void paging_frame_free(struct page_table_entry *page);
+struct page_dir *paging_make_dir();
+void paging_free_dir();
#endif \ No newline at end of file