/* * memory.h * * Copyright (C) 2019 Aleksandar Andrejevic * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef _MEMORY_H_ #define _MEMORY_H_ #include #include #include #include #include #include #include #define INVALID_PAGE ((physical_t)-1) #define PAGE_SIZE 0x1000 #define MAX_PAGING_LEVELS 6 #define MIN_PHYS_ADDR_BITS 16 #define MAX_PHYS_ADDR_BITS 52 #define MEMORY_MAX_BLOCKS 0x80000 #define MEMORY_METADATA_TOP 0xFF000000 #define PAGE_ALIGN(x) ((x) & ~(PAGE_SIZE - 1)) #define PAGE_OFFSET(x) ((x) & (PAGE_SIZE - 1)) #define PAGE_NUMBER(x) (PAGE_ALIGN(x) >> 12) #define PAGE_ALIGN_UP(x) PAGE_ALIGN((x) + PAGE_SIZE - 1) typedef qword_t physical_t; typedef physical_t page_num_t; typedef void *page_table_t; typedef enum { PAGE_STATUS_ABANDONED = 0, PAGE_STATUS_FREE, PAGE_STATUS_ALLOCATED, PAGE_STATUS_RESERVED, } page_status_t; typedef struct { mini_list_entry_t stack_link; page_status_t status : 2; byte_t map_level : 3; page_num_t number : 40; size_t map_count; } page_t; _Static_assert(PAGE_SIZE % sizeof(page_t) == 0, "The size of page_t must be a divisor of the page size."); typedef struct { page_t *pages; page_num_t count; } area_t; typedef struct { physical_t address; qword_t length; page_status_t status; } memory_map_entry_t; typedef enum { MEMORY_ZERO_BACKED_SECTION, MEMORY_FILE_BACKED_SECTION, MEMORY_PHYSICAL_BACKED_SECTION, } memory_section_backing_t; typedef struct { object_t header; memory_section_backing_t backing; page_num_t num_pages; union { page_t *pages; file_instance_t *file; /* strong reference */ }; } memory_section_t; typedef struct { avl_node_t by_addr_node; avl_node_t by_size_node; uintptr_t address; size_t size; memory_flags_t flags; memory_section_t *section; page_num_t section_offset; } memory_block_t; typedef struct { memory_block_t *blocks; dword_t *block_bitmap; avl_tree_t by_addr_tree; avl_tree_t by_size_tree; lock_t lock; page_t *root_page_table; } address_space_t; extern uintptr_t memory_metadata_base; extern const page_table_t memory_default_table; extern const page_table_t memory_shadow_table; extern address_space_t *memory_lower_space; extern address_space_t *const memory_upper_space; void memory_init(uintptr_t mboot_tags, size_t mboot_size); void *memory_request_metadata_space(size_t count, size_t size); page_t *memory_acquire_page(byte_t min_bits, byte_t max_bits, size_t alignment); void memory_acquire_area(byte_t min_bits, byte_t max_bits, size_t size, size_t alignment, area_t *area); void memory_release_page(page_t *page); void memory_release_area(const area_t *area); page_t *memory_find_page_by_address(physical_t address); void memory_claim_physical_region(physical_t address, qword_t size, page_status_t initial_status); void memory_abandon_physical_region(physical_t address, qword_t size); void memory_init_physical(memory_map_entry_t *mmap, size_t entry_count); static inline bool_t is_area_valid(const area_t *area) { return area->pages && area->count > 0 ? TRUE : FALSE; } page_t *memory_get_page_mapping(page_table_t table, void *address); sysret_t memory_map_page(page_table_t table, page_t *page, void *address, memory_flags_t access_flags); sysret_t memory_map_area(page_table_t table, const area_t *area, void *address, memory_flags_t access_flags); sysret_t memory_query_page_flags(page_table_t table, void *address, memory_flags_t *access_flags); sysret_t memory_adjust_page_flags(page_table_t table, void *address, memory_flags_t access_flags); sysret_t memory_unmap_clear_page(page_table_t table, void *address); sysret_t memory_unmap_keep_page(page_table_t table, void *address); sysret_t memory_unmap_clear_area(page_table_t table, void *address, size_t size); sysret_t memory_unmap_keep_area(page_table_t table, void *address, size_t size); sysret_t memory_load_default_table(page_t *new_default_table); sysret_t memory_load_shadow_table(page_t *new_shadow_table); sysret_t memory_unload_shadow_table(void); page_t *memory_create_page_table(void); sysret_t memory_commit(void *address, size_t size); void memory_init_mapping(void); memory_block_t *memory_get_block_for_address(void *address); sysret_t memory_allocate(address_space_t *space, void **address, size_t size, memory_flags_t flags, memory_section_t *section, page_num_t section_offset); sysret_t memory_free(address_space_t *space, void *address); sysret_t memory_view_area(address_space_t *space, void **address, const area_t *area, memory_flags_t flags); sysret_t memory_pin_buffer(const void *virtual, void **pinned, size_t size, bool_t lock_contents); void memory_init_virtual(const area_t *kernel_area); bool_t memory_fault_handler(void *address, registers_t *regs); void memory_cleanup(object_t *object); #endif