예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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;
        }
예제 #3
0
        /// <summary>
        /// Maps a physical address (range) to a free virtual address (range)
        /// </summary>
        /// <param name="directory">The page directory</param>
        /// <param name="phys">The physical address</param>
        /// <param name="size">The size of the range</param>
        /// <param name="flags">The flags</param>
        /// <returns>The virtual address</returns>
        public static void *MapToVirtual(PageDirectory *directory, int phys, int size, PageFlags flags)
        {
            int sizeAligned = (int)AlignUp((uint)size) / 0x1000;
            int free        = bitmap.FindFirstFreeRange(sizeAligned, true);
            int virt        = free * 0x1000;

            for (int i = 0; i < sizeAligned; i++)
            {
                int offset = i * 0x1000;
                MapPage(directory, phys + offset, virt + offset, flags);
                PhysicalMemoryManager.Set(phys + offset);
            }
            Paging.setDirectoryInternal(Paging.CurrentDirectoryPhysical);
            return((void *)virt);
        }
예제 #4
0
        /// <summary>
        /// Sets the page directory
        /// </summary>
        /// <param name="directoryVirtual">The virtual address of the page directory</param>
        /// <param name="directoryPhysical">The physical address of the page directory</param>
        public static void SetPageDirectory(PageDirectory *directoryVirtual, PageDirectory *directoryPhysical)
        {
            /**
             * Note: This is a way to solve the issue that a page directory is not available
             * in every other page directory (due to security).
             * So: upon a task switch, setting a directory physically works for the CPU
             * but we also need its virtual address.
             * Setting the virtual address with a getter and updating the CR3 with the physical address
             * also wont work, because it's not guaranteed you can read the page directory
             * as it may not be available in the current task.
             */

            CurrentDirectory         = directoryVirtual;
            CurrentDirectoryPhysical = directoryPhysical;
            setDirectoryInternal(directoryPhysical);
        }
예제 #5
0
        /// <summary>
        /// Frees a page directory
        /// </summary>
        /// <param name="directory">The directory</param>
        public static void FreeDirectory(PageDirectory *directory)
        {
            if (directory == CurrentDirectory)
            {
                Panic.DoPanic("Tried to free the current page directory");
            }

            if (directory == KernelDirectory)
            {
                Panic.DoPanic("Tried to free the kernel page directory");
            }

            // The directory was cloned, so it was allocated in one huge block
            PageDirectory *virt = CurrentDirectory;
            PageDirectory *phys = CurrentDirectoryPhysical;

            SetPageDirectory(KernelDirectory, KernelDirectory);
            Heap.Free(directory);
            SetPageDirectory(virt, phys);
        }
예제 #6
0
        /// <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));
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
 /// <summary>
 /// Sets the current paging directory in the CR3 register
 /// </summary>
 /// <param name="directory">The page directory</param>
 private static extern void setDirectoryInternal(PageDirectory *directory);