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
// 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)) {
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);
if (!FileUtil::Exists(fullpath)) {
// 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);
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));

View file

@ -6,6 +6,7 @@
#include <memory>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "common/assert.h"
#include "common/common_types.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
static const u64 applet_update_interval_us = 16666;
ResultCode Applet::Create(Service::APT::AppletId id,
std::weak_ptr<Service::APT::AppletManager> manager) {
ResultCode Applet::Create(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
const std::shared_ptr<Service::APT::AppletManager>& manager) {
switch (id) {
case Service::APT::AppletId::SoftwareKeyboard1:
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;
case Service::APT::AppletId::Ed1:
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;
case Service::APT::AppletId::Error:
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;
case Service::APT::AppletId::Mint:
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;
default:
LOG_ERROR(Service_APT, "Could not create applet {}", id);
@ -68,6 +69,17 @@ ResultCode Applet::Create(Service::APT::AppletId id,
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;
}
@ -80,8 +92,8 @@ std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
/// Handles updating the current Applet every time it's called.
static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) {
Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
std::shared_ptr<Applet> applet = Applet::Get(id);
const auto id = static_cast<Service::APT::AppletId>(applet_id);
const auto applet = Applet::Get(id);
ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id={:08X}", id);
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 {
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) {
if (auto locked = manager.lock()) {
locked->CancelAndSendParameter(parameter);
@ -118,12 +138,15 @@ void Applet::SendParameter(const Service::APT::MessageParameter& parameter) {
}
}
bool IsLibraryAppletRunning() {
// Check the applets map for instances of any applet
for (auto itr = applets.begin(); itr != applets.end(); ++itr)
if (itr->second != nullptr)
return true;
return false;
void Applet::CloseApplet(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer) {
if (auto locked = manager.lock()) {
locked->PrepareToCloseLibraryApplet(true, false, false);
locked->CloseLibraryApplet(std::move(object), buffer);
} else {
LOG_ERROR(Service_APT, "called after destructing applet manager");
}
is_running = false;
}
void Init() {

View file

@ -18,10 +18,12 @@ public:
* Creates an instance of the Applet subclass identified by the parameter.
* and stores it in a global map.
* @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.
*/
static ResultCode Create(Service::APT::AppletId id,
std::weak_ptr<Service::APT::AppletManager> manager);
static ResultCode Create(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
const std::shared_ptr<Service::APT::AppletManager>& manager);
/**
* Retrieves the Applet instance identified by the specified id.
@ -35,19 +37,12 @@ public:
* @param parameter Parameter data to handle.
* @returns ResultCode Whether the operation was successful or not.
*/
virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0;
/**
* 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);
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter);
/**
* 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.
@ -55,31 +50,45 @@ public:
virtual void Update() = 0;
protected:
Applet(Service::APT::AppletId id, std::weak_ptr<Service::APT::AppletManager> manager)
: id(id), manager(std::move(manager)) {}
Applet(Service::APT::AppletId id, Service::APT::AppletId parent, bool preload,
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.
* @param parameter Parameter data to handle.
* @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 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
/// Whether this applet is currently running instead of the host application or not.
bool is_running = false;
void SendParameter(const Service::APT::MessageParameter& parameter);
void CloseApplet(std::shared_ptr<Kernel::Object> object, const std::vector<u8>& buffer);
private:
std::weak_ptr<Service::APT::AppletManager> manager;
};
/// Returns whether a library applet is currently running
bool IsLibraryAppletRunning();
/// Initializes the HLE applets
void Init();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -21,7 +21,7 @@
namespace HLE::Applets {
ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
ResultCode SoftwareKeyboard::ReceiveParameterImpl(Service::APT::MessageParameter const& parameter) {
switch (parameter.signal) {
case Service::APT::SignalType::Request: {
// 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");
// Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result;
result.signal = Service::APT::SignalType::Response;
result.buffer.clear();
result.destination_id = Service::APT::AppletId::Application;
result.sender_id = id;
result.object = framebuffer_memory;
SendParameter({
.sender_id = id,
.destination_id = parent,
.signal = Service::APT::SignalType::Response,
.object = framebuffer_memory,
});
SendParameter(result);
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),
"The size of the parameter (SoftwareKeyboardConfig) is wrong");
@ -151,14 +150,16 @@ void SoftwareKeyboard::Update() {
config.text_offset = 0;
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
Service::APT::MessageParameter message;
message.buffer.resize(sizeof(SoftwareKeyboardConfig));
std::memcpy(message.buffer.data(), &config, message.buffer.size());
message.signal = Service::APT::SignalType::Message;
message.destination_id = Service::APT::AppletId::Application;
message.sender_id = id;
SendParameter(message);
SendParameter({
.sender_id = id,
.destination_id = parent,
.signal = Service::APT::SignalType::Message,
.buffer = buffer,
});
} else {
Finalize();
}
@ -168,18 +169,12 @@ void SoftwareKeyboard::DrawScreenKeyboard() {
// TODO(Subv): Draw the HLE keyboard, for now just do nothing
}
void SoftwareKeyboard::Finalize() {
// Let the application know that we're closing
Service::APT::MessageParameter message;
message.buffer.resize(sizeof(SoftwareKeyboardConfig));
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;
ResultCode SoftwareKeyboard::Finalize() {
std::vector<u8> buffer(sizeof(SoftwareKeyboardConfig));
std::memcpy(buffer.data(), &config, buffer.size());
CloseApplet(nullptr, buffer);
text_memory = nullptr;
return RESULT_SUCCESS;
}
Frontend::KeyboardConfig SoftwareKeyboard::ToFrontendConfig(

View file

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

View file

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

View file

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

View file

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/applets/applet.h"
#include "core/hle/service/am/am.h"
@ -14,8 +15,6 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager)
namespace Service::APT {
enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 };
struct AppletTitleData {
// There are two possible applet ids for each applet.
std::array<AppletId, 2> applet_ids;
@ -23,6 +22,7 @@ struct AppletTitleData {
// There's a specific TitleId per region for each applet.
static constexpr std::size_t NumRegions = 7;
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;
@ -44,7 +44,8 @@ static constexpr std::array<AppletTitleData, NumApplets> applet_titleids = {{
0x400300000AD02, 0x400300000B502}},
{{AppletId::InternetBrowser, AppletId::None},
{0x4003000008802, 0x4003000009402, 0x4003000009D02, 0x4003000008802, 0x400300000A602,
0x400300000AE02, 0x400300000B602}},
0x400300000AE02, 0x400300000B602},
{0x4003020008802, 0x4003020009402, 0x4003020009D02, 0x4003020008802, 0, 0x400302000AE02, 0}},
{{AppletId::InstructionManual, AppletId::None},
{0x4003000008602, 0x4003000009202, 0x4003000009B02, 0x4003000008602, 0x400300000A402,
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);
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];
}
AppletManager::AppletSlotData* AppletManager::GetAppletSlotData(AppletId id) {
auto GetSlot = [this](AppletSlot slot) -> AppletSlotData* {
return &applet_slots[static_cast<std::size_t>(slot)];
};
AppletManager::AppletSlot AppletManager::GetAppletSlotFromId(AppletId id) {
if (id == AppletId::Application) {
auto* slot = GetSlot(AppletSlot::Application);
if (slot->applet_id != AppletId::None)
return slot;
if (GetAppletSlot(AppletSlot::Application)->applet_id != AppletId::None)
return AppletSlot::Application;
return nullptr;
return AppletSlot::Error;
}
if (id == AppletId::AnySystemApplet) {
auto* system_slot = GetSlot(AppletSlot::SystemApplet);
if (system_slot->applet_id != AppletId::None)
return system_slot;
if (GetAppletSlot(AppletSlot::SystemApplet)->applet_id != AppletId::None)
return AppletSlot::SystemApplet;
// 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.
auto* home_slot = GetSlot(AppletSlot::HomeMenu);
if (home_slot->applet_id != AppletId::None)
return home_slot;
if (GetAppletSlot(AppletSlot::HomeMenu)->applet_id != AppletId::None)
return AppletSlot::HomeMenu;
return nullptr;
return AppletSlot::Error;
}
if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) {
auto* slot = GetSlot(AppletSlot::LibraryApplet);
if (slot->applet_id == AppletId::None)
return nullptr;
auto slot_data = GetAppletSlot(AppletSlot::LibraryApplet);
if (slot_data->applet_id == AppletId::None)
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 slot;
if (id == AppletId::AnySysLibraryApplet &&
applet_pos == static_cast<u32>(AppletPos::SysLibrary))
return slot;
return nullptr;
return AppletSlot::Error;
}
if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) {
auto* slot = GetSlot(AppletSlot::HomeMenu);
if (slot->applet_id != AppletId::None)
return slot;
if (GetAppletSlot(AppletSlot::HomeMenu)->applet_id != AppletId::None)
return AppletSlot::HomeMenu;
return nullptr;
return AppletSlot::Error;
}
for (auto& slot : applet_slots) {
if (slot.applet_id == id)
return &slot;
for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) {
if (applet_slots[slot].applet_id == id) {
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
static constexpr std::array<AppletSlot, 6> applet_position_slots = {
AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet,
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())
return nullptr;
AppletSlot slot = applet_position_slots[applet_pos];
return AppletSlot::Error;
auto slot = applet_position_slots[applet_pos];
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
// concurrently with other system applets.
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) {
next_parameter = parameter;
// Signal the event to let the receiver know that a new parameter is ready to be read
auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id));
if (slot_data == nullptr) {
LOG_DEBUG(Service_APT, "No applet was registered with the id {:03X}",
parameter.destination_id);
return;
}
LOG_DEBUG(
Service_APT, "Sending parameter from {:03X} to {:03X} with signal {:08X} and size {:08X}",
parameter.sender_id, parameter.destination_id, parameter.signal, parameter.buffer.size());
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) {
// A new parameter can not be sent if the previous one hasn't been consumed yet
if (next_parameter) {
return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
LOG_WARNING(Service_APT, "Parameter from {:03X} to {:03X} blocked by pending parameter.",
parameter.sender_id, parameter.destination_id);
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
CancelAndSendParameter(parameter);
if (auto dest_applet = HLE::Applets::Applet::Get(parameter.destination_id)) {
return dest_applet->ReceiveParameter(parameter);
} else {
return RESULT_SUCCESS;
}
return RESULT_SUCCESS;
}
ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) {
@ -224,7 +247,7 @@ ResultVal<MessageParameter> AppletManager::GlanceParameter(AppletId app_id) {
ErrorLevel::Status);
}
MessageParameter parameter = *next_parameter;
auto parameter = *next_parameter;
// Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter.
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,
AppletId receiver_appid) {
bool cancellation_success = true;
if (!next_parameter) {
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;
}
auto cancellation_success =
next_parameter && (!check_sender || next_parameter->sender_id == sender_appid) &&
(!check_receiver || next_parameter->destination_id == receiver_appid);
if (cancellation_success)
next_parameter = {};
@ -264,43 +279,57 @@ bool AppletManager::CancelParameter(bool check_sender, AppletId sender_appid, bo
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,
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
// 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) {
LOG_WARNING(Service_APT, "Applet attempted to register in occupied slot {:02X}", slot);
return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
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);
// Note: In the real console the title id of a given applet slot is set by the APT module when
// calling StartApplication.
slot_data->title_id = system.Kernel().GetCurrentProcess()->codeset->program_id;
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
// sent by the Home Menu after starting the app by way of APT::WakeupApplication. In some cases
// such as when starting a game directly or the Home Menu itself, we have to send the signal
// ourselves since the Home Menu is not running yet. We detect if the Home Menu is running by
// checking if there's an applet registered in the HomeMenu slot.
if (slot_data->applet_id == AppletId::HomeMenu ||
(slot_data->applet_id == AppletId::Application && !home_menu_slot)) {
// Initialize the APT parameter to wake up the application.
next_parameter.emplace();
next_parameter->signal = SignalType::Wakeup;
next_parameter->sender_id = AppletId::None;
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();
// sent by the Home Menu after starting the app by way of APT::WakeupApplication. However,
// if nothing is running yet the signal should be sent by APT::Initialize itself.
if (active_slot == AppletSlot::Error) {
active_slot = slot;
// Wake up the application.
SendParameter({
.sender_id = AppletId::None,
.destination_id = app_id,
.signal = SignalType::Wakeup,
});
}
return MakeResult<InitializeResult>(
@ -308,17 +337,23 @@ ResultVal<AppletManager::InitializeResult> AppletManager::Initialize(AppletId ap
}
ResultCode AppletManager::Enable(AppletAttributes attributes) {
auto* const slot_data = GetAppletSlotData(attributes);
if (!slot_data) {
return ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
auto slot = GetAppletSlotFromAttributes(attributes);
if (slot == AppletSlot::Error) {
LOG_WARNING(Service_APT,
"Attempted to register with attributes {:08X}, but could not find slot.",
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;
// Send any outstanding parameters to the newly-registered application
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);
delayed_parameter.reset();
}
@ -327,42 +362,29 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) {
}
bool AppletManager::IsRegistered(AppletId app_id) {
const auto* slot_data = GetAppletSlotData(app_id);
// 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;
auto slot = GetAppletSlotFromId(app_id);
return slot != AppletSlot::Error && GetAppletSlot(slot)->registered;
}
ResultCode AppletManager::PrepareToStartLibraryApplet(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 ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
const auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)];
if (slot.registered) {
return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
if (GetAppletSlot(AppletSlot::LibraryApplet)->registered) {
return {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);
u32 region_value = cfg->GetRegionValue();
auto process =
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, region_value));
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
if (process) {
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.
auto applet = HLE::Applets::Applet::Get(applet_id);
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;
} 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) {
const auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)];
if (slot.registered) {
return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
if (GetAppletSlot(AppletSlot::LibraryApplet)->registered) {
return {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);
u32 region_value = cfg->GetRegionValue();
auto process =
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, region_value));
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
if (process) {
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);
return RESULT_SUCCESS;
} 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) {
// TODO(Subv): This function should fail depending on the applet preparation state.
auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)];
slot.loaded = true;
GetAppletSlot(AppletSlot::LibraryApplet)->loaded = true;
return RESULT_SUCCESS;
}
ResultCode AppletManager::StartLibraryApplet(AppletId applet_id,
std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer) {
MessageParameter param;
param.destination_id = applet_id;
param.sender_id = AppletId::Application;
param.object = object;
param.signal = SignalType::Wakeup;
param.buffer = buffer;
CancelAndSendParameter(param);
active_slot = AppletSlot::LibraryApplet;
// In case the applet is being HLEd, attempt to communicate with it.
if (auto applet = HLE::Applets::Applet::Get(applet_id)) {
AppletStartupParameter parameter;
parameter.object = object;
parameter.buffer = buffer;
return applet->Start(parameter);
} else {
return RESULT_SUCCESS;
auto send_res = SendParameter({
.sender_id = GetAppletSlotId(last_library_launcher_slot),
.destination_id = applet_id,
.signal = SignalType::Wakeup,
.object = std::move(object),
.buffer = buffer,
});
if (send_res.IsError()) {
active_slot = last_library_launcher_slot;
return send_res;
}
return RESULT_SUCCESS;
}
ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiting,
bool jump_home) {
if (next_parameter) {
return ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status);
return {ErrCodes::ParameterPresent, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
if (!not_pause)
@ -452,57 +475,151 @@ ResultCode AppletManager::PrepareToCloseLibraryApplet(bool not_pause, bool exiti
}
ResultCode AppletManager::CloseLibraryApplet(std::shared_ptr<Kernel::Object> object,
std::vector<u8> buffer) {
auto& slot = applet_slots[static_cast<std::size_t>(AppletSlot::LibraryApplet)];
const std::vector<u8>& buffer) {
auto slot = GetAppletSlot(AppletSlot::LibraryApplet);
auto destination_id = GetAppletSlotId(last_library_launcher_slot);
MessageParameter param;
// 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);
active_slot = last_library_launcher_slot;
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) {
// TODO(Subv): Terminate the running applet title
slot.Reset();
CancelAndSendParameter(param);
// 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) {
const auto* slot = GetAppletSlotData(app_id);
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)");
auto slot = GetAppletSlotFromId(app_id);
if (slot == AppletSlot::Error) {
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
ErrorLevel::Status);
}
auto cfg = Service::CFG::GetModule(system);
ASSERT_MSG(cfg, "CFG Module missing!");
u32 region_value = cfg->GetRegionValue();
return MakeResult<AppletInfo>({GetTitleIdForApplet(app_id, region_value),
Service::FS::MediaType::NAND, slot->registered, slot->loaded,
slot->attributes.raw});
auto slot_data = GetAppletSlot(slot);
if (!slot_data->registered) {
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
ErrorLevel::Status);
}
// 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,
@ -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
// 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,
"Unimplemented application jump flags 1");
if (flags == ApplicationJumpFlags::UseCurrentParameters) {
title_id = application_slot.title_id;
}
app_jump_parameters.current_title_id = application_slot.title_id;
// Save the title data to send it to the Home Menu when DoApplicationJump is called.
auto application_slot_data = GetAppletSlot(AppletSlot::Application);
app_jump_parameters.current_title_id = application_slot_data->title_id;
// TODO(Subv): Retrieve the correct media type of the currently-running application. For now
// just assume 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.flags = flags;
@ -535,29 +649,29 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType
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
// 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
// running to do this, otherwise error 0xC8A0CFF0 is returned.
auto& application_slot = applet_slots[static_cast<size_t>(AppletSlot::Application)];
if (app_jump_parameters.flags != ApplicationJumpFlags::UseCurrentParameters) {
// The source program ID is not updated when using flags 0x2.
arg.source_program_id = application_slot.title_id;
}
application_slot.Reset();
auto application_slot_data = GetAppletSlot(AppletSlot::Application);
auto title_id = application_slot_data->title_id;
application_slot_data->Reset();
// 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.
// Note: The real console sends signal 17 (WakeupToLaunchApplication) to the Home Menu, this
// prompts it to call GetProgramIdOnApplicationJump and
// PrepareToStartApplication/StartApplication on the title to launch.
active_slot = AppletSlot::Application;
// 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
@ -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
// based only on the title id.
std::string new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type,
app_jump_parameters.next_title_id);
auto new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type,
app_jump_parameters.next_title_id);
if (new_path.empty() || !FileUtil::Exists(new_path)) {
LOG_CRITICAL(
Service_APT,
@ -594,16 +708,17 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) {
}
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 not.
if (active_slot == AppletSlot::Error ||
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
const auto& application_slot = applet_slots[static_cast<size_t>(AppletSlot::Application)];
if (application_slot.registered) {
// TODO(Subv): Convert this to the enum constructor of ResultCode
return ResultCode(0xc8a0cffc);
if (GetAppletSlot(AppletSlot::Application)->registered) {
return {ErrorDescription::AlreadyExists, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Status};
}
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.
ASSERT_MSG(app_start_parameters, "Trying to start an application without preparing it first.");
active_slot = AppletSlot::Application;
// Launch the title directly.
const auto process =
auto process =
NS::LaunchTitle(app_start_parameters->next_media_type, app_start_parameters->next_title_id);
if (!process) {
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() {
// 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.
MessageParameter wakeup_parameter{};
wakeup_parameter.signal = SignalType::Wakeup;
wakeup_parameter.sender_id = AppletId::HomeMenu;
wakeup_parameter.destination_id = AppletId::Application;
SendApplicationParameterAfterRegistration(wakeup_parameter);
SendApplicationParameterAfterRegistration({.sender_id = AppletId::HomeMenu,
.destination_id = AppletId::Application,
.signal = SignalType::Wakeup});
return RESULT_SUCCESS;
}
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 (slot && slot->registered) {
if (slot != AppletSlot::Error && GetAppletSlot(slot)->registered) {
CancelAndSendParameter(parameter);
return;
}
@ -677,22 +792,20 @@ void AppletManager::SendApplicationParameterAfterRegistration(const MessageParam
}
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
// 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 (menu_slot.registered) {
if (GetAppletSlot(AppletSlot::HomeMenu)->registered) {
// The Home Menu is already running.
return;
}
auto cfg = Service::CFG::GetModule(system);
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);
if (!process) {
LOG_WARNING(Service_APT,
@ -701,6 +814,7 @@ void AppletManager::EnsureHomeMenuLoaded() {
}
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) {
auto& slot_data = applet_slots[slot];
slot_data.slot = static_cast<AppletSlot>(slot);

View file

@ -103,10 +103,13 @@ private:
friend class boost::serialization::access;
};
/// Holds information about the parameters used in StartLibraryApplet
struct AppletStartupParameter {
std::shared_ptr<Kernel::Object> object = nullptr;
std::vector<u8> buffer;
enum class AppletPos {
Application = 0,
Library = 1,
System = 2,
SysLibrary = 3,
Resident = 4,
AutoLibrary = 5
};
union AppletAttributes {
@ -125,6 +128,56 @@ enum class ApplicationJumpFlags : u8 {
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> {
public:
explicit AppletManager(Core::System& system);
@ -142,41 +195,42 @@ public:
bool CancelParameter(bool check_sender, AppletId sender_appid, bool check_receiver,
AppletId receiver_appid);
struct GetLockHandleResult {
AppletAttributes corrected_attributes;
u32 state;
std::shared_ptr<Kernel::Mutex> lock;
};
ResultVal<GetLockHandleResult> GetLockHandle(AppletAttributes attributes);
struct InitializeResult {
std::shared_ptr<Kernel::Event> notification_event;
std::shared_ptr<Kernel::Event> parameter_event;
};
ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes);
ResultCode Enable(AppletAttributes attributes);
bool IsRegistered(AppletId app_id);
ResultCode PrepareToStartLibraryApplet(AppletId applet_id);
ResultCode PreloadLibraryApplet(AppletId applet_id);
ResultCode FinishPreloadingLibraryApplet(AppletId applet_id);
ResultCode StartLibraryApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer);
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,
ApplicationJumpFlags flags);
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);
ResultCode DoApplicationJump(const DeliverArg& arg);
boost::optional<DeliverArg> ReceiveDeliverArg() const {
return deliver_arg;
@ -197,49 +251,16 @@ public:
bool loaded;
u32 attributes;
};
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 {
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:
/// APT lock retrieved via GetLockHandle.
std::shared_ptr<Kernel::Mutex> lock;
/// Parameter data to be returned in the next call to Glance/ReceiveParameter.
// NOTE: A bug in gcc prevents serializing std::optional
boost::optional<MessageParameter> next_parameter;
@ -248,6 +269,10 @@ private:
/// APT::Initialize.
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;
enum class AppletSlot : u8 {
@ -292,16 +317,28 @@ private:
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.
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.
AppletSlotData* GetAppletSlotData(AppletId id);
AppletSlotData* GetAppletSlotData(AppletAttributes attributes);
AppletSlot last_library_launcher_slot = AppletSlot::Error;
SignalType library_applet_closing_command = SignalType::None;
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,
/// otherwise it queues for sending when the application registers itself with APT::Enable.
@ -309,12 +346,6 @@ private:
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>
void serialize(Archive& ar, const unsigned int file_version) {
ar& next_parameter;
@ -323,6 +354,11 @@ private:
ar& delayed_parameter;
ar& app_start_parameters;
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& library_applet_closing_command;
@ -332,7 +368,7 @@ private:
} // 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)
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_loaded;
ar& shared_font_relocated;
ar& lock;
ar& cpu_percent;
ar& unknown_ns_state_field;
ar& screen_capture_buffer;
@ -63,8 +62,8 @@ std::shared_ptr<Module> Module::NSInterface::GetModule() const {
void Module::NSInterface::SetWirelessRebootInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x06, 1, 2); // 0x00060042
u32 size = rp.Pop<u32>();
auto buffer = rp.PopStaticBuffer();
const auto size = rp.Pop<u32>();
const auto buffer = rp.PopStaticBuffer();
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) {
IPC::RequestParser rp(ctx, 0x2, 2, 0); // 0x20080
AppletId app_id = rp.PopEnum<AppletId>();
u32 attributes = rp.Pop<u32>();
const auto app_id = rp.PopEnum<AppletId>();
const auto attributes = rp.Pop<u32>();
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);
rb.Push(result.Code());
} else {
auto events = std::move(result).Unwrap();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
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() {
u8 font_region_code;
auto cfg = Service::CFG::GetModule(system);
ASSERT_MSG(cfg, "CFG Module missing!");
u8 font_region_code;
switch (cfg->GetRegionValue()) {
case 4: // CHN
font_region_code = 2;
@ -279,7 +278,7 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx) {
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);
@ -290,9 +289,11 @@ void Module::APTInterface::GetWirelessRebootInfo(Kernel::HLERequestContext& ctx)
void Module::APTInterface::NotifyToWait(Kernel::HLERequestContext& ctx) {
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);
rb.Push(RESULT_SUCCESS); // No error
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)
// Bit 5 tells the application that there's a pending APT parameter,
// this will cause the app to wait until parameter_event is signaled.
u32 applet_attributes = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
rb.Push(RESULT_SUCCESS); // No error
const auto attributes = rp.Pop<u32>();
// TODO(Subv): The output attributes should have an AppletPos of either Library or System |
// Library (depending on the type of the last launched applet) if the input attributes'
// AppletPos has the Library bit set.
LOG_DEBUG(Service_APT, "called applet_attributes={:#010X}", attributes);
rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable.
rb.Push<u32>(0); // Least significant bit = power button state
rb.PushCopyObjects(apt->lock);
LOG_WARNING(Service_APT, "(STUBBED) called applet_attributes={:#010X}", applet_attributes);
auto result = apt->applet_manager->GetLockHandle(attributes);
if (result.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(result.Code());
} 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) {
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);
@ -329,7 +332,8 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
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);
rb.Push(RESULT_SUCCESS); // No error
rb.Push<u32>(0);
@ -342,7 +346,8 @@ void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
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);
rb.Push(RESULT_SUCCESS); // No error
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) {
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);
rb.Push(RESULT_SUCCESS); // No error
rb.Push(static_cast<u32>(SignalType::None)); // Signal type
LOG_WARNING(Service_APT, "(STUBBED) called app_id={:#010X}", app_id);
}
void Module::APTInterface::SendParameter(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0xC, 4, 4); // 0xC0104
AppletId src_app_id = rp.PopEnum<AppletId>();
AppletId dst_app_id = rp.PopEnum<AppletId>();
SignalType signal_type = rp.PopEnum<SignalType>();
u32 buffer_size = rp.Pop<u32>();
std::shared_ptr<Kernel::Object> object = rp.PopGenericObject();
std::vector<u8> buffer = rp.PopStaticBuffer();
const auto src_app_id = rp.PopEnum<AppletId>();
const auto dst_app_id = rp.PopEnum<AppletId>();
const auto signal_type = rp.PopEnum<SignalType>();
const auto buffer_size = rp.Pop<u32>();
const auto object = rp.PopGenericObject();
const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT,
"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);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
MessageParameter param;
param.destination_id = dst_app_id;
param.sender_id = src_app_id;
param.object = std::move(object);
param.signal = signal_type;
param.buffer = std::move(buffer);
rb.Push(apt->applet_manager->SendParameter(param));
rb.Push(apt->applet_manager->SendParameter({
.sender_id = src_app_id,
.destination_id = dst_app_id,
.signal = signal_type,
.object = object,
.buffer = buffer,
}));
}
void Module::APTInterface::ReceiveParameter(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0xD, 2, 0); // 0xD0080
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);
auto next_parameter = apt->applet_manager->ReceiveParameter(app_id);
if (next_parameter.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
@ -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);
auto next_parameter = apt->applet_manager->GlanceParameter(app_id);
if (next_parameter.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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
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);
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);
}
}
void Module::APTInterface::CancelParameter(Kernel::HLERequestContext& ctx) {
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>();
AppletId sender_appid = rp.PopEnum<AppletId>();
bool check_receiver = rp.Pop<bool>();
AppletId receiver_appid = rp.PopEnum<AppletId>();
LOG_DEBUG(
Service_APT,
"called check_sender={}, sender_appid={:#010X}, check_receiver={}, receiver_appid={:#010X}",
check_sender, sender_appid, check_receiver, receiver_appid);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error
rb.Push(apt->applet_manager->CancelParameter(check_sender, sender_appid, check_receiver,
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) {
@ -464,8 +466,8 @@ void Module::APTInterface::PrepareToDoApplicationJump(Kernel::HLERequestContext&
u64 title_id = rp.Pop<u64>();
u8 media_type = rp.Pop<u8>();
LOG_WARNING(Service_APT, "(STUBBED) called title_id={:016X}, media_type={:#01X}, flags={:#08X}",
title_id, media_type, flags);
LOG_INFO(Service_APT, "called title_id={:016X}, media_type={:#01X}, flags={:#08X}", title_id,
media_type, flags);
ResultCode result = apt->applet_manager->PrepareToDoApplicationJump(
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) {
IPC::RequestParser rp(ctx, 0x32, 2, 4); // 0x00320084
auto param_size = rp.Pop<u32>();
auto hmac_size = rp.Pop<u32>();
constexpr u32 max_param_size{0x300};
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();
const auto param_size = rp.Pop<u32>();
const auto hmac_size = rp.Pop<u32>();
const auto param = rp.PopStaticBuffer();
const auto hmac = rp.PopStaticBuffer();
LOG_INFO(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->DoApplicationJump(
AppletManager::DeliverArg{std::move(param), std::move(hmac)}));
rb.Push(apt->applet_manager->DoApplicationJump(DeliverArg{param, hmac}));
}
void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx) {
@ -509,7 +494,7 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte
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);
rb.Push(RESULT_SUCCESS);
@ -520,13 +505,13 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte
}
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 hmac_size = rp.Pop<u32>();
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.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) {
IPC::RequestParser rp(ctx, 0x15, 5, 0); // 0x00150140
const u64 title_id = rp.Pop<u64>();
const auto media_type = rp.PopEnum<FS::MediaType>();
const auto title_id = rp.Pop<u64>();
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Padding
const u32 flags = rp.Pop<u32>();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->PrepareToStartApplication(title_id, media_type));
const auto flags = rp.Pop<u32>();
LOG_INFO(Service_APT, "called title_id={:#010X} media_type={} flags={:#010X}", title_id,
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) {
IPC::RequestParser rp(ctx, 0x1B, 3, 4); // 0x001B00C4
const u32 parameter_size = rp.Pop<u32>();
const u32 hmac_size = rp.Pop<u32>();
const bool paused = rp.Pop<bool>();
const std::vector<u8> parameter = rp.PopStaticBuffer();
const std::vector<u8> hmac = rp.PopStaticBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->StartApplication(parameter, hmac, paused));
const auto parameter_size = rp.Pop<u32>();
const auto hmac_size = rp.Pop<u32>();
const auto paused = rp.Pop<bool>();
const auto parameter = rp.PopStaticBuffer();
const auto hmac = rp.PopStaticBuffer();
LOG_INFO(Service_APT, "called parameter_size={:#010X}, hmac_size={:#010X}, 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) {
IPC::RequestParser rp(ctx, 0x1C, 0, 0); // 0x001C0000
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->WakeupApplication());
LOG_DEBUG(Service_APT, "called");
}
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 input_size = rp.Pop<u32>();
const auto output_size = rp.Pop<u32>();
[[maybe_unused]] const std::vector<u8> input = rp.PopStaticBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error
[[maybe_unused]] const auto input = rp.PopStaticBuffer();
LOG_WARNING(Service_APT,
"(STUBBED) called command={:#010X}, input_size={:#010X}, output_size={:#010X}",
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) {
IPC::RequestParser rp(ctx, 0x4F, 2, 0); // 0x4F0080
u32 value = rp.Pop<u32>();
apt->cpu_percent = rp.Pop<u32>();
const auto must_be_one = rp.Pop<u32>();
const auto value = rp.Pop<u32>();
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually {}!", value);
LOG_WARNING(Service_APT, "(STUBBED) called, must_be_one={}, value={}", must_be_one, 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);
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) {
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_ERROR(Service_APT, "This value should be one, but is actually {}!", value);
LOG_WARNING(Service_APT, "(STUBBED) called, must_be_one={}", must_be_one);
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);
rb.Push(RESULT_SUCCESS); // No error
rb.Push(apt->cpu_percent);
LOG_WARNING(Service_APT, "(STUBBED) called, value={}", value);
}
void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext& ctx) {
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);
@ -633,23 +618,33 @@ void Module::APTInterface::PrepareToStartLibraryApplet(Kernel::HLERequestContext
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) {
IPC::RequestParser rp(ctx, 0x1A, 0, 0); // 0x1A0000
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).
// This command must return an error when called, otherwise the Home Menu will try to reboot the
// system.
rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet,
ErrorSummary::InvalidState, ErrorLevel::Status));
LOG_DEBUG(Service_APT, "called");
}
void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx) {
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);
@ -659,7 +654,7 @@ void Module::APTInterface::PreloadLibraryApplet(Kernel::HLERequestContext& ctx)
void Module::APTInterface::FinishPreloadingLibraryApplet(Kernel::HLERequestContext& ctx) {
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);
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) {
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>();
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);
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->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) {
IPC::RequestParser rp(ctx, 0x27, 1, 4);
[[maybe_unused]] const u32 parameters_size = rp.Pop<u32>();
[[maybe_unused]] const std::shared_ptr<Kernel::Object> object = rp.PopGenericObject();
[[maybe_unused]] const std::vector<u8> buffer = rp.PopStaticBuffer();
[[maybe_unused]] const auto parameters_size = rp.Pop<u32>();
[[maybe_unused]] const auto object = rp.PopGenericObject();
[[maybe_unused]] const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called");
@ -697,19 +704,19 @@ void Module::APTInterface::CloseApplication(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::CancelLibraryApplet(Kernel::HLERequestContext& ctx) {
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);
rb.Push<u32>(1); // TODO: Find the return code meaning
LOG_WARNING(Service_APT, "(STUBBED) called exiting={}", exiting);
rb.Push(apt->applet_manager->CancelLibraryApplet(app_exiting));
}
void Module::APTInterface::PrepareToCloseLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x25, 3, 0); // 0x002500C0
bool not_pause = rp.Pop<bool>();
bool exiting = rp.Pop<bool>();
bool jump_to_home = rp.Pop<bool>();
const auto not_pause = rp.Pop<bool>();
const auto exiting = 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,
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));
}
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) {
IPC::RequestParser rp(ctx, 0x28, 1, 4); // 0x00280044
u32 parameter_size = rp.Pop<u32>();
auto object = rp.PopGenericObject();
std::vector<u8> buffer = rp.PopStaticBuffer();
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->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) {
IPC::RequestParser rp(ctx, 0x36, 1, 0); // 0x00360040
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::copy_n(apt->sys_menu_arg_buffer.cbegin(), size, buffer.begin());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS);
rb.PushStaticBuffer(std::move(buffer), 0);
LOG_DEBUG(Service_APT, "called");
}
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& buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called");
ASSERT_MSG(buffer.size() >= size, "Buffer too small to hold requested data");
std::copy_n(buffer.cbegin(), size, apt->sys_menu_arg_buffer.begin());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
LOG_DEBUG(Service_APT, "called");
}
void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx) {
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);
apt->screen_capture_buffer = rp.PopStaticBuffer();
apt->screen_capture_buffer = buffer;
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
@ -773,7 +803,10 @@ void Module::APTInterface::SendCaptureBufferInfo(Kernel::HLERequestContext& ctx)
void Module::APTInterface::ReceiveCaptureBufferInfo(Kernel::HLERequestContext& ctx) {
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);
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) {
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);
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) {
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);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
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) {
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);
rb.Push(RESULT_SUCCESS); // No error
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) {
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);
if (info.Failed()) {
@ -838,20 +875,11 @@ void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x51, 2, 0); // 0x00510080
u32 parameter_size = rp.Pop<u32>();
constexpr u32 max_parameter_size{0x1000};
const auto parameter_size = rp.Pop<u32>();
const auto startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>());
LOG_WARNING(Service_APT, "called, startup_argument_type={}, parameter_size={:#010X}",
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;
}
LOG_INFO(Service_APT, "called, startup_argument_type={}, parameter_size={:#010X}",
startup_argument_type, parameter_size);
std::vector<u8> param;
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);
rb.Push(RESULT_SUCCESS);
@ -887,13 +916,17 @@ void Module::APTInterface::GetStartupArgument(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x46, 4, 4);
const u32 output_size = rp.Pop<u32>();
const u32 input_size = rp.Pop<u32>();
const u32 nonce_offset = rp.Pop<u32>();
u32 nonce_size = rp.Pop<u32>();
const auto output_size = rp.Pop<u32>();
const auto input_size = rp.Pop<u32>();
const auto nonce_offset = rp.Pop<u32>();
auto nonce_size = rp.Pop<u32>();
auto& input = rp.PopMappedBuffer();
ASSERT(input.GetSize() == input_size);
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);
// 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,
"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
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);
rb.Push(RESULT_SUCCESS);
// Unmap buffer
rb.PushMappedBuffer(input);
rb.PushMappedBuffer(output);
@ -932,13 +961,17 @@ void Module::APTInterface::Wrap(Kernel::HLERequestContext& ctx) {
void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x47, 4, 4);
const u32 output_size = rp.Pop<u32>();
const u32 input_size = rp.Pop<u32>();
const u32 nonce_offset = rp.Pop<u32>();
u32 nonce_size = rp.Pop<u32>();
const auto output_size = rp.Pop<u32>();
const auto input_size = rp.Pop<u32>();
const auto nonce_offset = rp.Pop<u32>();
auto nonce_size = rp.Pop<u32>();
auto& input = rp.PopMappedBuffer();
ASSERT(input.GetSize() == input_size);
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);
// 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,
"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
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) {
IPC::RequestParser rp(ctx, 0x101, 0, 0); // 0x01010000
LOG_WARNING(Service_APT, "(STUBBED) called");
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (apt->unknown_ns_state_field) {
rb.Push(RESULT_SUCCESS);
@ -991,41 +1023,39 @@ void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) {
} else {
PTM::CheckNew3DS(rb);
}
LOG_WARNING(Service_APT, "(STUBBED) called");
}
void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x102, 0, 0); // 0x01020000
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
PTM::CheckNew3DS(rb);
LOG_WARNING(Service_APT, "(STUBBED) called");
PTM::CheckNew3DS(rb);
}
void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x103, 0, 0); // 0x01030000
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
LOG_WARNING(Service_APT, "(STUBBED) called");
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(Settings::values.is_new_3ds ? 2 : 1);
LOG_WARNING(Service_APT, "(STUBBED) called");
}
void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x105, 4, 0); // 0x01050100
const u64 program_id = rp.Pop<u64>();
const auto media_type = rp.PopEnum<FS::MediaType>();
const auto program_id = rp.Pop<u64>();
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
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
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS);
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)
@ -1046,8 +1076,6 @@ Module::Module(Core::System& system) : system(system) {
MemoryPermission::ReadWrite, MemoryPermission::Read,
0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont")
.Unwrap();
lock = system.Kernel().CreateMutex(false, "APT_U:Lock");
}
Module::~Module() {}

View file

@ -416,6 +416,17 @@ public:
*/
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
* Inputs:
@ -464,6 +475,22 @@ public:
*/
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
* Inputs:
@ -562,6 +589,16 @@ public:
*/
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
* Inputs:
@ -577,6 +614,21 @@ public:
*/
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
* Inputs:
@ -744,8 +796,6 @@ private:
bool shared_font_loaded = false;
bool shared_font_relocated = false;
std::shared_ptr<Kernel::Mutex> lock;
u32 cpu_percent = 0; ///< CPU time available to the running application
// 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"},
{0x00150140, &APT_A::PrepareToStartApplication, "PrepareToStartApplication"},
{0x00160040, &APT_A::PreloadLibraryApplet, "PreloadLibraryApplet"},
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
{0x00170040, &APT_A::FinishPreloadingLibraryApplet, "FinishPreloadingLibraryApplet"},
{0x00180040, &APT_A::PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
{0x00190040, &APT_A::PrepareToStartSystemApplet, "PrepareToStartSystemApplet"},
{0x001A0000, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B00C4, &APT_A::StartApplication, "StartApplication"},
{0x001C0000, &APT_A::WakeupApplication, "WakeupApplication"},
{0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, &APT_A::StartLibraryApplet, "StartLibraryApplet"},
{0x001F0084, nullptr, "StartSystemApplet"},
{0x001F0084, &APT_A::StartSystemApplet, "StartSystemApplet"},
{0x00200044, nullptr, "StartNewestHomeMenu"},
{0x00210000, nullptr, "OrderToCloseApplication"},
{0x00220040, nullptr, "PrepareToCloseApplication"},
{0x00230040, nullptr, "PrepareToJumpToApplication"},
{0x00240044, nullptr, "JumpToApplication"},
{0x002500C0, &APT_A::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"},
{0x00260000, nullptr, "PrepareToCloseSystemApplet"},
{0x00260000, &APT_A::PrepareToCloseSystemApplet, "PrepareToCloseSystemApplet"},
{0x00270044, &APT_A::CloseApplication, "CloseApplication"},
{0x00280044, &APT_A::CloseLibraryApplet, "CloseLibraryApplet"},
{0x00290044, nullptr, "CloseSystemApplet"},
{0x00290044, &APT_A::CloseSystemApplet, "CloseSystemApplet"},
{0x002A0000, nullptr, "OrderToCloseSystemApplet"},
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
{0x002C0044, nullptr, "JumpToHomeMenu"},
@ -63,8 +63,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x00330000, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
{0x00340084, nullptr, "SendDeliverArg"},
{0x00350080, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"},
{0x00360040, nullptr, "LoadSysMenuArg"},
{0x00370042, nullptr, "StoreSysMenuArg"},
{0x00360040, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"},
{0x00370042, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"},
{0x00380040, nullptr, "PreloadResidentApplet"},
{0x00390040, nullptr, "PrepareToStartResidentApplet"},
{0x003A0044, nullptr, "StartResidentApplet"},
@ -83,7 +83,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x00470104, &APT_A::Unwrap, "Unwrap"},
{0x00480100, nullptr, "GetProgramInfo"},
{0x00490180, nullptr, "Reboot"},
{0x004A0040, nullptr, "GetCaptureInfo"},
{0x004A0040, &APT_A::GetCaptureInfo, "GetCaptureInfo"},
{0x004B00C2, &APT_A::AppletUtility, "AppletUtility"},
{0x004C0000, nullptr, "SetFatalErrDispMode"},
{0x004D0080, nullptr, "GetAppletProgramInfo"},

View file

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

View file

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

View file

@ -1388,7 +1388,7 @@ Module::Module(Core::System& system) : system(system) {
auto archive_result = systemsavedata_factory.Open(archive_path, 0);
// 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!");
cecd_system_save_data_archive = std::move(archive_result).Unwrap();
} else {

View file

@ -620,6 +620,11 @@ ResultCode Module::FormatConfig() {
if (!res.IsSuccess())
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,
&CONSOLE_MODEL_OLD);
if (!res.IsSuccess())
@ -669,7 +674,7 @@ ResultCode Module::LoadConfigNANDSaveFile() {
auto archive_result = systemsavedata_factory.Open(archive_path, 0);
// 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
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.PushRaw(screen_name);
rb.Push(0);
LOG_INFO(Service_FRD, "returning the username defined in cfg");
}