forked from Bananymous/banan-os
				
			
			update main #1
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -32,6 +32,7 @@ set(KERNEL_SOURCES
 | 
			
		|||
	kernel/Input/PS2Keymap.cpp
 | 
			
		||||
	kernel/InterruptController.cpp
 | 
			
		||||
	kernel/kernel.cpp
 | 
			
		||||
	kernel/Memory/FileBackedRegion.cpp
 | 
			
		||||
	kernel/Memory/GeneralAllocator.cpp
 | 
			
		||||
	kernel/Memory/Heap.cpp
 | 
			
		||||
	kernel/Memory/kmalloc.cpp
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <kernel/FS/Inode.h>
 | 
			
		||||
#include <kernel/Memory/MemoryRegion.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	class FileBackedRegion final : public MemoryRegion
 | 
			
		||||
	{
 | 
			
		||||
		BAN_NON_COPYABLE(FileBackedRegion);
 | 
			
		||||
		BAN_NON_MOVABLE(FileBackedRegion);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		static BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> create(BAN::RefPtr<Inode>, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t);
 | 
			
		||||
		~FileBackedRegion();
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<bool> allocate_page_containing(vaddr_t vaddr) override;
 | 
			
		||||
 | 
			
		||||
		virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type flags, PageTable::flags_t page_flags);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		BAN::RefPtr<Inode> m_inode;
 | 
			
		||||
		const off_t m_offset;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ namespace Kernel
 | 
			
		|||
		BAN_NON_MOVABLE(MemoryRegion);
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		enum Type : uint8_t
 | 
			
		||||
		enum class Type : uint8_t
 | 
			
		||||
		{
 | 
			
		||||
			PRIVATE,
 | 
			
		||||
			SHARED
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,7 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
		BAN::ErrorOr<BAN::StringView> path_of(int) const;
 | 
			
		||||
		BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
 | 
			
		||||
		BAN::ErrorOr<int> flags_of(int) const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		struct OpenFileDescription : public BAN::RefCounted<OpenFileDescription>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,112 @@
 | 
			
		|||
#include <kernel/LockGuard.h>
 | 
			
		||||
#include <kernel/Memory/FileBackedRegion.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
 | 
			
		||||
namespace Kernel
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> FileBackedRegion::create(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(inode->mode().ifreg());
 | 
			
		||||
 | 
			
		||||
		if (type != Type::PRIVATE)
 | 
			
		||||
			return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
		if (offset < 0 || offset % PAGE_SIZE || size == 0)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		if (size > (size_t)inode->size() || (size_t)offset > (size_t)inode->size() - size)
 | 
			
		||||
			return BAN::Error::from_errno(EOVERFLOW);
 | 
			
		||||
 | 
			
		||||
		auto* region_ptr = new FileBackedRegion(inode, page_table, offset, size, type, flags);
 | 
			
		||||
		if (region_ptr == nullptr)
 | 
			
		||||
			return BAN::Error::from_errno(ENOMEM);
 | 
			
		||||
		auto region = BAN::UniqPtr<FileBackedRegion>::adopt(region_ptr);
 | 
			
		||||
 | 
			
		||||
		TRY(region->initialize(address_range));
 | 
			
		||||
 | 
			
		||||
		return region;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FileBackedRegion::FileBackedRegion(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, ssize_t size, Type type, PageTable::flags_t flags)
 | 
			
		||||
		: MemoryRegion(page_table, size, type, flags)
 | 
			
		||||
		, m_inode(inode)
 | 
			
		||||
		, m_offset(offset)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	FileBackedRegion::~FileBackedRegion()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_vaddr == 0)
 | 
			
		||||
			return;
 | 
			
		||||
		
 | 
			
		||||
		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> FileBackedRegion::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);
 | 
			
		||||
 | 
			
		||||
		size_t file_offset = m_offset + (vaddr - m_vaddr);
 | 
			
		||||
		size_t bytes = BAN::Math::min<size_t>(m_size - file_offset, PAGE_SIZE);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<size_t> read_ret = 0;
 | 
			
		||||
 | 
			
		||||
		// Zero out the new page
 | 
			
		||||
		if (&PageTable::current() == &m_page_table)
 | 
			
		||||
			read_ret = m_inode->read(file_offset, (void*)vaddr, bytes);
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			LockGuard _(PageTable::current());
 | 
			
		||||
			ASSERT(PageTable::current().is_page_free(0));
 | 
			
		||||
 | 
			
		||||
			PageTable::current().map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
 | 
			
		||||
			read_ret = m_inode->read(file_offset, (void*)0, bytes);
 | 
			
		||||
			memset((void*)0, 0x00, PAGE_SIZE);
 | 
			
		||||
			PageTable::current().unmap_page(0);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (read_ret.is_error())
 | 
			
		||||
		{
 | 
			
		||||
			Heap::get().release_page(paddr);
 | 
			
		||||
			m_page_table.unmap_page(vaddr);
 | 
			
		||||
			return read_ret.release_error();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (read_ret.value() < bytes)
 | 
			
		||||
		{
 | 
			
		||||
			dwarnln("Only {}/{} bytes read", read_ret.value(), bytes);
 | 
			
		||||
			Heap::get().release_page(paddr);
 | 
			
		||||
			m_page_table.unmap_page(vaddr);
 | 
			
		||||
			return BAN::Error::from_errno(EIO);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::clone(PageTable& new_page_table)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT_NOT_REACHED();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,13 +1,14 @@
 | 
			
		|||
#include <kernel/LockGuard.h>
 | 
			
		||||
#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);
 | 
			
		||||
		if (type != Type::PRIVATE)
 | 
			
		||||
			return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
		auto* region_ptr = new MemoryBackedRegion(page_table, size, type, flags);
 | 
			
		||||
		if (region_ptr == nullptr)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -309,6 +309,12 @@ namespace Kernel
 | 
			
		|||
		return m_open_files[fd]->inode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<int> OpenFileDescriptorSet::flags_of(int fd) const
 | 
			
		||||
	{
 | 
			
		||||
		TRY(validate_fd(fd));
 | 
			
		||||
		return m_open_files[fd]->flags;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
 | 
			
		||||
	{
 | 
			
		||||
		if (fd < 0 || fd >= (int)m_open_files.size())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@
 | 
			
		|||
#include <kernel/IDT.h>
 | 
			
		||||
#include <kernel/InterruptController.h>
 | 
			
		||||
#include <kernel/LockGuard.h>
 | 
			
		||||
#include <kernel/Memory/FileBackedRegion.h>
 | 
			
		||||
#include <kernel/Memory/Heap.h>
 | 
			
		||||
#include <kernel/Memory/MemoryBackedRegion.h>
 | 
			
		||||
#include <kernel/Memory/PageTableScope.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -810,29 +811,64 @@ namespace Kernel
 | 
			
		|||
		if (args->prot != PROT_NONE && args->prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		PageTable::flags_t flags = PageTable::Flags::UserSupervisor;
 | 
			
		||||
		if (args->prot & PROT_READ)
 | 
			
		||||
			flags |= PageTable::Flags::Present;
 | 
			
		||||
		if (args->prot & PROT_WRITE)
 | 
			
		||||
			flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
 | 
			
		||||
		if (args->prot & PROT_EXEC)
 | 
			
		||||
			flags |= PageTable::Flags::Execute | PageTable::Flags::Present;
 | 
			
		||||
		if (args->flags & MAP_FIXED)
 | 
			
		||||
			return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
		if (args->flags == (MAP_ANONYMOUS | MAP_PRIVATE))
 | 
			
		||||
		if (!(args->flags & MAP_PRIVATE) == !(args->flags & MAP_SHARED))
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
		auto region_type = (args->flags & MAP_PRIVATE) ? MemoryRegion::Type::PRIVATE : MemoryRegion::Type::SHARED;
 | 
			
		||||
 | 
			
		||||
		PageTable::flags_t page_flags = 0;
 | 
			
		||||
		if (args->prot & PROT_READ)
 | 
			
		||||
			page_flags |= PageTable::Flags::Present;
 | 
			
		||||
		if (args->prot & PROT_WRITE)
 | 
			
		||||
			page_flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
 | 
			
		||||
		if (args->prot & PROT_EXEC)
 | 
			
		||||
			page_flags |= PageTable::Flags::Execute | PageTable::Flags::Present;
 | 
			
		||||
 | 
			
		||||
		if (page_flags == 0)
 | 
			
		||||
			page_flags = PageTable::Flags::Reserved;
 | 
			
		||||
		else
 | 
			
		||||
			page_flags |= PageTable::Flags::UserSupervisor;
 | 
			
		||||
 | 
			
		||||
		if (args->flags & MAP_ANONYMOUS)
 | 
			
		||||
		{
 | 
			
		||||
			if (args->addr != nullptr)
 | 
			
		||||
				return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
			if (args->off != 0)
 | 
			
		||||
				return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
			if (args->len % PAGE_SIZE != 0)
 | 
			
		||||
				return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
			auto region = TRY(MemoryBackedRegion::create(
 | 
			
		||||
				page_table(),
 | 
			
		||||
				args->len,
 | 
			
		||||
				{ .start = 0x400000, .end = KERNEL_OFFSET },
 | 
			
		||||
				MemoryRegion::Type::PRIVATE,
 | 
			
		||||
				PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
 | 
			
		||||
				region_type, page_flags
 | 
			
		||||
			));
 | 
			
		||||
 | 
			
		||||
			LockGuard _(m_lock);
 | 
			
		||||
			TRY(m_mapped_regions.push_back(BAN::move(region)));
 | 
			
		||||
			return m_mapped_regions.back()->vaddr();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		auto inode = TRY(m_open_file_descriptors.inode_of(args->fildes));
 | 
			
		||||
		if (inode->mode().ifreg())
 | 
			
		||||
		{
 | 
			
		||||
			if (args->addr != nullptr)
 | 
			
		||||
				return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
			auto inode_flags = TRY(m_open_file_descriptors.flags_of(args->fildes));
 | 
			
		||||
			if (!(inode_flags & O_RDONLY))
 | 
			
		||||
				return BAN::Error::from_errno(EACCES);
 | 
			
		||||
			if (region_type == MemoryRegion::Type::SHARED)
 | 
			
		||||
				if (!(args->prot & PROT_WRITE) || !(inode_flags & O_WRONLY))
 | 
			
		||||
					return BAN::Error::from_errno(EACCES);
 | 
			
		||||
			
 | 
			
		||||
			auto region = TRY(FileBackedRegion::create(
 | 
			
		||||
				inode,
 | 
			
		||||
				page_table(),
 | 
			
		||||
				args->off, args->len,
 | 
			
		||||
				{ .start = 0x400000, .end = KERNEL_OFFSET },
 | 
			
		||||
				region_type, page_flags
 | 
			
		||||
			));
 | 
			
		||||
 | 
			
		||||
			LockGuard _(m_lock);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue