code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <utility>
#include "core/file_sys/vfs/vfs_vector.h"

namespace FileSys {
VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name_, VirtualDir parent_)
    : data(std::move(initial_data)), parent(std::move(parent_)), name(std::move(name_)) {}

VectorVfsFile::~VectorVfsFile() = default;

std::string VectorVfsFile::GetName() const {
    return name;
}

size_t VectorVfsFile::GetSize() const {
    return data.size();
}

bool VectorVfsFile::Resize(size_t new_size) {
    data.resize(new_size);
    return true;
}

VirtualDir VectorVfsFile::GetContainingDirectory() const {
    return parent;
}

bool VectorVfsFile::IsWritable() const {
    return true;
}

bool VectorVfsFile::IsReadable() const {
    return true;
}

std::size_t VectorVfsFile::Read(u8* data_, std::size_t length, std::size_t offset) const {
    const auto read = std::min(length, data.size() - offset);
    std::memcpy(data_, data.data() + offset, read);
    return read;
}

std::size_t VectorVfsFile::Write(const u8* data_, std::size_t length, std::size_t offset) {
    if (offset + length > data.size())
        data.resize(offset + length);
    const auto write = std::min(length, data.size() - offset);
    std::memcpy(data.data() + offset, data_, write);
    return write;
}

bool VectorVfsFile::Rename(std::string_view name_) {
    name = name_;
    return true;
}

void VectorVfsFile::Assign(std::vector<u8> new_data) {
    data = std::move(new_data);
}

VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
                                       std::vector<VirtualDir> dirs_, std::string name_,
                                       VirtualDir parent_)
    : files(std::move(files_)), dirs(std::move(dirs_)), parent(std::move(parent_)),
      name(std::move(name_)) {}

VectorVfsDirectory::~VectorVfsDirectory() = default;

std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const {
    return files;
}

std::vector<VirtualDir> VectorVfsDirectory::GetSubdirectories() const {
    return dirs;
}

bool VectorVfsDirectory::IsWritable() const {
    return false;
}

bool VectorVfsDirectory::IsReadable() const {
    return true;
}

std::string VectorVfsDirectory::GetName() const {
    return name;
}

VirtualDir VectorVfsDirectory::GetParentDirectory() const {
    return parent;
}

template <typename T>
static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view name) {
    const auto iter =
        std::find_if(vec.begin(), vec.end(), [name](const T& e) { return e->GetName() == name; });
    if (iter == vec.end())
        return false;

    vec.erase(iter);
    return true;
}

bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
    return FindAndRemoveVectorElement(dirs, subdir_name);
}

bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
    return FindAndRemoveVectorElement(files, file_name);
}

bool VectorVfsDirectory::Rename(std::string_view name_) {
    name = name_;
    return true;
}

VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
    return nullptr;
}

VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
    return nullptr;
}

void VectorVfsDirectory::AddFile(VirtualFile file) {
    files.push_back(std::move(file));
}

void VectorVfsDirectory::AddDirectory(VirtualDir dir) {
    dirs.push_back(std::move(dir));
}
} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <cstring>
#include <memory>
#include <string>
#include <vector>
#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

// An implementation of VfsFile that is backed by a statically-sized array
template <std::size_t size>
class ArrayVfsFile : public VfsFile {
public:
    explicit ArrayVfsFile(const std::array<u8, size>& data_, std::string name_ = "",
                          VirtualDir parent_ = nullptr)
        : data(data_), name(std::move(name_)), parent(std::move(parent_)) {}

    std::string GetName() const override {
        return name;
    }

    std::size_t GetSize() const override {
        return size;
    }

    bool Resize(std::size_t new_size) override {
        return false;
    }

    VirtualDir GetContainingDirectory() const override {
        return parent;
    }

    bool IsWritable() const override {
        return false;
    }

    bool IsReadable() const override {
        return true;
    }

    std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override {
        const auto read = std::min(length, size - offset);
        std::memcpy(data_, data.data() + offset, read);
        return read;
    }

    std::size_t Write(const u8* data_, std::size_t length, std::size_t offset) override {
        return 0;
    }

    bool Rename(std::string_view new_name) override {
        name = new_name;
        return true;
    }

private:
    std::array<u8, size> data;
    std::string name;
    VirtualDir parent;
};

template <std::size_t Size, typename... Args>
std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& data,
                                                  Args&&... args) {
    return std::make_shared<ArrayVfsFile<Size>>(data, std::forward<Args>(args)...);
}

// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
class VectorVfsFile : public VfsFile {
public:
    explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name_ = "",
                           VirtualDir parent_ = nullptr);
    ~VectorVfsFile() override;

    std::string GetName() const override;
    std::size_t GetSize() const override;
    bool Resize(std::size_t new_size) override;
    VirtualDir GetContainingDirectory() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
    std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
    bool Rename(std::string_view name) override;

    virtual void Assign(std::vector<u8> new_data);

private:
    std::vector<u8> data;
    VirtualDir parent;
    std::string name;
};

// An implementation of VfsDirectory that maintains two vectors for subdirectories and files.
// Vector data is supplied upon construction.
class VectorVfsDirectory : public VfsDirectory {
public:
    explicit VectorVfsDirectory(std::vector<VirtualFile> files = {},
                                std::vector<VirtualDir> dirs = {}, std::string name = "",
                                VirtualDir parent = nullptr);
    ~VectorVfsDirectory() override;

    std::vector<VirtualFile> GetFiles() const override;
    std::vector<VirtualDir> GetSubdirectories() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::string GetName() const override;
    VirtualDir GetParentDirectory() const override;
    bool DeleteSubdirectory(std::string_view subdir_name) override;
    bool DeleteFile(std::string_view file_name) override;
    bool Rename(std::string_view name) override;
    VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
    VirtualFile CreateFile(std::string_view file_name) override;

    virtual void AddFile(VirtualFile file);
    virtual void AddDirectory(VirtualDir dir);

private:
    std::vector<VirtualFile> files;
    std::vector<VirtualDir> dirs;

    VirtualDir parent;
    std::string name;
};

} // namespace FileSys

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <array>
#include <cstring>
#include <regex>
#include <string>

#include <mbedtls/md.h>
#include <mbedtls/sha256.h>

#include "common/fs/path_util.h"
#include "common/hex_util.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/key_manager.h"
#include "core/crypto/xts_encryption_layer.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/vfs/vfs_offset.h"
#include "core/file_sys/xts_archive.h"
#include "core/loader/loader.h"

namespace FileSys {

constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000;

template <typename SourceData, typename SourceKey, typename Destination>
static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t key_length,
                             const SourceData* data, std::size_t data_length) {
    mbedtls_md_context_t context;
    mbedtls_md_init(&context);

    if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
        mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
        mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
        mbedtls_md_hmac_finish(&context, reinterpret_cast<u8*>(out))) {
        mbedtls_md_free(&context);
        return false;
    }

    mbedtls_md_free(&context);
    return true;
}

NAX::NAX(VirtualFile file_)
    : header(std::make_unique<NAXHeader>()),
      file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
    std::string path = Common::FS::SanitizePath(file->GetFullPath());
    static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
                                           std::regex_constants::ECMAScript |
                                               std::regex_constants::icase);
    std::smatch match;
    if (!std::regex_search(path, match, nax_path_regex)) {
        status = Loader::ResultStatus::ErrorBadNAXFilePath;
        return;
    }

    const std::string two_dir = Common::ToUpper(match[1]);
    const std::string nca_id = Common::ToLower(match[2]);
    status = Parse(fmt::format("/registered/{}/{}.nca", two_dir, nca_id));
}

NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
    : header(std::make_unique<NAXHeader>()),
      file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
    Core::Crypto::SHA256Hash hash{};
    mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
    status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
                               Common::HexToString(nca_id, false)));
}

NAX::~NAX() = default;

Loader::ResultStatus NAX::Parse(std::string_view path) {
    if (file == nullptr) {
        return Loader::ResultStatus::ErrorNullFile;
    }
    if (file->ReadObject(header.get()) != sizeof(NAXHeader)) {
        return Loader::ResultStatus::ErrorBadNAXHeader;
    }
    if (header->magic != Common::MakeMagic('N', 'A', 'X', '0')) {
        return Loader::ResultStatus::ErrorBadNAXHeader;
    }
    if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size) {
        return Loader::ResultStatus::ErrorIncorrectNAXFileSize;
    }

    keys.DeriveSDSeedLazy();
    std::array<Core::Crypto::Key256, 2> sd_keys{};
    const auto sd_keys_res = Core::Crypto::DeriveSDKeys(sd_keys, keys);
    if (sd_keys_res != Loader::ResultStatus::Success) {
        return sd_keys_res;
    }

    const auto enc_keys = header->key_area;

    std::size_t i = 0;
    for (; i < sd_keys.size(); ++i) {
        std::array<Core::Crypto::Key128, 2> nax_keys{};
        if (!CalculateHMAC256(nax_keys.data(), sd_keys[i].data(), 0x10, path.data(), path.size())) {
            return Loader::ResultStatus::ErrorNAXKeyHMACFailed;
        }

        for (std::size_t j = 0; j < nax_keys.size(); ++j) {
            Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(nax_keys[j],
                                                                 Core::Crypto::Mode::ECB);
            cipher.Transcode(enc_keys[j].data(), 0x10, header->key_area[j].data(),
                             Core::Crypto::Op::Decrypt);
        }

        Core::Crypto::SHA256Hash validation{};
        if (!CalculateHMAC256(validation.data(), &header->magic, 0x60, sd_keys[i].data() + 0x10,
                              0x10)) {
            return Loader::ResultStatus::ErrorNAXValidationHMACFailed;
        }
        if (header->hmac == validation)
            break;
    }

    if (i == 2) {
        return Loader::ResultStatus::ErrorNAXKeyDerivationFailed;
    }

    type = static_cast<NAXContentType>(i);

    Core::Crypto::Key256 final_key{};
    std::memcpy(final_key.data(), &header->key_area, final_key.size());
    const auto enc_file =
        std::make_shared<OffsetVfsFile>(file, header->file_size, NAX_HEADER_PADDING_SIZE);
    dec_file = std::make_shared<Core::Crypto::XTSEncryptionLayer>(enc_file, final_key);

    return Loader::ResultStatus::Success;
}

Loader::ResultStatus NAX::GetStatus() const {
    return status;
}

VirtualFile NAX::GetDecrypted() const {
    return dec_file;
}

std::unique_ptr<NCA> NAX::AsNCA() const {
    if (type == NAXContentType::NCA)
        return std::make_unique<NCA>(GetDecrypted());
    return nullptr;
}

NAXContentType NAX::GetContentType() const {
    return type;
}

std::vector<VirtualFile> NAX::GetFiles() const {
    return {dec_file};
}

std::vector<VirtualDir> NAX::GetSubdirectories() const {
    return {};
}

std::string NAX::GetName() const {
    return file->GetName();
}

VirtualDir NAX::GetParentDirectory() const {
    return file->GetContainingDirectory();
}

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/vfs/vfs.h"

namespace Loader {
enum class ResultStatus : u16;
}

namespace FileSys {

class NCA;

struct NAXHeader {
    std::array<u8, 0x20> hmac;
    u64_le magic;
    std::array<Core::Crypto::Key128, 2> key_area;
    u64_le file_size;
    INSERT_PADDING_BYTES(0x30);
};
static_assert(sizeof(NAXHeader) == 0x80, "NAXHeader has incorrect size.");

enum class NAXContentType : u8 {
    Save = 0,
    NCA = 1,
};

class NAX : public ReadOnlyVfsDirectory {
public:
    explicit NAX(VirtualFile file);
    explicit NAX(VirtualFile file, std::array<u8, 0x10> nca_id);
    ~NAX() override;

    Loader::ResultStatus GetStatus() const;

    VirtualFile GetDecrypted() const;

    std::unique_ptr<NCA> AsNCA() const;

    NAXContentType GetContentType() const;

    std::vector<VirtualFile> GetFiles() const override;

    std::vector<VirtualDir> GetSubdirectories() const override;

    std::string GetName() const override;

    VirtualDir GetParentDirectory() const override;

private:
    Loader::ResultStatus Parse(std::string_view path);

    std::unique_ptr<NAXHeader> header;

    VirtualFile file;
    Loader::ResultStatus status;
    NAXContentType type{};

    VirtualFile dec_file;

    Core::Crypto::KeyManager& keys;
};
} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core::Frontend {

class Applet {
public:
    virtual ~Applet() = default;
    virtual void Close() const = 0;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/frontend/applets/cabinet.h"

#include <thread>

namespace Core::Frontend {

CabinetApplet::~CabinetApplet() = default;

void DefaultCabinetApplet::Close() const {}

void DefaultCabinetApplet::ShowCabinetApplet(
    const CabinetCallback& callback, const CabinetParameters& parameters,
    std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
    LOG_WARNING(Service_AM, "(STUBBED) called");
    callback(false, {});
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>
#include "core/frontend/applets/applet.h"
#include "core/hle/service/nfp/nfp_types.h"

namespace Service::NFC {
class NfcDevice;
} // namespace Service::NFC

namespace Core::Frontend {

struct CabinetParameters {
    Service::NFP::TagInfo tag_info;
    Service::NFP::RegisterInfo register_info;
    Service::NFP::CabinetMode mode;
};

using CabinetCallback = std::function<void(bool, const std::string&)>;

class CabinetApplet : public Applet {
public:
    virtual ~CabinetApplet();
    virtual void ShowCabinetApplet(const CabinetCallback& callback,
                                   const CabinetParameters& parameters,
                                   std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const = 0;
};

class DefaultCabinetApplet final : public CabinetApplet {
public:
    void Close() const override;
    void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
                           std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/assert.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "core/frontend/applets/controller.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"

namespace Core::Frontend {

ControllerApplet::~ControllerApplet() = default;

DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {}

DefaultControllerApplet::~DefaultControllerApplet() = default;

void DefaultControllerApplet::Close() const {}

void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callback,
                                                     const ControllerParameters& parameters) const {
    LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");

    const std::size_t min_supported_players =
        parameters.enable_single_mode ? 1 : parameters.min_players;

    // Disconnect Handheld first.
    auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
    handheld->Disconnect();

    // Deduce the best configuration based on the input parameters.
    for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
        auto* controller = hid_core.GetEmulatedControllerByIndex(index);

        // First, disconnect all controllers regardless of the value of keep_controllers_connected.
        // This makes it easy to connect the desired controllers.
        controller->Disconnect();

        // Only connect the minimum number of required players.
        if (index >= min_supported_players) {
            continue;
        }

        // Connect controllers based on the following priority list from highest to lowest priority:
        // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
        if (parameters.allow_pro_controller) {
            controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
            controller->Connect(true);
        } else if (parameters.allow_dual_joycons) {
            controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
            controller->Connect(true);
        } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
            // Assign left joycons to even player indices and right joycons to odd player indices.
            // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
            // a right Joycon for Player 2 in 2 Player Assist mode.
            if (index % 2 == 0) {
                controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
                controller->Connect(true);
            } else {
                controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
                controller->Connect(true);
            }
        } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
                   !Settings::IsDockedMode()) {
            // We should *never* reach here under any normal circumstances.
            controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
            controller->Connect(true);
        } else {
            ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!");
        }
    }

    callback(true);
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>
#include <vector>

#include "common/common_types.h"
#include "core/frontend/applets/applet.h"

namespace Core::HID {
class HIDCore;
}

namespace Core::Frontend {

using BorderColor = std::array<u8, 4>;
using ExplainText = std::array<char, 0x81>;

struct ControllerParameters {
    s8 min_players{};
    s8 max_players{};
    bool keep_controllers_connected{};
    bool enable_single_mode{};
    bool enable_border_color{};
    std::vector<BorderColor> border_colors{};
    bool enable_explain_text{};
    std::vector<ExplainText> explain_text{};
    bool allow_pro_controller{};
    bool allow_handheld{};
    bool allow_dual_joycons{};
    bool allow_left_joycon{};
    bool allow_right_joycon{};
    bool allow_gamecube_controller{};
};

class ControllerApplet : public Applet {
public:
    using ReconfigureCallback = std::function<void(bool)>;

    virtual ~ControllerApplet();

    virtual void ReconfigureControllers(ReconfigureCallback callback,
                                        const ControllerParameters& parameters) const = 0;
};

class DefaultControllerApplet final : public ControllerApplet {
public:
    explicit DefaultControllerApplet(HID::HIDCore& hid_core_);
    ~DefaultControllerApplet() override;

    void Close() const override;
    void ReconfigureControllers(ReconfigureCallback callback,
                                const ControllerParameters& parameters) const override;

private:
    HID::HIDCore& hid_core;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/frontend/applets/error.h"

namespace Core::Frontend {

ErrorApplet::~ErrorApplet() = default;

void DefaultErrorApplet::Close() const {}

void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const {
    LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
                 error.GetModule(), error.GetDescription(), error.raw);
}

void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
                                                FinishedCallback finished) const {
    LOG_CRITICAL(
        Service_Fatal,
        "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
        error.GetModule(), error.GetDescription(), error.raw, time.count());
}

void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text,
                                             std::string detail_text,
                                             FinishedCallback finished) const {
    LOG_CRITICAL(Service_Fatal,
                 "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
                 error.GetModule(), error.GetDescription(), error.raw);
    LOG_CRITICAL(Service_Fatal, "    Main Text: {}", main_text);
    LOG_CRITICAL(Service_Fatal, "    Detail Text: {}", detail_text);
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <chrono>
#include <functional>

#include "core/frontend/applets/applet.h"
#include "core/hle/result.h"

namespace Core::Frontend {

class ErrorApplet : public Applet {
public:
    using FinishedCallback = std::function<void()>;

    virtual ~ErrorApplet();

    virtual void ShowError(Result error, FinishedCallback finished) const = 0;

    virtual void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
                                        FinishedCallback finished) const = 0;

    virtual void ShowCustomErrorText(Result error, std::string dialog_text,
                                     std::string fullscreen_text,
                                     FinishedCallback finished) const = 0;
};

class DefaultErrorApplet final : public ErrorApplet {
public:
    void Close() const override;
    void ShowError(Result error, FinishedCallback finished) const override;
    void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
                                FinishedCallback finished) const override;
    void ShowCustomErrorText(Result error, std::string main_text, std::string detail_text,
                             FinishedCallback finished) const override;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/frontend/applets/general.h"

namespace Core::Frontend {

ParentalControlsApplet::~ParentalControlsApplet() = default;

DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default;

void DefaultParentalControlsApplet::Close() const {}

void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> finished,
                                              bool suspend_future_verification_temporarily) {
    LOG_INFO(Service_AM,
             "Application requested frontend to verify PIN (normal), "
             "suspend_future_verification_temporarily={}, verifying as correct.",
             suspend_future_verification_temporarily);
    finished(true);
}

void DefaultParentalControlsApplet::VerifyPINForSettings(std::function<void(bool)> finished) {
    LOG_INFO(Service_AM,
             "Application requested frontend to verify PIN (settings), verifying as correct.");
    finished(true);
}

void DefaultParentalControlsApplet::RegisterPIN(std::function<void()> finished) {
    LOG_INFO(Service_AM, "Application requested frontend to register new PIN");
    finished();
}

void DefaultParentalControlsApplet::ChangePIN(std::function<void()> finished) {
    LOG_INFO(Service_AM, "Application requested frontend to change PIN to new value");
    finished();
}

PhotoViewerApplet::~PhotoViewerApplet() = default;

DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default;

void DefaultPhotoViewerApplet::Close() const {}

void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id,
                                                        std::function<void()> finished) const {
    LOG_INFO(Service_AM,
             "Application requested frontend to display stored photos for title_id={:016X}",
             title_id);
    finished();
}

void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) const {
    LOG_INFO(Service_AM, "Application requested frontend to display all stored photos.");
    finished();
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>
#include "common/common_types.h"

#include "core/frontend/applets/applet.h"

namespace Core::Frontend {

class ParentalControlsApplet : public Applet {
public:
    virtual ~ParentalControlsApplet();

    // Prompts the user to enter a PIN and calls the callback with whether or not it matches the
    // correct PIN. If the bool is passed, and the PIN was recently entered correctly, the frontend
    // should not prompt and simply return true.
    virtual void VerifyPIN(std::function<void(bool)> finished,
                           bool suspend_future_verification_temporarily) = 0;

    // Prompts the user to enter a PIN and calls the callback for correctness. Frontends can
    // optionally alert the user that this is to change parental controls settings.
    virtual void VerifyPINForSettings(std::function<void(bool)> finished) = 0;

    // Prompts the user to create a new PIN for pctl and stores it with the service.
    virtual void RegisterPIN(std::function<void()> finished) = 0;

    // Prompts the user to verify the current PIN and then store a new one into pctl.
    virtual void ChangePIN(std::function<void()> finished) = 0;
};

class DefaultParentalControlsApplet final : public ParentalControlsApplet {
public:
    ~DefaultParentalControlsApplet() override;

    void Close() const override;
    void VerifyPIN(std::function<void(bool)> finished,
                   bool suspend_future_verification_temporarily) override;
    void VerifyPINForSettings(std::function<void(bool)> finished) override;
    void RegisterPIN(std::function<void()> finished) override;
    void ChangePIN(std::function<void()> finished) override;
};

class PhotoViewerApplet : public Applet {
public:
    virtual ~PhotoViewerApplet();

    virtual void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const = 0;
    virtual void ShowAllPhotos(std::function<void()> finished) const = 0;
};

class DefaultPhotoViewerApplet final : public PhotoViewerApplet {
public:
    ~DefaultPhotoViewerApplet() override;

    void Close() const override;
    void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override;
    void ShowAllPhotos(std::function<void()> finished) const override;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/frontend/applets/mii_edit.h"

namespace Core::Frontend {

MiiEditApplet::~MiiEditApplet() = default;

void DefaultMiiEditApplet::Close() const {}

void DefaultMiiEditApplet::ShowMiiEdit(const MiiEditCallback& callback) const {
    LOG_WARNING(Service_AM, "(STUBBED) called");

    callback();
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>

#include "core/frontend/applets/applet.h"

namespace Core::Frontend {

class MiiEditApplet : public Applet {
public:
    using MiiEditCallback = std::function<void()>;

    virtual ~MiiEditApplet();

    virtual void ShowMiiEdit(const MiiEditCallback& callback) const = 0;
};

class DefaultMiiEditApplet final : public MiiEditApplet {
public:
    void Close() const override;
    void ShowMiiEdit(const MiiEditCallback& callback) const override;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/settings.h"
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"

namespace Core::Frontend {

ProfileSelectApplet::~ProfileSelectApplet() = default;

void DefaultProfileSelectApplet::Close() const {}

void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback,
                                               const ProfileSelectParameters& parameters) const {
    Service::Account::ProfileManager manager;
    callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
    LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>
#include <optional>

#include "common/uuid.h"
#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/frontend/applet_profile_select.h"

namespace Core::Frontend {

struct ProfileSelectParameters {
    Service::AM::Frontend::UiMode mode;
    std::array<Common::UUID, 8> invalid_uid_list;
    Service::AM::Frontend::UiSettingsDisplayOptions display_options;
    Service::AM::Frontend::UserSelectionPurpose purpose;
};

class ProfileSelectApplet : public Applet {
public:
    using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>;

    virtual ~ProfileSelectApplet();

    virtual void SelectProfile(SelectProfileCallback callback,
                               const ProfileSelectParameters& parameters) const = 0;
};

class DefaultProfileSelectApplet final : public ProfileSelectApplet {
public:
    void Close() const override;
    void SelectProfile(SelectProfileCallback callback,
                       const ProfileSelectParameters& parameters) const override;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <thread>

#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/frontend/applets/software_keyboard.h"

namespace Core::Frontend {

SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;

DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;

void DefaultSoftwareKeyboardApplet::Close() const {}

void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
    bool is_inline, KeyboardInitializeParameters initialize_parameters,
    SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) {
    if (is_inline) {
        LOG_WARNING(
            Service_AM,
            "(STUBBED) called, backend requested to initialize the inline software keyboard.");

        submit_inline_callback = std::move(submit_inline_callback_);
    } else {
        LOG_WARNING(
            Service_AM,
            "(STUBBED) called, backend requested to initialize the normal software keyboard.");

        submit_normal_callback = std::move(submit_normal_callback_);
    }

    parameters = std::move(initialize_parameters);

    LOG_INFO(Service_AM,
             "\nKeyboardInitializeParameters:"
             "\nok_text={}"
             "\nheader_text={}"
             "\nsub_text={}"
             "\nguide_text={}"
             "\ninitial_text={}"
             "\nmax_text_length={}"
             "\nmin_text_length={}"
             "\ninitial_cursor_position={}"
             "\ntype={}"
             "\npassword_mode={}"
             "\ntext_draw_type={}"
             "\nkey_disable_flags={}"
             "\nuse_blur_background={}"
             "\nenable_backspace_button={}"
             "\nenable_return_button={}"
             "\ndisable_cancel_button={}",
             Common::UTF16ToUTF8(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text),
             Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text),
             Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length,
             parameters.min_text_length, parameters.initial_cursor_position, parameters.type,
             parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw,
             parameters.use_blur_background, parameters.enable_backspace_button,
             parameters.enable_return_button, parameters.disable_cancel_button);
}

void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
    LOG_WARNING(Service_AM,
                "(STUBBED) called, backend requested to show the normal software keyboard.");

    SubmitNormalText(u"yuzu");
}

void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
    Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
    std::u16string text_check_message) const {
    LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
}

void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard(
    InlineAppearParameters appear_parameters) const {
    LOG_WARNING(Service_AM,
                "(STUBBED) called, backend requested to show the inline software keyboard.");

    LOG_INFO(Service_AM,
             "\nInlineAppearParameters:"
             "\nmax_text_length={}"
             "\nmin_text_length={}"
             "\nkey_top_scale_x={}"
             "\nkey_top_scale_y={}"
             "\nkey_top_translate_x={}"
             "\nkey_top_translate_y={}"
             "\ntype={}"
             "\nkey_disable_flags={}"
             "\nkey_top_as_floating={}"
             "\nenable_backspace_button={}"
             "\nenable_return_button={}"
             "\ndisable_cancel_button={}",
             appear_parameters.max_text_length, appear_parameters.min_text_length,
             appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
             appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
             appear_parameters.type, appear_parameters.key_disable_flags.raw,
             appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
             appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);

    std::thread([this] { SubmitInlineText(u"yuzu"); }).detach();
}

void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
    LOG_WARNING(Service_AM,
                "(STUBBED) called, backend requested to hide the inline software keyboard.");
}

void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const {
    LOG_WARNING(Service_AM,
                "(STUBBED) called, backend requested to change the inline keyboard text.");

    LOG_INFO(Service_AM,
             "\nInlineTextParameters:"
             "\ninput_text={}"
             "\ncursor_position={}",
             Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);

    submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
                           text_parameters.input_text, text_parameters.cursor_position);
}

void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
    LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
}

void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
    submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true);
}

void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    for (std::size_t index = 0; index < text.size(); ++index) {
        submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
                               std::u16string(text.data(), text.data() + index + 1),
                               static_cast<s32>(index) + 1);

        std::this_thread::sleep_for(std::chrono::milliseconds(250));
    }

    submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter,
                           std::u16string(text), static_cast<s32>(text.size()));
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>

#include "common/common_types.h"

#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"

namespace Core::Frontend {

struct KeyboardInitializeParameters {
    std::u16string ok_text;
    std::u16string header_text;
    std::u16string sub_text;
    std::u16string guide_text;
    std::u16string initial_text;
    char16_t left_optional_symbol_key;
    char16_t right_optional_symbol_key;
    u32 max_text_length;
    u32 min_text_length;
    s32 initial_cursor_position;
    Service::AM::Frontend::SwkbdType type;
    Service::AM::Frontend::SwkbdPasswordMode password_mode;
    Service::AM::Frontend::SwkbdTextDrawType text_draw_type;
    Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
    bool use_blur_background;
    bool enable_backspace_button;
    bool enable_return_button;
    bool disable_cancel_button;
};

struct InlineAppearParameters {
    u32 max_text_length;
    u32 min_text_length;
    f32 key_top_scale_x;
    f32 key_top_scale_y;
    f32 key_top_translate_x;
    f32 key_top_translate_y;
    Service::AM::Frontend::SwkbdType type;
    Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
    bool key_top_as_floating;
    bool enable_backspace_button;
    bool enable_return_button;
    bool disable_cancel_button;
};

struct InlineTextParameters {
    std::u16string input_text;
    s32 cursor_position;
};

class SoftwareKeyboardApplet : public Applet {
public:
    using SubmitInlineCallback =
        std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>;
    using SubmitNormalCallback =
        std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>;

    virtual ~SoftwareKeyboardApplet();

    virtual void InitializeKeyboard(bool is_inline,
                                    KeyboardInitializeParameters initialize_parameters,
                                    SubmitNormalCallback submit_normal_callback_,
                                    SubmitInlineCallback submit_inline_callback_) = 0;

    virtual void ShowNormalKeyboard() const = 0;

    virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
                                     std::u16string text_check_message) const = 0;

    virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;

    virtual void HideInlineKeyboard() const = 0;

    virtual void InlineTextChanged(InlineTextParameters text_parameters) const = 0;

    virtual void ExitKeyboard() const = 0;
};

class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
public:
    ~DefaultSoftwareKeyboardApplet() override;

    void Close() const override;

    void InitializeKeyboard(bool is_inline, KeyboardInitializeParameters initialize_parameters,
                            SubmitNormalCallback submit_normal_callback_,
                            SubmitInlineCallback submit_inline_callback_) override;

    void ShowNormalKeyboard() const override;

    void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
                             std::u16string text_check_message) const override;

    void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;

    void HideInlineKeyboard() const override;

    void InlineTextChanged(InlineTextParameters text_parameters) const override;

    void ExitKeyboard() const override;

private:
    void SubmitNormalText(std::u16string text) const;
    void SubmitInlineText(std::u16string_view text) const;

    KeyboardInitializeParameters parameters{};

    mutable SubmitNormalCallback submit_normal_callback;
    mutable SubmitInlineCallback submit_inline_callback;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/frontend/applets/web_browser.h"

namespace Core::Frontend {

WebBrowserApplet::~WebBrowserApplet() = default;

DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;

void DefaultWebBrowserApplet::Close() const {}

void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url,
                                               ExtractROMFSCallback extract_romfs_callback,
                                               OpenWebPageCallback callback) const {
    LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
                local_url);

    callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
}

void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url,
                                                  OpenWebPageCallback callback) const {
    LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
                external_url);

    callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>

#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/frontend/applet_web_browser_types.h"

namespace Core::Frontend {

class WebBrowserApplet : public Applet {
public:
    using ExtractROMFSCallback = std::function<void()>;
    using OpenWebPageCallback =
        std::function<void(Service::AM::Frontend::WebExitReason, std::string)>;

    virtual ~WebBrowserApplet();

    virtual void OpenLocalWebPage(const std::string& local_url,
                                  ExtractROMFSCallback extract_romfs_callback,
                                  OpenWebPageCallback callback) const = 0;

    virtual void OpenExternalWebPage(const std::string& external_url,
                                     OpenWebPageCallback callback) const = 0;
};

class DefaultWebBrowserApplet final : public WebBrowserApplet {
public:
    ~DefaultWebBrowserApplet() override;

    void Close() const override;

    void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback,
                          OpenWebPageCallback callback) const override;

    void OpenExternalWebPage(const std::string& external_url,
                             OpenWebPageCallback callback) const override;
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <mutex>
#include "core/frontend/emu_window.h"

namespace Core::Frontend {

EmuWindow::EmuWindow() {
    // TODO: Find a better place to set this.
    config.min_client_area_size =
        std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height);
    active_config = config;
}

EmuWindow::~EmuWindow() {}

std::pair<f32, f32> EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const {
    std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
    const float x =
        static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
        static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
    const float y =
        static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
        static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);

    return std::make_pair(x, y);
}

std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const {
    new_x = std::max(new_x, framebuffer_layout.screen.left);
    new_x = std::min(new_x, framebuffer_layout.screen.right - 1);

    new_y = std::max(new_y, framebuffer_layout.screen.top);
    new_y = std::min(new_y, framebuffer_layout.screen.bottom - 1);

    return std::make_pair(new_x, new_y);
}

void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) {
    NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
}

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>
#include <utility>

#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"

namespace Core::Frontend {

class GraphicsContext;

/// Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation
enum class WindowSystemType {
    Headless,
    Windows,
    X11,
    Wayland,
    Cocoa,
    Android,
};

/**
 * Abstraction class used to provide an interface between emulation code and the frontend
 * (e.g. SDL, QGLWidget, GLFW, etc...).
 *
 * Design notes on the interaction between EmuWindow and the emulation core:
 * - Generally, decisions on anything visible to the user should be left up to the GUI.
 *   For example, the emulation core should not try to dictate some window title or size.
 *   This stuff is not the core's business and only causes problems with regards to thread-safety
 *   anyway.
 * - Under certain circumstances, it may be desirable for the core to politely request the GUI
 *   to set e.g. a minimum window size. However, the GUI should always be free to ignore any
 *   such hints.
 * - EmuWindow may expose some of its state as read-only to the emulation core, however care
 *   should be taken to make sure the provided information is self-consistent. This requires
 *   some sort of synchronization (most of this is still a TODO).
 * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
 *   re-read the upper points again and think about it if you don't see this.
 */
class EmuWindow {
public:
    /// Data structure to store emuwindow configuration
    struct WindowConfig {
        bool fullscreen = false;
        int res_width = 0;
        int res_height = 0;
        std::pair<u32, u32> min_client_area_size;
    };

    /// Data describing host window system information
    struct WindowSystemInfo {
        // Window system type. Determines which GL context or Vulkan WSI is used.
        WindowSystemType type = WindowSystemType::Headless;

        // Connection to a display server. This is used on X11 and Wayland platforms.
        void* display_connection = nullptr;

        // Render surface. This is a pointer to the native window handle, which depends
        // on the platform. e.g. HWND for Windows, Window for X11. If the surface is
        // set to nullptr, the video backend will run in headless mode.
        void* render_surface = nullptr;

        // Scale of the render surface. For hidpi systems, this will be >1.
        float render_surface_scale = 1.0f;
    };

    /// Called from GPU thread when a frame is displayed.
    virtual void OnFrameDisplayed() {}

    /**
     * Returns a GraphicsContext that the frontend provides to be used for rendering.
     */
    virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const = 0;

    /// Returns if window is shown (not minimized)
    virtual bool IsShown() const = 0;

    /**
     * Returns currently active configuration.
     * @note Accesses to the returned object need not be consistent because it may be modified in
     * another thread
     */
    const WindowConfig& GetActiveConfig() const {
        return active_config;
    }

    bool StrictContextRequired() const {
        return strict_context_required;
    }

    /**
     * Requests the internal configuration to be replaced by the specified argument at some point in
     * the future.
     * @note This method is thread-safe, because it delays configuration changes to the GUI event
     * loop. Hence there is no guarantee on when the requested configuration will be active.
     */
    void SetConfig(const WindowConfig& val) {
        config = val;
    }

    /**
     * Returns system information about the drawing area.
     */
    const WindowSystemInfo& GetWindowInfo() const {
        return window_info;
    }

    /**
     * Gets the framebuffer layout (width, height, and screen regions)
     * @note This method is thread-safe
     */
    const Layout::FramebufferLayout& GetFramebufferLayout() const {
        return framebuffer_layout;
    }

    /**
     * Convenience method to update the current frame layout
     * Read from the current settings to determine which layout to use.
     */
    void UpdateCurrentFramebufferLayout(u32 width, u32 height);

protected:
    explicit EmuWindow();
    virtual ~EmuWindow();

    /**
     * Processes any pending configuration changes from the last SetConfig call.
     * This method invokes OnMinimalClientAreaChangeRequest if the corresponding configuration
     * field changed.
     * @note Implementations will usually want to call this from the GUI thread.
     * @todo Actually call this in existing implementations.
     */
    void ProcessConfigurationChanges() {
        // TODO: For proper thread safety, we should eventually implement a proper
        // multiple-writer/single-reader queue...

        if (config.min_client_area_size != active_config.min_client_area_size) {
            OnMinimalClientAreaChangeRequest(config.min_client_area_size);
            config.min_client_area_size = active_config.min_client_area_size;
        }
    }

    /**
     * Update framebuffer layout with the given parameter.
     * @note EmuWindow implementations will usually use this in window resize event handlers.
     */
    void NotifyFramebufferLayoutChanged(const Layout::FramebufferLayout& layout) {
        framebuffer_layout = layout;
    }

    /**
     * Update internal client area size with the given parameter.
     * @note EmuWindow implementations will usually use this in window resize event handlers.
     */
    void NotifyClientAreaSizeChanged(std::pair<u32, u32> size) {
        client_area_width = size.first;
        client_area_height = size.second;
    }

    /**
     * Converts a screen position into the equivalent touchscreen position.
     */
    std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const;

    /**
     * Clip the provided coordinates to be inside the touchscreen area.
     */
    std::pair<u32, u32> ClipToTouchScreen(u32 new_x, u32 new_y) const;

    WindowSystemInfo window_info;

    bool strict_context_required = false;

private:
    /**
     * Handler called when the minimal client area was requested to be changed via SetConfig.
     * For the request to be honored, EmuWindow implementations will usually reimplement this
     * function.
     */
    virtual void OnMinimalClientAreaChangeRequest(std::pair<u32, u32>) {
        // By default, ignore this request and do nothing.
    }

    Layout::FramebufferLayout framebuffer_layout; ///< Current framebuffer layout

    u32 client_area_width;  ///< Current client width, should be set by window impl.
    u32 client_area_height; ///< Current client height, should be set by window impl.

    WindowConfig config;        ///< Internal configuration (changes pending for being applied in
                                /// ProcessConfigurationChanges)
    WindowConfig active_config; ///< Internal active configuration
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <cmath>

#include "common/assert.h"
#include "common/settings.h"
#include "common/settings_enums.h"
#include "core/frontend/framebuffer_layout.h"

namespace Layout {

// Finds the largest size subrectangle contained in window area that is confined to the aspect ratio
template <class T>
static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
                                         float screen_aspect_ratio) {
    const float scale = std::min(static_cast<float>(window_area.GetWidth()),
                                 static_cast<float>(window_area.GetHeight()) / screen_aspect_ratio);
    return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
                                static_cast<T>(std::round(scale * screen_aspect_ratio))};
}

FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
    ASSERT(width > 0);
    ASSERT(height > 0);
    // The drawing code needs at least somewhat valid values for both screens
    // so just calculate them both even if the other isn't showing.
    FramebufferLayout res{
        .width = width,
        .height = height,
        .screen = {},
        .is_srgb = false,
    };

    const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);
    const float emulation_aspect_ratio = EmulationAspectRatio(
        static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);

    const Common::Rectangle<u32> screen_window_area{0, 0, width, height};
    Common::Rectangle<u32> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);

    if (window_aspect_ratio < emulation_aspect_ratio) {
        screen = screen.TranslateX((screen_window_area.GetWidth() - screen.GetWidth()) / 2);
    } else {
        screen = screen.TranslateY((height - screen.GetHeight()) / 2);
    }

    res.screen = screen;
    return res;
}

FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale) {
    const bool is_docked = Settings::IsDockedMode();
    const u32 screen_width = is_docked ? ScreenDocked::Width : ScreenUndocked::Width;
    const u32 screen_height = is_docked ? ScreenDocked::Height : ScreenUndocked::Height;

    const u32 width = static_cast<u32>(static_cast<f32>(screen_width) * res_scale);
    const u32 height = static_cast<u32>(static_cast<f32>(screen_height) * res_scale);

    return DefaultFrameLayout(width, height);
}

float EmulationAspectRatio(AspectRatio aspect, float window_aspect_ratio) {
    switch (aspect) {
    case AspectRatio::Default:
        return static_cast<float>(ScreenUndocked::Height) / ScreenUndocked::Width;
    case AspectRatio::R4_3:
        return 3.0f / 4.0f;
    case AspectRatio::R21_9:
        return 9.0f / 21.0f;
    case AspectRatio::R16_10:
        return 10.0f / 16.0f;
    case AspectRatio::StretchToWindow:
        return window_aspect_ratio;
    default:
        return static_cast<float>(ScreenUndocked::Height) / ScreenUndocked::Width;
    }
}

} // namespace Layout


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/common_types.h"
#include "common/math_util.h"

namespace Layout {

namespace MinimumSize {
constexpr u32 Width = 640;
constexpr u32 Height = 360;
} // namespace MinimumSize

namespace ScreenUndocked {
constexpr u32 Width = 1280;
constexpr u32 Height = 720;
} // namespace ScreenUndocked

namespace ScreenDocked {
constexpr u32 Width = 1920;
constexpr u32 Height = 1080;
} // namespace ScreenDocked

enum class AspectRatio {
    Default,
    R4_3,
    R21_9,
    R16_10,
    StretchToWindow,
};

/// Describes the layout of the window framebuffer
struct FramebufferLayout {
    u32 width{ScreenUndocked::Width};
    u32 height{ScreenUndocked::Height};
    Common::Rectangle<u32> screen;
    bool is_srgb{};
};

/**
 * Factory method for constructing a default FramebufferLayout
 * @param width Window framebuffer width in pixels
 * @param height Window framebuffer height in pixels
 * @return Newly created FramebufferLayout object with default screen regions initialized
 */
FramebufferLayout DefaultFrameLayout(u32 width, u32 height);

/**
 * Convenience method to get frame layout by resolution scale
 * @param res_scale resolution scale factor
 */
FramebufferLayout FrameLayoutFromResolutionScale(f32 res_scale);

/**
 * Convenience method to determine emulation aspect ratio
 * @param aspect Represents the index of aspect ratio stored in Settings::values.aspect_ratio
 * @param window_aspect_ratio Current window aspect ratio
 * @return Emulation render window aspect ratio
 */
float EmulationAspectRatio(AspectRatio aspect, float window_aspect_ratio);

} // namespace Layout


code:
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>

#include "common/dynamic_library.h"

namespace Core::Frontend {

/**
 * Represents a drawing context that supports graphics operations.
 */
class GraphicsContext {
public:
    virtual ~GraphicsContext() = default;

    /// Inform the driver to swap the front/back buffers and present the current image
    virtual void SwapBuffers() {}

    /// Makes the graphics context current for the caller thread
    virtual void MakeCurrent() {}

    /// Releases (dunno if this is the "right" word) the context from the caller thread
    virtual void DoneCurrent() {}

    /// Gets the GPU driver library (used by Android only)
    virtual std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() {
        return {};
    }

    class Scoped {
    public:
        [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
            context.MakeCurrent();
        }
        ~Scoped() {
            if (active) {
                context.DoneCurrent();
            }
        }

        /// In the event that context was destroyed before the Scoped is destroyed, this provides a
        /// mechanism to prevent calling a destroyed object's method during the deconstructor
        void Cancel() {
            active = false;
        }

    private:
        GraphicsContext& context;
        bool active{true};
    };

    /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
    /// ends
    [[nodiscard]] Scoped Acquire() {
        return Scoped{*this};
    }
};

} // namespace Core::Frontend


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <atomic>
#include <bit>
#include <functional>
#include <mutex>
#include <utility>
#include <vector>

#include "core/device_memory_manager.h"

namespace Core {

class GPUDirtyMemoryManager {
public:
    GPUDirtyMemoryManager() : current{default_transform} {
        back_buffer.reserve(256);
        front_buffer.reserve(256);
    }

    ~GPUDirtyMemoryManager() = default;

    void Collect(PAddr address, size_t size) {
        TransformAddress t = BuildTransform(address, size);
        TransformAddress tmp, original;
        do {
            tmp = current.load(std::memory_order_acquire);
            original = tmp;
            if (tmp.address != t.address) {
                if (IsValid(tmp.address)) {
                    std::scoped_lock lk(guard);
                    back_buffer.emplace_back(tmp);
                    current.exchange(t, std::memory_order_relaxed);
                    return;
                }
                tmp.address = t.address;
                tmp.mask = 0;
            }
            if ((tmp.mask | t.mask) == tmp.mask) {
                return;
            }
            tmp.mask |= t.mask;
        } while (!current.compare_exchange_weak(original, tmp, std::memory_order_release,
                                                std::memory_order_relaxed));
    }

    void Gather(std::function<void(PAddr, size_t)>& callback) {
        {
            std::scoped_lock lk(guard);
            TransformAddress t = current.exchange(default_transform, std::memory_order_relaxed);
            front_buffer.swap(back_buffer);
            if (IsValid(t.address)) {
                front_buffer.emplace_back(t);
            }
        }
        for (auto& transform : front_buffer) {
            size_t offset = 0;
            u64 mask = transform.mask;
            while (mask != 0) {
                const size_t empty_bits = std::countr_zero(mask);
                offset += empty_bits << align_bits;
                mask = mask >> empty_bits;

                const size_t continuous_bits = std::countr_one(mask);
                callback((static_cast<PAddr>(transform.address) << page_bits) + offset,
                         continuous_bits << align_bits);
                mask = continuous_bits < align_size ? (mask >> continuous_bits) : 0;
                offset += continuous_bits << align_bits;
            }
        }
        front_buffer.clear();
    }

private:
    struct alignas(8) TransformAddress {
        u32 address;
        u32 mask;
    };

    constexpr static size_t page_bits = DEVICE_PAGEBITS - 1;
    constexpr static size_t page_size = 1ULL << page_bits;
    constexpr static size_t page_mask = page_size - 1;

    constexpr static size_t align_bits = 6U;
    constexpr static size_t align_size = 1U << align_bits;
    constexpr static size_t align_mask = align_size - 1;
    constexpr static TransformAddress default_transform = {.address = ~0U, .mask = 0U};

    bool IsValid(PAddr address) {
        return address < (1ULL << 39);
    }

    template <typename T>
    T CreateMask(size_t top_bit, size_t minor_bit) {
        T mask = ~T(0);
        mask <<= (sizeof(T) * 8 - top_bit);
        mask >>= (sizeof(T) * 8 - top_bit);
        mask >>= minor_bit;
        mask <<= minor_bit;
        return mask;
    }

    TransformAddress BuildTransform(PAddr address, size_t size) {
        const size_t minor_address = address & page_mask;
        const size_t minor_bit = minor_address >> align_bits;
        const size_t top_bit = (minor_address + size + align_mask) >> align_bits;
        TransformAddress result{};
        result.address = static_cast<u32>(address >> page_bits);
        result.mask = CreateMask<u32>(top_bit, minor_bit);
        return result;
    }

    std::atomic<TransformAddress> current{};
    std::mutex guard;
    std::vector<TransformAddress> back_buffer;
    std::vector<TransformAddress> front_buffer;
};

} // namespace Core


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <iterator>
#include <memory>
#include <optional>
#include <span>
#include <vector>

#include "common/assert.h"
#include "common/scratch_buffer.h"

namespace Core::Memory {

enum GuestMemoryFlags : u32 {
    Read = 1 << 0,
    Write = 1 << 1,
    Safe = 1 << 2,
    Cached = 1 << 3,

    SafeRead = Read | Safe,
    SafeWrite = Write | Safe,
    SafeReadWrite = SafeRead | SafeWrite,
    SafeReadCachedWrite = SafeReadWrite | Cached,

    UnsafeRead = Read,
    UnsafeWrite = Write,
    UnsafeReadWrite = UnsafeRead | UnsafeWrite,
    UnsafeReadCachedWrite = UnsafeReadWrite | Cached,
};

namespace {
template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemory {
    using iterator = T*;
    using const_iterator = const T*;
    using value_type = T;
    using element_type = T;
    using iterator_category = std::contiguous_iterator_tag;

public:
    GuestMemory() = delete;
    explicit GuestMemory(M& memory, u64 addr, std::size_t size,
                         Common::ScratchBuffer<T>* backup = nullptr)
        : m_memory{memory}, m_addr{addr}, m_size{size} {
        static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
        if constexpr (FLAGS & GuestMemoryFlags::Read) {
            Read(addr, size, backup);
        }
    }

    ~GuestMemory() = default;

    T* data() noexcept {
        return m_data_span.data();
    }

    const T* data() const noexcept {
        return m_data_span.data();
    }

    size_t size() const noexcept {
        return m_size;
    }

    size_t size_bytes() const noexcept {
        return this->size() * sizeof(T);
    }

    [[nodiscard]] T* begin() noexcept {
        return this->data();
    }

    [[nodiscard]] const T* begin() const noexcept {
        return this->data();
    }

    [[nodiscard]] T* end() noexcept {
        return this->data() + this->size();
    }

    [[nodiscard]] const T* end() const noexcept {
        return this->data() + this->size();
    }

    T& operator[](size_t index) noexcept {
        return m_data_span[index];
    }

    const T& operator[](size_t index) const noexcept {
        return m_data_span[index];
    }

    void SetAddressAndSize(u64 addr, std::size_t size) noexcept {
        m_addr = addr;
        m_size = size;
        m_addr_changed = true;
    }

    std::span<T> Read(u64 addr, std::size_t size,
                      Common::ScratchBuffer<T>* backup = nullptr) noexcept {
        m_addr = addr;
        m_size = size;
        if (m_size == 0) {
            m_is_data_copy = true;
            return {};
        }

        if (this->TrySetSpan()) {
            if constexpr (FLAGS & GuestMemoryFlags::Safe) {
                m_memory.FlushRegion(m_addr, this->size_bytes());
            }
        } else {
            if (backup) {
                backup->resize_destructive(this->size());
                m_data_span = *backup;
            } else {
                m_data_copy.resize(this->size());
                m_data_span = std::span(m_data_copy);
            }
            m_is_data_copy = true;
            m_span_valid = true;
            if constexpr (FLAGS & GuestMemoryFlags::Safe) {
                m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
            } else {
                m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
            }
        }
        return m_data_span;
    }

    void Write(std::span<T> write_data) noexcept {
        if constexpr (FLAGS & GuestMemoryFlags::Cached) {
            m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
        } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
            m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
        } else {
            m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
        }
    }

    bool TrySetSpan() noexcept {
        if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
            m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
            m_span_valid = true;
            return true;
        }
        return false;
    }

protected:
    bool IsDataCopy() const noexcept {
        return m_is_data_copy;
    }

    bool AddressChanged() const noexcept {
        return m_addr_changed;
    }

    M& m_memory;
    u64 m_addr{};
    size_t m_size{};
    std::span<T> m_data_span{};
    std::vector<T> m_data_copy{};
    bool m_span_valid{false};
    bool m_is_data_copy{false};
    bool m_addr_changed{false};
};

template <typename M, typename T, GuestMemoryFlags FLAGS>
class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> {
public:
    GuestMemoryScoped() = delete;
    explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
                               Common::ScratchBuffer<T>* backup = nullptr)
        : GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
        if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
            if (!this->TrySetSpan()) {
                if (backup) {
                    this->m_data_span = *backup;
                    this->m_span_valid = true;
                    this->m_is_data_copy = true;
                }
            }
        }
    }

    ~GuestMemoryScoped() {
        if constexpr (FLAGS & GuestMemoryFlags::Write) {
            if (this->size() == 0) [[unlikely]] {
                return;
            }

            if (this->AddressChanged() || this->IsDataCopy()) {
                ASSERT(this->m_span_valid);
                if constexpr (FLAGS & GuestMemoryFlags::Cached) {
                    this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
                } else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
                    this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
                } else {
                    this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
                }
            } else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
                                 (FLAGS & GuestMemoryFlags::Cached)) {
                this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
            }
        }
    }
};
} // namespace

} // namespace Core::Memory


code:
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <tuple>

#include "common/bit_util.h"
#include "common/common_types.h"

namespace Core {

namespace Hardware {

constexpr u64 BASE_CLOCK_RATE = 1'020'000'000; // Default CPU Frequency = 1020 MHz
constexpr u64 CNTFREQ = 19'200'000;            // CNTPCT_EL0 Frequency = 19.2 MHz
constexpr u32 NUM_CPU_CORES = 4;               // Number of CPU Cores

// Virtual to Physical core map.
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
    0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
};

static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();

static constexpr inline u64 VirtualCoreMask = [] {
    u64 mask = 0;
    for (size_t i = 0; i < NumVirtualCores; ++i) {
        mask |= (UINT64_C(1) << i);
    }
    return mask;
}();

static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) {
    u64 p_core_mask = 0;
    while (v_core_mask != 0) {
        const u64 next = std::countr_zero(v_core_mask);
        v_core_mask &= ~(static_cast<u64>(1) << next);
        p_core_mask |= (static_cast<u64>(1) << VirtualToPhysicalCoreMap[next]);
    }
    return p_core_mask;
}

// Cortex-A57 supports 4 memory watchpoints
constexpr u64 NUM_WATCHPOINTS = 4;

} // namespace Hardware

} // namespace Core


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/common_types.h"

// This file contains yuzu's HLE API version constants.

namespace HLE::ApiVersion {

// Horizon OS version constants.

constexpr u8 HOS_VERSION_MAJOR = 12;
constexpr u8 HOS_VERSION_MINOR = 1;
constexpr u8 HOS_VERSION_MICRO = 0;

// NintendoSDK version constants.

constexpr u8 SDK_REVISION_MAJOR = 1;
constexpr u8 SDK_REVISION_MINOR = 0;

constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "76b10c2dab7d3aa73fc162f8dff1655e6a21caf4";
constexpr char DISPLAY_VERSION[] = "12.1.0";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 12.1.0-1.0";

// Atmosphere version constants.

constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 1;
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 0;
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 0;

constexpr u32 AtmosphereTargetFirmwareWithRevision(u8 major, u8 minor, u8 micro, u8 rev) {
    return u32{major} << 24 | u32{minor} << 16 | u32{micro} << 8 | u32{rev};
}

constexpr u32 AtmosphereTargetFirmware(u8 major, u8 minor, u8 micro) {
    return AtmosphereTargetFirmwareWithRevision(major, minor, micro, 0);
}

constexpr u32 GetTargetFirmware() {
    return AtmosphereTargetFirmware(HOS_VERSION_MAJOR, HOS_VERSION_MINOR, HOS_VERSION_MICRO);
}

} // namespace HLE::ApiVersion


code:
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"

namespace IPC {

/// Size of the command buffer area, in 32-bit words.
constexpr std::size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32);

enum class ControlCommand : u32 {
    ConvertSessionToDomain = 0,
    ConvertDomainToSession = 1,
    DuplicateSession = 2,
    QueryPointerBufferSize = 3,
    DuplicateSessionEx = 4,
    Unspecified,
};

enum class CommandType : u32 {
    Invalid = 0,
    LegacyRequest = 1,
    Close = 2,
    LegacyControl = 3,
    Request = 4,
    Control = 5,
    RequestWithContext = 6,
    ControlWithContext = 7,
    TIPC_Close = 15,
    TIPC_CommandRegion = 16, // Start of TIPC commands, this is an offset.
};

struct CommandHeader {
    union {
        u32_le raw_low;
        BitField<0, 16, CommandType> type;
        BitField<16, 4, u32> num_buf_x_descriptors;
        BitField<20, 4, u32> num_buf_a_descriptors;
        BitField<24, 4, u32> num_buf_b_descriptors;
        BitField<28, 4, u32> num_buf_w_descriptors;
    };

    enum class BufferDescriptorCFlag : u32 {
        Disabled = 0,
        InlineDescriptor = 1,
        OneDescriptor = 2,
    };

    union {
        u32_le raw_high;
        BitField<0, 10, u32> data_size;
        BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags;
        BitField<31, 1, u32> enable_handle_descriptor;
    };

    bool IsTipc() const {
        return type.Value() >= CommandType::TIPC_CommandRegion;
    }

    bool IsCloseCommand() const {
        switch (type.Value()) {
        case CommandType::Close:
        case CommandType::TIPC_Close:
            return true;
        default:
            return false;
        }
    }
};
static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect");

union HandleDescriptorHeader {
    u32_le raw_high;
    BitField<0, 1, u32> send_current_pid;
    BitField<1, 4, u32> num_handles_to_copy;
    BitField<5, 4, u32> num_handles_to_move;
};
static_assert(sizeof(HandleDescriptorHeader) == 4, "HandleDescriptorHeader size is incorrect");

struct BufferDescriptorX {
    union {
        BitField<0, 6, u32> counter_bits_0_5;
        BitField<6, 3, u32> address_bits_36_38;
        BitField<9, 3, u32> counter_bits_9_11;
        BitField<12, 4, u32> address_bits_32_35;
        BitField<16, 16, u32> size;
    };

    u32_le address_bits_0_31;

    u32_le Counter() const {
        u32_le counter{counter_bits_0_5};
        counter |= counter_bits_9_11 << 9;
        return counter;
    }

    VAddr Address() const {
        VAddr address{address_bits_0_31};
        address |= static_cast<VAddr>(address_bits_32_35) << 32;
        address |= static_cast<VAddr>(address_bits_36_38) << 36;
        return address;
    }

    u64 Size() const {
        return static_cast<u64>(size);
    }
};
static_assert(sizeof(BufferDescriptorX) == 8, "BufferDescriptorX size is incorrect");

struct BufferDescriptorABW {
    u32_le size_bits_0_31;
    u32_le address_bits_0_31;

    union {
        BitField<0, 2, u32> flags;
        BitField<2, 3, u32> address_bits_36_38;
        BitField<24, 4, u32> size_bits_32_35;
        BitField<28, 4, u32> address_bits_32_35;
    };

    VAddr Address() const {
        VAddr address{address_bits_0_31};
        address |= static_cast<VAddr>(address_bits_32_35) << 32;
        address |= static_cast<VAddr>(address_bits_36_38) << 36;
        return address;
    }

    u64 Size() const {
        u64 size{size_bits_0_31};
        size |= static_cast<u64>(size_bits_32_35) << 32;
        return size;
    }
};
static_assert(sizeof(BufferDescriptorABW) == 12, "BufferDescriptorABW size is incorrect");

struct BufferDescriptorC {
    u32_le address_bits_0_31;

    union {
        BitField<0, 16, u32> address_bits_32_47;
        BitField<16, 16, u32> size;
    };

    VAddr Address() const {
        VAddr address{address_bits_0_31};
        address |= static_cast<VAddr>(address_bits_32_47) << 32;
        return address;
    }

    u64 Size() const {
        return static_cast<u64>(size);
    }
};
static_assert(sizeof(BufferDescriptorC) == 8, "BufferDescriptorC size is incorrect");

struct DataPayloadHeader {
    u32_le magic;
    INSERT_PADDING_WORDS_NOINIT(1);
};
static_assert(sizeof(DataPayloadHeader) == 8, "DataPayloadHeader size is incorrect");

struct DomainMessageHeader {
    enum class CommandType : u32_le {
        SendMessage = 1,
        CloseVirtualHandle = 2,
    };

    union {
        // Used when responding to an IPC request, Server -> Client.
        struct {
            u32_le num_objects;
            INSERT_PADDING_WORDS_NOINIT(3);
        };

        // Used when performing an IPC request, Client -> Server.
        struct {
            union {
                BitField<0, 8, CommandType> command;
                BitField<8, 8, u32> input_object_count;
                BitField<16, 16, u32> size;
            };
            u32_le object_id;
            INSERT_PADDING_WORDS_NOINIT(2);
        };

        std::array<u32, 4> raw;
    };
};
static_assert(sizeof(DomainMessageHeader) == 16, "DomainMessageHeader size is incorrect");

} // namespace IPC


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

// All architectures must define NumArchitectureDeviceRegions.
constexpr inline const auto NumArchitectureDeviceRegions = 3;

constexpr inline const auto KMemoryRegionType_Uart =
    KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
constexpr inline const auto KMemoryRegionType_InterruptCpuInterface =
    KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1)
        .SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_InterruptDistributor =
    KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2)
        .SetAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_Uart.GetValue() == (0x1D));
static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() ==
              (0x2D | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_InterruptDistributor.GetValue() ==
              (0x4D | KMemoryRegionAttr_NoUserMap));


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/alignment.h"
#include "common/literals.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/k_trace.h"

namespace Kernel {

namespace {

using namespace Common::Literals;

constexpr size_t CarveoutAlignment = 0x20000;
constexpr size_t CarveoutSizeMax = (512_MiB) - CarveoutAlignment;

bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
    // Above firmware 2.0.0, the PMC is not mappable.
    return memory_layout.GetPhysicalMemoryRegionTree().Insert(
               0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap) &&
           memory_layout.GetPhysicalMemoryRegionTree().Insert(
               0x7000E400, 0xC00,
               KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap);
}

void InsertPoolPartitionRegionIntoBothTrees(KMemoryLayout& memory_layout, size_t start, size_t size,
                                            KMemoryRegionType phys_type,
                                            KMemoryRegionType virt_type, u32& cur_attr) {
    const u32 attr = cur_attr++;
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(start, size,
                                                              static_cast<u32>(phys_type), attr));
    const KMemoryRegion* phys = memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
        static_cast<u32>(phys_type), attr);
    ASSERT(phys != nullptr);
    ASSERT(phys->GetEndAddress() != 0);
    ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size,
                                                             static_cast<u32>(virt_type), attr));
}

} // namespace

namespace Init {

void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
    ASSERT(SetupPowerManagementControllerMemoryRegion(memory_layout));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x50041000, 0x1000,
        KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x50042000, 0x1000,
        KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));

    // Map IRAM unconditionally, to support debug-logging-to-iram build config.
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x40000000, 0x40000, KMemoryRegionType_LegacyLpsIram | KMemoryRegionAttr_ShouldKernelMap));

    // Above firmware 2.0.0, prevent mapping the bpmp exception vectors or the ipatch region.
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
}

void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
    const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
    const KPhysicalAddress physical_memory_base_address =
        KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);

    // Insert blocks into the tree.
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram));
    ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
        GetInteger(physical_memory_base_address), ReservedEarlyDramSize,
        KMemoryRegionType_DramReservedEarly));

    // Insert the KTrace block at the end of Dram, if KTrace is enabled.
    static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
    if constexpr (IsKTraceEnabled) {
        const KPhysicalAddress ktrace_buffer_phys_addr =
            physical_memory_base_address + intended_memory_size - KTraceBufferSize;
        ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
            GetInteger(ktrace_buffer_phys_addr), KTraceBufferSize,
            KMemoryRegionType_KernelTraceBuffer));
    }
}

void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout) {
    // Start by identifying the extents of the DRAM memory region.
    const auto dram_extents = memory_layout.GetMainMemoryPhysicalExtents();
    ASSERT(dram_extents.GetEndAddress() != 0);

    // Determine the end of the pool region.
    const u64 pool_end = dram_extents.GetEndAddress() - KTraceBufferSize;

    // Find the start of the kernel DRAM region.
    const KMemoryRegion* kernel_dram_region =
        memory_layout.GetPhysicalMemoryRegionTree().FindFirstDerived(
            KMemoryRegionType_DramKernelBase);
    ASSERT(kernel_dram_region != nullptr);

    const u64 kernel_dram_start = kernel_dram_region->GetAddress();
    ASSERT(Common::IsAligned(kernel_dram_start, CarveoutAlignment));

    // Find the start of the pool partitions region.
    const KMemoryRegion* pool_partitions_region =
        memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
            KMemoryRegionType_DramPoolPartition, 0);
    ASSERT(pool_partitions_region != nullptr);
    const u64 pool_partitions_start = pool_partitions_region->GetAddress();

    // Setup the pool partition layouts.
    // On 5.0.0+, setup modern 4-pool-partition layout.

    // Get Application and Applet pool sizes.
    const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize();
    const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize();
    const size_t unsafe_system_pool_min_size =
        KSystemControl::Init::GetMinimumNonSecureSystemPoolSize();

    // Decide on starting addresses for our pools.
    const u64 application_pool_start = pool_end - application_pool_size;
    const u64 applet_pool_start = application_pool_start - applet_pool_size;
    const u64 unsafe_system_pool_start = std::min(
        kernel_dram_start + CarveoutSizeMax,
        Common::AlignDown(applet_pool_start - unsafe_system_pool_min_size, CarveoutAlignment));
    const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start;

    // We want to arrange application pool depending on where the middle of dram is.
    const u64 dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2;
    u32 cur_pool_attr = 0;
    size_t total_overhead_size = 0;
    if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) {
        InsertPoolPartitionRegionIntoBothTrees(
            memory_layout, application_pool_start, application_pool_size,
            KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
            cur_pool_attr);
        total_overhead_size +=
            KMemoryManager::CalculateManagementOverheadSize(application_pool_size);
    } else {
        const size_t first_application_pool_size = dram_midpoint - application_pool_start;
        const size_t second_application_pool_size =
            application_pool_start + application_pool_size - dram_midpoint;
        InsertPoolPartitionRegionIntoBothTrees(
            memory_layout, application_pool_start, first_application_pool_size,
            KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
            cur_pool_attr);
        InsertPoolPartitionRegionIntoBothTrees(
            memory_layout, dram_midpoint, second_application_pool_size,
            KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
            cur_pool_attr);
        total_overhead_size +=
            KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size);
        total_overhead_size +=
            KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size);
    }

    // Insert the applet pool.
    InsertPoolPartitionRegionIntoBothTrees(memory_layout, applet_pool_start, applet_pool_size,
                                           KMemoryRegionType_DramAppletPool,
                                           KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr);
    total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size);

    // Insert the nonsecure system pool.
    InsertPoolPartitionRegionIntoBothTrees(
        memory_layout, unsafe_system_pool_start, unsafe_system_pool_size,
        KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool,
        cur_pool_attr);
    total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size);

    // Insert the pool management region.
    total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(
        (unsafe_system_pool_start - pool_partitions_start) - total_overhead_size);
    const u64 pool_management_start = unsafe_system_pool_start - total_overhead_size;
    const size_t pool_management_size = total_overhead_size;
    u32 pool_management_attr = 0;
    InsertPoolPartitionRegionIntoBothTrees(
        memory_layout, pool_management_start, pool_management_size,
        KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement,
        pool_management_attr);

    // Insert the system pool.
    const u64 system_pool_size = pool_management_start - pool_partitions_start;
    InsertPoolPartitionRegionIntoBothTrees(memory_layout, pool_partitions_start, system_pool_size,
                                           KMemoryRegionType_DramSystemPool,
                                           KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr);
}

} // namespace Init

} // namespace Kernel


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/kernel/k_typed_address.h"

namespace Kernel {

constexpr inline KPhysicalAddress MainMemoryAddress = 0x80000000;

} // namespace Kernel


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

// All architectures must define NumBoardDeviceRegions.
constexpr inline const auto NumBoardDeviceRegions = 6;
// UNUSED: .Derive(NumBoardDeviceRegions, 0);
constexpr inline const auto KMemoryRegionType_MemoryController =
    KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1)
        .SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_MemoryController1 =
    KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2)
        .SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_MemoryController0 =
    KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3)
        .SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_PowerManagementController =
    KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition();
constexpr inline const auto KMemoryRegionType_LegacyLpsDevices =
    KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5);
static_assert(KMemoryRegionType_MemoryController.GetValue() ==
              (0x55 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_MemoryController1.GetValue() ==
              (0x65 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_MemoryController0.GetValue() ==
              (0x95 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5));

static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5);

constexpr inline const auto NumLegacyLpsDevices = 7;
constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0);
constexpr inline const auto KMemoryRegionType_LegacyLpsIram =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1);
constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2);
constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3);
constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4);
constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5);
constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst =
    KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6);
static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5);
static_assert(KMemoryRegionType_LegacyLpsIram.GetValue() == 0x5C5);
static_assert(KMemoryRegionType_LegacyLpsFlowController.GetValue() == 0x6C5);
static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr.GetValue() == 0x9C5);
static_assert(KMemoryRegionType_LegacyLpsSemaphore.GetValue() == 0xAC5);
static_assert(KMemoryRegionType_LegacyLpsAtomics.GetValue() == 0xCC5);
static_assert(KMemoryRegionType_LegacyLpsClkRst.GetValue() == 0x11C5);