diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 6f53357b..d5b4e0e5 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -2,7 +2,7 @@ "configurations": [ { "name": "Luna", - "compilerPath": "${workspaceFolder}/toolchain/x86-64-luna/bin/x86_64-luna-gcc", + "compilerPath": "${workspaceFolder}/toolchain/x86_64-luna/bin/x86_64-luna-gcc", "cStandard": "c17", "cppStandard": "c++20", "intelliSenseMode": "gcc-x64", @@ -10,9 +10,10 @@ "includePath": [ "${default}", "${workspaceFolder}/base/usr/include", - "${workspaceFolder}/libc/include" + "${workspaceFolder}/libc/include", + "${workspaceFolder}/luna/include" ] } ], "version": 4 -} \ No newline at end of file +} diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 12840186..22f2b7ab 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -72,6 +72,7 @@ endif() if(MOON_DEBUG_SYMBOLS) message(STATUS "Building Moon with debug symbols") target_compile_options(moon PRIVATE -ggdb) + include(debug.cmake) endif() target_link_options(moon PRIVATE -lgcc -Wl,--build-id=none -z max-page-size=0x1000 -mcmodel=kernel) diff --git a/kernel/debug.cmake b/kernel/debug.cmake new file mode 100644 index 00000000..74074888 --- /dev/null +++ b/kernel/debug.cmake @@ -0,0 +1 @@ +target_compile_definitions(moon PRIVATE LOCKED_VALUE_DEBUG) diff --git a/kernel/src/memory/KernelVM.cpp b/kernel/src/memory/KernelVM.cpp index 8c9379df..f09eeaa7 100644 --- a/kernel/src/memory/KernelVM.cpp +++ b/kernel/src/memory/KernelVM.cpp @@ -29,15 +29,16 @@ namespace KernelVM Result alloc_one_page() { auto kernelvm_bitmap = g_kernelvm_bitmap.lock(); - for (u64 index = 0; index < kernelvm_bitmap->size(); index++) - { - if (kernelvm_bitmap->get(index)) continue; - kernelvm_bitmap->set(index, true); - g_used_vm += ARCH_PAGE_SIZE; - return KERNEL_VM_RANGE_START + (index * ARCH_PAGE_SIZE); - } - return err(ENOMEM); + const auto maybe_index = kernelvm_bitmap->find(false); + if (!maybe_index.has_value()) return err(ENOMEM); + + const usize index = maybe_index.value(); + + kernelvm_bitmap->set(index, true); + g_used_vm += ARCH_PAGE_SIZE; + + return KERNEL_VM_RANGE_START + (index * ARCH_PAGE_SIZE); } bool find_several_pages_impl(usize count, u64& start_index) diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index 61eb24e4..62fd0acc 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -120,46 +120,57 @@ namespace MemoryManager frame_bitmap->initialize((void*)virtual_bitmap_base, frame_bitmap->size_in_bytes()); } - void lock_frame(u64 frame) + void do_lock_frame(u64 index, Bitmap& bitmap) { - const u64 index = frame / ARCH_PAGE_SIZE; - auto frame_bitmap = g_frame_bitmap.lock(); - if (frame_bitmap->get(index)) return; - frame_bitmap->set(index, true); + if (bitmap.get(index)) return; + bitmap.set(index, true); used_mem += ARCH_PAGE_SIZE; free_mem -= ARCH_PAGE_SIZE; } + void lock_frame(u64 frame) + { + const u64 index = frame / ARCH_PAGE_SIZE; + auto frame_bitmap = g_frame_bitmap.lock(); + do_lock_frame(index, *frame_bitmap); + } + void lock_frames(u64 frames, usize count) { - for (usize index = 0; index < count; index++) { lock_frame(frames + (index * ARCH_PAGE_SIZE)); } + auto frame_bitmap = g_frame_bitmap.lock(); + const u64 frame_index = frames / ARCH_PAGE_SIZE; + for (usize index = 0; index < count; index++) { do_lock_frame(frame_index + index, *frame_bitmap); } } Result alloc_frame() { auto frame_bitmap = g_frame_bitmap.lock(); - for (u64 index = start_index; index < frame_bitmap->size(); index++) - { - if (frame_bitmap->get(index)) continue; - frame_bitmap->set(index, true); - start_index = index + 1; - free_mem -= ARCH_PAGE_SIZE; - used_mem += ARCH_PAGE_SIZE; - return index * ARCH_PAGE_SIZE; - } - return err(ENOMEM); + const auto maybe_index = frame_bitmap->find(false, start_index); + if (!maybe_index.has_value()) return err(ENOMEM); + + const usize index = maybe_index.value(); + + start_index = index + 1; + do_lock_frame(index, *frame_bitmap); + + return index * ARCH_PAGE_SIZE; } Result free_frame(u64 frame) { const u64 index = frame / ARCH_PAGE_SIZE; + auto frame_bitmap = g_frame_bitmap.lock(); + if (index > frame_bitmap->size()) return err(EFAULT); if (!frame_bitmap->get(index)) return err(EFAULT); + frame_bitmap->set(index, false); + used_mem -= ARCH_PAGE_SIZE; free_mem += ARCH_PAGE_SIZE; + if (start_index > index) start_index = index; return {}; } diff --git a/kernel/src/thread/Spinlock.h b/kernel/src/thread/Spinlock.h index d54edd96..9a679d5f 100644 --- a/kernel/src/thread/Spinlock.h +++ b/kernel/src/thread/Spinlock.h @@ -1,4 +1,6 @@ #pragma once +#include "Log.h" +#include "arch/CPU.h" #include #include @@ -73,11 +75,25 @@ template class LockedValue { } +#ifndef LOCKED_VALUE_DEBUG LockedValueGuard lock() { m_lock.lock(); return { *this }; } +#else + LockedValueGuard lock() + { + if (m_lock.try_lock()) { return { *this }; } + + kwarnln("Spinning on a locked LockedValue. This might lead to a deadlock..."); + + CPU::print_stack_trace(); + + m_lock.lock(); + return { *this }; + } +#endif Option try_lock() { diff --git a/luna/include/luna/Bitmap.h b/luna/include/luna/Bitmap.h index 5b062fd7..46d6f757 100644 --- a/luna/include/luna/Bitmap.h +++ b/luna/include/luna/Bitmap.h @@ -1,4 +1,5 @@ #pragma once +#include #include class Bitmap @@ -34,11 +35,13 @@ class Bitmap return m_location; } + Option find(bool value, usize begin = 0) const; + void clear(bool value); void clear_region(usize start, usize bits, bool value); private: - u8 value_byte(bool b) + u8 value_byte(bool b) const { return b ? 0xff : 0; } diff --git a/luna/src/Bitmap.cpp b/luna/src/Bitmap.cpp index 5a3e5130..90530da0 100644 --- a/luna/src/Bitmap.cpp +++ b/luna/src/Bitmap.cpp @@ -86,3 +86,42 @@ void Bitmap::clear_region(usize start, usize bits, bool value) start++; } } + +Option Bitmap::find(bool value, usize begin) const +{ + expect(initialized(), "Bitmap was never initialized"); + + usize size = this->size(); + + expect(begin < size, "Start index out of range"); + + while (begin % 8) + { + if (get(begin) == value) return begin; + begin++; + } + + if (begin == size) return {}; + + usize i = begin / 8; + u8 byte_that_does_not_contain_value = value_byte(!value); + while (i < m_size_in_bytes) + { + if (m_location[i] == byte_that_does_not_contain_value) + { + i++; + continue; + } + + usize index = i * 8; + for (usize j = 0; j < 8; j++, index++) + { + if (get(index) == value) return index; + } + + // Once we've located a byte that contains the value, we should succeed in finding it. + unreachable(); + } + + return {}; +}