From b9560409a7452ecb40e890407d3132d89ba514a6 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Thu, 22 Aug 2013 01:44:46 +0200 Subject: [PATCH] Add virtual address space allocator for user-space. --- sortix/include/sortix/kernel/yielder.h | 70 ++++++++++++ sortix/include/sortix/mman.h | 5 + sortix/segment.cpp | 142 +++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 sortix/include/sortix/kernel/yielder.h diff --git a/sortix/include/sortix/kernel/yielder.h b/sortix/include/sortix/kernel/yielder.h new file mode 100644 index 00000000..23590180 --- /dev/null +++ b/sortix/include/sortix/kernel/yielder.h @@ -0,0 +1,70 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2013. + + This file is part of Sortix. + + Sortix is free software: you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation, either version 3 of the License, or (at your option) any later + version. + + Sortix is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + Sortix. If not, see . + + sortix/kernel/yielder.h + Template that allows creation of easily-iterable sequences. + +*******************************************************************************/ + +#ifndef INCLUDE_SORTIX_KERNEL_YIELDER_H +#define INCLUDE_SORTIX_KERNEL_YIELDER_H + +namespace Sortix { + +class finished_yielder { }; + +template class yielder_iterator +{ +public: + yielder_iterator(yielder_type yielder) : yielder_object(yielder) + { + has_value = yielder_object.yield(¤t_value); + } + + bool is_finished() const + { + return !has_value; + } + + bool operator!=(const yielder_iterator& other) const + { + return !(is_finished() && other.is_finished()); + } + + yielded_type operator*() + { + return current_value; + } + + const yielder_iterator& operator++() + { + has_value = yielder_object.yield(¤t_value); + return *this; + } + +private: + yielder_type yielder_object; + yielded_type current_value; + bool has_value; + +}; + +} // namespace Sortix + +#endif diff --git a/sortix/include/sortix/mman.h b/sortix/include/sortix/mman.h index 2cb20eae..28b36a74 100644 --- a/sortix/include/sortix/mman.h +++ b/sortix/include/sortix/mman.h @@ -48,4 +48,9 @@ #define MAP_SHARED (1<<0) #define MAP_PRIVATE (1<<1) +#define MAP_ANONYMOUS (1<<2) +#define MAP_FIXED (1<<3) + +#define MAP_FAILED ((void*) -1) + #endif diff --git a/sortix/segment.cpp b/sortix/segment.cpp index 2b91b218..67c6a42e 100644 --- a/sortix/segment.cpp +++ b/sortix/segment.cpp @@ -24,14 +24,19 @@ #include +#include #include #include #include +#include + #include +#include #include #include #include +#include namespace Sortix { @@ -105,4 +110,141 @@ bool AddSegment(Process* process, const struct segment* new_segment) return true; } +class segment_gaps +{ + typedef yielder_iterator my_iterator; + +public: + segment_gaps(finished_yielder) : process(0) { } + + segment_gaps(Process* process) : + process(process), + current_segment_index(0), + checked_leading(false), + checked_trailing(false) + { + Memory::GetUserVirtualArea(&userspace_addr, &userspace_size); + } + + bool yield(struct segment* result) + { + // process->segment_lock is held at this point. + + // Check if we have finished iterating all the segments. + if ( !process ) + return false; + + // If the process has no segments at all, our job is really easy. + if ( !process->segments_used ) + { + result->addr = userspace_addr; + result->size = userspace_size; + result->prot = 0; + process = NULL; + return true; + } + + // Find out whether there is a gap before the first segment. + if ( !checked_leading && (checked_leading = true) && + process->segments[0].addr != userspace_addr ) + { + result->addr = userspace_addr; + result->size = process->segments[0].addr - userspace_addr; + result->prot = 0; + return true; + } + + // Search through the segments until a gap follows one. + while ( current_segment_index + 1 < process->segments_used ) + { + result->addr = process->segments[current_segment_index].addr + + process->segments[current_segment_index].size; + result->size = process->segments[current_segment_index+1].addr - + result->addr; + result->prot = 0; + current_segment_index++; + if ( result->size ) + return true; + } + + // Find out if there is a gap after the last segment. + if ( !checked_trailing && (checked_trailing = true) && + process->segments[process->segments_used-1].addr + + process->segments[process->segments_used-1].size != + userspace_addr + userspace_size ) + { + result->addr = process->segments[process->segments_used-1].addr + + process->segments[process->segments_used-1].size; + result->size = userspace_addr + userspace_size - result->addr; + result->prot = 0; + return true; + } + + process = NULL; + + return false; + } + + my_iterator begin() const + { + return my_iterator(segment_gaps(*this)); + } + + my_iterator end() const + { + return my_iterator(segment_gaps{finished_yielder{}}); + } + +private: + Process* process; + uintptr_t userspace_addr; + size_t userspace_size; + size_t current_segment_index; + bool checked_leading; + bool checked_trailing; + +}; + +bool PlaceSegment(struct segment* solution, Process* process, void* addr_ptr, + size_t size, int flags) +{ + // process->segment_lock is held at this point. + + assert(!(flags & MAP_FIXED)); + + uintptr_t addr = (uintptr_t) addr_ptr; + bool found_any = false; + size_t best_distance = 0; + struct segment best; + + for ( struct segment gap : segment_gaps(process) ) + { + if ( gap.size < size ) + continue; + if ( gap.addr <= addr && addr + size - gap.addr <= gap.size ) + { + solution->addr = addr; + solution->size = size; + solution->prot = 0; + return true; + } + struct segment attempt; + size_t distance; + attempt.addr = gap.addr; + attempt.size = size; + attempt.prot = 0; + distance = addr < attempt.addr ? attempt.addr - addr : addr - attempt.addr; + if ( !found_any|| distance < best_distance ) + found_any = true, best_distance = distance, best = attempt; + attempt.addr = gap.addr + gap.size - size; + attempt.size = size; + attempt.prot = 0; + distance = addr < attempt.addr ? attempt.addr - addr : addr - attempt.addr; + if ( !found_any|| distance < best_distance ) + found_any = true, best_distance = distance, best = attempt; + } + + return *solution = best, found_any; +} + } // namespace Sortix