fork download
  1. // VirtMem.c
  2. // Property of Aperture Research Inc (c) 2012-2013
  3. // Licensed under Creative Commons Attribution 3.0 Unported.
  4.  
  5.  
  6. // Sets up the paging structures left by our bootstrap in (boot.s).
  7.  
  8. #include <stdlib.h>
  9.  
  10.  
  11. using namespace Kernel;
  12. using namespace Library;
  13.  
  14. namespace Kernel {
  15. namespace HAL {
  16. namespace VMem
  17. {
  18.  
  19. TPML *CurrentPML4T;
  20.  
  21. bool IsPaging;
  22.  
  23.  
  24. #define I_RECURSIVE_SLOT (511ULL)
  25.  
  26.  
  27. // Convert an address into array index of a structure
  28. // E.G. int index = I_PML4_INDEX(0xFFFFFFFFFFFFFFFF); // index = 511
  29. #define I_PML4_INDEX(addr) ((((uintptr_t)(addr))>>39) & 511)
  30. #define I_PDPT_INDEX(addr) ((((uintptr_t)(addr))>>30) & 511)
  31. #define I_PD_INDEX(addr) ((((uintptr_t)(addr))>>21) & 511)
  32. #define I_PT_INDEX(addr) ((((uintptr_t)(addr))>>12) & 511)
  33.  
  34. // Base address for paging structures
  35. #define KADDR_I_PT (0xFFFF000000000000ULL + (I_RECURSIVE_SLOT<<39))
  36. #define KADDR_I_PD (KADDR_I_PT + (I_RECURSIVE_SLOT<<30))
  37. #define KADDR_I_PDPT (KADDR_I_PD + (I_RECURSIVE_SLOT<<21))
  38. #define KADDR_I_PML4 (KADDR_I_PDPT + (I_RECURSIVE_SLOT<<12))
  39.  
  40. // Structures for given address, for example
  41. // uint64_t* pt = I_PT(addr)
  42. // uint64_t physical_addr = pt[I_PT_INDEX(addr)];
  43. #define I_PML4(addr) ((uint64_t*)KADDR_I_PML4)
  44. #define I_PDPT(addr) ((uint64_t*)(KADDR_I_PDPT + (((addr)>>27) & 0x00001FF000)))
  45. #define I_PD(addr) ((uint64_t*)(KADDR_I_PD + (((addr)>>18) & 0x003FFFF000)))
  46. #define I_PT(addr) ((uint64_t*)(KADDR_I_PT + (((addr)>>9) & 0x7FFFFFF000)))
  47.  
  48.  
  49.  
  50.  
  51. void Initialise()
  52. {
  53. TPML* const OriginalPml4 = (TPML* const)0x1000;
  54.  
  55.  
  56. // Put the physical address (We know it's 0x1000, since it's a constant) of the PML4T into the second last entry of itself, so it appears as a PDPT.
  57.  
  58. // This means that subsequently, the address of a PD would reside in one of 512 PDs in our 'PDPT' (PML4T in disguise), and so on
  59. // for the PD and PTs.
  60.  
  61.  
  62.  
  63. OriginalPml4->Entry[I_RECURSIVE_SLOT] = (uint64_t)OriginalPml4 | I_Present | I_ReadWrite;
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70. CurrentPML4T = OriginalPml4;
  71. IsPaging = 1;
  72. }
  73.  
  74. void SwitchPML4T(TPML *PML4T)
  75. {
  76. asm volatile("mov %0, %%cr3" :: "r"(PML4T));
  77. }
  78.  
  79.  
  80. bool MapAddr(uint64_t VirtAddr, uint64_t PhysAddr, uint64_t Flags)
  81. {
  82.  
  83. // Access PhysAddr using VirtAddr.
  84.  
  85. VirtAddr &= I_AlignMask;
  86. PhysAddr &= I_AlignMask;
  87.  
  88.  
  89. // // First, find out which page we will need.
  90.  
  91. uint64_t PageTableIndex = I_PT_INDEX(VirtAddr);
  92. uint64_t PageDirectoryIndex = I_PD_INDEX(VirtAddr);
  93. uint64_t PageDirectoryPointerTableIndex = I_PDPT_INDEX(VirtAddr);
  94. uint64_t PML4TIndex = I_PML4_INDEX(VirtAddr);
  95.  
  96.  
  97.  
  98. // Because these are indexes into structures, we need to use MODULO '%'
  99. // To change them to relative indexes, not absolute ones.
  100.  
  101. if(PML4TIndex == I_RECURSIVE_SLOT)
  102. {
  103. // We can't map 510, we need that for our recursive mapping.
  104. HALT("Tried to map to PML4[510]! (RESTRICTED, KERNEL USE)");
  105. }
  106.  
  107.  
  108.  
  109. // Now we know where all the stuff is at, let's start mapping.
  110. // First, we check if the desired PDPT is present:
  111.  
  112. if(!(CurrentPML4T->Entry[PML4TIndex]) & I_Present)
  113. {
  114. // It's not, so we have to set it to present.
  115. CurrentPML4T->Entry[PML4TIndex] = ((uint64_t)(HAL::AllocatePage()) & I_AlignMask) | 0x03;
  116.  
  117. // So we can access this later, put the address of the PDPT we just defined into the 'PML4T'.
  118. TPML *PML4 = (TPML*)(CurrentPML4T->Entry[I_RECURSIVE_SLOT] & I_AlignMask);
  119.  
  120. PML4->Entry[PML4TIndex] = CurrentPML4T->Entry[PML4TIndex] | I_Present | I_ReadWrite;
  121. invlpg(CurrentPML4T);
  122. }
  123.  
  124.  
  125. // Continue with our business here.
  126. // Check the PD:
  127. TPML *PDPT = (TPML*)(CurrentPML4T->Entry[PML4TIndex] & I_AlignMask);
  128.  
  129. if(!(PDPT->Entry[PageDirectoryPointerTableIndex]) & I_Present)
  130. {
  131. // uint64_t temp = HAL::PMem::AllocatePage_NoMap();
  132. PDPT->Entry[PageDirectoryPointerTableIndex] = ((uint64_t)(HAL::AllocatePage()) & I_AlignMask) | 0x03;
  133.  
  134. // Put the address of the PD into the PDPT.
  135.  
  136. TPML *PML4 = (TPML*)(CurrentPML4T->Entry[I_RECURSIVE_SLOT] & I_AlignMask);
  137. TPML *PML3 = (TPML*)(PML4->Entry[PML4TIndex] & I_AlignMask);
  138.  
  139. PML3->Entry[PageDirectoryPointerTableIndex] = PDPT->Entry[PageDirectoryPointerTableIndex] | I_Present | I_ReadWrite;
  140.  
  141. invlpg(PDPT);
  142. }
  143.  
  144.  
  145. // Next, we must check if the Page Table is present:
  146.  
  147. TPML *PageDirectory = (TPML*)(PDPT->Entry[PageDirectoryPointerTableIndex] & I_AlignMask);
  148. if(!(PageDirectory->Entry[PageDirectoryIndex]) & I_Present)
  149. {
  150.  
  151. PageDirectory->Entry[PageDirectoryIndex] = ((uint64_t)(HAL::AllocatePage()) & I_AlignMask) | 0x03;
  152. // PageDirectory->Entry[PageDirectoryIndex] &= I_AlignMask | 0x03;
  153.  
  154.  
  155. // Put the address of the PT into the PD.
  156.  
  157. TPML *PML4 = (TPML*)(CurrentPML4T->Entry[I_RECURSIVE_SLOT] & I_AlignMask);
  158. TPML *PML3 = (TPML*)(PML4->Entry[PML4TIndex] & I_AlignMask);
  159. TPML *PML2 = (TPML*)(PML3->Entry[PageDirectoryPointerTableIndex] & I_AlignMask);
  160.  
  161. PML2->Entry[PageDirectoryIndex] = PageDirectory->Entry[PageDirectoryIndex] | I_Present | I_ReadWrite;
  162. invlpg(PageDirectory);
  163. }
  164.  
  165.  
  166. bool r = true;
  167. TPML *PageTable = (TPML*)(PageDirectory->Entry[PageDirectoryIndex] & I_AlignMask);
  168. if(PageTable->Entry[PageTableIndex])
  169. r = false;
  170.  
  171. PageTable->Entry[PageTableIndex] = (PhysAddr & I_AlignMask) | Flags;
  172.  
  173. invlpg(PageTable);
  174.  
  175.  
  176.  
  177. // Flush TLB.
  178. asm volatile("mov %cr3, %rax; mov %rax, %cr3");
  179. return r;
  180. }
  181.  
  182.  
  183.  
  184.  
  185.  
  186. void UnMapAddr(uint64_t VirtAddr)
  187. {
  188.  
  189.  
  190. // First, find out which page we will need.
  191. uint64_t PageTableIndex = VirtAddr / 0x1000;
  192.  
  193. // Next, which Page Table does that page reside in?
  194. // Let's find out:
  195. uint64_t PageDirectoryIndex = PageTableIndex / 512;
  196.  
  197. // Page Directory:
  198. uint64_t PageDirectoryPointerTableIndex = PageDirectoryIndex / 512;
  199.  
  200. // Finally, which PDPT is it in?
  201. uint64_t PML4TIndex = PageDirectoryPointerTableIndex / 512;
  202.  
  203.  
  204.  
  205. // Because these are indexes into structures, we need to use MODULO '%'
  206. // To change them to relative indexes, not absolute ones.
  207.  
  208. PageTableIndex %= 512;
  209. PageDirectoryIndex %= 512;
  210. PageDirectoryPointerTableIndex %= 512;
  211.  
  212.  
  213. TPML *PML = (TPML*)(CurrentPML4T->Entry[510] & I_AlignMask);
  214.  
  215. if(PML)
  216. {
  217. TPML *PDPT = (TPML*)(PML->Entry[PML4TIndex] & I_AlignMask);
  218.  
  219. if(PDPT)
  220. {
  221. TPML *PageDirectory = (TPML*)(PDPT->Entry[PageDirectoryPointerTableIndex] & I_AlignMask);
  222.  
  223. if(PageDirectory)
  224. {
  225. TPML *PageTable = (TPML*)(PageDirectory->Entry[PageDirectoryIndex] & I_AlignMask);
  226.  
  227. PageTable->Entry[PageTableIndex] = 0;
  228. asm volatile("invlpg (%0)" : : "a" (VirtAddr));
  229. }
  230. else
  231. {
  232. return;
  233. }
  234. }
  235. else
  236. {
  237. return;
  238. }
  239. }
  240. else
  241. {
  242. return;
  243. }
  244.  
  245.  
  246.  
  247.  
  248. }
  249.  
  250.  
  251.  
  252. void MapRegion(uint64_t VirtAddr, uint64_t PhysAddr, uint64_t LengthInPages, uint64_t Flags)
  253. {
  254. for(uint64_t i = 0; i < LengthInPages; i++)
  255. {
  256. MapAddr(VirtAddr + (i * 0x1000), PhysAddr + (i * 0x1000), Flags);
  257. }
  258. }
  259.  
  260. void UnMapRegion(uint64_t VirtAddr, uint64_t LengthInPages)
  261. {
  262. for(uint64_t i = 0; i < LengthInPages; i++)
  263. {
  264. UnMapAddr(VirtAddr + (i * 0x1000));
  265. }
  266. }
  267.  
  268.  
  269. uint64_t GetMapping(uint64_t VirtAddr)
  270. {
  271. // First, find out which page we will need.
  272. uint64_t PageTableIndex = VirtAddr / 0x1000;
  273.  
  274. // Next, which Page Table does that page reside in?
  275. // Let's find out:
  276. uint64_t PageDirectoryIndex = PageTableIndex / 512;
  277.  
  278. // Page Directory:
  279. uint64_t PageDirectoryPointerTableIndex = PageDirectoryIndex / 512;
  280.  
  281. // Finally, which PDPT is it in?
  282. uint64_t PML4TIndex = PageDirectoryPointerTableIndex / 512;
  283.  
  284.  
  285.  
  286. // Because these are indexes into structures, we need to use MODULO '%'
  287. // To change them to relative indexes, not absolute ones.
  288.  
  289.  
  290.  
  291. PML4TIndex %= 512;
  292. PageTableIndex %= 512;
  293. PageDirectoryIndex %= 512;
  294. PageDirectoryPointerTableIndex %= 512;
  295.  
  296.  
  297. TPML *PML = (TPML*)(CurrentPML4T->Entry[510] & I_AlignMask);
  298.  
  299. if(PML)
  300. {
  301. TPML *PDPT = (TPML*)(PML->Entry[PML4TIndex] & I_AlignMask);
  302.  
  303. if(PDPT)
  304. {
  305. TPML *PageDirectory = (TPML*)(PDPT->Entry[PageDirectoryPointerTableIndex] & I_AlignMask);
  306.  
  307. if(PageDirectory)
  308. {
  309. TPML *PageTable = (TPML*)(PageDirectory->Entry[PageDirectoryIndex] & I_AlignMask);
  310. return (uint64_t)(PageTable->Entry[PageTableIndex] & I_AlignMask);
  311. }
  312. else
  313. {
  314. return 0;
  315. }
  316. }
  317. else
  318. {
  319. return 0;
  320. }
  321. }
  322. else
  323. {
  324. return 0;
  325. }
  326. }
  327.  
  328. uint64_t SearchPhysicalMapping(uint64_t PhysAddr)
  329. {
  330. // Search the page tables for the physical mapping.
  331.  
  332. // PML4
  333. for(int i = 0; i < 512; i++)
  334. {
  335. // Check if there's anything in there; if not, skip early
  336. if(!CurrentPML4T->Entry[i])
  337. {
  338. continue;
  339. }
  340.  
  341. // PDPT
  342. for(int f = 0; f < 512; f++)
  343. {
  344. if(!((TPML*)(CurrentPML4T->Entry[i]))->Entry[f])
  345. {
  346. continue;
  347. }
  348.  
  349. // PD
  350. for(int x = 0; x < 512; x++)
  351. {
  352. if(!((TPML*)((TPML*)(CurrentPML4T->Entry[i]))->Entry[f])->Entry[x])
  353. {
  354. continue;
  355. }
  356.  
  357. // PT
  358. for(int y = 0; y < 512; y++)
  359. {
  360. // Search the entries!
  361. TPML *PML4 = (TPML*)(CurrentPML4T->Entry[i] & I_AlignMask);
  362. TPML *PML3 = (TPML*)(PML4->Entry[f] & I_AlignMask);
  363. TPML *PML2 = (TPML*)(PML3->Entry[x] & I_AlignMask);
  364.  
  365.  
  366. return PML2->Entry[y];
  367. }
  368. }
  369. }
  370. }
  371. return 0;
  372. }
  373.  
  374. bool GetPagingFlag()
  375. {
  376. return IsPaging;
  377. }
  378. }
  379. }
  380. }
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty