aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/memory/paging.c
blob: e2c48b8cd8b76abff6c417e835d6b9dcd88e052d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#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>

struct page_dir *kernel_page_directory;

void paging_install()
{
	memory_init();

	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++) {
		page_table->entries[i].present = 1;
		page_table->entries[i].writable = 1;
		page_table->entries[i].address = SHIFT(i * PAGE_SIZE);
	}

	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);

	paging_switch_dir((u32)kernel_page_directory);
	paging_enable();
	info("Installed paging");

	// Test mallocing
	u32 *c = malloc(2048);
	c[42] = 0x4242;
	assert(c[42] == 0x4242);
	free(c);
	info("Malloc test succeeded!");
}

void paging_disable()
{
	u32 cr0 = cr0_get();
	cr0 &= 0x7fffffff;
	cr0_set(cr0);
	paging_enabled = 0;
}

void paging_enable()
{
	u32 cr0 = cr0_get();
	cr0 |= 0x80000000;
	cr0_set(cr0);
	paging_enabled = 1;
}

void paging_switch_dir(u32 dir)
{
	cr3_set(dir);
}

struct page_table_entry *paging_get_page(u32 address, struct page_dir *page_dir)
{
	struct page_table *page_table;

	address /= PAGE_SIZE;
	u32 n = address / PAGE_COUNT;

	if (page_dir->entries[n].present == 0) {
		page_table = kmalloc_frames(1);
		memset(page_table, 0, sizeof(struct page_table));

		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);
	}

	return &page_table->entries[address % PAGE_COUNT];
}

void paging_frame_alloc(struct page_table_entry *page)
{
	void *ptr = kmalloc_frames(1);

	if (page->address != 0) {
		warn("Page is already allocated");
		return;
	}
	page->address = SHIFT((u32)ptr);
	page->present = 1;
	page->user = 1;
}

void paging_frame_free(struct page_table_entry *page)
{
	kfree_frames((void *)UNSHIFT(page->address), 1);
	memset((void *)page, 0, sizeof(struct page_table_entry));
}

struct page_dir *paging_make_dir()
{
	struct page_dir *ret = kmalloc_frames(1);

	memcpy(ret, kernel_page_directory, sizeof(struct page_dir));

	return ret;
}

void paging_free_dir(struct page_dir *page_dir)
{
	kfree_frames(page_dir, 1);
}