kern: fix incorrect cache routines, implement SvcSetProcessMemoryPermission

This commit is contained in:
Michael Scire 2020-07-20 19:59:12 -07:00 committed by SciresM
parent 26df56cd87
commit 4fca870f2f
4 changed files with 57 additions and 11 deletions

View file

@ -371,7 +371,7 @@ namespace ams::kern::arch::arm64::cpu {
Result StoreDataCache(const void *addr, size_t size) {
KScopedCoreMigrationDisable dm;
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, DataCacheLineSize);
return StoreDataCacheRange(start, end);
}
@ -379,7 +379,7 @@ namespace ams::kern::arch::arm64::cpu {
Result FlushDataCache(const void *addr, size_t size) {
KScopedCoreMigrationDisable dm;
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr), DataCacheLineSize);
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, DataCacheLineSize);
return FlushDataCacheRange(start, end);
}
@ -387,7 +387,7 @@ namespace ams::kern::arch::arm64::cpu {
Result InvalidateInstructionCache(void *addr, size_t size) {
KScopedCoreMigrationDisable dm;
const uintptr_t start = util::AlignDown(reinterpret_cast<uintptr_t>(addr), InstructionCacheLineSize);
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr), InstructionCacheLineSize);
const uintptr_t end = util::AlignUp( reinterpret_cast<uintptr_t>(addr) + size, InstructionCacheLineSize);
R_TRY(InvalidateInstructionCacheRange(start, end));

View file

@ -40,6 +40,14 @@ namespace ams::kern::arch::arm64 {
MESOSPHERE_LOG("User Exception occurred in %s\n", cur_process->GetName());
for (size_t i = 0; i < 31; i++) {
MESOSPHERE_LOG("X[%02zu] = %016lx\n", i, context->x[i]);
}
MESOSPHERE_LOG("PC = %016lx\n", context->pc);
MESOSPHERE_LOG("SP = %016lx\n", context->sp);
MESOSPHERE_PANIC("Unhandled Exception in Supervisor Mode\n");
const u64 ec = (esr >> 26) & 0x3F;
switch (ec) {
case 0x0: /* Unknown */

View file

@ -1035,6 +1035,7 @@ namespace ams::kern {
KMemoryState new_state = old_state;
const bool is_w = (new_perm & KMemoryPermission_UserWrite) == KMemoryPermission_UserWrite;
const bool is_x = (new_perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute;
const bool was_x = (old_perm & KMemoryPermission_UserExecute) == KMemoryPermission_UserExecute;
MESOSPHERE_ASSERT(!(is_w && is_x));
if (is_w) {
@ -1050,6 +1051,9 @@ namespace ams::kern {
R_TRY(this->MakePageGroup(pg, GetInteger(addr), num_pages));
}
/* Succeed if there's nothing to do. */
R_SUCCEED_IF(old_perm == new_perm && old_state == new_state);
/* Create an update allocator. */
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
R_TRY(allocator.GetResult());
@ -1059,7 +1063,7 @@ namespace ams::kern {
/* Perform mapping operation. */
const KPageProperties properties = { new_perm, false, false, false };
const auto operation = is_x ? OperationType_ChangePermissionsAndRefresh : OperationType_ChangePermissions;
const auto operation = was_x ? OperationType_ChangePermissionsAndRefresh : OperationType_ChangePermissions;
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, operation, false));
/* Update the blocks. */

View file

@ -21,14 +21,48 @@ namespace ams::kern::svc {
namespace {
constexpr bool IsValidProcessMemoryPermission(ams::svc::MemoryPermission perm) {
switch (perm) {
case ams::svc::MemoryPermission_None:
case ams::svc::MemoryPermission_Read:
case ams::svc::MemoryPermission_ReadWrite:
case ams::svc::MemoryPermission_ReadExecute:
return true;
default:
return false;
}
}
Result SetProcessMemoryPermission(ams::svc::Handle process_handle, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) {
/* Validate the address/size. */
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
R_UNLESS(size > 0, svc::ResultInvalidSize());
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory());
R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory());
/* Validate the memory permission. */
R_UNLESS(IsValidProcessMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());
/* Get the process from its handle. */
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
/* Validate that the address is in range. */
auto &page_table = process->GetPageTable();
R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory());
/* Set the memory permission. */
return page_table.SetProcessMemoryPermission(address, size, perm);
}
}
/* ============================= 64 ABI ============================= */
Result SetProcessMemoryPermission64(ams::svc::Handle process_handle, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) {
MESOSPHERE_PANIC("Stubbed SvcSetProcessMemoryPermission64 was called.");
return SetProcessMemoryPermission(process_handle, address, size, perm);
}
Result MapProcessMemory64(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) {
@ -50,7 +84,7 @@ namespace ams::kern::svc {
/* ============================= 64From32 ABI ============================= */
Result SetProcessMemoryPermission64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size, ams::svc::MemoryPermission perm) {
MESOSPHERE_PANIC("Stubbed SvcSetProcessMemoryPermission64From32 was called.");
return SetProcessMemoryPermission(process_handle, address, size, perm);
}
Result MapProcessMemory64From32(ams::svc::Address dst_address, ams::svc::Handle process_handle, uint64_t src_address, ams::svc::Size size) {