Kernel/LibC: Implement mprotect
There may be some race conditions with this but i think this is good enough to start with
This commit is contained in:
parent
eb7922ab88
commit
f1369c8fd6
|
@ -16,7 +16,11 @@ namespace Kernel
|
|||
virtual bool is_partition() const { return false; }
|
||||
virtual bool is_storage_device() const { return false; }
|
||||
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) { (void)offset; (void)len; return BAN::Error::from_errno(EINVAL); }
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t, int status_flags)
|
||||
{
|
||||
(void)offset; (void)len; (void)status_flags;
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
virtual dev_t rdev() const override = 0;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace Kernel
|
|||
void sync_pixels_linear(uint32_t first_pixel, uint32_t pixel_count);
|
||||
void sync_pixels_rectangle(uint32_t top_right_x, uint32_t top_right_y, uint32_t width, uint32_t height);
|
||||
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) override;
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t, int status_flags) override;
|
||||
|
||||
virtual dev_t rdev() const override { return m_rdev; }
|
||||
virtual BAN::StringView name() const override { return m_name.sv(); }
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Kernel
|
|||
|
||||
class FileBackedRegion;
|
||||
class FileSystem;
|
||||
class SharedFileData;
|
||||
struct SharedFileData;
|
||||
|
||||
class Inode : public BAN::RefCounted<Inode>
|
||||
{
|
||||
|
|
|
@ -27,18 +27,18 @@ namespace Kernel
|
|||
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);
|
||||
static BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> create(BAN::RefPtr<Inode>, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t, int status_flags);
|
||||
~FileBackedRegion();
|
||||
|
||||
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override;
|
||||
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override;
|
||||
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
|
||||
BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
|
||||
|
||||
private:
|
||||
FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type flags, PageTable::flags_t page_flags);
|
||||
FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type type, PageTable::flags_t flags, int status_flags);
|
||||
|
||||
private:
|
||||
BAN::RefPtr<Inode> m_inode;
|
||||
|
|
|
@ -11,22 +11,22 @@ namespace Kernel
|
|||
BAN_NON_MOVABLE(MemoryBackedRegion);
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t);
|
||||
static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t, int status_flags);
|
||||
~MemoryBackedRegion();
|
||||
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||
|
||||
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
|
||||
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
|
||||
|
||||
// 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);
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
|
||||
BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
|
||||
|
||||
private:
|
||||
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t);
|
||||
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,10 @@ namespace Kernel
|
|||
size_t size() const { return m_size; }
|
||||
vaddr_t vaddr() const { return m_vaddr; }
|
||||
|
||||
int status_flags() const { return m_status_flags; }
|
||||
Type type() const { return m_type; }
|
||||
PageTable::flags_t flags() const { return m_flags; }
|
||||
|
||||
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
|
||||
size_t physical_page_count() const { return m_physical_page_count; }
|
||||
|
||||
|
@ -46,6 +50,7 @@ namespace Kernel
|
|||
void unpin();
|
||||
void wait_not_pinned();
|
||||
|
||||
BAN::ErrorOr<void> mprotect(PageTable::flags_t);
|
||||
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
|
||||
|
||||
// Returns error if no memory was available
|
||||
|
@ -56,7 +61,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0;
|
||||
|
||||
protected:
|
||||
MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags);
|
||||
MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags, int status_flags);
|
||||
BAN::ErrorOr<void> initialize(AddressRange);
|
||||
|
||||
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t address, bool wants_write) = 0;
|
||||
|
@ -65,7 +70,8 @@ namespace Kernel
|
|||
PageTable& m_page_table;
|
||||
const size_t m_size;
|
||||
const Type m_type;
|
||||
const PageTable::flags_t m_flags;
|
||||
PageTable::flags_t m_flags;
|
||||
const int m_status_flags;
|
||||
vaddr_t m_vaddr { 0 };
|
||||
size_t m_physical_page_count { 0 };
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/Memory/MemoryRegion.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
@ -55,15 +57,16 @@ namespace Kernel
|
|||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
|
||||
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
|
||||
|
||||
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
|
||||
BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
|
||||
|
||||
private:
|
||||
SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table)
|
||||
: MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags)
|
||||
: MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags, O_EXEC | O_RDWR)
|
||||
, m_object(object)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace Kernel
|
|||
|
||||
bool contains(vaddr_t address) const { return vaddr() <= address && address < vaddr() + size(); }
|
||||
|
||||
BAN::ErrorOr<void> allocate_page_for_demand_paging(vaddr_t address);
|
||||
BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t address);
|
||||
|
||||
private:
|
||||
VirtualRange(PageTable&, bool preallocated, bool has_guard_pages, vaddr_t, size_t, PageTable::flags_t);
|
||||
|
|
|
@ -170,6 +170,7 @@ 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_mprotect(void* addr, size_t len, int prot);
|
||||
BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags);
|
||||
|
||||
BAN::ErrorOr<long> sys_smo_create(size_t len, int prot);
|
||||
|
|
|
@ -241,9 +241,9 @@ namespace Kernel
|
|||
class FramebufferMemoryRegion : public MemoryRegion
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<FramebufferMemoryRegion>> create(PageTable& page_table, size_t size, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
|
||||
static BAN::ErrorOr<BAN::UniqPtr<FramebufferMemoryRegion>> create(PageTable& page_table, size_t size, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
|
||||
{
|
||||
auto* region_ptr = new FramebufferMemoryRegion(page_table, size, region_type, page_flags, framebuffer);
|
||||
auto* region_ptr = new FramebufferMemoryRegion(page_table, size, region_type, page_flags, status_flags, framebuffer);
|
||||
if (region_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr);
|
||||
|
@ -258,7 +258,7 @@ namespace Kernel
|
|||
m_framebuffer->sync_pixels_full();
|
||||
}
|
||||
|
||||
virtual BAN::ErrorOr<void> msync(vaddr_t vaddr, size_t size, int flags) override
|
||||
BAN::ErrorOr<void> msync(vaddr_t vaddr, size_t size, int flags) override
|
||||
{
|
||||
if (flags != MS_SYNC)
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
|
@ -281,9 +281,9 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override
|
||||
{
|
||||
auto* region_ptr = new FramebufferMemoryRegion(new_page_table, m_size, m_type, m_flags, m_framebuffer);
|
||||
auto* region_ptr = new FramebufferMemoryRegion(new_page_table, m_size, m_type, m_flags, m_status_flags, m_framebuffer);
|
||||
if (region_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr);
|
||||
|
@ -297,7 +297,7 @@ namespace Kernel
|
|||
// 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_impl(vaddr_t vaddr, bool wants_write) override
|
||||
BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override
|
||||
{
|
||||
(void)wants_write;
|
||||
|
||||
|
@ -312,8 +312,8 @@ namespace Kernel
|
|||
}
|
||||
|
||||
private:
|
||||
FramebufferMemoryRegion(PageTable& page_table, size_t size, MemoryRegion::Type region_type, PageTable::flags_t page_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
|
||||
: MemoryRegion(page_table, size, region_type, page_flags)
|
||||
FramebufferMemoryRegion(PageTable& page_table, size_t size, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
|
||||
: MemoryRegion(page_table, size, region_type, page_flags, status_flags)
|
||||
, m_framebuffer(framebuffer)
|
||||
{ }
|
||||
|
||||
|
@ -370,7 +370,7 @@ namespace Kernel
|
|||
BAN::RefPtr<FramebufferDevice> m_framebuffer;
|
||||
};
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FramebufferDevice::mmap_region(PageTable& page_table, off_t offset, size_t len, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags)
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FramebufferDevice::mmap_region(PageTable& page_table, off_t offset, size_t len, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags)
|
||||
{
|
||||
if (offset != 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
@ -379,7 +379,7 @@ namespace Kernel
|
|||
if (region_type != MemoryRegion::Type::SHARED)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto region = TRY(FramebufferMemoryRegion::create(page_table, len, address_range, region_type, page_flags, this));
|
||||
auto region = TRY(FramebufferMemoryRegion::create(page_table, len, address_range, region_type, page_flags, status_flags, this));
|
||||
return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ namespace Kernel::ELF
|
|||
file_backed_size,
|
||||
{ .start = pheader_base, .end = pheader_base + file_backed_size },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
flags
|
||||
flags, O_EXEC | O_RDWR
|
||||
));
|
||||
TRY(memory_regions.emplace_back(BAN::move(region)));
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ namespace Kernel::ELF
|
|||
(pheader_base + program_header.p_memsz) - (aligned_vaddr + file_backed_size),
|
||||
{ .start = aligned_vaddr + file_backed_size, .end = pheader_base + program_header.p_memsz },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
flags
|
||||
flags, O_EXEC | O_RDWR
|
||||
));
|
||||
|
||||
if (file_backed_size < program_header.p_filesz)
|
||||
|
@ -267,7 +267,8 @@ namespace Kernel::ELF
|
|||
offset + region_size,
|
||||
{ .start = last_loaded_address, .end = USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::Present
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::Present,
|
||||
O_EXEC | O_RDWR
|
||||
));
|
||||
|
||||
for (vaddr_t vaddr = region->vaddr(); vaddr < region->vaddr() + offset + region->size(); vaddr += PAGE_SIZE)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
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)
|
||||
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, int status_flags)
|
||||
{
|
||||
ASSERT(inode->mode().ifreg());
|
||||
|
||||
|
@ -16,14 +16,14 @@ namespace Kernel
|
|||
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);
|
||||
auto* region_ptr = new FileBackedRegion(inode, page_table, offset, size, type, flags, status_flags);
|
||||
if (region_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto region = BAN::UniqPtr<FileBackedRegion>::adopt(region_ptr);
|
||||
|
||||
TRY(region->initialize(address_range));
|
||||
|
||||
if (type == Type::PRIVATE && (flags & PageTable::Flags::ReadWrite))
|
||||
if (type == Type::PRIVATE)
|
||||
TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE)));
|
||||
|
||||
LockGuard _(inode->m_mutex);
|
||||
|
@ -39,8 +39,8 @@ namespace Kernel
|
|||
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)
|
||||
FileBackedRegion::FileBackedRegion(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, ssize_t size, Type type, PageTable::flags_t flags, int status_flags)
|
||||
: MemoryRegion(page_table, size, type, flags, status_flags)
|
||||
, m_inode(inode)
|
||||
, m_offset(offset)
|
||||
{
|
||||
|
@ -200,7 +200,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::clone(PageTable& page_table)
|
||||
{
|
||||
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
||||
auto result = TRY(FileBackedRegion::create(m_inode, page_table, m_offset, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags));
|
||||
auto result = TRY(FileBackedRegion::create(m_inode, page_table, m_offset, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
|
||||
|
||||
// non-dirty pages can go through demand paging
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> MemoryBackedRegion::create(PageTable& page_table, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags)
|
||||
BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> MemoryBackedRegion::create(PageTable& page_table, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags, int status_flags)
|
||||
{
|
||||
if (type != Type::PRIVATE)
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
|
||||
auto* region_ptr = new MemoryBackedRegion(page_table, size, type, flags);
|
||||
auto* region_ptr = new MemoryBackedRegion(page_table, size, type, flags, status_flags);
|
||||
if (region_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
|
||||
|
@ -19,8 +19,8 @@ namespace Kernel
|
|||
return region;
|
||||
}
|
||||
|
||||
MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags)
|
||||
: MemoryRegion(page_table, size, type, flags)
|
||||
MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags, int status_flags)
|
||||
: MemoryRegion(page_table, size, type, flags, status_flags)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ namespace Kernel
|
|||
ASSERT(&PageTable::current() == &m_page_table);
|
||||
|
||||
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
|
||||
auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags));
|
||||
auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
|
||||
|
||||
for (size_t offset = 0; offset < m_size; offset += PAGE_SIZE)
|
||||
{
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
MemoryRegion::MemoryRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags)
|
||||
MemoryRegion::MemoryRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags, int status_flags)
|
||||
: m_page_table(page_table)
|
||||
, m_size(size)
|
||||
, m_type(type)
|
||||
, m_flags(flags)
|
||||
, m_status_flags(status_flags)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -49,6 +50,25 @@ namespace Kernel
|
|||
return true;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> MemoryRegion::mprotect(PageTable::flags_t new_page_flags)
|
||||
{
|
||||
if (m_flags == new_page_flags)
|
||||
return {};
|
||||
|
||||
const size_t page_count = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
const vaddr_t vaddr = m_vaddr + i * PAGE_SIZE;
|
||||
const paddr_t paddr = m_page_table.physical_address_of(vaddr);
|
||||
if (paddr == 0)
|
||||
continue;
|
||||
m_page_table.map_page_at(paddr, vaddr, new_page_flags);
|
||||
}
|
||||
|
||||
m_flags = new_page_flags;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<bool> MemoryRegion::allocate_page_containing(vaddr_t address, bool wants_write)
|
||||
{
|
||||
ASSERT(contains(address));
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace Kernel
|
|||
else
|
||||
{
|
||||
const size_t page_count = size() / PAGE_SIZE;
|
||||
for (size_t i = m_has_guard_pages; i < page_count; i++)
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
PageTable::with_fast_page(m_paddrs[i], [&] {
|
||||
memset(PageTable::fast_page_as_ptr(), 0, PAGE_SIZE);
|
||||
|
@ -120,7 +120,7 @@ namespace Kernel
|
|||
auto result = TRY(create_to_vaddr(page_table, vaddr(), size(), m_flags, m_preallocated, m_has_guard_pages));
|
||||
|
||||
const size_t page_count = size() / PAGE_SIZE;
|
||||
for (size_t i = m_has_guard_pages; i < page_count; i++)
|
||||
for (size_t i = 0; i < page_count; i++)
|
||||
{
|
||||
if (m_paddrs[i] == 0)
|
||||
continue;
|
||||
|
@ -140,15 +140,17 @@ namespace Kernel
|
|||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
|
||||
BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
|
||||
{
|
||||
ASSERT(!m_preallocated);
|
||||
ASSERT(vaddr % PAGE_SIZE == 0);
|
||||
ASSERT(contains(vaddr));
|
||||
ASSERT(&PageTable::current() == &m_page_table);
|
||||
|
||||
if (m_preallocated)
|
||||
return false;
|
||||
|
||||
const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE;
|
||||
ASSERT(m_paddrs[index] == 0);
|
||||
if (m_paddrs[index])
|
||||
return false;
|
||||
|
||||
SpinLockGuard _(m_lock);
|
||||
|
||||
|
@ -159,7 +161,7 @@ namespace Kernel
|
|||
m_page_table.map_page_at(m_paddrs[index], vaddr, m_flags);
|
||||
memset(reinterpret_cast<void*>(vaddr), 0, PAGE_SIZE);
|
||||
|
||||
return {};
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -318,7 +318,8 @@ namespace Kernel
|
|||
tls_size,
|
||||
{ .start = master_addr, .end = USERSPACE_END },
|
||||
MemoryRegion::Type::PRIVATE,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
O_EXEC | O_RDWR
|
||||
));
|
||||
|
||||
BAN::Vector<uint8_t> temp_buffer;
|
||||
|
@ -2146,7 +2147,8 @@ namespace Kernel
|
|||
page_table(),
|
||||
args.len,
|
||||
address_range,
|
||||
region_type, page_flags
|
||||
region_type, page_flags,
|
||||
O_EXEC | O_RDWR
|
||||
));
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
|
@ -2173,7 +2175,8 @@ namespace Kernel
|
|||
page_table(),
|
||||
args.off, args.len,
|
||||
address_range,
|
||||
region_type, page_flags
|
||||
region_type, page_flags,
|
||||
status_flags
|
||||
));
|
||||
}
|
||||
else if (inode->is_device())
|
||||
|
@ -2182,7 +2185,8 @@ namespace Kernel
|
|||
page_table(),
|
||||
args.off, args.len,
|
||||
address_range,
|
||||
region_type, page_flags
|
||||
region_type, page_flags,
|
||||
status_flags
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -2228,6 +2232,70 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_mprotect(void* addr, size_t len, int prot)
|
||||
{
|
||||
if (len == 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
|
||||
if (vaddr % PAGE_SIZE != 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (auto rem = len % PAGE_SIZE)
|
||||
len += PAGE_SIZE - rem;
|
||||
|
||||
PageTable::flags_t flags = 0;
|
||||
if (prot & PROT_READ)
|
||||
flags |= PageTable::Flags::Present;
|
||||
if (prot & PROT_WRITE)
|
||||
flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
|
||||
if (prot & PROT_EXEC)
|
||||
flags |= PageTable::Flags::Execute | PageTable::Flags::Execute;
|
||||
|
||||
if (flags == 0)
|
||||
flags = PageTable::Flags::Reserved;
|
||||
else
|
||||
flags |= PageTable::Flags::UserSupervisor;
|
||||
|
||||
LockGuard _(m_process_lock);
|
||||
|
||||
// FIXME: We should protect partial regions.
|
||||
// This is a hack to only protect if the whole mmap region
|
||||
// is contained within [addr, addr + len]
|
||||
for (size_t i = 0; i < m_mapped_regions.size(); i++)
|
||||
{
|
||||
auto& region = m_mapped_regions[i];
|
||||
|
||||
const vaddr_t region_s = region->vaddr();
|
||||
const vaddr_t region_e = region->vaddr() + region->size();
|
||||
if (vaddr <= region_s && region_e <= vaddr + len)
|
||||
{
|
||||
const bool is_shared = (region->type() == MemoryRegion::Type::SHARED);
|
||||
const bool is_writable = (region->status_flags() & O_WRONLY);
|
||||
const bool want_write = (prot & PROT_WRITE);
|
||||
if (is_shared && want_write && !is_writable)
|
||||
return BAN::Error::from_errno(EACCES);
|
||||
|
||||
// FIXME: if the region is pinned writable, this may
|
||||
// cause some problems :D
|
||||
TRY(region->mprotect(flags));
|
||||
}
|
||||
else if (region->overlaps(vaddr, len))
|
||||
{
|
||||
const bool is_shared = (region->type() == MemoryRegion::Type::SHARED);
|
||||
const bool is_writable = (region->status_flags() & O_WRONLY);
|
||||
const bool want_write = (prot & PROT_WRITE);
|
||||
if (is_shared && want_write && !is_writable)
|
||||
return BAN::Error::from_errno(EACCES);
|
||||
|
||||
dwarnln("TODO: partial region mprotect");
|
||||
TRY(region->mprotect(flags | region->flags()));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_msync(void* addr, size_t len, int flags)
|
||||
{
|
||||
if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE)
|
||||
|
|
|
@ -52,6 +52,7 @@ __BEGIN_DECLS
|
|||
O(SYS_SYNC, sync) \
|
||||
O(SYS_MMAP, mmap) \
|
||||
O(SYS_MUNMAP, munmap) \
|
||||
O(SYS_MPROTECT, mprotect) \
|
||||
O(SYS_TTY_CTRL, tty_ctrl) \
|
||||
O(SYS_POWEROFF, poweroff) \
|
||||
O(SYS_FCHMODAT, fchmodat) \
|
||||
|
|
|
@ -24,6 +24,11 @@ int munmap(void* addr, size_t len)
|
|||
return syscall(SYS_MUNMAP, addr, len);
|
||||
}
|
||||
|
||||
int mprotect(void* addr, size_t len, int prot)
|
||||
{
|
||||
return syscall(SYS_MPROTECT, addr, len, prot);
|
||||
}
|
||||
|
||||
int msync(void* addr, size_t len, int flags)
|
||||
{
|
||||
pthread_testcancel();
|
||||
|
@ -45,8 +50,3 @@ int mlock(const void*, size_t)
|
|||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
int mprotect(void*, size_t, int)
|
||||
{
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue