diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
index 22976900f2..9c39f7b166 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
@@ -133,6 +133,11 @@ class InstallableFragment : Fragment() {
R.string.install_firmware_description,
install = { mainActivity.getFirmware.launch(arrayOf("application/zip")) }
),
+ Installable(
+ R.string.uninstall_firmware,
+ R.string.uninstall_firmware_description,
+ install = { mainActivity.uninstallFirmware() }
+ ),
Installable(
R.string.install_prod_keys,
R.string.install_prod_keys_description,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 79780fa1f0..468c758c2f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -376,7 +376,31 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
messageToShow
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
-
+ fun uninstallFirmware() {
+ val firmwarePath = File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
+ ProgressDialogFragment.newInstance(
+ this,
+ R.string.firmware_uninstalling
+ ) { progressCallback, _ ->
+ var messageToShow: Any
+ try {
+ // Ensure the firmware directory exists before attempting to delete
+ if (firmwarePath.exists()) {
+ firmwarePath.deleteRecursively()
+ // Optionally reinitialize the system or perform other necessary steps
+ NativeLibrary.initializeSystem(true)
+ homeViewModel.setCheckKeys(true)
+ messageToShow = getString(R.string.firmware_uninstalled_success)
+ } else {
+ messageToShow = getString(R.string.firmware_uninstalled_failure)
+ }
+ } catch (e: Exception) {
+ Log.error("[MainActivity] Firmware uninstall failed - ${e.message}")
+ messageToShow = getString(R.string.fatal_error)
+ }
+ messageToShow
+ }.show(supportFragmentManager, ProgressDialogFragment.TAG)
+ }
val getAmiiboKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index c0de9394e3..00a6a9adf7 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -143,6 +143,11 @@
Firmware installed successfully
Firmware installation failed
Make sure the firmware nca files are at the root of the zip and try again.
+ Uninstall firmware
+ Uninstalling the firmware will remove it from the device and may affect game compatibility.
+ Uninstalling firmware
+ Firmware uninstalled successfully
+ Firmware uninstallation failed
Share debug logs
Share eden\'s log file to debug issues
No log file found
diff --git a/src/core/hle/service/am/process_creation.cpp b/src/core/hle/service/am/process_creation.cpp
index aaa03c4c39..81a8fb0b44 100644
--- a/src/core/hle/service/am/process_creation.cpp
+++ b/src/core/hle/service/am/process_creation.cpp
@@ -60,24 +60,29 @@ std::unique_ptr CreateProcessImpl(std::unique_ptr& o
} // Anonymous namespace
std::unique_ptr CreateProcess(Core::System& system, u64 program_id,
- u8 minimum_key_generation, u8 maximum_key_generation) {
- FileSys::VirtualFile nca_raw = system.GetContentProviderUnion()
- .GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
+ u8 minimum_key_generation, u8 maximum_key_generation) {
+ // Attempt to load program NCA.
+ FileSys::VirtualFile nca_raw{};
+ // Get the program NCA from storage.
+ auto& storage = system.GetContentProviderUnion();
+ nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
+
+ // Ensure we retrieved a program NCA.
if (!nca_raw) {
return nullptr;
}
- FileSys::NCA nca(nca_raw);
- if (nca.GetStatus() != Loader::ResultStatus::Success) {
- return nullptr;
- }
-
- u8 current_gen = nca.GetKeyGeneration();
- if (minimum_key_generation > 0 && (current_gen < minimum_key_generation ||
- current_gen > maximum_key_generation)) {
- LOG_WARNING(Service_LDR, "Program {:016X} has unsupported generation {}. "
- "Attempting to load anyway...", program_id, current_gen);
+ // Ensure we have a suitable version.
+ if (minimum_key_generation > 0) {
+ FileSys::NCA nca(nca_raw);
+ if (nca.GetStatus() == Loader::ResultStatus::Success &&
+ (nca.GetKeyGeneration() < minimum_key_generation ||
+ nca.GetKeyGeneration() > maximum_key_generation)) {
+ LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
+ nca.GetKeyGeneration());
+ return nullptr;
+ }
}
std::unique_ptr loader;
@@ -101,7 +106,7 @@ std::unique_ptr CreateApplicationProcess(std::vector& out_control,
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
- std::fill(out_control.begin(), out_control.end(), (u8) 0);
+ std::fill(out_control.begin(), out_control.end(), 0);
}
auto& storage = system.GetContentProviderUnion();
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
index 5a787494a8..fc9c77fc36 100644
--- a/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.cpp
@@ -18,6 +18,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys
// clang-format off
static const FunctionInfo functions[] = {
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
+ {110, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxyForDebug>, "OpenSystemAppletProxyForDebug"},
{200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
{201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
{300, nullptr, "OpenOverlayAppletProxy"},
@@ -25,6 +26,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
{410, nullptr, "GetSystemAppletControllerForDebug"},
{450, D<&IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions>, "GetSystemProcessCommonFunctions"}, // 19.0.0+
+ {460, nullptr, "Unknown460"},
{1000, nullptr, "GetDebugFunctions"},
};
// clang-format on
@@ -49,6 +51,26 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
}
}
+Result IAllSystemAppletProxiesService::OpenSystemAppletProxyForDebug(
+ Out> out_proxy, ClientProcessId pid) {
+ LOG_DEBUG(Service_AM, "OpenSystemAppletProxyForDebug called");
+
+ auto process = system.ApplicationProcess();
+ if (!process) {
+ LOG_ERROR(Service_AM, "No application process available");
+ R_THROW(ResultUnknown);
+ }
+
+ if (const auto applet = GetAppletFromProcessId(pid)) {
+ *out_proxy = std::make_shared(
+ system, applet, process, m_window_system);
+ R_SUCCEED();
+ }
+
+ LOG_ERROR(Service_AM, "Applet not found for pid={}", pid.pid);
+ R_THROW(ResultUnknown);
+}
+
Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
Out> out_library_applet_proxy, ClientProcessId pid,
InCopyHandle process_handle,
diff --git a/src/core/hle/service/am/service/all_system_applet_proxies_service.h b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
index a3111c4c9b..72730ea55a 100644
--- a/src/core/hle/service/am/service/all_system_applet_proxies_service.h
+++ b/src/core/hle/service/am/service/all_system_applet_proxies_service.h
@@ -27,6 +27,7 @@ private:
Result OpenSystemAppletProxy(Out> out_system_applet_proxy,
ClientProcessId pid,
InCopyHandle process_handle);
+ Result OpenSystemAppletProxyForDebug(Out> out_proxy, ClientProcessId pid);
Result OpenLibraryAppletProxy(Out> out_library_applet_proxy,
ClientProcessId pid,
InCopyHandle process_handle,
diff --git a/src/core/hle/service/am/service/applet_common_functions.cpp b/src/core/hle/service/am/service/applet_common_functions.cpp
index a051000af4..ed203e979a 100644
--- a/src/core/hle/service/am/service/applet_common_functions.cpp
+++ b/src/core/hle/service/am/service/applet_common_functions.cpp
@@ -32,6 +32,11 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
{91, nullptr, "OpenNamedChannelAsChild"},
{100, nullptr, "SetApplicationCoreUsageMode"},
{300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"},
+ {310, nullptr, "IsSystemAppletHomeMenu"}, //19.0.0+
+ {311, nullptr, "Unknown311"},
+ {320, nullptr, "SetGpuTimeSliceBoost"}, //19.0.0+
+ {321, nullptr, "SetGpuTimeSliceBoostDueToApplication"}, //19.0.0+
+ {350, nullptr, "Unknown350"},
};
// clang-format on
diff --git a/src/core/hle/service/am/service/library_applet_creator.cpp b/src/core/hle/service/am/service/library_applet_creator.cpp
index 3ffb03bc97..413388d40a 100644
--- a/src/core/hle/service/am/service/library_applet_creator.cpp
+++ b/src/core/hle/service/am/service/library_applet_creator.cpp
@@ -111,9 +111,11 @@ std::shared_ptr CreateGuestApplet(Core::System& system,
Firmware1500 = 15,
Firmware1600 = 16,
Firmware1700 = 17,
+ Firmware1800 = 18,
+ Firmware1900 = 19,
};
- auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700);
+ auto process = CreateProcess(system, program_id, Firmware1400, Firmware1900);
if (!process) {
// Couldn't initialize the guest process
return {};
diff --git a/src/core/hle/service/am/service/process_winding_controller.cpp b/src/core/hle/service/am/service/process_winding_controller.cpp
index 10df830d70..a150248e71 100644
--- a/src/core/hle/service/am/service/process_winding_controller.cpp
+++ b/src/core/hle/service/am/service/process_winding_controller.cpp
@@ -15,7 +15,7 @@ IProcessWindingController::IProcessWindingController(Core::System& system_,
static const FunctionInfo functions[] = {
{0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"},
{11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"},
- {21, nullptr, "PushContext"},
+ {21, D<&IProcessWindingController::PushContext>, "PushContext"},
{22, nullptr, "PopContext"},
{23, nullptr, "CancelWindingReservation"},
{30, nullptr, "WindAndDoReserved"},
@@ -51,4 +51,9 @@ Result IProcessWindingController::OpenCallingLibraryApplet(
R_SUCCEED();
}
+Result IProcessWindingController::PushContext() {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/process_winding_controller.h b/src/core/hle/service/am/service/process_winding_controller.h
index 4408af1f1d..bcf341d94c 100644
--- a/src/core/hle/service/am/service/process_winding_controller.h
+++ b/src/core/hle/service/am/service/process_winding_controller.h
@@ -21,7 +21,7 @@ private:
Result GetLaunchReason(Out out_launch_reason);
Result OpenCallingLibraryApplet(
Out> out_calling_library_applet);
-
+ Result PushContext();
const std::shared_ptr