179 lines
5.9 KiB
C
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);
|
|
}
|