aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/include/arch/context_switching/syscall/main.hpp23
-rw-r--r--arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp9
-rw-r--r--arch/x86_64/src/context_switching/syscall/main.cpp17
-rw-r--r--arch/x86_64/src/context_switching/syscall/syscall_handler.cpp17
-rw-r--r--arch/x86_64/src/memory/heap/user_heap_allocator.cpp41
5 files changed, 99 insertions, 8 deletions
diff --git a/arch/x86_64/include/arch/context_switching/syscall/main.hpp b/arch/x86_64/include/arch/context_switching/syscall/main.hpp
index 3af5a5a..8587ab2 100644
--- a/arch/x86_64/include/arch/context_switching/syscall/main.hpp
+++ b/arch/x86_64/include/arch/context_switching/syscall/main.hpp
@@ -15,6 +15,10 @@ namespace teachos::arch::context_switching::syscall
{
WRITE = 1U, ///< Loads the arg_0 parameter as an address pointing to a const char array, which will then be printed
///< onto the VGA buffer screen.
+ EXPAND_HEAP = 2U, /// Expands the User Heap by additonally mapping 100 KiB of virtual page memory. Ignores the
+ /// parameters and uses them as out parameters instead, where arg_0 is the start of the newly
+ /// mapped heap area and arg_1 is the size of the entire area. Can be less than 100 KiB if less
+ /// space remains.
};
/**
@@ -23,7 +27,8 @@ namespace teachos::arch::context_switching::syscall
*/
enum class error
{
- OK = 0U,
+ OK = 0U, ///< No error occured in syscall.
+ OUT_OF_MEMORY = 1U, ///< Expanding heap failed because we have run out of mappable virtual address space.
};
/**
@@ -50,6 +55,16 @@ namespace teachos::arch::context_switching::syscall
};
/**
+ * @brief Response of a systemcall always containin an error code, signaling if the syscall even succeeded or not.
+ * Additionally it may contain up to 6 return values in the values struct.
+ */
+ struct response
+ {
+ error error_code; ///< Error code returned by the syscall. If it failed all the values will be 0.
+ arguments values; ///< Optional return values of the syscall implementation.
+ };
+
+ /**
* @brief Calls the method associated with the given syscall number and passes the given optional arguments to it,
* over the RDI, RSI, RDX, R10, R8 and R9 register.
*
@@ -58,10 +73,12 @@ namespace teachos::arch::context_switching::syscall
* @param args Optional arguments passable to the different syscall methods, called depending on the syscall_number.
* Not passing the required parameters to the method, will result in passing 0 instead, which might make the fail or
* not function correctly.
- * @return Bool-convertable error code converting to true if the syscall failed or false if it didn't.
+ * @return The syscall implementation always returns a bool-convertable error code converting to true if the syscall
+ * failed or false if it didn't. Additionally it might pase additional values besides the error code, they will be set
+ * in the arguments struct. So the value can be read and used for further processing.
*/
[[gnu::section(".user_text")]]
- auto syscall(type syscall_number, arguments args = {}) -> error;
+ auto syscall(type syscall_number, arguments args) -> response;
} // namespace teachos::arch::context_switching::syscall
diff --git a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp b/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp
index c50d2f6..cadec78 100644
--- a/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp
+++ b/arch/x86_64/include/arch/memory/heap/user_heap_allocator.hpp
@@ -48,6 +48,15 @@ namespace teachos::arch::memory::heap
[[gnu::section(".user_text")]] auto constexpr min_allocatable_size() -> std::size_t { return sizeof(memory_block); }
/**
+ * @brief Special functionality fo the user heap allocator. Which will result in it being expanded by a syscall with
+ * addtionally 100 KiB, which are mapped into the page table. Will always work until there is no physical memory
+ * left.
+ *
+ * @return Start of the newly with syscall allocated free memory block. Nullptr if the syscall failed.
+ */
+ [[gnu::section(".user_text")]] auto expand_heap_if_full() -> memory_block *;
+
+ /**
* @brief Removes a free memory block from the free list and returns its address so the caller can allocate into it.
*
* @param previous_block Free memory block before the block to allocate in our heap memory. Was to small to
diff --git a/arch/x86_64/src/context_switching/syscall/main.cpp b/arch/x86_64/src/context_switching/syscall/main.cpp
index 93fc613..996d7fb 100644
--- a/arch/x86_64/src/context_switching/syscall/main.cpp
+++ b/arch/x86_64/src/context_switching/syscall/main.cpp
@@ -2,7 +2,7 @@
namespace teachos::arch::context_switching::syscall
{
- auto syscall(type syscall_number, arguments args) -> error
+ auto syscall(type syscall_number, arguments args) -> response
{
asm volatile("mov %[input], %%rax"
: /* no output from call */
@@ -18,9 +18,18 @@ namespace teachos::arch::context_switching::syscall
asm volatile("syscall");
- error error{};
- asm volatile("mov %%rax, %[output]" : [output] "=m"(error));
- return error;
+ error error_code{};
+ asm volatile("mov %%rax, %[output]" : [output] "=m"(error_code));
+
+ arguments values{};
+ asm volatile("mov %%rdi, %[output]" : [output] "=m"(values.arg_0));
+ asm volatile("mov %%rsi, %[output]" : [output] "=m"(values.arg_1));
+ asm volatile("mov %%rdx, %[output]" : [output] "=m"(values.arg_2));
+ asm volatile("mov %%r10, %[output]" : [output] "=m"(values.arg_3));
+ asm volatile("mov %%r8, %[output]" : [output] "=m"(values.arg_4));
+ asm volatile("mov %%r9, %[output]" : [output] "=m"(values.arg_5));
+
+ return {error_code, values};
}
} // namespace teachos::arch::context_switching::syscall
diff --git a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp
index da9eb1b..b88f273 100644
--- a/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp
+++ b/arch/x86_64/src/context_switching/syscall/syscall_handler.cpp
@@ -16,6 +16,20 @@ namespace teachos::arch::context_switching::syscall
video::vga::text::newline();
return error::OK;
}
+
+ auto expand_user_heap() -> error
+ {
+ arguments args{};
+ asm volatile("mov %[input], %%rdi"
+ : /* no output from call */
+ : [input] "m"(args.arg_0)
+ : "memory");
+ asm volatile("mov %[input], %%rsi"
+ : /* no output from call */
+ : [input] "m"(args.arg_1)
+ : "memory");
+ return error::OUT_OF_MEMORY;
+ }
} // namespace
auto syscall_handler() -> void
@@ -46,6 +60,9 @@ namespace teachos::arch::context_switching::syscall
case type::WRITE:
result = write_to_vga_buffer(arg_0);
break;
+ case type::EXPAND_HEAP:
+ result = expand_user_heap();
+ break;
default:
teachos::arch::exception_handling::panic("[Syscall Handler] Invalid syscall number");
break;
diff --git a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
index 6843d66..ce8b0fa 100644
--- a/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
+++ b/arch/x86_64/src/memory/heap/user_heap_allocator.cpp
@@ -1,5 +1,6 @@
#include "arch/memory/heap/user_heap_allocator.hpp"
+#include "arch/context_switching/syscall/main.hpp"
#include "arch/exception_handling/assert.hpp"
#include "arch/exception_handling/panic.hpp"
@@ -18,7 +19,7 @@ namespace teachos::arch::memory::heap
heap_size > min_allocatable_size(),
"[Linked List Allocator] Total heap size can not be smaller than minimum of 16 bytes to hold "
"atleast one memory hole entry");
- first = new (reinterpret_cast<void *>(heap_start)) memory_block(heap_size, nullptr);
+ // first = new (reinterpret_cast<void *>(heap_start)) memory_block(heap_size, nullptr);
}
auto user_heap_allocator::allocate(std::size_t size) -> void *
@@ -57,6 +58,30 @@ namespace teachos::arch::memory::heap
current = current->next;
}
+ current = expand_heap_if_full();
+
+ if (current != nullptr)
+ {
+ if (current->size == total_size)
+ {
+ auto const memory_address = remove_free_memory_block(previous, current);
+ new (memory_address) std::size_t(total_size);
+ mutex.unlock();
+ return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
+ }
+ else if (current->size >= total_size + min_allocatable_size())
+ {
+ // Ensure that the allocated size block is atleast 16 bytes (required because if we free the hole afterwards
+ // there needs to be enough space for a memory block). Therefore we allocate more than is actually required if
+ // the total size was less and simply deallocate it as well
+ auto const max_size = std::max(total_size, min_allocatable_size());
+ auto const memory_address = split_free_memory_block(previous, current, max_size);
+ new (memory_address) std::size_t(max_size);
+ mutex.unlock();
+ return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(memory_address) + sizeof(std::size_t));
+ }
+ }
+
exception_handling::panic("[Linked List Allocator] Out of memory");
}
@@ -91,6 +116,20 @@ namespace teachos::arch::memory::heap
mutex.unlock();
}
+ auto user_heap_allocator::expand_heap_if_full() -> memory_block *
+ {
+ context_switching::syscall::arguments args{};
+ auto const result = context_switching::syscall::syscall(context_switching::syscall::type::EXPAND_HEAP, args);
+
+ if (!result.error_code)
+ {
+ uint64_t const heap_start = result.values.arg_0;
+ uint64_t const heap_size = result.values.arg_1;
+ return new (reinterpret_cast<void *>(heap_start)) memory_block(heap_size, nullptr);
+ }
+ return nullptr;
+ }
+
auto user_heap_allocator::remove_free_memory_block(memory_block * previous_block, memory_block * current_block)
-> void *
{