summaryrefslogtreecommitdiffstats
path: root/src/kernel/block.C
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;
    }
}
OpenPOWER on IntegriCloud