Kernel/Process: implement prvileged Map/Unmap
This is used by svcControlProcessMemory and maps memory as Locked/AliasCode pair. Also fixed a bug where map didn't apply specified permissions to the alias memory
This commit is contained in:
parent
f43524fff1
commit
617b388354
|
@ -303,7 +303,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
|||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perms) {
|
||||
ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perms,
|
||||
bool privileged) {
|
||||
LOG_DEBUG(Kernel, "Map memory target={:08X}, source={:08X}, size={:08X}, perms={:08X}", target,
|
||||
source, size, static_cast<u8>(perms));
|
||||
if (source < Memory::HEAP_VADDR || source + size > Memory::HEAP_VADDR_END ||
|
||||
|
@ -320,22 +321,39 @@ ResultCode Process::Map(VAddr target, VAddr source, u32 size, VMAPermission perm
|
|||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
if (source == target) {
|
||||
if (privileged) {
|
||||
// privileged Map allows identical source and target address, which simply changes the
|
||||
// state and the permission of the memory
|
||||
return vm_manager.ChangeMemoryState(source, size, MemoryState::Private,
|
||||
VMAPermission::ReadWrite, MemoryState::AliasCode,
|
||||
perms);
|
||||
}
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
MemoryState source_state = privileged ? MemoryState::Locked : MemoryState::Aliased;
|
||||
MemoryState target_state = privileged ? MemoryState::AliasCode : MemoryState::Alias;
|
||||
VMAPermission source_perm = privileged ? VMAPermission::None : VMAPermission::ReadWrite;
|
||||
|
||||
// Mark source region as Aliased
|
||||
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Private,
|
||||
VMAPermission::ReadWrite, MemoryState::Aliased,
|
||||
VMAPermission::ReadWrite));
|
||||
VMAPermission::ReadWrite, source_state, source_perm));
|
||||
|
||||
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size));
|
||||
VAddr interval_target = target;
|
||||
for (const auto [backing_memory, block_size] : backing_blocks) {
|
||||
auto target_vma = vm_manager.MapBackingMemory(interval_target, backing_memory, block_size,
|
||||
MemoryState::Alias);
|
||||
auto target_vma =
|
||||
vm_manager.MapBackingMemory(interval_target, backing_memory, block_size, target_state);
|
||||
ASSERT(target_vma.Succeeded());
|
||||
vm_manager.Reprotect(target_vma.Unwrap(), perms);
|
||||
interval_target += block_size;
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission perms) {
|
||||
ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission perms,
|
||||
bool privileged) {
|
||||
LOG_DEBUG(Kernel, "Unmap memory target={:08X}, source={:08X}, size={:08X}, perms={:08X}",
|
||||
target, source, size, static_cast<u8>(perms));
|
||||
if (source < Memory::HEAP_VADDR || source + size > Memory::HEAP_VADDR_END ||
|
||||
|
@ -349,11 +367,23 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
|
|||
// TODO(wwylele): check that the source and the target are actually a pair created by Map
|
||||
// Should return error 0xD8E007F5 in this case
|
||||
|
||||
if (source == target) {
|
||||
if (privileged) {
|
||||
// privileged Unmap allows identical source and target address, which simply changes
|
||||
// the state and the permission of the memory
|
||||
return vm_manager.ChangeMemoryState(source, size, MemoryState::AliasCode,
|
||||
VMAPermission::None, MemoryState::Private, perms);
|
||||
}
|
||||
return ERR_INVALID_ADDRESS_STATE;
|
||||
}
|
||||
|
||||
MemoryState source_state = privileged ? MemoryState::Locked : MemoryState::Aliased;
|
||||
|
||||
CASCADE_CODE(vm_manager.UnmapRange(target, size));
|
||||
|
||||
// Change back source region state. Note that the permission is reprotected according to param
|
||||
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Aliased,
|
||||
VMAPermission::None, MemoryState::Private, perms));
|
||||
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, source_state, VMAPermission::None,
|
||||
MemoryState::Private, perms));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -188,8 +188,10 @@ public:
|
|||
ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
|
||||
ResultCode LinearFree(VAddr target, u32 size);
|
||||
|
||||
ResultCode Map(VAddr target, VAddr source, u32 size, VMAPermission perms);
|
||||
ResultCode Unmap(VAddr target, VAddr source, u32 size, VMAPermission perms);
|
||||
ResultCode Map(VAddr target, VAddr source, u32 size, VMAPermission perms,
|
||||
bool privileged = false);
|
||||
ResultCode Unmap(VAddr target, VAddr source, u32 size, VMAPermission perms,
|
||||
bool privileged = false);
|
||||
|
||||
private:
|
||||
explicit Process(Kernel::KernelSystem& kernel);
|
||||
|
|
Reference in New Issue