core: Respect memory permissions in Map

This commit is contained in:
GPUCode
2023-11-17 21:43:15 +02:00
committed by t895
parent 4766baddf3
commit 5938a9582a
6 changed files with 117 additions and 58 deletions

View File

@ -88,6 +88,20 @@ Result FlushDataCache(AddressType addr, u64 size) {
R_SUCCEED();
}
constexpr Common::MemoryPermission ConvertToMemoryPermission(KMemoryPermission perm) {
Common::MemoryPermission perms{};
if (True(perm & KMemoryPermission::UserRead)) {
perms |= Common::MemoryPermission::Read;
}
if (True(perm & KMemoryPermission::UserWrite)) {
perms |= Common::MemoryPermission::Write;
}
if (True(perm & KMemoryPermission::UserExecute)) {
perms |= Common::MemoryPermission::Execute;
}
return perms;
}
} // namespace
void KPageTableBase::MemoryRange::Open() {
@ -5643,7 +5657,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
case OperationType::Map: {
ASSERT(virt_addr != 0);
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr);
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
ConvertToMemoryPermission(properties.perm));
// Open references to pages, if we should.
if (this->IsHeapPhysicalAddress(phys_addr)) {
@ -5658,8 +5673,18 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
}
case OperationType::ChangePermissions:
case OperationType::ChangePermissionsAndRefresh:
case OperationType::ChangePermissionsAndRefreshAndFlush:
case OperationType::ChangePermissionsAndRefreshAndFlush: {
const bool read = True(properties.perm & Kernel::KMemoryPermission::UserRead);
const bool write = True(properties.perm & Kernel::KMemoryPermission::UserWrite);
// todo: this doesn't really belong here and should go into m_memory to handle rasterizer
// access todo: ignore exec on non-direct-mapped case
const bool exec = True(properties.perm & Kernel::KMemoryPermission::UserExecute);
if (Settings::IsFastmemEnabled()) {
m_system.DeviceMemory().buffer.Protect(GetInteger(virt_addr), num_pages * PageSize,
read, write, exec);
}
R_SUCCEED();
}
default:
UNREACHABLE();
}
@ -5687,7 +5712,8 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
const size_t size{node.GetNumPages() * PageSize};
// Map the pages.
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress());
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
ConvertToMemoryPermission(properties.perm));
virt_addr += size;
}

View File

@ -53,7 +53,7 @@ struct Memory::Impl {
}
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target) {
Common::PhysicalAddress target, Common::MemoryPermission perms) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}",
@ -63,7 +63,7 @@ struct Memory::Impl {
if (Settings::IsFastmemEnabled()) {
system.DeviceMemory().buffer.Map(GetInteger(base),
GetInteger(target) - DramMemoryMap::Base, size);
GetInteger(target) - DramMemoryMap::Base, size, perms);
}
}
@ -831,8 +831,8 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
}
void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target) {
impl->MapMemoryRegion(page_table, base, size, target);
Common::PhysicalAddress target, Common::MemoryPermission perms) {
impl->MapMemoryRegion(page_table, base, size, target, perms);
}
void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) {

View File

@ -15,8 +15,9 @@
#include "core/hle/result.h"
namespace Common {
enum class MemoryPermission : u32;
struct PageTable;
}
} // namespace Common
namespace Core {
class System;
@ -82,9 +83,10 @@ public:
* @param size The amount of bytes to map. Must be page-aligned.
* @param target Buffer with the memory backing the mapping. Must be of length at least
* `size`.
* @param perms The permissions to map the memory with.
*/
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
Common::PhysicalAddress target);
Common::PhysicalAddress target, Common::MemoryPermission perms);
/**
* Unmaps a region of the emulated process address space.