From 1956a3bbbbcf23901f76f6f37d570e9499f621f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Mon, 18 Nov 2019 01:49:01 +0530 Subject: [PATCH] Make SVCs more accurate & Improve KSharedMemory This commit adds logging to almost all SVCs with the exception of svcGetSystemTick and adds accurate error handling to them. It also improves how KSharedMemory is handled. --- app/src/main/cpp/skyline/common.h | 11 +- .../main/cpp/skyline/gpu/devices/nvmap.cpp | 10 +- app/src/main/cpp/skyline/kernel/svc.cpp | 423 ++++++++++++------ app/src/main/cpp/skyline/kernel/svc.h | 21 +- .../skyline/kernel/types/KPrivateMemory.cpp | 6 +- .../skyline/kernel/types/KSharedMemory.cpp | 80 ++-- .../cpp/skyline/kernel/types/KSharedMemory.h | 31 +- .../main/cpp/skyline/kernel/types/KThread.cpp | 10 +- app/src/main/cpp/skyline/os.cpp | 20 +- app/src/main/cpp/skyline/os.h | 14 +- .../skyline/services/am/appletController.cpp | 2 +- app/src/main/cpp/skyline/services/hid/hid.cpp | 4 +- .../main/cpp/skyline/services/nvdrv/nvdrv.cpp | 5 +- app/src/main/cpp/skyline/services/vi/vi_m.cpp | 2 +- 14 files changed, 396 insertions(+), 243 deletions(-) diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index 6fa826ce..7081d0be 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -40,7 +40,8 @@ namespace skyline { constexpr u64 MapSize = 0x1000000000; //!< The size of the map region constexpr u64 TotalPhyMem = 0xF8000000; // ~4 GB of RAM constexpr size_t DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB - constexpr size_t DefHeapSize = PAGE_SIZE; //!< The default amount of heap + constexpr size_t HeapSizeDiv = 0x200000; //!< The amount heap size has to be divisible by + constexpr size_t DefHeapSize = HeapSizeDiv; //!< The default amount of heap constexpr size_t TlsSlotSize = 0x200; //!< The size of a single TLS slot constexpr u8 TlsSlots = PAGE_SIZE / TlsSlotSize; //!< The amount of TLS slots in a single page // Loader @@ -76,14 +77,18 @@ namespace skyline { // Status codes namespace status { constexpr u32 Success = 0x0; //!< "Success" + constexpr u32 NoMessages = 0x680; //!< "No message available" constexpr u32 ServiceInvName = 0xC15; //!< "Invalid name" constexpr u32 ServiceNotReg = 0xE15; //!< "Service not registered" + constexpr u32 InvSize = 0xCA01; //!< "Invalid size" constexpr u32 InvAddress = 0xCC01; //!< "Invalid address" + constexpr u32 InvPermission = 0xE001; //!< "Invalid Permission" constexpr u32 InvHandle = 0xE401; //!< "Invalid handle" + constexpr u32 InvCombination = 0xE801; //!< "Invalid combination" constexpr u32 MaxHandles = 0xEE01; //!< "Too many handles" - constexpr u32 Timeout = 0xEA01; //!< "Timeout while svcWaitSynchronization" + constexpr u32 Timeout = 0xEA01; //!< "Timeout" + constexpr u32 NotFound = 0xF201; //!< "Not found" constexpr u32 Unimpl = 0x177202; //!< "Unimplemented behaviour" - constexpr u32 NoMessages = 0x680; //!< "No message available" } }; diff --git a/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp b/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp index 50aa206d..68404bde 100644 --- a/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp +++ b/app/src/main/cpp/skyline/gpu/devices/nvmap.cpp @@ -21,7 +21,7 @@ namespace skyline::gpu::device { handleTable[handleIndex] = std::make_shared(idIndex++, data.size); data.handle = handleIndex++; state.thisProcess->WriteMemory(data, buffer.output[0].address); - state.logger->Info("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status); + state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status); } void NvMap::FromId(skyline::gpu::device::IoctlBuffers &buffer) { @@ -41,7 +41,7 @@ namespace skyline::gpu::device { state.thisProcess->WriteMemory(data, buffer.output[0].address); else buffer.status = NvStatus::BadValue; - state.logger->Info("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); + state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); } void NvMap::Alloc(IoctlBuffers &buffer) { @@ -61,7 +61,7 @@ namespace skyline::gpu::device { object->kind = data.kind; object->address = data.address; object->status = NvMapObject::Status::Allocated; - state.logger->Info("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status); + state.logger->Debug("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status); } void NvMap::Free(skyline::gpu::device::IoctlBuffers &buffer) { @@ -125,7 +125,7 @@ namespace skyline::gpu::device { break; } state.thisProcess->WriteMemory(data, buffer.output[0].address); - state.logger->Info("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status); + state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status); } void NvMap::GetId(skyline::gpu::device::IoctlBuffers &buffer) { @@ -135,6 +135,6 @@ namespace skyline::gpu::device { } data = state.thisProcess->ReadMemory(buffer.input[0].address); data.id = handleTable.at(data.handle)->id; state.thisProcess->WriteMemory(data, buffer.output[0].address); - state.logger->Info("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); + state.logger->Debug("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); } } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index d0873c74..af167aee 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -1,46 +1,74 @@ #include "svc.h" #include -#include namespace skyline::kernel::svc { void SetHeapSize(DeviceState &state) { - u32 size = state.nce->GetRegister(Wreg::W1); + const u32 size = state.nce->GetRegister(Wreg::W1); + if(size%constant::HeapSizeDiv != 0) { + state.nce->SetRegister(Xreg::X1, 0); + state.nce->SetRegister(Wreg::W0, constant::status::InvSize); + state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size); + return; + } std::shared_ptr heap; try { heap = state.thisProcess->memoryRegionMap.at(memory::Region::Heap); - heap->Resize(size, true); // This can fail due to not enough space to resize + heap->Resize(size, true); } catch (const exception &) { - state.logger->Warn("svcSetHeapSize is falling back to recreating memory"); + state.logger->Warn("svcSetHeapSize: Falling back to recreating memory"); state.thisProcess->UnmapPrivateRegion(memory::Region::Heap); heap = state.thisProcess->MapPrivateRegion(constant::HeapAddr, size, {true, true, false}, memory::Type::Heap, memory::Region::Heap).item; } state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Xreg::X1, heap->address); - state.logger->Debug("svcSetHeapSize allocated at 0x{:X} for 0x{:X} bytes", heap->address, heap->size); + state.logger->Debug("svcSetHeapSize: Allocated at 0x{:X} for 0x{:X} bytes", heap->address, heap->size); } void SetMemoryAttribute(DeviceState &state) { - u64 addr = state.nce->GetRegister(Xreg::X0); - u64 size = state.nce->GetRegister(Xreg::X1); - bool isUncached = (state.nce->GetRegister(Wreg::W2) == 8) && (state.nce->GetRegister(Wreg::W3) == 8); + const u64 addr = state.nce->GetRegister(Xreg::X0); + if((addr & (PAGE_SIZE - 1))) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: {}", addr); + return; + } + const u64 size = state.nce->GetRegister(Xreg::X1); + if((size & (PAGE_SIZE - 1)) || !size) { + state.nce->SetRegister(Wreg::W0, constant::status::InvSize); + state.logger->Warn("svcSetMemoryAttribute: 'size' {}: {}", size ? "not page aligned" : "is zero", size); + return; + } + u32 mask = state.nce->GetRegister(Wreg::W2); + u32 value = state.nce->GetRegister(Wreg::W3); + u32 maskedValue = mask | value; + if(maskedValue != mask) { + state.nce->SetRegister(Wreg::W0, constant::status::InvCombination); + state.logger->Warn("svcSetMemoryAttribute: 'mask' invalid: 0x{:X}, 0x{:X}", mask, value); + return; + } + memory::MemoryAttribute attribute = *reinterpret_cast(&maskedValue); bool found = false; for (const auto&[address, region] : state.thisProcess->memoryMap) { if (addr >= address && addr < (address + region->size)) { bool subFound = false; for (auto &subregion : region->regionInfoVec) { if ((address >= subregion.address) && (address < (subregion.address + subregion.size))) - subregion.isUncached = isUncached; + subregion.isUncached = attribute.isUncached; subFound = true; break; } if (!subFound) - region->regionInfoVec.emplace_back(addr, size, isUncached); + region->regionInfoVec.emplace_back(addr, size, static_cast(attribute.isUncached)); found = true; break; } } - state.logger->Debug("svcSetMemoryAttribute set caching to {} at 0x{:X} for 0x{:X} bytes", !isUncached, addr, size); - state.nce->SetRegister(Wreg::W0, found ? constant::status::Success : constant::status::InvAddress); + if(!found) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", addr); + return; + } + state.logger->Debug("svcSetMemoryAttribute: Set caching to {} at 0x{:X} for 0x{:X} bytes", !attribute.isUncached, addr, size); + state.nce->SetRegister(Wreg::W0, constant::status::Success); } void QueryMemory(DeviceState &state) { @@ -81,34 +109,49 @@ namespace skyline::kernel::svc { .size = static_cast(-constant::BaseEnd + 1), .type = static_cast(memory::Type::Unmapped) }; - state.logger->Warn("Cannot find block of address: 0x{:X}", addr); + state.logger->Debug("svcQueryMemory: Cannot find block of address: 0x{:X}", addr); } } + state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: {}, Is Uncached: {}, Permissions: {}{}{}", memInf.baseAddress, memInf.size, memInf.type, static_cast(memInf.memoryAttribute.isUncached), memInf.perms.r ? "R" : "-", memInf.perms.w ? "W" : "-", memInf.perms.x ? "X" : "-"); state.thisProcess->WriteMemory(memInf, state.nce->GetRegister(Xreg::X0)); state.nce->SetRegister(Wreg::W0, constant::status::Success); } void ExitProcess(DeviceState &state) { + state.logger->Debug("svcExitProcess: Exiting current process: {}", state.thisProcess->mainThread); state.os->KillThread(state.thisProcess->mainThread); } void CreateThread(DeviceState &state) { - // TODO: Support Core Mask potentially - auto thread = state.thisProcess->CreateThread(state.nce->GetRegister(Xreg::X1), state.nce->GetRegister(Xreg::X2), state.nce->GetRegister(Xreg::X3), static_cast(state.nce->GetRegister(Wreg::W4))); + u64 entryAddr = state.nce->GetRegister(Xreg::X1); + u64 entryArg = state.nce->GetRegister(Xreg::X2); + u64 stackTop = state.nce->GetRegister(Xreg::X3); + u8 priority = static_cast(state.nce->GetRegister(Wreg::W4)); + if(priority >= constant::PriorityNin.first && priority <= constant::PriorityNin.second) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcSetHeapSize: 'priority' invalid: {}", priority); + return; + } + auto thread = state.thisProcess->CreateThread(entryAddr, entryArg, stackTop, priority); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Wreg::W1, thread->handle); - state.logger->Info("Creating a thread: {}", thread->handle); + state.logger->Info("svcCreateThread: Created thread with handle 0x{:X}", thread->handle); } void StartThread(DeviceState &state) { - auto &object = state.thisProcess->handleTable.at(static_cast(state.nce->GetRegister(Wreg::W0))); - if (object->objectType == type::KType::KThread) - std::static_pointer_cast(object)->Start(); - else - throw exception("StartThread was called on a non-KThread object"); + auto handle = state.nce->GetRegister(Wreg::W0); + try { + auto thread = state.thisProcess->GetHandle(handle); + state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, {}", handle, thread->pid); + thread->Start(); + } catch (const std::exception&) { + state.logger->Warn("svcStartThread: 'handle' invalid: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + } } void ExitThread(DeviceState &state) { + state.logger->Debug("svcExitProcess: Exiting current thread: {}", state.thisThread->pid); state.os->KillThread(state.thisThread->pid); } @@ -118,62 +161,145 @@ namespace skyline::kernel::svc { case 0: case 1: case 2: + state.logger->Debug("svcSleepThread: Yielding thread: {}", in); state.thisThread->status = type::KThread::Status::Runnable; // Will cause the application to awaken on the next iteration of the main loop + break; default: + state.logger->Debug("svcSleepThread: Thread sleeping for {} ns", in); state.thisThread->timeout = GetCurrTimeNs() + in; state.thisThread->status = type::KThread::Status::Sleeping; } } void GetThreadPriority(DeviceState &state) { - state.nce->SetRegister(Wreg::W1, state.thisProcess->GetHandle(static_cast(state.nce->GetRegister(Wreg::W0)))->priority); - state.nce->SetRegister(Wreg::W0, constant::status::Success); + auto handle = state.nce->GetRegister(Wreg::W0); + try { + auto priority = state.thisProcess->GetHandle(handle)->priority; + state.nce->SetRegister(Wreg::W1, priority); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); + } catch (const std::exception&) { + state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + } } void SetThreadPriority(DeviceState &state) { - state.thisProcess->GetHandle(static_cast(state.nce->GetRegister(Wreg::W0)))->Start(); - state.nce->SetRegister(Wreg::W0, constant::status::Success); + auto handle = state.nce->GetRegister(Wreg::W0); + auto priority = state.nce->GetRegister(Wreg::W1); + try { + state.thisProcess->GetHandle(handle)->UpdatePriority(static_cast(priority)); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); + } catch (const std::exception&) { + state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + } } void MapSharedMemory(DeviceState &state) { - auto object = state.thisProcess->GetHandle(static_cast(state.nce->GetRegister(Wreg::W0))); - object->Map(state.nce->GetRegister(Xreg::X1), state.nce->GetRegister(Xreg::X2), state.thisProcess->mainThread); - state.nce->SetRegister(Wreg::W0, constant::status::Success); - } - - void CloseHandle(DeviceState &state) { - auto handle = static_cast(state.nce->GetRegister(Wreg::W0)); - state.logger->Debug("Closing handle: 0x{:X}", handle); - auto &object = state.thisProcess->handleTable.at(handle); - switch (object->objectType) { - case (type::KType::KThread): - state.os->KillThread(std::static_pointer_cast(object)->pid); - break; - case (type::KType::KProcess): - state.os->KillThread(std::static_pointer_cast(object)->mainThread); - break; - default: - state.thisProcess->handleTable.erase(handle); + try { + auto object = state.thisProcess->GetHandle(state.nce->GetRegister(Wreg::W0)); + u64 addr = state.nce->GetRegister(Xreg::X1); + if ((addr & (PAGE_SIZE - 1U))) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcMapSharedMemory: 'address' not page aligned: 0x{:X}", addr); + return; + } + const u64 size = state.nce->GetRegister(Xreg::X2); + if ((size & (PAGE_SIZE - 1U)) || !size) { + state.nce->SetRegister(Wreg::W0, constant::status::InvSize); + state.logger->Warn("svcMapSharedMemory: 'size' {}: {}", size ? "not page aligned" : "is zero", size); + return; + } + u32 perm = state.nce->GetRegister(Wreg::W3); + memory::Permission permission = *reinterpret_cast(&perm); + if ((permission.w && !permission.r) || (permission.x && !permission.r)) { + state.logger->Warn("svcMapSharedMemory: 'permission' invalid: {}{}{}", permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-"); + state.nce->SetRegister(Wreg::W0, constant::status::InvPermission); + return; + } + state.logger->Debug("svcMapSharedMemory: Mapping shared memory at 0x{:X} for {} bytes ({}{}{})", addr, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-"); + object->Map(addr, size, permission, state.thisProcess->mainThread); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + } catch (const std::exception &) { + state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.nce->GetRegister(Wreg::W0)); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); } - state.nce->SetRegister(Wreg::W0, constant::status::Success); } void CreateTransferMemory(DeviceState &state) { - u64 address = state.nce->GetRegister(Xreg::X1); + u64 addr = state.nce->GetRegister(Xreg::X1); + if ((addr & (PAGE_SIZE - 1U))) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: {}", addr); + return; + } u64 size = state.nce->GetRegister(Xreg::X2); - u32 perms = state.nce->GetRegister(Wreg::W3); - auto shmem = state.thisProcess->NewHandle(state.thisProcess->mainThread, address, size, *reinterpret_cast(&perms)); + if ((size & (PAGE_SIZE - 1U)) || !size) { + state.nce->SetRegister(Wreg::W0, constant::status::InvSize); + state.logger->Warn("svcCreateTransferMemory: 'size' {}: {}", size ? "not page aligned" : "is zero", size); + return; + } + u32 perm = state.nce->GetRegister(Wreg::W3); + memory::Permission permission = *reinterpret_cast(&perm); + if ((permission.w && !permission.r) || (permission.x && !permission.r)) { + state.logger->Warn("svcCreateTransferMemory: 'permission' invalid: {}{}{}", permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-"); + state.nce->SetRegister(Wreg::W0, constant::status::InvPermission); + return; + } + state.logger->Debug("svcCreateTransferMemory: Creating transfer memory at 0x{:X} for {} bytes ({}{}{})", addr, size, permission.r ? "R" : "-", permission.w ? "W" : "-", permission.x ? "X" : "-"); + auto shmem = state.thisProcess->NewHandle(state.thisProcess->mainThread, addr, size, permission); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Wreg::W1, shmem.handle); } - void ResetSignal(DeviceState &state) { + void CloseHandle(DeviceState &state) { + auto handle = static_cast(state.nce->GetRegister(Wreg::W0)); try { - state.thisProcess->GetHandle(state.nce->GetRegister(Wreg::W0))->ResetSignal(); - } catch (const exception &) { - state.thisProcess->GetHandle(state.nce->GetRegister(Wreg::W0))->ResetSignal(); + auto &object = state.thisProcess->handleTable.at(handle); + switch (object->objectType) { + case (type::KType::KThread): + state.os->KillThread(std::static_pointer_cast(object)->pid); + break; + case (type::KType::KProcess): + state.os->KillThread(std::static_pointer_cast(object)->mainThread); + break; + default: + state.thisProcess->handleTable.erase(handle); + } + state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + } catch(const std::exception&) { + state.logger->Warn("svcCloseHandle: 'handle' invalid: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + } + } + + void ResetSignal(DeviceState &state) { + auto handle = state.nce->GetRegister(Wreg::W0); + try { + auto &object = state.thisProcess->handleTable.at(handle); + switch (object->objectType) { + case (type::KType::KEvent): + std::static_pointer_cast(object)->ResetSignal(); + break; + case (type::KType::KProcess): + std::static_pointer_cast(object)->ResetSignal(); + break; + default: { + state.logger->Warn("svcResetSignal: 'handle' type invalid: 0x{:X} ({})", handle, object->objectType); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + return; + } + } + state.logger->Debug("svcResetSignal: Resetting signal: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + } catch(const std::out_of_range&) { + state.logger->Warn("svcResetSignal: 'handle' invalid: 0x{:X}", handle); + state.nce->SetRegister(Wreg::W0, constant::status::InvHandle); + return; } - state.nce->SetRegister(Wreg::W0, constant::status::Success); } void WaitSynchronization(DeviceState &state) { @@ -203,7 +329,7 @@ namespace skyline::kernel::svc { } auto syncObject = std::static_pointer_cast(object); if (syncObject->signalled) { - state.logger->Debug("Found signalled handle: 0x{:X}", handle); + state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", handle); state.nce->SetRegister(Wreg::W0, constant::status::Success); state.nce->SetRegister(Wreg::W1, index); state.thisThread->ClearWaitObjects(); @@ -212,16 +338,91 @@ namespace skyline::kernel::svc { state.thisThread->waitObjects.push_back(syncObject); syncObject->waitThreads.emplace_back(state.thisThread->pid, index); } - state.logger->Debug("Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, state.nce->GetRegister(Xreg::X3)); + auto timeout = state.nce->GetRegister(Xreg::X3); + state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); if (state.nce->GetRegister(Xreg::X3) != std::numeric_limits::max()) - state.thisThread->timeout = GetCurrTimeNs() + state.nce->GetRegister(Xreg::X3); + state.thisThread->timeout = GetCurrTimeNs() + timeout; else state.thisThread->timeout = 0; state.thisThread->status = type::KThread::Status::WaitSync; } + void ArbitrateLock(DeviceState &state) { + auto addr = state.nce->GetRegister(Xreg::X1); + if((addr & ((1UL << WORD_BIT) - 1U))) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcArbitrateLock: 'address' not word aligned: {}", addr); + return; + } + auto handle = state.nce->GetRegister(Wreg::W2); + if (handle != state.thisThread->handle) + throw exception("svcArbitrateLock: Called from another thread"); + state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X} for thread 0x{:X}", addr, handle); + state.thisProcess->MutexLock(addr); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + } + + void ArbitrateUnlock(DeviceState &state) { + auto addr = state.nce->GetRegister(Xreg::X0); + if((addr & ((1UL << WORD_BIT) - 1U))) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: {}", addr); + return; + } + state.logger->Debug("svcArbitrateUnlock: Unlocking mutex at 0x{:X}", addr); + state.thisProcess->MutexUnlock(addr); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + } + + void WaitProcessWideKeyAtomic(DeviceState &state) { + auto mtxAddr = state.nce->GetRegister(Xreg::X0); + if((mtxAddr & ((1UL << WORD_BIT) - 1U))) { + state.nce->SetRegister(Wreg::W0, constant::status::InvAddress); + state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: {}", mtxAddr); + return; + } + auto handle = state.nce->GetRegister(Wreg::W2); + if (handle != state.thisThread->handle) + throw exception("svcWaitProcessWideKeyAtomic: Called from another thread"); + state.thisProcess->MutexUnlock(mtxAddr); + auto condAddr = state.nce->GetRegister(Xreg::X1); + auto &cvarVec = state.thisProcess->condVarMap[condAddr]; + for (auto thread = cvarVec.begin();; thread++) { + if ((*thread)->priority < state.thisThread->priority) { + cvarVec.insert(thread, state.thisThread); + break; + } else if (thread + 1 == cvarVec.end()) { + cvarVec.push_back(state.thisThread); + break; + } + } + auto timeout = state.nce->GetRegister(Xreg::X3); + state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x:{:X}, Timeout: {} ns", mtxAddr, condAddr, timeout); + state.thisThread->status = type::KThread::Status::WaitCondVar; + state.thisThread->timeout = GetCurrTimeNs() + timeout; + state.nce->SetRegister(Wreg::W0, constant::status::Success); + } + + void SignalProcessWideKey(DeviceState &state) { + auto address = state.nce->GetRegister(Xreg::X0); + auto count = state.nce->GetRegister(Wreg::W1); + state.nce->SetRegister(Wreg::W0, constant::status::Success); + if (!state.thisProcess->condVarMap.count(address)) { + state.logger->Warn("svcSignalProcessWideKey: No Conditional-Variable at 0x{:X}", address); + return; + } + auto &cvarVec = state.thisProcess->condVarMap.at(address); + count = std::min(count, static_cast(cvarVec.size())); + for (uint index = 0; index < count; index++) + cvarVec[index]->status = type::KThread::Status::Runnable; + cvarVec.erase(cvarVec.begin(), cvarVec.begin() + count); + if (cvarVec.empty()) + state.thisProcess->condVarMap.erase(address); + state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count); + } + void GetSystemTick(DeviceState &state) { - u64 tick{}; + u64 tick; asm("STR X1, [SP, #-16]!\n\t" "MRS %0, CNTVCT_EL0\n\t" "MOV X1, #0xF800\n\t" @@ -233,60 +434,19 @@ namespace skyline::kernel::svc { state.nce->SetRegister(Xreg::X0, tick); } - void ArbitrateLock(DeviceState &state) { - if (state.nce->GetRegister(Wreg::W2) != state.thisThread->handle) - throw exception("A process requested locking a thread on behalf of another process"); - state.thisProcess->MutexLock(state.nce->GetRegister(Xreg::X1)); - state.nce->SetRegister(Wreg::W0, constant::status::Success); - } - - void ArbitrateUnlock(DeviceState &state) { - state.thisProcess->MutexUnlock(state.nce->GetRegister(Xreg::X0)); - state.nce->SetRegister(Wreg::W0, constant::status::Success); - } - - void WaitProcessWideKeyAtomic(DeviceState &state) { - auto mtxAddr = state.nce->GetRegister(Xreg::X0); - if (state.nce->GetRegister(Wreg::W2) != state.thisThread->handle) - throw exception("svcWaitProcessWideKeyAtomic was called on behalf of another thread"); - state.thisProcess->MutexUnlock(mtxAddr); - auto &cvarVec = state.thisProcess->condVarMap[state.nce->GetRegister(Xreg::X1)]; - for (auto thread = cvarVec.begin();; thread++) { - if ((*thread)->priority < state.thisThread->priority) { - cvarVec.insert(thread, state.thisThread); - break; - } else if (thread + 1 == cvarVec.end()) { - cvarVec.push_back(state.thisThread); - break; - } - } - state.thisThread->status = type::KThread::Status::WaitCondVar; - state.thisThread->timeout = GetCurrTimeNs() + state.nce->GetRegister(Xreg::X3); - state.nce->SetRegister(Wreg::W0, constant::status::Success); - } - - void SignalProcessWideKey(DeviceState &state) { - auto address = state.nce->GetRegister(Xreg::X0); - auto count = state.nce->GetRegister(Wreg::W1); - state.nce->SetRegister(Wreg::W0, constant::status::Success); - if (!state.thisProcess->condVarMap.count(address)) - return; // No threads to awaken - auto &cvarVec = state.thisProcess->condVarMap[address]; - count = std::min(count, static_cast(cvarVec.size())); - for (uint index = 0; index < count; index++) - cvarVec[index]->status = type::KThread::Status::Runnable; - cvarVec.erase(cvarVec.begin(), cvarVec.begin() + count); - if (cvarVec.empty()) - state.thisProcess->condVarMap.erase(address); - } - void ConnectToNamedPort(DeviceState &state) { - char port[constant::PortSize + 1]{0}; // +1 so string will always be null terminated + char port[constant::PortSize + 1]{0}; state.os->thisProcess->ReadMemory(port, state.nce->GetRegister(Xreg::X1), constant::PortSize); + handle_t handle{}; if (std::strcmp(port, "sm:") == 0) - state.nce->SetRegister(Wreg::W1, state.os->serviceManager.NewSession(service::Service::sm)); - else - throw exception("svcConnectToNamedPort tried connecting to invalid port: \"{}\"", port); + handle = state.os->serviceManager.NewSession(service::Service::sm); + else { + state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port); + state.nce->SetRegister(Wreg::W0, constant::status::NotFound); + return; + } + state.logger->Debug("svcConnectToNamedPort: Connecting to port '{}' at 0x{:X}", port, handle); + state.nce->SetRegister(Wreg::W1, handle); state.nce->SetRegister(Wreg::W0, constant::status::Success); } @@ -297,11 +457,12 @@ namespace skyline::kernel::svc { void GetThreadId(DeviceState &state) { pid_t pid{}; - if (state.nce->GetRegister(Wreg::W1) != constant::ThreadSelf) { - handle_t thread = state.nce->GetRegister(Wreg::W1); - pid = state.thisProcess->GetHandle(thread)->pid; + auto handle = state.nce->GetRegister(Wreg::W1); + if (handle != constant::ThreadSelf) { + pid = state.thisProcess->GetHandle(handle)->pid; } else pid = state.thisThread->pid; + state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid); state.nce->SetRegister(Xreg::X1, static_cast(pid)); state.nce->SetRegister(Wreg::W0, constant::status::Success); } @@ -314,65 +475,69 @@ namespace skyline::kernel::svc { } void GetInfo(DeviceState &state) { - state.logger->Debug("svcGetInfo called with ID0: {}, ID1: {}", state.nce->GetRegister(Wreg::W1), state.nce->GetRegister(Xreg::X3)); - switch (state.nce->GetRegister(Wreg::W1)) { + auto id0 = state.nce->GetRegister(Wreg::W1); + auto handle = state.nce->GetRegister(Wreg::W2); + auto id1 = state.nce->GetRegister(Xreg::X3); + u64 out{}; + switch (id0) { case constant::infoState::AllowedCpuIdBitmask: case constant::infoState::AllowedThreadPriorityMask: case constant::infoState::IsCurrentProcessBeingDebugged: case constant::infoState::TitleId: case constant::infoState::PrivilegedProcessId: - state.nce->SetRegister(Xreg::X1, 0); break; case constant::infoState::AliasRegionBaseAddr: - state.nce->SetRegister(Xreg::X1, constant::MapAddr); + out = constant::MapAddr; break; case constant::infoState::AliasRegionSize: - state.nce->SetRegister(Xreg::X1, constant::MapSize); + out = constant::MapSize; break; case constant::infoState::HeapRegionBaseAddr: - state.nce->SetRegister(Xreg::X1, state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address); + out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address; break; case constant::infoState::HeapRegionSize: - state.nce->SetRegister(Xreg::X1, state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->size); + out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->size; break; case constant::infoState::TotalMemoryAvailable: - state.nce->SetRegister(Xreg::X1, constant::TotalPhyMem); + out = constant::TotalPhyMem; break; case constant::infoState::TotalMemoryUsage: - state.nce->SetRegister(Xreg::X1, state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz + state.thisProcess->GetProgramSize()); + out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz + state.thisProcess->GetProgramSize(); break; case constant::infoState::AddressSpaceBaseAddr: - state.nce->SetRegister(Xreg::X1, constant::BaseAddr); + out = constant::BaseAddr; break; case constant::infoState::AddressSpaceSize: - state.nce->SetRegister(Xreg::X1, constant::BaseSize); + out = constant::BaseSize; break; case constant::infoState::StackRegionBaseAddr: - state.nce->SetRegister(Xreg::X1, state.thisThread->stackTop); + out = state.thisThread->stackTop; break; case constant::infoState::StackRegionSize: - state.nce->SetRegister(Xreg::X1, state.thisProcess->mainThreadStackSz); + out = state.thisProcess->mainThreadStackSz; break; case constant::infoState::PersonalMmHeapSize: - state.nce->SetRegister(Xreg::X1, constant::TotalPhyMem); + out = constant::TotalPhyMem; break; case constant::infoState::PersonalMmHeapUsage: - state.nce->SetRegister(Xreg::X1, state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz); + out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz; break; case constant::infoState::TotalMemoryAvailableWithoutMmHeap: - state.nce->SetRegister(Xreg::X1, constant::TotalPhyMem); // TODO: NPDM specifies SystemResourceSize, subtract that from this + out = constant::TotalPhyMem; // TODO: NPDM specifies SystemResourceSize, subtract that from this break; case constant::infoState::TotalMemoryUsedWithoutMmHeap: - state.nce->SetRegister(Xreg::X1, state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz); // TODO: Same as above + out = state.os->thisProcess->memoryRegionMap.at(memory::Region::Heap)->address + state.thisProcess->mainThreadStackSz; // TODO: Same as above break; case constant::infoState::UserExceptionContextAddr: - state.nce->SetRegister(Xreg::X1, state.thisProcess->tlsPages[0]->Get(0)); + out = state.thisProcess->tlsPages[0]->Get(0); break; default: - state.logger->Warn("Unimplemented svcGetInfo with ID0: {}, ID1: {}", state.nce->GetRegister(Wreg::W1), state.nce->GetRegister(Xreg::X3)); + state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1); state.nce->SetRegister(Wreg::W0, constant::status::Unimpl); return; } + state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", id0, id1, out); + state.nce->SetRegister(Xreg::X1, out); state.nce->SetRegister(Wreg::W0, constant::status::Success); } } diff --git a/app/src/main/cpp/skyline/kernel/svc.h b/app/src/main/cpp/skyline/kernel/svc.h index b9f3ebba..81332151 100644 --- a/app/src/main/cpp/skyline/kernel/svc.h +++ b/app/src/main/cpp/skyline/kernel/svc.h @@ -91,16 +91,16 @@ namespace skyline { */ void MapSharedMemory(DeviceState &state); - /** - * @brief Closes the specified handle - */ - void CloseHandle(DeviceState &state); - /** * @brief Returns a handle to a KSharedMemory object (https://switchbrew.org/wiki/SVC#svcCreateTransferMemory) */ void CreateTransferMemory(DeviceState &state); + /** + * @brief Closes the specified handle + */ + void CloseHandle(DeviceState &state); + /** * @brief This resets a particular KEvent or KProcess which is signalled (https://switchbrew.org/wiki/SVC#svcResetSignal) */ @@ -110,12 +110,6 @@ namespace skyline { * @brief Stalls a thread till a KSyncObject signals or the timeout has ended (https://switchbrew.org/wiki/SVC#svcWaitSynchronization) */ void WaitSynchronization(DeviceState &state); - - /** - * @brief This returns the value of CNTPCT_EL0 on the Switch (https://switchbrew.org/wiki/SVC#svcGetSystemTick) - */ - void GetSystemTick(DeviceState &state); - /** * @brief Locks a specified mutex */ @@ -136,6 +130,11 @@ namespace skyline { */ void SignalProcessWideKey(DeviceState &state); + /** + * @brief This returns the value of CNTPCT_EL0 on the Switch (https://switchbrew.org/wiki/SVC#svcGetSystemTick) + */ + void GetSystemTick(DeviceState &state); + /** * @brief Connects to a named IPC port */ diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index ecc3ab8e..861751c5 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -24,8 +24,8 @@ namespace skyline::kernel::type { this->address = fregs.regs[0]; } - u64 RemapPrivateFunc(u64 address, size_t oldSize, size_t size, u64 perms) { - return reinterpret_cast(mremap(reinterpret_cast(address), oldSize, size, 0)); + u64 RemapPrivateFunc(u64 address, size_t oldSize, size_t size, u64 flags) { + return reinterpret_cast(mremap(reinterpret_cast(address), oldSize, size, static_cast(flags))); } u64 KPrivateMemory::Resize(size_t newSize, bool canMove) { @@ -33,7 +33,7 @@ namespace skyline::kernel::type { fregs.regs[0] = address; fregs.regs[1] = size; fregs.regs[2] = newSize; - fregs.regs[3] = static_cast(PROT_READ | PROT_WRITE); + fregs.regs[3] = canMove ? MREMAP_MAYMOVE : 0; state.nce->ExecuteFunction(reinterpret_cast(RemapPrivateFunc), fregs, owner); if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) throw exception("An error occurred while remapping private region in child process"); diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index 15b08b8f..bb993f6a 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -8,28 +8,26 @@ namespace skyline::kernel::type { return reinterpret_cast(mmap(reinterpret_cast(address), size, static_cast(perms), MAP_SHARED | ((address) ? MAP_FIXED : 0), static_cast(fd), 0)); // NOLINT(hicpp-signed-bitwise) } - KSharedMemory::KSharedMemory(const DeviceState &state, pid_t pid, u64 kaddress, size_t ksize, const memory::Permission localPermission, const memory::Permission remotePermission, memory::Type type) : kaddress(kaddress), ksize(ksize), localPermission(localPermission), remotePermission(remotePermission), type(type), owner(pid), KObject(state, KType::KSharedMemory) { - fd = ASharedMemory_create("", ksize); + KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::Type type) : type(type), KObject(state, KType::KSharedMemory) { + fd = ASharedMemory_create("", size); if (fd < 0) throw exception("An error occurred while creating shared memory: {}", fd); - kaddress = MapSharedFunc(kaddress, ksize, static_cast(pid ? remotePermission.Get() : localPermission.Get()), static_cast(fd)); - if (kaddress == reinterpret_cast(MAP_FAILED)) // NOLINT(hicpp-signed-bitwise) + address = MapSharedFunc(address, size, static_cast(permission.Get()), static_cast(fd)); + if (address == reinterpret_cast(MAP_FAILED)) // NOLINT(hicpp-signed-bitwise) throw exception("An occurred while mapping shared region: {}", strerror(errno)); + procInfMap[0] = {address, size, permission}; } - u64 KSharedMemory::Map(u64 address, u64 size, pid_t process) { + u64 KSharedMemory::Map(u64 address, u64 size, memory::Permission permission, pid_t pid) { user_pt_regs fregs = {0}; fregs.regs[0] = address; fregs.regs[1] = size; - if (process == owner) - fregs.regs[2] = static_cast(localPermission.Get()); - else - fregs.regs[2] = static_cast(remotePermission.Get()); + fregs.regs[2] = static_cast(permission.Get()); fregs.regs[3] = static_cast(fd); - state.nce->ExecuteFunction(reinterpret_cast(MapSharedFunc), fregs, process); + state.nce->ExecuteFunction(reinterpret_cast(MapSharedFunc), fregs, pid); if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) throw exception("An error occurred while mapping shared region in child process"); - procInfMap[process] = {fregs.regs[0], size}; + procInfMap[pid] = {fregs.regs[0], size, permission}; return fregs.regs[0]; } @@ -40,14 +38,15 @@ namespace skyline::kernel::type { KSharedMemory::~KSharedMemory() { for (auto[process, procInf] : procInfMap) { try { - user_pt_regs fregs = {0}; - fregs.regs[0] = procInf.address; - fregs.regs[1] = procInf.size; - state.nce->ExecuteFunction(reinterpret_cast(UnmapSharedFunc), fregs, process); - } catch (const std::exception &) { - } + if(process) { + user_pt_regs fregs = {0}; + fregs.regs[0] = procInf.address; + fregs.regs[1] = procInf.size; + state.nce->ExecuteFunction(reinterpret_cast(UnmapSharedFunc), fregs, process); + } else + UnmapSharedFunc(procInf.address, procInf.size); + } catch (const std::exception &) {} } - UnmapSharedFunc(kaddress, ksize); close(fd); } @@ -57,54 +56,53 @@ namespace skyline::kernel::type { void KSharedMemory::Resize(size_t newSize) { for (auto&[process, procInf] : procInfMap) { - user_pt_regs fregs = {0}; - fregs.regs[0] = procInf.address; - fregs.regs[1] = procInf.size; - fregs.regs[2] = newSize; - state.nce->ExecuteFunction(reinterpret_cast(RemapSharedFunc), fregs, process); - if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) - throw exception("An error occurred while remapping shared region in child process"); + if(process) { + user_pt_regs fregs = {0}; + fregs.regs[0] = procInf.address; + fregs.regs[1] = procInf.size; + fregs.regs[2] = newSize; + state.nce->ExecuteFunction(reinterpret_cast(RemapSharedFunc), fregs, process); + if (reinterpret_cast(fregs.regs[0]) == MAP_FAILED) + throw exception("An error occurred while remapping shared region in child process"); + } else { + if (RemapSharedFunc(procInf.address, procInf.size, newSize) == reinterpret_cast(MAP_FAILED)) + throw exception("An occurred while remapping shared region: {}", strerror(errno)); + } procInf.size = newSize; } - if (RemapSharedFunc(kaddress, ksize, newSize) == reinterpret_cast(MAP_FAILED)) - throw exception("An occurred while remapping shared region: {}", strerror(errno)); - ksize = newSize; } u64 UpdatePermissionSharedFunc(u64 address, size_t size, u64 perms) { return static_cast(mprotect(reinterpret_cast(address), size, static_cast(perms))); } - void KSharedMemory::UpdatePermission(bool local, memory::Permission newPerms) { + void KSharedMemory::UpdatePermission(pid_t pid, memory::Permission permission) { for (auto&[process, procInf] : procInfMap) { - if ((local && process == owner) || (!local && process != owner)) { + if(process) { user_pt_regs fregs = {0}; fregs.regs[0] = procInf.address; fregs.regs[1] = procInf.size; - fregs.regs[2] = static_cast(newPerms.Get()); + fregs.regs[2] = static_cast(procInf.permission.Get()); state.nce->ExecuteFunction(reinterpret_cast(UpdatePermissionSharedFunc), fregs, process); if (static_cast(fregs.regs[0]) == -1) throw exception("An error occurred while updating shared region's permissions in child process"); + } else { + if (UpdatePermissionSharedFunc(procInf.address, procInf.size, static_cast(permission.Get())) == reinterpret_cast(MAP_FAILED)) + throw exception("An occurred while remapping shared region: {}", strerror(errno)); } + procInf.permission = permission; } - if ((local && owner == 0) || (!local && owner != 0)) - if (mprotect(reinterpret_cast(kaddress), ksize, newPerms.Get()) == -1) - throw exception("An occurred while updating shared region's permissions: {}", strerror(errno)); - if (local) - localPermission = newPerms; - else - remotePermission = newPerms; } - memory::MemoryInfo KSharedMemory::GetInfo(pid_t process) { + memory::MemoryInfo KSharedMemory::GetInfo(pid_t pid) { memory::MemoryInfo info{}; - const auto &procInf = procInfMap.at(process); + const auto &procInf = procInfMap.at(pid); info.baseAddress = procInf.address; info.size = procInf.size; info.type = static_cast(type); info.memoryAttribute.isIpcLocked = (info.ipcRefCount > 0); info.memoryAttribute.isDeviceShared = (info.deviceRefCount > 0); - info.perms = (process == owner) ? localPermission : remotePermission; + info.perms = procInf.permission; info.ipcRefCount = ipcRefCount; info.deviceRefCount = deviceRefCount; return info; diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h index 75a26990..77758f93 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h @@ -18,36 +18,31 @@ namespace skyline::kernel::type { struct ProcessInfo { u64 address; size_t size; + memory::Permission permission; }; std::unordered_map procInfMap; //!< Maps from a PID to where the memory was mapped to - pid_t owner; //!< The PID of the process owning this shared memory - u64 kaddress; //!< The address of the allocated memory for the kernel - size_t ksize; //!< The size of the allocated memory u16 ipcRefCount{}; //!< The amount of reference to this memory for IPC u16 deviceRefCount{}; //!< The amount of reference to this memory for IPC - memory::Permission localPermission; //!< The permission for the owner process - memory::Permission remotePermission; //!< The permission of any process except the owner process memory::Type type; //!< The type of this memory allocation /** * @param state The state of the device - * @param pid The PID of the owner thread - * @param kaddress The address of the allocation on the kernel (Arbitrary is 0) - * @param ksize The size of the allocation on the kernel - * @param localPermission The permission of the owner process - * @param remotePermission The permission of any process except the owner process + * @param address The address of the allocation on the kernel (Arbitrary is 0) + * @param size The size of the allocation on the kernel + * @param permission The permission of the kernel process * @param type The type of the memory */ - KSharedMemory(const DeviceState &state, pid_t pid, u64 kaddress, size_t ksize, const memory::Permission localPermission, const memory::Permission remotePermission, memory::Type type); + KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::Type type); /** * @brief Maps the shared memory at an address * @param address The address to map to (If NULL an arbitrary address is picked) * @param size The amount of shared memory to map - * @param process The PID of the process + * @param permission The permission of the kernel process + * @param pid The PID of the process * @return The address of the allocation */ - u64 Map(u64 address, u64 size, pid_t process); + u64 Map(const u64 address, const u64 size, memory::Permission permission, pid_t pid); /** * @brief Resize a chunk of memory as to change the size occupied by it @@ -57,16 +52,16 @@ namespace skyline::kernel::type { /** * Updates the permissions of a chunk of mapped memory - * @param local If true change local permissions else change remote permissions - * @param perms The new permissions to be set for the memory + * @param pid The PID of the requesting process + * @param permission The new permissions to be set for the memory */ - void UpdatePermission(bool local, memory::Permission newPerms); + void UpdatePermission(pid_t pid, memory::Permission permission); /** - * @param process The PID of the requesting process + * @param pid The PID of the requesting process * @return A Memory::MemoryInfo struct based on attributes of the memory */ - memory::MemoryInfo GetInfo(pid_t process); + memory::MemoryInfo GetInfo(pid_t pid); /** * @brief The destructor of shared memory, it deallocates the memory from all processes diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index eae18eec..87d70366 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -13,10 +13,12 @@ namespace skyline::kernel::type { } void KThread::Start() { - if (pid == parent->mainThread) - parent->status = KProcess::Status::Started; - status = Status::Running; - state.nce->StartProcess(entryPoint, entryArg, stackTop, handle, pid); + if(status == Status::Created) { + if (pid == parent->mainThread) + parent->status = KProcess::Status::Started; + status = Status::Running; + state.nce->StartProcess(entryPoint, entryArg, stackTop, handle, pid); + } } void KThread::UpdatePriority(u8 priority) { diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index b5284ab7..8e1601b0 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -62,15 +62,15 @@ namespace skyline::kernel { } } - void OS::SvcHandler(u16 svc) { - if (svc::SvcTable[svc]) { - state.logger->Debug("SVC called 0x{:X}", svc); - (*svc::SvcTable[svc])(state); - } else - throw exception("Unimplemented SVC 0x{:X}", svc); - } - - std::shared_ptr OS::MapSharedKernel(const u64 address, const size_t size, const memory::Permission kernelPermission, const memory::Permission remotePermission, const memory::Type type) { - return std::make_shared(state, 0, address, size, kernelPermission, remotePermission, type); + void OS::SvcHandler(const u16 svc) { + try { + if (svc::SvcTable[svc]) { + state.logger->Debug("SVC called 0x{:X}", svc); + (*svc::SvcTable[svc])(state); + } else + throw exception("Unimplemented SVC 0x{:X}", svc); + } catch(const exception& e) { + throw exception("{} (SVC: {})", e.what(), svc); + } } } diff --git a/app/src/main/cpp/skyline/os.h b/app/src/main/cpp/skyline/os.h index 256777ae..2f233683 100644 --- a/app/src/main/cpp/skyline/os.h +++ b/app/src/main/cpp/skyline/os.h @@ -55,18 +55,6 @@ namespace skyline::kernel { * @brief Handles a particular SuperVisor Call * @param svc The ID of the SVC to be called */ - void SvcHandler(u16 svc); - - /** - * @brief Map a chunk of shared memory (Use only when kernel should be owner process else create KSharedMemory directly) - * @param address The address to map to (Can be 0 if address doesn't matter) - * @param size The size of the chunk of memory - * @param localPermission The permissions of the memory for the kernel - * @param remotePermission The permissions of the memory for the processes - * @param type The type of the memory - * @param region The specific region this memory is mapped for - * @return A shared pointer to the kernel::type::KSharedMemory object - */ - std::shared_ptr MapSharedKernel(const u64 address, const size_t size, const memory::Permission kernelPermission, const memory::Permission remotePermission, const memory::Type type); + void SvcHandler(const u16 svc); }; } diff --git a/app/src/main/cpp/skyline/services/am/appletController.cpp b/app/src/main/cpp/skyline/services/am/appletController.cpp index c0657831..8817f7ff 100644 --- a/app/src/main/cpp/skyline/services/am/appletController.cpp +++ b/app/src/main/cpp/skyline/services/am/appletController.cpp @@ -21,7 +21,7 @@ namespace skyline::service::am { void ICommonStateGetter::GetEventHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto handle = state.thisProcess->InsertItem(messageEvent); - state.logger->Info("Event Handle: 0x{:X}", handle); + state.logger->Debug("Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); } diff --git a/app/src/main/cpp/skyline/services/hid/hid.cpp b/app/src/main/cpp/skyline/services/hid/hid.cpp index 0f549cfd..0553aecd 100644 --- a/app/src/main/cpp/skyline/services/hid/hid.cpp +++ b/app/src/main/cpp/skyline/services/hid/hid.cpp @@ -7,9 +7,9 @@ namespace skyline::service::hid { }) {} void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - hidSharedMemory = state.os->MapSharedKernel(0, constant::hidSharedMemSize, memory::Permission(true, false, false), memory::Permission(true, true, false), memory::Type::SharedMemory); + hidSharedMemory = std::make_shared(state, NULL, constant::hidSharedMemSize, memory::Permission(true, false, false), memory::Type::SharedMemory); auto handle = state.thisProcess->InsertItem(hidSharedMemory); - state.logger->Info("Writing HID SHM: {}", handle); + state.logger->Debug("HID Shared Memory Handle: {}", handle); response.copyHandles.push_back(handle); } diff --git a/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp b/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp index 60e142ff..07f31ffb 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/nvdrv.cpp @@ -42,9 +42,10 @@ namespace skyline::service::nvdrv { u32 fd; u32 eventId; } *input = reinterpret_cast(request.cmdArg); - state.logger->Info("QueryEvent: FD: {}, Event ID: {}", input->fd, input->eventId); auto event = std::make_shared(state); - response.copyHandles.push_back(state.thisProcess->InsertItem(event)); + auto handle = state.thisProcess->InsertItem(event); + state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", input->fd, input->eventId, handle); + response.copyHandles.push_back(handle); } void nvdrv::SetAruidByPID(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { diff --git a/app/src/main/cpp/skyline/services/vi/vi_m.cpp b/app/src/main/cpp/skyline/services/vi/vi_m.cpp index 159e7dfc..574dbc43 100644 --- a/app/src/main/cpp/skyline/services/vi/vi_m.cpp +++ b/app/src/main/cpp/skyline/services/vi/vi_m.cpp @@ -108,7 +108,7 @@ namespace skyline::service::vi { void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { handle_t handle = state.thisProcess->InsertItem(state.gpu->vsyncEvent); - state.logger->Info("VSyncEvent Handle: 0x{:X}", handle); + state.logger->Debug("VSync Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); }