blob: 25157dac5a1346b16b08c355ca390ae8edfbec82 (
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
|
#include <limits.h>
#include <assert.h>
#include <kernel/block.H>
#include <kernel/spte.H>
#include <kernel/vmmmgr.H>
#include <kernel/ptmgr.H>
Block::~Block()
{
// Release shadow PTE array.
delete[] iv_ptes;
// Delete next block in the chain.
if (iv_nextBlock)
{
delete iv_nextBlock;
}
}
void Block::init()
{
// Create a shadow PTE for each page.
iv_ptes = new ShadowPTE[iv_size / PAGESIZE];
}
ShadowPTE* Block::getPTE(uint64_t i_addr) const
{
return &iv_ptes[(i_addr - iv_baseAddr) / PAGESIZE];
};
bool Block::handlePageFault(task_t* i_task, uint64_t i_addr)
{
// Check containment, call down chain if address isn't in this block.
if (!isContained(i_addr))
{
return (iv_nextBlock ?
false : iv_nextBlock->handlePageFault(i_task, i_addr));
}
ShadowPTE* pte = getPTE(i_addr);
if (!pte->isPresent())
{
// TODO. Needs swapping support.
return false;
}
if (pte->getPage() == 0)
{
return false;
}
// Add page table entry.
PageTableManager::addEntry(
(i_addr / PAGESIZE) * PAGESIZE,
pte->getPage(),
(pte->isExecutable() ? VmmManager::RO_EXE_ACCESS :
(pte->isWritable() ? VmmManager::NORMAL_ACCESS :
VmmManager::READ_O_ACCESS)));
return true;
}
void Block::setPhysicalPage(uint64_t i_vAddr, uint64_t i_pAddr,
VmmManager::ACCESS_TYPES i_access)
{
// Check containment, call down chain if address isn't in this block.
if (!isContained(i_vAddr))
{
if (iv_nextBlock)
{
iv_nextBlock->setPhysicalPage(i_vAddr, i_pAddr, i_access);
}
else
{
// No block owns this address. Code bug.
kassert(iv_nextBlock);
}
return;
}
// Create virtual to physical mapping.
ShadowPTE* pte = getPTE(i_vAddr);
pte->setPageAddr(i_pAddr);
pte->setPresent(true);
switch(i_access)
{
case VmmManager::READ_O_ACCESS:
pte->setExecutable(false);
pte->setWritable(false);
break;
case VmmManager::NORMAL_ACCESS:
pte->setExecutable(false);
pte->setWritable(true);
break;
case VmmManager::RO_EXE_ACCESS:
pte->setExecutable(true);
pte->setWritable(false);
break;
default:
kassert(false);
break;
}
}
|