diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index d7f085cc..785f9a69 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -17,8 +17,8 @@ namespace skyline::kernel { case memory::AddressSpaceType::AddressSpace36Bit: { addressSpace.address = 0; addressSpace.size = 1UL << 36; - base.size = 0x78000000 + 0x180000000 + 0x180000000 + 0x180000000; - break; + base.size = 0x78000000 + 0x180000000 + 0x78000000 + 0x180000000; + throw exception("36-bit address spaces are not supported"); // Due to VMM base being forced at 0x800000 and it being used by ART } case memory::AddressSpaceType::AddressSpace39Bit: { @@ -67,18 +67,17 @@ namespace skyline::kernel { switch (addressSpace.size) { case 1UL << 36: { - code.address = base.address; + code.address = 0x800000; code.size = 0x78000000; if (code.address > address || (code.size - (address - code.address)) < size) throw exception("Code mapping larger than 36-bit code region"); alias.address = code.address + code.size; alias.size = 0x180000000; - stack.address = alias.address; - stack.size = 0x180000000; - heap.address = alias.address + alias.size; + stack.address = alias.address + alias.size; + stack.size = 0x78000000; + tlsIo = stack; //!< TLS/IO is shared with Stack on 36-bit + heap.address = stack.address + stack.size; heap.size = 0x180000000; - tlsIo.address = code.address; - tlsIo.size = 0; break; } @@ -100,7 +99,7 @@ namespace skyline::kernel { throw exception("Regions initialized without VMM initialization"); } - auto newSize{code.size + alias.size + stack.size + heap.size + tlsIo.size}; + auto newSize{code.size + alias.size + stack.size + heap.size + ((addressSpace.size == 1UL << 39) ? tlsIo.size : 0)}; if (newSize > base.size) throw exception("Region size has exceeded pre-allocated area: 0x{:X}/0x{:X}", newSize, base.size); if (newSize != base.size) @@ -177,10 +176,17 @@ namespace skyline::kernel { } size_t MemoryManager::GetMemoryUsage() { + std::shared_lock lock(mutex); size_t size{}; for (const auto &chunk : chunks) if (chunk.state != memory::states::Unmapped) size += chunk.size; return size; } + + size_t MemoryManager::GetKMemoryBlockSize() { + std::shared_lock lock(mutex); + constexpr size_t KMemoryBlockSize{0x40}; + return util::AlignUp(chunks.size() * KMemoryBlockSize, PAGE_SIZE); + } } diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 5a347d38..0d977451 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -240,6 +240,11 @@ namespace skyline { * @return The cumulative size of all memory mappings in bytes */ size_t GetMemoryUsage(); + + /** + * @return The total page-aligned size used to store memory block metadata, if they were KMemoryBlocks rather than ChunkDescriptor + */ + size_t GetKMemoryBlockSize(); }; } } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index a948fd6a..303de255 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -8,7 +8,7 @@ namespace skyline::kernel::svc { void SetHeapSize(const DeviceState &state) { - auto size{state.ctx->gpr.w1}; + u32 size{state.ctx->gpr.w1}; if (!util::IsAligned(size, 0x200000)) { state.ctx->gpr.w0 = result::InvalidSize; @@ -35,7 +35,7 @@ namespace skyline::kernel::svc { return; } - auto size{state.ctx->gpr.x1}; + size_t size{state.ctx->gpr.x1}; if (!util::PageAligned(size)) { state.ctx->gpr.w0 = result::InvalidSize; state.logger->Warn("svcSetMemoryAttribute: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); @@ -76,9 +76,9 @@ namespace skyline::kernel::svc { } void MapMemory(const DeviceState &state) { - auto destination{reinterpret_cast(state.ctx->gpr.x0)}; - auto source{reinterpret_cast(state.ctx->gpr.x1)}; - auto size{state.ctx->gpr.x2}; + auto destination{reinterpret_cast(state.ctx->gpr.x0)}; + auto source{reinterpret_cast(state.ctx->gpr.x1)}; + size_t size{state.ctx->gpr.x2}; if (!util::PageAligned(destination) || !util::PageAligned(source)) { state.ctx->gpr.w0 = result::InvalidAddress; @@ -124,9 +124,9 @@ namespace skyline::kernel::svc { } void UnmapMemory(const DeviceState &state) { - auto source{reinterpret_cast(state.ctx->gpr.x0)}; - auto destination{reinterpret_cast(state.ctx->gpr.x1)}; - auto size{state.ctx->gpr.x2}; + auto source{reinterpret_cast(state.ctx->gpr.x0)}; + auto destination{reinterpret_cast(state.ctx->gpr.x1)}; + size_t size{state.ctx->gpr.x2}; if (!util::PageAligned(destination) || !util::PageAligned(source)) { state.ctx->gpr.w0 = result::InvalidAddress; @@ -182,7 +182,7 @@ namespace skyline::kernel::svc { void QueryMemory(const DeviceState &state) { memory::MemoryInfo memInfo{}; - auto pointer{reinterpret_cast(state.ctx->gpr.x2)}; + auto pointer{reinterpret_cast(state.ctx->gpr.x2)}; auto chunk{state.process->memory.Get(pointer)}; if (chunk) { @@ -196,7 +196,7 @@ namespace skyline::kernel::svc { .ipcRefCount = 0, }; - state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", memInfo.address, memInfo.size, memInfo.type, static_cast(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-'); + state.logger->Debug("svcQueryMemory: Pointer: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", pointer, memInfo.address, memInfo.size, memInfo.type, static_cast(chunk->attributes.isUncached), chunk->permission.r ? 'R' : '-', chunk->permission.w ? 'W' : '-', chunk->permission.x ? 'X' : '-'); } else { auto addressSpaceEnd{reinterpret_cast(state.process->memory.addressSpace.address + state.process->memory.addressSpace.size)}; @@ -209,7 +209,7 @@ namespace skyline::kernel::svc { state.logger->Debug("svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X}", pointer); } - *reinterpret_cast(state.ctx->gpr.x0) = memInfo; + *reinterpret_cast(state.ctx->gpr.x0) = memInfo; state.ctx->gpr.w0 = Result{}; } @@ -220,10 +220,10 @@ namespace skyline::kernel::svc { } void CreateThread(const DeviceState &state) { - auto entry{reinterpret_cast(state.ctx->gpr.x1)}; + auto entry{reinterpret_cast(state.ctx->gpr.x1)}; auto entryArgument{state.ctx->gpr.x2}; - auto stackTop{reinterpret_cast(state.ctx->gpr.x3)}; - auto priority{static_cast(state.ctx->gpr.w4)}; + auto stackTop{reinterpret_cast(state.ctx->gpr.x3)}; + auto priority{static_cast(static_cast(state.ctx->gpr.w4))}; if (!constant::HosPriority.Valid(priority)) { state.ctx->gpr.w0 = result::InvalidAddress; @@ -243,7 +243,7 @@ namespace skyline::kernel::svc { } void StartThread(const DeviceState &state) { - auto handle{state.ctx->gpr.w0}; + KHandle handle{state.ctx->gpr.w0}; try { auto thread{state.process->GetHandle(handle)}; state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->id); @@ -262,7 +262,7 @@ namespace skyline::kernel::svc { } void SleepThread(const DeviceState &state) { - auto in{state.ctx->gpr.x0}; + u64 in{state.ctx->gpr.x0}; switch (in) { case 0: @@ -281,7 +281,7 @@ namespace skyline::kernel::svc { } void GetThreadPriority(const DeviceState &state) { - auto handle{state.ctx->gpr.w1}; + KHandle handle{state.ctx->gpr.w1}; try { auto priority{state.process->GetHandle(handle)->priority}; state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); @@ -295,8 +295,8 @@ namespace skyline::kernel::svc { } void SetThreadPriority(const DeviceState &state) { - auto handle{state.ctx->gpr.w0}; - auto priority{state.ctx->gpr.w1}; + KHandle handle{state.ctx->gpr.w0}; + u32 priority{state.ctx->gpr.w1}; try { state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); @@ -325,7 +325,7 @@ namespace skyline::kernel::svc { return; } - auto size{state.ctx->gpr.x2}; + size_t size{state.ctx->gpr.x2}; if (!util::PageAligned(size)) { state.ctx->gpr.w0 = result::InvalidSize; state.logger->Warn("svcMapSharedMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); @@ -345,7 +345,7 @@ namespace skyline::kernel::svc { state.ctx->gpr.w0 = Result{}; } catch (const std::exception &) { - state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.ctx->gpr.w0); + state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", static_cast(state.ctx->gpr.w0)); state.ctx->gpr.w0 = result::InvalidHandle; } } @@ -358,7 +358,7 @@ namespace skyline::kernel::svc { return; } - auto size{state.ctx->gpr.x2}; + size_t size{state.ctx->gpr.x2}; if (!util::PageAligned(size)) { state.ctx->gpr.w0 = result::InvalidSize; state.logger->Warn("svcCreateTransferMemory: 'size' {}: 0x{:X}", size ? "not page aligned" : "is zero", size); @@ -380,7 +380,7 @@ namespace skyline::kernel::svc { } void CloseHandle(const DeviceState &state) { - auto handle{static_cast(state.ctx->gpr.w0)}; + KHandle handle{static_cast(state.ctx->gpr.w0)}; try { state.process->CloseHandle(handle); state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle); @@ -392,7 +392,7 @@ namespace skyline::kernel::svc { } void ResetSignal(const DeviceState &state) { - auto handle{state.ctx->gpr.w0}; + KHandle handle{state.ctx->gpr.w0}; try { auto object{state.process->GetHandle(handle)}; switch (object->objectType) { @@ -423,7 +423,7 @@ namespace skyline::kernel::svc { void WaitSynchronization(const DeviceState &state) { constexpr u8 maxSyncHandles{0x40}; // The total amount of handles that can be passed to WaitSynchronization - auto numHandles{state.ctx->gpr.w2}; + u32 numHandles{state.ctx->gpr.w2}; if (numHandles > maxSyncHandles) { state.ctx->gpr.w0 = result::OutOfHandles; return; @@ -431,7 +431,7 @@ namespace skyline::kernel::svc { std::string handleStr; std::vector> objectTable; - span waitHandles(reinterpret_cast(state.ctx->gpr.x1), numHandles); + span waitHandles(reinterpret_cast(state.ctx->gpr.x1), numHandles); for (const auto &handle : waitHandles) { handleStr += fmt::format("* 0x{:X}\n", handle); @@ -453,7 +453,7 @@ namespace skyline::kernel::svc { objectTable.push_back(std::static_pointer_cast(object)); } - auto timeout{state.ctx->gpr.x3}; + u64 timeout{state.ctx->gpr.x3}; state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); auto start{util::GetTimeNs()}; @@ -487,21 +487,21 @@ namespace skyline::kernel::svc { try { state.process->GetHandle(state.ctx->gpr.w0)->cancelSync = true; } catch (const std::exception &) { - state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", state.ctx->gpr.w0); + state.logger->Warn("svcCancelSynchronization: 'handle' invalid: 0x{:X}", static_cast(state.ctx->gpr.w0)); state.ctx->gpr.w0 = result::InvalidHandle; } } void ArbitrateLock(const DeviceState &state) { - auto pointer{reinterpret_cast(state.ctx->gpr.x1)}; + auto pointer{reinterpret_cast(state.ctx->gpr.x1)}; if (!util::WordAligned(pointer)) { state.logger->Warn("svcArbitrateLock: 'pointer' not word aligned: 0x{:X}", pointer); state.ctx->gpr.w0 = result::InvalidAddress; return; } - auto ownerHandle{state.ctx->gpr.w0}; - auto requesterHandle{state.ctx->gpr.w2}; + KHandle ownerHandle{state.ctx->gpr.w0}; + KHandle requesterHandle{state.ctx->gpr.w2}; if (requesterHandle != state.thread->handle) throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", requesterHandle, state.thread->handle); @@ -516,7 +516,7 @@ namespace skyline::kernel::svc { } void ArbitrateUnlock(const DeviceState &state) { - auto mutex{reinterpret_cast(state.ctx->gpr.x0)}; + auto mutex{reinterpret_cast(state.ctx->gpr.x0)}; if (!util::WordAligned(mutex)) { state.logger->Warn("svcArbitrateUnlock: 'mutex' not word aligned: 0x{:X}", mutex); state.ctx->gpr.w0 = result::InvalidAddress; @@ -535,15 +535,15 @@ namespace skyline::kernel::svc { } void WaitProcessWideKeyAtomic(const DeviceState &state) { - auto mutex{reinterpret_cast(state.ctx->gpr.x0)}; + auto mutex{reinterpret_cast(state.ctx->gpr.x0)}; if (!util::WordAligned(mutex)) { state.logger->Warn("svcWaitProcessWideKeyAtomic: 'mutex' not word aligned: 0x{:X}", mutex); state.ctx->gpr.w0 = result::InvalidAddress; return; } - auto conditional{reinterpret_cast(state.ctx->gpr.x1)}; - auto handle{state.ctx->gpr.w2}; + auto conditional{reinterpret_cast(state.ctx->gpr.x1)}; + KHandle handle{state.ctx->gpr.w2}; if (handle != state.thread->handle) throw exception("svcWaitProcessWideKeyAtomic: Handle doesn't match current thread: 0x{:X} for thread 0x{:X}", handle, state.thread->handle); @@ -553,7 +553,7 @@ namespace skyline::kernel::svc { return; } - auto timeout{state.ctx->gpr.x3}; + u64 timeout{state.ctx->gpr.x3}; state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {} ns", mutex, conditional, timeout); if (state.process->ConditionalVariableWait(conditional, mutex, timeout)) { @@ -566,8 +566,8 @@ namespace skyline::kernel::svc { } void SignalProcessWideKey(const DeviceState &state) { - auto conditional{reinterpret_cast(state.ctx->gpr.x0)}; - auto count{state.ctx->gpr.w1}; + auto conditional{reinterpret_cast(state.ctx->gpr.x0)}; + KHandle count{state.ctx->gpr.w1}; state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", conditional, count); state.process->ConditionalVariableSignal(conditional, count); @@ -589,7 +589,7 @@ namespace skyline::kernel::svc { void ConnectToNamedPort(const DeviceState &state) { constexpr u8 portSize = 0x8; //!< The size of a port name string - std::string_view port(span(reinterpret_cast(state.ctx->gpr.x1), portSize).as_string(true)); + std::string_view port(span(reinterpret_cast(state.ctx->gpr.x1), portSize).as_string(true)); KHandle handle{}; if (port.compare("sm:") >= 0) { @@ -613,7 +613,7 @@ namespace skyline::kernel::svc { void GetThreadId(const DeviceState &state) { constexpr KHandle threadSelf{0xFFFF8000}; // The handle used by threads to refer to themselves - auto handle{state.ctx->gpr.w1}; + KHandle handle{state.ctx->gpr.w1}; pid_t pid{}; if (handle != threadSelf) @@ -628,7 +628,7 @@ namespace skyline::kernel::svc { } void OutputDebugString(const DeviceState &state) { - auto debug{span(reinterpret_cast(state.ctx->gpr.x0), state.ctx->gpr.x1).as_string()}; + auto debug{span(reinterpret_cast(state.ctx->gpr.x0), state.ctx->gpr.x1).as_string()}; if (debug.back() == '\n') debug.remove_suffix(1); @@ -638,91 +638,196 @@ namespace skyline::kernel::svc { } void GetInfo(const DeviceState &state) { - auto id0{state.ctx->gpr.w1}; - auto handle{state.ctx->gpr.w2}; - auto id1{state.ctx->gpr.x3}; + enum class InfoState : u32 { + // 1.0.0+ + AllowedCpuIdBitmask = 0x0, + AllowedThreadPriorityMask = 0x1, + AliasRegionBaseAddr = 0x2, + AliasRegionSize = 0x3, + HeapRegionBaseAddr = 0x4, + HeapRegionSize = 0x5, + TotalMemoryAvailable = 0x6, + TotalMemoryUsage = 0x7, + IsCurrentProcessBeingDebugged = 0x8, + ResourceLimit = 0x9, + IdleTickCount = 0xA, + RandomEntropy = 0xB, + // 2.0.0+ + AddressSpaceBaseAddr = 0xC, + AddressSpaceSize = 0xD, + StackRegionBaseAddr = 0xE, + StackRegionSize = 0xF, + // 3.0.0+ + TotalSystemResourceAvailable = 0x10, + TotalSystemResourceUsage = 0x11, + TitleId = 0x12, + // 4.0.0+ + PrivilegedProcessId = 0x13, + // 5.0.0+ + UserExceptionContextAddr = 0x14, + // 6.0.0+ + TotalMemoryAvailableWithoutSystemResource = 0x15, + TotalMemoryUsageWithoutSystemResource = 0x16, + }; - u64 out{}; + InfoState info{static_cast(state.ctx->gpr.w1)}; + KHandle handle{state.ctx->gpr.w2}; + u64 id1{state.ctx->gpr.x3}; constexpr u64 totalPhysicalMemory{0xF8000000}; // ~4 GB of RAM - switch (id0) { - case constant::infoState::AllowedCpuIdBitmask: - case constant::infoState::AllowedThreadPriorityMask: - case constant::infoState::IsCurrentProcessBeingDebugged: - case constant::infoState::TitleId: - case constant::infoState::PrivilegedProcessId: + u64 out{}; + switch (info) { + case InfoState::AllowedCpuIdBitmask: + case InfoState::AllowedThreadPriorityMask: + case InfoState::IsCurrentProcessBeingDebugged: + case InfoState::TitleId: + case InfoState::PrivilegedProcessId: break; - case constant::infoState::AliasRegionBaseAddr: + case InfoState::AliasRegionBaseAddr: out = state.process->memory.alias.address; break; - case constant::infoState::AliasRegionSize: + case InfoState::AliasRegionSize: out = state.process->memory.alias.size; break; - case constant::infoState::HeapRegionBaseAddr: + case InfoState::HeapRegionBaseAddr: out = state.process->memory.heap.address; break; - case constant::infoState::HeapRegionSize: + case InfoState::HeapRegionSize: out = state.process->memory.heap.size; break; - case constant::infoState::TotalMemoryAvailable: + case InfoState::TotalMemoryAvailable: out = totalPhysicalMemory; break; - case constant::infoState::TotalMemoryUsage: + case InfoState::TotalMemoryUsage: out = state.process->memory.GetMemoryUsage(); break; - case constant::infoState::AddressSpaceBaseAddr: + case InfoState::AddressSpaceBaseAddr: out = state.process->memory.base.address; break; - case constant::infoState::AddressSpaceSize: + case InfoState::AddressSpaceSize: out = state.process->memory.base.size; break; - case constant::infoState::StackRegionBaseAddr: + case InfoState::StackRegionBaseAddr: out = state.process->memory.stack.address; break; - case constant::infoState::StackRegionSize: + case InfoState::StackRegionSize: out = state.process->memory.stack.size; break; - case constant::infoState::PersonalMmHeapSize: - out = totalPhysicalMemory; + case InfoState::TotalSystemResourceAvailable: + out = totalPhysicalMemory; // TODO: NPDM specifies this in it's PersonalMmHeapSize field break; - case constant::infoState::PersonalMmHeapUsage: - out = state.process->heap->size + state.process->mainThreadStack->size; + case InfoState::TotalSystemResourceUsage: + // A very rough approximation of what this should be on the Switch, the amount of memory allocated for storing the memory blocks (https://switchbrew.org/wiki/Kernel_objects#KMemoryBlockManager) + out = state.process->memory.GetKMemoryBlockSize(); break; - case constant::infoState::TotalMemoryAvailableWithoutMmHeap: - out = totalPhysicalMemory; // TODO: NPDM specifies SystemResourceSize, subtract that from this + case InfoState::TotalMemoryAvailableWithoutSystemResource: + out = totalPhysicalMemory; // TODO: Subtract TotalSystemResourceAvailable from this break; - case constant::infoState::TotalMemoryUsedWithoutMmHeap: - out = state.process->heap->size + state.process->mainThreadStack->size; // TODO: Same as above + case InfoState::TotalMemoryUsageWithoutSystemResource: + out = state.process->memory.GetMemoryUsage(); break; - case constant::infoState::UserExceptionContextAddr: + case InfoState::UserExceptionContextAddr: out = reinterpret_cast(state.process->tlsPages[0]->Get(0)); break; default: - state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1); + state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", static_cast(info), id1); state.ctx->gpr.w0 = result::InvalidEnumValue; return; } - state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", id0, id1, out); + state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", static_cast(info), id1, out); state.ctx->gpr.x1 = out; state.ctx->gpr.w0 = Result{}; } + + void MapPhysicalMemory(const DeviceState &state) { + auto pointer{reinterpret_cast(state.ctx->gpr.x0)}; + size_t size{state.ctx->gpr.x1}; + + if (!util::PageAligned(pointer)) { + state.ctx->gpr.w0 = result::InvalidAddress; + return; + } + + if (!size || !util::PageAligned(size)) { + state.ctx->gpr.w0 = result::InvalidSize; + return; + } + + if (!state.process->memory.alias.IsInside(pointer) || !state.process->memory.alias.IsInside(pointer + size)) { + state.ctx->gpr.w0 = result::InvalidMemoryRegion; + return; + } + + state.process->NewHandle(pointer, size, memory::Permission{true, true, false}, memory::states::Heap); + + state.ctx->gpr.w0 = Result{}; + } + + void UnmapPhysicalMemory(const DeviceState &state) { + auto pointer{reinterpret_cast(state.ctx->gpr.x0)}; + size_t size{state.ctx->gpr.x1}; + + if (!util::PageAligned(pointer)) { + state.ctx->gpr.w0 = result::InvalidAddress; + return; + } + + if (!size || !util::PageAligned(size)) { + state.ctx->gpr.w0 = result::InvalidSize; + return; + } + + if (!state.process->memory.alias.IsInside(pointer) || !state.process->memory.alias.IsInside(pointer + size)) { + state.ctx->gpr.w0 = result::InvalidMemoryRegion; + return; + } + + auto end{pointer + size}; + while (pointer < end) { + auto memory{state.process->GetMemoryObject(pointer)}; + if (memory) { + auto item{static_pointer_cast(memory->item)}; + auto initialSize{item->size}; + if (item->memState == memory::states::Heap) { + if (item->ptr >= pointer) { + if (item->size <= size) { + item->Resize(0); + state.process->CloseHandle(memory->handle); + } else { + item->Remap(pointer + size, item->size - (size + (item->ptr - pointer))); + } + } else if (item->ptr < pointer) { + item->Resize(pointer - item->ptr); + } + } + pointer += initialSize; + size -= initialSize; + } else { + auto block{*state.process->memory.Get(pointer)}; + pointer += block.size; + size -= block.size; + } + } + + state.ctx->gpr.w0 = Result{}; + } } diff --git a/app/src/main/cpp/skyline/kernel/svc.h b/app/src/main/cpp/skyline/kernel/svc.h index 9e35b33d..1afa8dff 100644 --- a/app/src/main/cpp/skyline/kernel/svc.h +++ b/app/src/main/cpp/skyline/kernel/svc.h @@ -5,346 +5,324 @@ #include -namespace skyline { - namespace constant::infoState { - // 1.0.0+ - constexpr u8 AllowedCpuIdBitmask{0x0}; - constexpr u8 AllowedThreadPriorityMask{0x1}; - constexpr u8 AliasRegionBaseAddr{0x2}; - constexpr u8 AliasRegionSize{0x3}; - constexpr u8 HeapRegionBaseAddr{0x4}; - constexpr u8 HeapRegionSize{0x5}; - constexpr u8 TotalMemoryAvailable{0x6}; - constexpr u8 TotalMemoryUsage{0x7}; - constexpr u8 IsCurrentProcessBeingDebugged{0x8}; - constexpr u8 ResourceLimit{0x9}; - constexpr u8 IdleTickCount{0xA}; - constexpr u8 RandomEntropy{0xB}; - // 2.0.0+ - constexpr u8 AddressSpaceBaseAddr{0xC}; - constexpr u8 AddressSpaceSize{0xD}; - constexpr u8 StackRegionBaseAddr{0xE}; - constexpr u8 StackRegionSize{0xF}; - // 3.0.0+ - constexpr u8 PersonalMmHeapSize{0x10}; - constexpr u8 PersonalMmHeapUsage{0x11}; - constexpr u8 TitleId{0x12}; - // 4.0.0+ - constexpr u8 PrivilegedProcessId{0x13}; - // 5.0.0+ - constexpr u8 UserExceptionContextAddr{0x14}; - // 6.0.0+ - constexpr u8 TotalMemoryAvailableWithoutMmHeap{0x15}; - constexpr u8 TotalMemoryUsedWithoutMmHeap{0x16}; - } +namespace skyline::kernel::svc { + /** + * @brief Sets the process heap to a given size, it can both extend and shrink the heap + * @url https://switchbrew.org/wiki/SVC#SetHeapSize + */ + void SetHeapSize(const DeviceState &state); - namespace kernel::svc { - /** - * @brief Sets the process heap to a given size, it can both extend and shrink the heap - * @url https://switchbrew.org/wiki/SVC#SetHeapSize - */ - void SetHeapSize(const DeviceState &state); + /** + * @brief Change attribute of page-aligned memory region, this is used to turn on/off caching for a given memory area + * @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute + */ + void SetMemoryAttribute(const DeviceState &state); - /** - * @brief Change attribute of page-aligned memory region, this is used to turn on/off caching for a given memory area - * @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute - */ - void SetMemoryAttribute(const DeviceState &state); + /** + * @brief Maps a memory range into a different range, mainly used for adding guard pages around stack + * @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute + */ + void MapMemory(const DeviceState &state); - /** - * @brief Maps a memory range into a different range, mainly used for adding guard pages around stack - * @url https://switchbrew.org/wiki/SVC#SetMemoryAttribute - */ - void MapMemory(const DeviceState &state); + /** + * @brief Unmaps a region that was previously mapped with #MapMemory + * @url https://switchbrew.org/wiki/SVC#UnmapMemory + */ + void UnmapMemory(const DeviceState &state); - /** - * @brief Unmaps a region that was previously mapped with #MapMemory - * @url https://switchbrew.org/wiki/SVC#UnmapMemory - */ - void UnmapMemory(const DeviceState &state); + /** + * @brief Query information about an address + * @url https://switchbrew.org/wiki/SVC#QueryMemory + */ + void QueryMemory(const DeviceState &state); - /** - * @brief Query information about an address - * @url https://switchbrew.org/wiki/SVC#QueryMemory - */ - void QueryMemory(const DeviceState &state); + /** + * @brief Exits the current process + * @url https://switchbrew.org/wiki/SVC#ExitProcess + */ + void ExitProcess(const DeviceState &state); - /** - * @brief Exits the current process - * @url https://switchbrew.org/wiki/SVC#ExitProcess - */ - void ExitProcess(const DeviceState &state); + /** + * @brief Create a thread in the current process + * @url https://switchbrew.org/wiki/SVC#CreateThread + */ + void CreateThread(const DeviceState &state); - /** - * @brief Create a thread in the current process - * @url https://switchbrew.org/wiki/SVC#CreateThread - */ - void CreateThread(const DeviceState &state); + /** + * @brief Starts the thread for the provided handle + * @url https://switchbrew.org/wiki/SVC#StartThread + */ + void StartThread(const DeviceState &state); - /** - * @brief Starts the thread for the provided handle - * @url https://switchbrew.org/wiki/SVC#StartThread - */ - void StartThread(const DeviceState &state); + /** + * @brief Exits the current thread + * @url https://switchbrew.org/wiki/SVC#ExitThread + */ + void ExitThread(const DeviceState &state); - /** - * @brief Exits the current thread - * @url https://switchbrew.org/wiki/SVC#ExitThread - */ - void ExitThread(const DeviceState &state); + /** + * @brief Sleep for a specified amount of time, or yield thread + * @url https://switchbrew.org/wiki/SVC#SleepThread + */ + void SleepThread(const DeviceState &state); - /** - * @brief Sleep for a specified amount of time, or yield thread - * @url https://switchbrew.org/wiki/SVC#SleepThread - */ - void SleepThread(const DeviceState &state); + /** + * @brief Get priority of provided thread handle + * @url https://switchbrew.org/wiki/SVC#GetThreadPriority + */ + void GetThreadPriority(const DeviceState &state); - /** - * @brief Get priority of provided thread handle - * @url https://switchbrew.org/wiki/SVC#GetThreadPriority - */ - void GetThreadPriority(const DeviceState &state); + /** + * @brief Set priority of provided thread handle + * @url https://switchbrew.org/wiki/SVC#SetThreadPriority + */ + void SetThreadPriority(const DeviceState &state); - /** - * @brief Set priority of provided thread handle - * @url https://switchbrew.org/wiki/SVC#SetThreadPriority - */ - void SetThreadPriority(const DeviceState &state); + /** + * @brief Clears a KEvent of it's signal + * @url https://switchbrew.org/wiki/SVC#ClearEvent + */ + void ClearEvent(const DeviceState &state); - /** - * @brief Clears a KEvent of it's signal - * @url https://switchbrew.org/wiki/SVC#ClearEvent - */ - void ClearEvent(const DeviceState &state); + /** + * @brief Maps the block supplied by the handle + * @url https://switchbrew.org/wiki/SVC#MapSharedMemory + */ + void MapSharedMemory(const DeviceState &state); - /** - * @brief Maps the block supplied by the handle - * @url https://switchbrew.org/wiki/SVC#MapSharedMemory - */ - void MapSharedMemory(const DeviceState &state); + /** + * @brief Returns a handle to a KSharedMemory object + * @url https://switchbrew.org/wiki/SVC#CreateTransferMemory + */ + void CreateTransferMemory(const DeviceState &state); - /** - * @brief Returns a handle to a KSharedMemory object - * @url https://switchbrew.org/wiki/SVC#CreateTransferMemory - */ - void CreateTransferMemory(const DeviceState &state); + /** + * @brief Closes the specified handle + * @url https://switchbrew.org/wiki/SVC#CloseHandle + */ + void CloseHandle(const DeviceState &state); - /** - * @brief Closes the specified handle - * @url https://switchbrew.org/wiki/SVC#CloseHandle - */ - void CloseHandle(const DeviceState &state); + /** + * @brief Resets a particular KEvent or KProcess which is signalled + * @url https://switchbrew.org/wiki/SVC#ResetSignal + */ + void ResetSignal(const DeviceState &state); - /** - * @brief Resets a particular KEvent or KProcess which is signalled - * @url https://switchbrew.org/wiki/SVC#ResetSignal - */ - void ResetSignal(const DeviceState &state); + /** + * @brief Stalls a thread till a KSyncObject signals or the timeout has ended + * @url https://switchbrew.org/wiki/SVC#WaitSynchronization + */ + void WaitSynchronization(const DeviceState &state); - /** - * @brief Stalls a thread till a KSyncObject signals or the timeout has ended - * @url https://switchbrew.org/wiki/SVC#WaitSynchronization - */ - void WaitSynchronization(const DeviceState &state); + /** + * @brief If the referenced thread is currently in a synchronization call, that call will be interrupted + * @url https://switchbrew.org/wiki/SVC#CancelSynchronization + */ + void CancelSynchronization(const DeviceState &state); - /** - * @brief If the referenced thread is currently in a synchronization call, that call will be interrupted - * @url https://switchbrew.org/wiki/SVC#CancelSynchronization - */ - void CancelSynchronization(const DeviceState &state); + /** + * @brief Locks a specified mutex + * @url https://switchbrew.org/wiki/SVC#ArbitrateLock + */ + void ArbitrateLock(const DeviceState &state); - /** - * @brief Locks a specified mutex - * @url https://switchbrew.org/wiki/SVC#ArbitrateLock - */ - void ArbitrateLock(const DeviceState &state); + /** + * @brief Unlocks a specified mutex + * @url https://switchbrew.org/wiki/SVC#ArbitrateUnlock + */ + void ArbitrateUnlock(const DeviceState &state); - /** - * @brief Unlocks a specified mutex - * @url https://switchbrew.org/wiki/SVC#ArbitrateUnlock - */ - void ArbitrateUnlock(const DeviceState &state); + /** + * @brief Waits on a process-wide key (Conditional-Variable) + * @url https://switchbrew.org/wiki/SVC#WaitProcessWideKeyAtomic + */ + void WaitProcessWideKeyAtomic(const DeviceState &state); - /** - * @brief Waits on a process-wide key (Conditional-Variable) - * @url https://switchbrew.org/wiki/SVC#WaitProcessWideKeyAtomic - */ - void WaitProcessWideKeyAtomic(const DeviceState &state); + /** + * @brief Signals a process-wide key (Conditional-Variable) + * @url https://switchbrew.org/wiki/SVC#SignalProcessWideKey + */ + void SignalProcessWideKey(const DeviceState &state); - /** - * @brief Signals a process-wide key (Conditional-Variable) - * @url https://switchbrew.org/wiki/SVC#SignalProcessWideKey - */ - void SignalProcessWideKey(const DeviceState &state); + /** + * @brief Returns the value of CNTPCT_EL0 on the Switch + * @url https://switchbrew.org/wiki/SVC#GetSystemTick + */ + void GetSystemTick(const DeviceState &state); - /** - * @brief Returns the value of CNTPCT_EL0 on the Switch - * @url https://switchbrew.org/wiki/SVC#GetSystemTick - */ - void GetSystemTick(const DeviceState &state); + /** + * @brief Connects to a named IPC port + * @url https://switchbrew.org/wiki/SVC#ConnectToNamedPort + */ + void ConnectToNamedPort(const DeviceState &state); - /** - * @brief Connects to a named IPC port - * @url https://switchbrew.org/wiki/SVC#ConnectToNamedPort - */ - void ConnectToNamedPort(const DeviceState &state); + /** + * @brief Send a synchronous IPC request to a service + * @url https://switchbrew.org/wiki/SVC#SendSyncRequest + */ + void SendSyncRequest(const DeviceState &state); - /** - * @brief Send a synchronous IPC request to a service - * @url https://switchbrew.org/wiki/SVC#SendSyncRequest - */ - void SendSyncRequest(const DeviceState &state); + /** + * @brief Retrieves the PID of a specific thread + * @url https://switchbrew.org/wiki/SVC#GetThreadId + */ + void GetThreadId(const DeviceState &state); - /** - * @brief Retrieves the PID of a specific thread - * @url https://switchbrew.org/wiki/SVC#GetThreadId - */ - void GetThreadId(const DeviceState &state); + /** + * @brief Outputs a debug string + * @url https://switchbrew.org/wiki/SVC#OutputDebugString + */ + void OutputDebugString(const DeviceState &state); - /** - * @brief Outputs a debug string - * @url https://switchbrew.org/wiki/SVC#OutputDebugString - */ - void OutputDebugString(const DeviceState &state); + /** + * @brief Retrieves a piece of information + * @url https://switchbrew.org/wiki/SVC#GetInfo + */ + void GetInfo(const DeviceState &state); - /** - * @brief Retrieves a piece of information - * @url https://switchbrew.org/wiki/SVC#GetInfo - */ - void GetInfo(const DeviceState &state); + /** + * @brief Maps physical memory to a part of virtual memory + * @url https://switchbrew.org/wiki/SVC#MapPhysicalMemory + */ + void MapPhysicalMemory(const DeviceState &state); - /** - * @brief The SVC Table maps all SVCs to their corresponding functions - */ - static std::array SvcTable{ - nullptr, // 0x00 (Does not exist) - SetHeapSize, // 0x01 - nullptr, // 0x02 - SetMemoryAttribute, // 0x03 - MapMemory, // 0x04 - UnmapMemory, // 0x05 - QueryMemory, // 0x06 - ExitProcess, // 0x07 - CreateThread, // 0x08 - StartThread, // 0x09 - ExitThread, // 0x0A - SleepThread, // 0x0B - GetThreadPriority, // 0x0C - SetThreadPriority, // 0x0D - nullptr, // 0x0E - nullptr, // 0x0F - nullptr, // 0x10 - nullptr, // 0x11 - ClearEvent, // 0x12 - MapSharedMemory, // 0x13 - nullptr, // 0x14 - CreateTransferMemory, // 0x15 - CloseHandle, // 0x16 - ResetSignal, // 0x17 - WaitSynchronization, // 0x18 - CancelSynchronization, // 0x19 - ArbitrateLock, // 0x1A - ArbitrateUnlock, // 0x1B - WaitProcessWideKeyAtomic, // 0x1C - SignalProcessWideKey, // 0x1D - GetSystemTick, // 0x1E - ConnectToNamedPort, // 0x1F - nullptr, // 0x20 - SendSyncRequest, // 0x21 - nullptr, // 0x22 - nullptr, // 0x23 - nullptr, // 0x24 - GetThreadId, // 0x25 - nullptr, // 0x26 - OutputDebugString, // 0x27 - nullptr, // 0x28 - GetInfo, // 0x29 - nullptr, // 0x2A - nullptr, // 0x2B - nullptr, // 0x2C - nullptr, // 0x2D - nullptr, // 0x2E - nullptr, // 0x2F - nullptr, // 0x30 - nullptr, // 0x31 - nullptr, // 0x32 - nullptr, // 0x33 - nullptr, // 0x34 - nullptr, // 0x35 - nullptr, // 0x36 - nullptr, // 0x37 - nullptr, // 0x38 - nullptr, // 0x39 - nullptr, // 0x3A - nullptr, // 0x3B - nullptr, // 0x3C - nullptr, // 0x3D - nullptr, // 0x3E - nullptr, // 0x3F - nullptr, // 0x40 - nullptr, // 0x41 - nullptr, // 0x42 - nullptr, // 0x43 - nullptr, // 0x44 - nullptr, // 0x45 - nullptr, // 0x46 - nullptr, // 0x47 - nullptr, // 0x48 - nullptr, // 0x49 - nullptr, // 0x4A - nullptr, // 0x4B - nullptr, // 0x4C - nullptr, // 0x4D - nullptr, // 0x4E - nullptr, // 0x4F - nullptr, // 0x50 - nullptr, // 0x51 - nullptr, // 0x52 - nullptr, // 0x53 - nullptr, // 0x54 - nullptr, // 0x55 - nullptr, // 0x56 - nullptr, // 0x57 - nullptr, // 0x58 - nullptr, // 0x59 - nullptr, // 0x5A - nullptr, // 0x5B - nullptr, // 0x5C - nullptr, // 0x5D - nullptr, // 0x5E - nullptr, // 0x5F - nullptr, // 0x60 - nullptr, // 0x61 - nullptr, // 0x62 - nullptr, // 0x63 - nullptr, // 0x64 - nullptr, // 0x65 - nullptr, // 0x66 - nullptr, // 0x67 - nullptr, // 0x68 - nullptr, // 0x69 - nullptr, // 0x6A - nullptr, // 0x6B - nullptr, // 0x6C - nullptr, // 0x6D - nullptr, // 0x6E - nullptr, // 0x6F - nullptr, // 0x70 - nullptr, // 0x71 - nullptr, // 0x72 - nullptr, // 0x73 - nullptr, // 0x74 - nullptr, // 0x75 - nullptr, // 0x76 - nullptr, // 0x77 - nullptr, // 0x78 - nullptr, // 0x79 - nullptr, // 0x7A - nullptr, // 0x7B - nullptr, // 0x7C - nullptr, // 0x7D - nullptr, // 0x7E - nullptr // 0x7F - }; - } + /** + * @brief Unmaps previously mapped physical memory + * @url https://switchbrew.org/wiki/SVC#UnmapPhysicalMemory + */ + void UnmapPhysicalMemory(const DeviceState &state); + + /** + * @brief The SVC Table maps all SVCs to their corresponding functions + */ + static std::array SvcTable{ + nullptr, // 0x00 (Does not exist) + SetHeapSize, // 0x01 + nullptr, // 0x02 + SetMemoryAttribute, // 0x03 + MapMemory, // 0x04 + UnmapMemory, // 0x05 + QueryMemory, // 0x06 + ExitProcess, // 0x07 + CreateThread, // 0x08 + StartThread, // 0x09 + ExitThread, // 0x0A + SleepThread, // 0x0B + GetThreadPriority, // 0x0C + SetThreadPriority, // 0x0D + nullptr, // 0x0E + nullptr, // 0x0F + nullptr, // 0x10 + nullptr, // 0x11 + ClearEvent, // 0x12 + MapSharedMemory, // 0x13 + nullptr, // 0x14 + CreateTransferMemory, // 0x15 + CloseHandle, // 0x16 + ResetSignal, // 0x17 + WaitSynchronization, // 0x18 + CancelSynchronization, // 0x19 + ArbitrateLock, // 0x1A + ArbitrateUnlock, // 0x1B + WaitProcessWideKeyAtomic, // 0x1C + SignalProcessWideKey, // 0x1D + GetSystemTick, // 0x1E + ConnectToNamedPort, // 0x1F + nullptr, // 0x20 + SendSyncRequest, // 0x21 + nullptr, // 0x22 + nullptr, // 0x23 + nullptr, // 0x24 + GetThreadId, // 0x25 + nullptr, // 0x26 + OutputDebugString, // 0x27 + nullptr, // 0x28 + GetInfo, // 0x29 + nullptr, // 0x2A + nullptr, // 0x2B + MapPhysicalMemory, // 0x2C + UnmapPhysicalMemory, // 0x2D + nullptr, // 0x2E + nullptr, // 0x2F + nullptr, // 0x30 + nullptr, // 0x31 + nullptr, // 0x32 + nullptr, // 0x33 + nullptr, // 0x34 + nullptr, // 0x35 + nullptr, // 0x36 + nullptr, // 0x37 + nullptr, // 0x38 + nullptr, // 0x39 + nullptr, // 0x3A + nullptr, // 0x3B + nullptr, // 0x3C + nullptr, // 0x3D + nullptr, // 0x3E + nullptr, // 0x3F + nullptr, // 0x40 + nullptr, // 0x41 + nullptr, // 0x42 + nullptr, // 0x43 + nullptr, // 0x44 + nullptr, // 0x45 + nullptr, // 0x46 + nullptr, // 0x47 + nullptr, // 0x48 + nullptr, // 0x49 + nullptr, // 0x4A + nullptr, // 0x4B + nullptr, // 0x4C + nullptr, // 0x4D + nullptr, // 0x4E + nullptr, // 0x4F + nullptr, // 0x50 + nullptr, // 0x51 + nullptr, // 0x52 + nullptr, // 0x53 + nullptr, // 0x54 + nullptr, // 0x55 + nullptr, // 0x56 + nullptr, // 0x57 + nullptr, // 0x58 + nullptr, // 0x59 + nullptr, // 0x5A + nullptr, // 0x5B + nullptr, // 0x5C + nullptr, // 0x5D + nullptr, // 0x5E + nullptr, // 0x5F + nullptr, // 0x60 + nullptr, // 0x61 + nullptr, // 0x62 + nullptr, // 0x63 + nullptr, // 0x64 + nullptr, // 0x65 + nullptr, // 0x66 + nullptr, // 0x67 + nullptr, // 0x68 + nullptr, // 0x69 + nullptr, // 0x6A + nullptr, // 0x6B + nullptr, // 0x6C + nullptr, // 0x6D + nullptr, // 0x6E + nullptr, // 0x6F + nullptr, // 0x70 + nullptr, // 0x71 + nullptr, // 0x72 + nullptr, // 0x73 + nullptr, // 0x74 + nullptr, // 0x75 + nullptr, // 0x76 + nullptr, // 0x77 + nullptr, // 0x78 + nullptr, // 0x79 + nullptr, // 0x7A + nullptr, // 0x7B + nullptr, // 0x7C + nullptr, // 0x7D + nullptr, // 0x7E + nullptr // 0x7F + }; } diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index ca01fa97..06bb0f0e 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -8,7 +8,7 @@ #include "KProcess.h" namespace skyline::kernel::type { - KPrivateMemory::KPrivateMemory(const DeviceState &state, u8* ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) { + KPrivateMemory::KPrivateMemory(const DeviceState &state, u8 *ptr, size_t size, memory::Permission permission, memory::MemoryState memState) : ptr(ptr), size(size), permission(permission), memState(memState), KMemory(state, KType::KPrivateMemory) { if (!state.process->memory.base.IsInside(ptr) || !state.process->memory.base.IsInside(ptr + size)) throw exception("KPrivateMemory allocation isn't inside guest address space: 0x{:X} - 0x{:X}", ptr, ptr + size); if (!util::PageAligned(ptr) || !util::PageAligned(size)) @@ -47,7 +47,20 @@ namespace skyline::kernel::type { size = nSize; } - void KPrivateMemory::UpdatePermission(u8* ptr, size_t size, memory::Permission permission) { + void KPrivateMemory::Remap(u8 *nPtr, size_t nSize) { + if (!state.process->memory.base.IsInside(nPtr) || !state.process->memory.base.IsInside(nPtr + nSize)) + throw exception("KPrivateMemory remapping isn't inside guest address space: 0x{:X} - 0x{:X}", nPtr, nPtr + nSize); + if (!util::PageAligned(nPtr) || !util::PageAligned(nSize)) + throw exception("KPrivateMemory remapping isn't page-aligned: 0x{:X} - 0x{:X} (0x{:X})", nPtr, nPtr + nSize, nSize); + + if (mprotect(ptr, size, PROT_NONE) < 0) + throw exception("An occurred while remapping private memory: {}", strerror(errno)); + + if (mprotect(nPtr, nSize, PROT_NONE) < 0) + throw exception("An occurred while remapping private memory: {}", strerror(errno)); + } + + void KPrivateMemory::UpdatePermission(u8 *ptr, size_t size, memory::Permission permission) { ptr = std::clamp(ptr, this->ptr, this->ptr + this->size); size = std::min(size, static_cast((this->ptr + this->size) - ptr)); diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h index b8295098..c85ad57e 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.h @@ -24,6 +24,11 @@ namespace skyline::kernel::type { void Resize(size_t size); + /** + * @note Only contents of any overlapping regions will be retained + */ + void Remap(u8* ptr, size_t size); + inline span Get() override { return span(ptr, size); } diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 90e5ce8c..d2449260 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -23,6 +23,9 @@ namespace skyline { * @brief KProcess manages process-global state such as memory, kernel handles allocated to the process and synchronization primitives */ class KProcess : public KSyncObject { + public: + MemoryManager memory; // This is here to ensure it is present during the destruction of dependent objects + private: std::vector> handles; std::shared_mutex handleMutex; @@ -63,7 +66,6 @@ namespace skyline { }; public: - MemoryManager memory; std::shared_ptr mainThreadStack; std::shared_ptr heap; std::vector> threads; diff --git a/app/src/main/cpp/skyline/loader/nca.cpp b/app/src/main/cpp/skyline/loader/nca.cpp index b15b7f3c..1da1c735 100644 --- a/app/src/main/cpp/skyline/loader/nca.cpp +++ b/app/src/main/cpp/skyline/loader/nca.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) -#include #include #include "nso.h" #include "nca.h" diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index cf255727..258da19f 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -35,7 +35,9 @@ namespace skyline::nce { void NCE::SignalHandler(int signal, siginfo *, void *context) { ThreadContext *threadCtx; - asm("MRS %0, TPIDR_EL0":"=r"(threadCtx)); + asm volatile("MRS %x0, TPIDR_EL0":"=r"(threadCtx)); + asm volatile("MSR TPIDR_EL0, %x0"::"r"(threadCtx->hostTpidrEl0)); + const auto &state{*threadCtx->state}; state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal)); @@ -68,9 +70,11 @@ namespace skyline::nce { for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2) cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? ' ' : '\0', index + 1, ctx.regs[index]); - state.logger->Debug("Process Trace:{}", trace); - state.logger->Debug("Raw Instructions: 0x{}", raw); - state.logger->Debug("CPU Context:{}", cpuContext); + state.logger->Warn("Process Trace:{}", trace); + state.logger->Warn("Raw Instructions: 0x{}", raw); + state.logger->Warn("CPU Context:{}", cpuContext); + + asm volatile("MSR TPIDR_EL0, %x0"::"r"(threadCtx)); } NCE::NCE(DeviceState &state) : state(state) {} diff --git a/app/src/main/cpp/skyline/nce/guest.h b/app/src/main/cpp/skyline/nce/guest.h index 532d228b..69a4ebe2 100644 --- a/app/src/main/cpp/skyline/nce/guest.h +++ b/app/src/main/cpp/skyline/nce/guest.h @@ -8,6 +8,20 @@ namespace skyline { struct DeviceState; namespace nce { + struct WRegister { + u32 lower; + u32 upper; + + constexpr operator u32() { + return lower; + } + + void operator=(u32 value) { + lower = value; + upper = 0; + } + }; + /** * @brief The state of callee-saved general purpose registers in the guest * @note Read about ARMv8 registers here: https://developer.arm.com/architectures/learn-the-architecture/armv8-a-instruction-set-architecture/registers-in-aarch64-general-purpose-registers @@ -37,44 +51,25 @@ namespace skyline { u64 x18; }; struct { - u32 w0; - u32 __w0__; - u32 w1; - u32 __w1__; - u32 w2; - u32 __w2__; - u32 w3; - u32 __w3__; - u32 w4; - u32 __w4__; - u32 w5; - u32 __w5__; - u32 w6; - u32 __w6__; - u32 w7; - u32 __w7__; - u32 w8; - u32 __w8__; - u32 w9; - u32 __w9__; - u32 w10; - u32 __w10__; - u32 w11; - u32 __w11__; - u32 w12; - u32 __w12__; - u32 w13; - u32 __w13__; - u32 w14; - u32 __w14__; - u32 w15; - u32 __w15__; - u32 w16; - u32 __w16__; - u32 w17; - u32 __w17__; - u32 w18; - u32 __w18__; + WRegister w0; + WRegister w1; + WRegister w2; + WRegister w3; + WRegister w4; + WRegister w5; + WRegister w6; + WRegister w7; + WRegister w8; + WRegister w9; + WRegister w10; + WRegister w11; + WRegister w12; + WRegister w13; + WRegister w14; + WRegister w15; + WRegister w16; + WRegister w17; + WRegister w18; }; };