diff --git a/README.md b/README.md index 3da8d8f40..24290ba28 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3971. +This is the source code for early-access 3972. ## Legal Notice diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index a7e414b81..c4f631924 100755 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp @@ -9,6 +9,7 @@ #include "input_common/drivers/virtual_gamepad.h" #include "input_common/main.h" #include "jni/emu_window/emu_window.h" +#include "jni/native.h" void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { m_window_width = ANativeWindow_getWidth(surface); @@ -57,6 +58,13 @@ void EmuWindow_Android::OnRemoveNfcTag() { m_input_subsystem->GetVirtualAmiibo()->CloseAmiibo(); } +void EmuWindow_Android::OnFrameDisplayed() { + if (!m_first_frame) { + EmulationSession::GetInstance().OnEmulationStarted(); + m_first_frame = true; + } +} + EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, ANativeWindow* surface, std::shared_ptr driver_library) diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index b38087f73..a34a0e479 100755 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h @@ -45,7 +45,7 @@ public: float gyro_z, float accel_x, float accel_y, float accel_z); void OnReadNfcTag(std::span data); void OnRemoveNfcTag(); - void OnFrameDisplayed() override {} + void OnFrameDisplayed() override; std::unique_ptr CreateSharedContext() const override { return {std::make_unique(m_driver_library)}; @@ -61,4 +61,6 @@ private: float m_window_height{}; std::shared_ptr m_driver_library; + + bool m_first_frame = false; }; diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 1484cc224..64663b084 100755 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -372,8 +372,6 @@ void EmulationSession::RunEmulation() { m_system.InitializeDebugger(); } - OnEmulationStarted(); - while (true) { { [[maybe_unused]] std::unique_lock lock(m_mutex); diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index 6b02c44b5..78ef96802 100755 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h @@ -52,9 +52,10 @@ public: void OnGamepadDisconnectEvent([[maybe_unused]] int index); SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); + static void OnEmulationStarted(); + private: static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max); - static void OnEmulationStarted(); static void OnEmulationStopped(Core::SystemResultStatus result); private: diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 93e7d7a44..3945c3bf8 100755 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -562,6 +562,120 @@ static std::string PaginateBuffer(std::string_view buffer, std::string_view requ } } +static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) { + Kernel::KMemoryInfo mem_info; + Kernel::Svc::MemoryInfo svc_mem_info; + Kernel::Svc::PageInfo page_info; + VAddr cur_addr{base}; + + // Expect: r-x Code (.text) + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + svc_mem_info = mem_info.GetSvcMemoryInfo(); + cur_addr = svc_mem_info.base_address + svc_mem_info.size; + if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || + svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { + return cur_addr - 1; + } + + // Expect: r-- Code (.rodata) + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + svc_mem_info = mem_info.GetSvcMemoryInfo(); + cur_addr = svc_mem_info.base_address + svc_mem_info.size; + if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || + svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) { + return cur_addr - 1; + } + + // Expect: rw- CodeData (.data) + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + svc_mem_info = mem_info.GetSvcMemoryInfo(); + cur_addr = svc_mem_info.base_address + svc_mem_info.size; + return cur_addr - 1; +} + +static Loader::AppLoader::Modules FindModules(Core::System& system) { + Loader::AppLoader::Modules modules; + + auto& page_table = system.ApplicationProcess()->GetPageTable(); + auto& memory = system.ApplicationMemory(); + VAddr cur_addr = 0; + + // Look for executable sections in Code or AliasCode regions. + while (true) { + Kernel::KMemoryInfo mem_info{}; + Kernel::Svc::PageInfo page_info{}; + R_ASSERT( + page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + auto svc_mem_info = mem_info.GetSvcMemoryInfo(); + + if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute && + (svc_mem_info.state == Kernel::Svc::MemoryState::Code || + svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) { + // Try to read the module name from its path. + constexpr s32 PathLengthMax = 0x200; + struct { + u32 zero; + s32 path_length; + std::array path; + } module_path; + + if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path, + sizeof(module_path))) { + if (module_path.zero == 0 && module_path.path_length > 0) { + // Truncate module name. + module_path.path[PathLengthMax - 1] = '\0'; + + // Ignore leading directories. + char* path_pointer = module_path.path.data(); + + for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) && + module_path.path[i] != '\0'; + i++) { + if (module_path.path[i] == '/' || module_path.path[i] == '\\') { + path_pointer = module_path.path.data() + i + 1; + } + } + + // Insert output. + modules.emplace(svc_mem_info.base_address, path_pointer); + } + } + } + + // Check if we're done. + const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size; + if (next_address <= cur_addr) { + break; + } + + cur_addr = next_address; + } + + return modules; +} + +static VAddr FindMainModuleEntrypoint(Core::System& system) { + Loader::AppLoader::Modules modules; + system.GetAppLoader().ReadNSOModules(modules); + + // Do we have a module named main? + const auto main = std::find_if(modules.begin(), modules.end(), + [](const auto& key) { return key.second == "main"; }); + + if (main != modules.end()) { + return main->first; + } + + // Do we have any loaded executable sections? + modules = FindModules(system); + if (!modules.empty()) { + return modules.begin()->first; + } + + // As a last resort, use the start of the code region. + return GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart()); +} + void GDBStub::HandleQuery(std::string_view command) { if (command.starts_with("TStatus")) { // no tracepoint support @@ -573,21 +687,10 @@ void GDBStub::HandleQuery(std::string_view command) { const auto target_xml{arch->GetTargetXML()}; SendReply(PaginateBuffer(target_xml, command.substr(30))); } else if (command.starts_with("Offsets")) { - Loader::AppLoader::Modules modules; - system.GetAppLoader().ReadNSOModules(modules); - - const auto main = std::find_if(modules.begin(), modules.end(), - [](const auto& key) { return key.second == "main"; }); - if (main != modules.end()) { - SendReply(fmt::format("TextSeg={:x}", main->first)); - } else { - SendReply(fmt::format( - "TextSeg={:x}", - GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart()))); - } + const auto main_offset = FindMainModuleEntrypoint(system); + SendReply(fmt::format("TextSeg={:x}", main_offset)); } else if (command.starts_with("Xfer:libraries:read::")) { - Loader::AppLoader::Modules modules; - system.GetAppLoader().ReadNSOModules(modules); + auto modules = FindModules(system); std::string buffer; buffer += R"()"; @@ -727,37 +830,6 @@ static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::Memory } } -static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) { - Kernel::KMemoryInfo mem_info; - Kernel::Svc::MemoryInfo svc_mem_info; - Kernel::Svc::PageInfo page_info; - VAddr cur_addr{base}; - - // Expect: r-x Code (.text) - R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - svc_mem_info = mem_info.GetSvcMemoryInfo(); - cur_addr = svc_mem_info.base_address + svc_mem_info.size; - if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || - svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { - return cur_addr - 1; - } - - // Expect: r-- Code (.rodata) - R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - svc_mem_info = mem_info.GetSvcMemoryInfo(); - cur_addr = svc_mem_info.base_address + svc_mem_info.size; - if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || - svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) { - return cur_addr - 1; - } - - // Expect: rw- CodeData (.data) - R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - svc_mem_info = mem_info.GetSvcMemoryInfo(); - cur_addr = svc_mem_info.base_address + svc_mem_info.size; - return cur_addr - 1; -} - void GDBStub::HandleRcmd(const std::vector& command) { std::string_view command_str{reinterpret_cast(&command[0]), command.size()}; std::string reply; @@ -784,8 +856,7 @@ void GDBStub::HandleRcmd(const std::vector& command) { reply = "Fastmem is not enabled.\n"; } } else if (command_str == "get info") { - Loader::AppLoader::Modules modules; - system.GetAppLoader().ReadNSOModules(modules); + auto modules = FindModules(system); reply = fmt::format("Process: {:#x} ({})\n" "Program Id: {:#018x}\n", diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp index fb890f978..274fee493 100755 --- a/src/core/hle/kernel/k_capabilities.cpp +++ b/src/core/hle/kernel/k_capabilities.cpp @@ -5,6 +5,7 @@ #include "core/hle/kernel/k_capabilities.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_process_page_table.h" +#include "core/hle/kernel/k_trace.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_version.h" @@ -329,6 +330,8 @@ Result KCapabilities::SetCapabilities(std::span caps, KProcessPageTab // Map the range. R_TRY(this->MapRange_(cap, size_cap, page_table)); + } else if (GetCapabilityType(cap) == CapabilityType::MapRegion && !IsKTraceEnabled) { + continue; } else { R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table)); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 7e40f84b3..0c6f238e8 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1910,7 +1910,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t StartGameType type, AmLaunchType launch_type) { LOG_INFO(Frontend, "yuzu starting..."); - if (program_id > static_cast(Service::AM::Applets::AppletProgramId::MaxProgramId)) { + if (program_id == 0 || + program_id > static_cast(Service::AM::Applets::AppletProgramId::MaxProgramId)) { StoreRecentFile(filename); // Put the filename on top of the list } @@ -4324,7 +4325,7 @@ void GMainWindow::OnAlbum() { const auto filename = QString::fromStdString(album_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path(); - BootGame(filename); + BootGame(filename, AlbumId); } void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { @@ -4348,7 +4349,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); UISettings::values.roms_path = QFileInfo(filename).path(); - BootGame(filename); + BootGame(filename, CabinetId); } void GMainWindow::OnMiiEdit() { @@ -4371,7 +4372,7 @@ void GMainWindow::OnMiiEdit() { const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); UISettings::values.roms_path = QFileInfo(filename).path(); - BootGame(filename); + BootGame(filename, MiiEditId); } void GMainWindow::OnCaptureScreenshot() {