Skip to content

Commit

Permalink
libNX Applet Manager Initalization
Browse files Browse the repository at this point in the history
This commit completes the 'am' initialization for libNX
  • Loading branch information
PixelyIon committed Sep 27, 2019
1 parent a5d63c9 commit f7effe8
Show file tree
Hide file tree
Showing 15 changed files with 301 additions and 16 deletions.
1 change: 1 addition & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/kernel/services/set/sys.cpp
${source_DIR}/skyline/kernel/services/apm/apm.cpp
${source_DIR}/skyline/kernel/services/am/appletOE.cpp
${source_DIR}/skyline/kernel/services/fatal/fatal.cpp
)
target_link_libraries(skyline fmt tinyxml2)
target_compile_options(skyline PRIVATE -Wno-c++17-extensions)
3 changes: 1 addition & 2 deletions app/src/main/cpp/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <jni.h>
#include <pthread.h>
#include <csignal>
#include <string>
#include <thread>
Expand All @@ -12,7 +11,7 @@ bool Halt = false;
void ThreadMain(const std::string romPath, const std::string prefPath, const std::string logPath) {
auto logger = std::make_shared<skyline::Logger>(logPath);
auto settings = std::make_shared<skyline::Settings>(prefPath);
//settings->List(log); // (Uncomment when you want to print out all settings strings)
//settings->List(logger); // (Uncomment when you want to print out all settings strings)
auto start = std::chrono::steady_clock::now();
try {
skyline::kernel::OS os(logger, settings);
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/cpp/skyline/kernel/ipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace skyline::kernel::ipc {
}

if (payload->magic != constant::SfciMagic)
state.logger->Write(Logger::Warn, "Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));
state.logger->Write(Logger::Debug, "Unexpected Magic in PayloadHeader: 0x{:X}", u32(payload->magic));

if (header->c_flag == static_cast<u8>(BufferCFlag::SingleDescriptor)) {
vecBufC.push_back(reinterpret_cast<BufferDescriptorC *>(currPtr));
Expand Down
74 changes: 72 additions & 2 deletions app/src/main/cpp/skyline/kernel/services/am/appletOE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ namespace skyline::kernel::service::am {
{0x0, SFunc(IApplicationProxy::GetCommonStateGetter)},
{0x1, SFunc(IApplicationProxy::GetSelfController)},
{0x2, SFunc(IApplicationProxy::GetWindowController)},
{0x3, SFunc(IApplicationProxy::GetAudioController)},
{0x4, SFunc(IApplicationProxy::GetDisplayController)},
{0xB, SFunc(IApplicationProxy::GetLibraryAppletCreator)},
{0x14, SFunc(IApplicationProxy::GetApplicationFunctions)}
{0x14, SFunc(IApplicationProxy::GetApplicationFunctions)},
{0x3E8, SFunc(IApplicationProxy::GetDisplayController)}
}) {}

void IApplicationProxy::GetCommonStateGetter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
Expand All @@ -29,6 +32,14 @@ namespace skyline::kernel::service::am {
manager.NewService(Service::am_IWindowController, session, response);
}

void IApplicationProxy::GetAudioController(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
manager.NewService(Service::am_IAudioController, session, response);
}

void IApplicationProxy::GetDisplayController(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
manager.NewService(Service::am_IDisplayController, session, response);
}

void IApplicationProxy::GetLibraryAppletCreator(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
manager.NewService(Service::am_ILibraryAppletCreator, session, response);
}
Expand All @@ -37,18 +48,77 @@ namespace skyline::kernel::service::am {
manager.NewService(Service::am_IApplicationFunctions, session, response);
}

void IApplicationProxy::IDebugFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
manager.NewService(Service::am_IDebugFunctions, session, response);
}

ICommonStateGetter::ICommonStateGetter(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_ICommonStateGetter, {
}) {}
{0x0, SFunc(ICommonStateGetter::GetEventHandle)},
{0x9, SFunc(ICommonStateGetter::GetCurrentFocusState)},
{0x5, SFunc(ICommonStateGetter::GetOperationMode)},
{0x6, SFunc(ICommonStateGetter::GetPerformanceMode)}
}) {
operationMode = static_cast<OperationMode>(state.settings->GetBool("operation_mode"));
state.logger->Write(Logger::Info, "Switch on mode: {}", static_cast<bool>(operationMode) ? "Docked" : "Handheld");
}

void ICommonStateGetter::GetEventHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
messageEvent = state.thisProcess->NewHandle<type::KEvent>();
response.copyHandles.push_back(messageEvent->handle);
}

void ICommonStateGetter::GetCurrentFocusState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u8>(static_cast<u8>(ApplicationStatus::InFocus));
}

void ICommonStateGetter::GetOperationMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u8>(static_cast<u8>(operationMode));
}

void ICommonStateGetter::GetPerformanceMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u32>(static_cast<u32>(operationMode));
}

ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_ISelfController, {
{0xB, SFunc(ISelfController::SetOperationModeChangedNotification)},
{0xC, SFunc(ISelfController::SetPerformanceModeChangedNotification)},
{0xD, SFunc(ISelfController::SetFocusHandlingMode)}
}) {}

void ISelfController::SetFocusHandlingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}

void ISelfController::SetOperationModeChangedNotification(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}

void ISelfController::SetPerformanceModeChangedNotification(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}

IWindowController::IWindowController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IWindowController, {
{0x1, SFunc(IWindowController::GetAppletResourceUserId)},
{0xA, SFunc(IWindowController::AcquireForegroundRights)}
}) {}

void IWindowController::GetAppletResourceUserId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue(static_cast<u64>(state.thisProcess->mainThread));
}

void IWindowController::AcquireForegroundRights(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {}

IAudioController::IAudioController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IAudioController, {
}) {}

IDisplayController::IDisplayController(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IDisplayController, {
}) {}

ILibraryAppletCreator::ILibraryAppletCreator(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_ILibraryAppletCreator, {
}) {}

IApplicationFunctions::IApplicationFunctions(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IApplicationFunctions, {
{0x28, SFunc(IApplicationFunctions::NotifyRunning)}
}) {}

void IApplicationFunctions::NotifyRunning(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.WriteValue<u8>(1);
}

IDebugFunctions::IDebugFunctions(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, false, Service::am_IDebugFunctions, {
}) {}
}
116 changes: 116 additions & 0 deletions app/src/main/cpp/skyline/kernel/services/am/appletOE.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "../base_service.h"
#include "../serviceman.h"
#include "../../types/KProcess.h"
#include "../../types/KEvent.h"

namespace skyline::kernel::service::am {
/**
Expand Down Expand Up @@ -39,6 +41,16 @@ namespace skyline::kernel::service::am {
*/
void GetWindowController(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns #IAudioController (https://switchbrew.org/wiki/Applet_Manager_services#IAudioController)
*/
void GetAudioController(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns #IDisplayController (https://switchbrew.org/wiki/Applet_Manager_services#IDisplayController)
*/
void GetDisplayController(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns #ILibraryAppletCreator (https://switchbrew.org/wiki/Applet_Manager_services#ILibraryAppletCreator)
*/
Expand All @@ -48,30 +60,134 @@ namespace skyline::kernel::service::am {
* @brief This returns #IApplicationFunctions (https://switchbrew.org/wiki/Applet_Manager_services#IApplicationFunctions)
*/
void GetApplicationFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns #IDebugFunctions (https://switchbrew.org/wiki/Applet_Manager_services#IDebugFunctions)
*/
void IDebugFunctions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#ICommonStateGetter
*/
class ICommonStateGetter : public BaseService {
private:
std::shared_ptr<type::KEvent> messageEvent{};

enum class ApplicationStatus : u8 {
InFocus = 1, OutOfFocus = 2
};

enum class OperationMode : u8 {
Handheld = 0, Docked = 1
} operationMode;
public:
ICommonStateGetter(const DeviceState &state, ServiceManager &manager);

/**
* @brief This returns the handle to a KEvent object that is signalled whenever RecieveMessage has a message (https://switchbrew.org/wiki/Applet_Manager_services#GetEventHandle)
*/
void GetEventHandle(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns if an application is in focus or not. It always returns in focus on the emulator (https://switchbrew.org/wiki/Applet_Manager_services#GetCurrentFocusState)
*/
void GetCurrentFocusState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns the current OperationMode (https://switchbrew.org/wiki/Applet_Manager_services#GetOperationMode)
*/
void GetOperationMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This returns the current PerformanceMode (Same as operationMode but u32) (https://switchbrew.org/wiki/Applet_Manager_services#GetPerformanceMode)
*/
void GetPerformanceMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#ISelfController
*/
class ISelfController : public BaseService {
public:
ISelfController(const DeviceState &state, ServiceManager &manager);

/**
* @brief This function inputs a u8 bool flag and no output (Stubbed) (https://switchbrew.org/wiki/Applet_Manager_services#SetOperationModeChangedNotification)
*/
void SetOperationModeChangedNotification(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This function inputs a u8 bool flag and no output (Stubbed) (https://switchbrew.org/wiki/Applet_Manager_services#SetPerformanceModeChangedNotification)
*/
void SetPerformanceModeChangedNotification(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This function inputs 3 unknown u8 values and has no output (Stubbed) (https://switchbrew.org/wiki/Applet_Manager_services#GetCurrentFocusState)
*/
void SetFocusHandlingMode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#IWindowController
*/
class IWindowController : public BaseService {
public:
IWindowController(const DeviceState &state, ServiceManager &manager);

/**
* @brief This returns the PID of the current application (https://switchbrew.org/wiki/Applet_Manager_services#GetAppletResourceUserId)
*/
void GetAppletResourceUserId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

/**
* @brief This function has mo inputs or outputs (Stubbed) (https://switchbrew.org/wiki/Applet_Manager_services#AcquireForegroundRights)
*/
void AcquireForegroundRights(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#IAudioController
*/
class IAudioController : public BaseService {
public:
IAudioController(const DeviceState &state, ServiceManager &manager);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#IDisplayController
*/
class IDisplayController : public BaseService {
public:
IDisplayController(const DeviceState &state, ServiceManager &manager);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#ILibraryAppletCreator
*/
class ILibraryAppletCreator : public BaseService {
public:
ILibraryAppletCreator(const DeviceState &state, ServiceManager &manager);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#IApplicationFunctions
*/
class IApplicationFunctions : public BaseService {
public:
IApplicationFunctions(const DeviceState &state, ServiceManager &manager);

/**
* @brief This just returns 1 regardless of input (https://switchbrew.org/wiki/Applet_Manager_services#NotifyRunning)
*/
void NotifyRunning(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};

/**
* @brief https://switchbrew.org/wiki/Applet_Manager_services#IDebugFunctions
*/
class IDebugFunctions : public BaseService {
public:
IDebugFunctions(const DeviceState &state, ServiceManager &manager);
};
}
29 changes: 27 additions & 2 deletions app/src/main/cpp/skyline/kernel/services/base_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,29 @@ namespace skyline::kernel::service {
* @brief This contains an enum for every service that's present
*/
enum class Service {
sm, set_sys, apm, apm_ISession, am_appletOE, am_IApplicationProxy, am_ICommonStateGetter, am_IApplicationFunctions, am_ISelfController, am_IWindowController, am_ILibraryAppletCreator
sm,
fatal_u,
set_sys,
apm,
apm_ISession,
am_appletOE,
am_IApplicationProxy,
am_ICommonStateGetter,
am_IApplicationFunctions,
am_ISelfController,
am_IWindowController,
am_IAudioController,
am_IDisplayController,
am_ILibraryAppletCreator,
am_IDebugFunctions,
};

/**
* @brief A map from every service's name as a std::string to the corresponding serviceEnum
*/
const static std::unordered_map<std::string, Service> ServiceString = {
{"sm:", Service::sm},
{"fatal:u", Service::fatal_u},
{"set:sys", Service::set_sys},
{"apm", Service::apm},
{"apm:ISession", Service::apm_ISession},
Expand All @@ -30,8 +45,11 @@ namespace skyline::kernel::service {
{"am:ICommonStateGetter", Service::am_ICommonStateGetter},
{"am:ISelfController", Service::am_ISelfController},
{"am:IWindowController", Service::am_IWindowController},
{"am:IAudioController", Service::am_IAudioController},
{"am:IDisplayController", Service::am_IDisplayController},
{"am:ILibraryAppletCreator", Service::am_ILibraryAppletCreator},
{"am:IApplicationFunctions", Service::am_IApplicationFunctions},
{"am:IDebugFunctions", Service::am_IDebugFunctions},
};

class ServiceManager;
Expand Down Expand Up @@ -73,10 +91,17 @@ namespace skyline::kernel::service {
* @param response The corresponding IpcResponse object
*/
void HandleRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
std::function<void(type::KSession &, ipc::IpcRequest &, ipc::IpcResponse &)> function;
try {
vTable.at(request.payload->value)(session, request, response);
function = vTable.at(request.payload->value);
} catch (std::out_of_range&) {
state.logger->Write(Logger::Warn, "Cannot find function in service '{0}' (Type: {1}): 0x{2:X} ({2})", getName(), serviceType, u32(request.payload->value));
return;
}
try {
function(session, request, response);
} catch (std::exception& e) {
throw exception(e.what());
}
};

Expand Down
11 changes: 11 additions & 0 deletions app/src/main/cpp/skyline/kernel/services/fatal/fatal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "fatal.h"

namespace skyline::kernel::service::fatal {
fatalU::fatalU(const DeviceState &state, ServiceManager& manager) : BaseService(state, manager, false, Service::fatal_u, {
{0x0, SFunc(fatalU::ThrowFatal)}
}) {}

void fatalU::ThrowFatal(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
throw exception("A fatal error has caused emulation to stop");
}
}
19 changes: 19 additions & 0 deletions app/src/main/cpp/skyline/kernel/services/fatal/fatal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "../base_service.h"
#include "../serviceman.h"

namespace skyline::kernel::service::fatal {
/**
* @brief fatal_u is used by applications to throw errors (https://switchbrew.org/wiki/Fatal_services#fatal:u)
*/
class fatalU : public BaseService {
public:
fatalU(const DeviceState &state, ServiceManager& manager);

/**
* @brief This throws an exception so that emulation will quit
*/
void ThrowFatal(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
};
}
Loading

0 comments on commit f7effe8

Please sign in to comment.