Overhaul memory allocation model

This commit makes several fundamental changes to memory handling:

- the frame allocator is now only an allocator for free frames, and does
  not track used frames.
- the frame allocator now stores its free list inside the free frames
  themselves, as a hybrid stack/span model.
  - This has the implication that all frames must currently fit within
    the offset area.
- kutil has a new allocator interface, which is the only allowed way for
  any code outside of src/kernel to allocate. Code under src/kernel
  _may_ use new/delete, but should prefer the allocator interface.
- the heap manager has become heap_allocator, which is merely an
  implementation of kutil::allocator which doles out sections of a given
  address range.
- the heap manager now only writes block headers when necessary,
  avoiding page faults until they're actually needed
- page_manager now has a page fault handler, which checks with the
  address_manager to see if the address is known, and provides a frame
  mapping if it is, allowing heap manager to work with its entire
  address size from the start. (Currently 32GiB.)
This commit is contained in:
Justin C. Miller
2019-04-16 01:13:09 -07:00
parent fd1adc0262
commit 6302e8b73a
33 changed files with 782 additions and 1010 deletions

View File

@@ -0,0 +1,70 @@
#pragma once
/// \file frame_allocator.h
/// Allocator for physical memory frames
#include <stdint.h>
#include "kutil/allocator.h"
#include "kutil/linked_list.h"
struct frame_block;
using frame_block_list = kutil::linked_list<frame_block>;
/// Allocator for physical memory frames
class frame_allocator
{
public:
/// Default constructor
frame_allocator();
/// Get free frames from the free list. Only frames from the first free block
/// are returned, so the number may be less than requested, but they will
/// be contiguous.
/// \arg count The maximum number of frames to get
/// \arg address [out] The physical address of the first frame
/// \returns The number of frames retrieved
size_t allocate(size_t count, uintptr_t *address);
/// Free previously allocated frames.
/// \arg address The physical address of the first frame to free
/// \arg count The number of frames to be freed
void free(uintptr_t address, size_t count);
/// Get a memory allocator that allocates raw pages
/// \returns The allocator ojbect
kutil::allocator & raw_allocator() { return m_raw_alloc; }
private:
class raw_alloc :
public kutil::allocator
{
public:
raw_alloc(frame_allocator &fa);
virtual void * allocate(size_t size) override;
virtual void free(void *p) override;
private:
frame_allocator &m_fa;
};
raw_alloc m_raw_alloc;
frame_block_list m_free; ///< Free frames list
frame_allocator(const frame_allocator &) = delete;
};
/// A block of contiguous frames. Each `frame_block` represents contiguous
/// physical frames with the same attributes.
struct frame_block
{
uintptr_t address;
uint32_t count;
/// Compare two blocks by address.
/// \arg rhs The right-hand comparator
/// \returns <0 if this is sorts earlier, >0 if this sorts later, 0 for equal
int compare(const frame_block *rhs) const;
};
extern frame_allocator g_frame_allocator;