summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--externals/CMakeLists.txt6
m---------externals/dynarmic0
-rw-r--r--externals/find-modules/Findopus.cmake2
-rw-r--r--externals/opus/CMakeLists.txt2
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/common_sizes.h43
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/threadsafe_queue.h10
-rw-r--r--src/core/CMakeLists.txt11
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/file_sys/control_metadata.cpp8
-rw-r--r--src/core/file_sys/control_metadata.h2
-rw-r--r--src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc20
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc52
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp164
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.h28
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/secure_monitor.h26
-rw-r--r--src/core/hle/kernel/k_address_space_info.cpp43
-rw-r--r--src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp199
-rw-r--r--src/core/hle/kernel/k_memory_layout.cpp166
-rw-r--r--src/core/hle/kernel/k_memory_layout.h397
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp12
-rw-r--r--src/core/hle/kernel/k_memory_manager.h18
-rw-r--r--src/core/hle/kernel/k_memory_region.h350
-rw-r--r--src/core/hle/kernel/k_memory_region_type.h338
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp22
-rw-r--r--src/core/hle/kernel/k_scheduler.h11
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h11
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h13
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h4
-rw-r--r--src/core/hle/kernel/k_spin_lock.h6
-rw-r--r--src/core/hle/kernel/k_system_control.cpp42
-rw-r--r--src/core/hle/kernel/k_system_control.h18
-rw-r--r--src/core/hle/kernel/k_thread.h4
-rw-r--r--src/core/hle/kernel/k_trace.h12
-rw-r--r--src/core/hle/kernel/kernel.cpp326
-rw-r--r--src/core/hle/kernel/kernel.h2
-rw-r--r--src/core/hle/kernel/svc.cpp132
-rw-r--r--src/core/hle/service/am/am.cpp22
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp2
-rw-r--r--src/core/hle/service/audio/audin_a.cpp8
-rw-r--r--src/core/hle/service/audio/audin_u.cpp14
-rw-r--r--src/core/hle/service/audio/audout_a.cpp12
-rw-r--r--src/core/hle/service/audio/audout_u.cpp6
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp4
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp7
-rw-r--r--src/core/hle/service/audio/audren_a.cpp12
-rw-r--r--src/core/hle/service/audio/audren_u.cpp6
-rw-r--r--src/core/hle/service/audio/audren_u.h2
-rw-r--r--src/core/hle/service/audio/codecctl.cpp26
-rw-r--r--src/core/hle/service/bcat/module.cpp2
-rw-r--r--src/core/hle/service/bpc/bpc.cpp4
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp19
-rw-r--r--src/core/hle/service/btm/btm.cpp1
-rw-r--r--src/core/hle/service/caps/caps_a.cpp1
-rw-r--r--src/core/hle/service/caps/caps_u.cpp1
-rw-r--r--src/core/hle/service/erpt/erpt.cpp7
-rw-r--r--src/core/hle/service/friend/friend.cpp14
-rw-r--r--src/core/hle/service/glue/arp.cpp11
-rw-r--r--src/core/hle/service/glue/arp.h2
-rw-r--r--src/core/hle/service/glue/bgtc.cpp27
-rw-r--r--src/core/hle/service/glue/bgtc.h8
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp4
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp106
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/hid/xcd.cpp2
-rw-r--r--src/core/hle/service/ldr/ldr.cpp32
-rw-r--r--src/core/hle/service/nim/nim.cpp99
-rw-r--r--src/core/hle/service/npns/npns.cpp3
-rw-r--r--src/core/hle/service/ns/ns.cpp41
-rw-r--r--src/core/hle/service/ns/pl_u.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp17
-rw-r--r--src/core/hle/service/olsc/olsc.cpp1
-rw-r--r--src/core/hle/service/pcie/pcie.cpp2
-rw-r--r--src/core/hle/service/pctl/module.cpp251
-rw-r--r--src/core/hle/service/pctl/module.h19
-rw-r--r--src/core/hle/service/pctl/pctl.cpp5
-rw-r--r--src/core/hle/service/pctl/pctl.h3
-rw-r--r--src/core/hle/service/service.cpp6
-rw-r--r--src/core/hle/service/set/set_sys.cpp6
-rw-r--r--src/core/hle/service/sm/sm.cpp9
-rw-r--r--src/core/hle/service/sockets/ethc.cpp1
-rw-r--r--src/core/hle/service/sockets/nsd.cpp1
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp4
-rw-r--r--src/core/hle/service/spl/spl.cpp3
-rw-r--r--src/core/hle/service/time/time.cpp11
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp1
-rw-r--r--src/core/hle/service/usb/usb.cpp42
-rw-r--r--src/core/hle/service/vi/vi.cpp8
-rw-r--r--src/core/hle/service/wlan/wlan.cpp7
-rw-r--r--src/core/settings.h1
-rw-r--r--src/video_core/gpu.cpp4
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/gpu_thread.cpp62
-rw-r--r--src/video_core/gpu_thread.h15
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp8
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h2
-rw-r--r--src/yuzu/configuration/config.cpp1
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui22
104 files changed, 3129 insertions, 413 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac7c3ce90..6ea6c650e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -172,6 +172,8 @@ macro(yuzu_find_packages)
"nlohmann_json 3.8 nlohmann_json/3.8.0"
"ZLIB 1.2 zlib/1.2.11"
"zstd 1.4 zstd/1.4.8"
+ # can't use opus until AVX check is fixed: https://github.com/yuzu-emu/yuzu/pull/4068
+ #"opus 1.3 opus/1.3.1"
)
foreach(PACKAGE ${REQUIRED_LIBS})
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 851c282b4..891a47c3c 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -97,4 +97,8 @@ if (ENABLE_WEB_SERVICE)
endif()
# Opus
-add_subdirectory(opus)
+find_package(opus 1.3)
+if (NOT opus_FOUND)
+ message(STATUS "opus 1.3 or newer not found, falling back to externals")
+ add_subdirectory(opus EXCLUDE_FROM_ALL)
+endif()
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject c788bcdf17e6bc1d1a1dd315106b952013f5ecb
+Subproject b2a4da5e65985e6b0a20ac8ac37d14425a2a39d
diff --git a/externals/find-modules/Findopus.cmake b/externals/find-modules/Findopus.cmake
index de84bd995..2bce56122 100644
--- a/externals/find-modules/Findopus.cmake
+++ b/externals/find-modules/Findopus.cmake
@@ -28,7 +28,7 @@ if(opus_FOUND)
endif()
if(opus_FOUND AND NOT TARGET Opus::Opus)
- add_library(Opus::Opus UNKNOWN IMPORTED)
+ add_library(Opus::Opus UNKNOWN IMPORTED GLOBAL)
set_target_properties(Opus::Opus PROPERTIES
IMPORTED_LOCATION "${opus_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_opus_CFLAGS_OTHER}"
diff --git a/externals/opus/CMakeLists.txt b/externals/opus/CMakeLists.txt
index 94a86551f..16f5af9f2 100644
--- a/externals/opus/CMakeLists.txt
+++ b/externals/opus/CMakeLists.txt
@@ -252,3 +252,5 @@ PRIVATE
opus/silk/float
opus/src
)
+
+add_library(Opus::Opus ALIAS opus)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 66931ac97..9f8dafa3b 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -110,6 +110,7 @@ add_library(common STATIC
cityhash.h
common_funcs.h
common_paths.h
+ common_sizes.h
common_types.h
concepts.h
div_ceil.h
diff --git a/src/common/common_sizes.h b/src/common/common_sizes.h
new file mode 100644
index 000000000..7e9fd968b
--- /dev/null
+++ b/src/common/common_sizes.h
@@ -0,0 +1,43 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <limits>
+
+#include "common/common_types.h"
+
+namespace Common {
+
+enum : u64 {
+ Size_1_KB = 0x400ULL,
+ Size_64_KB = 64ULL * Size_1_KB,
+ Size_128_KB = 128ULL * Size_1_KB,
+ Size_1_MB = 0x100000ULL,
+ Size_2_MB = 2ULL * Size_1_MB,
+ Size_4_MB = 4ULL * Size_1_MB,
+ Size_5_MB = 5ULL * Size_1_MB,
+ Size_14_MB = 14ULL * Size_1_MB,
+ Size_32_MB = 32ULL * Size_1_MB,
+ Size_33_MB = 33ULL * Size_1_MB,
+ Size_128_MB = 128ULL * Size_1_MB,
+ Size_448_MB = 448ULL * Size_1_MB,
+ Size_507_MB = 507ULL * Size_1_MB,
+ Size_562_MB = 562ULL * Size_1_MB,
+ Size_1554_MB = 1554ULL * Size_1_MB,
+ Size_2048_MB = 2048ULL * Size_1_MB,
+ Size_2193_MB = 2193ULL * Size_1_MB,
+ Size_3285_MB = 3285ULL * Size_1_MB,
+ Size_4916_MB = 4916ULL * Size_1_MB,
+ Size_1_GB = 0x40000000ULL,
+ Size_2_GB = 2ULL * Size_1_GB,
+ Size_4_GB = 4ULL * Size_1_GB,
+ Size_6_GB = 6ULL * Size_1_GB,
+ Size_8_GB = 8ULL * Size_1_GB,
+ Size_64_GB = 64ULL * Size_1_GB,
+ Size_512_GB = 512ULL * Size_1_GB,
+ Size_Invalid = std::numeric_limits<u64>::max(),
+};
+
+} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 2d4d2e9e7..4575df24d 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -212,6 +212,7 @@ void DebuggerBackend::Write(const Entry& entry) {
SUB(Service, ARP) \
SUB(Service, BCAT) \
SUB(Service, BPC) \
+ SUB(Service, BGTC) \
SUB(Service, BTDRV) \
SUB(Service, BTM) \
SUB(Service, Capture) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 835894918..3d7b7dab7 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -66,6 +66,7 @@ enum class Class : ClassType {
Service_ARP, ///< The ARP service
Service_Audio, ///< The Audio (Audio control) service
Service_BCAT, ///< The BCAT service
+ Service_BGTC, ///< The BGTC (Background Task Controller) service
Service_BPC, ///< The BPC service
Service_BTDRV, ///< The Bluetooth driver service
Service_BTM, ///< The BTM service
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index a4647314a..ad04df8ca 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -83,11 +83,15 @@ public:
return true;
}
- T PopWait() {
+ void Wait() {
if (Empty()) {
std::unique_lock lock{cv_mutex};
cv.wait(lock, [this]() { return !Empty(); });
}
+ }
+
+ T PopWait() {
+ Wait();
T t;
Pop(t);
return t;
@@ -156,6 +160,10 @@ public:
return spsc_queue.Pop(t);
}
+ void Wait() {
+ spsc_queue.Wait();
+ }
+
T PopWait() {
return spsc_queue.PopWait();
}
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 17f251c37..167ee13f3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -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
@@ -666,7 +673,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
-target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
+target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus zip)
if (YUZU_ENABLE_BOXCAT)
target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 305f56ff1..56b47e671 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -296,7 +296,7 @@ struct System::Impl {
exit_lock = false;
if (gpu_core) {
- gpu_core->WaitIdle();
+ gpu_core->ShutDown();
}
services.reset();
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index b0a130345..f66759815 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.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));
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 403c4219a..dd9837cf5 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -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{};
diff --git a/src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc b/src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc
new file mode 100644
index 000000000..857b512ba
--- /dev/null
+++ b/src/core/hle/kernel/arch/arm64/k_memory_region_device_types.inc
@@ -0,0 +1,20 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// All architectures must define NumArchitectureDeviceRegions.
+constexpr inline const auto NumArchitectureDeviceRegions = 3;
+
+constexpr inline const auto KMemoryRegionType_Uart =
+ KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
+constexpr inline const auto KMemoryRegionType_InterruptCpuInterface =
+ KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_InterruptDistributor =
+ KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+static_assert(KMemoryRegionType_Uart.GetValue() == (0x1D));
+static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() ==
+ (0x2D | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_InterruptDistributor.GetValue() ==
+ (0x4D | KMemoryRegionAttr_NoUserMap));
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc b/src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc
new file mode 100644
index 000000000..58d6c0b16
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc
@@ -0,0 +1,52 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// All architectures must define NumBoardDeviceRegions.
+constexpr inline const auto NumBoardDeviceRegions = 6;
+// UNUSED: .Derive(NumBoardDeviceRegions, 0);
+constexpr inline const auto KMemoryRegionType_MemoryController =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_MemoryController1 =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_MemoryController0 =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap);
+constexpr inline const auto KMemoryRegionType_PowerManagementController =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition();
+constexpr inline const auto KMemoryRegionType_LegacyLpsDevices =
+ KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5);
+static_assert(KMemoryRegionType_MemoryController.GetValue() ==
+ (0x55 | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_MemoryController1.GetValue() ==
+ (0x65 | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_MemoryController0.GetValue() ==
+ (0x95 | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5));
+
+static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5);
+
+constexpr inline const auto NumLegacyLpsDevices = 7;
+constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0);
+constexpr inline const auto KMemoryRegionType_LegacyLpsIram =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1);
+constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2);
+constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3);
+constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4);
+constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5);
+constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst =
+ KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6);
+static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5);
+static_assert(KMemoryRegionType_LegacyLpsIram.GetValue() == 0x5C5);
+static_assert(KMemoryRegionType_LegacyLpsFlowController.GetValue() == 0x6C5);
+static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr.GetValue() == 0x9C5);
+static_assert(KMemoryRegionType_LegacyLpsSemaphore.GetValue() == 0xAC5);
+static_assert(KMemoryRegionType_LegacyLpsAtomics.GetValue() == 0xCC5);
+static_assert(KMemoryRegionType_LegacyLpsClkRst.GetValue() == 0x11C5);
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
new file mode 100644
index 000000000..86472b5ce
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -0,0 +1,164 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <random>
+
+#include "common/common_sizes.h"
+#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
+#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
+#include "core/hle/kernel/k_trace.h"
+
+namespace Kernel::Board::Nintendo::Nx {
+
+namespace impl {
+
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024;
+
+} // namespace impl
+
+constexpr const std::size_t RequiredNonSecureSystemMemorySize =
+ impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
+ impl::RequiredNonSecureSystemMemorySizeMisc;
+
+namespace {
+
+u32 GetMemoryModeForInit() {
+ return 0x01;
+}
+
+u32 GetMemorySizeForInit() {
+ return 0;
+}
+
+Smc::MemoryArrangement GetMemoryArrangeForInit() {
+ switch (GetMemoryModeForInit() & 0x3F) {
+ case 0x01:
+ default:
+ return Smc::MemoryArrangement_4GB;
+ case 0x02:
+ return Smc::MemoryArrangement_4GBForAppletDev;
+ case 0x03:
+ return Smc::MemoryArrangement_4GBForSystemDev;
+ case 0x11:
+ return Smc::MemoryArrangement_6GB;
+ case 0x12:
+ return Smc::MemoryArrangement_6GBForAppletDev;
+ case 0x21:
+ return Smc::MemoryArrangement_8GB;
+ }
+}
+} // namespace
+
+// Initialization.
+size_t KSystemControl::Init::GetIntendedMemorySize() {
+ switch (GetMemorySizeForInit()) {
+ case Smc::MemorySize_4GB:
+ default: // All invalid modes should go to 4GB.
+ return Common::Size_4_GB;
+ case Smc::MemorySize_6GB:
+ return Common::Size_6_GB;
+ case Smc::MemorySize_8GB:
+ return Common::Size_8_GB;
+ }
+}
+
+PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
+ return base_address;
+}
+
+bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
+ return true;
+}
+
+std::size_t KSystemControl::Init::GetApplicationPoolSize() {
+ // Get the base pool size.
+ const size_t base_pool_size = []() -> size_t {
+ switch (GetMemoryArrangeForInit()) {
+ case Smc::MemoryArrangement_4GB:
+ default:
+ return Common::Size_3285_MB;
+ case Smc::MemoryArrangement_4GBForAppletDev:
+ return Common::Size_2048_MB;
+ case Smc::MemoryArrangement_4GBForSystemDev:
+ return Common::Size_3285_MB;
+ case Smc::MemoryArrangement_6GB:
+ return Common::Size_4916_MB;
+ case Smc::MemoryArrangement_6GBForAppletDev:
+ return Common::Size_3285_MB;
+ case Smc::MemoryArrangement_8GB:
+ return Common::Size_4916_MB;
+ }
+ }();
+
+ // Return (possibly) adjusted size.
+ return base_pool_size;
+}
+
+size_t KSystemControl::Init::GetAppletPoolSize() {
+ // Get the base pool size.
+ const size_t base_pool_size = []() -> size_t {
+ switch (GetMemoryArrangeForInit()) {
+ case Smc::MemoryArrangement_4GB:
+ default:
+ return Common::Size_507_MB;
+ case Smc::MemoryArrangement_4GBForAppletDev:
+ return Common::Size_1554_MB;
+ case Smc::MemoryArrangement_4GBForSystemDev:
+ return Common::Size_448_MB;
+ case Smc::MemoryArrangement_6GB:
+ return Common::Size_562_MB;
+ case Smc::MemoryArrangement_6GBForAppletDev:
+ return Common::Size_2193_MB;
+ case Smc::MemoryArrangement_8GB:
+ return Common::Size_2193_MB;
+ }
+ }();
+
+ // Return (possibly) adjusted size.
+ constexpr size_t ExtraSystemMemoryForAtmosphere = Common::Size_33_MB;
+ return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
+}
+
+size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
+ // Verify that our minimum is at least as large as Nintendo's.
+ constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize;
+ static_assert(MinimumSize >= 0x29C8000);
+
+ return MinimumSize;
+}
+
+namespace {
+template <typename F>
+u64 GenerateUniformRange(u64 min, u64 max, F f) {
+ // Handle the case where the difference is too large to represent.
+ if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
+ return f();
+ }
+
+ // Iterate until we get a value in range.
+ const u64 range_size = ((max + 1) - min);
+ const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
+ while (true) {
+ if (const u64 rnd = f(); rnd < effective_max) {
+ return min + (rnd % range_size);
+ }
+ }
+}
+
+} // Anonymous namespace
+
+u64 KSystemControl::GenerateRandomU64() {
+ static std::random_device device;
+ static std::mt19937 gen(device());
+ static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
+ return distribution(gen);
+}
+
+u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
+ return GenerateUniformRange(min, max, GenerateRandomU64);
+}
+
+} // namespace Kernel::Board::Nintendo::Nx
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.h b/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
new file mode 100644
index 000000000..52f230ced
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
@@ -0,0 +1,28 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Kernel::Board::Nintendo::Nx {
+
+class KSystemControl {
+public:
+ class Init {
+ public:
+ // Initialization.
+ static std::size_t GetIntendedMemorySize();
+ static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
+ static bool ShouldIncreaseThreadResourceLimit();
+ static std::size_t GetApplicationPoolSize();
+ static std::size_t GetAppletPoolSize();
+ static std::size_t GetMinimumNonSecureSystemPoolSize();
+ };
+
+ static u64 GenerateRandomRange(u64 min, u64 max);
+ static u64 GenerateRandomU64();
+};
+
+} // namespace Kernel::Board::Nintendo::Nx
diff --git a/src/core/hle/kernel/board/nintendo/nx/secure_monitor.h b/src/core/hle/kernel/board/nintendo/nx/secure_monitor.h
new file mode 100644
index 000000000..0c366b252
--- /dev/null
+++ b/src/core/hle/kernel/board/nintendo/nx/secure_monitor.h
@@ -0,0 +1,26 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Kernel::Board::Nintendo::Nx::Smc {
+
+enum MemorySize {
+ MemorySize_4GB = 0,
+ MemorySize_6GB = 1,
+ MemorySize_8GB = 2,
+};
+
+enum MemoryArrangement {
+ MemoryArrangement_4GB = 0,
+ MemoryArrangement_4GBForAppletDev = 1,
+ MemoryArrangement_4GBForSystemDev = 2,
+ MemoryArrangement_6GB = 3,
+ MemoryArrangement_6GBForAppletDev = 4,
+ MemoryArrangement_8GB = 5,
+};
+
+} // namespace Kernel::Board::Nintendo::Nx::Smc
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp
index 24944d15b..c7549f7a2 100644
--- a/src/core/hle/kernel/k_address_space_info.cpp
+++ b/src/core/hle/kernel/k_address_space_info.cpp
@@ -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 =
diff --git a/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp b/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp
new file mode 100644
index 000000000..a78551291
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp
@@ -0,0 +1,199 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/alignment.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_system_control.h"
+#include "core/hle/kernel/k_trace.h"
+
+namespace Kernel {
+
+namespace {
+
+constexpr size_t CarveoutAlignment = 0x20000;
+constexpr size_t CarveoutSizeMax = (512ULL * 1024 * 1024) - CarveoutAlignment;
+
+bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
+ // Above firmware 2.0.0, the PMC is not mappable.
+ return memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7000E000, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap) &&
+ memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7000E400, 0xC00,
+ KMemoryRegionType_PowerManagementController | KMemoryRegionAttr_NoUserMap);
+}
+
+void InsertPoolPartitionRegionIntoBothTrees(KMemoryLayout& memory_layout, size_t start, size_t size,
+ KMemoryRegionType phys_type,
+ KMemoryRegionType virt_type, u32& cur_attr) {
+ const u32 attr = cur_attr++;
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(start, size,
+ static_cast<u32>(phys_type), attr));
+ const KMemoryRegion* phys = memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
+ static_cast<u32>(phys_type), attr);
+ ASSERT(phys != nullptr);
+ ASSERT(phys->GetEndAddress() != 0);
+ ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size,
+ static_cast<u32>(virt_type), attr));
+}
+
+} // namespace
+
+namespace Init {
+
+void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
+ ASSERT(SetupPowerManagementControllerMemoryRegion(memory_layout));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50041000, 0x1000,
+ KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50042000, 0x1000,
+ KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+
+ // Map IRAM unconditionally, to support debug-logging-to-iram build config.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x40000000, 0x40000, KMemoryRegionType_LegacyLpsIram | KMemoryRegionAttr_ShouldKernelMap));
+
+ // Above firmware 2.0.0, prevent mapping the bpmp exception vectors or the ipatch region.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ 0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap));
+}
+
+void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
+ const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
+ const PAddr physical_memory_base_address =
+ KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);
+
+ // Insert blocks into the tree.
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ physical_memory_base_address, intended_memory_size, KMemoryRegionType_Dram));
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ physical_memory_base_address, ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly));
+
+ // Insert the KTrace block at the end of Dram, if KTrace is enabled.
+ static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
+ if constexpr (IsKTraceEnabled) {
+ const PAddr ktrace_buffer_phys_addr =
+ physical_memory_base_address + intended_memory_size - KTraceBufferSize;
+ ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
+ ktrace_buffer_phys_addr, KTraceBufferSize, KMemoryRegionType_KernelTraceBuffer));
+ }
+}
+
+void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout) {
+ // Start by identifying the extents of the DRAM memory region.
+ const auto dram_extents = memory_layout.GetMainMemoryPhysicalExtents();
+ ASSERT(dram_extents.GetEndAddress() != 0);
+
+ // Determine the end of the pool region.
+ const u64 pool_end = dram_extents.GetEndAddress() - KTraceBufferSize;
+
+ // Find the start of the kernel DRAM region.
+ const KMemoryRegion* kernel_dram_region =
+ memory_layout.GetPhysicalMemoryRegionTree().FindFirstDerived(
+ KMemoryRegionType_DramKernelBase);
+ ASSERT(kernel_dram_region != nullptr);
+
+ const u64 kernel_dram_start = kernel_dram_region->GetAddress();
+ ASSERT(Common::IsAligned(kernel_dram_start, CarveoutAlignment));
+
+ // Find the start of the pool partitions region.
+ const KMemoryRegion* pool_partitions_region =
+ memory_layout.GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(
+ KMemoryRegionType_DramPoolPartition, 0);
+ ASSERT(pool_partitions_region != nullptr);
+ const u64 pool_partitions_start = pool_partitions_region->GetAddress();
+
+ // Setup the pool partition layouts.
+ // On 5.0.0+, setup modern 4-pool-partition layout.
+
+ // Get Application and Applet pool sizes.
+ const size_t application_pool_size = KSystemControl::Init::GetApplicationPoolSize();
+ const size_t applet_pool_size = KSystemControl::Init::GetAppletPoolSize();
+ const size_t unsafe_system_pool_min_size =
+ KSystemControl::Init::GetMinimumNonSecureSystemPoolSize();
+
+ // Decide on starting addresses for our pools.
+ const u64 application_pool_start = pool_end - application_pool_size;
+ const u64 applet_pool_start = application_pool_start - applet_pool_size;
+ const u64 unsafe_system_pool_start = std::min(
+ kernel_dram_start + CarveoutSizeMax,
+ Common::AlignDown(applet_pool_start - unsafe_system_pool_min_size, CarveoutAlignment));
+ const size_t unsafe_system_pool_size = applet_pool_start - unsafe_system_pool_start;
+
+ // We want to arrange application pool depending on where the middle of dram is.
+ const u64 dram_midpoint = (dram_extents.GetAddress() + dram_extents.GetEndAddress()) / 2;
+ u32 cur_pool_attr = 0;
+ size_t total_overhead_size = 0;
+ if (dram_extents.GetEndAddress() <= dram_midpoint || dram_midpoint <= application_pool_start) {
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, application_pool_start, application_pool_size,
+ KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
+ cur_pool_attr);
+ total_overhead_size +=
+ KMemoryManager::CalculateManagementOverheadSize(application_pool_size);
+ } else {
+ const size_t first_application_pool_size = dram_midpoint - application_pool_start;
+ const size_t second_application_pool_size =
+ application_pool_start + application_pool_size - dram_midpoint;
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, application_pool_start, first_application_pool_size,
+ KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
+ cur_pool_attr);
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, dram_midpoint, second_application_pool_size,
+ KMemoryRegionType_DramApplicationPool, KMemoryRegionType_VirtualDramApplicationPool,
+ cur_pool_attr);
+ total_overhead_size +=
+ KMemoryManager::CalculateManagementOverheadSize(first_application_pool_size);
+ total_overhead_size +=
+ KMemoryManager::CalculateManagementOverheadSize(second_application_pool_size);
+ }
+
+ // Insert the applet pool.
+ InsertPoolPartitionRegionIntoBothTrees(memory_layout, applet_pool_start, applet_pool_size,
+ KMemoryRegionType_DramAppletPool,
+ KMemoryRegionType_VirtualDramAppletPool, cur_pool_attr);
+ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(applet_pool_size);
+
+ // Insert the nonsecure system pool.
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, unsafe_system_pool_start, unsafe_system_pool_size,
+ KMemoryRegionType_DramSystemNonSecurePool, KMemoryRegionType_VirtualDramSystemNonSecurePool,
+ cur_pool_attr);
+ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(unsafe_system_pool_size);
+
+ // Insert the pool management region.
+ total_overhead_size += KMemoryManager::CalculateManagementOverheadSize(
+ (unsafe_system_pool_start - pool_partitions_start) - total_overhead_size);
+ const u64 pool_management_start = unsafe_system_pool_start - total_overhead_size;
+ const size_t pool_management_size = total_overhead_size;
+ u32 pool_management_attr = 0;
+ InsertPoolPartitionRegionIntoBothTrees(
+ memory_layout, pool_management_start, pool_management_size,
+ KMemoryRegionType_DramPoolManagement, KMemoryRegionType_VirtualDramPoolManagement,
+ pool_management_attr);
+
+ // Insert the system pool.
+ const u64 system_pool_size = pool_management_start - pool_partitions_start;
+ InsertPoolPartitionRegionIntoBothTrees(memory_layout, pool_partitions_start, system_pool_size,
+ KMemoryRegionType_DramSystemPool,
+ KMemoryRegionType_VirtualDramSystemPool, cur_pool_attr);
+}
+
+} // namespace Init
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_layout.cpp b/src/core/hle/kernel/k_memory_layout.cpp
new file mode 100644
index 000000000..fb1e2435f
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_layout.cpp
@@ -0,0 +1,166 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <array>
+
+#include "common/alignment.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_system_control.h"
+
+namespace Kernel {
+
+namespace {
+
+template <typename... Args>
+KMemoryRegion* AllocateRegion(KMemoryRegionAllocator& memory_region_allocator, Args&&... args) {
+ return memory_region_allocator.Allocate(std::forward<Args>(args)...);
+}
+
+} // namespace
+
+KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_)
+ : memory_region_allocator{memory_region_allocator_} {}
+
+void KMemoryRegionTree::InsertDirectly(u64 address, u64 last_address, u32 attr, u32 type_id) {
+ this->insert(*AllocateRegion(memory_region_allocator, address, last_address, attr, type_id));
+}
+
+bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
+ // Locate the memory region that contains the address.
+ KMemoryRegion* found = this->FindModifiable(address);
+
+ // We require that the old attr is correct.
+ if (found->GetAttributes() != old_attr) {
+ return false;
+ }
+
+ // We further require that the region can be split from the old region.
+ const u64 inserted_region_end = address + size;
+ const u64 inserted_region_last = inserted_region_end - 1;
+ if (found->GetLastAddress() < inserted_region_last) {
+ return false;
+ }
+
+ // Further, we require that the type id is a valid transformation.
+ if (!found->CanDerive(type_id)) {
+ return false;
+ }
+
+ // Cache information from the region before we remove it.
+ const u64 old_address = found->GetAddress();
+ const u64 old_last = found->GetLastAddress();
+ const u64 old_pair = found->GetPairAddress();
+ const u32 old_type = found->GetType();
+
+ // Erase the existing region from the tree.
+ this->erase(this->iterator_to(*found));
+
+ // Insert the new region into the tree.
+ if (old_address == address) {
+ // Reuse the old object for the new region, if we can.
+ found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
+ this->insert(*found);
+ } else {
+ // If we can't re-use, adjust the old region.
+ found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
+ this->insert(*found);
+
+ // Insert a new region for the split.
+ const u64 new_pair = (old_pair != std::numeric_limits<u64>::max())
+ ? old_pair + (address - old_address)
+ : old_pair;
+ this->insert(*AllocateRegion(memory_region_allocator, address, inserted_region_last,
+ new_pair, new_attr, type_id));
+ }
+
+ // If we need to insert a region after the region, do so.
+ if (old_last != inserted_region_last) {
+ const u64 after_pair = (old_pair != std::numeric_limits<u64>::max())
+ ? old_pair + (inserted_region_end - old_address)
+ : old_pair;
+ this->insert(*AllocateRegion(memory_region_allocator, inserted_region_end, old_last,
+ after_pair, old_attr, old_type));
+ }
+
+ return true;
+}
+
+VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id) {
+ // We want to find the total extents of the type id.
+ const auto extents = this->GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
+
+ // Ensure that our alignment is correct.
+ ASSERT(Common::IsAligned(extents.GetAddress(), alignment));
+
+ const u64 first_address = extents.GetAddress();
+ const u64 last_address = extents.GetLastAddress();
+
+ const u64 first_index = first_address / alignment;
+ const u64 last_index = last_address / alignment;
+
+ while (true) {
+ const u64 candidate =
+ KSystemControl::GenerateRandomRange(first_index, last_index) * alignment;
+
+ // Ensure that the candidate doesn't overflow with the size.
+ if (!(candidate < candidate + size)) {
+ continue;
+ }
+
+ const u64 candidate_last = candidate + size - 1;
+
+ // Ensure that the candidate fits within the region.
+ if (candidate_last > last_address) {
+ continue;
+ }
+
+ // Locate the candidate region, and ensure it fits and has the correct type id.
+ if (const auto& candidate_region = *this->Find(candidate);
+ !(candidate_last <= candidate_region.GetLastAddress() &&
+ candidate_region.GetType() == type_id)) {
+ continue;
+ }
+
+ return candidate;
+ }
+}
+
+KMemoryLayout::KMemoryLayout()
+ : virtual_tree{memory_region_allocator}, physical_tree{memory_region_allocator},
+ virtual_linear_tree{memory_region_allocator}, physical_linear_tree{memory_region_allocator} {}
+
+void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
+ VAddr linear_virtual_start) {
+ // Set static differences.
+ linear_phys_to_virt_diff = linear_virtual_start - aligned_linear_phys_start;
+ linear_virt_to_phys_diff = aligned_linear_phys_start - linear_virtual_start;
+
+ // Initialize linear trees.
+ for (auto& region : GetPhysicalMemoryRegionTree()) {
+ if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
+ GetPhysicalLinearMemoryRegionTree().InsertDirectly(
+ region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
+ region.GetType());
+ }
+ }
+
+ for (auto& region : GetVirtualMemoryRegionTree()) {
+ if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
+ GetVirtualLinearMemoryRegionTree().InsertDirectly(
+ region.GetAddress(), region.GetLastAddress(), region.GetAttributes(),
+ region.GetType());
+ }
+ }
+}
+
+size_t KMemoryLayout::GetResourceRegionSizeForInit() {
+ // Calculate resource region size based on whether we allow extra threads.
+ const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
+ size_t resource_region_size =
+ KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0);
+
+ return resource_region_size;
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h
index 0821d2d8c..288642d9a 100644
--- a/src/core/hle/kernel/k_memory_layout.h
+++ b/src/core/hle/kernel/k_memory_layout.h
@@ -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;
-
+class KMemoryLayout final {
public:
- constexpr PAddr StartAddress() const {
- return start_address;
+ 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;
+ }
+
+ VAddr GetLinearVirtualAddress(PAddr address) const {
+ return address + linear_phys_to_virt_diff;
+ }
+ PAddr GetLinearPhysicalAddress(VAddr address) const {
+ return address + linear_virt_to_phys_diff;
+ }
+
+ const KMemoryRegion* FindVirtual(VAddr address) const {
+ return Find(address, GetVirtualMemoryRegionTree());
+ }
+ const KMemoryRegion* FindPhysical(PAddr address) const {
+ return Find(address, GetPhysicalMemoryRegionTree());
+ }
+
+ 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);
}
- constexpr PAddr EndAddress() const {
- return end_address;
+ auto GetKernelTraceBufferRegionPhysicalExtents() const {
+ return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
+ KMemoryRegionType_KernelTraceBuffer);
}
private:
- constexpr KMemoryRegion() = default;
- constexpr KMemoryRegion(PAddr start_address, PAddr end_address)
- : start_address{start_address}, end_address{end_address} {}
+ 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 PAddr start_address{};
- const PAddr end_address{};
-};
+ // 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;
+ }
+ }
-class KMemoryLayout final {
-public:
- constexpr const KMemoryRegion& Application() const {
- return application;
+ 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;
}
- constexpr const KMemoryRegion& Applet() const {
- return applet;
+ template <typename AddressType>
+ static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
+ return tree.Find(address);
}
- constexpr const KMemoryRegion& System() const {
- return system;
+ static KMemoryRegion& Dereference(KMemoryRegion* region) {
+ ASSERT(region != nullptr);
+ return *region;
}
- 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};
+ 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:
- 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} {}
-
- const KMemoryRegion application;
- const KMemoryRegion applet;
- const KMemoryRegion system;
+ 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
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index 9027602bf..aa71697b2 100644
--- a/src/core/hle/kernel/k_memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -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
diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h
index ae9f683b8..ac840b3d0 100644
--- a/src/core/hle/kernel/k_memory_manager.h
+++ b/src/core/hle/kernel/k_memory_manager.h
@@ -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));
@@ -86,6 +94,16 @@ private:
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;
std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address);
diff --git a/src/core/hle/kernel/k_memory_region.h b/src/core/hle/kernel/k_memory_region.h
new file mode 100644
index 000000000..a861c04ab
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_region.h
@@ -0,0 +1,350 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/intrusive_red_black_tree.h"
+#include "core/hle/kernel/k_memory_region_type.h"
+
+namespace Kernel {
+
+class KMemoryRegionAllocator;
+
+class KMemoryRegion final : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryRegion>,
+ NonCopyable {
+ friend class KMemoryRegionTree;
+
+public:
+ constexpr KMemoryRegion() = default;
+ constexpr KMemoryRegion(u64 address_, u64 last_address_)
+ : address{address_}, last_address{last_address_} {}
+ constexpr KMemoryRegion(u64 address_, u64 last_address_, u64 pair_address_, u32 attributes_,
+ u32 type_id_)
+ : address(address_), last_address(last_address_), pair_address(pair_address_),
+ attributes(attributes_), type_id(type_id_) {}
+ constexpr KMemoryRegion(u64 address_, u64 last_address_, u32 attributes_, u32 type_id_)
+ : KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
+ type_id_) {}
+
+ static constexpr int Compare(const KMemoryRegion& lhs, const KMemoryRegion& rhs) {
+ if (lhs.GetAddress() < rhs.GetAddress()) {
+ return -1;
+ } else if (lhs.GetAddress() <= rhs.GetLastAddress()) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+private:
+ constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
+ address = a;
+ pair_address = p;
+ last_address = la;
+ attributes = r;
+ type_id = t;
+ }
+
+public:
+ constexpr u64 GetAddress() const {
+ return address;
+ }
+
+ constexpr u64 GetPairAddress() const {
+ return pair_address;
+ }
+
+ constexpr u64 GetLastAddress() const {
+ return last_address;
+ }
+
+ constexpr u64 GetEndAddress() const {
+ return this->GetLastAddress() + 1;
+ }
+
+ constexpr size_t GetSize() const {
+ return this->GetEndAddress() - this->GetAddress();
+ }
+
+ constexpr u32 GetAttributes() const {
+ return attributes;
+ }
+
+ constexpr u32 GetType() const {
+ return type_id;
+ }
+
+ constexpr void SetType(u32 type) {
+ ASSERT(this->CanDerive(type));
+ type_id = type;
+ }
+
+ constexpr bool Contains(u64 address) const {
+ ASSERT(this->GetEndAddress() != 0);
+ return this->GetAddress() <= address && address <= this->GetLastAddress();
+ }
+
+ constexpr bool IsDerivedFrom(u32 type) const {
+ return (this->GetType() | type) == this->GetType();
+ }
+
+ constexpr bool HasTypeAttribute(u32 attr) const {
+ return (this->GetType() | attr) == this->GetType();
+ }
+
+ constexpr bool CanDerive(u32 type) const {
+ return (this->GetType() | type) == type;
+ }
+
+ constexpr void SetPairAddress(u64 a) {
+ pair_address = a;
+ }
+
+ constexpr void SetTypeAttribute(u32 attr) {
+ type_id |= attr;
+ }
+
+private:
+ u64 address{};
+ u64 last_address{};
+ u64 pair_address{};
+ u32 attributes{};
+ u32 type_id{};
+};
+
+class KMemoryRegionTree final : NonCopyable {
+public:
+ struct DerivedRegionExtents {
+ const KMemoryRegion* first_region{};
+ const KMemoryRegion* last_region{};
+
+ constexpr DerivedRegionExtents() = default;
+
+ constexpr u64 GetAddress() const {
+ return this->first_region->GetAddress();
+ }
+
+ constexpr u64 GetLastAddress() const {
+ return this->last_region->GetLastAddress();
+ }
+
+ constexpr u64 GetEndAddress() const {
+ return this->GetLastAddress() + 1;
+ }
+
+ constexpr size_t GetSize() const {
+ return this->GetEndAddress() - this->GetAddress();
+ }
+ };
+
+private:
+ using TreeType =
+ Common::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
+
+public:
+ using value_type = TreeType::value_type;
+ using size_type = TreeType::size_type;
+ using difference_type = TreeType::difference_type;
+ using pointer = TreeType::pointer;
+ using const_pointer = TreeType::const_pointer;
+ using reference = TreeType::reference;
+ using const_reference = TreeType::const_reference;
+ using iterator = TreeType::iterator;
+ using const_iterator = TreeType::const_iterator;
+
+private:
+ TreeType m_tree{};
+ KMemoryRegionAllocator& memory_region_allocator;
+
+public:
+ explicit KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_);
+
+public:
+ KMemoryRegion* FindModifiable(u64 address) {
+ if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
+ return std::addressof(*it);
+ } else {
+ return nullptr;
+ }
+ }
+
+ const KMemoryRegion* Find(u64 address) const {
+ if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->cend()) {
+ return std::addressof(*it);
+ } else {
+ return nullptr;
+ }
+ }
+
+ const KMemoryRegion* FindByType(KMemoryRegionType type_id) const {
+ for (auto it = this->cbegin(); it != this->cend(); ++it) {
+ if (it->GetType() == static_cast<u32>(type_id)) {
+ return std::addressof(*it);
+ }
+ }
+ return nullptr;
+ }
+
+ const KMemoryRegion* FindByTypeAndAttribute(u32 type_id, u32 attr) const {
+ for (auto it = this->cbegin(); it != this->cend(); ++it) {
+ if (it->GetType() == type_id && it->GetAttributes() == attr) {
+ return std::addressof(*it);
+ }
+ }
+ return nullptr;
+ }
+
+ const KMemoryRegion* FindFirstDerived(KMemoryRegionType type_id) const {
+ for (auto it = this->cbegin(); it != this->cend(); it++) {
+ if (it->IsDerivedFrom(type_id)) {
+ return std::addressof(*it);
+ }
+ }
+ return nullptr;
+ }
+
+ const KMemoryRegion* FindLastDerived(KMemoryRegionType type_id) const {
+ const KMemoryRegion* region = nullptr;
+ for (auto it = this->begin(); it != this->end(); it++) {
+ if (it->IsDerivedFrom(type_id)) {
+ region = std::addressof(*it);
+ }
+ }
+ return region;
+ }
+
+ DerivedRegionExtents GetDerivedRegionExtents(KMemoryRegionType type_id) const {
+ DerivedRegionExtents extents;
+
+ ASSERT(extents.first_region == nullptr);
+ ASSERT(extents.last_region == nullptr);
+
+ for (auto it = this->cbegin(); it != this->cend(); it++) {
+ if (it->IsDerivedFrom(type_id)) {
+ if (extents.first_region == nullptr) {
+ extents.first_region = std::addressof(*it);
+ }
+ extents.last_region = std::addressof(*it);
+ }
+ }
+
+ ASSERT(extents.first_region != nullptr);
+ ASSERT(extents.last_region != nullptr);
+
+ return extents;
+ }
+
+ DerivedRegionExtents GetDerivedRegionExtents(u32 type_id) const {
+ return GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
+ }
+
+public:
+ void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
+ bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
+
+ VAddr GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
+
+ VAddr GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
+ size_t guard_size) {
+ return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
+ }
+
+public:
+ // Iterator accessors.
+ iterator begin() {
+ return m_tree.begin();
+ }
+
+ const_iterator begin() const {
+ return m_tree.begin();
+ }
+
+ iterator end() {
+ return m_tree.end();
+ }
+
+ const_iterator end() const {
+ return m_tree.end();
+ }
+
+ const_iterator cbegin() const {
+ return this->begin();
+ }
+
+ const_iterator cend() const {
+ return this->end();
+ }
+
+ iterator iterator_to(reference ref) {
+ return m_tree.iterator_to(ref);
+ }
+
+ const_iterator iterator_to(const_reference ref) const {
+ return m_tree.iterator_to(ref);
+ }
+
+ // Content management.
+ bool empty() const {
+ return m_tree.empty();
+ }
+
+ reference back() {
+ return m_tree.back();
+ }
+
+ const_reference back() const {
+ return m_tree.back();
+ }
+
+ reference front() {
+ return m_tree.front();
+ }
+
+ const_reference front() const {
+ return m_tree.front();
+ }
+
+ iterator insert(reference ref) {
+ return m_tree.insert(ref);
+ }
+
+ iterator erase(iterator it) {
+ return m_tree.erase(it);
+ }
+
+ iterator find(const_reference ref) const {
+ return m_tree.find(ref);
+ }
+
+ iterator nfind(const_reference ref) const {
+ return m_tree.nfind(ref);
+ }
+};
+
+class KMemoryRegionAllocator final : NonCopyable {
+public:
+ static constexpr size_t MaxMemoryRegions = 200;
+
+ constexpr KMemoryRegionAllocator() = default;
+
+ template <typename... Args>
+ KMemoryRegion* Allocate(Args&&... args) {
+ // Ensure we stay within the bounds of our heap.
+ ASSERT(this->num_regions < MaxMemoryRegions);
+
+ // Create the new region.
+ KMemoryRegion* region = std::addressof(this->region_heap[this->num_regions++]);
+ new (region) KMemoryRegion(std::forward<Args>(args)...);
+
+ return region;
+ }
+
+private:
+ std::array<KMemoryRegion, MaxMemoryRegions> region_heap{};
+ size_t num_regions{};
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_region_type.h b/src/core/hle/kernel/k_memory_region_type.h
new file mode 100644
index 000000000..a05e66677
--- /dev/null
+++ b/src/core/hle/kernel/k_memory_region_type.h
@@ -0,0 +1,338 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/bit_util.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+#define ARCH_ARM64
+#define BOARD_NINTENDO_NX
+
+namespace Kernel {
+
+enum KMemoryRegionType : u32 {
+ KMemoryRegionAttr_CarveoutProtected = 0x04000000,
+ KMemoryRegionAttr_DidKernelMap = 0x08000000,
+ KMemoryRegionAttr_ShouldKernelMap = 0x10000000,
+ KMemoryRegionAttr_UserReadOnly = 0x20000000,
+ KMemoryRegionAttr_NoUserMap = 0x40000000,
+ KMemoryRegionAttr_LinearMapped = 0x80000000,
+};
+DECLARE_ENUM_FLAG_OPERATORS(KMemoryRegionType);
+
+namespace impl {
+
+constexpr size_t BitsForDeriveSparse(size_t n) {
+ return n + 1;
+}
+
+constexpr size_t BitsForDeriveDense(size_t n) {
+ size_t low = 0, high = 1;
+ for (size_t i = 0; i < n - 1; ++i) {
+ if ((++low) == high) {
+ ++high;
+ low = 0;
+ }
+ }
+ return high + 1;
+}
+
+class KMemoryRegionTypeValue {
+public:
+ using ValueType = std::underlying_type_t<KMemoryRegionType>;
+
+ constexpr KMemoryRegionTypeValue() = default;
+
+ constexpr operator KMemoryRegionType() const {
+ return static_cast<KMemoryRegionType>(m_value);
+ }
+
+ constexpr ValueType GetValue() const {
+ return m_value;
+ }
+
+ constexpr const KMemoryRegionTypeValue& Finalize() {
+ m_finalized = true;
+ return *this;
+ }
+
+ constexpr const KMemoryRegionTypeValue& SetSparseOnly() {
+ m_sparse_only = true;
+ return *this;
+ }
+
+ constexpr const KMemoryRegionTypeValue& SetDenseOnly() {
+ m_dense_only = true;
+ return *this;
+ }
+
+ constexpr KMemoryRegionTypeValue& SetAttribute(u32 attr) {
+ m_value |= attr;
+ return *this;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveInitial(
+ size_t i, size_t next = Common::BitSize<ValueType>()) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value = (ValueType{1} << i);
+ new_type.m_next_bit = next;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveAttribute(u32 attr) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= attr;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveTransition(size_t ofs = 0, size_t adv = 1) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
+ new_type.m_next_bit += adv;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue DeriveSparse(size_t ofs, size_t n, size_t i) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= (ValueType{1} << (m_next_bit + ofs));
+ new_type.m_value |= (ValueType{1} << (m_next_bit + ofs + 1 + i));
+ new_type.m_next_bit += ofs + n + 1;
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue Derive(size_t n, size_t i) const {
+ size_t low = 0, high = 1;
+ for (size_t j = 0; j < i; ++j) {
+ if ((++low) == high) {
+ ++high;
+ low = 0;
+ }
+ }
+
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_value |= (ValueType{1} << (m_next_bit + low));
+ new_type.m_value |= (ValueType{1} << (m_next_bit + high));
+ new_type.m_next_bit += BitsForDeriveDense(n);
+ return new_type;
+ }
+
+ constexpr KMemoryRegionTypeValue Advance(size_t n) const {
+ KMemoryRegionTypeValue new_type = *this;
+ new_type.m_next_bit += n;
+ return new_type;
+ }
+
+ constexpr bool IsAncestorOf(ValueType v) const {
+ return (m_value | v) == v;
+ }
+
+private:
+ constexpr KMemoryRegionTypeValue(ValueType v) : m_value(v) {}
+
+private:
+ ValueType m_value{};
+ size_t m_next_bit{};
+ bool m_finalized{};
+ bool m_sparse_only{};
+ bool m_dense_only{};
+};
+
+} // namespace impl
+
+constexpr auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue();
+constexpr auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2);
+constexpr auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2);
+static_assert(KMemoryRegionType_Kernel.GetValue() == 0x1);
+static_assert(KMemoryRegionType_Dram.GetValue() == 0x2);
+
+constexpr auto KMemoryRegionType_DramKernelBase =
+ KMemoryRegionType_Dram.DeriveSparse(0, 3, 0)
+ .SetAttribute(KMemoryRegionAttr_NoUserMap)
+ .SetAttribute(KMemoryRegionAttr_CarveoutProtected);
+constexpr auto KMemoryRegionType_DramReservedBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 1);
+constexpr auto KMemoryRegionType_DramHeapBase =
+ KMemoryRegionType_Dram.DeriveSparse(0, 3, 2).SetAttribute(KMemoryRegionAttr_LinearMapped);
+static_assert(KMemoryRegionType_DramKernelBase.GetValue() ==
+ (0xE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramReservedBase.GetValue() == (0x16));
+static_assert(KMemoryRegionType_DramHeapBase.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped));
+
+constexpr auto KMemoryRegionType_DramKernelCode =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 0);
+constexpr auto KMemoryRegionType_DramKernelSlab =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 1);
+constexpr auto KMemoryRegionType_DramKernelPtHeap =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 2).SetAttribute(
+ KMemoryRegionAttr_LinearMapped);
+constexpr auto KMemoryRegionType_DramKernelInitPt =
+ KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 3).SetAttribute(
+ KMemoryRegionAttr_LinearMapped);
+static_assert(KMemoryRegionType_DramKernelCode.GetValue() ==
+ (0xCE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramKernelSlab.GetValue() ==
+ (0x14E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramKernelPtHeap.GetValue() ==
+ (0x24E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_LinearMapped));
+static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
+ (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_LinearMapped));
+
+constexpr auto KMemoryRegionType_DramReservedEarly =
+ KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
+static_assert(KMemoryRegionType_DramReservedEarly.GetValue() ==
+ (0x16 | KMemoryRegionAttr_NoUserMap));
+
+constexpr auto KMemoryRegionType_KernelTraceBuffer =
+ KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 0)
+ .SetAttribute(KMemoryRegionAttr_LinearMapped)
+ .SetAttribute(KMemoryRegionAttr_UserReadOnly);
+constexpr auto KMemoryRegionType_OnMemoryBootImage =
+ KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 1);
+constexpr auto KMemoryRegionType_DTB = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2);
+static_assert(KMemoryRegionType_KernelTraceBuffer.GetValue() ==
+ (0xD6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_UserReadOnly));
+static_assert(KMemoryRegionType_OnMemoryBootImage.GetValue() == 0x156);
+static_assert(KMemoryRegionType_DTB.GetValue() == 0x256);
+
+constexpr auto KMemoryRegionType_DramPoolPartition =
+ KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
+static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
+ (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+
+constexpr auto KMemoryRegionType_DramPoolManagement =
+ KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
+ KMemoryRegionAttr_CarveoutProtected);
+constexpr auto KMemoryRegionType_DramUserPool =
+ KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
+static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
+ (0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_CarveoutProtected));
+static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
+ (0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+
+constexpr auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
+constexpr auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
+constexpr auto KMemoryRegionType_DramSystemNonSecurePool =
+ KMemoryRegionType_DramUserPool.Derive(4, 2);
+constexpr auto KMemoryRegionType_DramSystemPool =
+ KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
+static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
+ (0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramAppletPool.GetValue() ==
+ (0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() ==
+ (0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
+static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
+ (0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
+ KMemoryRegionAttr_CarveoutProtected));
+
+constexpr auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
+constexpr auto KMemoryRegionType_VirtualDramKernelPtHeap =
+ KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
+constexpr auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
+ KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
+static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
+static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
+static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
+
+constexpr auto KMemoryRegionType_VirtualDramKernelInitPt =
+ KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
+constexpr auto KMemoryRegionType_VirtualDramPoolManagement =
+ KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
+constexpr auto KMemoryRegionType_VirtualDramUserPool =
+ KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
+static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
+static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
+static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
+
+// NOTE: For unknown reason, the pools are derived out-of-order here. It's worth eventually trying
+// to understand why Nintendo made this choice.
+// UNUSED: .Derive(6, 0);
+// UNUSED: .Derive(6, 1);
+constexpr auto KMemoryRegionType_VirtualDramAppletPool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
+constexpr auto KMemoryRegionType_VirtualDramApplicationPool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
+constexpr auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
+constexpr auto KMemoryRegionType_VirtualDramSystemPool =
+ KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
+static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
+static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
+static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
+static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
+
+constexpr auto KMemoryRegionType_ArchDeviceBase =
+ KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
+constexpr auto KMemoryRegionType_BoardDeviceBase =
+ KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
+static_assert(KMemoryRegionType_ArchDeviceBase.GetValue() == 0x5);
+static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5);
+
+#if defined(ARCH_ARM64)
+#include "core/hle/kernel/arch/arm64/k_memory_region_device_types.inc"
+#elif defined(ARCH_ARM)
+#error "Unimplemented"
+#else
+// Default to no architecture devices.
+constexpr auto NumArchitectureDeviceRegions = 0;
+#endif
+static_assert(NumArchitectureDeviceRegions >= 0);
+
+#if defined(BOARD_NINTENDO_NX)
+#include "core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc"
+#else
+// Default to no board devices.
+constexpr auto NumBoardDeviceRegions = 0;
+#endif
+static_assert(NumBoardDeviceRegions >= 0);
+
+constexpr auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0);
+constexpr auto KMemoryRegionType_KernelStack = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1);
+constexpr auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2);
+constexpr auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3);
+static_assert(KMemoryRegionType_KernelCode.GetValue() == 0x19);
+static_assert(KMemoryRegionType_KernelStack.GetValue() == 0x29);
+static_assert(KMemoryRegionType_KernelMisc.GetValue() == 0x49);
+static_assert(KMemoryRegionType_KernelSlab.GetValue() == 0x89);
+
+constexpr auto KMemoryRegionType_KernelMiscDerivedBase =
+ KMemoryRegionType_KernelMisc.DeriveTransition();
+static_assert(KMemoryRegionType_KernelMiscDerivedBase.GetValue() == 0x149);
+
+// UNUSED: .Derive(7, 0);
+constexpr auto KMemoryRegionType_KernelMiscMainStack =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 1);
+constexpr auto KMemoryRegionType_KernelMiscMappedDevice =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 2);
+constexpr auto KMemoryRegionType_KernelMiscExceptionStack =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 3);
+constexpr auto KMemoryRegionType_KernelMiscUnknownDebug =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 4);
+// UNUSED: .Derive(7, 5);
+constexpr auto KMemoryRegionType_KernelMiscIdleStack =
+ KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 6);
+static_assert(KMemoryRegionType_KernelMiscMainStack.GetValue() == 0xB49);
+static_assert(KMemoryRegionType_KernelMiscMappedDevice.GetValue() == 0xD49);
+static_assert(KMemoryRegionType_KernelMiscExceptionStack.GetValue() == 0x1349);
+static_assert(KMemoryRegionType_KernelMiscUnknownDebug.GetValue() == 0x1549);
+static_assert(KMemoryRegionType_KernelMiscIdleStack.GetValue() == 0x2349);
+
+constexpr auto KMemoryRegionType_KernelTemp = KMemoryRegionType_Kernel.Advance(2).Derive(2, 0);
+static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
+
+constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
+ if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
+ return KMemoryRegionType_VirtualDramKernelTraceBuffer;
+ } else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
+ return KMemoryRegionType_VirtualDramKernelPtHeap;
+ } else {
+ return KMemoryRegionType_Dram;
+ }
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index e7de48476..d1df97305 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -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;
}
}
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index f595b9a5c..8e32865aa 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -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,12 +192,12 @@ private:
u64 last_context_switch_time{};
const s32 core_id;
- Common::SpinLock guard{};
+ KSpinLock guard{};
};
-class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
+class [[nodiscard]] KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
public:
- explicit KScopedSchedulerLock(KernelCore& kernel);
+ explicit KScopedSchedulerLock(KernelCore & kernel);
~KScopedSchedulerLock();
};
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 169455d18..47e315555 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -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{};
};
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index d7cc557b2..72c3b0252 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -20,19 +20,22 @@ concept KLockable = !std::is_reference_v<T> && requires(T & t) {
};
template <typename T>
-requires KLockable<T> class KScopedLock {
+requires KLockable<T> class [[nodiscard]] KScopedLock {
public:
- explicit KScopedLock(T* l) : lock_ptr(l) {
+ explicit KScopedLock(T * l) : lock_ptr(l) {
this->lock_ptr->Lock();
}
- explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */
- }
+ explicit KScopedLock(T & l) : KScopedLock(std::addressof(l)) {}
+
~KScopedLock() {
this->lock_ptr->Unlock();
}
KScopedLock(const KScopedLock&) = delete;
- KScopedLock(KScopedLock&&) = delete;
+ KScopedLock& operator=(const KScopedLock&) = delete;
+
+ KScopedLock(KScopedLock &&) = delete;
+ KScopedLock& operator=(KScopedLock&&) = delete;
private:
T* lock_ptr;
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index f8189e107..ebecf0c77 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -15,9 +15,9 @@
namespace Kernel {
-class KScopedSchedulerLockAndSleep {
+class [[nodiscard]] KScopedSchedulerLockAndSleep {
public:
- explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout)
+ explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
: kernel(kernel), thread(t), timeout_tick(timeout) {
// Lock the scheduler.
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
diff --git a/src/core/hle/kernel/k_spin_lock.h b/src/core/hle/kernel/k_spin_lock.h
index 12c4b2e88..4d87d006a 100644
--- a/src/core/hle/kernel/k_spin_lock.h
+++ b/src/core/hle/kernel/k_spin_lock.h
@@ -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
diff --git a/src/core/hle/kernel/k_system_control.cpp b/src/core/hle/kernel/k_system_control.cpp
deleted file mode 100644
index aa1682f69..000000000
--- a/src/core/hle/kernel/k_system_control.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <random>
-
-#include "core/hle/kernel/k_system_control.h"
-
-namespace Kernel {
-
-namespace {
-template <typename F>
-u64 GenerateUniformRange(u64 min, u64 max, F f) {
- // Handle the case where the difference is too large to represent.
- if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
- return f();
- }
-
- // Iterate until we get a value in range.
- const u64 range_size = ((max + 1) - min);
- const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
- while (true) {
- if (const u64 rnd = f(); rnd < effective_max) {
- return min + (rnd % range_size);
- }
- }
-}
-
-} // Anonymous namespace
-
-u64 KSystemControl::GenerateRandomU64() {
- static std::random_device device;
- static std::mt19937 gen(device());
- static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
- return distribution(gen);
-}
-
-u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
- return GenerateUniformRange(min, max, GenerateRandomU64);
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/k_system_control.h b/src/core/hle/kernel/k_system_control.h
index 1d5b64ffa..d755082c2 100644
--- a/src/core/hle/kernel/k_system_control.h
+++ b/src/core/hle/kernel/k_system_control.h
@@ -6,14 +6,18 @@
#include "common/common_types.h"
-namespace Kernel {
+#define BOARD_NINTENDO_NX
+
+#ifdef BOARD_NINTENDO_NX
-class KSystemControl {
-public:
- KSystemControl() = default;
+#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
- static u64 GenerateRandomRange(u64 min, u64 max);
- static u64 GenerateRandomU64();
-};
+namespace Kernel {
+
+using Kernel::Board::Nintendo::Nx::KSystemControl;
} // namespace Kernel
+
+#else
+#error "Unknown board for KSystemControl"
+#endif
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 1c19b23dc..1c86fdd20 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -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{};
diff --git a/src/core/hle/kernel/k_trace.h b/src/core/hle/kernel/k_trace.h
new file mode 100644
index 000000000..91ebf9ab2
--- /dev/null
+++ b/src/core/hle/kernel/k_trace.h
@@ -0,0 +1,12 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Kernel {
+
+constexpr bool IsKTraceEnabled = false;
+constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16 * 1024 * 1024 : 0;
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 5b6c7792e..8fd990577 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -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"
@@ -143,10 +144,10 @@ struct KernelCore::Impl {
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
.IsSuccess());
- ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess());
+ ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
// Derived from recent software updates. The kernel reserves 27MB
constexpr u64 kernel_size{0x1b00000};
@@ -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
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 56906f2da..a500e63bc 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -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.
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 326d3b9ec..fcffc746d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2455,6 +2455,74 @@ static const FunctionDef SVC_Table_32[] = {
{0x79, nullptr, "Unknown"},
{0x7A, nullptr, "Unknown"},
{0x7B, nullptr, "TerminateProcess32"},
+ {0x7C, nullptr, "GetProcessInfo32"},
+ {0x7D, nullptr, "CreateResourceLimit32"},
+ {0x7E, nullptr, "SetResourceLimitLimitValue32"},
+ {0x7F, nullptr, "CallSecureMonitor32"},
+ {0x80, nullptr, "Unknown"},
+ {0x81, nullptr, "Unknown"},
+ {0x82, nullptr, "Unknown"},
+ {0x83, nullptr, "Unknown"},
+ {0x84, nullptr, "Unknown"},
+ {0x85, nullptr, "Unknown"},
+ {0x86, nullptr, "Unknown"},
+ {0x87, nullptr, "Unknown"},
+ {0x88, nullptr, "Unknown"},
+ {0x89, nullptr, "Unknown"},
+ {0x8A, nullptr, "Unknown"},
+ {0x8B, nullptr, "Unknown"},
+ {0x8C, nullptr, "Unknown"},
+ {0x8D, nullptr, "Unknown"},
+ {0x8E, nullptr, "Unknown"},
+ {0x8F, nullptr, "Unknown"},
+ {0x90, nullptr, "Unknown"},
+ {0x91, nullptr, "Unknown"},
+ {0x92, nullptr, "Unknown"},
+ {0x93, nullptr, "Unknown"},
+ {0x94, nullptr, "Unknown"},
+ {0x95, nullptr, "Unknown"},
+ {0x96, nullptr, "Unknown"},
+ {0x97, nullptr, "Unknown"},
+ {0x98, nullptr, "Unknown"},
+ {0x99, nullptr, "Unknown"},
+ {0x9A, nullptr, "Unknown"},
+ {0x9B, nullptr, "Unknown"},
+ {0x9C, nullptr, "Unknown"},
+ {0x9D, nullptr, "Unknown"},
+ {0x9E, nullptr, "Unknown"},
+ {0x9F, nullptr, "Unknown"},
+ {0xA0, nullptr, "Unknown"},
+ {0xA1, nullptr, "Unknown"},
+ {0xA2, nullptr, "Unknown"},
+ {0xA3, nullptr, "Unknown"},
+ {0xA4, nullptr, "Unknown"},
+ {0xA5, nullptr, "Unknown"},
+ {0xA6, nullptr, "Unknown"},
+ {0xA7, nullptr, "Unknown"},
+ {0xA8, nullptr, "Unknown"},
+ {0xA9, nullptr, "Unknown"},
+ {0xAA, nullptr, "Unknown"},
+ {0xAB, nullptr, "Unknown"},
+ {0xAC, nullptr, "Unknown"},
+ {0xAD, nullptr, "Unknown"},
+ {0xAE, nullptr, "Unknown"},
+ {0xAF, nullptr, "Unknown"},
+ {0xB0, nullptr, "Unknown"},
+ {0xB1, nullptr, "Unknown"},
+ {0xB2, nullptr, "Unknown"},
+ {0xB3, nullptr, "Unknown"},
+ {0xB4, nullptr, "Unknown"},
+ {0xB5, nullptr, "Unknown"},
+ {0xB6, nullptr, "Unknown"},
+ {0xB7, nullptr, "Unknown"},
+ {0xB8, nullptr, "Unknown"},
+ {0xB9, nullptr, "Unknown"},
+ {0xBA, nullptr, "Unknown"},
+ {0xBB, nullptr, "Unknown"},
+ {0xBC, nullptr, "Unknown"},
+ {0xBD, nullptr, "Unknown"},
+ {0xBE, nullptr, "Unknown"},
+ {0xBF, nullptr, "Unknown"},
};
static const FunctionDef SVC_Table_64[] = {
@@ -2586,6 +2654,70 @@ static const FunctionDef SVC_Table_64[] = {
{0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"},
{0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
{0x7F, nullptr, "CallSecureMonitor"},
+ {0x80, nullptr, "Unknown"},
+ {0x81, nullptr, "Unknown"},
+ {0x82, nullptr, "Unknown"},
+ {0x83, nullptr, "Unknown"},
+ {0x84, nullptr, "Unknown"},
+ {0x85, nullptr, "Unknown"},
+ {0x86, nullptr, "Unknown"},
+ {0x87, nullptr, "Unknown"},
+ {0x88, nullptr, "Unknown"},
+ {0x89, nullptr, "Unknown"},
+ {0x8A, nullptr, "Unknown"},
+ {0x8B, nullptr, "Unknown"},
+ {0x8C, nullptr, "Unknown"},
+ {0x8D, nullptr, "Unknown"},
+ {0x8E, nullptr, "Unknown"},
+ {0x8F, nullptr, "Unknown"},
+ {0x90, nullptr, "Unknown"},
+ {0x91, nullptr, "Unknown"},
+ {0x92, nullptr, "Unknown"},
+ {0x93, nullptr, "Unknown"},
+ {0x94, nullptr, "Unknown"},
+ {0x95, nullptr, "Unknown"},
+ {0x96, nullptr, "Unknown"},
+ {0x97, nullptr, "Unknown"},
+ {0x98, nullptr, "Unknown"},
+ {0x99, nullptr, "Unknown"},
+ {0x9A, nullptr, "Unknown"},
+ {0x9B, nullptr, "Unknown"},
+ {0x9C, nullptr, "Unknown"},
+ {0x9D, nullptr, "Unknown"},
+ {0x9E, nullptr, "Unknown"},
+ {0x9F, nullptr, "Unknown"},
+ {0xA0, nullptr, "Unknown"},
+ {0xA1, nullptr, "Unknown"},
+ {0xA2, nullptr, "Unknown"},
+ {0xA3, nullptr, "Unknown"},
+ {0xA4, nullptr, "Unknown"},
+ {0xA5, nullptr, "Unknown"},
+ {0xA6, nullptr, "Unknown"},
+ {0xA7, nullptr, "Unknown"},
+ {0xA8, nullptr, "Unknown"},
+ {0xA9, nullptr, "Unknown"},
+ {0xAA, nullptr, "Unknown"},
+ {0xAB, nullptr, "Unknown"},
+ {0xAC, nullptr, "Unknown"},
+ {0xAD, nullptr, "Unknown"},
+ {0xAE, nullptr, "Unknown"},
+ {0xAF, nullptr, "Unknown"},
+ {0xB0, nullptr, "Unknown"},
+ {0xB1, nullptr, "Unknown"},
+ {0xB2, nullptr, "Unknown"},
+ {0xB3, nullptr, "Unknown"},
+ {0xB4, nullptr, "Unknown"},
+ {0xB5, nullptr, "Unknown"},
+ {0xB6, nullptr, "Unknown"},
+ {0xB7, nullptr, "Unknown"},
+ {0xB8, nullptr, "Unknown"},
+ {0xB9, nullptr, "Unknown"},
+ {0xBA, nullptr, "Unknown"},
+ {0xBB, nullptr, "Unknown"},
+ {0xBC, nullptr, "Unknown"},
+ {0xBD, nullptr, "Unknown"},
+ {0xBE, nullptr, "Unknown"},
+ {0xBF, nullptr, "Unknown"},
};
static const FunctionDef* GetSVCInfo32(u32 func_num) {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d91237cba..4374487a3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -231,6 +231,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{10, nullptr, "PerformSystemButtonPressing"},
{20, nullptr, "InvalidateTransitionLayer"},
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
+ {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
{40, nullptr, "GetAppletResourceUsageInfo"},
{100, nullptr, "SetCpuBoostModeForApplet"},
{101, nullptr, "CancelCpuBoostModeForApplet"},
@@ -242,6 +243,7 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{130, nullptr, "FriendInvitationSetApplicationParameter"},
{131, nullptr, "FriendInvitationClearApplicationParameter"},
{132, nullptr, "FriendInvitationPushApplicationParameter"},
+ {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
};
// clang-format on
@@ -297,6 +299,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
{100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
{110, nullptr, "SetApplicationAlbumUserData"},
+ {120, nullptr, "SaveCurrentScreenshot"},
{1000, nullptr, "GetDebugStorageChannel"},
};
// clang-format on
@@ -645,6 +648,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{11, nullptr, "ReleaseSleepLock"},
{12, nullptr, "ReleaseSleepLockTransiently"},
{13, nullptr, "GetAcquiredSleepLockEvent"},
+ {14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, nullptr, "GetReaderLockAccessorEx"},
@@ -656,6 +660,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
{54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
{55, nullptr, "IsInControllerFirmwareUpdateSection"},
+ {59, nullptr, "SetVrPositionForDebug"},
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
@@ -664,14 +669,21 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"},
+ {68, nullptr, "GetBuiltInDisplayType"},
{80, nullptr, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
+ {110, nullptr, "OpenMyGpuErrorHandler"},
{200, nullptr, "GetOperationModeSystemInfo"},
{300, nullptr, "GetSettingsPlatformRegion"},
{400, nullptr, "ActivateMigrationService"},
{401, nullptr, "DeactivateMigrationService"},
+ {500, nullptr, "DisableSleepTillShutdown"},
+ {501, nullptr, "SuppressDisablingSleepTemporarily"},
+ {502, nullptr, "IsSleepEnabled"},
+ {503, nullptr, "IsDisablingSleepSuppressed"},
+ {900, nullptr, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
};
// clang-format on
@@ -1203,11 +1215,14 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
{27, nullptr, "CreateCacheStorage"},
+ {28, nullptr, "GetSaveDataSizeMax"},
+ {29, nullptr, "GetCacheStorageMax"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
{33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
{34, nullptr, "SelectApplicationLicense"},
+ {35, nullptr, "GetDeviceSaveDataSizeMax"},
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
{50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
{60, nullptr, "SetMediaPlaybackStateForApplication"},
@@ -1231,6 +1246,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
+ {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
{141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
{150, nullptr, "GetNotificationStorageChannelEvent"},
@@ -1239,6 +1255,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{170, nullptr, "SetHdcpAuthenticationActivated"},
{180, nullptr, "GetLaunchRequiredVersion"},
{181, nullptr, "UpgradeLaunchRequiredVersion"},
+ {190, nullptr, "SendServerMaintenanceOverlayNotification"},
+ {200, nullptr, "GetLastApplicationExitReason"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, nullptr, "PrepareForJit"},
@@ -1705,9 +1723,12 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
{21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
+ {40, nullptr, "IsSleepEnabled"},
+ {41, nullptr, "IsRebootEnabled"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
{110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
{200, nullptr, "LaunchDevMenu"},
+ {1000, nullptr, "SetLastApplicationExitReason"},
};
// clang-format on
@@ -1751,6 +1772,7 @@ IGlobalStateController::IGlobalStateController(Core::System& system_)
{13, nullptr, "UpdateDefaultDisplayResolution"},
{14, nullptr, "ShouldSleepOnBoot"},
{15, nullptr, "GetHdcpAuthenticationFailedEvent"},
+ {30, nullptr, "OpenCradleFirmwareUpdater"},
};
// clang-format on
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 8d657c0bf..0f51e5871 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -118,8 +118,10 @@ AOC_U::AOC_U(Core::System& system_)
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
+ {10, nullptr, "GetAddOnContentListChangedEventWithProcessId"},
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
+ {110, nullptr, "CreateContentsServiceManager"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
index 79c3aa920..10acaad19 100644
--- a/src/core/hle/service/audio/audin_a.cpp
+++ b/src/core/hle/service/audio/audin_a.cpp
@@ -9,10 +9,10 @@ namespace Service::Audio {
AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendAudioIns"},
- {1, nullptr, "RequestResumeAudioIns"},
- {2, nullptr, "GetAudioInsProcessMasterVolume"},
- {3, nullptr, "SetAudioInsProcessMasterVolume"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
+ {2, nullptr, "GetProcessMasterVolume"},
+ {3, nullptr, "SetProcessMasterVolume"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 26a6deddf..ecd05e4a6 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -15,19 +15,19 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAudioInState"},
- {1, nullptr, "StartAudioIn"},
- {2, nullptr, "StopAudioIn"},
+ {1, nullptr, "Start"},
+ {2, nullptr, "Stop"},
{3, nullptr, "AppendAudioInBuffer"},
{4, nullptr, "RegisterBufferEvent"},
{5, nullptr, "GetReleasedAudioInBuffer"},
{6, nullptr, "ContainsAudioInBuffer"},
- {7, nullptr, "AppendAudioInBufferWithUserEvent"},
+ {7, nullptr, "AppendUacInBuffer"},
{8, nullptr, "AppendAudioInBufferAuto"},
- {9, nullptr, "GetReleasedAudioInBufferAuto"},
- {10, nullptr, "AppendAudioInBufferWithUserEventAuto"},
+ {9, nullptr, "GetReleasedAudioInBuffersAuto"},
+ {10, nullptr, "AppendUacInBufferAuto"},
{11, nullptr, "GetAudioInBufferCount"},
- {12, nullptr, "SetAudioInDeviceGain"},
- {13, nullptr, "GetAudioInDeviceGain"},
+ {12, nullptr, "SetDeviceGain"},
+ {13, nullptr, "GetDeviceGain"},
{14, nullptr, "FlushAudioInBuffers"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
index 19825fd5d..3ee522b50 100644
--- a/src/core/hle/service/audio/audout_a.cpp
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -9,12 +9,12 @@ namespace Service::Audio {
AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendAudioOuts"},
- {1, nullptr, "RequestResumeAudioOuts"},
- {2, nullptr, "GetAudioOutsProcessMasterVolume"},
- {3, nullptr, "SetAudioOutsProcessMasterVolume"},
- {4, nullptr, "GetAudioOutsProcessRecordVolume"},
- {5, nullptr, "SetAudioOutsProcessRecordVolume"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
+ {2, nullptr, "GetProcessMasterVolume"},
+ {3, nullptr, "SetProcessMasterVolume"},
+ {4, nullptr, "GetProcessRecordVolume"},
+ {5, nullptr, "SetProcessRecordVolume"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 5ed9cb20e..5f51fca9a 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -49,11 +49,11 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
- {1, &IAudioOut::StartAudioOut, "StartAudioOut"},
- {2, &IAudioOut::StopAudioOut, "StopAudioOut"},
+ {1, &IAudioOut::StartAudioOut, "Start"},
+ {2, &IAudioOut::StopAudioOut, "Stop"},
{3, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBuffer"},
{4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
- {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffer"},
+ {5, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBuffers"},
{6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
{7, &IAudioOut::AppendAudioOutBufferImpl, "AppendAudioOutBufferAuto"},
{8, &IAudioOut::GetReleasedAudioOutBufferImpl, "GetReleasedAudioOutBufferAuto"},
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
index c5ab7cad4..70fc17ae2 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -9,8 +9,8 @@ namespace Service::Audio {
AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendFinalOutputRecorders"},
- {1, nullptr, "RequestResumeFinalOutputRecorders"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index eb5c63c62..74a65ccff 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -13,16 +13,17 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetFinalOutputRecorderState"},
- {1, nullptr, "StartFinalOutputRecorder"},
- {2, nullptr, "StopFinalOutputRecorder"},
+ {1, nullptr, "Start"},
+ {2, nullptr, "Stop"},
{3, nullptr, "AppendFinalOutputRecorderBuffer"},
{4, nullptr, "RegisterBufferEvent"},
- {5, nullptr, "GetReleasedFinalOutputRecorderBuffer"},
+ {5, nullptr, "GetReleasedFinalOutputRecorderBuffers"},
{6, nullptr, "ContainsFinalOutputRecorderBuffer"},
{7, nullptr, "GetFinalOutputRecorderBufferEndTime"},
{8, nullptr, "AppendFinalOutputRecorderBufferAuto"},
{9, nullptr, "GetReleasedFinalOutputRecorderBufferAuto"},
{10, nullptr, "FlushFinalOutputRecorderBuffers"},
+ {11, nullptr, "AttachWorkBuffer"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
index 5e9f866f0..cf8c34a15 100644
--- a/src/core/hle/service/audio/audren_a.cpp
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -9,14 +9,14 @@ namespace Service::Audio {
AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendAudioRenderers"},
- {1, nullptr, "RequestResumeAudioRenderers"},
- {2, nullptr, "GetAudioRenderersProcessMasterVolume"},
- {3, nullptr, "SetAudioRenderersProcessMasterVolume"},
+ {0, nullptr, "RequestSuspend"},
+ {1, nullptr, "RequestResume"},
+ {2, nullptr, "GetProcessMasterVolume"},
+ {3, nullptr, "SetProcessMasterVolume"},
{4, nullptr, "RegisterAppletResourceUserId"},
{5, nullptr, "UnregisterAppletResourceUserId"},
- {6, nullptr, "GetAudioRenderersProcessRecordVolume"},
- {7, nullptr, "SetAudioRenderersProcessRecordVolume"},
+ {6, nullptr, "GetProcessRecordVolume"},
+ {7, nullptr, "SetProcessRecordVolume"},
};
// clang-format on
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index b2b2ffc5a..572be8e00 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -332,9 +332,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
- {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
+ {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetWorkBufferSize"},
{2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
- {3, &AudRenU::OpenAudioRendererAuto, "OpenAudioRendererAuto"},
+ {3, &AudRenU::OpenAudioRendererForManualExecution, "OpenAudioRendererForManualExecution"},
{4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
};
// clang-format on
@@ -665,7 +665,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
}
-void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
+void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
OpenAudioRendererImpl(ctx);
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index d693dc406..37e8b4716 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -25,7 +25,7 @@ private:
void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
- void OpenAudioRendererAuto(Kernel::HLERequestContext& ctx);
+ void OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx);
void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
index 94afec1b6..42961d908 100644
--- a/src/core/hle/service/audio/codecctl.cpp
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -8,19 +8,19 @@ namespace Service::Audio {
CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} {
static const FunctionInfo functions[] = {
- {0, nullptr, "InitializeCodecController"},
- {1, nullptr, "FinalizeCodecController"},
- {2, nullptr, "SleepCodecController"},
- {3, nullptr, "WakeCodecController"},
- {4, nullptr, "SetCodecVolume"},
- {5, nullptr, "GetCodecVolumeMax"},
- {6, nullptr, "GetCodecVolumeMin"},
- {7, nullptr, "SetCodecActiveTarget"},
- {8, nullptr, "GetCodecActiveTarget"},
- {9, nullptr, "BindCodecHeadphoneMicJackInterrupt"},
- {10, nullptr, "IsCodecHeadphoneMicJackInserted"},
- {11, nullptr, "ClearCodecHeadphoneMicJackInterrupt"},
- {12, nullptr, "IsCodecDeviceRequested"},
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "Finalize"},
+ {2, nullptr, "Sleep"},
+ {3, nullptr, "Wake"},
+ {4, nullptr, "SetVolume"},
+ {5, nullptr, "GetVolumeMax"},
+ {6, nullptr, "GetVolumeMin"},
+ {7, nullptr, "SetActiveTarget"},
+ {8, nullptr, "GetActiveTarget"},
+ {9, nullptr, "BindHeadphoneMicJackInterrupt"},
+ {10, nullptr, "IsHeadphoneMicJackInserted"},
+ {11, nullptr, "ClearHeadphoneMicJackInterrupt"},
+ {12, nullptr, "IsRequested"},
};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 503109fdd..b68e2c345 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -155,10 +155,12 @@ public:
{30210, nullptr, "SetDeliveryTaskTimer"},
{30300, nullptr, "RegisterSystemApplicationDeliveryTasks"},
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
+ {90101, nullptr, "Unknown90101"},
{90200, nullptr, "GetDeliveryList"},
{90201, &IBcatService::ClearDeliveryCacheStorage, "ClearDeliveryCacheStorage"},
{90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
{90300, nullptr, "GetPushNotificationLog"},
+ {90301, nullptr, "Unknown90301"},
};
// clang-format on
RegisterHandlers(functions);
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
index e4630320e..78e01d8d8 100644
--- a/src/core/hle/service/bpc/bpc.cpp
+++ b/src/core/hle/service/bpc/bpc.cpp
@@ -29,8 +29,8 @@ public:
{11, nullptr, "CreateWakeupTimerEx"},
{12, nullptr, "GetLastEnabledWakeupTimerType"},
{13, nullptr, "CleanAllWakeupTimers"},
- {14, nullptr, "Unknown"},
- {15, nullptr, "Unknown2"},
+ {14, nullptr, "GetPowerButton"},
+ {15, nullptr, "SetEnableWakeupTimer"},
};
// clang-format on
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 17a2ac899..af3a5842d 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -156,6 +156,25 @@ public:
{97, nullptr, "RegisterBleHidEvent"},
{98, nullptr, "SetBleScanParameter"},
{99, nullptr, "MoveToSecondaryPiconet"},
+ {100, nullptr, "IsBluetoothEnabled"},
+ {128, nullptr, "AcquireAudioEvent"},
+ {129, nullptr, "GetAudioEventInfo"},
+ {130, nullptr, "OpenAudioConnection"},
+ {131, nullptr, "CloseAudioConnection"},
+ {132, nullptr, "OpenAudioOut"},
+ {133, nullptr, "CloseAudioOut"},
+ {134, nullptr, "AcquireAudioOutStateChangedEvent"},
+ {135, nullptr, "StartAudioOut"},
+ {136, nullptr, "StopAudioOut"},
+ {137, nullptr, "GetAudioOutState"},
+ {138, nullptr, "GetAudioOutFeedingCodec"},
+ {139, nullptr, "GetAudioOutFeedingParameter"},
+ {140, nullptr, "AcquireAudioOutBufferAvailableEvent"},
+ {141, nullptr, "SendAudioData"},
+ {142, nullptr, "AcquireAudioControlInputStateChangedEvent"},
+ {143, nullptr, "GetAudioControlInputState"},
+ {144, nullptr, "AcquireAudioConnectionStateChangedEvent"},
+ {145, nullptr, "GetConnectedAudioDevice"},
{256, nullptr, "IsManufacturingMode"},
{257, nullptr, "EmulateBluetoothCrash"},
{258, nullptr, "GetBleChannelMap"},
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 9cf2ee92a..d1ebc2388 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -223,6 +223,7 @@ public:
{10, nullptr, "GetGattClientDisconnectionReason"},
{11, nullptr, "GetBleConnectionParameter"},
{12, nullptr, "GetBleConnectionParameterRequest"},
+ {13, nullptr, "Unknown13"},
};
// clang-format on
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index 1fe4f0e14..6220e9f77 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -49,6 +49,7 @@ CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
{16, nullptr, "GetAlbumMountResult"},
{17, nullptr, "GetAlbumUsage16"},
{18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
{100, nullptr, "GetAlbumFileCountEx0"},
{101, nullptr, "GetAlbumFileListEx0"},
{202, nullptr, "SaveEditedScreenShot"},
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index 842316a2e..10b8d54b1 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -43,6 +43,7 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
{141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
{142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
{143, nullptr, "GetAlbumFileList4AaeUidAruid"},
+ {144, nullptr, "GetAllAlbumFileList3AaeAruid"},
{60002, nullptr, "OpenAccessorSessionForApplication"},
};
// clang-format on
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index 4924c61c3..c767926a4 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -16,7 +16,7 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SubmitContext"},
- {1, nullptr, "CreateReport"},
+ {1, nullptr, "CreateReportV0"},
{2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
{3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
{4, nullptr, "UpdatePowerOnTime"},
@@ -26,6 +26,11 @@ public:
{8, nullptr, "ClearApplicationLaunchTime"},
{9, nullptr, "SubmitAttachment"},
{10, nullptr, "CreateReportWithAttachments"},
+ {11, nullptr, "CreateReport"},
+ {20, nullptr, "RegisterRunningApplet"},
+ {21, nullptr, "UnregisterRunningApplet"},
+ {22, nullptr, "UpdateAppletSuspendedDuration"},
+ {30, nullptr, "InvalidateForcedShutdownDetection"},
};
// clang-format on
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 0a6621ef2..a35979053 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -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>();
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index fc77e7286..322125135 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -41,6 +41,12 @@ ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_)
{1, &ARP_R::GetApplicationLaunchPropertyWithApplicationId, "GetApplicationLaunchPropertyWithApplicationId"},
{2, &ARP_R::GetApplicationControlProperty, "GetApplicationControlProperty"},
{3, &ARP_R::GetApplicationControlPropertyWithApplicationId, "GetApplicationControlPropertyWithApplicationId"},
+ {4, nullptr, "GetApplicationInstanceUnregistrationNotifier"},
+ {5, nullptr, "ListApplicationInstanceId"},
+ {6, nullptr, "GetMicroApplicationInstanceId"},
+ {7, nullptr, "GetApplicationCertificate"},
+ {9998, nullptr, "GetPreomiaApplicationLaunchProperty"},
+ {9999, nullptr, "GetPreomiaApplicationControlProperty"},
};
// clang-format on
@@ -243,7 +249,8 @@ ARP_W::ARP_W(Core::System& system_, ARPManager& manager_)
// clang-format off
static const FunctionInfo functions[] = {
{0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
- {1, &ARP_W::DeleteProperties, "DeleteProperties"},
+ {1, &ARP_W::UnregisterApplicationInstance , "UnregisterApplicationInstance "},
+ {2, nullptr, "AcquireUpdater"},
};
// clang-format on
@@ -270,7 +277,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface(registrar);
}
-void ARP_W::DeleteProperties(Kernel::HLERequestContext& ctx) {
+void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h
index 34b412e26..0df3c5e1f 100644
--- a/src/core/hle/service/glue/arp.h
+++ b/src/core/hle/service/glue/arp.h
@@ -32,7 +32,7 @@ public:
private:
void AcquireRegistrar(Kernel::HLERequestContext& ctx);
- void DeleteProperties(Kernel::HLERequestContext& ctx);
+ void UnregisterApplicationInstance(Kernel::HLERequestContext& ctx);
ARPManager& manager;
std::shared_ptr<IRegistrar> registrar;
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp
index a478b68e1..daecfff15 100644
--- a/src/core/hle/service/glue/bgtc.cpp
+++ b/src/core/hle/service/glue/bgtc.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
#include "core/hle/service/glue/bgtc.h"
namespace Service::Glue {
@@ -9,6 +12,26 @@ namespace Service::Glue {
BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
// clang-format off
static const FunctionInfo functions[] = {
+ {100, &BGTC_T::OpenTaskService, "OpenTaskService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+BGTC_T::~BGTC_T() = default;
+
+void BGTC_T::OpenTaskService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_BGTC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ITaskService>(system);
+}
+
+ITaskService::ITaskService(Core::System& system_) : ServiceFramework{system_, "ITaskService"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
{1, nullptr, "NotifyTaskStarting"},
{2, nullptr, "NotifyTaskFinished"},
{3, nullptr, "GetTriggerEvent"},
@@ -20,16 +43,18 @@ BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
{13, nullptr, "UnscheduleTask"},
{14, nullptr, "GetScheduleEvent"},
{15, nullptr, "SchedulePeriodicTask"},
+ {16, nullptr, "Unknown16"},
{101, nullptr, "GetOperationMode"},
{102, nullptr, "WillDisconnectNetworkWhenEnteringSleep"},
{103, nullptr, "WillStayHalfAwakeInsteadSleep"},
+ {200, nullptr, "Unknown200"},
};
// clang-format on
RegisterHandlers(functions);
}
-BGTC_T::~BGTC_T() = default;
+ITaskService::~ITaskService() = default;
BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} {
// clang-format off
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h
index 906116ba6..4c0142fd5 100644
--- a/src/core/hle/service/glue/bgtc.h
+++ b/src/core/hle/service/glue/bgtc.h
@@ -16,6 +16,14 @@ class BGTC_T final : public ServiceFramework<BGTC_T> {
public:
explicit BGTC_T(Core::System& system_);
~BGTC_T() override;
+
+ void OpenTaskService(Kernel::HLERequestContext& ctx);
+};
+
+class ITaskService final : public ServiceFramework<ITaskService> {
+public:
+ explicit ITaskService(Core::System& system_);
+ ~ITaskService() override;
};
class BGTC_SC final : public ServiceFramework<BGTC_SC> {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 1df62f98e..673db68c7 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -1138,6 +1138,10 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot
unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
}
+void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
+ analog_stick_use_center_clamp = use_center_clamp;
+}
+
void Controller_NPad::ClearAllConnectedControllers() {
for (auto& controller : connected_controllers) {
if (controller.is_connected && controller.type != NPadControllerType::None) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index bc2e6779d..873a0a1e2 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -219,6 +219,7 @@ public:
LedPattern GetLedPattern(u32 npad_id);
bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
+ void SetAnalogStickUseCenterClamp(bool use_center_clamp);
void ClearAllConnectedControllers();
void DisconnectAllConnectedControllers();
void ConnectAllDisconnectedControllers();
@@ -577,6 +578,7 @@ private:
std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
std::array<ControllerHolder, 10> connected_controllers{};
std::array<bool, 10> unintended_home_button_input_protection{};
+ bool analog_stick_use_center_clamp{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool sixaxis_sensors_enabled{true};
f32 sixaxis_fusion_parameter1{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ba27bbb05..a1a779cc0 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -263,7 +263,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
{131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
- {134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
+ {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
{135, nullptr, "SetNpadCaptureButtonAssignment"},
{136, nullptr, "ClearNpadCaptureButtonAssignment"},
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
@@ -278,6 +278,7 @@ Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
{209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
{210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
{211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
+ {212, nullptr, "SendVibrationValueInBool"},
{300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
{301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
{302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -1087,6 +1088,27 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
rb.Push(RESULT_SUCCESS);
}
+void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool analog_stick_use_center_clamp;
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
+ parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
@@ -1553,6 +1575,7 @@ public:
{11, nullptr, "SetTouchScreenAutoPilotState"},
{12, nullptr, "UnsetTouchScreenAutoPilotState"},
{13, nullptr, "GetTouchScreenConfiguration"},
+ {14, nullptr, "ProcessTouchScreenAutoTune"},
{20, nullptr, "DeactivateMouse"},
{21, nullptr, "SetMouseAutoPilotState"},
{22, nullptr, "UnsetMouseAutoPilotState"},
@@ -1562,6 +1585,7 @@ public:
{50, nullptr, "DeactivateXpad"},
{51, nullptr, "SetXpadAutoPilotState"},
{52, nullptr, "UnsetXpadAutoPilotState"},
+ {53, nullptr, "DeactivateJoyXpad"},
{60, nullptr, "ClearNpadSystemCommonPolicy"},
{61, nullptr, "DeactivateNpad"},
{62, nullptr, "ForceDisconnectNpad"},
@@ -1632,6 +1656,11 @@ public:
{244, nullptr, "RequestKuinaFirmwareVersion"},
{245, nullptr, "GetKuinaFirmwareVersion"},
{246, nullptr, "GetVidPid"},
+ {247, nullptr, "GetAnalogStickCalibrationValue"},
+ {248, nullptr, "GetUniquePadIdsFull"},
+ {249, nullptr, "ConnectUniquePad"},
+ {250, nullptr, "IsVirtual"},
+ {251, nullptr, "GetAnalogStickModuleParam"},
{301, nullptr, "GetAbstractedPadHandles"},
{302, nullptr, "GetAbstractedPadState"},
{303, nullptr, "GetAbstractedPadsState"},
@@ -1652,12 +1681,16 @@ public:
{401, nullptr, "DisableRailDeviceFiltering"},
{402, nullptr, "EnableWiredPairing"},
{403, nullptr, "EnableShipmentModeAutoClear"},
+ {404, nullptr, "SetRailEnabled"},
{500, nullptr, "SetFactoryInt"},
{501, nullptr, "IsFactoryBootEnabled"},
{550, nullptr, "SetAnalogStickModelDataTemporarily"},
{551, nullptr, "GetAnalogStickModelData"},
{552, nullptr, "ResetAnalogStickModelData"},
{600, nullptr, "ConvertPadState"},
+ {650, nullptr, "AddButtonPlayData"},
+ {651, nullptr, "StartButtonPlayData"},
+ {652, nullptr, "StopButtonPlayData"},
{2000, nullptr, "DeactivateDigitizer"},
{2001, nullptr, "SetDigitizerAutoPilotState"},
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
@@ -1689,6 +1722,8 @@ public:
{215, nullptr, "IsNfcActivated"},
{230, nullptr, "AcquireIrSensorEventHandle"},
{231, nullptr, "ActivateIrSensor"},
+ {232, nullptr, "GetIrSensorState"},
+ {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
{301, nullptr, "ActivateNpadSystem"},
{303, nullptr, "ApplyNpadSystemCommonPolicy"},
{304, nullptr, "EnableAssigningSingleOnSlSrPress"},
@@ -1703,9 +1738,16 @@ public:
{313, nullptr, "GetNpadCaptureButtonAssignment"},
{314, nullptr, "GetAppletFooterUiType"},
{315, nullptr, "GetAppletDetailedUiType"},
+ {316, nullptr, "GetNpadInterfaceType"},
+ {317, nullptr, "GetNpadLeftRightInterfaceType"},
+ {318, nullptr, "HasBattery"},
+ {319, nullptr, "HasLeftRightBattery"},
{321, nullptr, "GetUniquePadsFromNpad"},
{322, nullptr, "GetIrSensorState"},
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
+ {324, nullptr, "GetUniquePadButtonSet"},
+ {325, nullptr, "GetUniquePadColor"},
+ {326, nullptr, "GetUniquePadAppletDetailedUiType"},
{500, nullptr, "SetAppletResourceUserId"},
{501, nullptr, "RegisterAppletResourceUserId"},
{502, nullptr, "UnregisterAppletResourceUserId"},
@@ -1716,10 +1758,13 @@ public:
{511, nullptr, "GetVibrationMasterVolume"},
{512, nullptr, "BeginPermitVibrationSession"},
{513, nullptr, "EndPermitVibrationSession"},
+ {514, nullptr, "Unknown514"},
{520, nullptr, "EnableHandheldHids"},
{521, nullptr, "DisableHandheldHids"},
{522, nullptr, "SetJoyConRailEnabled"},
{523, nullptr, "IsJoyConRailEnabled"},
+ {524, nullptr, "IsHandheldHidsEnabled"},
+ {525, nullptr, "IsJoyConAttachedOnAllRail"},
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
{541, nullptr, "GetPlayReportControllerUsages"},
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@@ -1795,6 +1840,65 @@ public:
{1154, nullptr, "IsFirmwareAvailableForNotification"},
{1155, nullptr, "SetForceHandheldStyleVibration"},
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
+ {1157, nullptr, "CancelConnectionTrigger"},
+ {1200, nullptr, "IsButtonConfigSupported"},
+ {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
+ {1202, nullptr, "DeleteButtonConfig"},
+ {1203, nullptr, "DeleteButtonConfigEmbedded"},
+ {1204, nullptr, "SetButtonConfigEnabled"},
+ {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
+ {1206, nullptr, "IsButtonConfigEnabled"},
+ {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
+ {1208, nullptr, "SetButtonConfigEmbedded"},
+ {1209, nullptr, "SetButtonConfigFull"},
+ {1210, nullptr, "SetButtonConfigLeft"},
+ {1211, nullptr, "SetButtonConfigRight"},
+ {1212, nullptr, "GetButtonConfigEmbedded"},
+ {1213, nullptr, "GetButtonConfigFull"},
+ {1214, nullptr, "GetButtonConfigLeft"},
+ {1215, nullptr, "GetButtonConfigRight"},
+ {1250, nullptr, "IsCustomButtonConfigSupported"},
+ {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
+ {1252, nullptr, "IsDefaultButtonConfigFull"},
+ {1253, nullptr, "IsDefaultButtonConfigLeft"},
+ {1254, nullptr, "IsDefaultButtonConfigRight"},
+ {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
+ {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
+ {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
+ {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
+ {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
+ {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
+ {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
+ {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
+ {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
+ {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
+ {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
+ {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
+ {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
+ {1268, nullptr, "DeleteButtonConfigStorageFull"},
+ {1269, nullptr, "DeleteButtonConfigStorageLeft"},
+ {1270, nullptr, "DeleteButtonConfigStorageRight"},
+ {1271, nullptr, "IsUsingCustomButtonConfig"},
+ {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
+ {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
+ {1274, nullptr, "SetDefaultButtonConfig"},
+ {1275, nullptr, "SetAllDefaultButtonConfig"},
+ {1276, nullptr, "SetHidButtonConfigEmbedded"},
+ {1277, nullptr, "SetHidButtonConfigFull"},
+ {1278, nullptr, "SetHidButtonConfigLeft"},
+ {1279, nullptr, "SetHidButtonConfigRight"},
+ {1280, nullptr, "GetHidButtonConfigEmbedded"},
+ {1281, nullptr, "GetHidButtonConfigFull"},
+ {1282, nullptr, "GetHidButtonConfigLeft"},
+ {1283, nullptr, "GetHidButtonConfigRight"},
+ {1284, nullptr, "GetButtonConfigStorageEmbedded"},
+ {1285, nullptr, "GetButtonConfigStorageFull"},
+ {1286, nullptr, "GetButtonConfigStorageLeft"},
+ {1287, nullptr, "GetButtonConfigStorageRight"},
+ {1288, nullptr, "SetButtonConfigStorageEmbedded"},
+ {1289, nullptr, "SetButtonConfigStorageFull"},
+ {1290, nullptr, "DeleteButtonConfigStorageRight"},
+ {1291, nullptr, "DeleteButtonConfigStorageRight"},
};
// clang-format on
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 36ed228c8..c2bdd39a3 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -129,6 +129,7 @@ private:
void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
+ void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx);
void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
void SendVibrationValue(Kernel::HLERequestContext& ctx);
void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp
index 43a8840d0..b1efa3d05 100644
--- a/src/core/hle/service/hid/xcd.cpp
+++ b/src/core/hle/service/hid/xcd.cpp
@@ -28,6 +28,8 @@ XCD_SYS::XCD_SYS(Core::System& system_) : ServiceFramework{system_, "xcd:sys"} {
{20, nullptr, "StartMifareWrite"},
{101, nullptr, "GetAwakeTriggerReasonForLeftRail"},
{102, nullptr, "GetAwakeTriggerReasonForRightRail"},
+ {103, nullptr, "GetAwakeTriggerBatteryLevelTransitionForLeftRail"},
+ {104, nullptr, "GetAwakeTriggerBatteryLevelTransitionForRightRail"},
};
// clang-format on
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d111c1357..c8bc60ad1 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -118,9 +118,9 @@ public:
explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "AddProcessToDebugLaunchQueue"},
- {1, nullptr, "ClearDebugLaunchQueue"},
- {2, nullptr, "GetNsoInfos"},
+ {0, nullptr, "SetProgramArgument"},
+ {1, nullptr, "FlushArguments"},
+ {2, nullptr, "GetProcessModuleInfo"},
};
// clang-format on
@@ -135,8 +135,8 @@ public:
static const FunctionInfo functions[] = {
{0, nullptr, "CreateProcess"},
{1, nullptr, "GetProgramInfo"},
- {2, nullptr, "RegisterTitle"},
- {3, nullptr, "UnregisterTitle"},
+ {2, nullptr, "PinProgram"},
+ {3, nullptr, "UnpinProgram"},
{4, nullptr, "SetEnabledProgramVerification"},
};
// clang-format on
@@ -150,8 +150,8 @@ public:
explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "AddProcessToLaunchQueue"},
- {1, nullptr, "ClearLaunchQueue"},
+ {0, nullptr, "SetProgramArgument"},
+ {1, nullptr, "FlushArguments"},
};
// clang-format on
@@ -164,19 +164,19 @@ public:
explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &RelocatableObject::LoadNro, "LoadNro"},
- {1, &RelocatableObject::UnloadNro, "UnloadNro"},
- {2, &RelocatableObject::LoadNrr, "LoadNrr"},
- {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
+ {0, &RelocatableObject::LoadModule, "LoadModule"},
+ {1, &RelocatableObject::UnloadModule, "UnloadModule"},
+ {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"},
+ {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"},
{4, &RelocatableObject::Initialize, "Initialize"},
- {10, nullptr, "LoadNrrEx"},
+ {10, nullptr, "RegisterModuleInfo2"},
};
// clang-format on
RegisterHandlers(functions);
}
- void LoadNrr(Kernel::HLERequestContext& ctx) {
+ void RegisterModuleInfo(Kernel::HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le nrr_address;
@@ -273,7 +273,7 @@ public:
rb.Push(RESULT_SUCCESS);
}
- void UnloadNrr(Kernel::HLERequestContext& ctx) {
+ void UnregisterModuleInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto pid = rp.Pop<u64>();
const auto nrr_address = rp.Pop<VAddr>();
@@ -408,7 +408,7 @@ public:
data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite);
}
- void LoadNro(Kernel::HLERequestContext& ctx) {
+ void LoadModule(Kernel::HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le image_address;
@@ -546,7 +546,7 @@ public:
return RESULT_SUCCESS;
}
- void UnloadNro(Kernel::HLERequestContext& ctx) {
+ void UnloadModule(Kernel::HLERequestContext& ctx) {
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index f3be0b878..fee360ab9 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -125,51 +125,51 @@ public:
{39, nullptr, "PrepareShutdown"},
{40, nullptr, "ListApplyDeltaTask"},
{41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"},
- {42, nullptr, "Unknown42"},
- {43, nullptr, "Unknown43"},
- {44, nullptr, "Unknown44"},
- {45, nullptr, "Unknown45"},
- {46, nullptr, "Unknown46"},
- {47, nullptr, "Unknown47"},
- {48, nullptr, "Unknown48"},
- {49, nullptr, "Unknown49"},
- {50, nullptr, "Unknown50"},
- {51, nullptr, "Unknown51"},
- {52, nullptr, "Unknown52"},
- {53, nullptr, "Unknown53"},
- {54, nullptr, "Unknown54"},
- {55, nullptr, "Unknown55"},
- {56, nullptr, "Unknown56"},
- {57, nullptr, "Unknown57"},
- {58, nullptr, "Unknown58"},
- {59, nullptr, "Unknown59"},
- {60, nullptr, "Unknown60"},
- {61, nullptr, "Unknown61"},
- {62, nullptr, "Unknown62"},
- {63, nullptr, "Unknown63"},
- {64, nullptr, "Unknown64"},
- {65, nullptr, "Unknown65"},
- {66, nullptr, "Unknown66"},
- {67, nullptr, "Unknown67"},
- {68, nullptr, "Unknown68"},
- {69, nullptr, "Unknown69"},
- {70, nullptr, "Unknown70"},
- {71, nullptr, "Unknown71"},
- {72, nullptr, "Unknown72"},
- {73, nullptr, "Unknown73"},
- {74, nullptr, "Unknown74"},
- {75, nullptr, "Unknown75"},
- {76, nullptr, "Unknown76"},
- {77, nullptr, "Unknown77"},
- {78, nullptr, "Unknown78"},
- {79, nullptr, "Unknown79"},
- {80, nullptr, "Unknown80"},
- {81, nullptr, "Unknown81"},
- {82, nullptr, "Unknown82"},
- {83, nullptr, "Unknown83"},
+ {42, nullptr, "CreateApplyDeltaTaskFromDownloadTask"},
+ {43, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
+ {44, nullptr, "GetApplyDeltaTaskRequiredStorage"},
+ {45, nullptr, "CalculateNetworkInstallTaskContentsSize"},
+ {46, nullptr, "PrepareShutdownForSystemUpdate"},
+ {47, nullptr, "FindMaxRequiredApplicationVersionOfTask"},
+ {48, nullptr, "CommitNetworkInstallTaskPartially"},
+ {49, nullptr, "ListNetworkInstallTaskCommittedContentMeta"},
+ {50, nullptr, "ListNetworkInstallTaskNotCommittedContentMeta"},
+ {51, nullptr, "FindMaxRequiredSystemVersionOfTask"},
+ {52, nullptr, "GetNetworkInstallTaskErrorContext"},
+ {53, nullptr, "CreateLocalCommunicationReceiveApplicationTask"},
+ {54, nullptr, "DestroyLocalCommunicationReceiveApplicationTask"},
+ {55, nullptr, "ListLocalCommunicationReceiveApplicationTask"},
+ {56, nullptr, "RequestLocalCommunicationReceiveApplicationTaskRun"},
+ {57, nullptr, "GetLocalCommunicationReceiveApplicationTaskInfo"},
+ {58, nullptr, "CommitLocalCommunicationReceiveApplicationTask"},
+ {59, nullptr, "ListLocalCommunicationReceiveApplicationTaskContentMeta"},
+ {60, nullptr, "CreateLocalCommunicationSendApplicationTask"},
+ {61, nullptr, "RequestLocalCommunicationSendApplicationTaskRun"},
+ {62, nullptr, "GetLocalCommunicationReceiveApplicationTaskErrorContext"},
+ {63, nullptr, "GetLocalCommunicationSendApplicationTaskInfo"},
+ {64, nullptr, "DestroyLocalCommunicationSendApplicationTask"},
+ {65, nullptr, "GetLocalCommunicationSendApplicationTaskErrorContext"},
+ {66, nullptr, "CalculateLocalCommunicationReceiveApplicationTaskRequiredSize"},
+ {67, nullptr, "ListApplicationLocalCommunicationReceiveApplicationTask"},
+ {68, nullptr, "ListApplicationLocalCommunicationSendApplicationTask"},
+ {69, nullptr, "CreateLocalCommunicationReceiveSystemUpdateTask"},
+ {70, nullptr, "DestroyLocalCommunicationReceiveSystemUpdateTask"},
+ {71, nullptr, "ListLocalCommunicationReceiveSystemUpdateTask"},
+ {72, nullptr, "RequestLocalCommunicationReceiveSystemUpdateTaskRun"},
+ {73, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskInfo"},
+ {74, nullptr, "CommitLocalCommunicationReceiveSystemUpdateTask"},
+ {75, nullptr, "GetLocalCommunicationReceiveSystemUpdateTaskErrorContext"},
+ {76, nullptr, "CreateLocalCommunicationSendSystemUpdateTask"},
+ {77, nullptr, "RequestLocalCommunicationSendSystemUpdateTaskRun"},
+ {78, nullptr, "GetLocalCommunicationSendSystemUpdateTaskInfo"},
+ {79, nullptr, "DestroyLocalCommunicationSendSystemUpdateTask"},
+ {80, nullptr, "GetLocalCommunicationSendSystemUpdateTaskErrorContext"},
+ {81, nullptr, "ListLocalCommunicationSendSystemUpdateTask"},
+ {82, nullptr, "GetReceivedSystemDataPath"},
+ {83, nullptr, "CalculateApplyDeltaTaskOccupiedSize"},
{84, nullptr, "Unknown84"},
- {85, nullptr, "Unknown85"},
- {86, nullptr, "Unknown86"},
+ {85, nullptr, "ListNetworkInstallTaskContentMetaFromInstallMeta"},
+ {86, nullptr, "ListNetworkInstallTaskOccupiedSize"},
{87, nullptr, "Unknown87"},
{88, nullptr, "Unknown88"},
{89, nullptr, "Unknown89"},
@@ -202,6 +202,17 @@ public:
{116, nullptr, "Unknown116"},
{117, nullptr, "Unknown117"},
{118, nullptr, "Unknown118"},
+ {119, nullptr, "Unknown119"},
+ {120, nullptr, "Unknown120"},
+ {121, nullptr, "Unknown121"},
+ {122, nullptr, "Unknown122"},
+ {123, nullptr, "Unknown123"},
+ {124, nullptr, "Unknown124"},
+ {125, nullptr, "Unknown125"},
+ {126, nullptr, "Unknown126"},
+ {127, nullptr, "Unknown127"},
+ {128, nullptr, "Unknown128"},
+ {129, nullptr, "Unknown129"},
};
// clang-format on
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index f7a58f659..e4c703da4 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -49,6 +49,8 @@ public:
{151, nullptr, "GetStateWithHandover"},
{152, nullptr, "GetStateChangeEventWithHandover"},
{153, nullptr, "GetDropEventWithHandover"},
+ {154, nullptr, "CreateTokenAsync"},
+ {155, nullptr, "CreateTokenAsyncWithApplicationId"},
{161, nullptr, "GetRequestChangeStateCancelEvent"},
{162, nullptr, "RequestChangeStateForceTimedWithCancelEvent"},
{201, nullptr, "RequestChangeStateForceTimed"},
@@ -84,6 +86,7 @@ public:
{151, nullptr, "GetStateWithHandover"},
{152, nullptr, "GetStateChangeEventWithHandover"},
{153, nullptr, "GetDropEventWithHandover"},
+ {154, nullptr, "CreateTokenAsync"},
};
// clang-format on
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 6ccf8995c..5fe7a9189 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -55,6 +55,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
+ {31, nullptr, "Unknown31"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
@@ -182,6 +183,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{913, nullptr, "ListAllApplicationRecord"},
{914, nullptr, "HideApplicationRecord"},
{915, nullptr, "ShowApplicationRecord"},
+ {916, nullptr, "IsApplicationAutoDeleteDisabled"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
@@ -201,6 +203,8 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1310, nullptr, "RequestMoveApplicationEntity"},
{1311, nullptr, "EstimateSizeToMove"},
{1312, nullptr, "HasMovableEntity"},
+ {1313, nullptr, "CleanupOrphanContents"},
+ {1314, nullptr, "CheckPreconditionSatisfiedToMove"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
@@ -215,6 +219,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1704, nullptr, "GetApplicationViewWithPromotionInfo"},
+ {1705, nullptr, "IsPatchAutoDeletableApplication"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
@@ -269,6 +274,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2351, nullptr, "RequestNoDownloadRightsErrorResolution"},
{2352, nullptr, "RequestResolveNoDownloadRightsError"},
{2353, nullptr, "GetApplicationDownloadTaskInfo"},
+ {2354, nullptr, "PrioritizeApplicationBackgroundTask"},
+ {2355, nullptr, "Unknown2355"},
+ {2356, nullptr, "Unknown2356"},
{2400, nullptr, "GetPromotionInfo"},
{2401, nullptr, "CountPromotionInfo"},
{2402, nullptr, "ListPromotionInfo"},
@@ -282,6 +290,21 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2515, nullptr, "CleanupAllPlaceHolderAndFragmentsIfNoTask"},
{2516, nullptr, "EnsureApplicationCertificate"},
{2800, nullptr, "GetApplicationIdOfPreomia"},
+ {3000, nullptr, "RegisterDeviceLockKey"},
+ {3001, nullptr, "UnregisterDeviceLockKey"},
+ {3002, nullptr, "VerifyDeviceLockKey"},
+ {3003, nullptr, "HideApplicationIcon"},
+ {3004, nullptr, "ShowApplicationIcon"},
+ {3005, nullptr, "HideApplicationTitle"},
+ {3006, nullptr, "ShowApplicationTitle"},
+ {3007, nullptr, "EnableGameCard"},
+ {3008, nullptr, "DisableGameCard"},
+ {3009, nullptr, "EnableLocalContentShare"},
+ {3010, nullptr, "DisableLocalContentShare"},
+ {3011, nullptr, "IsApplicationIconHidden"},
+ {3012, nullptr, "IsApplicationTitleHidden"},
+ {3013, nullptr, "IsGameCardEnabled"},
+ {3014, nullptr, "IsLocalContentShareEnabled"},
{9999, nullptr, "GetApplicationCertificate"},
};
// clang-format on
@@ -441,7 +464,11 @@ IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
+ {900, nullptr, "ImportAutoUpdatePolicyJsonForDebug"},
+ {901, nullptr, "ListDefaultAutoUpdatePolicy"},
+ {902, nullptr, "ListAutoUpdatePolicyForSpecificApplication"},
{1000, nullptr, "PerformAutoUpdate"},
+ {1001, nullptr, "ListAutoUpdateSchedule"},
};
// clang-format on
@@ -547,6 +574,9 @@ IFactoryResetInterface::~IFactoryResetInterface() = default;
NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
+ {7988, nullptr, "GetDynamicRightsInterface"},
+ {7989, nullptr, "GetReadOnlyApplicationControlDataInterface"},
+ {7991, nullptr, "GetReadOnlyApplicationRecordInterface"},
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
@@ -575,18 +605,22 @@ public:
{0, nullptr, "LaunchProgram"},
{1, nullptr, "TerminateProcess"},
{2, nullptr, "TerminateProgram"},
- {4, nullptr, "GetShellEventHandle"},
+ {4, nullptr, "GetShellEvent"},
{5, nullptr, "GetShellEventInfo"},
{6, nullptr, "TerminateApplication"},
{7, nullptr, "PrepareLaunchProgramFromHost"},
- {8, nullptr, "LaunchApplication"},
+ {8, nullptr, "LaunchApplicationFromHost"},
{9, nullptr, "LaunchApplicationWithStorageIdForDevelop"},
{10, nullptr, "IsSystemMemoryResourceLimitBoosted"},
{11, nullptr, "GetRunningApplicationProcessIdForDevelop"},
- {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"},
+ {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActiveForDevelop"},
{13, nullptr, "CreateApplicationResourceForDevelop"},
{14, nullptr, "IsPreomiaForDevelop"},
{15, nullptr, "GetApplicationProgramIdFromHost"},
+ {16, nullptr, "RefreshCachedDebugValues"},
+ {17, nullptr, "PrepareLaunchApplicationFromHost"},
+ {18, nullptr, "GetLaunchEvent"},
+ {19, nullptr, "GetLaunchResult"},
};
// clang-format on
@@ -699,6 +733,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
+ std::make_shared<NS>("ns:ro", system)->InstallAsService(service_manager);
std::make_shared<NS_DEV>(system)->InstallAsService(service_manager);
std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index fcd15d81f..da139fdc4 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -154,6 +154,10 @@ PL_U::PL_U(Core::System& system_)
{100, nullptr, "RequestApplicationFunctionAuthorization"},
{101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
{102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"},
+ {103, nullptr, "RefreshApplicationFunctionBlackListDebugRecord"},
+ {104, nullptr, "RequestApplicationFunctionAuthorizationByProgramId"},
+ {105, nullptr, "GetFunctionBlackListSystemVersionToAuthorize"},
+ {106, nullptr, "GetFunctionBlackListVersion"},
{1000, nullptr, "LoadNgWordDataForPlatformRegionChina"},
{1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"},
};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 4898dc27a..c2f152190 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -23,17 +23,22 @@ namespace {
template <typename T>
std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
std::size_t offset) {
- std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
- offset += count * sizeof(T);
- return offset;
+ if (!dst.empty()) {
+ std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
+ }
+ return 0;
}
// Write vectors will write data to the output buffer
template <typename T>
std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
- std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
- offset += src.size() * sizeof(T);
- return offset;
+ if (src.empty()) {
+ return 0;
+ } else {
+ std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
+ offset += src.size() * sizeof(T);
+ return offset;
+ }
}
} // Anonymous namespace
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index e2ac71fa1..b066c3417 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -26,6 +26,7 @@ public:
{22, nullptr, "DeleteSaveDataBackupAsync"},
{25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
{26, nullptr, "DownloadSaveDataBackupAsync"},
+ {27, nullptr, "UploadSaveDataBackupAsync"},
{9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
{9013, nullptr, "GetSaveDataBackupSettingForDebug"},
{9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
index f6686fc4d..9bc851591 100644
--- a/src/core/hle/service/pcie/pcie.cpp
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -37,7 +37,7 @@ public:
{19, nullptr, "SetIrqEnable"},
{20, nullptr, "SetAspmEnable"},
{21, nullptr, "SetResetUponResumeEnable"},
- {22, nullptr, "Unknown22"},
+ {22, nullptr, "ResetFunction"},
{23, nullptr, "Unknown23"},
};
// clang-format on
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index f9089bf2f..dc59702f1 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -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"},
@@ -50,6 +64,7 @@ public:
{1046, nullptr, "DisableFeaturesForReset"},
{1047, nullptr, "NotifyApplicationDownloadStarted"},
{1048, nullptr, "NotifyNetworkProfileCreated"},
+ {1049, nullptr, "ResetFreeCommunicationApplicationList"},
{1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
{1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
{1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
@@ -69,6 +84,8 @@ public:
{1421, nullptr, "GetAccountNickname"},
{1424, nullptr, "GetAccountState"},
{1425, nullptr, "RequestPostEvents"},
+ {1426, nullptr, "GetPostEventInterval"},
+ {1427, nullptr, "SetPostEventInterval"},
{1432, nullptr, "GetSynchronizationEvent"},
{1451, nullptr, "StartPlayTimer"},
{1452, nullptr, "StopPlayTimer"},
@@ -119,62 +136,235 @@ public:
}
private:
+ 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_WARNING(Service_PCTL, "(STUBBED) called");
+ 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 +372,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 +382,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
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h
index 4c7e09a3b..032481b00 100644
--- a/src/core/hle/service/pctl/module.h
+++ b/src/core/hle/service/pctl/module.h
@@ -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{};
};
};
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 16dd34f90..e4d155c86 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -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"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 275d23007..fd0a1e486 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -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;
};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 1da56bc27..aec399076 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -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) {
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index b58b2c8c5..5909fdd85 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -261,6 +261,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{155, nullptr, "SetAccountOnlineStorageSettings"},
{156, nullptr, "GetPctlReadyFlag"},
{157, nullptr, "SetPctlReadyFlag"},
+ {158, nullptr, "GetAnalogStickUserCalibrationL"},
+ {159, nullptr, "SetAnalogStickUserCalibrationL"},
+ {160, nullptr, "GetAnalogStickUserCalibrationR"},
+ {161, nullptr, "SetAnalogStickUserCalibrationR"},
{162, nullptr, "GetPtmBatteryVersion"},
{163, nullptr, "SetPtmBatteryVersion"},
{164, nullptr, "GetUsb30HostEnableFlag"},
@@ -302,6 +306,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{200, nullptr, "SetButtonConfigRegisteredSettings"},
{201, nullptr, "GetFieldTestingFlag"},
{202, nullptr, "SetFieldTestingFlag"},
+ {203, nullptr, "GetPanelCrcMode"},
+ {204, nullptr, "SetPanelCrcMode"},
};
// clang-format on
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 2b91a89d1..94608d529 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -190,10 +190,11 @@ SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
: ServiceFramework{system_, "sm:", 4},
service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
static const FunctionInfo functions[] = {
- {0x00000000, &SM::Initialize, "Initialize"},
- {0x00000001, &SM::GetService, "GetService"},
- {0x00000002, &SM::RegisterService, "RegisterService"},
- {0x00000003, &SM::UnregisterService, "UnregisterService"},
+ {0, &SM::Initialize, "Initialize"},
+ {1, &SM::GetService, "GetService"},
+ {2, &SM::RegisterService, "RegisterService"},
+ {3, &SM::UnregisterService, "UnregisterService"},
+ {4, nullptr, "DetachClient"},
};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
index 05681ca2d..899a64c2f 100644
--- a/src/core/hle/service/sockets/ethc.cpp
+++ b/src/core/hle/service/sockets/ethc.cpp
@@ -15,6 +15,7 @@ ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} {
{3, nullptr, "GetMediaList"},
{4, nullptr, "SetMediaType"},
{5, nullptr, "GetMediaType"},
+ {6, nullptr, "Unknown6"},
};
// clang-format on
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index 51c3739bb..1159debc5 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -9,6 +9,7 @@ namespace Service::Sockets {
NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
// clang-format off
static const FunctionInfo functions[] = {
+ {5, nullptr, "GetSettingUrl"},
{10, nullptr, "GetSettingName"},
{11, nullptr, "GetEnvironmentIdentifier"},
{12, nullptr, "GetDeviceId"},
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 3a6329f56..5c71f423c 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -9,8 +9,8 @@ namespace Service::Sockets {
SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
static const FunctionInfo functions[] = {
- {0, nullptr, "SetDnsAddressesPrivate"},
- {1, nullptr, "GetDnsAddressPrivate"},
+ {0, nullptr, "SetDnsAddressesPrivateRequest"},
+ {1, nullptr, "GetDnsAddressPrivateRequest"},
{2, nullptr, "GetHostByNameRequest"},
{3, nullptr, "GetHostByAddrRequest"},
{4, nullptr, "GetHostStringErrorRequest"},
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index 4e212610f..fff3f3c42 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -60,6 +60,8 @@ SPL_FS::SPL_FS(Core::System& system_, std::shared_ptr<Module> module_)
{4, nullptr, "GenerateAesKey"},
{5, nullptr, "SetConfig"},
{7, &SPL::GetRandomBytes, "GenerateRandomBytes"},
+ {9, nullptr, "ImportLotusKey"},
+ {10, nullptr, "DecryptLotusMessage"},
{11, nullptr, "IsDevelopment"},
{12, nullptr, "GenerateSpecificAesKey"},
{14, nullptr, "DecryptAesKey"},
@@ -123,6 +125,7 @@ SPL_ES::SPL_ES(Core::System& system_, std::shared_ptr<Module> module_)
{14, nullptr, "DecryptAesKey"},
{15, nullptr, "CryptAesCtr"},
{16, nullptr, "ComputeCmac"},
+ {17, nullptr, "ImportEsKey"},
{18, nullptr, "UnwrapTitleKey"},
{20, nullptr, "PrepareEsCommonKey"},
{21, nullptr, "AllocateAesKeyslot"},
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 998e12b4d..63e0247de 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -328,9 +328,14 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
- IPC::RequestParser rp{ctx};
- const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>();
- const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>();
+ Clock::ClockSnapshot snapshot_a;
+ Clock::ClockSnapshot snapshot_b;
+
+ const auto snapshot_a_data = ctx.ReadBuffer(0);
+ const auto snapshot_b_data = ctx.ReadBuffer(1);
+
+ std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot));
+ std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot));
auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset -
snapshot_a.user_context.offset)};
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index 25cecbc83..3117627cf 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -20,6 +20,7 @@ ITimeZoneService ::ITimeZoneService(Core::System& system_,
{3, nullptr, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
{5, nullptr, "GetTimeZoneRuleVersion"},
+ {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index 579de83e4..b3b230a8c 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -69,15 +69,15 @@ public:
: ServiceFramework{system_, "IClientEpSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Open"},
+ {0, nullptr, "ReOpen"},
{1, nullptr, "Close"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Populate"},
+ {2, nullptr, "GetCompletionEvent"},
+ {3, nullptr, "PopulateRing"},
{4, nullptr, "PostBufferAsync"},
{5, nullptr, "GetXferReport"},
{6, nullptr, "PostBufferMultiAsync"},
- {7, nullptr, "Unknown7"},
- {8, nullptr, "Unknown8"},
+ {7, nullptr, "CreateSmmuSpace"},
+ {8, nullptr, "ShareReportRing"},
};
// clang-format on
@@ -91,7 +91,7 @@ public:
: ServiceFramework{system_, "IClientIfSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
+ {0, nullptr, "GetStateChangeEvent"},
{1, nullptr, "SetInterface"},
{2, nullptr, "GetInterface"},
{3, nullptr, "GetAlternateInterface"},
@@ -176,15 +176,15 @@ public:
: ServiceFramework{system_, "IPdCradleSession"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "VdmUserWrite"},
- {1, nullptr, "VdmUserRead"},
- {2, nullptr, "Vdm20Init"},
- {3, nullptr, "GetFwType"},
- {4, nullptr, "GetFwRevision"},
- {5, nullptr, "GetManufacturerId"},
- {6, nullptr, "GetDeviceId"},
- {7, nullptr, "Unknown7"},
- {8, nullptr, "Unknown8"},
+ {0, nullptr, "SetCradleVdo"},
+ {1, nullptr, "GetCradleVdo"},
+ {2, nullptr, "ResetCradleUsbHub"},
+ {3, nullptr, "GetHostPdcFirmwareType"},
+ {4, nullptr, "GetHostPdcFirmwareRevision"},
+ {5, nullptr, "GetHostPdcManufactureId"},
+ {6, nullptr, "GetHostPdcDeviceId"},
+ {7, nullptr, "AwakeCradle"},
+ {8, nullptr, "SleepCradle"},
};
// clang-format on
@@ -219,12 +219,12 @@ public:
explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
- {1, nullptr, "Unknown1"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Unknown3"},
- {4, nullptr, "Unknown4"},
- {5, nullptr, "Unknown5"},
+ {0, nullptr, "GetPowerEvent"},
+ {1, nullptr, "GetPowerState"},
+ {2, nullptr, "GetDataEvent"},
+ {3, nullptr, "GetDataRole"},
+ {4, nullptr, "SetDiagData"},
+ {5, nullptr, "GetDiagData"},
};
// clang-format on
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 7423287ea..a1a7ac987 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -695,6 +695,7 @@ public:
{2205, &ISystemDisplayService::SetLayerZ, "SetLayerZ"},
{2207, &ISystemDisplayService::SetLayerVisibility, "SetLayerVisibility"},
{2209, nullptr, "SetLayerAlpha"},
+ {2210, nullptr, "SetLayerPositionAndSize"},
{2312, nullptr, "CreateStrayLayer"},
{2400, nullptr, "OpenIndirectLayer"},
{2401, nullptr, "CloseIndirectLayer"},
@@ -718,6 +719,7 @@ public:
{3215, nullptr, "SetDisplayGamma"},
{3216, nullptr, "GetDisplayCmuLuma"},
{3217, nullptr, "SetDisplayCmuLuma"},
+ {3218, nullptr, "SetDisplayCrcMode"},
{6013, nullptr, "GetLayerPresentationSubmissionTimestamps"},
{8225, nullptr, "GetSharedBufferMemoryHandleId"},
{8250, nullptr, "OpenSharedLayer"},
@@ -729,6 +731,7 @@ public:
{8256, nullptr, "GetSharedFrameBufferAcquirableEvent"},
{8257, nullptr, "FillSharedFrameBufferColor"},
{8258, nullptr, "CancelSharedFrameBuffer"},
+ {9000, nullptr, "GetDp2hdmiController"},
};
RegisterHandlers(functions);
}
@@ -808,10 +811,15 @@ public:
{2402, nullptr, "GetDisplayHotplugState"},
{2501, nullptr, "GetCompositorErrorInfo"},
{2601, nullptr, "GetDisplayErrorEvent"},
+ {2701, nullptr, "GetDisplayFatalErrorEvent"},
{4201, nullptr, "SetDisplayAlpha"},
{4203, nullptr, "SetDisplayLayerStack"},
{4205, nullptr, "SetDisplayPowerState"},
{4206, nullptr, "SetDefaultDisplay"},
+ {4207, nullptr, "ResetDisplayPanel"},
+ {4208, nullptr, "SetDisplayFatalErrorEnabled"},
+ {4209, nullptr, "IsDisplayPanelOn"},
+ {4300, nullptr, "GetInternalPanelId"},
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
{6001, nullptr, "RemoveFromLayerStack"},
{6002, &IManagerDisplayService::SetLayerVisibility, "SetLayerVisibility"},
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
index ddbf04069..44957e01d 100644
--- a/src/core/hle/service/wlan/wlan.cpp
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -46,6 +46,13 @@ public:
{28, nullptr, "Unknown28"},
{29, nullptr, "Unknown29"},
{30, nullptr, "Unknown30"},
+ {31, nullptr, "Unknown31"},
+ {32, nullptr, "Unknown32"},
+ {33, nullptr, "Unknown33"},
+ {34, nullptr, "Unknown34"},
+ {35, nullptr, "Unknown35"},
+ {36, nullptr, "Unknown36"},
+ {37, nullptr, "Unknown37"},
};
// clang-format on
diff --git a/src/core/settings.h b/src/core/settings.h
index d849dded3..a81016b23 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -222,6 +222,7 @@ struct Values {
bool quest_flag;
bool disable_macro_jit;
bool extended_logging;
+ bool use_auto_stub;
// Miscellaneous
std::string log_filter;
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index c61f44619..009c6f574 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -517,8 +517,8 @@ void GPU::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const {
interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
}
-void GPU::WaitIdle() const {
- gpu_thread.WaitIdle();
+void GPU::ShutDown() {
+ gpu_thread.ShutDown();
}
void GPU::OnCommandListEnd() {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b2ee45496..ecab35d3b 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -219,8 +219,8 @@ public:
return *shader_notify;
}
- // Waits for the GPU to finish working
- void WaitIdle() const;
+ // Stops the GPU execution and waits for the GPU to finish working
+ void ShutDown();
/// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
void WaitFence(u32 syncpoint_id, u32 value);
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 99353f15f..7addfbc7b 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -29,8 +29,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
system.RegisterHostThread();
// Wait for first GPU command before acquiring the window context
- while (state.queue.Empty())
- ;
+ state.queue.Wait();
// If emulation was stopped during disk shader loading, abort before trying to acquire context
if (!state.is_running) {
@@ -57,11 +56,17 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
} else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
} else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
- return;
+ ASSERT(state.is_running == false);
} else {
UNREACHABLE();
}
state.signaled_fence.store(next.fence);
+ if (next.block) {
+ // We have to lock the write_lock to ensure that the condition_variable wait not get a
+ // race between the check and the lock itself.
+ std::lock_guard lk(state.write_lock);
+ state.cv.notify_all();
+ }
}
}
@@ -69,13 +74,7 @@ ThreadManager::ThreadManager(Core::System& system_, bool is_async_)
: system{system_}, is_async{is_async_} {}
ThreadManager::~ThreadManager() {
- if (!thread.joinable()) {
- return;
- }
-
- // Notify GPU thread that a shutdown is pending
- PushCommand(EndProcessingCommand());
- thread.join();
+ ShutDown();
}
void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
@@ -112,9 +111,8 @@ void ThreadManager::FlushRegion(VAddr addr, u64 size) {
case Settings::GPUAccuracy::Extreme: {
auto& gpu = system.GPU();
u64 fence = gpu.RequestFlush(addr, size);
- PushCommand(GPUTickCommand());
- while (fence > gpu.CurrentFlushRequestFence()) {
- }
+ PushCommand(GPUTickCommand(), true);
+ ASSERT(fence <= gpu.CurrentFlushRequestFence());
break;
}
default:
@@ -131,23 +129,45 @@ void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
rasterizer->OnCPUWrite(addr, size);
}
-void ThreadManager::WaitIdle() const {
- while (state.last_fence > state.signaled_fence.load(std::memory_order_relaxed) &&
- system.IsPoweredOn()) {
+void ThreadManager::ShutDown() {
+ if (!state.is_running) {
+ return;
}
+
+ {
+ std::lock_guard lk(state.write_lock);
+ state.is_running = false;
+ state.cv.notify_all();
+ }
+
+ if (!thread.joinable()) {
+ return;
+ }
+
+ // Notify GPU thread that a shutdown is pending
+ PushCommand(EndProcessingCommand());
+ thread.join();
}
void ThreadManager::OnCommandListEnd() {
PushCommand(OnCommandListEndCommand());
}
-u64 ThreadManager::PushCommand(CommandData&& command_data) {
- const u64 fence{++state.last_fence};
- state.queue.Push(CommandDataContainer(std::move(command_data), fence));
-
+u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
if (!is_async) {
// In synchronous GPU mode, block the caller until the command has executed
- WaitIdle();
+ block = true;
+ }
+
+ std::unique_lock lk(state.write_lock);
+ const u64 fence{++state.last_fence};
+ state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
+
+ if (block) {
+ state.cv.wait(lk, [this, fence] {
+ return fence <= state.signaled_fence.load(std::memory_order_relaxed) ||
+ !state.is_running;
+ });
}
return fence;
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 18269e51c..11a648f38 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -90,21 +90,24 @@ using CommandData =
struct CommandDataContainer {
CommandDataContainer() = default;
- explicit CommandDataContainer(CommandData&& data_, u64 next_fence_)
- : data{std::move(data_)}, fence{next_fence_} {}
+ explicit CommandDataContainer(CommandData&& data_, u64 next_fence_, bool block_)
+ : data{std::move(data_)}, fence{next_fence_}, block(block_) {}
CommandData data;
u64 fence{};
+ bool block{};
};
/// Struct used to synchronize the GPU thread
struct SynchState final {
std::atomic_bool is_running{true};
- using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
+ using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
+ std::mutex write_lock;
CommandQueue queue;
u64 last_fence{};
std::atomic<u64> signaled_fence{};
+ std::condition_variable cv;
};
/// Class used to manage the GPU thread
@@ -132,14 +135,14 @@ public:
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated
void FlushAndInvalidateRegion(VAddr addr, u64 size);
- // Wait until the gpu thread is idle.
- void WaitIdle() const;
+ // Stops the GPU execution and waits for the GPU to finish working
+ void ShutDown();
void OnCommandListEnd();
private:
/// Pushes a command to be executed by the GPU thread
- u64 PushCommand(CommandData&& command_data);
+ u64 PushCommand(CommandData&& command_data, bool block = false);
Core::System& system;
const bool is_async;
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 1cc720ddd..14e5f36e2 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -143,7 +143,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
scheduler.WaitWorker();
- swapchain.AcquireNextImage();
+ while (!swapchain.AcquireNextImage()) {
+ swapchain.Create(layout.width, layout.height, is_srgb);
+ blit_screen.Recreate();
+ }
const VkSemaphore render_semaphore = blit_screen.Draw(*framebuffer, use_accelerated);
scheduler.Flush(render_semaphore);
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 0b63bd6c8..dfd5c65ba 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -82,11 +82,13 @@ void VKSwapchain::Create(u32 width, u32 height, bool srgb) {
resource_ticks.resize(image_count);
}
-void VKSwapchain::AcquireNextImage() {
- device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
- *present_semaphores[frame_index], {}, &image_index);
+bool VKSwapchain::AcquireNextImage() {
+ const VkResult result =
+ device.GetLogical().AcquireNextImageKHR(*swapchain, std::numeric_limits<u64>::max(),
+ *present_semaphores[frame_index], {}, &image_index);
scheduler.Wait(resource_ticks[image_index]);
+ return result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR;
}
bool VKSwapchain::Present(VkSemaphore render_semaphore) {
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index a728511e0..adc8d27cf 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -28,7 +28,7 @@ public:
void Create(u32 width, u32 height, bool srgb);
/// Acquires the next image in the swapchain, waits as needed.
- void AcquireNextImage();
+ bool AcquireNextImage();
/// Presents the rendered image to the swapchain. Returns true when the swapchains had to be
/// recreated. Takes responsability for the ownership of fence.
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 1bac57bb2..1d6155999 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -641,6 +641,7 @@ void Config::ReadDebuggingValues() {
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
Settings::values.extended_logging =
ReadSetting(QStringLiteral("extended_logging"), false).toBool();
+ Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
qt_config->endGroup();
}
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 121873f95..2a5b3f5e7 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -34,6 +34,7 @@ void ConfigureDebug::SetConfiguration() {
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
ui->reporting_services->setChecked(Settings::values.reporting_services);
ui->quest_flag->setChecked(Settings::values.quest_flag);
+ ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@@ -47,6 +48,7 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
Settings::values.reporting_services = ui->reporting_services->isChecked();
Settings::values.quest_flag = ui->quest_flag->isChecked();
+ Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
Settings::values.extended_logging = ui->extended_logging->isChecked();
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 9186aa732..ae48b728c 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -185,6 +185,28 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="use_auto_stub">
+ <property name="text">
+ <string>Enable Auto-Stub</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>This will be reset automatically when yuzu closes.</string>
+ </property>
+ <property name="indent">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>