am: Implement UserChannel parameters

Used by the Super Mairo 3D All-Stars collection.
This commit is contained in:
FearlessTobi 2023-09-10 02:36:26 +02:00 committed by Liam
parent 36917d8a8f
commit 87c0ba129c
9 changed files with 70 additions and 19 deletions

View file

@ -562,6 +562,8 @@ struct System::Impl {
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_write_manager{};
std::deque<std::vector<u8>> user_channel;
};
System::System() : impl{std::make_unique<Impl>(*this)} {}
@ -1036,6 +1038,10 @@ void System::ExecuteProgram(std::size_t program_index) {
}
}
std::deque<std::vector<u8>>& System::GetUserChannel() {
return impl->user_channel;
}
void System::RegisterExitCallback(ExitCallback&& callback) {
impl->exit_callback = std::move(callback);
}

View file

@ -4,6 +4,7 @@
#pragma once
#include <cstddef>
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
@ -459,6 +460,12 @@ public:
*/
void ExecuteProgram(std::size_t program_index);
/**
* Gets a reference to the user channel stack.
* It is used to transfer data between programs.
*/
[[nodiscard]] std::deque<std::vector<u8>>& GetUserChannel();
/// Type used for the frontend to designate a callback for System to exit the application.
using ExitCallback = std::function<void()>;

View file

@ -1518,12 +1518,26 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto kind = rp.PopEnum<LaunchParameterKind>();
LOG_WARNING(Service_AM, "(STUBBED) called, kind={:08X}", kind);
LOG_INFO(Service_AM, "called, kind={:08X}", kind);
if (kind == LaunchParameterKind::UserChannel) {
LOG_ERROR(Service_AM, "Popping from UserChannel is not supported!");
auto channel = system.GetUserChannel();
if (channel.empty()) {
LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultNoDataInChannel);
return;
}
auto data = channel.back();
channel.pop_back();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(system, std::move(data));
} else if (kind == LaunchParameterKind::AccountPreselectedUser &&
!launch_popped_account_preselect) {
// TODO: Verify this is hw-accurate
LaunchParameterAccountPreselectedUser params{};
params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC;
@ -1535,7 +1549,6 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
params.current_user = *uuid;
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
@ -1543,12 +1556,11 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(system, std::move(buffer));
launch_popped_account_preselect = true;
return;
} else {
LOG_ERROR(Service_AM, "Unknown launch parameter kind.");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultNoDataInChannel);
}
LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(AM::ResultNoDataInChannel);
}
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
@ -1840,14 +1852,22 @@ void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
}
void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called");
system.GetUserChannel().clear();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
const auto storage = rp.PopIpcInterface<IStorage>().lock();
if (storage) {
system.GetUserChannel().push_back(storage->GetData());
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);