kern: SvcInvalidateProcessDataCache

This commit is contained in:
Michael Scire 2020-07-23 20:07:40 -07:00 committed by SciresM
parent 46935fea80
commit 418de7b0dc
4 changed files with 91 additions and 2 deletions

View File

@ -128,6 +128,10 @@ namespace ams::kern::arch::arm64 {
return this->page_table.MakeAndOpenPageGroupContiguous(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
}
Result InvalidateProcessDataCache(KProcessAddress address, size_t size) {
return this->page_table.InvalidateProcessDataCache(address, size);
}
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
return this->page_table.LockForDeviceAddressSpace(out, address, size, perm, is_aligned);
}

View File

@ -313,6 +313,8 @@ namespace ams::kern {
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
Result MakeAndOpenPageGroupContiguous(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned);
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size);
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size);

View File

@ -1822,6 +1822,73 @@ namespace ams::kern {
return ResultSuccess();
}
Result KPageTableBase::InvalidateProcessDataCache(KProcessAddress address, size_t size) {
/* Check that the region is in range. */
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
/* Lock the table. */
KScopedLightLock lk(this->general_lock);
/* Check the memory state. */
R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_Uncached, KMemoryAttribute_None));
/* Get the impl. */
auto &impl = this->GetImpl();
/* Begin traversal. */
TraversalContext context;
TraversalEntry next_entry;
bool traverse_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), address);
R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory());
/* Prepare tracking variables. */
KPhysicalAddress cur_addr = next_entry.phys_addr;
size_t cur_size = next_entry.block_size - (GetInteger(cur_addr) & (next_entry.block_size - 1));
size_t tot_size = cur_size;
/* Iterate. */
while (tot_size < size) {
/* Continue the traversal. */
traverse_valid = impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
R_UNLESS(traverse_valid, svc::ResultInvalidCurrentMemory());
if (next_entry.phys_addr != (cur_addr + cur_size)) {
/* Check that the pages are linearly mapped. */
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
/* Invalidate the block. */
if (cur_size > 0) {
/* NOTE: Nintendo does not check the result of invalidation. */
cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size);
}
/* Advance. */
cur_addr = next_entry.phys_addr;
cur_size = next_entry.block_size;
} else {
cur_size += next_entry.block_size;
}
tot_size += next_entry.block_size;
}
/* Ensure we use the right size for the last block. */
if (tot_size > size) {
cur_size -= (tot_size - size);
}
/* Check that the last block is linearly mapped. */
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), svc::ResultInvalidCurrentMemory());
/* Invalidate the last block. */
if (cur_size > 0) {
/* NOTE: Nintendo does not check the result of invalidation. */
cpu::InvalidateDataCache(GetVoidPointer(GetLinearMappedVirtualAddress(cur_addr)), cur_size);
}
return ResultSuccess();
}
Result KPageTableBase::LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
/* Lightly validate the range before doing anything else. */
const size_t num_pages = size / PageSize;

View File

@ -73,6 +73,22 @@ namespace ams::kern::svc {
return ResultSuccess();
}
Result InvalidateProcessDataCache(ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
/* Validate address/size. */
R_UNLESS(size > 0, svc::ResultInvalidSize());
R_UNLESS(address == static_cast<uintptr_t>(address), svc::ResultInvalidCurrentMemory());
R_UNLESS(size == static_cast<size_t>(size), svc::ResultInvalidCurrentMemory());
/* Get the process from its handle. */
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(process_handle);
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
/* Invalidate the cache. */
R_TRY(process->GetPageTable().InvalidateProcessDataCache(address, size));
return ResultSuccess();
}
Result StoreProcessDataCache(ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
/* Validate address/size. */
R_UNLESS(size > 0, svc::ResultInvalidSize());
@ -140,7 +156,7 @@ namespace ams::kern::svc {
}
Result InvalidateProcessDataCache64(ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
MESOSPHERE_PANIC("Stubbed SvcInvalidateProcessDataCache64 was called.");
return InvalidateProcessDataCache(process_handle, address, size);
}
Result StoreProcessDataCache64(ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
@ -162,7 +178,7 @@ namespace ams::kern::svc {
}
Result InvalidateProcessDataCache64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size) {
MESOSPHERE_PANIC("Stubbed SvcInvalidateProcessDataCache64From32 was called.");
return InvalidateProcessDataCache(process_handle, address, size);
}
Result StoreProcessDataCache64From32(ams::svc::Handle process_handle, uint64_t address, uint64_t size) {