#include "serial.hpp"
#include "interrupts.hpp"
-void remove_some_mem(os::phys_ptr<os::paging::page> mem_start,
- os::phys_ptr<os::paging::page> mem_end,
- os::phys_ptr<os::paging::page> remove_start,
- os::phys_ptr<os::paging::page> remove_end,
- std::invocable<os::phys_ptr<os::paging::page>, os::phys_ptr<os::paging::page>> auto callback
- ) {
- if (remove_start <= mem_start && mem_start < remove_end && remove_end < mem_end) {
- // Removes start:
- callback(remove_end, mem_end);
- } else if (mem_start < remove_start && remove_start < mem_end && mem_end <= remove_end) {
- // Removes end:
- callback(mem_start, remove_start);
- } else if (remove_start <= mem_start && mem_end <= remove_end) {
- // Removes all:
- } else if (mem_start < remove_start && remove_end < mem_end) {
- // Removes middle:
- callback(mem_start, remove_start);
- callback(remove_end, mem_end);
- } else {
- // Remove nothing:
- callback(mem_start, mem_end);
- }
-}
-
os::idt<32> idt;
extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
os::assert(os::cpu_has_msr(), "MSRs aren't supported.");
if (!os::init_serial_port()) {
- os::hlt();
+ while (true) {
+ os::hlt();
+ }
}
- const os::phys_ptr<os::paging::page> kernel_start = ([]() {
- os::phys_ptr<os::paging::page> ptr = nullptr;
- asm("mov $_kernel_phys_start,%0" : "=ri"(ptr));
- return ptr;
- })();
- const os::phys_ptr<os::paging::page> kernel_end = ([]() {
- os::phys_ptr<os::paging::page> ptr = nullptr;
- asm("mov $_kernel_phys_end,%0" : "=ri"(ptr));
- return ptr;
- })();
- const os::phys_ptr<os::paging::page> info_start{info.get_phys_addr() / 0x1000 * 0x1000}; // Round start down.
- const os::phys_ptr<os::paging::page> info_end{(info.get_phys_addr() + info->total_size + 0x1000 - 1) / 0x1000 * 0x1000}; // Round end up.
- bool info_pages_wholly_usable = false;
+ {
+ struct {
+ os::phys_ptr<os::paging::page> start_address = nullptr;
+ os::phys_ptr<os::paging::page> end_address = nullptr;
+ } available_ram[50];
+ std::size_t available_ram_length = 0;
- for (auto it = multiboot2::next(info); it->type != multiboot2::info::type_t::end; it = multiboot2::next(it)) {
- switch (it->type) {
- case multiboot2::info::type_t::memory_map:
- for (std::size_t i = 0; i < multiboot2::memory_map_number_of_entries(it); i++) {
- if (multiboot2::memory_map_type(it, i) == 1) {
- const os::phys_ptr<os::paging::page> s{(multiboot2::memory_map_base_addr(it, i) + 0x1000 - 1) / 0x1000 * 0x1000};
- const os::phys_ptr<os::paging::page> e{(multiboot2::memory_map_base_addr(it, i) + multiboot2::memory_map_length(it, i)) / 0x1000 * 0x1000};
- if (s < e) {
- remove_some_mem(
- s, e, kernel_start, kernel_end,
- [info_start, info_end] (auto s, auto e) {
- remove_some_mem(
- s, e, info_start, info_end,
- [] (auto s, auto e) {
- os::paging::page_allocator.deallocate({.ptr = s, .size = std::uint64_t(e - s)});
- }
- );
+ for (auto it = multiboot2::next(info); it->type != multiboot2::info::type_t::end; it = multiboot2::next(it)) {
+ switch (it->type) {
+ case multiboot2::info::type_t::memory_map:
+ for (std::size_t i = 0; i < multiboot2::memory_map_number_of_entries(it); i++) {
+ if (multiboot2::memory_map_type(it, i) == 1) {
+ // Rounded up, to avoid including non-ram.
+ const os::phys_ptr<os::paging::page>
+ s{(multiboot2::memory_map_base_addr(it, i) + 0x1000 - 1) / 0x1000 * 0x1000};
+ // Rounded down, to avoid including non-ram.
+ const os::phys_ptr<os::paging::page>
+ e{(multiboot2::memory_map_base_addr(it, i) + multiboot2::memory_map_length(it, i)) / 0x1000 * 0x1000 - 0x1000};
+ if (s <= e) { // In the case where no full page is included in the ram section, don't add it.
+ os::assert(available_ram_length < 50, "Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
+ available_ram[available_ram_length++] = {.start_address = s, .end_address = e};
}
- );
}
- bool info_usable = true;
- remove_some_mem(info_start, info_end, s, e, [&info_usable](auto, auto) {
- info_usable = false;
- });
- info_pages_wholly_usable = info_pages_wholly_usable || info_usable;
- // info_pages_wholly_usable will only be false if no usable RAM section covers all the multiboot info struct.
- // This allows me to make sure that I don't use any unusable RAM, in the very improbable case where the
- // multiboot info struct is in a partially usable memory page.
}
+ break;
+ default: break;
}
- break;
- default: break;
}
- }
- // Deallocate multiboot info structure: not usable anymore.
- if (info_pages_wholly_usable) {
- os::paging::page_allocator.deallocate({.ptr = info_start, .size = std::uint64_t(info_end - info_start)});
- } else if (info_start + 1 < info_end - 1) {
- // Ignore the first and last blocks: ensures all the RAM is truly usable.
- os::paging::page_allocator.deallocate({.ptr = info_start + 1, .size = std::uint64_t(info_end - info_start - 2)});
+ // kernel_start and kernel_end are aligned to 4K by the linker script.
+ const os::phys_ptr<os::paging::page> s = ([]() {
+ os::phys_ptr<os::paging::page> ptr = nullptr;
+ asm("mov $_kernel_phys_start,%0" : "=ri"(ptr));
+ return ptr;
+ })();
+ const os::phys_ptr<os::paging::page> e = ([]() {
+ os::phys_ptr<os::paging::page> ptr = nullptr;
+ asm("mov $_kernel_phys_end,%0" : "=ri"(ptr));
+ return ptr - 1; // [s, e], not [s, e[
+ })();
+
+ // Remove kernel from available RAM:
+ for (std::size_t i = 0; i < available_ram_length; i++) {
+ if (e < available_ram[i].start_address || available_ram[i].end_address < s) {
+ continue;
+ }
+ if (s <= available_ram[i].start_address && available_ram[i].end_address <= e) {
+ available_ram[i] = available_ram[--available_ram_length];
+ } else if (s <= available_ram[i].start_address) {
+ available_ram[i].start_address = e + 1; // Since e < end_address, new start_address <= end_address.
+ } else if (available_ram[i].end_address <= e) {
+ available_ram[i].end_address = s - 1; // Since start_address < s, start_address <= new end_address.
+ } else {
+ os::assert(available_ram_length < 50, "Too much available RAM sections to initialise correctly. Will fix eventually, probably.");
+ available_ram[available_ram_length] = available_ram[i];
+ available_ram[i].end_address = s - 1;
+ available_ram[available_ram_length].start_address = e + 1;
+ available_ram_length++;
+ }
+ }
+
+ // Add available RAM to the page allocator (warning: overrides the multiboot info structure):
+ for (std::size_t i = 0; i < available_ram_length; i++) {
+ os::paging::page_allocator.deallocate({
+ .ptr = available_ram[i].start_address,
+ .size = std::size_t(available_ram[i].end_address - available_ram[i].start_address + 1)
+ });
+ }
}
os::print("RAM:\n");