[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

79
src/kernel/vm_mapper.h Normal file
View File

@@ -0,0 +1,79 @@
#pragma once
/// \file vm_mapper.h
/// VMA to address space mapping interface and implementing objects
#include <stdint.h>
#include "kutil/vector.h"
class vm_area;
class vm_space;
/// An interface to map vm_areas to one or more vm_spaces
class vm_mapper
{
public:
virtual ~vm_mapper() {}
/// Check whether the owning VMA can be resized to the given size.
/// \arg size The desired size
/// \returns True if resize is possible
virtual bool can_resize(size_t size) const = 0;
/// Map the given physical pages into the owning VMA at the given offset
/// \arg offset Offset into the VMA of the requested virtual address
/// \arg count Number of contiguous physical pages to map
/// \arg phys The starting physical address of the pages
virtual void map(uintptr_t offset, size_t count, uintptr_t phys) = 0;
/// Unmap the pages corresponding to the given offset from the owning VMA
/// \arg offset Offset into the VMA of the requested virtual address
/// \arg count Number of pages to unmap
virtual void unmap(uintptr_t offset, size_t count) = 0;
/// Add the given address space to the list of spaces the owning VMA is
/// mapped to, if applicable.
virtual void add(vm_space *space) {}
/// Remove the given address space from the list of spaces the owning VMA
/// is mapped to, if applicable.
virtual void remove(vm_space *space) {}
};
/// A vm_mapper that maps a VMA to a single vm_space
class vm_mapper_single :
public vm_mapper
{
public:
vm_mapper_single(vm_area &area, vm_space &space);
virtual ~vm_mapper_single();
virtual bool can_resize(size_t size) const override;
virtual void map(uintptr_t offset, size_t count, uintptr_t phys) override;
virtual void unmap(uintptr_t offset, size_t count) override;
private:
vm_area &m_area;
vm_space &m_space;
};
/// A vm_mapper that maps a VMA to multiple vm_spaces
class vm_mapper_multi :
public vm_mapper
{
public:
vm_mapper_multi(vm_area &area);
virtual ~vm_mapper_multi();
virtual bool can_resize(size_t size) const override;
virtual void map(uintptr_t offset, size_t count, uintptr_t phys) override;
virtual void unmap(uintptr_t offset, size_t count) override;
virtual void add(vm_space *space) override;
virtual void remove(vm_space *space) override;
private:
vm_area &m_area;
kutil::vector<vm_space*> m_spaces;
};