/
vmm.cpp
143 lines (118 loc) · 4.16 KB
/
vmm.cpp
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
extern "C" {
#include "common.h"
#include "monitor.h"
#include "idt.h"
}
#include "vmm.h"
#include "pmm.h"
uint32_t *VirtualMemoryManager::m_directory = (uint32_t*)PAGE_DIR_VIRTUAL_ADDR;
uint32_t *VirtualMemoryManager::m_tables = (uint32_t*)PAGE_TABLE_VIRTUAL_ADDR;
void VirtualMemoryManager::initialize()
{
idt_register_interrupt_handler(14, &pagefaultHandler);
// allocate a page directory
page_directory_t *pd = (page_directory_t*)PhysMemManager::allocatePage();
// zero it out
memset(pd, 0, PAGE_SIZE);
pd[0] = PhysMemManager::allocatePage() | PAGE_PRESENT | PAGE_WRITE;
uint32_t *pt = (uint32_t*)(pd[0] & PAGE_MASK);
for (int i=0; i<1024; i++) {
pt[i] = i*PAGE_SIZE | PAGE_PRESENT | PAGE_WRITE;
}
// assign second last table and zero out
pd[1022] = PhysMemManager::allocatePage() | PAGE_PRESENT | PAGE_WRITE;
pt = (uint32_t*)(pd[1022] & PAGE_MASK);
memset(pt, 0, PAGE_SIZE);
// http://wiki.osdev.org/Paging#Manipulation
//
// The last entry of the second-last table is the directory itself.
pt[1023] = (uint32_t)pd | PAGE_PRESENT | PAGE_WRITE;
// ..and the last table loops back on the directory
pd[1023] = (uint32_t)pd | PAGE_PRESENT | PAGE_WRITE;
switchDirectory(pd);
// turn on paging
uint32_t cr0;
__asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000;
__asm volatile("mov %0, %%cr0" : : "r"(cr0));
uint32_t pt_idx = PAGE_DIR_IDX((PMM_STACK_OFFSET>>12));
m_directory[pt_idx] = PhysMemManager::allocatePage() | PAGE_PRESENT | PAGE_WRITE;
memset((uint32_t*)m_tables[pt_idx*1024], 0, PAGE_SIZE);
PhysMemManager::pagingActive = true;
}
void VirtualMemoryManager::switchDirectory(page_directory_t *pd)
{
__asm volatile("mov %0, %%cr3" : : "r"(pd));
}
void VirtualMemoryManager::map(uint32_t va, uint32_t pa, uint32_t flags)
{
uint32_t virtual_page = va / PAGE_SIZE;
uint32_t pt_idx = PAGE_DIR_IDX(virtual_page);
if (m_directory[pt_idx] == 0) {
// create page
m_directory[pt_idx] = PhysMemManager::allocatePage() | PAGE_PRESENT | PAGE_WRITE;
memset((uint32_t*)m_tables[pt_idx*1024], 0, PAGE_SIZE);
}
m_tables[virtual_page] = (pa & PAGE_MASK) | flags;
}
void VirtualMemoryManager::unmap(uint32_t va)
{
uint32_t virtual_page = va / PAGE_SIZE;
m_tables[virtual_page] = 0;
// tell the CPU that we invalidated it, clears the entry in the TLB
__asm volatile("invlpg (%0)" : : "a"(va));
}
char VirtualMemoryManager::getMapping(uint32_t va, uint32_t *pa)
{
uint32_t virtual_page = va/PAGE_SIZE;
uint32_t pt_idx = PAGE_DIR_IDX(virtual_page);
if (m_directory[pt_idx] == 0) {
return 0;//return false
}
if (m_tables[virtual_page] != 0) {
if (pa)
*pa = m_tables[virtual_page] & PAGE_MASK;
return 1;
}
return 0;
}
void VirtualMemoryManager::pagefaultHandler(registers_t *regs)
{
uint32_t cr2;
__asm volatile("mov %%cr2, %0" : "=r"(cr2));
monitor_write("Page fault at ");
monitor_write_hex(regs->eip);
monitor_write(", faulting address ");
monitor_write_hex(cr2);
monitor_put('\n');
monitor_write("Error: ");
switch(regs->err_code) {
case 0:
monitor_write("Supervisory process tried to read a non-present page entry\n");
break;
case 1:
monitor_write("Supervisory process tried to read a page and caused a protection fault\n");
break;
case 2:
monitor_write("Supervisory process tried to write to a non-present page entry\n");
break;
case 3:
monitor_write("Supervisory process tried to write a page and caused a protection fault\n");
break;
case 4:
monitor_write("User process tried to read a non-present page entry\n");
break;
case 5:
monitor_write("User process tried to read a page and caused a protection fault\n");
break;
case 6:
monitor_write("User process tried to write to a non-present page entry\n");
break;
case 7:
monitor_write("User process tried to write a page and caused a protection fault\n");
break;
default:
monitor_write("Unknown error\n");
}
panic("");
}