early-access version 1559
This commit is contained in:
@@ -141,6 +141,9 @@ add_library(core STATIC
|
||||
hardware_interrupt_manager.h
|
||||
hle/ipc.h
|
||||
hle/ipc_helpers.h
|
||||
hle/kernel/board/nintendo/nx/k_system_control.cpp
|
||||
hle/kernel/board/nintendo/nx/k_system_control.h
|
||||
hle/kernel/board/nintendo/nx/secure_monitor.h
|
||||
hle/kernel/client_port.cpp
|
||||
hle/kernel/client_port.h
|
||||
hle/kernel/client_session.cpp
|
||||
@@ -169,9 +172,13 @@ add_library(core STATIC
|
||||
hle/kernel/k_memory_block.h
|
||||
hle/kernel/k_memory_block_manager.cpp
|
||||
hle/kernel/k_memory_block_manager.h
|
||||
hle/kernel/k_memory_layout.cpp
|
||||
hle/kernel/k_memory_layout.board.nintendo_nx.cpp
|
||||
hle/kernel/k_memory_layout.h
|
||||
hle/kernel/k_memory_manager.cpp
|
||||
hle/kernel/k_memory_manager.h
|
||||
hle/kernel/k_memory_region.h
|
||||
hle/kernel/k_memory_region_type.h
|
||||
hle/kernel/k_page_bitmap.h
|
||||
hle/kernel/k_page_heap.cpp
|
||||
hle/kernel/k_page_heap.h
|
||||
@@ -196,11 +203,11 @@ add_library(core STATIC
|
||||
hle/kernel/k_spin_lock.h
|
||||
hle/kernel/k_synchronization_object.cpp
|
||||
hle/kernel/k_synchronization_object.h
|
||||
hle/kernel/k_system_control.cpp
|
||||
hle/kernel/k_system_control.h
|
||||
hle/kernel/k_thread.cpp
|
||||
hle/kernel/k_thread.h
|
||||
hle/kernel/k_thread_queue.h
|
||||
hle/kernel/k_trace.h
|
||||
hle/kernel/k_writable_event.cpp
|
||||
hle/kernel/k_writable_event.h
|
||||
hle/kernel/kernel.cpp
|
||||
@@ -264,6 +271,7 @@ add_library(core STATIC
|
||||
hle/service/am/applets/general_backend.h
|
||||
hle/service/am/applets/profile_select.cpp
|
||||
hle/service/am/applets/profile_select.h
|
||||
hle/service/am/applets/software_keyboard_types.h
|
||||
hle/service/am/applets/software_keyboard.cpp
|
||||
hle/service/am/applets/software_keyboard.h
|
||||
hle/service/am/applets/web_browser.cpp
|
||||
|
@@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const {
|
||||
return raw.device_save_data_size;
|
||||
}
|
||||
|
||||
u32 NACP::GetParentalControlFlag() const {
|
||||
return raw.parental_control;
|
||||
}
|
||||
|
||||
const std::array<u8, 0x20>& NACP::GetRatingAge() const {
|
||||
return raw.rating_age;
|
||||
}
|
||||
|
||||
std::vector<u8> NACP::GetRawBytes() const {
|
||||
std::vector<u8> out(sizeof(RawNACP));
|
||||
std::memcpy(out.data(), &raw, sizeof(RawNACP));
|
||||
|
@@ -114,6 +114,8 @@ public:
|
||||
std::vector<u8> GetRawBytes() const;
|
||||
bool GetUserAccountSwitchLock() const;
|
||||
u64 GetDeviceSaveDataSize() const;
|
||||
u32 GetParentalControlFlag() const;
|
||||
const std::array<u8, 0x20>& GetRatingAge() const;
|
||||
|
||||
private:
|
||||
RawNACP raw{};
|
||||
|
@@ -1,29 +1,149 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/backend.h"
|
||||
#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;
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::RequestText(
|
||||
std::function<void(std::optional<std::u16string>)> out,
|
||||
SoftwareKeyboardParameters parameters) const {
|
||||
if (parameters.initial_text.empty())
|
||||
out(u"yuzu");
|
||||
DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
|
||||
|
||||
out(parameters.initial_text);
|
||||
void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
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::SendTextCheckDialog(
|
||||
std::u16string error_message, std::function<void()> finished_check) const {
|
||||
void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
|
||||
LOG_WARNING(Service_AM,
|
||||
"(STUBBED) called - Default fallback software keyboard does not support text "
|
||||
"check! (error_message={})",
|
||||
Common::UTF16ToUTF8(error_message));
|
||||
finished_check();
|
||||
"(STUBBED) called, backend requested to show the normal software keyboard.");
|
||||
|
||||
SubmitNormalText(u"yuzu");
|
||||
}
|
||||
|
||||
void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
|
||||
Service::AM::Applets::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::Applets::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::Applets::SwkbdResult::Ok, text);
|
||||
}
|
||||
|
||||
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::Applets::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::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
|
||||
static_cast<s32>(text.size()));
|
||||
}
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
@@ -1,54 +1,116 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include "common/bit_field.h"
|
||||
#include <thread>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/service/am/applets/software_keyboard_types.h"
|
||||
|
||||
namespace Core::Frontend {
|
||||
struct SoftwareKeyboardParameters {
|
||||
std::u16string submit_text;
|
||||
|
||||
struct KeyboardInitializeParameters {
|
||||
std::u16string ok_text;
|
||||
std::u16string header_text;
|
||||
std::u16string sub_text;
|
||||
std::u16string guide_text;
|
||||
std::u16string initial_text;
|
||||
std::size_t max_length;
|
||||
bool password;
|
||||
bool cursor_at_beginning;
|
||||
u32 max_text_length;
|
||||
u32 min_text_length;
|
||||
s32 initial_cursor_position;
|
||||
Service::AM::Applets::SwkbdType type;
|
||||
Service::AM::Applets::SwkbdPasswordMode password_mode;
|
||||
Service::AM::Applets::SwkbdTextDrawType text_draw_type;
|
||||
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
|
||||
bool use_blur_background;
|
||||
bool enable_backspace_button;
|
||||
bool enable_return_button;
|
||||
bool disable_cancel_button;
|
||||
};
|
||||
|
||||
union {
|
||||
u8 value;
|
||||
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::Applets::SwkbdType type;
|
||||
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
|
||||
bool key_top_as_floating;
|
||||
bool enable_backspace_button;
|
||||
bool enable_return_button;
|
||||
bool disable_cancel_button;
|
||||
};
|
||||
|
||||
BitField<1, 1, u8> disable_space;
|
||||
BitField<2, 1, u8> disable_address;
|
||||
BitField<3, 1, u8> disable_percent;
|
||||
BitField<4, 1, u8> disable_slash;
|
||||
BitField<6, 1, u8> disable_number;
|
||||
BitField<7, 1, u8> disable_download_code;
|
||||
};
|
||||
struct InlineTextParameters {
|
||||
std::u16string input_text;
|
||||
s32 cursor_position;
|
||||
};
|
||||
|
||||
class SoftwareKeyboardApplet {
|
||||
public:
|
||||
virtual ~SoftwareKeyboardApplet();
|
||||
|
||||
virtual void RequestText(std::function<void(std::optional<std::u16string>)> out,
|
||||
SoftwareKeyboardParameters parameters) const = 0;
|
||||
virtual void SendTextCheckDialog(std::u16string error_message,
|
||||
std::function<void()> finished_check) const = 0;
|
||||
virtual void InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) = 0;
|
||||
|
||||
virtual void ShowNormalKeyboard() const = 0;
|
||||
|
||||
virtual void ShowTextCheckDialog(Service::AM::Applets::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:
|
||||
void RequestText(std::function<void(std::optional<std::u16string>)> out,
|
||||
SoftwareKeyboardParameters parameters) const override;
|
||||
void SendTextCheckDialog(std::u16string error_message,
|
||||
std::function<void()> finished_check) const override;
|
||||
~DefaultSoftwareKeyboardApplet() override;
|
||||
|
||||
void InitializeKeyboard(
|
||||
bool is_inline, KeyboardInitializeParameters initialize_parameters,
|
||||
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
submit_normal_callback_,
|
||||
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback_) override;
|
||||
|
||||
void ShowNormalKeyboard() const override;
|
||||
|
||||
void ShowTextCheckDialog(Service::AM::Applets::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 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
|
||||
submit_normal_callback;
|
||||
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
|
||||
submit_inline_callback;
|
||||
};
|
||||
|
||||
} // namespace Core::Frontend
|
||||
|
@@ -12,7 +12,9 @@ InputInterpreter::InputInterpreter(Core::System& system)
|
||||
: npad{system.ServiceManager()
|
||||
.GetService<Service::HID::Hid>("hid")
|
||||
->GetAppletResource()
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {}
|
||||
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
|
||||
ResetButtonStates();
|
||||
}
|
||||
|
||||
InputInterpreter::~InputInterpreter() = default;
|
||||
|
||||
@@ -25,6 +27,17 @@ void InputInterpreter::PollInput() {
|
||||
button_states[current_index] = button_state;
|
||||
}
|
||||
|
||||
void InputInterpreter::ResetButtonStates() {
|
||||
previous_index = 0;
|
||||
current_index = 0;
|
||||
|
||||
button_states[0] = 0xFFFFFFFF;
|
||||
|
||||
for (std::size_t i = 1; i < button_states.size(); ++i) {
|
||||
button_states[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool InputInterpreter::IsButtonPressed(HIDButton button) const {
|
||||
return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
|
||||
}
|
||||
|
@@ -66,6 +66,9 @@ public:
|
||||
/// Gets a button state from HID and inserts it into the array of button states.
|
||||
void PollInput();
|
||||
|
||||
/// Resets all the button states to their defaults.
|
||||
void ResetButtonStates();
|
||||
|
||||
/**
|
||||
* Checks whether the button is pressed.
|
||||
*
|
||||
|
@@ -75,10 +75,14 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
|
||||
if (incoming) {
|
||||
// Populate the object lists with the data in the IPC request.
|
||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
|
||||
copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
|
||||
const u32 copy_handle{rp.Pop<Handle>()};
|
||||
copy_handles.push_back(copy_handle);
|
||||
copy_objects.push_back(handle_table.GetGeneric(copy_handle));
|
||||
}
|
||||
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
|
||||
move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
|
||||
const u32 move_handle{rp.Pop<Handle>()};
|
||||
move_handles.push_back(move_handle);
|
||||
move_objects.push_back(handle_table.GetGeneric(move_handle));
|
||||
}
|
||||
} else {
|
||||
// For responses we just ignore the handles, they're empty and will be populated when
|
||||
|
@@ -210,6 +210,14 @@ public:
|
||||
/// Helper function to test whether the output buffer at buffer_index can be written
|
||||
bool CanWriteBuffer(std::size_t buffer_index = 0) const;
|
||||
|
||||
Handle GetCopyHandle(std::size_t index) const {
|
||||
return copy_handles.at(index);
|
||||
}
|
||||
|
||||
Handle GetMoveHandle(std::size_t index) const {
|
||||
return move_handles.at(index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetCopyObject(std::size_t index) {
|
||||
return DynamicObjectCast<T>(copy_objects.at(index));
|
||||
@@ -285,6 +293,8 @@ private:
|
||||
std::shared_ptr<Kernel::ServerSession> server_session;
|
||||
std::shared_ptr<KThread> thread;
|
||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||
boost::container::small_vector<Handle, 8> move_handles;
|
||||
boost::container::small_vector<Handle, 8> copy_handles;
|
||||
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
|
||||
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
|
||||
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
|
||||
|
@@ -5,45 +5,34 @@
|
||||
#include <array>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_sizes.h"
|
||||
#include "core/hle/kernel/k_address_space_info.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
namespace {
|
||||
|
||||
enum : u64 {
|
||||
Size_1_MB = 0x100000,
|
||||
Size_2_MB = 2 * Size_1_MB,
|
||||
Size_128_MB = 128 * Size_1_MB,
|
||||
Size_1_GB = 0x40000000,
|
||||
Size_2_GB = 2 * Size_1_GB,
|
||||
Size_4_GB = 4 * Size_1_GB,
|
||||
Size_6_GB = 6 * Size_1_GB,
|
||||
Size_64_GB = 64 * Size_1_GB,
|
||||
Size_512_GB = 512 * Size_1_GB,
|
||||
Invalid = std::numeric_limits<u64>::max(),
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
|
||||
{ .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
|
||||
{ .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||
{ .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||
{ .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||
{ .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
|
||||
{ .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||
{ .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||
{ .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||
{ .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
||||
{ .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
|
||||
{ .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||
{ .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||
{ .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
|
||||
{ .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
|
||||
{ .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||
{ .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
|
||||
{ .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||
{ .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
||||
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
|
||||
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
|
||||
return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid;
|
||||
return index < AddressSpaceInfos.size() &&
|
||||
AddressSpaceInfos[index].address != Common::Size_Invalid;
|
||||
}
|
||||
|
||||
using IndexArray =
|
||||
|
@@ -1,23 +1,69 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_sizes.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/device_memory.h"
|
||||
#include "core/hle/kernel/k_memory_region.h"
|
||||
#include "core/hle/kernel/k_memory_region_type.h"
|
||||
#include "core/hle/kernel/memory_types.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024;
|
||||
constexpr std::size_t L1BlockSize = Common::Size_1_GB;
|
||||
constexpr std::size_t L2BlockSize = Common::Size_2_MB;
|
||||
|
||||
constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
|
||||
return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
|
||||
}
|
||||
|
||||
constexpr std::size_t MainMemorySize = Common::Size_4_GB;
|
||||
constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
|
||||
|
||||
constexpr std::size_t ReservedEarlyDramSize = 0x60000;
|
||||
constexpr std::size_t DramPhysicalAddress = 0x80000000;
|
||||
|
||||
constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
|
||||
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
|
||||
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
|
||||
|
||||
constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
|
||||
constexpr std::size_t KernelVirtualAddressSpaceEnd =
|
||||
KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
|
||||
constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1;
|
||||
constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ULL;
|
||||
constexpr std::size_t KernelVirtualAddressSpaceSize =
|
||||
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
|
||||
constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
|
||||
constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
|
||||
constexpr std::size_t KernelVirtualAddressCodeEnd =
|
||||
KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
|
||||
|
||||
constexpr std::size_t KernelPhysicalAddressSpaceBase = 0ULL;
|
||||
constexpr std::size_t KernelPhysicalAddressSpaceEnd =
|
||||
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth;
|
||||
constexpr std::size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ULL;
|
||||
constexpr std::size_t KernelPhysicalAddressSpaceSize =
|
||||
KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
|
||||
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
|
||||
|
||||
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
|
||||
constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
|
||||
|
||||
constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
|
||||
constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
|
||||
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
|
||||
|
||||
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
|
||||
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
|
||||
|
||||
constexpr std::size_t KernelResourceSize =
|
||||
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
|
||||
|
||||
constexpr bool IsKernelAddressKey(VAddr key) {
|
||||
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
|
||||
@@ -27,64 +73,327 @@ constexpr bool IsKernelAddress(VAddr address) {
|
||||
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
|
||||
}
|
||||
|
||||
class KMemoryRegion final {
|
||||
friend class KMemoryLayout;
|
||||
|
||||
public:
|
||||
constexpr PAddr StartAddress() const {
|
||||
return start_address;
|
||||
}
|
||||
|
||||
constexpr PAddr EndAddress() const {
|
||||
return end_address;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr KMemoryRegion() = default;
|
||||
constexpr KMemoryRegion(PAddr start_address, PAddr end_address)
|
||||
: start_address{start_address}, end_address{end_address} {}
|
||||
|
||||
const PAddr start_address{};
|
||||
const PAddr end_address{};
|
||||
};
|
||||
|
||||
class KMemoryLayout final {
|
||||
public:
|
||||
constexpr const KMemoryRegion& Application() const {
|
||||
return application;
|
||||
KMemoryLayout();
|
||||
|
||||
KMemoryRegionTree& GetVirtualMemoryRegionTree() {
|
||||
return virtual_tree;
|
||||
}
|
||||
const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
|
||||
return virtual_tree;
|
||||
}
|
||||
KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
|
||||
return physical_tree;
|
||||
}
|
||||
const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
|
||||
return physical_tree;
|
||||
}
|
||||
KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
|
||||
return virtual_linear_tree;
|
||||
}
|
||||
const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
|
||||
return virtual_linear_tree;
|
||||
}
|
||||
KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
|
||||
return physical_linear_tree;
|
||||
}
|
||||
const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
|
||||
return physical_linear_tree;
|
||||
}
|
||||
|
||||
constexpr const KMemoryRegion& Applet() const {
|
||||
return applet;
|
||||
VAddr GetLinearVirtualAddress(PAddr address) const {
|
||||
return address + linear_phys_to_virt_diff;
|
||||
}
|
||||
PAddr GetLinearPhysicalAddress(VAddr address) const {
|
||||
return address + linear_virt_to_phys_diff;
|
||||
}
|
||||
|
||||
constexpr const KMemoryRegion& System() const {
|
||||
return system;
|
||||
const KMemoryRegion* FindVirtual(VAddr address) const {
|
||||
return Find(address, GetVirtualMemoryRegionTree());
|
||||
}
|
||||
const KMemoryRegion* FindPhysical(PAddr address) const {
|
||||
return Find(address, GetPhysicalMemoryRegionTree());
|
||||
}
|
||||
|
||||
static constexpr KMemoryLayout GetDefaultLayout() {
|
||||
constexpr std::size_t application_size{0xcd500000};
|
||||
constexpr std::size_t applet_size{0x1fb00000};
|
||||
constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size};
|
||||
constexpr PAddr application_end_address{Core::DramMemoryMap::End};
|
||||
constexpr PAddr applet_start_address{application_start_address - applet_size};
|
||||
constexpr PAddr applet_end_address{applet_start_address + applet_size};
|
||||
constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd};
|
||||
constexpr PAddr system_end_address{applet_start_address};
|
||||
return {application_start_address, application_end_address, applet_start_address,
|
||||
applet_end_address, system_start_address, system_end_address};
|
||||
const KMemoryRegion* FindVirtualLinear(VAddr address) const {
|
||||
return Find(address, GetVirtualLinearMemoryRegionTree());
|
||||
}
|
||||
const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
|
||||
return Find(address, GetPhysicalLinearMemoryRegionTree());
|
||||
}
|
||||
|
||||
VAddr GetMainStackTopAddress(s32 core_id) const {
|
||||
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
|
||||
}
|
||||
VAddr GetIdleStackTopAddress(s32 core_id) const {
|
||||
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
|
||||
}
|
||||
VAddr GetExceptionStackTopAddress(s32 core_id) const {
|
||||
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
|
||||
}
|
||||
|
||||
VAddr GetSlabRegionAddress() const {
|
||||
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
|
||||
.GetAddress();
|
||||
}
|
||||
|
||||
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
|
||||
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
|
||||
}
|
||||
PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
|
||||
return GetDeviceRegion(type).GetAddress();
|
||||
}
|
||||
VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
|
||||
return GetDeviceRegion(type).GetPairAddress();
|
||||
}
|
||||
|
||||
const KMemoryRegion& GetPoolManagementRegion() const {
|
||||
return Dereference(
|
||||
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement));
|
||||
}
|
||||
const KMemoryRegion& GetPageTableHeapRegion() const {
|
||||
return Dereference(
|
||||
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap));
|
||||
}
|
||||
const KMemoryRegion& GetKernelStackRegion() const {
|
||||
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack));
|
||||
}
|
||||
const KMemoryRegion& GetTempRegion() const {
|
||||
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp));
|
||||
}
|
||||
|
||||
const KMemoryRegion& GetKernelTraceBufferRegion() const {
|
||||
return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(
|
||||
KMemoryRegionType_VirtualDramKernelTraceBuffer));
|
||||
}
|
||||
|
||||
const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
|
||||
return Dereference(FindVirtualLinear(address));
|
||||
}
|
||||
|
||||
const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
|
||||
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
|
||||
}
|
||||
const KMemoryRegion* GetPhysicalOnMemoryBootImageRegion() const {
|
||||
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage);
|
||||
}
|
||||
const KMemoryRegion* GetPhysicalDTBRegion() const {
|
||||
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
|
||||
}
|
||||
|
||||
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
|
||||
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
|
||||
KMemoryRegionType_DramUserPool);
|
||||
}
|
||||
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
|
||||
return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
|
||||
KMemoryRegionType_VirtualDramUserPool);
|
||||
}
|
||||
|
||||
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
|
||||
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
|
||||
KMemoryRegionType_DramUserPool);
|
||||
}
|
||||
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
|
||||
return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
|
||||
KMemoryRegionType_VirtualDramUserPool);
|
||||
}
|
||||
|
||||
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
|
||||
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
|
||||
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
|
||||
}
|
||||
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
|
||||
size_t size) const {
|
||||
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
|
||||
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
|
||||
}
|
||||
|
||||
std::pair<size_t, size_t> GetTotalAndKernelMemorySizes() const {
|
||||
size_t total_size = 0, kernel_size = 0;
|
||||
for (const auto& region : GetPhysicalMemoryRegionTree()) {
|
||||
if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
|
||||
total_size += region.GetSize();
|
||||
if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
|
||||
kernel_size += region.GetSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::make_pair(total_size, kernel_size);
|
||||
}
|
||||
|
||||
void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
|
||||
VAddr linear_virtual_start);
|
||||
static size_t GetResourceRegionSizeForInit();
|
||||
|
||||
auto GetKernelRegionExtents() const {
|
||||
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
|
||||
}
|
||||
auto GetKernelCodeRegionExtents() const {
|
||||
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode);
|
||||
}
|
||||
auto GetKernelStackRegionExtents() const {
|
||||
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack);
|
||||
}
|
||||
auto GetKernelMiscRegionExtents() const {
|
||||
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc);
|
||||
}
|
||||
auto GetKernelSlabRegionExtents() const {
|
||||
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab);
|
||||
}
|
||||
|
||||
auto GetLinearRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionAttr_LinearMapped);
|
||||
}
|
||||
|
||||
auto GetLinearRegionVirtualExtents() const {
|
||||
const auto physical = GetLinearRegionPhysicalExtents();
|
||||
return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
|
||||
GetLinearVirtualAddress(physical.GetLastAddress()), 0,
|
||||
KMemoryRegionType_None);
|
||||
}
|
||||
|
||||
auto GetMainMemoryPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram);
|
||||
}
|
||||
auto GetCarveoutRegionExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionAttr_CarveoutProtected);
|
||||
}
|
||||
|
||||
auto GetKernelRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramKernelBase);
|
||||
}
|
||||
auto GetKernelCodeRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramKernelCode);
|
||||
}
|
||||
auto GetKernelSlabRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramKernelSlab);
|
||||
}
|
||||
auto GetKernelPageTableHeapRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramKernelPtHeap);
|
||||
}
|
||||
auto GetKernelInitPageTableRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramKernelInitPt);
|
||||
}
|
||||
|
||||
auto GetKernelPoolManagementRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramPoolManagement);
|
||||
}
|
||||
auto GetKernelPoolPartitionRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramPoolPartition);
|
||||
}
|
||||
auto GetKernelSystemPoolRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramSystemPool);
|
||||
}
|
||||
auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramSystemNonSecurePool);
|
||||
}
|
||||
auto GetKernelAppletPoolRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramAppletPool);
|
||||
}
|
||||
auto GetKernelApplicationPoolRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_DramApplicationPool);
|
||||
}
|
||||
|
||||
auto GetKernelTraceBufferRegionPhysicalExtents() const {
|
||||
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionType_KernelTraceBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size,
|
||||
PAddr applet_start_address, std::size_t applet_size,
|
||||
PAddr system_start_address, std::size_t system_size)
|
||||
: application{application_start_address, application_size},
|
||||
applet{applet_start_address, applet_size}, system{system_start_address, system_size} {}
|
||||
template <typename AddressType>
|
||||
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
|
||||
const KMemoryRegionTree& tree, KMemoryRegionType type) {
|
||||
// Check if the cached region already contains the address.
|
||||
if (region != nullptr && region->Contains(address)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const KMemoryRegion application;
|
||||
const KMemoryRegion applet;
|
||||
const KMemoryRegion system;
|
||||
// Find the containing region, and update the cache.
|
||||
if (const KMemoryRegion* found = tree.Find(address);
|
||||
found != nullptr && found->IsDerivedFrom(type)) {
|
||||
region = found;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
|
||||
const KMemoryRegionTree& tree, KMemoryRegionType type) {
|
||||
// Get the end of the checked region.
|
||||
const u64 last_address = address + size - 1;
|
||||
|
||||
// Walk the tree to verify the region is correct.
|
||||
const KMemoryRegion* cur =
|
||||
(region != nullptr && region->Contains(address)) ? region : tree.Find(address);
|
||||
while (cur != nullptr && cur->IsDerivedFrom(type)) {
|
||||
if (last_address <= cur->GetLastAddress()) {
|
||||
region = cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
cur = cur->GetNext();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename AddressType>
|
||||
static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
|
||||
return tree.Find(address);
|
||||
}
|
||||
|
||||
static KMemoryRegion& Dereference(KMemoryRegion* region) {
|
||||
ASSERT(region != nullptr);
|
||||
return *region;
|
||||
}
|
||||
|
||||
static const KMemoryRegion& Dereference(const KMemoryRegion* region) {
|
||||
ASSERT(region != nullptr);
|
||||
return *region;
|
||||
}
|
||||
|
||||
VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
|
||||
const auto& region = Dereference(
|
||||
GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
|
||||
ASSERT(region.GetEndAddress() != 0);
|
||||
return region.GetEndAddress();
|
||||
}
|
||||
|
||||
private:
|
||||
u64 linear_phys_to_virt_diff{};
|
||||
u64 linear_virt_to_phys_diff{};
|
||||
KMemoryRegionAllocator memory_region_allocator;
|
||||
KMemoryRegionTree virtual_tree;
|
||||
KMemoryRegionTree physical_tree;
|
||||
KMemoryRegionTree virtual_linear_tree;
|
||||
KMemoryRegionTree physical_linear_tree;
|
||||
};
|
||||
|
||||
namespace Init {
|
||||
|
||||
// These should be generic, regardless of board.
|
||||
void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout);
|
||||
|
||||
// These may be implemented in a board-specific manner.
|
||||
void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout);
|
||||
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout);
|
||||
|
||||
} // namespace Init
|
||||
|
||||
} // namespace Kernel
|
||||
|
@@ -173,4 +173,16 @@ ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_page
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
std::size_t KMemoryManager::Impl::CalculateManagementOverheadSize(std::size_t region_size) {
|
||||
const std::size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
|
||||
const std::size_t optimize_map_size =
|
||||
(Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
|
||||
Common::BitSize<u64>()) *
|
||||
sizeof(u64);
|
||||
const std::size_t manager_meta_size =
|
||||
Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
|
||||
const std::size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
|
||||
return manager_meta_size + page_heap_size;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
@@ -29,6 +29,10 @@ public:
|
||||
|
||||
Shift = 4,
|
||||
Mask = (0xF << Shift),
|
||||
|
||||
// Aliases.
|
||||
Unsafe = Application,
|
||||
Secure = System,
|
||||
};
|
||||
|
||||
enum class Direction : u32 {
|
||||
@@ -56,6 +60,10 @@ public:
|
||||
static constexpr std::size_t MaxManagerCount = 10;
|
||||
|
||||
public:
|
||||
static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
|
||||
return Impl::CalculateManagementOverheadSize(region_size);
|
||||
}
|
||||
|
||||
static constexpr u32 EncodeOption(Pool pool, Direction dir) {
|
||||
return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
|
||||
(static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
|
||||
@@ -85,6 +93,16 @@ private:
|
||||
KPageHeap heap;
|
||||
Pool pool{};
|
||||
|
||||
public:
|
||||
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
|
||||
|
||||
static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
|
||||
std::size_t region_size) {
|
||||
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
|
||||
Common::BitSize<u64>()) *
|
||||
sizeof(u64);
|
||||
}
|
||||
|
||||
public:
|
||||
Impl() = default;
|
||||
|
||||
|
@@ -62,7 +62,7 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
|
||||
}
|
||||
|
||||
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
||||
std::scoped_lock lock{guard};
|
||||
KScopedSpinLock lk{guard};
|
||||
if (KThread* prev_highest_thread = state.highest_priority_thread;
|
||||
prev_highest_thread != highest_thread) {
|
||||
if (prev_highest_thread != nullptr) {
|
||||
@@ -637,11 +637,11 @@ void KScheduler::RescheduleCurrentCore() {
|
||||
if (phys_core.IsInterrupted()) {
|
||||
phys_core.ClearInterrupt();
|
||||
}
|
||||
guard.lock();
|
||||
guard.Lock();
|
||||
if (state.needs_scheduling.load()) {
|
||||
Schedule();
|
||||
} else {
|
||||
guard.unlock();
|
||||
guard.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +669,7 @@ void KScheduler::Unload(KThread* thread) {
|
||||
} else {
|
||||
prev_thread = nullptr;
|
||||
}
|
||||
thread->context_guard.unlock();
|
||||
thread->context_guard.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,7 +713,7 @@ void KScheduler::ScheduleImpl() {
|
||||
|
||||
// If we're not actually switching thread, there's nothing to do.
|
||||
if (next_thread == current_thread.load()) {
|
||||
guard.unlock();
|
||||
guard.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -732,7 +732,7 @@ void KScheduler::ScheduleImpl() {
|
||||
} else {
|
||||
old_context = &idle_thread->GetHostContext();
|
||||
}
|
||||
guard.unlock();
|
||||
guard.Unlock();
|
||||
|
||||
Common::Fiber::YieldTo(*old_context, *switch_fiber);
|
||||
/// When a thread wakes up, the scheduler may have changed to other in another core.
|
||||
@@ -748,24 +748,24 @@ void KScheduler::OnSwitch(void* this_scheduler) {
|
||||
void KScheduler::SwitchToCurrent() {
|
||||
while (true) {
|
||||
{
|
||||
std::scoped_lock lock{guard};
|
||||
KScopedSpinLock lk{guard};
|
||||
current_thread.store(state.highest_priority_thread);
|
||||
state.needs_scheduling.store(false);
|
||||
}
|
||||
const auto is_switch_pending = [this] {
|
||||
std::scoped_lock lock{guard};
|
||||
KScopedSpinLock lk{guard};
|
||||
return state.needs_scheduling.load();
|
||||
};
|
||||
do {
|
||||
auto next_thread = current_thread.load();
|
||||
if (next_thread != nullptr) {
|
||||
next_thread->context_guard.lock();
|
||||
next_thread->context_guard.Lock();
|
||||
if (next_thread->GetRawState() != ThreadState::Runnable) {
|
||||
next_thread->context_guard.unlock();
|
||||
next_thread->context_guard.Unlock();
|
||||
break;
|
||||
}
|
||||
if (next_thread->GetActiveCore() != core_id) {
|
||||
next_thread->context_guard.unlock();
|
||||
next_thread->context_guard.Unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -2,19 +2,16 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/hle/kernel/global_scheduler_context.h"
|
||||
#include "core/hle/kernel/k_priority_queue.h"
|
||||
#include "core/hle/kernel/k_scheduler_lock.h"
|
||||
#include "core/hle/kernel/k_scoped_lock.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
|
||||
namespace Common {
|
||||
class Fiber;
|
||||
@@ -195,7 +192,7 @@ private:
|
||||
u64 last_context_switch_time{};
|
||||
const s32 core_id;
|
||||
|
||||
Common::SpinLock guard{};
|
||||
KSpinLock guard{};
|
||||
};
|
||||
|
||||
class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
|
||||
|
@@ -2,14 +2,11 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
||||
@@ -34,7 +31,7 @@ public:
|
||||
} else {
|
||||
// Otherwise, we want to disable scheduling and acquire the spinlock.
|
||||
SchedulerType::DisableScheduling(kernel);
|
||||
spin_lock.lock();
|
||||
spin_lock.Lock();
|
||||
|
||||
// For debug, ensure that our state is valid.
|
||||
ASSERT(lock_count == 0);
|
||||
@@ -58,7 +55,7 @@ public:
|
||||
|
||||
// Note that we no longer hold the lock, and unlock the spinlock.
|
||||
owner_thread = nullptr;
|
||||
spin_lock.unlock();
|
||||
spin_lock.Unlock();
|
||||
|
||||
// Enable scheduling, and perform a rescheduling operation.
|
||||
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
|
||||
@@ -67,7 +64,7 @@ public:
|
||||
|
||||
private:
|
||||
KernelCore& kernel;
|
||||
Common::SpinLock spin_lock{};
|
||||
KAlignedSpinLock spin_lock{};
|
||||
s32 lock_count{};
|
||||
KThread* owner_thread{};
|
||||
};
|
||||
|
@@ -28,6 +28,12 @@ private:
|
||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
|
||||
using KAlignedSpinLock = KSpinLock;
|
||||
using KNotAlignedSpinLock = KSpinLock;
|
||||
|
||||
using KScopedSpinLock = KScopedLock<KSpinLock>;
|
||||
using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>;
|
||||
using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>;
|
||||
|
||||
} // namespace Kernel
|
||||
|
@@ -6,14 +6,18 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#define BOARD_NINTENDO_NX
|
||||
|
||||
#ifdef BOARD_NINTENDO_NX
|
||||
|
||||
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class KSystemControl {
|
||||
public:
|
||||
KSystemControl() = default;
|
||||
|
||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
||||
static u64 GenerateRandomU64();
|
||||
};
|
||||
using Kernel::Board::Nintendo::Nx::KSystemControl;
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
#else
|
||||
#error "Unknown board for KSystemControl"
|
||||
#endif
|
||||
|
@@ -14,10 +14,10 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/hle/kernel/k_affinity_mask.h"
|
||||
#include "core/hle/kernel/k_light_lock.h"
|
||||
#include "core/hle/kernel/k_spin_lock.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
@@ -732,7 +732,7 @@ private:
|
||||
s8 priority_inheritance_count{};
|
||||
bool resource_limit_release_hint{};
|
||||
StackParameters stack_parameters{};
|
||||
Common::SpinLock context_guard{};
|
||||
KSpinLock context_guard{};
|
||||
|
||||
// For emulation
|
||||
std::shared_ptr<Common::Fiber> host_context{};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_sizes.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/thread.h"
|
||||
@@ -268,45 +269,314 @@ struct KernelCore::Impl {
|
||||
return schedulers[thread_id]->GetCurrentThread();
|
||||
}
|
||||
|
||||
void DeriveInitialMemoryLayout(KMemoryLayout& memory_layout) {
|
||||
// Insert the root region for the virtual memory tree, from which all other regions will
|
||||
// derive.
|
||||
memory_layout.GetVirtualMemoryRegionTree().InsertDirectly(
|
||||
KernelVirtualAddressSpaceBase,
|
||||
KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
|
||||
|
||||
// Insert the root region for the physical memory tree, from which all other regions will
|
||||
// derive.
|
||||
memory_layout.GetPhysicalMemoryRegionTree().InsertDirectly(
|
||||
KernelPhysicalAddressSpaceBase,
|
||||
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
|
||||
|
||||
// Save start and end for ease of use.
|
||||
const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
|
||||
const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
|
||||
|
||||
// Setup the containing kernel region.
|
||||
constexpr size_t KernelRegionSize = Common::Size_1_GB;
|
||||
constexpr size_t KernelRegionAlign = Common::Size_1_GB;
|
||||
constexpr VAddr kernel_region_start =
|
||||
Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
|
||||
size_t kernel_region_size = KernelRegionSize;
|
||||
if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
|
||||
kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
|
||||
}
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
|
||||
|
||||
// Setup the code region.
|
||||
constexpr size_t CodeRegionAlign = PageSize;
|
||||
constexpr VAddr code_region_start =
|
||||
Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
|
||||
constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
|
||||
constexpr size_t code_region_size = code_region_end - code_region_start;
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
code_region_start, code_region_size, KMemoryRegionType_KernelCode));
|
||||
|
||||
// Setup board-specific device physical regions.
|
||||
Init::SetupDevicePhysicalMemoryRegions(memory_layout);
|
||||
|
||||
// Determine the amount of space needed for the misc region.
|
||||
size_t misc_region_needed_size;
|
||||
{
|
||||
// Each core has a one page stack for all three stack types (Main, Idle, Exception).
|
||||
misc_region_needed_size = Core::Hardware::NUM_CPU_CORES * (3 * (PageSize + PageSize));
|
||||
|
||||
// Account for each auto-map device.
|
||||
for (const auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||
if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
|
||||
// Check that the region is valid.
|
||||
ASSERT(region.GetEndAddress() != 0);
|
||||
|
||||
// Account for the region.
|
||||
misc_region_needed_size +=
|
||||
PageSize + (Common::AlignUp(region.GetLastAddress(), PageSize) -
|
||||
Common::AlignDown(region.GetAddress(), PageSize));
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply the needed size by three, to account for the need for guard space.
|
||||
misc_region_needed_size *= 3;
|
||||
}
|
||||
|
||||
// Decide on the actual size for the misc region.
|
||||
constexpr size_t MiscRegionAlign = KernelAslrAlignment;
|
||||
constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
|
||||
const size_t misc_region_size = Common::AlignUp(
|
||||
std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
|
||||
ASSERT(misc_region_size > 0);
|
||||
|
||||
// Setup the misc region.
|
||||
const VAddr misc_region_start =
|
||||
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||
misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
|
||||
|
||||
// Setup the stack region.
|
||||
constexpr size_t StackRegionSize = Common::Size_14_MB;
|
||||
constexpr size_t StackRegionAlign = KernelAslrAlignment;
|
||||
const VAddr stack_region_start =
|
||||
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||
StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
|
||||
|
||||
// Determine the size of the resource region.
|
||||
const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
|
||||
|
||||
// Determine the size of the slab region.
|
||||
const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
|
||||
ASSERT(slab_region_size <= resource_region_size);
|
||||
|
||||
// Setup the slab region.
|
||||
const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
|
||||
const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
|
||||
const PAddr slab_start_phys_addr = code_end_phys_addr;
|
||||
const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
|
||||
constexpr size_t SlabRegionAlign = KernelAslrAlignment;
|
||||
const size_t slab_region_needed_size =
|
||||
Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
|
||||
Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
|
||||
const VAddr slab_region_start =
|
||||
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||
slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
|
||||
(code_end_phys_addr % SlabRegionAlign);
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
|
||||
|
||||
// Setup the temp region.
|
||||
constexpr size_t TempRegionSize = Common::Size_128_MB;
|
||||
constexpr size_t TempRegionAlign = KernelAslrAlignment;
|
||||
const VAddr temp_region_start =
|
||||
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||
TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
|
||||
KMemoryRegionType_KernelTemp));
|
||||
|
||||
// Automatically map in devices that have auto-map attributes.
|
||||
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||
// We only care about kernel regions.
|
||||
if (!region.IsDerivedFrom(KMemoryRegionType_Kernel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether we should map the region.
|
||||
if (!region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this region has already been mapped, no need to consider it.
|
||||
if (region.HasTypeAttribute(KMemoryRegionAttr_DidKernelMap)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check that the region is valid.
|
||||
ASSERT(region.GetEndAddress() != 0);
|
||||
|
||||
// Set the attribute to note we've mapped this region.
|
||||
region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
|
||||
|
||||
// Create a virtual pair region and insert it into the tree.
|
||||
const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
|
||||
const size_t map_size =
|
||||
Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
|
||||
const VAddr map_virt_addr =
|
||||
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
|
||||
map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
|
||||
region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
|
||||
}
|
||||
|
||||
Init::SetupDramPhysicalMemoryRegions(memory_layout);
|
||||
|
||||
// Insert a physical region for the kernel code region.
|
||||
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||
code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
|
||||
|
||||
// Insert a physical region for the kernel slab region.
|
||||
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||
slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
|
||||
|
||||
// Determine size available for kernel page table heaps, requiring > 8 MB.
|
||||
const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
|
||||
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
|
||||
ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
|
||||
|
||||
// Insert a physical region for the kernel page table heap region
|
||||
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||
slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
|
||||
|
||||
// All DRAM regions that we haven't tagged by this point will be mapped under the linear
|
||||
// mapping. Tag them.
|
||||
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||
if (region.GetType() == KMemoryRegionType_Dram) {
|
||||
// Check that the region is valid.
|
||||
ASSERT(region.GetEndAddress() != 0);
|
||||
|
||||
// Set the linear map attribute.
|
||||
region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the linear region extents.
|
||||
const auto linear_extents =
|
||||
memory_layout.GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||
KMemoryRegionAttr_LinearMapped);
|
||||
ASSERT(linear_extents.GetEndAddress() != 0);
|
||||
|
||||
// Setup the linear mapping region.
|
||||
constexpr size_t LinearRegionAlign = Common::Size_1_GB;
|
||||
const PAddr aligned_linear_phys_start =
|
||||
Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
|
||||
const size_t linear_region_size =
|
||||
Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
|
||||
aligned_linear_phys_start;
|
||||
const VAddr linear_region_start =
|
||||
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
|
||||
linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
|
||||
|
||||
const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
|
||||
|
||||
// Map and create regions for all the linearly-mapped data.
|
||||
{
|
||||
PAddr cur_phys_addr = 0;
|
||||
u64 cur_size = 0;
|
||||
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||
if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(region.GetEndAddress() != 0);
|
||||
|
||||
if (cur_size == 0) {
|
||||
cur_phys_addr = region.GetAddress();
|
||||
cur_size = region.GetSize();
|
||||
} else if (cur_phys_addr + cur_size == region.GetAddress()) {
|
||||
cur_size += region.GetSize();
|
||||
} else {
|
||||
cur_phys_addr = region.GetAddress();
|
||||
cur_size = region.GetSize();
|
||||
}
|
||||
|
||||
const VAddr region_virt_addr =
|
||||
region.GetAddress() + linear_region_phys_to_virt_diff;
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
region_virt_addr, region.GetSize(),
|
||||
GetTypeForVirtualLinearMapping(region.GetType())));
|
||||
region.SetPairAddress(region_virt_addr);
|
||||
|
||||
KMemoryRegion* virt_region =
|
||||
memory_layout.GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
|
||||
ASSERT(virt_region != nullptr);
|
||||
virt_region->SetPairAddress(region.GetAddress());
|
||||
}
|
||||
}
|
||||
|
||||
// Insert regions for the initial page table region.
|
||||
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||
resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
|
||||
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||
resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
|
||||
KMemoryRegionType_VirtualDramKernelInitPt));
|
||||
|
||||
// All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
|
||||
// some pool partition. Tag them.
|
||||
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||
if (region.GetType() == (KMemoryRegionType_Dram | KMemoryRegionAttr_LinearMapped)) {
|
||||
region.SetType(KMemoryRegionType_DramPoolPartition);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup all other memory regions needed to arrange the pool partitions.
|
||||
Init::SetupPoolPartitionMemoryRegions(memory_layout);
|
||||
|
||||
// Cache all linear regions in their own trees for faster access, later.
|
||||
memory_layout.InitializeLinearMemoryRegionTrees(aligned_linear_phys_start,
|
||||
linear_region_start);
|
||||
}
|
||||
|
||||
void InitializeMemoryLayout() {
|
||||
// Initialize memory layout
|
||||
constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()};
|
||||
// Derive the initial memory layout from the emulated board
|
||||
KMemoryLayout memory_layout;
|
||||
DeriveInitialMemoryLayout(memory_layout);
|
||||
|
||||
const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
|
||||
const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
|
||||
const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
|
||||
|
||||
// Initialize memory managers
|
||||
memory_manager = std::make_unique<KMemoryManager>();
|
||||
memory_manager->InitializeManager(KMemoryManager::Pool::Application,
|
||||
application_pool.GetAddress(),
|
||||
application_pool.GetEndAddress());
|
||||
memory_manager->InitializeManager(KMemoryManager::Pool::Applet, applet_pool.GetAddress(),
|
||||
applet_pool.GetEndAddress());
|
||||
memory_manager->InitializeManager(KMemoryManager::Pool::System, system_pool.GetAddress(),
|
||||
system_pool.GetEndAddress());
|
||||
|
||||
// Setup memory regions for emulated processes
|
||||
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
|
||||
constexpr std::size_t hid_size{0x40000};
|
||||
constexpr std::size_t font_size{0x1100000};
|
||||
constexpr std::size_t irs_size{0x8000};
|
||||
constexpr std::size_t time_size{0x1000};
|
||||
constexpr PAddr hid_addr{layout.System().StartAddress()};
|
||||
constexpr PAddr font_pa{layout.System().StartAddress() + hid_size};
|
||||
constexpr PAddr irs_addr{layout.System().StartAddress() + hid_size + font_size};
|
||||
constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
|
||||
|
||||
// Initialize memory manager
|
||||
memory_manager = std::make_unique<KMemoryManager>();
|
||||
memory_manager->InitializeManager(KMemoryManager::Pool::Application,
|
||||
layout.Application().StartAddress(),
|
||||
layout.Application().EndAddress());
|
||||
memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
|
||||
layout.Applet().StartAddress(),
|
||||
layout.Applet().EndAddress());
|
||||
memory_manager->InitializeManager(KMemoryManager::Pool::System,
|
||||
layout.System().StartAddress(),
|
||||
layout.System().EndAddress());
|
||||
const PAddr hid_phys_addr{system_pool.GetAddress()};
|
||||
const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
|
||||
const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
|
||||
const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
|
||||
|
||||
hid_shared_mem = Kernel::KSharedMemory::Create(
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size,
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
|
||||
"HID:SharedMemory");
|
||||
font_shared_mem = Kernel::KSharedMemory::Create(
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size,
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
|
||||
"Font:SharedMemory");
|
||||
irs_shared_mem = Kernel::KSharedMemory::Create(
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size,
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
|
||||
"IRS:SharedMemory");
|
||||
time_shared_mem = Kernel::KSharedMemory::Create(
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size,
|
||||
system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
|
||||
KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
|
||||
"Time:SharedMemory");
|
||||
|
||||
// Allocate slab heaps
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project / PPSSPP Project
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
@@ -959,7 +959,7 @@ private:
|
||||
|
||||
auto storage = applet->GetBroker().PopNormalDataToGame();
|
||||
if (storage == nullptr) {
|
||||
LOG_ERROR(Service_AM,
|
||||
LOG_DEBUG(Service_AM,
|
||||
"storage is a nullptr. There is no data in the current normal channel");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
@@ -990,7 +990,7 @@ private:
|
||||
|
||||
auto storage = applet->GetBroker().PopInteractiveDataToGame();
|
||||
if (storage == nullptr) {
|
||||
LOG_ERROR(Service_AM,
|
||||
LOG_DEBUG(Service_AM,
|
||||
"storage is a nullptr. There is no data in the current interactive channel");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||
@@ -1113,7 +1113,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
|
||||
{2, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
|
||||
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
|
||||
{12, nullptr, "CreateHandleStorage"},
|
||||
{12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -1122,14 +1122,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
|
||||
|
||||
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto applet_id = rp.PopRaw<Applets::AppletId>();
|
||||
const auto applet_mode = rp.PopRaw<u32>();
|
||||
const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
||||
applet_mode);
|
||||
|
||||
const auto& applet_manager{system.GetAppletManager()};
|
||||
const auto applet = applet_manager.GetApplet(applet_id);
|
||||
const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
|
||||
|
||||
if (applet == nullptr) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
||||
@@ -1147,9 +1148,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
|
||||
|
||||
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 size{rp.Pop<u64>()};
|
||||
|
||||
const s64 size{rp.Pop<s64>()};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> buffer(size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
@@ -1158,18 +1168,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
rp.SetCurrentOffset(3);
|
||||
const auto handle{rp.Pop<Kernel::Handle>()};
|
||||
struct Parameters {
|
||||
u8 permissions;
|
||||
s64 size;
|
||||
};
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
|
||||
parameters.size, handle);
|
||||
|
||||
if (parameters.size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem =
|
||||
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
|
||||
|
||||
if (transfer_mem == nullptr) {
|
||||
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
const u8* const mem_begin = transfer_mem->GetPointer();
|
||||
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
|
||||
std::vector<u8> memory{mem_begin, mem_end};
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IStorage>(system, std::move(memory));
|
||||
}
|
||||
|
||||
void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const s64 size{rp.Pop<s64>()};
|
||||
const auto handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
auto transfer_mem =
|
||||
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
|
||||
|
||||
if (transfer_mem == nullptr) {
|
||||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_UNKNOWN);
|
||||
return;
|
||||
|
@@ -254,6 +254,7 @@ private:
|
||||
void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
|
||||
void CreateStorage(Kernel::HLERequestContext& ctx);
|
||||
void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
|
||||
void CreateHandleStorage(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
|
||||
|
@@ -241,31 +241,31 @@ void AppletManager::ClearAll() {
|
||||
frontend = {};
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
|
||||
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
|
||||
switch (id) {
|
||||
case AppletId::Auth:
|
||||
return std::make_shared<Auth>(system, *frontend.parental_controls);
|
||||
return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
|
||||
case AppletId::Controller:
|
||||
return std::make_shared<Controller>(system, *frontend.controller);
|
||||
return std::make_shared<Controller>(system, mode, *frontend.controller);
|
||||
case AppletId::Error:
|
||||
return std::make_shared<Error>(system, *frontend.error);
|
||||
return std::make_shared<Error>(system, mode, *frontend.error);
|
||||
case AppletId::ProfileSelect:
|
||||
return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
|
||||
return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
|
||||
return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
|
||||
case AppletId::Web:
|
||||
case AppletId::Shop:
|
||||
case AppletId::OfflineWeb:
|
||||
case AppletId::LoginShare:
|
||||
case AppletId::WebAuth:
|
||||
return std::make_shared<WebBrowser>(system, *frontend.web_browser);
|
||||
return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
|
||||
case AppletId::PhotoViewer:
|
||||
return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
|
||||
return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
|
||||
default:
|
||||
UNIMPLEMENTED_MSG(
|
||||
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
|
||||
static_cast<u8>(id));
|
||||
return std::make_shared<StubApplet>(system, id);
|
||||
return std::make_shared<StubApplet>(system, id, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -62,6 +62,14 @@ enum class AppletId : u32 {
|
||||
MyPage = 0x1A,
|
||||
};
|
||||
|
||||
enum class LibraryAppletMode : u32 {
|
||||
AllForeground = 0,
|
||||
Background = 1,
|
||||
NoUI = 2,
|
||||
BackgroundIndirectDisplay = 3,
|
||||
AllForegroundInitiallyHidden = 4,
|
||||
};
|
||||
|
||||
class AppletDataBroker final {
|
||||
public:
|
||||
explicit AppletDataBroker(Kernel::KernelCore& kernel_);
|
||||
@@ -200,7 +208,7 @@ public:
|
||||
void SetDefaultAppletsIfMissing();
|
||||
void ClearAll();
|
||||
|
||||
std::shared_ptr<Applet> GetApplet(AppletId id) const;
|
||||
std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
|
||||
|
||||
private:
|
||||
AppletFrontendSet frontend;
|
||||
|
@@ -45,8 +45,9 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
||||
};
|
||||
}
|
||||
|
||||
Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
|
||||
Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ControllerApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
|
||||
Controller::~Controller() = default;
|
||||
|
||||
|
@@ -106,7 +106,8 @@ static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
|
||||
|
||||
class Controller final : public Applet {
|
||||
public:
|
||||
explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
|
||||
explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ControllerApplet& frontend_);
|
||||
~Controller() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -119,6 +120,7 @@ public:
|
||||
void ConfigurationComplete();
|
||||
|
||||
private:
|
||||
LibraryAppletMode applet_mode;
|
||||
const Core::Frontend::ControllerApplet& frontend;
|
||||
Core::System& system;
|
||||
|
||||
|
@@ -86,8 +86,9 @@ ResultCode Decode64BitError(u64 error) {
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
|
||||
Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ErrorApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
|
||||
Error::~Error() = default;
|
||||
|
||||
|
@@ -25,7 +25,8 @@ enum class ErrorAppletMode : u8 {
|
||||
|
||||
class Error final : public Applet {
|
||||
public:
|
||||
explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_);
|
||||
explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ErrorApplet& frontend_);
|
||||
~Error() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -40,6 +41,7 @@ public:
|
||||
private:
|
||||
union ErrorArguments;
|
||||
|
||||
LibraryAppletMode applet_mode;
|
||||
const Core::Frontend::ErrorApplet& frontend;
|
||||
ResultCode error_code = RESULT_SUCCESS;
|
||||
ErrorAppletMode mode = ErrorAppletMode::ShowError;
|
||||
|
@@ -37,8 +37,9 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
|
||||
}
|
||||
}
|
||||
|
||||
Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
|
||||
Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::ParentalControlsApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
|
||||
Auth::~Auth() = default;
|
||||
|
||||
@@ -152,8 +153,9 @@ void Auth::AuthFinished(bool is_successful) {
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
|
||||
PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::PhotoViewerApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
|
||||
PhotoViewer::~PhotoViewer() = default;
|
||||
|
||||
@@ -202,8 +204,8 @@ void PhotoViewer::ViewFinished() {
|
||||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
StubApplet::StubApplet(Core::System& system_, AppletId id_)
|
||||
: Applet{system_.Kernel()}, id{id_}, system{system_} {}
|
||||
StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
|
||||
: Applet{system_.Kernel()}, id{id_}, applet_mode{applet_mode_}, system{system_} {}
|
||||
|
||||
StubApplet::~StubApplet() = default;
|
||||
|
||||
|
@@ -20,7 +20,8 @@ enum class AuthAppletType : u32 {
|
||||
|
||||
class Auth final : public Applet {
|
||||
public:
|
||||
explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_);
|
||||
explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::ParentalControlsApplet& frontend_);
|
||||
~Auth() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -32,6 +33,7 @@ public:
|
||||
void AuthFinished(bool is_successful = true);
|
||||
|
||||
private:
|
||||
LibraryAppletMode applet_mode;
|
||||
Core::Frontend::ParentalControlsApplet& frontend;
|
||||
Core::System& system;
|
||||
bool complete = false;
|
||||
@@ -50,7 +52,8 @@ enum class PhotoViewerAppletMode : u8 {
|
||||
|
||||
class PhotoViewer final : public Applet {
|
||||
public:
|
||||
explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_);
|
||||
explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::PhotoViewerApplet& frontend_);
|
||||
~PhotoViewer() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -62,6 +65,7 @@ public:
|
||||
void ViewFinished();
|
||||
|
||||
private:
|
||||
LibraryAppletMode applet_mode;
|
||||
const Core::Frontend::PhotoViewerApplet& frontend;
|
||||
bool complete = false;
|
||||
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
|
||||
@@ -70,7 +74,7 @@ private:
|
||||
|
||||
class StubApplet final : public Applet {
|
||||
public:
|
||||
explicit StubApplet(Core::System& system_, AppletId id_);
|
||||
explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
|
||||
~StubApplet() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -82,6 +86,7 @@ public:
|
||||
|
||||
private:
|
||||
AppletId id;
|
||||
LibraryAppletMode applet_mode;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
|
@@ -15,9 +15,9 @@ namespace Service::AM::Applets {
|
||||
|
||||
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
|
||||
|
||||
ProfileSelect::ProfileSelect(Core::System& system_,
|
||||
ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ProfileSelectApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
|
||||
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
|
||||
|
||||
ProfileSelect::~ProfileSelect() = default;
|
||||
|
||||
|
@@ -33,7 +33,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
|
||||
|
||||
class ProfileSelect final : public Applet {
|
||||
public:
|
||||
explicit ProfileSelect(Core::System& system_,
|
||||
explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::ProfileSelectApplet& frontend_);
|
||||
~ProfileSelect() override;
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
void SelectionComplete(std::optional<Common::UUID> uuid);
|
||||
|
||||
private:
|
||||
LibraryAppletMode applet_mode;
|
||||
const Core::Frontend::ProfileSelectApplet& frontend;
|
||||
|
||||
UserSelectionConfig config;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,14 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
|
||||
union ResultCode;
|
||||
#include "core/hle/service/am/applets/software_keyboard_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -22,45 +16,10 @@ class System;
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
enum class KeysetDisable : u32 {
|
||||
Space = 0x02,
|
||||
Address = 0x04,
|
||||
Percent = 0x08,
|
||||
Slashes = 0x10,
|
||||
Numbers = 0x40,
|
||||
DownloadCode = 0x80,
|
||||
};
|
||||
|
||||
struct KeyboardConfig {
|
||||
INSERT_PADDING_BYTES(4);
|
||||
std::array<char16_t, 9> submit_text;
|
||||
u16_le left_symbol_key;
|
||||
u16_le right_symbol_key;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
KeysetDisable keyset_disable_bitmask;
|
||||
u32_le initial_cursor_position;
|
||||
std::array<char16_t, 65> header_text;
|
||||
std::array<char16_t, 129> sub_text;
|
||||
std::array<char16_t, 257> guide_text;
|
||||
u32_le length_limit;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
u32_le is_password;
|
||||
INSERT_PADDING_BYTES(5);
|
||||
bool utf_8;
|
||||
bool draw_background;
|
||||
u32_le initial_string_offset;
|
||||
u32_le initial_string_size;
|
||||
u32_le user_dictionary_offset;
|
||||
u32_le user_dictionary_size;
|
||||
bool text_check;
|
||||
u64_le text_check_callback;
|
||||
};
|
||||
static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
|
||||
|
||||
class SoftwareKeyboard final : public Applet {
|
||||
public:
|
||||
explicit SoftwareKeyboard(Core::System& system_,
|
||||
const Core::Frontend::SoftwareKeyboardApplet& frontend_);
|
||||
explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
Core::Frontend::SoftwareKeyboardApplet& frontend_);
|
||||
~SoftwareKeyboard() override;
|
||||
|
||||
void Initialize() override;
|
||||
@@ -70,17 +29,139 @@ public:
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
void WriteText(std::optional<std::u16string> text);
|
||||
/**
|
||||
* Submits the input text to the application.
|
||||
* If text checking is enabled, the application will verify the input text.
|
||||
* If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted.
|
||||
* This should only be used by the normal software keyboard.
|
||||
*
|
||||
* @param result SwkbdResult enum
|
||||
* @param submitted_text UTF-16 encoded string
|
||||
*/
|
||||
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
|
||||
|
||||
/**
|
||||
* Submits the input text to the application.
|
||||
* If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted.
|
||||
* This should only be used by the inline software keyboard.
|
||||
*
|
||||
* @param reply_type SwkbdReplyType enum
|
||||
* @param submitted_text UTF-16 encoded string
|
||||
* @param cursor_position The current position of the text cursor
|
||||
*/
|
||||
void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
|
||||
s32 cursor_position);
|
||||
|
||||
private:
|
||||
const Core::Frontend::SoftwareKeyboardApplet& frontend;
|
||||
/// Initializes the normal software keyboard.
|
||||
void InitializeForeground();
|
||||
|
||||
KeyboardConfig config;
|
||||
std::u16string initial_text;
|
||||
bool complete = false;
|
||||
bool is_inline = false;
|
||||
std::vector<u8> final_data;
|
||||
/// Initializes the inline software keyboard.
|
||||
void InitializeBackground(LibraryAppletMode applet_mode);
|
||||
|
||||
/// Processes the text check sent by the application.
|
||||
void ProcessTextCheck();
|
||||
|
||||
/// Processes the inline software keyboard request command sent by the application.
|
||||
void ProcessInlineKeyboardRequest();
|
||||
|
||||
/// Submits the input text and exits the applet.
|
||||
void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text);
|
||||
|
||||
/// Submits the input text for text checking.
|
||||
void SubmitForTextCheck(std::u16string submitted_text);
|
||||
|
||||
/// Sends a reply to the application after processing a request command.
|
||||
void SendReply(SwkbdReplyType reply_type);
|
||||
|
||||
/// Changes the inline keyboard state.
|
||||
void ChangeState(SwkbdState state);
|
||||
|
||||
/**
|
||||
* Signals the frontend to initialize the software keyboard with common parameters.
|
||||
* This initializes either the normal software keyboard or the inline software keyboard
|
||||
* depending on the state of is_background.
|
||||
* Note that this does not cause the keyboard to appear.
|
||||
* Use the respective Show*Keyboard() functions to cause the respective keyboards to appear.
|
||||
*/
|
||||
void InitializeFrontendKeyboard();
|
||||
|
||||
/// Signals the frontend to show the normal software keyboard.
|
||||
void ShowNormalKeyboard();
|
||||
|
||||
/// Signals the frontend to show the text check dialog.
|
||||
void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
|
||||
std::u16string text_check_message);
|
||||
|
||||
/// Signals the frontend to show the inline software keyboard.
|
||||
void ShowInlineKeyboard();
|
||||
|
||||
/// Signals the frontend to hide the inline software keyboard.
|
||||
void HideInlineKeyboard();
|
||||
|
||||
/// Signals the frontend that the current inline keyboard text has changed.
|
||||
void InlineTextChanged();
|
||||
|
||||
/// Signals both the frontend and application that the software keyboard is exiting.
|
||||
void ExitKeyboard();
|
||||
|
||||
// Inline Software Keyboard Requests
|
||||
|
||||
void RequestFinalize(const std::vector<u8>& request_data);
|
||||
void RequestSetUserWordInfo(const std::vector<u8>& request_data);
|
||||
void RequestSetCustomizeDic(const std::vector<u8>& request_data);
|
||||
void RequestCalc(const std::vector<u8>& request_data);
|
||||
void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data);
|
||||
void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data);
|
||||
void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data);
|
||||
void RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data);
|
||||
|
||||
// Inline Software Keyboard Replies
|
||||
|
||||
void ReplyFinishedInitialize();
|
||||
void ReplyDefault();
|
||||
void ReplyChangedString();
|
||||
void ReplyMovedCursor();
|
||||
void ReplyMovedTab();
|
||||
void ReplyDecidedEnter();
|
||||
void ReplyDecidedCancel();
|
||||
void ReplyChangedStringUtf8();
|
||||
void ReplyMovedCursorUtf8();
|
||||
void ReplyDecidedEnterUtf8();
|
||||
void ReplyUnsetCustomizeDic();
|
||||
void ReplyReleasedUserWordInfo();
|
||||
void ReplyUnsetCustomizedDictionaries();
|
||||
void ReplyChangedStringV2();
|
||||
void ReplyMovedCursorV2();
|
||||
void ReplyChangedStringUtf8V2();
|
||||
void ReplyMovedCursorUtf8V2();
|
||||
|
||||
LibraryAppletMode applet_mode;
|
||||
Core::Frontend::SoftwareKeyboardApplet& frontend;
|
||||
Core::System& system;
|
||||
|
||||
SwkbdAppletVersion swkbd_applet_version;
|
||||
|
||||
SwkbdConfigCommon swkbd_config_common;
|
||||
SwkbdConfigOld swkbd_config_old;
|
||||
SwkbdConfigOld2 swkbd_config_old2;
|
||||
SwkbdConfigNew swkbd_config_new;
|
||||
std::u16string initial_text;
|
||||
|
||||
SwkbdState swkbd_state{SwkbdState::NotInitialized};
|
||||
SwkbdInitializeArg swkbd_initialize_arg;
|
||||
SwkbdCalcArg swkbd_calc_arg;
|
||||
bool use_changed_string_v2{false};
|
||||
bool use_moved_cursor_v2{false};
|
||||
bool inline_use_utf8{false};
|
||||
s32 current_cursor_position{};
|
||||
|
||||
std::u16string current_text;
|
||||
|
||||
bool is_background{false};
|
||||
|
||||
bool complete{false};
|
||||
ResultCode status{RESULT_SUCCESS};
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
|
@@ -13,11 +13,11 @@
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
static constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
|
||||
static constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
|
||||
static constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
|
||||
static constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
|
||||
static constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
|
||||
constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
|
||||
constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
|
||||
constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
|
||||
constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
|
||||
constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
|
||||
|
||||
enum class SwkbdAppletVersion : u32_le {
|
||||
Version5 = 0x5, // 1.0.0
|
||||
|
@@ -208,8 +208,9 @@ void ExtractSharedFonts(Core::System& system) {
|
||||
|
||||
} // namespace
|
||||
|
||||
WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
|
||||
WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::WebBrowserApplet& frontend_)
|
||||
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend(frontend_), system{system_} {}
|
||||
|
||||
WebBrowser::~WebBrowser() = default;
|
||||
|
||||
|
@@ -25,7 +25,8 @@ namespace Service::AM::Applets {
|
||||
|
||||
class WebBrowser final : public Applet {
|
||||
public:
|
||||
WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_);
|
||||
WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
|
||||
const Core::Frontend::WebBrowserApplet& frontend_);
|
||||
|
||||
~WebBrowser() override;
|
||||
|
||||
@@ -63,6 +64,7 @@ private:
|
||||
void ExecuteWifi();
|
||||
void ExecuteLobby();
|
||||
|
||||
LibraryAppletMode applet_mode;
|
||||
const Core::Frontend::WebBrowserApplet& frontend;
|
||||
|
||||
bool complete{false};
|
||||
|
@@ -38,7 +38,7 @@ public:
|
||||
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
||||
{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
|
||||
{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
|
||||
{10700, nullptr, "GetPlayHistoryRegistrationKey"},
|
||||
{10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
|
||||
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
|
||||
{10702, nullptr, "AddPlayHistory"},
|
||||
{11000, nullptr, "GetProfileImageUrl"},
|
||||
@@ -153,6 +153,18 @@ private:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto local_play = rp.Pop<bool>();
|
||||
const auto uuid = rp.PopRaw<Common::UUID>();
|
||||
|
||||
LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
|
||||
uuid.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetFriendList(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto friend_offset = rp.Pop<u32>();
|
||||
|
@@ -36,6 +36,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
|
||||
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
||||
Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
|
||||
system.GPU().PushCommandBuffer(cmdlist);
|
||||
system.GPU().MemoryManager().InvalidateQueuedCaches();
|
||||
}
|
||||
return UnmapBuffer(input, output);
|
||||
}
|
||||
|
@@ -193,7 +193,13 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
|
||||
return NvResult::InvalidState;
|
||||
}
|
||||
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
||||
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
||||
if (vic_device) {
|
||||
// UnmapVicFrame defers texture_cache invalidation of the frame address until
|
||||
// the stream is over
|
||||
gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size);
|
||||
} else {
|
||||
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
||||
}
|
||||
} else {
|
||||
// This occurs quite frequently, however does not seem to impact functionality
|
||||
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
|
||||
|
@@ -160,6 +160,7 @@ protected:
|
||||
|
||||
s32_le nvmap_fd{};
|
||||
u32_le submit_timeout{};
|
||||
bool vic_device{};
|
||||
std::shared_ptr<nvmap> nvmap_dev;
|
||||
SyncpointManager& syncpoint_manager;
|
||||
std::array<u32, MaxSyncPoints> device_syncpoints{};
|
||||
|
@@ -12,8 +12,9 @@
|
||||
namespace Service::Nvidia::Devices {
|
||||
nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
||||
SyncpointManager& syncpoint_manager)
|
||||
: nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
|
||||
|
||||
: nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {
|
||||
vic_device = true;
|
||||
}
|
||||
nvhost_vic::~nvhost_vic() = default;
|
||||
|
||||
NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||
|
@@ -3,16 +3,30 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/pctl/module.h"
|
||||
#include "core/hle/service/pctl/pctl.h"
|
||||
|
||||
namespace Service::PCTL {
|
||||
|
||||
namespace Error {
|
||||
|
||||
constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101};
|
||||
constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
|
||||
constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131};
|
||||
constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
|
||||
|
||||
} // namespace Error
|
||||
|
||||
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
|
||||
public:
|
||||
explicit IParentalControlService(Core::System& system_)
|
||||
: ServiceFramework{system_, "IParentalControlService"} {
|
||||
explicit IParentalControlService(Core::System& system_, Capability capability)
|
||||
: ServiceFramework{system_, "IParentalControlService"}, system(system_),
|
||||
capability(capability) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, &IParentalControlService::Initialize, "Initialize"},
|
||||
@@ -28,13 +42,13 @@ public:
|
||||
{1010, nullptr, "IsRestrictedSystemSettingsEntered"},
|
||||
{1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
|
||||
{1012, nullptr, "GetRestrictedFeatures"},
|
||||
{1013, nullptr, "ConfirmStereoVisionPermission"},
|
||||
{1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
|
||||
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
|
||||
{1015, nullptr, "ConfirmPlayableApplicationVideo"},
|
||||
{1016, nullptr, "ConfirmShowNewsPermission"},
|
||||
{1017, nullptr, "EndFreeCommunication"},
|
||||
{1018, nullptr, "IsFreeCommunicationAvailable"},
|
||||
{1031, nullptr, "IsRestrictionEnabled"},
|
||||
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
|
||||
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
|
||||
{1032, nullptr, "GetSafetyLevel"},
|
||||
{1033, nullptr, "SetSafetyLevel"},
|
||||
{1034, nullptr, "GetSafetyLevelSettings"},
|
||||
@@ -119,62 +133,235 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
bool CheckFreeCommunicationPermissionImpl() const {
|
||||
if (states.temporary_unlocked) {
|
||||
return true;
|
||||
}
|
||||
if ((states.application_info.parental_control_flag & 1) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (pin_code[0] == '\0') {
|
||||
return true;
|
||||
}
|
||||
if (!settings.is_free_communication_default_on) {
|
||||
return true;
|
||||
}
|
||||
// TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
|
||||
// but as we don't have multiproceses support yet, we can just assume our application is
|
||||
// valid for the time being
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConfirmStereoVisionPermissionImpl() const {
|
||||
if (states.temporary_unlocked) {
|
||||
return true;
|
||||
}
|
||||
if (pin_code[0] == '\0') {
|
||||
return true;
|
||||
}
|
||||
if (!settings.is_stero_vision_restricted) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetStereoVisionRestrictionImpl(bool is_restricted) {
|
||||
if (settings.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pin_code[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
settings.is_stero_vision_restricted = is_restricted;
|
||||
}
|
||||
|
||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
if (False(capability & (Capability::Application | Capability::System))) {
|
||||
LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(ogniK): Recovery flag initialization for pctl:r
|
||||
|
||||
const auto tid = system.CurrentProcess()->GetTitleID();
|
||||
if (tid != 0) {
|
||||
const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
|
||||
system.GetContentProvider()};
|
||||
const auto control = pm.GetControlMetadata();
|
||||
if (control.first) {
|
||||
states.tid_from_event = 0;
|
||||
states.launch_time_valid = false;
|
||||
states.is_suspended = false;
|
||||
states.free_communication = false;
|
||||
states.stereo_vision = false;
|
||||
states.application_info = ApplicationInfo{
|
||||
.tid = tid,
|
||||
.age_rating = control.first->GetRatingAge(),
|
||||
.parental_control_flag = control.first->GetParentalControlFlag(),
|
||||
.capability = capability,
|
||||
};
|
||||
|
||||
if (False(capability & (Capability::System | Capability::Recovery))) {
|
||||
// TODO(ogniK): Signal application launch event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
if (!CheckFreeCommunicationPermissionImpl()) {
|
||||
rb.Push(Error::ResultNoFreeCommunication);
|
||||
} else {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
states.free_communication = true;
|
||||
}
|
||||
|
||||
void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
states.stereo_vision = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
|
||||
void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
if (!CheckFreeCommunicationPermissionImpl()) {
|
||||
rb.Push(Error::ResultNoFreeCommunication);
|
||||
} else {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
if (False(capability & (Capability::Status | Capability::Recovery))) {
|
||||
LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
|
||||
rb.Push(Error::ResultNoCapability);
|
||||
rb.Push(false);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(pin_code[0] != '\0');
|
||||
}
|
||||
|
||||
void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
|
||||
if (False(capability & Capability::StereoVision)) {
|
||||
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
|
||||
rb.Push(Error::ResultNoCapability);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pin_code[0] == '\0') {
|
||||
rb.Push(Error::ResultNoRestrictionEnabled);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(true);
|
||||
if (!ConfirmStereoVisionPermissionImpl()) {
|
||||
rb.Push(Error::ResultStereoVisionRestricted);
|
||||
rb.Push(false);
|
||||
} else {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(true);
|
||||
}
|
||||
}
|
||||
|
||||
void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto can_use = rp.Pop<bool>();
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use);
|
||||
|
||||
can_use_stereo_vision = can_use;
|
||||
LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
if (False(capability & Capability::StereoVision)) {
|
||||
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
|
||||
rb.Push(Error::ResultNoCapability);
|
||||
return;
|
||||
}
|
||||
|
||||
SetStereoVisionRestrictionImpl(can_use);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
if (False(capability & Capability::StereoVision)) {
|
||||
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
|
||||
rb.Push(Error::ResultNoCapability);
|
||||
rb.Push(false);
|
||||
return;
|
||||
}
|
||||
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(can_use_stereo_vision);
|
||||
rb.Push(settings.is_stero_vision_restricted);
|
||||
}
|
||||
|
||||
void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_PCTL, "called");
|
||||
|
||||
states.stereo_vision = false;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
struct ApplicationInfo {
|
||||
u64 tid{};
|
||||
std::array<u8, 32> age_rating{};
|
||||
u32 parental_control_flag{};
|
||||
Capability capability{};
|
||||
};
|
||||
|
||||
struct States {
|
||||
u64 current_tid{};
|
||||
ApplicationInfo application_info{};
|
||||
u64 tid_from_event{};
|
||||
bool launch_time_valid{};
|
||||
bool is_suspended{};
|
||||
bool temporary_unlocked{};
|
||||
bool free_communication{};
|
||||
bool stereo_vision{};
|
||||
};
|
||||
|
||||
struct ParentalControlSettings {
|
||||
bool is_stero_vision_restricted{};
|
||||
bool is_free_communication_default_on{};
|
||||
bool disabled{};
|
||||
};
|
||||
|
||||
States states{};
|
||||
ParentalControlSettings settings{};
|
||||
std::array<char, 8> pin_code{};
|
||||
bool can_use_stereo_vision = true;
|
||||
Core::System& system;
|
||||
Capability capability{};
|
||||
};
|
||||
|
||||
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
|
||||
@@ -182,7 +369,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IParentalControlService>(system);
|
||||
// TODO(ogniK): Get TID from process
|
||||
|
||||
rb.PushIpcInterface<IParentalControlService>(system, capability);
|
||||
}
|
||||
|
||||
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
|
||||
@@ -190,21 +379,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IParentalControlService>(system);
|
||||
rb.PushIpcInterface<IParentalControlService>(system, capability);
|
||||
}
|
||||
|
||||
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
|
||||
const char* name)
|
||||
: ServiceFramework{system_, name}, module{std::move(module_)} {}
|
||||
const char* name, Capability capability)
|
||||
: ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
|
||||
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
|
||||
auto module = std::make_shared<Module>();
|
||||
std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager);
|
||||
std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager);
|
||||
std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager);
|
||||
std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager);
|
||||
std::make_shared<PCTL>(system, module, "pctl",
|
||||
Capability::Application | Capability::SnsPost | Capability::Status |
|
||||
Capability::StereoVision)
|
||||
->InstallAsService(service_manager);
|
||||
// TODO(ogniK): Implement remaining capabilities
|
||||
std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
|
||||
->InstallAsService(service_manager);
|
||||
std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
|
||||
->InstallAsService(service_manager);
|
||||
std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
|
||||
->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::PCTL
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
@@ -12,12 +13,23 @@ class System;
|
||||
|
||||
namespace Service::PCTL {
|
||||
|
||||
enum class Capability : u32 {
|
||||
None = 0,
|
||||
Application = 1 << 0,
|
||||
SnsPost = 1 << 1,
|
||||
Recovery = 1 << 6,
|
||||
Status = 1 << 8,
|
||||
StereoVision = 1 << 9,
|
||||
System = 1 << 15,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(Capability);
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
|
||||
const char* name);
|
||||
explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
|
||||
Capability capability);
|
||||
~Interface() override;
|
||||
|
||||
void CreateService(Kernel::HLERequestContext& ctx);
|
||||
@@ -25,6 +37,9 @@ public:
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> module;
|
||||
|
||||
private:
|
||||
Capability capability{};
|
||||
};
|
||||
};
|
||||
|
||||
|
@@ -6,8 +6,9 @@
|
||||
|
||||
namespace Service::PCTL {
|
||||
|
||||
PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name)
|
||||
: Interface{system_, std::move(module_), name} {
|
||||
PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
|
||||
Capability capability)
|
||||
: Interface{system_, std::move(module_), name, capability} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &PCTL::CreateService, "CreateService"},
|
||||
{1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
|
||||
|
@@ -14,7 +14,8 @@ namespace Service::PCTL {
|
||||
|
||||
class PCTL final : public Module::Interface {
|
||||
public:
|
||||
explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name);
|
||||
explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
|
||||
Capability capability);
|
||||
~PCTL() override;
|
||||
};
|
||||
|
||||
|
@@ -70,6 +70,7 @@
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/hle/service/wlan/wlan.h"
|
||||
#include "core/reporter.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
@@ -146,6 +147,11 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
|
||||
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
|
||||
service_name);
|
||||
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
|
||||
if (Settings::values.use_auto_stub) {
|
||||
LOG_WARNING(Service, "Using auto stub fallback!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
||||
|
@@ -139,6 +139,7 @@ struct Values {
|
||||
Setting<int> vulkan_device;
|
||||
|
||||
Setting<u16> resolution_factor{1};
|
||||
Setting<int> fullscreen_mode;
|
||||
Setting<int> aspect_ratio;
|
||||
Setting<int> max_anisotropy;
|
||||
Setting<bool> use_frame_limit;
|
||||
@@ -222,6 +223,7 @@ struct Values {
|
||||
bool quest_flag;
|
||||
bool disable_macro_jit;
|
||||
bool extended_logging;
|
||||
bool use_auto_stub;
|
||||
|
||||
// Miscellaneous
|
||||
std::string log_filter;
|
||||
|
Reference in New Issue
Block a user