summaryrefslogtreecommitdiffstats
path: root/src/core/hle/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/svc.cpp')
-rw-r--r--src/core/hle/svc.cpp158
1 files changed, 143 insertions, 15 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index bb64fdfb7..89ac45a6f 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -10,11 +10,11 @@
#include "common/symbols.h"
#include "core/core_timing.h"
-#include "core/mem_map.h"
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
@@ -41,32 +41,114 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
+const ResultCode ERR_MISALIGNED_ADDRESS{ // 0xE0E01BF1
+ ErrorDescription::MisalignedAddress, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage};
+const ResultCode ERR_MISALIGNED_SIZE{ // 0xE0E01BF2
+ ErrorDescription::MisalignedSize, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage};
+const ResultCode ERR_INVALID_COMBINATION{ // 0xE0E01BEE
+ ErrorDescription::InvalidCombination, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage};
+
enum ControlMemoryOperation {
- MEMORY_OPERATION_HEAP = 0x00000003,
- MEMORY_OPERATION_GSP_HEAP = 0x00010003,
+ MEMOP_FREE = 1,
+ MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel
+ MEMOP_COMMIT = 3,
+ MEMOP_MAP = 4,
+ MEMOP_UNMAP = 5,
+ MEMOP_PROTECT = 6,
+ MEMOP_OPERATION_MASK = 0xFF,
+
+ MEMOP_REGION_APP = 0x100,
+ MEMOP_REGION_SYSTEM = 0x200,
+ MEMOP_REGION_BASE = 0x300,
+ MEMOP_REGION_MASK = 0xF00,
+
+ MEMOP_LINEAR = 0x10000,
};
/// Map application or GSP heap memory
static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
- LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
+ using namespace Kernel;
+
+ LOG_DEBUG(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X",
operation, addr0, addr1, size, permissions);
- switch (operation) {
+ if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
+ return ERR_MISALIGNED_ADDRESS;
+ }
+ if ((size & Memory::PAGE_MASK) != 0) {
+ return ERR_MISALIGNED_SIZE;
+ }
+
+ u32 region = operation & MEMOP_REGION_MASK;
+ operation &= ~MEMOP_REGION_MASK;
+
+ if (region != 0) {
+ LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", region);
+ }
+
+ if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) {
+ return ERR_INVALID_COMBINATION;
+ }
+ VMAPermission vma_permissions = (VMAPermission)permissions;
+
+ auto& process = *g_current_process;
+
+ switch (operation & MEMOP_OPERATION_MASK) {
+ case MEMOP_FREE:
+ {
+ if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
+ ResultCode result = process.HeapFree(addr0, size);
+ if (result.IsError()) return result;
+ } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) {
+ ResultCode result = process.LinearFree(addr0, size);
+ if (result.IsError()) return result;
+ } else {
+ return ERR_INVALID_ADDRESS;
+ }
+ *out_addr = addr0;
+ break;
+ }
+
+ case MEMOP_COMMIT:
+ {
+ if (operation & MEMOP_LINEAR) {
+ CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions));
+ } else {
+ CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
+ }
+ break;
+ }
- // Map normal heap memory
- case MEMORY_OPERATION_HEAP:
- *out_addr = Memory::MapBlock_Heap(size, operation, permissions);
+ case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
+ {
+ CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
break;
+ }
+
+ case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
+ {
+ ResultCode result = process.HeapFree(addr0, size);
+ if (result.IsError()) return result;
+ break;
+ }
- // Map GSP heap memory
- case MEMORY_OPERATION_GSP_HEAP:
- *out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions);
+ case MEMOP_PROTECT:
+ {
+ ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions);
+ if (result.IsError()) return result;
break;
+ }
- // Unknown ControlMemory operation
default:
LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
+ return ERR_INVALID_COMBINATION;
}
+
+ process.vm_manager.LogLayout(Log::Level::Trace);
+
return RESULT_SUCCESS;
}
@@ -537,9 +619,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf
if (process == nullptr)
return ERR_INVALID_HANDLE;
- auto vma = process->address_space->FindVMA(addr);
+ auto vma = process->vm_manager.FindVMA(addr);
- if (vma == process->address_space->vma_map.end())
+ if (vma == Kernel::g_current_process->vm_manager.vma_map.end())
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
memory_info->base_address = vma->second.base;
@@ -692,6 +774,52 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
return RESULT_SUCCESS;
}
+static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
+ LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
+
+ using Kernel::Process;
+ Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
+ if (process == nullptr)
+ return ERR_INVALID_HANDLE;
+
+ switch (type) {
+ case 0:
+ case 2:
+ // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
+ // what's the difference between them.
+ *out = process->heap_used + process->linear_heap_used + process->misc_memory_used;
+ break;
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ // These are valid, but not implemented yet
+ LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type);
+ break;
+ case 20:
+ *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase();
+ break;
+ default:
+ LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type);
+
+ if (type >= 21 && type <= 23) {
+ return ResultCode( // 0xE0E01BF4
+ ErrorDescription::NotImplemented, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ } else {
+ return ResultCode( // 0xD8E007ED
+ ErrorDescription::InvalidEnumValue, ErrorModule::Kernel,
+ ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
+ }
+ break;
+ }
+
+ return RESULT_SUCCESS;
+}
+
namespace {
struct FunctionDef {
using Func = void();
@@ -746,7 +874,7 @@ static const FunctionDef SVC_Table[] = {
{0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"},
{0x29, nullptr, "GetHandleInfo"},
{0x2A, nullptr, "GetSystemInfo"},
- {0x2B, nullptr, "GetProcessInfo"},
+ {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"},
{0x2C, nullptr, "GetThreadInfo"},
{0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
{0x2E, nullptr, "SendSyncRequest1"},