From 4287ec6cb018fb7f1b763ca83cc056e3a69e8508 Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 9 Jan 2023 17:59:52 +0100 Subject: [PATCH] Bitmap: Introduce a new method 'find' and use it in MM and KernelVM This method looks for the first bit with a value, optionally from a starting index, and returns its index. This should be (haven't benchmarked) way faster than the manual way, AKA what MM and KernelVM were doing. This is due to this method using bit and byte manipulation tricks instead of just calling get() until getting the desired result :) --- .vscode/c_cpp_properties.json | 7 +++-- kernel/CMakeLists.txt | 1 + kernel/debug.cmake | 1 + kernel/src/memory/KernelVM.cpp | 17 ++++++------ kernel/src/memory/MemoryManager.cpp | 43 ++++++++++++++++++----------- kernel/src/thread/Spinlock.h | 16 +++++++++++ luna/include/luna/Bitmap.h | 5 +++- luna/src/Bitmap.cpp | 39 ++++++++++++++++++++++++++ 8 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 kernel/debug.cmake 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 {}; +}