From 65018aedbc155d25de102b6243e382c3e18ad187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Sat, 11 Jan 2020 10:22:25 +0530 Subject: [PATCH] Complete making the kernel thread-safe #2 + Fix Shared Memory Implementation This commit makes the kernel completely thread-safe and fixes an issue that caused libNX games to not work due to an error with KSharedMemory. In addition, implement GroupMutex to allow the kernel threads to run in parallel but still allow them to not overlap with the JNI thread. --- app/CMakeLists.txt | 3 +- app/src/main/cpp/.clang-tidy | 155 +++++ app/src/main/cpp/main.cpp | 10 +- app/src/main/cpp/skyline/common.cpp | 13 +- app/src/main/cpp/skyline/common.h | 36 +- app/src/main/cpp/skyline/gpu.cpp | 8 +- app/src/main/cpp/skyline/gpu/display.cpp | 60 +- app/src/main/cpp/skyline/gpu/display.h | 57 +- app/src/main/cpp/skyline/gpu/parcel.cpp | 2 +- app/src/main/cpp/skyline/gpu/parcel.h | 2 +- app/src/main/cpp/skyline/jvm.cpp | 10 +- app/src/main/cpp/skyline/jvm.h | 2 +- app/src/main/cpp/skyline/kernel/ipc.h | 4 +- app/src/main/cpp/skyline/kernel/svc.cpp | 142 ++--- .../cpp/skyline/kernel/svc.cpp___jb_old___ | 534 ------------------ app/src/main/cpp/skyline/kernel/svc.h | 1 + .../main/cpp/skyline/kernel/types/KEvent.h | 10 - .../skyline/kernel/types/KPrivateMemory.cpp | 7 +- .../cpp/skyline/kernel/types/KProcess.cpp | 62 +- .../main/cpp/skyline/kernel/types/KProcess.h | 18 +- .../skyline/kernel/types/KSharedMemory.cpp | 10 +- .../cpp/skyline/kernel/types/KSharedMemory.h | 2 +- .../cpp/skyline/kernel/types/KSyncObject.cpp | 16 - .../cpp/skyline/kernel/types/KSyncObject.h | 18 +- .../main/cpp/skyline/kernel/types/KThread.cpp | 35 +- .../main/cpp/skyline/kernel/types/KThread.h | 19 +- .../skyline/kernel/types/KTransferMemory.cpp | 23 +- app/src/main/cpp/skyline/nce.cpp | 64 ++- app/src/main/cpp/skyline/nce.h | 4 +- app/src/main/cpp/skyline/nce/guest.cpp | 79 ++- app/src/main/cpp/skyline/nce/guest.h | 9 +- app/src/main/cpp/skyline/nce/guest_common.h | 12 +- app/src/main/cpp/skyline/os.cpp | 14 +- app/src/main/cpp/skyline/os.h | 2 +- .../main/cpp/skyline/services/am/applet.cpp | 12 +- app/src/main/cpp/skyline/services/am/applet.h | 10 +- .../skyline/services/am/appletController.cpp | 6 +- .../skyline/services/am/appletController.h | 4 +- .../main/cpp/skyline/services/serviceman.cpp | 4 +- 39 files changed, 547 insertions(+), 932 deletions(-) create mode 100644 app/src/main/cpp/.clang-tidy delete mode 100644 app/src/main/cpp/skyline/kernel/svc.cpp___jb_old___ delete mode 100644 app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 8069f74f..de973ce5 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -38,7 +38,6 @@ add_library(skyline SHARED ${source_DIR}/skyline/loader/nro.cpp ${source_DIR}/skyline/kernel/ipc.cpp ${source_DIR}/skyline/kernel/svc.cpp - ${source_DIR}/skyline/kernel/types/KSyncObject.cpp ${source_DIR}/skyline/kernel/types/KProcess.cpp ${source_DIR}/skyline/kernel/types/KThread.cpp ${source_DIR}/skyline/kernel/types/KSharedMemory.cpp @@ -59,5 +58,5 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/vi/vi_m.cpp ) -target_link_libraries(skyline vulkan GLESv3 EGL android fmt tinyxml2) +target_link_libraries(skyline vulkan android fmt tinyxml2) target_compile_options(skyline PRIVATE -Wno-c++17-extensions) diff --git a/app/src/main/cpp/.clang-tidy b/app/src/main/cpp/.clang-tidy new file mode 100644 index 00000000..da3d27f7 --- /dev/null +++ b/app/src/main/cpp/.clang-tidy @@ -0,0 +1,155 @@ +--- +Checks: 'clang-diagnostic-*,clang-analyzer-*,*, android-*, -bugprone-bool-pointer-implicit-conversion, -cert-env33-c, -cert-dcl50-cpp, -cert-dcl59-cpp, -cppcoreguidelines-no-malloc, -cppcoreguidelines-owning-memory, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, -cppcoreguidelines-pro-bounds-pointer-arithmetic, -cppcoreguidelines-pro-type-const-cast, + -cppcoreguidelines-pro-type-cstyle-cast, -cppcoreguidelines-pro-type-reinterpret-cast, -cppcoreguidelines-pro-type-union-access, -cppcoreguidelines-pro-type-vararg, -cppcoreguidelines-special-member-functions, -fuchsia-*, -google-*, google-default-arguments, google-explicit-constructor, google-runtime-member-string-references, google-runtime-operator, -hicpp-braces-around-statements, + -hicpp-braces-around-statements, -hicpp-named-parameter, -hicpp-no-array-decay, -hicpp-no-assembler, -hicpp-no-malloc, -hicpp-function-size, -hicpp-special-member-functions, -hicpp-vararg, -llvm-*, -objc-*, -readability-else-after-return, -readability-implicit-bool-conversion, -readability-named-parameter, -readability-simplify-boolean-expr, -readability-braces-around-statements, + -readability-identifier-naming, -readability-function-size, -readability-redundant-member-init, -misc-bool-pointer-implicit-conversion, -misc-definitions-in-headers, -misc-unused-alias-decls, -misc-unused-parameters, -misc-unused-using-decls, -modernize-use-using, -modernize-use-default-member-init, -clang-diagnostic-*, -clang-analyzer-*, -hicpp-signed-bitwise' +WarningsAsErrors: '' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +FormatStyle: none +CheckOptions: + - key: bugprone-argument-comment.StrictMode + value: '0' + - key: bugprone-assert-side-effect.AssertMacros + value: assert + - key: bugprone-assert-side-effect.CheckFunctionCalls + value: '0' + - key: bugprone-dangling-handle.HandleClasses + value: 'std::basic_string_view;std::experimental::basic_string_view' + - key: bugprone-string-constructor.LargeLengthThreshold + value: '8388608' + - key: bugprone-string-constructor.WarnOnLargeLength + value: '1' + - key: cert-err09-cpp.CheckThrowTemporaries + value: '1' + - key: cert-err61-cpp.CheckThrowTemporaries + value: '1' + - key: cert-oop11-cpp.IncludeStyle + value: llvm + - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays + value: '0' + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: hicpp-member-init.IgnoreArrays + value: '0' + - key: hicpp-move-const-arg.CheckTriviallyCopyableMove + value: '1' + - key: hicpp-use-auto.RemoveStars + value: '0' + - key: hicpp-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: hicpp-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: hicpp-use-emplace.TupleMakeFunctions + value: '::std::make_pair;::std::make_tuple' + - key: hicpp-use-emplace.TupleTypes + value: '::std::pair;::std::tuple' + - key: hicpp-use-equals-default.IgnoreMacros + value: '1' + - key: hicpp-use-noexcept.ReplacementString + value: '' + - key: hicpp-use-noexcept.UseNoexceptFalse + value: '1' + - key: hicpp-use-nullptr.NullMacros + value: '' + - key: misc-misplaced-widening-cast.CheckImplicitCasts + value: '0' + - key: misc-sizeof-expression.WarnOnSizeOfCompareToConstant + value: '1' + - key: misc-sizeof-expression.WarnOnSizeOfConstant + value: '1' + - key: misc-sizeof-expression.WarnOnSizeOfThis + value: '1' + - key: misc-suspicious-enum-usage.StrictMode + value: '0' + - key: misc-suspicious-missing-comma.MaxConcatenatedTokens + value: '5' + - key: misc-suspicious-missing-comma.RatioThreshold + value: '0.200000' + - key: misc-suspicious-missing-comma.SizeThreshold + value: '5' + - key: misc-suspicious-string-compare.StringCompareLikeFunctions + value: '' + - key: misc-suspicious-string-compare.WarnOnImplicitComparison + value: '1' + - key: misc-suspicious-string-compare.WarnOnLogicalNotComparison + value: '0' + - key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries + value: '1' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-make-shared.IgnoreMacros + value: '1' + - key: modernize-make-shared.IncludeStyle + value: '0' + - key: modernize-make-shared.MakeSmartPtrFunction + value: 'std::make_shared' + - key: modernize-make-shared.MakeSmartPtrFunctionHeader + value: memory + - key: modernize-make-unique.IgnoreMacros + value: '1' + - key: modernize-make-unique.IncludeStyle + value: '0' + - key: modernize-make-unique.MakeSmartPtrFunction + value: 'std::make_unique' + - key: modernize-make-unique.MakeSmartPtrFunctionHeader + value: memory + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-pass-by-value.ValuesOnly + value: '0' + - key: modernize-raw-string-literal.ReplaceShorterLiterals + value: '0' + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-replace-random-shuffle.IncludeStyle + value: llvm + - key: modernize-use-auto.RemoveStars + value: '0' + - key: modernize-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: modernize-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: modernize-use-emplace.TupleMakeFunctions + value: '::std::make_pair;::std::make_tuple' + - key: modernize-use-emplace.TupleTypes + value: '::std::pair;::std::tuple' + - key: modernize-use-equals-default.IgnoreMacros + value: '1' + - key: modernize-use-noexcept.ReplacementString + value: '' + - key: modernize-use-noexcept.UseNoexceptFalse + value: '1' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: modernize-use-transparent-functors.SafeMode + value: '0' + - key: performance-faster-string-find.StringLikeClasses + value: 'std::basic_string' + - key: performance-for-range-copy.WarnOnAllAutoCopies + value: '0' + - key: performance-inefficient-string-concatenation.StrictMode + value: '0' + - key: performance-inefficient-vector-operation.VectorLikeClasses + value: '::std::vector' + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: '1' + - key: performance-move-constructor-init.IncludeStyle + value: llvm + - key: performance-type-promotion-in-math-fn.IncludeStyle + value: llvm + - key: performance-unnecessary-value-param.IncludeStyle + value: llvm + - key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold + value: '3' +... diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index 0fe0b311..917cc99a 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -7,7 +7,7 @@ bool Halt; jobject Surface; uint FaultCount; -skyline::Mutex jniMtx; +skyline::GroupMutex jniMtx; void signalHandler(int signal) { syslog(LOG_ERR, "Halting program due to signal: %s", strsignal(signal)); @@ -56,16 +56,16 @@ extern "C" JNIEXPORT void Java_emu_skyline_GameActivity_executeRom(JNIEnv *env, } extern "C" JNIEXPORT void Java_emu_skyline_GameActivity_setHalt(JNIEnv *env, jobject instance, jboolean halt) { - jniMtx.lock(); + jniMtx.lock(skyline::GroupMutex::Group::Group2); Halt = halt; jniMtx.unlock(); } extern "C" JNIEXPORT void Java_emu_skyline_GameActivity_setSurface(JNIEnv *env, jobject instance, jobject surface) { - jniMtx.lock(); - if(!env->IsSameObject(Surface, nullptr)) + jniMtx.lock(skyline::GroupMutex::Group::Group2); + if (!env->IsSameObject(Surface, nullptr)) env->DeleteGlobalRef(Surface); - if(!env->IsSameObject(surface, nullptr)) + if (!env->IsSameObject(surface, nullptr)) Surface = env->NewGlobalRef(surface); else Surface = surface; diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp index 2abbc7a0..3bf214a2 100644 --- a/app/src/main/cpp/skyline/common.cpp +++ b/app/src/main/cpp/skyline/common.cpp @@ -16,6 +16,17 @@ namespace skyline { return !flag.test_and_set(std::memory_order_acquire); } + void GroupMutex::lock(Group group) { + auto none = Group::None; + while (!flag.compare_exchange_weak(none, group) && flag != group); + num++; + } + + void GroupMutex::unlock() { + if (!--num) + flag.exchange(Group::None); + } + Settings::Settings(const int preferenceFd) { tinyxml2::XMLDocument pref; if (pref.LoadFile(fdopen(preferenceFd, "r"))) @@ -95,5 +106,5 @@ namespace skyline { } thread_local std::shared_ptr DeviceState::thread = 0; - thread_local ThreadContext* DeviceState::ctx = 0; + thread_local ThreadContext *DeviceState::ctx = 0; } diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index 6d69222f..976e45a3 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -42,7 +42,7 @@ namespace skyline { constexpr u16 BrkRdy = 0xFF; //!< This is reserved for our kernel's to know when a process/thread is ready constexpr u32 TpidrroEl0 = 0x5E83; //!< ID of TPIDRRO_EL0 in MRS constexpr u32 CntfrqEl0 = 0x5F00; //!< ID of CNTFRQ_EL0 in MRS - constexpr u32 TegraX1Freq = 0x124F800; //!< The clock frequency of the Tegra X1 + constexpr u32 TegraX1Freq = 0x124F800; //!< The clock frequency of the Tegra X1 (19.2 MHz) constexpr u32 CntpctEl0 = 0x5F01; //!< ID of CNTPCT_EL0 in MRS constexpr u32 CntvctEl0 = 0x5F02; //!< ID of CNTVCT_EL0 in MRS // Kernel @@ -111,7 +111,7 @@ namespace skyline { void lock(); /** - * @brief Lock the mutex if it is unlocked else return + * @brief Try to lock the mutex if it is unlocked else return * @return If the mutex was successfully locked or not */ bool try_lock(); @@ -122,6 +122,36 @@ namespace skyline { void unlock(); }; + /** + * @brief The GroupMutex class is a special type of mutex that allows two groups of users and only allows one group to run in parallel + */ + class GroupMutex { + public: + /** + * @brief This enumeration holds all the possible owners of the mutex + */ + enum class Group : u8 { + None = 0, //!< No group owns this mutex + Group1 = 1, //!< Group 1 owns this mutex + Group2 = 2 //!< Group 2 owns this mutex + }; + + /** + * @brief Wait on and lock the mutex + */ + void lock(Group group = Group::Group1); + + /** + * @brief Unlock the mutex + * @note Undefined behavior in case unlocked by thread in non-owner group + */ + void unlock(); + + private: + std::atomic flag = Group::None; //!< An atomic flag to hold which group holds the mutex + std::atomic num = 0; //!< An atomic u8 keeping track of how many users are holding the mutex + }; + /** * @brief The Logger class is to write log output to file and logcat */ @@ -293,7 +323,7 @@ namespace skyline { kernel::OS *os; //!< This holds a reference to the OS class std::shared_ptr &process; //!< This holds a reference to the process object thread_local static std::shared_ptr thread; //!< This holds a reference to the current thread object - thread_local static ThreadContext* ctx; //!< This holds the context of the thread + thread_local static ThreadContext *ctx; //!< This holds the context of the thread std::shared_ptr nce; //!< This holds a reference to the NCE class std::shared_ptr gpu; //!< This holds a reference to the GPU class std::shared_ptr jvmManager; //!< This holds a reference to the JvmManager class diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp index f063bed6..cc2bc600 100644 --- a/app/src/main/cpp/skyline/gpu.cpp +++ b/app/src/main/cpp/skyline/gpu.cpp @@ -62,8 +62,8 @@ namespace skyline::gpu { u8 *inBlock = inBuffer; u8 *outBlock = outBuffer + (y * strideBytes) + x; for (u32 i = 0; i < 32; i++) { - const u32 yT = ((i >> 1) & 0x06) | (i & 0x01); // NOLINT(hicpp-signed-bitwise) - const u32 xT = ((i << 3) & 0x10) | ((i << 1) & 0x20); // NOLINT(hicpp-signed-bitwise) + const u32 yT = ((i >> 1) & 0x06) | (i & 0x01); + const u32 xT = ((i << 3) & 0x10) | ((i << 1) & 0x20); std::memcpy(outBlock + (yT * strideBytes) + xT, inBlock, sizeof(u128)); inBlock += sizeof(u128); } @@ -135,8 +135,8 @@ namespace skyline::gpu { void GPU::Ioctl(u32 fd, u32 cmd, kernel::ipc::IpcRequest &request, kernel::ipc::IpcResponse &response) { state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd); try { - if(request.inputBuf.empty() || request.outputBuf.empty()) { - if(request.inputBuf.empty()) { + if (request.inputBuf.empty() || request.outputBuf.empty()) { + if (request.inputBuf.empty()) { device::IoctlData data(request.outputBuf.at(0)); fdMap.at(fd)->HandleIoctl(cmd, data); response.Push(data.status); diff --git a/app/src/main/cpp/skyline/gpu/display.cpp b/app/src/main/cpp/skyline/gpu/display.cpp index de399240..9f5e96bf 100644 --- a/app/src/main/cpp/skyline/gpu/display.cpp +++ b/app/src/main/cpp/skyline/gpu/display.cpp @@ -17,7 +17,7 @@ namespace skyline::gpu { if (!nvBuffer) throw exception("A QueueBuffer request has an invalid NVMap Handle ({}) and ID ({})", gbpBuffer.nvmapHandle, gbpBuffer.nvmapId); } - switch(gbpBuffer.format) { + switch (gbpBuffer.format) { case WINDOW_FORMAT_RGBA_8888: case WINDOW_FORMAT_RGBX_8888: bpp = sizeof(u32); @@ -34,10 +34,6 @@ namespace skyline::gpu { state.process->ReadMemory(dataBuffer.data(), nvBuffer->address + gbpBuffer.offset, gbpBuffer.size); } - BufferQueue::WaitContext::WaitContext(std::shared_ptr thread, DequeueIn input, kernel::ipc::OutputBuffer& buffer) : thread(std::move(thread)), input(input), buffer(buffer) {} - - BufferQueue::DequeueOut::DequeueOut(u32 slot) : slot(slot), _unk0_(0x1), _unk1_(0x24) {} - BufferQueue::BufferQueue(const DeviceState &state) : state(state) {} void BufferQueue::RequestBuffer(Parcel &in, Parcel &out) { @@ -50,9 +46,15 @@ namespace skyline::gpu { } void BufferQueue::DequeueBuffer(Parcel &in, Parcel &out) { - auto *data = reinterpret_cast(in.data.data() + constant::TokenLength); + struct Data { + u32 format; + u32 width; + u32 height; + u32 timestamps; + u32 usage; + } *data = reinterpret_cast(in.data.data() + constant::TokenLength); i64 slot{-1}; - while(slot == -1) { + while (slot == -1) { for (auto &buffer : queue) { if (buffer.second->status == BufferStatus::Free && buffer.second->resolution.width == data->width && buffer.second->resolution.height == data->height && buffer.second->gbpBuffer.usage == data->usage) { slot = buffer.first; @@ -62,7 +64,12 @@ namespace skyline::gpu { } sched_yield(); } - DequeueOut output(static_cast(slot)); + struct { + u32 slot; + u32 _unk_[13]; + } output{ + .slot = static_cast(slot) + }; out.WriteData(output); state.logger->Debug("DequeueBuffer: Width: {}, Height: {}, Format: {}, Usage: {}, Timestamps: {}, Slot: {}", data->width, data->height, data->format, data->usage, data->timestamps, slot); } @@ -118,28 +125,19 @@ namespace skyline::gpu { auto gbpBuffer = reinterpret_cast(pointer); queue[data->slot] = std::make_shared(state, data->slot, *gbpBuffer); state.gpu->bufferEvent->Signal(); - state.logger->Debug("SetPreallocatedBuffer: Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", data->slot, gbpBuffer->magic, gbpBuffer->width, gbpBuffer->height, gbpBuffer->stride, gbpBuffer->format, gbpBuffer->usage, gbpBuffer->index,gbpBuffer->nvmapId, gbpBuffer->nvmapHandle, gbpBuffer->offset, (1U << gbpBuffer->blockHeightLog2), gbpBuffer->size); - } - - void BufferQueue::FreeBuffer(u32 slotNo) { - auto &slot = queue.at(slotNo); - if (waitVec.empty()) - slot->status = BufferStatus::Free; - else { - auto context = waitVec.begin(); - while (context != waitVec.end()) { - if (slot->resolution.width == context->input.width && slot->resolution.height == context->input.height && slot->gbpBuffer.usage == context->input.usage) { - context->thread->WakeUp(); - gpu::Parcel out(state); - DequeueOut output(slotNo); - out.WriteData(output); - out.WriteParcel(context->buffer); - slot->status = BufferStatus::Dequeued; - waitVec.erase(context); - break; - } - context++; - } - } + state.logger->Debug("SetPreallocatedBuffer: Slot: {}, Magic: 0x{:X}, Width: {}, Height: {}, Stride: {}, Format: {}, Usage: {}, Index: {}, ID: {}, Handle: {}, Offset: 0x{:X}, Block Height: {}, Size: 0x{:X}", + data->slot, + gbpBuffer->magic, + gbpBuffer->width, + gbpBuffer->height, + gbpBuffer->stride, + gbpBuffer->format, + gbpBuffer->usage, + gbpBuffer->index, + gbpBuffer->nvmapId, + gbpBuffer->nvmapHandle, + gbpBuffer->offset, + (1U << gbpBuffer->blockHeightLog2), + gbpBuffer->size); } } diff --git a/app/src/main/cpp/skyline/gpu/display.h b/app/src/main/cpp/skyline/gpu/display.h index f6cec24d..0d08022e 100644 --- a/app/src/main/cpp/skyline/gpu/display.h +++ b/app/src/main/cpp/skyline/gpu/display.h @@ -13,11 +13,11 @@ namespace skyline::gpu { u32 width; //!< The width component of the resolution u32 height; //!< The height component of the resolution - bool operator==(const Resolution &r) { + inline bool operator==(const Resolution &r) { return (width == r.width) && (height == r.height); } - bool operator!=(const Resolution &r) { + inline bool operator!=(const Resolution &r) { return !operator==(r); } }; @@ -58,8 +58,7 @@ namespace skyline::gpu { enum class BufferStatus { Free, Dequeued, - Queued, - Acquired + Queued }; /** @@ -106,7 +105,6 @@ namespace skyline::gpu { GbpBuffer gbpBuffer; //!< The information about the underlying buffer BufferStatus status{BufferStatus::Free}; //!< The status of this buffer std::vector dataBuffer; //!< The vector holding the actual pixel data - std::vector swizzBuffer; //!< The vector holding the swizzled pixel data std::shared_ptr nvBuffer{}; //!< A shared pointer to the buffer's nvmap object /** @@ -123,55 +121,12 @@ namespace skyline::gpu { }; /** - * @brief This holds the state of all the buffers used by the guest application + * @brief This is used to manage and queue up all display buffers to be shown */ class BufferQueue { private: const DeviceState &state; //!< The state of the device - /** - * @brief This is the input struct for DequeueBuffer - */ - struct DequeueIn { - u32 format; - u32 width; - u32 height; - u32 timestamps; - u32 usage; - }; - - /** - * @brief This is the output struct for DequeueBuffer - */ - struct DequeueOut { - u32 slot; //!< The slot of the dequeued buffer - u32 _unk0_; - u32 _unk1_; - u32 _unk2_[11]{}; - - /** - * @param slot The slot of the dequeued buffer - */ - DequeueOut(u32 slot); - }; - - /** - * @brief This holds the context of a thread waiting on a buffer - */ - struct WaitContext { - std::shared_ptr thread; //!< The thread that is waiting on a buffer - DequeueIn input; //!< The input of DequeueBuffer - kernel::ipc::OutputBuffer buffer; //!< The output buffer to write the parcel into - - /** - * @param thread The thread that is waiting on a buffer - * @param input The input of DequeueBuffer - * @param buffer The output buffer to write the parcel into - */ - WaitContext(std::shared_ptr thread, DequeueIn input, kernel::ipc::OutputBuffer& buffer); - }; - std::vector waitVec; //!< A vector of shared pointers to threads waiting on a buffer - public: std::unordered_map> queue; //!< A vector of shared pointers to all the queued buffers std::queue> displayQueue; //!< A queue of all the buffers to be posted to the display @@ -210,6 +165,8 @@ namespace skyline::gpu { * @brief This frees a buffer which is currently queued * @param slotNo The slot of the buffer */ - void FreeBuffer(u32 slotNo); + inline void FreeBuffer(u32 slotNo) { + queue.at(slotNo)->status = BufferStatus::Free; + } }; } diff --git a/app/src/main/cpp/skyline/gpu/parcel.cpp b/app/src/main/cpp/skyline/gpu/parcel.cpp index fd3a6d79..a624c583 100644 --- a/app/src/main/cpp/skyline/gpu/parcel.cpp +++ b/app/src/main/cpp/skyline/gpu/parcel.cpp @@ -17,7 +17,7 @@ namespace skyline::gpu { Parcel::Parcel(const DeviceState &state) : state(state) {} - u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer& buffer) { + u64 Parcel::WriteParcel(kernel::ipc::OutputBuffer &buffer) { return WriteParcel(buffer.address, buffer.size); } diff --git a/app/src/main/cpp/skyline/gpu/parcel.h b/app/src/main/cpp/skyline/gpu/parcel.h index c0c66dcf..09de3265 100644 --- a/app/src/main/cpp/skyline/gpu/parcel.h +++ b/app/src/main/cpp/skyline/gpu/parcel.h @@ -82,7 +82,7 @@ namespace skyline::gpu { * @param buffer The buffer to write into * @return The total size of the message */ - u64 WriteParcel(kernel::ipc::OutputBuffer& buffer); + u64 WriteParcel(kernel::ipc::OutputBuffer &buffer); /** * @brief Writes the Parcel object into the process's memory diff --git a/app/src/main/cpp/skyline/jvm.cpp b/app/src/main/cpp/skyline/jvm.cpp index d14901a1..ed0694fb 100644 --- a/app/src/main/cpp/skyline/jvm.cpp +++ b/app/src/main/cpp/skyline/jvm.cpp @@ -5,21 +5,21 @@ thread_local JNIEnv *env; namespace skyline { JvmManager::JvmManager(JNIEnv *environ, jobject instance) : instance(instance), instanceClass(reinterpret_cast(environ->NewGlobalRef(environ->GetObjectClass(instance)))) { env = environ; - if(env->GetJavaVM(&vm) < 0) + if (env->GetJavaVM(&vm) < 0) throw exception("Cannot get JavaVM from environment"); } void JvmManager::AttachThread() { - if(!env) + if (!env) vm->AttachCurrentThread(&env, nullptr); } void JvmManager::DetachThread() { - if(env) + if (env) vm->DetachCurrentThread(); } - JNIEnv* JvmManager::GetEnv() { + JNIEnv *JvmManager::GetEnv() { return env; } @@ -31,7 +31,7 @@ namespace skyline { return env->IsSameObject(env->GetObjectField(instance, env->GetFieldID(instanceClass, key, signature)), nullptr); } - bool JvmManager::CheckNull(jobject& object) { + bool JvmManager::CheckNull(jobject &object) { return env->IsSameObject(object, nullptr); } } diff --git a/app/src/main/cpp/skyline/jvm.h b/app/src/main/cpp/skyline/jvm.h index ebf31d1a..ab630ac5 100644 --- a/app/src/main/cpp/skyline/jvm.h +++ b/app/src/main/cpp/skyline/jvm.h @@ -32,7 +32,7 @@ namespace skyline { /** * @brief Returns a pointer to the JNI environment for the current thread */ - JNIEnv* GetEnv(); + JNIEnv *GetEnv(); /** * @brief Retrieves a specific field of the given type from the activity diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index cbcb6081..3cee270b 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -259,8 +259,8 @@ namespace skyline::kernel::ipc { * @tparam ValueType The type of the object to read */ template - inline ValueType& Pop() { - ValueType& value = *reinterpret_cast(payloadOffset); + inline ValueType &Pop() { + ValueType &value = *reinterpret_cast(payloadOffset); payloadOffset += sizeof(ValueType); return value; } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 17fb6397..b8d1ffd5 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -4,7 +4,7 @@ namespace skyline::kernel::svc { void SetHeapSize(DeviceState &state) { const u32 size = state.ctx->registers.w1; - if(size%constant::HeapSizeDiv != 0) { + if (size % constant::HeapSizeDiv != 0) { state.ctx->registers.x1 = 0; state.ctx->registers.w0 = constant::status::InvSize; state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size); @@ -26,13 +26,13 @@ namespace skyline::kernel::svc { void SetMemoryAttribute(DeviceState &state) { const u64 addr = state.ctx->registers.x0; - if((addr & (PAGE_SIZE - 1U))) { + if ((addr & (PAGE_SIZE - 1U))) { state.ctx->registers.w0 = constant::status::InvAddress; state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: {}", addr); return; } const u64 size = state.ctx->registers.x1; - if((size & (PAGE_SIZE - 1U)) || !size) { + if ((size & (PAGE_SIZE - 1U)) || !size) { state.ctx->registers.w0 = constant::status::InvSize; state.logger->Warn("svcSetMemoryAttribute: 'size' {}: {}", size ? "not page aligned" : "is zero", size); return; @@ -40,12 +40,12 @@ namespace skyline::kernel::svc { u32 mask = state.ctx->registers.w2; u32 value = state.ctx->registers.w3; u32 maskedValue = mask | value; - if(maskedValue != mask) { + if (maskedValue != mask) { state.ctx->registers.w0 = constant::status::InvCombination; state.logger->Warn("svcSetMemoryAttribute: 'mask' invalid: 0x{:X}, 0x{:X}", mask, value); return; } - memory::MemoryAttribute attribute = *reinterpret_cast(&maskedValue); + memory::MemoryAttribute attribute = *reinterpret_cast(&maskedValue); bool found = false; for (const auto&[address, region] : state.process->memoryMap) { if (addr >= address && addr < (address + region->size)) { @@ -62,7 +62,7 @@ namespace skyline::kernel::svc { break; } } - if(!found) { + if (!found) { state.ctx->registers.w0 = constant::status::InvAddress; state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", addr); return; @@ -73,7 +73,7 @@ namespace skyline::kernel::svc { void QueryMemory(DeviceState &state) { memory::MemoryInfo memInfo{}; - u64 addr = (state.ctx->registers.x2 & ~(PAGE_SIZE - 1)); + u64 addr = state.ctx->registers.x2 & ~(PAGE_SIZE - 1); bool found = false; for (const auto&[address, region] : state.process->memoryMap) { if (addr >= address && addr < (address + region->size)) { @@ -126,7 +126,7 @@ namespace skyline::kernel::svc { u64 entryArg = state.ctx->registers.x2; u64 stackTop = state.ctx->registers.x3; u8 priority = static_cast(state.ctx->registers.w4); - if((priority < constant::PriorityNin.first) && (priority > constant::PriorityNin.second)) { // NOLINT(misc-redundant-expression) + if ((priority < constant::PriorityNin.first) && (priority > constant::PriorityNin.second)) { // NOLINT(misc-redundant-expression) state.ctx->registers.w0 = constant::status::InvAddress; state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority); return; @@ -143,7 +143,7 @@ namespace skyline::kernel::svc { auto thread = state.process->GetHandle(handle); state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->pid); thread->Start(); - } catch (const std::exception&) { + } catch (const std::exception &) { state.logger->Warn("svcStartThread: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; } @@ -161,12 +161,9 @@ namespace skyline::kernel::svc { case 1: case 2: state.logger->Debug("svcSleepThread: Yielding thread: {}", in); - state.thread->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.thread->timeout = GetCurrTimeNs() + in; - state.thread->status = type::KThread::Status::Sleeping; } } @@ -177,7 +174,7 @@ namespace skyline::kernel::svc { state.ctx->registers.w1 = priority; state.ctx->registers.w0 = constant::status::Success; state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); - } catch (const std::exception&) { + } catch (const std::exception &) { state.logger->Warn("svcGetThreadPriority: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; } @@ -190,7 +187,7 @@ namespace skyline::kernel::svc { state.process->GetHandle(handle)->UpdatePriority(static_cast(priority)); state.ctx->registers.w0 = constant::status::Success; state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); - } catch (const std::exception&) { + } catch (const std::exception &) { state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; } @@ -259,7 +256,7 @@ namespace skyline::kernel::svc { state.process->handleTable.erase(handle); state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::Success; - } catch(const std::exception&) { + } catch (const std::exception &) { state.logger->Warn("svcCloseHandle: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; } @@ -284,7 +281,7 @@ namespace skyline::kernel::svc { } state.logger->Debug("svcResetSignal: Resetting signal: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::Success; - } catch(const std::out_of_range&) { + } catch (const std::out_of_range &) { state.logger->Warn("svcResetSignal: 'handle' invalid: 0x{:X}", handle); state.ctx->registers.w0 = constant::status::InvHandle; return; @@ -298,9 +295,9 @@ namespace skyline::kernel::svc { return; } std::vector waitHandles(numHandles); + std::vector> objectTable; state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(handle_t)); std::string handleStr; - uint index{}; for (const auto &handle : waitHandles) { handleStr += fmt::format("* 0x{:X}\n", handle); auto object = state.process->handleTable.at(handle); @@ -312,33 +309,34 @@ namespace skyline::kernel::svc { break; default: { state.ctx->registers.w0 = constant::status::InvHandle; - state.thread->ClearWaitObjects(); return; } } - auto syncObject = std::static_pointer_cast(object); - if (syncObject->signalled) { - state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::Success; - state.ctx->registers.w1 = index; - state.thread->ClearWaitObjects(); + objectTable.push_back(std::static_pointer_cast(object)); + } + state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, state.ctx->registers.x3); + auto timeout = state.ctx->registers.x3 + GetCurrTimeNs(); + while (true) { + uint index{}; + for (const auto &object : objectTable) { + if (object->signalled) { + state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", waitHandles.at(index)); + state.ctx->registers.w0 = constant::status::Success; + state.ctx->registers.w1 = index; + return; + } + index++; + } + if (GetCurrTimeNs() >= timeout) { + state.ctx->registers.w0 = constant::status::Timeout; return; } - state.thread->waitObjects.push_back(syncObject); - syncObject->waitThreads.emplace_back(state.thread->pid, index); } - auto timeout = state.ctx->registers.x3; - state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); - if (state.ctx->registers.x3 != std::numeric_limits::max()) - state.thread->timeout = GetCurrTimeNs() + timeout; - else - state.thread->timeout = 0; - state.thread->status = type::KThread::Status::WaitSync; } void ArbitrateLock(DeviceState &state) { auto addr = state.ctx->registers.x1; - if((addr & ((1UL << WORD_BIT) - 1U))) { + if ((addr & ((1UL << WORD_BIT) - 1U))) { state.ctx->registers.w0 = constant::status::InvAddress; state.logger->Warn("svcArbitrateLock: 'address' not word aligned: {}", addr); return; @@ -353,7 +351,7 @@ namespace skyline::kernel::svc { void ArbitrateUnlock(DeviceState &state) { auto addr = state.ctx->registers.x0; - if((addr & ((1UL << WORD_BIT) - 1U))) { + if ((addr & ((1UL << WORD_BIT) - 1U))) { state.ctx->registers.w0 = constant::status::InvAddress; state.logger->Warn("svcArbitrateUnlock: 'address' not word aligned: {}", addr); return; @@ -365,49 +363,53 @@ namespace skyline::kernel::svc { void WaitProcessWideKeyAtomic(DeviceState &state) { auto mtxAddr = state.ctx->registers.x0; - if((mtxAddr & ((1UL << WORD_BIT) - 1U))) { - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: {}", mtxAddr); - return; - } - auto handle = state.ctx->registers.w2; - if (handle != state.thread->handle) - throw exception("svcWaitProcessWideKeyAtomic: Called from another thread"); - state.process->MutexUnlock(mtxAddr); auto condAddr = state.ctx->registers.x1; - auto &cvarVec = state.process->condVarMap[condAddr]; - for (auto thread = cvarVec.begin();; thread++) { - if ((*thread)->priority < state.thread->priority) { - cvarVec.insert(thread, state.thread); - break; - } else if (thread + 1 == cvarVec.end()) { - cvarVec.push_back(state.thread); - break; + try { + auto &cvar = state.process->condVarMap.at(condAddr); + if ((mtxAddr & ((1UL << WORD_BIT) - 1U))) { + state.ctx->registers.w0 = constant::status::InvAddress; + state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: {}", mtxAddr); + return; } + auto handle = state.ctx->registers.w2; + if (handle != state.thread->handle) + throw exception("svcWaitProcessWideKeyAtomic: Called from another thread"); + state.process->MutexLock(mtxAddr); + auto &mutex = state.process->mutexMap.at(mtxAddr); + auto timeout = state.ctx->registers.x3; + state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x:{:X}, Timeout: {} ns", mtxAddr, condAddr, timeout); + timespec spec{}; + clock_gettime(CLOCK_REALTIME, &spec); + u128 time = u128(spec.tv_sec * 1000000000U + spec.tv_nsec) + timeout; // u128 to prevent overflow + spec.tv_sec = static_cast(time / 1000000000U); + spec.tv_nsec = static_cast(time % 1000000000U); + if (pthread_cond_timedwait(&cvar, &mutex, &spec) == ETIMEDOUT) + state.ctx->registers.w0 = constant::status::Timeout; + else + state.ctx->registers.w0 = constant::status::Success; + state.process->MutexUnlock(mtxAddr); + } catch (const std::out_of_range &) { + state.logger->Debug("svcWaitProcessWideKeyAtomic: No Conditional-Variable at 0x{:X}", condAddr); + state.process->condVarMap[condAddr] = PTHREAD_COND_INITIALIZER; + state.ctx->registers.w0 = constant::status::Success; } - auto timeout = state.ctx->registers.x3; - state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x:{:X}, Timeout: {} ns", mtxAddr, condAddr, timeout); - state.thread->status = type::KThread::Status::WaitCondVar; - state.thread->timeout = GetCurrTimeNs() + timeout; - state.ctx->registers.w0 = constant::status::Success; } void SignalProcessWideKey(DeviceState &state) { auto address = state.ctx->registers.x0; - auto count = state.ctx->registers.w1; - state.ctx->registers.w0 = constant::status::Success; - if (!state.process->condVarMap.count(address)) { + auto count = state.ctx->registers.x1; + try { + state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count); + auto &cvar = state.process->condVarMap.at(address); + /* + for (u32 iter = 0; iter < count; iter++) + pthread_cond_signal(&cvar); + */ + } catch (const std::out_of_range &) { state.logger->Debug("svcSignalProcessWideKey: No Conditional-Variable at 0x{:X}", address); - return; + state.process->condVarMap[address] = PTHREAD_COND_INITIALIZER; } - auto &cvarVec = state.process->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.process->condVarMap.erase(address); - state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count); + state.ctx->registers.w0 = constant::status::Success; } void GetSystemTick(DeviceState &state) { @@ -459,7 +461,7 @@ namespace skyline::kernel::svc { void OutputDebugString(DeviceState &state) { std::string debug(state.ctx->registers.x1, '\0'); state.process->ReadMemory(debug.data(), state.ctx->registers.x0, state.ctx->registers.x1); - if(debug.back() == '\n') + if (debug.back() == '\n') debug.pop_back(); state.logger->Info("Debug Output: {}", debug); state.ctx->registers.w0 = constant::status::Success; diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp___jb_old___ b/app/src/main/cpp/skyline/kernel/svc.cpp___jb_old___ deleted file mode 100644 index a3107ceb..00000000 --- a/app/src/main/cpp/skyline/kernel/svc.cpp___jb_old___ +++ /dev/null @@ -1,534 +0,0 @@ -#include "svc.h" -#include - -namespace skyline::kernel::svc { - void SetHeapSize(DeviceState &state) { - const u32 size = state.ctx->registers.w1; - if(size%constant::HeapSizeDiv != 0) { - state.ctx->registers.x1 = 0; - state.ctx->registers.w0 = constant::status::InvSize; - state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size); - return; - } - std::shared_ptr heap; - try { - heap = state.process->memoryRegionMap.at(memory::Region::Heap); - heap->Resize(size, true); - } catch (const exception &) { - state.logger->Warn("svcSetHeapSize: Falling back to recreating memory"); - state.process->UnmapPrivateRegion(memory::Region::Heap); - heap = state.process->MapPrivateRegion(constant::HeapAddr, size, {true, true, false}, memory::Type::Heap, memory::Region::Heap).item; - } - state.ctx->registers.w0 = constant::status::Success; - state.ctx->registers.x1 = heap->address; - state.logger->Debug("svcSetHeapSize: Allocated at 0x{:X} for 0x{:X} bytes", heap->address, heap->size); - } - - void SetMemoryAttribute(DeviceState &state) { - const u64 addr = state.ctx->registers.x0; - if((addr & (PAGE_SIZE - 1U))) { - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcSetMemoryAttribute: 'address' not page aligned: {}", addr); - return; - } - const u64 size = state.ctx->registers.x1; - if((size & (PAGE_SIZE - 1U)) || !size) { - state.ctx->registers.w0 = constant::status::InvSize; - state.logger->Warn("svcSetMemoryAttribute: 'size' {}: {}", size ? "not page aligned" : "is zero", size); - return; - } - u32 mask = state.ctx->registers.w2; - u32 value = state.ctx->registers.w3; - u32 maskedValue = mask | value; - if(maskedValue != mask) { - state.ctx->registers.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.process->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 = attribute.isUncached; - subFound = true; - break; - } - if (!subFound) - region->regionInfoVec.emplace_back(addr, size, static_cast(attribute.isUncached)); - found = true; - break; - } - } - if(!found) { - state.ctx->registers.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.ctx->registers.w0 = constant::status::Success; - } - - void QueryMemory(DeviceState &state) { - memory::MemoryInfo memInfo{}; - u64 addr = (state.ctx->registers.x2 & ~(PAGE_SIZE-1)); - bool found = false; - for (const auto&[address, region] : state.process->memoryMap) { - if (addr >= address && addr < (address + region->size)) { - memInfo = region->GetInfo(addr); - found = true; - break; - } - } - if (!found) { - for (const auto &object : state.process->handleTable) { - if (object.second->objectType == type::KType::KSharedMemory) { - const auto &mem = state.process->GetHandle(object.first); - if (mem->guest.valid()) { - if (addr >= mem->guest.address && addr < (mem->guest.address + mem->guest.size)) { - memInfo = mem->GetInfo(); - found = true; - break; - } - } - } else if (object.second->objectType == type::KType::KTransferMemory) { - const auto &mem = state.process->GetHandle(object.first); - if (addr >= mem->cAddress && addr < (mem->cAddress + mem->cSize)) { - memInfo = mem->GetInfo(); - found = true; - break; - } - } - } - if (!found) { - memInfo = { - .baseAddress = constant::BaseAddr, - .size = static_cast(constant::BaseEnd), - .type = static_cast(memory::Type::Unmapped) - }; - state.logger->Debug("svcQueryMemory: Cannot find block of address: 0x{:X}", addr); - } - } - state.logger->Debug("svcQueryMemory: Address: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{}", memInfo.baseAddress, memInfo.size, memInfo.type, static_cast(memInfo.memoryAttribute.isUncached), memInfo.r ? "R" : "-", memInfo.w ? "W" : "-", memInfo.x ? "X" : "-"); - state.process->WriteMemory(memInfo, state.ctx->registers.x0); - state.ctx->registers.w0 = constant::status::Success; - } - - void ExitProcess(DeviceState &state) { - state.logger->Debug("svcExitProcess: Exiting current process: {}", state.process->pid); - state.os->KillThread(state.process->pid); - } - - void CreateThread(DeviceState &state) { - u64 entryAddr = state.ctx->registers.x1; - u64 entryArg = state.ctx->registers.x2; - u64 stackTop = state.ctx->registers.x3; - u8 priority = static_cast(state.ctx->registers.w4); - if((priority < constant::PriorityNin.first) && (priority > constant::PriorityNin.second)) { // NOLINT(misc-redundant-expression) - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority); - return; - } - auto thread = state.process->CreateThread(entryAddr, entryArg, stackTop, priority); - state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, PID: {})", thread->handle, entryAddr, entryArg, stackTop, priority, thread->pid); - state.ctx->registers.w1 = thread->handle; - state.ctx->registers.w0 = constant::status::Success; - } - - void StartThread(DeviceState &state) { - auto handle = state.ctx->registers.w0; - try { - auto thread = state.process->GetHandle(handle); - state.logger->Debug("svcStartThread: Starting thread: 0x{:X}, PID: {}", handle, thread->pid); - thread->Start(); - } catch (const std::exception&) { - state.logger->Warn("svcStartThread: 'handle' invalid: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::InvHandle; - } - } - - void ExitThread(DeviceState &state) { - state.logger->Debug("svcExitProcess: Exiting current thread: {}", state.thread->pid); - state.os->KillThread(state.thread->pid); - } - - void SleepThread(DeviceState &state) { - auto in = state.ctx->registers.x0; - switch (in) { - case 0: - case 1: - case 2: - state.logger->Debug("svcSleepThread: Yielding thread: {}", in); - state.thread->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.thread->timeout = GetCurrTimeNs() + in; - state.thread->status = type::KThread::Status::Sleeping; - } - } - - void GetThreadPriority(DeviceState &state) { - auto handle = state.ctx->registers.w0; - try { - auto priority = state.process->GetHandle(handle)->priority; - state.ctx->registers.w1 = priority; - state.ctx->registers.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.ctx->registers.w0 = constant::status::InvHandle; - } - } - - void SetThreadPriority(DeviceState &state) { - auto handle = state.ctx->registers.w0; - auto priority = state.ctx->registers.w1; - try { - state.process->GetHandle(handle)->UpdatePriority(static_cast(priority)); - state.ctx->registers.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.ctx->registers.w0 = constant::status::InvHandle; - } - } - - void MapSharedMemory(DeviceState &state) { - try { - auto object = state.process->GetHandle(state.ctx->registers.w0); - u64 addr = state.ctx->registers.x1; - if ((addr & (PAGE_SIZE - 1U))) { - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcMapSharedMemory: 'address' not page aligned: 0x{:X}", addr); - return; - } - const u64 size = state.ctx->registers.x2; - if ((size & (PAGE_SIZE - 1U)) || !size) { - state.ctx->registers.w0 = constant::status::InvSize; - state.logger->Warn("svcMapSharedMemory: 'size' {}: {}", size ? "not page aligned" : "is zero", size); - return; - } - u32 perm = state.ctx->registers.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.ctx->registers.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.ctx->registers.w0 = constant::status::Success; - } catch (const std::exception &) { - state.logger->Warn("svcMapSharedMemory: 'handle' invalid: 0x{:X}", state.ctx->registers.w0); - state.ctx->registers.w0 = constant::status::InvHandle; - } - } - - void CreateTransferMemory(DeviceState &state) { - u64 addr = state.ctx->registers.x1; - if ((addr & (PAGE_SIZE - 1U))) { - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcCreateTransferMemory: 'address' not page aligned: {}", addr); - return; - } - u64 size = state.ctx->registers.x2; - if ((size & (PAGE_SIZE - 1U)) || !size) { - state.ctx->registers.w0 = constant::status::InvSize; - state.logger->Warn("svcCreateTransferMemory: 'size' {}: {}", size ? "not page aligned" : "is zero", size); - return; - } - u32 perm = state.ctx->registers.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.ctx->registers.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.process->NewHandle(state.process->pid, addr, size, permission); - state.ctx->registers.w0 = constant::status::Success; - state.ctx->registers.w1 = shmem.handle; - } - - void CloseHandle(DeviceState &state) { - auto handle = static_cast(state.ctx->registers.w0); - try { - state.process->handleTable.erase(handle); - state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::Success; - } catch(const std::exception&) { - state.logger->Warn("svcCloseHandle: 'handle' invalid: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::InvHandle; - } - } - - void ResetSignal(DeviceState &state) { - auto handle = state.ctx->registers.w0; - try { - auto &object = state.process->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.ctx->registers.w0 = constant::status::InvHandle; - return; - } - } - state.logger->Debug("svcResetSignal: Resetting signal: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::Success; - } catch(const std::out_of_range&) { - state.logger->Warn("svcResetSignal: 'handle' invalid: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::InvHandle; - return; - } - } - - void WaitSynchronization(DeviceState &state) { - auto numHandles = state.ctx->registers.w2; - if (numHandles > constant::MaxSyncHandles) { - state.ctx->registers.w0 = constant::status::MaxHandles; - return; - } - std::vector waitHandles(numHandles); - state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(handle_t)); - std::string handleStr; - uint index{}; - for (const auto &handle : waitHandles) { - handleStr += fmt::format("* 0x{:X}\n", handle); - auto object = state.process->handleTable.at(handle); - switch (object->objectType) { - case type::KType::KProcess: - case type::KType::KThread: - case type::KType::KEvent: - case type::KType::KSession: - break; - default: { - state.ctx->registers.w0 = constant::status::InvHandle; - state.thread->ClearWaitObjects(); - return; - } - } - auto syncObject = std::static_pointer_cast(object); - if (syncObject->signalled) { - state.logger->Debug("svcWaitSynchronization: Signalled handle: 0x{:X}", handle); - state.ctx->registers.w0 = constant::status::Success; - state.ctx->registers.w1 = index; - state.thread->ClearWaitObjects(); - return; - } - state.thread->waitObjects.push_back(syncObject); - syncObject->waitThreads.emplace_back(state.thread->pid, index); - } - auto timeout = state.ctx->registers.x3; - state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); - if (state.ctx->registers.x3 != std::numeric_limits::max()) - state.thread->timeout = GetCurrTimeNs() + timeout; - else - state.thread->timeout = 0; - state.thread->status = type::KThread::Status::WaitSync; - } - - void ArbitrateLock(DeviceState &state) { - auto addr = state.ctx->registers.x1; - if((addr & ((1UL << WORD_BIT) - 1U))) { - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcArbitrateLock: 'address' not word aligned: {}", addr); - return; - } - auto handle = state.ctx->registers.w2; - if (handle != state.thread->handle) - throw exception("svcArbitrateLock: Called from another thread"); - state.logger->Debug("svcArbitrateLock: Locking mutex at 0x{:X} for thread 0x{:X}", addr, handle); - state.process->MutexLock(addr); - state.ctx->registers.w0 = constant::status::Success; - } - - void ArbitrateUnlock(DeviceState &state) { - auto addr = state.ctx->registers.x0; - if((addr & ((1UL << WORD_BIT) - 1U))) { - state.ctx->registers.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.process->MutexUnlock(addr); - state.ctx->registers.w0 = constant::status::Success; - } - - void WaitProcessWideKeyAtomic(DeviceState &state) { - auto mtxAddr = state.ctx->registers.x0; - if((mtxAddr & ((1UL << WORD_BIT) - 1U))) { - state.ctx->registers.w0 = constant::status::InvAddress; - state.logger->Warn("svcWaitProcessWideKeyAtomic: mutex address not word aligned: {}", mtxAddr); - return; - } - auto handle = state.ctx->registers.w2; - if (handle != state.thread->handle) - throw exception("svcWaitProcessWideKeyAtomic: Called from another thread"); - state.process->MutexUnlock(mtxAddr); - auto condAddr = state.ctx->registers.x1; - auto &cvarVec = state.process->condVarMap[condAddr]; - for (auto thread = cvarVec.begin();; thread++) { - if ((*thread)->priority < state.thread->priority) { - cvarVec.insert(thread, state.thread); - break; - } else if (thread + 1 == cvarVec.end()) { - cvarVec.push_back(state.thread); - break; - } - } - auto timeout = state.ctx->registers.x3; - state.logger->Debug("svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x:{:X}, Timeout: {} ns", mtxAddr, condAddr, timeout); - state.thread->status = type::KThread::Status::WaitCondVar; - state.thread->timeout = GetCurrTimeNs() + timeout; - state.ctx->registers.w0 = constant::status::Success; - } - - void SignalProcessWideKey(DeviceState &state) { - auto address = state.ctx->registers.x0; - auto count = state.ctx->registers.w1; - state.ctx->registers.w0 = constant::status::Success; - if (!state.process->condVarMap.count(address)) { - state.logger->Debug("svcSignalProcessWideKey: No Conditional-Variable at 0x{:X}", address); - return; - } - auto &cvarVec = state.process->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.process->condVarMap.erase(address); - state.logger->Debug("svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {}", address, count); - } - - void GetSystemTick(DeviceState &state) { - u64 tick; - asm("STR X1, [SP, #-16]!\n\t" - "MRS %0, CNTVCT_EL0\n\t" - "MOV X1, #0xF800\n\t" - "MOVK X1, #0x124, lsl #16\n\t" - "MUL %0, %0, X1\n\t" - "MRS X1, CNTFRQ_EL0\n\t" - "UDIV %0, %0, X1\n\t" - "LDR X1, [SP], #16" : "=r"(tick)); - state.ctx->registers.x0 = tick; - } - - void ConnectToNamedPort(DeviceState &state) { - char port[constant::PortSize + 1]{0}; - state.process->ReadMemory(port, state.ctx->registers.x1, constant::PortSize); - handle_t handle{}; - if (std::strcmp(port, "sm:") == 0) - handle = state.os->serviceManager.NewSession(service::Service::sm); - else { - state.logger->Warn("svcConnectToNamedPort: Connecting to invalid port: '{}'", port); - state.ctx->registers.w0 = constant::status::NotFound; - return; - } - state.logger->Debug("svcConnectToNamedPort: Connecting to port '{}' at 0x{:X}", port, handle); - state.ctx->registers.w1 = handle; - state.ctx->registers.w0 = constant::status::Success; - } - - void SendSyncRequest(DeviceState &state) { - state.os->serviceManager.SyncRequestHandler(static_cast(state.ctx->registers.x0)); - state.ctx->registers.w0 = constant::status::Success; - } - - void GetThreadId(DeviceState &state) { - pid_t pid{}; - auto handle = state.ctx->registers.w1; - if (handle != constant::ThreadSelf) { - pid = state.process->GetHandle(handle)->pid; - } else - pid = state.thread->pid; - state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid); - state.ctx->registers.x1 = static_cast(pid); - state.ctx->registers.w0 = constant::status::Success; - } - - void OutputDebugString(DeviceState &state) { - std::string debug(state.ctx->registers.x1, '\0'); - state.process->ReadMemory(debug.data(), state.ctx->registers.x0, state.ctx->registers.x1); - if(debug.back() == '\n') - debug.pop_back(); - state.logger->Info("Debug Output: {}", debug); - state.ctx->registers.w0 = constant::status::Success; - } - - void GetInfo(DeviceState &state) { - auto id0 = state.ctx->registers.w1; - auto handle = state.ctx->registers.w2; - auto id1 = state.ctx->registers.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: - break; - case constant::infoState::AliasRegionBaseAddr: - out = constant::MapAddr; - break; - case constant::infoState::AliasRegionSize: - out = constant::MapSize; - break; - case constant::infoState::HeapRegionBaseAddr: - out = state.process->memoryRegionMap.at(memory::Region::Heap)->address; - break; - case constant::infoState::HeapRegionSize: - out = state.process->memoryRegionMap.at(memory::Region::Heap)->size; - break; - case constant::infoState::TotalMemoryAvailable: - out = constant::TotalPhyMem; - break; - case constant::infoState::TotalMemoryUsage: - out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz + state.process->GetProgramSize(); - break; - case constant::infoState::AddressSpaceBaseAddr: - out = constant::BaseAddr; - break; - case constant::infoState::AddressSpaceSize: - out = constant::BaseEnd; - break; - case constant::infoState::StackRegionBaseAddr: - out = state.thread->stackTop; - break; - case constant::infoState::StackRegionSize: - out = state.process->mainThreadStackSz; - break; - case constant::infoState::PersonalMmHeapSize: - out = constant::TotalPhyMem; - break; - case constant::infoState::PersonalMmHeapUsage: - out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz; - break; - case constant::infoState::TotalMemoryAvailableWithoutMmHeap: - out = constant::TotalPhyMem; // TODO: NPDM specifies SystemResourceSize, subtract that from this - break; - case constant::infoState::TotalMemoryUsedWithoutMmHeap: - out = state.process->memoryRegionMap.at(memory::Region::Heap)->address + state.process->mainThreadStackSz; // TODO: Same as above - break; - case constant::infoState::UserExceptionContextAddr: - out = state.process->tlsPages[0]->Get(0); - break; - default: - state.logger->Warn("svcGetInfo: Unimplemented case ID0: {}, ID1: {}", id0, id1); - state.ctx->registers.w0 = constant::status::Unimpl; - return; - } - state.logger->Debug("svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X}", id0, id1, out); - state.ctx->registers.x1 = out; - state.ctx->registers.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 81332151..080e2aa3 100644 --- a/app/src/main/cpp/skyline/kernel/svc.h +++ b/app/src/main/cpp/skyline/kernel/svc.h @@ -110,6 +110,7 @@ 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 Locks a specified mutex */ diff --git a/app/src/main/cpp/skyline/kernel/types/KEvent.h b/app/src/main/cpp/skyline/kernel/types/KEvent.h index eb529961..3eca2d90 100644 --- a/app/src/main/cpp/skyline/kernel/types/KEvent.h +++ b/app/src/main/cpp/skyline/kernel/types/KEvent.h @@ -13,16 +13,6 @@ namespace skyline::kernel::type { */ KEvent(const DeviceState &state) : KSyncObject(state, KType::KEvent) {} - /** - * @brief Signals all threads waiting on this object - */ - virtual inline void Signal() { - if (!signalled) { - KSyncObject::Signal(); - signalled = true; - } - } - /** * @brief Resets the KEvent to an unsignalled state */ diff --git a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp index ab7855d4..28c6662b 100644 --- a/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KPrivateMemory.cpp @@ -9,7 +9,7 @@ namespace skyline::kernel::type { fregs.x0 = dstAddress; fregs.x1 = size; fregs.x2 = static_cast(permission.Get()); - fregs.x3 = static_cast(MAP_PRIVATE | MAP_ANONYMOUS | ((dstAddress) ? MAP_FIXED : 0)); // NOLINT(hicpp-signed-bitwise) + fregs.x3 = static_cast(MAP_PRIVATE | MAP_ANONYMOUS | ((dstAddress) ? MAP_FIXED : 0)); fregs.x4 = static_cast(-1); fregs.x8 = __NR_mmap; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, thread); @@ -79,13 +79,14 @@ namespace skyline::kernel::type { KPrivateMemory::~KPrivateMemory() { try { - if(state.process) { + if (state.process) { Registers fregs{}; fregs.x0 = address; fregs.x1 = size; fregs.x8 = __NR_munmap; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, state.process->pid); } - } catch (const std::exception &) {} + } catch (const std::exception &) { + } } }; diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index c1532f3d..50c232e1 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -3,7 +3,6 @@ #include #include #include -#include namespace skyline::kernel::type { KProcess::TlsPage::TlsPage(u64 address) : address(address) {} @@ -39,20 +38,21 @@ namespace skyline::kernel::type { return tlsPage->ReserveSlot(); } - KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize, std::shared_ptr& tlsMemory) : pid(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) { + KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize, std::shared_ptr &tlsMemory) : pid(pid), mainThreadStackSz(stackSize), KSyncObject(state, KType::KProcess) { auto thread = NewHandle(pid, entryPoint, 0x0, stackBase + stackSize, 0, constant::DefaultPriority, this, tlsMemory).item; // Remove GetTlsSlot from KThread ctor and cleanup ctor in general threadMap[pid] = thread; state.nce->WaitThreadInit(thread); thread->tls = GetTlsSlot(); MapPrivateRegion(constant::HeapAddr, constant::DefHeapSize, {true, true, false}, memory::Type::Heap, memory::Region::Heap); - memFd = open(fmt::format("/proc/{}/mem", pid).c_str(), O_RDWR | O_CLOEXEC); // NOLINT(hicpp-signed-bitwise) + memFd = open(fmt::format("/proc/{}/mem", pid).c_str(), O_RDWR | O_CLOEXEC); if (memFd == -1) throw exception("Cannot open file descriptor to /proc/{}/mem, \"{}\"", pid, strerror(errno)); } KProcess::~KProcess() { close(memFd); + status = Status::Exiting; } /** @@ -64,7 +64,7 @@ namespace skyline::kernel::type { } u64 CreateThreadFunc(u64 stackTop) { - pid_t pid = clone(&ExecuteChild, reinterpret_cast(stackTop), CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO, nullptr); // NOLINT(hicpp-signed-bitwise) + pid_t pid = clone(&ExecuteChild, reinterpret_cast(stackTop), CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO, nullptr); return static_cast(pid); } @@ -85,7 +85,7 @@ namespace skyline::kernel::type { threadMap[pid] = process; return process; */ - return 0; + return nullptr; } void KProcess::ReadMemory(void *destination, u64 offset, size_t size) const { @@ -96,10 +96,6 @@ namespace skyline::kernel::type { pwrite64(memFd, source, size, offset); } - int KProcess::GetMemoryFd() const { - return memFd; - } - KProcess::HandleOut KProcess::MapPrivateRegion(u64 address, size_t size, const memory::Permission perms, const memory::Type type, const memory::Region region) { auto mem = NewHandle(address, size, perms, type, threadMap.at(pid)); memoryMap[mem.item->address] = mem.item; @@ -123,44 +119,28 @@ namespace skyline::kernel::type { } void KProcess::MutexLock(u64 address) { - auto mtxVec = state.process->mutexMap[address]; - u32 mtxVal = state.process->ReadMemory(address); - if (mtxVec.empty()) { + try { + auto mtx = mutexMap.at(address); + pthread_mutex_lock(&mtx); + u32 mtxVal = ReadMemory(address); mtxVal = (mtxVal & ~constant::MtxOwnerMask) | state.thread->handle; - state.process->WriteMemory(mtxVal, address); - } else { - for (auto thread = mtxVec.begin();; thread++) { - if ((*thread)->priority < state.thread->priority) { - mtxVec.insert(thread, state.thread); - break; - } else if (thread + 1 == mtxVec.end()) { - mtxVec.push_back(state.thread); - break; - } - } - state.thread->status = KThread::Status::WaitMutex; + WriteMemory(mtxVal, address); + } catch (const std::out_of_range &) { + mutexMap[address] = PTHREAD_MUTEX_INITIALIZER; } } void KProcess::MutexUnlock(u64 address) { - auto mtxVec = state.process->mutexMap[address]; - u32 mtxVal = state.process->ReadMemory(address); - if ((mtxVal & constant::MtxOwnerMask) != state.thread->pid) - throw exception("A non-owner thread tried to release a mutex"); - if (mtxVec.empty()) { + try { + auto mtx = mutexMap.at(address); + u32 mtxVal = ReadMemory(address); + if ((mtxVal & constant::MtxOwnerMask) != state.thread->handle) + throw exception("A non-owner thread tried to release a mutex"); mtxVal = 0; - } else { - auto &thread = mtxVec.front(); - mtxVal = (mtxVal & ~constant::MtxOwnerMask) | thread->handle; - thread->status = KThread::Status::Runnable; - mtxVec.erase(mtxVec.begin()); - if (!mtxVec.empty()) - mtxVal |= (~constant::MtxOwnerMask); + WriteMemory(mtxVal, address); + pthread_mutex_unlock(&mtx); + } catch (const std::out_of_range &) { + mutexMap[address] = PTHREAD_MUTEX_INITIALIZER; } - state.process->WriteMemory(mtxVal, address); - } - - void KProcess::ResetSignal() { - signalled = false; } } diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index 432404a8..9eff4fef 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -6,6 +6,7 @@ #include "KSharedMemory.h" #include "KSession.h" #include "KEvent.h" +#include namespace skyline::kernel::type { /** @@ -70,10 +71,9 @@ namespace skyline::kernel::type { std::unordered_map> memoryRegionMap; //!< A mapping from every MemoryRegion to a shared pointer of it's corresponding KPrivateMemory std::unordered_map> handleTable; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object std::unordered_map> threadMap; //!< A mapping from a PID to it's corresponding KThread object - std::unordered_map>> mutexMap; //!< A map from a mutex's address to a vector of threads waiting on it (Sorted by priority) - std::unordered_map>> condVarMap; //!< A map from a conditional variable's address to a vector of threads waiting on it (Sorted by priority) + std::unordered_map mutexMap; //!< A map from a mutex's address to a vector of threads waiting on it + std::unordered_map condVarMap; //!< A map from a conditional variable's address to a vector of threads waiting on it std::vector> tlsPages; //!< A vector of all allocated TLS pages - /** * This is used as the output for functions that return created kernel objects * @tparam objectClass The class of the kernel object @@ -93,7 +93,7 @@ namespace skyline::kernel::type { * @param stackSize The size of the stack * @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process */ - KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize, std::shared_ptr& tlsMemory); + KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, u64 stackBase, u64 stackSize, std::shared_ptr &tlsMemory); /** * Close the file descriptor to the process's memory @@ -150,12 +150,6 @@ namespace skyline::kernel::type { */ void WriteMemory(void *source, u64 offset, size_t size) const; - /** - * @brief Returns the FD of the memory for the process - * @return The FD of the memory for the process - */ - int GetMemoryFd() const; - /** * @brief Map a chunk of process local memory (private memory) * @param address The address to map to (Can be 0 if address doesn't matter) @@ -258,6 +252,8 @@ namespace skyline::kernel::type { /** * @brief This resets the object to an unsignalled state */ - void ResetSignal(); + inline void ResetSignal() { + signalled = false; + } }; } diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index 096d1130..6fb21d1d 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -7,7 +7,7 @@ namespace skyline::kernel::type { u64 MapSharedFunc(u64 address, size_t size, u64 perms, u64 fd) { - 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) + return reinterpret_cast(mmap(reinterpret_cast(address), size, static_cast(perms), MAP_SHARED | ((address) ? MAP_FIXED : 0), static_cast(fd), 0)); } KSharedMemory::KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::Type type) : type(type), KObject(state, KType::KSharedMemory) { @@ -15,7 +15,7 @@ namespace skyline::kernel::type { if (fd < 0) throw exception("An error occurred while creating shared memory: {}", fd); address = reinterpret_cast(mmap(reinterpret_cast(address), size, permission.Get(), MAP_SHARED | ((address) ? MAP_FIXED : 0), static_cast(fd), 0)); - if (address == reinterpret_cast(MAP_FAILED)) // NOLINT(hicpp-signed-bitwise) + if (address == reinterpret_cast(MAP_FAILED)) throw exception("An occurred while mapping shared region: {}", strerror(errno)); kernel = {address, size, permission}; } @@ -25,9 +25,8 @@ namespace skyline::kernel::type { fregs.x0 = address; fregs.x1 = size; fregs.x2 = static_cast(permission.Get()); - fregs.x3 = static_cast(MAP_SHARED | ((address) ? MAP_FIXED : 0)); // NOLINT(hicpp-signed-bitwise) + fregs.x3 = static_cast(MAP_SHARED | ((address) ? MAP_FIXED : 0)); fregs.x4 = static_cast(fd); - fregs.x4 = static_cast(-1); fregs.x8 = __NR_mmap; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, state.thread->pid); if (fregs.x0 < 0) @@ -51,7 +50,8 @@ namespace skyline::kernel::type { } if (kernel.valid()) UnmapSharedFunc(kernel.address, kernel.size); - } catch (const std::exception &) {} + } catch (const std::exception &) { + } close(fd); } diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h index 8e4a0247..92b8665b 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h @@ -60,7 +60,7 @@ namespace skyline::kernel::type { * @param permission The new permissions to be set for the memory * @param kernel Set the permissions for the kernel rather than the guest */ - void UpdatePermission(memory::Permission permission, bool host=0); + void UpdatePermission(memory::Permission permission, bool host = 0); /** * @brief Creates a MemoryInfo struct from the current instance diff --git a/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp b/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp deleted file mode 100644 index b623c746..00000000 --- a/app/src/main/cpp/skyline/kernel/types/KSyncObject.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "KSyncObject.h" -#include - -namespace skyline::kernel::type { - KSyncObject::KSyncObject(const skyline::DeviceState &state, skyline::kernel::type::KType type) : KObject(state, type) {} - - KSyncObject::threadInfo::threadInfo(pid_t process, u32 index) : process(process), index(index) {} - - void KSyncObject::Signal() { - for (const auto &info : waitThreads) { - state.ctx->registers.w1 = info.index; - state.process->threadMap.at(info.process)->status = KThread::Status::Runnable; - } - waitThreads.clear(); - } -} diff --git a/app/src/main/cpp/skyline/kernel/types/KSyncObject.h b/app/src/main/cpp/skyline/kernel/types/KSyncObject.h index c35c5472..24f5b46f 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSyncObject.h +++ b/app/src/main/cpp/skyline/kernel/types/KSyncObject.h @@ -9,27 +9,19 @@ namespace skyline::kernel::type { */ class KSyncObject : public KObject { public: - bool signalled{false}; //!< If the current object is signalled (Used by KEvent as it stays signalled till svcClearEvent or svcClearSignal is called) - /** - * @brief This holds information about a specific thread that's waiting on this object - */ - struct threadInfo { - pid_t process; //!< The PID of the waiting thread - u32 index; //!< The index of the object in the wait list - - threadInfo(pid_t process, u32 index); - }; - std::vector waitThreads; //!< A vector of threads waiting on this object + std::atomic signalled{false}; //!< If the current object is signalled (Used as object stays signalled till the signal is consumed) /** * @param state The state of the device * @param type The type of the object */ - KSyncObject(const DeviceState &state, skyline::kernel::type::KType type); + KSyncObject(const DeviceState &state, skyline::kernel::type::KType type) : KObject(state, type) {}; /** * @brief A function for calling when a particular KSyncObject is signalled */ - virtual void Signal(); + virtual void Signal() { + signalled = true; + } }; } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index e8fe5f2a..467d32be 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -4,8 +4,8 @@ #include namespace skyline::kernel::type { - KThread::KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr& tlsMemory) : handle(handle), pid(self_pid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state, - KType::KThread) { + KThread::KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr &tlsMemory) : handle(handle), pid(self_pid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state, + KType::KThread) { UpdatePriority(priority); } @@ -14,7 +14,7 @@ namespace skyline::kernel::type { } void KThread::Start() { - if(status == Status::Created) { + if (status == Status::Created) { if (pid == parent->pid) parent->status = KProcess::Status::Started; status = Status::Running; @@ -23,9 +23,8 @@ namespace skyline::kernel::type { } void KThread::Kill() { - if(status != Status::Dead) { + if (status != Status::Dead) { status = Status::Dead; - kill(pid, SIGKILL); Signal(); } } @@ -36,30 +35,4 @@ namespace skyline::kernel::type { if (setpriority(PRIO_PROCESS, static_cast(pid), liPriority) == -1) throw exception("Couldn't set process priority to {} for PID: {}", liPriority, pid); } - - void KThread::Sleep() { - if (status == Status::Running) { - status = Status::Sleeping; - timeout = 0; - } - } - - void KThread::WakeUp() { - if (status == Status::Sleeping) - status = Status::Runnable; - } - - void KThread::ClearWaitObjects() { - for (auto &object : waitObjects) { - auto iter = object->waitThreads.begin(); - while (iter != object->waitThreads.end()) { - if (iter->process == pid) { - object->waitThreads.erase(iter); - break; - } - iter++; - } - } - waitObjects.clear(); - } } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index 374f678d..00401a3d 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -17,16 +17,9 @@ namespace skyline::kernel::type { enum class Status { Created, //!< The thread has been created but has not been started yet Running, //!< The thread is running currently - Sleeping, //!< The thread is sleeping due to svcSleepThread - WaitSync, //!< The thread is waiting for a KSyncObject signal - WaitMutex, //!< The thread is waiting on a Mutex - WaitCondVar, //!< The thread is waiting on a Conditional Variable - Runnable, //!< The thread is ready to run after waiting Dead //!< The thread is dead and not running } status = Status::Created; //!< The state of the thread std::shared_ptr ctxMemory; //!< The KSharedMemory of the shared memory allocated by the guest process TLS - std::vector> waitObjects; //!< A vector holding the objects this thread is waiting for - u64 timeout{}; //!< The end of a timeout for svcWaitSynchronization or the end of the sleep period for svcSleepThread handle_t handle; // The handle of the object in the handle table pid_t pid; //!< The PID of the current thread (As in kernel PID and not PGID [In short, Linux implements threads as processes that share a lot of stuff at the kernel level]) u64 stackTop; //!< The top of the stack (Where it starts growing downwards from) @@ -45,7 +38,7 @@ namespace skyline::kernel::type { * @param parent The parent process of this thread * @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process */ - KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr& tlsMemory); + KThread(const DeviceState &state, handle_t handle, pid_t self_pid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr &tlsMemory); /** * @brief Kills the thread and deallocates the memory allocated for stack. @@ -62,21 +55,11 @@ namespace skyline::kernel::type { */ void Kill(); - /** - * @brief This causes this thread to sleep indefinitely (no-op if thread is already sleeping) - */ - void Sleep(); - /** * @brief This wakes up the thread from it's sleep (no-op if thread is already awake) */ void WakeUp(); - /** - * @brief This clears all the objects in the waitObjects vector - */ - void ClearWaitObjects(); - /** * @brief Update the priority level for the process. * @details Set the priority of the current thread to `priority` using setpriority [https://linux.die.net/man/3/setpriority]. We rescale the priority from Nintendo scale to that of Android. diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp index 2b2300f8..6e6b3b47 100644 --- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.cpp @@ -5,7 +5,7 @@ namespace skyline::kernel::type { u64 MapTransferFunc(u64 address, size_t size, u64 perms) { - return reinterpret_cast(mmap(reinterpret_cast(address), size, static_cast(perms), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0)); // NOLINT(hicpp-signed-bitwise) + return reinterpret_cast(mmap(reinterpret_cast(address), size, static_cast(perms), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0)); } KTransferMemory::KTransferMemory(const DeviceState &state, pid_t pid, u64 address, size_t size, const memory::Permission permission) : owner(pid), cSize(size), permission(permission), KObject(state, KType::KTransferMemory) { @@ -14,7 +14,7 @@ namespace skyline::kernel::type { fregs.x0 = address; fregs.x1 = size; fregs.x2 = static_cast(permission.Get()); - fregs.x3 = static_cast(MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0)); // NOLINT(hicpp-signed-bitwise) + fregs.x3 = static_cast(MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0)); fregs.x4 = static_cast(-1); fregs.x8 = __NR_mmap; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, pid); @@ -22,28 +22,23 @@ namespace skyline::kernel::type { throw exception("An error occurred while mapping shared region in child process"); cAddress = fregs.x0; } else { - address = MapTransferFunc(address, size, static_cast(permission.Get())); + address = reinterpret_cast(mmap(reinterpret_cast(address), size, permission.Get(), MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0), -1, 0)); if (reinterpret_cast(address) == MAP_FAILED) throw exception("An error occurred while mapping transfer memory in kernel"); cAddress = address; } } - u64 UnmapTransferFunc(u64 address, size_t size) { - return static_cast(munmap(reinterpret_cast(address), size)); - } - u64 KTransferMemory::Transfer(pid_t process, u64 address, u64 size) { if (process) { Registers fregs{}; fregs.x0 = address; fregs.x1 = size; fregs.x2 = static_cast(permission.Get()); - fregs.x3 = static_cast(MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0)); // NOLINT(hicpp-signed-bitwise) + fregs.x3 = static_cast(MAP_ANONYMOUS | MAP_PRIVATE | ((address) ? MAP_FIXED : 0)); fregs.x4 = static_cast(-1); fregs.x8 = __NR_mmap; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, process); - // state.nce->ExecuteFunction(reinterpret_cast(MapTransferFunc), fregs, process); if (fregs.x0 < 0) throw exception("An error occurred while mapping transfer memory in child process"); address = fregs.x0; @@ -65,11 +60,10 @@ namespace skyline::kernel::type { fregs.x1 = size; fregs.x8 = __NR_munmap; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, owner); - // state.nce->ExecuteFunction(reinterpret_cast(UnmapTransferFunc), fregs, owner); if (fregs.x0 < 0) throw exception("An error occurred while unmapping transfer memory in child process"); } else { - if (reinterpret_cast(UnmapTransferFunc(address, size)) == MAP_FAILED) + if (reinterpret_cast(munmap(reinterpret_cast(address), size)) == MAP_FAILED) throw exception("An error occurred while unmapping transfer memory in kernel"); } owner = process; @@ -96,14 +90,15 @@ namespace skyline::kernel::type { KTransferMemory::~KTransferMemory() { if (owner) { try { - if(state.process) { + if (state.process) { Registers fregs{}; fregs.x0 = cAddress; fregs.x1 = cSize; state.nce->ExecuteFunction(ThreadCall::Syscall, fregs, state.process->pid); } - } catch (const std::exception &) {} + } catch (const std::exception &) { + } } else - UnmapTransferFunc(cAddress, cSize); + munmap(reinterpret_cast(cAddress), cSize); } }; diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index d22e49ac..6158b78f 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -1,4 +1,5 @@ #include +#include #include "os.h" #include "jvm.h" #include "nce/guest.h" @@ -6,14 +7,17 @@ #include "kernel/svc.h" extern bool Halt; -extern skyline::Mutex jniMtx; +extern skyline::GroupMutex jniMtx; namespace skyline { void NCE::KernelThread(pid_t thread) { try { state.thread = state.process->threadMap.at(thread); state.ctx = reinterpret_cast(state.thread->ctxMemory->guest.address); - while (!Halt) { + while (true) { + std::lock_guard jniGd(jniMtx); + if (Halt) + break; if (state.ctx->state == ThreadState::WaitKernel) { const u16 svc = static_cast(state.ctx->commandId); try { @@ -29,6 +33,7 @@ namespace skyline { } else if (state.ctx->state == ThreadState::GuestCrash) { state.logger->Warn("Thread with PID {} has crashed due to signal: {}", thread, strsignal(state.ctx->commandId)); ThreadTrace(); + state.ctx->state = ThreadState::WaitRun; break; } } @@ -37,7 +42,12 @@ namespace skyline { } catch (...) { state.logger->Error("An unknown exception has occurred"); } - state.os->KillThread(thread); + if (thread == state.process->pid) { + jniMtx.lock(GroupMutex::Group::Group2); + state.os->KillThread(thread); + Halt = true; + jniMtx.unlock(); + } } NCE::NCE(DeviceState &state) : state(state) {} @@ -48,15 +58,25 @@ namespace skyline { } void NCE::Execute() { - while (!Halt && state.os->process) { + while (true) { std::lock_guard jniGd(jniMtx); + if (Halt) + break; state.os->serviceManager.Loop(); state.gpu->Loop(); } - Halt = false; + jniMtx.lock(GroupMutex::Group::Group2); + Halt = true; + jniMtx.unlock(); } - void ExecuteFunctionCtx(ThreadCall call, Registers &funcRegs, ThreadContext *ctx) { + /** + * This function will not work if optimizations are enabled as ThreadContext isn't volatile + * and due to that is not read on every iteration of the while loop. + * However, making ThreadContext or parts of it volatile slows down the applications as a whole. + * So, we opted to use the hacky solution and disable optimizations for this single function. + */ + void ExecuteFunctionCtx(ThreadCall call, Registers &funcRegs, ThreadContext *ctx) __attribute__ ((optnone)) { ctx->commandId = static_cast(call); Registers registers = ctx->registers; while (ctx->state != ThreadState::WaitInit && ctx->state != ThreadState::WaitKernel); @@ -72,10 +92,13 @@ namespace skyline { } void NCE::ExecuteFunction(ThreadCall call, Registers &funcRegs, pid_t pid) { - ExecuteFunctionCtx(call, funcRegs, reinterpret_cast(state.process->threadMap.at(pid)->ctxMemory->kernel.address)); + if (state.process->status != kernel::type::KProcess::Status::Exiting) + ExecuteFunctionCtx(call, funcRegs, reinterpret_cast(state.process->threadMap.at(pid)->ctxMemory->kernel.address)); + else + throw std::out_of_range("The KProcess object is missing"); } - void NCE::WaitThreadInit(std::shared_ptr &thread) { + void NCE::WaitThreadInit(std::shared_ptr &thread) __attribute__ ((optnone)) { auto ctx = reinterpret_cast(thread->ctxMemory->kernel.address); while (ctx->state == ThreadState::NotReady); } @@ -98,7 +121,7 @@ namespace skyline { ctx = ctx ? ctx : state.ctx; if (numHist) { std::vector instrs(numHist); - u64 size = (sizeof(u32) * numHist); + u64 size = sizeof(u32) * numHist; u64 offset = ctx->pc - size + (2 * sizeof(u32)); state.process->ReadMemory(instrs.data(), offset, size); for (auto &instr : instrs) { @@ -111,17 +134,22 @@ namespace skyline { offset += sizeof(u32); } } + if (ctx->faultAddress) + regStr += fmt::format("\nFault Address: 0x{:X}", ctx->faultAddress); + if (ctx->sp) + regStr += fmt::format("\nStack Pointer: 0x{:X}", ctx->sp); for (u16 index = 0; index < constant::NumRegs - 1; index += 2) { regStr += fmt::format("\nX{}: 0x{:X}, X{}: 0x{:X}", index, ctx->registers.regs[index], index + 1, ctx->registers.regs[index + 1]); } if (numHist) { state.logger->Debug("Process Trace:{}", trace); - state.logger->Debug("Raw Instructions: 0x{}\nCPU Context:{}", raw, regStr); + state.logger->Debug("Raw Instructions: 0x{}", raw); + state.logger->Debug("CPU Context:{}", regStr); } else - state.logger->Warn("CPU Context:{}", regStr); + state.logger->Debug("CPU Context:{}", regStr); } - const std::array cntpctEl0X0 = { + const std::array cntpctEl0X0 = { 0xA9BF0BE1, // STP X1, X2, [SP, #-16]! 0x3C9F0FE0, // STR Q0, [SP, #-16]! 0x3C9F0FE1, // STR Q1, [SP, #-16]! @@ -138,10 +166,11 @@ namespace skyline { 0x9E790000, // FCVTZU X0, D0 0x3CC107E2, // LDR Q2, [SP], #16 0x3CC107E1, // LDR Q1, [SP], #16 + 0x3CC107E0, // LDR Q0, [SP], #16 0xA8C10BE1, // LDP X1, X2, [SP], #16 }; - const std::array cntpctEl0X1 = { + const std::array cntpctEl0X1 = { 0xA9BF0BE0, // STP X0, X2, [SP, #-16]! 0x3C9F0FE0, // STR Q0, [SP, #-16]! 0x3C9F0FE1, // STR Q1, [SP, #-16]! @@ -158,10 +187,11 @@ namespace skyline { 0x9E790001, // FCVTZU X0, D0 0x3CC107E2, // LDR Q2, [SP], #16 0x3CC107E1, // LDR Q1, [SP], #16 + 0x3CC107E0, // LDR Q0, [SP], #16 0xA8C10BE0, // LDP X0, X2, [SP], #16 }; - std::array cntpctEl0Xn = { + std::array cntpctEl0Xn = { 0xA9BF07E0, // STP X0, X1, [SP, #-16]! 0x3C9F0FE0, // STR Q0, [SP, #-16]! 0x3C9F0FE1, // STR Q1, [SP, #-16]! @@ -178,6 +208,7 @@ namespace skyline { 0x00000000, // FCVTZU Xn, D0 (Set at runtime) 0x3CC107E2, // LDR Q2, [SP], #16 0x3CC107E1, // LDR Q1, [SP], #16 + 0x3CC107E0, // LDR Q0, [SP], #16 0xA8C107E0, // LDP X0, X1, [SP], #16 }; @@ -268,9 +299,6 @@ namespace skyline { patch.push_back(ldrX0); patch.push_back(bret.raw); } else if (instrMrs->srcReg == constant::CntpctEl0) { - instr::Mrs mrs(constant::CntvctEl0, regs::X(instrMrs->destReg)); - *address = mrs.raw; - /* instr::B bjunc(offset); if (instrMrs->destReg == 0) offset += cntpctEl0X0.size() * sizeof(u32); @@ -294,7 +322,6 @@ namespace skyline { patch.push_back(instr); } patch.push_back(bret.raw); - */ } else if (instrMrs->srcReg == constant::CntfrqEl0) { instr::B bjunc(offset); auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), constant::TegraX1Freq); @@ -311,6 +338,7 @@ namespace skyline { offset -= sizeof(u32); patchOffset -= sizeof(u32); } + patch.resize(patch.size() + PAGE_SIZE - 1 & ~(PAGE_SIZE - 1), 0x0); return patch; } } diff --git a/app/src/main/cpp/skyline/nce.h b/app/src/main/cpp/skyline/nce.h index 83012756..cf5e4c7f 100644 --- a/app/src/main/cpp/skyline/nce.h +++ b/app/src/main/cpp/skyline/nce.h @@ -42,7 +42,7 @@ namespace skyline { * @param funcRegs A set of registers to run the function * @param thread The thread to execute the function on */ - void ExecuteFunction(ThreadCall call, Registers &funcRegs, std::shared_ptr& thread); + void ExecuteFunction(ThreadCall call, Registers &funcRegs, std::shared_ptr &thread); /** * @brief Execute any arbitrary function on a particular child process @@ -56,7 +56,7 @@ namespace skyline { * @brief Waits till a thread is ready to execute commands * @param thread The KThread to wait for initialization */ - void WaitThreadInit(std::shared_ptr& thread); + void WaitThreadInit(std::shared_ptr &thread); /** * @brief Sets the X0 and X1 registers in a thread and starts it and it's kernel thread diff --git a/app/src/main/cpp/skyline/nce/guest.cpp b/app/src/main/cpp/skyline/nce/guest.cpp index 8ecbb123..6d019012 100644 --- a/app/src/main/cpp/skyline/nce/guest.cpp +++ b/app/src/main/cpp/skyline/nce/guest.cpp @@ -1,6 +1,7 @@ #include -#include -#include +#include +#include +#include // This is used implicitly #include "guest_common.h" #define FORCE_INLINE __attribute__((always_inline)) inline // NOLINT(cppcoreguidelines-macro-usage) @@ -95,11 +96,71 @@ namespace skyline::guest { asm("MRS %0, TPIDR_EL0":"=r"(ctx)); ctx->pc = pc; ctx->commandId = svc; + if (svc == 0xB) { // svcSleepThread + switch (ctx->registers.x0) { + case 0: + case 1: + case 2: { + asm("MOV X0, XZR\n\t" + "MOV X1, XZR\n\t" + "MOV X2, XZR\n\t" + "MOV X3, XZR\n\t" + "MOV X4, XZR\n\t" + "MOV X5, XZR\n\t" + "MOV X8, #124\n\t" // __NR_sched_yield + "STR LR, [SP, #-16]!\n\t" + "MOV LR, SP\n\t" + "SVC #0\n\t" + "MOV SP, LR\n\t" + "LDR LR, [SP], #16":: : "x0", "x1", "x2", "x3", "x4", "x5", "x8"); + break; + } + default: { + struct timespec spec = { + .tv_sec = static_cast(ctx->registers.x0 / 1000000000), + .tv_nsec = static_cast(ctx->registers.x0 % 1000000000) + }; + volatile register __unused timespec *specPtr asm("x0") = &spec; + asm("MOV X1, XZR\n\t" + "MOV X2, XZR\n\t" + "MOV X3, XZR\n\t" + "MOV X4, XZR\n\t" + "MOV X5, XZR\n\t" + "MOV X8, #101\n\t" // __NR_nanosleep + "STR LR, [SP, #-16]!\n\t" + "MOV LR, SP\n\t" + "SVC #0\n\t" + "MOV SP, LR\n\t" + "LDR LR, [SP], #16":: : "x0", "x1", "x2", "x3", "x4", "x5", "x8"); + } + } + return; + } else if (svc == 0x1E) { + asm("STP X1, X2, [SP, #-16]!\n\t" + "STR Q0, [SP, #-16]!\n\t" + "STR Q1, [SP, #-16]!\n\t" + "STR Q2, [SP, #-16]!\n\t" + "MRS X1, CNTFRQ_EL0\n\t" + "MRS X2, CNTVCT_EL0\n\t" + "UCVTF D0, X0\n\t" + "MOV X1, 87411174408192\n\t" + "MOVK X1, 0x4172, LSL 48\n\t" + "FMOV D2, X1\n\t" + "UCVTF D1, X1\n\t" + "FDIV D0, D0, D2\n\t" + "FMUL D0, D0, D1\n\t" + "FCVTZU %0, D0\n\t" + "LDR Q2, [SP], #16\n\t" + "LDR Q1, [SP], #16\n\t" + "LDR Q0, [SP], #16\n\t" + "LDP X1, X2, [SP], #16"::"r"(ctx->registers.x0)); + return; + } while (true) { ctx->state = ThreadState::WaitKernel; while (ctx->state == ThreadState::WaitKernel); if (ctx->state == ThreadState::WaitRun) - return; + break; else if (ctx->state == ThreadState::WaitFunc) { if (ctx->commandId == static_cast(ThreadCall::Syscall)) { saveCtxStack(); @@ -114,17 +175,23 @@ namespace skyline::guest { } } } + ctx->state = ThreadState::Running; } void signalHandler(int signal, siginfo_t *info, ucontext_t *ucontext) { volatile ThreadContext *ctx; asm("MRS %0, TPIDR_EL0":"=r"(ctx)); - for (u8 index = 0; index < constant::NumRegs; index++) + for (u8 index = 0; index < 30; index++) ctx->registers.regs[index] = ucontext->uc_mcontext.regs[index]; ctx->pc = ucontext->uc_mcontext.pc; ctx->commandId = static_cast(signal); - ctx->state = ThreadState::GuestCrash; - exit(0); + ctx->faultAddress = ucontext->uc_mcontext.fault_address; + ctx->sp = ucontext->uc_mcontext.sp; + while (true) { + ctx->state = ThreadState::GuestCrash; + if (ctx->state == ThreadState::WaitRun) + exit(0); + } } void entry(u64 address) { diff --git a/app/src/main/cpp/skyline/nce/guest.h b/app/src/main/cpp/skyline/nce/guest.h index be77f0ab..0479fc6b 100644 --- a/app/src/main/cpp/skyline/nce/guest.h +++ b/app/src/main/cpp/skyline/nce/guest.h @@ -4,10 +4,17 @@ namespace skyline { namespace guest { constexpr size_t saveCtxSize = 20 * sizeof(u32); constexpr size_t loadCtxSize = 20 * sizeof(u32); - constexpr size_t svcHandlerSize = 200 * sizeof(u32); + #ifdef NDEBUG + constexpr size_t svcHandlerSize = 150 * sizeof(u32); + #else + constexpr size_t svcHandlerSize = 250 * sizeof(u32); + #endif + void entry(u64 address); + extern "C" void saveCtx(void); extern "C" void loadCtx(void); + void svcHandler(u64 pc, u32 svc); } } diff --git a/app/src/main/cpp/skyline/nce/guest_common.h b/app/src/main/cpp/skyline/nce/guest_common.h index 09fd4de2..c9a9eaf0 100644 --- a/app/src/main/cpp/skyline/nce/guest_common.h +++ b/app/src/main/cpp/skyline/nce/guest_common.h @@ -121,12 +121,12 @@ namespace skyline { * @brief This enumeration is used to convey the state of a thread to the kernel */ enum class ThreadState : u32 { - NotReady = 0, //!< The thread hasn't yet entered the entry handler - Running = 1, //!< The thread is currently executing code + NotReady = 0, //!< The thread hasn't yet entered the entry handler + Running = 1, //!< The thread is currently executing code WaitKernel = 2, //!< The thread is currently waiting on the kernel - WaitRun = 3, //!< The thread should be ready to run - WaitInit = 4, //!< The thread is waiting to be initialized - WaitFunc = 5, //!< The kernel is waiting for the thread to run a function + WaitRun = 3, //!< The thread should be ready to run + WaitInit = 4, //!< The thread is waiting to be initialized + WaitFunc = 5, //!< The kernel is waiting for the thread to run a function GuestCrash = 6, //!< This is a notification to the kernel that the guest has crashed }; @@ -146,5 +146,7 @@ namespace skyline { u64 pc; //!< The program counter register on the guest Registers registers; //!< The general purpose registers on the guest u64 tpidrroEl0; //!< The value for TPIDRRO_EL0 for the current thread + u64 faultAddress; //!< The address a fault has occurred at during guest crash + u64 sp; //!< The current location of the stack pointer set during guest crash }; } diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index de8a7638..bc7fe38d 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -19,7 +19,7 @@ namespace skyline::kernel { std::shared_ptr OS::CreateProcess(u64 entry, u64 argument, size_t stackSize) { madvise(reinterpret_cast(constant::BaseAddr), constant::BaseEnd, MADV_DONTFORK); - auto *stack = static_cast(mmap(nullptr, stackSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS | MAP_STACK, -1, 0)); // NOLINT(hicpp-signed-bitwise) + auto *stack = static_cast(mmap(nullptr, stackSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS | MAP_STACK, -1, 0)); madvise(stack, reinterpret_cast(stack) + stackSize, MADV_DOFORK); if (stack == MAP_FAILED) throw exception("Failed to allocate stack memory"); @@ -27,12 +27,13 @@ namespace skyline::kernel { munmap(stack, stackSize); throw exception("Failed to create guard pages"); } - auto tlsMem = std::make_shared(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission(true, true, 0), memory::Type::Reserved); // NOLINT(hicpp-signed-bitwise) + auto tlsMem = std::make_shared(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission(true, true, false), memory::Type::Reserved); tlsMem->guest = tlsMem->kernel; madvise(reinterpret_cast(tlsMem->guest.address), tlsMem->guest.size, MADV_DOFORK); - pid_t pid = clone(reinterpret_cast(&guest::entry), stack + stackSize, CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast(entry), nullptr, reinterpret_cast(tlsMem->guest.address)); // NOLINT(hicpp-signed-bitwise) + pid_t pid = clone(reinterpret_cast(&guest::entry), stack + stackSize, CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast(entry), nullptr, reinterpret_cast(tlsMem->guest.address)); if (pid == -1) throw exception("Call to clone() has failed: {}", strerror(errno)); + state.logger->Debug("Successfully created process with PID: {}", pid); process = std::make_shared(state, pid, argument, reinterpret_cast(stack), stackSize, tlsMem); state.logger->Debug("Successfully created process with PID: {}", pid); return process; @@ -41,14 +42,11 @@ namespace skyline::kernel { void OS::KillThread(pid_t pid) { if (process->pid == pid) { state.logger->Debug("Killing process with PID: {}", pid); - for (auto&[key, value]: process->threadMap) { - value->Kill(); - } - process.reset(); + for (auto &thread: process->threadMap) + thread.second->Kill(); } else { state.logger->Debug("Killing thread with TID: {}", pid); process->threadMap.at(pid)->Kill(); - process->threadMap.erase(pid); } } } diff --git a/app/src/main/cpp/skyline/os.h b/app/src/main/cpp/skyline/os.h index 2e1a49e3..d318fdd1 100644 --- a/app/src/main/cpp/skyline/os.h +++ b/app/src/main/cpp/skyline/os.h @@ -26,7 +26,7 @@ namespace skyline::kernel { * @param settings An instance of the Settings class * @param window The ANativeWindow object to draw the screen to */ - OS(std::shared_ptr& jvmManager, std::shared_ptr &logger, std::shared_ptr &settings); + OS(std::shared_ptr &jvmManager, std::shared_ptr &logger, std::shared_ptr &settings); /** * @brief Execute a particular ROM file. This launches the main process and calls the NCE class to handle execution. diff --git a/app/src/main/cpp/skyline/services/am/applet.cpp b/app/src/main/cpp/skyline/services/am/applet.cpp index eac044ed..271c16e8 100644 --- a/app/src/main/cpp/skyline/services/am/applet.cpp +++ b/app/src/main/cpp/skyline/services/am/applet.cpp @@ -10,7 +10,7 @@ namespace skyline::service::am { manager.RegisterService(SRVREG(IApplicationProxy), session, response); } - appletAE::appletAE(const DeviceState& state, ServiceManager& manager) : BaseService(state, manager, false, Service::am_appletAE, { + appletAE::appletAE(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_appletAE, { {0x64, SFUNC(appletAE::OpenSystemAppletProxy)}, {0xC8, SFUNC(appletAE::OpenLibraryAppletProxy)}, {0xC9, SFUNC(appletAE::OpenLibraryAppletProxy)}, @@ -26,11 +26,11 @@ namespace skyline::service::am { manager.RegisterService(SRVREG(IApplicationProxy), session, response); } - void appletAE::OpenOverlayAppletProxy(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response) { + void appletAE::OpenOverlayAppletProxy(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { manager.RegisterService(SRVREG(IOverlayAppletProxy), session, response); } - void appletAE::OpenSystemAppletProxy(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response) { + void appletAE::OpenSystemAppletProxy(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { manager.RegisterService(SRVREG(ISystemAppletProxy), session, response); } @@ -64,7 +64,7 @@ namespace skyline::service::am { manager.RegisterService(SRVREG(IDebugFunctions), session, response); } - void BaseProxy::GetAppletCommonFunctions(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response) { + void BaseProxy::GetAppletCommonFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { manager.RegisterService(SRVREG(IAppletCommonFunctions), session, response); } @@ -93,7 +93,7 @@ namespace skyline::service::am { {0x3E8, SFUNC(BaseProxy::GetDebugFunctions)} }) {} - ISystemAppletProxy::ISystemAppletProxy(const DeviceState& state, ServiceManager& manager) : BaseProxy(state, manager, Service::am_ISystemAppletProxy, { + ISystemAppletProxy::ISystemAppletProxy(const DeviceState &state, ServiceManager &manager) : BaseProxy(state, manager, Service::am_ISystemAppletProxy, { {0x0, SFUNC(BaseProxy::GetCommonStateGetter)}, {0x1, SFUNC(BaseProxy::GetSelfController)}, {0x2, SFUNC(BaseProxy::GetWindowController)}, @@ -104,7 +104,7 @@ namespace skyline::service::am { {0x3E8, SFUNC(BaseProxy::GetDebugFunctions)} }) {} - IOverlayAppletProxy::IOverlayAppletProxy(const DeviceState& state, ServiceManager& manager) : BaseProxy(state, manager, Service::am_IOverlayAppletProxy, { + IOverlayAppletProxy::IOverlayAppletProxy(const DeviceState &state, ServiceManager &manager) : BaseProxy(state, manager, Service::am_IOverlayAppletProxy, { {0x0, SFUNC(BaseProxy::GetCommonStateGetter)}, {0x1, SFUNC(BaseProxy::GetSelfController)}, {0x2, SFUNC(BaseProxy::GetWindowController)}, diff --git a/app/src/main/cpp/skyline/services/am/applet.h b/app/src/main/cpp/skyline/services/am/applet.h index d4f22e0d..416079a4 100644 --- a/app/src/main/cpp/skyline/services/am/applet.h +++ b/app/src/main/cpp/skyline/services/am/applet.h @@ -37,12 +37,12 @@ namespace skyline::service::am { /** * @brief This returns #IOverlayAppletProxy (https://switchbrew.org/wiki/Applet_Manager_services#OpenOverlayAppletProxy) */ - void OpenOverlayAppletProxy(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response); + void OpenOverlayAppletProxy(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** * @brief This returns #ISystemAppletProxy (https://switchbrew.org/wiki/Applet_Manager_services#OpenSystemAppletProxy) */ - void OpenSystemAppletProxy(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response); + void OpenSystemAppletProxy(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); }; /** @@ -90,7 +90,7 @@ namespace skyline::service::am { /** * @brief This returns #IAppletCommonFunctions (https://switchbrew.org/wiki/Applet_Manager_services#IAppletCommonFunctions) */ - void GetAppletCommonFunctions(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response); + void GetAppletCommonFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); }; /** @@ -111,7 +111,7 @@ namespace skyline::service::am { */ class IOverlayAppletProxy : public BaseProxy { public: - IOverlayAppletProxy(const DeviceState& state, ServiceManager& manager); + IOverlayAppletProxy(const DeviceState &state, ServiceManager &manager); }; /** @@ -119,7 +119,7 @@ namespace skyline::service::am { */ class ISystemAppletProxy : public BaseProxy { public: - ISystemAppletProxy(const DeviceState& state, ServiceManager& manager); + ISystemAppletProxy(const DeviceState &state, ServiceManager &manager); }; /** diff --git a/app/src/main/cpp/skyline/services/am/appletController.cpp b/app/src/main/cpp/skyline/services/am/appletController.cpp index eea63c32..5d868a0c 100644 --- a/app/src/main/cpp/skyline/services/am/appletController.cpp +++ b/app/src/main/cpp/skyline/services/am/appletController.cpp @@ -46,11 +46,11 @@ namespace skyline::service::am { response.Push(static_cast(operationMode)); } - void ICommonStateGetter::GetDefaultDisplayResolution(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response) { + void ICommonStateGetter::GetDefaultDisplayResolution(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { if (operationMode == OperationMode::Handheld) { response.Push(constant::HandheldResolutionW); response.Push(constant::HandheldResolutionH); - } else if (operationMode == OperationMode::Docked) { + } else if (operationMode == OperationMode::Docked) { response.Push(constant::DockedResolutionW); response.Push(constant::DockedResolutionH); } @@ -111,6 +111,6 @@ namespace skyline::service::am { IDebugFunctions::IDebugFunctions(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IDebugFunctions, { }) {} - IAppletCommonFunctions::IAppletCommonFunctions(const DeviceState& state, ServiceManager& manager) : BaseService(state, manager, false, Service::am_IAppletCommonFunctions, { + IAppletCommonFunctions::IAppletCommonFunctions(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IAppletCommonFunctions, { }) {} } diff --git a/app/src/main/cpp/skyline/services/am/appletController.h b/app/src/main/cpp/skyline/services/am/appletController.h index e24a7c3e..5bf6528e 100644 --- a/app/src/main/cpp/skyline/services/am/appletController.h +++ b/app/src/main/cpp/skyline/services/am/appletController.h @@ -76,7 +76,7 @@ namespace skyline::service::am { /** * @brief This returns the current display width and height in two u32s (https://switchbrew.org/wiki/Applet_Manager_services#GetDefaultDisplayResolution) */ - void GetDefaultDisplayResolution(type::KSession& session, ipc::IpcRequest& request, ipc::IpcResponse& response); + void GetDefaultDisplayResolution(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); }; /** @@ -180,6 +180,6 @@ namespace skyline::service::am { */ class IAppletCommonFunctions : public BaseService { public: - IAppletCommonFunctions(const DeviceState& state, ServiceManager& manager); + IAppletCommonFunctions(const DeviceState &state, ServiceManager &manager); }; } diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index 8984a5f8..989ba9e7 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -17,7 +17,7 @@ namespace skyline::service { ServiceManager::ServiceManager(const DeviceState &state) : state(state) {} std::shared_ptr ServiceManager::GetService(const Service serviceType) { - if(serviceMap.count(serviceType)) { + if (serviceMap.count(serviceType)) { return serviceMap.at(serviceType); } std::shared_ptr serviceObj; @@ -169,7 +169,7 @@ namespace skyline::service { void ServiceManager::Loop() { std::lock_guard serviceGuard(mutex); - for (auto& [type, service] : serviceMap) + for (auto&[type, service] : serviceMap) if (service->hasLoop) service->Loop(); }