citra-emu
/
citra-canary
Archived
1
0
Fork 0

apt: Implement additional applet state management. (#6303)

* apt: Implement additional library applet state management.

* kernel: Clear process handle table on exit.

* apt: Implement system applet commands.

* apt: Pop MediaType from command buffers with correct size.

* apt: Improve accuracy of parameters and HLE applet lifecycle.

* apt: General cleanup.

* file_sys: Make system save data open error code more correct.

Not sure if this is the exact right error code, but it's at least
more correct than before as Game Notes will now create its system
save data instead of throwing a fatal error.

* apt: Fix launching New 3DS Internet Browser.

* frd: Correct fix to GetMyScreenName response.
This commit is contained in:
Steveice10 2023-02-28 04:09:54 -08:00 committed by GitHub
parent 8b116aaa04
commit 3c15398f9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 966 additions and 705 deletions

View File

@ -589,7 +589,7 @@ void System::Reset() {
// TODO: Properly implement the reset // TODO: Properly implement the reset
// Since the system is completely reinitialized, we'll have to store the deliver arg manually. // Since the system is completely reinitialized, we'll have to store the deliver arg manually.
boost::optional<Service::APT::AppletManager::DeliverArg> deliver_arg; boost::optional<Service::APT::DeliverArg> deliver_arg;
if (auto apt = Service::APT::GetModule(*this)) { if (auto apt = Service::APT::GetModule(*this)) {
deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg(); deliver_arg = apt->GetAppletManager()->ReceiveDeliverArg();
} }

View File

@ -60,7 +60,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
std::string fullpath = GetSystemSaveDataPath(base_path, path); std::string fullpath = GetSystemSaveDataPath(base_path, path);
if (!FileUtil::Exists(fullpath)) { if (!FileUtil::Exists(fullpath)) {
// TODO(Subv): Check error code, this one is probably wrong // TODO(Subv): Check error code, this one is probably wrong
return ERR_NOT_FORMATTED; return ERROR_NOT_FOUND;
} }
auto archive = std::make_unique<SaveDataArchive>(fullpath); auto archive = std::make_unique<SaveDataArchive>(fullpath);
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));

View File

@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <utility>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/core.h" #include "core/core.h"
@ -42,24 +43,24 @@ static Core::TimingEventType* applet_update_event = nullptr;
/// The interval at which the Applet update callback will be called, 16.6ms /// The interval at which the Applet update callback will be called, 16.6ms
static const u64 applet_update_interval_us = 16666; static const u64 applet_update_interval_us = 16666;
ResultCode Applet::Create(Service::APT::AppletId id, ResultCode Applet::Create(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
std::weak_ptr<Service::APT::AppletManager> manager) { const std::shared_ptr<Service::APT::AppletManager>& manager) {
switch (id) { switch (id) {
case Service::APT::AppletId::SoftwareKeyboard1: case Service::APT::AppletId::SoftwareKeyboard1:
case Service::APT::AppletId::SoftwareKeyboard2: case Service::APT::AppletId::SoftwareKeyboard2:
applets[id] = std::make_shared<SoftwareKeyboard>(id, std::move(manager)); applets[id] = std::make_shared<SoftwareKeyboard>(id, parent, preload, manager);
break; break;
case Service::APT::AppletId::Ed1: case Service::APT::AppletId::Ed1:
case Service::APT::AppletId::Ed2: case Service::APT::AppletId::Ed2:
applets[id] = std::make_shared<MiiSelector>(id, std::move(manager)); applets[id] = std::make_shared<MiiSelector>(id, parent, preload, manager);
break; break;
case Service::APT::AppletId::Error: case Service::APT::AppletId::Error:
case Service::APT::AppletId::Error2: case Service::APT::AppletId::Error2:
applets[id] = std::make_shared<ErrEula>(id, std::move(manager)); applets[id] = std::make_shared<ErrEula>(id, parent, preload, manager);
break; break;
case Service::APT::AppletId::Mint: case Service::APT::AppletId::Mint:
case Service::APT::AppletId::Mint2: case Service::APT::AppletId::Mint2:
applets[id] = std::make_shared<Mint>(id, std::move(manager)); applets[id] = std::make_shared<Mint>(id, parent, preload, manager);
break; break;
default: default:
LOG_ERROR(Service_APT, "Could not create applet {}", id); LOG_ERROR(Service_APT, "Could not create applet {}", id);
@ -68,6 +69,17 @@ ResultCode Applet::Create(Service::APT::AppletId id,
ErrorSummary::NotSupported, ErrorLevel::Permanent); ErrorSummary::NotSupported, ErrorLevel::Permanent);
} }
Service::APT::AppletAttributes attributes;
attributes.applet_pos.Assign(static_cast<u32>(Service::APT::AppletPos::AutoLibrary));
attributes.is_home_menu.Assign(false);
const auto lock_handle_data = manager->GetLockHandle(attributes);
manager->Initialize(id, lock_handle_data->corrected_attributes);
manager->Enable(lock_handle_data->corrected_attributes);
if (preload) {
manager->FinishPreloadingLibraryApplet(id);
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -80,8 +92,8 @@ std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
/// Handles updating the current Applet every time it's called. /// Handles updating the current Applet every time it's called.
static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) { static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) {
Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id); const auto id = static_cast<Service::APT::AppletId>(applet_id);
std::shared_ptr<Applet> applet = Applet::Get(id); const auto applet = Applet::Get(id);
ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id={:08X}", id); ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id={:08X}", id);
applet->Update(); applet->Update();
@ -96,20 +108,28 @@ static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) {
} }
} }
ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
ResultCode result = StartImpl(parameter);
if (result.IsError())
return result;
// Schedule the update event
Core::System::GetInstance().CoreTiming().ScheduleEvent(
usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
return result;
}
bool Applet::IsRunning() const { bool Applet::IsRunning() const {
return is_running; return is_running;
} }
ResultCode Applet::ReceiveParameter(const Service::APT::MessageParameter& parameter) {
switch (parameter.signal) {
case Service::APT::SignalType::Wakeup: {
ResultCode result = Start(parameter);
if (!result.IsError()) {
// Schedule the update event
Core::System::GetInstance().CoreTiming().ScheduleEvent(
usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
}
return result;
}
case Service::APT::SignalType::WakeupByCancel:
return Finalize();
default:
return ReceiveParameterImpl(parameter);
}
}
void Applet::SendParameter(const Service::APT::MessageParameter& parameter) { void Applet::SendParameter(const Service::APT::MessageParameter& parameter) {
if (auto locked = manager.lock()) { if (auto locked = manager.lock()) {
locked->CancelAndSendParameter(parameter); locked->CancelAndSendParameter(parameter);
@ -118,12 +138,15 @@ void Applet::SendParameter(const Service::APT::MessageParameter& parameter) {
} }
} }
bool IsLibraryAppletRunning() { void Applet::CloseApplet(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer) {
// Check the applets map for instances of any applet if (auto locked = manager.lock()) {
for (auto itr = applets.begin(); itr != applets.end(); ++itr) locked->PrepareToCloseLibraryApplet(true, false, false);
if (itr->second != nullptr) locked->CloseLibraryApplet(std::move(object), buffer);
return true; } else {
return false; LOG_ERROR(Service_APT, "called after destructing applet manager");
}
is_running = false;
} }
void Init() { void Init() {

View File

@ -18,10 +18,12 @@ public:
* Creates an instance of the Applet subclass identified by the parameter. * Creates an instance of the Applet subclass identified by the parameter.
* and stores it in a global map. * and stores it in a global map.
* @param id Id of the applet to create. * @param id Id of the applet to create.
* @param parent Id of the applet's parent.
* @param preload Whether the applet is being preloaded.
* @returns ResultCode Whether the operation was successful or not. * @returns ResultCode Whether the operation was successful or not.
*/ */
static ResultCode Create(Service::APT::AppletId id, static ResultCode Create(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
std::weak_ptr<Service::APT::AppletManager> manager); const std::shared_ptr<Service::APT::AppletManager>& manager);
/** /**
* Retrieves the Applet instance identified by the specified id. * Retrieves the Applet instance identified by the specified id.
@ -35,19 +37,12 @@ public:
* @param parameter Parameter data to handle. * @param parameter Parameter data to handle.
* @returns ResultCode Whether the operation was successful or not. * @returns ResultCode Whether the operation was successful or not.
*/ */
virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0; ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter);
/**
* Handles the Applet start event, triggered from the application.
* @param parameter Parameter data to handle.
* @returns ResultCode Whether the operation was successful or not.
*/
ResultCode Start(const Service::APT::AppletStartupParameter& parameter);
/** /**
* Whether the applet is currently executing instead of the host application or not. * Whether the applet is currently executing instead of the host application or not.
*/ */
bool IsRunning() const; [[nodiscard]] bool IsRunning() const;
/** /**
* Handles an update tick for the Applet, lets it update the screen, send commands, etc. * Handles an update tick for the Applet, lets it update the screen, send commands, etc.
@ -55,31 +50,45 @@ public:
virtual void Update() = 0; virtual void Update() = 0;
protected: protected:
Applet(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) Applet(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
: id(id), manager(std::move(manager)) {} std::weak_ptr<Service::APT::AppletManager> manager)
: id(id), parent(parent), preload(preload), manager(std::move(manager)) {}
/**
* Handles a parameter from the application.
* @param parameter Parameter data to handle.
* @returns ResultCode Whether the operation was successful or not.
*/
virtual ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) = 0;
/** /**
* Handles the Applet start event, triggered from the application. * Handles the Applet start event, triggered from the application.
* @param parameter Parameter data to handle. * @param parameter Parameter data to handle.
* @returns ResultCode Whether the operation was successful or not. * @returns ResultCode Whether the operation was successful or not.
*/ */
virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0; virtual ResultCode Start(const Service::APT::MessageParameter& parameter) = 0;
/**
* Sends the LibAppletClosing signal to the application,
* along with the relevant data buffers.
*/
virtual ResultCode Finalize() = 0;
Service::APT::AppletId id; ///< Id of this Applet Service::APT::AppletId id; ///< Id of this Applet
Service::APT::AppletId parent; ///< Id of this Applet's parent
bool preload; ///< Whether the Applet is being preloaded.
std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
/// Whether this applet is currently running instead of the host application or not. /// Whether this applet is currently running instead of the host application or not.
bool is_running = false; bool is_running = false;
void SendParameter(const Service::APT::MessageParameter& parameter); void SendParameter(const Service::APT::MessageParameter& parameter);
void CloseApplet(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer);
private: private:
std::weak_ptr<Service::APT::AppletManager> manager; std::weak_ptr<Service::APT::AppletManager> manager;
}; };
/// Returns whether a library applet is currently running
bool IsLibraryAppletRunning();
/// Initializes the HLE applets /// Initializes the HLE applets
void Init(); void Init();

View File

@ -9,7 +9,7 @@
namespace HLE::Applets { namespace HLE::Applets {
ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& parameter) { ResultCode ErrEula::ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) {
if (parameter.signal != Service::APT::SignalType::Request) { if (parameter.signal != Service::APT::SignalType::Request) {
LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal); LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal);
UNIMPLEMENTED(); UNIMPLEMENTED();
@ -33,34 +33,33 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
"ErrEula Memory"); "ErrEula Memory");
// Send the response message with the newly created SharedMemory // Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result; SendParameter({
result.signal = Service::APT::SignalType::Response; .sender_id = id,
result.buffer.clear(); .destination_id = parent,
result.destination_id = Service::APT::AppletId::Application; .signal = Service::APT::SignalType::Response,
result.sender_id = id; .object = framebuffer_memory,
result.object = framebuffer_memory; });
SendParameter(result);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) { ResultCode ErrEula::Start(const Service::APT::MessageParameter& parameter) {
is_running = true; is_running = true;
startup_param = parameter.buffer;
// TODO(Subv): Set the expected fields in the response buffer before resending it to the // TODO(Subv): Set the expected fields in the response buffer before resending it to the
// application. // application.
// TODO(Subv): Reverse the parameter format for the ErrEula applet // TODO(Subv): Reverse the parameter format for the ErrEula applet
// Let the application know that we're closing // Let the application know that we're closing.
Service::APT::MessageParameter message; Finalize();
message.buffer.resize(parameter.buffer.size()); return RESULT_SUCCESS;
std::fill(message.buffer.begin(), message.buffer.end(), 0); }
message.signal = Service::APT::SignalType::WakeupByExit;
message.destination_id = Service::APT::AppletId::Application;
message.sender_id = id;
SendParameter(message);
is_running = false; ResultCode ErrEula::Finalize() {
std::vector<u8> buffer(startup_param.size());
std::fill(buffer.begin(), buffer.end(), 0);
CloseApplet(nullptr, buffer);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }

View File

@ -11,11 +11,13 @@ namespace HLE::Applets {
class ErrEula final : public Applet { class ErrEula final : public Applet {
public: public:
explicit ErrEula(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) explicit ErrEula(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
: Applet(id, std::move(manager)) {} std::weak_ptr<Service::APT::AppletManager> manager)
: Applet(id, parent, preload, std::move(manager)) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; ResultCode Start(const Service::APT::MessageParameter& parameter) override;
ResultCode Finalize() override;
void Update() override; void Update() override;
private: private:
@ -23,6 +25,9 @@ private:
/// It holds the framebuffer info retrieved by the application with /// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo /// GSPGPU::ImportDisplayCaptureInfo
std::shared_ptr<Kernel::SharedMemory> framebuffer_memory; std::shared_ptr<Kernel::SharedMemory> framebuffer_memory;
/// Parameter received by the applet on start.
std::vector<u8> startup_param;
}; };
} // namespace HLE::Applets } // namespace HLE::Applets

View File

@ -19,7 +19,7 @@
namespace HLE::Applets { namespace HLE::Applets {
ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& parameter) { ResultCode MiiSelector::ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) {
if (parameter.signal != Service::APT::SignalType::Request) { if (parameter.signal != Service::APT::SignalType::Request) {
LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal); LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal);
UNIMPLEMENTED(); UNIMPLEMENTED();
@ -42,18 +42,17 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
"MiiSelector Memory"); "MiiSelector Memory");
// Send the response message with the newly created SharedMemory // Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result; SendParameter({
result.signal = Service::APT::SignalType::Response; .sender_id = id,
result.buffer.clear(); .destination_id = parent,
result.destination_id = Service::APT::AppletId::Application; .signal = Service::APT::SignalType::Response,
result.sender_id = id; .object = framebuffer_memory,
result.object = framebuffer_memory; });
SendParameter(result);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) { ResultCode MiiSelector::Start(const Service::APT::MessageParameter& parameter) {
ASSERT_MSG(parameter.buffer.size() == sizeof(config), ASSERT_MSG(parameter.buffer.size() == sizeof(config),
"The size of the parameter (MiiConfig) is wrong"); "The size of the parameter (MiiConfig) is wrong");
@ -85,17 +84,11 @@ void MiiSelector::Update() {
Finalize(); Finalize();
} }
void MiiSelector::Finalize() { ResultCode MiiSelector::Finalize() {
// Let the application know that we're closing std::vector<u8> buffer(sizeof(MiiResult));
Service::APT::MessageParameter message; std::memcpy(buffer.data(), &result, buffer.size());
message.buffer.resize(sizeof(MiiResult)); CloseApplet(nullptr, buffer);
std::memcpy(message.buffer.data(), &result, message.buffer.size()); return RESULT_SUCCESS;
message.signal = Service::APT::SignalType::WakeupByExit;
message.destination_id = Service::APT::AppletId::Application;
message.sender_id = id;
SendParameter(message);
is_running = false;
} }
MiiResult MiiSelector::GetStandardMiiResult() { MiiResult MiiSelector::GetStandardMiiResult() {

View File

@ -115,19 +115,15 @@ ASSERT_REG_POSITION(guest_mii_name, 0x6C);
class MiiSelector final : public Applet { class MiiSelector final : public Applet {
public: public:
MiiSelector(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) MiiSelector(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
: Applet(id, std::move(manager)) {} std::weak_ptr<Service::APT::AppletManager> manager)
: Applet(id, parent, preload, std::move(manager)) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; ResultCode Start(const Service::APT::MessageParameter& parameter) override;
ResultCode Finalize() override;
void Update() override; void Update() override;
/**
* Sends the LibAppletClosing signal to the application,
* along with the relevant data buffers.
*/
void Finalize();
static MiiResult GetStandardMiiResult(); static MiiResult GetStandardMiiResult();
private: private:

View File

@ -9,7 +9,7 @@
namespace HLE::Applets { namespace HLE::Applets {
ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& parameter) { ResultCode Mint::ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) {
if (parameter.signal != Service::APT::SignalType::Request) { if (parameter.signal != Service::APT::SignalType::Request) {
LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal); LOG_ERROR(Service_APT, "unsupported signal {}", parameter.signal);
UNIMPLEMENTED(); UNIMPLEMENTED();
@ -33,34 +33,33 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete
"Mint Memory"); "Mint Memory");
// Send the response message with the newly created SharedMemory // Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result; SendParameter({
result.signal = Service::APT::SignalType::Response; .sender_id = id,
result.buffer.clear(); .destination_id = parent,
result.destination_id = Service::APT::AppletId::Application; .signal = Service::APT::SignalType::Response,
result.sender_id = id; .object = framebuffer_memory,
result.object = framebuffer_memory; });
SendParameter(result);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode Mint::StartImpl(const Service::APT::AppletStartupParameter& parameter) { ResultCode Mint::Start(const Service::APT::MessageParameter& parameter) {
is_running = true; is_running = true;
startup_param = parameter.buffer;
// TODO(Subv): Set the expected fields in the response buffer before resending it to the // TODO(Subv): Set the expected fields in the response buffer before resending it to the
// application. // application.
// TODO(Subv): Reverse the parameter format for the Mint applet // TODO(Subv): Reverse the parameter format for the Mint applet
// Let the application know that we're closing // Let the application know that we're closing
Service::APT::MessageParameter message; Finalize();
message.buffer.resize(parameter.buffer.size()); return RESULT_SUCCESS;
std::fill(message.buffer.begin(), message.buffer.end(), 0); }
message.signal = Service::APT::SignalType::WakeupByExit;
message.destination_id = Service::APT::AppletId::Application;
message.sender_id = id;
SendParameter(message);
is_running = false; ResultCode Mint::Finalize() {
std::vector<u8> buffer(startup_param.size());
std::fill(buffer.begin(), buffer.end(), 0);
CloseApplet(nullptr, buffer);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }

View File

@ -11,11 +11,13 @@ namespace HLE::Applets {
class Mint final : public Applet { class Mint final : public Applet {
public: public:
explicit Mint(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) explicit Mint(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
: Applet(id, std::move(manager)) {} std::weak_ptr<Service::APT::AppletManager> manager)
: Applet(id, parent, preload, std::move(manager)) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; ResultCode Start(const Service::APT::MessageParameter& parameter) override;
ResultCode Finalize() override;
void Update() override; void Update() override;
private: private:
@ -23,6 +25,9 @@ private:
/// It holds the framebuffer info retrieved by the application with /// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo /// GSPGPU::ImportDisplayCaptureInfo
std::shared_ptr<Kernel::SharedMemory> framebuffer_memory; std::shared_ptr<Kernel::SharedMemory> framebuffer_memory;
/// Parameter received by the applet on start.
std::vector<u8> startup_param;
}; };
} // namespace HLE::Applets } // namespace HLE::Applets

View File

@ -21,7 +21,7 @@
namespace HLE::Applets { namespace HLE::Applets {
ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) { ResultCode SoftwareKeyboard::ReceiveParameterImpl(Service::APT::MessageParameter const& parameter) {
switch (parameter.signal) { switch (parameter.signal) {
case Service::APT::SignalType::Request: { case Service::APT::SignalType::Request: {
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared // The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
@ -39,14 +39,13 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
"SoftwareKeyboard Memory"); "SoftwareKeyboard Memory");
// Send the response message with the newly created SharedMemory // Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result; SendParameter({
result.signal = Service::APT::SignalType::Response; .sender_id = id,
result.buffer.clear(); .destination_id = parent,
result.destination_id = Service::APT::AppletId::Application; .signal = Service::APT::SignalType::Response,
result.sender_id = id; .object = framebuffer_memory,
result.object = framebuffer_memory; });
SendParameter(result);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -92,7 +91,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
} }
} }
ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) { ResultCode SoftwareKeyboard::Start(Service::APT::MessageParameter const& parameter) {
ASSERT_MSG(parameter.buffer.size() == sizeof(config), ASSERT_MSG(parameter.buffer.size() == sizeof(config),
"The size of the parameter (SoftwareKeyboardConfig) is wrong"); "The size of the parameter (SoftwareKeyboardConfig) is wrong");
@ -151,14 +150,16 @@ void SoftwareKeyboard::Update() {
config.text_offset = 0; config.text_offset = 0;
if (config.filter_flags & HLE::Applets::SoftwareKeyboardFilter::Callback) { if (config.filter_flags & HLE::Applets::SoftwareKeyboardFilter::Callback) {
std::vector<u8> buffer(sizeof(SoftwareKeyboardConfig));
std::memcpy(buffer.data(), &config, buffer.size());
// Send the message to invoke callback // Send the message to invoke callback
Service::APT::MessageParameter message; SendParameter({
message.buffer.resize(sizeof(SoftwareKeyboardConfig)); .sender_id = id,
std::memcpy(message.buffer.data(), &config, message.buffer.size()); .destination_id = parent,
message.signal = Service::APT::SignalType::Message; .signal = Service::APT::SignalType::Message,
message.destination_id = Service::APT::AppletId::Application; .buffer = buffer,
message.sender_id = id; });
SendParameter(message);
} else { } else {
Finalize(); Finalize();
} }
@ -168,18 +169,12 @@ void SoftwareKeyboard::DrawScreenKeyboard() {
// TODO(Subv): Draw the HLE keyboard, for now just do nothing // TODO(Subv): Draw the HLE keyboard, for now just do nothing
} }
void SoftwareKeyboard::Finalize() { ResultCode SoftwareKeyboard::Finalize() {
// Let the application know that we're closing std::vector<u8> buffer(sizeof(SoftwareKeyboardConfig));
Service::APT::MessageParameter message; std::memcpy(buffer.data(), &config, buffer.size());
message.buffer.resize(sizeof(SoftwareKeyboardConfig)); CloseApplet(nullptr, buffer);
std::memcpy(message.buffer.data(), &config, message.buffer.size());
message.signal = Service::APT::SignalType::WakeupByExit;
message.destination_id = Service::APT::AppletId::Application;
message.sender_id = id;
SendParameter(message);
is_running = false;
text_memory = nullptr; text_memory = nullptr;
return RESULT_SUCCESS;
} }
Frontend::KeyboardConfig SoftwareKeyboard::ToFrontendConfig( Frontend::KeyboardConfig SoftwareKeyboard::ToFrontendConfig(

View File

@ -175,11 +175,13 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config
class SoftwareKeyboard final : public Applet { class SoftwareKeyboard final : public Applet {
public: public:
SoftwareKeyboard(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager) SoftwareKeyboard(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
: Applet(id, std::move(manager)) {} std::weak_ptr<Service::APT::AppletManager> manager)
: Applet(id, parent, preload, std::move(manager)) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override; ResultCode ReceiveParameterImpl(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override; ResultCode Start(const Service::APT::MessageParameter& parameter) override;
ResultCode Finalize() override;
void Update() override; void Update() override;
/** /**
@ -187,12 +189,6 @@ public:
*/ */
void DrawScreenKeyboard(); void DrawScreenKeyboard();
/**
* Sends the LibAppletClosing signal to the application,
* along with the relevant data buffers.
*/
void Finalize();
private: private:
Frontend::KeyboardConfig ToFrontendConfig(const SoftwareKeyboardConfig& config) const; Frontend::KeyboardConfig ToFrontendConfig(const SoftwareKeyboardConfig& config) const;

View File

@ -208,6 +208,9 @@ void Process::Exit() {
if (plgldr) { if (plgldr) {
plgldr->OnProcessExit(*this, kernel); plgldr->OnProcessExit(*this, kernel);
} }
// Clear the process's open handles.
handle_table.Clear();
} }
VAddr Process::GetLinearHeapAreaAddress() const { VAddr Process::GetLinearHeapAreaAddress() const {

View File

@ -36,6 +36,7 @@ void Module::Interface::ConnectAsync(Kernel::HLERequestContext& ctx) {
rp.Skip(2, false); // ProcessId descriptor rp.Skip(2, false); // ProcessId descriptor
ac->connect_event = rp.PopObject<Kernel::Event>(); ac->connect_event = rp.PopObject<Kernel::Event>();
rp.Skip(2, false); // Buffer descriptor
if (ac->connect_event) { if (ac->connect_event) {
ac->connect_event->SetName("AC:connect_event"); ac->connect_event->SetName("AC:connect_event");

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/applets/applet.h" #include "core/hle/applets/applet.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
@ -14,8 +15,6 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager)
namespace Service::APT { namespace Service::APT {
enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 };
struct AppletTitleData { struct AppletTitleData {
// There are two possible applet ids for each applet. // There are two possible applet ids for each applet.
std::array<AppletId, 2> applet_ids; std::array<AppletId, 2> applet_ids;
@ -23,6 +22,7 @@ struct AppletTitleData {
// There's a specific TitleId per region for each applet. // There's a specific TitleId per region for each applet.
static constexpr std::size_t NumRegions = 7; static constexpr std::size_t NumRegions = 7;
std::array<u64, NumRegions> title_ids; std::array<u64, NumRegions> title_ids;
std::array<u64, NumRegions> n3ds_title_ids = {0, 0, 0, 0, 0, 0, 0};
}; };
static constexpr std::size_t NumApplets = 29; static constexpr std::size_t NumApplets = 29;
@ -44,7 +44,8 @@ static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
0x400300000AD02, 0x400300000B502}}, 0x400300000AD02, 0x400300000B502}},
{{AppletId::InternetBrowser, AppletId::None}, {{AppletId::InternetBrowser, AppletId::None},
{0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602, {0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
0x400300000AE02, 0x400300000B602}}, 0x400300000AE02, 0x400300000B602},
{0x4003020008802, 0x4003020009402, 0x4003020009D02, 0x4003020008802, 0, 0x400302000AE02, 0}},
{{AppletId::InstructionManual, AppletId::None}, {{AppletId::InstructionManual, AppletId::None},
{0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402, {0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402,
0x400300000AC02, 0x400300000B402}}, 0x400300000AC02, 0x400300000B402}},
@ -100,117 +101,139 @@ static u64 GetTitleIdForApplet(AppletId id, u32 region_value) {
ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x{:#05X}", id); ASSERT_MSG(itr != applet_titleids.end(), "Unknown applet id 0x{:#05X}", id);
auto n3ds_title_id = itr->n3ds_title_ids[region_value];
if (n3ds_title_id != 0 && Settings::values.is_new_3ds.GetValue()) {
return n3ds_title_id;
}
return itr->title_ids[region_value]; return itr->title_ids[region_value];
} }
AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) { AppletManager::AppletSlot AppletManager::GetAppletSlotFromId(AppletId id) {
auto GetSlot = [this](AppletSlot slot) -> AppletSlotData* {
return &applet_slots[static_cast<std::size_t>(slot)];
};
if (id == AppletId::Application) { if (id == AppletId::Application) {
auto* slot = GetSlot(AppletSlot::Application); if (GetAppletSlot(AppletSlot::Application)->applet_id != AppletId::None)
if (slot->applet_id != AppletId::None) return AppletSlot::Application;
return slot;
return nullptr; return AppletSlot::Error;
} }
if (id == AppletId::AnySystemApplet) { if (id == AppletId::AnySystemApplet) {
auto* system_slot = GetSlot(AppletSlot::SystemApplet); if (GetAppletSlot(AppletSlot::SystemApplet)->applet_id != AppletId::None)
if (system_slot->applet_id != AppletId::None) return AppletSlot::SystemApplet;
return system_slot;
// The Home Menu is also a system applet, but it lives in its own slot to be able to run // The Home Menu is also a system applet, but it lives in its own slot to be able to run
// concurrently with other system applets. // concurrently with other system applets.
auto* home_slot = GetSlot(AppletSlot::HomeMenu); if (GetAppletSlot(AppletSlot::HomeMenu)->applet_id != AppletId::None)
if (home_slot->applet_id != AppletId::None) return AppletSlot::HomeMenu;
return home_slot;
return nullptr; return AppletSlot::Error;
} }
if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) {
auto* slot = GetSlot(AppletSlot::LibraryApplet); auto slot_data = GetAppletSlot(AppletSlot::LibraryApplet);
if (slot->applet_id == AppletId::None) if (slot_data->applet_id == AppletId::None)
return nullptr; return AppletSlot::Error;
u32 applet_pos = slot->attributes.applet_pos; auto applet_pos = static_cast<AppletPos>(slot_data->attributes.applet_pos.Value());
if ((id == AppletId::AnyLibraryApplet && applet_pos == AppletPos::Library) ||
(id == AppletId::AnySysLibraryApplet && applet_pos == AppletPos::SysLibrary))
return AppletSlot::LibraryApplet;
if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library)) return AppletSlot::Error;
return slot;
if (id == AppletId::AnySysLibraryApplet &&
applet_pos == static_cast<u32>(AppletPos::SysLibrary))
return slot;
return nullptr;
} }
if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) {
auto* slot = GetSlot(AppletSlot::HomeMenu); if (GetAppletSlot(AppletSlot::HomeMenu)->applet_id != AppletId::None)
if (slot->applet_id != AppletId::None) return AppletSlot::HomeMenu;
return slot;
return nullptr; return AppletSlot::Error;
} }
for (auto& slot : applet_slots) { for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) {
if (slot.applet_id == id) if (applet_slots[slot].applet_id == id) {
return &slot; return static_cast<AppletSlot>(slot);
}
} }
return nullptr; return AppletSlot::Error;
} }
AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletAttributes attributes) { AppletManager::AppletSlot AppletManager::GetAppletSlotFromAttributes(AppletAttributes attributes) {
// Mapping from AppletPos to AppletSlot // Mapping from AppletPos to AppletSlot
static constexpr std::array<AppletSlot, 6> applet_position_slots = { static constexpr std::array<AppletSlot, 6> applet_position_slots = {
AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet, AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet,
AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet}; AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet};
u32 applet_pos = attributes.applet_pos; auto applet_pos = attributes.applet_pos;
if (applet_pos >= applet_position_slots.size()) if (applet_pos >= applet_position_slots.size())
return nullptr; return AppletSlot::Error;
AppletSlot slot = applet_position_slots[applet_pos];
auto slot = applet_position_slots[applet_pos];
if (slot == AppletSlot::Error) if (slot == AppletSlot::Error)
return nullptr; return AppletSlot::Error;
// The Home Menu is a system applet, however, it has its own applet slot so that it can run // The Home Menu is a system applet, however, it has its own applet slot so that it can run
// concurrently with other system applets. // concurrently with other system applets.
if (slot == AppletSlot::SystemApplet && attributes.is_home_menu) if (slot == AppletSlot::SystemApplet && attributes.is_home_menu)
return &applet_slots[static_cast<std::size_t>(AppletSlot::HomeMenu)]; return AppletSlot::HomeMenu;
return &applet_slots[static_cast<std::size_t>(slot)]; return slot;
}
AppletManager::AppletSlot AppletManager::GetAppletSlotFromPos(AppletPos pos) {
AppletId applet_id;
switch (pos) {
case AppletPos::Application:
applet_id = AppletId::Application;
break;
case AppletPos::Library:
applet_id = AppletId::AnyLibraryApplet;
break;
case AppletPos::System:
applet_id = AppletId::AnySystemApplet;
break;
case AppletPos::SysLibrary:
applet_id = AppletId::AnySysLibraryApplet;
break;
default:
return AppletSlot::Error;
}
return GetAppletSlotFromId(applet_id);
} }
void AppletManager::CancelAndSendParameter(const MessageParameter& parameter) { void AppletManager::CancelAndSendParameter(const MessageParameter& parameter) {
next_parameter = parameter; LOG_DEBUG(
// Signal the event to let the receiver know that a new parameter is ready to be read Service_APT, "Sending parameter from {:03X} to {:03X} with signal {:08X} and size {:08X}",
auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id)); parameter.sender_id, parameter.destination_id, parameter.signal, parameter.buffer.size());
if (slot_data == nullptr) {
LOG_DEBUG(Service_APT, "No applet was registered with the id {:03X}",
parameter.destination_id);
return;
}
slot_data->parameter_event->Signal(); // If the applet is being HLEd, send directly to the applet.
if (auto dest_applet = HLE::Applets::Applet::Get(parameter.destination_id)) {
dest_applet->ReceiveParameter(parameter);
} else {
// Otherwise, send the parameter the LLE way.
next_parameter = parameter;
// Signal the event to let the receiver know that a new parameter is ready to be read
auto slot = GetAppletSlotFromId(parameter.destination_id);
if (slot != AppletSlot::Error) {
GetAppletSlot(slot)->parameter_event->Signal();
} else {
LOG_DEBUG(Service_APT, "No applet was registered with ID {:03X}",
parameter.destination_id);
}
}
} }
ResultCode AppletManager::SendParameter(const MessageParameter& parameter) { ResultCode AppletManager::SendParameter(const MessageParameter& parameter) {
// A new parameter can not be sent if the previous one hasn't been consumed yet // A new parameter can not be sent if the previous one hasn't been consumed yet
if (next_parameter) { if (next_parameter) {
return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, LOG_WARNING(Service_APT, "Parameter from {:03X} to {:03X} blocked by pending parameter.",
ErrorSummary::InvalidState, ErrorLevel::Status); parameter.sender_id, parameter.destination_id);
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
} }
CancelAndSendParameter(parameter); CancelAndSendParameter(parameter);
if (auto dest_applet = HLE::Applets::Applet::Get(parameter.destination_id)) { return RESULT_SUCCESS;
return dest_applet->ReceiveParameter(parameter);
} else {
return RESULT_SUCCESS;
}
} }
ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) { ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) {
@ -224,7 +247,7 @@ ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) {
ErrorLevel::Status); ErrorLevel::Status);
} }
MessageParameter parameter = *next_parameter; auto parameter = *next_parameter;
// Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter. // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter.
if (next_parameter->signal == SignalType::DspSleep || if (next_parameter->signal == SignalType::DspSleep ||
@ -246,17 +269,9 @@ ResultVal<MessageParameter> AppletManager::ReceiveParameter(AppletId app_id) {
bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver,
AppletId receiver_appid) { AppletId receiver_appid) {
bool cancellation_success = true; auto cancellation_success =
next_parameter && (!check_sender || next_parameter->sender_id == sender_appid) &&
if (!next_parameter) { (!check_receiver || next_parameter->destination_id == receiver_appid);
cancellation_success = false;
} else {
if (check_sender && next_parameter->sender_id != sender_appid)
cancellation_success = false;
if (check_receiver && next_parameter->destination_id != receiver_appid)
cancellation_success = false;
}
if (cancellation_success) if (cancellation_success)
next_parameter = {}; next_parameter = {};
@ -264,43 +279,57 @@ bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bo
return cancellation_success; return cancellation_success;
} }
ResultVal<AppletManager::GetLockHandleResult> AppletManager::GetLockHandle(
AppletAttributes attributes) {
auto corrected_attributes = attributes;
if (attributes.applet_pos == static_cast<u32>(AppletPos::Library) ||
attributes.applet_pos == static_cast<u32>(AppletPos::SysLibrary) ||
attributes.applet_pos == static_cast<u32>(AppletPos::AutoLibrary)) {
auto corrected_pos = last_library_launcher_slot == AppletSlot::Application
? AppletPos::Library
: AppletPos::SysLibrary;
corrected_attributes.applet_pos.Assign(static_cast<u32>(corrected_pos));
LOG_DEBUG(Service_APT, "Corrected applet attributes from {:08X} to {:08X}", attributes.raw,
corrected_attributes.raw);
}
return MakeResult<AppletManager::GetLockHandleResult>({corrected_attributes, 0, lock});
}
ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId app_id, ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId app_id,
AppletAttributes attributes) { AppletAttributes attributes) {
auto* const slot_data = GetAppletSlotData(attributes); auto slot = GetAppletSlotFromAttributes(attributes);
// Note: The real NS service does not check if the attributes value is valid before accessing // Note: The real NS service does not check if the attributes value is valid before accessing
// the data in the array // the data in the array
ASSERT_MSG(slot_data, "Invalid application attributes"); ASSERT_MSG(slot != AppletSlot::Error, "Invalid application attributes");
auto slot_data = GetAppletSlot(slot);
if (slot_data->registered) { if (slot_data->registered) {
LOG_WARNING(Service_APT, "Applet attempted to register in occupied slot {:02X}", slot);
return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status); ErrorSummary::InvalidState, ErrorLevel::Status);
} }
LOG_DEBUG(Service_APT, "Initializing applet with ID {:03X} and attributes {:08X}.", app_id,
attributes.raw);
slot_data->applet_id = static_cast<AppletId>(app_id); slot_data->applet_id = static_cast<AppletId>(app_id);
// Note: In the real console the title id of a given applet slot is set by the APT module when // Note: In the real console the title id of a given applet slot is set by the APT module when
// calling StartApplication. // calling StartApplication.
slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id; slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id;
slot_data->attributes.raw = attributes.raw; slot_data->attributes.raw = attributes.raw;
const auto* home_menu_slot = GetAppletSlotData(AppletId::HomeMenu);
// Applications need to receive a Wakeup signal to actually start up, this signal is usually // Applications need to receive a Wakeup signal to actually start up, this signal is usually
// sent by the Home Menu after starting the app by way of APT::WakeupApplication. In some cases // sent by the Home Menu after starting the app by way of APT::WakeupApplication. However,
// such as when starting a game directly or the Home Menu itself, we have to send the signal // if nothing is running yet the signal should be sent by APT::Initialize itself.
// ourselves since the Home Menu is not running yet. We detect if the Home Menu is running by if (active_slot == AppletSlot::Error) {
// checking if there's an applet registered in the HomeMenu slot. active_slot = slot;
if (slot_data->applet_id == AppletId::HomeMenu ||
(slot_data->applet_id == AppletId::Application && !home_menu_slot)) { // Wake up the application.
// Initialize the APT parameter to wake up the application. SendParameter({
next_parameter.emplace(); .sender_id = AppletId::None,
next_parameter->signal = SignalType::Wakeup; .destination_id = app_id,
next_parameter->sender_id = AppletId::None; .signal = SignalType::Wakeup,
next_parameter->destination_id = app_id; });
// Not signaling the parameter event will cause the application (or Home Menu) to hang
// during startup. In the real console, it is usually the Kernel and Home Menu who cause NS
// to signal the HomeMenu and Application parameter events, respectively.
slot_data->parameter_event->Signal();
} }
return MakeResult<InitializeResult>( return MakeResult<InitializeResult>(
@ -308,17 +337,23 @@ ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId ap
} }
ResultCode AppletManager::Enable(AppletAttributes attributes) { ResultCode AppletManager::Enable(AppletAttributes attributes) {
auto* const slot_data = GetAppletSlotData(attributes); auto slot = GetAppletSlotFromAttributes(attributes);
if (slot == AppletSlot::Error) {
if (!slot_data) { LOG_WARNING(Service_APT,
return ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, "Attempted to register with attributes {:08X}, but could not find slot.",
ErrorSummary::InvalidState, ErrorLevel::Status); attributes.raw);
return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
} }
LOG_DEBUG(Service_APT, "Registering applet with attributes {:08X}.", attributes.raw);
auto slot_data = GetAppletSlot(slot);
slot_data->registered = true; slot_data->registered = true;
// Send any outstanding parameters to the newly-registered application // Send any outstanding parameters to the newly-registered application
if (delayed_parameter && delayed_parameter->destination_id == slot_data->applet_id) { if (delayed_parameter && delayed_parameter->destination_id == slot_data->applet_id) {
// TODO: Real APT would loop trying to send the parameter until it succeeds,
// essentially waiting for existing parameters to be delivered.
CancelAndSendParameter(*delayed_parameter); CancelAndSendParameter(*delayed_parameter);
delayed_parameter.reset(); delayed_parameter.reset();
} }
@ -327,42 +362,29 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) {
} }
bool AppletManager::IsRegistered(AppletId app_id) { bool AppletManager::IsRegistered(AppletId app_id) {
const auto* slot_data = GetAppletSlotData(app_id); auto slot = GetAppletSlotFromId(app_id);
return slot != AppletSlot::Error && GetAppletSlot(slot)->registered;
// Check if an LLE applet was registered first, then fallback to HLE applets
bool is_registered = slot_data && slot_data->registered;
if (!is_registered) {
if (app_id == AppletId::AnyLibraryApplet) {
is_registered = HLE::Applets::IsLibraryAppletRunning();
} else if (auto applet = HLE::Applets::Applet::Get(app_id)) {
// The applet exists, set it as registered.
is_registered = true;
}
}
return is_registered;
} }
ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
// The real APT service returns an error if there's a pending APT parameter when this function // The real APT service returns an error if there's a pending APT parameter when this function
// is called. // is called.
if (next_parameter) { if (next_parameter) {
return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorSummary::InvalidState, ErrorLevel::Status); ErrorLevel::Status};
} }
const auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)]; if (GetAppletSlot(AppletSlot::LibraryApplet)->registered) {
return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState,
if (slot.registered) { ErrorLevel::Status};
return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
} }
last_library_launcher_slot = active_slot;
last_prepared_library_applet = applet_id;
auto cfg = Service::CFG::GetModule(system); auto cfg = Service::CFG::GetModule(system);
u32 region_value = cfg->GetRegionValue();
auto process = auto process =
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, region_value)); NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
if (process) { if (process) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -370,25 +392,27 @@ ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
// If we weren't able to load the native applet title, try to fallback to an HLE implementation. // If we weren't able to load the native applet title, try to fallback to an HLE implementation.
auto applet = HLE::Applets::Applet::Get(applet_id); auto applet = HLE::Applets::Applet::Get(applet_id);
if (applet) { if (applet) {
LOG_WARNING(Service_APT, "applet has already been started id={:08X}", applet_id); LOG_WARNING(Service_APT, "applet has already been started id={:03X}", applet_id);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} else { } else {
return HLE::Applets::Applet::Create(applet_id, shared_from_this()); auto parent = GetAppletSlotId(last_library_launcher_slot);
LOG_DEBUG(Service_APT, "Creating HLE applet {:03X} with parent {:03X}", applet_id, parent);
return HLE::Applets::Applet::Create(applet_id, parent, false, shared_from_this());
} }
} }
ResultCode AppletManager::PreloadLibraryApplet(AppletId applet_id) { ResultCode AppletManager::PreloadLibraryApplet(AppletId applet_id) {
const auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)]; if (GetAppletSlot(AppletSlot::LibraryApplet)->registered) {
return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState,
if (slot.registered) { ErrorLevel::Status};
return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
} }
last_library_launcher_slot = active_slot;
last_prepared_library_applet = applet_id;
auto cfg = Service::CFG::GetModule(system); auto cfg = Service::CFG::GetModule(system);
u32 region_value = cfg->GetRegionValue();
auto process = auto process =
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, region_value)); NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
if (process) { if (process) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -399,44 +423,43 @@ ResultCode AppletManager::PreloadLibraryApplet(AppletId applet_id) {
LOG_WARNING(Service_APT, "applet has already been started id={:08X}", applet_id); LOG_WARNING(Service_APT, "applet has already been started id={:08X}", applet_id);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} else { } else {
return HLE::Applets::Applet::Create(applet_id, shared_from_this()); auto parent = GetAppletSlotId(last_library_launcher_slot);
LOG_DEBUG(Service_APT, "Creating HLE applet {:03X} with parent {:03X}", applet_id, parent);
return HLE::Applets::Applet::Create(applet_id, parent, true, shared_from_this());
} }
} }
ResultCode AppletManager::FinishPreloadingLibraryApplet(AppletId applet_id) { ResultCode AppletManager::FinishPreloadingLibraryApplet(AppletId applet_id) {
// TODO(Subv): This function should fail depending on the applet preparation state. // TODO(Subv): This function should fail depending on the applet preparation state.
auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)]; GetAppletSlot(AppletSlot::LibraryApplet)->loaded = true;
slot.loaded = true;
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode AppletManager::StartLibraryApplet(AppletId applet_id, ResultCode AppletManager::StartLibraryApplet(AppletId applet_id,
std::shared_ptr<Kernel::Object> object, std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer) { const std::vector<u8>& buffer) {
MessageParameter param; active_slot = AppletSlot::LibraryApplet;
param.destination_id = applet_id;
param.sender_id = AppletId::Application;
param.object = object;
param.signal = SignalType::Wakeup;
param.buffer = buffer;
CancelAndSendParameter(param);
// In case the applet is being HLEd, attempt to communicate with it. auto send_res = SendParameter({
if (auto applet = HLE::Applets::Applet::Get(applet_id)) { .sender_id = GetAppletSlotId(last_library_launcher_slot),
AppletStartupParameter parameter; .destination_id = applet_id,
parameter.object = object; .signal = SignalType::Wakeup,
parameter.buffer = buffer; .object = std::move(object),
return applet->Start(parameter); .buffer = buffer,
} else { });
return RESULT_SUCCESS; if (send_res.IsError()) {
active_slot = last_library_launcher_slot;
return send_res;
} }
return RESULT_SUCCESS;
} }
ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiting, ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiting,
bool jump_home) { bool jump_home) {
if (next_parameter) { if (next_parameter) {
return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorSummary::InvalidState, ErrorLevel::Status); ErrorLevel::Status};
} }
if (!not_pause) if (!not_pause)
@ -452,57 +475,151 @@ ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiti
} }
ResultCode AppletManager::CloseLibraryApplet(std::shared_ptr<Kernel::Object> object, ResultCode AppletManager::CloseLibraryApplet(std::shared_ptr<Kernel::Object> object,
std::vector<u8> buffer) { const std::vector<u8>& buffer) {
auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)]; auto slot = GetAppletSlot(AppletSlot::LibraryApplet);
auto destination_id = GetAppletSlotId(last_library_launcher_slot);
MessageParameter param; active_slot = last_library_launcher_slot;
// TODO(Subv): The destination id should be the "current applet slot id", which changes
// constantly depending on what is going on in the system. Most of the time it is the running
// application, but it could be something else if a system applet is launched.
param.destination_id = AppletId::Application;
param.sender_id = slot.applet_id;
param.object = std::move(object);
param.signal = library_applet_closing_command;
param.buffer = std::move(buffer);
ResultCode result = SendParameter(param); MessageParameter param = {
.sender_id = slot->applet_id,
.destination_id = destination_id,
.signal = library_applet_closing_command,
.object = std::move(object),
.buffer = buffer,
};
if (library_applet_closing_command != SignalType::WakeupByPause) { if (library_applet_closing_command != SignalType::WakeupByPause) {
// TODO(Subv): Terminate the running applet title CancelAndSendParameter(param);
slot.Reset(); // TODO: Terminate the running applet title
slot->Reset();
} else {
SendParameter(param);
} }
return result; return RESULT_SUCCESS;
}
ResultCode AppletManager::CancelLibraryApplet(bool app_exiting) {
if (next_parameter) {
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
auto slot = GetAppletSlot(AppletSlot::LibraryApplet);
if (!slot->registered) {
return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
return SendParameter({
.sender_id = GetAppletSlotId(last_library_launcher_slot),
.destination_id = slot->applet_id,
.signal = SignalType::WakeupByCancel,
});
}
ResultCode AppletManager::PrepareToStartSystemApplet(AppletId applet_id) {
// The real APT service returns an error if there's a pending APT parameter when this function
// is called.
if (next_parameter) {
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
last_system_launcher_slot = active_slot;
return RESULT_SUCCESS;
}
ResultCode AppletManager::StartSystemApplet(AppletId applet_id,
std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer) {
auto source_applet_id = AppletId::None;
if (last_system_launcher_slot != AppletSlot::Error) {
const auto slot_data = GetAppletSlot(last_system_launcher_slot);
source_applet_id = slot_data->applet_id;
// If a system applet is launching another system applet, reset the slot to avoid conflicts.
// This is needed because system applets won't necessarily call CloseSystemApplet before
// exiting.
if (last_system_launcher_slot == AppletSlot::SystemApplet) {
slot_data->Reset();
}
}
// If a system applet is not already registered, it is started by APT.
const auto slot_id =
applet_id == AppletId::HomeMenu ? AppletSlot::HomeMenu : AppletSlot::SystemApplet;
if (!GetAppletSlot(slot_id)->registered) {
auto cfg = Service::CFG::GetModule(system);
auto process = NS::LaunchTitle(FS::MediaType::NAND,
GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
if (!process) {
// TODO: Find the right error code.
return {ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported,
ErrorLevel::Permanent};
}
}
active_slot = slot_id;
SendApplicationParameterAfterRegistration({
.sender_id = source_applet_id,
.destination_id = applet_id,
.signal = SignalType::Wakeup,
.object = std::move(object),
.buffer = buffer,
});
return RESULT_SUCCESS;
}
ResultCode AppletManager::PrepareToCloseSystemApplet() {
if (next_parameter) {
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
return RESULT_SUCCESS;
}
ResultCode AppletManager::CloseSystemApplet(std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer) {
ASSERT_MSG(active_slot == AppletSlot::HomeMenu || active_slot == AppletSlot::SystemApplet,
"Attempting to close a system applet from a non-system applet.");
auto slot = GetAppletSlot(active_slot);
active_slot = last_system_launcher_slot;
// TODO: Send a parameter to the application only if the application ordered the applet to
// close.
// TODO: Terminate the running applet title
slot->Reset();
return RESULT_SUCCESS;
} }
ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_id) { ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_id) {
const auto* slot = GetAppletSlotData(app_id); auto slot = GetAppletSlotFromId(app_id);
if (slot == AppletSlot::Error) {
if (slot == nullptr || !slot->registered) {
// See if there's an HLE applet and try to use it before erroring out.
auto hle_applet = HLE::Applets::Applet::Get(app_id);
if (hle_applet == nullptr) {
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
ErrorSummary::NotFound, ErrorLevel::Status);
}
LOG_WARNING(Service_APT, "Using HLE applet info for applet {:03X}", app_id);
// TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
return MakeResult<AppletInfo>({0, Service::FS::MediaType::NAND, true, true, 0});
}
if (app_id == AppletId::Application) {
// TODO(Subv): Implement this once Application launching is implemented
LOG_ERROR(Service_APT, "Unimplemented GetAppletInfo(Application)");
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
ErrorLevel::Status); ErrorLevel::Status);
} }
auto cfg = Service::CFG::GetModule(system); auto slot_data = GetAppletSlot(slot);
ASSERT_MSG(cfg, "CFG Module missing!"); if (!slot_data->registered) {
u32 region_value = cfg->GetRegionValue(); return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
return MakeResult<AppletInfo>({GetTitleIdForApplet(app_id, region_value), ErrorLevel::Status);
Service::FS::MediaType::NAND, slot->registered, slot->loaded, }
slot->attributes.raw});
// TODO: Basic heuristic to guess media type, needs proper implementation.
auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000
? Service::FS::MediaType::SDMC
: Service::FS::MediaType::NAND;
return MakeResult<AppletInfo>({slot_data->title_id, media_type, slot_data->registered,
slot_data->loaded, slot_data->attributes.raw});
} }
ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type,
@ -511,21 +628,18 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType
// for the Application slot is already in use. The way this is implemented in hardware is to // for the Application slot is already in use. The way this is implemented in hardware is to
// launch the Home Menu and tell it to launch our desired application. // launch the Home Menu and tell it to launch our desired application.
// Save the title data to send it to the Home Menu when DoApplicationJump is called.
const auto& application_slot = applet_slots[static_cast<size_t>(AppletSlot::Application)];
ASSERT_MSG(flags != ApplicationJumpFlags::UseStoredParameters, ASSERT_MSG(flags != ApplicationJumpFlags::UseStoredParameters,
"Unimplemented application jump flags 1"); "Unimplemented application jump flags 1");
if (flags == ApplicationJumpFlags::UseCurrentParameters) { // Save the title data to send it to the Home Menu when DoApplicationJump is called.
title_id = application_slot.title_id; auto application_slot_data = GetAppletSlot(AppletSlot::Application);
} app_jump_parameters.current_title_id = application_slot_data->title_id;
app_jump_parameters.current_title_id = application_slot.title_id;
// TODO(Subv): Retrieve the correct media type of the currently-running application. For now // TODO(Subv): Retrieve the correct media type of the currently-running application. For now
// just assume NAND. // just assume NAND.
app_jump_parameters.current_media_type = FS::MediaType::NAND; app_jump_parameters.current_media_type = FS::MediaType::NAND;
app_jump_parameters.next_title_id = title_id; app_jump_parameters.next_title_id = flags == ApplicationJumpFlags::UseCurrentParameters
? application_slot_data->title_id
: title_id;
app_jump_parameters.next_media_type = media_type; app_jump_parameters.next_media_type = media_type;
app_jump_parameters.flags = flags; app_jump_parameters.flags = flags;
@ -535,29 +649,29 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode AppletManager::DoApplicationJump(DeliverArg arg) { ResultCode AppletManager::DoApplicationJump(const DeliverArg& arg) {
// Note: The real console uses the Home Menu to perform the application jump, it goes // Note: The real console uses the Home Menu to perform the application jump, it goes
// OldApplication->Home Menu->NewApplication. We do not need to use the Home Menu to do this so // OldApplication->Home Menu->NewApplication. We do not need to use the Home Menu to do this so
// we launch the new application directly. In the real APT service, the Home Menu must be // we launch the new application directly. In the real APT service, the Home Menu must be
// running to do this, otherwise error 0xC8A0CFF0 is returned. // running to do this, otherwise error 0xC8A0CFF0 is returned.
auto& application_slot = applet_slots[static_cast<size_t>(AppletSlot::Application)]; auto application_slot_data = GetAppletSlot(AppletSlot::Application);
auto title_id = application_slot_data->title_id;
if (app_jump_parameters.flags != ApplicationJumpFlags::UseCurrentParameters) { application_slot_data->Reset();
// The source program ID is not updated when using flags 0x2.
arg.source_program_id = application_slot.title_id;
}
application_slot.Reset();
// Set the delivery parameters. // Set the delivery parameters.
deliver_arg = std::move(arg); deliver_arg = arg;
if (app_jump_parameters.flags != ApplicationJumpFlags::UseCurrentParameters) {
// The source program ID is not updated when using flags 0x2.
deliver_arg->source_program_id = title_id;
}
// TODO(Subv): Terminate the current Application. // TODO(Subv): Terminate the current Application.
// Note: The real console sends signal 17 (WakeupToLaunchApplication) to the Home Menu, this // Note: The real console sends signal 17 (WakeupToLaunchApplication) to the Home Menu, this
// prompts it to call GetProgramIdOnApplicationJump and // prompts it to call GetProgramIdOnApplicationJump and
// PrepareToStartApplication/StartApplication on the title to launch. // PrepareToStartApplication/StartApplication on the title to launch.
active_slot = AppletSlot::Application;
// Perform a soft-reset if we're trying to relaunch the same title. // Perform a soft-reset if we're trying to relaunch the same title.
// TODO(Subv): Note that this reboots the entire emulated system, a better way would be to // TODO(Subv): Note that this reboots the entire emulated system, a better way would be to
@ -565,8 +679,8 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) {
// installed titles since we have no way of getting the file path of an arbitrary game dump // installed titles since we have no way of getting the file path of an arbitrary game dump
// based only on the title id. // based only on the title id.
std::string new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, auto new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type,
app_jump_parameters.next_title_id); app_jump_parameters.next_title_id);
if (new_path.empty() || !FileUtil::Exists(new_path)) { if (new_path.empty() || !FileUtil::Exists(new_path)) {
LOG_CRITICAL( LOG_CRITICAL(
Service_APT, Service_APT,
@ -594,16 +708,17 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) {
} }
ResultCode AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType media_type) { ResultCode AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType media_type) {
// TODO(Subv): This should check that the current applet is of System type and return 0xc8a0cc04 if (active_slot == AppletSlot::Error ||
// if not. GetAppletSlot(active_slot)->attributes.applet_pos != static_cast<u32>(AppletPos::System)) {
return {ErrCodes::InvalidAppletSlot, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
// TODO(Subv): This should return 0xc8a0cff0 if the applet preparation state is already set // TODO(Subv): This should return 0xc8a0cff0 if the applet preparation state is already set
const auto& application_slot = applet_slots[static_cast<size_t>(AppletSlot::Application)]; if (GetAppletSlot(AppletSlot::Application)->registered) {
return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState,
if (application_slot.registered) { ErrorLevel::Status};
// TODO(Subv): Convert this to the enum constructor of ResultCode
return ResultCode(0xc8a0cffc);
} }
ASSERT_MSG(!app_start_parameters, ASSERT_MSG(!app_start_parameters,
@ -633,8 +748,10 @@ ResultCode AppletManager::StartApplication(const std::vector<u8>& parameter,
// PM::LaunchTitle. We should research more about that. // PM::LaunchTitle. We should research more about that.
ASSERT_MSG(app_start_parameters, "Trying to start an application without preparing it first."); ASSERT_MSG(app_start_parameters, "Trying to start an application without preparing it first.");
active_slot = AppletSlot::Application;
// Launch the title directly. // Launch the title directly.
const auto process = auto process =
NS::LaunchTitle(app_start_parameters->next_media_type, app_start_parameters->next_title_id); NS::LaunchTitle(app_start_parameters->next_media_type, app_start_parameters->next_title_id);
if (!process) { if (!process) {
LOG_CRITICAL(Service_APT, "Failed to launch title during application start, exiting."); LOG_CRITICAL(Service_APT, "Failed to launch title during application start, exiting.");
@ -652,22 +769,20 @@ ResultCode AppletManager::StartApplication(const std::vector<u8>& parameter,
ResultCode AppletManager::WakeupApplication() { ResultCode AppletManager::WakeupApplication() {
// Send a Wakeup signal via the apt parameter to the application once it registers itself. // Send a Wakeup signal via the apt parameter to the application once it registers itself.
// The real APT service does this by spinwaiting on another thread until the application is // The real APT service does this by spin waiting on another thread until the application is
// registered. // registered.
MessageParameter wakeup_parameter{}; SendApplicationParameterAfterRegistration({.sender_id = AppletId::HomeMenu,
wakeup_parameter.signal = SignalType::Wakeup; .destination_id = AppletId::Application,
wakeup_parameter.sender_id = AppletId::HomeMenu; .signal = SignalType::Wakeup});
wakeup_parameter.destination_id = AppletId::Application;
SendApplicationParameterAfterRegistration(wakeup_parameter);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
void AppletManager::SendApplicationParameterAfterRegistration(const MessageParameter& parameter) { void AppletManager::SendApplicationParameterAfterRegistration(const MessageParameter& parameter) {
const auto* slot = GetAppletSlotData(AppletId::Application); auto slot = GetAppletSlotFromId(parameter.destination_id);
// If the application is already registered, immediately send the parameter // If the application is already registered, immediately send the parameter
if (slot && slot->registered) { if (slot != AppletSlot::Error && GetAppletSlot(slot)->registered) {
CancelAndSendParameter(parameter); CancelAndSendParameter(parameter);
return; return;
} }
@ -677,22 +792,20 @@ void AppletManager::SendApplicationParameterAfterRegistration(const MessageParam
} }
void AppletManager::EnsureHomeMenuLoaded() { void AppletManager::EnsureHomeMenuLoaded() {
const auto& system_slot = applet_slots[static_cast<size_t>(AppletSlot::SystemApplet)];
// TODO(Subv): The real APT service sends signal 12 (WakeupByCancel) to the currently running // TODO(Subv): The real APT service sends signal 12 (WakeupByCancel) to the currently running
// System applet, waits for it to finish, and then launches the Home Menu. // System applet, waits for it to finish, and then launches the Home Menu.
ASSERT_MSG(!system_slot.registered, "A system applet is already running"); ASSERT_MSG(!GetAppletSlot(AppletSlot::SystemApplet)->registered,
"A system applet is already running");
const auto& menu_slot = applet_slots[static_cast<size_t>(AppletSlot::HomeMenu)]; if (GetAppletSlot(AppletSlot::HomeMenu)->registered) {
if (menu_slot.registered) {
// The Home Menu is already running. // The Home Menu is already running.
return; return;
} }
auto cfg = Service::CFG::GetModule(system); auto cfg = Service::CFG::GetModule(system);
ASSERT_MSG(cfg, "CFG Module missing!"); ASSERT_MSG(cfg, "CFG Module missing!");
u32 region_value = cfg->GetRegionValue();
u64 menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, region_value); auto menu_title_id = GetTitleIdForApplet(AppletId::HomeMenu, cfg->GetRegionValue());
auto process = NS::LaunchTitle(FS::MediaType::NAND, menu_title_id); auto process = NS::LaunchTitle(FS::MediaType::NAND, menu_title_id);
if (!process) { if (!process) {
LOG_WARNING(Service_APT, LOG_WARNING(Service_APT,
@ -701,6 +814,7 @@ void AppletManager::EnsureHomeMenuLoaded() {
} }
AppletManager::AppletManager(Core::System& system) : system(system) { AppletManager::AppletManager(Core::System& system) : system(system) {
lock = system.Kernel().CreateMutex(false, "APT_U:Lock");
for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) { for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) {
auto& slot_data = applet_slots[slot]; auto& slot_data = applet_slots[slot];
slot_data.slot = static_cast<AppletSlot>(slot); slot_data.slot = static_cast<AppletSlot>(slot);

View File

@ -103,10 +103,13 @@ private:
friend class boost::serialization::access; friend class boost::serialization::access;
}; };
/// Holds information about the parameters used in StartLibraryApplet enum class AppletPos {
struct AppletStartupParameter { Application = 0,
std::shared_ptr<Kernel::Object> object = nullptr; Library = 1,
std::vector<u8> buffer; System = 2,
SysLibrary = 3,
Resident = 4,
AutoLibrary = 5
}; };
union AppletAttributes { union AppletAttributes {
@ -125,6 +128,56 @@ enum class ApplicationJumpFlags : u8 {
UseCurrentParameters = 2 UseCurrentParameters = 2
}; };
struct DeliverArg {
std::vector<u8> param;
std::vector<u8> hmac;
u64 source_program_id = std::numeric_limits<u64>::max();
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& param;
ar& hmac;
ar& source_program_id;
}
friend class boost::serialization::access;
};
struct ApplicationJumpParameters {
u64 next_title_id;
FS::MediaType next_media_type;
ApplicationJumpFlags flags;
u64 current_title_id;
FS::MediaType current_media_type;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& next_title_id;
ar& next_media_type;
if (file_version > 0) {
ar& flags;
}
ar& current_title_id;
ar& current_media_type;
}
friend class boost::serialization::access;
};
struct ApplicationStartParameters {
u64 next_title_id;
FS::MediaType next_media_type;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& next_title_id;
ar& next_media_type;
}
friend class boost::serialization::access;
};
class AppletManager : public std::enable_shared_from_this<AppletManager> { class AppletManager : public std::enable_shared_from_this<AppletManager> {
public: public:
explicit AppletManager(Core::System& system); explicit AppletManager(Core::System& system);
@ -142,41 +195,42 @@ public:
bool CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver, bool CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver,
AppletId receiver_appid); AppletId receiver_appid);
struct GetLockHandleResult {
AppletAttributes corrected_attributes;
u32 state;
std::shared_ptr<Kernel::Mutex> lock;
};
ResultVal<GetLockHandleResult> GetLockHandle(AppletAttributes attributes);
struct InitializeResult { struct InitializeResult {
std::shared_ptr<Kernel::Event> notification_event; std::shared_ptr<Kernel::Event> notification_event;
std::shared_ptr<Kernel::Event> parameter_event; std::shared_ptr<Kernel::Event> parameter_event;
}; };
ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes); ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes);
ResultCode Enable(AppletAttributes attributes); ResultCode Enable(AppletAttributes attributes);
bool IsRegistered(AppletId app_id); bool IsRegistered(AppletId app_id);
ResultCode PrepareToStartLibraryApplet(AppletId applet_id); ResultCode PrepareToStartLibraryApplet(AppletId applet_id);
ResultCode PreloadLibraryApplet(AppletId applet_id); ResultCode PreloadLibraryApplet(AppletId applet_id);
ResultCode FinishPreloadingLibraryApplet(AppletId applet_id); ResultCode FinishPreloadingLibraryApplet(AppletId applet_id);
ResultCode StartLibraryApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object, ResultCode StartLibraryApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer); const std::vector<u8>& buffer);
ResultCode PrepareToCloseLibraryApplet(bool not_pause, bool exiting, bool jump_home); ResultCode PrepareToCloseLibraryApplet(bool not_pause, bool exiting, bool jump_home);
ResultCode CloseLibraryApplet(std::shared_ptr<Kernel::Object> object, std::vector<u8> buffer); ResultCode CloseLibraryApplet(std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer);
ResultCode CancelLibraryApplet(bool app_exiting);
ResultCode PrepareToStartSystemApplet(AppletId applet_id);
ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer);
ResultCode PrepareToCloseSystemApplet();
ResultCode CloseSystemApplet(std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer);
ResultCode PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, ResultCode PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type,
ApplicationJumpFlags flags); ApplicationJumpFlags flags);
ResultCode DoApplicationJump(const DeliverArg& arg);
struct DeliverArg {
std::vector<u8> param;
std::vector<u8> hmac;
u64 source_program_id = std::numeric_limits<u64>::max();
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& param;
ar& hmac;
ar& source_program_id;
}
friend class boost::serialization::access;
};
ResultCode DoApplicationJump(DeliverArg arg);
boost::optional<DeliverArg> ReceiveDeliverArg() const { boost::optional<DeliverArg> ReceiveDeliverArg() const {
return deliver_arg; return deliver_arg;
@ -197,49 +251,16 @@ public:
bool loaded; bool loaded;
u32 attributes; u32 attributes;
}; };
ResultVal<AppletInfo> GetAppletInfo(AppletId app_id); ResultVal<AppletInfo> GetAppletInfo(AppletId app_id);
struct ApplicationJumpParameters {
u64 next_title_id;
FS::MediaType next_media_type;
ApplicationJumpFlags flags;
u64 current_title_id;
FS::MediaType current_media_type;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& next_title_id;
ar& next_media_type;
if (file_version > 0) {
ar& flags;
}
ar& current_title_id;
ar& current_media_type;
}
friend class boost::serialization::access;
};
ApplicationJumpParameters GetApplicationJumpParameters() const { ApplicationJumpParameters GetApplicationJumpParameters() const {
return app_jump_parameters; return app_jump_parameters;
} }
struct ApplicationStartParameters {
u64 next_title_id;
FS::MediaType next_media_type;
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& next_title_id;
ar& next_media_type;
}
friend class boost::serialization::access;
};
private: private:
/// APT lock retrieved via GetLockHandle.
std::shared_ptr<Kernel::Mutex> lock;
/// Parameter data to be returned in the next call to Glance/ReceiveParameter. /// Parameter data to be returned in the next call to Glance/ReceiveParameter.
// NOTE: A bug in gcc prevents serializing std::optional // NOTE: A bug in gcc prevents serializing std::optional
boost::optional<MessageParameter> next_parameter; boost::optional<MessageParameter> next_parameter;
@ -248,6 +269,10 @@ private:
/// APT::Initialize. /// APT::Initialize.
boost::optional<MessageParameter> delayed_parameter; boost::optional<MessageParameter> delayed_parameter;
ApplicationJumpParameters app_jump_parameters{};
boost::optional<ApplicationStartParameters> app_start_parameters{};
boost::optional<DeliverArg> deliver_arg{};
static constexpr std::size_t NumAppletSlot = 4; static constexpr std::size_t NumAppletSlot = 4;
enum class AppletSlot : u8 { enum class AppletSlot : u8 {
@ -292,16 +317,28 @@ private:
friend class boost::serialization::access; friend class boost::serialization::access;
}; };
ApplicationJumpParameters app_jump_parameters{};
boost::optional<ApplicationStartParameters> app_start_parameters{};
boost::optional<DeliverArg> deliver_arg{};
// Holds data about the concurrently running applets in the system. // Holds data about the concurrently running applets in the system.
std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; std::array<AppletSlotData, NumAppletSlot> applet_slots = {};
AppletSlot active_slot = AppletSlot::Error;
// This overload returns nullptr if no applet with the specified id has been started. AppletSlot last_library_launcher_slot = AppletSlot::Error;
AppletSlotData* GetAppletSlotData(AppletId id); SignalType library_applet_closing_command = SignalType::None;
AppletSlotData* GetAppletSlotData(AppletAttributes attributes); AppletId last_prepared_library_applet = AppletId::None;
AppletSlot last_system_launcher_slot = AppletSlot::Error;
Core::System& system;
AppletSlotData* GetAppletSlot(AppletSlot slot) {
return &applet_slots[static_cast<std::size_t>(slot)];
}
AppletId GetAppletSlotId(AppletSlot slot) {
return slot != AppletSlot::Error ? GetAppletSlot(slot)->applet_id : AppletId::None;
}
AppletSlot GetAppletSlotFromId(AppletId id);
AppletSlot GetAppletSlotFromAttributes(AppletAttributes attributes);
AppletSlot GetAppletSlotFromPos(AppletPos pos);
/// Checks if the Application slot has already been registered and sends the parameter to it, /// Checks if the Application slot has already been registered and sends the parameter to it,
/// otherwise it queues for sending when the application registers itself with APT::Enable. /// otherwise it queues for sending when the application registers itself with APT::Enable.
@ -309,12 +346,6 @@ private:
void EnsureHomeMenuLoaded(); void EnsureHomeMenuLoaded();
// Command that will be sent to the application when a library applet calls CloseLibraryApplet.
SignalType library_applet_closing_command;
Core::System& system;
private:
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) { void serialize(Archive& ar, const unsigned int file_version) {
ar& next_parameter; ar& next_parameter;
@ -323,6 +354,11 @@ private:
ar& delayed_parameter; ar& delayed_parameter;
ar& app_start_parameters; ar& app_start_parameters;
ar& deliver_arg; ar& deliver_arg;
ar& active_slot;
ar& last_library_launcher_slot;
ar& last_prepared_library_applet;
ar& last_system_launcher_slot;
ar& lock;
} }
ar& applet_slots; ar& applet_slots;
ar& library_applet_closing_command; ar& library_applet_closing_command;
@ -332,7 +368,7 @@ private:
} // namespace Service::APT } // namespace Service::APT
BOOST_CLASS_VERSION(Service::APT::AppletManager::ApplicationJumpParameters, 1) BOOST_CLASS_VERSION(Service::APT::ApplicationJumpParameters, 1)
BOOST_CLASS_VERSION(Service::APT::AppletManager, 1) BOOST_CLASS_VERSION(Service::APT::AppletManager, 1)
SERVICE_CONSTRUCT(Service::APT::AppletManager) SERVICE_CONSTRUCT(Service::APT::AppletManager)

View File

@ -39,7 +39,6 @@ void Module::serialize(Archive& ar, const unsigned int file_version) {
ar& shared_font_mem; ar& shared_font_mem;
ar& shared_font_loaded; ar& shared_font_loaded;
ar& shared_font_relocated; ar& shared_font_relocated;
ar& lock;
ar& cpu_percent; ar& cpu_percent;
ar& unknown_ns_state_field; ar& unknown_ns_state_field;
ar& screen_capture_buffer; ar& screen_capture_buffer;
@ -63,8 +62,8 @@ std::shared_ptr<Module> Module::NSInterface::GetModule() const {
void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx) { void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x06, 1, 2); // 0x00060042 IPC::RequestParser rp(ctx, 0x06, 1, 2); // 0x00060042
u32 size = rp.Pop<u32>(); const auto size = rp.Pop<u32>();
auto buffer = rp.PopStaticBuffer(); const auto buffer = rp.PopStaticBuffer();
apt->wireless_reboot_info = std::move(buffer); apt->wireless_reboot_info = std::move(buffer);
@ -76,8 +75,8 @@ void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx)
void Module::APTInterface::Initialize(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Initialize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x2, 2, 0); // 0x20080 IPC::RequestParser rp(ctx, 0x2, 2, 0); // 0x20080
AppletId app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
u32 attributes = rp.Pop<u32>(); const auto attributes = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called app_id={:#010X}, attributes={:#010X}", app_id, attributes); LOG_DEBUG(Service_APT, "called app_id={:#010X}, attributes={:#010X}", app_id, attributes);
@ -86,10 +85,9 @@ void Module::APTInterface::Initialize(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(result.Code()); rb.Push(result.Code());
} else { } else {
auto events = std::move(result).Unwrap();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(events.notification_event, events.parameter_event); rb.PushCopyObjects(result->notification_event, result->parameter_event);
} }
} }
@ -148,9 +146,10 @@ static u32 DecompressLZ11(const u8* in, u8* out) {
} }
bool Module::LoadSharedFont() { bool Module::LoadSharedFont() {
u8 font_region_code;
auto cfg = Service::CFG::GetModule(system); auto cfg = Service::CFG::GetModule(system);
ASSERT_MSG(cfg, "CFG Module missing!"); ASSERT_MSG(cfg, "CFG Module missing!");
u8 font_region_code;
switch (cfg->GetRegionValue()) { switch (cfg->GetRegionValue()) {
case 4: // CHN case 4: // CHN
font_region_code = 2; font_region_code = 2;
@ -279,7 +278,7 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x45, 1, 0); // 0x00450040 IPC::RequestParser rp(ctx, 0x45, 1, 0); // 0x00450040
u32 size = rp.Pop<u32>(); const auto size = rp.Pop<u32>();
LOG_WARNING(Service_APT, "called size={:08X}", size); LOG_WARNING(Service_APT, "called size={:08X}", size);
@ -290,9 +289,11 @@ void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx)
void Module::APTInterface::NotifyToWait(Kernel::HLERequestContext& ctx) { void Module::APTInterface::NotifyToWait(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x43, 1, 0); // 0x430040 IPC::RequestParser rp(ctx, 0x43, 1, 0); // 0x430040
u32 app_id = rp.Pop<u32>(); const auto app_id = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, "(STUBBED) app_id={}", app_id); LOG_WARNING(Service_APT, "(STUBBED) app_id={}", app_id);
} }
@ -302,24 +303,26 @@ void Module::APTInterface::GetLockHandle(Kernel::HLERequestContext& ctx) {
// Bits [0:2] are the applet type (System, Library, etc) // Bits [0:2] are the applet type (System, Library, etc)
// Bit 5 tells the application that there's a pending APT parameter, // Bit 5 tells the application that there's a pending APT parameter,
// this will cause the app to wait until parameter_event is signaled. // this will cause the app to wait until parameter_event is signaled.
u32 applet_attributes = rp.Pop<u32>(); const auto attributes = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
rb.Push(RESULT_SUCCESS); // No error
// TODO(Subv): The output attributes should have an AppletPos of either Library or System | LOG_DEBUG(Service_APT, "called applet_attributes={:#010X}", attributes);
// Library (depending on the type of the last launched applet) if the input attributes'
// AppletPos has the Library bit set.
rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. auto result = apt->applet_manager->GetLockHandle(attributes);
rb.Push<u32>(0); // Least significant bit = power button state if (result.Failed()) {
rb.PushCopyObjects(apt->lock); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(result.Code());
LOG_WARNING(Service_APT, "(STUBBED) called applet_attributes={:#010X}", applet_attributes); } else {
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
rb.Push(RESULT_SUCCESS);
rb.PushRaw(result->corrected_attributes);
rb.Push<u32>(result->state);
rb.PushCopyObjects(result->lock);
}
} }
void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x3, 1, 0); // 0x30040 IPC::RequestParser rp(ctx, 0x3, 1, 0); // 0x30040
u32 attributes = rp.Pop<u32>(); const auto attributes = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called attributes={:#010X}", attributes); LOG_DEBUG(Service_APT, "called attributes={:#010X}", attributes);
@ -329,7 +332,8 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x5, 1, 0); // 0x50040 IPC::RequestParser rp(ctx, 0x5, 1, 0); // 0x50040
u32 unk = rp.Pop<u32>(); const auto unk = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push<u32>(0); rb.Push<u32>(0);
@ -342,7 +346,8 @@ void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x9, 1, 0); // 0x90040 IPC::RequestParser rp(ctx, 0x9, 1, 0); // 0x90040
AppletId app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push(apt->applet_manager->IsRegistered(app_id)); rb.Push(apt->applet_manager->IsRegistered(app_id));
@ -352,21 +357,23 @@ void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) { void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0xB, 1, 0); // 0xB0040 IPC::RequestParser rp(ctx, 0xB, 1, 0); // 0xB0040
u32 app_id = rp.Pop<u32>(); const auto app_id = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push(static_cast<u32>(SignalType::None)); // Signal type rb.Push(static_cast<u32>(SignalType::None)); // Signal type
LOG_WARNING(Service_APT, "(STUBBED) called app_id={:#010X}", app_id); LOG_WARNING(Service_APT, "(STUBBED) called app_id={:#010X}", app_id);
} }
void Module::APTInterface::SendParameter(Kernel::HLERequestContext& ctx) { void Module::APTInterface::SendParameter(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0xC, 4, 4); // 0xC0104 IPC::RequestParser rp(ctx, 0xC, 4, 4); // 0xC0104
AppletId src_app_id = rp.PopEnum<AppletId>(); const auto src_app_id = rp.PopEnum<AppletId>();
AppletId dst_app_id = rp.PopEnum<AppletId>(); const auto dst_app_id = rp.PopEnum<AppletId>();
SignalType signal_type = rp.PopEnum<SignalType>(); const auto signal_type = rp.PopEnum<SignalType>();
u32 buffer_size = rp.Pop<u32>(); const auto buffer_size = rp.Pop<u32>();
std::shared_ptr<Kernel::Object> object = rp.PopGenericObject(); const auto object = rp.PopGenericObject();
std::vector<u8> buffer = rp.PopStaticBuffer(); const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, LOG_DEBUG(Service_APT,
"called src_app_id={:#010X}, dst_app_id={:#010X}, signal_type={:#010X}," "called src_app_id={:#010X}, dst_app_id={:#010X}, signal_type={:#010X},"
@ -374,42 +381,39 @@ void Module::APTInterface::SendParameter(Kernel::HLERequestContext& ctx) {
src_app_id, dst_app_id, signal_type, buffer_size); src_app_id, dst_app_id, signal_type, buffer_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->SendParameter({
MessageParameter param; .sender_id = src_app_id,
param.destination_id = dst_app_id; .destination_id = dst_app_id,
param.sender_id = src_app_id; .signal = signal_type,
param.object = std::move(object); .object = object,
param.signal = signal_type; .buffer = buffer,
param.buffer = std::move(buffer); }));
rb.Push(apt->applet_manager->SendParameter(param));
} }
void Module::APTInterface::ReceiveParameter(Kernel::HLERequestContext& ctx) { void Module::APTInterface::ReceiveParameter(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0xD, 2, 0); // 0xD0080 IPC::RequestParser rp(ctx, 0xD, 2, 0); // 0xD0080
const auto app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
const u32 buffer_size = rp.Pop<u32>(); const auto buffer_size = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called app_id={:#010X}, buffer_size={:#010X}", app_id, buffer_size); LOG_DEBUG(Service_APT, "called app_id={:#010X}, buffer_size={:#010X}", app_id, buffer_size);
auto next_parameter = apt->applet_manager->ReceiveParameter(app_id); auto next_parameter = apt->applet_manager->ReceiveParameter(app_id);
if (next_parameter.Failed()) { if (next_parameter.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(next_parameter.Code()); rb.Push(next_parameter.Code());
return; } else {
const auto size = std::min(static_cast<u32>(next_parameter->buffer.size()), buffer_size);
next_parameter->buffer.resize(
buffer_size); // APT always push a buffer with the maximum size
IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
rb.Push(RESULT_SUCCESS); // No error
rb.PushEnum(next_parameter->sender_id);
rb.PushEnum(next_parameter->signal); // Signal type
rb.Push(size); // Parameter buffer size
rb.PushMoveObjects(next_parameter->object);
rb.PushStaticBuffer(std::move(next_parameter->buffer), 0);
} }
IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
rb.Push(RESULT_SUCCESS); // No error
rb.PushEnum(next_parameter->sender_id);
rb.PushEnum(next_parameter->signal); // Signal type
ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small!");
rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size
rb.PushMoveObjects(next_parameter->object);
next_parameter->buffer.resize(buffer_size); // APT always push a buffer with the maximum size
rb.PushStaticBuffer(std::move(next_parameter->buffer), 0);
} }
void Module::APTInterface::GlanceParameter(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GlanceParameter(Kernel::HLERequestContext& ctx) {
@ -420,42 +424,40 @@ void Module::APTInterface::GlanceParameter(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_APT, "called app_id={:#010X}, buffer_size={:#010X}", app_id, buffer_size); LOG_DEBUG(Service_APT, "called app_id={:#010X}, buffer_size={:#010X}", app_id, buffer_size);
auto next_parameter = apt->applet_manager->GlanceParameter(app_id); auto next_parameter = apt->applet_manager->GlanceParameter(app_id);
if (next_parameter.Failed()) { if (next_parameter.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(next_parameter.Code()); rb.Push(next_parameter.Code());
return; } else {
} const auto size = std::min(static_cast<u32>(next_parameter->buffer.size()), buffer_size);
next_parameter->buffer.resize(
buffer_size); // APT always push a buffer with the maximum size
IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.PushEnum(next_parameter->sender_id); rb.PushEnum(next_parameter->sender_id);
rb.PushEnum(next_parameter->signal); // Signal type rb.PushEnum(next_parameter->signal); // Signal type
ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small!"); rb.Push(size); // Parameter buffer size
rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size rb.PushMoveObjects(next_parameter->object);
rb.PushMoveObjects(next_parameter->object); rb.PushStaticBuffer(std::move(next_parameter->buffer), 0);
next_parameter->buffer.resize(buffer_size); // APT always push a buffer with the maximum size }
rb.PushStaticBuffer(std::move(next_parameter->buffer), 0);
} }
void Module::APTInterface::CancelParameter(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CancelParameter(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0xF, 4, 0); // 0xF0100 IPC::RequestParser rp(ctx, 0xF, 4, 0); // 0xF0100
const auto check_sender = rp.Pop<bool>();
const auto sender_appid = rp.PopEnum<AppletId>();
const auto check_receiver = rp.Pop<bool>();
const auto receiver_appid = rp.PopEnum<AppletId>();
bool check_sender = rp.Pop<bool>(); LOG_DEBUG(
AppletId sender_appid = rp.PopEnum<AppletId>(); Service_APT,
bool check_receiver = rp.Pop<bool>(); "called check_sender={}, sender_appid={:#010X}, check_receiver={}, receiver_appid={:#010X}",
AppletId receiver_appid = rp.PopEnum<AppletId>(); check_sender, sender_appid, check_receiver, receiver_appid);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push(apt->applet_manager->CancelParameter(check_sender, sender_appid, check_receiver, rb.Push(apt->applet_manager->CancelParameter(check_sender, sender_appid, check_receiver,
receiver_appid)); receiver_appid));
LOG_DEBUG(Service_APT,
"called check_sender={}, sender_appid={:#010X}, "
"check_receiver={}, receiver_appid={:#010X}",
check_sender, sender_appid, check_receiver, receiver_appid);
} }
void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext& ctx) {
@ -464,8 +466,8 @@ void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext&
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
u8 media_type = rp.Pop<u8>(); u8 media_type = rp.Pop<u8>();
LOG_WARNING(Service_APT, "(STUBBED) called title_id={:016X}, media_type={:#01X}, flags={:#08X}", LOG_INFO(Service_APT, "called title_id={:016X}, media_type={:#01X}, flags={:#08X}", title_id,
title_id, media_type, flags); media_type, flags);
ResultCode result = apt->applet_manager->PrepareToDoApplicationJump( ResultCode result = apt->applet_manager->PrepareToDoApplicationJump(
title_id, static_cast<FS::MediaType>(media_type), flags); title_id, static_cast<FS::MediaType>(media_type), flags);
@ -476,32 +478,15 @@ void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext&
void Module::APTInterface::DoApplicationJump(Kernel::HLERequestContext& ctx) { void Module::APTInterface::DoApplicationJump(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x32, 2, 4); // 0x00320084 IPC::RequestParser rp(ctx, 0x32, 2, 4); // 0x00320084
auto param_size = rp.Pop<u32>(); const auto param_size = rp.Pop<u32>();
auto hmac_size = rp.Pop<u32>(); const auto hmac_size = rp.Pop<u32>();
const auto param = rp.PopStaticBuffer();
constexpr u32 max_param_size{0x300}; const auto hmac = rp.PopStaticBuffer();
constexpr u32 max_hmac_size{0x20};
if (param_size > max_param_size) {
LOG_ERROR(Service_APT,
"Param size is outside the valid range (capped to {:#010X}): param_size={:#010X}",
max_param_size, param_size);
param_size = max_param_size;
}
if (hmac_size > max_hmac_size) {
LOG_ERROR(Service_APT,
"HMAC size is outside the valid range (capped to {:#010X}): hmac_size={:#010X}",
max_hmac_size, hmac_size);
hmac_size = max_hmac_size;
}
auto param = rp.PopStaticBuffer();
auto hmac = rp.PopStaticBuffer();
LOG_INFO(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size); LOG_INFO(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->DoApplicationJump( rb.Push(apt->applet_manager->DoApplicationJump(DeliverArg{param, hmac}));
AppletManager::DeliverArg{std::move(param), std::move(hmac)}));
} }
void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx) {
@ -509,7 +494,7 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte
LOG_DEBUG(Service_APT, "called"); LOG_DEBUG(Service_APT, "called");
auto parameters = apt->applet_manager->GetApplicationJumpParameters(); const auto parameters = apt->applet_manager->GetApplicationJumpParameters();
IPC::RequestBuilder rb = rp.MakeBuilder(7, 0); IPC::RequestBuilder rb = rp.MakeBuilder(7, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
@ -520,13 +505,13 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte
} }
void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) { void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x35, 2, 4); // 0x00350080 IPC::RequestParser rp(ctx, 0x35, 2, 0); // 0x00350080
const auto param_size = rp.Pop<u32>(); const auto param_size = rp.Pop<u32>();
const auto hmac_size = rp.Pop<u32>(); const auto hmac_size = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size); LOG_DEBUG(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size);
auto arg = apt->applet_manager->ReceiveDeliverArg().value_or(AppletManager::DeliverArg{}); auto arg = apt->applet_manager->ReceiveDeliverArg().value_or(DeliverArg{});
arg.param.resize(param_size); arg.param.resize(param_size);
arg.hmac.resize(std::min<std::size_t>(hmac_size, 0x20)); arg.hmac.resize(std::min<std::size_t>(hmac_size, 0x20));
@ -540,40 +525,40 @@ void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::PrepareToStartApplication(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToStartApplication(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x15, 5, 0); // 0x00150140 IPC::RequestParser rp(ctx, 0x15, 5, 0); // 0x00150140
const u64 title_id = rp.Pop<u64>(); const auto title_id = rp.Pop<u64>();
const auto media_type = rp.PopEnum<FS::MediaType>(); const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Padding rp.Skip(1, false); // Padding
const u32 flags = rp.Pop<u32>(); const auto flags = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->PrepareToStartApplication(title_id, media_type));
LOG_INFO(Service_APT, "called title_id={:#010X} media_type={} flags={:#010X}", title_id, LOG_INFO(Service_APT, "called title_id={:#010X} media_type={} flags={:#010X}", title_id,
media_type, flags); media_type, flags);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->PrepareToStartApplication(title_id, media_type));
} }
void Module::APTInterface::StartApplication(Kernel::HLERequestContext& ctx) { void Module::APTInterface::StartApplication(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1B, 3, 4); // 0x001B00C4 IPC::RequestParser rp(ctx, 0x1B, 3, 4); // 0x001B00C4
const u32 parameter_size = rp.Pop<u32>(); const auto parameter_size = rp.Pop<u32>();
const u32 hmac_size = rp.Pop<u32>(); const auto hmac_size = rp.Pop<u32>();
const bool paused = rp.Pop<bool>(); const auto paused = rp.Pop<bool>();
const std::vector<u8> parameter = rp.PopStaticBuffer(); const auto parameter = rp.PopStaticBuffer();
const std::vector<u8> hmac = rp.PopStaticBuffer(); const auto hmac = rp.PopStaticBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->StartApplication(parameter, hmac, paused));
LOG_INFO(Service_APT, "called parameter_size={:#010X}, hmac_size={:#010X}, paused={}", LOG_INFO(Service_APT, "called parameter_size={:#010X}, hmac_size={:#010X}, paused={}",
parameter_size, hmac_size, paused); parameter_size, hmac_size, paused);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->StartApplication(parameter, hmac, paused));
} }
void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) { void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1C, 0, 0); // 0x001C0000 IPC::RequestParser rp(ctx, 0x1C, 0, 0); // 0x001C0000
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->WakeupApplication()); rb.Push(apt->applet_manager->WakeupApplication());
LOG_DEBUG(Service_APT, "called");
} }
void Module::APTInterface::AppletUtility(Kernel::HLERequestContext& ctx) { void Module::APTInterface::AppletUtility(Kernel::HLERequestContext& ctx) {
@ -583,49 +568,49 @@ void Module::APTInterface::AppletUtility(Kernel::HLERequestContext& ctx) {
const auto utility_command = rp.Pop<u32>(); const auto utility_command = rp.Pop<u32>();
const auto input_size = rp.Pop<u32>(); const auto input_size = rp.Pop<u32>();
const auto output_size = rp.Pop<u32>(); const auto output_size = rp.Pop<u32>();
[[maybe_unused]] const std::vector<u8> input = rp.PopStaticBuffer(); [[maybe_unused]] const auto input = rp.PopStaticBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, LOG_WARNING(Service_APT,
"(STUBBED) called command={:#010X}, input_size={:#010X}, output_size={:#010X}", "(STUBBED) called command={:#010X}, input_size={:#010X}, output_size={:#010X}",
utility_command, input_size, output_size); utility_command, input_size, output_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error
} }
void Module::APTInterface::SetAppCpuTimeLimit(Kernel::HLERequestContext& ctx) { void Module::APTInterface::SetAppCpuTimeLimit(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x4F, 2, 0); // 0x4F0080 IPC::RequestParser rp(ctx, 0x4F, 2, 0); // 0x4F0080
u32 value = rp.Pop<u32>(); const auto must_be_one = rp.Pop<u32>();
apt->cpu_percent = rp.Pop<u32>(); const auto value = rp.Pop<u32>();
if (value != 1) { LOG_WARNING(Service_APT, "(STUBBED) called, must_be_one={}, value={}", must_be_one, value);
LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", value); if (must_be_one != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", must_be_one);
} }
apt->cpu_percent = value;
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, "(STUBBED) called, cpu_percent={}, value={}", apt->cpu_percent, value);
} }
void Module::APTInterface::GetAppCpuTimeLimit(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetAppCpuTimeLimit(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x50, 1, 0); // 0x500040 IPC::RequestParser rp(ctx, 0x50, 1, 0); // 0x500040
u32 value = rp.Pop<u32>(); const auto must_be_one = rp.Pop<u32>();
if (value != 1) { LOG_WARNING(Service_APT, "(STUBBED) called, must_be_one={}", must_be_one);
LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", value); if (must_be_one != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", must_be_one);
} }
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push(apt->cpu_percent); rb.Push(apt->cpu_percent);
LOG_WARNING(Service_APT, "(STUBBED) called, value={}", value);
} }
void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x18, 1, 0); // 0x180040 IPC::RequestParser rp(ctx, 0x18, 1, 0); // 0x180040
AppletId applet_id = rp.PopEnum<AppletId>(); const auto applet_id = rp.PopEnum<AppletId>();
LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id); LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id);
@ -633,23 +618,33 @@ void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext
rb.Push(apt->applet_manager->PrepareToStartLibraryApplet(applet_id)); rb.Push(apt->applet_manager->PrepareToStartLibraryApplet(applet_id));
} }
void Module::APTInterface::PrepareToStartSystemApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x19, 1, 0); // 0x190040
const auto applet_id = rp.PopEnum<AppletId>();
LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->PrepareToStartSystemApplet(applet_id));
}
void Module::APTInterface::PrepareToStartNewestHomeMenu(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToStartNewestHomeMenu(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1A, 0, 0); // 0x1A0000 IPC::RequestParser rp(ctx, 0x1A, 0, 0); // 0x1A0000
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
LOG_DEBUG(Service_APT, "called");
// TODO(Subv): This command can only be called by a System Applet (return 0xC8A0CC04 otherwise). // TODO(Subv): This command can only be called by a System Applet (return 0xC8A0CC04 otherwise).
// This command must return an error when called, otherwise the Home Menu will try to reboot the // This command must return an error when called, otherwise the Home Menu will try to reboot the
// system. // system.
rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status)); ErrorSummary::InvalidState, ErrorLevel::Status));
LOG_DEBUG(Service_APT, "called");
} }
void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x16, 1, 0); // 0x160040 IPC::RequestParser rp(ctx, 0x16, 1, 0); // 0x160040
AppletId applet_id = rp.PopEnum<AppletId>(); const auto applet_id = rp.PopEnum<AppletId>();
LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id); LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id);
@ -659,7 +654,7 @@ void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx)
void Module::APTInterface::FinishPreloadingLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::FinishPreloadingLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x17, 1, 0); // 0x00170040 IPC::RequestParser rp(ctx, 0x17, 1, 0); // 0x00170040
AppletId applet_id = rp.PopEnum<AppletId>(); const auto applet_id = rp.PopEnum<AppletId>();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->FinishPreloadingLibraryApplet(applet_id)); rb.Push(apt->applet_manager->FinishPreloadingLibraryApplet(applet_id));
@ -669,23 +664,35 @@ void Module::APTInterface::FinishPreloadingLibraryApplet(Kernel::HLERequestConte
void Module::APTInterface::StartLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::StartLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1E, 2, 4); // 0x1E0084 IPC::RequestParser rp(ctx, 0x1E, 2, 4); // 0x1E0084
AppletId applet_id = rp.PopEnum<AppletId>(); const auto applet_id = rp.PopEnum<AppletId>();
const auto buffer_size = rp.Pop<u32>();
const auto object = rp.PopGenericObject();
const auto buffer = rp.PopStaticBuffer();
[[maybe_unused]] const std::size_t buffer_size = rp.Pop<u32>(); LOG_DEBUG(Service_APT, "called, applet_id={:08X}, size={:08X}", applet_id, buffer_size);
std::shared_ptr<Kernel::Object> object = rp.PopGenericObject();
const std::vector<u8> buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called, applet_id={:08X}", applet_id);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->StartLibraryApplet(applet_id, std::move(object), buffer)); rb.Push(apt->applet_manager->StartLibraryApplet(applet_id, object, buffer));
}
void Module::APTInterface::StartSystemApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1F, 2, 4); // 0x1F0084
const auto applet_id = rp.PopEnum<AppletId>();
const auto buffer_size = rp.Pop<u32>();
const auto object = rp.PopGenericObject();
const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called, applet_id={:08X}, size={:08X}", applet_id, buffer_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->StartSystemApplet(applet_id, object, buffer));
} }
void Module::APTInterface::CloseApplication(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CloseApplication(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x27, 1, 4); IPC::RequestParser rp(ctx, 0x27, 1, 4);
[[maybe_unused]] const u32 parameters_size = rp.Pop<u32>(); [[maybe_unused]] const auto parameters_size = rp.Pop<u32>();
[[maybe_unused]] const std::shared_ptr<Kernel::Object> object = rp.PopGenericObject(); [[maybe_unused]] const auto object = rp.PopGenericObject();
[[maybe_unused]] const std::vector<u8> buffer = rp.PopStaticBuffer(); [[maybe_unused]] const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called"); LOG_DEBUG(Service_APT, "called");
@ -697,19 +704,19 @@ void Module::APTInterface::CloseApplication(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::CancelLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CancelLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x3B, 1, 0); // 0x003B0040 IPC::RequestParser rp(ctx, 0x3B, 1, 0); // 0x003B0040
bool exiting = rp.Pop<bool>(); const auto app_exiting = rp.Pop<bool>();
LOG_DEBUG(Service_APT, "called app_exiting={}", app_exiting);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push<u32>(1); // TODO: Find the return code meaning rb.Push(apt->applet_manager->CancelLibraryApplet(app_exiting));
LOG_WARNING(Service_APT, "(STUBBED) called exiting={}", exiting);
} }
void Module::APTInterface::PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x25, 3, 0); // 0x002500C0 IPC::RequestParser rp(ctx, 0x25, 3, 0); // 0x002500C0
bool not_pause = rp.Pop<bool>(); const auto not_pause = rp.Pop<bool>();
bool exiting = rp.Pop<bool>(); const auto exiting = rp.Pop<bool>();
bool jump_to_home = rp.Pop<bool>(); const auto jump_to_home = rp.Pop<bool>();
LOG_DEBUG(Service_APT, "called not_pause={} exiting={} jump_to_home={}", not_pause, exiting, LOG_DEBUG(Service_APT, "called not_pause={} exiting={} jump_to_home={}", not_pause, exiting,
jump_to_home); jump_to_home);
@ -718,32 +725,52 @@ void Module::APTInterface::PrepareToCloseLibraryApplet(Kernel::HLERequestContext
rb.Push(apt->applet_manager->PrepareToCloseLibraryApplet(not_pause, exiting, jump_to_home)); rb.Push(apt->applet_manager->PrepareToCloseLibraryApplet(not_pause, exiting, jump_to_home));
} }
void Module::APTInterface::PrepareToCloseSystemApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x26, 0, 0); // 0x260000
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->PrepareToCloseSystemApplet());
}
void Module::APTInterface::CloseLibraryApplet(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CloseLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x28, 1, 4); // 0x00280044 IPC::RequestParser rp(ctx, 0x28, 1, 4); // 0x00280044
u32 parameter_size = rp.Pop<u32>(); const auto parameter_size = rp.Pop<u32>();
auto object = rp.PopGenericObject(); const auto object = rp.PopGenericObject();
std::vector<u8> buffer = rp.PopStaticBuffer(); const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called size={}", parameter_size); LOG_DEBUG(Service_APT, "called size={}", parameter_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->CloseLibraryApplet(std::move(object), std::move(buffer))); rb.Push(apt->applet_manager->CloseLibraryApplet(object, buffer));
}
void Module::APTInterface::CloseSystemApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x29, 1, 4); // 0x00280044
const auto parameter_size = rp.Pop<u32>();
const auto object = rp.PopGenericObject();
const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called size={}", parameter_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->CloseSystemApplet(object, buffer));
} }
void Module::APTInterface::LoadSysMenuArg(Kernel::HLERequestContext& ctx) { void Module::APTInterface::LoadSysMenuArg(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x36, 1, 0); // 0x00360040 IPC::RequestParser rp(ctx, 0x36, 1, 0); // 0x00360040
const auto size = std::min(std::size_t{rp.Pop<u32>()}, SysMenuArgSize); const auto size = std::min(std::size_t{rp.Pop<u32>()}, SysMenuArgSize);
// This service function does not clear the buffer. LOG_DEBUG(Service_APT, "called");
// This service function does not clear the buffer.
std::vector<u8> buffer(size); std::vector<u8> buffer(size);
std::copy_n(apt->sys_menu_arg_buffer.cbegin(), size, buffer.begin()); std::copy_n(apt->sys_menu_arg_buffer.cbegin(), size, buffer.begin());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushStaticBuffer(std::move(buffer), 0); rb.PushStaticBuffer(std::move(buffer), 0);
LOG_DEBUG(Service_APT, "called");
} }
void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) { void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) {
@ -751,21 +778,24 @@ void Module::APTInterface::StoreSysMenuArg(Kernel::HLERequestContext& ctx) {
const auto size = std::min(std::size_t{rp.Pop<u32>()}, SysMenuArgSize); const auto size = std::min(std::size_t{rp.Pop<u32>()}, SysMenuArgSize);
const auto& buffer = rp.PopStaticBuffer(); const auto& buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called");
ASSERT_MSG(buffer.size() >= size, "Buffer too small to hold requested data"); ASSERT_MSG(buffer.size() >= size, "Buffer too small to hold requested data");
std::copy_n(buffer.cbegin(), size, apt->sys_menu_arg_buffer.begin()); std::copy_n(buffer.cbegin(), size, apt->sys_menu_arg_buffer.begin());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_DEBUG(Service_APT, "called");
} }
void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x40, 1, 2); // 0x00400042 IPC::RequestParser rp(ctx, 0x40, 1, 2); // 0x00400042
u32 size = rp.Pop<u32>(); const auto size = rp.Pop<u32>();
const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called");
ASSERT(size == 0x20); ASSERT(size == 0x20);
apt->screen_capture_buffer = rp.PopStaticBuffer(); apt->screen_capture_buffer = buffer;
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
@ -773,7 +803,10 @@ void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx)
void Module::APTInterface::ReceiveCaptureBufferInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::ReceiveCaptureBufferInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x41, 1, 0); // 0x00410040 IPC::RequestParser rp(ctx, 0x41, 1, 0); // 0x00410040
u32 size = rp.Pop<u32>(); const auto size = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called");
ASSERT(size == 0x20); ASSERT(size == 0x20);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
@ -784,7 +817,9 @@ void Module::APTInterface::ReceiveCaptureBufferInfo(Kernel::HLERequestContext& c
void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x4A, 1, 0); // 0x004A0040 IPC::RequestParser rp(ctx, 0x4A, 1, 0); // 0x004A0040
const u32 size = rp.Pop<u32>(); const auto size = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called");
ASSERT(size == 0x20); ASSERT(size == 0x20);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
@ -797,29 +832,31 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::SetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { void Module::APTInterface::SetScreenCapPostPermission(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x55, 1, 0); // 0x00550040 IPC::RequestParser rp(ctx, 0x55, 1, 0); // 0x00550040
LOG_DEBUG(Service_APT, "called, screen_capture_post_permission={}",
apt->screen_capture_post_permission);
apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, "(STUBBED) called, screen_capture_post_permission={}",
apt->screen_capture_post_permission);
} }
void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x56, 0, 0); // 0x00560000 IPC::RequestParser rp(ctx, 0x56, 0, 0); // 0x00560000
LOG_DEBUG(Service_APT, "(STUBBED) called, screen_capture_post_permission={}",
apt->screen_capture_post_permission);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push(static_cast<u32>(apt->screen_capture_post_permission)); rb.Push(static_cast<u32>(apt->screen_capture_post_permission));
LOG_WARNING(Service_APT, "(STUBBED) called, screen_capture_post_permission={}",
apt->screen_capture_post_permission);
} }
void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x6, 1, 0); // 0x60040 IPC::RequestParser rp(ctx, 0x6, 1, 0); // 0x60040
auto app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
LOG_DEBUG(Service_APT, "called, app_id={}", app_id); LOG_DEBUG(Service_APT, "called, app_id={:08X}", app_id);
auto info = apt->applet_manager->GetAppletInfo(app_id); auto info = apt->applet_manager->GetAppletInfo(app_id);
if (info.Failed()) { if (info.Failed()) {
@ -838,20 +875,11 @@ void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x51, 2, 0); // 0x00510080 IPC::RequestParser rp(ctx, 0x51, 2, 0); // 0x00510080
u32 parameter_size = rp.Pop<u32>(); const auto parameter_size = rp.Pop<u32>();
constexpr u32 max_parameter_size{0x1000};
const auto startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>()); const auto startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>());
LOG_WARNING(Service_APT, "called, startup_argument_type={}, parameter_size={:#010X}", LOG_INFO(Service_APT, "called, startup_argument_type={}, parameter_size={:#010X}",
startup_argument_type, parameter_size); startup_argument_type, parameter_size);
if (parameter_size > max_parameter_size) {
LOG_ERROR(Service_APT,
"Parameter size is outside the valid range (capped to {:#010X}): "
"parameter_size={:#010X}",
max_parameter_size, parameter_size);
parameter_size = max_parameter_size;
}
std::vector<u8> param; std::vector<u8> param;
bool exists = false; bool exists = false;
@ -877,7 +905,8 @@ void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) {
} }
} }
param.resize(parameter_size); constexpr u32 max_parameter_size{0x1000};
param.resize(std::min(parameter_size, max_parameter_size));
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
@ -887,13 +916,17 @@ void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x46, 4, 4); IPC::RequestParser rp(ctx, 0x46, 4, 4);
const u32 output_size = rp.Pop<u32>(); const auto output_size = rp.Pop<u32>();
const u32 input_size = rp.Pop<u32>(); const auto input_size = rp.Pop<u32>();
const u32 nonce_offset = rp.Pop<u32>(); const auto nonce_offset = rp.Pop<u32>();
u32 nonce_size = rp.Pop<u32>(); auto nonce_size = rp.Pop<u32>();
auto& input = rp.PopMappedBuffer(); auto& input = rp.PopMappedBuffer();
ASSERT(input.GetSize() == input_size);
auto& output = rp.PopMappedBuffer(); auto& output = rp.PopMappedBuffer();
LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}",
output_size, input_size, nonce_offset, nonce_size);
ASSERT(input.GetSize() == input_size);
ASSERT(output.GetSize() == output_size); ASSERT(output.GetSize() == output_size);
// Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't
@ -901,9 +934,6 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(output_size == input_size + HW::AES::CCM_MAC_SIZE, ASSERT_MSG(output_size == input_size + HW::AES::CCM_MAC_SIZE,
"input_size ({}) doesn't match to output_size ({})", input_size, output_size); "input_size ({}) doesn't match to output_size ({})", input_size, output_size);
LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}",
output_size, input_size, nonce_offset, nonce_size);
// Note: This weird nonce size modification is verified against real 3DS // Note: This weird nonce size modification is verified against real 3DS
nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE); nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE);
@ -924,7 +954,6 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
// Unmap buffer // Unmap buffer
rb.PushMappedBuffer(input); rb.PushMappedBuffer(input);
rb.PushMappedBuffer(output); rb.PushMappedBuffer(output);
@ -932,13 +961,17 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x47, 4, 4); IPC::RequestParser rp(ctx, 0x47, 4, 4);
const u32 output_size = rp.Pop<u32>(); const auto output_size = rp.Pop<u32>();
const u32 input_size = rp.Pop<u32>(); const auto input_size = rp.Pop<u32>();
const u32 nonce_offset = rp.Pop<u32>(); const auto nonce_offset = rp.Pop<u32>();
u32 nonce_size = rp.Pop<u32>(); auto nonce_size = rp.Pop<u32>();
auto& input = rp.PopMappedBuffer(); auto& input = rp.PopMappedBuffer();
ASSERT(input.GetSize() == input_size);
auto& output = rp.PopMappedBuffer(); auto& output = rp.PopMappedBuffer();
LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}",
output_size, input_size, nonce_offset, nonce_size);
ASSERT(input.GetSize() == input_size);
ASSERT(output.GetSize() == output_size); ASSERT(output.GetSize() == output_size);
// Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't // Note: real 3DS still returns SUCCESS when the sizes don't match. It seems that it doesn't
@ -946,9 +979,6 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(output_size == input_size - HW::AES::CCM_MAC_SIZE, ASSERT_MSG(output_size == input_size - HW::AES::CCM_MAC_SIZE,
"input_size ({}) doesn't match to output_size ({})", input_size, output_size); "input_size ({}) doesn't match to output_size ({})", input_size, output_size);
LOG_DEBUG(Service_APT, "called, output_size={}, input_size={}, nonce_offset={}, nonce_size={}",
output_size, input_size, nonce_offset, nonce_size);
// Note: This weird nonce size modification is verified against real 3DS // Note: This weird nonce size modification is verified against real 3DS
nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE); nonce_size = std::min<u32>(nonce_size & ~3, HW::AES::CCM_NONCE_SIZE);
@ -984,6 +1014,8 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x101, 0, 0); // 0x01010000 IPC::RequestParser rp(ctx, 0x101, 0, 0); // 0x01010000
LOG_WARNING(Service_APT, "(STUBBED) called");
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (apt->unknown_ns_state_field) { if (apt->unknown_ns_state_field) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
@ -991,41 +1023,39 @@ void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) {
} else { } else {
PTM::CheckNew3DS(rb); PTM::CheckNew3DS(rb);
} }
LOG_WARNING(Service_APT, "(STUBBED) called");
} }
void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x102, 0, 0); // 0x01020000 IPC::RequestParser rp(ctx, 0x102, 0, 0); // 0x01020000
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
PTM::CheckNew3DS(rb);
LOG_WARNING(Service_APT, "(STUBBED) called"); LOG_WARNING(Service_APT, "(STUBBED) called");
PTM::CheckNew3DS(rb);
} }
void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x103, 0, 0); // 0x01030000 IPC::RequestParser rp(ctx, 0x103, 0, 0); // 0x01030000
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
LOG_WARNING(Service_APT, "(STUBBED) called");
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push<u8>(Settings::values.is_new_3ds ? 2 : 1); rb.Push<u8>(Settings::values.is_new_3ds ? 2 : 1);
LOG_WARNING(Service_APT, "(STUBBED) called");
} }
void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) { void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x105, 4, 0); // 0x01050100 IPC::RequestParser rp(ctx, 0x105, 4, 0); // 0x01050100
const u64 program_id = rp.Pop<u64>(); const auto program_id = rp.Pop<u64>();
const auto media_type = rp.PopEnum<FS::MediaType>(); const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Padding rp.Skip(1, false); // Padding
LOG_DEBUG(Service_APT, "called, title_id={:016X} media_type={}", program_id, media_type);
// We allow all titles to be launched, so this function is a no-op // We allow all titles to be launched, so this function is a no-op
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(true); rb.Push(true);
LOG_DEBUG(Service_APT, "called, title_id={:016X} media_type={}", program_id, media_type);
} }
Module::APTInterface::APTInterface(std::shared_ptr<Module> apt, const char* name, u32 max_session) Module::APTInterface::APTInterface(std::shared_ptr<Module> apt, const char* name, u32 max_session)
@ -1046,8 +1076,6 @@ Module::Module(Core::System& system) : system(system) {
MemoryPermission::ReadWrite, MemoryPermission::Read, MemoryPermission::ReadWrite, MemoryPermission::Read,
0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont") 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont")
.Unwrap(); .Unwrap();
lock = system.Kernel().CreateMutex(false, "APT_U:Lock");
} }
Module::~Module() {} Module::~Module() {}

View File

@ -416,6 +416,17 @@ public:
*/ */
void PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx); void PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx);
/**
* APT::PrepareToStartSystemApplet service function
* Inputs:
* 0 : Command header [0x00190040]
* 1 : Id of the applet to start
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
void PrepareToStartSystemApplet(Kernel::HLERequestContext& ctx);
/** /**
* APT::PrepareToStartNewestHomeMenu service function * APT::PrepareToStartNewestHomeMenu service function
* Inputs: * Inputs:
@ -464,6 +475,22 @@ public:
*/ */
void StartLibraryApplet(Kernel::HLERequestContext& ctx); void StartLibraryApplet(Kernel::HLERequestContext& ctx);
/**
* APT::StartSystemApplet service function
* Inputs:
* 0 : Command header [0x001F0084]
* 1 : Id of the applet to start
* 2 : Buffer size
* 3 : 0x0
* 4 : Handle passed to the applet
* 5 : (Size << 14) | 2
* 6 : Input buffer virtual address
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
void StartSystemApplet(Kernel::HLERequestContext& ctx);
/** /**
* APT::CloseApplication service function * APT::CloseApplication service function
* Inputs: * Inputs:
@ -562,6 +589,16 @@ public:
*/ */
void PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx); void PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx);
/**
* APT::PrepareToCloseSystemApplet service function
* Inputs:
* 0 : Command header [0x00260000]
* Outputs:
* 0 : Header code
* 1 : Result code
*/
void PrepareToCloseSystemApplet(Kernel::HLERequestContext& ctx);
/** /**
* APT::CloseLibraryApplet service function * APT::CloseLibraryApplet service function
* Inputs: * Inputs:
@ -577,6 +614,21 @@ public:
*/ */
void CloseLibraryApplet(Kernel::HLERequestContext& ctx); void CloseLibraryApplet(Kernel::HLERequestContext& ctx);
/**
* APT::CloseSystemApplet service function
* Inputs:
* 0 : Command header [0x00290044]
* 1 : Buffer size
* 2 : 0x0
* 3 : Object handle
* 4 : (Size << 14) | 2
* 5 : Input buffer virtual address
* Outputs:
* 0 : Header code
* 1 : Result code
*/
void CloseSystemApplet(Kernel::HLERequestContext& ctx);
/** /**
* APT::LoadSysMenuArg service function * APT::LoadSysMenuArg service function
* Inputs: * Inputs:
@ -744,8 +796,6 @@ private:
bool shared_font_loaded = false; bool shared_font_loaded = false;
bool shared_font_relocated = false; bool shared_font_relocated = false;
std::shared_ptr<Kernel::Mutex> lock;
u32 cpu_percent = 0; ///< CPU time available to the running application u32 cpu_percent = 0; ///< CPU time available to the running application
// APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode

View File

@ -32,25 +32,25 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x00140040, nullptr, "SetPreparationState"}, {0x00140040, nullptr, "SetPreparationState"},
{0x00150140, &APT_A::PrepareToStartApplication, "PrepareToStartApplication"}, {0x00150140, &APT_A::PrepareToStartApplication, "PrepareToStartApplication"},
{0x00160040, &APT_A::PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00160040, &APT_A::PreloadLibraryApplet, "PreloadLibraryApplet"},
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, {0x00170040, &APT_A::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"},
{0x00180040, &APT_A::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, {0x00180040, &APT_A::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
{0x00190040, nullptr, "PrepareToStartSystemApplet"}, {0x00190040, &APT_A::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"},
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, {0x001A0000, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B00C4, &APT_A::StartApplication, "StartApplication"}, {0x001B00C4, &APT_A::StartApplication, "StartApplication"},
{0x001C0000, &APT_A::WakeupApplication, "WakeupApplication"}, {0x001C0000, &APT_A::WakeupApplication, "WakeupApplication"},
{0x001D0000, nullptr, "CancelApplication"}, {0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, {0x001E0084, &APT_A::StartLibraryApplet, "StartLibraryApplet"},
{0x001F0084, nullptr, "StartSystemApplet"}, {0x001F0084, &APT_A::StartSystemApplet, "StartSystemApplet"},
{0x00200044, nullptr, "StartNewestHomeMenu"}, {0x00200044, nullptr, "StartNewestHomeMenu"},
{0x00210000, nullptr, "OrderToCloseApplication"}, {0x00210000, nullptr, "OrderToCloseApplication"},
{0x00220040, nullptr, "PrepareToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"},
{0x00230040, nullptr, "PrepareToJumpToApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"},
{0x00240044, nullptr, "JumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"},
{0x002500C0, &APT_A::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, {0x002500C0, &APT_A::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"},
{0x00260000, nullptr, "PrepareToCloseSystemApplet"}, {0x00260000, &APT_A::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"},
{0x00270044, &APT_A::CloseApplication, "CloseApplication"}, {0x00270044, &APT_A::CloseApplication, "CloseApplication"},
{0x00280044, &APT_A::CloseLibraryApplet, "CloseLibraryApplet"}, {0x00280044, &APT_A::CloseLibraryApplet, "CloseLibraryApplet"},
{0x00290044, nullptr, "CloseSystemApplet"}, {0x00290044, &APT_A::CloseSystemApplet, "CloseSystemApplet"},
{0x002A0000, nullptr, "OrderToCloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
{0x002C0044, nullptr, "JumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"},
@ -63,8 +63,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x00330000, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x00330000, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
{0x00340084, nullptr, "SendDeliverArg"}, {0x00340084, nullptr, "SendDeliverArg"},
{0x00350080, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"}, {0x00350080, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"},
{0x00360040, nullptr, "LoadSysMenuArg"}, {0x00360040, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"},
{0x00370042, nullptr, "StoreSysMenuArg"}, {0x00370042, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"},
{0x00380040, nullptr, "PreloadResidentApplet"}, {0x00380040, nullptr, "PreloadResidentApplet"},
{0x00390040, nullptr, "PrepareToStartResidentApplet"}, {0x00390040, nullptr, "PrepareToStartResidentApplet"},
{0x003A0044, nullptr, "StartResidentApplet"}, {0x003A0044, nullptr, "StartResidentApplet"},
@ -83,7 +83,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x00470104, &APT_A::Unwrap, "Unwrap"}, {0x00470104, &APT_A::Unwrap, "Unwrap"},
{0x00480100, nullptr, "GetProgramInfo"}, {0x00480100, nullptr, "GetProgramInfo"},
{0x00490180, nullptr, "Reboot"}, {0x00490180, nullptr, "Reboot"},
{0x004A0040, nullptr, "GetCaptureInfo"}, {0x004A0040, &APT_A::GetCaptureInfo, "GetCaptureInfo"},
{0x004B00C2, &APT_A::AppletUtility, "AppletUtility"}, {0x004B00C2, &APT_A::AppletUtility, "AppletUtility"},
{0x004C0000, nullptr, "SetFatalErrDispMode"}, {0x004C0000, nullptr, "SetFatalErrDispMode"},
{0x004D0080, nullptr, "GetAppletProgramInfo"}, {0x004D0080, nullptr, "GetAppletProgramInfo"},

View File

@ -24,7 +24,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x000C0104, &APT_S::SendParameter, "SendParameter"}, {0x000C0104, &APT_S::SendParameter, "SendParameter"},
{0x000D0080, &APT_S::ReceiveParameter, "ReceiveParameter"}, {0x000D0080, &APT_S::ReceiveParameter, "ReceiveParameter"},
{0x000E0080, &APT_S::GlanceParameter, "GlanceParameter"}, {0x000E0080, &APT_S::GlanceParameter, "GlanceParameter"},
{0x000F0100, nullptr, "CancelParameter"}, {0x000F0100, &APT_S::CancelParameter, "CancelParameter"},
{0x001000C2, nullptr, "DebugFunc"}, {0x001000C2, nullptr, "DebugFunc"},
{0x001100C0, nullptr, "MapProgramIdForDebug"}, {0x001100C0, nullptr, "MapProgramIdForDebug"},
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"}, {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
@ -34,23 +34,23 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x00160040, &APT_S::PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00160040, &APT_S::PreloadLibraryApplet, "PreloadLibraryApplet"},
{0x00170040, &APT_S::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"}, {0x00170040, &APT_S::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"},
{0x00180040, &APT_S::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, {0x00180040, &APT_S::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
{0x00190040, nullptr, "PrepareToStartSystemApplet"}, {0x00190040, &APT_S::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"},
{0x001A0000, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001A0000, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B00C4, &APT_S::StartApplication, "StartApplication"}, {0x001B00C4, &APT_S::StartApplication, "StartApplication"},
{0x001C0000, &APT_S::WakeupApplication, "WakeupApplication"}, {0x001C0000, &APT_S::WakeupApplication, "WakeupApplication"},
{0x001D0000, nullptr, "CancelApplication"}, {0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, {0x001E0084, &APT_S::StartLibraryApplet, "StartLibraryApplet"},
{0x001F0084, nullptr, "StartSystemApplet"}, {0x001F0084, &APT_S::StartSystemApplet, "StartSystemApplet"},
{0x00200044, nullptr, "StartNewestHomeMenu"}, {0x00200044, nullptr, "StartNewestHomeMenu"},
{0x00210000, nullptr, "OrderToCloseApplication"}, {0x00210000, nullptr, "OrderToCloseApplication"},
{0x00220040, nullptr, "PrepareToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"},
{0x00230040, nullptr, "PrepareToJumpToApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"},
{0x00240044, nullptr, "JumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"},
{0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, {0x002500C0, &APT_S::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"},
{0x00260000, nullptr, "PrepareToCloseSystemApplet"}, {0x00260000, &APT_S::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"},
{0x00270044, &APT_S::CloseApplication, "CloseApplication"}, {0x00270044, &APT_S::CloseApplication, "CloseApplication"},
{0x00280044, nullptr, "CloseLibraryApplet"}, {0x00280044, &APT_S::CloseLibraryApplet, "CloseLibraryApplet"},
{0x00290044, nullptr, "CloseSystemApplet"}, {0x00290044, &APT_S::CloseSystemApplet, "CloseSystemApplet"},
{0x002A0000, nullptr, "OrderToCloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
{0x002C0044, nullptr, "JumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"},
@ -62,13 +62,13 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x00320084, &APT_S::DoApplicationJump, "DoApplicationJump"}, {0x00320084, &APT_S::DoApplicationJump, "DoApplicationJump"},
{0x00330000, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x00330000, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
{0x00340084, nullptr, "SendDeliverArg"}, {0x00340084, nullptr, "SendDeliverArg"},
{0x00350080, nullptr, "ReceiveDeliverArg"}, {0x00350080, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"},
{0x00360040, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"}, {0x00360040, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"},
{0x00370042, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"}, {0x00370042, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"},
{0x00380040, nullptr, "PreloadResidentApplet"}, {0x00380040, nullptr, "PreloadResidentApplet"},
{0x00390040, nullptr, "PrepareToStartResidentApplet"}, {0x00390040, nullptr, "PrepareToStartResidentApplet"},
{0x003A0044, nullptr, "StartResidentApplet"}, {0x003A0044, nullptr, "StartResidentApplet"},
{0x003B0040, nullptr, "CancelLibraryApplet"}, {0x003B0040, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"},
{0x003C0042, nullptr, "SendDspSleep"}, {0x003C0042, nullptr, "SendDspSleep"},
{0x003D0042, nullptr, "SendDspWakeUp"}, {0x003D0042, nullptr, "SendDspWakeUp"},
{0x003E0080, nullptr, "ReplySleepQuery"}, {0x003E0080, nullptr, "ReplySleepQuery"},

View File

@ -34,23 +34,23 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x00160040, &APT_U::PreloadLibraryApplet, "PreloadLibraryApplet"}, {0x00160040, &APT_U::PreloadLibraryApplet, "PreloadLibraryApplet"},
{0x00170040, &APT_U::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"}, {0x00170040, &APT_U::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"},
{0x00180040, &APT_U::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"}, {0x00180040, &APT_U::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
{0x00190040, nullptr, "PrepareToStartSystemApplet"}, {0x00190040, &APT_U::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"},
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, {0x001A0000, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B00C4, &APT_U::StartApplication, "StartApplication"}, {0x001B00C4, &APT_U::StartApplication, "StartApplication"},
{0x001C0000, &APT_U::WakeupApplication, "WakeupApplication"}, {0x001C0000, &APT_U::WakeupApplication, "WakeupApplication"},
{0x001D0000, nullptr, "CancelApplication"}, {0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, {0x001E0084, &APT_U::StartLibraryApplet, "StartLibraryApplet"},
{0x001F0084, nullptr, "StartSystemApplet"}, {0x001F0084, &APT_U::StartSystemApplet, "StartSystemApplet"},
{0x00200044, nullptr, "StartNewestHomeMenu"}, {0x00200044, nullptr, "StartNewestHomeMenu"},
{0x00210000, nullptr, "OrderToCloseApplication"}, {0x00210000, nullptr, "OrderToCloseApplication"},
{0x00220040, nullptr, "PrepareToCloseApplication"}, {0x00220040, nullptr, "PrepareToCloseApplication"},
{0x00230040, nullptr, "PrepareToJumpToApplication"}, {0x00230040, nullptr, "PrepareToJumpToApplication"},
{0x00240044, nullptr, "JumpToApplication"}, {0x00240044, nullptr, "JumpToApplication"},
{0x002500C0, &APT_U::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, {0x002500C0, &APT_U::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"},
{0x00260000, nullptr, "PrepareToCloseSystemApplet"}, {0x00260000, &APT_U::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"},
{0x00270044, &APT_U::CloseApplication, "CloseApplication"}, {0x00270044, &APT_U::CloseApplication, "CloseApplication"},
{0x00280044, &APT_U::CloseLibraryApplet, "CloseLibraryApplet"}, {0x00280044, &APT_U::CloseLibraryApplet, "CloseLibraryApplet"},
{0x00290044, nullptr, "CloseSystemApplet"}, {0x00290044, &APT_U::CloseSystemApplet, "CloseSystemApplet"},
{0x002A0000, nullptr, "OrderToCloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"}, {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
{0x002C0044, nullptr, "JumpToHomeMenu"}, {0x002C0044, nullptr, "JumpToHomeMenu"},
@ -95,10 +95,13 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x00530104, nullptr, "Unwrap1"}, {0x00530104, nullptr, "Unwrap1"},
{0x00550040, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x00550040, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"},
{0x00560000, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x00560000, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"},
{0x00570044, nullptr, "WakeupApplication2"},
{0x00580002, nullptr, "GetProgramID"}, {0x00580002, nullptr, "GetProgramID"},
{0x01010000, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"}, {0x01010000, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"},
{0x01020000, &APT_U::CheckNew3DS, "CheckNew3DS"}, {0x01020000, &APT_U::CheckNew3DS, "CheckNew3DS"},
{0x01030000, &APT_U::Unknown0x0103, "Unknown0x0103"}, {0x01030000, &APT_U::Unknown0x0103, "Unknown0x0103"},
{0x01040000, nullptr, "IsStandardMemoryLayout"},
{0x01050100, &APT_U::IsTitleAllowed, "IsTitleAllowed"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
} }

View File

@ -1388,7 +1388,7 @@ Module::Module(Core::System& system) : system(system) {
auto archive_result = systemsavedata_factory.Open(archive_path, 0); auto archive_result = systemsavedata_factory.Open(archive_path, 0);
// If the archive didn't exist, create the files inside // If the archive didn't exist, create the files inside
if (archive_result.Code() != FileSys::ERR_NOT_FORMATTED) { if (archive_result.Code() != FileSys::ERROR_NOT_FOUND) {
ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!"); ASSERT_MSG(archive_result.Succeeded(), "Could not open the CECD SystemSaveData archive!");
cecd_system_save_data_archive = std::move(archive_result).Unwrap(); cecd_system_save_data_archive = std::move(archive_result).Unwrap();
} else { } else {

View File

@ -620,6 +620,11 @@ ResultCode Module::FormatConfig() {
if (!res.IsSuccess()) if (!res.IsSuccess())
return res; return res;
u8 unknown_data = 0;
res = CreateConfigInfoBlk(Unknown_0x000E0000, sizeof(unknown_data), 0x2, &unknown_data);
if (!res.IsSuccess())
return res;
res = CreateConfigInfoBlk(ConsoleModelBlockID, sizeof(CONSOLE_MODEL_OLD), 0xC, res = CreateConfigInfoBlk(ConsoleModelBlockID, sizeof(CONSOLE_MODEL_OLD), 0xC,
&CONSOLE_MODEL_OLD); &CONSOLE_MODEL_OLD);
if (!res.IsSuccess()) if (!res.IsSuccess())
@ -669,7 +674,7 @@ ResultCode Module::LoadConfigNANDSaveFile() {
auto archive_result = systemsavedata_factory.Open(archive_path, 0); auto archive_result = systemsavedata_factory.Open(archive_path, 0);
// If the archive didn't exist, create the files inside // If the archive didn't exist, create the files inside
if (archive_result.Code() == FileSys::ERR_NOT_FORMATTED) { if (archive_result.Code() == FileSys::ERROR_NOT_FOUND) {
// Format the archive to create the directories // Format the archive to create the directories
systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0); systemsavedata_factory.Format(archive_path, FileSys::ArchiveFormatInfo(), 0);

View File

@ -110,6 +110,7 @@ void Module::Interface::GetMyScreenName(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushRaw(screen_name); rb.PushRaw(screen_name);
rb.Push(0);
LOG_INFO(Service_FRD, "returning the username defined in cfg"); LOG_INFO(Service_FRD, "returning the username defined in cfg");
} }