diff options
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 158 |
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 @@ | |||
| 10 | #include "common/symbols.h" | 10 | #include "common/symbols.h" |
| 11 | 11 | ||
| 12 | #include "core/core_timing.h" | 12 | #include "core/core_timing.h" |
| 13 | #include "core/mem_map.h" | ||
| 14 | #include "core/arm/arm_interface.h" | 13 | #include "core/arm/arm_interface.h" |
| 15 | 14 | ||
| 16 | #include "core/hle/kernel/address_arbiter.h" | 15 | #include "core/hle/kernel/address_arbiter.h" |
| 17 | #include "core/hle/kernel/event.h" | 16 | #include "core/hle/kernel/event.h" |
| 17 | #include "core/hle/kernel/memory.h" | ||
| 18 | #include "core/hle/kernel/mutex.h" | 18 | #include "core/hle/kernel/mutex.h" |
| 19 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/resource_limit.h" | 20 | #include "core/hle/kernel/resource_limit.h" |
| @@ -41,32 +41,114 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, | |||
| 41 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, | 41 | const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, |
| 42 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E | 42 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E |
| 43 | 43 | ||
| 44 | const ResultCode ERR_MISALIGNED_ADDRESS{ // 0xE0E01BF1 | ||
| 45 | ErrorDescription::MisalignedAddress, ErrorModule::OS, | ||
| 46 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 47 | const ResultCode ERR_MISALIGNED_SIZE{ // 0xE0E01BF2 | ||
| 48 | ErrorDescription::MisalignedSize, ErrorModule::OS, | ||
| 49 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 50 | const ResultCode ERR_INVALID_COMBINATION{ // 0xE0E01BEE | ||
| 51 | ErrorDescription::InvalidCombination, ErrorModule::OS, | ||
| 52 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | ||
| 53 | |||
| 44 | enum ControlMemoryOperation { | 54 | enum ControlMemoryOperation { |
| 45 | MEMORY_OPERATION_HEAP = 0x00000003, | 55 | MEMOP_FREE = 1, |
| 46 | MEMORY_OPERATION_GSP_HEAP = 0x00010003, | 56 | MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel |
| 57 | MEMOP_COMMIT = 3, | ||
| 58 | MEMOP_MAP = 4, | ||
| 59 | MEMOP_UNMAP = 5, | ||
| 60 | MEMOP_PROTECT = 6, | ||
| 61 | MEMOP_OPERATION_MASK = 0xFF, | ||
| 62 | |||
| 63 | MEMOP_REGION_APP = 0x100, | ||
| 64 | MEMOP_REGION_SYSTEM = 0x200, | ||
| 65 | MEMOP_REGION_BASE = 0x300, | ||
| 66 | MEMOP_REGION_MASK = 0xF00, | ||
| 67 | |||
| 68 | MEMOP_LINEAR = 0x10000, | ||
| 47 | }; | 69 | }; |
| 48 | 70 | ||
| 49 | /// Map application or GSP heap memory | 71 | /// Map application or GSP heap memory |
| 50 | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { | 72 | static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { |
| 51 | LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", | 73 | using namespace Kernel; |
| 74 | |||
| 75 | LOG_DEBUG(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X", | ||
| 52 | operation, addr0, addr1, size, permissions); | 76 | operation, addr0, addr1, size, permissions); |
| 53 | 77 | ||
| 54 | switch (operation) { | 78 | if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) { |
| 79 | return ERR_MISALIGNED_ADDRESS; | ||
| 80 | } | ||
| 81 | if ((size & Memory::PAGE_MASK) != 0) { | ||
| 82 | return ERR_MISALIGNED_SIZE; | ||
| 83 | } | ||
| 84 | |||
| 85 | u32 region = operation & MEMOP_REGION_MASK; | ||
| 86 | operation &= ~MEMOP_REGION_MASK; | ||
| 87 | |||
| 88 | if (region != 0) { | ||
| 89 | LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", region); | ||
| 90 | } | ||
| 91 | |||
| 92 | if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) { | ||
| 93 | return ERR_INVALID_COMBINATION; | ||
| 94 | } | ||
| 95 | VMAPermission vma_permissions = (VMAPermission)permissions; | ||
| 96 | |||
| 97 | auto& process = *g_current_process; | ||
| 98 | |||
| 99 | switch (operation & MEMOP_OPERATION_MASK) { | ||
| 100 | case MEMOP_FREE: | ||
| 101 | { | ||
| 102 | if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { | ||
| 103 | ResultCode result = process.HeapFree(addr0, size); | ||
| 104 | if (result.IsError()) return result; | ||
| 105 | } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) { | ||
| 106 | ResultCode result = process.LinearFree(addr0, size); | ||
| 107 | if (result.IsError()) return result; | ||
| 108 | } else { | ||
| 109 | return ERR_INVALID_ADDRESS; | ||
| 110 | } | ||
| 111 | *out_addr = addr0; | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | |||
| 115 | case MEMOP_COMMIT: | ||
| 116 | { | ||
| 117 | if (operation & MEMOP_LINEAR) { | ||
| 118 | CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions)); | ||
| 119 | } else { | ||
| 120 | CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); | ||
| 121 | } | ||
| 122 | break; | ||
| 123 | } | ||
| 55 | 124 | ||
| 56 | // Map normal heap memory | 125 | case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented |
| 57 | case MEMORY_OPERATION_HEAP: | 126 | { |
| 58 | *out_addr = Memory::MapBlock_Heap(size, operation, permissions); | 127 | CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); |
| 59 | break; | 128 | break; |
| 129 | } | ||
| 130 | |||
| 131 | case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented | ||
| 132 | { | ||
| 133 | ResultCode result = process.HeapFree(addr0, size); | ||
| 134 | if (result.IsError()) return result; | ||
| 135 | break; | ||
| 136 | } | ||
| 60 | 137 | ||
| 61 | // Map GSP heap memory | 138 | case MEMOP_PROTECT: |
| 62 | case MEMORY_OPERATION_GSP_HEAP: | 139 | { |
| 63 | *out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions); | 140 | ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions); |
| 141 | if (result.IsError()) return result; | ||
| 64 | break; | 142 | break; |
| 143 | } | ||
| 65 | 144 | ||
| 66 | // Unknown ControlMemory operation | ||
| 67 | default: | 145 | default: |
| 68 | LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); | 146 | LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); |
| 147 | return ERR_INVALID_COMBINATION; | ||
| 69 | } | 148 | } |
| 149 | |||
| 150 | process.vm_manager.LogLayout(Log::Level::Trace); | ||
| 151 | |||
| 70 | return RESULT_SUCCESS; | 152 | return RESULT_SUCCESS; |
| 71 | } | 153 | } |
| 72 | 154 | ||
| @@ -537,9 +619,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf | |||
| 537 | if (process == nullptr) | 619 | if (process == nullptr) |
| 538 | return ERR_INVALID_HANDLE; | 620 | return ERR_INVALID_HANDLE; |
| 539 | 621 | ||
| 540 | auto vma = process->address_space->FindVMA(addr); | 622 | auto vma = process->vm_manager.FindVMA(addr); |
| 541 | 623 | ||
| 542 | if (vma == process->address_space->vma_map.end()) | 624 | if (vma == Kernel::g_current_process->vm_manager.vma_map.end()) |
| 543 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 625 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); |
| 544 | 626 | ||
| 545 | memory_info->base_address = vma->second.base; | 627 | memory_info->base_address = vma->second.base; |
| @@ -692,6 +774,52 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | |||
| 692 | return RESULT_SUCCESS; | 774 | return RESULT_SUCCESS; |
| 693 | } | 775 | } |
| 694 | 776 | ||
| 777 | static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { | ||
| 778 | LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type); | ||
| 779 | |||
| 780 | using Kernel::Process; | ||
| 781 | Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle); | ||
| 782 | if (process == nullptr) | ||
| 783 | return ERR_INVALID_HANDLE; | ||
| 784 | |||
| 785 | switch (type) { | ||
| 786 | case 0: | ||
| 787 | case 2: | ||
| 788 | // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure | ||
| 789 | // what's the difference between them. | ||
| 790 | *out = process->heap_used + process->linear_heap_used + process->misc_memory_used; | ||
| 791 | break; | ||
| 792 | case 1: | ||
| 793 | case 3: | ||
| 794 | case 4: | ||
| 795 | case 5: | ||
| 796 | case 6: | ||
| 797 | case 7: | ||
| 798 | case 8: | ||
| 799 | // These are valid, but not implemented yet | ||
| 800 | LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type); | ||
| 801 | break; | ||
| 802 | case 20: | ||
| 803 | *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase(); | ||
| 804 | break; | ||
| 805 | default: | ||
| 806 | LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type); | ||
| 807 | |||
| 808 | if (type >= 21 && type <= 23) { | ||
| 809 | return ResultCode( // 0xE0E01BF4 | ||
| 810 | ErrorDescription::NotImplemented, ErrorModule::OS, | ||
| 811 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 812 | } else { | ||
| 813 | return ResultCode( // 0xD8E007ED | ||
| 814 | ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, | ||
| 815 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | ||
| 816 | } | ||
| 817 | break; | ||
| 818 | } | ||
| 819 | |||
| 820 | return RESULT_SUCCESS; | ||
| 821 | } | ||
| 822 | |||
| 695 | namespace { | 823 | namespace { |
| 696 | struct FunctionDef { | 824 | struct FunctionDef { |
| 697 | using Func = void(); | 825 | using Func = void(); |
| @@ -746,7 +874,7 @@ static const FunctionDef SVC_Table[] = { | |||
| 746 | {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, | 874 | {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, |
| 747 | {0x29, nullptr, "GetHandleInfo"}, | 875 | {0x29, nullptr, "GetHandleInfo"}, |
| 748 | {0x2A, nullptr, "GetSystemInfo"}, | 876 | {0x2A, nullptr, "GetSystemInfo"}, |
| 749 | {0x2B, nullptr, "GetProcessInfo"}, | 877 | {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, |
| 750 | {0x2C, nullptr, "GetThreadInfo"}, | 878 | {0x2C, nullptr, "GetThreadInfo"}, |
| 751 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, | 879 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, |
| 752 | {0x2E, nullptr, "SendSyncRequest1"}, | 880 | {0x2E, nullptr, "SendSyncRequest1"}, |