From 117c6dfb97016b35d35f374b3ce39d49e6b53d10 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 2 Jul 2023 00:56:56 +0300 Subject: [PATCH 1/9] Make 3DS clock return system time and not UTC time --- src/core/memory.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 37c13c7d..9318c627 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -3,6 +3,7 @@ #include "resource_limits.hpp" #include #include // For time since epoch +#include using namespace KernelMemoryTypes; @@ -424,9 +425,19 @@ void Memory::mirrorMapping(u32 destAddress, u32 sourceAddress, u32 size) { u64 Memory::timeSince3DSEpoch() { using namespace std::chrono; - // ms since Jan 1 1970 - milliseconds ms = duration_cast(system_clock::now().time_since_epoch()); - // ms between Jan 1 1900 and Jan 1 1970 (2208988800 seconds elapsed between the two) + std::time_t rawTime = std::time(nullptr); // Get current UTC time + auto localTime = std::localtime(&rawTime); // Convert to local time + + bool daylightSavings = localTime->tm_isdst; // Get if time includes DST + localTime = std::gmtime(&rawTime); + + // Use gmtime + mktime to calculate difference between local time and UTC + auto timezoneDifference = rawTime - std::mktime(localTime); + if (daylightSavings) { + timezoneDifference += 60ull * 60ull; // Add 1 hour (60 seconds * 60 minutes) + } + + milliseconds ms = duration_cast(seconds(rawTime + timezoneDifference)); constexpr u64 offset = 2208988800ull * 1000; return ms.count() + offset; } \ No newline at end of file From 8930d44f5d1ed9a16178da39f4ede337ee4760b2 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 2 Jul 2023 01:00:57 +0300 Subject: [PATCH 2/9] Proper daylight savings time check --- src/core/memory.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9318c627..dfa155a2 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -428,7 +428,7 @@ u64 Memory::timeSince3DSEpoch() { std::time_t rawTime = std::time(nullptr); // Get current UTC time auto localTime = std::localtime(&rawTime); // Convert to local time - bool daylightSavings = localTime->tm_isdst; // Get if time includes DST + bool daylightSavings = localTime->tm_isdst > 0; // Get if time includes DST localTime = std::gmtime(&rawTime); // Use gmtime + mktime to calculate difference between local time and UTC @@ -437,7 +437,8 @@ u64 Memory::timeSince3DSEpoch() { timezoneDifference += 60ull * 60ull; // Add 1 hour (60 seconds * 60 minutes) } - milliseconds ms = duration_cast(seconds(rawTime + timezoneDifference)); - constexpr u64 offset = 2208988800ull * 1000; - return ms.count() + offset; + // seconds between Jan 1 1900 and Jan 1 1970 + constexpr u64 offset = 2208988800ull; + milliseconds ms = duration_cast(seconds(rawTime + timezoneDifference + offset)); + return ms.count(); } \ No newline at end of file From cb251581847fadf642c2f36c218e64fd5005c146 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 2 Jul 2023 17:10:47 +0300 Subject: [PATCH 3/9] Stop downloading LLVM on MacOS CI --- .github/workflows/MacOS_Build.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/MacOS_Build.yml b/.github/workflows/MacOS_Build.yml index 819d4647..4007e0e9 100644 --- a/.github/workflows/MacOS_Build.yml +++ b/.github/workflows/MacOS_Build.yml @@ -23,13 +23,10 @@ jobs: - name: Fetch submodules run: git submodule update --init --recursive - - name: Install LLVM # MacOS comes with "AppleClang" instead of regular Clang, and it can't build the project because no proper C++20 - run: brew install llvm - - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration From cba1b9f39b949d4b63f3745e2a93d85a304414b4 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 2 Jul 2023 20:18:34 +0300 Subject: [PATCH 4/9] [NCCH loader] Fix crypto check --- src/core/loader/ncch.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 0f29ddb5..5a94dd55 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -54,14 +54,6 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn romFS.hashRegionSize = u64(*(u32*)&header[0x1B8]) * mediaUnit; if (encrypted) { - if (!aesEngine.haveKeys()) { - Helpers::panic( - "Loaded an encrypted ROM but AES keys don't seem to have been provided correctly! Navigate to the emulator's\n" - "app data folder and make sure you have a sysdata directory with a file called aes_keys.txt which contains your keys!" - ); - return false; - } - Crypto::AESKey primaryKeyY; Crypto::AESKey secondaryKeyY; std::memcpy(primaryKeyY.data(), header, primaryKeyY.size()); @@ -128,6 +120,14 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn } // If it's truly encrypted, we need to read section again. if (encrypted) { + if (!aesEngine.haveKeys()) { + Helpers::panic( + "Loaded an encrypted ROM but AES keys don't seem to have been provided correctly! Navigate to the emulator's\n" + "app data folder and make sure you have a sysdata directory with a file called aes_keys.txt which contains your keys!" + ); + return false; + } + auto [success, bytes] = readFromFile(file, exheaderInfo, &exheader[0], 0, exheaderSize); if (!success || bytes != exheaderSize) { printf("Failed to read Extended NCCH header\n"); From 0b2ff6c5c8534d3138c8f5b3bf201163f2e27160 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 2 Jul 2023 22:36:45 +0300 Subject: [PATCH 5/9] Separate user and dev builds --- .github/workflows/Linux_Build.yml | 2 +- .github/workflows/MacOS_Build.yml | 2 +- .github/workflows/Windows_Build.yml | 2 +- CMakeLists.txt | 12 ++++++++- include/helpers.hpp | 34 +++++++++++++++++------- src/core/kernel/directory_operations.cpp | 2 +- src/core/renderer_gl/renderer_gl.cpp | 4 ++- src/core/services/apt.cpp | 5 +++- src/core/services/cecd.cpp | 5 +++- 9 files changed, 50 insertions(+), 18 deletions(-) diff --git a/.github/workflows/Linux_Build.yml b/.github/workflows/Linux_Build.yml index 71a318a8..d58c3c94 100644 --- a/.github/workflows/Linux_Build.yml +++ b/.github/workflows/Linux_Build.yml @@ -26,7 +26,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_USER_BUILD=ON - name: Build # Build your program with the given configuration diff --git a/.github/workflows/MacOS_Build.yml b/.github/workflows/MacOS_Build.yml index 819d4647..942452d8 100644 --- a/.github/workflows/MacOS_Build.yml +++ b/.github/workflows/MacOS_Build.yml @@ -29,7 +29,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -DENABLE_USER_BUILD=ON - name: Build # Build your program with the given configuration diff --git a/.github/workflows/Windows_Build.yml b/.github/workflows/Windows_Build.yml index 0a4abe41..2e8a8562 100644 --- a/.github/workflows/Windows_Build.yml +++ b/.github/workflows/Windows_Build.yml @@ -26,7 +26,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_USER_BUILD=ON - name: Build # Build your program with the given configuration diff --git a/CMakeLists.txt b/CMakeLists.txt index b7310d95..6596ffe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,10 @@ endif() project(Alber) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +option(DISABLE_PANIC_DEV "Make a build with fewer and less intrusive asserts" OFF) option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF) option(ENABLE_LTO "Enable link-time optimization" OFF) +option(ENABLE_USER_BUILD "Make a user-facing build. These builds have various assertions disabled, LTO, and more" OFF) include_directories(${PROJECT_SOURCE_DIR}/include/) include_directories(${PROJECT_SOURCE_DIR}/include/kernel) @@ -159,7 +161,7 @@ source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES}) add_executable(Alber ${SOURCE_FILES} ${FS_SOURCE_FILES} ${CRYPTO_SOURCE_FILES} ${KERNEL_SOURCE_FILES} ${LOADER_SOURCE_FILES} ${SERVICE_SOURCE_FILES} ${PICA_SOURCE_FILES} ${RENDERER_GL_SOURCE_FILES} ${THIRD_PARTY_SOURCE_FILES} ${HEADER_FILES}) -if(ENABLE_LTO) +if(ENABLE_LTO OR ENABLE_USER_BUILD) set_target_properties(Alber PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() @@ -167,4 +169,12 @@ target_link_libraries(Alber PRIVATE dynarmic SDL2-static glad cryptopp) if(GPU_DEBUG_INFO) target_compile_definitions(Alber PRIVATE GPU_DEBUG_INFO=1) +endif() + +if(ENABLE_USER_BUILD) + target_compile_definitions(Alber PRIVATE PANDA3DS_USER_BUILD=1) +endif() + +if(ENABLE_USER_BUILD OR DISABLE_PANIC_DEV) + target_compile_definitions(Alber PRIVATE PANDA3DS_LIMITED_PANICS=1) endif() \ No newline at end of file diff --git a/include/helpers.hpp b/include/helpers.hpp index 53c57c7c..9830cc88 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -30,24 +30,31 @@ using s32 = std::int32_t; using s64 = std::int64_t; namespace Helpers { - [[noreturn]] static void panic(const char* fmt, ...) { - std::va_list args; - va_start(args, fmt); + // Unconditional panic, unlike panicDev which does not panic on user builds + template + [[noreturn]] static void panic(const char* fmt, Args&&... args) { std::cout << termcolor::on_red << "[FATAL] "; - std::vprintf(fmt, args); + std::printf(fmt, args...); std::cout << termcolor::reset << "\n"; - va_end(args); exit(1); } + +#ifdef PANDA3DS_LIMITED_PANICS + template + static void panicDev(const char* fmt, Args&&... args) {} +#else + template + [[noreturn]] static void panicDev(const char* fmt, Args&&... args) { + panic(fmt, args...); + } +#endif - static void warn(const char* fmt, ...) { - std::va_list args; - va_start(args, fmt); + template + static void warn(const char* fmt, Args&&... args) { std::cout << termcolor::on_red << "[Warning] "; - std::vprintf(fmt, args); + std::printf(fmt, args...); std::cout << termcolor::reset << "\n"; - va_end(args); } static constexpr bool buildingInDebugMode() { @@ -57,6 +64,13 @@ namespace Helpers { return true; } + static constexpr bool isUserBuild() { +#ifdef PANDA3DS_USER_BUILD + return true; +#endif + return false; + } + static void debug_printf(const char* fmt, ...) { if constexpr (buildingInDebugMode()) { std::va_list args; diff --git a/src/core/kernel/directory_operations.cpp b/src/core/kernel/directory_operations.cpp index 567d9cb8..fe4f58f4 100644 --- a/src/core/kernel/directory_operations.cpp +++ b/src/core/kernel/directory_operations.cpp @@ -33,7 +33,7 @@ void Kernel::readDirectory(u32 messagePointer, Handle directory) { const u32 entryCount = mem.read32(messagePointer + 4); const u32 outPointer = mem.read32(messagePointer + 12); logFileIO("Directory::Read (handle = %X, entry count = %d, out pointer = %08X)\n", directory, entryCount, outPointer); - Helpers::panic("Unimplemented FsDir::Read"); + Helpers::panicDev("Unimplemented FsDir::Read"); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, 0); diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 0cbc9cbc..487c9db8 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -695,7 +695,9 @@ void Renderer::bindDepthBuffer() { tex = depthBufferCache.add(sampleBuffer).texture.m_handle; } - if (PICA::DepthFmt::Depth24Stencil8 != depthBufferFormat) Helpers::panic("TODO: Should we remove stencil attachment?"); + if (PICA::DepthFmt::Depth24Stencil8 != depthBufferFormat) { + Helpers::panicDev("TODO: Should we remove stencil attachment?"); + } auto attachment = depthBufferFormat == PICA::DepthFmt::Depth24Stencil8 ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT; glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex, 0); } diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index f2c7612d..becf637f 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -81,7 +81,10 @@ void APTService::handleSyncRequest(u32 messagePointer) { case APTCommands::SetApplicationCpuTimeLimit: setApplicationCpuTimeLimit(messagePointer); break; case APTCommands::SetScreencapPostPermission: setScreencapPostPermission(messagePointer); break; case APTCommands::TheSmashBrosFunction: theSmashBrosFunction(messagePointer); break; - default: Helpers::panic("APT service requested. Command: %08X\n", command); + default: + Helpers::panicDev("APT service requested. Command: %08X\n", command); + mem.write32(messagePointer + 4, Result::Success); + break; } } diff --git a/src/core/services/cecd.cpp b/src/core/services/cecd.cpp index f641e40d..dd9ccb2f 100644 --- a/src/core/services/cecd.cpp +++ b/src/core/services/cecd.cpp @@ -16,7 +16,10 @@ void CECDService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { case CECDCommands::GetInfoEventHandle: getInfoEventHandle(messagePointer); break; - default: Helpers::panic("CECD service requested. Command: %08X\n", command); + default: + Helpers::panicDev("CECD service requested. Command: %08X\n", command); + mem.write32(messagePointer + 4, Result::Success); + break; } } From d5d8f869e4b0b76c7bbaf5db88b854f9ffd253fc Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 2 Jul 2023 23:00:15 +0300 Subject: [PATCH 6/9] Update idle_thread.cpp --- src/core/kernel/idle_thread.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/kernel/idle_thread.cpp b/src/core/kernel/idle_thread.cpp index 5389fecc..5abba373 100644 --- a/src/core/kernel/idle_thread.cpp +++ b/src/core/kernel/idle_thread.cpp @@ -59,12 +59,12 @@ void Kernel::setupIdleThread() { t.fpscr = FPSCR::ThreadDefault; // Our idle thread should have as low of a priority as possible, because, well, it's an idle thread. - // We handle this by giving it a priority of 0xff, which is lower than is actually allowed for user threads - // (High priority value = low priority) - t.priority = 0xff; + // We handle this by giving it a priority of 0x40, which is lower than is actually allowed for user threads + // (High priority value = low priority). This is the same priority used in the retail kernel. + t.priority = 0x40; t.status = ThreadStatus::Ready; // Add idle thread to the list of thread indices threadIndices.push_back(idleThreadIndex); sortThreads(); -} \ No newline at end of file +} From 50c0c7fea553c9b46eaa2615608a947686d34fa0 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Mon, 3 Jul 2023 02:02:18 +0300 Subject: [PATCH 7/9] Try to tone down warnings Co-Authored-By: Wunk --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6596ffe7..cccd9e2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 12) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 12) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fbracket-depth=4096") endif() @@ -13,6 +13,10 @@ endif() project(Alber) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security") +endif() + option(DISABLE_PANIC_DEV "Make a build with fewer and less intrusive asserts" OFF) option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF) option(ENABLE_LTO "Enable link-time optimization" OFF) @@ -177,4 +181,4 @@ endif() if(ENABLE_USER_BUILD OR DISABLE_PANIC_DEV) target_compile_definitions(Alber PRIVATE PANDA3DS_LIMITED_PANICS=1) -endif() \ No newline at end of file +endif() From f262cf2836f9d232c51160b9b8c2a1ab7c5896f7 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:25:09 +0300 Subject: [PATCH 8/9] Fix false positives in crypto code hopefully --- src/core/loader/ncch.cpp | 72 ++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 5a94dd55..75e0196a 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -44,15 +44,20 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn exheaderInfo.offset = info.offset + 0x200; exheaderInfo.size = exheaderSize; exheaderInfo.hashRegionSize = 0; + exheaderInfo.encryptionInfo = std::nullopt; exeFS.offset = info.offset + u64(*(u32*)&header[0x1A0]) * mediaUnit; exeFS.size = u64(*(u32*)&header[0x1A4]) * mediaUnit; exeFS.hashRegionSize = u64(*(u32*)&header[0x1A8]) * mediaUnit; + exeFS.encryptionInfo = std::nullopt; romFS.offset = info.offset + u64(*(u32*)&header[0x1B0]) * mediaUnit; romFS.size = u64(*(u32*)&header[0x1B4]) * mediaUnit; romFS.hashRegionSize = u64(*(u32*)&header[0x1B8]) * mediaUnit; + romFS.encryptionInfo = std::nullopt; + // Shows whether we got the primary and secondary keys correctly + bool gotCryptoKeys = true; if (encrypted) { Crypto::AESKey primaryKeyY; Crypto::AESKey secondaryKeyY; @@ -61,44 +66,36 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn if (!seedCrypto) { secondaryKeyY = primaryKeyY; } else { - Helpers::panic("Seed crypto is not supported"); - return false; + Helpers::warn("Seed crypto is not supported"); + gotCryptoKeys = false; } auto primaryResult = getPrimaryKey(aesEngine, primaryKeyY); - - if (!primaryResult.first) { - Helpers::panic("getPrimaryKey failed!"); - return false; - } - - Crypto::AESKey primaryKey = primaryResult.second; - auto secondaryResult = getSecondaryKey(aesEngine, secondaryKeyY); - if (!secondaryResult.first) { - Helpers::panic("getSecondaryKey failed!"); - return false; + if (!primaryResult.first || !secondaryResult.first) { + gotCryptoKeys = false; + } else { + Crypto::AESKey primaryKey = primaryResult.second; + Crypto::AESKey secondaryKey = secondaryResult.second; + + EncryptionInfo encryptionInfoTmp; + encryptionInfoTmp.normalKey = primaryKey; + encryptionInfoTmp.initialCounter.fill(0); + + for (std::size_t i = 1; i <= sizeof(std::uint64_t) - 1; i++) { + encryptionInfoTmp.initialCounter[i] = header[0x108 + sizeof(std::uint64_t) - 1 - i]; + } + encryptionInfoTmp.initialCounter[8] = 1; + exheaderInfo.encryptionInfo = encryptionInfoTmp; + + encryptionInfoTmp.initialCounter[8] = 2; + exeFS.encryptionInfo = encryptionInfoTmp; + + encryptionInfoTmp.normalKey = secondaryKey; + encryptionInfoTmp.initialCounter[8] = 3; + romFS.encryptionInfo = encryptionInfoTmp; } - - Crypto::AESKey secondaryKey = secondaryResult.second; - - EncryptionInfo encryptionInfoTmp; - encryptionInfoTmp.normalKey = primaryKey; - encryptionInfoTmp.initialCounter.fill(0); - - for (std::size_t i = 1; i <= sizeof(std::uint64_t) - 1; i++) { - encryptionInfoTmp.initialCounter[i] = header[0x108 + sizeof(std::uint64_t) - 1 - i]; - } - encryptionInfoTmp.initialCounter[8] = 1; - exheaderInfo.encryptionInfo = encryptionInfoTmp; - - encryptionInfoTmp.initialCounter[8] = 2; - exeFS.encryptionInfo = encryptionInfoTmp; - - encryptionInfoTmp.normalKey = secondaryKey; - encryptionInfoTmp.initialCounter[8] = 3; - romFS.encryptionInfo = encryptionInfoTmp; } if (exheaderSize != 0) { @@ -117,7 +114,13 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn if (u32(programID) == u32(jumpID) && encrypted) { printf("NCSD is supposedly ecrypted but not actually encrypted\n"); encrypted = false; + + // Cartridge is not actually encrypted, set all of our encryption info structures to nullopt + exheaderInfo.encryptionInfo = std::nullopt; + romFS.encryptionInfo = std::nullopt; + exeFS.encryptionInfo = std::nullopt; } + // If it's truly encrypted, we need to read section again. if (encrypted) { if (!aesEngine.haveKeys()) { @@ -128,6 +131,11 @@ bool NCCH::loadFromHeader(Crypto::AESEngine &aesEngine, IOFile& file, const FSIn return false; } + if (!gotCryptoKeys) { + Helpers::panic("ROM is encrypted but it seems we couldn't get either the primary or the secondary key"); + return false; + } + auto [success, bytes] = readFromFile(file, exheaderInfo, &exheader[0], 0, exheaderSize); if (!success || bytes != exheaderSize) { printf("Failed to read Extended NCCH header\n"); From 14356902abed2adc203ffb42e6dfa8f16435ef26 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Mon, 3 Jul 2023 19:50:42 +0300 Subject: [PATCH 9/9] [HID] Implement DisableAccelerometer/DisableGyroscopeLow --- include/services/hid.hpp | 2 ++ src/core/services/hid.cpp | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/services/hid.hpp b/include/services/hid.hpp index beadf7f1..70bae750 100644 --- a/include/services/hid.hpp +++ b/include/services/hid.hpp @@ -63,6 +63,8 @@ class HIDService { MAKE_LOG_FUNCTION(log, hidLogger) // Service commands + void disableAccelerometer(u32 messagePointer); + void disableGyroscopeLow(u32 messagePointer); void enableAccelerometer(u32 messagePointer); void enableGyroscopeLow(u32 messagePointer); void getGyroscopeLowCalibrateParam(u32 messagePointer); diff --git a/src/core/services/hid.cpp b/src/core/services/hid.cpp index 7993dc7a..27a078f2 100644 --- a/src/core/services/hid.cpp +++ b/src/core/services/hid.cpp @@ -7,7 +7,9 @@ namespace HIDCommands { enum : u32 { GetIPCHandles = 0x000A0000, EnableAccelerometer = 0x00110000, + DisableAccelerometer = 0x00120000, EnableGyroscopeLow = 0x00130000, + DisableGyroscopeLow = 0x00140000, GetGyroscopeLowRawToDpsCoefficient = 0x00150000, GetGyroscopeLowCalibrateParam = 0x00160000 }; @@ -36,6 +38,8 @@ void HIDService::reset() { void HIDService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case HIDCommands::DisableAccelerometer: disableAccelerometer(messagePointer); break; + case HIDCommands::DisableGyroscopeLow: disableGyroscopeLow(messagePointer); break; case HIDCommands::EnableAccelerometer: enableAccelerometer(messagePointer); break; case HIDCommands::EnableGyroscopeLow: enableGyroscopeLow(messagePointer); break; case HIDCommands::GetGyroscopeLowCalibrateParam: getGyroscopeLowCalibrateParam(messagePointer); break; @@ -53,6 +57,14 @@ void HIDService::enableAccelerometer(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void HIDService::disableAccelerometer(u32 messagePointer) { + log("HID::DisableAccelerometer\n"); + accelerometerEnabled = false; + + mem.write32(messagePointer, IPC::responseHeader(0x12, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void HIDService::enableGyroscopeLow(u32 messagePointer) { log("HID::EnableGyroscopeLow\n"); gyroEnabled = true; @@ -61,6 +73,14 @@ void HIDService::enableGyroscopeLow(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } +void HIDService::disableGyroscopeLow(u32 messagePointer) { + log("HID::DisableGyroscopeLow\n"); + gyroEnabled = false; + + mem.write32(messagePointer, IPC::responseHeader(0x14, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + void HIDService::getGyroscopeLowCalibrateParam(u32 messagePointer) { log("HID::GetGyroscopeLowCalibrateParam\n"); constexpr s16 unit = 6700; // Approximately from Citra which took it from hardware