[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

98
src/kernel/vm_mapper.cpp Normal file
View File

@@ -0,0 +1,98 @@
#include "objects/vm_area.h"
#include "vm_mapper.h"
#include "vm_space.h"
vm_mapper_single::vm_mapper_single(vm_area &area, vm_space &space) :
m_area(area), m_space(space)
{}
vm_mapper_single::~vm_mapper_single()
{
m_space.clear(m_area, 0, memory::page_count(m_area.size()), true);
}
bool
vm_mapper_single::can_resize(size_t size) const
{
return m_space.can_resize(m_area, size);
}
void
vm_mapper_single::map(uintptr_t offset, size_t count, uintptr_t phys)
{
m_space.page_in(m_area, offset, phys, count);
}
void
vm_mapper_single::unmap(uintptr_t offset, size_t count)
{
m_space.clear(m_area, offset, count, true);
}
vm_mapper_multi::vm_mapper_multi(vm_area &area) :
m_area(area)
{
}
vm_mapper_multi::~vm_mapper_multi()
{
if (!m_spaces.count())
return;
size_t count = memory::page_count(m_area.size());
for (int i = 1; i < m_spaces.count(); ++i)
m_spaces[i]->clear(m_area, 0, count);
m_spaces[0]->clear(m_area, 0, count, true);
}
bool
vm_mapper_multi::can_resize(size_t size) const
{
for (auto &it : m_spaces)
if (!it->can_resize(m_area, size))
return false;
return true;
}
void
vm_mapper_multi::map(uintptr_t offset, size_t count, uintptr_t phys)
{
for (auto &it : m_spaces)
it->page_in(m_area, offset, phys, count);
}
void
vm_mapper_multi::unmap(uintptr_t offset, size_t count)
{
for (auto &it : m_spaces)
it->clear(m_area, offset, count);
}
void
vm_mapper_multi::add(vm_space *space)
{
if (m_spaces.count()) {
vm_space *source = m_spaces[0];
space->copy_from(*source, m_area);
}
m_spaces.append(space);
}
void
vm_mapper_multi::remove(vm_space *space)
{
size_t count = memory::page_count(m_area.size());
for (int i = 0; i < m_spaces.count(); ++i) {
if (m_spaces[i] == space) {
m_spaces.remove_swap_at(i);
space->clear(m_area, 0, count, m_spaces.count() == 0);
}
}
}