diff options
| author | 2015-07-17 23:19:16 -0300 | |
|---|---|---|
| committer | 2015-08-16 01:03:45 -0300 | |
| commit | cdeeecf0807d0005356f30db0f7164c5891a9245 (patch) | |
| tree | e32e6d673cdac358df0abd3d3ece13f37c1c28d5 /src/core/hle/svc.cpp | |
| parent | Memory: Move PAGE_MASK and PAGE_BITS to memory.h (diff) | |
| download | yuzu-cdeeecf0807d0005356f30db0f7164c5891a9245.tar.gz yuzu-cdeeecf0807d0005356f30db0f7164c5891a9245.tar.xz yuzu-cdeeecf0807d0005356f30db0f7164c5891a9245.zip | |
Kernel: Properly implement ControlMemory FREE and COMMIT
Diffstat (limited to 'src/core/hle/svc.cpp')
| -rw-r--r-- | src/core/hle/svc.cpp | 108 |
1 files changed, 95 insertions, 13 deletions
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index bb64fdfb7..91260fe71 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -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 | } | ||
| 55 | 91 | ||
| 56 | // Map normal heap memory | 92 | if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) { |
| 57 | case MEMORY_OPERATION_HEAP: | 93 | return ERR_INVALID_COMBINATION; |
| 58 | *out_addr = Memory::MapBlock_Heap(size, operation, permissions); | 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 >= Memory::LINEAR_HEAP_VADDR && addr0 < Memory::LINEAR_HEAP_VADDR_END) { | ||
| 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; | ||
| 59 | break; | 112 | break; |
| 113 | } | ||
| 60 | 114 | ||
| 61 | // Map GSP heap memory | 115 | case MEMOP_COMMIT: |
| 62 | case MEMORY_OPERATION_GSP_HEAP: | 116 | { |
| 63 | *out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions); | 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 | } | ||
| 64 | break; | 122 | break; |
| 123 | } | ||
| 124 | |||
| 125 | case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented | ||
| 126 | { | ||
| 127 | CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions)); | ||
| 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 | } | ||
| 137 | |||
| 138 | case MEMOP_PROTECT: | ||
| 139 | { | ||
| 140 | ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions); | ||
| 141 | if (result.IsError()) return result; | ||
| 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; |