forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -35,6 +35,8 @@ set(KERNEL_SOURCES
 | 
			
		|||
	kernel/Memory/GeneralAllocator.cpp
 | 
			
		||||
	kernel/Memory/Heap.cpp
 | 
			
		||||
	kernel/Memory/kmalloc.cpp
 | 
			
		||||
	kernel/Memory/MemoryBackedRegion.cpp
 | 
			
		||||
	kernel/Memory/MemoryRegion.cpp
 | 
			
		||||
	kernel/Memory/PhysicalRange.cpp
 | 
			
		||||
	kernel/Memory/VirtualRange.cpp
 | 
			
		||||
	kernel/Networking/E1000.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <kernel/Memory/MemoryRegion.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class MemoryBackedRegion final : public MemoryRegion
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(MemoryBackedRegion);
 | 
			
		||||
		BAN_NON_MOVABLE(MemoryBackedRegion);
 | 
			
		||||
	
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t);
 | 
			
		||||
		~MemoryBackedRegion();
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<bool> allocate_page_containing(vaddr_t vaddr) override;
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
 | 
			
		||||
 | 
			
		||||
		// Copy data from buffer into this region
 | 
			
		||||
		// This can fail if no memory is mapped and no free memory was available
 | 
			
		||||
		BAN::ErrorOr<void> copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <BAN/UniqPtr.h>
 | 
			
		||||
#include <kernel/Memory/PageTable.h>
 | 
			
		||||
#include <kernel/Memory/Types.h>
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	struct AddressRange
 | 
			
		||||
	{
 | 
			
		||||
		vaddr_t start;
 | 
			
		||||
		vaddr_t end;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	class MemoryRegion
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(MemoryRegion);
 | 
			
		||||
		BAN_NON_MOVABLE(MemoryRegion);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		enum Type : uint8_t
 | 
			
		||||
		{
 | 
			
		||||
			PRIVATE,
 | 
			
		||||
			SHARED
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		virtual ~MemoryRegion();
 | 
			
		||||
 | 
			
		||||
		bool contains(vaddr_t address) const;
 | 
			
		||||
		bool contains_fully(vaddr_t address, size_t size) const;
 | 
			
		||||
		bool overlaps(vaddr_t address, size_t size) const;
 | 
			
		||||
 | 
			
		||||
		size_t size() const { return m_size; }
 | 
			
		||||
		vaddr_t vaddr() const { return m_vaddr; }
 | 
			
		||||
 | 
			
		||||
		// Returns error if no memory was available
 | 
			
		||||
		// Returns true if page was succesfully allocated
 | 
			
		||||
		// Returns false if page was already allocated
 | 
			
		||||
		virtual BAN::ErrorOr<bool> allocate_page_containing(vaddr_t address) = 0;
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0;
 | 
			
		||||
	
 | 
			
		||||
	protected:
 | 
			
		||||
		MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags);
 | 
			
		||||
		BAN::ErrorOr<void> initialize(AddressRange);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		PageTable& m_page_table;
 | 
			
		||||
		const size_t m_size;
 | 
			
		||||
		const Type m_type;
 | 
			
		||||
		const PageTable::flags_t m_flags;
 | 
			
		||||
		vaddr_t m_vaddr { 0 };
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
#include <kernel/Credentials.h>
 | 
			
		||||
#include <kernel/FS/Inode.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/VirtualRange.h>
 | 
			
		||||
#include <kernel/Memory/MemoryRegion.h>
 | 
			
		||||
#include <kernel/OpenFileDescriptorSet.h>
 | 
			
		||||
#include <kernel/SpinLock.h>
 | 
			
		||||
#include <kernel/Terminal/TTY.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +174,7 @@ namespace Kernel
 | 
			
		|||
		OpenFileDescriptorSet m_open_file_descriptors;
 | 
			
		||||
 | 
			
		||||
		BAN::UniqPtr<LibELF::LoadableELF> m_loadable_elf;
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<VirtualRange>> m_mapped_ranges;
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<MemoryRegion>> m_mapped_regions;
 | 
			
		||||
 | 
			
		||||
		pid_t m_sid;
 | 
			
		||||
		pid_t m_pgrp;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,124 @@
 | 
			
		|||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/MemoryBackedRegion.h>
 | 
			
		||||
#include <kernel/LockGuard.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> MemoryBackedRegion::create(PageTable& page_table, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(type == Type::PRIVATE);
 | 
			
		||||
 | 
			
		||||
		auto* region_ptr = new MemoryBackedRegion(page_table, size, type, flags);
 | 
			
		||||
		if (region_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
 | 
			
		||||
 | 
			
		||||
		TRY(region->initialize(address_range));
 | 
			
		||||
 | 
			
		||||
		return region;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags)
 | 
			
		||||
		: MemoryRegion(page_table, size, type, flags)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MemoryBackedRegion::~MemoryBackedRegion()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_type == Type::PRIVATE);
 | 
			
		||||
 | 
			
		||||
		size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
 | 
			
		||||
		for (size_t i = 0; i < needed_pages; i++)
 | 
			
		||||
		{
 | 
			
		||||
			paddr_t paddr = m_page_table.physical_address_of(m_vaddr + i * PAGE_SIZE);
 | 
			
		||||
			if (paddr != 0)
 | 
			
		||||
				Heap::get().release_page(paddr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<bool> MemoryBackedRegion::allocate_page_containing(vaddr_t address)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_type == Type::PRIVATE);
 | 
			
		||||
 | 
			
		||||
		ASSERT(contains(address));
 | 
			
		||||
 | 
			
		||||
		// Check if address is already mapped
 | 
			
		||||
		vaddr_t vaddr = address & PAGE_ADDR_MASK;
 | 
			
		||||
		if (m_page_table.physical_address_of(vaddr) != 0)
 | 
			
		||||
			return false;
 | 
			
		||||
		
 | 
			
		||||
		// Map new physcial page to address
 | 
			
		||||
		paddr_t paddr = Heap::get().take_free_page();
 | 
			
		||||
		if (paddr == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		m_page_table.map_page_at(paddr, vaddr, m_flags);
 | 
			
		||||
 | 
			
		||||
		// Zero out the new page
 | 
			
		||||
		if (&PageTable::current() == &m_page_table)
 | 
			
		||||
			memset((void*)vaddr, 0x00, PAGE_SIZE);
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			LockGuard _(PageTable::current());
 | 
			
		||||
			ASSERT(PageTable::current().is_page_free(0));
 | 
			
		||||
 | 
			
		||||
			PageTable::current().map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
			memset((void*)0, 0x00, PAGE_SIZE);
 | 
			
		||||
			PageTable::current().unmap_page(0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> MemoryBackedRegion::clone(PageTable& new_page_table)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(&PageTable::current() == &m_page_table);
 | 
			
		||||
 | 
			
		||||
		auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + m_size }, m_type, m_flags));
 | 
			
		||||
 | 
			
		||||
		for (size_t offset = 0; offset < m_size; offset += PAGE_SIZE)
 | 
			
		||||
		{
 | 
			
		||||
			paddr_t paddr = m_page_table.physical_address_of(m_vaddr + offset);
 | 
			
		||||
			if (paddr == 0)
 | 
			
		||||
				continue;
 | 
			
		||||
			TRY(result->copy_data_to_region(offset, (const uint8_t*)(m_vaddr + offset), PAGE_SIZE));
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return BAN::UniqPtr<MemoryRegion>(BAN::move(result));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> MemoryBackedRegion::copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(offset_into_region + buffer_size <= m_size);
 | 
			
		||||
 | 
			
		||||
		size_t written = 0;
 | 
			
		||||
		while (written < buffer_size)
 | 
			
		||||
		{
 | 
			
		||||
			vaddr_t write_vaddr = m_vaddr + offset_into_region + written;
 | 
			
		||||
			vaddr_t page_offset = write_vaddr % PAGE_SIZE;
 | 
			
		||||
			size_t bytes = BAN::Math::min<size_t>(buffer_size - written, PAGE_SIZE - page_offset);
 | 
			
		||||
 | 
			
		||||
			TRY(allocate_page_containing(write_vaddr));
 | 
			
		||||
 | 
			
		||||
			if (&PageTable::current() == &m_page_table)
 | 
			
		||||
				memcpy((void*)write_vaddr, (void*)(buffer + written), bytes);
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				paddr_t paddr = m_page_table.physical_address_of(write_vaddr & PAGE_ADDR_MASK);
 | 
			
		||||
				ASSERT(paddr);
 | 
			
		||||
 | 
			
		||||
				LockGuard _(PageTable::current());
 | 
			
		||||
				ASSERT(PageTable::current().is_page_free(0));
 | 
			
		||||
 | 
			
		||||
				PageTable::current().map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
				memcpy((void*)page_offset, (void*)(buffer + written), bytes);
 | 
			
		||||
				PageTable::current().unmap_page(0);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			written += bytes;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
#include <kernel/Memory/MemoryRegion.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	MemoryRegion::MemoryRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags)
 | 
			
		||||
		: m_page_table(page_table)
 | 
			
		||||
		, m_size(size)
 | 
			
		||||
		, m_type(type)
 | 
			
		||||
		, m_flags(flags)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	MemoryRegion::~MemoryRegion()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_vaddr)
 | 
			
		||||
			m_page_table.unmap_range(m_vaddr, m_size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> MemoryRegion::initialize(AddressRange address_range)
 | 
			
		||||
	{
 | 
			
		||||
		size_t needed_pages = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
 | 
			
		||||
		m_vaddr = m_page_table.reserve_free_contiguous_pages(needed_pages, address_range.start);
 | 
			
		||||
		if (m_vaddr == 0)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		if (m_vaddr + needed_pages * PAGE_SIZE > address_range.end)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool MemoryRegion::contains(vaddr_t address) const
 | 
			
		||||
	{
 | 
			
		||||
		return m_vaddr <= address && address < m_vaddr + m_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool MemoryRegion::contains_fully(vaddr_t address, size_t size) const
 | 
			
		||||
	{
 | 
			
		||||
		return m_vaddr <= address && address + size < m_vaddr + m_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool MemoryRegion::overlaps(vaddr_t address, size_t size) const
 | 
			
		||||
	{
 | 
			
		||||
		if (address + size < m_vaddr)
 | 
			
		||||
			return false;
 | 
			
		||||
		if (address >= m_vaddr + m_size)
 | 
			
		||||
			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include <kernel/InterruptController.h>
 | 
			
		||||
#include <kernel/LockGuard.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/MemoryBackedRegion.h>
 | 
			
		||||
#include <kernel/Memory/PageTableScope.h>
 | 
			
		||||
#include <kernel/Process.h>
 | 
			
		||||
#include <kernel/Scheduler.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -128,23 +129,23 @@ namespace Kernel
 | 
			
		|||
			if (auto rem = needed_bytes % PAGE_SIZE)
 | 
			
		||||
				needed_bytes += PAGE_SIZE - rem;
 | 
			
		||||
 | 
			
		||||
			auto argv_range = MUST(VirtualRange::create_to_vaddr_range(
 | 
			
		||||
			auto argv_region = MUST(MemoryBackedRegion::create(
 | 
			
		||||
				process->page_table(),
 | 
			
		||||
				0x400000, KERNEL_OFFSET,
 | 
			
		||||
				needed_bytes,
 | 
			
		||||
				PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
 | 
			
		||||
				true
 | 
			
		||||
				{ .start = 0x400000, .end = KERNEL_OFFSET },
 | 
			
		||||
				MemoryRegion::Type::PRIVATE,
 | 
			
		||||
				PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
 | 
			
		||||
			));
 | 
			
		||||
 | 
			
		||||
			uintptr_t temp = argv_range->vaddr() + sizeof(char*) * 2;
 | 
			
		||||
			argv_range->copy_from(0, (uint8_t*)&temp, sizeof(char*));			
 | 
			
		||||
			uintptr_t temp = argv_region->vaddr() + sizeof(char*) * 2;
 | 
			
		||||
			MUST(argv_region->copy_data_to_region(0, (const uint8_t*)&temp, sizeof(char*)));
 | 
			
		||||
 | 
			
		||||
			temp = 0;
 | 
			
		||||
			argv_range->copy_from(sizeof(char*), (uint8_t*)&temp, sizeof(char*));	
 | 
			
		||||
			MUST(argv_region->copy_data_to_region(sizeof(char*), (const uint8_t*)&temp, sizeof(char*)));
 | 
			
		||||
 | 
			
		||||
			argv_range->copy_from(sizeof(char*) * 2, (const uint8_t*)path.data(), path.size());
 | 
			
		||||
			MUST(argv_region->copy_data_to_region(sizeof(char*) * 2, (const uint8_t*)path.data(), path.size()));
 | 
			
		||||
 | 
			
		||||
			MUST(process->m_mapped_ranges.push_back(BAN::move(argv_range)));
 | 
			
		||||
			MUST(process->m_mapped_regions.push_back(BAN::move(argv_region)));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		process->m_userspace_info.argc = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +173,8 @@ namespace Kernel
 | 
			
		|||
	Process::~Process()
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(m_threads.empty());
 | 
			
		||||
		ASSERT(m_mapped_ranges.empty());
 | 
			
		||||
		ASSERT(m_mapped_regions.empty());
 | 
			
		||||
		ASSERT(!m_loadable_elf);
 | 
			
		||||
		ASSERT(m_exit_status.waiting == 0);
 | 
			
		||||
		ASSERT(&PageTable::current() != m_page_table.ptr());
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -205,7 +207,8 @@ namespace Kernel
 | 
			
		|||
		m_open_file_descriptors.close_all();
 | 
			
		||||
 | 
			
		||||
		// NOTE: We must unmap ranges while the page table is still alive
 | 
			
		||||
		m_mapped_ranges.clear();
 | 
			
		||||
		m_mapped_regions.clear();
 | 
			
		||||
		m_loadable_elf.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void Process::on_thread_exit(Thread& thread)
 | 
			
		||||
| 
						 | 
				
			
			@ -318,10 +321,10 @@ namespace Kernel
 | 
			
		|||
		OpenFileDescriptorSet open_file_descriptors(m_credentials);
 | 
			
		||||
		TRY(open_file_descriptors.clone_from(m_open_file_descriptors));
 | 
			
		||||
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<VirtualRange>> mapped_ranges;
 | 
			
		||||
		TRY(mapped_ranges.reserve(m_mapped_ranges.size()));
 | 
			
		||||
		for (auto& mapped_range : m_mapped_ranges)
 | 
			
		||||
			MUST(mapped_ranges.push_back(TRY(mapped_range->clone(*page_table))));
 | 
			
		||||
		BAN::Vector<BAN::UniqPtr<MemoryRegion>> mapped_regions;
 | 
			
		||||
		TRY(mapped_regions.reserve(m_mapped_regions.size()));
 | 
			
		||||
		for (auto& mapped_region : m_mapped_regions)
 | 
			
		||||
			MUST(mapped_regions.push_back(TRY(mapped_region->clone(*page_table))));
 | 
			
		||||
 | 
			
		||||
		auto loadable_elf = TRY(m_loadable_elf->clone(*page_table));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +333,7 @@ namespace Kernel
 | 
			
		|||
		forked->m_working_directory = BAN::move(working_directory);
 | 
			
		||||
		forked->m_page_table = BAN::move(page_table);
 | 
			
		||||
		forked->m_open_file_descriptors = BAN::move(open_file_descriptors);
 | 
			
		||||
		forked->m_mapped_ranges = BAN::move(mapped_ranges);
 | 
			
		||||
		forked->m_mapped_regions = BAN::move(mapped_regions);
 | 
			
		||||
		forked->m_loadable_elf = BAN::move(loadable_elf);
 | 
			
		||||
		forked->m_is_userspace = m_is_userspace;
 | 
			
		||||
		forked->m_userspace_info = m_userspace_info;
 | 
			
		||||
| 
						 | 
				
			
			@ -373,7 +376,7 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
			m_open_file_descriptors.close_cloexec();
 | 
			
		||||
 | 
			
		||||
			m_mapped_ranges.clear();
 | 
			
		||||
			m_mapped_regions.clear();
 | 
			
		||||
			m_loadable_elf.clear();
 | 
			
		||||
 | 
			
		||||
			m_loadable_elf = TRY(load_elf_for_exec(m_credentials, executable_path, m_working_directory, page_table()));
 | 
			
		||||
| 
						 | 
				
			
			@ -387,8 +390,8 @@ namespace Kernel
 | 
			
		|||
			ASSERT(&Process::current() == this);
 | 
			
		||||
 | 
			
		||||
			// allocate memory on the new process for arguments and environment
 | 
			
		||||
			auto create_range =
 | 
			
		||||
				[&](const auto& container) -> BAN::UniqPtr<VirtualRange>
 | 
			
		||||
			auto create_region =
 | 
			
		||||
				[&](BAN::Span<BAN::String> container) -> BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>>
 | 
			
		||||
				{
 | 
			
		||||
					size_t bytes = sizeof(char*);
 | 
			
		||||
					for (auto& elem : container)
 | 
			
		||||
| 
						 | 
				
			
			@ -397,36 +400,36 @@ namespace Kernel
 | 
			
		|||
					if (auto rem = bytes % PAGE_SIZE)
 | 
			
		||||
						bytes += PAGE_SIZE - rem;
 | 
			
		||||
 | 
			
		||||
					auto range = MUST(VirtualRange::create_to_vaddr_range(
 | 
			
		||||
					auto region = TRY(MemoryBackedRegion::create(
 | 
			
		||||
						page_table(),
 | 
			
		||||
						0x400000, KERNEL_OFFSET,
 | 
			
		||||
						bytes,
 | 
			
		||||
						PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
 | 
			
		||||
						true
 | 
			
		||||
						{ .start = 0x400000, .end = KERNEL_OFFSET },
 | 
			
		||||
						MemoryRegion::Type::PRIVATE,
 | 
			
		||||
						PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
 | 
			
		||||
					));
 | 
			
		||||
 | 
			
		||||
					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());
 | 
			
		||||
						uintptr_t ptr_addr = region->vaddr() + data_offset;
 | 
			
		||||
						TRY(region->copy_data_to_region(sizeof(char*) * i, (const uint8_t*)&ptr_addr, sizeof(char*)));
 | 
			
		||||
						TRY(region->copy_data_to_region(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*));
 | 
			
		||||
					TRY(region->copy_data_to_region(sizeof(char*) * container.size(), (const uint8_t*)&null, sizeof(char*)));
 | 
			
		||||
 | 
			
		||||
					return BAN::move(range);
 | 
			
		||||
					return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
			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 argv_region = MUST(create_region(str_argv.span()));
 | 
			
		||||
			m_userspace_info.argv = (char**)argv_region->vaddr();
 | 
			
		||||
			MUST(m_mapped_regions.push_back(BAN::move(argv_region)));
 | 
			
		||||
 | 
			
		||||
			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)));
 | 
			
		||||
			auto envp_region = MUST(create_region(str_envp.span()));
 | 
			
		||||
			m_userspace_info.envp = (char**)envp_region->vaddr();
 | 
			
		||||
			MUST(m_mapped_regions.push_back(BAN::move(envp_region)));
 | 
			
		||||
 | 
			
		||||
			m_userspace_info.argc = str_argv.size();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -544,11 +547,11 @@ namespace Kernel
 | 
			
		|||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto& mapped_range : m_mapped_ranges)
 | 
			
		||||
		for (auto& region : m_mapped_regions)
 | 
			
		||||
		{
 | 
			
		||||
			if (!mapped_range->contains(address))
 | 
			
		||||
			if (!region->contains(address))
 | 
			
		||||
				continue;
 | 
			
		||||
			TRY(mapped_range->allocate_page_for_demand_paging(address));
 | 
			
		||||
			TRY(region->allocate_page_containing(address));
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -824,17 +827,17 @@ namespace Kernel
 | 
			
		|||
			if (args->len % PAGE_SIZE != 0)
 | 
			
		||||
				return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
			auto range = TRY(VirtualRange::create_to_vaddr_range(
 | 
			
		||||
			auto region = TRY(MemoryBackedRegion::create(
 | 
			
		||||
				page_table(),
 | 
			
		||||
				0x400000, KERNEL_OFFSET,
 | 
			
		||||
				args->len,
 | 
			
		||||
				PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
 | 
			
		||||
				false
 | 
			
		||||
				{ .start = 0x400000, .end = KERNEL_OFFSET },
 | 
			
		||||
				MemoryRegion::Type::PRIVATE,
 | 
			
		||||
				PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
 | 
			
		||||
			));
 | 
			
		||||
 | 
			
		||||
			LockGuard _(m_lock);
 | 
			
		||||
			TRY(m_mapped_ranges.push_back(BAN::move(range)));
 | 
			
		||||
			return m_mapped_ranges.back()->vaddr();
 | 
			
		||||
			TRY(m_mapped_regions.push_back(BAN::move(region)));
 | 
			
		||||
			return m_mapped_regions.back()->vaddr();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
| 
						 | 
				
			
			@ -851,13 +854,10 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
		LockGuard _(m_lock);
 | 
			
		||||
 | 
			
		||||
		for (size_t i = 0; i < m_mapped_ranges.size(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			auto& range = m_mapped_ranges[i];
 | 
			
		||||
			if (vaddr + len < range->vaddr() || vaddr >= range->vaddr() + range->size())
 | 
			
		||||
				continue;
 | 
			
		||||
			m_mapped_ranges.remove(i);
 | 
			
		||||
		}
 | 
			
		||||
		// FIXME: We should only map partial regions
 | 
			
		||||
		for (size_t i = 0; i < m_mapped_regions.size(); i++)
 | 
			
		||||
			if (m_mapped_regions[i]->overlaps(vaddr, len))
 | 
			
		||||
				m_mapped_regions.remove(i);
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -1341,10 +1341,11 @@ namespace Kernel
 | 
			
		|||
			return;
 | 
			
		||||
 | 
			
		||||
		// FIXME: should we allow cross mapping access?
 | 
			
		||||
		for (auto& mapped_range : m_mapped_ranges)
 | 
			
		||||
			if (vaddr >= mapped_range->vaddr() && vaddr + size <= mapped_range->vaddr() + mapped_range->size())
 | 
			
		||||
		for (auto& mapped_region : m_mapped_regions)
 | 
			
		||||
			mapped_region->contains_fully(vaddr, size);
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
		// FIXME: elf should contain full range [vaddr, vaddr + size)
 | 
			
		||||
		if (m_loadable_elf->contains(vaddr))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue