Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/arch/x86/paging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <delegate>
#include <util/bitops.hpp>
#include <util/units.hpp>
#include <kernel/memory.hpp>
#include <mem/vmap.hpp>
#include <cstdlib>
#include <expects>

Expand Down
2 changes: 1 addition & 1 deletion api/hal/machine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <memory>

#include <arch.hpp>
#include <util/allocator.hpp>
#include <mem/allocator.hpp>

namespace os {
namespace detail { class Machine; }
Expand Down
2 changes: 1 addition & 1 deletion api/hal/machine_memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// limitations under the License.

#include <os.hpp>
#include <util/alloc_lstack.hpp>
#include <mem/alloc/lstack.hpp>

#ifndef OS_MACHINE_MEMORY_HPP
#define OS_MACHINE_MEMORY_HPP
Expand Down
29 changes: 29 additions & 0 deletions api/mem/alloc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef MEM_ALLOC_HPP
#define MEM_ALLOC_HPP

#include <mem/alloc/buddy.hpp>
#include <mem/allocator.hpp>

namespace os::mem {
static constexpr size_t PAGE_SZ = 4096; // TODO: put elsewhere

using Raw_allocator = buddy::Alloc<false>;

/** Get default allocator for untyped allocations */
Raw_allocator& raw_allocator();

template <typename T>
using Typed_allocator = Allocator<T, Raw_allocator>;

/** Get default std::allocator for typed allocations */
template <typename T>
inline Typed_allocator<T> system_allocator() {
return Typed_allocator<T>(raw_allocator());
}

/** True once the heap is initialized and usable */
bool heap_ready();

} // namespace os::mem

#endif // MEM_ALLOC_HPP
167 changes: 167 additions & 0 deletions api/mem/alloc/arena.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#ifndef MEM_ALLOC_ARENA_HPP
#define MEM_ALLOC_ARENA_HPP

#include "kprint"
#include <cstdint>
#include <cstddef>
#include <list>
#include <algorithm>

namespace os::mem {

struct Region { uintptr_t addr; size_t size; };

class Arena {
public:
static constexpr size_t PAGE_SZ = 4096;

Arena(uintptr_t base, size_t size)
: base_{align_up(base, PAGE_SZ)}, size_{align_down(size, PAGE_SZ)} {
if (size_) free_.push_back({base_, size_});
}

void* allocate(size_t len) noexcept {
return allocate_aligned(PAGE_SZ, len);
}

void* allocate_aligned(size_t alignment, size_t len) noexcept {
alignment = std::max(alignment, PAGE_SZ);
len = align_up(len, PAGE_SZ);

for (auto it = free_.begin(); it != free_.end(); ++it) {
uintptr_t a = align_up(it->addr, alignment);
if (a + len > it->addr + it->size) continue;

// split left
if (a > it->addr) {
Region left{it->addr, a - it->addr};
it->addr = a;
it->size -= left.size;
free_.insert(std::upper_bound(free_.begin(), free_.end(), left, cmp), left);
}

// split right
const uintptr_t end = it->addr + len;
const uintptr_t it_end = it->addr + it->size;
if (end < it_end) {
Region right{end, it_end - end};
it->size = len;
free_.insert(std::upper_bound(free_.begin(), free_.end(), right, cmp), right);
}

void* ret = (void*)it->addr;
free_.erase(it);
return ret;
}
return nullptr;
}

void* allocate_at(void* addr, size_t len) noexcept {
// assumes region is deallocated
kprintf("[arena] allocating at %p, %zu bytes", addr, len);

uintptr_t a = (uintptr_t)addr;
len = align_up(len, PAGE_SZ);
if (a < base_ || a + len > base_ + size_) return nullptr;

for (auto it = free_.begin(); it != free_.end(); ++it) {
const uintptr_t start = it->addr;
const uintptr_t end = start + it->size;
if (a >= start && a + len <= end) {
Region left{start, a - start};
Region right{a + len, end - (a + len)};
free_.erase(it);
if (left.size)
free_.insert(std::upper_bound(free_.begin(), free_.end(), left, cmp), left);
if (right.size)
free_.insert(std::upper_bound(free_.begin(), free_.end(), right, cmp), right);
return addr;
}
}
return nullptr;
}

void deallocate(void* addr, size_t len) noexcept {
if (!addr || !len) return;
Region r{align_down((uintptr_t)addr, PAGE_SZ), align_up(len, PAGE_SZ)};

auto it = std::upper_bound(free_.begin(), free_.end(), r, cmp);
if (it != free_.begin()) {
auto prev = std::prev(it);
if (prev->addr + prev->size == r.addr) {
prev->size += r.size;
maybe_merge_with_next(prev);
return;
}
}
it = free_.insert(it, r);
maybe_merge_with_next(it);
}

bool is_range_free(uintptr_t a, size_t len) const noexcept {
len = align_up(len, PAGE_SZ);
for (auto& r : free_) {
if (a >= r.addr && a + len <= r.addr + r.size) {
return true;
}
if (a + len <= r.addr) {
break; // past it
}
}
return false;
}

size_t bytes_free() const noexcept {
size_t s = 0;
for (auto& r : free_) s += r.size;
return s;
}

size_t bytes_used() const noexcept {
return size_ - bytes_free();
}

uintptr_t allocation_end() const noexcept {
if (free_.empty()) return base_ + size_;
auto last = std::prev(free_.end());
if (last->addr + last->size == base_ + size_) return last->addr;
return base_ + size_;
}

void reset() {
free_.clear();
if (size_) free_.push_back({base_, size_});
}

// alignment helpers
template<typename T>
static constexpr T align_up(T x, size_t a) noexcept {
return (x + a - 1) & ~(T)(a - 1);
}
template<typename T>
static constexpr T align_down(T x, size_t a) noexcept {
return x & ~(T)(a - 1);
}

private:
static inline bool cmp(const Region& a, const Region& b) noexcept {
return a.addr < b.addr;
}

void maybe_merge_with_next(std::list<Region>::iterator it) {
auto nx = std::next(it);
if (nx != free_.end() && it->addr + it->size == nx->addr) {
it->size += nx->size;
free_.erase(nx);
}
}

uintptr_t base_{0};
size_t size_{0};
std::list<Region> free_;
};

} // namespace os::mem

#endif // MEM_ALLOC_ARENA_HPP

2 changes: 2 additions & 0 deletions api/util/alloc_buddy.hpp → api/mem/alloc/buddy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ namespace util {
}

namespace os::mem::buddy {
static constexpr size_t PAGE_SZ = 4096;

using namespace util::literals;
using namespace util::bitops;

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
49 changes: 49 additions & 0 deletions api/mem/flags.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef MEM_FLAGS_HPP
#define MEM_FLAGS_HPP

#include <cstdint>
#include <sys/mman.h>
#include <util/bitops.hpp>

// TODO: separate architecture-specific Access flags from allocation-specific
namespace os::mem {
enum class Access : uint8_t {
none = 0,
read = 1,
write = 2,
execute = 4
};
}

namespace os::mem::alloc {
enum class Sharing : uint64_t {
Anonymous = MAP_ANONYMOUS, // not backed by any file
Shared = MAP_SHARED, // shared with other processes, changes are carried to underlying file
Private = MAP_PRIVATE, // copy-on-write. (note: changes to underlying files post-mapping is unspecified)
FixedOverride = MAP_FIXED, // place mapping at address. underlying [data:data+length) is discarded
FixedFriendly = MAP_FIXED_NOREPLACE // same as fixed, but fails if region was occuppied
};

using Flags = os::mem::alloc::Sharing; // FIXME: ::Sharing should be its own type for exclusivity
using Protection = os::mem::Access; // HACK: works since we're assuming x86
} // os::mem

namespace util {
inline namespace bitops {
template<>
struct enable_bitmask_ops<os::mem::Access> {
using type = typename std::underlying_type<os::mem::Access>::type;
static constexpr bool enable = true;
};
}

inline namespace bitops {
template<>
struct enable_bitmask_ops<os::mem::alloc::Sharing> {
using type = typename std::underlying_type<os::mem::alloc::Sharing>::type;
static constexpr bool enable = true;
};
}
}

#endif // MEM_FLAGS_HPP
6 changes: 3 additions & 3 deletions api/kernel/memmap.hpp → api/mem/memmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
// limitations under the License.

#pragma once
#ifndef KERNEL_MEMMAP_HPP
#define KERNEL_MEMMAP_HPP
#ifndef MEM_MEMMAP_HPP
#define MEM_MEMMAP_HPP

#include <cassert>
#include <delegate>
Expand Down Expand Up @@ -466,4 +466,4 @@ class Memory_map {
}; //< class Memory_map

} // ns os::mem
#endif //< KERNEL_MEMMAP_HPP
#endif //< MEM_MEMMAP_HPP
Loading