forked from makeopensource/mOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpaging.c
More file actions
156 lines (118 loc) · 4.44 KB
/
paging.c
File metadata and controls
156 lines (118 loc) · 4.44 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "paging.h"
#include "stdlib/string.h"
// room for 3 page tables (12 MiB of mapped memory)
#define IDENTITY_PT_BASE 0x92000
#define IDENTITY_PT_LIMIT 0x95000
#define TABLE_COUNT ((IDENTITY_PT_LIMIT - IDENTITY_PT_BASE) / 0x1000)
#define MiB4 0x400000
PageDirectory *idendirectory = (PageDirectory *)(ID_PAGE_DIRECTORY_BASE);
bool pageTablePresent(PageDirectoryEntry tableEntry) {
return tableEntry & ENTRY_PRESENT;
}
bool pageEntryPresent(PageTableEntry entry) {
// mask out all but first bit
return entry & ENTRY_PRESENT;
}
void setEntryAddr(PageTableEntry *entry, const void *addr) {
if (entry == NULL)
return;
*entry = ((uint32_t)(addr)&ENTRY_ADDR) | (*entry & ~(ENTRY_ADDR));
}
void setActivePageDir(PageDirectory *dir) {
if (dir == NULL)
dir = idendirectory;
__asm__ volatile("mov %0, %%cr3" : : "a"(dir));
}
PageDirectory *getActivePageDir(void) {
PageDirectory *dir = NULL;
__asm__ volatile("mov %%cr3, %0" : "=r"(dir));
return dir;
}
void resetTLB(void) {
// setting the active directory to the current updates the TLB
setActivePageDir(getActivePageDir());
}
#define PAGE_TABLE_OFFSET 22
#define PAGE_ENTRY_OFFSET 12
// highest 10 bits
uint16_t vaddrDirectoryIdx(const void *vaddr) {
return (uint32_t)(vaddr) >> PAGE_TABLE_OFFSET;
}
// middle 10 bits
uint16_t vaddrEntryIdx(const void *vaddr) {
// shifted right 12 then 10-bit mask
return ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0x3ff;
}
// low 12 bits
uint16_t vaddrOffset(const void *vaddr) {
// 12-bit mask
return (uint32_t)(vaddr)&0xfff;
}
void *toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) {
uint32_t vaddr = offset;
vaddr |= (uint32_t)(entryIdx) << PAGE_ENTRY_OFFSET;
vaddr |= (uint32_t)(dirIdx) << PAGE_TABLE_OFFSET;
return (void *)(vaddr);
}
PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, const void *vaddr) {
if (directory == NULL)
directory = getActivePageDir();
uint16_t tableidx = vaddrDirectoryIdx(vaddr);
return &directory->entries[tableidx];
}
PageTableEntry *vaddrTableEntry(PageDirectory *directory, const void *vaddr) {
// this will never be null (unless something really bad happened)
PageDirectoryEntry *dirEntry = vaddrDirEntry(directory, vaddr);
PageTable *table = (PageTable *)((*dirEntry) & ENTRY_ADDR);
if (table == NULL)
return NULL;
uint16_t entryidx = vaddrEntryIdx(vaddr);
return &table->entries[entryidx];
}
void *vaddrToPaddr(PageDirectory *dir, const void *vaddr) {
if (dir == NULL)
dir = getActivePageDir();
// get and verify page entry
PageTableEntry *entry = vaddrTableEntry(dir, vaddr);
if (entry == NULL)
return NULL;
uint32_t paddr = vaddrOffset(vaddr);
// apply offset
return (void *)(paddr + ((*entry) & ENTRY_ADDR));
}
// identity maps the entire table at directory entry idx
void identityMapTable(PageDirectory *directory, uint16_t idx, uint32_t flags) {
PageTable *table = (PageTable *)(directory->entries[idx] & ENTRY_ADDR);
// 4GiB per directory
// 4MiB per table
uint32_t baseAddr = idx * MiB4;
for (uint32_t page_idx = 0; page_idx < PAGE_ENTRY_COUNT; ++page_idx) {
PageTableEntry entry = flags & ~(ENTRY_ADDR);
// 4KiB per entry
entry |= (baseAddr + page_idx * PAGE_SIZE) & ENTRY_ADDR;
table->entries[page_idx] = entry;
}
}
// preconditions, idx < PAGE_ENTRY_COUNT, table is 4KiB aligned
void addTableToDirectory(PageDirectory *directory, uint16_t idx,
PageTable *table, uint32_t flags) {
PageDirectoryEntry entry = flags & ~(ENTRY_ADDR);
entry |= (uint32_t)(table)&ENTRY_ADDR;
directory->entries[idx] = entry;
}
void initPaging(void) {
// clear the memory (essentially say no page tables exist)
memset(idendirectory, 0, PAGE_ENTRY_COUNT * sizeof(PageDirectoryEntry));
// identity map 12MiB and setup directory
for (uint16_t idx = 0; idx < TABLE_COUNT; ++idx) {
PageTable *addr = (PageTable *)((idx * PAGE_SIZE) + IDENTITY_PT_BASE);
memset(addr, 0, PAGE_ENTRY_COUNT * sizeof(PageTableEntry));
addTableToDirectory(idendirectory, idx, addr, DEFAULT_ENTRY_FLAGS);
identityMapTable(idendirectory, idx, DEFAULT_ENTRY_FLAGS);
}
setActivePageDir(idendirectory);
// enable paging flags in cr0
__asm__ volatile("mov %cr0, %eax \n\t"
"or $0x80000001, %eax\n\t"
"mov %eax, %cr0");
}