blob: 04a353c754a3ec7d352ec3dc0b9dfaa8ee14483c (
plain)
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
118
119
120
121
122
123
124
125
126
127
|
#include <mm/paging.h>
#include <mm/kernel_heap.h>
#include <toxic/errno.h>
#include <toxic/config.h>
#include <toxic/vga.h>
void paging_load_directory(uint32_t *directory);
static struct page_directory *current_directory;
struct page_directory*
paging_new_directory(uint8_t flags)
{
int i, j;
int offset = 0;
/* Allocate the global directory */
struct page_directory *new_directory = kzalloc(sizeof(struct page_directory));
uint32_t *directory = kzalloc(sizeof(uint32_t) * PAGING_ENTRIES_PER_TABLE);
/* Allocate a new page table for each page directory entry */
for (i = 0; i < PAGING_ENTRIES_PER_TABLE; i++) {
uint32_t *page_table = kzalloc(sizeof(uint32_t) * PAGING_ENTRIES_PER_TABLE);
/*
* Each PTE is initialized now with the linear physical address.
* I don't think this is a good idea, but I'll change it later.
*
* In theory we should not allocate memory for PTEs not used, so
* this is in general a waste of space. A page table should be allocated only
* when we actually need to allocate space there.
*
* Also, PTEs should point to NULL instead of defaulting to a
* physical address.
*/
for (j = 0; j < PAGING_ENTRIES_PER_TABLE; j++)
page_table[j] = (offset + (j * PAGE_SIZE)) | flags;
offset += (PAGING_ENTRIES_PER_TABLE * PAGE_SIZE);
/*
* Set the whole directory as WRITABLE so we don't
* prevent any page to be writable
*/
directory[i] = (uint32_t)page_table | flags | PAGING_IS_WRITABLE;
}
new_directory->directory = directory;
return new_directory;
}
bool
paging_is_aligned(void *addr)
{
return ((uint32_t)addr % PAGE_SIZE) == 0;
}
uint32_t *
paging_get_directory(struct page_directory *pd)
{
return pd->directory;
}
void
paging_switch(struct page_directory *directory)
{
paging_load_directory(paging_get_directory(directory));
current_directory = directory;
}
int
paging_get_indexes(
void *vaddr,
uint32_t *dir_idx,
uint32_t *table_idx)
{
int ret = 0;
if (!paging_is_aligned(vaddr)) {
ret = -EINVAL;
goto out;
}
*dir_idx = (uint32_t)vaddr >> PAGING_DIRECTORY_BITS;
*table_idx = ((uint32_t)vaddr >> PAGING_TABLE_BITS) & PAGING_TABLE_MASK;
out:
return ret;
}
/*
* Configure a PTE to map virtual address vaddr to physical address paddr
* setting the entry bits to flags
*/
int
paging_map_vaddr(
struct page_directory *page_dir,
void *vaddr,
void *paddr,
uint32_t flags)
{
uint32_t *directory;
uint32_t *page_table;
uint32_t dir_idx = 0;
uint32_t table_idx;
uint32_t dir_entry;
uint32_t pte = (uint32_t)paddr;
int ret = 0;
if (!paging_is_aligned(vaddr) || !paging_is_aligned(paddr)) {
return -EINVAL;
}
ret = paging_get_indexes(vaddr, &dir_idx, &table_idx);
if (ret < 0)
return ret;
directory = paging_get_directory(page_dir);
dir_entry = (uint32_t)directory[dir_idx];
page_table = (uint32_t *)(dir_entry & (~PAGING_PAGE_OFFSET_MASK));
page_table[table_idx] = pte | flags;
return ret;
}
|