The Pedigree Project  0.1
TlbManager.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "pedigree/kernel/processor/mips32/TlbManager.h"
21 #include "../mips_common/AsidManager.h"
22 #include "VirtualAddressSpace.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/debugger/Debugger.h"
25 #include "pedigree/kernel/panic.h"
26 #include "pedigree/kernel/processor/InterruptManager.h"
27 #include "pedigree/kernel/processor/Processor.h"
28 
30 
32 {
33  return m_Instance;
34 }
35 
37 {
38 }
39 
41 {
42 }
43 
45 {
46  // Firstly get the size of the TLB. This function trashes all the TLB
47  // entries so is done first.
49 
50  // Now flush the entire TLB. This writes values in KSEG1 into all of them,
51  // so that there is no possible way any could trigger.
53 
54  // Write the address of our page table into the Context register.
55  writeContext(VIRTUAL_PAGE_DIRECTORY);
56 
57  // We need 1 fixed TLB entry for the VirtualAddressSpace.
58  writeWired(1);
59 
60  // We use 4K pages always.
61  writePageMask(0);
62 
63  // We handle the "TLB Exception (load/instruction fetch)" (2)
64  // and "TLB Exception (store)" (3)
65  // exceptions.
68 }
69 
70 void MIPS32TlbManager::interrupt(size_t interruptNumber, InterruptState &state)
71 {
72  // The BadVAddr register will have the address that we couldn't access.
73  // To make that into a 'chunk' index, we need to shift right by 12 bits
74  // (to remove the page offset) and mask to only the bottom 11 bits
75  // (2048 == 0x800).
76  uintptr_t badvaddr = state.m_BadVAddr;
77  uintptr_t chunkIdx = (badvaddr >> 12) & 0x7FF;
78 
79  // Sanity check - was this TLB miss for the page table? or for elsewhere?
80  if ((badvaddr < 0xC0000000) || (badvaddr >= 0xC0800000))
81  {
82  // Page fault.
83  static LargeStaticString str;
84  str.clear();
85  str += "Page fault (";
86  str.append(badvaddr, 16);
87  str += ")";
88  Debugger::instance().start(state, str);
89  panic("Page fault");
90  }
91 
92  // As the R4000 maps one virtual page to two consecutive physical frames,
93  // we need to ensure that the first chunk we ask for is aligned properly.
94  uintptr_t chunkSelect = chunkIdx & 0x1; // Which chunk were we accessing?
95  chunkIdx &= ~0x1;
96 
97  // TODO: get the current virtual address space!
98  MIPS32VirtualAddressSpace &addressSpace =
99  static_cast<MIPS32VirtualAddressSpace &>(
101  uintptr_t phys1 = addressSpace.getPageTableChunk(chunkIdx);
102  uintptr_t phys2 = addressSpace.getPageTableChunk(chunkIdx + 1);
103 
104  NOTICE(
105  "BadVaddr: " << Hex << badvaddr << ", chunkIdx: " << chunkIdx
106  << ", phys1: " << phys1 << ", phys2: " << phys2);
107 
108  if ((phys1 == 0 && chunkSelect == 0) || (phys2 == 0 && chunkSelect == 1))
109  {
110  // Page fault.
111  static LargeStaticString str;
112  str.clear();
113  str += "Page fault";
114  Debugger::instance().start(state, str);
115  panic("Page fault");
116  }
117 
118  // Current EntryHi
119  uintptr_t curEntryHi;
120  CP0_READ_ENTRYHI(curEntryHi);
121 
122  NOTICE("CurEntryHi: " << Hex << curEntryHi);
123 
124  // Get the current ASID.
125  AsidManager::Asid asid = 0; // TODO
126 
127  // Generate an EntryHi value.
128  uintptr_t entryHi = (badvaddr & ~0x1FFF) | (curEntryHi & 0xFF);
129 
130  // Generate an EntryLo0 value.
131  uintptr_t entryLo0 = phys1;
132  if (entryLo0 != 0)
133  {
134  entryLo0 >>= 6;
135  entryLo0 |= MIPS32_PTE_VALID | MIPS32_PTE_CACHED | MIPS32_PTE_DIRTY;
136  }
137 
138  // Generate an EntryLo1 value.
139  uintptr_t entryLo1 = phys2;
140  if (entryLo1 != 0)
141  {
142  entryLo1 >>= 6;
143  entryLo1 |= MIPS32_PTE_VALID | MIPS32_PTE_CACHED | MIPS32_PTE_DIRTY;
144  }
145 
146  // Write into the TLB.
147  writeTlb(entryHi, entryLo0, entryLo1);
148 
149  // Now that the chunk is in the TLB, we can read the bad virtual address
150  // and check if it is NULL. If so, this is a page fault.
151  // uintptr_t *pBadvaddr = reinterpret_cast<uintptr_t*> (badvaddr);
152  // if (*pBadvaddr == 0)
153  // {
154  // // Page fault.
155  // static LargeStaticString str;
156  // str.clear();
157  // str += "Page fault";
158  // Debugger::instance().start(state, str);
159  // panic("Page fault");
160  // }
161 
162  // Success.
163 }
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
static void writeWired(uintptr_t wired)
void interrupt(size_t interruptNumber, InterruptState &state)
Definition: TlbManager.cc:70
static Debugger & instance()
Definition: Debugger.h:48
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static MIPS32TlbManager m_Instance
static void writePageMask(uintptr_t pageMask)
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
#define NOTICE(text)
Definition: Log.h:74
static void flush(uintptr_t numEntries)
Definition: Log.h:136
static void writeTlb(uintptr_t entryHi, uintptr_t entryLo0, uintptr_t entryLo1)
static uintptr_t getNumEntries()
uint8_t Asid
Definition: AsidManager.h:48
static void writeContext(uintptr_t context)
static MIPS32TlbManager & instance()
Definition: TlbManager.cc:31
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
static InterruptManager & instance()
uintptr_t getPageTableChunk(uintptr_t chunkIdx)