Compare commits
7 Commits
9f5fb547f7
...
985d45ddfb
Author | SHA1 | Date | |
---|---|---|---|
985d45ddfb | |||
d2856d8812 | |||
29dad5651d | |||
1d51935d43 | |||
fc0779a2f9 | |||
fe47e0d5cb | |||
f8ed74fda5 |
@ -1,4 +1,5 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "arch/CPU.h"
|
||||||
#include "arch/Serial.h"
|
#include "arch/Serial.h"
|
||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
#include "video/TextConsole.h"
|
#include "video/TextConsole.h"
|
||||||
@ -113,3 +114,15 @@ bool log_text_console_enabled()
|
|||||||
{
|
{
|
||||||
return g_text_console_enabled;
|
return g_text_console_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool g_check_already_failed = false;
|
||||||
|
|
||||||
|
_noreturn bool __check_failed(const char* file, const char* line, const char* func, const char* expr)
|
||||||
|
{
|
||||||
|
if (!g_check_already_failed)
|
||||||
|
{ // Avoid endlessly failing when trying to report a failed check.
|
||||||
|
g_check_already_failed = true;
|
||||||
|
kerrorln("ERROR: Check failed at %s:%s, in %s: %s", file, line, func, expr);
|
||||||
|
}
|
||||||
|
CPU::efficient_halt();
|
||||||
|
}
|
@ -35,15 +35,3 @@ namespace Serial
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool g_check_already_failed = false;
|
|
||||||
|
|
||||||
_noreturn bool __check_failed(const char* file, const char* line, const char* func, const char* expr)
|
|
||||||
{
|
|
||||||
if (!g_check_already_failed)
|
|
||||||
{ // Avoid endlessly failing when trying to report a failed check.
|
|
||||||
g_check_already_failed = true;
|
|
||||||
Serial::printf("ERROR: Check failed at %s:%s, in %s: %s\n", file, line, func, expr);
|
|
||||||
}
|
|
||||||
CPU::efficient_halt();
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
|
#include "Log.h"
|
||||||
#include "arch/Serial.h"
|
#include "arch/Serial.h"
|
||||||
#include "boot/bootboot.h"
|
#include "boot/bootboot.h"
|
||||||
#include <Result.h>
|
#include <Result.h>
|
||||||
@ -46,8 +47,7 @@ static u64 bootloader_time_to_unix(u8 boottime[8])
|
|||||||
int second = bcd_number_to_decimal(boottime[6]);
|
int second = bcd_number_to_decimal(boottime[6]);
|
||||||
// "The last byte can store 1/100th second precision, but in lack of support on most platforms, it is 0x00".
|
// "The last byte can store 1/100th second precision, but in lack of support on most platforms, it is 0x00".
|
||||||
// Therefore, let's not rely on it.
|
// Therefore, let's not rely on it.
|
||||||
Serial::printf("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC\n", day, month, year, hour, minute, second)
|
kinfoln("Current time: %.2d/%.2d/%d %.2d:%.2d:%.2d UTC", day, month, year, hour, minute, second).release_value();
|
||||||
.release_value();
|
|
||||||
return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second);
|
return broken_down_to_unix(year - 1900, make_yday(year, month) + (day - 1), hour, minute, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "arch/x86_64/CPU.h"
|
#include "arch/x86_64/CPU.h"
|
||||||
|
#include "Log.h"
|
||||||
#include "arch/Serial.h"
|
#include "arch/Serial.h"
|
||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
#include "arch/x86_64/IO.h"
|
#include "arch/x86_64/IO.h"
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
#include <SystemError.h>
|
||||||
#include <Types.h>
|
#include <Types.h>
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
|
|
||||||
@ -274,7 +276,7 @@ static void setup_idt()
|
|||||||
// Interrupt handling
|
// Interrupt handling
|
||||||
|
|
||||||
#define FIXME_UNHANDLED_INTERRUPT(name) \
|
#define FIXME_UNHANDLED_INTERRUPT(name) \
|
||||||
Serial::println("FIXME(interrupt): " name); \
|
kerrorln("FIXME(interrupt): %s", name); \
|
||||||
CPU::efficient_halt();
|
CPU::efficient_halt();
|
||||||
|
|
||||||
extern "C" void handle_x86_exception([[maybe_unused]] Registers* regs)
|
extern "C" void handle_x86_exception([[maybe_unused]] Registers* regs)
|
||||||
@ -314,20 +316,20 @@ extern "C" void arch_interrupt_entry(Registers* regs)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial::println("IRQ catched! Halting.");
|
kwarnln("IRQ catched! Halting.");
|
||||||
CPU::efficient_halt();
|
CPU::efficient_halt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" [[noreturn]] void arch_double_fault()
|
extern "C" [[noreturn]] void arch_double_fault()
|
||||||
{
|
{
|
||||||
Serial::println("ERROR: Catched double fault");
|
kerrorln("ERROR: Catched double fault");
|
||||||
CPU::efficient_halt();
|
CPU::efficient_halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" [[noreturn]] void arch_machine_check()
|
extern "C" [[noreturn]] void arch_machine_check()
|
||||||
{
|
{
|
||||||
Serial::println("ERROR: Machine check failed");
|
kerrorln("ERROR: Machine check failed");
|
||||||
CPU::efficient_halt();
|
CPU::efficient_halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,11 +349,11 @@ namespace CPU
|
|||||||
static char brand_string[49];
|
static char brand_string[49];
|
||||||
|
|
||||||
u32 buf[4];
|
u32 buf[4];
|
||||||
if (!__get_cpuid(0x80000002, &buf[0], &buf[1], &buf[2], &buf[3])) return err;
|
if (!__get_cpuid(0x80000002, &buf[0], &buf[1], &buf[2], &buf[3])) return err(ENOTSUP);
|
||||||
memcpy(brand_string, buf, 16);
|
memcpy(brand_string, buf, 16);
|
||||||
if (!__get_cpuid(0x80000003, &buf[0], &buf[1], &buf[2], &buf[3])) return err;
|
if (!__get_cpuid(0x80000003, &buf[0], &buf[1], &buf[2], &buf[3])) return err(ENOTSUP);
|
||||||
memcpy(&brand_string[16], buf, 16);
|
memcpy(&brand_string[16], buf, 16);
|
||||||
if (!__get_cpuid(0x80000004, &buf[0], &buf[1], &buf[2], &buf[3])) return err;
|
if (!__get_cpuid(0x80000004, &buf[0], &buf[1], &buf[2], &buf[3])) return err(ENOTSUP);
|
||||||
memcpy(&brand_string[32], buf, 16);
|
memcpy(&brand_string[32], buf, 16);
|
||||||
|
|
||||||
brand_string[48] = 0; // null-terminate it :)
|
brand_string[48] = 0; // null-terminate it :)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
#include <SystemError.h>
|
||||||
|
|
||||||
#define PAGE_SIZE 4096
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
@ -161,12 +162,12 @@ namespace MMU
|
|||||||
Result<PageTableEntry*> find_entry(u64 virt)
|
Result<PageTableEntry*> find_entry(u64 virt)
|
||||||
{
|
{
|
||||||
auto& l4 = l4_entry(virt);
|
auto& l4 = l4_entry(virt);
|
||||||
if (!l4.present) return err;
|
if (!l4.present) return err(EFAULT);
|
||||||
auto& l3 = l3_entry(virt);
|
auto& l3 = l3_entry(virt);
|
||||||
if (!l3.present) return err;
|
if (!l3.present) return err(EFAULT);
|
||||||
if (l3.larger_pages) return &l3;
|
if (l3.larger_pages) return &l3;
|
||||||
auto& l2 = l2_entry(virt);
|
auto& l2 = l2_entry(virt);
|
||||||
if (!l2.present) return err;
|
if (!l2.present) return err(EFAULT);
|
||||||
if (l2.larger_pages) return &l2;
|
if (l2.larger_pages) return &l2;
|
||||||
return &l1_entry(virt);
|
return &l1_entry(virt);
|
||||||
}
|
}
|
||||||
@ -174,16 +175,16 @@ namespace MMU
|
|||||||
Result<PageTableEntry*> apply_cascading_flags(u64 virt, int flags)
|
Result<PageTableEntry*> apply_cascading_flags(u64 virt, int flags)
|
||||||
{
|
{
|
||||||
auto& l4 = l4_entry(virt);
|
auto& l4 = l4_entry(virt);
|
||||||
if (!l4.present) return err;
|
if (!l4.present) return err(EFAULT);
|
||||||
if (flags & Flags::ReadWrite) l4.read_write = true;
|
if (flags & Flags::ReadWrite) l4.read_write = true;
|
||||||
if (flags & Flags::User) l4.user = true;
|
if (flags & Flags::User) l4.user = true;
|
||||||
auto& l3 = l3_entry(virt);
|
auto& l3 = l3_entry(virt);
|
||||||
if (!l3.present) return err;
|
if (!l3.present) return err(EFAULT);
|
||||||
if (l3.larger_pages) return &l3;
|
if (l3.larger_pages) return &l3;
|
||||||
if (flags & Flags::ReadWrite) l3.read_write = true;
|
if (flags & Flags::ReadWrite) l3.read_write = true;
|
||||||
if (flags & Flags::User) l3.user = true;
|
if (flags & Flags::User) l3.user = true;
|
||||||
auto& l2 = l2_entry(virt);
|
auto& l2 = l2_entry(virt);
|
||||||
if (!l2.present) return err;
|
if (!l2.present) return err(EFAULT);
|
||||||
if (l2.larger_pages) return &l2;
|
if (l2.larger_pages) return &l2;
|
||||||
if (flags & Flags::ReadWrite) l2.read_write = true;
|
if (flags & Flags::ReadWrite) l2.read_write = true;
|
||||||
if (flags & Flags::User) l2.user = true;
|
if (flags & Flags::User) l2.user = true;
|
||||||
@ -217,7 +218,7 @@ namespace MMU
|
|||||||
if (flags & Flags::ReadWrite) l3.read_write = true;
|
if (flags & Flags::ReadWrite) l3.read_write = true;
|
||||||
if (flags & Flags::User) l3.user = true;
|
if (flags & Flags::User) l3.user = true;
|
||||||
|
|
||||||
if (l3.larger_pages) return err; // FIXME: Replacing larger pages is not supported ATM
|
if (l3.larger_pages) return err(EFIXME); // FIXME: Replacing larger pages is not supported ATM
|
||||||
|
|
||||||
auto& l2 = l2_entry(virt);
|
auto& l2 = l2_entry(virt);
|
||||||
if (!l2.present)
|
if (!l2.present)
|
||||||
@ -231,10 +232,10 @@ namespace MMU
|
|||||||
if (flags & Flags::ReadWrite) l2.read_write = true;
|
if (flags & Flags::ReadWrite) l2.read_write = true;
|
||||||
if (flags & Flags::User) l2.user = true;
|
if (flags & Flags::User) l2.user = true;
|
||||||
|
|
||||||
if (l2.larger_pages) return err; // FIXME: Replacing larger pages is not supported ATM
|
if (l2.larger_pages) return err(EFIXME); // FIXME: Replacing larger pages is not supported ATM
|
||||||
|
|
||||||
auto& l1 = l1_entry(virt);
|
auto& l1 = l1_entry(virt);
|
||||||
if (l1.present) return err; // Please explicitly unmap the page before mapping it again.
|
if (l1.present) return err(EEXIST); // Please explicitly unmap the page before mapping it again.
|
||||||
l1.ignore0 = l1.ignore1 = false;
|
l1.ignore0 = l1.ignore1 = false;
|
||||||
l1.present = true;
|
l1.present = true;
|
||||||
l1.read_write = (flags & Flags::ReadWrite);
|
l1.read_write = (flags & Flags::ReadWrite);
|
||||||
@ -249,7 +250,7 @@ namespace MMU
|
|||||||
Result<void> remap(u64 virt, int flags)
|
Result<void> remap(u64 virt, int flags)
|
||||||
{
|
{
|
||||||
auto& l1 = *TRY(apply_cascading_flags(virt, flags));
|
auto& l1 = *TRY(apply_cascading_flags(virt, flags));
|
||||||
if (!l1.present) return err;
|
if (!l1.present) return err(EFAULT);
|
||||||
l1.read_write = (flags & Flags::ReadWrite);
|
l1.read_write = (flags & Flags::ReadWrite);
|
||||||
l1.user = (flags & Flags::User);
|
l1.user = (flags & Flags::User);
|
||||||
l1.write_through = (flags & Flags::WriteThrough);
|
l1.write_through = (flags & Flags::WriteThrough);
|
||||||
@ -261,7 +262,7 @@ namespace MMU
|
|||||||
Result<u64> unmap(u64 virt)
|
Result<u64> unmap(u64 virt)
|
||||||
{
|
{
|
||||||
auto& l1 = *TRY(find_entry(virt));
|
auto& l1 = *TRY(find_entry(virt));
|
||||||
if (!l1.present) return err;
|
if (!l1.present) return err(EFAULT);
|
||||||
u64 address = l1.get_address();
|
u64 address = l1.get_address();
|
||||||
memset(&l1, 0, sizeof(l1));
|
memset(&l1, 0, sizeof(l1));
|
||||||
flush_page(virt);
|
flush_page(virt);
|
||||||
@ -271,14 +272,14 @@ namespace MMU
|
|||||||
Result<u64> get_physical(u64 virt)
|
Result<u64> get_physical(u64 virt)
|
||||||
{
|
{
|
||||||
auto& l1 = *TRY(find_entry(virt));
|
auto& l1 = *TRY(find_entry(virt));
|
||||||
if (!l1.present) return err;
|
if (!l1.present) return err(EFAULT);
|
||||||
return l1.get_address();
|
return l1.get_address();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<int> get_flags(u64 virt)
|
Result<int> get_flags(u64 virt)
|
||||||
{
|
{
|
||||||
auto& l1 = *TRY(find_entry(virt));
|
auto& l1 = *TRY(find_entry(virt));
|
||||||
if (!l1.present) return err;
|
if (!l1.present) return err(EFAULT);
|
||||||
return arch_flags_to_mmu(l1);
|
return arch_flags_to_mmu(l1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ void Init::check_magic()
|
|||||||
{
|
{
|
||||||
if (memcmp(bootboot.magic, BOOTBOOT_MAGIC, 4))
|
if (memcmp(bootboot.magic, BOOTBOOT_MAGIC, 4))
|
||||||
{
|
{
|
||||||
Serial::println("ERROR: Invalid magic value from bootloader");
|
kerrorln("ERROR: Invalid magic value from bootloader");
|
||||||
for (;;)
|
for (;;)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -11,67 +11,28 @@
|
|||||||
|
|
||||||
Result<void> init()
|
Result<void> init()
|
||||||
{
|
{
|
||||||
Serial::println("Hello, world!");
|
kinfoln("Hello, world!");
|
||||||
|
|
||||||
Serial::printf("Current platform: %s\n", CPU::platform_string());
|
kinfoln("Current platform: %s", CPU::platform_string());
|
||||||
|
|
||||||
Serial::println(TRY(CPU::identify()));
|
kinfoln("Current processor: %s", TRY(CPU::identify()));
|
||||||
|
|
||||||
const u64 address = 0xfffffffff8000000;
|
|
||||||
|
|
||||||
Serial::printf("Mapping address 0x%lx\n", address);
|
|
||||||
|
|
||||||
TRY(MemoryManager::alloc_at(address, 1, MMU::ReadWrite));
|
|
||||||
|
|
||||||
TRY(MMU::remap(address, MMU::ReadWrite | MMU::User));
|
|
||||||
|
|
||||||
int flags = TRY(MMU::get_flags(address));
|
|
||||||
|
|
||||||
if (flags & MMU::ReadWrite) Serial::println("Mapping is now writable");
|
|
||||||
if (flags & MMU::User) Serial::println("Mapping is now user accessible");
|
|
||||||
|
|
||||||
u64 old = TRY(MMU::unmap(address));
|
|
||||||
|
|
||||||
Serial::printf("Unmapped page, was pointing to %#lx\n", old);
|
|
||||||
|
|
||||||
TextConsole::set_foreground(0xff000055);
|
|
||||||
TextConsole::set_background(0xff88ff00);
|
|
||||||
|
|
||||||
TextConsole::printf("Hello from Moon for the %s architecture!\n", CPU::platform_string());
|
|
||||||
|
|
||||||
Timer::init();
|
Timer::init();
|
||||||
|
|
||||||
kinfoln("Hello, world!");
|
|
||||||
kwarnln("THIS IS A WARNING");
|
|
||||||
kerrorln("ERROR: Please do something.");
|
|
||||||
|
|
||||||
CPU::platform_finish_init();
|
CPU::platform_finish_init();
|
||||||
|
|
||||||
CPU::enable_interrupts();
|
CPU::enable_interrupts();
|
||||||
|
|
||||||
usize start = 0;
|
|
||||||
|
|
||||||
int* mem = TRY(make<int>());
|
|
||||||
*(volatile int*)mem = 6;
|
|
||||||
Serial::printf("Read %d from memory\n", *mem);
|
|
||||||
|
|
||||||
TRY(destroy(mem));
|
|
||||||
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
|
to_dynamic_unit(MemoryManager::total(), buffer, sizeof(buffer));
|
||||||
|
kinfoln("Total memory: %s", buffer);
|
||||||
to_dynamic_unit(MemoryManager::free(), buffer, sizeof(buffer));
|
to_dynamic_unit(MemoryManager::free(), buffer, sizeof(buffer));
|
||||||
kinfoln("Free memory: %s", buffer);
|
kinfoln("Free memory: %s", buffer);
|
||||||
to_dynamic_unit(MemoryManager::used(), buffer, sizeof(buffer));
|
to_dynamic_unit(MemoryManager::used(), buffer, sizeof(buffer));
|
||||||
kinfoln("Used memory: %s", buffer);
|
kinfoln("Used memory: %s", buffer);
|
||||||
to_dynamic_unit(MemoryManager::reserved(), buffer, sizeof(buffer));
|
to_dynamic_unit(MemoryManager::reserved(), buffer, sizeof(buffer));
|
||||||
kinfoln("Reserved memory: %s", buffer);
|
kinfoln("Reserved memory: %s", buffer);
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
while ((Timer::ticks_ms() - start) < 100) { CPU::wait_for_interrupt(); }
|
|
||||||
start = Timer::ticks_ms();
|
|
||||||
kdbgln("%8zu milliseconds have passed!", start);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +41,6 @@ extern "C" [[noreturn]] void _start()
|
|||||||
Init::check_magic();
|
Init::check_magic();
|
||||||
Init::early_init();
|
Init::early_init();
|
||||||
auto rc = init();
|
auto rc = init();
|
||||||
rc.release_value();
|
if (rc.has_error()) kerrorln("Runtime error: %s", rc.error_string());
|
||||||
CPU::efficient_halt();
|
CPU::efficient_halt();
|
||||||
}
|
}
|
@ -1,9 +1,11 @@
|
|||||||
#include "memory/Heap.h"
|
#include "memory/Heap.h"
|
||||||
|
#include "Log.h"
|
||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
#include "arch/Serial.h"
|
#include "arch/Serial.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include <Alignment.h>
|
#include <Alignment.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
#include <SystemError.h>
|
||||||
|
|
||||||
static constexpr int BLOCK_USED = 1 << 0;
|
static constexpr int BLOCK_USED = 1 << 0;
|
||||||
static constexpr int BLOCK_START_MEM = 1 << 1;
|
static constexpr int BLOCK_START_MEM = 1 << 1;
|
||||||
@ -97,7 +99,7 @@ static Result<HeapBlock*> split(HeapBlock* block, usize size)
|
|||||||
usize old_size =
|
usize old_size =
|
||||||
block->full_size; // Save the old value of this variable since we are going to use it after modifying it
|
block->full_size; // Save the old value of this variable since we are going to use it after modifying it
|
||||||
|
|
||||||
if (available < (size + sizeof(HeapBlock))) return err;
|
if (available < (size + sizeof(HeapBlock))) return err(0); // This error is not propagated.
|
||||||
|
|
||||||
usize offset = get_fair_offset_to_split_at(block, size + sizeof(HeapBlock));
|
usize offset = get_fair_offset_to_split_at(block, size + sizeof(HeapBlock));
|
||||||
block->full_size = offset; // shrink the old block to fit this offset
|
block->full_size = offset; // shrink the old block to fit this offset
|
||||||
@ -239,18 +241,18 @@ Result<void> kfree(void* ptr)
|
|||||||
{
|
{
|
||||||
if (block->magic == BLOCK_DEAD)
|
if (block->magic == BLOCK_DEAD)
|
||||||
{
|
{
|
||||||
Serial::printf("ERROR: Attempt to free memory at %p, which was already freed\n", ptr);
|
kerrorln("ERROR: Attempt to free memory at %p, which was already freed", ptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Serial::printf("ERROR: Attempt to free memory at %p, which wasn't allocated with kmalloc\n", ptr);
|
kerrorln("ERROR: Attempt to free memory at %p, which wasn't allocated with kmalloc", ptr);
|
||||||
|
|
||||||
return err;
|
return err(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_block_free(block))
|
if (is_block_free(block))
|
||||||
{
|
{
|
||||||
Serial::printf("ERROR: Attempt to free memory at %p, which was already freed\n", ptr);
|
kerrorln("ERROR: Attempt to free memory at %p, which was already freed", ptr);
|
||||||
return err;
|
return err(EFAULT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
block->status &= ~BLOCK_USED;
|
block->status &= ~BLOCK_USED;
|
||||||
@ -295,20 +297,20 @@ Result<void*> krealloc(void* ptr, usize size)
|
|||||||
{
|
{
|
||||||
if (block->magic == BLOCK_DEAD)
|
if (block->magic == BLOCK_DEAD)
|
||||||
{
|
{
|
||||||
Serial::printf("ERROR: Attempt to realloc memory at %p, which was already freed\n", ptr);
|
kerrorln("ERROR: Attempt to realloc memory at %p, which was already freed", ptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Serial::printf("ERROR: Attempt to realloc memory at %p, which wasn't allocated with kmalloc\n", ptr);
|
kerrorln("ERROR: Attempt to realloc memory at %p, which wasn't allocated with kmalloc", ptr);
|
||||||
|
|
||||||
return err;
|
return err(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
size = align_up(size, 16UL);
|
size = align_up(size, 16UL);
|
||||||
|
|
||||||
if (is_block_free(block))
|
if (is_block_free(block))
|
||||||
{
|
{
|
||||||
Serial::printf("ERROR: Attempt to realloc memory at %p, which was already freed\n", ptr);
|
kerrorln("ERROR: Attempt to realloc memory at %p, which was already freed", ptr);
|
||||||
return err;
|
return err(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->full_size >= size)
|
if (block->full_size >= size)
|
||||||
@ -335,10 +337,10 @@ Result<void*> kcalloc(usize nmemb, usize size)
|
|||||||
|
|
||||||
void dump_heap_usage()
|
void dump_heap_usage()
|
||||||
{
|
{
|
||||||
Serial::println("-- Dumping usage stats for kernel heap:");
|
kdbgln("-- Dumping usage stats for kernel heap:");
|
||||||
if (!heap_start)
|
if (!heap_start)
|
||||||
{
|
{
|
||||||
Serial::println("- Heap is not currently being used");
|
kdbgln("- Heap is not currently being used");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
usize alloc_total = 0;
|
usize alloc_total = 0;
|
||||||
@ -348,19 +350,18 @@ void dump_heap_usage()
|
|||||||
{
|
{
|
||||||
if (is_block_free(block))
|
if (is_block_free(block))
|
||||||
{
|
{
|
||||||
Serial::printf("- Available block, of size %zu\n", block->full_size);
|
kdbgln("- Available block, of size %zu", block->full_size);
|
||||||
alloc_total += block->full_size + sizeof(HeapBlock);
|
alloc_total += block->full_size + sizeof(HeapBlock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial::printf("- Used block, of size %zu, of which %zu bytes are being used\n", block->full_size,
|
kdbgln("- Used block, of size %zu, of which %zu bytes are being used", block->full_size, block->req_size);
|
||||||
block->req_size);
|
|
||||||
alloc_total += block->full_size + sizeof(HeapBlock);
|
alloc_total += block->full_size + sizeof(HeapBlock);
|
||||||
alloc_used += block->req_size;
|
alloc_used += block->req_size;
|
||||||
}
|
}
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial::printf("-- Total memory allocated for heap: %zu bytes\n", alloc_total);
|
kdbgln("-- Total memory allocated for heap: %zu bytes", alloc_total);
|
||||||
Serial::printf("-- Heap memory in use by the kernel: %zu bytes\n", alloc_used);
|
kdbgln("-- Heap memory in use by the kernel: %zu bytes", alloc_used);
|
||||||
}
|
}
|
@ -1,9 +1,10 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
|
#include "Log.h"
|
||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
#include "arch/Serial.h"
|
|
||||||
#include "boot/bootboot.h"
|
#include "boot/bootboot.h"
|
||||||
#include <Alignment.h>
|
#include <Alignment.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
#include <SystemError.h>
|
||||||
#include <Types.h>
|
#include <Types.h>
|
||||||
|
|
||||||
extern BOOTBOOT bootboot;
|
extern BOOTBOOT bootboot;
|
||||||
@ -87,7 +88,7 @@ namespace MemoryManager
|
|||||||
page_virtual_bitmap_addr = page_bitmap_addr; // we'll map this to virtual memory as soon as the MMU is ready
|
page_virtual_bitmap_addr = page_bitmap_addr; // we'll map this to virtual memory as soon as the MMU is ready
|
||||||
if ((total_mem / ARCH_PAGE_SIZE / 8) >= biggest_memory_block_size)
|
if ((total_mem / ARCH_PAGE_SIZE / 8) >= biggest_memory_block_size)
|
||||||
{
|
{
|
||||||
Serial::println("ERROR: No single memory block is enough to hold the page bitmap");
|
kerrorln("ERROR: No single memory block is enough to hold the page bitmap");
|
||||||
for (;;)
|
for (;;)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -143,14 +144,14 @@ namespace MemoryManager
|
|||||||
return index * ARCH_PAGE_SIZE;
|
return index * ARCH_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err; // FIXME: ENOMEM.
|
return err(ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> free_frame(u64 frame)
|
Result<void> free_frame(u64 frame)
|
||||||
{
|
{
|
||||||
const u64 index = frame / ARCH_PAGE_SIZE;
|
const u64 index = frame / ARCH_PAGE_SIZE;
|
||||||
if (index > (page_bitmap_size * 8)) return err;
|
if (index > (page_bitmap_size * 8)) return err(EFAULT);
|
||||||
if (!page_bitmap_read(index)) return err;
|
if (!page_bitmap_read(index)) return err(EFAULT);
|
||||||
page_bitmap_set(index, false);
|
page_bitmap_set(index, false);
|
||||||
used_mem -= ARCH_PAGE_SIZE;
|
used_mem -= ARCH_PAGE_SIZE;
|
||||||
free_mem += ARCH_PAGE_SIZE;
|
free_mem += ARCH_PAGE_SIZE;
|
||||||
@ -272,4 +273,9 @@ namespace MemoryManager
|
|||||||
{
|
{
|
||||||
return reserved_mem;
|
return reserved_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 total()
|
||||||
|
{
|
||||||
|
return free_mem + used_mem + reserved_mem;
|
||||||
|
}
|
||||||
}
|
}
|
@ -30,4 +30,5 @@ namespace MemoryManager
|
|||||||
u64 free();
|
u64 free();
|
||||||
u64 used();
|
u64 used();
|
||||||
u64 reserved();
|
u64 reserved();
|
||||||
|
u64 total();
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ set(FREESTANDING_SOURCES
|
|||||||
NumberParsing.cpp
|
NumberParsing.cpp
|
||||||
String.cpp
|
String.cpp
|
||||||
Units.cpp
|
Units.cpp
|
||||||
|
SystemError.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <Check.h>
|
#include <Check.h>
|
||||||
#include <Move.h>
|
#include <Move.h>
|
||||||
#include <PlacementNew.h>
|
#include <PlacementNew.h>
|
||||||
|
#include <SystemError.h>
|
||||||
#include <Types.h>
|
#include <Types.h>
|
||||||
|
|
||||||
struct Error
|
struct Error
|
||||||
@ -92,6 +93,12 @@ template <typename T> class Result
|
|||||||
return {m_error};
|
return {m_error};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* error_string()
|
||||||
|
{
|
||||||
|
check(has_error());
|
||||||
|
return ::error_string(m_error);
|
||||||
|
}
|
||||||
|
|
||||||
T value()
|
T value()
|
||||||
{
|
{
|
||||||
check(has_value());
|
check(has_value());
|
||||||
@ -224,6 +231,12 @@ template <> class Result<void>
|
|||||||
return {m_error};
|
return {m_error};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* error_string()
|
||||||
|
{
|
||||||
|
check(has_error());
|
||||||
|
return ::error_string(m_error);
|
||||||
|
}
|
||||||
|
|
||||||
void value()
|
void value()
|
||||||
{
|
{
|
||||||
check(has_value());
|
check(has_value());
|
||||||
@ -242,7 +255,7 @@ template <> class Result<void>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define err Error{0}
|
#define err(x) Error{x}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#define TRY(expr) \
|
#define TRY(expr) \
|
||||||
|
60
luna/SystemError.cpp
Normal file
60
luna/SystemError.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include <SystemError.h>
|
||||||
|
|
||||||
|
const char* error_string(int error)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case 0: return "Success (not an error)";
|
||||||
|
case EPERM: return "Operation not permitted";
|
||||||
|
case ENOENT: return "No such file or directory";
|
||||||
|
case ESRCH: return "No such process";
|
||||||
|
case EINTR: return "Interrupted system call";
|
||||||
|
case EIO: return "Input/output error";
|
||||||
|
case ENXIO: return "No such device or address";
|
||||||
|
case E2BIG: return "Argument list too long";
|
||||||
|
case ENOEXEC: return "Exec format error";
|
||||||
|
case EBADF: return "Bad file descriptor";
|
||||||
|
case ECHILD: return "No child processes";
|
||||||
|
case EAGAIN: return "Resource temporarily unavailable";
|
||||||
|
case ENOMEM: return "Cannot allocate memory";
|
||||||
|
case EACCES: return "Permission denied";
|
||||||
|
case EFAULT: return "Bad address";
|
||||||
|
case EBUSY: return "Device or resource busy";
|
||||||
|
case EEXIST: return "File exists";
|
||||||
|
case EXDEV: return "Invalid cross-device link";
|
||||||
|
case ENODEV: return "No such device";
|
||||||
|
case ENOTDIR: return "Not a directory";
|
||||||
|
case EISDIR: return "Is a directory";
|
||||||
|
case EINVAL: return "Invalid argument";
|
||||||
|
case ENFILE: return "Too many open files in system";
|
||||||
|
case EMFILE: return "Too many open files";
|
||||||
|
case ENOTTY: return "Inappropriate ioctl for device";
|
||||||
|
case EFBIG: return "File too large";
|
||||||
|
case ENOSPC: return "No space left on device";
|
||||||
|
case ESPIPE: return "Illegal seek";
|
||||||
|
case EROFS: return "Read-only file system";
|
||||||
|
case EMLINK: return "Too many links";
|
||||||
|
case EPIPE: return "Broken pipe";
|
||||||
|
case EDOM: return "Numerical argument out of domain";
|
||||||
|
case ERANGE: return "Numerical result out of range";
|
||||||
|
case EDEADLK: return "Resource deadlock avoided";
|
||||||
|
case ENAMETOOLONG: return "File name too long";
|
||||||
|
case ENOLCK: return "No locks available";
|
||||||
|
case ENOSYS: return "Function not implemented";
|
||||||
|
case ENOTEMPTY: return "Directory not empty";
|
||||||
|
case ELOOP: return "Too many levels of symbolic links";
|
||||||
|
case ENOMSG: return "No message of desired type";
|
||||||
|
case EOVERFLOW: return "Value too large for defined data type";
|
||||||
|
case EILSEQ: return "Invalid or incomplete multibyte or wide character";
|
||||||
|
case ENOTSOCK: return "Socket operation on non-socket";
|
||||||
|
case ENOTSUP: return "Operation not supported";
|
||||||
|
case EADDRINUSE: return "Address already in use";
|
||||||
|
case ENETRESET: return "Network dropped connection on reset";
|
||||||
|
case ECONNRESET: return "Connection reset by peer";
|
||||||
|
case EISCONN: return "Transport endpoint is already connected";
|
||||||
|
case ETIMEDOUT: return "Connection timed out";
|
||||||
|
case EALREADY: return "Operation already in progress";
|
||||||
|
case EFIXME: return "Functionality not yet implemented";
|
||||||
|
default: return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
58
luna/SystemError.h
Normal file
58
luna/SystemError.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define EPERM 1 // Operation not permitted
|
||||||
|
#define ENOENT 2 // No such file or directory
|
||||||
|
#define ESRCH 3 // No such process
|
||||||
|
#define EINTR 4 // Interrupted system call
|
||||||
|
#define EIO 5 // Input/output error
|
||||||
|
#define ENXIO 6 // No such device or address
|
||||||
|
#define E2BIG 7 // Argument list too long
|
||||||
|
#define ENOEXEC 8 // Exec format error
|
||||||
|
#define EBADF 9 // Bad file descriptor
|
||||||
|
#define ECHILD 10 // No child processes
|
||||||
|
#define EAGAIN 11 // Resource temporarily unavailable
|
||||||
|
#define EWOULDBLOCK 11 // Resource temporarily unavailable
|
||||||
|
#define ENOMEM 12 // Cannot allocate memory
|
||||||
|
#define EACCES 13 // Permission denied
|
||||||
|
#define EFAULT 14 // Bad address
|
||||||
|
#define EBUSY 16 // Device or resource busy
|
||||||
|
#define EEXIST 17 // File exists
|
||||||
|
#define EXDEV 18 // Invalid cross-device link
|
||||||
|
#define ENODEV 19 // No such device
|
||||||
|
#define ENOTDIR 20 // Not a directory
|
||||||
|
#define EISDIR 21 // Is a directory
|
||||||
|
#define EINVAL 22 // Invalid argument
|
||||||
|
#define ENFILE 23 // Too many open files in system
|
||||||
|
#define EMFILE 24 // Too many open files
|
||||||
|
#define ENOTTY 25 // Inappropriate ioctl for device
|
||||||
|
#define EFBIG 27 // File too large
|
||||||
|
#define ENOSPC 28 // No space left on device
|
||||||
|
#define ESPIPE 29 // Illegal seek
|
||||||
|
#define EROFS 30 // Read-only file system
|
||||||
|
#define EMLINK 31 // Too many links
|
||||||
|
#define EPIPE 32 // Broken pipe
|
||||||
|
#define EDOM 33 // Numerical argument out of domain
|
||||||
|
#define ERANGE 34 // Numerical result out of range
|
||||||
|
#define EDEADLK 35 // Resource deadlock avoided
|
||||||
|
#define ENAMETOOLONG 36 // File name too long
|
||||||
|
#define ENOLCK 37 // No locks available
|
||||||
|
#define ENOSYS 38 // Function not implemented
|
||||||
|
#define ENOTEMPTY 39 // Directory not empty
|
||||||
|
#define ELOOP 40 // Too many levels of symbolic links
|
||||||
|
#define ENOMSG 42 // No message of desired type
|
||||||
|
#define EOVERFLOW 75 // Value too large for defined data type
|
||||||
|
#define EILSEQ 84 // Invalid or incomplete multibyte or wide character
|
||||||
|
#define ENOTSOCK 88 // Socket operation on non-socket
|
||||||
|
#define ENOTSUP 95 // Operation not supported
|
||||||
|
#define EOPNOTSUPP 95 // Operation not supported
|
||||||
|
#define EADDRINUSE 98 // Address already in use
|
||||||
|
#define ENETRESET 102 // Network dropped connection on reset
|
||||||
|
#define ECONNRESET 104 // Connection reset by peer
|
||||||
|
#define EISCONN 106 // Transport endpoint is already connected
|
||||||
|
#define ETIMEDOUT 110 // Connection timed out
|
||||||
|
#define EALREADY 114 // Operation already in progress
|
||||||
|
|
||||||
|
// This one is Luna-specific.
|
||||||
|
#define EFIXME 342 // Functionality not yet implemented
|
||||||
|
|
||||||
|
const char* error_string(int error);
|
@ -1,15 +1,14 @@
|
|||||||
#include <Format.h>
|
#include <Format.h>
|
||||||
#include <Units.h>
|
#include <Units.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
Result<usize> to_dynamic_unit(usize value, char* buffer, size_t max)
|
Result<usize> to_dynamic_unit(usize value, char* buffer, size_t max)
|
||||||
{
|
{
|
||||||
if (value < 1024) { return string_format(buffer, max, "%u bytes", value); }
|
if (value < 1024) { return string_format(buffer, max, "%u bytes", value); }
|
||||||
|
|
||||||
const char* unit_prefixes = "KMGTPE";
|
const char* unit_prefixes = "KMGTPE";
|
||||||
for (int i = 40; i >= 0 && value > (0xfffccccccccccccUL >> i); i -= 10)
|
while (value > (1024 * 1024))
|
||||||
{
|
{
|
||||||
value >>= 10;
|
value /= 1024;
|
||||||
unit_prefixes++;
|
unit_prefixes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user