The Pedigree Project  0.1
mips32/VirtualAddressSpace.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 "VirtualAddressSpace.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/panic.h"
23 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
24 #include "pedigree/kernel/processor/Processor.h"
25 #include "pedigree/kernel/processor/types.h"
26 #include "pedigree/kernel/utilities/utility.h"
27 
28 static bool g_Kseg2Initialised = false;
29 
32 
34 {
36 }
37 
39 {
40  // TODO
41  // return new X86VirtualAddressSpace();
42  return 0;
43 }
44 
46  : VirtualAddressSpace(reinterpret_cast<void *>(KERNEL_VIRTUAL_HEAP))
47 {
48  // TODO Locks around here? When it's getting initialised I'm pretty sure
49  // no other processors will be brought up, and threading won't be enabled.
50 
51  // If we haven't yet NULL'd KSEG2, do it now.
52  if (!g_Kseg2Initialised)
53  {
54  ByteSet(m_pKseg2Directory, 0, 512 * sizeof(uintptr_t));
55  g_Kseg2Initialised = true;
56  }
57  // NULL Kuseg.
58  ByteSet(m_pKusegDirectory, 0, 1024 * sizeof(uintptr_t));
59 }
60 
62 {
63  for (int i = 0; i < 1024; i++)
64  {
65  if (m_pKusegDirectory[i] != 0)
66  {
68  static_cast<physical_uintptr_t>(m_pKusegDirectory[i]));
69  }
70  }
71 }
72 
74 {
75  // In MIPS, all possible addresses are valid.
76  return true;
77 }
78 
79 bool MIPS32VirtualAddressSpace::isMapped(void *virtualAddress)
80 {
81  // What page is this virtual address in?
82  uintptr_t page = reinterpret_cast<uintptr_t>(virtualAddress) >> 12;
83 
84  // What page table chunk is that page's mapping located in?
85  // (pageIndex * 2) / 4096, because each page has 2 words of data associated
86  // with it.
87  uintptr_t chunkIdx = (page * 2) / 4096;
88  // At what offset in that chunk will we find information about the page
89  // mapping?
90  uintptr_t chunkOff = (page * 2) % 4096;
91 
92  // Get the chunk.
93  uintptr_t chunkAddr = getPageTableChunk(chunkIdx);
94 
95  // If it was NULL, there is no mapping.
96  if (chunkAddr == 0)
97  return false;
98 
99  // Is this in the first 512MB of RAM? if so, we can access it via KSEG0.
100  if (chunkAddr < 0x20000000)
101  {
102  uintptr_t mapping =
103  *reinterpret_cast<uintptr_t *>(KSEG0(chunkAddr) + chunkOff);
104  // Is it NULL?
105  if (mapping == 0)
106  return false;
107  // Is it valid?
108  if ((mapping & MIPS32_PTE_VALID) == 0)
109  return false;
110  // Otherwise, the mapping is valid.
111  return true;
112  }
113  else
114  {
115  // We need to temporarily map the page into KSEG2.
116  panic("Physical addressing over 512MB not implemented yet!");
117  }
118 }
119 
121  physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)
122 {
123  // Cast virtualAddress into a nicer type for arithmetic.
124  uintptr_t nVirtualAddress = reinterpret_cast<uintptr_t>(virtualAddress);
125 
126  // Firstly, do a sanity check to see if virtualAddress is within KSEG2 or
127  // KUSEG.
128  if (!IS_KUSEG(nVirtualAddress) && !IS_KSEG2(nVirtualAddress))
129  {
130  WARNING(
131  "MIPS32VirtualAddressSpace::map("
132  << Hex << physicalAddress << ", " << nVirtualAddress << ", "
133  << flags << "): invalid virtual address.");
134  return false;
135  }
136 
137  // Secondly, sanity check to ensure this address isn't where the page table
138  // should be...!
139  if ((nVirtualAddress >= 0xC0000000) && (nVirtualAddress < 0xC0800000))
140  {
141  WARNING(
142  "MIPS32VirtualAddressSpace::map("
143  << Hex << physicalAddress << ", " << nVirtualAddress << ", "
144  << flags << "): invalid virtual address.");
145  return false;
146  }
147 
148  // What page is this virtual address in?
149  uintptr_t page = nVirtualAddress >> 12;
150 
151  // What page table chunk is that page's mapping located in?
152  // Each chunk can hold 512 descriptors (4096/8).
153  uintptr_t chunkIdx = page / 512;
154  // At what offset in that chunk will we find information about the page
155  // mapping? Each chunk can hold 512 descriptors (4096/8), each being 8
156  // bytes.
157  uintptr_t chunkOff = (page % 512) * 8;
158 
159  // Get the chunk.
160  uintptr_t chunkAddr = getPageTableChunk(chunkIdx);
161 
162  // If it was NULL, there is no mapping.
163  if (chunkAddr == 0)
164  {
165  // ...So we have to make one!
166  chunkAddr = generateNullChunk();
167  setPageTableChunk(chunkIdx, chunkAddr);
168  }
169 
170  // Is this in the first 512MB of RAM? if so, we can access it via KSEG0.
171  if (chunkAddr < 0x20000000)
172  {
173  uintptr_t *mapping =
174  reinterpret_cast<uintptr_t *>(KSEG0(chunkAddr) + chunkOff);
175  // Is it non-NULL?
176  if (*mapping != 0)
177  {
178  // Address is already mapped.
179  WARNING(
180  "MIPS32VirtualAddressSpace::map("
181  << Hex << physicalAddress << ", " << nVirtualAddress << ", "
182  << flags << "): Address already mapped.");
183  return false;
184  }
185 
186  // Make our mapping.
187 
188  // 33 22222222221111111111
189  // 10 987654321098765432109876 543 2 1 0
190  // +--+------------------------+---+-+-+-+
191  // |00| PHYSICAL FRAME NUMBER | C |D|V|G|
192  // +--+------------------------+---+-+-+-+
193 
194  uintptr_t pfn = (static_cast<uintptr_t>(physicalAddress) >> 6) &
195  0x3FFFFFC0; // Shift right 6 because the 12 LSBs of an
196  // address are dumped.
197  uintptr_t c =
198  (flags & CacheDisable) ? MIPS32_PTE_UNCACHED : MIPS32_PTE_CACHED;
199  uintptr_t d = (flags & Write) ? MIPS32_PTE_DIRTY : 0;
200  uintptr_t v = MIPS32_PTE_VALID;
201  uintptr_t g = 0;
202  // Write the EntryLo mapping.
204  *mapping = pfn | c | d | v | g;
205 
206  // The next 32 bits are ours to mess around with, we store the processor
207  // independent flag set there.
208  *++mapping = flags;
209 
210  // We are success.
211  return true;
212  }
213  else
214  {
215  // We need to temporarily map the page into KSEG2.
216  panic("Physical addressing over 512MB not implemented yet!");
217  }
218 }
219 
221  void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)
222 {
223  // What page is this virtual address in?
224  uintptr_t page = reinterpret_cast<uintptr_t>(virtualAddress) >> 12;
225 
226  // What page table chunk is that page's mapping located in?
227  // (pageIndex * 2) / 4096, because each page has 2 words of data associated
228  // with it.
229  uintptr_t chunkIdx = (page * 2) / 4096;
230  // At what offset in that chunk will we find information about the page
231  // mapping?
232  uintptr_t chunkOff = (page * 2) % 4096;
233 
234  // Get the chunk.
235  uintptr_t chunkAddr = getPageTableChunk(chunkIdx);
236 
237  // If it was NULL, there is no mapping.
238  if (chunkAddr == 0)
239  {
240  physicalAddress = 0;
241  return;
242  }
243 
244  // Is this in the first 512MB of RAM? if so, we can access it via KSEG0.
245  if (chunkAddr < 0x20000000)
246  {
247  uintptr_t mapping =
248  *reinterpret_cast<uintptr_t *>(KSEG0(chunkAddr) + chunkOff);
249  uintptr_t _flags =
250  *reinterpret_cast<uintptr_t *>(KSEG0(chunkAddr) + chunkOff + 4);
251  // Is it NULL?
252  if (mapping == 0)
253  {
254  physicalAddress = 0;
255  return;
256  }
257  // Is it valid?
258  if ((mapping & MIPS32_PTE_VALID) == 0)
259  {
260  physicalAddress = 0;
261  return;
262  }
263  // Otherwise, the mapping is valid.
264  physicalAddress = (mapping << 6) & 0xFFFFF000;
265  flags = _flags;
266  return;
267  }
268  else
269  {
270  // We need to temporarily map the page into KSEG2.
271  panic("Physical addressing over 512MB not implemented yet!");
272  }
273 }
274 
275 void MIPS32VirtualAddressSpace::setFlags(void *virtualAddress, size_t newFlags)
276 {
277 }
278 
279 void MIPS32VirtualAddressSpace::unmap(void *virtualAddress)
280 {
281 }
282 
283 uintptr_t MIPS32VirtualAddressSpace::getPageTableChunk(uintptr_t chunkIdx)
284 {
285  if (chunkIdx < 1024)
286  {
287  return m_pKusegDirectory[chunkIdx];
288  }
289  else if (chunkIdx >= 1536) // 1536 = 1024+512.
290  {
291  return m_pKseg2Directory[chunkIdx - 1536];
292  }
293  else
294  {
295  ERROR("Invalid page table chunk index: " << Dec << chunkIdx);
296  return 0;
297  }
298 }
299 
301 {
302  // TODO
303  return 0;
304 }
305 void MIPS32VirtualAddressSpace::freeStack(void *pStack)
306 {
307  // TODO
308 }
309 
310 void MIPS32VirtualAddressSpace::setPageTableChunk(
311  uintptr_t chunkIdx, uintptr_t chunkAddr)
312 {
313  NOTICE("setPageTableChunk(" << Hex << chunkIdx << ", " << chunkAddr << ")");
314  if (chunkIdx < 1024)
315  {
316  m_pKusegDirectory[chunkIdx] = chunkAddr;
317  }
318  else if (chunkIdx >= 1536) // 1536 = 1024+512.
319  {
320  m_pKseg2Directory[chunkIdx - 1536] = chunkAddr;
321  }
322  else
323  {
324  ERROR("Invalid page table chunk index: " << Dec << chunkIdx);
325  }
326 }
327 
329 {
330  physical_uintptr_t frame = PhysicalMemoryManager::instance().allocatePage();
331 
332  // If the page is under 512MB, we can access it through KSEG0.
333  if (frame < 0x20000000)
334  {
335  ByteSet(reinterpret_cast<void *>(KSEG0(frame)), 0, PAGE_SIZE);
336  return static_cast<uintptr_t>(frame);
337  }
338  else
339  {
340  // We need to temporarily map the page into KSEG2.
341  panic("Physical addressing over 512MB not implemented yet!");
342  }
343 }
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)
static PhysicalMemoryManager & instance()
virtual void getMapping(void *virtualAddress, physical_uintptr_t &physicalAddress, size_t &flags)
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
virtual void setFlags(void *virtualAddress, size_t newFlags)
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual bool isAddressValid(void *virtualAddress)
#define WARNING(text)
Definition: Log.h:78
static VirtualAddressSpace * create()
uintptr_t physicalAddress(physical_uintptr_t address) PURE
Definition: utils.h:38
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
virtual bool isMapped(void *virtualAddress)
#define ERROR(text)
Definition: Log.h:82
virtual void unmap(void *virtualAddress)
virtual void freePage(physical_uintptr_t page)=0
Definition: Log.h:138
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
uintptr_t getPageTableChunk(uintptr_t chunkIdx)