diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/kernel/svc/svc_physical_memory.cpp | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp new file mode 100644 index 000000000..c2fbfb59a --- /dev/null +++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp @@ -0,0 +1,183 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/svc.h" + +namespace Kernel::Svc { + +/// Set the process heap to a given Size. It can both extend and shrink the heap. +Result SetHeapSize(Core::System& system, u64* out_address, u64 size) { + LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); + + // Validate size. + R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); + R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); + + // Set the heap size. + R_RETURN(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size)); +} + +/// Maps memory at a desired address +Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + + if (!Common::Is4KBAligned(addr)) { + LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); + R_THROW(ResultInvalidAddress); + } + + if (!Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + R_THROW(ResultInvalidSize); + } + + if (size == 0) { + LOG_ERROR(Kernel_SVC, "Size is zero"); + R_THROW(ResultInvalidSize); + } + + if (!(addr < addr + size)) { + LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); + R_THROW(ResultInvalidMemoryRegion); + } + + KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; + auto& page_table{current_process->PageTable()}; + + if (current_process->GetSystemResourceSize() == 0) { + LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); + R_THROW(ResultInvalidState); + } + + if (!page_table.IsInsideAddressSpace(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, + size); + R_THROW(ResultInvalidMemoryRegion); + } + + if (page_table.IsOutsideAliasRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, + size); + R_THROW(ResultInvalidMemoryRegion); + } + + R_RETURN(page_table.MapPhysicalMemory(addr, size)); +} + +/// Unmaps memory previously mapped via MapPhysicalMemory +Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { + LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); + + if (!Common::Is4KBAligned(addr)) { + LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr); + R_THROW(ResultInvalidAddress); + } + + if (!Common::Is4KBAligned(size)) { + LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size); + R_THROW(ResultInvalidSize); + } + + if (size == 0) { + LOG_ERROR(Kernel_SVC, "Size is zero"); + R_THROW(ResultInvalidSize); + } + + if (!(addr < addr + size)) { + LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); + R_THROW(ResultInvalidMemoryRegion); + } + + KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; + auto& page_table{current_process->PageTable()}; + + if (current_process->GetSystemResourceSize() == 0) { + LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); + R_THROW(ResultInvalidState); + } + + if (!page_table.IsInsideAddressSpace(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, + size); + R_THROW(ResultInvalidMemoryRegion); + } + + if (page_table.IsOutsideAliasRegion(addr, size)) { + LOG_ERROR(Kernel_SVC, + "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, + size); + R_THROW(ResultInvalidMemoryRegion); + } + + R_RETURN(page_table.UnmapPhysicalMemory(addr, size)); +} + +Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetUnsafeLimit(Core::System& system, uint64_t limit) { + UNIMPLEMENTED(); + R_THROW(ResultNotImplemented); +} + +Result SetHeapSize64(Core::System& system, uint64_t* out_address, uint64_t size) { + R_RETURN(SetHeapSize(system, out_address, size)); +} + +Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(MapPhysicalMemory(system, address, size)); +} + +Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(UnmapPhysicalMemory(system, address, size)); +} + +Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(MapPhysicalMemoryUnsafe(system, address, size)); +} + +Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) { + R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size)); +} + +Result SetUnsafeLimit64(Core::System& system, uint64_t limit) { + R_RETURN(SetUnsafeLimit(system, limit)); +} + +Result SetHeapSize64From32(Core::System& system, uint64_t* out_address, uint32_t size) { + R_RETURN(SetHeapSize(system, out_address, size)); +} + +Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(MapPhysicalMemory(system, address, size)); +} + +Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(UnmapPhysicalMemory(system, address, size)); +} + +Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(MapPhysicalMemoryUnsafe(system, address, size)); +} + +Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) { + R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size)); +} + +Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit) { + R_RETURN(SetUnsafeLimit(system, limit)); +} + +} // namespace Kernel::Svc |