From 773ee25e5a8e4ce0a63d276469f9cafe501c7855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Wed, 25 Mar 2020 23:29:37 +0530 Subject: [PATCH] Refactor Common This refactored common by: * Moving out as many constants to class/function local scopes from being declared in `common` * Spacing out common and any function to which a constant was moved out to * Fixing comments here and there In addition, some naming inconsistencies were fixed as well. --- .idea/inspectionProfiles/Project_Default.xml | 4 +- app/src/main/cpp/main.cpp | 2 +- app/src/main/cpp/skyline/audio/common.h | 72 +- app/src/main/cpp/skyline/audio/resampler.cpp | 21 +- app/src/main/cpp/skyline/common.cpp | 28 +- app/src/main/cpp/skyline/common.h | 51 +- app/src/main/cpp/skyline/kernel/ipc.cpp | 51 +- app/src/main/cpp/skyline/kernel/ipc.h | 13 +- app/src/main/cpp/skyline/kernel/memory.h | 36 +- app/src/main/cpp/skyline/kernel/svc.cpp | 90 ++- app/src/main/cpp/skyline/kernel/svc.h | 3 +- .../cpp/skyline/kernel/types/KProcess.cpp | 16 +- .../main/cpp/skyline/kernel/types/KProcess.h | 687 +++++++++--------- .../main/cpp/skyline/kernel/types/KSession.h | 6 +- .../skyline/kernel/types/KSharedMemory.cpp | 12 +- .../cpp/skyline/kernel/types/KSharedMemory.h | 4 +- .../main/cpp/skyline/kernel/types/KThread.cpp | 10 +- .../main/cpp/skyline/kernel/types/KThread.h | 6 +- .../skyline/kernel/types/KTransferMemory.h | 2 +- app/src/main/cpp/skyline/loader/nro.cpp | 15 +- app/src/main/cpp/skyline/nce.cpp | 48 +- app/src/main/cpp/skyline/nce/guest.h | 10 +- app/src/main/cpp/skyline/os.cpp | 4 +- .../cpp/skyline/services/audio/IAudioOut.cpp | 4 +- .../services/audio/IAudioOutManager.cpp | 4 +- .../skyline/services/audio/IAudioOutManager.h | 33 +- .../audio/IAudioRenderer/IAudioRenderer.cpp | 6 +- .../audio/IAudioRenderer/IAudioRenderer.h | 215 +++--- .../audio/IAudioRenderer/revisionInfo.h | 129 ++-- .../services/audio/IAudioRenderer/voice.cpp | 14 +- .../services/audio/IAudioRenderer/voice.h | 2 +- .../services/audio/IAudioRendererManager.cpp | 8 +- .../cpp/skyline/services/common/parcel.cpp | 20 +- .../main/cpp/skyline/services/common/parcel.h | 8 +- .../skyline/services/hid/IAppletResource.cpp | 2 +- .../skyline/services/hid/IAppletResource.h | 31 +- .../services/hosbinder/IHOSBinderDriver.cpp | 16 +- .../cpp/skyline/services/hosbinder/display.h | 2 +- .../skyline/services/nvdrv/devices/nvmap.h | 4 +- .../main/cpp/skyline/services/serviceman.cpp | 10 +- .../main/cpp/skyline/services/serviceman.h | 6 +- .../services/timesrv/ITimeZoneService.cpp | 6 +- .../services/timesrv/ITimeZoneService.h | 6 +- .../visrv/IApplicationDisplayService.cpp | 2 +- 44 files changed, 906 insertions(+), 813 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index d51d0e81..8e55800a 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1621,7 +1621,7 @@ - + @@ -1644,7 +1644,7 @@ - + diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp index 716d7eda..cc008f2a 100644 --- a/app/src/main/cpp/main.cpp +++ b/app/src/main/cpp/main.cpp @@ -29,7 +29,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_GameActivity_executeRom(JNIEnv *env, std::signal(SIGABRT, signalHandler); std::signal(SIGFPE, signalHandler); - setpriority(PRIO_PROCESS, static_cast(getpid()), skyline::constant::PriorityAn.second); + setpriority(PRIO_PROCESS, static_cast(getpid()), skyline::constant::AndroidPriority.second); auto jvmManager = std::make_shared(env, instance); auto settings = std::make_shared(preferenceFd); diff --git a/app/src/main/cpp/skyline/audio/common.h b/app/src/main/cpp/skyline/audio/common.h index b393309e..4e76ab1f 100644 --- a/app/src/main/cpp/skyline/audio/common.h +++ b/app/src/main/cpp/skyline/audio/common.h @@ -3,41 +3,43 @@ #include #include -namespace skyline::audio { - /** - * @brief The available PCM stream formats - */ - enum class PcmFormat : u8 { - Invalid = 0, //!< An invalid PCM format - Int8 = 1, //!< 8 bit integer PCM - Int16 = 2, //!< 16 bit integer PCM - Int24 = 3, //!< 24 bit integer PCM - Int32 = 4, //!< 32 bit integer PCM - PcmFloat = 5, //!< Floating point PCM - AdPcm = 6 //!< Adaptive differential PCM - }; - - /** - * @brief The state of an audio track - */ - enum class AudioOutState : u8 { - Started = 0, //!< Stream is started and is playing - Stopped = 1, //!< Stream is stopped, there are no samples left to play - Paused = 2 //!< Stream is paused, some samples may not have been played yet - }; - - /** - * @brief Stores various information about pushed buffers - */ - struct BufferIdentifier { - u64 tag; //!< The tag of the buffer - u64 finalSample; //!< The final sample this buffer will be played in - bool released; //!< Whether the buffer has been released - }; - +namespace skyline { namespace constant { - constexpr int SampleRate = 48000; //!< The sampling rate to use for the oboe audio output - constexpr int ChannelCount = 2; //!< The amount of channels to use for the oboe audio output - constexpr oboe::AudioFormat PcmFormat = oboe::AudioFormat::I16; //!< The pcm data format to use for the oboe audio output + constexpr auto SampleRate = 48000; //!< The sampling rate to use for the oboe audio output + constexpr auto ChannelCount = 2; //!< The amount of channels to use for the oboe audio output + constexpr auto PcmFormat = oboe::AudioFormat::I16; //!< The pcm data format to use for the oboe audio output }; + + namespace audio { + /** + * @brief The available PCM stream formats + */ + enum class PcmFormat : u8 { + Invalid = 0, //!< An invalid PCM format + Int8 = 1, //!< 8 bit integer PCM + Int16 = 2, //!< 16 bit integer PCM + Int24 = 3, //!< 24 bit integer PCM + Int32 = 4, //!< 32 bit integer PCM + PcmFloat = 5, //!< Floating point PCM + AdPcm = 6 //!< Adaptive differential PCM + }; + + /** + * @brief The state of an audio track + */ + enum class AudioOutState : u8 { + Started = 0, //!< Stream is started and is playing + Stopped = 1, //!< Stream is stopped, there are no samples left to play + Paused = 2 //!< Stream is paused, some samples may not have been played yet + }; + + /** + * @brief Stores various information about pushed buffers + */ + struct BufferIdentifier { + u64 tag; //!< The tag of the buffer + u64 finalSample; //!< The final sample this buffer will be played in + bool released; //!< Whether the buffer has been released + }; + } } diff --git a/app/src/main/cpp/skyline/audio/resampler.cpp b/app/src/main/cpp/skyline/audio/resampler.cpp index e86a0fd8..bce079c5 100644 --- a/app/src/main/cpp/skyline/audio/resampler.cpp +++ b/app/src/main/cpp/skyline/audio/resampler.cpp @@ -10,7 +10,7 @@ namespace skyline::audio { i32 d; }; - constexpr std::array curveLut0 = {{ + constexpr std::array CurveLut0 = {{ {6600, 19426, 6722, 3}, {6479, 19424, 6845, 9}, {6359, 19419, 6968, 15}, {6239, 19412, 7093, 22}, {6121, 19403, 7219, 28}, {6004, 19391, 7345, 34}, {5888, 19377, 7472, 41}, {5773, 19361, 7600, 48}, {5659, 19342, 7728, 55}, {5546, 19321, 7857, 62}, {5434, 19298, 7987, 69}, {5323, 19273, 8118, 77}, @@ -44,7 +44,7 @@ namespace skyline::audio { {48, 7600, 19361, 5773}, {41, 7472, 19377, 5888}, {34, 7345, 19391, 6004}, {28, 7219, 19403, 6121}, {22, 7093, 19412, 6239}, {15, 6968, 19419, 6359}, {9, 6845, 19424, 6479}, {3, 6722, 19426, 6600}}}; - constexpr std::array curveLut1 = {{ + constexpr std::array CurveLut1 = {{ {-68, 32639, 69, -5}, {-200, 32630, 212, -15}, {-328, 32613, 359, -26}, {-450, 32586, 512, -36}, {-568, 32551, 669, -47}, {-680, 32507, 832, -58}, {-788, 32454, 1000, -69}, {-891, 32393, 1174, -80}, {-990, 32323, 1352, -92}, {-1084, 32244, 1536, -103}, {-1173, 32157, 1724, -115}, {-1258, 32061, 1919, -128}, @@ -78,7 +78,7 @@ namespace skyline::audio { {-80, 1174, 32393, -891}, {-69, 1000, 32454, -788}, {-58, 832, 32507, -680}, {-47, 669, 32551, -568}, {-36, 512, 32586, -450}, {-26, 359, 32613, -328}, {-15, 212, 32630, -200}, {-5, 69, 32639, -68}}}; - constexpr std::array curveLut2 = {{ + constexpr std::array CurveLut2 = {{ {3195, 26287, 3329, -32}, {3064, 26281, 3467, -34}, {2936, 26270, 3608, -38}, {2811, 26253, 3751, -42}, {2688, 26230, 3897, -46}, {2568, 26202, 4046, -50}, {2451, 26169, 4199, -54}, {2338, 26130, 4354, -58}, {2227, 26085, 4512, -63}, {2120, 26035, 4673, -67}, {2015, 25980, 4837, -72}, {1912, 25919, 5004, -76}, @@ -118,14 +118,13 @@ namespace skyline::audio { std::vector outputBuffer(static_cast(outputSize)); const std::array &lut = [step] { - if (step > 0xaaaa) { - return curveLut0; - } else if (step <= 0x8000) { - return curveLut1; - } else { - return curveLut2; - } - } (); + if (step > 0xaaaa) + return CurveLut0; + else if (step <= 0x8000) + return CurveLut1; + else + return CurveLut2; + }(); for (uint outIndex = 0, inIndex = 0; outIndex < outputBuffer.size(); outIndex += channelCount) { uint lutIndex = (fraction >> 8) << 2; diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp index 26fd5da6..da4cca8b 100644 --- a/app/src/main/cpp/skyline/common.cpp +++ b/app/src/main/cpp/skyline/common.cpp @@ -11,6 +11,7 @@ namespace skyline { for (int i = 0; i < 1000; ++i) { if (!flag.test_and_set(std::memory_order_acquire)) return; + asm volatile("yield"); } sched_yield(); @@ -21,14 +22,17 @@ namespace skyline { auto none = Group::None; constexpr u64 timeout = 100; // The timeout in ns auto end = utils::GetTimeNs() + timeout; + while (true) { if (next == group) { if (flag == group) { std::lock_guard lock(mtx); + if (flag == group) { auto groupT = group; next.compare_exchange_strong(groupT, Group::None); num++; + return; } } else { @@ -36,6 +40,7 @@ namespace skyline { } } else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) { std::lock_guard lock(mtx); + if (flag == group) { num++; return; @@ -43,6 +48,7 @@ namespace skyline { } else { next.compare_exchange_weak(none, group); } + none = Group::None; asm volatile("yield"); } @@ -50,38 +56,44 @@ namespace skyline { void GroupMutex::unlock() { std::lock_guard lock(mtx); + if (!--num) flag.exchange(next); } Settings::Settings(const int preferenceFd) { tinyxml2::XMLDocument pref; + if (pref.LoadFile(fdopen(preferenceFd, "r"))) throw exception("TinyXML2 Error: " + std::string(pref.ErrorStr())); + tinyxml2::XMLElement *elem = pref.LastChild()->FirstChild()->ToElement(); + while (elem) { switch (elem->Value()[0]) { case 's': stringMap[elem->FindAttribute("name")->Value()] = elem->GetText(); break; + case 'b': - boolMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute( - "value")->BoolValue(); + boolMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute("value")->BoolValue(); break; + case 'i': - intMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute( - "value")->IntValue(); + intMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute("value")->IntValue(); break; + default: - syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(), - elem->FindAttribute("name")->Value()); + syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(), elem->FindAttribute("name")->Value()); break; }; + if (elem->NextSibling()) elem = elem->NextSibling()->ToElement(); else break; } + pref.Clear(); } @@ -100,6 +112,7 @@ namespace skyline { void Settings::List(const std::shared_ptr &logger) { for (auto &iter : stringMap) logger->Info("Key: {}, Value: {}, Type: String", iter.first, GetString(iter.first)); + for (auto &iter : boolMap) logger->Info("Key: {}, Value: {}, Type: Bool", iter.first, GetBool(iter.first)); } @@ -115,15 +128,18 @@ namespace skyline { void Logger::WriteHeader(const std::string &str) { syslog(LOG_ALERT, "%s", str.c_str()); + logFile << "0|" << str << "\n"; logFile.flush(); } void Logger::Write(const LogLevel level, std::string str) { syslog(levelSyslog[static_cast(level)], "%s", str.c_str()); + for (auto &character : str) if (character == '\n') character = '\\'; + logFile << "1|" << levelStr[static_cast(level)] << "|" << str << "\n"; logFile.flush(); } diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index 90e73d56..7dbf2dd2 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -19,47 +19,20 @@ #include "nce/guest_common.h" namespace skyline { - using handle_t = u32; //!< The type of a kernel handle + using KHandle = u32; //!< The type of a kernel handle namespace constant { // Memory - constexpr u64 BaseAddress = 0x8000000; //!< The address space base - constexpr u64 TotalPhyMem = 0xF8000000; // ~4 GB of RAM - constexpr size_t DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB - constexpr size_t HeapSizeDiv = 0x200000; //!< The amount heap size has to be divisible by - constexpr size_t DefHeapSize = HeapSizeDiv; //!< The default amount of heap - constexpr size_t TlsSlotSize = 0x200; //!< The size of a single TLS slot - constexpr u8 TlsSlots = PAGE_SIZE / TlsSlotSize; //!< The amount of TLS slots in a single page - // Loader - constexpr u32 NroMagic = 0x304F524E; //!< "NRO0" in reverse, this is written at the start of every NRO file - // NCE - constexpr u8 NumRegs = 30; //!< The amount of registers that ARMv8 has - constexpr u32 TpidrroEl0 = 0x5E83; //!< ID of TPIDRRO_EL0 in MRS - constexpr u32 CntfrqEl0 = 0x5F00; //!< ID of CNTFRQ_EL0 in MRS - constexpr u32 TegraX1Freq = 19200000; //!< 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 + constexpr auto BaseAddress = 0x8000000; //!< The address space base + constexpr auto DefStackSize = 0x1E8480; //!< The default amount of stack: 2 MB // Kernel - constexpr u64 MaxSyncHandles = 0x40; //!< The total amount of handles that can be passed to WaitSynchronization - constexpr handle_t BaseHandleIndex = 0xD000; // The index of the base handle - constexpr handle_t ThreadSelf = 0xFFFF8000; //!< This is the handle used by threads to refer to themselves - constexpr u8 DefaultPriority = 44; //!< The default priority of a process - constexpr std::pair PriorityAn = {19, -8}; //!< The range of priority for Android, taken from https://medium.com/mindorks/exploring-android-thread-priority-5d0542eebbd1 - constexpr std::pair PriorityNin = {0, 63}; //!< The range of priority for the Nintendo Switch - constexpr u32 MtxOwnerMask = 0xBFFFFFFF; //!< The mask of values which contain the owner of a mutex - // IPC - constexpr size_t TlsIpcSize = 0x100; //!< The size of the IPC command buffer in a TLS slot - constexpr u8 PortSize = 0x8; //!< The size of a port name string - constexpr u32 SfcoMagic = 0x4F434653; //!< SFCO in reverse, written to IPC messages - constexpr u32 SfciMagic = 0x49434653; //!< SFCI in reverse, present in received IPC messages - constexpr u64 IpcPaddingSum = 0x10; //!< The sum of the padding surrounding DataPayload - constexpr handle_t BaseVirtualHandleIndex = 0x1; // The index of the base virtual handle - // GPU - constexpr u32 HandheldResolutionW = 1280; //!< The width component of the handheld resolution - constexpr u32 HandheldResolutionH = 720; //!< The height component of the handheld resolution - constexpr u32 DockedResolutionW = 1920; //!< The width component of the docked resolution - constexpr u32 DockedResolutionH = 1080; //!< The height component of the docked resolution - constexpr u32 TokenLength = 0x50; //!< The length of the token on BufferQueue parcels + constexpr std::pair AndroidPriority = {19, -8}; //!< The range of priority for Android + constexpr std::pair SwitchPriority = {0, 63}; //!< The range of priority for the Nintendo Switch + // Display + constexpr auto HandheldResolutionW = 1280; //!< The width component of the handheld resolution + constexpr auto HandheldResolutionH = 720; //!< The height component of the handheld resolution + constexpr auto DockedResolutionW = 1920; //!< The width component of the docked resolution + constexpr auto DockedResolutionH = 1080; //!< The height component of the docked resolution // Status codes namespace status { constexpr u32 Success = 0x0; //!< "Success" @@ -98,13 +71,13 @@ namespace skyline { * @return The current time in nanoseconds */ inline u64 GetTimeNs() { - constexpr uint64_t NsInSecond = 1000000000; + constexpr uint64_t nsInSecond = 1000000000; static u64 frequency{}; if (!frequency) asm("MRS %0, CNTFRQ_EL0" : "=r"(frequency)); u64 ticks; asm("MRS %0, CNTVCT_EL0" : "=r"(ticks)); - return ((ticks / frequency) * NsInSecond) + (((ticks % frequency) * NsInSecond + (frequency / 2)) / frequency); + return ((ticks / frequency) * nsInSecond) + (((ticks % frequency) * nsInSecond + (frequency / 2)) / frequency); } /** diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp index 396b075b..c7954958 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.cpp +++ b/app/src/main/cpp/skyline/kernel/ipc.cpp @@ -23,12 +23,12 @@ namespace skyline::kernel::ipc { handleDesc = reinterpret_cast(pointer); pointer += sizeof(HandleDescriptor) + (handleDesc->sendPid ? sizeof(u64) : 0); for (uint index = 0; handleDesc->copyCount > index; index++) { - copyHandles.push_back(*reinterpret_cast(pointer)); - pointer += sizeof(handle_t); + copyHandles.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(KHandle); } for (uint index = 0; handleDesc->moveCount > index; index++) { - moveHandles.push_back(*reinterpret_cast(pointer)); - pointer += sizeof(handle_t); + moveHandles.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(KHandle); } } @@ -69,7 +69,9 @@ namespace skyline::kernel::ipc { pointer += sizeof(BufferDescriptorABW); } - u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front + constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload + + u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front pointer += padding; if (isDomain && (header->type == CommandType::Request)) { @@ -84,24 +86,26 @@ namespace skyline::kernel::ipc { pointer += domain->payloadSz; for (uint index = 0; domain->inputCount > index; index++) { - domainObjects.push_back(*reinterpret_cast(pointer)); - pointer += sizeof(handle_t); + domainObjects.push_back(*reinterpret_cast(pointer)); + pointer += sizeof(KHandle); } } else { payload = reinterpret_cast(pointer); pointer += sizeof(PayloadHeader); cmdArg = pointer; - cmdArgSz = (header->rawSize * sizeof(u32)) - (constant::IpcPaddingSum + sizeof(PayloadHeader)); + cmdArgSz = (header->rawSize * sizeof(u32)) - (ipcPaddingSum + sizeof(PayloadHeader)); pointer += cmdArgSz; } payloadOffset = cmdArg; - if (payload->magic != constant::SfciMagic && header->type != CommandType::Control) + constexpr auto sfciMagic = 0x49434653; //!< SFCI in reverse, present in received IPC messages + + if (payload->magic != sfciMagic && header->type != CommandType::Control) state.logger->Debug("Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic)); - pointer += constant::IpcPaddingSum - padding; + pointer += ipcPaddingSum - padding; if (header->cFlag == BufferCFlag::SingleDescriptor) { auto bufC = reinterpret_cast(pointer); @@ -135,10 +139,14 @@ namespace skyline::kernel::ipc { void IpcResponse::WriteResponse() { auto tls = state.process->GetPointer(state.thread->tls); u8 *pointer = tls; - memset(tls, 0, constant::TlsIpcSize); + + constexpr auto tlsIpcSize = 0x100; // The size of the IPC command buffer in a TLS slot + memset(tls, 0, tlsIpcSize); + + constexpr auto ipcPaddingSum = 0x10; // The sum of the padding surrounding the data payload auto header = reinterpret_cast(pointer); - header->rawSize = static_cast((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(handle_t)) + constant::IpcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo + header->rawSize = static_cast((sizeof(PayloadHeader) + argVec.size() + (domainObjects.size() * sizeof(KHandle)) + ipcPaddingSum + (isDomain ? sizeof(DomainHeaderRequest) : 0)) / sizeof(u32)); // Size is in 32-bit units because Nintendo header->handleDesc = (!copyHandles.empty() || !moveHandles.empty()); pointer += sizeof(CommandHeader); @@ -149,17 +157,17 @@ namespace skyline::kernel::ipc { pointer += sizeof(HandleDescriptor); for (unsigned int copyHandle : copyHandles) { - *reinterpret_cast(pointer) = copyHandle; - pointer += sizeof(handle_t); + *reinterpret_cast(pointer) = copyHandle; + pointer += sizeof(KHandle); } for (unsigned int moveHandle : moveHandles) { - *reinterpret_cast(pointer) = moveHandle; - pointer += sizeof(handle_t); + *reinterpret_cast(pointer) = moveHandle; + pointer += sizeof(KHandle); } } - u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(constant::IpcPaddingSum - 1U)) + constant::IpcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front + u64 padding = ((((reinterpret_cast(pointer) - reinterpret_cast(tls)) - 1U) & ~(ipcPaddingSum - 1U)) + ipcPaddingSum + (reinterpret_cast(tls) - reinterpret_cast(pointer))); // Calculate the amount of padding at the front pointer += padding; if (isDomain) { @@ -168,19 +176,22 @@ namespace skyline::kernel::ipc { pointer += sizeof(DomainHeaderResponse); } + constexpr auto sfcoMagic = 0x4F434653; // SFCO in reverse, IPC Response Magic + auto payload = reinterpret_cast(pointer); - payload->magic = constant::SfcoMagic; + payload->magic = sfcoMagic; payload->version = 1; payload->value = errorCode; pointer += sizeof(PayloadHeader); + if (!argVec.empty()) memcpy(pointer, argVec.data(), argVec.size()); pointer += argVec.size(); if (isDomain) { for (auto &domainObject : domainObjects) { - *reinterpret_cast(pointer) = domainObject; - pointer += sizeof(handle_t); + *reinterpret_cast(pointer) = domainObject; + pointer += sizeof(KHandle); } } diff --git a/app/src/main/cpp/skyline/kernel/ipc.h b/app/src/main/cpp/skyline/kernel/ipc.h index 266bf01b..8fbeb805 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.h +++ b/app/src/main/cpp/skyline/kernel/ipc.h @@ -242,7 +242,6 @@ namespace skyline::kernel::ipc { u8 *payloadOffset; //!< This is the offset of the data read from the payload public: - //std::array tls; //!< A static-sized array where TLS data is actually copied to CommandHeader *header{}; //!< The header of the request HandleDescriptor *handleDesc{}; //!< The handle descriptor in case CommandHeader::handle_desc is true in the header bool isDomain{}; //!< If this is a domain request @@ -250,9 +249,9 @@ namespace skyline::kernel::ipc { PayloadHeader *payload{}; //!< This is the header of the payload u8 *cmdArg{}; //!< This is a pointer to the data payload (End of PayloadHeader) u64 cmdArgSz{}; //!< This is the size of the data payload - std::vector copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles) - std::vector moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied - std::vector domainObjects; //!< A vector of all input domain objects + std::vector copyHandles; //!< A vector of handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles) + std::vector moveHandles; //!< A vector of handles that should be moved from the server to the client process rather than copied + std::vector domainObjects; //!< A vector of all input domain objects std::vector inputBuf; //!< This is a vector of input buffers std::vector outputBuf; //!< This is a vector of output buffers @@ -295,9 +294,9 @@ namespace skyline::kernel::ipc { bool nWrite{}; //!< This is to signal the IPC handler to not write this, as it will be manually written bool isDomain{}; //!< If this is a domain request u32 errorCode{}; //!< The error code to respond with, it is 0 (Success) by default - std::vector copyHandles; //!< A vector of handles to copy - std::vector moveHandles; //!< A vector of handles to move - std::vector domainObjects; //!< A vector of domain objects to write + std::vector copyHandles; //!< A vector of handles to copy + std::vector moveHandles; //!< A vector of handles to move + std::vector domainObjects; //!< A vector of domain objects to write /** * @param isDomain If the following request is a domain request diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 50fb666e..4910d540 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -117,24 +117,24 @@ namespace skyline { struct { MemoryType type; //!< The MemoryType of this memory block - bool PermissionChangeAllowed : 1; //!< If the application can use svcSetMemoryPermission on this block - bool ForceReadWritableByDebugSyscalls : 1; //!< If the application can use svcWriteDebugProcessMemory on this block - bool IpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=0 - bool NonDeviceIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=3 - bool NonSecureIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=1 + bool permissionChangeAllowed : 1; //!< If the application can use svcSetMemoryPermission on this block + bool forceReadWritableByDebugSyscalls : 1; //!< If the application can use svcWriteDebugProcessMemory on this block + bool ipcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=0 + bool nonDeviceIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=3 + bool nonSecureIpcSendAllowed : 1; //!< If this block is allowed to be sent as an IPC buffer with flags=1 bool _pad0_ : 1; - bool ProcessPermissionChangeAllowed : 1; //!< If the application can use svcSetProcessMemoryPermission on this block - bool MapAllowed : 1; //!< If the application can use svcMapMemory on this block - bool UnmapProcessCodeMemoryAllowed : 1; //!< If the application can use svcUnmapProcessCodeMemory on this block - bool TransferMemoryAllowed : 1; //!< If the application can use svcCreateTransferMemory on this block - bool QueryPhysicalAddressAllowed : 1; //!< If the application can use svcQueryPhysicalAddress on this block - bool MapDeviceAllowed : 1; //!< If the application can use svcMapDeviceAddressSpace or svcMapDeviceAddressSpaceByForce on this block - bool MapDeviceAlignedAllowed : 1; //!< If the application can use svcMapDeviceAddressSpaceAligned on this block - bool IpcBufferAllowed : 1; //!< If the application can use this block with svcSendSyncRequestWithUserBuffer - bool IsReferenceCounted : 1; //!< If the physical memory blocks backing this region are reference counted - bool MapProcessAllowed : 1; //!< If the application can use svcMapProcessMemory on this block - bool AttributeChangeAllowed : 1; //!< If the application can use svcSetMemoryAttribute on this block - bool CodeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block + bool processPermissionChangeAllowed : 1; //!< If the application can use svcSetProcessMemoryPermission on this block + bool mapAllowed : 1; //!< If the application can use svcMapMemory on this block + bool unmapProcessCodeMemoryAllowed : 1; //!< If the application can use svcUnmapProcessCodeMemory on this block + bool transferMemoryAllowed : 1; //!< If the application can use svcCreateTransferMemory on this block + bool queryPhysicalAddressAllowed : 1; //!< If the application can use svcQueryPhysicalAddress on this block + bool mapDeviceAllowed : 1; //!< If the application can use svcMapDeviceAddressSpace or svcMapDeviceAddressSpaceByForce on this block + bool mapDeviceAlignedAllowed : 1; //!< If the application can use svcMapDeviceAddressSpaceAligned on this block + bool ipcBufferAllowed : 1; //!< If the application can use this block with svcSendSyncRequestWithUserBuffer + bool isReferenceCounted : 1; //!< If the physical memory blocks backing this region are reference counted + bool mapProcessAllowed : 1; //!< If the application can use svcMapProcessMemory on this block + bool attributeChangeAllowed : 1; //!< If the application can use svcSetMemoryAttribute on this block + bool codeMemoryAllowed : 1; //!< If the application can use svcCreateCodeMemory on this block }; u32 value; }; @@ -143,7 +143,7 @@ namespace skyline { /** * @brief The preset states that different regions are set to (https://switchbrew.org/wiki/SVC#MemoryType) */ - namespace MemoryStates { + namespace states { constexpr MemoryState Unmapped = 0x00000000; constexpr MemoryState Io = 0x00002001; constexpr MemoryState CodeStatic = 0x00DC7E03; diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 34adae3a..fbf2348d 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -3,17 +3,23 @@ namespace skyline::kernel::svc { void SetHeapSize(DeviceState &state) { + constexpr auto heapSizeAlign = 0x200000; // The heap size has to be a multiple of this value const u32 size = state.ctx->registers.w1; - if (size % constant::HeapSizeDiv != 0) { + + if (size % heapSizeAlign != 0) { state.ctx->registers.w0 = constant::status::InvSize; state.ctx->registers.x1 = 0; + state.logger->Warn("svcSetHeapSize: 'size' not divisible by 2MB: {}", size); return; } + auto &heap = state.process->heap; heap->Resize(size); + 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); } @@ -45,7 +51,7 @@ namespace skyline::kernel::svc { state.logger->Warn("svcSetMemoryAttribute: Cannot find memory region: 0x{:X}", address); return; } - if (!chunk->state.AttributeChangeAllowed) { + if (!chunk->state.attributeChangeAllowed) { state.ctx->registers.w0 = constant::status::InvState; state.logger->Warn("svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X}", address); return; @@ -82,12 +88,12 @@ namespace skyline::kernel::svc { state.logger->Warn("svcMapMemory: Source has no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size); return; } - if (!descriptor->chunk.state.MapAllowed) { + if (!descriptor->chunk.state.mapAllowed) { state.ctx->registers.w0 = constant::status::InvState; state.logger->Warn("svcMapMemory: Source doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, descriptor->chunk.state.value); return; } - state.process->NewHandle(destination, size, descriptor->block.permission, memory::MemoryStates::Stack); + state.process->NewHandle(destination, size, descriptor->block.permission, memory::states::Stack); state.process->CopyMemory(source, destination, size); auto object = state.process->GetMemoryObject(source); if (!object) @@ -124,7 +130,7 @@ namespace skyline::kernel::svc { state.logger->Warn("svcUnmapMemory: Addresses have no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes)", source, destination, size); return; } - if (!destDesc->chunk.state.MapAllowed) { + if (!destDesc->chunk.state.mapAllowed) { state.ctx->registers.w0 = constant::status::InvState; state.logger->Warn("svcUnmapMemory: Destination doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X}", source, destination, size, destDesc->chunk.state.value); return; @@ -181,7 +187,7 @@ namespace skyline::kernel::svc { u64 entryArgument = 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)) { + if ((priority < constant::SwitchPriority.first) || (priority > constant::SwitchPriority.second)) { state.ctx->registers.w0 = constant::status::InvAddress; state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority); return; @@ -312,7 +318,7 @@ namespace skyline::kernel::svc { } void CloseHandle(DeviceState &state) { - auto handle = static_cast(state.ctx->registers.w0); + auto handle = static_cast(state.ctx->registers.w0); try { state.process->handles.erase(handle); state.logger->Debug("svcCloseHandle: Closing handle: 0x{:X}", handle); @@ -350,40 +356,52 @@ namespace skyline::kernel::svc { } void WaitSynchronization(DeviceState &state) { + constexpr auto maxSyncHandles = 0x40; // The total amount of handles that can be passed to WaitSynchronization auto numHandles = state.ctx->registers.w2; - if (numHandles > constant::MaxSyncHandles) { + if (numHandles > maxSyncHandles) { state.ctx->registers.w0 = constant::status::MaxHandles; return; } - std::vector waitHandles(numHandles); - std::vector> objectTable; - state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(handle_t)); + std::string handleStr; + std::vector> objectTable; + std::vector waitHandles(numHandles); + + state.process->ReadMemory(waitHandles.data(), state.ctx->registers.x1, numHandles * sizeof(KHandle)); + for (const auto &handle : waitHandles) { handleStr += fmt::format("* 0x{:X}\n", handle); + auto object = state.process->handles.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; return; } } + objectTable.push_back(std::static_pointer_cast(object)); } + auto timeout = state.ctx->registers.x3; state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); + auto start = utils::GetTimeNs(); + while (true) { if (state.thread->cancelSync) { state.thread->cancelSync = false; state.ctx->registers.w0 = constant::status::Interrupted; break; } + uint index{}; for (const auto &object : objectTable) { if (object->signalled) { @@ -394,6 +412,7 @@ namespace skyline::kernel::svc { } index++; } + if ((utils::GetTimeNs() - start) >= timeout) { state.logger->Debug("svcWaitSynchronization: Wait has timed out"); state.ctx->registers.w0 = constant::status::Timeout; @@ -496,34 +515,41 @@ namespace skyline::kernel::svc { } 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) { + constexpr auto portSize = 0x8; //!< The size of a port name string + std::string_view port(state.process->GetPointer(state.ctx->registers.x1), portSize); + + KHandle handle{}; + if (port.compare("sm:") >= 0) { handle = state.os->serviceManager.NewSession(service::Service::sm_IUserInterface); } 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.os->serviceManager.SyncRequestHandler(static_cast(state.ctx->registers.x0)); state.ctx->registers.w0 = constant::status::Success; } void GetThreadId(DeviceState &state) { - pid_t pid{}; + constexpr KHandle threadSelf = 0xFFFF8000; // This is the handle used by threads to refer to themselves auto handle = state.ctx->registers.w1; - if (handle != constant::ThreadSelf) + pid_t pid{}; + + if (handle != 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; } @@ -540,7 +566,11 @@ namespace skyline::kernel::svc { auto id0 = state.ctx->registers.w1; auto handle = state.ctx->registers.w2; auto id1 = state.ctx->registers.x3; + + constexpr auto totalPhysicalMemory = 0xF8000000; // ~4 GB of RAM + u64 out{}; + switch (id0) { case constant::infoState::AllowedCpuIdBitmask: case constant::infoState::AllowedThreadPriorityMask: @@ -548,57 +578,75 @@ namespace skyline::kernel::svc { case constant::infoState::TitleId: case constant::infoState::PrivilegedProcessId: break; + case constant::infoState::AliasRegionBaseAddr: out = state.os->memory.GetRegion(memory::Regions::Alias).address; break; + case constant::infoState::AliasRegionSize: out = state.os->memory.GetRegion(memory::Regions::Alias).size; break; + case constant::infoState::HeapRegionBaseAddr: out = state.os->memory.GetRegion(memory::Regions::Heap).address; break; + case constant::infoState::HeapRegionSize: out = state.os->memory.GetRegion(memory::Regions::Heap).size; break; + case constant::infoState::TotalMemoryAvailable: - out = constant::TotalPhyMem; + out = totalPhysicalMemory; break; + case constant::infoState::TotalMemoryUsage: out = state.process->heap->address + constant::DefStackSize + state.os->memory.GetProgramSize(); break; + case constant::infoState::AddressSpaceBaseAddr: out = state.os->memory.GetRegion(memory::Regions::Base).address; break; + case constant::infoState::AddressSpaceSize: out = state.os->memory.GetRegion(memory::Regions::Base).size; break; + case constant::infoState::StackRegionBaseAddr: out = state.os->memory.GetRegion(memory::Regions::Stack).address; break; + case constant::infoState::StackRegionSize: out = state.os->memory.GetRegion(memory::Regions::Stack).size; break; + case constant::infoState::PersonalMmHeapSize: - out = constant::TotalPhyMem; + out = totalPhysicalMemory; break; + case constant::infoState::PersonalMmHeapUsage: out = state.process->heap->address + constant::DefStackSize; break; + case constant::infoState::TotalMemoryAvailableWithoutMmHeap: - out = constant::TotalPhyMem; // TODO: NPDM specifies SystemResourceSize, subtract that from this + out = totalPhysicalMemory; // TODO: NPDM specifies SystemResourceSize, subtract that from this break; + case constant::infoState::TotalMemoryUsedWithoutMmHeap: out = state.process->heap->size + constant::DefStackSize; // 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 c5b1d9e0..f78ff39f 100644 --- a/app/src/main/cpp/skyline/kernel/svc.h +++ b/app/src/main/cpp/skyline/kernel/svc.h @@ -34,7 +34,8 @@ namespace skyline { // 6.0.0+ constexpr u8 TotalMemoryAvailableWithoutMmHeap = 0x15; constexpr u8 TotalMemoryUsedWithoutMmHeap = 0x16; - }; + } + namespace kernel::svc { /** * @brief Sets the process heap to a given Size. It can both extend and shrink the heap. (https://switchbrew.org/wiki/SVC#SetHeapSize) diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index 9599a400..c27b1534 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -38,23 +38,29 @@ namespace skyline::kernel::type { } else { address = (*(tlsPages.end() - 1))->address + PAGE_SIZE; } - auto tlsMem = NewHandle(address, PAGE_SIZE, memory::Permission(true, true, false), memory::MemoryStates::ThreadLocal).item; + auto tlsMem = NewHandle(address, PAGE_SIZE, memory::Permission(true, true, false), memory::states::ThreadLocal).item; tlsPages.push_back(std::make_shared(tlsMem->address)); + auto &tlsPage = tlsPages.back(); if (tlsPages.empty()) tlsPage->ReserveSlot(); // User-mode exception handling + return tlsPage->ReserveSlot(); } void KProcess::InitializeMemory() { - heap = NewHandle(state.os->memory.GetRegion(memory::Regions::Heap).address, constant::DefHeapSize, memory::Permission{true, true, false}, memory::MemoryStates::Heap).item; + constexpr size_t DefHeapSize = 0x200000; // The default amount of heap + heap = NewHandle(state.os->memory.GetRegion(memory::Regions::Heap).address, DefHeapSize, memory::Permission{true, true, false}, memory::states::Heap).item; threads[pid]->tls = GetTlsSlot(); } KProcess::KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, std::shared_ptr &stack, std::shared_ptr &tlsMemory) : pid(pid), stack(stack), KSyncObject(state, KType::KProcess) { - auto thread = NewHandle(pid, entryPoint, 0x0, stack->guest.address + stack->guest.size, 0, constant::DefaultPriority, this, tlsMemory).item; + constexpr auto DefaultPriority = 44; // The default priority of a process + + auto thread = NewHandle(pid, entryPoint, 0x0, stack->guest.address + stack->guest.size, 0, DefaultPriority, this, tlsMemory).item; threads[pid] = thread; state.nce->WaitThreadInit(thread); + 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)); @@ -67,7 +73,7 @@ namespace skyline::kernel::type { std::shared_ptr KProcess::CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority) { auto size = (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - auto tlsMem = std::make_shared(state, 0, size, memory::Permission{true, true, false}, memory::MemoryStates::Reserved); + auto tlsMem = std::make_shared(state, 0, size, memory::Permission{true, true, false}, memory::states::Reserved); Registers fregs{}; fregs.x0 = CLONE_THREAD | CLONE_SIGHAND | CLONE_PTRACE | CLONE_FS | CLONE_VM | CLONE_FILES | CLONE_IO; fregs.x1 = stackTop; @@ -166,7 +172,7 @@ namespace skyline::kernel::type { return std::nullopt; } - bool KProcess::MutexLock(u64 address, handle_t owner) { + bool KProcess::MutexLock(u64 address, KHandle owner) { std::unique_lock lock(mutexLock); auto mtx = GetPointer(address); auto &mtxWaiters = mutexes[address]; diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index dd6a789e..944221a5 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -9,372 +9,381 @@ #include #include -namespace skyline::kernel::type { - /** - * @brief The KProcess class is responsible for holding the state of a process - */ - class KProcess : public KSyncObject { - private: +namespace skyline { + namespace constant { + constexpr auto TlsSlotSize = 0x200; //!< The size of a single TLS slot + constexpr auto TlsSlots = PAGE_SIZE / TlsSlotSize; //!< The amount of TLS slots in a single page + constexpr KHandle BaseHandleIndex = 0xD000; // The index of the base handle + constexpr u32 MtxOwnerMask = 0xBFFFFFFF; //!< The mask of values which contain the owner of a mutex + } + + namespace kernel::type { /** - * @brief This class holds a single TLS page's status - * @details tls_page_t holds the status of a single TLS page (A page is 4096 bytes on ARMv8). - * Each TLS page has 8 slots, each 0x200 (512) bytes in size. - * The first slot of the first page is reserved for user-mode exception handling. - * Read more about TLS here: https://switchbrew.org/wiki/Thread_Local_Storage - */ - struct TlsPage { - u64 address; //!< The address of the page allocated for TLS - u8 index = 0; //!< The slots are assigned sequentially, this holds the index of the last TLS slot reserved - bool slot[constant::TlsSlots]{0}; //!< An array of booleans denoting which TLS slots are reserved + * @brief The KProcess class is responsible for holding the state of a process + */ + class KProcess : public KSyncObject { + private: + /** + * @brief This class holds a single TLS page's status + * @details tls_page_t holds the status of a single TLS page (A page is 4096 bytes on ARMv8). + * Each TLS page has 8 slots, each 0x200 (512) bytes in size. + * The first slot of the first page is reserved for user-mode exception handling. + * Read more about TLS here: https://switchbrew.org/wiki/Thread_Local_Storage + */ + struct TlsPage { + u64 address; //!< The address of the page allocated for TLS + u8 index = 0; //!< The slots are assigned sequentially, this holds the index of the last TLS slot reserved + bool slot[constant::TlsSlots]{0}; //!< An array of booleans denoting which TLS slots are reserved + + /** + * @param address The address of the allocated page + */ + TlsPage(u64 address); + + /** + * @brief Reserves a single 0x200 byte TLS slot + * @return The address of the reserved slot + */ + u64 ReserveSlot(); + + /** + * @brief Returns the address of a particular slot + * @param slotNo The number of the slot to be returned + * @return The address of the specified slot + */ + u64 Get(u8 slotNo); + + /** + * @brief Returns boolean on if the TLS page has free slots or not + * @return If the whole page is full or not + */ + bool Full(); + }; /** - * @param address The address of the allocated page - */ - TlsPage(u64 address); + * @brief Returns a TLS slot from an arbitrary TLS page + * @return The address of a free TLS slot + */ + u64 GetTlsSlot(); /** - * @brief Reserves a single 0x200 byte TLS slot - * @return The address of the reserved slot - */ - u64 ReserveSlot(); + * @brief This initializes heap and the initial TLS page + */ + void InitializeMemory(); + + public: + friend OS; /** - * @brief Returns the address of a particular slot - * @param slotNo The number of the slot to be returned - * @return The address of the specified slot - */ - u64 Get(u8 slotNo); + * @brief This is used as the output for functions that return created kernel objects + * @tparam objectClass The class of the kernel object + */ + template + struct HandleOut { + std::shared_ptr item; //!< A shared pointer to the object + KHandle handle; //!< The handle of the object in the process + }; /** - * @brief Returns boolean on if the TLS page has free slots or not - * @return If the whole page is full or not - */ - bool Full(); - }; + * @brief This enum is used to describe the current status of the process + */ + enum class Status { + Created, //!< The process was created but the main thread has not started yet + Started, //!< The process has been started + Exiting //!< The process is exiting + } status = Status::Created; //!< The state of the process - /** - * @brief Returns a TLS slot from an arbitrary TLS page - * @return The address of a free TLS slot - */ - u64 GetTlsSlot(); + /** + * @brief This is used to hold information about a single waiting thread for mutexes and conditional variables + */ + struct WaitStatus { + std::atomic_bool flag{false}; //!< The underlying atomic flag of the thread + u8 priority; //!< The priority of the thread + KHandle handle; //!< The handle of the thread + u64 mutexAddress{}; //!< The address of the mutex - /** - * @brief This initializes heap and the initial TLS page - */ - void InitializeMemory(); + WaitStatus(u8 priority, KHandle handle) : priority(priority), handle(handle) {} - public: - friend OS; + WaitStatus(u8 priority, KHandle handle, u64 mutexAddress) : priority(priority), handle(handle), mutexAddress(mutexAddress) {} + }; - /** - * @brief This is used as the output for functions that return created kernel objects - * @tparam objectClass The class of the kernel object - */ - template - struct HandleOut { - std::shared_ptr item; //!< A shared pointer to the object - handle_t handle; //!< The handle of the object in the process - }; + KHandle handleIndex = constant::BaseHandleIndex; //!< This is used to keep track of what to map as an handle + pid_t pid; //!< The PID of the main thread + int memFd; //!< The file descriptor to the memory of the process + std::unordered_map> handles; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object + std::unordered_map> threads; //!< A mapping from a PID to it's corresponding KThread object + std::unordered_map>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it + std::unordered_map>> conditionals; //!< 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 + std::shared_ptr stack; //!< The shared memory used to hold the stack of the main thread + std::shared_ptr heap; //!< The kernel memory object backing the allocated heap + Mutex mutexLock; //!< This mutex is to prevent concurrent mutex operations to happen at once + Mutex conditionalLock; //!< This mutex is to prevent concurrent conditional variable operations to happen at once - /** - * @brief This enum is used to describe the current status of the process - */ - enum class Status { - Created, //!< The process was created but the main thread has not started yet - Started, //!< The process has been started - Exiting //!< The process is exiting - } status = Status::Created; //!< The state of the process + /** + * @brief Creates a KThread object for the main thread and opens the process's memory file + * @param state The state of the device + * @param pid The PID of the main thread + * @param entryPoint The address to start execution at + * @param stack The KSharedMemory object for Stack memory allocated by the guest process + * @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process + */ + KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, std::shared_ptr &stack, std::shared_ptr &tlsMemory); - /** - * @brief This is used to hold information about a single waiting thread for mutexes and conditional variables - */ - struct WaitStatus { - std::atomic_bool flag{false}; //!< The underlying atomic flag of the thread - u8 priority; //!< The priority of the thread - handle_t handle; //!< The handle of the thread - u64 mutexAddress{}; //!< The address of the mutex + /** + * Close the file descriptor to the process's memory + */ + ~KProcess(); - WaitStatus(u8 priority, handle_t handle) : priority(priority), handle(handle) {} + /** + * @brief Create a thread in this process + * @param entryPoint The address of the initial function + * @param entryArg An argument to the function + * @param stackTop The top of the stack + * @param priority The priority of the thread + * @return An instance of KThread class for the corresponding thread + */ + std::shared_ptr CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority); - WaitStatus(u8 priority, handle_t handle, u64 mutexAddress) : priority(priority), handle(handle), mutexAddress(mutexAddress) {} - }; + /** + * @brief This returns the host address for a specific address in guest memory + * @param address The corresponding guest address + * @return The corresponding host address + */ + u64 GetHostAddress(const u64 address) const; - handle_t handleIndex = constant::BaseHandleIndex; //!< This is used to keep track of what to map as an handle - pid_t pid; //!< The PID of the main thread - int memFd; //!< The file descriptor to the memory of the process - std::unordered_map> handles; //!< A mapping from a handle_t to it's corresponding KObject which is the actual underlying object - std::unordered_map> threads; //!< A mapping from a PID to it's corresponding KThread object - std::unordered_map>> mutexes; //!< A map from a mutex's address to a vector of Mutex objects for threads waiting on it - std::unordered_map>> conditionals; //!< 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 - std::shared_ptr stack; //!< The shared memory used to hold the stack of the main thread - std::shared_ptr heap; //!< The kernel memory object backing the allocated heap - Mutex mutexLock; //!< This mutex is to prevent concurrent mutex operations to happen at once - Mutex conditionalLock; //!< This mutex is to prevent concurrent conditional variable operations to happen at once - - /** - * @brief Creates a KThread object for the main thread and opens the process's memory file - * @param state The state of the device - * @param pid The PID of the main thread - * @param entryPoint The address to start execution at - * @param stack The KSharedMemory object for Stack memory allocated by the guest process - * @param tlsMemory The KSharedMemory object for TLS memory allocated by the guest process - */ - KProcess(const DeviceState &state, pid_t pid, u64 entryPoint, std::shared_ptr &stack, std::shared_ptr &tlsMemory); - - /** - * Close the file descriptor to the process's memory - */ - ~KProcess(); - - /** - * @brief Create a thread in this process - * @param entryPoint The address of the initial function - * @param entryArg An argument to the function - * @param stackTop The top of the stack - * @param priority The priority of the thread - * @return An instance of KThread class for the corresponding thread - */ - std::shared_ptr CreateThread(u64 entryPoint, u64 entryArg, u64 stackTop, u8 priority); - - /** - * @brief This returns the host address for a specific address in guest memory - * @param address The corresponding guest address - * @return The corresponding host address - */ - u64 GetHostAddress(const u64 address) const; - - /** - * @tparam Type The type of the pointer to return - * @param address The address on the guest - * @return A pointer corresponding to a certain address on the guest - * @note This can return a nullptr if the address is invalid - */ - template - inline Type *GetPointer(const u64 address) const { - return reinterpret_cast(GetHostAddress(address)); - } - - /** - * @brief Returns a reference to an object from guest memory - * @tparam Type The type of the object to be read - * @param address The address of the object - * @return A reference to object with type T - */ - template - inline Type &GetReference(u64 address) const { - auto source = GetPointer(address); - if (source) - return *source; - else - throw exception("Cannot retrieve reference to object not in shared guest memory"); - } - - /** - * @brief Returns a copy of an object from guest memory - * @tparam Type The type of the object to be read - * @param address The address of the object - * @return A copy of the object from guest memory - */ - template - inline Type GetObject(u64 address) const { - auto source = GetPointer(address); - if (source) { - return *source; - } else { - Type item{}; - ReadMemory(&item, address, sizeof(Type)); - return item; + /** + * @tparam Type The type of the pointer to return + * @param address The address on the guest + * @return A pointer corresponding to a certain address on the guest + * @note This can return a nullptr if the address is invalid + */ + template + inline Type *GetPointer(const u64 address) const { + return reinterpret_cast(GetHostAddress(address)); } - } - /** - * @brief Returns a string from guest memory - * @param address The address of the object - * @param maxSize The maximum size of the string - * @return A copy of a string in guest memory - */ - inline std::string GetString(u64 address, const size_t maxSize) const { - auto source = GetPointer(address); - if (source) - return std::string(source, maxSize); - std::string debug(maxSize, '\0'); - ReadMemory(debug.data(), address, maxSize); - return debug; - } - - /** - * @brief Writes an object to guest memory - * @tparam Type The type of the object to be written - * @param item The object to write - * @param address The address of the object - */ - template - inline void WriteMemory(Type &item, u64 address) const { - auto destination = GetPointer(address); - if (destination) { - *destination = item; - } else { - WriteMemory(&item, address, sizeof(Type)); - } - } - - /** - * @brief Writes an object to guest memory - * @tparam Type The type of the object to be written - * @param item The object to write - * @param address The address of the object - */ - template - inline void WriteMemory(const Type &item, u64 address) const { - auto destination = GetPointer(address); - if (destination) { - *destination = item; - } else { - WriteMemory(&item, address, sizeof(Type)); - } - } - - /** - * @brief Read data from the guest's memory - * @param destination The address to the location where the process memory is written - * @param offset The address to read from in process memory - * @param size The amount of memory to be read - * @param forceGuest This flag forces the write to be performed in guest address space - */ - void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const; - - /** - * @brief Write to the guest's memory - * @param source The address of where the data to be written is present - * @param offset The address to write to in process memory - * @param size The amount of memory to be written - * @param forceGuest This flag forces the write to be performed in guest address space - */ - void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const; - - /** - * @brief Copy one chunk to another in the guest's memory - * @param source The address of where the data to read is present - * @param destination The address to write the read data to - * @param size The amount of memory to be copied - */ - void CopyMemory(const u64 source, const u64 destination, const size_t size) const; - - /** - * @brief Creates a new handle to a KObject and adds it to the process handle_table - * @tparam objectClass The class of the kernel object to create - * @param args The arguments for the kernel object except handle, pid and state - * @return A shared pointer to the corresponding object - */ - template - HandleOut NewHandle(objectArgs... args) { - std::shared_ptr item; - if constexpr (std::is_same()) - item = std::make_shared(state, handleIndex, args...); - else - item = std::make_shared(state, args...); - handles[handleIndex] = std::static_pointer_cast(item); - return {item, handleIndex++}; - } - - /** - * @brief Inserts an item into the process handle table - * @param item The item to insert - * @return The handle of the corresponding item in the handle table - */ - template - handle_t InsertItem(std::shared_ptr &item) { - handles[handleIndex] = std::static_pointer_cast(item); - return handleIndex++; - } - - /** - * @brief Returns the underlying kernel object for a handle - * @tparam objectClass The class of the kernel object present in the handle - * @param handle The handle of the object - * @return A shared pointer to the object - */ - template - std::shared_ptr GetHandle(handle_t handle) { - KType objectType; - if constexpr(std::is_same()) - objectType = KType::KThread; - else if constexpr(std::is_same()) - objectType = KType::KProcess; - else if constexpr(std::is_same()) - objectType = KType::KSharedMemory; - else if constexpr(std::is_same()) - objectType = KType::KTransferMemory; - else if constexpr(std::is_same()) - objectType = KType::KPrivateMemory; - else if constexpr(std::is_same()) - objectType = KType::KSession; - else if constexpr(std::is_same()) - objectType = KType::KEvent; - else - throw exception("KProcess::GetHandle couldn't determine object type"); - try { - auto item = handles.at(handle); - if (item->objectType == objectType) - return std::static_pointer_cast(item); + /** + * @brief Returns a reference to an object from guest memory + * @tparam Type The type of the object to be read + * @param address The address of the object + * @return A reference to object with type T + */ + template + inline Type &GetReference(u64 address) const { + auto source = GetPointer(address); + if (source) + return *source; else - throw exception("Tried to get kernel object (0x{:X}) with different type: {} when object is {}", handle, objectType, item->objectType); - } catch (std::out_of_range) { - throw exception("GetHandle was called with invalid handle: 0x{:X}", handle); + throw exception("Cannot retrieve reference to object not in shared guest memory"); } - } - /** - * @brief Retrieves a kernel memory object that owns the specified address - * @param address The address to look for - * @return A shared pointer to the corresponding KMemory object - */ - std::optional> GetMemoryObject(u64 address); + /** + * @brief Returns a copy of an object from guest memory + * @tparam Type The type of the object to be read + * @param address The address of the object + * @return A copy of the object from guest memory + */ + template + inline Type GetObject(u64 address) const { + auto source = GetPointer(address); + if (source) { + return *source; + } else { + Type item{}; + ReadMemory(&item, address, sizeof(Type)); + return item; + } + } - /** - * @brief This deletes a certain handle from the handle table - * @param handle The handle to delete - */ - inline void DeleteHandle(handle_t handle) { - handles.erase(handle); - } + /** + * @brief Returns a string from guest memory + * @param address The address of the object + * @param maxSize The maximum size of the string + * @return A copy of a string in guest memory + */ + inline std::string GetString(u64 address, const size_t maxSize) const { + auto source = GetPointer(address); + if (source) + return std::string(source, maxSize); + std::string debug(maxSize, '\0'); + ReadMemory(debug.data(), address, maxSize); + return debug; + } - /** - * @brief This locks the Mutex at the specified address - * @param address The address of the mutex - * @param owner The handle of the current mutex owner - * @return If the mutex was successfully locked - */ - bool MutexLock(u64 address, handle_t owner); + /** + * @brief Writes an object to guest memory + * @tparam Type The type of the object to be written + * @param item The object to write + * @param address The address of the object + */ + template + inline void WriteMemory(Type &item, u64 address) const { + auto destination = GetPointer(address); + if (destination) { + *destination = item; + } else { + WriteMemory(&item, address, sizeof(Type)); + } + } - /** - * @brief This unlocks the Mutex at the specified address - * @param address The address of the mutex - * @return If the mutex was successfully unlocked - */ - bool MutexUnlock(u64 address); + /** + * @brief Writes an object to guest memory + * @tparam Type The type of the object to be written + * @param item The object to write + * @param address The address of the object + */ + template + inline void WriteMemory(const Type &item, u64 address) const { + auto destination = GetPointer(address); + if (destination) { + *destination = item; + } else { + WriteMemory(&item, address, sizeof(Type)); + } + } - /** - * @param conditionalAddress The address of the conditional variable - * @param mutexAddress The address of the mutex - * @param timeout The amount of time to wait for the conditional variable - * @return If the conditional variable was successfully waited for or timed out - */ - bool ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout); + /** + * @brief Read data from the guest's memory + * @param destination The address to the location where the process memory is written + * @param offset The address to read from in process memory + * @param size The amount of memory to be read + * @param forceGuest This flag forces the write to be performed in guest address space + */ + void ReadMemory(void *destination, const u64 offset, const size_t size, const bool forceGuest = false) const; - /** - * @brief This signals a number of conditional variable waiters - * @param address The address of the conditional variable - * @param amount The amount of waiters to signal - */ - void ConditionalVariableSignal(u64 address, u64 amount); + /** + * @brief Write to the guest's memory + * @param source The address of where the data to be written is present + * @param offset The address to write to in process memory + * @param size The amount of memory to be written + * @param forceGuest This flag forces the write to be performed in guest address space + */ + void WriteMemory(void *source, const u64 offset, const size_t size, const bool forceGuest = false) const; - /** - * @brief This resets the object to an unsignalled state - */ - inline void ResetSignal() { - signalled = false; - } - }; + /** + * @brief Copy one chunk to another in the guest's memory + * @param source The address of where the data to read is present + * @param destination The address to write the read data to + * @param size The amount of memory to be copied + */ + void CopyMemory(const u64 source, const u64 destination, const size_t size) const; + + /** + * @brief Creates a new handle to a KObject and adds it to the process handle_table + * @tparam objectClass The class of the kernel object to create + * @param args The arguments for the kernel object except handle, pid and state + * @return A shared pointer to the corresponding object + */ + template + HandleOut NewHandle(objectArgs... args) { + std::shared_ptr item; + if constexpr (std::is_same()) + item = std::make_shared(state, handleIndex, args...); + else + item = std::make_shared(state, args...); + handles[handleIndex] = std::static_pointer_cast(item); + return {item, handleIndex++}; + } + + /** + * @brief Inserts an item into the process handle table + * @param item The item to insert + * @return The handle of the corresponding item in the handle table + */ + template + KHandle InsertItem(std::shared_ptr &item) { + handles[handleIndex] = std::static_pointer_cast(item); + return handleIndex++; + } + + /** + * @brief Returns the underlying kernel object for a handle + * @tparam objectClass The class of the kernel object present in the handle + * @param handle The handle of the object + * @return A shared pointer to the object + */ + template + std::shared_ptr GetHandle(KHandle handle) { + KType objectType; + if constexpr(std::is_same()) + objectType = KType::KThread; + else if constexpr(std::is_same()) + objectType = KType::KProcess; + else if constexpr(std::is_same()) + objectType = KType::KSharedMemory; + else if constexpr(std::is_same()) + objectType = KType::KTransferMemory; + else if constexpr(std::is_same()) + objectType = KType::KPrivateMemory; + else if constexpr(std::is_same()) + objectType = KType::KSession; + else if constexpr(std::is_same()) + objectType = KType::KEvent; + else + throw exception("KProcess::GetHandle couldn't determine object type"); + try { + auto item = handles.at(handle); + if (item->objectType == objectType) + return std::static_pointer_cast(item); + else + throw exception("Tried to get kernel object (0x{:X}) with different type: {} when object is {}", handle, objectType, item->objectType); + } catch (std::out_of_range) { + throw exception("GetHandle was called with invalid handle: 0x{:X}", handle); + } + } + + /** + * @brief Retrieves a kernel memory object that owns the specified address + * @param address The address to look for + * @return A shared pointer to the corresponding KMemory object + */ + std::optional> GetMemoryObject(u64 address); + + /** + * @brief This deletes a certain handle from the handle table + * @param handle The handle to delete + */ + inline void DeleteHandle(KHandle handle) { + handles.erase(handle); + } + + /** + * @brief This locks the Mutex at the specified address + * @param address The address of the mutex + * @param owner The handle of the current mutex owner + * @return If the mutex was successfully locked + */ + bool MutexLock(u64 address, KHandle owner); + + /** + * @brief This unlocks the Mutex at the specified address + * @param address The address of the mutex + * @return If the mutex was successfully unlocked + */ + bool MutexUnlock(u64 address); + + /** + * @param conditionalAddress The address of the conditional variable + * @param mutexAddress The address of the mutex + * @param timeout The amount of time to wait for the conditional variable + * @return If the conditional variable was successfully waited for or timed out + */ + bool ConditionalVariableWait(u64 conditionalAddress, u64 mutexAddress, u64 timeout); + + /** + * @brief This signals a number of conditional variable waiters + * @param address The address of the conditional variable + * @param amount The amount of waiters to signal + */ + void ConditionalVariableSignal(u64 address, u64 amount); + + /** + * @brief This resets the object to an unsignalled state + */ + inline void ResetSignal() { + signalled = false; + } + }; + } } diff --git a/app/src/main/cpp/skyline/kernel/types/KSession.h b/app/src/main/cpp/skyline/kernel/types/KSession.h index 4b1442af..3e386905 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSession.h +++ b/app/src/main/cpp/skyline/kernel/types/KSession.h @@ -11,8 +11,8 @@ namespace skyline::kernel::type { class KSession : public KSyncObject { public: const std::shared_ptr serviceObject; //!< A shared pointer to the service class - std::unordered_map> domainTable; //!< This maps from a virtual handle to it's service - handle_t handleIndex = constant::BaseVirtualHandleIndex; + std::unordered_map> domainTable; //!< This maps from a virtual handle to it's service + KHandle handleIndex{0x1}; //!< The currently allocated handle index const service::Service serviceType; //!< The type of the service enum class ServiceStatus { Open, Closed } serviceStatus{ServiceStatus::Open}; //!< If the session is open or closed bool isDomain{}; //!< Holds if this is a domain session or not @@ -27,7 +27,7 @@ namespace skyline::kernel::type { * This converts this session into a domain session (https://switchbrew.org/wiki/IPC_Marshalling#Domains) * @return The virtual handle of this service in the domain */ - handle_t ConvertDomain() { + KHandle ConvertDomain() { isDomain = true; domainTable[handleIndex] = serviceObject; return handleIndex++; diff --git a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp index 286ad94c..888ec1fe 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.cpp @@ -50,7 +50,7 @@ namespace skyline::kernel::type { } void KSharedMemory::Resize(size_t size) { - if (guest.valid() && kernel.valid()) { + if (guest.Valid() && kernel.Valid()) { if (close(fd) < 0) throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno)); fd = ASharedMemory_create("KSharedMemory", size); @@ -98,7 +98,7 @@ namespace skyline::kernel::type { throw exception("An occurred while mapping shared memory: {}", strerror(errno)); guest.size = size; MemoryManager::ResizeChunk(chunk, size); - } else if (kernel.valid()) { + } else if (kernel.Valid()) { if (close(fd) < 0) throw exception("An error occurred while trying to close shared memory FD: {}", strerror(errno)); fd = ASharedMemory_create("KSharedMemory", size); @@ -119,7 +119,7 @@ namespace skyline::kernel::type { } void KSharedMemory::UpdatePermission(u64 address, u64 size, memory::Permission permission, bool host) { - if (guest.valid() && !host) { + if (guest.Valid() && !host) { Registers fregs{ .x0 = address, .x1 = size, @@ -137,7 +137,7 @@ namespace skyline::kernel::type { }; MemoryManager::InsertBlock(chunk, block); } - if (kernel.valid() && host) { + if (kernel.Valid() && host) { if (mprotect(reinterpret_cast(kernel.address), kernel.size, permission.Get()) == reinterpret_cast(MAP_FAILED)) throw exception("An error occurred while remapping shared memory: {}", strerror(errno)); kernel.permission = permission; @@ -146,7 +146,7 @@ namespace skyline::kernel::type { KSharedMemory::~KSharedMemory() { try { - if (guest.valid() && state.process) { + if (guest.Valid() && state.process) { Registers fregs{ .x0 = guest.address, .x1 = guest.size, @@ -156,7 +156,7 @@ namespace skyline::kernel::type { } } catch (const std::exception &) { } - if (kernel.valid()) + if (kernel.Valid()) munmap(reinterpret_cast(kernel.address), kernel.size); state.os->memory.DeleteChunk(guest.address); 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 8dffee25..9fc19d4d 100644 --- a/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KSharedMemory.h @@ -24,7 +24,7 @@ namespace skyline::kernel::type { * @brief Returns if the object is valid * @return If the MapInfo object is valid */ - inline bool valid() { return address && size && permission.Get(); } + inline bool Valid() { return address && size && permission.Get(); } } kernel, guest; /** @@ -35,7 +35,7 @@ namespace skyline::kernel::type { * @param memState The MemoryState of the chunk of memory * @param mmapFlags Additional flags to pass to mmap */ - KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::MemoryStates::SharedMemory, int mmapFlags = 0); + KSharedMemory(const DeviceState &state, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::states::SharedMemory, int mmapFlags = 0); /** * @brief Maps the shared memory in the guest diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index dc1d6783..ccac06c1 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -4,8 +4,7 @@ #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, KHandle handle, pid_t selfPid, u64 entryPoint, u64 entryArg, u64 stackTop, u64 tls, u8 priority, KProcess *parent, std::shared_ptr &tlsMemory) : handle(handle), pid(selfPid), entryPoint(entryPoint), entryArg(entryArg), stackTop(stackTop), tls(tls), priority(priority), parent(parent), ctxMemory(tlsMemory), KSyncObject(state, KType::KThread) { UpdatePriority(priority); } @@ -31,8 +30,9 @@ namespace skyline::kernel::type { void KThread::UpdatePriority(u8 priority) { this->priority = priority; - auto liPriority = static_cast(constant::PriorityAn.first + ((static_cast(constant::PriorityAn.second - constant::PriorityAn.first) / static_cast(constant::PriorityNin.second - constant::PriorityNin.first)) * (static_cast(priority) - constant::PriorityNin.first))); // Resize range PriorityNin (Nintendo Priority) to PriorityAn (Android Priority) - if (setpriority(PRIO_PROCESS, static_cast(pid), liPriority) == -1) - throw exception("Couldn't set process priority to {} for PID: {}", liPriority, pid); + auto linuxPriority = static_cast(constant::AndroidPriority.first + ((static_cast(constant::AndroidPriority.second - constant::AndroidPriority.first) / static_cast(constant::SwitchPriority.second - constant::SwitchPriority.first)) * (static_cast(priority) - constant::SwitchPriority.first))); // Resize range SwitchPriority (Nintendo Priority) to AndroidPriority (Android Priority) + + if (setpriority(PRIO_PROCESS, static_cast(pid), linuxPriority) == -1) + throw exception("Couldn't set process priority to {} for PID: {}", linuxPriority, pid); } } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index 09b4d9ae..1c80ff9b 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -21,7 +21,7 @@ namespace skyline::kernel::type { } status = Status::Created; //!< The state of the thread std::atomic cancelSync{false}; //!< This is to flag to a thread to cancel a synchronization call it currently is in std::shared_ptr ctxMemory; //!< The KSharedMemory of the shared memory allocated by the guest process TLS - handle_t handle; // The handle of the object in the handle table + KHandle 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) u64 tls; //!< The address of TLS (Thread Local Storage) slot assigned to the current thread @@ -30,7 +30,7 @@ namespace skyline::kernel::type { /** * @param state The state of the device * @param handle The handle of the current thread - * @param self_pid The PID of this thread + * @param selfPid The PID of this thread * @param entryPoint The address to start execution at * @param entryArg An argument to pass to the process on entry * @param stackTop The top of the stack @@ -39,7 +39,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, KHandle handle, pid_t selfPid, 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. diff --git a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h index 4f1ddb56..2e59ac51 100644 --- a/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h +++ b/app/src/main/cpp/skyline/kernel/types/KTransferMemory.h @@ -23,7 +23,7 @@ namespace skyline::kernel::type { * @param type The type of the memory * @param memState The MemoryState of the chunk of memory */ - KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::MemoryStates::TransferMemory); + KTransferMemory(const DeviceState &state, bool host, u64 address, size_t size, const memory::Permission permission, memory::MemoryState memState = memory::states::TransferMemory); /** * @brief Transfers this piece of memory to another process diff --git a/app/src/main/cpp/skyline/loader/nro.cpp b/app/src/main/cpp/skyline/loader/nro.cpp index 8a3fa874..883648c2 100644 --- a/app/src/main/cpp/skyline/loader/nro.cpp +++ b/app/src/main/cpp/skyline/loader/nro.cpp @@ -5,7 +5,10 @@ namespace skyline::loader { NroLoader::NroLoader(const int romFd) : Loader(romFd) { ReadOffset((u32 *) &header, 0x0, sizeof(NroHeader)); - if (header.magic != constant::NroMagic) + + constexpr auto nroMagic = 0x304F524E; // "NRO0" in reverse, this is written at the start of every NRO file + + if (header.magic != nroMagic) throw exception("Invalid NRO magic! 0x{0:X}", header.magic); } @@ -26,19 +29,19 @@ namespace skyline::loader { u64 patchSize = patch.size() * sizeof(u32); u64 padding = utils::AlignUp(textSize + rodataSize + dataSize + header.bssSize + patchSize, PAGE_SIZE) - (textSize + rodataSize + dataSize + header.bssSize + patchSize); - process->NewHandle(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::MemoryStates::CodeStatic); // R-X + process->NewHandle(constant::BaseAddress, textSize, memory::Permission{true, true, true}, memory::states::CodeStatic); // R-X state.logger->Debug("Successfully mapped section .text @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress, textSize); - process->NewHandle(constant::BaseAddress + textSize, rodataSize, memory::Permission{true, false, false}, memory::MemoryStates::CodeReadOnly); // R-- + process->NewHandle(constant::BaseAddress + textSize, rodataSize, memory::Permission{true, false, false}, memory::states::CodeReadOnly); // R-- state.logger->Debug("Successfully mapped section .ro @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize, rodataSize); - process->NewHandle(constant::BaseAddress + textSize + rodataSize, dataSize, memory::Permission{true, true, false}, memory::MemoryStates::CodeStatic); // RW- + process->NewHandle(constant::BaseAddress + textSize + rodataSize, dataSize, memory::Permission{true, true, false}, memory::states::CodeStatic); // RW- state.logger->Debug("Successfully mapped section .data @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize + rodataSize, dataSize); - process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize, memory::Permission{true, true, true}, memory::MemoryStates::CodeMutable); // RWX + process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize, memory::Permission{true, true, true}, memory::states::CodeMutable); // RWX state.logger->Debug("Successfully mapped section .bss @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize + rodataSize + dataSize, header.bssSize); - process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize + padding, memory::Permission{true, true, true}, memory::MemoryStates::CodeStatic); // RWX + process->NewHandle(constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize + padding, memory::Permission{true, true, true}, memory::states::CodeStatic); // RWX state.logger->Debug("Successfully mapped section .patch @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddress + textSize + rodataSize + dataSize + header.bssSize, patchSize); process->WriteMemory(text.data(), constant::BaseAddress, textSize); diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index 72745346..f5bbcdd8 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -189,7 +189,9 @@ namespace skyline { if (ctx->sp) regStr += fmt::format("\nStack Pointer: 0x{:X}", ctx->sp); - for (u16 index = 0; index < constant::NumRegs - 1; index += 2) { + constexpr auto numRegisters = 31; //!< The amount of general-purpose registers in ARMv8 + + for (u16 index = 0; index < numRegisters - 2; index += 2) { auto xStr = index < 10 ? " X" : "X"; regStr += fmt::format("\n{}{}: 0x{:<16X} {}{}: 0x{:X}", xStr, index, ctx->registers.regs[index], xStr, index + 1, ctx->registers.regs[index + 1]); } @@ -204,20 +206,26 @@ namespace skyline { } std::vector NCE::PatchCode(std::vector &code, u64 baseAddress, i64 offset) { + constexpr auto TpidrroEl0 = 0x5E83; // ID of TPIDRRO_EL0 in MRS + constexpr auto CntfrqEl0 = 0x5F00; // ID of CNTFRQ_EL0 in MRS + constexpr auto CntpctEl0 = 0x5F01; // ID of CNTPCT_EL0 in MRS + constexpr auto CntvctEl0 = 0x5F02; // ID of CNTVCT_EL0 in MRS + constexpr auto TegraX1Freq = 19200000; // The clock frequency of the Tegra X1 (19.2 MHz) + u32 *start = reinterpret_cast(code.data()); u32 *end = start + (code.size() / sizeof(u32)); i64 patchOffset = offset; - std::vector patch((guest::saveCtxSize + guest::loadCtxSize + guest::svcHandlerSize) / sizeof(u32)); + std::vector patch((guest::SaveCtxSize + guest::LoadCtxSize + guest::SvcHandlerSize) / sizeof(u32)); - std::memcpy(patch.data(), reinterpret_cast(&guest::SaveCtx), guest::saveCtxSize); - offset += guest::saveCtxSize; + std::memcpy(patch.data(), reinterpret_cast(&guest::SaveCtx), guest::SaveCtxSize); + offset += guest::SaveCtxSize; - std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize, reinterpret_cast(&guest::LoadCtx), guest::loadCtxSize); - offset += guest::loadCtxSize; + std::memcpy(reinterpret_cast(patch.data()) + guest::SaveCtxSize, reinterpret_cast(&guest::LoadCtx), guest::LoadCtxSize); + offset += guest::LoadCtxSize; - std::memcpy(reinterpret_cast(patch.data()) + guest::saveCtxSize + guest::loadCtxSize, reinterpret_cast(&guest::SvcHandler), guest::svcHandlerSize); - offset += guest::svcHandlerSize; + std::memcpy(reinterpret_cast(patch.data()) + guest::SaveCtxSize + guest::LoadCtxSize, reinterpret_cast(&guest::SvcHandler), guest::SvcHandlerSize); + offset += guest::SvcHandlerSize; static u64 frequency{}; if (!frequency) @@ -238,10 +246,10 @@ namespace skyline { offset += sizeof(u32) * movPc.size(); instr::Movz movCmd(regs::W1, static_cast(instrSvc->value)); offset += sizeof(movCmd); - instr::BL bSvcHandler((patchOffset + guest::saveCtxSize + guest::loadCtxSize) - offset); + instr::BL bSvcHandler((patchOffset + guest::SaveCtxSize + guest::LoadCtxSize) - offset); offset += sizeof(bSvcHandler); - instr::BL bLdCtx((patchOffset + guest::saveCtxSize) - offset); + instr::BL bLdCtx((patchOffset + guest::SaveCtxSize) - offset); offset += sizeof(bLdCtx); constexpr u32 ldrLr = 0xF84107FE; // LDR LR, [SP], #16 offset += sizeof(ldrLr); @@ -259,7 +267,7 @@ namespace skyline { patch.push_back(ldrLr); patch.push_back(bret.raw); } else if (instrMrs->Verify()) { - if (instrMrs->srcReg == constant::TpidrroEl0) { + if (instrMrs->srcReg == TpidrroEl0) { instr::B bJunc(offset); u32 strX0{}; if (instrMrs->destReg != regs::X0) { @@ -291,10 +299,10 @@ namespace skyline { if (ldrX0) patch.push_back(ldrX0); patch.push_back(bret.raw); - } else if (frequency != constant::TegraX1Freq) { - if (instrMrs->srcReg == constant::CntpctEl0) { + } else if (frequency != TegraX1Freq) { + if (instrMrs->srcReg == CntpctEl0) { instr::B bJunc(offset); - offset += guest::rescaleClockSize; + offset += guest::RescaleClockSize; instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP] ldr.destReg = instrMrs->destReg; offset += sizeof(ldr); @@ -305,14 +313,14 @@ namespace skyline { *address = bJunc.raw; auto size = patch.size(); - patch.resize(size + (guest::rescaleClockSize / sizeof(u32))); - std::memcpy(patch.data() + size, reinterpret_cast(&guest::RescaleClock), guest::rescaleClockSize); + patch.resize(size + (guest::RescaleClockSize / sizeof(u32))); + std::memcpy(patch.data() + size, reinterpret_cast(&guest::RescaleClock), guest::RescaleClockSize); patch.push_back(ldr.raw); patch.push_back(addSp); patch.push_back(bret.raw); - } else if (instrMrs->srcReg == constant::CntfrqEl0) { + } else if (instrMrs->srcReg == CntfrqEl0) { instr::B bJunc(offset); - auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), constant::TegraX1Freq); + auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), TegraX1Freq); offset += sizeof(u32) * movFreq.size(); instr::B bret(-offset + sizeof(u32)); offset += sizeof(bret); @@ -323,8 +331,8 @@ namespace skyline { patch.push_back(bret.raw); } } else { - if (instrMrs->srcReg == constant::CntpctEl0) { - instr::Mrs mrs(constant::CntvctEl0, regs::X(instrMrs->destReg)); + if (instrMrs->srcReg == CntpctEl0) { + instr::Mrs mrs(CntvctEl0, regs::X(instrMrs->destReg)); *address = mrs.raw; } } diff --git a/app/src/main/cpp/skyline/nce/guest.h b/app/src/main/cpp/skyline/nce/guest.h index 9cfce6e7..32e400e5 100644 --- a/app/src/main/cpp/skyline/nce/guest.h +++ b/app/src/main/cpp/skyline/nce/guest.h @@ -2,13 +2,13 @@ namespace skyline { namespace guest { - constexpr size_t saveCtxSize = 20 * sizeof(u32); //!< The size of the SaveCtx function in 32-bit ARMv8 instructions - constexpr size_t loadCtxSize = 20 * sizeof(u32); //!< The size of the LoadCtx function in 32-bit ARMv8 instructions - constexpr size_t rescaleClockSize = 16 * sizeof(u32); //!< The size of the RescaleClock function in 32-bit ARMv8 instructions + constexpr size_t SaveCtxSize = 20 * sizeof(u32); //!< The size of the SaveCtx function in 32-bit ARMv8 instructions + constexpr size_t LoadCtxSize = 20 * sizeof(u32); //!< The size of the LoadCtx function in 32-bit ARMv8 instructions + constexpr size_t RescaleClockSize = 16 * sizeof(u32); //!< The size of the RescaleClock function in 32-bit ARMv8 instructions #ifdef NDEBUG - constexpr size_t svcHandlerSize = 225 * sizeof(u32); //!< The size of the SvcHandler (Release) function in 32-bit ARMv8 instructions + constexpr size_t SvcHandlerSize = 225 * sizeof(u32); //!< The size of the SvcHandler (Release) function in 32-bit ARMv8 instructions #else - constexpr size_t svcHandlerSize = 400 * sizeof(u32); //!< The size of the SvcHandler (Debug) function in 32-bit ARMv8 instructions + constexpr size_t SvcHandlerSize = 400 * sizeof(u32); //!< The size of the SvcHandler (Debug) function in 32-bit ARMv8 instructions #endif /** diff --git a/app/src/main/cpp/skyline/os.cpp b/app/src/main/cpp/skyline/os.cpp index 8021c74b..22fdf615 100644 --- a/app/src/main/cpp/skyline/os.cpp +++ b/app/src/main/cpp/skyline/os.cpp @@ -19,11 +19,11 @@ namespace skyline::kernel { } std::shared_ptr OS::CreateProcess(u64 entry, u64 argument, size_t stackSize) { - auto stack = std::make_shared(state, 0, stackSize, memory::Permission{true, true, false}, memory::MemoryStates::Reserved, MAP_NORESERVE | MAP_STACK); + auto stack = std::make_shared(state, 0, stackSize, memory::Permission{true, true, false}, memory::states::Reserved, MAP_NORESERVE | MAP_STACK); stack->guest = stack->kernel; if (mprotect(reinterpret_cast(stack->guest.address), PAGE_SIZE, PROT_NONE)) 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, false}, memory::MemoryStates::Reserved); + auto tlsMem = std::make_shared(state, 0, (sizeof(ThreadContext) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1), memory::Permission{true, true, false}, memory::states::Reserved); tlsMem->guest = tlsMem->kernel; pid_t pid = clone(reinterpret_cast(&guest::GuestEntry), reinterpret_cast(stack->guest.address + stackSize), CLONE_FILES | CLONE_FS | CLONE_SETTLS | SIGCHLD, reinterpret_cast(entry), nullptr, reinterpret_cast(tlsMem->guest.address)); if (pid == -1) diff --git a/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp b/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp index dd3f2f4f..1b375e0f 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp @@ -11,7 +11,7 @@ namespace skyline::service::audio { {0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)}, {0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)} }) { - track = state.audio->OpenTrack(channelCount, skyline::audio::constant::SampleRate, [this]() { this->releaseEvent->Signal(); }); + track = state.audio->OpenTrack(channelCount, constant::SampleRate, [this]() { this->releaseEvent->Signal(); }); } IAudioOut::~IAudioOut() { @@ -46,7 +46,7 @@ namespace skyline::service::audio { tmpSampleBuffer.resize(data.sampleSize / sizeof(i16)); state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize); - resampler.ResampleBuffer(tmpSampleBuffer, static_cast(sampleRate) / skyline::audio::constant::SampleRate, channelCount); + resampler.ResampleBuffer(tmpSampleBuffer, static_cast(sampleRate) / constant::SampleRate, channelCount); track->AppendBuffer(tmpSampleBuffer, tag); } diff --git a/app/src/main/cpp/skyline/services/audio/IAudioOutManager.cpp b/app/src/main/cpp/skyline/services/audio/IAudioOutManager.cpp index 2c6dc24b..85ce7767 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioOutManager.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioOutManager.cpp @@ -20,8 +20,8 @@ namespace skyline::service::audio { state.logger->Debug("audoutU: Opening an IAudioOut with sample rate: {}, channel count: {}", sampleRate, channelCount); - sampleRate = sampleRate ? sampleRate : skyline::audio::constant::SampleRate; - channelCount = channelCount ? channelCount : static_cast(skyline::audio::constant::ChannelCount); + sampleRate = sampleRate ? sampleRate : constant::SampleRate; + channelCount = channelCount ? channelCount : static_cast(constant::ChannelCount); manager.RegisterService(std::make_shared(state, manager, channelCount, sampleRate), session, response); response.Push(sampleRate); diff --git a/app/src/main/cpp/skyline/services/audio/IAudioOutManager.h b/app/src/main/cpp/skyline/services/audio/IAudioOutManager.h index f90e9510..dfc040fb 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioOutManager.h +++ b/app/src/main/cpp/skyline/services/audio/IAudioOutManager.h @@ -3,27 +3,28 @@ #include #include #include - -namespace skyline::service::audio { +namespace skyline { namespace constant { constexpr std::string_view DefaultAudioOutName = "DeviceOut"; //!< The default audio output device name }; - /** - * @brief IAudioOutManager or audout:u is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u) - */ - class IAudioOutManager : public BaseService { - public: - IAudioOutManager(const DeviceState &state, ServiceManager &manager); - + namespace service::audio { /** - * @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts) + * @brief IAudioOutManager or audout:u is used to manage audio outputs (https://switchbrew.org/wiki/Audio_services#audout:u) */ - void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + class IAudioOutManager : public BaseService { + public: + IAudioOutManager(const DeviceState &state, ServiceManager &manager); - /** - * @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut) - */ - void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - }; + /** + * @brief Returns a list of all available audio outputs (https://switchbrew.org/wiki/Audio_services#ListAudioOuts) + */ + void ListAudioOuts(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Creates a new audoutU::IAudioOut object and returns a handle to it (https://switchbrew.org/wiki/Audio_services#OpenAudioOut) + */ + void OpenAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; + } } diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp index 14b9754d..7e650c0b 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.cpp @@ -13,7 +13,7 @@ namespace skyline::service::audio::IAudioRenderer { {0x6, SFUNC(IAudioRenderer::Stop)}, {0x7, SFUNC(IAudioRenderer::QuerySystemEvent)}, }) { - track = state.audio->OpenTrack(skyline::audio::constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); }); + track = state.audio->OpenTrack(constant::ChannelCount, params.sampleRate, [this]() { this->releaseEvent->Signal(); }); track->Start(); memoryPools.resize(memoryPoolCount); @@ -132,7 +132,7 @@ namespace skyline::service::audio::IAudioRenderer { void IAudioRenderer::MixFinalBuffer() { int setIndex = 0; - sampleBuffer.resize(samplesPerBuffer * skyline::audio::constant::ChannelCount); + sampleBuffer.resize(static_cast(samplesPerBuffer * constant::ChannelCount)); for (auto &voice : voices) { if (!voice.Playable()) @@ -149,7 +149,7 @@ namespace skyline::service::audio::IAudioRenderer { if (voiceBufferSize == 0) break; - pendingSamples -= voiceBufferSize / skyline::audio::constant::ChannelCount; + pendingSamples -= voiceBufferSize / constant::ChannelCount; for (int i = voiceBufferOffset; i < voiceBufferOffset + voiceBufferSize; i++) { if (setIndex == bufferOffset) { diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h index 326a401c..b48e399d 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/IAudioRenderer.h @@ -9,127 +9,130 @@ #include "voice.h" #include "revisionInfo.h" -namespace skyline::service::audio::IAudioRenderer { +namespace skyline { namespace constant { - constexpr int BufferAlignment = 0x40; //!< The alignment for all audren buffers + constexpr auto BufferAlignment = 0x40; //!< The alignment for all audren buffers } - /** - * @brief The parameters used to configure an IAudioRenderer - */ - struct AudioRendererParams { - u32 sampleRate; //!< The sample rate to use for the renderer - u32 sampleCount; //!< The buffer sample count - u32 mixBufferCount; //!< The amount of mix buffers to use - u32 subMixCount; //!< The amount of sub mixes to use - u32 voiceCount; //!< The amount of voices to use - u32 sinkCount; //!< The amount of sinks to use - u32 effectCount; //!< The amount of effects to use - u32 performanceManagerCount; //!< The amount of performance managers to use - u32 voiceDropEnable; //!< Whether to enable voice drop - u32 splitterCount; //!< The amount of splitters to use - u32 splitterDestinationDataCount; //!< The amount of splitter destination outputs to use - u32 _unk0_; - u32 revision; //!< The revision of audren to use - }; - static_assert(sizeof(AudioRendererParams) == 0x34); - - /** - * @brief Header containing information about the software side audren implementation - */ - struct UpdateDataHeader { - u32 revision; //!< Revision of the software implementation - u32 behaviorSize; //!< The total size of the behaviour info - u32 memoryPoolSize; //!< The total size of all MemoryPoolIn structs - u32 voiceSize; //!< The total size of all VoiceIn structs - u32 voiceResourceSize; //!< The total size of the voice resources - u32 effectSize; //!< The total size of all EffectIn structs - u32 mixSize; //!< The total size of all mixer descriptors in the input - u32 sinkSize; //!< The total size of all sink descriptors in the input - u32 performanceManagerSize; //!< The total size of all performance manager descriptors in the input - u32 _unk0_; - u32 elapsedFrameCountInfoSize; //!< The total size of all the elapsed frame info - u32 _unk1_[4]; - u32 totalSize; //!< The total size of the whole input - }; - static_assert(sizeof(UpdateDataHeader) == 0x40); - - /** - * @brief IAudioRenderer is used to control an audio renderer output (https://switchbrew.org/wiki/Audio_services#IAudioRenderer) - */ - class IAudioRenderer : public BaseService { - private: - AudioRendererParams rendererParams; //!< The parameters to use for the renderer - RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used - std::shared_ptr track; //!< The audio track associated with the audio renderer - std::shared_ptr releaseEvent; //!< The KEvent that is signalled when a buffer has been released - std::vector memoryPools; //!< An vector of all memory pools that the guest may need - std::vector effects; //!< An vector of all effects that the guest may need - std::vector voices; //!< An vector of all voices that the guest may need - std::vector sampleBuffer; //!< The final output data that is appended to the stream - - skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback - const size_t memoryPoolCount; //!< The amount of memory pools the guest may need - const int samplesPerBuffer; //!< The amount of samples each appended buffer should contain + namespace service::audio::IAudioRenderer { /** - * @brief Obtains new sample data from voices and mixes it together into the sample buffer + * @brief The parameters used to configure an IAudioRenderer */ - void MixFinalBuffer(); + struct AudioRendererParams { + u32 sampleRate; //!< The sample rate to use for the renderer + u32 sampleCount; //!< The buffer sample count + u32 mixBufferCount; //!< The amount of mix buffers to use + u32 subMixCount; //!< The amount of sub mixes to use + u32 voiceCount; //!< The amount of voices to use + u32 sinkCount; //!< The amount of sinks to use + u32 effectCount; //!< The amount of effects to use + u32 performanceManagerCount; //!< The amount of performance managers to use + u32 voiceDropEnable; //!< Whether to enable voice drop + u32 splitterCount; //!< The amount of splitters to use + u32 splitterDestinationDataCount; //!< The amount of splitter destination outputs to use + u32 _unk0_; + u32 revision; //!< The revision of audren to use + }; + static_assert(sizeof(AudioRendererParams) == 0x34); /** - * @brief Appends all released buffers with new mixed sample data + * @brief Header containing information about the software side audren implementation */ - void UpdateAudio(); - - public: - /** - * @param params The parameters to use for rendering - */ - IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms); + struct UpdateDataHeader { + u32 revision; //!< Revision of the software implementation + u32 behaviorSize; //!< The total size of the behaviour info + u32 memoryPoolSize; //!< The total size of all MemoryPoolIn structs + u32 voiceSize; //!< The total size of all VoiceIn structs + u32 voiceResourceSize; //!< The total size of the voice resources + u32 effectSize; //!< The total size of all EffectIn structs + u32 mixSize; //!< The total size of all mixer descriptors in the input + u32 sinkSize; //!< The total size of all sink descriptors in the input + u32 performanceManagerSize; //!< The total size of all performance manager descriptors in the input + u32 _unk0_; + u32 elapsedFrameCountInfoSize; //!< The total size of all the elapsed frame info + u32 _unk1_[4]; + u32 totalSize; //!< The total size of the whole input + }; + static_assert(sizeof(UpdateDataHeader) == 0x40); /** - * @brief Closes the audio track - */ - ~IAudioRenderer(); - - /** - * @brief Returns the sample rate (https://switchbrew.org/wiki/Audio_services#GetSampleRate) - */ - void GetSampleRate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - - /** - * @brief Returns the sample count (https://switchbrew.org/wiki/Audio_services#GetSampleCount) + * @brief IAudioRenderer is used to control an audio renderer output (https://switchbrew.org/wiki/Audio_services#IAudioRenderer) */ - void GetSampleCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + class IAudioRenderer : public BaseService { + private: + AudioRendererParams rendererParams; //!< The parameters to use for the renderer + RevisionInfo revisionInfo{}; //!< Stores info about supported features for the audren revision used + std::shared_ptr track; //!< The audio track associated with the audio renderer + std::shared_ptr releaseEvent; //!< The KEvent that is signalled when a buffer has been released + std::vector memoryPools; //!< An vector of all memory pools that the guest may need + std::vector effects; //!< An vector of all effects that the guest may need + std::vector voices; //!< An vector of all voices that the guest may need + std::vector sampleBuffer; //!< The final output data that is appended to the stream - /** - * @brief Returns the number of mix buffers (https://switchbrew.org/wiki/Audio_services#GetMixBufferCount) - */ - void GetMixBufferCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + skyline::audio::AudioOutState playbackState{skyline::audio::AudioOutState::Stopped}; //!< The current state of playback + const size_t memoryPoolCount; //!< The amount of memory pools the guest may need + const int samplesPerBuffer; //!< The amount of samples each appended buffer should contain - /** - * @brief Returns the state of the renderer (https://switchbrew.org/wiki/Audio_services#GetAudioRendererState) (stubbed)? - */ - void GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Obtains new sample data from voices and mixes it together into the sample buffer + */ + void MixFinalBuffer(); - /** - * @brief Updates the audio renderer state and appends new data to playback buffers - */ - void RequestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Appends all released buffers with new mixed sample data + */ + void UpdateAudio(); - /** - * @brief Start the audio stream from the renderer - */ - void Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + public: + /** + * @param params The parameters to use for rendering + */ + IAudioRenderer(const DeviceState &state, ServiceManager &manager, AudioRendererParams ¶ms); - /** - * @brief Stop the audio stream from the renderer - */ - void Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Closes the audio track + */ + ~IAudioRenderer(); - /** - * @brief Returns a handle to the sample release KEvent - */ - void QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - }; + /** + * @brief Returns the sample rate (https://switchbrew.org/wiki/Audio_services#GetSampleRate) + */ + void GetSampleRate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Returns the sample count (https://switchbrew.org/wiki/Audio_services#GetSampleCount) + */ + void GetSampleCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Returns the number of mix buffers (https://switchbrew.org/wiki/Audio_services#GetMixBufferCount) + */ + void GetMixBufferCount(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Returns the state of the renderer (https://switchbrew.org/wiki/Audio_services#GetAudioRendererState) (stubbed)? + */ + void GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Updates the audio renderer state and appends new data to playback buffers + */ + void RequestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Start the audio stream from the renderer + */ + void Start(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Stop the audio stream from the renderer + */ + void Stop(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Returns a handle to the sample release KEvent + */ + void QuerySystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; + } } diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/revisionInfo.h b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/revisionInfo.h index 11c1c649..ac8f19e7 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/revisionInfo.h +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/revisionInfo.h @@ -1,8 +1,7 @@ #pragma once #include - -namespace skyline::service::audio::IAudioRenderer { +namespace skyline { namespace constant { constexpr u32 SupportedRevision = 7; //!< The audren revision our implementation supports constexpr u32 Rev0Magic = ('R' << 0) | ('E' << 8) | ('V' << 16) | ('0' << 24); //!< The HOS 1.0 revision magic @@ -17,67 +16,69 @@ namespace skyline::service::audio::IAudioRenderer { }; } - /** - * @brief Extracts the audren version from a revision magic - * @param revision The revision magic - * @return The revision number from the magic - */ - inline u32 ExtractVersionFromRevision(u32 revision) { - return (revision - constant::Rev0Magic) >> 24; + namespace service::audio::IAudioRenderer { + /** + * @brief Extracts the audren version from a revision magic + * @param revision The revision magic + * @return The revision number from the magic + */ + inline u32 ExtractVersionFromRevision(u32 revision) { + return (revision - constant::Rev0Magic) >> 24; + } + + /** + * @brief The RevisionInfo class is used to query the supported features of various audren revisions + */ + class RevisionInfo { + private: + u32 userRevision; //!< The current audren revision of the guest + + public: + /** + * @brief Extracts the audren revision from the magic and sets the behaviour revision to it + * @param revision The revision magic from guest + */ + inline void SetUserRevision(u32 revision) { + userRevision = ExtractVersionFromRevision(revision); + + if (userRevision > constant::SupportedRevision) + throw exception("Unsupported audren revision: {}", userRevision); + } + + /** + * @return Whether the splitter is supported + */ + inline bool SplitterSupported() { + return userRevision >= constant::supportTags::Splitter; + } + + /** + * @return Whether the splitter is fixed + */ + inline bool SplitterBugFixed() { + return userRevision >= constant::supportTags::SplitterBugFix; + } + + /** + * @return Whether the new performance metrics format is used + */ + inline bool UsesPerformanceMetricDataFormatV2() { + return userRevision >= constant::supportTags::PerformanceMetricsDataFormatV2; + } + + /** + * @return Whether varying command buffer sizes are supported + */ + inline bool VaradicCommandBufferSizeSupported() { + return userRevision >= constant::supportTags::VaradicCommandBufferSize; + } + + /** + * @return Whether elapsed frame counting is supported + */ + inline bool ElapsedFrameCountSupported() { + return userRevision >= constant::supportTags::ElapsedFrameCount; + } + }; } - - /** - * @brief The RevisionInfo class is used to query the supported features of various audren revisions - */ - class RevisionInfo { - private: - u32 userRevision; //!< The current audren revision of the guest - - public: - /** - * @brief Extracts the audren revision from the magic and sets the behaviour revision to it - * @param revision The revision magic from guest - */ - inline void SetUserRevision(u32 revision) { - userRevision = ExtractVersionFromRevision(revision); - - if (userRevision > constant::SupportedRevision) - throw exception("Unsupported audren revision: {}", userRevision); - } - - /** - * @return Whether the splitter is supported - */ - inline bool SplitterSupported() { - return userRevision >= constant::supportTags::Splitter; - } - - /** - * @return Whether the splitter is fixed - */ - inline bool SplitterBugFixed() { - return userRevision >= constant::supportTags::SplitterBugFix; - } - - /** - * @return Whether the new performance metrics format is used - */ - inline bool UsesPerformanceMetricDataFormatV2() { - return userRevision >= constant::supportTags::PerformanceMetricsDataFormatV2; - } - - /** - * @return Whether varying command buffer sizes are supported - */ - inline bool VaradicCommandBufferSizeSupported() { - return userRevision >= constant::supportTags::VaradicCommandBufferSize; - } - - /** - * @return Whether elapsed frame counting is supported - */ - inline bool ElapsedFrameCountSupported() { - return userRevision >= constant::supportTags::ElapsedFrameCount; - } - }; } diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.cpp b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.cpp index 7f3b8893..7be0d3eb 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.cpp @@ -55,15 +55,15 @@ namespace skyline::service::audio::IAudioRenderer { throw exception("Unsupported voice PCM format: {}", pcmFormat); } - if (sampleRate != skyline::audio::constant::SampleRate) - sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast(sampleRate) / skyline::audio::constant::SampleRate, channelCount); + if (sampleRate != constant::SampleRate) + sampleBuffer = resampler.ResampleBuffer(sampleBuffer, static_cast(sampleRate) / constant::SampleRate, channelCount); - if (channelCount == 1 && skyline::audio::constant::ChannelCount != channelCount) { + if (channelCount == 1 && constant::ChannelCount != channelCount) { size_t originalSize = sampleBuffer.size(); - sampleBuffer.resize((originalSize / channelCount) * skyline::audio::constant::ChannelCount); + sampleBuffer.resize((originalSize / channelCount) * constant::ChannelCount); for (size_t monoIndex = originalSize - 1, targetIndex = sampleBuffer.size(); monoIndex > 0; monoIndex--) - for (uint i = 0; i < skyline::audio::constant::ChannelCount; i++) + for (uint i = 0; i < constant::ChannelCount; i++) sampleBuffer[--targetIndex] = sampleBuffer[monoIndex]; } } @@ -82,9 +82,9 @@ namespace skyline::service::audio::IAudioRenderer { } outOffset = sampleOffset; - outSize = std::min(maxSamples * skyline::audio::constant::ChannelCount, static_cast(sampleBuffer.size() - sampleOffset)); + outSize = std::min(maxSamples * constant::ChannelCount, static_cast(sampleBuffer.size() - sampleOffset)); - output.playedSamplesCount += outSize / skyline::audio::constant::ChannelCount; + output.playedSamplesCount += outSize / constant::ChannelCount; sampleOffset += outSize; if (sampleOffset == sampleBuffer.size()) { diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.h b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.h index ba18bf13..1c47f03c 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.h +++ b/app/src/main/cpp/skyline/services/audio/IAudioRenderer/voice.h @@ -91,7 +91,7 @@ namespace skyline::service::audio::IAudioRenderer { bool acquired{false}; //!< If the voice is in use bool bufferReload{true}; //!< If the buffer needs to be updated - int bufferIndex{}; //!< The index of the wave buffer currently in use + uint bufferIndex{}; //!< The index of the wave buffer currently in use int sampleOffset{}; //!< The offset in the sample data of the current wave buffer int sampleRate{}; //!< The sample rate of the sample data int channelCount{}; //!< The amount of channels in the sample data diff --git a/app/src/main/cpp/skyline/services/audio/IAudioRendererManager.cpp b/app/src/main/cpp/skyline/services/audio/IAudioRendererManager.cpp index 4e5270a8..dd8ae325 100644 --- a/app/src/main/cpp/skyline/services/audio/IAudioRendererManager.cpp +++ b/app/src/main/cpp/skyline/services/audio/IAudioRendererManager.cpp @@ -25,25 +25,25 @@ namespace skyline::service::audio { u32 totalMixCount = params.subMixCount + 1; - i64 size = utils::AlignUp(params.mixBufferCount * 4, IAudioRenderer::constant::BufferAlignment) + + i64 size = utils::AlignUp(params.mixBufferCount * 4, constant::BufferAlignment) + params.subMixCount * 0x400 + totalMixCount * 0x940 + params.voiceCount * 0x3F0 + utils::AlignUp(totalMixCount * 8, 16) + utils::AlignUp(params.voiceCount * 8, 16) + - utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), IAudioRenderer::constant::BufferAlignment) + + utils::AlignUp(((params.sinkCount + params.subMixCount) * 0x3C0 + params.sampleCount * 4) * (params.mixBufferCount + 6), constant::BufferAlignment) + (params.sinkCount + params.subMixCount) * 0x2C0 + (params.effectCount + params.voiceCount * 4) * 0x30 + 0x50; if (revisionInfo.SplitterSupported()) { - i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, IAudioRenderer::constant::BufferAlignment); + i32 nodeStateWorkSize = utils::AlignUp(totalMixCount, constant::BufferAlignment); if (nodeStateWorkSize < 0) nodeStateWorkSize |= 7; nodeStateWorkSize = 4 * (totalMixCount * totalMixCount) + 12 * totalMixCount + 2 * (nodeStateWorkSize / 8); - i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, IAudioRenderer::constant::BufferAlignment); + i32 edgeMatrixWorkSize = utils::AlignUp(totalMixCount * totalMixCount, constant::BufferAlignment); if (edgeMatrixWorkSize < 0) edgeMatrixWorkSize |= 7; diff --git a/app/src/main/cpp/skyline/services/common/parcel.cpp b/app/src/main/cpp/skyline/services/common/parcel.cpp index 1150fdc7..55667b07 100644 --- a/app/src/main/cpp/skyline/services/common/parcel.cpp +++ b/app/src/main/cpp/skyline/services/common/parcel.cpp @@ -3,14 +3,19 @@ #include namespace skyline::service { - Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state) : Parcel(buffer.address, buffer.size, state) {} + Parcel::Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state, bool hasToken) : Parcel(buffer.address, buffer.size, state, hasToken) {} - Parcel::Parcel(u64 address, u64 size, const DeviceState &state) : state(state) { + Parcel::Parcel(u64 address, u64 size, const DeviceState &state, bool hasToken) : state(state) { state.process->ReadMemory(&header, address, sizeof(ParcelHeader)); + if (size < (sizeof(ParcelHeader) + header.dataSize + header.objectsSize)) throw exception("The size of the parcel according to the header exceeds the specified size"); - data.resize(header.dataSize); - state.process->ReadMemory(data.data(), address + header.dataOffset, header.dataSize); + + constexpr auto tokenLength = 0x50; // The length of the token on BufferQueue parcels + + data.resize(header.dataSize - (hasToken ? tokenLength : 0)); + state.process->ReadMemory(data.data(), address + header.dataOffset + (hasToken ? tokenLength : 0), header.dataSize - (hasToken ? tokenLength : 0)); + objects.resize(header.objectsSize); state.process->ReadMemory(objects.data(), address + header.objectsOffset, header.objectsSize); } @@ -24,14 +29,19 @@ namespace skyline::service { u64 Parcel::WriteParcel(u64 address, u64 maxSize) { header.dataSize = static_cast(data.size()); header.dataOffset = sizeof(ParcelHeader); + header.objectsSize = static_cast(objects.size()); header.objectsOffset = sizeof(ParcelHeader) + data.size(); - u64 totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize; + + auto totalSize = sizeof(ParcelHeader) + header.dataSize + header.objectsSize; + if (maxSize < totalSize) throw exception("The size of the parcel exceeds maxSize"); + state.process->WriteMemory(header, address); state.process->WriteMemory(data.data(), address + header.dataOffset, data.size()); state.process->WriteMemory(objects.data(), address + header.objectsOffset, objects.size()); + return totalSize; } } diff --git a/app/src/main/cpp/skyline/services/common/parcel.h b/app/src/main/cpp/skyline/services/common/parcel.h index c7ff5d5a..871ef62c 100644 --- a/app/src/main/cpp/skyline/services/common/parcel.h +++ b/app/src/main/cpp/skyline/services/common/parcel.h @@ -10,7 +10,7 @@ namespace skyline::service { class Parcel { private: /** - * @brief This holds the header of a parcel + * @brief The header of an Android Parcel structure */ struct ParcelHeader { u32 dataSize; @@ -30,16 +30,18 @@ namespace skyline::service { * @brief This constructor fills in the Parcel object with data from a IPC buffer * @param buffer The buffer that contains the parcel * @param state The state of the device + * @param hasToken If the parcel starts with a token, it is skipped if this flag is true */ - Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state); + Parcel(kernel::ipc::InputBuffer &buffer, const DeviceState &state, bool hasToken = false); /** * @brief This constructor fills in the Parcel object with data from a Parcel on a remote process * @param address The remote address of the parcel * @param size The size of the parcel * @param state The state of the device + * @param hasToken If the parcel starts with a token, it is skipped if this flag is true */ - Parcel(u64 address, u64 size, const DeviceState &state); + Parcel(u64 address, u64 size, const DeviceState &state, bool hasToken = false); /** * @brief This constructor is used to create an empty parcel then write to a process diff --git a/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp b/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp index 6a167d3f..ca6bfd8d 100644 --- a/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp +++ b/app/src/main/cpp/skyline/services/hid/IAppletResource.cpp @@ -6,7 +6,7 @@ namespace skyline::service::hid { }) {} void IAppletResource::GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - hidSharedMemory = std::make_shared(state, NULL, constant::hidSharedMemSize, memory::Permission{true, false, false}); + hidSharedMemory = std::make_shared(state, NULL, constant::HidSharedMemSize, memory::Permission{true, false, false}); auto handle = state.process->InsertItem(hidSharedMemory); state.logger->Debug("HID Shared Memory Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); diff --git a/app/src/main/cpp/skyline/services/hid/IAppletResource.h b/app/src/main/cpp/skyline/services/hid/IAppletResource.h index 6e017bac..796b2555 100644 --- a/app/src/main/cpp/skyline/services/hid/IAppletResource.h +++ b/app/src/main/cpp/skyline/services/hid/IAppletResource.h @@ -3,24 +3,25 @@ #include #include #include - -namespace skyline::service::hid { +namespace skyline { namespace constant { - constexpr size_t hidSharedMemSize = 0x40000; //!< The size of HID Shared Memory (https://switchbrew.org/wiki/HID_Shared_Memory) + constexpr auto HidSharedMemSize = 0x40000; //!< The size of HID Shared Memory (https://switchbrew.org/wiki/HID_Shared_Memory) } - /** - * @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource) - */ - class IAppletResource : public BaseService { - public: - std::shared_ptr hidSharedMemory; //!< A pointer to HID shared memory - - IAppletResource(const DeviceState &state, ServiceManager &manager); - + namespace service::hid { /** - * @brief This opens a handle to HID shared memory (https://switchbrew.org/wiki/HID_services#GetSharedMemoryHandle) + * @brief IAppletResource is used to get a handle to the HID shared memory (https://switchbrew.org/wiki/HID_services#IAppletResource) */ - void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - }; + class IAppletResource : public BaseService { + public: + std::shared_ptr hidSharedMemory; //!< A pointer to HID shared memory + + IAppletResource(const DeviceState &state, ServiceManager &manager); + + /** + * @brief This opens a handle to HID shared memory (https://switchbrew.org/wiki/HID_services#GetSharedMemoryHandle) + */ + void GetSharedMemoryHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + }; + } } diff --git a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp index 0e636a31..c475aba1 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/IHOSBinderDriver.cpp @@ -14,7 +14,7 @@ namespace skyline::service::hosbinder { }) {} void IHOSBinderDriver::RequestBuffer(Parcel &in, Parcel &out) { - u32 slot = *reinterpret_cast(in.data.data() + constant::TokenLength); + u32 slot = *reinterpret_cast(in.data.data()); out.WriteData(1); out.WriteData(sizeof(GbpBuffer)); out.WriteData(0); @@ -29,7 +29,7 @@ namespace skyline::service::hosbinder { u32 height; u32 timestamps; u32 usage; - } *data = reinterpret_cast(in.data.data() + constant::TokenLength); + } *data = reinterpret_cast(in.data.data()); i64 slot{-1}; while (slot == -1) { @@ -66,7 +66,7 @@ namespace skyline::service::hosbinder { u64 _unk0_; u32 swapInterval; Fence fence[4]; - } *data = reinterpret_cast(in.data.data() + constant::TokenLength); + } *data = reinterpret_cast(in.data.data()); auto buffer = queue.at(data->slot); buffer->status = BufferStatus::Queued; @@ -100,13 +100,13 @@ namespace skyline::service::hosbinder { struct Data { u32 slot; Fence fence[4]; - } *data = reinterpret_cast(parcel.data.data() + constant::TokenLength); + } *data = reinterpret_cast(parcel.data.data()); FreeBuffer(data->slot); state.logger->Debug("CancelBuffer: Slot: {}", data->slot); } void IHOSBinderDriver::SetPreallocatedBuffer(Parcel &parcel) { - auto pointer = parcel.data.data() + constant::TokenLength; + auto pointer = parcel.data.data(); struct Data { u32 slot; u32 _unk0_; @@ -159,7 +159,7 @@ namespace skyline::service::hosbinder { auto layerId = request.Pop(); auto code = request.Pop(); - Parcel in(request.inputBuf.at(0), state); + Parcel in(request.inputBuf.at(0), state, true); Parcel out(state); state.logger->Debug("TransactParcel: Layer ID: {}, Code: {}", layerId, code); @@ -211,7 +211,7 @@ namespace skyline::service::hosbinder { } void IHOSBinderDriver::GetNativeHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - handle_t handle = state.process->InsertItem(state.gpu->bufferEvent); + KHandle handle = state.process->InsertItem(state.gpu->bufferEvent); state.logger->Debug("Display Buffer Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); response.Push(constant::status::Success); @@ -219,7 +219,7 @@ namespace skyline::service::hosbinder { void IHOSBinderDriver::SetDisplay(const std::string &name) { try { - const auto type = displayTypeMap.at(name); + const auto type = DisplayTypeMap.at(name); if (displayId == DisplayId::Null) displayId = type; else diff --git a/app/src/main/cpp/skyline/services/hosbinder/display.h b/app/src/main/cpp/skyline/services/hosbinder/display.h index e99ee5ea..05e08693 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/display.h +++ b/app/src/main/cpp/skyline/services/hosbinder/display.h @@ -17,7 +17,7 @@ namespace skyline::service::hosbinder { /** * @brief A mapping from a display's name to it's displayType entry */ - static const std::unordered_map displayTypeMap{ + static const std::unordered_map DisplayTypeMap{ {"Default", DisplayId::Default}, {"External", DisplayId::External}, {"Edid", DisplayId::Edid}, diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h index 8e0d8870..e5e65f22 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h @@ -32,8 +32,8 @@ namespace skyline::service::nvdrv::device { NvMapObject(u32 id, u32 size); }; - std::unordered_map> handleTable; //!< A mapping from a handle to it's corresponding NvMapObject - handle_t handleIndex{1}; //!< This is used to keep track of the next handle to allocate + std::unordered_map> handleTable; //!< A mapping from a handle to it's corresponding NvMapObject + KHandle handleIndex{1}; //!< This is used to keep track of the next handle to allocate u32 idIndex{1}; //!< This is used to keep track of the next ID to allocate NvMap(const DeviceState &state); diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index 7aeda422..bc86e50f 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -70,7 +70,7 @@ namespace skyline::service { return serviceObj; } - handle_t ServiceManager::NewSession(const Service serviceType) { + KHandle ServiceManager::NewSession(const Service serviceType) { std::lock_guard serviceGuard(mutex); return state.process->NewHandle(CreateService(serviceType)).handle; } @@ -78,7 +78,7 @@ namespace skyline::service { std::shared_ptr ServiceManager::NewService(const std::string &serviceName, type::KSession &session, ipc::IpcResponse &response) { std::lock_guard serviceGuard(mutex); auto serviceObject = CreateService(ServiceString.at(serviceName)); - handle_t handle{}; + KHandle handle{}; if (response.isDomain) { session.domainTable[++session.handleIndex] = serviceObject; response.domainObjects.push_back(session.handleIndex); @@ -93,7 +93,7 @@ namespace skyline::service { void ServiceManager::RegisterService(std::shared_ptr serviceObject, type::KSession &session, ipc::IpcResponse &response, bool submodule) { // NOLINT(performance-unnecessary-value-param) std::lock_guard serviceGuard(mutex); - handle_t handle{}; + KHandle handle{}; if (response.isDomain) { session.domainTable[session.handleIndex] = serviceObject; response.domainObjects.push_back(session.handleIndex); @@ -107,7 +107,7 @@ namespace skyline::service { state.logger->Debug("Service has been registered: \"{}\" (0x{:X})", serviceObject->serviceName, handle); } - void ServiceManager::CloseSession(const handle_t handle) { + void ServiceManager::CloseSession(const KHandle handle) { std::lock_guard serviceGuard(mutex); auto session = state.process->GetHandle(handle); if (session->serviceStatus == type::KSession::ServiceStatus::Open) { @@ -121,7 +121,7 @@ namespace skyline::service { } }; - void ServiceManager::SyncRequestHandler(const handle_t handle) { + void ServiceManager::SyncRequestHandler(const KHandle handle) { auto session = state.process->GetHandle(handle); state.logger->Debug("----Start----"); state.logger->Debug("Handle is 0x{:X}", handle); diff --git a/app/src/main/cpp/skyline/services/serviceman.h b/app/src/main/cpp/skyline/services/serviceman.h index 2cbaa1d8..81445464 100644 --- a/app/src/main/cpp/skyline/services/serviceman.h +++ b/app/src/main/cpp/skyline/services/serviceman.h @@ -32,7 +32,7 @@ namespace skyline::service { * @param serviceType The type of the service * @return Handle to KService object of the service */ - handle_t NewSession(const Service serviceType); + KHandle NewSession(const Service serviceType); /** * @brief Creates a new service using it's type enum and writes it's handle or virtual handle (If it's a domain request) to IpcResponse @@ -66,12 +66,12 @@ namespace skyline::service { * @brief Closes an existing session to a service * @param service The handle of the KService object */ - void CloseSession(const handle_t handle); + void CloseSession(const KHandle handle); /** * @brief Handles a Synchronous IPC Request * @param handle The handle of the object */ - void SyncRequestHandler(const handle_t handle); + void SyncRequestHandler(const KHandle handle); }; } diff --git a/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.cpp b/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.cpp index 990248f7..d7febd9f 100644 --- a/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.cpp +++ b/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.cpp @@ -17,11 +17,11 @@ namespace skyline::service::timesrv { }; response.Push(calendarTime); CalendarAdditionalInfo calendarInfo{ - .day_week = static_cast(calender.tm_wday), - .day_month = static_cast(calender.tm_mday), + .dayWeek = static_cast(calender.tm_wday), + .dayMonth = static_cast(calender.tm_mday), .name = *reinterpret_cast(calender.tm_zone), .dst = static_cast(calender.tm_isdst), - .utc_rel = static_cast(calender.tm_gmtoff) + .utcRel = static_cast(calender.tm_gmtoff) }; response.Push(calendarInfo); } diff --git a/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.h b/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.h index d777163b..85ea2c01 100644 --- a/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.h +++ b/app/src/main/cpp/skyline/services/timesrv/ITimeZoneService.h @@ -27,11 +27,11 @@ namespace skyline::service::timesrv { * @brief This is passed in addition to CalendarTime */ struct CalendarAdditionalInfo { - u32 day_week; - u32 day_month; + u32 dayWeek; + u32 dayMonth; u64 name; i32 dst; - u32 utc_rel; + u32 utcRel; }; static_assert(sizeof(CalendarAdditionalInfo) == 0x18); diff --git a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp index a570ee00..88fd48b0 100644 --- a/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp +++ b/app/src/main/cpp/skyline/services/visrv/IApplicationDisplayService.cpp @@ -88,7 +88,7 @@ namespace skyline::service::visrv { } void IApplicationDisplayService::GetDisplayVsyncEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - handle_t handle = state.process->InsertItem(state.gpu->vsyncEvent); + KHandle handle = state.process->InsertItem(state.gpu->vsyncEvent); state.logger->Debug("VSync Event Handle: 0x{:X}", handle); response.copyHandles.push_back(handle); }