Merge branch 'master' of https://github.com/GPUCode/citra into vulkan-2

This commit is contained in:
GPUCode
2023-03-02 16:19:54 +02:00
30 changed files with 1060 additions and 761 deletions

View File

@@ -17,7 +17,7 @@ ccache -s
mkdir build && cd build
# TODO: LibreSSL ASM disabled due to platform detection issues in build.
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" \
-DCMAKE_OSX_ARCHITECTURES="$TARGET_ARCH" \
-DENABLE_QT_TRANSLATION=ON \
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
@@ -30,4 +30,7 @@ ninja
ccache -s
ctest -VV -C Release
CURRENT_ARCH=`arch`
if [ "$TARGET_ARCH" = "$CURRENT_ARCH" ]; then
ctest -VV -C Release
fi

45
.ci/macos/universal.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash -ex
. .ci/common/pre-upload.sh
REV_NAME="citra-osx-${GITDATE}-${GITREV}"
ARCHIVE_NAME="${REV_NAME}.tar.gz"
COMPRESSION_FLAGS="-czvf"
ARTIFACTS_LIST=($ARTIFACTS)
# Set up the base artifact to combine into.
BASE_ARTIFACT=${ARTIFACTS_LIST[0]}
BASE_ARTIFACT_ARCH="${BASE_ARTIFACT##*-}"
tar xf $BASE_ARTIFACT/$REV_NAME.tar.gz -C $BASE_ARTIFACT
mv $BASE_ARTIFACT/$REV_NAME $REV_NAME
# Executable binary paths that need to be combined.
BIN_PATHS=(citra citra-room citra-qt.app/Contents/MacOS/citra-qt)
# Dylib paths that need to be combined.
IFS=$'\n'
DYLIB_PATHS=($(cd $REV_NAME && find . -name '*.dylib'))
unset IFS
# Combine all of the executable binaries and dylibs.
for OTHER_ARTIFACT in "${ARTIFACTS_LIST[@]:1}"; do
OTHER_ARTIFACT_ARCH="${OTHER_ARTIFACT##*-}"
tar xf $OTHER_ARTIFACT/$REV_NAME.tar.gz -C $OTHER_ARTIFACT
for BIN_PATH in "${BIN_PATHS[@]}"; do
lipo -create -output $REV_NAME/$BIN_PATH $REV_NAME/$BIN_PATH $OTHER_ARTIFACT/$REV_NAME/$BIN_PATH
done
for DYLIB_PATH in "${DYLIB_PATHS[@]}"; do
# Only merge if the libraries do not have conflicting arches, otherwise it will fail.
DYLIB_INFO=`file $REV_NAME/$DYLIB_PATH`
OTHER_DYLIB_INFO=`file $OTHER_ARTIFACT/$REV_NAME/$DYLIB_PATH`
if ! [[ "$DYLIB_INFO" =~ "$OTHER_ARTIFACT_ARCH" ]] && ! [[ "$OTHER_DYLIB_INFO" =~ "$BASE_ARTIFACT_ARCH" ]]; then
lipo -create -output $REV_NAME/$DYLIB_PATH $REV_NAME/$DYLIB_PATH $OTHER_ARTIFACT/$REV_NAME/$DYLIB_PATH
fi
done
done
. .ci/common/post-upload.sh

View File

@@ -74,6 +74,9 @@ jobs:
path: artifacts/
macos:
runs-on: macos-latest
strategy:
matrix:
arch: ["x86_64", "arm64"]
steps:
- uses: actions/checkout@v3
with:
@@ -82,9 +85,9 @@ jobs:
uses: actions/cache@v3
with:
path: ~/Library/Caches/ccache
key: ${{ runner.os }}-macos-${{ github.sha }}
key: ${{ runner.os }}-macos-${{ matrix.arch }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-macos-
${{ runner.os }}-macos-${{ matrix.arch }}-
- name: Query tag name
uses: little-core-labs/get-git-tag@v3.0.2
id: tagName
@@ -95,13 +98,49 @@ jobs:
env:
MACOSX_DEPLOYMENT_TARGET: "10.13"
ENABLE_COMPATIBILITY_REPORTING: "ON"
TARGET_ARCH: ${{ matrix.arch }}
- name: Pack
run: ./.ci/macos/upload.sh
- name: Upload
uses: actions/upload-artifact@v3
with:
name: macos
name: macos-${{ matrix.arch }}
path: artifacts/
macos-universal:
runs-on: macos-latest
needs: macos
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Query tag name
uses: little-core-labs/get-git-tag@v3.0.2
id: tagName
- name: Download x86 build
uses: actions/download-artifact@master
with:
name: macos-x86_64
path: macos-x86_64/
- name: Download ARM64 build
uses: actions/download-artifact@master
with:
name: macos-arm64
path: macos-arm64/
- name: Create universal app
run: ./.ci/macos/universal.sh
env:
ARTIFACTS: macos-x86_64 macos-arm64
# - name: Upload
# uses: actions/upload-artifact@v3
# with:
# name: macos
# path: artifacts/
- name: Delete intermediate artifacts
uses: geekyeggo/delete-artifact@v2
with:
name: |
macos-x86_64
macos-arm64
windows:
runs-on: windows-latest
steps:
@@ -196,7 +235,7 @@ jobs:
TRANSIFEX_API_TOKEN: ${{ secrets.TRANSIFEX_API_TOKEN }}
release:
runs-on: ubuntu-latest
needs: [build, android, macos, source, windows]
needs: [build, android, macos-universal, source, windows]
if: ${{ startsWith(github.ref, 'refs/tags/') }}
steps:
- uses: actions/download-artifact@v3

View File

@@ -727,8 +727,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_LoadState(JNIEnv* env, jclass clazz
}
void Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env, jclass clazz) {
// TODO: Log the Common::g_build_fullname once the CI is setup for android
LOG_INFO(Frontend, "Citra Version: Android Beta | {}-{}", Common::g_scm_branch,
LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
Common::g_scm_desc);
LOG_INFO(Frontend, "Host CPU: {}", Common::GetCPUCaps().cpu_string);
// There is no decent way to get the OS version, so we log the API level instead.

View File

@@ -113,7 +113,6 @@ __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
#endif
constexpr int default_mouse_timeout = 2500;
constexpr int num_options_3d = 5;
/**
* "Callouts" are one-time instructional messages shown to the user. In the config settings, there
@@ -221,7 +220,6 @@ GMainWindow::GMainWindow()
ConnectMenuEvents();
ConnectWidgetEvents();
Connect3DStateEvents();
LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
Common::g_scm_desc);
@@ -362,20 +360,6 @@ void GMainWindow::InitializeWidgets() {
statusBar()->insertPermanentWidget(0, graphics_api_button);
option_3d_button = new QPushButton();
option_3d_button->setObjectName(QStringLiteral("3DOptionStatusBarButton"));
option_3d_button->setFocusPolicy(Qt::NoFocus);
option_3d_button->setToolTip(tr("Indicates the current 3D setting. Click to toggle."));
factor_3d_slider = new QSlider(Qt::Orientation::Horizontal, this);
factor_3d_slider->setStyleSheet(QStringLiteral("QSlider { padding: 4px; }"));
factor_3d_slider->setToolTip(tr("Current 3D factor while 3D is enabled."));
factor_3d_slider->setRange(0, 100);
Update3DState();
statusBar()->insertPermanentWidget(1, option_3d_button);
statusBar()->insertPermanentWidget(2, factor_3d_slider);
statusBar()->addPermanentWidget(multiplayer_state->GetStatusText());
statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon());
@@ -627,8 +611,6 @@ void GMainWindow::InitializeHotkeys() {
connect_shortcut(QStringLiteral("Mute Audio"),
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
connect_shortcut(QStringLiteral("Toggle 3D"), &GMainWindow::Toggle3D);
// We use "static" here in order to avoid capturing by lambda due to a MSVC bug, which makes the
// variable hold a garbage value after this function exits
static constexpr u16 FACTOR_3D_STEP = 5;
@@ -885,12 +867,6 @@ void GMainWindow::UpdateMenuState() {
}
}
void GMainWindow::Connect3DStateEvents() {
connect(option_3d_button, &QPushButton::clicked, this, &GMainWindow::Toggle3D);
connect(factor_3d_slider, qOverload<int>(&QSlider::valueChanged), this,
[](int value) { Settings::values.factor_3d = value; });
}
void GMainWindow::OnDisplayTitleBars(bool show) {
QList<QDockWidget*> widgets = findChildren<QDockWidget*>();
@@ -1971,7 +1947,6 @@ void GMainWindow::OnConfigure() {
}
UpdateSecondaryWindowVisibility();
UpdateAPIIndicator(false);
Update3DState();
} else {
Settings::values.input_profiles = old_input_profiles;
Settings::values.touch_from_button_maps = old_touch_from_button_maps;
@@ -2265,18 +2240,6 @@ void GMainWindow::UpdateStatusBar() {
emu_frametime_label->setVisible(true);
}
void GMainWindow::Update3DState() {
static const std::array options_3d = {tr("Off"), tr("Side by Side"), tr("Anaglyph"),
tr("Interlaced"), tr("Reverse Interlaced")};
option_3d_button->setText(
tr("3D: %1").arg(options_3d[static_cast<int>(Settings::values.render_3d.GetValue())]));
factor_3d_slider->setValue(Settings::values.factor_3d.GetValue());
factor_3d_slider->setVisible(Settings::values.render_3d.GetValue() !=
Settings::StereoRenderOption::Off);
}
void GMainWindow::HideMouseCursor() {
if (emu_thread == nullptr || !UISettings::values.hide_mouse.GetValue()) {
mouse_hide_timer.stop();
@@ -2408,12 +2371,6 @@ void GMainWindow::OnMenuAboutCitra() {
about.exec();
}
void GMainWindow::Toggle3D() {
Settings::values.render_3d = static_cast<Settings::StereoRenderOption>(
(static_cast<int>(Settings::values.render_3d.GetValue()) + 1) % num_options_3d);
Update3DState();
}
bool GMainWindow::ConfirmClose() {
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
return true;

View File

@@ -121,7 +121,6 @@ private:
void RestoreUIState();
void ConnectWidgetEvents();
void Connect3DStateEvents();
void ConnectMenuEvents();
void UpdateMenuState();
@@ -229,7 +228,6 @@ private slots:
void OnStopVideoDumping();
#endif
void OnCoreError(Core::System::ResultStatus, std::string);
void Toggle3D();
/// Called whenever a user selects Help->About Citra
void OnMenuAboutCitra();
void OnUpdateFound(bool found, bool error);
@@ -241,7 +239,6 @@ private slots:
private:
Q_INVOKABLE void OnMoviePlaybackCompleted();
void UpdateStatusBar();
void Update3DState();
void LoadTranslation();
void UpdateWindowTitle();
void UpdateUISettings();
@@ -267,8 +264,6 @@ private:
QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr;
QPushButton* graphics_api_button = nullptr;
QPushButton* option_3d_button = nullptr;
QSlider* factor_3d_slider = nullptr;
QTimer status_bar_update_timer;
bool message_label_used_for_movie = false;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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