From c65c91e1bcedcb4ff6571678ac64dd2d95583000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Wed, 21 Oct 2020 22:39:35 +0530 Subject: [PATCH] Implement NPDM, Core Mask SVCs + Fix VMM bug + Introduce Verbose Log Level --- app/CMakeLists.txt | 35 +++--- app/src/main/cpp/skyline/common.cpp | 4 +- app/src/main/cpp/skyline/common.h | 34 ++---- app/src/main/cpp/skyline/kernel/ipc.cpp | 22 ++-- app/src/main/cpp/skyline/kernel/memory.cpp | 3 +- app/src/main/cpp/skyline/kernel/memory.h | 5 +- app/src/main/cpp/skyline/kernel/svc.cpp | 112 ++++++++++++++---- app/src/main/cpp/skyline/kernel/svc.h | 24 +++- .../cpp/skyline/kernel/types/KProcess.cpp | 7 +- .../main/cpp/skyline/kernel/types/KProcess.h | 14 ++- .../main/cpp/skyline/kernel/types/KThread.cpp | 3 +- .../main/cpp/skyline/kernel/types/KThread.h | 10 +- app/src/main/cpp/skyline/loader/loader.h | 4 +- app/src/main/cpp/skyline/loader/nca.cpp | 5 +- app/src/main/cpp/skyline/loader/nro.cpp | 2 +- app/src/main/cpp/skyline/loader/nsp.cpp | 4 +- .../main/cpp/skyline/services/serviceman.cpp | 6 +- app/src/main/cpp/skyline/vfs/npdm.cpp | 43 +++++++ app/src/main/cpp/skyline/vfs/npdm.h | 54 +++++++++ app/src/main/res/values/array.xml | 2 + 20 files changed, 291 insertions(+), 102 deletions(-) create mode 100644 app/src/main/cpp/skyline/vfs/npdm.cpp create mode 100644 app/src/main/cpp/skyline/vfs/npdm.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 68770a6a..99bb8cc1 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -36,12 +36,18 @@ add_library(skyline SHARED ${source_DIR}/skyline/nce/guest.S ${source_DIR}/skyline/nce.cpp ${source_DIR}/skyline/jvm.cpp + ${source_DIR}/skyline/os.cpp + ${source_DIR}/skyline/kernel/memory.cpp + ${source_DIR}/skyline/kernel/ipc.cpp + ${source_DIR}/skyline/kernel/svc.cpp + ${source_DIR}/skyline/kernel/types/KProcess.cpp + ${source_DIR}/skyline/kernel/types/KThread.cpp + ${source_DIR}/skyline/kernel/types/KSharedMemory.cpp + ${source_DIR}/skyline/kernel/types/KPrivateMemory.cpp ${source_DIR}/skyline/audio.cpp ${source_DIR}/skyline/audio/track.cpp ${source_DIR}/skyline/audio/resampler.cpp ${source_DIR}/skyline/audio/adpcm_decoder.cpp - ${source_DIR}/skyline/crypto/aes_cipher.cpp - ${source_DIR}/skyline/crypto/key_store.cpp ${source_DIR}/skyline/gpu.cpp ${source_DIR}/skyline/gpu/macro_interpreter.cpp ${source_DIR}/skyline/gpu/memory_manager.cpp @@ -52,19 +58,21 @@ add_library(skyline SHARED ${source_DIR}/skyline/input/npad.cpp ${source_DIR}/skyline/input/npad_device.cpp ${source_DIR}/skyline/input/touch.cpp - ${source_DIR}/skyline/os.cpp + ${source_DIR}/skyline/crypto/aes_cipher.cpp + ${source_DIR}/skyline/crypto/key_store.cpp ${source_DIR}/skyline/loader/loader.cpp ${source_DIR}/skyline/loader/nro.cpp ${source_DIR}/skyline/loader/nso.cpp ${source_DIR}/skyline/loader/nca.cpp ${source_DIR}/skyline/loader/nsp.cpp - ${source_DIR}/skyline/kernel/memory.cpp - ${source_DIR}/skyline/kernel/ipc.cpp - ${source_DIR}/skyline/kernel/svc.cpp - ${source_DIR}/skyline/kernel/types/KProcess.cpp - ${source_DIR}/skyline/kernel/types/KThread.cpp - ${source_DIR}/skyline/kernel/types/KSharedMemory.cpp - ${source_DIR}/skyline/kernel/types/KPrivateMemory.cpp + ${source_DIR}/skyline/vfs/os_filesystem.cpp + ${source_DIR}/skyline/vfs/partition_filesystem.cpp + ${source_DIR}/skyline/vfs/ctr_encrypted_backing.cpp + ${source_DIR}/skyline/vfs/rom_filesystem.cpp + ${source_DIR}/skyline/vfs/os_backing.cpp + ${source_DIR}/skyline/vfs/nacp.cpp + ${source_DIR}/skyline/vfs/npdm.cpp + ${source_DIR}/skyline/vfs/nca.cpp ${source_DIR}/skyline/services/serviceman.cpp ${source_DIR}/skyline/services/base_service.cpp ${source_DIR}/skyline/services/common/parcel.cpp @@ -149,13 +157,6 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/ssl/ISslService.cpp ${source_DIR}/skyline/services/ssl/ISslContext.cpp ${source_DIR}/skyline/services/prepo/IPrepoService.cpp - ${source_DIR}/skyline/vfs/os_filesystem.cpp - ${source_DIR}/skyline/vfs/partition_filesystem.cpp - ${source_DIR}/skyline/vfs/ctr_encrypted_backing.cpp - ${source_DIR}/skyline/vfs/rom_filesystem.cpp - ${source_DIR}/skyline/vfs/os_backing.cpp - ${source_DIR}/skyline/vfs/nacp.cpp - ${source_DIR}/skyline/vfs/nca.cpp ) target_link_libraries(skyline vulkan android fmt tinyxml2 oboe lz4_static mbedtls::mbedcrypto) diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp index c4df5865..3ff04704 100644 --- a/app/src/main/cpp/skyline/common.cpp +++ b/app/src/main/cpp/skyline/common.cpp @@ -141,8 +141,8 @@ namespace skyline { } void Logger::Write(LogLevel level, std::string str) { - constexpr std::array levelCharacter{'0', '1', '2', '3'}; // The LogLevel as written out to a file - constexpr std::array levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG}; // This corresponds to LogLevel and provides it's equivalent for NDK Logging + constexpr std::array levelCharacter{'0', '1', '2', '3', '4'}; // The LogLevel as written out to a file + constexpr std::array levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE}; // This corresponds to LogLevel and provides it's equivalent for NDK Logging __android_log_write(levelAlog[static_cast(level)], "emu-cpp", str.c_str()); diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index ac5643cc..1a27cc6e 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -436,6 +436,7 @@ namespace skyline { Warn, Info, Debug, + Verbose, }; LogLevel configLevel; //!< The minimum level of logs to write @@ -453,22 +454,11 @@ namespace skyline { /** * @brief Writes a header, should only be used for emulation starting and ending - * @param str The value to be written */ void WriteHeader(const std::string &str); - /** - * @brief Write a log to the log file - * @param level The level of the log - * @param str The value to be written - */ void Write(LogLevel level, std::string str); - /** - * @brief Write an error log with libfmt formatting - * @param formatStr The value to be written, with libfmt formatting - * @param args The arguments based on format_str - */ template inline void Error(const S &formatStr, Args &&... args) { if (LogLevel::Error <= configLevel) { @@ -476,11 +466,6 @@ namespace skyline { } } - /** - * @brief Write a debug log with libfmt formatting - * @param formatStr The value to be written, with libfmt formatting - * @param args The arguments based on format_str - */ template inline void Warn(const S &formatStr, Args &&... args) { if (LogLevel::Warn <= configLevel) { @@ -488,11 +473,6 @@ namespace skyline { } } - /** - * @brief Write a debug log with libfmt formatting - * @param formatStr The value to be written, with libfmt formatting - * @param args The arguments based on format_str - */ template inline void Info(const S &formatStr, Args &&... args) { if (LogLevel::Info <= configLevel) { @@ -500,17 +480,19 @@ namespace skyline { } } - /** - * @brief Write a debug log with libfmt formatting - * @param formatStr The value to be written, with libfmt formatting - * @param args The arguments based on format_str - */ template inline void Debug(const S &formatStr, Args &&... args) { if (LogLevel::Debug <= configLevel) { Write(LogLevel::Debug, fmt::format(formatStr, util::FmtCast(args)...)); } } + + template + inline void Verbose(const S &formatStr, Args &&... args) { + if (LogLevel::Verbose <= configLevel) { + Write(LogLevel::Verbose, fmt::format(formatStr, util::FmtCast(args)...)); + } + } }; /** diff --git a/app/src/main/cpp/skyline/kernel/ipc.cpp b/app/src/main/cpp/skyline/kernel/ipc.cpp index c8292fde..ebcc1499 100644 --- a/app/src/main/cpp/skyline/kernel/ipc.cpp +++ b/app/src/main/cpp/skyline/kernel/ipc.cpp @@ -31,7 +31,7 @@ namespace skyline::kernel::ipc { auto bufX{reinterpret_cast(pointer)}; if (bufX->Pointer()) { inputBuf.emplace_back(bufX->Pointer(), static_cast(bufX->size)); - state.logger->Debug("Buf X #{}: 0x{:X}, 0x{:X}, #{}", index, bufX->Pointer(), static_cast(bufX->size), static_cast(bufX->Counter())); + state.logger->Verbose("Buf X #{}: 0x{:X}, 0x{:X}, #{}", index, bufX->Pointer(), static_cast(bufX->size), static_cast(bufX->Counter())); } pointer += sizeof(BufferDescriptorX); } @@ -40,7 +40,7 @@ namespace skyline::kernel::ipc { auto bufA{reinterpret_cast(pointer)}; if (bufA->Pointer()) { inputBuf.emplace_back(bufA->Pointer(), bufA->Size()); - state.logger->Debug("Buf A #{}: 0x{:X}, 0x{:X}", index, bufA->Pointer(), static_cast(bufA->Size())); + state.logger->Verbose("Buf A #{}: 0x{:X}, 0x{:X}", index, bufA->Pointer(), static_cast(bufA->Size())); } pointer += sizeof(BufferDescriptorABW); } @@ -49,7 +49,7 @@ namespace skyline::kernel::ipc { auto bufB{reinterpret_cast(pointer)}; if (bufB->Pointer()) { outputBuf.emplace_back(bufB->Pointer(), bufB->Size()); - state.logger->Debug("Buf B #{}: 0x{:X}, 0x{:X}", index, bufB->Pointer(), static_cast(bufB->Size())); + state.logger->Verbose("Buf B #{}: 0x{:X}, 0x{:X}", index, bufB->Pointer(), static_cast(bufB->Size())); } pointer += sizeof(BufferDescriptorABW); } @@ -59,7 +59,7 @@ namespace skyline::kernel::ipc { if (bufW->Pointer()) { outputBuf.emplace_back(bufW->Pointer(), bufW->Size()); outputBuf.emplace_back(bufW->Pointer(), bufW->Size()); - state.logger->Debug("Buf W #{}: 0x{:X}, 0x{:X}", index, bufW->Pointer(), static_cast(bufW->Size())); + state.logger->Verbose("Buf W #{}: 0x{:X}, 0x{:X}", index, bufW->Pointer(), static_cast(bufW->Size())); } pointer += sizeof(BufferDescriptorABW); } @@ -103,26 +103,26 @@ namespace skyline::kernel::ipc { auto bufC{reinterpret_cast(pointer)}; if (bufC->address) { outputBuf.emplace_back(bufC->Pointer(), static_cast(bufC->size)); - state.logger->Debug("Buf C: 0x{:X}, 0x{:X}", bufC->Pointer(), static_cast(bufC->size)); + state.logger->Verbose("Buf C: 0x{:X}, 0x{:X}", bufC->Pointer(), static_cast(bufC->size)); } } else if (header->cFlag > BufferCFlag::SingleDescriptor) { for (u8 index{}; (static_cast(header->cFlag) - 2) > index; index++) { // (cFlag - 2) C descriptors are present auto bufC{reinterpret_cast(pointer)}; if (bufC->address) { outputBuf.emplace_back(bufC->Pointer(), static_cast(bufC->size)); - state.logger->Debug("Buf C #{}: 0x{:X}, 0x{:X}", index, bufC->Pointer(), static_cast(bufC->size)); + state.logger->Verbose("Buf C #{}: 0x{:X}, 0x{:X}", index, bufC->Pointer(), static_cast(bufC->size)); } pointer += sizeof(BufferDescriptorC); } } if (header->type == CommandType::Request || header->type == CommandType::RequestWithContext) { - state.logger->Debug("Header: Input No: {}, Output No: {}, Raw Size: {}", inputBuf.size(), outputBuf.size(), static_cast(cmdArgSz)); + state.logger->Verbose("Header: Input No: {}, Output No: {}, Raw Size: {}", inputBuf.size(), outputBuf.size(), static_cast(cmdArgSz)); if (header->handleDesc) - state.logger->Debug("Handle Descriptor: Send PID: {}, Copy Count: {}, Move Count: {}", static_cast(handleDesc->sendPid), static_cast(handleDesc->copyCount), static_cast(handleDesc->moveCount)); + state.logger->Verbose("Handle Descriptor: Send PID: {}, Copy Count: {}, Move Count: {}", static_cast(handleDesc->sendPid), static_cast(handleDesc->copyCount), static_cast(handleDesc->moveCount)); if (isDomain) - state.logger->Debug("Domain Header: Command: {}, Input Object Count: {}, Object ID: 0x{:X}", domain->command, domain->inputCount, domain->objectId); - state.logger->Debug("Command ID: 0x{:X}", static_cast(payload->value)); + state.logger->Verbose("Domain Header: Command: {}, Input Object Count: {}, Object ID: 0x{:X}", domain->command, domain->inputCount, domain->objectId); + state.logger->Verbose("Command ID: 0x{:X}", static_cast(payload->value)); } } @@ -183,6 +183,6 @@ namespace skyline::kernel::ipc { } } - state.logger->Debug("Output: Raw Size: {}, Command ID: 0x{:X}, Copy Handles: {}, Move Handles: {}", static_cast(header->rawSize), static_cast(payloadHeader->value), copyHandles.size(), moveHandles.size()); + state.logger->Verbose("Output: Raw Size: {}, Command ID: 0x{:X}, Copy Handles: {}, Move Handles: {}", static_cast(header->rawSize), static_cast(payloadHeader->value), copyHandles.size(), moveHandles.size()); } } diff --git a/app/src/main/cpp/skyline/kernel/memory.cpp b/app/src/main/cpp/skyline/kernel/memory.cpp index 785f9a69..da2bb428 100644 --- a/app/src/main/cpp/skyline/kernel/memory.cpp +++ b/app/src/main/cpp/skyline/kernel/memory.cpp @@ -12,6 +12,7 @@ namespace skyline::kernel { void MemoryManager::InitializeVmm(memory::AddressSpaceType type) { switch (type) { case memory::AddressSpaceType::AddressSpace32Bit: + case memory::AddressSpaceType::AddressSpace32BitNoReserved: throw exception("32-bit address spaces are not supported"); case memory::AddressSpaceType::AddressSpace36Bit: { @@ -119,7 +120,7 @@ namespace skyline::kernel { if (upper == chunks.begin()) throw exception("InsertChunk: Chunk inserted outside address space: 0x{:X} - 0x{:X} and 0x{:X} - 0x{:X}", upper->ptr, upper->ptr + upper->size, chunk.ptr, chunk.ptr + chunk.size); - upper = chunks.erase(upper, std::upper_bound(upper, chunks.end(), chunk.ptr + chunk.size, [](const u8 *ptr, const ChunkDescriptor &chunk) -> bool { return ptr < chunk.ptr; })); + upper = chunks.erase(upper, std::upper_bound(upper, chunks.end(), chunk.ptr + chunk.size, [](const u8 *ptr, const ChunkDescriptor &chunk) -> bool { return ptr < chunk.ptr + chunk.size; })); if (upper != chunks.end() && upper->ptr < chunk.ptr + chunk.size) { auto end{upper->ptr + upper->size}; upper->ptr = chunk.ptr + chunk.size; diff --git a/app/src/main/cpp/skyline/kernel/memory.h b/app/src/main/cpp/skyline/kernel/memory.h index 0d977451..52c1a981 100644 --- a/app/src/main/cpp/skyline/kernel/memory.h +++ b/app/src/main/cpp/skyline/kernel/memory.h @@ -179,8 +179,9 @@ namespace skyline { }; enum class AddressSpaceType : u8 { - AddressSpace32Bit, //!< 32-bit address space used by 32-bit applications - AddressSpace36Bit, //!< 36-bit address space used by 64-bit applications before 2.0.0 + AddressSpace32Bit = 0, //!< 32-bit address space used by 32-bit applications + AddressSpace36Bit = 1, //!< 36-bit address space used by 64-bit applications before 2.0.0 + AddressSpace32BitNoReserved = 2, //!< 32-bit address space without the map region AddressSpace39Bit, //!< 39-bit address space used by 64-bit applications after 2.0.0 }; } diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 303de255..80d9a83a 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -219,14 +219,26 @@ namespace skyline::kernel::svc { exit(0); } + constexpr i32 IdealCoreDontCare{-1}; + constexpr i32 IdealCoreUseProcessValue{-2}; + constexpr i32 IdealCoreNoUpdate{-3}; + void CreateThread(const DeviceState &state) { auto entry{reinterpret_cast(state.ctx->gpr.x1)}; auto entryArgument{state.ctx->gpr.x2}; auto stackTop{reinterpret_cast(state.ctx->gpr.x3)}; auto priority{static_cast(static_cast(state.ctx->gpr.w4))}; + auto idealCore{static_cast(static_cast(state.ctx->gpr.w5))}; + + idealCore = (idealCore == IdealCoreUseProcessValue) ? state.process->npdm.meta.idealCore : idealCore; + if (idealCore < 0 || idealCore >= constant::CoreCount) { + state.ctx->gpr.w0 = result::InvalidCoreId; + state.logger->Warn("svcCreateThread: 'idealCore' invalid: {}", idealCore); + return; + } if (!constant::HosPriority.Valid(priority)) { - state.ctx->gpr.w0 = result::InvalidAddress; + state.ctx->gpr.w0 = result::InvalidPriority; state.logger->Warn("svcCreateThread: 'priority' invalid: {}", priority); return; } @@ -235,7 +247,7 @@ namespace skyline::kernel::svc { if (!stack) throw exception("svcCreateThread: Cannot find memory object in handle table for thread stack: 0x{:X}", stackTop); - auto thread{state.process->CreateThread(entry, entryArgument, stackTop, priority)}; + auto thread{state.process->CreateThread(entry, entryArgument, stackTop, priority, idealCore)}; state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, ID: {})", thread->handle, entry, entryArgument, stackTop, priority, thread->id); state.ctx->gpr.w1 = thread->handle; @@ -283,8 +295,9 @@ namespace skyline::kernel::svc { void GetThreadPriority(const DeviceState &state) { KHandle handle{state.ctx->gpr.w1}; try { - auto priority{state.process->GetHandle(handle)->priority}; - state.logger->Debug("svcGetThreadPriority: Writing thread priority {}", priority); + auto thread{state.process->GetHandle(handle)}; + auto priority{thread->priority}; + state.logger->Debug("svcGetThreadPriority: Retrieving thread #{}'s priority: {}", thread->id, priority); state.ctx->gpr.w1 = priority; state.ctx->gpr.w0 = Result{}; @@ -297,10 +310,15 @@ namespace skyline::kernel::svc { void SetThreadPriority(const DeviceState &state) { KHandle handle{state.ctx->gpr.w0}; u32 priority{state.ctx->gpr.w1}; - + if (!constant::HosPriority.Valid(priority)) { + state.logger->Warn("svcSetThreadPriority: 'priority' invalid: 0x{:X}", priority); + state.ctx->gpr.w0 = result::InvalidPriority; + return; + } try { - state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", priority); - state.process->GetHandle(handle)->UpdatePriority(static_cast(priority)); + auto thread{state.process->GetHandle(handle)}; + state.logger->Debug("svcSetThreadPriority: Setting thread priority to {}", thread->id, priority); + thread->UpdatePriority(static_cast(priority)); state.ctx->gpr.w0 = Result{}; } catch (const std::exception &) { state.logger->Warn("svcSetThreadPriority: 'handle' invalid: 0x{:X}", handle); @@ -308,6 +326,62 @@ namespace skyline::kernel::svc { } } + void GetThreadCoreMask(const DeviceState &state) { + KHandle handle{state.ctx->gpr.w2}; + try { + auto thread{state.process->GetHandle(handle)}; + auto idealCore{thread->idealCore}; + auto affinityMask{thread->affinityMask}; + state.logger->Debug("svcGetThreadCoreMask: Writing thread #{}'s Ideal Core ({}) + Affinity Mask ({})", thread->id, idealCore, affinityMask.to_string()); + + state.ctx->gpr.x2 = affinityMask.to_ullong(); + state.ctx->gpr.w1 = idealCore; + state.ctx->gpr.w0 = Result{}; + } catch (const std::exception &) { + state.logger->Warn("svcGetThreadCoreMask: 'handle' invalid: 0x{:X}", handle); + state.ctx->gpr.w0 = result::InvalidHandle; + } + } + + void SetThreadCoreMask(const DeviceState &state) { + KHandle handle{state.ctx->gpr.w0}; + i32 idealCore{static_cast(state.ctx->gpr.w1)}; + std::bitset affinityMask{state.ctx->gpr.x2}; + try { + auto thread{state.process->GetHandle(handle)}; + + if (idealCore == IdealCoreUseProcessValue) { + idealCore = state.process->npdm.meta.idealCore; + affinityMask.reset().set(idealCore); + } else if (idealCore == IdealCoreNoUpdate) { + idealCore = thread->idealCore; + } else if (idealCore == IdealCoreDontCare) { + idealCore = __builtin_ctzll(affinityMask.to_ullong()); // The first enabled core in the affinity mask + } + + if (affinityMask.none() || !affinityMask.test(idealCore)) { + state.logger->Warn("svcSetThreadCoreMask: 'affinityMask' invalid: {} (Ideal Core: {})", affinityMask.to_string(), idealCore); + state.ctx->gpr.w0 = result::InvalidCombination; + return; + } + + state.logger->Debug("svcSetThreadCoreMask: Setting thread #{}'s Ideal Core ({}) + Affinity Mask ({})", thread->id, idealCore, affinityMask.to_string()); + + thread->idealCore = idealCore; + thread->affinityMask = affinityMask; + + state.ctx->gpr.w0 = Result{}; + } catch (const std::exception &) { + state.logger->Warn("svcSetThreadCoreMask: 'handle' invalid: 0x{:X}", handle); + state.ctx->gpr.w0 = result::InvalidHandle; + } + } + + void GetCurrentProcessorNumber(const DeviceState &state) { + state.logger->Debug("svcGetCurrentProcessorNumber: Writing current core for thread #{}: {}", state.thread->id, state.thread->coreId); + state.ctx->gpr.w0 = state.thread->coreId; + } + void ClearEvent(const DeviceState &state) { auto object{state.process->GetHandle(state.ctx->gpr.w0)}; object->signalled = false; @@ -612,18 +686,12 @@ namespace skyline::kernel::svc { } void GetThreadId(const DeviceState &state) { - constexpr KHandle threadSelf{0xFFFF8000}; // The handle used by threads to refer to themselves KHandle handle{state.ctx->gpr.w1}; - pid_t pid{}; - - if (handle != threadSelf) - pid = state.process->GetHandle(handle)->id; - else - pid = state.thread->id; + size_t pid{state.process->GetHandle(handle)->id}; state.logger->Debug("svcGetThreadId: Handle: 0x{:X}, PID: {}", handle, pid); - state.ctx->gpr.x1 = static_cast(pid); + state.ctx->gpr.x1 = pid; state.ctx->gpr.w0 = Result{}; } @@ -706,7 +774,11 @@ namespace skyline::kernel::svc { break; case InfoState::TotalMemoryUsage: - out = state.process->memory.GetMemoryUsage(); + out = state.process->memory.GetMemoryUsage() + state.process->memory.GetKMemoryBlockSize(); + break; + + case InfoState::RandomEntropy: + out = util::GetTimeTicks(); break; case InfoState::AddressSpaceBaseAddr: @@ -726,20 +798,20 @@ namespace skyline::kernel::svc { break; case InfoState::TotalSystemResourceAvailable: - out = totalPhysicalMemory; // TODO: NPDM specifies this in it's PersonalMmHeapSize field + out = state.process->npdm.meta.systemResourceSize; break; case InfoState::TotalSystemResourceUsage: // A very rough approximation of what this should be on the Switch, the amount of memory allocated for storing the memory blocks (https://switchbrew.org/wiki/Kernel_objects#KMemoryBlockManager) - out = state.process->memory.GetKMemoryBlockSize(); + out = std::min(static_cast(state.process->npdm.meta.systemResourceSize), state.process->memory.GetKMemoryBlockSize()); break; case InfoState::TotalMemoryAvailableWithoutSystemResource: - out = totalPhysicalMemory; // TODO: Subtract TotalSystemResourceAvailable from this + out = totalPhysicalMemory - state.process->npdm.meta.systemResourceSize; break; case InfoState::TotalMemoryUsageWithoutSystemResource: - out = state.process->memory.GetMemoryUsage(); + out = state.process->memory.GetMemoryUsage(); // Our regular estimates don't contain the system resources break; case InfoState::UserExceptionContextAddr: diff --git a/app/src/main/cpp/skyline/kernel/svc.h b/app/src/main/cpp/skyline/kernel/svc.h index 1afa8dff..669ec241 100644 --- a/app/src/main/cpp/skyline/kernel/svc.h +++ b/app/src/main/cpp/skyline/kernel/svc.h @@ -78,6 +78,24 @@ namespace skyline::kernel::svc { */ void SetThreadPriority(const DeviceState &state); + /** + * @brief Get core mask of provided thread handle + * @url https://switchbrew.org/wiki/SVC#GetThreadCoreMask + */ + void GetThreadCoreMask(const DeviceState &state); + + /** + * @brief Set core mask of provided thread handle + * @url https://switchbrew.org/wiki/SVC#SetThreadCoreMask + */ + void SetThreadCoreMask(const DeviceState &state); + + /** + * @brief Returns the core on which the current thread is running + * @url https://switchbrew.org/wiki/SVC#GetCurrentProcessorNumber + */ + void GetCurrentProcessorNumber(const DeviceState &state); + /** * @brief Clears a KEvent of it's signal * @url https://switchbrew.org/wiki/SVC#ClearEvent @@ -210,9 +228,9 @@ namespace skyline::kernel::svc { SleepThread, // 0x0B GetThreadPriority, // 0x0C SetThreadPriority, // 0x0D - nullptr, // 0x0E - nullptr, // 0x0F - nullptr, // 0x10 + GetThreadCoreMask, // 0x0E + SetThreadCoreMask, // 0x0F + GetCurrentProcessorNumber, // 0x10 nullptr, // 0x11 ClearEvent, // 0x12 MapSharedMemory, // 0x13 diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp index b248199f..93e90aec 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.cpp @@ -49,15 +49,14 @@ namespace skyline::kernel::type { return tlsPage->ReserveSlot(); } - std::shared_ptr KProcess::CreateThread(void *entry, u64 argument, void *stackTop, i8 priority) { + std::shared_ptr KProcess::CreateThread(void *entry, u64 argument, void *stackTop, i8 priority, i8 idealCore) { if (!stackTop && threads.empty()) { //!< Main thread stack is created by the kernel and owned by the process - constexpr u64 DefaultStackSize{0x200000}; //!< The default amount of stack: 2 MB - mainThreadStack = mainThreadStack.make_shared(state, reinterpret_cast(state.process->memory.stack.address), DefaultStackSize, memory::Permission{true, true, false}, memory::states::Stack); + mainThreadStack = mainThreadStack.make_shared(state, reinterpret_cast(state.process->memory.stack.address), state.process->npdm.meta.mainThreadStackSize, memory::Permission{true, true, false}, memory::states::Stack); if (mprotect(mainThreadStack->ptr, PAGE_SIZE, PROT_NONE)) throw exception("Failed to create guard page for thread stack at 0x{:X}", mainThreadStack->ptr); stackTop = mainThreadStack->ptr + mainThreadStack->size; } - auto thread{NewHandle(this, threads.size(), entry, argument, stackTop, priority).item}; + auto thread{NewHandle(this, threads.size(), entry, argument, stackTop, (priority == -1) ? state.process->npdm.meta.mainThreadPriority : priority, (idealCore == -1) ? state.process->npdm.meta.idealCore : idealCore).item}; threads.push_back(thread); return thread; } diff --git a/app/src/main/cpp/skyline/kernel/types/KProcess.h b/app/src/main/cpp/skyline/kernel/types/KProcess.h index d2449260..e099590c 100644 --- a/app/src/main/cpp/skyline/kernel/types/KProcess.h +++ b/app/src/main/cpp/skyline/kernel/types/KProcess.h @@ -5,6 +5,7 @@ #include #include +#include #include "KThread.h" #include "KTransferMemory.h" #include "KSession.h" @@ -70,6 +71,7 @@ namespace skyline { std::shared_ptr heap; std::vector> threads; std::vector> tlsPages; + vfs::NPDM npdm; KProcess(const DeviceState &state); @@ -83,7 +85,10 @@ namespace skyline { */ u8* AllocateTlsSlot(); - std::shared_ptr CreateThread(void *entry, u64 argument = 0, void *stackTop = nullptr, i8 priority = constant::DefaultPriority); + /** + * @note The default values are for the main thread and will use values from the NPDM + */ + std::shared_ptr CreateThread(void *entry, u64 argument = 0, void *stackTop = nullptr, i8 priority = -1, i8 idealCore = -1); /** * @brief The output for functions that return created kernel objects @@ -130,9 +135,12 @@ namespace skyline { std::shared_lock lock(handleMutex); KType objectType; - if constexpr(std::is_same()) + if constexpr(std::is_same()) { + constexpr KHandle threadSelf{0xFFFF8000}; // The handle used by threads to refer to themselves + if (handle == threadSelf) + return state.thread; objectType = KType::KThread; - else if constexpr(std::is_same()) + } else if constexpr(std::is_same()) objectType = KType::KProcess; else if constexpr(std::is_same()) objectType = KType::KSharedMemory; diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.cpp b/app/src/main/cpp/skyline/kernel/types/KThread.cpp index e40cec64..bf209f07 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.cpp +++ b/app/src/main/cpp/skyline/kernel/types/KThread.cpp @@ -12,7 +12,8 @@ #include "KProcess.h" namespace skyline::kernel::type { - KThread::KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, i8 priority) : handle(handle), parent(parent), id(id), entry(entry), entryArgument(argument), stackTop(stackTop), KSyncObject(state, KType::KThread) { + KThread::KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, i8 priority, i8 idealCore) : handle(handle), parent(parent), id(id), entry(entry), entryArgument(argument), stackTop(stackTop), idealCore(idealCore), coreId(idealCore), KSyncObject(state, KType::KThread) { + affinityMask.set(coreId); UpdatePriority(priority); } diff --git a/app/src/main/cpp/skyline/kernel/types/KThread.h b/app/src/main/cpp/skyline/kernel/types/KThread.h index 5dc726f5..bd599ace 100644 --- a/app/src/main/cpp/skyline/kernel/types/KThread.h +++ b/app/src/main/cpp/skyline/kernel/types/KThread.h @@ -34,7 +34,7 @@ namespace skyline { } namespace constant { - constexpr i8 DefaultPriority{44}; // The default priority of an HOS process + constexpr u8 CoreCount{4}; // The amount of cores an HOS process can be scheduled onto (User applications can only be on the first 3 cores, the last one is reserved for the system) constexpr kernel::type::Priority AndroidPriority{19, -8}; //!< The range of priorities for Android constexpr kernel::type::Priority HosPriority{0, 63}; //!< The range of priorities for Horizon OS } @@ -62,9 +62,13 @@ namespace skyline { void* entry; u64 entryArgument; void* stackTop; - i8 priority; - KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, i8 priority = constant::DefaultPriority); + i8 priority; + i8 idealCore; + i8 coreId; //!< The CPU core on which this thread is running + std::bitset affinityMask{}; //!< The CPU core on which this thread is running + + KThread(const DeviceState &state, KHandle handle, KProcess *parent, size_t id, void *entry, u64 argument, void *stackTop, i8 priority, i8 idealCore); ~KThread(); diff --git a/app/src/main/cpp/skyline/loader/loader.h b/app/src/main/cpp/skyline/loader/loader.h index 81c6d139..eb77c2c3 100644 --- a/app/src/main/cpp/skyline/loader/loader.h +++ b/app/src/main/cpp/skyline/loader/loader.h @@ -66,8 +66,8 @@ namespace skyline::loader { static ExecutableLoadInfo LoadExecutable(const std::shared_ptr process, const DeviceState &state, Executable &executable, size_t offset = 0); public: - std::shared_ptr nacp; //!< The NACP of the current application - std::shared_ptr romFs; //!< The RomFS of the current application + std::optional nacp; + std::shared_ptr romFs; virtual ~Loader() = default; diff --git a/app/src/main/cpp/skyline/loader/nca.cpp b/app/src/main/cpp/skyline/loader/nca.cpp index 1da1c735..20415400 100644 --- a/app/src/main/cpp/skyline/loader/nca.cpp +++ b/app/src/main/cpp/skyline/loader/nca.cpp @@ -26,7 +26,7 @@ namespace skyline::loader { u8* base{loadInfo.base}; void* entry{loadInfo.entry}; - state.logger->Info("Loaded nso 'rtld' at 0x{:X}", base); + state.logger->Info("Loaded nso 'rtld' at 0x{:X} (.text @ 0x{:X})", base, entry); for (const auto &nso : {"main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { nsoFile = exeFs->OpenFile(nso); @@ -35,7 +35,7 @@ namespace skyline::loader { continue; loadInfo = NsoLoader::LoadNso(nsoFile, process, state, offset); - state.logger->Info("Loaded nso '{}' at 0x{:X}", nso, base + offset); + state.logger->Info("Loaded '{}.nso' at 0x{:X} (.text @ 0x{:X})", nso, base + offset, loadInfo.entry); offset += loadInfo.size; } @@ -45,6 +45,7 @@ namespace skyline::loader { } void* NcaLoader::LoadProcessData(const std::shared_ptr process, const DeviceState &state) { + process->npdm = vfs::NPDM(nca.exeFs->OpenFile("main.npdm")); return LoadExeFs(nca.exeFs, process, state); } } diff --git a/app/src/main/cpp/skyline/loader/nro.cpp b/app/src/main/cpp/skyline/loader/nro.cpp index 755cc8d6..3714f56f 100644 --- a/app/src/main/cpp/skyline/loader/nro.cpp +++ b/app/src/main/cpp/skyline/loader/nro.cpp @@ -22,7 +22,7 @@ namespace skyline::loader { throw exception("Invalid ASET magic! 0x{0:X}", assetHeader.magic); NroAssetSection &nacpHeader{assetHeader.nacp}; - nacp = std::make_shared(std::make_shared(backing, header.size + nacpHeader.offset, nacpHeader.size)); + nacp.emplace(std::make_shared(backing, header.size + nacpHeader.offset, nacpHeader.size)); NroAssetSection &romFsHeader{assetHeader.romFs}; romFs = std::make_shared(backing, header.size + romFsHeader.offset, romFsHeader.size); diff --git a/app/src/main/cpp/skyline/loader/nsp.cpp b/app/src/main/cpp/skyline/loader/nsp.cpp index adabd78b..b663ada0 100644 --- a/app/src/main/cpp/skyline/loader/nsp.cpp +++ b/app/src/main/cpp/skyline/loader/nsp.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include "nca.h" #include "nsp.h" @@ -31,10 +32,11 @@ namespace skyline::loader { romFs = programNca->romFs; controlRomFs = std::make_shared(controlNca->romFs); - nacp = std::make_shared(controlRomFs->OpenFile("control.nacp")); + nacp.emplace(controlRomFs->OpenFile("control.nacp")); } void* NspLoader::LoadProcessData(const std::shared_ptr process, const DeviceState &state) { + process->npdm = vfs::NPDM(programNca->exeFs->OpenFile("main.npdm")); return NcaLoader::LoadExeFs(programNca->exeFs, process, state); } diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index ee10afa8..70a8e415 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -136,8 +136,8 @@ namespace skyline::service { void ServiceManager::SyncRequestHandler(KHandle handle) { auto session{state.process->GetHandle(handle)}; - state.logger->Debug("----Start----"); - state.logger->Debug("Handle is 0x{:X}", handle); + state.logger->Verbose("----IPC Start----"); + state.logger->Verbose("Handle is 0x{:X}", handle); if (session->isOpen) { ipc::IpcRequest request(session->isDomain, state); @@ -205,6 +205,6 @@ namespace skyline::service { } else { state.logger->Warn("svcSendSyncRequest called on closed handle: 0x{:X}", handle); } - state.logger->Debug("====End===="); + state.logger->Verbose("====IPC End===="); } } diff --git a/app/src/main/cpp/skyline/vfs/npdm.cpp b/app/src/main/cpp/skyline/vfs/npdm.cpp new file mode 100644 index 00000000..c70e0af2 --- /dev/null +++ b/app/src/main/cpp/skyline/vfs/npdm.cpp @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include "npdm.h" + +namespace skyline::vfs { + constexpr u32 MetaMagic = util::MakeMagic("META"); + + NPDM::NPDM() { + constexpr i8 DefaultPriority{44}; // The default priority of an HOS process + constexpr i8 DefaultCore{0}; // The default core for an HOS process + constexpr u64 DefaultStackSize{0x200000}; //!< The default amount of stack: 2 MiB + constexpr u64 DefaultSystemResourceSize{0x1FE00000}; //!< The amount of memory reserved for system resources, it's the maximum at 510 MiB + meta = { + .magic = MetaMagic, + .flags = { + { + .is64Bit = true, + .type = memory::AddressSpaceType::AddressSpace39Bit, + .optimizeMemoryAllocation = false, + } + }, + .mainThreadPriority = DefaultPriority, + .idealCore = DefaultCore, + .mainThreadStackSize = DefaultStackSize, + .systemResourceSize = DefaultSystemResourceSize, + .name = "Application", + }; + } + + NPDM::NPDM(const std::shared_ptr &backing) { + meta = backing->Read(); + if(meta.magic != MetaMagic) + throw exception("NPDM Meta Magic isn't correct: 0x{:X} (\"META\" = 0x{:X})", meta.magic, MetaMagic); + if (!constant::HosPriority.Valid(meta.mainThreadPriority)) + throw exception("NPDM Main Thread Priority isn't valid: {}", meta.mainThreadStackSize); + if (meta.idealCore >= constant::CoreCount) + throw exception("NPDM Ideal Core isn't valid: {}", meta.idealCore); + if (!util::PageAligned(meta.mainThreadStackSize)) + throw exception("NPDM Main Thread Stack isn't page aligned: 0x{:X}", meta.mainThreadStackSize); + } +} diff --git a/app/src/main/cpp/skyline/vfs/npdm.h b/app/src/main/cpp/skyline/vfs/npdm.h new file mode 100644 index 00000000..cfe472e1 --- /dev/null +++ b/app/src/main/cpp/skyline/vfs/npdm.h @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include "backing.h" +#include + +namespace skyline::vfs { + /** + * @url https://switchbrew.org/wiki/NPDM + */ + class NPDM { + public: + /** + * @url https://switchbrew.org/wiki/NPDM#META + */ + struct __attribute__((packed)) NpdmMeta { + u32 magic; //!< "META" + u32 acidSignatureKeyGeneration; + u32 _unk0_; + union { + struct { + bool is64Bit : 1; + memory::AddressSpaceType type : 2; + bool optimizeMemoryAllocation : 1; + }; + u8 raw{}; + } flags; + u8 _unk1_; + u8 mainThreadPriority; + u8 idealCore; + u32 _unk2_; + u32 systemResourceSize; //!< 3.0.0+ + u32 version; + u32 mainThreadStackSize; + std::array name; //!< "Application" + std::array productCode; + u8 _unk3_[0x30]; + u32 aciOffset; + u32 aciSize; + u32 acidOffset; + u32 acidSize; + } meta; + + static_assert(sizeof(NpdmMeta::flags) == sizeof(u8)); + static_assert(sizeof(NpdmMeta) == 0x80); + + public: + NPDM(); + + NPDM(const std::shared_ptr &backing); + }; +} diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index ffba65c5..3a43fcd7 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -5,12 +5,14 @@ Warn Info Debug + Verbose 0 1 2 3 + 4 List