forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -32,7 +32,6 @@ set(KERNEL_SOURCES
 | 
			
		|||
	kernel/Input/PS2Keymap.cpp
 | 
			
		||||
	kernel/InterruptController.cpp
 | 
			
		||||
	kernel/kernel.cpp
 | 
			
		||||
	kernel/Memory/FixedWidthAllocator.cpp
 | 
			
		||||
	kernel/Memory/GeneralAllocator.cpp
 | 
			
		||||
	kernel/Memory/Heap.cpp
 | 
			
		||||
	kernel/Memory/kmalloc.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,64 +0,0 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/Errors.h>
 | 
			
		||||
#include <BAN/UniqPtr.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/PageTable.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class FixedWidthAllocator
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(FixedWidthAllocator);
 | 
			
		||||
		BAN_NON_MOVABLE(FixedWidthAllocator);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::UniqPtr<FixedWidthAllocator>> create(PageTable&, uint32_t);
 | 
			
		||||
		~FixedWidthAllocator();
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<BAN::UniqPtr<FixedWidthAllocator>> clone(PageTable&);
 | 
			
		||||
 | 
			
		||||
		vaddr_t allocate();
 | 
			
		||||
		bool deallocate(vaddr_t);
 | 
			
		||||
 | 
			
		||||
		uint32_t allocation_size() const { return m_allocation_size; }
 | 
			
		||||
 | 
			
		||||
		uint32_t allocations() const { return m_allocations; }
 | 
			
		||||
		uint32_t max_allocations() const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		FixedWidthAllocator(PageTable&, uint32_t);
 | 
			
		||||
		BAN::ErrorOr<void> initialize();
 | 
			
		||||
 | 
			
		||||
		bool allocate_page_if_needed(vaddr_t, uint8_t flags);
 | 
			
		||||
 | 
			
		||||
		struct node
 | 
			
		||||
		{
 | 
			
		||||
			node* prev { nullptr };
 | 
			
		||||
			node* next { nullptr };
 | 
			
		||||
			bool allocated { false };
 | 
			
		||||
		};
 | 
			
		||||
		vaddr_t address_of_node(const node*) const;
 | 
			
		||||
		node* node_from_address(vaddr_t) const;
 | 
			
		||||
		void allocate_page_for_node_if_needed(const node*);
 | 
			
		||||
 | 
			
		||||
		void allocate_node(node*);
 | 
			
		||||
		void deallocate_node(node*);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		static constexpr uint32_t m_min_allocation_size = 16;
 | 
			
		||||
 | 
			
		||||
		PageTable& m_page_table;
 | 
			
		||||
		const uint32_t m_allocation_size;
 | 
			
		||||
		
 | 
			
		||||
		vaddr_t m_nodes_page { 0 };
 | 
			
		||||
		vaddr_t m_allocated_pages { 0 };
 | 
			
		||||
 | 
			
		||||
		node* m_free_list { nullptr };
 | 
			
		||||
		node* m_used_list { nullptr };
 | 
			
		||||
 | 
			
		||||
		uint32_t m_allocations { 0 };
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -6,8 +6,6 @@
 | 
			
		|||
#include <BAN/Vector.h>
 | 
			
		||||
#include <kernel/Credentials.h>
 | 
			
		||||
#include <kernel/FS/Inode.h>
 | 
			
		||||
#include <kernel/Memory/FixedWidthAllocator.h>
 | 
			
		||||
#include <kernel/Memory/GeneralAllocator.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/VirtualRange.h>
 | 
			
		||||
#include <kernel/OpenFileDescriptorSet.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -117,9 +115,6 @@ namespace Kernel
 | 
			
		|||
		BAN::ErrorOr<long> sys_mmap(const sys_mmap_t&);
 | 
			
		||||
		BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<long> sys_alloc(size_t);
 | 
			
		||||
		BAN::ErrorOr<long> sys_free(void*);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<long> sys_signal(int, void (*)(int));
 | 
			
		||||
		BAN::ErrorOr<long> sys_raise(int signal);
 | 
			
		||||
		static BAN::ErrorOr<long> sys_kill(pid_t pid, int signal);
 | 
			
		||||
| 
						 | 
				
			
			@ -181,9 +176,6 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<VirtualRange>> m_private_anonymous_mappings;
 | 
			
		||||
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<FixedWidthAllocator>> m_fixed_width_allocators;
 | 
			
		||||
		BAN::UniqPtr<GeneralAllocator> m_general_allocator;
 | 
			
		||||
 | 
			
		||||
		vaddr_t m_signal_handlers[_SIGMAX + 1] { };
 | 
			
		||||
		uint64_t m_signal_pending_mask { 0 };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,288 +0,0 @@
 | 
			
		|||
#include <kernel/Memory/FixedWidthAllocator.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<FixedWidthAllocator>> FixedWidthAllocator::create(PageTable& page_table, uint32_t allocation_size)
 | 
			
		||||
	{
 | 
			
		||||
		auto* allocator_ptr = new FixedWidthAllocator(page_table, allocation_size);
 | 
			
		||||
		if (allocator_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		auto allocator = BAN::UniqPtr<FixedWidthAllocator>::adopt(allocator_ptr);
 | 
			
		||||
		TRY(allocator->initialize());
 | 
			
		||||
		return allocator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FixedWidthAllocator::FixedWidthAllocator(PageTable& page_table, uint32_t allocation_size)
 | 
			
		||||
		: m_page_table(page_table)
 | 
			
		||||
		, m_allocation_size(BAN::Math::max(allocation_size, m_min_allocation_size))
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(BAN::Math::is_power_of_two(allocation_size));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> FixedWidthAllocator::initialize()
 | 
			
		||||
	{
 | 
			
		||||
		m_nodes_page = (vaddr_t)kmalloc(PAGE_SIZE);
 | 
			
		||||
		if (!m_nodes_page)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
 | 
			
		||||
		m_allocated_pages = (vaddr_t)kmalloc(PAGE_SIZE);
 | 
			
		||||
		if (!m_allocated_pages)
 | 
			
		||||
		{
 | 
			
		||||
			kfree((void*)m_nodes_page);
 | 
			
		||||
			m_nodes_page = 0;
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		memset((void*)m_nodes_page, 0, PAGE_SIZE);
 | 
			
		||||
		memset((void*)m_allocated_pages, 0, PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
		node* node_table = (node*)m_nodes_page;
 | 
			
		||||
		for (uint32_t i = 0; i < PAGE_SIZE / sizeof(node); i++)
 | 
			
		||||
		{
 | 
			
		||||
			node_table[i].next = &node_table[i + 1];
 | 
			
		||||
			node_table[i].prev = &node_table[i - 1];
 | 
			
		||||
		}
 | 
			
		||||
		node_table[0].prev = nullptr;
 | 
			
		||||
		node_table[PAGE_SIZE / sizeof(node) - 1].next = nullptr;
 | 
			
		||||
 | 
			
		||||
		m_free_list = node_table;
 | 
			
		||||
		m_used_list = nullptr;
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FixedWidthAllocator::~FixedWidthAllocator()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_nodes_page && m_allocated_pages)
 | 
			
		||||
		{
 | 
			
		||||
			for (uint32_t page_index = 0; page_index < PAGE_SIZE / sizeof(vaddr_t); page_index++)
 | 
			
		||||
			{
 | 
			
		||||
				vaddr_t page_vaddr = ((vaddr_t*)m_allocated_pages)[page_index];
 | 
			
		||||
				if (page_vaddr == 0)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				ASSERT(!m_page_table.is_page_free(page_vaddr));
 | 
			
		||||
				Heap::get().release_page(m_page_table.physical_address_of(page_vaddr));
 | 
			
		||||
				m_page_table.unmap_page(page_vaddr);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (m_nodes_page)
 | 
			
		||||
			kfree((void*)m_nodes_page);
 | 
			
		||||
		if (m_allocated_pages)
 | 
			
		||||
			kfree((void*)m_allocated_pages);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	paddr_t FixedWidthAllocator::allocate()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_free_list == nullptr)
 | 
			
		||||
			return 0;
 | 
			
		||||
		node* node = m_free_list;
 | 
			
		||||
		allocate_node(node);
 | 
			
		||||
		allocate_page_for_node_if_needed(node);
 | 
			
		||||
		return address_of_node(node);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool FixedWidthAllocator::deallocate(vaddr_t address)
 | 
			
		||||
	{
 | 
			
		||||
		if (address % m_allocation_size)
 | 
			
		||||
			return false;
 | 
			
		||||
		if (m_allocations == 0)
 | 
			
		||||
			return false;
 | 
			
		||||
		
 | 
			
		||||
		node* node = node_from_address(address);
 | 
			
		||||
		if (node == nullptr)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		if (!node->allocated)
 | 
			
		||||
		{
 | 
			
		||||
			dwarnln("deallocate called on unallocated address");
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		deallocate_node(node);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void FixedWidthAllocator::allocate_node(node* node)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(!node->allocated);
 | 
			
		||||
		node->allocated = true;
 | 
			
		||||
 | 
			
		||||
		if (node == m_free_list)
 | 
			
		||||
			m_free_list = node->next;
 | 
			
		||||
 | 
			
		||||
		if (node->prev)
 | 
			
		||||
			node->prev->next = node->next;
 | 
			
		||||
		if (node->next)
 | 
			
		||||
			node->next->prev = node->prev;
 | 
			
		||||
 | 
			
		||||
		node->next = m_used_list;
 | 
			
		||||
		node->prev = nullptr;
 | 
			
		||||
 | 
			
		||||
		if (m_used_list)
 | 
			
		||||
			m_used_list->prev = node;
 | 
			
		||||
		m_used_list = node;
 | 
			
		||||
 | 
			
		||||
		m_allocations++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void FixedWidthAllocator::deallocate_node(node* node)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(node->allocated);
 | 
			
		||||
		node->allocated = false;
 | 
			
		||||
 | 
			
		||||
		if (node == m_used_list)
 | 
			
		||||
			m_used_list = node->next;
 | 
			
		||||
 | 
			
		||||
		if (node->prev)
 | 
			
		||||
			node->prev->next = node->next;
 | 
			
		||||
		if (node->next)
 | 
			
		||||
			node->next->prev = node->prev;
 | 
			
		||||
 | 
			
		||||
		node->next = m_free_list;
 | 
			
		||||
		node->prev = nullptr;
 | 
			
		||||
 | 
			
		||||
		if (m_free_list)
 | 
			
		||||
			m_free_list->prev = node;
 | 
			
		||||
		m_free_list = node;
 | 
			
		||||
 | 
			
		||||
		m_allocations--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t FixedWidthAllocator::max_allocations() const
 | 
			
		||||
	{
 | 
			
		||||
		return PAGE_SIZE / sizeof(node);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vaddr_t FixedWidthAllocator::address_of_node(const node* node) const
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t index = node - (struct node*)m_nodes_page;
 | 
			
		||||
 | 
			
		||||
		uint32_t page_index = index / (PAGE_SIZE / m_allocation_size);
 | 
			
		||||
		ASSERT(page_index < PAGE_SIZE / sizeof(vaddr_t));
 | 
			
		||||
 | 
			
		||||
		uint32_t offset = index % (PAGE_SIZE / m_allocation_size);
 | 
			
		||||
 | 
			
		||||
		vaddr_t page_begin = ((vaddr_t*)m_allocated_pages)[page_index];
 | 
			
		||||
		ASSERT(page_begin);
 | 
			
		||||
 | 
			
		||||
		return page_begin + offset * m_allocation_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FixedWidthAllocator::node* FixedWidthAllocator::node_from_address(vaddr_t address) const
 | 
			
		||||
	{
 | 
			
		||||
		// TODO: This probably should be optimized from O(n) preferably to O(1) but I
 | 
			
		||||
		//       don't want to think about performance now.
 | 
			
		||||
		
 | 
			
		||||
		ASSERT(address % m_allocation_size == 0);
 | 
			
		||||
 | 
			
		||||
		vaddr_t page_begin = address / PAGE_SIZE * PAGE_SIZE;
 | 
			
		||||
 | 
			
		||||
		for (uint32_t page_index = 0; page_index < PAGE_SIZE / sizeof(vaddr_t); page_index++)
 | 
			
		||||
		{
 | 
			
		||||
			vaddr_t vaddr = ((vaddr_t*)m_allocated_pages)[page_index];
 | 
			
		||||
			if (vaddr != page_begin)
 | 
			
		||||
				continue;
 | 
			
		||||
			
 | 
			
		||||
			uint32_t offset = (address - page_begin) / m_allocation_size;
 | 
			
		||||
 | 
			
		||||
			node* result = (node*)m_nodes_page;
 | 
			
		||||
			result += page_index * PAGE_SIZE / m_allocation_size;
 | 
			
		||||
			result += offset;
 | 
			
		||||
			ASSERT(address_of_node(result) == address);
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void FixedWidthAllocator::allocate_page_for_node_if_needed(const node* node)
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t index = node - (struct node*)m_nodes_page;
 | 
			
		||||
 | 
			
		||||
		uint32_t page_index = index / (PAGE_SIZE / m_allocation_size);
 | 
			
		||||
		ASSERT(page_index < PAGE_SIZE / sizeof(vaddr_t));
 | 
			
		||||
 | 
			
		||||
		vaddr_t& page_vaddr = ((vaddr_t*)m_allocated_pages)[page_index];
 | 
			
		||||
		if (page_vaddr)
 | 
			
		||||
			return;
 | 
			
		||||
		
 | 
			
		||||
		paddr_t page_paddr = Heap::get().take_free_page();
 | 
			
		||||
		ASSERT(page_paddr);
 | 
			
		||||
 | 
			
		||||
		page_vaddr = m_page_table.reserve_free_page(0x300000);
 | 
			
		||||
		ASSERT(page_vaddr);
 | 
			
		||||
		
 | 
			
		||||
		m_page_table.map_page_at(page_paddr, page_vaddr, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool FixedWidthAllocator::allocate_page_if_needed(vaddr_t vaddr, uint8_t flags)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(vaddr % PAGE_SIZE == 0);
 | 
			
		||||
 | 
			
		||||
		// Check if page is already allocated
 | 
			
		||||
		for (uint32_t page_index = 0; page_index < PAGE_SIZE / sizeof(vaddr_t); page_index++)
 | 
			
		||||
		{
 | 
			
		||||
			vaddr_t page_begin = ((vaddr_t*)m_allocated_pages)[page_index];
 | 
			
		||||
			if (vaddr == page_begin)
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Page is not allocated so the vaddr must not be in use
 | 
			
		||||
		ASSERT(m_page_table.is_page_free(vaddr));
 | 
			
		||||
 | 
			
		||||
		// Allocate the vaddr on empty page
 | 
			
		||||
		for (uint32_t page_index = 0; page_index < PAGE_SIZE / sizeof(vaddr_t); page_index++)
 | 
			
		||||
		{
 | 
			
		||||
			vaddr_t& page_begin = ((vaddr_t*)m_allocated_pages)[page_index];
 | 
			
		||||
			if (page_begin == 0)
 | 
			
		||||
			{
 | 
			
		||||
				paddr_t paddr = Heap::get().take_free_page();
 | 
			
		||||
				ASSERT(paddr);
 | 
			
		||||
				m_page_table.map_page_at(paddr, vaddr, flags);
 | 
			
		||||
				page_begin = vaddr;
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ASSERT_NOT_REACHED();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<FixedWidthAllocator>> FixedWidthAllocator::clone(PageTable& new_page_table)
 | 
			
		||||
	{
 | 
			
		||||
		auto allocator = TRY(FixedWidthAllocator::create(new_page_table, allocation_size()));
 | 
			
		||||
 | 
			
		||||
		m_page_table.lock();
 | 
			
		||||
		ASSERT(m_page_table.is_page_free(0));
 | 
			
		||||
 | 
			
		||||
		for (node* node = m_used_list; node; node = node->next)
 | 
			
		||||
		{
 | 
			
		||||
			ASSERT(node->allocated);
 | 
			
		||||
 | 
			
		||||
			vaddr_t vaddr = address_of_node(node);
 | 
			
		||||
			vaddr_t page_begin = vaddr & PAGE_ADDR_MASK;
 | 
			
		||||
			PageTable::flags_t flags = m_page_table.get_page_flags(page_begin);
 | 
			
		||||
 | 
			
		||||
			// Allocate and copy all data from this allocation to the new one
 | 
			
		||||
			if (allocator->allocate_page_if_needed(page_begin, flags))
 | 
			
		||||
			{
 | 
			
		||||
				paddr_t paddr = new_page_table.physical_address_of(page_begin);
 | 
			
		||||
				m_page_table.map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
				memcpy((void*)0, (void*)page_begin, PAGE_SIZE);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Now that we are sure the page is allocated, we can access the node
 | 
			
		||||
			struct node* new_node = allocator->node_from_address(vaddr);
 | 
			
		||||
			allocator->allocate_node(new_node);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m_page_table.unmap_page(0);
 | 
			
		||||
 | 
			
		||||
		m_page_table.unlock();
 | 
			
		||||
 | 
			
		||||
		return allocator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -117,11 +117,27 @@ namespace Kernel
 | 
			
		|||
		{
 | 
			
		||||
			PageTableScope _(process->page_table());
 | 
			
		||||
 | 
			
		||||
			argv = (char**)MUST(process->sys_alloc(sizeof(char**) * 2));
 | 
			
		||||
			argv[0] = (char*)MUST(process->sys_alloc(path.size() + 1));
 | 
			
		||||
			memcpy(argv[0], path.data(), path.size());
 | 
			
		||||
			argv[0][path.size()] = '\0';
 | 
			
		||||
			argv[1] = nullptr;
 | 
			
		||||
			size_t needed_bytes = sizeof(char*) * 2 + path.size() + 1;
 | 
			
		||||
			if (auto rem = needed_bytes % PAGE_SIZE)
 | 
			
		||||
				needed_bytes += PAGE_SIZE - rem;
 | 
			
		||||
 | 
			
		||||
			auto argv_range = MUST(VirtualRange::create_to_vaddr_range(
 | 
			
		||||
				process->page_table(),
 | 
			
		||||
				0x400000, KERNEL_OFFSET,
 | 
			
		||||
				needed_bytes,
 | 
			
		||||
				PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
 | 
			
		||||
			));
 | 
			
		||||
			argv_range->set_zero();
 | 
			
		||||
 | 
			
		||||
			uintptr_t temp = argv_range->vaddr() + sizeof(char*) * 2;
 | 
			
		||||
			argv_range->copy_from(0, (uint8_t*)&temp, sizeof(char*));			
 | 
			
		||||
 | 
			
		||||
			temp = 0;
 | 
			
		||||
			argv_range->copy_from(sizeof(char*), (uint8_t*)&temp, sizeof(char*));	
 | 
			
		||||
 | 
			
		||||
			argv_range->copy_from(sizeof(char*) * 2, (const uint8_t*)path.data(), path.size());
 | 
			
		||||
 | 
			
		||||
			MUST(process->m_mapped_ranges.push_back(BAN::move(argv_range)));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		process->m_userspace_info.argc = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -149,8 +165,6 @@ namespace Kernel
 | 
			
		|||
	Process::~Process()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_threads.empty());
 | 
			
		||||
		ASSERT(m_fixed_width_allocators.empty());
 | 
			
		||||
		ASSERT(!m_general_allocator);
 | 
			
		||||
		ASSERT(m_private_anonymous_mappings.empty());
 | 
			
		||||
		ASSERT(m_mapped_ranges.empty());
 | 
			
		||||
		ASSERT(m_exit_status.waiting == 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -187,10 +201,6 @@ namespace Kernel
 | 
			
		|||
		// NOTE: We must unmap ranges while the page table is still alive
 | 
			
		||||
		m_private_anonymous_mappings.clear();
 | 
			
		||||
		m_mapped_ranges.clear();
 | 
			
		||||
 | 
			
		||||
		// NOTE: We must clear allocators while the page table is still alive
 | 
			
		||||
		m_fixed_width_allocators.clear();
 | 
			
		||||
		m_general_allocator.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void Process::on_thread_exit(Thread& thread)
 | 
			
		||||
| 
						 | 
				
			
			@ -331,16 +341,6 @@ namespace Kernel
 | 
			
		|||
		for (auto& mapped_range : m_mapped_ranges)
 | 
			
		||||
			MUST(mapped_ranges.push_back(TRY(mapped_range->clone(*page_table))));
 | 
			
		||||
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<FixedWidthAllocator>> fixed_width_allocators;
 | 
			
		||||
		TRY(fixed_width_allocators.reserve(m_fixed_width_allocators.size()));
 | 
			
		||||
		for (auto& allocator : m_fixed_width_allocators)
 | 
			
		||||
			if (allocator->allocations() > 0)
 | 
			
		||||
				MUST(fixed_width_allocators.push_back(TRY(allocator->clone(*page_table))));
 | 
			
		||||
 | 
			
		||||
		BAN::UniqPtr<GeneralAllocator> general_allocator;
 | 
			
		||||
		if (m_general_allocator)
 | 
			
		||||
			general_allocator = TRY(m_general_allocator->clone(*page_table));
 | 
			
		||||
 | 
			
		||||
		Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
 | 
			
		||||
		forked->m_controlling_terminal = m_controlling_terminal;
 | 
			
		||||
		forked->m_working_directory = BAN::move(working_directory);
 | 
			
		||||
| 
						 | 
				
			
			@ -348,8 +348,6 @@ namespace Kernel
 | 
			
		|||
		forked->m_open_file_descriptors = BAN::move(open_file_descriptors);
 | 
			
		||||
		forked->m_private_anonymous_mappings = BAN::move(private_anonymous_mappings);
 | 
			
		||||
		forked->m_mapped_ranges = BAN::move(mapped_ranges);
 | 
			
		||||
		forked->m_fixed_width_allocators = BAN::move(fixed_width_allocators);
 | 
			
		||||
		forked->m_general_allocator = BAN::move(general_allocator);
 | 
			
		||||
		forked->m_is_userspace = m_is_userspace;
 | 
			
		||||
		forked->m_userspace_info = m_userspace_info;
 | 
			
		||||
		forked->m_has_called_exec = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -390,8 +388,6 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
			m_open_file_descriptors.close_cloexec();
 | 
			
		||||
 | 
			
		||||
			m_fixed_width_allocators.clear();
 | 
			
		||||
			m_general_allocator.clear();
 | 
			
		||||
			m_private_anonymous_mappings.clear();
 | 
			
		||||
			m_mapped_ranges.clear();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -409,27 +405,46 @@ namespace Kernel
 | 
			
		|||
			ASSERT(&Process::current() == this);
 | 
			
		||||
 | 
			
		||||
			// allocate memory on the new process for arguments and environment
 | 
			
		||||
			{
 | 
			
		||||
				LockGuard _(page_table());
 | 
			
		||||
 | 
			
		||||
				m_userspace_info.argv = (char**)MUST(sys_alloc(sizeof(char**) * (str_argv.size() + 1)));
 | 
			
		||||
				for (size_t i = 0; i < str_argv.size(); i++)
 | 
			
		||||
			auto create_range =
 | 
			
		||||
				[&](const auto& container) -> BAN::UniqPtr<VirtualRange>
 | 
			
		||||
				{
 | 
			
		||||
					m_userspace_info.argv[i] = (char*)MUST(sys_alloc(str_argv[i].size() + 1));
 | 
			
		||||
					memcpy(m_userspace_info.argv[i], str_argv[i].data(), str_argv[i].size());
 | 
			
		||||
					m_userspace_info.argv[i][str_argv[i].size()] = '\0';
 | 
			
		||||
				}
 | 
			
		||||
				m_userspace_info.argv[str_argv.size()] = nullptr;
 | 
			
		||||
					size_t bytes = sizeof(char*);
 | 
			
		||||
					for (auto& elem : container)
 | 
			
		||||
						bytes += sizeof(char*) + elem.size() + 1;
 | 
			
		||||
 | 
			
		||||
				m_userspace_info.envp = (char**)MUST(sys_alloc(sizeof(char**) * (str_envp.size() + 1)));
 | 
			
		||||
				for (size_t i = 0; i < str_envp.size(); i++)
 | 
			
		||||
				{
 | 
			
		||||
					m_userspace_info.envp[i] = (char*)MUST(sys_alloc(str_envp[i].size() + 1));
 | 
			
		||||
					memcpy(m_userspace_info.envp[i], str_envp[i].data(), str_envp[i].size());
 | 
			
		||||
					m_userspace_info.envp[i][str_envp[i].size()] = '\0';
 | 
			
		||||
				}
 | 
			
		||||
				m_userspace_info.envp[str_envp.size()] = nullptr;
 | 
			
		||||
			}
 | 
			
		||||
					if (auto rem = bytes % PAGE_SIZE)
 | 
			
		||||
						bytes += PAGE_SIZE - rem;
 | 
			
		||||
 | 
			
		||||
					auto range = MUST(VirtualRange::create_to_vaddr_range(
 | 
			
		||||
						page_table(),
 | 
			
		||||
						0x400000, KERNEL_OFFSET,
 | 
			
		||||
						bytes,
 | 
			
		||||
						PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
 | 
			
		||||
					));
 | 
			
		||||
					range->set_zero();
 | 
			
		||||
 | 
			
		||||
					size_t data_offset = sizeof(char*) * (container.size() + 1);
 | 
			
		||||
					for (size_t i = 0; i < container.size(); i++)
 | 
			
		||||
					{
 | 
			
		||||
						uintptr_t ptr_addr = range->vaddr() + data_offset;
 | 
			
		||||
						range->copy_from(sizeof(char*) * i, (const uint8_t*)&ptr_addr, sizeof(char*));
 | 
			
		||||
						range->copy_from(data_offset, (const uint8_t*)container[i].data(), container[i].size());
 | 
			
		||||
						data_offset += container[i].size() + 1;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					uintptr_t null = 0;
 | 
			
		||||
					range->copy_from(sizeof(char*) * container.size(), (const uint8_t*)&null, sizeof(char*));
 | 
			
		||||
 | 
			
		||||
					return BAN::move(range);
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
			auto argv_range = create_range(str_argv);
 | 
			
		||||
			m_userspace_info.argv = (char**)argv_range->vaddr();
 | 
			
		||||
			MUST(m_mapped_ranges.push_back(BAN::move(argv_range)));
 | 
			
		||||
 | 
			
		||||
			auto envp_range = create_range(str_envp);
 | 
			
		||||
			m_userspace_info.envp = (char**)envp_range->vaddr();
 | 
			
		||||
			MUST(m_mapped_ranges.push_back(BAN::move(envp_range)));
 | 
			
		||||
 | 
			
		||||
			m_userspace_info.argc = str_argv.size();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -829,92 +844,6 @@ namespace Kernel
 | 
			
		|||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static constexpr size_t allocator_size_for_allocation(size_t value)
 | 
			
		||||
	{
 | 
			
		||||
		if (value <= 256) {
 | 
			
		||||
			if (value <= 64)
 | 
			
		||||
				return 64;
 | 
			
		||||
			else
 | 
			
		||||
				return 256;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (value <= 1024)
 | 
			
		||||
				return 1024;
 | 
			
		||||
			else
 | 
			
		||||
				return 4096;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<long> Process::sys_alloc(size_t bytes)
 | 
			
		||||
	{
 | 
			
		||||
		vaddr_t address = 0;
 | 
			
		||||
 | 
			
		||||
		if (bytes <= PAGE_SIZE)
 | 
			
		||||
		{
 | 
			
		||||
			// Do fixed width allocation
 | 
			
		||||
			size_t allocation_size = allocator_size_for_allocation(bytes);
 | 
			
		||||
			ASSERT(bytes <= allocation_size);
 | 
			
		||||
			ASSERT(allocation_size <= PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
			LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
			bool needs_new_allocator { true };
 | 
			
		||||
 | 
			
		||||
			for (auto& allocator : m_fixed_width_allocators)
 | 
			
		||||
			{
 | 
			
		||||
				if (allocator->allocation_size() == allocation_size && allocator->allocations() < allocator->max_allocations())
 | 
			
		||||
				{
 | 
			
		||||
					address = allocator->allocate();
 | 
			
		||||
					needs_new_allocator = false;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (needs_new_allocator)
 | 
			
		||||
			{
 | 
			
		||||
				auto allocator = TRY(FixedWidthAllocator::create(page_table(), allocation_size));
 | 
			
		||||
				TRY(m_fixed_width_allocators.push_back(BAN::move(allocator)));
 | 
			
		||||
				address = m_fixed_width_allocators.back()->allocate();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
			if (!m_general_allocator)
 | 
			
		||||
				m_general_allocator = TRY(GeneralAllocator::create(page_table(), 0x400000));
 | 
			
		||||
 | 
			
		||||
			address = m_general_allocator->allocate(bytes);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (address == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return address;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<long> Process::sys_free(void* ptr)
 | 
			
		||||
	{
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < m_fixed_width_allocators.size(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			auto& allocator = m_fixed_width_allocators[i];
 | 
			
		||||
			if (allocator->deallocate((vaddr_t)ptr))
 | 
			
		||||
			{
 | 
			
		||||
				// TODO: This might be too much. Maybe we should only
 | 
			
		||||
				//       remove allocators when we have low memory... ?
 | 
			
		||||
				if (allocator->allocations() == 0)
 | 
			
		||||
					m_fixed_width_allocators.remove(i);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (m_general_allocator && m_general_allocator->deallocate((vaddr_t)ptr))
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		dwarnln("free called on pointer that was not allocated");
 | 
			
		||||
		return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<long> Process::sys_termid(char* buffer) const
 | 
			
		||||
	{
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue