os::halt();
}
- uintptr_t ram_ptr;
- asm("mov $test_ram - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
- os::paging::page_allocator page_allocator(ram_ptr);
+
+ os::paging::page_allocator page_allocator{([]() {
+ os::phys_ptr<os::paging::page> ram_ptr = nullptr;
+ asm("mov $page_list_one_past_end - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
+ return ram_ptr;
+ })()};
+ {
+ os::phys_ptr<os::paging::page> ram_ptr = nullptr;
+ asm("mov $test_ram - 0xFFFFFFFF80000000,%0" : "=ri"(ram_ptr));
+ page_allocator.deallocate({.ptr = ram_ptr, .size = 256});
+ }
+
+ page_allocator.print_all();
+ {
+ os::println("Alloc #1.");
+ auto mem1 = page_allocator.allocate(0x10);
+ page_allocator.print_all();
+ os::println("Alloc #2.");
+ auto mem2 = page_allocator.allocate(0x20);
+ page_allocator.print_all();
+ os::println("Dealloc #1.");
+ page_allocator.deallocate(mem1);
+ page_allocator.print_all();
+ os::println("Dealloc #2.");
+ page_allocator.deallocate(mem2);
+ page_allocator.print_all();
+ }
os::framebuffer framebuffer;
multiboot2::color_info(it)
);
break;
+ case multiboot2::info::type_t::memory_map:
+ os::println("Memory map.");
+ break;
default: break;
}
}
- for (size_t x = 0; x < framebuffer.get_width(); x++) {
- for (size_t y = 0; y < framebuffer.get_height(); y++) {
+ for (std::size_t x = 0; x < framebuffer.get_width(); x++) {
+ for (std::size_t y = 0; y < framebuffer.get_height(); y++) {
framebuffer.putpixel(x, y, {
- .r = uint8_t(x * 256 / framebuffer.get_width()),
+ .r = std::uint8_t(x * 256 / framebuffer.get_width()),
.g = 0,
- .b = uint8_t(y * 256 / framebuffer.get_height()),
+ .b = std::uint8_t(y * 256 / framebuffer.get_height()),
});
}
}
#include "paging.hpp"
-os::paging::page_allocator::page_allocator(os::phys_ptr<paging::page> head): head(head.get_phys_addr()) {
- phys_ptr<page> prev{nullptr};
- for (auto it = this->head; it != nullptr; prev = it, it = it->next_streak) {
- if (prev >= it) {
- os::println("Error: unordered memory given to the page allocator.");
- break;
- }
- while (it.get_phys_addr() + it->streak_size * 0x1000 == it->next_streak.get_phys_addr()) {
- it->streak_size += it->next_streak->streak_size;
- it->next_streak = it->next_streak->next_streak;
- }
- }
+os::paging::page_allocator::page_allocator(phys_ptr<paging::page> one_past_end): begin_(one_past_end.get_phys_addr()), end_(begin_) {
+ end_->prev = nullptr;
+ end_->next = nullptr;
+ end_->size = 1;
}
void os::paging::page_allocator::print_all() const {
- if (head == nullptr) {
+ if (is_empty()) {
os::println("No RAM left.");
- } else for (auto it = head; it != nullptr; it = it->next_streak) {
+ } else for (auto it = begin(); it != end(); it = it->next) {
os::print("addr:size = 0x");
os::print(it.get_phys_addr());
os::print(":0x");
- os::print(it->streak_size);
+ os::print(it->size);
os::printc('\n');
}
}
-os::paging::page_allocator::block os::paging::page_allocator::allocate(uint64_t count) {
- phys_ptr<page> prev{nullptr};
- for (auto it = head; it != nullptr; prev = it, it = it->next_streak) {
- if (it->streak_size == count) {
- if (prev == nullptr) {
- head = it->next_streak;
- } else {
- prev->next_streak = it->next_streak;
- }
+// void os::paging::page_allocator::mark_as_used(block b);
+os::paging::page_allocator::block os::paging::page_allocator::allocate(std::uint64_t count) {
+ for (auto it = begin(); it != end(); it = it->next) {
+ if (count == it->size) {
+ erase(it);
return {
- .ptr = it.get_phys_addr(),
+ .ptr = phys_ptr<paging::page>(it.get_phys_addr()),
.size = count,
};
- }
- if (it->streak_size > count) {
- if (prev == nullptr) {
- head = it.get_phys_addr() + count * 0x1000;
- head->streak_size = it->streak_size - count;
- head->next_streak = it->next_streak;
- } else {
- prev->next_streak = it.get_phys_addr() + count * 0x1000;
- prev->next_streak->streak_size = it->streak_size - count;
- head->next_streak->next_streak = it->next_streak;
- }
+ } else if (count < it->size) {
+ erase(split_at_offset(it, count));
return {
- .ptr = it.get_phys_addr(),
+ .ptr = phys_ptr<paging::page>(it.get_phys_addr()),
.size = count,
};
}
}
- return {.ptr = nullptr, .size = 0};
+ return { .ptr = nullptr, .size = 0 };
}
-
void os::paging::page_allocator::deallocate(block b) {
- const phys_ptr<page> ptr = b.ptr.get_phys_addr();
- const uint64_t size = b.size;
-
+ const phys_ptr<page> b_it{b.ptr.get_phys_addr()};
+ auto it = begin();
+ while (it != end() && it < b_it) { it = it->next; }
+ try_merge_next(try_merge_prev(insert(it, b)));
+}
+
+bool os::paging::page_allocator::is_empty() const { return begin() == end(); }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::begin() { return begin_; }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::end() { return end_; }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::begin() const { return begin_; }
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::end() const { return end_; }
- phys_ptr<page> before{nullptr};
- phys_ptr<page> after = head;
- while (after != nullptr && after < ptr) {
- before = after;
- after = after->next_streak;
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::insert(phys_ptr<page> it, block b) {
+ const phys_ptr<page> b_it{b.ptr.get_phys_addr()};
+ if (it->prev == nullptr) {
+ begin_ = b_it;
+ } else {
+ it->prev->next = b_it;
}
- if (before != nullptr && before.get_phys_addr() + 0x1000 * before->streak_size == ptr) {
- // Should merge with previous.
- if (after != nullptr && ptr.get_phys_addr() + 0x1000 * size == after) {
- // Should merge with next.
- before->streak_size += size + after->streak_size;
- before->next_streak = after->next_streak;
- } else {
- // Shouldn't merge with next.
- before->streak_size += size;
- }
+ b_it->prev = it->prev;
+ b_it->next = it;
+ it->prev = b_it;
+ b_it->size = b.size;
+ return b_it;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::try_merge_prev(phys_ptr<page> it) {
+ os::assert(it != end(), "end() passed to page_allocator::try_merge_prev(phys_ptr<page>).");
+ if (it->prev == nullptr) { return it; }
+ if (it->prev + it->prev->size != it) { return it; }
+ it->prev->size += it->size;
+ return erase(it)->prev;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::try_merge_next(phys_ptr<page> it) {
+ os::assert(it != end(), "end() passed to page_allocator::try_merge_next(phys_ptr<page>).");
+ if (it->next == end()) return it;
+ try_merge_prev(it->next);
+ return it;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::erase(phys_ptr<page> it) {
+ os::assert(it != end(), "end() passed to page_allocator::remove(phys_ptr<page>).");
+ if (it->prev == nullptr) {
+ begin_ = it->next;
} else {
- // Shouldn't merge with previous.
- if (after != nullptr && ptr.get_phys_addr() + 0x1000 * size == after) {
- // Should merge with next.
- if (before != nullptr) {
- before->next_streak = before->next_streak.get_phys_addr() - 0x1000 * size;
- before->next_streak->next_streak = after->next_streak;
- before->next_streak->streak_size = after->streak_size + size;
- } else {
- head = head.get_phys_addr() - 0x1000 * size;
- head->next_streak = after->next_streak;
- head->streak_size = after->streak_size + size;
- }
- } else {
- // Shouldn't merge with next.
- if (before != nullptr) {
- before->next_streak = ptr;
- ptr->next_streak = after;
- ptr->streak_size = size;
- } else {
- head = ptr;
- ptr->next_streak = after;
- ptr->streak_size = size;
- }
- }
+ it->prev->next = it->next;
}
+ it->next->prev = it->prev;
+ return it->next;
+}
+os::phys_ptr<os::paging::page_allocator::page> os::paging::page_allocator::split_at_offset(phys_ptr<page> it, std::size_t offset) {
+ os::assert(it != end(), "end() passed to page_allocator::split_at_offset(phys_ptr<page>, std::size_t).");
+ os::assert(offset < it->size, "offset passed to page_allocator::split_at_offset(phys_ptr<page>, std::size_t) was too big.");
+ os::assert(offset != 0, "offset 0 passed to page_allocator::split_at_offset(phys_ptr<page>, std::size_t).");
+ phys_ptr<page> after_split = it + offset;
+ insert(it->next, block{ .ptr = phys_ptr<paging::page>{after_split.get_phys_addr()}, .size = it->size - offset });
+ it->size = offset;
+ return it;
}
#pragma once
-#include <stdint.h>
+#include <cstdint>
#include "serial.hpp"
#include "utils.hpp"
inline void PK(unsigned v) {
os::assert(is_page(), "Error: write to protection key of non-page.");
os::assert((v & 0xF) == v, "Error: incorrect protection key.");
- data = (data & ~(0xFul << 59)) | (uint64_t(v) << 59);
+ data = (data & ~(0xFul << 59)) | (std::uint64_t(v) << 59);
}
inline unsigned AVL_high() {
return (data >> 52) & (is_page() ? 0x7F : 0x7FF);
}
inline void AVL_high(unsigned v) {
os::assert((v & (is_page() ? 0x7F : 0x7FF)) == v, "Error: incorrect AVL high bits.");
- data = (data & ~((is_page() ? 0x7Ful : 0x7FFul) << 52)) | (uint64_t(v) << 52);
+ data = (data & ~((is_page() ? 0x7Ful : 0x7FFul) << 52)) | (std::uint64_t(v) << 52);
}
inline phys_ptr<paging_table<order - 1>> base_address() {
return {data & 0x000FFFFFFFFFF000 & ~(order != 0 && is_page() ? 1ul << 12 : 0ul)};
}
inline void base_address(phys_ptr<paging_table<order - 1>> v) {
- const uint64_t v_int = v.get_phys_addr();
+ const std::uint64_t v_int = v.get_phys_addr();
os::assert((v_int & 0x000FFFFFFFFFF000 & (0xFFFFFFFFFFFFF000 << (is_page() ? 9 * order : 0))) == v_int, "Error: incorrect base address.");
data = (data & ~0x000FFFFFFFFFF000ul & ~(order != 0 && is_page() ? 1ul << 12 : 0ul)) | v_int;
}
}
private:
- uint64_t data;
+ std::uint64_t data;
};
template <int order>
template<>
struct paging_table<-1> {
- uint8_t contents[0x1000];
+ std::uint8_t contents[0x1000];
};
using PML4T = paging_table<3>;
public:
struct block {
phys_ptr<paging::page> ptr = nullptr;
- uint64_t size;
+ std::uint64_t size;
};
- page_allocator(phys_ptr<paging::page> head);
+ page_allocator(phys_ptr<paging::page> one_past_end_page);
void print_all() const;
- block allocate(uint64_t page_count);
+ void mark_as_used(block b);
+ block allocate(std::uint64_t page_count);
void deallocate(block b);
private:
struct __attribute__((aligned(0x1000))) page {
- uint64_t streak_size;
- phys_ptr<page> next_streak;
- char padding[0x1000 - 8 - 8];
+ phys_ptr<page> prev;
+ phys_ptr<page> next;
+ std::uint64_t size;
+ char padding[0x1000 - 8 * 3];
};
static_assert(sizeof(page) == 0x1000);
static_assert(alignof(page) == 0x1000);
- phys_ptr<page> head;
+ phys_ptr<page> begin_;
+ phys_ptr<page> end_;
+
+ phys_ptr<page> begin();
+ phys_ptr<page> end();
+ phys_ptr<page> begin() const;
+ phys_ptr<page> end() const;
+ bool is_empty() const;
+ phys_ptr<page> insert(phys_ptr<page> it, block b);
+ phys_ptr<page> try_merge_prev(phys_ptr<page> it);
+ phys_ptr<page> try_merge_next(phys_ptr<page> it);
+ phys_ptr<page> erase(phys_ptr<page> it);
+ phys_ptr<page> split_at_offset(phys_ptr<page> it, std::size_t offset);
};
}} // os::paging