Files
MentOS/mentos/inc/mem/paging.h
T
Enrico Fraccaroli (Galfurian) 1b2bc49d41 Update license and remove unused files.
2022-01-27 15:12:36 -05:00

255 lines
9.1 KiB
C

/// @file paging.h
/// @brief Implementation of a memory paging management.
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
/// See LICENSE.md for details.
#pragma once
#include "mem/zone_allocator.h"
#include "proc_access.h"
#include "kernel.h"
#include "stddef.h"
#include "boot.h"
/// Size of a page.
#define PAGE_SIZE 4096U
/// The start of the process area.
#define PROCAREA_START_ADDR 0x00000000
/// The end of the process area (and start of the kernel area).
#define PROCAREA_END_ADDR 0xC0000000
/// @brief An entry of a page directory.
typedef struct page_dir_entry_t {
unsigned int present : 1; ///< TODO: Comment.
unsigned int rw : 1; ///< TODO: Comment.
unsigned int user : 1; ///< TODO: Comment.
unsigned int w_through : 1; ///< TODO: Comment.
unsigned int cache : 1; ///< TODO: Comment.
unsigned int accessed : 1; ///< TODO: Comment.
unsigned int reserved : 1; ///< TODO: Comment.
unsigned int page_size : 1; ///< TODO: Comment.
unsigned int global : 1; ///< TODO: Comment.
unsigned int available : 3; ///< TODO: Comment.
unsigned int frame : 20; ///< TODO: Comment.
} page_dir_entry_t;
/// @brief An entry of a page table.
typedef struct page_table_entry_t {
unsigned int present : 1; ///< TODO: Comment.
unsigned int rw : 1; ///< TODO: Comment.
unsigned int user : 1; ///< TODO: Comment.
unsigned int w_through : 1; ///< TODO: Comment.
unsigned int cache : 1; ///< TODO: Comment.
unsigned int accessed : 1; ///< TODO: Comment.
unsigned int dirty : 1; ///< TODO: Comment.
unsigned int zero : 1; ///< TODO: Comment.
unsigned int global : 1; ///< TODO: Comment.
unsigned int kernel_cow : 1; ///< TODO: Comment.
unsigned int available : 2; ///< TODO: Comment.
unsigned int frame : 20; ///< TODO: Comment.
} page_table_entry_t;
/// @brief Flags associated with virtual memory areas.
enum MEMMAP_FLAGS {
MM_USER = 0x1, ///< Area belongs to user.
MM_GLOBAL = 0x2, ///< Area is global.
MM_RW = 0x4, ///< Area has user read/write perm.
MM_PRESENT = 0x8, ///< Area is valid.
// Kernel flags
MM_COW = 0x10, ///< Area is copy on write.
MM_UPDADDR = 0x20, ///< Check?
};
/// @brief A page table.
/// @details
/// It contains 1024 entries which can be addressed by 10 bits (log_2(1024)).
typedef struct page_table_t {
page_table_entry_t pages[1024]; ///< Array of pages.
} __attribute__((aligned(PAGE_SIZE))) page_table_t;
/// @brief A page directory.
/// @details In the two-level paging, this is the first level.
typedef struct page_directory_t {
/// We need a table that contains virtual address, so that we can
/// actually get to the tables (size: 1024 * 4 = 4096 byte).
page_dir_entry_t entries[1024];
} __attribute__((aligned(PAGE_SIZE))) page_directory_t;
/// @brief Virtual Memory Area, used to store details of a process segment.
typedef struct vm_area_struct_t {
/// Memory descriptor associated.
struct mm_struct_t *vm_mm;
/// Start address of the segment, inclusive.
uint32_t vm_start;
/// End address of the segment, exclusive.
uint32_t vm_end;
/// List of memory areas.
list_head vm_list;
/// Permissions.
pgprot_t vm_page_prot;
/// Flags.
unsigned short vm_flags;
/// rbtree node.
// struct rb_node vm_rb;
} vm_area_struct_t;
/// @brief Memory Descriptor, used to store details about the memory of a user process.
typedef struct mm_struct_t {
/// List of memory area (vm_area_struct reference).
list_head mmap_list;
// /// rbtree of memory area.
// struct rb_root mm_rb;
/// Last memory area used.
vm_area_struct_t *mmap_cache;
/// Process page directory.
page_directory_t *pgd;
/// Number of memory area.
int map_count;
/// List of mm_struct.
list_head mm_list;
/// CODE start.
uint32_t start_code;
/// CODE end.
uint32_t end_code;
/// DATA start.
uint32_t start_data;
/// DATA end.
uint32_t end_data;
/// HEAP start.
uint32_t start_brk;
/// HEAP end.
uint32_t brk;
/// STACK start.
uint32_t start_stack;
/// ARGS start.
uint32_t arg_start;
/// ARGS end.
uint32_t arg_end;
/// ENVIRONMENT start.
uint32_t env_start;
/// ENVIRONMENT end.
uint32_t env_end;
/// Number of mapped pages.
unsigned int total_vm;
} mm_struct_t;
/// @brief Cache used to store page tables.
extern kmem_cache_t *pgtbl_cache;
/// @brief Initializes paging
/// @param info Information coming from bootloader.
void paging_init(boot_info_t *info);
/// @brief Provide access to the main page directory.
/// @return A pointer to the main page directory.
page_directory_t *paging_get_main_directory();
/// @brief Provide access to the current paging directory.
/// @return A pointer to the current page directory.
static inline page_directory_t *paging_get_current_directory()
{
return (page_directory_t *)get_cr3();
}
/// @brief Switches paging directory, the pointer must be a physical address.
/// @param dir A pointer to the new page directory.
static inline void paging_switch_directory(page_directory_t *dir)
{
set_cr3((uintptr_t)dir);
}
/// @brief Switches paging directory, the pointer can be a lowmem address.
/// @param dir A pointer to the new page directory.
void paging_switch_directory_va(page_directory_t *dir);
/// @brief Invalidate a single tlb page (the one that maps the specified virtual address)
/// @param addr The address of the page table.
void paging_flush_tlb_single(unsigned long addr);
/// @brief Enables paging.
static inline void paging_enable()
{
// Clear the PSE bit from cr4.
set_cr4(bitmask_clear(get_cr4(), CR4_PSE));
// Set the PG bit in cr0.
set_cr0(bitmask_set(get_cr0(), CR0_PG));
}
/// @brief Returns if paging is enabled.
/// @return 1 if paging is enables, 0 otherwise.
static inline int paging_is_enabled()
{
return bitmask_check(get_cr0(), CR0_PG);
}
/// @brief Handles a page fault.
/// @param f The interrupt stack frame.
void page_fault_handler(pt_regs *f);
/// @brief Gets a page from a virtual address
/// @param pgdir The target page directory.
/// @param virt_start The virtual address to query
/// @param size A pointer to the requested size of the data, size is updated if physical memory is not contiguous
/// @return Pointer to the page.
page_t *mem_virtual_to_page(page_directory_t *pgdir, uint32_t virt_start, size_t *size);
/// @brief Creates a virtual to physical mapping, incrementing pages usage counters.
/// @param pgd The target page directory.
/// @param virt_start The virtual address to map to.
/// @param phy_start The physical address to map.
/// @param size The size of the segment.
/// @param flags The flags for the memory range.
void mem_upd_vm_area(page_directory_t *pgd, uint32_t virt_start, uint32_t phy_start, size_t size, uint32_t flags);
/// @brief Clones a range of pages between two distinct page tables
/// @param src_pgd The source page directory.
/// @param dst_pgd The dest page directory.
/// @param src_start The source virtual address for the clone.
/// @param dst_start The destination virtual address for the clone.
/// @param size The size of the segment.
/// @param flags The flags for the new dst memory range.
void mem_clone_vm_area(page_directory_t *src_pgd,
page_directory_t *dst_pgd,
uint32_t src_start,
uint32_t dst_start,
size_t size,
uint32_t flags);
/// @brief Create a virtual memory area.
/// @param mm The memory descriptor which will contain the new segment.
/// @param virt_start The virtual address to map to.
/// @param size The size of the segment.
/// @param pgflags The flags for the new memory area.
/// @param gfpflags The Get Free Pages flags.
/// @return The virtual address of the starting point of the segment.
uint32_t create_vm_area(mm_struct_t *mm,
uint32_t virt_start,
size_t size,
uint32_t pgflags,
uint32_t gfpflags);
/// @brief Clone a virtual memory area, using copy on write if specified
/// @param mm The memory descriptor which will contain the new segment.
/// @param area The area to clone
/// @param cow Whether to use copy-on-write or just copy everything.
/// @param gfpflags The Get Free Pages flags.
/// @return Zero on success.
uint32_t clone_vm_area(mm_struct_t *mm,
vm_area_struct_t *area,
int cow,
uint32_t gfpflags);
/// @brief Creates the main memory descriptor.
/// @param stack_size The size of the stack in byte.
/// @return The Memory Descriptor created.
mm_struct_t *create_blank_process_image(size_t stack_size);
/// @brief Create a Memory Descriptor.
/// @param mmp The memory map to clone
/// @return The Memory Descriptor created.
mm_struct_t *clone_process_image(mm_struct_t *mmp);
/// @brief Free Memory Descriptor with all the memory segment contained.
/// @param mm The Memory Descriptor to free.
void destroy_process_image(mm_struct_t *mm);