/// <summary> /// Creates a new page directory using only physical memory (used in Init) /// </summary> /// <param name="flags">The flags</param> /// <returns>The page directory</returns> public static PageDirectory *CreateNewDirectoryPhysically(PageFlags flags) { // Allocate a new block of physical memory to store our physical page in PageDirectory *directory = (PageDirectory *)Heap.AlignedAlloc(0x1000, sizeof(PageDirectory)); directory->PhysicalDirectory = directory; if (directory == null) { Panic.DoPanic("directory == null"); } // Allocate the tables for (int i = 0; i < 1024; i++) { PageTable *table = (PageTable *)PhysicalMemoryManager.Alloc(); if (table == null) { Panic.DoPanic("table == null"); } Memory.Memclear(table, sizeof(PageTable)); // Note: At this point, virtual address == physical address due to identity mapping directory->PhysicalTables[i] = (int)table | (int)flags; directory->VirtualTables[i] = (int)table; } return(directory); }
/// <summary> /// Maps a page in a directory /// </summary> /// <param name="directory">The page directory</param> /// <param name="phys">The physical address</param> /// <param name="virt">The virtual address</param> /// <param name="flags">The flags</param> public static void MapPage(PageDirectory *directory, int phys, int virt, PageFlags flags) { // Get indices int pageIndex = virt / 0x1000; int tableIndex = pageIndex / 1024; // Set page using its virtual address PageTable *table = (PageTable *)directory->VirtualTables[tableIndex]; table->Pages[pageIndex & (1024 - 1)] = ToFrameAddress(phys) | (int)flags; }
/// <summary> /// Gets the physical address from a virtual address /// </summary> /// <param name="pageDir">The page directory to look into</param> /// <param name="virt">The virtual address</param> /// <returns>The physical address</returns> public static void *GetPhysicalFromVirtual(PageDirectory *pageDir, void *virt) { // Get indices int address = (int)virt; int remaining = address % 0x1000; int frame = address / 0x1000; // Find corresponding table to the virtual address PageTable *table = (PageTable *)pageDir->VirtualTables[frame / 1024]; if (table == null) { Panic.DoPanic("table == null"); } // Calculate page int page = table->Pages[frame & (1024 - 1)]; return((void *)(GetFrameAddress(page) + remaining)); }
/// <summary> /// Clones a page directory and its tables /// </summary> /// <param name="source">The source page directory</param> /// <returns>The cloned page directory</returns> public static PageDirectory *CloneDirectory(PageDirectory *source) { // Note: sizeof(PageDirectory) is not neccesarily a page int pageDirSizeAligned = (int)AlignUp((uint)sizeof(PageDirectory)); // One block for the page directory and the page tables int allocated = (int)Heap.AlignedAlloc(0x1000, pageDirSizeAligned + 1024 * sizeof(PageTable)); if (allocated == 0) { Panic.DoPanic("Couldn't clone page directory because there is no memory left"); } PageDirectory *destination = (PageDirectory *)allocated; destination->PhysicalDirectory = (PageDirectory *)GetPhysicalFromVirtual((void *)allocated); for (int i = 0; i < 1024; i++) { int sourceTable = source->VirtualTables[i]; if (sourceTable == 0) { Panic.DoPanic("sourceTable == 0?!"); } // Get the pointer without the flags and the flags seperately PageTable *sourceTablePtr = (PageTable *)sourceTable; int flags = source->PhysicalTables[i] & 0xFFF; // Calculate addresses int addressOffset = pageDirSizeAligned + i * sizeof(PageTable); PageTable *newTable = (PageTable *)(allocated + addressOffset); int newTablePhysical = (int)GetPhysicalFromVirtual(newTable); // Copy table data and set pointers Memory.Memcpy(newTable, sourceTablePtr, sizeof(PageTable)); destination->PhysicalTables[i] = newTablePhysical | flags; destination->VirtualTables[i] = (int)newTable; } return(destination); }