The Pedigree Project  0.1
HashedPageTable.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 "HashedPageTable.h"
21 #include "InterruptManager.h"
22 #include "VirtualAddressSpace.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/machine/openfirmware/Device.h"
25 #include "pedigree/kernel/machine/openfirmware/OpenFirmware.h"
26 #include "pedigree/kernel/panic.h"
27 #include "pedigree/kernel/processor/Processor.h"
28 
29 extern "C" void sdr1_trampoline(uint32_t);
30 
32 struct HTABSize
33 {
34  uint32_t
36  uint32_t size;
37  uint32_t mask;
38 };
39 
40 const int g_nHtabSizes = 10;
41 const HTABSize g_pHtabSizes[10] = {
42  {0x800000, 0x10000, 0x000}, {0x1000000, 0x20000, 0x001},
43  {0x2000000, 0x40000, 0x003}, {0x4000000, 0x80000, 0x007},
44  {0x8000000, 0x100000, 0x00F}, {0x10000000, 0x200000, 0x01F},
45  {0x20000000, 0x400000, 0x03F}, {0x40000000, 0x800000, 0x07F},
46  {0x80000000, 0x1000000, 0x0FF}, {0xFFFFFFFF, 0x2000000, 0x1FF}};
47 
49 
51 {
52  return m_Instance;
53 }
54 
55 HashedPageTable::HashedPageTable() : m_pHtab(0), m_Size(0), m_Mask(0)
56 {
57 }
58 
59 HashedPageTable::~HashedPageTable()
60 {
61 }
62 
63 void HashedPageTable::initialise(Translations &translations, uint32_t ramMax)
64 {
65  // How big should our page table be?
66  int selectedIndex = 0;
67  for (int i = 0; i < g_nHtabSizes; i++)
68  {
69  if (g_pHtabSizes[i].memorySize > ramMax)
70  {
71  selectedIndex = i - 1;
72  break;
73  }
74  }
75  if (selectedIndex == -1)
76  selectedIndex = 0;
77 
78  // Find some physical space to put our page table.
79  m_Size = g_pHtabSizes[selectedIndex].size;
80  uint32_t htabPhys = translations.findFreePhysicalMemory(m_Size, m_Size);
81  if (htabPhys == 0)
82  panic("Couldn't find anywhere to load the HTAB!");
83 
84  // Write this translation back to the Translations struct.
85  translations.addTranslation(HTAB_VIRTUAL, htabPhys, m_Size, 0x10 /* M=1 */);
86 
87  // Make a mapping for our page table.
88  OFDevice chosen(OpenFirmware::instance().findDevice("/chosen"));
89  OFDevice mmu(chosen.getProperty("mmu"));
90 
91  mmu.executeMethod(
92  "map", 4,
93  reinterpret_cast<OFParam>(0x2), // M=1
94  reinterpret_cast<OFParam>(g_pHtabSizes[selectedIndex].size),
95  reinterpret_cast<OFParam>(HTAB_VIRTUAL),
96  reinterpret_cast<OFParam>(htabPhys));
97 
98  // There is a minimum mask of 10 bits - the .mask parameter details how many
99  // *more* bits are masked.
100  m_Mask = (g_pHtabSizes[selectedIndex].mask << 10) | 0x0000003FF;
101  m_pHtab = reinterpret_cast<PTEG *>(HTAB_VIRTUAL);
102 
103  // Initialise by setting everything to zero.
104  ByteSet(reinterpret_cast<uint8_t *>(m_pHtab), 0, m_Size);
105 
106  // For each translation, add mappings.
107  for (unsigned int i = 0; i < translations.getNumTranslations(); i++)
108  {
109  Translations::Translation translation = translations.getTranslation(i);
110  for (unsigned int j = 0; j < translation.size; j += 0x1000)
111  {
112  // The VSID is for kernel space, which starts at 0 and extends to
113  // 15. We use the top 4 bits as an index. Convert 'mode' into a
114  // VirtualAddressSpace:: form.
115  uint32_t mode = translation.mode;
116  uint32_t newMode = VirtualAddressSpace::Write;
117  if (mode & 0x40)
119  if (mode & 0x20)
121  if (mode & 0x10)
123  if (mode & 0x08)
124  newMode |= VirtualAddressSpace::Guarded;
125 
126  // Special case for 0xDF000000 - that is our trampoline and needs to
127  // keep the current VSID - See below.
128  uint32_t vsid = 0 + (translation.virt >> 28);
129  if (translation.virt == 0xdf000000)
130  {
131  asm volatile("mfsr %0, 13" : "=r"(vsid));
132  vsid &= 0x0FFFFFFFF;
133  }
134  addMapping(
135  translation.virt + j, translation.phys + j, newMode, vsid);
136  }
137  }
138 
139  // Set up the segment registers for the kernel address space.
140 
141  // Install the HTAB.
143  uint32_t sdr1 = htabPhys | g_pHtabSizes[selectedIndex].mask;
145 
146  // When we change page table, we will be running in invalid segments (there
147  // is no way to guarantee that the VSIDs openfirmware has set up are the
148  // same as ours). So, we have a trampoline which is linked at an address in
149  // a different segment to all the kernel code (0xDF000000). We call that,
150  // which changes all segment registers except SR 0xD (so it doesn't affect
151  // its own code), then changes page tables. It jumps back here, and we're
152  // running in the new segment and in the new page table. We still need to
153  // change segment register 0xD to be 0x0000000d, however.
154  sdr1_trampoline(sdr1);
155  asm volatile("mtsr 13, %0" : : "r"(13));
156  asm volatile("mtspr 528, %0" : : "r"(0));
157  asm volatile("mtspr 530, %0" : : "r"(0));
158  asm volatile("mtspr 532, %0" : : "r"(0));
159  asm volatile("mtspr 534, %0" : : "r"(0));
160  asm volatile("mtspr 536, %0" : : "r"(0));
161  asm volatile("mtspr 538, %0" : : "r"(0));
162  asm volatile("mtspr 540, %0" : : "r"(0));
163  asm volatile("mtspr 542, %0" : : "r"(0));
164  asm volatile("sync");
165  asm volatile("isync");
166 }
167 
169  uint32_t effectiveAddress, uint32_t physicalAddress, uint32_t mode,
170  uint32_t vsid)
171 {
172  uint32_t input1 = vsid & 0x7FFFF; // Mask only the bottom 19 bits.
173  uint32_t input2 = (effectiveAddress >> 12) & 0xffff;
174  uint32_t primaryHash = input1 ^ input2;
175  uint32_t secondaryHash = ~primaryHash;
176 
177  primaryHash &= m_Mask;
178  secondaryHash &= m_Mask;
179 
180  int wimg = 0;
182  wimg |= 0x8;
184  wimg |= 0x4;
186  wimg |= 0x2;
187  if (mode & VirtualAddressSpace::Guarded)
188  wimg |= 0x1;
189 
190  // Assuming Ks = 0 and Kp = 1
191  int pp = 0;
193  pp = 0;
194  else if (!(mode & VirtualAddressSpace::Write))
195  pp = 1;
196  else if (mode & VirtualAddressSpace::CopyOnWrite)
197  pp = 3;
198  else
199  pp = 2;
200  pp = 0;
201  for (int i = 0; i < 8; i++)
202  {
203  if (m_pHtab[primaryHash].entries[i].v == 0)
204  {
205  // Set the PTE up.
206  m_pHtab[primaryHash].entries[i].vsid = vsid;
207  m_pHtab[primaryHash].entries[i].h = 0; // Primary hash
208  m_pHtab[primaryHash].entries[i].api =
209  (effectiveAddress >> 22) & 0x3F;
210  m_pHtab[primaryHash].entries[i].rpn = physicalAddress >> 12;
211  m_pHtab[primaryHash].entries[i].w =
212  (mode & VirtualAddressSpace::WriteThrough) ? 1 : 0;
213  m_pHtab[primaryHash].entries[i].i =
214  (mode & VirtualAddressSpace::CacheDisable) ? 1 : 0;
215  m_pHtab[primaryHash].entries[i].m =
216  (mode & VirtualAddressSpace::MemoryCoherent) ? 1 : 0;
217  m_pHtab[primaryHash].entries[i].g =
218  (mode & VirtualAddressSpace::Guarded) ? 1 : 0;
219  m_pHtab[primaryHash].entries[i].pp = pp;
220  m_pHtab[primaryHash].entries[i].v = 1; // Valid.
221  asm volatile("sync");
222  return;
223  }
224  }
225 
226  for (int i = 0; i < 8; i++)
227  {
228  if (m_pHtab[secondaryHash].entries[i].v == 0)
229  {
230  // Set the PTE up.
231  m_pHtab[secondaryHash].entries[i].vsid = vsid;
232  m_pHtab[secondaryHash].entries[i].h = 1; // Secondary hash.
233  m_pHtab[secondaryHash].entries[i].api =
234  (effectiveAddress & 0x0FFFFFFF) >> 22;
235  m_pHtab[secondaryHash].entries[i].rpn = physicalAddress >> 12;
236  m_pHtab[secondaryHash].entries[i].w =
237  (mode & VirtualAddressSpace::WriteThrough) ? 1 : 0;
238  m_pHtab[secondaryHash].entries[i].i =
239  (mode & VirtualAddressSpace::CacheDisable) ? 1 : 0;
240  m_pHtab[secondaryHash].entries[i].m =
241  (mode & VirtualAddressSpace::MemoryCoherent) ? 1 : 0;
242  m_pHtab[secondaryHash].entries[i].g =
243  (mode & VirtualAddressSpace::Guarded) ? 1 : 0;
244  m_pHtab[secondaryHash].entries[i].pp = pp;
245  m_pHtab[secondaryHash].entries[i].v = 1; // Valid.
246  asm volatile("sync");
247  return;
248  }
249  }
250 
251  // Else destroy the last entry in the first hash.
253  FATAL("api: " << Hex << (m_pHtab[primaryHash].entries[7].api << 22));
254  panic("Destroying hash table entry!");
255  m_pHtab[primaryHash].entries[7].v = 0;
256  m_pHtab[primaryHash].entries[7].vsid = vsid;
257  m_pHtab[primaryHash].entries[7].h = 0; // Primary hash
258  m_pHtab[primaryHash].entries[7].api = (effectiveAddress & 0x0FFFFFFF) >> 22;
259  m_pHtab[primaryHash].entries[7].rpn = physicalAddress >> 12;
260  m_pHtab[primaryHash].entries[7].w =
261  (mode & VirtualAddressSpace::WriteThrough) ? 1 : 0;
262  m_pHtab[primaryHash].entries[7].i =
263  (mode & VirtualAddressSpace::CacheDisable) ? 1 : 0;
264  m_pHtab[primaryHash].entries[7].m =
265  (mode & VirtualAddressSpace::MemoryCoherent) ? 1 : 0;
266  m_pHtab[primaryHash].entries[7].g =
267  (mode & VirtualAddressSpace::Guarded) ? 1 : 0;
268 
269  m_pHtab[primaryHash].entries[7].pp = pp;
270  m_pHtab[primaryHash].entries[7].v = 1; // Valid.
271  asm volatile("sync");
272 }
273 
274 void HashedPageTable::removeMapping(uint32_t effectiveAddress, uint32_t vsid)
275 {
276  // Calculate the primary and secondary hashes.
277  uint32_t input1 = vsid & 0x7FFFF; // Mask only the bottom 19 bits.
278  uint32_t input2 = (effectiveAddress >> 12) & 0xffff;
279  uint32_t primaryHash = input1 ^ input2;
280  uint32_t secondaryHash = ~primaryHash;
281 
282  primaryHash &= m_Mask;
283  secondaryHash &= m_Mask;
284 
285  for (int i = 0; i < 8; i++)
286  {
287  // If the primary entry is valid and refers to our EA and VSID, delete
288  // it.
289  if ((m_pHtab[primaryHash].entries[i].v) &&
290  (m_pHtab[primaryHash].entries[i].api ==
291  ((effectiveAddress & 0x0FFFFFFF) >> 22)) &&
292  (m_pHtab[primaryHash].entries[i].vsid == vsid))
293  {
294  m_pHtab[primaryHash].entries[i].v = 0;
295  asm volatile("sync");
296  asm volatile("tlbie %0" : : "r"(effectiveAddress));
297  asm volatile("sync");
298  }
299  }
300  for (int i = 0; i < 8; i++)
301  {
302  // If the secondary entry is valid and refers to our EA and VSID, delete
303  // it.
304  if ((m_pHtab[secondaryHash].entries[i].v) &&
305  (m_pHtab[secondaryHash].entries[i].api ==
306  ((effectiveAddress & 0x0FFFFFFF) >> 22)) &&
307  (m_pHtab[secondaryHash].entries[i].vsid == vsid))
308  {
309  m_pHtab[secondaryHash].entries[i].v = 0;
310  asm volatile("sync");
311  asm volatile("tlbie %0" : : "r"(effectiveAddress));
312  asm volatile("sync");
313  }
314  }
315 }
316 
317 bool HashedPageTable::isMapped(uint32_t effectiveAddress, uint32_t vsid)
318 {
319  // Calculate the primary and secondary hashes.
320  uint32_t input1 = vsid & 0x7FFFF; // Mask only the bottom 19 bits.
321  uint32_t input2 = (effectiveAddress >> 12) & 0xffff;
322  uint32_t primaryHash = input1 ^ input2;
323  uint32_t secondaryHash = ~primaryHash;
324 
325  primaryHash &= m_Mask;
326  secondaryHash &= m_Mask;
327 
328  for (int i = 0; i < 8; i++)
329  {
330  // If the primary entry is valid and refers to our EA and VSID, delete
331  // it.
332  if ((m_pHtab[primaryHash].entries[i].v) &&
333  (m_pHtab[primaryHash].entries[i].api ==
334  ((effectiveAddress & 0x0FFFFFFF) >> 22)) &&
335  (m_pHtab[primaryHash].entries[i].vsid == vsid))
336  {
337  // Found - one exists.
338  return true;
339  }
340  }
341  for (int i = 0; i < 8; i++)
342  {
343  // If the secondary entry is valid and refers to our EA and VSID, delete
344  // it.
345  if ((m_pHtab[secondaryHash].entries[i].v) &&
346  (m_pHtab[secondaryHash].entries[i].api ==
347  ((effectiveAddress & 0x0FFFFFFF) >> 22)) &&
348  (m_pHtab[secondaryHash].entries[i].vsid == vsid))
349  {
350  return true;
351  }
352  }
353  return false;
354 }
355 
356 uint32_t HashedPageTable::getMapping(uint32_t effectiveAddress, uint32_t vsid)
357 {
358  // Calculate the primary and secondary hashes.
359  uint32_t input1 = vsid & 0x7FFFF; // Mask only the bottom 19 bits.
360  uint32_t input2 = (effectiveAddress >> 12) & 0xffff;
361  uint32_t primaryHash = input1 ^ input2;
362  uint32_t secondaryHash = ~primaryHash;
363 
364  primaryHash &= m_Mask;
365  secondaryHash &= m_Mask;
366 
367  for (int i = 0; i < 8; i++)
368  {
369  // If the primary entry is valid and refers to our EA and VSID, delete
370  // it.
371  if ((m_pHtab[primaryHash].entries[i].v) &&
372  (m_pHtab[primaryHash].entries[i].api ==
373  ((effectiveAddress & 0x0FFFFFFF) >> 22)) &&
374  (m_pHtab[primaryHash].entries[i].vsid == vsid))
375  {
376  return m_pHtab[primaryHash].entries[i].rpn << 12;
377  }
378  }
379  for (int i = 0; i < 8; i++)
380  {
381  // If the secondary entry is valid and refers to our EA and VSID, delete
382  // it.
383  if ((m_pHtab[secondaryHash].entries[i].v) &&
384  (m_pHtab[secondaryHash].entries[i].api ==
385  ((effectiveAddress & 0x0FFFFFFF) >> 22)) &&
386  (m_pHtab[secondaryHash].entries[i].vsid == vsid))
387  {
388  return m_pHtab[secondaryHash].entries[i].rpn << 12;
389  }
390  }
391  return 0;
392 }
393 
395  size_t n, uintptr_t virt, physical_uintptr_t phys, size_t size,
396  uint32_t mode)
397 {
398  uint32_t bl;
399  switch (size)
400  {
401  case 0x20000:
402  bl = 0x0;
403  break; // 128KB
404  case 0x40000:
405  bl = 0x1;
406  break; // 256KB
407  case 0x80000:
408  bl = 0x3;
409  break; // 512KB
410  case 0x100000:
411  bl = 0x7;
412  break; // 1MB
413  case 0x200000:
414  bl = 0xF;
415  break; // 2MB
416  case 0x400000:
417  bl = 0x1F;
418  break; // 4MB
419  case 0x800000:
420  bl = 0x3F;
421  break; // 8MB
422  case 0x1000000:
423  bl = 0x7F;
424  break; // 16MB
425  case 0x2000000:
426  bl = 0xFF;
427  break; // 32MB
428  case 0x4000000:
429  bl = 0x1FF;
430  break; // 64MB
431  case 0x8000000:
432  bl = 0x3FF;
433  break; // 128MB
434  case 0x10000000:
435  bl = 0x7FF;
436  break; // 256MB
437  default:
438  bl = 0x7F; // 16MB
439  };
440 
441  BATU ibath;
442  ibath.bepi = virt >> 17;
443  ibath.unused = 0;
444  ibath.bl = bl;
445  ibath.vs = (mode & VirtualAddressSpace::KernelMode) ? 1 : 0;
446  ibath.vp = (mode & VirtualAddressSpace::KernelMode) ? 0 : 1;
447 
448  BATL ibatl;
449  ibatl.brpn = phys >> 17;
450  ibatl.unused1 = 0;
451  ibatl.wimg = 0;
452  ibatl.unused2 = 0;
453  ibatl.pp = 0x2;
454 
455  switch (n)
456  {
457  case 0:
458  asm volatile("mtspr 528, %0; mtspr 529, %1"
459  :
460  : "r"(ibath), "r"(ibatl));
461  break;
462  case 1:
463  asm volatile("mtspr 530, %0; mtspr 531, %1"
464  :
465  : "r"(ibath), "r"(ibatl));
466  break;
467  case 2:
468  asm volatile("mtspr 532, %0; mtspr 533, %1"
469  :
470  : "r"(ibath), "r"(ibatl));
471  break;
472  case 3:
473  asm volatile("mtspr 534, %0; mtspr 535, %1"
474  :
475  : "r"(ibath), "r"(ibatl));
476  break;
477  default:
478  panic("Bad index for IBAT");
479  }
480 }
481 
483  size_t n, uintptr_t virt, physical_uintptr_t phys, size_t size,
484  uint32_t mode)
485 {
486  uint32_t bl;
487  switch (size)
488  {
489  case 0x20000:
490  bl = 0x0;
491  break; // 128KB
492  case 0x40000:
493  bl = 0x1;
494  break; // 256KB
495  case 0x80000:
496  bl = 0x3;
497  break; // 512KB
498  case 0x100000:
499  bl = 0x7;
500  break; // 1MB
501  case 0x200000:
502  bl = 0xF;
503  break; // 2MB
504  case 0x400000:
505  bl = 0x1F;
506  break; // 4MB
507  case 0x800000:
508  bl = 0x3F;
509  break; // 8MB
510  case 0x1000000:
511  bl = 0x7F;
512  break; // 16MB
513  case 0x2000000:
514  bl = 0xFF;
515  break; // 32MB
516  case 0x4000000:
517  bl = 0x1FF;
518  break; // 64MB
519  case 0x8000000:
520  bl = 0x3FF;
521  break; // 128MB
522  case 0x10000000:
523  bl = 0x7FF;
524  break; // 256MB
525  default:
526  bl = 0x7F; // 16MB
527  };
528 
529  BATU dbath;
530  dbath.bepi = virt >> 17;
531  dbath.unused = 0;
532  dbath.bl = bl;
533  dbath.vs = (mode & VirtualAddressSpace::KernelMode) ? 1 : 0;
534  dbath.vp = (mode & VirtualAddressSpace::KernelMode) ? 0 : 1;
535 
536  BATL dbatl;
537  dbatl.brpn = phys >> 17;
538  dbatl.unused1 = 0;
539  dbatl.wimg = 0;
540  dbatl.unused2 = 0;
541  dbatl.pp = 0x2;
542 
543  switch (n)
544  {
545  case 0:
546  asm volatile("mtspr 536, %0; mtspr 537, %1"
547  :
548  : "r"(dbath), "r"(dbatl));
549  break;
550  case 1:
551  asm volatile("mtspr 538, %0; mtspr 539, %1"
552  :
553  : "r"(dbath), "r"(dbatl));
554  break;
555  case 2:
556  asm volatile("mtspr 540, %0; mtspr 541, %1"
557  :
558  : "r"(dbath), "r"(dbatl));
559  break;
560  case 3:
561  asm volatile("mtspr 542, %0; mtspr 543, %1"
562  :
563  : "r"(dbath), "r"(dbatl));
564  break;
565  default:
566  panic("Bad index for DBAT");
567  }
568 }
static HashedPageTable & instance()
uint32_t size
The size of the HTAB.
void setDBAT(size_t n, uintptr_t virt, physical_uintptr_t phys, size_t size, uint32_t mode)
uint32_t memorySize
The minimum size of RAM to make this size worthwhile.
void setIBAT(size_t n, uintptr_t virt, physical_uintptr_t phys, size_t size, uint32_t mode)
static OpenFirmware & instance()
Definition: OpenFirmware.h:45
bool isMapped(uint32_t effectiveAddress, uint32_t vsid)
void addMapping(uint32_t effectiveAddress, uint32_t physicalAddress, uint32_t mode, uint32_t vsid)
void removeMapping(uint32_t effectiveAddress, uint32_t vsid)
static HashedPageTable m_Instance
uint32_t getMapping(uint32_t effectiveAddress, uint32_t vsid)
uintptr_t physicalAddress(physical_uintptr_t address) PURE
Definition: utils.h:38
Definition: Log.h:136
uint32_t mask
The mask to be entered into the SDR1 register.
Translation getTranslation(size_t n)
Definition: Translation.cc:57
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition: panic.cc:121
void initialise(Translations &translations, uint32_t ramMax)
#define FATAL(text)
Definition: Log.h:89
void addTranslation(uint32_t virt, uint32_t phys, uint32_t size, uint32_t mode)
Definition: Translation.cc:67
uint32_t findFreePhysicalMemory(uint32_t size, uint32_t align=0x100000)
Definition: Translation.cc:80
size_t getNumTranslations()
Definition: Translation.cc:62