[kernel] Spit out vm_area types

The vm_space allow() functionality was a bit janky; using VMAs for all
regions would be a lot cleaner. To that end, this change:

- Adds a "static array" ctor to kutil::vector for setting the kernel
  address space's VMA list. This way a kernel heap VMA can be created
  without the heap already existing.
- Splits vm_area into different subclasses depending on desired behavior
- Splits out the concept of vm_mapper which maps vm_areas to vm_spaces,
  so that some kinds of VMA can be inherently single-space
- Implements VMA resizing so that userspace can grow allocations.
- Obsolete page_table_indices is removed

Also, the following bugs were fixed:

- kutil::map iterators on empty maps no longer break
- memory::page_count was doing page-align, not page-count

See: Github bug #242
See: [frobozz blog post](https://jsix.dev/posts/frobozz/)

Tags:
This commit is contained in:
2020-09-26 21:47:15 -07:00
parent 0e0975e5f6
commit 13aee1755e
19 changed files with 533 additions and 190 deletions

View File

@@ -5,8 +5,8 @@
#include <stdint.h>
#include "kutil/enum_bitfields.h"
#include "kutil/vector.h"
#include "page_table.h"
struct page_table;
class process;
struct TCB;
class vm_area;
@@ -47,23 +47,19 @@ public:
/// Get the kernel virtual memory space
static vm_space & kernel_space();
/// Copy a range of mappings from the given address space
/// \arg source The address space that already contains the mappings
/// \arg from The starting virtual address in the source address space
/// \arg to The starting virtual address in this address space
/// \arg count The number of page entries to copy
void copy_from(const vm_space &source, uintptr_t from, uintptr_t to, size_t count);
/// Map virtual addressses to the given physical pages
/// \arg virt The starting virutal address
/// \arg phys The starting physical address
/// \arg count The number of contiugous physical pages to map
void page_in(uintptr_t virt, uintptr_t phys, size_t count);
/// \arg area The VMA this mapping applies to
/// \arg offset Offset of the starting virutal address from the VMA base
/// \arg phys The starting physical address
/// \arg count The number of contiugous physical pages to map
void page_in(const vm_area &area, uintptr_t offset, uintptr_t phys, size_t count);
/// Clear mappings from the given region
/// \arg start The starting virutal address to clear
/// \arg area The VMA these mappings applies to
/// \arg offset Offset of the starting virutal address from the VMA base
/// \arg count The number of pages worth of mappings to clear
void clear(uintptr_t start, size_t count);
/// \arg free If true, free the pages back to the system
void clear(const vm_area &vma, uintptr_t start, size_t count, bool free = false);
/// Mark whether allocation is allowed or not in a range of
/// virtual memory.
@@ -106,6 +102,18 @@ public:
static size_t copy(vm_space &source, vm_space &dest, void *from, void *to, size_t length);
private:
friend class vm_mapper_single;
friend class vm_mapper_multi;
/// Find a given VMA in this address space
bool find_vma(const vm_area &vma, uintptr_t &base) const;
/// Check if a VMA can be resized
bool can_resize(const vm_area &vma, size_t size) const;
/// Copy a range of mappings from the given address space
void copy_from(const vm_space &source, const vm_area &vma);
bool m_kernel;
page_table *m_pml4;