Files
MentOS/mentos/src/mem/vmem_map.c
T
Enrico Fraccaroli (Galfurian) 4275002414 Fix wrong type.
2023-06-14 12:49:16 -04:00

179 lines
5.9 KiB
C

/// @file vmem_map.c
/// @brief Virtual memory mapping routines.
/// @copyright (c) 2014-2023 This file is distributed under the MIT License.
/// See LICENSE.md for details.
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[VMEM ]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "mem/vmem_map.h"
#include "system/panic.h"
#include "string.h"
/// Virtual addresses manager.
static virt_map_page_manager_t virt_default_mapping;
/// TODO: check.
#define VIRTUAL_MEMORY_PAGES_COUNT (VIRTUAL_MEMORY_SIZE_MB * 256)
/// TODO: check.
#define VIRTUAL_MAPPING_BASE (PROCAREA_END_ADDR + 0x38000000)
/// TODO: check.
#define VIRT_PAGE_TO_ADDRESS(page) ((((page)-virt_pages) * PAGE_SIZE) + VIRTUAL_MAPPING_BASE)
/// TODO: check.
#define VIRT_ADDRESS_TO_PAGE(addr) ((((addr)-VIRTUAL_MAPPING_BASE) / PAGE_SIZE) + virt_pages)
/// Array of virtual pages.
virt_map_page_t virt_pages[VIRTUAL_MEMORY_PAGES_COUNT];
void virt_init(void)
{
buddy_system_init(
&virt_default_mapping.bb_instance,
"virt_manager",
virt_pages,
BBSTRUCT_OFFSET(virt_map_page_t, bbpage),
sizeof(virt_map_page_t),
VIRTUAL_MEMORY_PAGES_COUNT);
page_directory_t *mainpgd = paging_get_main_directory();
uint32_t start_virt_pfn = VIRTUAL_MAPPING_BASE / PAGE_SIZE;
uint32_t start_virt_pgt = start_virt_pfn / 1024;
uint32_t start_virt_tbl_idx = start_virt_pfn % 1024;
uint32_t pfn_num = VIRTUAL_MEMORY_PAGES_COUNT;
// Alloc all page tables inside the main directory, so they will be shared across
// all page directories of processes
for (uint32_t i = start_virt_pgt; i < 1024 && (pfn_num > 0); i++) {
page_dir_entry_t *entry = mainpgd->entries + i;
page_table_t *table;
// Alloc virtual page table
entry->present = 1;
entry->rw = 0;
entry->global = 1;
entry->user = 0;
entry->accessed = 0;
entry->available = 1;
table = kmem_cache_alloc(pgtbl_cache, GFP_KERNEL);
uint32_t start_page = (i == start_virt_pgt) ? start_virt_tbl_idx : 0;
for (uint32_t j = start_page; j < 1024 && (pfn_num > 0); j++, pfn_num--) {
table->pages[j].frame = 0;
table->pages[j].rw = 0;
table->pages[j].present = 0;
table->pages[j].global = 1;
table->pages[j].user = 0;
}
page_t *table_page = get_lowmem_page_from_address((uint32_t)table);
uint32_t phy_addr = get_physical_address_from_page(table_page);
entry->frame = phy_addr >> 12u;
}
}
static virt_map_page_t *_alloc_virt_pages(uint32_t pfn_count)
{
unsigned order = find_nearest_order_greater(0, pfn_count << 12);
virt_map_page_t *vpage = PG_FROM_BBSTRUCT(bb_alloc_pages(&virt_default_mapping.bb_instance, order), virt_map_page_t, bbpage);
return vpage;
}
uint32_t virt_map_physical_pages(page_t *page, int pfn_count)
{
virt_map_page_t *vpage = _alloc_virt_pages(pfn_count);
if (!vpage)
return 0;
uint32_t virt_address = VIRT_PAGE_TO_ADDRESS(vpage);
uint32_t phy_address = get_physical_address_from_page(page);
mem_upd_vm_area(paging_get_main_directory(), virt_address, phy_address,
pfn_count * PAGE_SIZE, MM_PRESENT | MM_RW | MM_GLOBAL | MM_UPDADDR);
return virt_address;
}
virt_map_page_t *virt_map_alloc(uint32_t size)
{
uint32_t pages_count = (size + PAGE_SIZE - 1) / PAGE_SIZE;
return _alloc_virt_pages(pages_count);
}
uint32_t virt_map_vaddress(mm_struct_t *mm, virt_map_page_t *vpage, uint32_t vaddr, uint32_t size)
{
uint32_t start_map_virt_address = VIRT_PAGE_TO_ADDRESS(vpage);
// Clone the source vaddr the the requested virtual memory portion
mem_clone_vm_area(mm->pgd,
paging_get_main_directory(),
vaddr,
start_map_virt_address,
size,
MM_PRESENT | MM_RW | MM_GLOBAL | MM_UPDADDR);
return start_map_virt_address;
}
int virtual_check_address(uint32_t addr)
{
return addr >= VIRTUAL_MAPPING_BASE; // && addr < VIRTUAL_MAPPING_BASE + VIRTUAL_MEMORY_PAGES_COUNT * PAGE_SIZE;
}
void virt_unmap(uint32_t addr)
{
virt_map_page_t *page = VIRT_ADDRESS_TO_PAGE(addr);
virt_unmap_pg(page);
}
void virt_unmap_pg(virt_map_page_t *page)
{
uint32_t addr = VIRT_PAGE_TO_ADDRESS(page);
// Set all virtual pages as not present
mem_upd_vm_area(paging_get_main_directory(), addr, 0,
(1 << page->bbpage.order) * PAGE_SIZE, MM_GLOBAL);
// and avoiding unwanted memory accesses by the kernel
bb_free_pages(&virt_default_mapping.bb_instance, &page->bbpage);
}
// FIXME: Check if this function should support unaligned page-boundaries copy
void virt_memcpy(mm_struct_t *dst_mm, uint32_t dst_vaddr, mm_struct_t *src_mm, uint32_t src_vaddr, uint32_t size)
{
const uint32_t VMEM_BUFFER_SIZE = 65536;
uint32_t buffer_size = min(VMEM_BUFFER_SIZE, size);
virt_map_page_t *src_vpage = virt_map_alloc(size);
virt_map_page_t *dst_vpage = virt_map_alloc(size);
if (!src_vpage || !dst_vpage) {
kernel_panic("Cannot copy virtual memory address, unable to reserve vmem!");
}
for (;;) {
uint32_t src_map = virt_map_vaddress(src_mm, src_vpage, src_vaddr, buffer_size);
uint32_t dst_map = virt_map_vaddress(dst_mm, dst_vpage, dst_vaddr, buffer_size);
uint32_t cpy_size = min(buffer_size, size);
memcpy((void *)dst_map, (void *)src_map, cpy_size);
if (size <= buffer_size) {
break;
}
size -= cpy_size;
src_vaddr += cpy_size;
dst_vaddr += cpy_size;
}
virt_unmap_pg(src_vpage);
virt_unmap_pg(dst_vpage);
}