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
2 changed files with 42 additions and 10 deletions
|
@ -303,7 +303,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
||||||
return RESULT_SUCCESS;
|
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,
|
LOG_DEBUG(Kernel, "Map memory target={:08X}, source={:08X}, size={:08X}, perms={:08X}", target,
|
||||||
source, size, static_cast<u8>(perms));
|
source, size, static_cast<u8>(perms));
|
||||||
if (source < Memory::HEAP_VADDR || source + size > Memory::HEAP_VADDR_END ||
|
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;
|
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
|
// Mark source region as Aliased
|
||||||
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Private,
|
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Private,
|
||||||
VMAPermission::ReadWrite, MemoryState::Aliased,
|
VMAPermission::ReadWrite, source_state, source_perm));
|
||||||
VMAPermission::ReadWrite));
|
|
||||||
|
|
||||||
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size));
|
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(source, size));
|
||||||
VAddr interval_target = target;
|
VAddr interval_target = target;
|
||||||
for (const auto [backing_memory, block_size] : backing_blocks) {
|
for (const auto [backing_memory, block_size] : backing_blocks) {
|
||||||
auto target_vma = vm_manager.MapBackingMemory(interval_target, backing_memory, block_size,
|
auto target_vma =
|
||||||
MemoryState::Alias);
|
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;
|
interval_target += block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
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}",
|
LOG_DEBUG(Kernel, "Unmap memory target={:08X}, source={:08X}, size={:08X}, perms={:08X}",
|
||||||
target, source, size, static_cast<u8>(perms));
|
target, source, size, static_cast<u8>(perms));
|
||||||
if (source < Memory::HEAP_VADDR || source + size > Memory::HEAP_VADDR_END ||
|
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
|
// TODO(wwylele): check that the source and the target are actually a pair created by Map
|
||||||
// Should return error 0xD8E007F5 in this case
|
// 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));
|
CASCADE_CODE(vm_manager.UnmapRange(target, size));
|
||||||
|
|
||||||
// Change back source region state. Note that the permission is reprotected according to param
|
// Change back source region state. Note that the permission is reprotected according to param
|
||||||
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, MemoryState::Aliased,
|
CASCADE_CODE(vm_manager.ChangeMemoryState(source, size, source_state, VMAPermission::None,
|
||||||
VMAPermission::None, MemoryState::Private, perms));
|
MemoryState::Private, perms));
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,8 +188,10 @@ public:
|
||||||
ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
|
ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
|
||||||
ResultCode LinearFree(VAddr target, u32 size);
|
ResultCode LinearFree(VAddr target, u32 size);
|
||||||
|
|
||||||
ResultCode Map(VAddr target, VAddr source, u32 size, VMAPermission perms);
|
ResultCode Map(VAddr target, VAddr source, u32 size, VMAPermission perms,
|
||||||
ResultCode Unmap(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:
|
private:
|
||||||
explicit Process(Kernel::KernelSystem& kernel);
|
explicit Process(Kernel::KernelSystem& kernel);
|
||||||
|
|
Loading…
Reference in a new issue