service/apt: Add and implement more service commands. (#6721)
* service/apt: Add and implement more service commands. * service/apt: Implement power button. * Address review comments and fix GetApplicationRunningMode bug.
This commit is contained in:
parent
51996c54f0
commit
bb364d9bc0
@ -29,7 +29,7 @@ Config::~Config() {
|
||||
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
|
||||
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G,
|
||||
Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N,
|
||||
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B,
|
||||
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V,
|
||||
};
|
||||
|
||||
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
|
||||
|
@ -162,7 +162,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight,
|
||||
ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect,
|
||||
ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR,
|
||||
ui->buttonHome,
|
||||
ui->buttonHome, ui->buttonPower,
|
||||
};
|
||||
|
||||
analog_map_buttons = {{
|
||||
|
@ -305,6 +305,24 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_34">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_37">
|
||||
<property name="text">
|
||||
<string>Power:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonPower">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_28">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_36">
|
||||
@ -340,7 +358,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_32">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_40">
|
||||
|
@ -100,13 +100,14 @@ enum Values {
|
||||
ZR,
|
||||
|
||||
Home,
|
||||
Power,
|
||||
|
||||
NumButtons,
|
||||
};
|
||||
|
||||
constexpr int BUTTON_HID_BEGIN = A;
|
||||
constexpr int BUTTON_IR_BEGIN = ZL;
|
||||
constexpr int BUTTON_NS_BEGIN = Home;
|
||||
constexpr int BUTTON_NS_BEGIN = Power;
|
||||
|
||||
constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN;
|
||||
constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN;
|
||||
@ -134,6 +135,7 @@ static const std::array<const char*, NumButtons> mapping = {{
|
||||
"button_zl",
|
||||
"button_zr",
|
||||
"button_home",
|
||||
"button_power",
|
||||
}};
|
||||
|
||||
} // namespace NativeButton
|
||||
|
@ -259,14 +259,13 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
return ResultStatus::ErrorGetLoader;
|
||||
}
|
||||
std::pair<std::optional<u32>, Loader::ResultStatus> system_mode =
|
||||
app_loader->LoadKernelSystemMode();
|
||||
|
||||
if (system_mode.second != Loader::ResultStatus::Success) {
|
||||
auto memory_mode = app_loader->LoadKernelMemoryMode();
|
||||
if (memory_mode.second != Loader::ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
|
||||
static_cast<int>(system_mode.second));
|
||||
static_cast<int>(memory_mode.second));
|
||||
|
||||
switch (system_mode.second) {
|
||||
switch (memory_mode.second) {
|
||||
case Loader::ResultStatus::ErrorEncrypted:
|
||||
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
||||
case Loader::ResultStatus::ErrorInvalidFormat:
|
||||
@ -278,15 +277,15 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(system_mode.first);
|
||||
auto n3ds_mode = app_loader->LoadKernelN3dsMode();
|
||||
ASSERT(n3ds_mode.first);
|
||||
ASSERT(memory_mode.first);
|
||||
auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities();
|
||||
ASSERT(n3ds_hw_caps.first);
|
||||
u32 num_cores = 2;
|
||||
if (Settings::values.is_new_3ds) {
|
||||
num_cores = 4;
|
||||
}
|
||||
ResultStatus init_result{
|
||||
Init(emu_window, secondary_window, *system_mode.first, *n3ds_mode.first, num_cores)};
|
||||
Init(emu_window, secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores)};
|
||||
if (init_result != ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
||||
static_cast<u32>(init_result));
|
||||
@ -363,8 +362,9 @@ void System::Reschedule() {
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
|
||||
Frontend::EmuWindow* secondary_window, u32 system_mode,
|
||||
u8 n3ds_mode, u32 num_cores) {
|
||||
Frontend::EmuWindow* secondary_window,
|
||||
Kernel::MemoryMode memory_mode,
|
||||
const Kernel::New3dsHwCapabilities& n3ds_hw_caps, u32 num_cores) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
memory = std::make_unique<Memory::MemorySystem>();
|
||||
@ -372,7 +372,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
|
||||
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue());
|
||||
|
||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
||||
*memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps);
|
||||
|
||||
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
|
||||
cpu_cores.reserve(num_cores);
|
||||
@ -673,10 +673,10 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
|
||||
Shutdown(true);
|
||||
|
||||
// Re-initialize everything like it was before
|
||||
auto system_mode = this->app_loader->LoadKernelSystemMode();
|
||||
auto n3ds_mode = this->app_loader->LoadKernelN3dsMode();
|
||||
auto memory_mode = this->app_loader->LoadKernelMemoryMode();
|
||||
auto n3ds_hw_caps = this->app_loader->LoadNew3dsHwCapabilities();
|
||||
[[maybe_unused]] const System::ResultStatus result = Init(
|
||||
*m_emu_window, m_secondary_window, *system_mode.first, *n3ds_mode.first, num_cores);
|
||||
*m_emu_window, m_secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores);
|
||||
}
|
||||
|
||||
// flush on save, don't flush on load
|
||||
|
@ -342,8 +342,10 @@ private:
|
||||
* @return ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
[[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window,
|
||||
Frontend::EmuWindow* secondary_window, u32 system_mode,
|
||||
u8 n3ds_mode, u32 num_cores);
|
||||
Frontend::EmuWindow* secondary_window,
|
||||
Kernel::MemoryMode memory_mode,
|
||||
const Kernel::New3dsHwCapabilities& n3ds_hw_caps,
|
||||
u32 num_cores);
|
||||
|
||||
/// Reschedule the core emulation
|
||||
void Reschedule();
|
||||
|
@ -165,7 +165,11 @@ struct ExHeader_StorageInfo {
|
||||
struct ExHeader_ARM11_SystemLocalCaps {
|
||||
u64_le program_id;
|
||||
u32_le core_version;
|
||||
u8 reserved_flag;
|
||||
union {
|
||||
u8 n3ds_cpu_flags;
|
||||
BitField<0, 1, u8> enable_l2_cache;
|
||||
BitField<1, 1, u8> enable_804MHz_cpu;
|
||||
};
|
||||
u8 n3ds_mode;
|
||||
union {
|
||||
u8 flags0;
|
||||
|
@ -23,13 +23,15 @@ namespace Kernel {
|
||||
|
||||
/// Initialize the kernel
|
||||
KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
|
||||
std::function<void()> prepare_reschedule_callback, u32 system_mode,
|
||||
u32 num_cores, u8 n3ds_mode)
|
||||
std::function<void()> prepare_reschedule_callback,
|
||||
MemoryMode memory_mode, u32 num_cores,
|
||||
const New3dsHwCapabilities& n3ds_hw_caps)
|
||||
: memory(memory), timing(timing),
|
||||
prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
|
||||
prepare_reschedule_callback(std::move(prepare_reschedule_callback)), memory_mode(memory_mode),
|
||||
n3ds_hw_caps(n3ds_hw_caps) {
|
||||
std::generate(memory_regions.begin(), memory_regions.end(),
|
||||
[] { return std::make_shared<MemoryRegionInfo>(); });
|
||||
MemoryInit(system_mode, n3ds_mode);
|
||||
MemoryInit(memory_mode, n3ds_hw_caps.memory_mode);
|
||||
|
||||
resource_limits = std::make_unique<ResourceLimitList>(*this);
|
||||
for (u32 core_id = 0; core_id < num_cores; ++core_id) {
|
||||
@ -176,6 +178,8 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& shared_page_handler;
|
||||
ar& stored_processes;
|
||||
ar& next_thread_id;
|
||||
ar& memory_mode;
|
||||
ar& n3ds_hw_caps;
|
||||
// Deliberately don't include debugger info to allow debugging through loads
|
||||
|
||||
if (Archive::is_loading::value) {
|
||||
|
@ -97,11 +97,44 @@ union CoreVersion {
|
||||
BitField<24, 8, u32> major;
|
||||
};
|
||||
|
||||
/// Common memory memory modes.
|
||||
enum class MemoryMode : u8 {
|
||||
Prod = 0, ///< 64MB app memory
|
||||
Dev1 = 2, ///< 96MB app memory
|
||||
Dev2 = 3, ///< 80MB app memory
|
||||
Dev3 = 4, ///< 72MB app memory
|
||||
Dev4 = 5, ///< 32MB app memory
|
||||
};
|
||||
|
||||
/// New 3DS memory modes.
|
||||
enum class New3dsMemoryMode : u8 {
|
||||
Legacy = 0, ///< Use Old 3DS system mode.
|
||||
NewProd = 1, ///< 124MB app memory
|
||||
NewDev1 = 2, ///< 178MB app memory
|
||||
NewDev2 = 3, ///< 124MB app memory
|
||||
};
|
||||
|
||||
/// Structure containing N3DS hardware capability flags.
|
||||
struct New3dsHwCapabilities {
|
||||
bool enable_l2_cache; ///< Whether extra L2 cache should be enabled.
|
||||
bool enable_804MHz_cpu; ///< Whether the CPU should run at 804MHz.
|
||||
New3dsMemoryMode memory_mode; ///< The New 3DS memory mode.
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& enable_l2_cache;
|
||||
ar& enable_804MHz_cpu;
|
||||
ar& memory_mode;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class KernelSystem {
|
||||
public:
|
||||
explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
|
||||
std::function<void()> prepare_reschedule_callback, u32 system_mode,
|
||||
u32 num_cores, u8 n3ds_mode);
|
||||
std::function<void()> prepare_reschedule_callback, MemoryMode memory_mode,
|
||||
u32 num_cores, const New3dsHwCapabilities& n3ds_hw_caps);
|
||||
~KernelSystem();
|
||||
|
||||
using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
|
||||
@ -279,6 +312,14 @@ public:
|
||||
|
||||
void ResetThreadIDs();
|
||||
|
||||
MemoryMode GetMemoryMode() const {
|
||||
return memory_mode;
|
||||
}
|
||||
|
||||
const New3dsHwCapabilities& GetNew3dsHwCapabilities() const {
|
||||
return n3ds_hw_caps;
|
||||
}
|
||||
|
||||
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
|
||||
std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports;
|
||||
|
||||
@ -289,7 +330,7 @@ public:
|
||||
Core::Timing& timing;
|
||||
|
||||
private:
|
||||
void MemoryInit(u32 mem_type, u8 n3ds_mode);
|
||||
void MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode);
|
||||
|
||||
std::function<void()> prepare_reschedule_callback;
|
||||
|
||||
@ -324,6 +365,9 @@ private:
|
||||
|
||||
u32 next_thread_id;
|
||||
|
||||
MemoryMode memory_mode;
|
||||
New3dsHwCapabilities n3ds_hw_caps;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
|
@ -37,29 +37,20 @@ static const u32 memory_region_sizes[8][3] = {
|
||||
{0x0B200000, 0x02E00000, 0x02000000}, // 7
|
||||
};
|
||||
|
||||
namespace MemoryMode {
|
||||
enum N3DSMode : u8 {
|
||||
Mode6 = 1,
|
||||
Mode7 = 2,
|
||||
Mode6_2 = 3,
|
||||
};
|
||||
}
|
||||
|
||||
void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
|
||||
ASSERT(mem_type != 1);
|
||||
|
||||
void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode) {
|
||||
const bool is_new_3ds = Settings::values.is_new_3ds.GetValue();
|
||||
u32 reported_mem_type = mem_type;
|
||||
u32 mem_type_index = static_cast<u32>(memory_mode);
|
||||
u32 reported_mem_type = static_cast<u32>(memory_mode);
|
||||
if (is_new_3ds) {
|
||||
if (n3ds_mode == MemoryMode::Mode6 || n3ds_mode == MemoryMode::Mode6_2) {
|
||||
mem_type = 6;
|
||||
if (n3ds_mode == New3dsMemoryMode::NewProd || n3ds_mode == New3dsMemoryMode::NewDev2) {
|
||||
mem_type_index = 6;
|
||||
reported_mem_type = 6;
|
||||
} else if (n3ds_mode == MemoryMode::Mode7) {
|
||||
mem_type = 7;
|
||||
} else if (n3ds_mode == New3dsMemoryMode::NewDev1) {
|
||||
mem_type_index = 7;
|
||||
reported_mem_type = 7;
|
||||
} else {
|
||||
// On the N3ds, all O3ds configurations (<=5) are forced to 6 instead.
|
||||
mem_type = 6;
|
||||
mem_type_index = 6;
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +58,7 @@ void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
|
||||
// the sizes specified in the memory_region_sizes table.
|
||||
VAddr base = 0;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]);
|
||||
memory_regions[i]->Reset(base, memory_region_sizes[mem_type_index][i]);
|
||||
|
||||
base += memory_regions[i]->size;
|
||||
}
|
||||
|
@ -521,6 +521,11 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetTitleUpdateId(u64 title_id) {
|
||||
// Real services seem to just discard and replace the whole high word.
|
||||
return (title_id & 0xFFFFFFFF) | (static_cast<u64>(TID_HIGH_UPDATE) << 32);
|
||||
}
|
||||
|
||||
Service::FS::MediaType GetTitleMediaType(u64 titleId) {
|
||||
u16 platform = static_cast<u16>(titleId >> 48);
|
||||
u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF);
|
||||
|
@ -118,6 +118,13 @@ InstallStatus InstallCIA(const std::string& path,
|
||||
*/
|
||||
InstallStatus InstallFromNus(u64 title_id, int version = -1);
|
||||
|
||||
/**
|
||||
* Get the update title ID for a title
|
||||
* @param titleId the title ID
|
||||
* @returns The update title ID
|
||||
*/
|
||||
u64 GetTitleUpdateId(u64 title_id);
|
||||
|
||||
/**
|
||||
* Get the mediatype for an installed title
|
||||
* @param titleId the installed title ID
|
||||
|
@ -19,7 +19,7 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager)
|
||||
namespace Service::APT {
|
||||
|
||||
/// The interval at which the home button update callback will be called, 16.6ms
|
||||
static constexpr u64 home_button_update_interval_us = 16666;
|
||||
static constexpr u64 button_update_interval_us = 16666;
|
||||
|
||||
struct AppletTitleData {
|
||||
// There are two possible applet ids for each applet.
|
||||
@ -407,11 +407,56 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode AppletManager::Finalize(AppletId app_id) {
|
||||
auto slot = GetAppletSlotFromId(app_id);
|
||||
if (slot == AppletSlot::Error) {
|
||||
return {ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
|
||||
ErrorLevel::Status};
|
||||
}
|
||||
|
||||
auto slot_data = GetAppletSlot(slot);
|
||||
slot_data->Reset();
|
||||
|
||||
auto inactive = active_slot == AppletSlot::Error;
|
||||
if (!inactive) {
|
||||
auto active_slot_data = GetAppletSlot(active_slot);
|
||||
inactive = active_slot_data->applet_id == AppletId::None ||
|
||||
active_slot_data->attributes.applet_pos.Value() == AppletPos::Invalid;
|
||||
}
|
||||
|
||||
if (inactive) {
|
||||
active_slot = GetAppletSlotFromPos(AppletPos::System);
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
u32 AppletManager::CountRegisteredApplet() {
|
||||
return static_cast<u32>(std::count_if(applet_slots.begin(), applet_slots.end(),
|
||||
[](auto& slot_data) { return slot_data.registered; }));
|
||||
}
|
||||
|
||||
bool AppletManager::IsRegistered(AppletId app_id) {
|
||||
auto slot = GetAppletSlotFromId(app_id);
|
||||
return slot != AppletSlot::Error && GetAppletSlot(slot)->registered;
|
||||
}
|
||||
|
||||
ResultVal<AppletAttributes> AppletManager::GetAttribute(AppletId app_id) {
|
||||
auto slot = GetAppletSlotFromId(app_id);
|
||||
if (slot == AppletSlot::Error) {
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
|
||||
ErrorLevel::Status);
|
||||
}
|
||||
|
||||
auto slot_data = GetAppletSlot(slot);
|
||||
if (!slot_data->registered) {
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
|
||||
ErrorLevel::Status);
|
||||
}
|
||||
|
||||
return slot_data->attributes;
|
||||
}
|
||||
|
||||
ResultVal<Notification> AppletManager::InquireNotification(AppletId app_id) {
|
||||
auto slot = GetAppletSlotFromId(app_id);
|
||||
if (slot != AppletSlot::Error) {
|
||||
@ -441,6 +486,15 @@ ResultCode AppletManager::SendNotification(Notification notification) {
|
||||
ErrorLevel::Status};
|
||||
}
|
||||
|
||||
void AppletManager::SendNotificationToAll(Notification notification) {
|
||||
for (auto& slot_data : applet_slots) {
|
||||
if (slot_data.registered) {
|
||||
slot_data.notification = notification;
|
||||
slot_data.notification_event->Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -594,6 +648,71 @@ ResultCode AppletManager::CancelLibraryApplet(bool app_exiting) {
|
||||
});
|
||||
}
|
||||
|
||||
ResultCode AppletManager::SendDspSleep(AppletId from_applet_id,
|
||||
std::shared_ptr<Kernel::Object> object) {
|
||||
auto lib_slot = GetAppletSlotFromPos(AppletPos::Library);
|
||||
auto lib_app_id =
|
||||
lib_slot != AppletSlot::Error ? GetAppletSlot(lib_slot)->applet_id : AppletId::None;
|
||||
if (from_applet_id == lib_app_id) {
|
||||
SendParameter({
|
||||
.sender_id = from_applet_id,
|
||||
.destination_id = AppletId::Application,
|
||||
.signal = SignalType::DspSleep,
|
||||
.object = std::move(object),
|
||||
});
|
||||
}
|
||||
|
||||
auto sys_lib_slot = GetAppletSlotFromPos(AppletPos::SysLibrary);
|
||||
auto sys_lib_app_id =
|
||||
sys_lib_slot != AppletSlot::Error ? GetAppletSlot(sys_lib_slot)->applet_id : AppletId::None;
|
||||
if (from_applet_id == sys_lib_app_id) {
|
||||
auto sys_slot = GetAppletSlotFromPos(AppletPos::System);
|
||||
auto sys_app_id =
|
||||
sys_slot != AppletSlot::Error ? GetAppletSlot(sys_slot)->applet_id : AppletId::None;
|
||||
SendParameter({
|
||||
.sender_id = from_applet_id,
|
||||
.destination_id = sys_app_id,
|
||||
.signal = SignalType::DspSleep,
|
||||
.object = std::move(object),
|
||||
});
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode AppletManager::SendDspWakeUp(AppletId from_applet_id,
|
||||
std::shared_ptr<Kernel::Object> object) {
|
||||
auto lib_slot = GetAppletSlotFromPos(AppletPos::Library);
|
||||
auto lib_app_id =
|
||||
lib_slot != AppletSlot::Error ? GetAppletSlot(lib_slot)->applet_id : AppletId::None;
|
||||
if (from_applet_id == lib_app_id) {
|
||||
SendParameter({
|
||||
.sender_id = from_applet_id,
|
||||
.destination_id = AppletId::Application,
|
||||
.signal = SignalType::DspSleep,
|
||||
.object = std::move(object),
|
||||
});
|
||||
} else {
|
||||
auto sys_lib_slot = GetAppletSlotFromPos(AppletPos::SysLibrary);
|
||||
auto sys_lib_app_id = sys_lib_slot != AppletSlot::Error
|
||||
? GetAppletSlot(sys_lib_slot)->applet_id
|
||||
: AppletId::None;
|
||||
if (from_applet_id == sys_lib_app_id) {
|
||||
auto sys_slot = GetAppletSlotFromPos(AppletPos::System);
|
||||
auto sys_app_id =
|
||||
sys_slot != AppletSlot::Error ? GetAppletSlot(sys_slot)->applet_id : AppletId::None;
|
||||
SendParameter({
|
||||
.sender_id = from_applet_id,
|
||||
.destination_id = sys_app_id,
|
||||
.signal = SignalType::DspSleep,
|
||||
.object = std::move(object),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
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.
|
||||
@ -963,10 +1082,7 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i
|
||||
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;
|
||||
auto media_type = Service::AM::GetTitleMediaType(slot_data->title_id);
|
||||
return AppletInfo{
|
||||
.title_id = slot_data->title_id,
|
||||
.media_type = media_type,
|
||||
@ -976,6 +1092,61 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i
|
||||
};
|
||||
}
|
||||
|
||||
ResultVal<Service::FS::MediaType> AppletManager::Unknown54(u32 in_param) {
|
||||
auto slot_data = GetAppletSlot(AppletSlot::Application);
|
||||
if (slot_data->applet_id == AppletId::None) {
|
||||
return ResultCode{ErrCodes::AppNotRunning, ErrorModule::Applet, ErrorSummary::InvalidState,
|
||||
ErrorLevel::Permanent};
|
||||
}
|
||||
|
||||
if (in_param >= 0x80) {
|
||||
// TODO: Add error description name when the parameter is known.
|
||||
return ResultCode{10, ErrorModule::Applet, ErrorSummary::InvalidArgument,
|
||||
ErrorLevel::Usage};
|
||||
}
|
||||
|
||||
// TODO: Figure out what this logic is actually for.
|
||||
auto check_target =
|
||||
in_param >= 0x40 ? Service::FS::MediaType::GameCard : Service::FS::MediaType::SDMC;
|
||||
auto check_update = in_param == 0x01 || in_param == 0x42;
|
||||
|
||||
auto app_media_type = Service::AM::GetTitleMediaType(slot_data->title_id);
|
||||
auto app_update_media_type =
|
||||
Service::AM::GetTitleMediaType(Service::AM::GetTitleUpdateId(slot_data->title_id));
|
||||
if (app_media_type == check_target || (check_update && app_update_media_type == check_target)) {
|
||||
return Service::FS::MediaType::SDMC;
|
||||
} else {
|
||||
return Service::FS::MediaType::NAND;
|
||||
}
|
||||
}
|
||||
|
||||
TargetPlatform AppletManager::GetTargetPlatform() {
|
||||
if (Settings::values.is_new_3ds.GetValue() && !new_3ds_mode_blocked) {
|
||||
return TargetPlatform::New3ds;
|
||||
} else {
|
||||
return TargetPlatform::Old3ds;
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationRunningMode AppletManager::GetApplicationRunningMode() {
|
||||
auto slot_data = GetAppletSlot(AppletSlot::Application);
|
||||
if (slot_data->applet_id == AppletId::None) {
|
||||
return ApplicationRunningMode::NoApplication;
|
||||
}
|
||||
|
||||
// APT checks whether the system is a New 3DS and the 804MHz CPU speed is enabled to determine
|
||||
// the result.
|
||||
auto new_3ds_mode = GetTargetPlatform() == TargetPlatform::New3ds &&
|
||||
system.Kernel().GetNew3dsHwCapabilities().enable_804MHz_cpu;
|
||||
if (slot_data->registered) {
|
||||
return new_3ds_mode ? ApplicationRunningMode::New3dsRegistered
|
||||
: ApplicationRunningMode::Old3dsRegistered;
|
||||
} else {
|
||||
return new_3ds_mode ? ApplicationRunningMode::New3dsUnregistered
|
||||
: ApplicationRunningMode::Old3dsUnregistered;
|
||||
}
|
||||
}
|
||||
|
||||
ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type,
|
||||
ApplicationJumpFlags flags) {
|
||||
// A running application can not launch another application directly because the applet state
|
||||
@ -988,11 +1159,8 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType
|
||||
// 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: Basic heuristic to guess media type, needs proper implementation.
|
||||
app_jump_parameters.current_media_type =
|
||||
((application_slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000
|
||||
? Service::FS::MediaType::SDMC
|
||||
: Service::FS::MediaType::NAND;
|
||||
Service::AM::GetTitleMediaType(application_slot_data->title_id);
|
||||
if (flags == ApplicationJumpFlags::UseCurrentParameters) {
|
||||
app_jump_parameters.next_title_id = app_jump_parameters.current_title_id;
|
||||
app_jump_parameters.next_media_type = app_jump_parameters.current_media_type;
|
||||
@ -1055,19 +1223,8 @@ ResultCode AppletManager::DoApplicationJump(const DeliverArg& arg) {
|
||||
return RESULT_SUCCESS;
|
||||
*/
|
||||
|
||||
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)) {
|
||||
// TODO: This can happen if the requested title is not installed. Need a way to find
|
||||
// non-installed titles in the game list.
|
||||
LOG_CRITICAL(
|
||||
Service_APT,
|
||||
"Failed to find title during application jump: {} Resetting current title instead.",
|
||||
new_path);
|
||||
new_path.clear();
|
||||
}
|
||||
|
||||
system.RequestReset(new_path);
|
||||
NS::RebootToTitle(system, app_jump_parameters.next_media_type,
|
||||
app_jump_parameters.next_title_id);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -1126,13 +1283,14 @@ ResultCode AppletManager::StartApplication(const std::vector<u8>& parameter,
|
||||
app_start_parameters.reset();
|
||||
|
||||
if (!paused) {
|
||||
return WakeupApplication();
|
||||
return WakeupApplication(nullptr, {});
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode AppletManager::WakeupApplication() {
|
||||
ResultCode AppletManager::WakeupApplication(std::shared_ptr<Kernel::Object> object,
|
||||
const std::vector<u8>& buffer) {
|
||||
// Send a Wakeup signal via the apt parameter to the application once it registers itself.
|
||||
// The real APT service does this by spin waiting on another thread until the application is
|
||||
// registered.
|
||||
@ -1140,6 +1298,8 @@ ResultCode AppletManager::WakeupApplication() {
|
||||
.sender_id = AppletId::HomeMenu,
|
||||
.destination_id = AppletId::Application,
|
||||
.signal = SignalType::Wakeup,
|
||||
.object = std::move(object),
|
||||
.buffer = buffer,
|
||||
});
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
@ -1248,27 +1408,38 @@ void AppletManager::CaptureFrameBuffers() {
|
||||
void AppletManager::LoadInputDevices() {
|
||||
home_button = Input::CreateDevice<Input::ButtonDevice>(
|
||||
Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]);
|
||||
power_button = Input::CreateDevice<Input::ButtonDevice>(
|
||||
Settings::values.current_input_profile.buttons[Settings::NativeButton::Power]);
|
||||
}
|
||||
|
||||
void AppletManager::HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) {
|
||||
void AppletManager::ButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) {
|
||||
if (is_device_reload_pending.exchange(false)) {
|
||||
LoadInputDevices();
|
||||
}
|
||||
|
||||
const bool state = home_button->GetStatus();
|
||||
// NOTE: We technically do support loading and jumping to home menu even if it isn't
|
||||
// initially registered. However since the home menu suspend is not bug-free, we don't
|
||||
// want normal users who didn't launch the home menu accidentally pressing the home
|
||||
// button binding and freezing their game, so for now, gate it to only environments
|
||||
// where the home menu was already loaded by the user (last condition).
|
||||
if (state && !last_home_button_state && GetAppletSlot(AppletSlot::HomeMenu)->registered) {
|
||||
SendNotification(Notification::HomeButtonSingle);
|
||||
|
||||
if (GetAppletSlot(AppletSlot::HomeMenu)->registered) {
|
||||
const bool home_state = home_button->GetStatus();
|
||||
if (home_state && !last_home_button_state) {
|
||||
SendNotification(Notification::HomeButtonSingle);
|
||||
}
|
||||
last_home_button_state = home_state;
|
||||
|
||||
const bool power_state = power_button->GetStatus();
|
||||
if (power_state && !last_power_button_state) {
|
||||
SendNotificationToAll(Notification::PowerButtonClick);
|
||||
}
|
||||
last_power_button_state = power_state;
|
||||
}
|
||||
last_home_button_state = state;
|
||||
|
||||
// Reschedule recurrent event
|
||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||
usToCycles(home_button_update_interval_us) - cycles_late, home_button_update_event);
|
||||
system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us) - cycles_late,
|
||||
button_update_event);
|
||||
}
|
||||
|
||||
AppletManager::AppletManager(Core::System& system) : system(system) {
|
||||
@ -1286,12 +1457,11 @@ AppletManager::AppletManager(Core::System& system) : system(system) {
|
||||
system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Parameter");
|
||||
}
|
||||
HLE::Applets::Init();
|
||||
home_button_update_event = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||
"Home Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) {
|
||||
HomeButtonUpdateEvent(user_data, cycles_late);
|
||||
button_update_event = system.CoreTiming().RegisterEvent(
|
||||
"APT Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) {
|
||||
ButtonUpdateEvent(user_data, cycles_late);
|
||||
});
|
||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||
usToCycles(home_button_update_interval_us), home_button_update_event);
|
||||
system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us), button_update_event);
|
||||
}
|
||||
|
||||
AppletManager::~AppletManager() {
|
||||
|
@ -99,6 +99,21 @@ enum class AppletId : u32 {
|
||||
Memolib2 = 0x409,
|
||||
};
|
||||
|
||||
/// Application Old/New 3DS target platforms
|
||||
enum class TargetPlatform : u8 {
|
||||
Old3ds = 0,
|
||||
New3ds = 1,
|
||||
};
|
||||
|
||||
/// Application Old/New 3DS running modes
|
||||
enum class ApplicationRunningMode : u8 {
|
||||
NoApplication = 0,
|
||||
Old3dsRegistered = 1,
|
||||
New3dsRegistered = 2,
|
||||
Old3dsUnregistered = 3,
|
||||
New3dsUnregistered = 4,
|
||||
};
|
||||
|
||||
/// Holds information about the parameters used in Send/Glance/ReceiveParameter
|
||||
struct MessageParameter {
|
||||
AppletId sender_id = AppletId::None;
|
||||
@ -256,10 +271,14 @@ public:
|
||||
ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes);
|
||||
|
||||
ResultCode Enable(AppletAttributes attributes);
|
||||
ResultCode Finalize(AppletId app_id);
|
||||
u32 CountRegisteredApplet();
|
||||
bool IsRegistered(AppletId app_id);
|
||||
ResultVal<AppletAttributes> GetAttribute(AppletId app_id);
|
||||
|
||||
ResultVal<Notification> InquireNotification(AppletId app_id);
|
||||
ResultCode SendNotification(Notification notification);
|
||||
void SendNotificationToAll(Notification notification);
|
||||
|
||||
ResultCode PrepareToStartLibraryApplet(AppletId applet_id);
|
||||
ResultCode PreloadLibraryApplet(AppletId applet_id);
|
||||
@ -271,6 +290,9 @@ public:
|
||||
const std::vector<u8>& buffer);
|
||||
ResultCode CancelLibraryApplet(bool app_exiting);
|
||||
|
||||
ResultCode SendDspSleep(AppletId from_applet_id, std::shared_ptr<Kernel::Object> object);
|
||||
ResultCode SendDspWakeUp(AppletId from_applet_id, std::shared_ptr<Kernel::Object> object);
|
||||
|
||||
ResultCode PrepareToStartSystemApplet(AppletId applet_id);
|
||||
ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object,
|
||||
const std::vector<u8>& buffer);
|
||||
@ -294,8 +316,10 @@ public:
|
||||
ApplicationJumpFlags flags);
|
||||
ResultCode DoApplicationJump(const DeliverArg& arg);
|
||||
|
||||
boost::optional<DeliverArg> ReceiveDeliverArg() const {
|
||||
return deliver_arg;
|
||||
boost::optional<DeliverArg> ReceiveDeliverArg() {
|
||||
auto arg = deliver_arg;
|
||||
deliver_arg = boost::none;
|
||||
return arg;
|
||||
}
|
||||
void SetDeliverArg(boost::optional<DeliverArg> arg) {
|
||||
deliver_arg = std::move(arg);
|
||||
@ -324,7 +348,8 @@ public:
|
||||
ResultCode PrepareToStartApplication(u64 title_id, FS::MediaType media_type);
|
||||
ResultCode StartApplication(const std::vector<u8>& parameter, const std::vector<u8>& hmac,
|
||||
bool paused);
|
||||
ResultCode WakeupApplication();
|
||||
ResultCode WakeupApplication(std::shared_ptr<Kernel::Object> object,
|
||||
const std::vector<u8>& buffer);
|
||||
ResultCode CancelApplication();
|
||||
|
||||
struct AppletManInfo {
|
||||
@ -349,6 +374,10 @@ public:
|
||||
return app_jump_parameters;
|
||||
}
|
||||
|
||||
ResultVal<Service::FS::MediaType> Unknown54(u32 in_param);
|
||||
TargetPlatform GetTargetPlatform();
|
||||
ApplicationRunningMode GetApplicationRunningMode();
|
||||
|
||||
private:
|
||||
/// APT lock retrieved via GetLockHandle.
|
||||
std::shared_ptr<Kernel::Mutex> lock;
|
||||
@ -427,10 +456,16 @@ private:
|
||||
bool application_cancelled = false;
|
||||
AppletSlot application_close_target = AppletSlot::Error;
|
||||
|
||||
Core::TimingEventType* home_button_update_event;
|
||||
// This flag is used to determine if an app that supports New 3DS capabilities should use them.
|
||||
// It also affects the results of APT:GetTargetPlatform and APT:GetApplicationRunningMode.
|
||||
bool new_3ds_mode_blocked = false;
|
||||
|
||||
Core::TimingEventType* button_update_event;
|
||||
std::atomic<bool> is_device_reload_pending{true};
|
||||
std::unique_ptr<Input::ButtonDevice> home_button;
|
||||
std::unique_ptr<Input::ButtonDevice> power_button;
|
||||
bool last_home_button_state = false;
|
||||
bool last_power_button_state = false;
|
||||
|
||||
Core::System& system;
|
||||
|
||||
@ -455,7 +490,7 @@ private:
|
||||
void CaptureFrameBuffers();
|
||||
|
||||
void LoadInputDevices();
|
||||
void HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late);
|
||||
void ButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late);
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
@ -474,6 +509,7 @@ private:
|
||||
ar& ordered_to_close_application;
|
||||
ar& application_cancelled;
|
||||
ar& application_close_target;
|
||||
ar& new_3ds_mode_blocked;
|
||||
ar& lock;
|
||||
ar& capture_info;
|
||||
}
|
||||
|
@ -16,16 +16,19 @@
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/romfs.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/apt/applet_manager.h"
|
||||
#include "core/hle/service/apt/apt.h"
|
||||
#include "core/hle/service/apt/apt_a.h"
|
||||
#include "core/hle/service/apt/apt_s.h"
|
||||
#include "core/hle/service/apt/apt_u.h"
|
||||
#include "core/hle/service/apt/bcfnt/bcfnt.h"
|
||||
#include "core/hle/service/apt/ns.h"
|
||||
#include "core/hle/service/apt/ns_c.h"
|
||||
#include "core/hle/service/apt/ns_s.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/fs/fs_user.h"
|
||||
#include "core/hle/service/ptm/ptm.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hw/aes/ccm.h"
|
||||
@ -41,7 +44,6 @@ void Module::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& shared_font_loaded;
|
||||
ar& shared_font_relocated;
|
||||
ar& cpu_percent;
|
||||
ar& unknown_ns_state_field;
|
||||
ar& screen_capture_post_permission;
|
||||
ar& applet_manager;
|
||||
if (file_version > 0) {
|
||||
@ -90,14 +92,19 @@ void Module::NSInterface::RebootSystem(Kernel::HLERequestContext& ctx) {
|
||||
const auto title_id = rp.Pop<u64>();
|
||||
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
|
||||
rp.Skip(1, false); // Skip padding
|
||||
// TODO: Utilize requested memory type.
|
||||
const auto mem_type = rp.Pop<u8>();
|
||||
|
||||
LOG_WARNING(Service_APT,
|
||||
"called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}",
|
||||
launch_title, title_id, media_type, mem_type);
|
||||
|
||||
// TODO: Implement loading a specific title.
|
||||
apt->system.RequestReset();
|
||||
// TODO: Handle mem type.
|
||||
if (launch_title) {
|
||||
NS::RebootToTitle(apt->system, media_type, title_id);
|
||||
} else {
|
||||
apt->system.RequestReset();
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@ -371,6 +378,16 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(apt->applet_manager->Enable(attributes));
|
||||
}
|
||||
|
||||
void Module::APTInterface::Finalize(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
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->Finalize(applet_id));
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
auto applet_pos = rp.PopEnum<AppletPos>();
|
||||
@ -391,6 +408,16 @@ void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
void Module::APTInterface::CountRegisteredApplet(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(apt->applet_manager->CountRegisteredApplet());
|
||||
}
|
||||
|
||||
void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto app_id = rp.PopEnum<AppletId>();
|
||||
@ -402,6 +429,23 @@ void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id);
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetAttribute(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto app_id = rp.PopEnum<AppletId>();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id);
|
||||
|
||||
auto applet_attr = apt->applet_manager->GetAttribute(app_id);
|
||||
if (applet_attr.Failed()) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(applet_attr.Code());
|
||||
} else {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(applet_attr.Unwrap().raw);
|
||||
}
|
||||
}
|
||||
|
||||
void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto app_id = rp.PopEnum<AppletId>();
|
||||
@ -557,6 +601,21 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte
|
||||
rb.Push(static_cast<u8>(parameters.next_media_type));
|
||||
}
|
||||
|
||||
void Module::APTInterface::SendDeliverArg(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
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_DEBUG(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size);
|
||||
|
||||
apt->applet_manager->SetDeliverArg(DeliverArg{param, hmac});
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto param_size = rp.Pop<u32>();
|
||||
@ -611,7 +670,7 @@ void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(apt->applet_manager->WakeupApplication());
|
||||
rb.Push(apt->applet_manager->WakeupApplication(nullptr, {}));
|
||||
}
|
||||
|
||||
void Module::APTInterface::CancelApplication(Kernel::HLERequestContext& ctx) {
|
||||
@ -856,6 +915,28 @@ void Module::APTInterface::OrderToCloseSystemApplet(Kernel::HLERequestContext& c
|
||||
rb.Push(apt->applet_manager->OrderToCloseSystemApplet());
|
||||
}
|
||||
|
||||
void Module::APTInterface::SendDspSleep(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto from_app_id = rp.PopEnum<AppletId>();
|
||||
const auto object = rp.PopGenericObject();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called, from_app_id={:08X}", from_app_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(apt->applet_manager->SendDspSleep(from_app_id, object));
|
||||
}
|
||||
|
||||
void Module::APTInterface::SendDspWakeUp(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto from_app_id = rp.PopEnum<AppletId>();
|
||||
const auto object = rp.PopGenericObject();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called, from_app_id={:08X}", from_app_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(apt->applet_manager->SendDspWakeUp(from_app_id, object));
|
||||
}
|
||||
|
||||
void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
@ -972,29 +1053,124 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushStaticBuffer(std::move(screen_capture_buffer), 0);
|
||||
}
|
||||
|
||||
void Module::APTInterface::SetScreenCapPostPermission(Kernel::HLERequestContext& ctx) {
|
||||
void Module::APTInterface::Unknown54(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
auto in_param = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called, screen_capture_post_permission={}",
|
||||
apt->screen_capture_post_permission);
|
||||
LOG_DEBUG(Service_APT, "called, in_param={}", in_param);
|
||||
|
||||
apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF);
|
||||
auto media_type = apt->applet_manager->Unknown54(in_param);
|
||||
if (media_type.Failed()) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(media_type.Code());
|
||||
} else {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(media_type.Unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
void Module::APTInterface::SetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
auto permission = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called, permission={}", permission);
|
||||
|
||||
apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(permission & 0xF);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS); // No error
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) {
|
||||
void Module::APTInterface::GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_APT, "(STUBBED) called, screen_capture_post_permission={}",
|
||||
apt->screen_capture_post_permission);
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS); // No error
|
||||
rb.Push(static_cast<u32>(apt->screen_capture_post_permission));
|
||||
}
|
||||
|
||||
void Module::APTInterface::WakeupApplication2(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto buffer_size = rp.Pop<u32>();
|
||||
const auto object = rp.PopGenericObject();
|
||||
const auto buffer = rp.PopStaticBuffer();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called buffer_size={:#010X}", buffer_size);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(apt->applet_manager->WakeupApplication(object, buffer));
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetProgramId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto process_id = rp.PopPID();
|
||||
|
||||
LOG_DEBUG(Service_APT, "called process_id={}", process_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
auto fs_user =
|
||||
Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>("fs:USER");
|
||||
ASSERT_MSG(fs_user != nullptr, "fs:USER service is missing.");
|
||||
|
||||
auto program_info_result = fs_user->GetProgramLaunchInfo(process_id);
|
||||
if (program_info_result.Failed()) {
|
||||
// On failure, APT still returns a success result with a program ID of 0.
|
||||
rb.Push<u64>(0);
|
||||
} else {
|
||||
rb.Push(program_info_result.Unwrap().program_id);
|
||||
}
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetProgramInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto title_id = rp.Pop<u64>();
|
||||
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
|
||||
rp.Skip(1, false); // Skip padding
|
||||
|
||||
LOG_WARNING(Service_APT, "called title_id={:016X}, media_type={:02X}", title_id, media_type);
|
||||
|
||||
std::string path = Service::AM::GetTitleContentPath(media_type, title_id);
|
||||
auto loader = Loader::GetLoader(path);
|
||||
if (!loader) {
|
||||
LOG_WARNING(Service_APT, "Could not find .app for title 0x{:016x}", title_id);
|
||||
|
||||
// TODO: Proper error code
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
auto memory_mode = loader->LoadKernelMemoryMode();
|
||||
if (memory_mode.second != Loader::ResultStatus::Success || !memory_mode.first) {
|
||||
LOG_ERROR(Service_APT, "Could not load memory mode for title 0x{:016x}", title_id);
|
||||
|
||||
// TODO: Proper error code
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
auto core_version = loader->LoadCoreVersion();
|
||||
if (core_version.second != Loader::ResultStatus::Success || !core_version.first) {
|
||||
LOG_ERROR(Service_APT, "Could not load core version for title 0x{:016x}", title_id);
|
||||
|
||||
// TODO: Proper error code
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u8>(memory_mode.first.value()));
|
||||
rb.Push(core_version.first.value());
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto app_id = rp.PopEnum<AppletId>();
|
||||
@ -1154,37 +1330,83 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) {
|
||||
rb.PushMappedBuffer(output);
|
||||
}
|
||||
|
||||
void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) {
|
||||
void Module::APTInterface::Reboot(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
const auto title_id = rp.Pop<u64>();
|
||||
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
|
||||
rp.Skip(1, false); // Skip padding
|
||||
const auto mem_type = rp.Pop<u8>();
|
||||
const auto firm_tid_low = rp.Pop<u32>();
|
||||
|
||||
LOG_WARNING(Service_APT,
|
||||
"called title_id={:016X}, media_type={:02X}, mem_type={:02X}, firm_tid_low={:08X}",
|
||||
title_id, media_type, mem_type, firm_tid_low);
|
||||
|
||||
// TODO: Handle mem type and FIRM TID low.
|
||||
NS::RebootToTitle(apt->system, media_type, title_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::APTInterface::HardwareResetAsync(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called");
|
||||
LOG_WARNING(Service_APT, "called");
|
||||
|
||||
apt->system.RequestReset();
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::APTInterface::GetTargetPlatform(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
if (apt->unknown_ns_state_field) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
} else {
|
||||
PTM::CheckNew3DS(rb);
|
||||
}
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(apt->applet_manager->GetTargetPlatform());
|
||||
}
|
||||
|
||||
void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called");
|
||||
|
||||
PTM::CheckNew3DS(rb);
|
||||
}
|
||||
|
||||
void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) {
|
||||
void Module::APTInterface::GetApplicationRunningMode(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
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);
|
||||
rb.PushEnum(apt->applet_manager->GetApplicationRunningMode());
|
||||
}
|
||||
|
||||
void Module::APTInterface::IsStandardMemoryLayout(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_APT, "called");
|
||||
|
||||
bool is_standard;
|
||||
if (Settings::values.is_new_3ds) {
|
||||
// Memory layout is standard if it is not NewDev1 (178MB)
|
||||
is_standard = apt->system.Kernel().GetNew3dsHwCapabilities().memory_mode !=
|
||||
Kernel::New3dsMemoryMode::NewDev1;
|
||||
} else {
|
||||
// Memory layout is standard if it is Prod (64MB)
|
||||
is_standard = apt->system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod;
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(is_standard);
|
||||
}
|
||||
|
||||
void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -214,6 +214,15 @@ public:
|
||||
*/
|
||||
void Enable(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::Finalize service function
|
||||
* Inputs:
|
||||
* 1 : Applet ID
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void Finalize(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::GetAppletManInfo service function.
|
||||
* Inputs:
|
||||
@ -241,6 +250,15 @@ public:
|
||||
*/
|
||||
void GetAppletInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::CountRegisteredApplet service function
|
||||
* Outputs:
|
||||
* 0 : Return header
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Number of registered applets
|
||||
*/
|
||||
void CountRegisteredApplet(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::IsRegistered service function. This returns whether the specified AppID is
|
||||
* registered with NS yet. An AppID is "registered" once the process associated with the
|
||||
@ -257,6 +275,17 @@ public:
|
||||
*/
|
||||
void IsRegistered(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::GetAttribute service function
|
||||
* Inputs:
|
||||
* 1 : AppID
|
||||
* Outputs:
|
||||
* 0 : Return header
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Applet Attributes
|
||||
*/
|
||||
void GetAttribute(Kernel::HLERequestContext& ctx);
|
||||
|
||||
void InquireNotification(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
@ -596,6 +625,21 @@ public:
|
||||
*/
|
||||
void GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::SendDeliverArg service function
|
||||
* Inputs:
|
||||
* 0 : Command header [0x00340084]
|
||||
* 1 : Parameter Size (capped to 0x300)
|
||||
* 2 : HMAC Size (capped to 0x20)
|
||||
* 3 : (Parameter Size << 14) | 2
|
||||
* 4 : Input buffer for Parameter
|
||||
* 5 : (HMAC Size << 14) | 0x802
|
||||
* 6 : Input buffer for HMAC
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SendDeliverArg(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::ReceiveDeliverArg service function
|
||||
* Inputs:
|
||||
@ -687,6 +731,30 @@ public:
|
||||
*/
|
||||
void OrderToCloseSystemApplet(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::SendDspSleep service function
|
||||
* Inputs:
|
||||
* 1 : Source App ID
|
||||
* 2 : Handle translation header (0x0)
|
||||
* 3 : Handle parameter
|
||||
* Outputs:
|
||||
* 0 : Header code
|
||||
* 1 : Result code
|
||||
*/
|
||||
void SendDspSleep(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::SendDspWakeUp service function
|
||||
* Inputs:
|
||||
* 1 : Source App ID
|
||||
* 2 : Handle translation header (0x0)
|
||||
* 3 : Handle parameter
|
||||
* Outputs:
|
||||
* 0 : Header code
|
||||
* 1 : Result code
|
||||
*/
|
||||
void SendDspWakeUp(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::PrepareToJumpToHomeMenu service function
|
||||
* Inputs:
|
||||
@ -818,27 +886,97 @@ public:
|
||||
void GetStartupArgument(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::SetScreenCapPostPermission service function
|
||||
* APT::Unknown54 service function
|
||||
* Inputs:
|
||||
* 0 : Header Code[0x00540040]
|
||||
* 1 : Unknown
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Media Type
|
||||
*/
|
||||
void Unknown54(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::SetScreenCapturePostPermission service function
|
||||
* Inputs:
|
||||
* 0 : Header Code[0x00550040]
|
||||
* 1 : u8 The screenshot posting permission
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void SetScreenCapPostPermission(Kernel::HLERequestContext& ctx);
|
||||
void SetScreenCapturePostPermission(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::GetScreenCapPostPermission service function
|
||||
* APT::GetScreenCapturePostPermission service function
|
||||
* Inputs:
|
||||
* 0 : Header Code[0x00560000]
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : u8 The screenshot posting permission
|
||||
*/
|
||||
void GetScreenCapPostPermission(Kernel::HLERequestContext& ctx);
|
||||
void GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::CheckNew3DSApp service function
|
||||
* APT::WakeupApplication2 service function.
|
||||
* Inputs:
|
||||
* 1 : Buffer parameter size, (max is 0x1000)
|
||||
* 2 : Handle translation header (0x0)
|
||||
* 3 : Handle parameter
|
||||
* 4 : (Buffer parameter size << 14) | 2
|
||||
* 5 : Buffer parameter pointer
|
||||
* Outputs:
|
||||
* 0 : Return Header
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void WakeupApplication2(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::GetProgramId service function.
|
||||
* Inputs:
|
||||
* 1 : Process ID translation header (0x20)
|
||||
* 2 : Process ID (filled in by kernel)
|
||||
* Outputs:
|
||||
* 0 : Return Header
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2-3 : u64 Program ID
|
||||
*/
|
||||
void GetProgramId(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::GetProgramInfo service function.
|
||||
* Inputs:
|
||||
* 1-2 : Title ID
|
||||
* 3 : Media Type
|
||||
* 4 : Padding
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2 : Required app memory mode
|
||||
* 3 : Required app FIRM title ID low
|
||||
*/
|
||||
void GetProgramInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::Reboot service function.
|
||||
* Inputs:
|
||||
* 1-2 : Title ID
|
||||
* 3 : Media Type
|
||||
* 4 : Padding
|
||||
* 5 : Launch memory type
|
||||
* 6 : FIRM title ID low 32-bits
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void Reboot(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::HardwareResetAsync service function.
|
||||
* Outputs:
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void HardwareResetAsync(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::GetTargetPlatform service function
|
||||
* Outputs:
|
||||
* 1: Result code, 0 on success, otherwise error code
|
||||
* 2: u8 output: 0 = Old3DS, 1 = New3DS.
|
||||
@ -849,7 +987,7 @@ public:
|
||||
* Normally this NS state field is zero, however this state field is set to 1
|
||||
* when APT:PrepareToStartApplication is used with flags bit8 is set.
|
||||
*/
|
||||
void CheckNew3DSApp(Kernel::HLERequestContext& ctx);
|
||||
void GetTargetPlatform(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* Wrapper for PTMSYSM:CheckNew3DS
|
||||
@ -861,12 +999,20 @@ public:
|
||||
void CheckNew3DS(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::Unknown0x0103 service function. Determines whether Smash 4 allows C-Stick
|
||||
* APT::GetApplicationRunningMode service function
|
||||
* Outputs:
|
||||
* 1: Result code, 0 on success otherwise error code
|
||||
* 2: u8 output: 2 = New3DS+valid/initialized (in Smash 4), 1 = Old3DS or invalid
|
||||
* 2: u8 output: 0 = No application, 1/3 = Old 3DS, 2/4 = New 3DS
|
||||
*/
|
||||
void Unknown0x0103(Kernel::HLERequestContext& ctx);
|
||||
void GetApplicationRunningMode(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::IsStandardMemoryLayout service function
|
||||
* Outputs:
|
||||
* 1: Result code, 0 on success otherwise error code
|
||||
* 2: bool output: Whether the system is in its standard memory layout.
|
||||
*/
|
||||
void IsStandardMemoryLayout(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* APT::IsTitleAllowed service function
|
||||
@ -906,9 +1052,6 @@ private:
|
||||
|
||||
u32 cpu_percent = 0; ///< CPU time available to the running application
|
||||
|
||||
// APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode
|
||||
u8 unknown_ns_state_field = 0;
|
||||
|
||||
std::array<u8, SysMenuArgSize> sys_menu_arg_buffer;
|
||||
|
||||
ScreencapPostPermission screen_capture_post_permission =
|
||||
|
@ -14,13 +14,13 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
|
||||
{0x0001, &APT_A::GetLockHandle, "GetLockHandle"},
|
||||
{0x0002, &APT_A::Initialize, "Initialize"},
|
||||
{0x0003, &APT_A::Enable, "Enable"},
|
||||
{0x0004, nullptr, "Finalize"},
|
||||
{0x0004, &APT_A::Finalize, "Finalize"},
|
||||
{0x0005, &APT_A::GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x0006, &APT_A::GetAppletInfo, "GetAppletInfo"},
|
||||
{0x0007, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x0008, nullptr, "CountRegisteredApplet"},
|
||||
{0x0008, &APT_A::CountRegisteredApplet, "CountRegisteredApplet"},
|
||||
{0x0009, &APT_A::IsRegistered, "IsRegistered"},
|
||||
{0x000A, nullptr, "GetAttribute"},
|
||||
{0x000A, &APT_A::GetAttribute, "GetAttribute"},
|
||||
{0x000B, &APT_A::InquireNotification, "InquireNotification"},
|
||||
{0x000C, &APT_A::SendParameter, "SendParameter"},
|
||||
{0x000D, &APT_A::ReceiveParameter, "ReceiveParameter"},
|
||||
@ -39,7 +39,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
|
||||
{0x001A, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B, &APT_A::StartApplication, "StartApplication"},
|
||||
{0x001C, &APT_A::WakeupApplication, "WakeupApplication"},
|
||||
{0x001D, nullptr, "CancelApplication"},
|
||||
{0x001D, &APT_A::CancelApplication, "CancelApplication"},
|
||||
{0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"},
|
||||
{0x0020, nullptr, "StartNewestHomeMenu"},
|
||||
@ -62,7 +62,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
|
||||
{0x0031, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"},
|
||||
{0x0032, &APT_A::DoApplicationJump, "DoApplicationJump"},
|
||||
{0x0033, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
|
||||
{0x0034, nullptr, "SendDeliverArg"},
|
||||
{0x0034, &APT_A::SendDeliverArg, "SendDeliverArg"},
|
||||
{0x0035, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"},
|
||||
{0x0036, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"},
|
||||
{0x0037, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"},
|
||||
@ -70,8 +70,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
|
||||
{0x0039, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A, nullptr, "StartResidentApplet"},
|
||||
{0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"},
|
||||
{0x003C, nullptr, "SendDspSleep"},
|
||||
{0x003D, nullptr, "SendDspWakeUp"},
|
||||
{0x003C, &APT_A::SendDspSleep, "SendDspSleep"},
|
||||
{0x003D, &APT_A::SendDspWakeUp, "SendDspWakeUp"},
|
||||
{0x003E, nullptr, "ReplySleepQuery"},
|
||||
{0x003F, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
||||
@ -82,26 +82,27 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
|
||||
{0x0045, &APT_A::GetWirelessRebootInfo, "GetWirelessRebootInfo"},
|
||||
{0x0046, &APT_A::Wrap, "Wrap"},
|
||||
{0x0047, &APT_A::Unwrap, "Unwrap"},
|
||||
{0x0048, nullptr, "GetProgramInfo"},
|
||||
{0x0049, nullptr, "Reboot"},
|
||||
{0x0048, &APT_A::GetProgramInfo, "GetProgramInfo"},
|
||||
{0x0049, &APT_A::Reboot, "Reboot"},
|
||||
{0x004A, &APT_A::GetCaptureInfo, "GetCaptureInfo"},
|
||||
{0x004B, &APT_A::AppletUtility, "AppletUtility"},
|
||||
{0x004C, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E, nullptr, "HardwareResetAsync"},
|
||||
{0x004E, &APT_A::HardwareResetAsync, "HardwareResetAsync"},
|
||||
{0x004F, &APT_A::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x0050, &APT_A::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x0051, &APT_A::GetStartupArgument, "GetStartupArgument"},
|
||||
{0x0052, nullptr, "Wrap1"},
|
||||
{0x0053, nullptr, "Unwrap1"},
|
||||
{0x0055, &APT_A::SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x0056, &APT_A::GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x0057, nullptr, "WakeupApplication2"},
|
||||
{0x0058, nullptr, "GetProgramID"},
|
||||
{0x0101, &APT_A::CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x0054, &APT_A::Unknown54, "Unknown54"},
|
||||
{0x0055, &APT_A::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"},
|
||||
{0x0056, &APT_A::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"},
|
||||
{0x0057, &APT_A::WakeupApplication2, "WakeupApplication2"},
|
||||
{0x0058, &APT_A::GetProgramId, "GetProgramId"},
|
||||
{0x0101, &APT_A::GetTargetPlatform, "GetTargetPlatform"},
|
||||
{0x0102, &APT_A::CheckNew3DS, "CheckNew3DS"},
|
||||
{0x0103, &APT_A::Unknown0x0103, "Unknown0x0103"},
|
||||
{0x0104, nullptr, "IsStandardMemoryLayout"},
|
||||
{0x0103, &APT_A::GetApplicationRunningMode, "GetApplicationRunningMode"},
|
||||
{0x0104, &APT_A::IsStandardMemoryLayout, "IsStandardMemoryLayout"},
|
||||
{0x0105, &APT_A::IsTitleAllowed, "IsTitleAllowed"},
|
||||
// clang-format on
|
||||
};
|
||||
|
@ -14,13 +14,13 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
|
||||
{0x0001, &APT_S::GetLockHandle, "GetLockHandle"},
|
||||
{0x0002, &APT_S::Initialize, "Initialize"},
|
||||
{0x0003, &APT_S::Enable, "Enable"},
|
||||
{0x0004, nullptr, "Finalize"},
|
||||
{0x0004, &APT_S::Finalize, "Finalize"},
|
||||
{0x0005, &APT_S::GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x0006, &APT_S::GetAppletInfo, "GetAppletInfo"},
|
||||
{0x0007, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x0008, nullptr, "CountRegisteredApplet"},
|
||||
{0x0008, &APT_S::CountRegisteredApplet, "CountRegisteredApplet"},
|
||||
{0x0009, &APT_S::IsRegistered, "IsRegistered"},
|
||||
{0x000A, nullptr, "GetAttribute"},
|
||||
{0x000A, &APT_S::GetAttribute, "GetAttribute"},
|
||||
{0x000B, &APT_S::InquireNotification, "InquireNotification"},
|
||||
{0x000C, &APT_S::SendParameter, "SendParameter"},
|
||||
{0x000D, &APT_S::ReceiveParameter, "ReceiveParameter"},
|
||||
@ -39,7 +39,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
|
||||
{0x001A, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B, &APT_S::StartApplication, "StartApplication"},
|
||||
{0x001C, &APT_S::WakeupApplication, "WakeupApplication"},
|
||||
{0x001D, nullptr, "CancelApplication"},
|
||||
{0x001D, &APT_S::CancelApplication, "CancelApplication"},
|
||||
{0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"},
|
||||
{0x0020, nullptr, "StartNewestHomeMenu"},
|
||||
@ -62,7 +62,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
|
||||
{0x0031, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"},
|
||||
{0x0032, &APT_S::DoApplicationJump, "DoApplicationJump"},
|
||||
{0x0033, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
|
||||
{0x0034, nullptr, "SendDeliverArg"},
|
||||
{0x0034, &APT_S::SendDeliverArg, "SendDeliverArg"},
|
||||
{0x0035, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"},
|
||||
{0x0036, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"},
|
||||
{0x0037, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"},
|
||||
@ -70,8 +70,8 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
|
||||
{0x0039, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A, nullptr, "StartResidentApplet"},
|
||||
{0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"},
|
||||
{0x003C, nullptr, "SendDspSleep"},
|
||||
{0x003D, nullptr, "SendDspWakeUp"},
|
||||
{0x003C, &APT_S::SendDspSleep, "SendDspSleep"},
|
||||
{0x003D, &APT_S::SendDspWakeUp, "SendDspWakeUp"},
|
||||
{0x003E, nullptr, "ReplySleepQuery"},
|
||||
{0x003F, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
||||
@ -82,26 +82,27 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
|
||||
{0x0045, &APT_S::GetWirelessRebootInfo, "GetWirelessRebootInfo"},
|
||||
{0x0046, &APT_S::Wrap, "Wrap"},
|
||||
{0x0047, &APT_S::Unwrap, "Unwrap"},
|
||||
{0x0048, nullptr, "GetProgramInfo"},
|
||||
{0x0049, nullptr, "Reboot"},
|
||||
{0x0048, &APT_S::GetProgramInfo, "GetProgramInfo"},
|
||||
{0x0049, &APT_S::Reboot, "Reboot"},
|
||||
{0x004A, &APT_S::GetCaptureInfo, "GetCaptureInfo"},
|
||||
{0x004B, &APT_S::AppletUtility, "AppletUtility"},
|
||||
{0x004C, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E, nullptr, "HardwareResetAsync"},
|
||||
{0x004E, &APT_S::HardwareResetAsync, "HardwareResetAsync"},
|
||||
{0x004F, &APT_S::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x0050, &APT_S::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x0051, &APT_S::GetStartupArgument, "GetStartupArgument"},
|
||||
{0x0052, nullptr, "Wrap1"},
|
||||
{0x0053, nullptr, "Unwrap1"},
|
||||
{0x0055, &APT_S::SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x0056, &APT_S::GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x0057, nullptr, "WakeupApplication2"},
|
||||
{0x0058, nullptr, "GetProgramID"},
|
||||
{0x0101, &APT_S::CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x0054, &APT_S::Unknown54, "Unknown54"},
|
||||
{0x0055, &APT_S::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"},
|
||||
{0x0056, &APT_S::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"},
|
||||
{0x0057, &APT_S::WakeupApplication2, "WakeupApplication2"},
|
||||
{0x0058, &APT_S::GetProgramId, "GetProgramId"},
|
||||
{0x0101, &APT_S::GetTargetPlatform, "GetTargetPlatform"},
|
||||
{0x0102, &APT_S::CheckNew3DS, "CheckNew3DS"},
|
||||
{0x0103, &APT_S::Unknown0x0103, "Unknown0x0103"},
|
||||
{0x0104, nullptr, "IsStandardMemoryLayout"},
|
||||
{0x0103, &APT_S::GetApplicationRunningMode, "GetApplicationRunningMode"},
|
||||
{0x0104, &APT_S::IsStandardMemoryLayout, "IsStandardMemoryLayout"},
|
||||
{0x0105, &APT_S::IsTitleAllowed, "IsTitleAllowed"},
|
||||
// clang-format on
|
||||
};
|
||||
|
@ -14,13 +14,13 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
|
||||
{0x0001, &APT_U::GetLockHandle, "GetLockHandle"},
|
||||
{0x0002, &APT_U::Initialize, "Initialize"},
|
||||
{0x0003, &APT_U::Enable, "Enable"},
|
||||
{0x0004, nullptr, "Finalize"},
|
||||
{0x0004, &APT_U::Finalize, "Finalize"},
|
||||
{0x0005, &APT_U::GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x0006, &APT_U::GetAppletInfo, "GetAppletInfo"},
|
||||
{0x0007, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x0008, nullptr, "CountRegisteredApplet"},
|
||||
{0x0008, &APT_U::CountRegisteredApplet, "CountRegisteredApplet"},
|
||||
{0x0009, &APT_U::IsRegistered, "IsRegistered"},
|
||||
{0x000A, nullptr, "GetAttribute"},
|
||||
{0x000A, &APT_U::GetAttribute, "GetAttribute"},
|
||||
{0x000B, &APT_U::InquireNotification, "InquireNotification"},
|
||||
{0x000C, &APT_U::SendParameter, "SendParameter"},
|
||||
{0x000D, &APT_U::ReceiveParameter, "ReceiveParameter"},
|
||||
@ -39,7 +39,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
|
||||
{0x001A, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B, &APT_U::StartApplication, "StartApplication"},
|
||||
{0x001C, &APT_U::WakeupApplication, "WakeupApplication"},
|
||||
{0x001D, nullptr, "CancelApplication"},
|
||||
{0x001D, &APT_U::CancelApplication, "CancelApplication"},
|
||||
{0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"},
|
||||
{0x0020, nullptr, "StartNewestHomeMenu"},
|
||||
@ -62,7 +62,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
|
||||
{0x0031, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"},
|
||||
{0x0032, &APT_U::DoApplicationJump, "DoApplicationJump"},
|
||||
{0x0033, &APT_U::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
|
||||
{0x0034, nullptr, "SendDeliverArg"},
|
||||
{0x0034, &APT_U::SendDeliverArg, "SendDeliverArg"},
|
||||
{0x0035, &APT_U::ReceiveDeliverArg, "ReceiveDeliverArg"},
|
||||
{0x0036, &APT_U::LoadSysMenuArg, "LoadSysMenuArg"},
|
||||
{0x0037, &APT_U::StoreSysMenuArg, "StoreSysMenuArg"},
|
||||
@ -70,8 +70,8 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
|
||||
{0x0039, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A, nullptr, "StartResidentApplet"},
|
||||
{0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"},
|
||||
{0x003C, nullptr, "SendDspSleep"},
|
||||
{0x003D, nullptr, "SendDspWakeUp"},
|
||||
{0x003C, &APT_U::SendDspSleep, "SendDspSleep"},
|
||||
{0x003D, &APT_U::SendDspWakeUp, "SendDspWakeUp"},
|
||||
{0x003E, nullptr, "ReplySleepQuery"},
|
||||
{0x003F, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
|
||||
@ -82,26 +82,27 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
|
||||
{0x0045, &APT_U::GetWirelessRebootInfo, "GetWirelessRebootInfo"},
|
||||
{0x0046, &APT_U::Wrap, "Wrap"},
|
||||
{0x0047, &APT_U::Unwrap, "Unwrap"},
|
||||
{0x0048, nullptr, "GetProgramInfo"},
|
||||
{0x0049, nullptr, "Reboot"},
|
||||
{0x0048, &APT_U::GetProgramInfo, "GetProgramInfo"},
|
||||
{0x0049, &APT_U::Reboot, "Reboot"},
|
||||
{0x004A, &APT_U::GetCaptureInfo, "GetCaptureInfo"},
|
||||
{0x004B, &APT_U::AppletUtility, "AppletUtility"},
|
||||
{0x004C, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E, nullptr, "HardwareResetAsync"},
|
||||
{0x004E, &APT_U::HardwareResetAsync, "HardwareResetAsync"},
|
||||
{0x004F, &APT_U::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x0050, &APT_U::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x0051, &APT_U::GetStartupArgument, "GetStartupArgument"},
|
||||
{0x0052, nullptr, "Wrap1"},
|
||||
{0x0053, nullptr, "Unwrap1"},
|
||||
{0x0055, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x0056, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x0057, nullptr, "WakeupApplication2"},
|
||||
{0x0058, nullptr, "GetProgramID"},
|
||||
{0x0101, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x0054, &APT_U::Unknown54, "Unknown54"},
|
||||
{0x0055, &APT_U::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"},
|
||||
{0x0056, &APT_U::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"},
|
||||
{0x0057, &APT_U::WakeupApplication2, "WakeupApplication2"},
|
||||
{0x0058, &APT_U::GetProgramId, "GetProgramId"},
|
||||
{0x0101, &APT_U::GetTargetPlatform, "GetTargetPlatform"},
|
||||
{0x0102, &APT_U::CheckNew3DS, "CheckNew3DS"},
|
||||
{0x0103, &APT_U::Unknown0x0103, "Unknown0x0103"},
|
||||
{0x0104, nullptr, "IsStandardMemoryLayout"},
|
||||
{0x0103, &APT_U::GetApplicationRunningMode, "GetApplicationRunningMode"},
|
||||
{0x0104, &APT_U::IsStandardMemoryLayout, "IsStandardMemoryLayout"},
|
||||
{0x0105, &APT_U::IsTitleAllowed, "IsTitleAllowed"},
|
||||
// clang-format on
|
||||
};
|
||||
|
@ -8,5 +8,6 @@ namespace Service::APT::ErrCodes {
|
||||
enum {
|
||||
ParameterPresent = 2,
|
||||
InvalidAppletSlot = 4,
|
||||
AppNotRunning = 11,
|
||||
};
|
||||
} // namespace Service::APT::ErrCodes
|
||||
|
@ -29,4 +29,17 @@ std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title
|
||||
return process;
|
||||
}
|
||||
|
||||
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id) {
|
||||
auto new_path = AM::GetTitleContentPath(media_type, title_id);
|
||||
if (new_path.empty() || !FileUtil::Exists(new_path)) {
|
||||
// TODO: This can happen if the requested title is not installed. Need a way to find
|
||||
// non-installed titles in the game list.
|
||||
LOG_CRITICAL(Service_APT,
|
||||
"Failed to find title '{}' to jump to, resetting current title instead.",
|
||||
new_path);
|
||||
new_path.clear();
|
||||
}
|
||||
system.RequestReset(new_path);
|
||||
}
|
||||
|
||||
} // namespace Service::NS
|
||||
|
@ -18,4 +18,7 @@ namespace Service::NS {
|
||||
/// Loads and launches the title identified by title_id in the specified media type.
|
||||
std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id);
|
||||
|
||||
/// Reboots the system to the specified title.
|
||||
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id);
|
||||
|
||||
} // namespace Service::NS
|
||||
|
@ -672,30 +672,23 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
u32 process_id = rp.Pop<u32>();
|
||||
const auto process_id = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service_FS, "process_id={}", process_id);
|
||||
|
||||
auto program_info = program_info_map.find(process_id);
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
|
||||
|
||||
if (program_info == program_info_map.end()) {
|
||||
auto program_info_result = GetProgramLaunchInfo(process_id);
|
||||
if (program_info_result.Failed()) {
|
||||
// Note: In this case, the rest of the parameters are not changed but the command header
|
||||
// remains the same.
|
||||
rb.Push(ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS,
|
||||
ErrorSummary::NotFound, ErrorLevel::Status));
|
||||
rb.Push(program_info_result.Code());
|
||||
rb.Skip(4, false);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(program_info->second.program_id);
|
||||
rb.Push(static_cast<u8>(program_info->second.media_type));
|
||||
|
||||
// TODO(Subv): Find out what this value means.
|
||||
rb.Push<u32>(0);
|
||||
rb.PushRaw(program_info_result.Unwrap());
|
||||
}
|
||||
|
||||
void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <unordered_map>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
@ -17,6 +18,13 @@ namespace Service::FS {
|
||||
|
||||
class ArchiveManager;
|
||||
|
||||
struct ProgramInfo {
|
||||
u64 program_id;
|
||||
MediaType media_type;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
};
|
||||
static_assert(sizeof(ProgramInfo) == 0x10, "ProgramInfo struct has incorrect size");
|
||||
|
||||
struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||
// We retrieves program ID for client process on FS::Initialize(WithSDKVersion)
|
||||
// Real 3DS matches program ID and process ID based on data registered by loader via fs:REG, so
|
||||
@ -45,6 +53,17 @@ public:
|
||||
|
||||
std::string GetCurrentGamecardPath() const;
|
||||
|
||||
/// Gets the registered program info of a process.
|
||||
ResultVal<ProgramInfo> GetProgramLaunchInfo(u32 process_id) const {
|
||||
auto info = program_info_map.find(process_id);
|
||||
if (info != program_info_map.end()) {
|
||||
return info->second;
|
||||
} else {
|
||||
return ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS,
|
||||
ErrorSummary::NotFound, ErrorLevel::Status);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@ -602,11 +621,6 @@ private:
|
||||
static ResultVal<u16> GetSpecialContentIndexFromTMD(MediaType media_type, u64 title_id,
|
||||
SpecialContentType type);
|
||||
|
||||
struct ProgramInfo {
|
||||
u64 program_id;
|
||||
MediaType media_type;
|
||||
};
|
||||
|
||||
std::unordered_map<u32, ProgramInfo> program_info_map;
|
||||
std::string current_gamecard_path;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/romfs_reader.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
@ -99,23 +100,36 @@ public:
|
||||
virtual ResultStatus Load(std::shared_ptr<Kernel::Process>& process) = 0;
|
||||
|
||||
/**
|
||||
* Loads the system mode that this application needs.
|
||||
* This function defaults to 2 (96MB allocated to the application) if it can't read the
|
||||
* Loads the core version (FIRM title ID low) that this application needs.
|
||||
* This function defaults to 0x2 (NATIVE_FIRM) if it can't read the
|
||||
* information.
|
||||
* @returns A pair with the optional system mode, and the status.
|
||||
* @returns A pair with the optional core version, and the status.
|
||||
*/
|
||||
virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() {
|
||||
// 96MB allocated to the application.
|
||||
return std::make_pair(2, ResultStatus::Success);
|
||||
virtual std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() {
|
||||
return std::make_pair(0x2, ResultStatus::Success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the N3ds mode that this application uses.
|
||||
* It defaults to 0 (O3DS default) if it can't read the information.
|
||||
* @returns A pair with the optional N3ds mode, and the status.
|
||||
* Loads the memory mode that this application needs.
|
||||
* This function defaults to Dev1 (96MB allocated to the application) if it can't read the
|
||||
* information.
|
||||
* @returns A pair with the optional memory mode, and the status.
|
||||
*/
|
||||
virtual std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() {
|
||||
return std::make_pair(u8(0), ResultStatus::Success);
|
||||
virtual std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() {
|
||||
// 96MB allocated to the application.
|
||||
return std::make_pair(Kernel::MemoryMode::Dev1, ResultStatus::Success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the N3DS hardware capabilities that this application uses.
|
||||
* It defaults to all disabled (O3DS) if it can't read the information.
|
||||
* @returns A pair with the optional N3DS hardware capabilities, and the status.
|
||||
*/
|
||||
virtual std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus>
|
||||
LoadNew3dsHwCapabilities() {
|
||||
return std::make_pair(
|
||||
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy},
|
||||
ResultStatus::Success);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/ncch_container.h"
|
||||
#include "core/file_sys/title_metadata.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
@ -47,7 +48,7 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
|
||||
return FileType::Error;
|
||||
}
|
||||
|
||||
std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() {
|
||||
std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadCoreVersion() {
|
||||
if (!is_loaded) {
|
||||
ResultStatus res = base_ncch.Load();
|
||||
if (res != ResultStatus::Success) {
|
||||
@ -55,12 +56,12 @@ std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode
|
||||
}
|
||||
}
|
||||
|
||||
// Set the system mode as the one from the exheader.
|
||||
return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.system_mode.Value(),
|
||||
ResultStatus::Success);
|
||||
// Provide the core version from the exheader.
|
||||
auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps;
|
||||
return std::make_pair(ncch_caps.core_version, ResultStatus::Success);
|
||||
}
|
||||
|
||||
std::pair<std::optional<u8>, ResultStatus> AppLoader_NCCH::LoadKernelN3dsMode() {
|
||||
std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> AppLoader_NCCH::LoadKernelMemoryMode() {
|
||||
if (!is_loaded) {
|
||||
ResultStatus res = base_ncch.Load();
|
||||
if (res != ResultStatus::Success) {
|
||||
@ -68,9 +69,29 @@ std::pair<std::optional<u8>, ResultStatus> AppLoader_NCCH::LoadKernelN3dsMode()
|
||||
}
|
||||
}
|
||||
|
||||
// Set the system mode as the one from the exheader.
|
||||
return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.n3ds_mode,
|
||||
ResultStatus::Success);
|
||||
// Provide the memory mode from the exheader.
|
||||
auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps;
|
||||
auto mode = static_cast<Kernel::MemoryMode>(ncch_caps.system_mode.Value());
|
||||
return std::make_pair(mode, ResultStatus::Success);
|
||||
}
|
||||
|
||||
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus>
|
||||
AppLoader_NCCH::LoadNew3dsHwCapabilities() {
|
||||
if (!is_loaded) {
|
||||
ResultStatus res = base_ncch.Load();
|
||||
if (res != ResultStatus::Success) {
|
||||
return std::make_pair(std::nullopt, res);
|
||||
}
|
||||
}
|
||||
|
||||
// Provide the capabilities from the exheader.
|
||||
auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps;
|
||||
auto caps = Kernel::New3dsHwCapabilities{
|
||||
ncch_caps.enable_l2_cache != 0,
|
||||
ncch_caps.enable_804MHz_cpu != 0,
|
||||
static_cast<Kernel::New3dsMemoryMode>(ncch_caps.n3ds_mode),
|
||||
};
|
||||
return std::make_pair(std::move(caps), ResultStatus::Success);
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) {
|
||||
|
@ -32,13 +32,16 @@ public:
|
||||
|
||||
ResultStatus Load(std::shared_ptr<Kernel::Process>& process) override;
|
||||
|
||||
std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() override;
|
||||
|
||||
/**
|
||||
* Loads the Exheader and returns the system mode for this application.
|
||||
* @returns A pair with the optional system mode, and and the status.
|
||||
*/
|
||||
std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() override;
|
||||
std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() override;
|
||||
|
||||
std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() override;
|
||||
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities()
|
||||
override;
|
||||
|
||||
ResultStatus IsExecutable(bool& out_executable) override;
|
||||
|
||||
|
@ -18,7 +18,8 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||
timing = std::make_unique<Core::Timing>(1, 100);
|
||||
memory = std::make_unique<Memory::MemorySystem>();
|
||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||
*memory, *timing, [] {}, 0, 1, 0);
|
||||
*memory, *timing, [] {}, Kernel::MemoryMode::Prod, 1,
|
||||
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
|
||||
|
||||
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
||||
page_table = kernel->GetCurrentProcess()->vm_manager.page_table;
|
||||
|
@ -25,7 +25,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||
Core::Timing timing(1, 100);
|
||||
Memory::MemorySystem memory;
|
||||
Kernel::KernelSystem kernel(
|
||||
memory, timing, [] {}, 0, 1, 0);
|
||||
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
|
||||
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
|
||||
auto [server, client] = kernel.CreateSessionPair();
|
||||
HLERequestContext context(kernel, std::move(server), nullptr);
|
||||
|
||||
@ -248,7 +249,8 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||
Core::Timing timing(1, 100);
|
||||
Memory::MemorySystem memory;
|
||||
Kernel::KernelSystem kernel(
|
||||
memory, timing, [] {}, 0, 1, 0);
|
||||
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
|
||||
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
|
||||
auto [server, client] = kernel.CreateSessionPair();
|
||||
HLERequestContext context(kernel, std::move(server), nullptr);
|
||||
|
||||
|
@ -11,7 +11,8 @@ TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") {
|
||||
Core::Timing timing(1, 100);
|
||||
Memory::MemorySystem memory;
|
||||
Kernel::KernelSystem kernel(
|
||||
memory, timing, [] {}, 0, 1, 0);
|
||||
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
|
||||
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
|
||||
SECTION("these regions should not be mapped on an empty process") {
|
||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||
CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
|
||||
|
@ -17,7 +17,8 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
|
||||
Core::Timing timing(1, 100);
|
||||
Memory::MemorySystem memory;
|
||||
Kernel::KernelSystem kernel(
|
||||
memory, timing, [] {}, 0, 1, 0);
|
||||
memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
|
||||
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
|
||||
Kernel::Process process(kernel);
|
||||
SECTION("mapping memory") {
|
||||
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
|
||||
|
Loading…
Reference in New Issue
Block a user