summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt32
-rw-r--r--externals/CMakeLists.txt15
m---------externals/SDL0
m---------externals/ffmpeg0
m---------externals/mbedtls0
-rw-r--r--src/common/common_funcs.h23
-rw-r--r--src/common/intrusive_red_black_tree.h1
-rw-r--r--src/common/parent_of_member.h8
-rw-r--r--src/common/tree.h2
-rw-r--r--src/core/CMakeLists.txt72
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.cpp4
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.h2
-rw-r--r--src/core/core.cpp22
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/cpu_manager.h2
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp4
-rw-r--r--src/core/crypto/ctr_encryption_layer.h2
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/file_sys/nca_metadata.cpp8
-rw-r--r--src/core/file_sys/nca_metadata.h4
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.cpp2
-rw-r--r--src/core/file_sys/submission_package.cpp4
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp8
-rw-r--r--src/core/file_sys/vfs_concat.h4
-rw-r--r--src/core/file_sys/vfs_layered.cpp4
-rw-r--r--src/core/file_sys/vfs_layered.h2
-rw-r--r--src/core/file_sys/vfs_libzip.cpp9
-rw-r--r--src/core/file_sys/vfs_static.h6
-rw-r--r--src/core/file_sys/vfs_vector.cpp4
-rw-r--r--src/core/file_sys/vfs_vector.h4
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/hle/ipc.h17
-rw-r--r--src/core/hle/ipc_helpers.h151
-rw-r--r--src/core/hle/kernel/client_port.cpp47
-rw-r--r--src/core/hle/kernel/client_port.h63
-rw-r--r--src/core/hle/kernel/client_session.cpp53
-rw-r--r--src/core/hle/kernel/client_session.h68
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp10
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h10
-rw-r--r--src/core/hle/kernel/handle_table.cpp131
-rw-r--r--src/core/hle/kernel/handle_table.h144
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp183
-rw-r--r--src/core/hle/kernel/hle_ipc.h88
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp192
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.h43
-rw-r--r--src/core/hle/kernel/k_auto_object.cpp14
-rw-r--r--src/core/hle/kernel/k_auto_object.h302
-rw-r--r--src/core/hle/kernel/k_auto_object_container.cpp28
-rw-r--r--src/core/hle/kernel/k_auto_object_container.h70
-rw-r--r--src/core/hle/kernel/k_class_token.cpp133
-rw-r--r--src/core/hle/kernel/k_class_token.h131
-rw-r--r--src/core/hle/kernel/k_client_port.cpp125
-rw-r--r--src/core/hle/kernel/k_client_port.h61
-rw-r--r--src/core/hle/kernel/k_client_session.cpp32
-rw-r--r--src/core/hle/kernel/k_client_session.h61
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp34
-rw-r--r--src/core/hle/kernel/k_event.cpp46
-rw-r--r--src/core/hle/kernel/k_event.h45
-rw-r--r--src/core/hle/kernel/k_handle_table.cpp135
-rw-r--r--src/core/hle/kernel/k_handle_table.h310
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h3
-rw-r--r--src/core/hle/kernel/k_linked_list.h238
-rw-r--r--src/core/hle/kernel/k_memory_block.h4
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.cpp38
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.h2
-rw-r--r--src/core/hle/kernel/k_memory_region.h4
-rw-r--r--src/core/hle/kernel/k_page_linked_list.h2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp59
-rw-r--r--src/core/hle/kernel/k_page_table.h11
-rw-r--r--src/core/hle/kernel/k_port.cpp68
-rw-r--r--src/core/hle/kernel/k_port.h69
-rw-r--r--src/core/hle/kernel/k_process.cpp (renamed from src/core/hle/kernel/process.cpp)149
-rw-r--r--src/core/hle/kernel/k_process.h (renamed from src/core/hle/kernel/process.h)63
-rw-r--r--src/core/hle/kernel/k_readable_event.cpp15
-rw-r--r--src/core/hle/kernel/k_readable_event.h29
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp14
-rw-r--r--src/core/hle/kernel/k_resource_limit.h29
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp55
-rw-r--r--src/core/hle/kernel/k_scheduler.h12
-rw-r--r--src/core/hle/kernel/k_scoped_resource_reservation.h14
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h6
-rw-r--r--src/core/hle/kernel/k_server_port.cpp104
-rw-r--r--src/core/hle/kernel/k_server_port.h80
-rw-r--r--src/core/hle/kernel/k_server_session.cpp (renamed from src/core/hle/kernel/server_session.cpp)86
-rw-r--r--src/core/hle/kernel/k_server_session.h (renamed from src/core/hle/kernel/server_session.h)82
-rw-r--r--src/core/hle/kernel/k_session.cpp85
-rw-r--r--src/core/hle/kernel/k_session.h96
-rw-r--r--src/core/hle/kernel/k_shared_memory.cpp86
-rw-r--r--src/core/hle/kernel/k_shared_memory.h69
-rw-r--r--src/core/hle/kernel/k_slab_heap.h9
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp21
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h21
-rw-r--r--src/core/hle/kernel/k_thread.cpp145
-rw-r--r--src/core/hle/kernel/k_thread.h133
-rw-r--r--src/core/hle/kernel/k_thread_queue.h2
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp45
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h66
-rw-r--r--src/core/hle/kernel/k_writable_event.cpp19
-rw-r--r--src/core/hle/kernel/k_writable_event.h24
-rw-r--r--src/core/hle/kernel/kernel.cpp258
-rw-r--r--src/core/hle/kernel/kernel.h133
-rw-r--r--src/core/hle/kernel/object.cpp42
-rw-r--r--src/core/hle/kernel/object.h96
-rw-r--r--src/core/hle/kernel/physical_core.cpp8
-rw-r--r--src/core/hle/kernel/physical_core.h4
-rw-r--r--src/core/hle/kernel/process_capability.cpp18
-rw-r--r--src/core/hle/kernel/server_port.cpp54
-rw-r--r--src/core/hle/kernel/server_port.h98
-rw-r--r--src/core/hle/kernel/service_thread.cpp29
-rw-r--r--src/core/hle/kernel/service_thread.h4
-rw-r--r--src/core/hle/kernel/session.cpp41
-rw-r--r--src/core/hle/kernel/session.h64
-rw-r--r--src/core/hle/kernel/slab_helpers.h148
-rw-r--r--src/core/hle/kernel/svc.cpp1000
-rw-r--r--src/core/hle/kernel/svc_common.h15
-rw-r--r--src/core/hle/kernel/svc_results.h18
-rw-r--r--src/core/hle/kernel/svc_wrap.h56
-rw-r--r--src/core/hle/kernel/time_manager.cpp17
-rw-r--r--src/core/hle/kernel/time_manager.h2
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp55
-rw-r--r--src/core/hle/kernel/transfer_memory.h96
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp129
-rw-r--r--src/core/hle/service/am/am.h24
-rw-r--r--src/core/hle/service/am/applets/applets.cpp46
-rw-r--r--src/core/hle/service/am/applets/applets.h16
-rw-r--r--src/core/hle/service/am/applets/error.cpp2
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp2
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp24
-rw-r--r--src/core/hle/service/aoc/aoc_u.h3
-rw-r--r--src/core/hle/service/apm/controller.cpp10
-rw-r--r--src/core/hle/service/apm/controller.h2
-rw-r--r--src/core/hle/service/audio/audout_u.cpp16
-rw-r--r--src/core/hle/service/audio/audren_u.cpp61
-rw-r--r--src/core/hle/service/audio/audren_u.h2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp8
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp19
-rw-r--r--src/core/hle/service/bcat/backend/backend.h7
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp13
-rw-r--r--src/core/hle/service/bcat/module.cpp10
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp12
-rw-r--r--src/core/hle/service/btm/btm.cpp39
-rw-r--r--src/core/hle/service/fatal/fatal.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp2
-rw-r--r--src/core/hle/service/friend/friend.cpp12
-rw-r--r--src/core/hle/service/glue/arp.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp352
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h77
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/npad.h8
-rw-r--r--src/core/hle/service/hid/hid.cpp30
-rw-r--r--src/core/hle/service/hid/hid.h6
-rw-r--r--src/core/hle/service/hid/irs.cpp6
-rw-r--r--src/core/hle/service/hid/irs.h6
-rw-r--r--src/core/hle/service/ldr/ldr.cpp16
-rw-r--r--src/core/hle/service/mii/manager.h2
-rw-r--r--src/core/hle/service/mii/mii.cpp4
-rw-r--r--src/core/hle/service/mm/mm_u.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp39
-rw-r--r--src/core/hle/service/nfp/nfp.h5
-rw-r--r--src/core/hle/service/nifm/nifm.cpp18
-rw-r--r--src/core/hle/service/nim/nim.cpp17
-rw-r--r--src/core/hle/service/ns/pl_u.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h12
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp18
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h6
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.cpp2
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp25
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h8
-rw-r--r--src/core/hle/service/pctl/module.cpp2
-rw-r--r--src/core/hle/service/pctl/pctl.cpp4
-rw-r--r--src/core/hle/service/pctl/pctl.h2
-rw-r--r--src/core/hle/service/pm/pm.cpp27
-rw-r--r--src/core/hle/service/prepo/prepo.cpp10
-rw-r--r--src/core/hle/service/ptm/psm.cpp18
-rw-r--r--src/core/hle/service/service.cpp68
-rw-r--r--src/core/hle/service/service.h49
-rw-r--r--src/core/hle/service/set/set_sys.cpp2
-rw-r--r--src/core/hle/service/sm/controller.cpp22
-rw-r--r--src/core/hle/service/sm/sm.cpp164
-rw-r--r--src/core/hle/service/sm/sm.h35
-rw-r--r--src/core/hle/service/ssl/ssl.cpp42
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_core.h4
-rw-r--r--src/core/hle/service/time/local_system_clock_context_writer.h4
-rw-r--r--src/core/hle/service/time/network_system_clock_context_writer.h4
-rw-r--r--src/core/hle/service/time/standard_local_system_clock_core.h4
-rw-r--r--src/core/hle/service/time/standard_network_system_clock_core.h10
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp29
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h11
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp4
-rw-r--r--src/core/hle/service/time/system_clock_core.h2
-rw-r--r--src/core/hle/service/time/time.cpp5
-rw-r--r--src/core/hle/service/time/time_manager.cpp2
-rw-r--r--src/core/hle/service/time/time_manager.h2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp17
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h6
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp4
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h2
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp14
-rw-r--r--src/core/hle/service/vi/display/vi_display.h22
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp2
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h4
-rw-r--r--src/core/hle/service/vi/vi.cpp28
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp27
-rw-r--r--src/core/loader/deconstructed_rom_directory.h6
-rw-r--r--src/core/loader/elf.cpp4
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/kip.cpp4
-rw-r--r--src/core/loader/kip.h2
-rw-r--r--src/core/loader/loader.cpp4
-rw-r--r--src/core/loader/loader.h6
-rw-r--r--src/core/loader/nax.cpp4
-rw-r--r--src/core/loader/nax.h2
-rw-r--r--src/core/loader/nca.cpp4
-rw-r--r--src/core/loader/nca.h2
-rw-r--r--src/core/loader/nro.cpp8
-rw-r--r--src/core/loader/nro.h6
-rw-r--r--src/core/loader/nso.cpp6
-rw-r--r--src/core/loader/nso.h6
-rw-r--r--src/core/loader/nsp.cpp4
-rw-r--r--src/core/loader/nsp.h2
-rw-r--r--src/core/loader/xci.cpp4
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/memory.cpp64
-rw-r--r--src/core/memory.h34
-rw-r--r--src/core/memory/cheat_engine.cpp16
-rw-r--r--src/core/memory/cheat_engine.h8
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp3
-rw-r--r--src/core/memory/dmnt_cheat_vm.h2
-rw-r--r--src/core/perf_stats.cpp2
-rw-r--r--src/core/perf_stats.h2
-rw-r--r--src/core/reporter.cpp4
-rw-r--r--src/core/reporter.h2
-rw-r--r--src/input_common/main.cpp5
-rw-r--r--src/input_common/sdl/sdl.h3
-rw-r--r--src/input_common/sdl/sdl_impl.cpp153
-rw-r--r--src/input_common/sdl/sdl_impl.h1
-rw-r--r--src/video_core/memory_manager.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h8
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp26
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h10
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp38
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h5
-rw-r--r--src/video_core/texture_cache/texture_cache.h57
-rw-r--r--src/video_core/texture_cache/types.h7
-rw-r--r--src/yuzu/bootmanager.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp8
-rw-r--r--src/yuzu/configuration/configure_ui.cpp1
-rw-r--r--src/yuzu/debugger/wait_tree.cpp34
-rw-r--r--src/yuzu/debugger/wait_tree.h20
-rw-r--r--src/yuzu/main.cpp19
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
273 files changed, 6153 insertions, 3647 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 73274c2e0..3faa2b5ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,8 @@ project(yuzu)
12# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON 12# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
13option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) 13option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
14CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF) 14CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
15# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
16CMAKE_DEPENDENT_OPTION(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" NOT UNIX "ENABLE_SDL2" OFF)
15 17
16option(ENABLE_QT "Enable the Qt frontend" ON) 18option(ENABLE_QT "Enable the Qt frontend" ON)
17option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) 19option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
@@ -274,7 +276,7 @@ if (ENABLE_SDL2)
274 if (YUZU_USE_BUNDLED_SDL2) 276 if (YUZU_USE_BUNDLED_SDL2)
275 # Detect toolchain and platform 277 # Detect toolchain and platform
276 if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64) 278 if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
277 set(SDL2_VER "SDL2-2.0.14") 279 set(SDL2_VER "SDL2-2.0.15-prerelease")
278 else() 280 else()
279 message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.") 281 message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
280 endif() 282 endif()
@@ -292,20 +294,24 @@ if (ENABLE_SDL2)
292 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}") 294 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
293 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") 295 target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
294 else() 296 else()
295 find_package(SDL2 2.0.14 QUIET) 297 if (YUZU_ALLOW_SYSTEM_SDL2)
296 298 find_package(SDL2 2.0.15 QUIET)
297 if (SDL2_FOUND) 299
298 # Some installations don't set SDL2_LIBRARIES 300 if (SDL2_FOUND)
299 if("${SDL2_LIBRARIES}" STREQUAL "") 301 # Some installations don't set SDL2_LIBRARIES
300 message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2") 302 if("${SDL2_LIBRARIES}" STREQUAL "")
301 set(SDL2_LIBRARIES "SDL2::SDL2") 303 message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
304 set(SDL2_LIBRARIES "SDL2::SDL2")
305 endif()
306
307 include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
308 add_library(SDL2 INTERFACE)
309 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
310 else()
311 message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.")
302 endif() 312 endif()
303
304 include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
305 add_library(SDL2 INTERFACE)
306 target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
307 else() 313 else()
308 message(STATUS "SDL2 2.0.14 or newer not found, falling back to externals.") 314 message(STATUS "Using SDL2 from externals.")
309 endif() 315 endif()
310 endif() 316 endif()
311endif() 317endif()
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index e044d9730..fe1c088ca 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -47,7 +47,22 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
47 47
48# SDL2 48# SDL2
49if (NOT SDL2_FOUND AND ENABLE_SDL2) 49if (NOT SDL2_FOUND AND ENABLE_SDL2)
50 # Yuzu itself needs: Events Joystick Haptic Sensor Timers
51 # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
52 set(SDL_UNUSED_SUBSYSTEMS
53 Atomic Audio Render Power Threads
54 File CPUinfo Filesystem Locale)
55 foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
56 string(TOUPPER ${_SUB} _OPT)
57 option(SDL_${_OPT} "" OFF)
58 endforeach()
59
60 set(SDL_STATIC ON)
61 set(SDL_SHARED OFF)
62 option(HIDAPI "" ON)
63
50 add_subdirectory(SDL EXCLUDE_FROM_ALL) 64 add_subdirectory(SDL EXCLUDE_FROM_ALL)
65 add_library(SDL2 ALIAS SDL2-static)
51endif() 66endif()
52 67
53# SoundTouch 68# SoundTouch
diff --git a/externals/SDL b/externals/SDL
Subproject 4cd981609b50ed273d80c635c1ca4c1e5518fb2 Subproject 107db2d89953ee7cc03417d43da1f26bd03aad5
diff --git a/externals/ffmpeg b/externals/ffmpeg
Subproject 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fd Subproject 79e8d17024e6c6328a40fcee191ffd70798a9c6
diff --git a/externals/mbedtls b/externals/mbedtls
Subproject eac2416b8fdb2cb9c867a538100bf95326bad75 Subproject 8c88150ca139e06aa2aae8349df8292a88148ea
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 4ace2cd33..17d1ee86b 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -108,6 +108,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
108 } \ 108 } \
109 } 109 }
110 110
111#define YUZU_NON_COPYABLE(cls) \
112 cls(const cls&) = delete; \
113 cls& operator=(const cls&) = delete
114
115#define YUZU_NON_MOVEABLE(cls) \
116 cls(cls&&) = delete; \
117 cls& operator=(cls&&) = delete
118
111#define R_SUCCEEDED(res) (res.IsSuccess()) 119#define R_SUCCEEDED(res) (res.IsSuccess())
112 120
113/// Evaluates an expression that returns a result, and returns the result if it would fail. 121/// Evaluates an expression that returns a result, and returns the result if it would fail.
@@ -128,4 +136,19 @@ namespace Common {
128 return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24; 136 return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
129} 137}
130 138
139// std::size() does not support zero-size C arrays. We're fixing that.
140template <class C>
141constexpr auto Size(const C& c) -> decltype(c.size()) {
142 return std::size(c);
143}
144
145template <class C>
146constexpr std::size_t Size(const C& c) {
147 if constexpr (sizeof(C) == 0) {
148 return 0;
149 } else {
150 return std::size(c);
151 }
152}
153
131} // namespace Common 154} // namespace Common
diff --git a/src/common/intrusive_red_black_tree.h b/src/common/intrusive_red_black_tree.h
index c0bbcd457..1f696fe80 100644
--- a/src/common/intrusive_red_black_tree.h
+++ b/src/common/intrusive_red_black_tree.h
@@ -509,7 +509,6 @@ private:
509 509
510private: 510private:
511 static constexpr TypedStorage<Derived> DerivedStorage = {}; 511 static constexpr TypedStorage<Derived> DerivedStorage = {};
512 static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage));
513}; 512};
514 513
515template <auto T, class Derived = impl::GetParentType<T>> 514template <auto T, class Derived = impl::GetParentType<T>>
diff --git a/src/common/parent_of_member.h b/src/common/parent_of_member.h
index d9a14529d..e0f8ab5c8 100644
--- a/src/common/parent_of_member.h
+++ b/src/common/parent_of_member.h
@@ -133,27 +133,27 @@ template <auto MemberPtr>
133using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member; 133using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
134 134
135template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> 135template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
136static inline std::ptrdiff_t OffsetOf = [] { 136constexpr std::ptrdiff_t OffsetOf() {
137 using DeducedParentType = GetParentType<MemberPtr>; 137 using DeducedParentType = GetParentType<MemberPtr>;
138 using MemberType = GetMemberType<MemberPtr>; 138 using MemberType = GetMemberType<MemberPtr>;
139 static_assert(std::is_base_of<DeducedParentType, RealParentType>::value || 139 static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
140 std::is_same<RealParentType, DeducedParentType>::value); 140 std::is_same<RealParentType, DeducedParentType>::value);
141 141
142 return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr); 142 return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
143}(); 143};
144 144
145} // namespace impl 145} // namespace impl
146 146
147template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> 147template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
148constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) { 148constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
149 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; 149 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
150 return *static_cast<RealParentType*>( 150 return *static_cast<RealParentType*>(
151 static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset)); 151 static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
152} 152}
153 153
154template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> 154template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
155constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) { 155constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
156 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; 156 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
157 return *static_cast<const RealParentType*>(static_cast<const void*>( 157 return *static_cast<const RealParentType*>(static_cast<const void*>(
158 static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset)); 158 static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
159} 159}
diff --git a/src/common/tree.h b/src/common/tree.h
index 3da49e422..9d2d0df4e 100644
--- a/src/common/tree.h
+++ b/src/common/tree.h
@@ -322,7 +322,7 @@ void RB_INSERT_COLOR(RBHead<Node>* head, Node* elm) {
322template <typename Node> 322template <typename Node>
323void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) { 323void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) {
324 Node* tmp; 324 Node* tmp;
325 while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root()) { 325 while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root() && parent != nullptr) {
326 if (RB_LEFT(parent) == elm) { 326 if (RB_LEFT(parent) == elm) {
327 tmp = RB_RIGHT(parent); 327 tmp = RB_RIGHT(parent);
328 if (RB_IS_RED(tmp)) { 328 if (RB_IS_RED(tmp)) {
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c28abc24c..efb851f5a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -144,31 +144,40 @@ add_library(core STATIC
144 hle/kernel/board/nintendo/nx/k_system_control.cpp 144 hle/kernel/board/nintendo/nx/k_system_control.cpp
145 hle/kernel/board/nintendo/nx/k_system_control.h 145 hle/kernel/board/nintendo/nx/k_system_control.h
146 hle/kernel/board/nintendo/nx/secure_monitor.h 146 hle/kernel/board/nintendo/nx/secure_monitor.h
147 hle/kernel/client_port.cpp
148 hle/kernel/client_port.h
149 hle/kernel/client_session.cpp
150 hle/kernel/client_session.h
151 hle/kernel/code_set.cpp 147 hle/kernel/code_set.cpp
152 hle/kernel/code_set.h 148 hle/kernel/code_set.h
153 hle/kernel/svc_results.h 149 hle/kernel/svc_results.h
154 hle/kernel/global_scheduler_context.cpp 150 hle/kernel/global_scheduler_context.cpp
155 hle/kernel/global_scheduler_context.h 151 hle/kernel/global_scheduler_context.h
156 hle/kernel/handle_table.cpp
157 hle/kernel/handle_table.h
158 hle/kernel/hle_ipc.cpp 152 hle/kernel/hle_ipc.cpp
159 hle/kernel/hle_ipc.h 153 hle/kernel/hle_ipc.h
154 hle/kernel/init/init_slab_setup.cpp
155 hle/kernel/init/init_slab_setup.h
160 hle/kernel/k_address_arbiter.cpp 156 hle/kernel/k_address_arbiter.cpp
161 hle/kernel/k_address_arbiter.h 157 hle/kernel/k_address_arbiter.h
162 hle/kernel/k_address_space_info.cpp 158 hle/kernel/k_address_space_info.cpp
163 hle/kernel/k_address_space_info.h 159 hle/kernel/k_address_space_info.h
160 hle/kernel/k_auto_object.cpp
161 hle/kernel/k_auto_object.h
162 hle/kernel/k_auto_object_container.cpp
163 hle/kernel/k_auto_object_container.h
164 hle/kernel/k_affinity_mask.h 164 hle/kernel/k_affinity_mask.h
165 hle/kernel/k_class_token.cpp
166 hle/kernel/k_class_token.h
167 hle/kernel/k_client_port.cpp
168 hle/kernel/k_client_port.h
169 hle/kernel/k_client_session.cpp
170 hle/kernel/k_client_session.h
165 hle/kernel/k_condition_variable.cpp 171 hle/kernel/k_condition_variable.cpp
166 hle/kernel/k_condition_variable.h 172 hle/kernel/k_condition_variable.h
167 hle/kernel/k_event.cpp 173 hle/kernel/k_event.cpp
168 hle/kernel/k_event.h 174 hle/kernel/k_event.h
175 hle/kernel/k_handle_table.cpp
176 hle/kernel/k_handle_table.h
169 hle/kernel/k_light_condition_variable.h 177 hle/kernel/k_light_condition_variable.h
170 hle/kernel/k_light_lock.cpp 178 hle/kernel/k_light_lock.cpp
171 hle/kernel/k_light_lock.h 179 hle/kernel/k_light_lock.h
180 hle/kernel/k_linked_list.h
172 hle/kernel/k_memory_block.h 181 hle/kernel/k_memory_block.h
173 hle/kernel/k_memory_block_manager.cpp 182 hle/kernel/k_memory_block_manager.cpp
174 hle/kernel/k_memory_block_manager.h 183 hle/kernel/k_memory_block_manager.h
@@ -185,7 +194,11 @@ add_library(core STATIC
185 hle/kernel/k_page_linked_list.h 194 hle/kernel/k_page_linked_list.h
186 hle/kernel/k_page_table.cpp 195 hle/kernel/k_page_table.cpp
187 hle/kernel/k_page_table.h 196 hle/kernel/k_page_table.h
197 hle/kernel/k_port.cpp
198 hle/kernel/k_port.h
188 hle/kernel/k_priority_queue.h 199 hle/kernel/k_priority_queue.h
200 hle/kernel/k_process.cpp
201 hle/kernel/k_process.h
189 hle/kernel/k_readable_event.cpp 202 hle/kernel/k_readable_event.cpp
190 hle/kernel/k_readable_event.h 203 hle/kernel/k_readable_event.h
191 hle/kernel/k_resource_limit.cpp 204 hle/kernel/k_resource_limit.cpp
@@ -196,6 +209,12 @@ add_library(core STATIC
196 hle/kernel/k_scoped_lock.h 209 hle/kernel/k_scoped_lock.h
197 hle/kernel/k_scoped_resource_reservation.h 210 hle/kernel/k_scoped_resource_reservation.h
198 hle/kernel/k_scoped_scheduler_lock_and_sleep.h 211 hle/kernel/k_scoped_scheduler_lock_and_sleep.h
212 hle/kernel/k_server_port.cpp
213 hle/kernel/k_server_port.h
214 hle/kernel/k_server_session.cpp
215 hle/kernel/k_server_session.h
216 hle/kernel/k_session.cpp
217 hle/kernel/k_session.h
199 hle/kernel/k_shared_memory.cpp 218 hle/kernel/k_shared_memory.cpp
200 hle/kernel/k_shared_memory.h 219 hle/kernel/k_shared_memory.h
201 hle/kernel/k_slab_heap.h 220 hle/kernel/k_slab_heap.h
@@ -208,28 +227,21 @@ add_library(core STATIC
208 hle/kernel/k_thread.h 227 hle/kernel/k_thread.h
209 hle/kernel/k_thread_queue.h 228 hle/kernel/k_thread_queue.h
210 hle/kernel/k_trace.h 229 hle/kernel/k_trace.h
230 hle/kernel/k_transfer_memory.cpp
231 hle/kernel/k_transfer_memory.h
211 hle/kernel/k_writable_event.cpp 232 hle/kernel/k_writable_event.cpp
212 hle/kernel/k_writable_event.h 233 hle/kernel/k_writable_event.h
213 hle/kernel/kernel.cpp 234 hle/kernel/kernel.cpp
214 hle/kernel/kernel.h 235 hle/kernel/kernel.h
215 hle/kernel/memory_types.h 236 hle/kernel/memory_types.h
216 hle/kernel/object.cpp
217 hle/kernel/object.h
218 hle/kernel/physical_core.cpp 237 hle/kernel/physical_core.cpp
219 hle/kernel/physical_core.h 238 hle/kernel/physical_core.h
220 hle/kernel/physical_memory.h 239 hle/kernel/physical_memory.h
221 hle/kernel/process.cpp
222 hle/kernel/process.h
223 hle/kernel/process_capability.cpp 240 hle/kernel/process_capability.cpp
224 hle/kernel/process_capability.h 241 hle/kernel/process_capability.h
225 hle/kernel/server_port.cpp
226 hle/kernel/server_port.h
227 hle/kernel/server_session.cpp
228 hle/kernel/server_session.h
229 hle/kernel/service_thread.cpp 242 hle/kernel/service_thread.cpp
230 hle/kernel/service_thread.h 243 hle/kernel/service_thread.h
231 hle/kernel/session.cpp 244 hle/kernel/slab_helpers.h
232 hle/kernel/session.h
233 hle/kernel/svc.cpp 245 hle/kernel/svc.cpp
234 hle/kernel/svc.h 246 hle/kernel/svc.h
235 hle/kernel/svc_common.h 247 hle/kernel/svc_common.h
@@ -237,8 +249,6 @@ add_library(core STATIC
237 hle/kernel/svc_wrap.h 249 hle/kernel/svc_wrap.h
238 hle/kernel/time_manager.cpp 250 hle/kernel/time_manager.cpp
239 hle/kernel/time_manager.h 251 hle/kernel/time_manager.h
240 hle/kernel/transfer_memory.cpp
241 hle/kernel/transfer_memory.h
242 hle/lock.cpp 252 hle/lock.cpp
243 hle/lock.h 253 hle/lock.h
244 hle/result.h 254 hle/result.h
@@ -641,20 +651,17 @@ endif()
641 651
642if (MSVC) 652if (MSVC)
643 target_compile_options(core PRIVATE 653 target_compile_options(core PRIVATE
644 # 'expression' : signed/unsigned mismatch 654 /we4018 # 'expression' : signed/unsigned mismatch
645 /we4018 655 /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
646 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) 656 /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
647 /we4244 657 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
648 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch 658 /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
649 /we4245 659 /we4305 # 'context' : truncation from 'type1' to 'type2'
650 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 660 /we4456 # Declaration of 'identifier' hides previous local declaration
651 /we4254 661 /we4457 # Declaration of 'identifier' hides function parameter
652 # 'var' : conversion from 'size_t' to 'type', possible loss of data 662 /we4458 # Declaration of 'identifier' hides class member
653 /we4267 663 /we4459 # Declaration of 'identifier' hides global declaration
654 # 'context' : truncation from 'type1' to 'type2' 664 /we4715 # 'function' : not all control paths return a value
655 /we4305
656 # 'function' : not all control paths return a value
657 /we4715
658 ) 665 )
659else() 666else()
660 target_compile_options(core PRIVATE 667 target_compile_options(core PRIVATE
@@ -662,6 +669,7 @@ else()
662 -Werror=ignored-qualifiers 669 -Werror=ignored-qualifiers
663 -Werror=implicit-fallthrough 670 -Werror=implicit-fallthrough
664 -Werror=sign-compare 671 -Werror=sign-compare
672 -Werror=shadow
665 673
666 $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> 674 $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
667 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> 675 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 42a37e84f..ab3266916 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -24,7 +24,7 @@ namespace Core {
24 24
25class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { 25class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
26public: 26public:
27 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent) : parent(parent) {} 27 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) : parent{parent_} {}
28 28
29 u8 MemoryRead8(u32 vaddr) override { 29 u8 MemoryRead8(u32 vaddr) override {
30 return parent.system.Memory().Read8(vaddr); 30 return parent.system.Memory().Read8(vaddr);
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 4ff72abd8..a4d830e48 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -16,8 +16,8 @@
16#include "core/core.h" 16#include "core/core.h"
17#include "core/core_timing.h" 17#include "core/core_timing.h"
18#include "core/hardware_properties.h" 18#include "core/hardware_properties.h"
19#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_scheduler.h" 20#include "core/hle/kernel/k_scheduler.h"
20#include "core/hle/kernel/process.h"
21#include "core/hle/kernel/svc.h" 21#include "core/hle/kernel/svc.h"
22#include "core/memory.h" 22#include "core/memory.h"
23 23
@@ -27,7 +27,7 @@ using Vector = Dynarmic::A64::Vector;
27 27
28class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { 28class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
29public: 29public:
30 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent) : parent(parent) {} 30 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) : parent{parent_} {}
31 31
32 u8 MemoryRead8(u64 vaddr) override { 32 u8 MemoryRead8(u64 vaddr) override {
33 return parent.system.Memory().Read8(vaddr); 33 return parent.system.Memory().Read8(vaddr);
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index dc6f4af3a..8597beddf 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -18,7 +18,7 @@ class DynarmicCP15 final : public Dynarmic::A32::Coprocessor {
18public: 18public:
19 using CoprocReg = Dynarmic::A32::CoprocReg; 19 using CoprocReg = Dynarmic::A32::CoprocReg;
20 20
21 explicit DynarmicCP15(ARM_Dynarmic_32& parent) : parent(parent) {} 21 explicit DynarmicCP15(ARM_Dynarmic_32& parent_) : parent{parent_} {}
22 22
23 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, 23 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd,
24 CoprocReg CRn, CoprocReg CRm, 24 CoprocReg CRn, CoprocReg CRm,
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
index 4e209f6a5..9426a3edf 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
@@ -9,8 +9,8 @@
9 9
10namespace Core { 10namespace Core {
11 11
12DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count) 12DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_)
13 : monitor(core_count), memory{memory} {} 13 : monitor{core_count_}, memory{memory_} {}
14 14
15DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default; 15DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
16 16
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/arm_exclusive_monitor.h
index 964f4a55d..f9f056a59 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/arm_exclusive_monitor.h
@@ -22,7 +22,7 @@ namespace Core {
22 22
23class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 23class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
24public: 24public:
25 explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count); 25 explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_);
26 ~DynarmicExclusiveMonitor() override; 26 ~DynarmicExclusiveMonitor() override;
27 27
28 u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override; 28 u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index d459d6c34..434bf3262 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -27,12 +27,12 @@
27#include "core/file_sys/vfs_concat.h" 27#include "core/file_sys/vfs_concat.h"
28#include "core/file_sys/vfs_real.h" 28#include "core/file_sys/vfs_real.h"
29#include "core/hardware_interrupt_manager.h" 29#include "core/hardware_interrupt_manager.h"
30#include "core/hle/kernel/client_port.h" 30#include "core/hle/kernel/k_client_port.h"
31#include "core/hle/kernel/k_process.h"
31#include "core/hle/kernel/k_scheduler.h" 32#include "core/hle/kernel/k_scheduler.h"
32#include "core/hle/kernel/k_thread.h" 33#include "core/hle/kernel/k_thread.h"
33#include "core/hle/kernel/kernel.h" 34#include "core/hle/kernel/kernel.h"
34#include "core/hle/kernel/physical_core.h" 35#include "core/hle/kernel/physical_core.h"
35#include "core/hle/kernel/process.h"
36#include "core/hle/service/am/applets/applets.h" 36#include "core/hle/service/am/applets/applets.h"
37#include "core/hle/service/apm/controller.h" 37#include "core/hle/service/apm/controller.h"
38#include "core/hle/service/filesystem/filesystem.h" 38#include "core/hle/service/filesystem/filesystem.h"
@@ -166,9 +166,9 @@ struct System::Impl {
166 cpu_manager.SetAsyncGpu(is_async_gpu); 166 cpu_manager.SetAsyncGpu(is_async_gpu);
167 core_timing.SetMulticore(is_multicore); 167 core_timing.SetMulticore(is_multicore);
168 168
169 core_timing.Initialize([&system]() { system.RegisterHostThread(); });
170 kernel.Initialize(); 169 kernel.Initialize();
171 cpu_manager.Initialize(); 170 cpu_manager.Initialize();
171 core_timing.Initialize([&system]() { system.RegisterHostThread(); });
172 172
173 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( 173 const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
174 std::chrono::system_clock::now().time_since_epoch()); 174 std::chrono::system_clock::now().time_since_epoch());
@@ -233,8 +233,11 @@ struct System::Impl {
233 } 233 }
234 234
235 telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); 235 telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
236 auto main_process = 236 auto main_process = Kernel::KProcess::Create(system.Kernel());
237 Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); 237 ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
238 Kernel::KProcess::ProcessType::Userland)
239 .IsSuccess());
240 main_process->Open();
238 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); 241 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
239 if (load_result != Loader::ResultStatus::Success) { 242 if (load_result != Loader::ResultStatus::Success) {
240 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); 243 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
@@ -244,7 +247,7 @@ struct System::Impl {
244 static_cast<u32>(load_result)); 247 static_cast<u32>(load_result));
245 } 248 }
246 AddGlueRegistrationForProcess(*app_loader, *main_process); 249 AddGlueRegistrationForProcess(*app_loader, *main_process);
247 kernel.MakeCurrentProcess(main_process.get()); 250 kernel.MakeCurrentProcess(main_process);
248 kernel.InitializeCores(); 251 kernel.InitializeCores();
249 252
250 // Initialize cheat engine 253 // Initialize cheat engine
@@ -311,6 +314,7 @@ struct System::Impl {
311 gpu_core.reset(); 314 gpu_core.reset();
312 perf_stats.reset(); 315 perf_stats.reset();
313 kernel.Shutdown(); 316 kernel.Shutdown();
317 memory.Reset();
314 applet_manager.ClearAll(); 318 applet_manager.ClearAll();
315 319
316 LOG_DEBUG(Core, "Shutdown OK"); 320 LOG_DEBUG(Core, "Shutdown OK");
@@ -322,7 +326,7 @@ struct System::Impl {
322 return app_loader->ReadTitle(out); 326 return app_loader->ReadTitle(out);
323 } 327 }
324 328
325 void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::Process& process) { 329 void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
326 std::vector<u8> nacp_data; 330 std::vector<u8> nacp_data;
327 FileSys::NACP nacp; 331 FileSys::NACP nacp;
328 if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) { 332 if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
@@ -513,7 +517,7 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
513 return impl->kernel.GlobalSchedulerContext(); 517 return impl->kernel.GlobalSchedulerContext();
514} 518}
515 519
516Kernel::Process* System::CurrentProcess() { 520Kernel::KProcess* System::CurrentProcess() {
517 return impl->kernel.CurrentProcess(); 521 return impl->kernel.CurrentProcess();
518} 522}
519 523
@@ -525,7 +529,7 @@ const Core::DeviceMemory& System::DeviceMemory() const {
525 return *impl->device_memory; 529 return *impl->device_memory;
526} 530}
527 531
528const Kernel::Process* System::CurrentProcess() const { 532const Kernel::KProcess* System::CurrentProcess() const {
529 return impl->kernel.CurrentProcess(); 533 return impl->kernel.CurrentProcess();
530} 534}
531 535
diff --git a/src/core/core.h b/src/core/core.h
index f1068d23f..8b93ba998 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -12,7 +12,6 @@
12 12
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/file_sys/vfs_types.h" 14#include "core/file_sys/vfs_types.h"
15#include "core/hle/kernel/object.h"
16 15
17namespace Core::Frontend { 16namespace Core::Frontend {
18class EmuWindow; 17class EmuWindow;
@@ -29,7 +28,7 @@ namespace Kernel {
29class GlobalSchedulerContext; 28class GlobalSchedulerContext;
30class KernelCore; 29class KernelCore;
31class PhysicalCore; 30class PhysicalCore;
32class Process; 31class KProcess;
33class KScheduler; 32class KScheduler;
34} // namespace Kernel 33} // namespace Kernel
35 34
@@ -264,10 +263,10 @@ public:
264 [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const; 263 [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
265 264
266 /// Provides a pointer to the current process 265 /// Provides a pointer to the current process
267 [[nodiscard]] Kernel::Process* CurrentProcess(); 266 [[nodiscard]] Kernel::KProcess* CurrentProcess();
268 267
269 /// Provides a constant pointer to the current process. 268 /// Provides a constant pointer to the current process.
270 [[nodiscard]] const Kernel::Process* CurrentProcess() const; 269 [[nodiscard]] const Kernel::KProcess* CurrentProcess() const;
271 270
272 /// Provides a reference to the core timing instance. 271 /// Provides a reference to the core timing instance.
273 [[nodiscard]] Timing::CoreTiming& CoreTiming(); 272 [[nodiscard]] Timing::CoreTiming& CoreTiming();
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index bdb374792..7e195346b 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -18,7 +18,7 @@
18 18
19namespace Core { 19namespace Core {
20 20
21CpuManager::CpuManager(System& system) : system{system} {} 21CpuManager::CpuManager(System& system_) : system{system_} {}
22CpuManager::~CpuManager() = default; 22CpuManager::~CpuManager() = default;
23 23
24void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) { 24void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) {
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index 9817017c0..140263b09 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -25,7 +25,7 @@ class System;
25 25
26class CpuManager { 26class CpuManager {
27public: 27public:
28 explicit CpuManager(System& system); 28 explicit CpuManager(System& system_);
29 CpuManager(const CpuManager&) = delete; 29 CpuManager(const CpuManager&) = delete;
30 CpuManager(CpuManager&&) = delete; 30 CpuManager(CpuManager&&) = delete;
31 31
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp
index 5c84bb0a4..1231da8e3 100644
--- a/src/core/crypto/ctr_encryption_layer.cpp
+++ b/src/core/crypto/ctr_encryption_layer.cpp
@@ -10,8 +10,8 @@
10namespace Core::Crypto { 10namespace Core::Crypto {
11 11
12CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, 12CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
13 std::size_t base_offset) 13 std::size_t base_offset_)
14 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {} 14 : EncryptionLayer(std::move(base_)), base_offset(base_offset_), cipher(key_, Mode::CTR) {}
15 15
16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { 16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
17 if (length == 0) 17 if (length == 0)
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
index a2429f001..f86f01b6f 100644
--- a/src/core/crypto/ctr_encryption_layer.h
+++ b/src/core/crypto/ctr_encryption_layer.h
@@ -17,7 +17,7 @@ class CTREncryptionLayer : public EncryptionLayer {
17public: 17public:
18 using IVData = std::array<u8, 16>; 18 using IVData = std::array<u8, 16>;
19 19
20 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset); 20 CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, std::size_t base_offset_);
21 21
22 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 22 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
23 23
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 070ed439e..a4b739c63 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -458,7 +458,7 @@ static std::array<u8, size> operator^(const std::array<u8, size>& lhs,
458 const std::array<u8, size>& rhs) { 458 const std::array<u8, size>& rhs) {
459 std::array<u8, size> out; 459 std::array<u8, size> out;
460 std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(), 460 std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(),
461 [](u8 lhs, u8 rhs) { return u8(lhs ^ rhs); }); 461 [](u8 lhs_elem, u8 rhs_elem) { return u8(lhs_elem ^ rhs_elem); });
462 return out; 462 return out;
463} 463}
464 464
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 3596541b2..f5cb4aa8c 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -39,10 +39,10 @@ CNMT::CNMT(VirtualFile file) {
39 } 39 }
40} 40}
41 41
42CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, 42CNMT::CNMT(CNMTHeader header_, OptionalHeader opt_header_,
43 std::vector<MetaRecord> meta_records) 43 std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_)
44 : header(std::move(header)), opt_header(std::move(opt_header)), 44 : header(std::move(header_)), opt_header(std::move(opt_header_)),
45 content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} 45 content_records(std::move(content_records_)), meta_records(std::move(meta_records_)) {}
46 46
47CNMT::~CNMT() = default; 47CNMT::~CNMT() = default;
48 48
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 53535e5f5..ce1138a17 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -87,8 +87,8 @@ static_assert(sizeof(CNMTHeader) == 0x20, "CNMTHeader has incorrect size.");
87class CNMT { 87class CNMT {
88public: 88public:
89 explicit CNMT(VirtualFile file); 89 explicit CNMT(VirtualFile file);
90 CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, 90 CNMT(CNMTHeader header_, OptionalHeader opt_header_,
91 std::vector<MetaRecord> meta_records); 91 std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_);
92 ~CNMT(); 92 ~CNMT();
93 93
94 u64 GetTitleID() const; 94 u64 GetTitleID() const;
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index de6ab721d..aa7f3072f 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -13,7 +13,7 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/romfs_factory.h" 15#include "core/file_sys/romfs_factory.h"
16#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/k_process.h"
17#include "core/hle/service/filesystem/filesystem.h" 17#include "core/hle/service/filesystem/filesystem.h"
18#include "core/loader/loader.h" 18#include "core/loader/loader.h"
19 19
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index fa68af3a8..f973d1d21 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -9,7 +9,7 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/file_sys/savedata_factory.h" 10#include "core/file_sys/savedata_factory.h"
11#include "core/file_sys/vfs.h" 11#include "core/file_sys/vfs.h"
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/k_process.h"
13 13
14namespace FileSys { 14namespace FileSys {
15 15
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 80e560970..d51d469e3 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -20,8 +20,8 @@
20 20
21namespace FileSys { 21namespace FileSys {
22 22
23NSP::NSP(VirtualFile file_, std::size_t program_index) 23NSP::NSP(VirtualFile file_, std::size_t program_index_)
24 : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success}, 24 : file(std::move(file_)), program_index(program_index_), status{Loader::ResultStatus::Success},
25 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { 25 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
26 if (pfs->GetStatus() != Loader::ResultStatus::Success) { 26 if (pfs->GetStatus() != Loader::ResultStatus::Success) {
27 status = pfs->GetStatus(); 27 status = pfs->GetStatus();
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 54581a6f3..ecb3b6f15 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
27 27
28class NSP : public ReadOnlyVfsDirectory { 28class NSP : public ReadOnlyVfsDirectory {
29public: 29public:
30 explicit NSP(VirtualFile file, std::size_t program_index = 0); 30 explicit NSP(VirtualFile file_, std::size_t program_index_ = 0);
31 ~NSP() override; 31 ~NSP() override;
32 32
33 Loader::ResultStatus GetStatus() const; 33 Loader::ResultStatus GetStatus() const;
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 619081502..5f8c09124 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -23,8 +23,8 @@ static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFil
23 return map.begin()->first == 0; 23 return map.begin()->first == 0;
24} 24}
25 25
26ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) 26ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name_)
27 : name(std::move(name)) { 27 : name(std::move(name_)) {
28 std::size_t next_offset = 0; 28 std::size_t next_offset = 0;
29 for (const auto& file : files_) { 29 for (const auto& file : files_) {
30 files.emplace(next_offset, file); 30 files.emplace(next_offset, file);
@@ -32,8 +32,8 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
32 } 32 }
33} 33}
34 34
35ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name) 35ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name_)
36 : files(std::move(files_)), name(std::move(name)) { 36 : files(std::move(files_)), name(std::move(name_)) {
37 ASSERT(VerifyConcatenationMapContinuity(files)); 37 ASSERT(VerifyConcatenationMapContinuity(files));
38} 38}
39 39
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 3397d32cd..cd32960a5 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -14,8 +14,8 @@ namespace FileSys {
14// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently 14// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
15// read-only. 15// read-only.
16class ConcatenatedVfsFile : public VfsFile { 16class ConcatenatedVfsFile : public VfsFile {
17 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); 17 explicit ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name_);
18 ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name); 18 explicit ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name_);
19 19
20public: 20public:
21 ~ConcatenatedVfsFile() override; 21 ~ConcatenatedVfsFile() override;
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 192740058..e093c4db2 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -8,8 +8,8 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) 11LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_)
12 : dirs(std::move(dirs)), name(std::move(name)) {} 12 : dirs(std::move(dirs_)), name(std::move(name_)) {}
13 13
14LayeredVfsDirectory::~LayeredVfsDirectory() = default; 14LayeredVfsDirectory::~LayeredVfsDirectory() = default;
15 15
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h
index cb4b32e91..cd6baf28c 100644
--- a/src/core/file_sys/vfs_layered.h
+++ b/src/core/file_sys/vfs_layered.h
@@ -13,7 +13,7 @@ namespace FileSys {
13// one and falling back to the one after. The highest priority directory (overwrites all others) 13// one and falling back to the one after. The highest priority directory (overwrites all others)
14// should be element 0 in the dirs vector. 14// should be element 0 in the dirs vector.
15class LayeredVfsDirectory : public VfsDirectory { 15class LayeredVfsDirectory : public VfsDirectory {
16 LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); 16 explicit LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_);
17 17
18public: 18public:
19 ~LayeredVfsDirectory() override; 19 ~LayeredVfsDirectory() override;
diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp
index 429d7bc8b..618eb658a 100644
--- a/src/core/file_sys/vfs_libzip.cpp
+++ b/src/core/file_sys/vfs_libzip.cpp
@@ -3,7 +3,16 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#endif
6#include <zip.h> 11#include <zip.h>
12#ifdef __GNUC__
13#pragma GCC diagnostic pop
14#endif
15
7#include "common/logging/backend.h" 16#include "common/logging/backend.h"
8#include "core/file_sys/vfs.h" 17#include "core/file_sys/vfs.h"
9#include "core/file_sys/vfs_libzip.h" 18#include "core/file_sys/vfs_libzip.h"
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index c840b24b9..f5b66cf71 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -14,9 +14,9 @@ namespace FileSys {
14 14
15class StaticVfsFile : public VfsFile { 15class StaticVfsFile : public VfsFile {
16public: 16public:
17 explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "", 17 explicit StaticVfsFile(u8 value_, std::size_t size_ = 0, std::string name_ = "",
18 VirtualDir parent = nullptr) 18 VirtualDir parent_ = nullptr)
19 : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {} 19 : value{value_}, size{size_}, name{std::move(name_)}, parent{std::move(parent_)} {}
20 20
21 std::string GetName() const override { 21 std::string GetName() const override {
22 return name; 22 return name;
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 1a3f06227..f64b88639 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -7,8 +7,8 @@
7#include "core/file_sys/vfs_vector.h" 7#include "core/file_sys/vfs_vector.h"
8 8
9namespace FileSys { 9namespace FileSys {
10VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) 10VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name_, VirtualDir parent_)
11 : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {} 11 : data(std::move(initial_data)), parent(std::move(parent_)), name(std::move(name_)) {}
12 12
13VectorVfsFile::~VectorVfsFile() = default; 13VectorVfsFile::~VectorVfsFile() = default;
14 14
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index c10c527b6..73f180070 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -75,8 +75,8 @@ std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& da
75// An implementation of VfsFile that is backed by a vector optionally supplied upon construction 75// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
76class VectorVfsFile : public VfsFile { 76class VectorVfsFile : public VfsFile {
77public: 77public:
78 explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name = "", 78 explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name_ = "",
79 VirtualDir parent = nullptr); 79 VirtualDir parent_ = nullptr);
80 ~VectorVfsFile() override; 80 ~VectorVfsFile() override;
81 81
82 std::string GetName() const override; 82 std::string GetName() const override;
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index cff49899a..e11ec0b0b 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -26,7 +26,7 @@ public:
26private: 26private:
27 class Device : public Input::TouchDevice { 27 class Device : public Input::TouchDevice {
28 public: 28 public:
29 explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} 29 explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {}
30 Input::TouchStatus GetStatus() const override { 30 Input::TouchStatus GetStatus() const override {
31 if (auto state = touch_state.lock()) { 31 if (auto state = touch_state.lock()) {
32 std::lock_guard guard{state->mutex}; 32 std::lock_guard guard{state->mutex};
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index 55b1716e4..602e12606 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -32,7 +32,8 @@ enum class CommandType : u32 {
32 Control = 5, 32 Control = 5,
33 RequestWithContext = 6, 33 RequestWithContext = 6,
34 ControlWithContext = 7, 34 ControlWithContext = 7,
35 Unspecified, 35 TIPC_Close = 15,
36 TIPC_CommandRegion = 16, // Start of TIPC commands, this is an offset.
36}; 37};
37 38
38struct CommandHeader { 39struct CommandHeader {
@@ -57,6 +58,20 @@ struct CommandHeader {
57 BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; 58 BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags;
58 BitField<31, 1, u32> enable_handle_descriptor; 59 BitField<31, 1, u32> enable_handle_descriptor;
59 }; 60 };
61
62 bool IsTipc() const {
63 return type.Value() >= CommandType::TIPC_CommandRegion;
64 }
65
66 bool IsCloseCommand() const {
67 switch (type.Value()) {
68 case CommandType::Close:
69 case CommandType::TIPC_Close:
70 return true;
71 default:
72 return false;
73 }
74 }
60}; 75};
61static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); 76static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect");
62 77
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 56cc911d1..497f35d23 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -13,12 +13,11 @@
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "core/hle/ipc.h" 15#include "core/hle/ipc.h"
16#include "core/hle/kernel/client_port.h"
17#include "core/hle/kernel/client_session.h"
18#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
19#include "core/hle/kernel/object.h" 17#include "core/hle/kernel/k_client_port.h"
20#include "core/hle/kernel/server_session.h" 18#include "core/hle/kernel/k_process.h"
21#include "core/hle/kernel/session.h" 19#include "core/hle/kernel/k_resource_limit.h"
20#include "core/hle/kernel/k_session.h"
22#include "core/hle/result.h" 21#include "core/hle/result.h"
23 22
24namespace IPC { 23namespace IPC {
@@ -29,19 +28,19 @@ class RequestHelperBase {
29protected: 28protected:
30 Kernel::HLERequestContext* context = nullptr; 29 Kernel::HLERequestContext* context = nullptr;
31 u32* cmdbuf; 30 u32* cmdbuf;
32 ptrdiff_t index = 0; 31 u32 index = 0;
33 32
34public: 33public:
35 explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {} 34 explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {}
36 35
37 explicit RequestHelperBase(Kernel::HLERequestContext& context) 36 explicit RequestHelperBase(Kernel::HLERequestContext& ctx)
38 : context(&context), cmdbuf(context.CommandBuffer()) {} 37 : context(&ctx), cmdbuf(ctx.CommandBuffer()) {}
39 38
40 void Skip(u32 size_in_words, bool set_to_null) { 39 void Skip(u32 size_in_words, bool set_to_null) {
41 if (set_to_null) { 40 if (set_to_null) {
42 memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); 41 memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
43 } 42 }
44 index += static_cast<ptrdiff_t>(size_in_words); 43 index += size_in_words;
45 } 44 }
46 45
47 /** 46 /**
@@ -54,11 +53,11 @@ public:
54 } 53 }
55 54
56 u32 GetCurrentOffset() const { 55 u32 GetCurrentOffset() const {
57 return static_cast<u32>(index); 56 return index;
58 } 57 }
59 58
60 void SetCurrentOffset(u32 offset) { 59 void SetCurrentOffset(u32 offset) {
61 index = static_cast<ptrdiff_t>(offset); 60 index = offset;
62 } 61 }
63}; 62};
64 63
@@ -72,64 +71,79 @@ public:
72 AlwaysMoveHandles = 1, 71 AlwaysMoveHandles = 1,
73 }; 72 };
74 73
75 explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, 74 explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size_,
76 u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, 75 u32 num_handles_to_copy_ = 0, u32 num_objects_to_move_ = 0,
77 Flags flags = Flags::None) 76 Flags flags = Flags::None)
78 : RequestHelperBase(context), normal_params_size(normal_params_size), 77 : RequestHelperBase(ctx), normal_params_size(normal_params_size_),
79 num_handles_to_copy(num_handles_to_copy), 78 num_handles_to_copy(num_handles_to_copy_),
80 num_objects_to_move(num_objects_to_move), kernel{context.kernel} { 79 num_objects_to_move(num_objects_to_move_), kernel{ctx.kernel} {
81 80
82 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); 81 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
83 82
84 context.ClearIncomingObjects(); 83 ctx.ClearIncomingObjects();
85 84
86 IPC::CommandHeader header{}; 85 IPC::CommandHeader header{};
87 86
88 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory 87 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
89 // padding. 88 // padding.
90 u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; 89 u32 raw_data_size = ctx.IsTipc()
90 ? normal_params_size - 1
91 : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
91 92
92 u32 num_handles_to_move{}; 93 u32 num_handles_to_move{};
93 u32 num_domain_objects{}; 94 u32 num_domain_objects{};
94 const bool always_move_handles{ 95 const bool always_move_handles{
95 (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0}; 96 (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
96 if (!context.Session()->IsDomain() || always_move_handles) { 97 if (!ctx.Session()->IsDomain() || always_move_handles) {
97 num_handles_to_move = num_objects_to_move; 98 num_handles_to_move = num_objects_to_move;
98 } else { 99 } else {
99 num_domain_objects = num_objects_to_move; 100 num_domain_objects = num_objects_to_move;
100 } 101 }
101 102
102 if (context.Session()->IsDomain()) { 103 if (ctx.Session()->IsDomain()) {
103 raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; 104 raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects);
104 } 105 }
105 106
107 if (ctx.IsTipc()) {
108 header.type.Assign(ctx.GetCommandType());
109 }
110
111 ctx.data_size = static_cast<u32>(raw_data_size);
106 header.data_size.Assign(static_cast<u32>(raw_data_size)); 112 header.data_size.Assign(static_cast<u32>(raw_data_size));
107 if (num_handles_to_copy || num_handles_to_move) { 113 if (num_handles_to_copy != 0 || num_handles_to_move != 0) {
108 header.enable_handle_descriptor.Assign(1); 114 header.enable_handle_descriptor.Assign(1);
109 } 115 }
110 PushRaw(header); 116 PushRaw(header);
111 117
112 if (header.enable_handle_descriptor) { 118 if (header.enable_handle_descriptor) {
113 IPC::HandleDescriptorHeader handle_descriptor_header{}; 119 IPC::HandleDescriptorHeader handle_descriptor_header{};
114 handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy); 120 handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy_);
115 handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move); 121 handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move);
116 PushRaw(handle_descriptor_header); 122 PushRaw(handle_descriptor_header);
123
124 ctx.handles_offset = index;
125
117 Skip(num_handles_to_copy + num_handles_to_move, true); 126 Skip(num_handles_to_copy + num_handles_to_move, true);
118 } 127 }
119 128
120 AlignWithPadding(); 129 if (!ctx.IsTipc()) {
130 AlignWithPadding();
121 131
122 if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) { 132 if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) {
123 IPC::DomainMessageHeader domain_header{}; 133 IPC::DomainMessageHeader domain_header{};
124 domain_header.num_objects = num_domain_objects; 134 domain_header.num_objects = num_domain_objects;
125 PushRaw(domain_header); 135 PushRaw(domain_header);
136 }
137
138 IPC::DataPayloadHeader data_payload_header{};
139 data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
140 PushRaw(data_payload_header);
126 } 141 }
127 142
128 IPC::DataPayloadHeader data_payload_header{}; 143 data_payload_index = index;
129 data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
130 PushRaw(data_payload_header);
131 144
132 datapayload_index = index; 145 ctx.data_payload_offset = index;
146 ctx.domain_offset = index + raw_data_size / 4;
133 } 147 }
134 148
135 template <class T> 149 template <class T>
@@ -137,9 +151,14 @@ public:
137 if (context->Session()->IsDomain()) { 151 if (context->Session()->IsDomain()) {
138 context->AddDomainObject(std::move(iface)); 152 context->AddDomainObject(std::move(iface));
139 } else { 153 } else {
140 auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName()); 154 // kernel.CurrentProcess()->GetResourceLimit()->Reserve(
141 context->AddMoveObject(std::move(client)); 155 // Kernel::LimitableResource::Sessions, 1);
142 iface->ClientConnected(std::move(server)); 156
157 auto* session = Kernel::KSession::Create(kernel);
158 session->Initialize(nullptr, iface->GetServiceName());
159
160 context->AddMoveObject(&session->GetClientSession());
161 iface->ClientConnected(&session->GetServerSession());
143 } 162 }
144 } 163 }
145 164
@@ -153,7 +172,7 @@ public:
153 const std::size_t num_move_objects = context->NumMoveObjects(); 172 const std::size_t num_move_objects = context->NumMoveObjects();
154 ASSERT_MSG(!num_domain_objects || !num_move_objects, 173 ASSERT_MSG(!num_domain_objects || !num_move_objects,
155 "cannot move normal handles and domain objects"); 174 "cannot move normal handles and domain objects");
156 ASSERT_MSG((index - datapayload_index) == normal_params_size, 175 ASSERT_MSG((index - data_payload_index) == normal_params_size,
157 "normal_params_size value is incorrect"); 176 "normal_params_size value is incorrect");
158 ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, 177 ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move,
159 "num_objects_to_move value is incorrect"); 178 "num_objects_to_move value is incorrect");
@@ -215,23 +234,29 @@ public:
215 void PushRaw(const T& value); 234 void PushRaw(const T& value);
216 235
217 template <typename... O> 236 template <typename... O>
218 void PushMoveObjects(std::shared_ptr<O>... pointers); 237 void PushMoveObjects(O*... pointers);
238
239 template <typename... O>
240 void PushMoveObjects(O&... pointers);
241
242 template <typename... O>
243 void PushCopyObjects(O*... pointers);
219 244
220 template <typename... O> 245 template <typename... O>
221 void PushCopyObjects(std::shared_ptr<O>... pointers); 246 void PushCopyObjects(O&... pointers);
222 247
223private: 248private:
224 u32 normal_params_size{}; 249 u32 normal_params_size{};
225 u32 num_handles_to_copy{}; 250 u32 num_handles_to_copy{};
226 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent 251 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
227 std::ptrdiff_t datapayload_index{}; 252 u32 data_payload_index{};
228 Kernel::KernelCore& kernel; 253 Kernel::KernelCore& kernel;
229}; 254};
230 255
231/// Push /// 256/// Push ///
232 257
233inline void ResponseBuilder::PushImpl(s32 value) { 258inline void ResponseBuilder::PushImpl(s32 value) {
234 cmdbuf[index++] = static_cast<u32>(value); 259 cmdbuf[index++] = value;
235} 260}
236 261
237inline void ResponseBuilder::PushImpl(u32 value) { 262inline void ResponseBuilder::PushImpl(u32 value) {
@@ -301,18 +326,34 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value
301} 326}
302 327
303template <typename... O> 328template <typename... O>
304inline void ResponseBuilder::PushCopyObjects(std::shared_ptr<O>... pointers) { 329inline void ResponseBuilder::PushCopyObjects(O*... pointers) {
305 auto objects = {pointers...}; 330 auto objects = {pointers...};
306 for (auto& object : objects) { 331 for (auto& object : objects) {
307 context->AddCopyObject(std::move(object)); 332 context->AddCopyObject(object);
333 }
334}
335
336template <typename... O>
337inline void ResponseBuilder::PushCopyObjects(O&... pointers) {
338 auto objects = {&pointers...};
339 for (auto& object : objects) {
340 context->AddCopyObject(object);
308 } 341 }
309} 342}
310 343
311template <typename... O> 344template <typename... O>
312inline void ResponseBuilder::PushMoveObjects(std::shared_ptr<O>... pointers) { 345inline void ResponseBuilder::PushMoveObjects(O*... pointers) {
313 auto objects = {pointers...}; 346 auto objects = {pointers...};
314 for (auto& object : objects) { 347 for (auto& object : objects) {
315 context->AddMoveObject(std::move(object)); 348 context->AddMoveObject(object);
349 }
350}
351
352template <typename... O>
353inline void ResponseBuilder::PushMoveObjects(O&... pointers) {
354 auto objects = {&pointers...};
355 for (auto& object : objects) {
356 context->AddMoveObject(object);
316 } 357 }
317} 358}
318 359
@@ -320,9 +361,9 @@ class RequestParser : public RequestHelperBase {
320public: 361public:
321 explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {} 362 explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
322 363
323 explicit RequestParser(Kernel::HLERequestContext& context) : RequestHelperBase(context) { 364 explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) {
324 ASSERT_MSG(context.GetDataPayloadOffset(), "context is incomplete"); 365 ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
325 Skip(context.GetDataPayloadOffset(), false); 366 Skip(ctx.GetDataPayloadOffset(), false);
326 // Skip the u64 command id, it's already stored in the context 367 // Skip the u64 command id, it's already stored in the context
327 static constexpr u32 CommandIdSize = 2; 368 static constexpr u32 CommandIdSize = 2;
328 Skip(CommandIdSize, false); 369 Skip(CommandIdSize, false);
@@ -359,12 +400,6 @@ public:
359 template <typename T> 400 template <typename T>
360 T PopRaw(); 401 T PopRaw();
361 402
362 template <typename T>
363 std::shared_ptr<T> GetMoveObject(std::size_t index);
364
365 template <typename T>
366 std::shared_ptr<T> GetCopyObject(std::size_t index);
367
368 template <class T> 403 template <class T>
369 std::shared_ptr<T> PopIpcInterface() { 404 std::shared_ptr<T> PopIpcInterface() {
370 ASSERT(context->Session()->IsDomain()); 405 ASSERT(context->Session()->IsDomain());
@@ -469,14 +504,4 @@ void RequestParser::Pop(First& first_value, Other&... other_values) {
469 Pop(other_values...); 504 Pop(other_values...);
470} 505}
471 506
472template <typename T>
473std::shared_ptr<T> RequestParser::GetMoveObject(std::size_t index) {
474 return context->GetMoveObject<T>(index);
475}
476
477template <typename T>
478std::shared_ptr<T> RequestParser::GetCopyObject(std::size_t index) {
479 return context->GetCopyObject<T>(index);
480}
481
482} // namespace IPC 507} // namespace IPC
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
deleted file mode 100644
index 0b6957e31..000000000
--- a/src/core/hle/kernel/client_port.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/client_port.h"
6#include "core/hle/kernel/client_session.h"
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/server_port.h"
10#include "core/hle/kernel/session.h"
11#include "core/hle/kernel/svc_results.h"
12
13namespace Kernel {
14
15ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
16ClientPort::~ClientPort() = default;
17
18std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
19 return server_port;
20}
21
22ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
23 if (active_sessions >= max_sessions) {
24 return ResultMaxConnectionsReached;
25 }
26 active_sessions++;
27
28 auto [client, server] = Kernel::Session::Create(kernel, name);
29
30 if (server_port->HasHLEHandler()) {
31 server_port->GetHLEHandler()->ClientConnected(std::move(server));
32 } else {
33 server_port->AppendPendingSession(std::move(server));
34 }
35
36 return MakeResult(std::move(client));
37}
38
39void ClientPort::ConnectionClosed() {
40 if (active_sessions == 0) {
41 return;
42 }
43
44 --active_sessions;
45}
46
47} // namespace Kernel
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
deleted file mode 100644
index 77559ebf9..000000000
--- a/src/core/hle/kernel/client_port.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include "common/common_types.h"
11#include "core/hle/kernel/object.h"
12#include "core/hle/result.h"
13
14namespace Kernel {
15
16class ClientSession;
17class KernelCore;
18class ServerPort;
19
20class ClientPort final : public Object {
21public:
22 explicit ClientPort(KernelCore& kernel);
23 ~ClientPort() override;
24
25 friend class ServerPort;
26 std::string GetTypeName() const override {
27 return "ClientPort";
28 }
29 std::string GetName() const override {
30 return name;
31 }
32
33 static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort;
34 HandleType GetHandleType() const override {
35 return HANDLE_TYPE;
36 }
37
38 std::shared_ptr<ServerPort> GetServerPort() const;
39
40 /**
41 * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
42 * list of pending sessions, and signals the ServerPort, causing any threads
43 * waiting on it to awake.
44 * @returns ClientSession The client endpoint of the created Session pair, or error code.
45 */
46 ResultVal<std::shared_ptr<ClientSession>> Connect();
47
48 /**
49 * Signifies that a previously active connection has been closed,
50 * decreasing the total number of active connections to this port.
51 */
52 void ConnectionClosed();
53
54 void Finalize() override {}
55
56private:
57 std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
58 u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
59 u32 active_sessions = 0; ///< Number of currently open sessions to this port
60 std::string name; ///< Name of client port (optional)
61};
62
63} // namespace Kernel
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
deleted file mode 100644
index e230f365a..000000000
--- a/src/core/hle/kernel/client_session.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/client_session.h"
6#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/kernel/k_thread.h"
8#include "core/hle/kernel/server_session.h"
9#include "core/hle/kernel/session.h"
10#include "core/hle/kernel/svc_results.h"
11#include "core/hle/result.h"
12
13namespace Kernel {
14
15ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
16
17ClientSession::~ClientSession() {
18 // This destructor will be called automatically when the last ClientSession handle is closed by
19 // the emulated application.
20 if (parent->Server()) {
21 parent->Server()->ClientDisconnected();
22 }
23}
24
25bool ClientSession::IsSignaled() const {
26 UNIMPLEMENTED();
27 return true;
28}
29
30ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
31 std::shared_ptr<Session> parent,
32 std::string name) {
33 std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)};
34
35 client_session->name = std::move(name);
36 client_session->parent = std::move(parent);
37
38 return MakeResult(std::move(client_session));
39}
40
41ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread,
42 Core::Memory::Memory& memory,
43 Core::Timing::CoreTiming& core_timing) {
44 // Keep ServerSession alive until we're done working with it.
45 if (!parent->Server()) {
46 return ResultSessionClosedByRemote;
47 }
48
49 // Signal the server session that new data is available
50 return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing);
51}
52
53} // namespace Kernel
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
deleted file mode 100644
index 85aafeaf4..000000000
--- a/src/core/hle/kernel/client_session.h
+++ /dev/null
@@ -1,68 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include "core/hle/kernel/k_synchronization_object.h"
11#include "core/hle/result.h"
12
13union ResultCode;
14
15namespace Core::Memory {
16class Memory;
17}
18
19namespace Core::Timing {
20class CoreTiming;
21}
22
23namespace Kernel {
24
25class KernelCore;
26class Session;
27class KThread;
28
29class ClientSession final : public KSynchronizationObject {
30public:
31 explicit ClientSession(KernelCore& kernel);
32 ~ClientSession() override;
33
34 friend class Session;
35
36 std::string GetTypeName() const override {
37 return "ClientSession";
38 }
39
40 std::string GetName() const override {
41 return name;
42 }
43
44 static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
45 HandleType GetHandleType() const override {
46 return HANDLE_TYPE;
47 }
48
49 ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
50 Core::Timing::CoreTiming& core_timing);
51
52 bool IsSignaled() const override;
53
54 void Finalize() override {}
55
56private:
57 static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
58 std::shared_ptr<Session> parent,
59 std::string name = "Unknown");
60
61 /// The parent session, which links to the server endpoint.
62 std::shared_ptr<Session> parent;
63
64 /// Name of the client session (optional)
65 std::string name;
66};
67
68} // namespace Kernel
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index c6838649f..4f4e338e3 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -12,17 +12,17 @@
12 12
13namespace Kernel { 13namespace Kernel {
14 14
15GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel) 15GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel_)
16 : kernel{kernel}, scheduler_lock{kernel} {} 16 : kernel{kernel_}, scheduler_lock{kernel_} {}
17 17
18GlobalSchedulerContext::~GlobalSchedulerContext() = default; 18GlobalSchedulerContext::~GlobalSchedulerContext() = default;
19 19
20void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) { 20void GlobalSchedulerContext::AddThread(KThread* thread) {
21 std::scoped_lock lock{global_list_guard}; 21 std::scoped_lock lock{global_list_guard};
22 thread_list.push_back(std::move(thread)); 22 thread_list.push_back(thread);
23} 23}
24 24
25void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) { 25void GlobalSchedulerContext::RemoveThread(KThread* thread) {
26 std::scoped_lock lock{global_list_guard}; 26 std::scoped_lock lock{global_list_guard};
27 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), 27 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
28 thread_list.end()); 28 thread_list.end());
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index 11592843e..6f44b534f 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -34,17 +34,17 @@ class GlobalSchedulerContext final {
34public: 34public:
35 using LockType = KAbstractSchedulerLock<KScheduler>; 35 using LockType = KAbstractSchedulerLock<KScheduler>;
36 36
37 explicit GlobalSchedulerContext(KernelCore& kernel); 37 explicit GlobalSchedulerContext(KernelCore& kernel_);
38 ~GlobalSchedulerContext(); 38 ~GlobalSchedulerContext();
39 39
40 /// Adds a new thread to the scheduler 40 /// Adds a new thread to the scheduler
41 void AddThread(std::shared_ptr<KThread> thread); 41 void AddThread(KThread* thread);
42 42
43 /// Removes a thread from the scheduler 43 /// Removes a thread from the scheduler
44 void RemoveThread(std::shared_ptr<KThread> thread); 44 void RemoveThread(KThread* thread);
45 45
46 /// Returns a list of all threads managed by the scheduler 46 /// Returns a list of all threads managed by the scheduler
47 [[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const { 47 [[nodiscard]] const std::vector<KThread*>& GetThreadList() const {
48 return thread_list; 48 return thread_list;
49 } 49 }
50 50
@@ -79,7 +79,7 @@ private:
79 LockType scheduler_lock; 79 LockType scheduler_lock;
80 80
81 /// Lists all thread ids that aren't deleted/etc. 81 /// Lists all thread ids that aren't deleted/etc.
82 std::vector<std::shared_ptr<KThread>> thread_list; 82 std::vector<KThread*> thread_list;
83 Common::SpinLock global_list_guard{}; 83 Common::SpinLock global_list_guard{};
84}; 84};
85 85
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
deleted file mode 100644
index f96d34078..000000000
--- a/src/core/hle/kernel/handle_table.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <utility>
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/core.h"
9#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/k_thread.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/svc_results.h"
15
16namespace Kernel {
17namespace {
18constexpr u16 GetSlot(Handle handle) {
19 return static_cast<u16>(handle >> 15);
20}
21
22constexpr u16 GetGeneration(Handle handle) {
23 return static_cast<u16>(handle & 0x7FFF);
24}
25} // Anonymous namespace
26
27HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} {
28 Clear();
29}
30
31HandleTable::~HandleTable() = default;
32
33ResultCode HandleTable::SetSize(s32 handle_table_size) {
34 if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
35 LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT);
36 return ResultOutOfMemory;
37 }
38
39 // Values less than or equal to zero indicate to use the maximum allowable
40 // size for the handle table in the actual kernel, so we ignore the given
41 // value in that case, since we assume this by default unless this function
42 // is called.
43 if (handle_table_size > 0) {
44 table_size = static_cast<u16>(handle_table_size);
45 }
46
47 return RESULT_SUCCESS;
48}
49
50ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) {
51 DEBUG_ASSERT(obj != nullptr);
52
53 const u16 slot = next_free_slot;
54 if (slot >= table_size) {
55 LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
56 return ResultHandleTableFull;
57 }
58 next_free_slot = generations[slot];
59
60 const u16 generation = next_generation++;
61
62 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
63 // Horizon OS uses zero to represent an invalid handle, so skip to 1.
64 if (next_generation >= (1 << 15)) {
65 next_generation = 1;
66 }
67
68 generations[slot] = generation;
69 objects[slot] = std::move(obj);
70
71 Handle handle = generation | (slot << 15);
72 return MakeResult<Handle>(handle);
73}
74
75ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
76 std::shared_ptr<Object> object = GetGeneric(handle);
77 if (object == nullptr) {
78 LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
79 return ResultInvalidHandle;
80 }
81 return Create(std::move(object));
82}
83
84ResultCode HandleTable::Close(Handle handle) {
85 if (!IsValid(handle)) {
86 LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle);
87 return ResultInvalidHandle;
88 }
89
90 const u16 slot = GetSlot(handle);
91
92 if (objects[slot].use_count() == 1) {
93 objects[slot]->Finalize();
94 }
95
96 objects[slot] = nullptr;
97
98 generations[slot] = next_free_slot;
99 next_free_slot = slot;
100 return RESULT_SUCCESS;
101}
102
103bool HandleTable::IsValid(Handle handle) const {
104 const std::size_t slot = GetSlot(handle);
105 const u16 generation = GetGeneration(handle);
106
107 return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;
108}
109
110std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
111 if (handle == CurrentThread) {
112 return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread());
113 } else if (handle == CurrentProcess) {
114 return SharedFrom(kernel.CurrentProcess());
115 }
116
117 if (!IsValid(handle)) {
118 return nullptr;
119 }
120 return objects[GetSlot(handle)];
121}
122
123void HandleTable::Clear() {
124 for (u16 i = 0; i < table_size; ++i) {
125 generations[i] = static_cast<u16>(i + 1);
126 objects[i] = nullptr;
127 }
128 next_free_slot = 0;
129}
130
131} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
deleted file mode 100644
index c9dab8cdd..000000000
--- a/src/core/hle/kernel/handle_table.h
+++ /dev/null
@@ -1,144 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <cstddef>
9#include <memory>
10
11#include "common/common_types.h"
12#include "core/hle/kernel/object.h"
13#include "core/hle/result.h"
14
15namespace Kernel {
16
17class KernelCore;
18
19enum KernelHandle : Handle {
20 InvalidHandle = 0,
21 CurrentThread = 0xFFFF8000,
22 CurrentProcess = 0xFFFF8001,
23};
24
25/**
26 * This class allows the creation of Handles, which are references to objects that can be tested
27 * for validity and looked up. Here they are used to pass references to kernel objects to/from the
28 * emulated process. it has been designed so that it follows the same handle format and has
29 * approximately the same restrictions as the handle manager in the CTR-OS.
30 *
31 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
32 * The slot index is used to index into the arrays in this class to access the data corresponding
33 * to the Handle.
34 *
35 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
36 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
37 * value of the counter is stored into the Handle as well as in the handle table (in the
38 * "generations" array). When looking up a handle, the Handle's generation must match with the
39 * value stored on the class, otherwise the Handle is considered invalid.
40 *
41 * To find free slots when allocating a Handle without needing to scan the entire object array, the
42 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
43 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
44 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
45 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
46 * verified and isn't likely to cause any problems.
47 */
48class HandleTable final : NonCopyable {
49public:
50 /// This is the maximum limit of handles allowed per process in Horizon
51 static constexpr std::size_t MAX_COUNT = 1024;
52
53 explicit HandleTable(KernelCore& kernel);
54 ~HandleTable();
55
56 /**
57 * Sets the number of handles that may be in use at one time
58 * for this handle table.
59 *
60 * @param handle_table_size The desired size to limit the handle table to.
61 *
62 * @returns an error code indicating if initialization was successful.
63 * If initialization was not successful, then ERR_OUT_OF_MEMORY
64 * will be returned.
65 *
66 * @pre handle_table_size must be within the range [0, 1024]
67 */
68 ResultCode SetSize(s32 handle_table_size);
69
70 /**
71 * Allocates a handle for the given object.
72 * @return The created Handle or one of the following errors:
73 * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded.
74 */
75 ResultVal<Handle> Create(std::shared_ptr<Object> obj);
76
77 /**
78 * Returns a new handle that points to the same object as the passed in handle.
79 * @return The duplicated Handle or one of the following errors:
80 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
81 * - Any errors returned by `Create()`.
82 */
83 ResultVal<Handle> Duplicate(Handle handle);
84
85 /**
86 * Closes a handle, removing it from the table and decreasing the object's ref-count.
87 * @return `RESULT_SUCCESS` or one of the following errors:
88 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
89 */
90 ResultCode Close(Handle handle);
91
92 /// Checks if a handle is valid and points to an existing object.
93 bool IsValid(Handle handle) const;
94
95 /**
96 * Looks up a handle.
97 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
98 */
99 std::shared_ptr<Object> GetGeneric(Handle handle) const;
100
101 /**
102 * Looks up a handle while verifying its type.
103 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
104 * type differs from the requested one.
105 */
106 template <class T>
107 std::shared_ptr<T> Get(Handle handle) const {
108 return DynamicObjectCast<T>(GetGeneric(handle));
109 }
110
111 /// Closes all handles held in this table.
112 void Clear();
113
114private:
115 /// Stores the Object referenced by the handle or null if the slot is empty.
116 std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
117
118 /**
119 * The value of `next_generation` when the handle was created, used to check for validity. For
120 * empty slots, contains the index of the next free slot in the list.
121 */
122 std::array<u16, MAX_COUNT> generations;
123
124 /**
125 * The limited size of the handle table. This can be specified by process
126 * capabilities in order to restrict the overall number of handles that
127 * can be created in a process instance
128 */
129 u16 table_size = static_cast<u16>(MAX_COUNT);
130
131 /**
132 * Global counter of the number of created handles. Stored in `generations` when a handle is
133 * created, and wraps around to 1 when it hits 0x8000.
134 */
135 u16 next_generation = 1;
136
137 /// Head of the free slots linked list.
138 u16 next_free_slot = 0;
139
140 /// Underlying kernel instance that this handle table operates under.
141 KernelCore& kernel;
142};
143
144} // namespace Kernel
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 2b363b1d9..ce3466df8 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -14,17 +14,16 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "core/hle/ipc_helpers.h" 16#include "core/hle/ipc_helpers.h"
17#include "core/hle/kernel/handle_table.h"
18#include "core/hle/kernel/hle_ipc.h" 17#include "core/hle/kernel/hle_ipc.h"
18#include "core/hle/kernel/k_handle_table.h"
19#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_readable_event.h" 20#include "core/hle/kernel/k_readable_event.h"
20#include "core/hle/kernel/k_scheduler.h" 21#include "core/hle/kernel/k_scheduler.h"
21#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 22#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
23#include "core/hle/kernel/k_server_session.h"
22#include "core/hle/kernel/k_thread.h" 24#include "core/hle/kernel/k_thread.h"
23#include "core/hle/kernel/k_writable_event.h" 25#include "core/hle/kernel/k_writable_event.h"
24#include "core/hle/kernel/kernel.h" 26#include "core/hle/kernel/kernel.h"
25#include "core/hle/kernel/object.h"
26#include "core/hle/kernel/process.h"
27#include "core/hle/kernel/server_session.h"
28#include "core/hle/kernel/svc_results.h" 27#include "core/hle/kernel/svc_results.h"
29#include "core/hle/kernel/time_manager.h" 28#include "core/hle/kernel/time_manager.h"
30#include "core/memory.h" 29#include "core/memory.h"
@@ -35,33 +34,28 @@ SessionRequestHandler::SessionRequestHandler() = default;
35 34
36SessionRequestHandler::~SessionRequestHandler() = default; 35SessionRequestHandler::~SessionRequestHandler() = default;
37 36
38void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) { 37void SessionRequestHandler::ClientConnected(KServerSession* session) {
39 server_session->SetHleHandler(shared_from_this()); 38 session->SetHleHandler(shared_from_this());
40 connected_sessions.push_back(std::move(server_session));
41} 39}
42 40
43void SessionRequestHandler::ClientDisconnected( 41void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
44 const std::shared_ptr<ServerSession>& server_session) { 42 session->SetHleHandler(nullptr);
45 server_session->SetHleHandler(nullptr);
46 boost::range::remove_erase(connected_sessions, server_session);
47} 43}
48 44
49HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, 45HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
50 std::shared_ptr<ServerSession> server_session, 46 KServerSession* server_session_, KThread* thread_)
51 std::shared_ptr<KThread> thread) 47 : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
52 : server_session(std::move(server_session)),
53 thread(std::move(thread)), kernel{kernel}, memory{memory} {
54 cmd_buf[0] = 0; 48 cmd_buf[0] = 0;
55} 49}
56 50
57HLERequestContext::~HLERequestContext() = default; 51HLERequestContext::~HLERequestContext() = default;
58 52
59void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, 53void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf,
60 bool incoming) { 54 bool incoming) {
61 IPC::RequestParser rp(src_cmdbuf); 55 IPC::RequestParser rp(src_cmdbuf);
62 command_header = rp.PopRaw<IPC::CommandHeader>(); 56 command_header = rp.PopRaw<IPC::CommandHeader>();
63 57
64 if (command_header->type == IPC::CommandType::Close) { 58 if (command_header->IsCloseCommand()) {
65 // Close does not populate the rest of the IPC header 59 // Close does not populate the rest of the IPC header
66 return; 60 return;
67 } 61 }
@@ -77,12 +71,12 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
77 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { 71 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
78 const u32 copy_handle{rp.Pop<Handle>()}; 72 const u32 copy_handle{rp.Pop<Handle>()};
79 copy_handles.push_back(copy_handle); 73 copy_handles.push_back(copy_handle);
80 copy_objects.push_back(handle_table.GetGeneric(copy_handle)); 74 copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe());
81 } 75 }
82 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { 76 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
83 const u32 move_handle{rp.Pop<Handle>()}; 77 const u32 move_handle{rp.Pop<Handle>()};
84 move_handles.push_back(move_handle); 78 move_handles.push_back(move_handle);
85 move_objects.push_back(handle_table.GetGeneric(move_handle)); 79 move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe());
86 } 80 }
87 } else { 81 } else {
88 // For responses we just ignore the handles, they're empty and will be populated when 82 // For responses we just ignore the handles, they're empty and will be populated when
@@ -105,39 +99,43 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
105 buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 99 buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
106 } 100 }
107 101
108 buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; 102 const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
109 103
110 // Padding to align to 16 bytes 104 if (!command_header->IsTipc()) {
111 rp.AlignWithPadding(); 105 // Padding to align to 16 bytes
112 106 rp.AlignWithPadding();
113 if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request || 107
114 command_header->type == IPC::CommandType::RequestWithContext) || 108 if (Session()->IsDomain() &&
115 !incoming)) { 109 ((command_header->type == IPC::CommandType::Request ||
116 // If this is an incoming message, only CommandType "Request" has a domain header 110 command_header->type == IPC::CommandType::RequestWithContext) ||
117 // All outgoing domain messages have the domain header, if only incoming has it 111 !incoming)) {
118 if (incoming || domain_message_header) { 112 // If this is an incoming message, only CommandType "Request" has a domain header
119 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); 113 // All outgoing domain messages have the domain header, if only incoming has it
120 } else { 114 if (incoming || domain_message_header) {
121 if (Session()->IsDomain()) { 115 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
122 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); 116 } else {
117 if (Session()->IsDomain()) {
118 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
119 }
123 } 120 }
124 } 121 }
125 }
126 122
127 data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>(); 123 data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>();
128 124
129 data_payload_offset = rp.GetCurrentOffset(); 125 data_payload_offset = rp.GetCurrentOffset();
130 126
131 if (domain_message_header && domain_message_header->command == 127 if (domain_message_header &&
132 IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) { 128 domain_message_header->command ==
133 // CloseVirtualHandle command does not have SFC* or any data 129 IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) {
134 return; 130 // CloseVirtualHandle command does not have SFC* or any data
135 } 131 return;
132 }
136 133
137 if (incoming) { 134 if (incoming) {
138 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I')); 135 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
139 } else { 136 } else {
140 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O')); 137 ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
138 }
141 } 139 }
142 140
143 rp.SetCurrentOffset(buffer_c_offset); 141 rp.SetCurrentOffset(buffer_c_offset);
@@ -169,87 +167,70 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
169 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. 167 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
170} 168}
171 169
172ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, 170ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
173 u32_le* src_cmdbuf) { 171 u32_le* src_cmdbuf) {
174 ParseCommandBuffer(handle_table, src_cmdbuf, true); 172 ParseCommandBuffer(handle_table, src_cmdbuf, true);
175 if (command_header->type == IPC::CommandType::Close) { 173
174 if (command_header->IsCloseCommand()) {
176 // Close does not populate the rest of the IPC header 175 // Close does not populate the rest of the IPC header
177 return RESULT_SUCCESS; 176 return RESULT_SUCCESS;
178 } 177 }
179 178
180 // The data_size already includes the payload header, the padding and the domain header. 179 std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin());
181 std::size_t size = data_payload_offset + command_header->data_size - 180
182 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
183 if (domain_message_header)
184 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
185 std::copy_n(src_cmdbuf, size, cmd_buf.begin());
186 return RESULT_SUCCESS; 181 return RESULT_SUCCESS;
187} 182}
188 183
189ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) { 184ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
190 auto& owner_process = *thread.GetOwnerProcess(); 185 auto current_offset = handles_offset;
186 auto& owner_process = *requesting_thread.GetOwnerProcess();
191 auto& handle_table = owner_process.GetHandleTable(); 187 auto& handle_table = owner_process.GetHandleTable();
192 188
193 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
194 memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
195 dst_cmdbuf.size() * sizeof(u32));
196
197 // The header was already built in the internal command buffer. Attempt to parse it to verify
198 // the integrity and then copy it over to the target command buffer.
199 ParseCommandBuffer(handle_table, cmd_buf.data(), false);
200
201 // The data_size already includes the payload header, the padding and the domain header. 189 // The data_size already includes the payload header, the padding and the domain header.
202 std::size_t size = data_payload_offset + command_header->data_size - 190 std::size_t size{};
203 sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
204 if (domain_message_header)
205 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
206
207 std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data());
208 191
209 if (command_header->enable_handle_descriptor) { 192 if (IsTipc()) {
210 ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), 193 size = cmd_buf.size();
211 "Handle descriptor bit set but no handles to translate"); 194 } else {
212 // We write the translated handles at a specific offset in the command buffer, this space 195 size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
213 // was already reserved when writing the header. 196 if (Session()->IsDomain()) {
214 std::size_t current_offset = 197 size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
215 (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
216 ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
217
218 ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
219 ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
220
221 // We don't make a distinction between copy and move handles when translating since HLE
222 // services don't deal with handles directly. However, the guest applications might check
223 // for specific values in each of these descriptors.
224 for (auto& object : copy_objects) {
225 ASSERT(object != nullptr);
226 dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
227 } 198 }
199 }
228 200
229 for (auto& object : move_objects) { 201 for (auto& object : copy_objects) {
230 ASSERT(object != nullptr); 202 Handle handle{};
231 dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap(); 203 if (object) {
204 R_TRY(handle_table.Add(&handle, object));
232 } 205 }
206 cmd_buf[current_offset++] = handle;
233 } 207 }
208 for (auto& object : move_objects) {
209 Handle handle{};
210 if (object) {
211 R_TRY(handle_table.Add(&handle, object));
234 212
235 // TODO(Subv): Translate the X/A/B/W buffers. 213 // Close our reference to the object, as it is being moved to the caller.
214 object->Close();
215 }
216 cmd_buf[current_offset++] = handle;
217 }
236 218
237 if (Session()->IsDomain() && domain_message_header) { 219 // Write the domain objects to the command buffer, these go after the raw untranslated data.
238 ASSERT(domain_message_header->num_objects == domain_objects.size()); 220 // TODO(Subv): This completely ignores C buffers.
239 // Write the domain objects to the command buffer, these go after the raw untranslated data.
240 // TODO(Subv): This completely ignores C buffers.
241 std::size_t domain_offset = size - domain_message_header->num_objects;
242 221
222 if (Session()->IsDomain()) {
223 current_offset = domain_offset - static_cast<u32>(domain_objects.size());
243 for (const auto& object : domain_objects) { 224 for (const auto& object : domain_objects) {
244 server_session->AppendDomainRequestHandler(object); 225 server_session->AppendDomainRequestHandler(object);
245 dst_cmdbuf[domain_offset++] = 226 cmd_buf[current_offset++] =
246 static_cast<u32_le>(server_session->NumDomainRequestHandlers()); 227 static_cast<u32_le>(server_session->NumDomainRequestHandlers());
247 } 228 }
248 } 229 }
249 230
250 // Copy the translated command buffer back into the thread's command buffer area. 231 // Copy the translated command buffer back into the thread's command buffer area.
251 memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), 232 memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(),
252 dst_cmdbuf.size() * sizeof(u32)); 233 size * sizeof(u32));
253 234
254 return RESULT_SUCCESS; 235 return RESULT_SUCCESS;
255} 236}
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 6fba42615..4fba300dc 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -16,7 +16,8 @@
16#include "common/concepts.h" 16#include "common/concepts.h"
17#include "common/swap.h" 17#include "common/swap.h"
18#include "core/hle/ipc.h" 18#include "core/hle/ipc.h"
19#include "core/hle/kernel/object.h" 19#include "core/hle/kernel/k_auto_object.h"
20#include "core/hle/kernel/svc_common.h"
20 21
21union ResultCode; 22union ResultCode;
22 23
@@ -35,13 +36,14 @@ class ServiceFrameworkBase;
35namespace Kernel { 36namespace Kernel {
36 37
37class Domain; 38class Domain;
38class HandleTable;
39class HLERequestContext; 39class HLERequestContext;
40class KernelCore; 40class KernelCore;
41class Process; 41class KHandleTable;
42class ServerSession; 42class KProcess;
43class KServerSession;
43class KThread; 44class KThread;
44class KReadableEvent; 45class KReadableEvent;
46class KSession;
45class KWritableEvent; 47class KWritableEvent;
46 48
47enum class ThreadWakeupReason; 49enum class ThreadWakeupReason;
@@ -64,27 +66,22 @@ public:
64 * this request (ServerSession, Originator thread, Translated command buffer, etc). 66 * this request (ServerSession, Originator thread, Translated command buffer, etc).
65 * @returns ResultCode the result code of the translate operation. 67 * @returns ResultCode the result code of the translate operation.
66 */ 68 */
67 virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0; 69 virtual ResultCode HandleSyncRequest(Kernel::KServerSession& session,
70 Kernel::HLERequestContext& context) = 0;
68 71
69 /** 72 /**
70 * Signals that a client has just connected to this HLE handler and keeps the 73 * Signals that a client has just connected to this HLE handler and keeps the
71 * associated ServerSession alive for the duration of the connection. 74 * associated ServerSession alive for the duration of the connection.
72 * @param server_session Owning pointer to the ServerSession associated with the connection. 75 * @param server_session Owning pointer to the ServerSession associated with the connection.
73 */ 76 */
74 void ClientConnected(std::shared_ptr<ServerSession> server_session); 77 void ClientConnected(KServerSession* session);
75 78
76 /** 79 /**
77 * Signals that a client has just disconnected from this HLE handler and releases the 80 * Signals that a client has just disconnected from this HLE handler and releases the
78 * associated ServerSession. 81 * associated ServerSession.
79 * @param server_session ServerSession associated with the connection. 82 * @param server_session ServerSession associated with the connection.
80 */ 83 */
81 void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session); 84 void ClientDisconnected(KServerSession* session);
82
83protected:
84 /// List of sessions that are connected to this handler.
85 /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
86 /// for the duration of the connection.
87 std::vector<std::shared_ptr<ServerSession>> connected_sessions;
88}; 85};
89 86
90/** 87/**
@@ -109,8 +106,7 @@ protected:
109class HLERequestContext { 106class HLERequestContext {
110public: 107public:
111 explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, 108 explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
112 std::shared_ptr<ServerSession> session, 109 KServerSession* session, KThread* thread);
113 std::shared_ptr<KThread> thread);
114 ~HLERequestContext(); 110 ~HLERequestContext();
115 111
116 /// Returns a pointer to the IPC command buffer for this request. 112 /// Returns a pointer to the IPC command buffer for this request.
@@ -122,26 +118,39 @@ public:
122 * Returns the session through which this request was made. This can be used as a map key to 118 * Returns the session through which this request was made. This can be used as a map key to
123 * access per-client data on services. 119 * access per-client data on services.
124 */ 120 */
125 const std::shared_ptr<Kernel::ServerSession>& Session() const { 121 Kernel::KServerSession* Session() {
126 return server_session; 122 return server_session;
127 } 123 }
128 124
129 /// Populates this context with data from the requesting process/thread. 125 /// Populates this context with data from the requesting process/thread.
130 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, 126 ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
131 u32_le* src_cmdbuf); 127 u32_le* src_cmdbuf);
132 128
133 /// Writes data from this context back to the requesting process/thread. 129 /// Writes data from this context back to the requesting process/thread.
134 ResultCode WriteToOutgoingCommandBuffer(KThread& thread); 130 ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread);
135 131
136 u32_le GetCommand() const { 132 u32_le GetHipcCommand() const {
137 return command; 133 return command;
138 } 134 }
139 135
136 u32_le GetTipcCommand() const {
137 return static_cast<u32_le>(command_header->type.Value()) -
138 static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion);
139 }
140
141 u32_le GetCommand() const {
142 return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand();
143 }
144
145 bool IsTipc() const {
146 return command_header->IsTipc();
147 }
148
140 IPC::CommandType GetCommandType() const { 149 IPC::CommandType GetCommandType() const {
141 return command_header->type; 150 return command_header->type;
142 } 151 }
143 152
144 unsigned GetDataPayloadOffset() const { 153 u32 GetDataPayloadOffset() const {
145 return data_payload_offset; 154 return data_payload_offset;
146 } 155 }
147 156
@@ -218,22 +227,12 @@ public:
218 return move_handles.at(index); 227 return move_handles.at(index);
219 } 228 }
220 229
221 template <typename T> 230 void AddMoveObject(KAutoObject* object) {
222 std::shared_ptr<T> GetCopyObject(std::size_t index) { 231 move_objects.emplace_back(object);
223 return DynamicObjectCast<T>(copy_objects.at(index));
224 } 232 }
225 233
226 template <typename T> 234 void AddCopyObject(KAutoObject* object) {
227 std::shared_ptr<T> GetMoveObject(std::size_t index) { 235 copy_objects.emplace_back(object);
228 return DynamicObjectCast<T>(move_objects.at(index));
229 }
230
231 void AddMoveObject(std::shared_ptr<Object> object) {
232 move_objects.emplace_back(std::move(object));
233 }
234
235 void AddCopyObject(std::shared_ptr<Object> object) {
236 copy_objects.emplace_back(std::move(object));
237 } 236 }
238 237
239 void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { 238 void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
@@ -276,10 +275,6 @@ public:
276 return *thread; 275 return *thread;
277 } 276 }
278 277
279 const KThread& GetThread() const {
280 return *thread;
281 }
282
283 bool IsThreadWaiting() const { 278 bool IsThreadWaiting() const {
284 return is_thread_waiting; 279 return is_thread_waiting;
285 } 280 }
@@ -287,16 +282,17 @@ public:
287private: 282private:
288 friend class IPC::ResponseBuilder; 283 friend class IPC::ResponseBuilder;
289 284
290 void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); 285 void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
291 286
292 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 287 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
293 std::shared_ptr<Kernel::ServerSession> server_session; 288 Kernel::KServerSession* server_session{};
294 std::shared_ptr<KThread> thread; 289 KThread* thread;
290
295 // TODO(yuriks): Check common usage of this and optimize size accordingly 291 // TODO(yuriks): Check common usage of this and optimize size accordingly
296 boost::container::small_vector<Handle, 8> move_handles; 292 boost::container::small_vector<Handle, 8> move_handles;
297 boost::container::small_vector<Handle, 8> copy_handles; 293 boost::container::small_vector<Handle, 8> copy_handles;
298 boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; 294 boost::container::small_vector<KAutoObject*, 8> move_objects;
299 boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; 295 boost::container::small_vector<KAutoObject*, 8> copy_objects;
300 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; 296 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
301 297
302 std::optional<IPC::CommandHeader> command_header; 298 std::optional<IPC::CommandHeader> command_header;
@@ -309,8 +305,10 @@ private:
309 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; 305 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
310 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; 306 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
311 307
312 unsigned data_payload_offset{}; 308 u32 data_payload_offset{};
313 unsigned buffer_c_offset{}; 309 u32 handles_offset{};
310 u32 domain_offset{};
311 u32 data_size{};
314 u32_le command{}; 312 u32_le command{};
315 313
316 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; 314 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
new file mode 100644
index 000000000..69ae405e6
--- /dev/null
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -0,0 +1,192 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/alignment.h"
6#include "common/assert.h"
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "core/core.h"
10#include "core/hardware_properties.h"
11#include "core/hle/kernel/init/init_slab_setup.h"
12#include "core/hle/kernel/k_event.h"
13#include "core/hle/kernel/k_memory_layout.h"
14#include "core/hle/kernel/k_memory_manager.h"
15#include "core/hle/kernel/k_port.h"
16#include "core/hle/kernel/k_process.h"
17#include "core/hle/kernel/k_resource_limit.h"
18#include "core/hle/kernel/k_session.h"
19#include "core/hle/kernel/k_shared_memory.h"
20#include "core/hle/kernel/k_system_control.h"
21#include "core/hle/kernel/k_thread.h"
22#include "core/hle/kernel/k_transfer_memory.h"
23#include "core/hle/kernel/memory_types.h"
24#include "core/memory.h"
25
26namespace Kernel::Init {
27
28#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS
29
30#define FOREACH_SLAB_TYPE(HANDLER, ...) \
31 HANDLER(KProcess, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \
32 HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
33 HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
34 HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
35 HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
36 HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
37 HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
38 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
39
40namespace {
41
42#define DEFINE_SLAB_TYPE_ENUM_MEMBER(NAME, COUNT, ...) KSlabType_##NAME,
43
44enum KSlabType : u32 {
45 FOREACH_SLAB_TYPE(DEFINE_SLAB_TYPE_ENUM_MEMBER) KSlabType_Count,
46};
47
48#undef DEFINE_SLAB_TYPE_ENUM_MEMBER
49
50// Constexpr counts.
51constexpr size_t SlabCountKProcess = 80;
52constexpr size_t SlabCountKThread = 800;
53constexpr size_t SlabCountKEvent = 700;
54constexpr size_t SlabCountKInterruptEvent = 100;
55constexpr size_t SlabCountKPort = 256 + 0x20; // Extra 0x20 ports over Nintendo for homebrew.
56constexpr size_t SlabCountKSharedMemory = 80;
57constexpr size_t SlabCountKTransferMemory = 200;
58constexpr size_t SlabCountKCodeMemory = 10;
59constexpr size_t SlabCountKDeviceAddressSpace = 300;
60constexpr size_t SlabCountKSession = 933;
61constexpr size_t SlabCountKLightSession = 100;
62constexpr size_t SlabCountKObjectName = 7;
63constexpr size_t SlabCountKResourceLimit = 5;
64constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES;
65constexpr size_t SlabCountKAlpha = 1;
66constexpr size_t SlabCountKBeta = 6;
67
68constexpr size_t SlabCountExtraKThread = 160;
69
70template <typename T>
71VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address,
72 size_t num_objects) {
73 const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*));
74 VAddr start = Common::AlignUp(address, alignof(T));
75
76 if (size > 0) {
77 const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1);
78 ASSERT(region != nullptr);
79 ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab));
80 T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size);
81 }
82
83 return start + size;
84}
85
86} // namespace
87
88KSlabResourceCounts KSlabResourceCounts::CreateDefault() {
89 return {
90 .num_KProcess = SlabCountKProcess,
91 .num_KThread = SlabCountKThread,
92 .num_KEvent = SlabCountKEvent,
93 .num_KInterruptEvent = SlabCountKInterruptEvent,
94 .num_KPort = SlabCountKPort,
95 .num_KSharedMemory = SlabCountKSharedMemory,
96 .num_KTransferMemory = SlabCountKTransferMemory,
97 .num_KCodeMemory = SlabCountKCodeMemory,
98 .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace,
99 .num_KSession = SlabCountKSession,
100 .num_KLightSession = SlabCountKLightSession,
101 .num_KObjectName = SlabCountKObjectName,
102 .num_KResourceLimit = SlabCountKResourceLimit,
103 .num_KDebug = SlabCountKDebug,
104 .num_KAlpha = SlabCountKAlpha,
105 .num_KBeta = SlabCountKBeta,
106 };
107}
108
109void InitializeSlabResourceCounts(KernelCore& kernel) {
110 kernel.SlabResourceCounts() = KSlabResourceCounts::CreateDefault();
111 if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) {
112 kernel.SlabResourceCounts().num_KThread += SlabCountExtraKThread;
113 }
114}
115
116size_t CalculateTotalSlabHeapSize(const KernelCore& kernel) {
117 size_t size = 0;
118
119#define ADD_SLAB_SIZE(NAME, COUNT, ...) \
120 { \
121 size += alignof(NAME); \
122 size += Common::AlignUp(sizeof(NAME) * (COUNT), alignof(void*)); \
123 };
124
125 // Add the size required for each slab.
126 FOREACH_SLAB_TYPE(ADD_SLAB_SIZE)
127
128#undef ADD_SLAB_SIZE
129
130 // Add the reserved size.
131 size += KernelSlabHeapGapsSize;
132
133 return size;
134}
135
136void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
137 auto& kernel = system.Kernel();
138
139 // Get the start of the slab region, since that's where we'll be working.
140 VAddr address = memory_layout.GetSlabRegionAddress();
141
142 // Initialize slab type array to be in sorted order.
143 std::array<KSlabType, KSlabType_Count> slab_types;
144 for (size_t i = 0; i < slab_types.size(); i++) {
145 slab_types[i] = static_cast<KSlabType>(i);
146 }
147
148 // N shuffles the slab type array with the following simple algorithm.
149 for (size_t i = 0; i < slab_types.size(); i++) {
150 const size_t rnd = KSystemControl::GenerateRandomRange(0, slab_types.size() - 1);
151 std::swap(slab_types[i], slab_types[rnd]);
152 }
153
154 // Create an array to represent the gaps between the slabs.
155 const size_t total_gap_size = KernelSlabHeapGapsSize;
156 std::array<size_t, slab_types.size()> slab_gaps;
157 for (size_t i = 0; i < slab_gaps.size(); i++) {
158 // Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange
159 // is inclusive. However, Nintendo also has the off-by-one error, and it's "harmless", so we
160 // will include it ourselves.
161 slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size);
162 }
163
164 // Sort the array, so that we can treat differences between values as offsets to the starts of
165 // slabs.
166 for (size_t i = 1; i < slab_gaps.size(); i++) {
167 for (size_t j = i; j > 0 && slab_gaps[j - 1] > slab_gaps[j]; j--) {
168 std::swap(slab_gaps[j], slab_gaps[j - 1]);
169 }
170 }
171
172 for (size_t i = 0; i < slab_types.size(); i++) {
173 // Add the random gap to the address.
174 address += (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1];
175
176#define INITIALIZE_SLAB_HEAP(NAME, COUNT, ...) \
177 case KSlabType_##NAME: \
178 address = InitializeSlabHeap<NAME>(system, memory_layout, address, COUNT); \
179 break;
180
181 // Initialize the slabheap.
182 switch (slab_types[i]) {
183 // For each of the slab types, we want to initialize that heap.
184 FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP)
185 // If we somehow get an invalid type, abort.
186 default:
187 UNREACHABLE();
188 }
189 }
190}
191
192} // namespace Kernel::Init
diff --git a/src/core/hle/kernel/init/init_slab_setup.h b/src/core/hle/kernel/init/init_slab_setup.h
new file mode 100644
index 000000000..a8f7e0918
--- /dev/null
+++ b/src/core/hle/kernel/init/init_slab_setup.h
@@ -0,0 +1,43 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Core {
8class System;
9} // namespace Core
10
11namespace Kernel {
12class KernelCore;
13class KMemoryLayout;
14} // namespace Kernel
15
16namespace Kernel::Init {
17
18struct KSlabResourceCounts {
19 static KSlabResourceCounts CreateDefault();
20
21 size_t num_KProcess;
22 size_t num_KThread;
23 size_t num_KEvent;
24 size_t num_KInterruptEvent;
25 size_t num_KPort;
26 size_t num_KSharedMemory;
27 size_t num_KTransferMemory;
28 size_t num_KCodeMemory;
29 size_t num_KDeviceAddressSpace;
30 size_t num_KSession;
31 size_t num_KLightSession;
32 size_t num_KObjectName;
33 size_t num_KResourceLimit;
34 size_t num_KDebug;
35 size_t num_KAlpha;
36 size_t num_KBeta;
37};
38
39void InitializeSlabResourceCounts(KernelCore& kernel);
40size_t CalculateTotalSlabHeapSize(const KernelCore& kernel);
41void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout);
42
43} // namespace Kernel::Init
diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp
new file mode 100644
index 000000000..dbe237f09
--- /dev/null
+++ b/src/core/hle/kernel/k_auto_object.cpp
@@ -0,0 +1,14 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_auto_object.h"
6
7namespace Kernel {
8
9KAutoObject* KAutoObject::Create(KAutoObject* obj) {
10 obj->m_ref_count = 1;
11 return obj;
12}
13
14} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
new file mode 100644
index 000000000..bc18582be
--- /dev/null
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -0,0 +1,302 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <string>
9
10#include "common/assert.h"
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13#include "common/intrusive_red_black_tree.h"
14#include "core/hle/kernel/k_class_token.h"
15
16namespace Kernel {
17
18class KernelCore;
19class KProcess;
20
21#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
22 YUZU_NON_COPYABLE(CLASS); \
23 YUZU_NON_MOVEABLE(CLASS); \
24 \
25private: \
26 friend class ::Kernel::KClassTokenGenerator; \
27 static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
28 static constexpr inline const char* const TypeName = #CLASS; \
29 static constexpr inline ClassTokenType ClassToken() { \
30 return ::Kernel::ClassToken<CLASS>; \
31 } \
32 \
33public: \
34 using BaseClass = BASE_CLASS; \
35 static constexpr TypeObj GetStaticTypeObj() { \
36 constexpr ClassTokenType Token = ClassToken(); \
37 return TypeObj(TypeName, Token); \
38 } \
39 static constexpr const char* GetStaticTypeName() { \
40 return TypeName; \
41 } \
42 virtual TypeObj GetTypeObj() const { \
43 return GetStaticTypeObj(); \
44 } \
45 virtual const char* GetTypeName() const { \
46 return GetStaticTypeName(); \
47 } \
48 \
49private: \
50 constexpr bool operator!=(const TypeObj& rhs)
51
52class KAutoObject {
53protected:
54 class TypeObj {
55 public:
56 constexpr explicit TypeObj(const char* n, ClassTokenType tok)
57 : m_name(n), m_class_token(tok) {}
58
59 constexpr const char* GetName() const {
60 return m_name;
61 }
62 constexpr ClassTokenType GetClassToken() const {
63 return m_class_token;
64 }
65
66 constexpr bool operator==(const TypeObj& rhs) const {
67 return this->GetClassToken() == rhs.GetClassToken();
68 }
69
70 constexpr bool operator!=(const TypeObj& rhs) const {
71 return this->GetClassToken() != rhs.GetClassToken();
72 }
73
74 constexpr bool IsDerivedFrom(const TypeObj& rhs) const {
75 return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
76 }
77
78 private:
79 const char* m_name;
80 ClassTokenType m_class_token;
81 };
82
83private:
84 KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
85
86public:
87 explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {}
88 virtual ~KAutoObject() = default;
89
90 static KAutoObject* Create(KAutoObject* ptr);
91
92 // Destroy is responsible for destroying the auto object's resources when ref_count hits zero.
93 virtual void Destroy() {
94 UNIMPLEMENTED();
95 }
96
97 // Finalize is responsible for cleaning up resource, but does not destroy the object.
98 virtual void Finalize() {}
99
100 virtual KProcess* GetOwner() const {
101 return nullptr;
102 }
103
104 u32 GetReferenceCount() const {
105 return m_ref_count.load();
106 }
107
108 bool IsDerivedFrom(const TypeObj& rhs) const {
109 return this->GetTypeObj().IsDerivedFrom(rhs);
110 }
111
112 bool IsDerivedFrom(const KAutoObject& rhs) const {
113 return this->IsDerivedFrom(rhs.GetTypeObj());
114 }
115
116 template <typename Derived>
117 Derived DynamicCast() {
118 static_assert(std::is_pointer_v<Derived>);
119 using DerivedType = std::remove_pointer_t<Derived>;
120
121 if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
122 return static_cast<Derived>(this);
123 } else {
124 return nullptr;
125 }
126 }
127
128 template <typename Derived>
129 const Derived DynamicCast() const {
130 static_assert(std::is_pointer_v<Derived>);
131 using DerivedType = std::remove_pointer_t<Derived>;
132
133 if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
134 return static_cast<Derived>(this);
135 } else {
136 return nullptr;
137 }
138 }
139
140 bool Open() {
141 // Atomically increment the reference count, only if it's positive.
142 u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
143 do {
144 if (cur_ref_count == 0) {
145 return false;
146 }
147 ASSERT(cur_ref_count < cur_ref_count + 1);
148 } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1,
149 std::memory_order_relaxed));
150
151 return true;
152 }
153
154 void Close() {
155 // Atomically decrement the reference count, not allowing it to become negative.
156 u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
157 do {
158 ASSERT(cur_ref_count > 0);
159 } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1,
160 std::memory_order_relaxed));
161
162 // If ref count hits zero, destroy the object.
163 if (cur_ref_count - 1 == 0) {
164 this->Destroy();
165 }
166 }
167
168protected:
169 KernelCore& kernel;
170 std::string name;
171
172private:
173 std::atomic<u32> m_ref_count{};
174};
175
176class KAutoObjectWithListContainer;
177
178class KAutoObjectWithList : public KAutoObject {
179public:
180 explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
181
182 static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
183 const u64 lid = lhs.GetId();
184 const u64 rid = rhs.GetId();
185
186 if (lid < rid) {
187 return -1;
188 } else if (lid > rid) {
189 return 1;
190 } else {
191 return 0;
192 }
193 }
194
195public:
196 virtual u64 GetId() const {
197 return reinterpret_cast<u64>(this);
198 }
199
200 virtual const std::string& GetName() const {
201 return name;
202 }
203
204private:
205 friend class KAutoObjectWithListContainer;
206
207 Common::IntrusiveRedBlackTreeNode list_node;
208};
209
210template <typename T>
211class KScopedAutoObject {
212 YUZU_NON_COPYABLE(KScopedAutoObject);
213
214public:
215 constexpr KScopedAutoObject() = default;
216
217 constexpr KScopedAutoObject(T* o) : m_obj(o) {
218 if (m_obj != nullptr) {
219 m_obj->Open();
220 }
221 }
222
223 ~KScopedAutoObject() {
224 if (m_obj != nullptr) {
225 m_obj->Close();
226 }
227 m_obj = nullptr;
228 }
229
230 template <typename U>
231 requires(std::derived_from<T, U> ||
232 std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
233 if constexpr (std::derived_from<U, T>) {
234 // Upcast.
235 m_obj = rhs.m_obj;
236 rhs.m_obj = nullptr;
237 } else {
238 // Downcast.
239 T* derived = nullptr;
240 if (rhs.m_obj != nullptr) {
241 derived = rhs.m_obj->template DynamicCast<T*>();
242 if (derived == nullptr) {
243 rhs.m_obj->Close();
244 }
245 }
246
247 m_obj = derived;
248 rhs.m_obj = nullptr;
249 }
250 }
251
252 constexpr KScopedAutoObject<T>& operator=(KScopedAutoObject<T>&& rhs) {
253 rhs.Swap(*this);
254 return *this;
255 }
256
257 constexpr T* operator->() {
258 return m_obj;
259 }
260 constexpr T& operator*() {
261 return *m_obj;
262 }
263
264 constexpr void Reset(T* o) {
265 KScopedAutoObject(o).Swap(*this);
266 }
267
268 constexpr T* GetPointerUnsafe() {
269 return m_obj;
270 }
271
272 constexpr T* GetPointerUnsafe() const {
273 return m_obj;
274 }
275
276 constexpr T* ReleasePointerUnsafe() {
277 T* ret = m_obj;
278 m_obj = nullptr;
279 return ret;
280 }
281
282 constexpr bool IsNull() const {
283 return m_obj == nullptr;
284 }
285 constexpr bool IsNotNull() const {
286 return m_obj != nullptr;
287 }
288
289private:
290 template <typename U>
291 friend class KScopedAutoObject;
292
293private:
294 T* m_obj{};
295
296private:
297 constexpr void Swap(KScopedAutoObject& rhs) noexcept {
298 std::swap(m_obj, rhs.m_obj);
299 }
300};
301
302} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object_container.cpp b/src/core/hle/kernel/k_auto_object_container.cpp
new file mode 100644
index 000000000..fc0c28874
--- /dev/null
+++ b/src/core/hle/kernel/k_auto_object_container.cpp
@@ -0,0 +1,28 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_auto_object_container.h"
6
7namespace Kernel {
8
9void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
10 KScopedLightLock lk(m_lock);
11
12 m_object_list.insert(*obj);
13}
14
15void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
16 KScopedLightLock lk(m_lock);
17
18 m_object_list.erase(m_object_list.iterator_to(*obj));
19}
20
21size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
22 KScopedLightLock lk(m_lock);
23
24 return std::count_if(m_object_list.begin(), m_object_list.end(),
25 [&](const auto& obj) { return obj.GetOwner() == owner; });
26}
27
28} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object_container.h b/src/core/hle/kernel/k_auto_object_container.h
new file mode 100644
index 000000000..ff40cf5a7
--- /dev/null
+++ b/src/core/hle/kernel/k_auto_object_container.h
@@ -0,0 +1,70 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8
9#include "common/assert.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "common/intrusive_red_black_tree.h"
13#include "core/hle/kernel/k_auto_object.h"
14#include "core/hle/kernel/k_light_lock.h"
15
16namespace Kernel {
17
18class KernelCore;
19class KProcess;
20
21class KAutoObjectWithListContainer {
22 YUZU_NON_COPYABLE(KAutoObjectWithListContainer);
23 YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
24
25public:
26 using ListType = Common::IntrusiveRedBlackTreeMemberTraits<
27 &KAutoObjectWithList::list_node>::TreeType<KAutoObjectWithList>;
28
29public:
30 class ListAccessor : public KScopedLightLock {
31 public:
32 explicit ListAccessor(KAutoObjectWithListContainer* container)
33 : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
34 explicit ListAccessor(KAutoObjectWithListContainer& container)
35 : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
36
37 typename ListType::iterator begin() const {
38 return m_list.begin();
39 }
40
41 typename ListType::iterator end() const {
42 return m_list.end();
43 }
44
45 typename ListType::iterator find(typename ListType::const_reference ref) const {
46 return m_list.find(ref);
47 }
48
49 private:
50 ListType& m_list;
51 };
52
53 friend class ListAccessor;
54
55public:
56 KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
57
58 void Initialize() {}
59 void Finalize() {}
60
61 void Register(KAutoObjectWithList* obj);
62 void Unregister(KAutoObjectWithList* obj);
63 size_t GetOwnedCount(KProcess* owner);
64
65private:
66 KLightLock m_lock;
67 ListType m_object_list;
68};
69
70} // namespace Kernel
diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp
new file mode 100644
index 000000000..beb8a2a05
--- /dev/null
+++ b/src/core/hle/kernel/k_class_token.cpp
@@ -0,0 +1,133 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_auto_object.h"
6#include "core/hle/kernel/k_class_token.h"
7#include "core/hle/kernel/k_client_port.h"
8#include "core/hle/kernel/k_client_session.h"
9#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_port.h"
11#include "core/hle/kernel/k_process.h"
12#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/kernel/k_resource_limit.h"
14#include "core/hle/kernel/k_server_port.h"
15#include "core/hle/kernel/k_server_session.h"
16#include "core/hle/kernel/k_session.h"
17#include "core/hle/kernel/k_shared_memory.h"
18#include "core/hle/kernel/k_synchronization_object.h"
19#include "core/hle/kernel/k_thread.h"
20#include "core/hle/kernel/k_transfer_memory.h"
21#include "core/hle/kernel/k_writable_event.h"
22
23namespace Kernel {
24
25// Ensure that we generate correct class tokens for all types.
26
27// Ensure that the absolute token values are correct.
28static_assert(ClassToken<KAutoObject> == 0b00000000'00000000);
29static_assert(ClassToken<KSynchronizationObject> == 0b00000000'00000001);
30static_assert(ClassToken<KReadableEvent> == 0b00000000'00000011);
31// static_assert(ClassToken<KInterruptEvent> == 0b00000111'00000011);
32// static_assert(ClassToken<KDebug> == 0b00001011'00000001);
33static_assert(ClassToken<KThread> == 0b00010011'00000001);
34static_assert(ClassToken<KServerPort> == 0b00100011'00000001);
35static_assert(ClassToken<KServerSession> == 0b01000011'00000001);
36static_assert(ClassToken<KClientPort> == 0b10000011'00000001);
37static_assert(ClassToken<KClientSession> == 0b00001101'00000000);
38static_assert(ClassToken<KProcess> == 0b00010101'00000001);
39static_assert(ClassToken<KResourceLimit> == 0b00100101'00000000);
40// static_assert(ClassToken<KLightSession> == 0b01000101'00000000);
41static_assert(ClassToken<KPort> == 0b10000101'00000000);
42static_assert(ClassToken<KSession> == 0b00011001'00000000);
43static_assert(ClassToken<KSharedMemory> == 0b00101001'00000000);
44static_assert(ClassToken<KEvent> == 0b01001001'00000000);
45static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000);
46// static_assert(ClassToken<KLightClientSession> == 0b00110001'00000000);
47// static_assert(ClassToken<KLightServerSession> == 0b01010001'00000000);
48static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
49// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
50// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
51// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
52
53// Ensure that the token hierarchy is correct.
54
55// Base classes
56static_assert(ClassToken<KAutoObject> == (0b00000000));
57static_assert(ClassToken<KSynchronizationObject> == (0b00000001 | ClassToken<KAutoObject>));
58static_assert(ClassToken<KReadableEvent> == (0b00000010 | ClassToken<KSynchronizationObject>));
59
60// Final classes
61// static_assert(ClassToken<KInterruptEvent> == ((0b00000111 << 8) | ClassToken<KReadableEvent>));
62// static_assert(ClassToken<KDebug> == ((0b00001011 << 8) | ClassToken<KSynchronizationObject>));
63static_assert(ClassToken<KThread> == ((0b00010011 << 8) | ClassToken<KSynchronizationObject>));
64static_assert(ClassToken<KServerPort> == ((0b00100011 << 8) | ClassToken<KSynchronizationObject>));
65static_assert(ClassToken<KServerSession> ==
66 ((0b01000011 << 8) | ClassToken<KSynchronizationObject>));
67static_assert(ClassToken<KClientPort> == ((0b10000011 << 8) | ClassToken<KSynchronizationObject>));
68static_assert(ClassToken<KClientSession> == ((0b00001101 << 8) | ClassToken<KAutoObject>));
69static_assert(ClassToken<KProcess> == ((0b00010101 << 8) | ClassToken<KSynchronizationObject>));
70static_assert(ClassToken<KResourceLimit> == ((0b00100101 << 8) | ClassToken<KAutoObject>));
71// static_assert(ClassToken<KLightSession> == ((0b01000101 << 8) | ClassToken<KAutoObject>));
72static_assert(ClassToken<KPort> == ((0b10000101 << 8) | ClassToken<KAutoObject>));
73static_assert(ClassToken<KSession> == ((0b00011001 << 8) | ClassToken<KAutoObject>));
74static_assert(ClassToken<KSharedMemory> == ((0b00101001 << 8) | ClassToken<KAutoObject>));
75static_assert(ClassToken<KEvent> == ((0b01001001 << 8) | ClassToken<KAutoObject>));
76static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAutoObject>));
77// static_assert(ClassToken<KLightClientSession> == ((0b00110001 << 8) | ClassToken<KAutoObject>));
78// static_assert(ClassToken<KLightServerSession> == ((0b01010001 << 8) | ClassToken<KAutoObject>));
79static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
80// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
81// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
82// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
83
84// Ensure that the token hierarchy reflects the class hierarchy.
85
86// Base classes.
87static_assert(!std::is_final<KSynchronizationObject>::value &&
88 std::is_base_of<KAutoObject, KSynchronizationObject>::value);
89static_assert(!std::is_final<KReadableEvent>::value &&
90 std::is_base_of<KSynchronizationObject, KReadableEvent>::value);
91
92// Final classes
93// static_assert(std::is_final<KInterruptEvent>::value &&
94// std::is_base_of<KReadableEvent, KInterruptEvent>::value);
95// static_assert(std::is_final<KDebug>::value &&
96// std::is_base_of<KSynchronizationObject, KDebug>::value);
97static_assert(std::is_final<KThread>::value &&
98 std::is_base_of<KSynchronizationObject, KThread>::value);
99static_assert(std::is_final<KServerPort>::value &&
100 std::is_base_of<KSynchronizationObject, KServerPort>::value);
101static_assert(std::is_final<KServerSession>::value &&
102 std::is_base_of<KSynchronizationObject, KServerSession>::value);
103static_assert(std::is_final<KClientPort>::value &&
104 std::is_base_of<KSynchronizationObject, KClientPort>::value);
105static_assert(std::is_final<KClientSession>::value &&
106 std::is_base_of<KAutoObject, KClientSession>::value);
107static_assert(std::is_final<KProcess>::value &&
108 std::is_base_of<KSynchronizationObject, KProcess>::value);
109static_assert(std::is_final<KResourceLimit>::value &&
110 std::is_base_of<KAutoObject, KResourceLimit>::value);
111// static_assert(std::is_final<KLightSession>::value &&
112// std::is_base_of<KAutoObject, KLightSession>::value);
113static_assert(std::is_final<KPort>::value && std::is_base_of<KAutoObject, KPort>::value);
114static_assert(std::is_final<KSession>::value && std::is_base_of<KAutoObject, KSession>::value);
115static_assert(std::is_final<KSharedMemory>::value &&
116 std::is_base_of<KAutoObject, KSharedMemory>::value);
117static_assert(std::is_final<KEvent>::value && std::is_base_of<KAutoObject, KEvent>::value);
118static_assert(std::is_final<KWritableEvent>::value &&
119 std::is_base_of<KAutoObject, KWritableEvent>::value);
120// static_assert(std::is_final<KLightClientSession>::value &&
121// std::is_base_of<KAutoObject, KLightClientSession>::value);
122// static_assert(std::is_final<KLightServerSession>::value &&
123// std::is_base_of<KAutoObject, KLightServerSession>::value);
124static_assert(std::is_final<KTransferMemory>::value &&
125 std::is_base_of<KAutoObject, KTransferMemory>::value);
126// static_assert(std::is_final<KDeviceAddressSpace>::value &&
127// std::is_base_of<KAutoObject, KDeviceAddressSpace>::value);
128// static_assert(std::is_final<KSessionRequest>::value &&
129// std::is_base_of<KAutoObject, KSessionRequest>::value);
130// static_assert(std::is_final<KCodeMemory>::value &&
131// std::is_base_of<KAutoObject, KCodeMemory>::value);
132
133} // namespace Kernel
diff --git a/src/core/hle/kernel/k_class_token.h b/src/core/hle/kernel/k_class_token.h
new file mode 100644
index 000000000..c28db49ec
--- /dev/null
+++ b/src/core/hle/kernel/k_class_token.h
@@ -0,0 +1,131 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8
9#include "common/assert.h"
10#include "common/bit_util.h"
11#include "common/common_types.h"
12
13namespace Kernel {
14
15class KAutoObject;
16
17class KClassTokenGenerator {
18public:
19 using TokenBaseType = u16;
20
21public:
22 static constexpr size_t BaseClassBits = 8;
23 static constexpr size_t FinalClassBits = (sizeof(TokenBaseType) * CHAR_BIT) - BaseClassBits;
24 // One bit per base class.
25 static constexpr size_t NumBaseClasses = BaseClassBits;
26 // Final classes are permutations of three bits.
27 static constexpr size_t NumFinalClasses = [] {
28 TokenBaseType index = 0;
29 for (size_t i = 0; i < FinalClassBits; i++) {
30 for (size_t j = i + 1; j < FinalClassBits; j++) {
31 for (size_t k = j + 1; k < FinalClassBits; k++) {
32 index++;
33 }
34 }
35 }
36 return index;
37 }();
38
39private:
40 template <TokenBaseType Index>
41 static constexpr inline TokenBaseType BaseClassToken = 1U << Index;
42
43 template <TokenBaseType Index>
44 static constexpr inline TokenBaseType FinalClassToken = [] {
45 TokenBaseType index = 0;
46 for (size_t i = 0; i < FinalClassBits; i++) {
47 for (size_t j = i + 1; j < FinalClassBits; j++) {
48 for (size_t k = j + 1; k < FinalClassBits; k++) {
49 if ((index++) == Index) {
50 return static_cast<TokenBaseType>(((1ULL << i) | (1ULL << j) | (1ULL << k))
51 << BaseClassBits);
52 }
53 }
54 }
55 }
56 }();
57
58 template <typename T>
59 static constexpr inline TokenBaseType GetClassToken() {
60 static_assert(std::is_base_of<KAutoObject, T>::value);
61 if constexpr (std::is_same<T, KAutoObject>::value) {
62 static_assert(T::ObjectType == ObjectType::KAutoObject);
63 return 0;
64 } else if constexpr (!std::is_final<T>::value) {
65 static_assert(ObjectType::BaseClassesStart <= T::ObjectType &&
66 T::ObjectType < ObjectType::BaseClassesEnd);
67 constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
68 static_cast<TokenBaseType>(ObjectType::BaseClassesStart);
69 return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
70 } else if constexpr (ObjectType::FinalClassesStart <= T::ObjectType &&
71 T::ObjectType < ObjectType::FinalClassesEnd) {
72 constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
73 static_cast<TokenBaseType>(ObjectType::FinalClassesStart);
74 return FinalClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
75 } else {
76 static_assert(!std::is_same<T, T>::value, "GetClassToken: Invalid Type");
77 }
78 };
79
80public:
81 enum class ObjectType {
82 KAutoObject,
83
84 BaseClassesStart,
85
86 KSynchronizationObject = BaseClassesStart,
87 KReadableEvent,
88
89 BaseClassesEnd,
90
91 FinalClassesStart = BaseClassesEnd,
92
93 KInterruptEvent = FinalClassesStart,
94 KDebug,
95 KThread,
96 KServerPort,
97 KServerSession,
98 KClientPort,
99 KClientSession,
100 KProcess,
101 KResourceLimit,
102 KLightSession,
103 KPort,
104 KSession,
105 KSharedMemory,
106 KEvent,
107 KWritableEvent,
108 KLightClientSession,
109 KLightServerSession,
110 KTransferMemory,
111 KDeviceAddressSpace,
112 KSessionRequest,
113 KCodeMemory,
114
115 // NOTE: True order for these has not been determined yet.
116 KAlpha,
117 KBeta,
118
119 FinalClassesEnd = FinalClassesStart + NumFinalClasses,
120 };
121
122 template <typename T>
123 static constexpr inline TokenBaseType ClassToken = GetClassToken<T>();
124};
125
126using ClassTokenType = KClassTokenGenerator::TokenBaseType;
127
128template <typename T>
129static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<T>;
130
131} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
new file mode 100644
index 000000000..ad01cf67e
--- /dev/null
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -0,0 +1,125 @@
1// Copyright 2021 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/scope_exit.h"
6#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/kernel/k_client_port.h"
8#include "core/hle/kernel/k_port.h"
9#include "core/hle/kernel/k_scheduler.h"
10#include "core/hle/kernel/k_scoped_resource_reservation.h"
11#include "core/hle/kernel/k_session.h"
12#include "core/hle/kernel/svc_results.h"
13
14namespace Kernel {
15
16KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
17KClientPort::~KClientPort() = default;
18
19void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) {
20 // Set member variables.
21 num_sessions = 0;
22 peak_sessions = 0;
23 parent = parent_;
24 max_sessions = max_sessions_;
25 name = std::move(name_);
26}
27
28void KClientPort::OnSessionFinalized() {
29 KScopedSchedulerLock sl{kernel};
30
31 const auto prev = num_sessions--;
32 if (prev == max_sessions) {
33 this->NotifyAvailable();
34 }
35}
36
37void KClientPort::OnServerClosed() {}
38
39bool KClientPort::IsLight() const {
40 return this->GetParent()->IsLight();
41}
42
43bool KClientPort::IsServerClosed() const {
44 return this->GetParent()->IsServerClosed();
45}
46
47void KClientPort::Destroy() {
48 // Note with our parent that we're closed.
49 parent->OnClientClosed();
50
51 // Close our reference to our parent.
52 parent->Close();
53}
54
55bool KClientPort::IsSignaled() const {
56 return num_sessions < max_sessions;
57}
58
59ResultCode KClientPort::CreateSession(KClientSession** out) {
60 // Reserve a new session from the resource limit.
61 // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
62 // LimitableResource::Sessions);
63 // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
64
65 // Update the session counts.
66 {
67 // Atomically increment the number of sessions.
68 s32 new_sessions;
69 {
70 const auto max = max_sessions;
71 auto cur_sessions = num_sessions.load(std::memory_order_acquire);
72 do {
73 R_UNLESS(cur_sessions < max, ResultOutOfSessions);
74 new_sessions = cur_sessions + 1;
75 } while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
76 std::memory_order_relaxed));
77 }
78
79 // Atomically update the peak session tracking.
80 {
81 auto peak = peak_sessions.load(std::memory_order_acquire);
82 do {
83 if (peak >= new_sessions) {
84 break;
85 }
86 } while (!peak_sessions.compare_exchange_weak(peak, new_sessions,
87 std::memory_order_relaxed));
88 }
89 }
90
91 // Create a new session.
92 KSession* session = KSession::Create(kernel);
93 if (session == nullptr) {
94 // Decrement the session count.
95 const auto prev = num_sessions--;
96 if (prev == max_sessions) {
97 this->NotifyAvailable();
98 }
99
100 return ResultOutOfResource;
101 }
102
103 // Initialize the session.
104 session->Initialize(this, parent->GetName());
105
106 // Commit the session reservation.
107 // session_reservation.Commit();
108
109 // Register the session.
110 KSession::Register(kernel, session);
111 auto session_guard = SCOPE_GUARD({
112 session->GetClientSession().Close();
113 session->GetServerSession().Close();
114 });
115
116 // Enqueue the session with our parent.
117 R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession())));
118
119 // We succeeded, so set the output.
120 session_guard.Cancel();
121 *out = std::addressof(session->GetClientSession());
122 return RESULT_SUCCESS;
123}
124
125} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
new file mode 100644
index 000000000..d00ce3ddd
--- /dev/null
+++ b/src/core/hle/kernel/k_client_port.h
@@ -0,0 +1,61 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include "common/common_types.h"
11#include "core/hle/kernel/k_synchronization_object.h"
12#include "core/hle/result.h"
13
14namespace Kernel {
15
16class KClientSession;
17class KernelCore;
18class KPort;
19
20class KClientPort final : public KSynchronizationObject {
21 KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
22
23public:
24 explicit KClientPort(KernelCore& kernel_);
25 virtual ~KClientPort() override;
26
27 void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
28 void OnSessionFinalized();
29 void OnServerClosed();
30
31 const KPort* GetParent() const {
32 return parent;
33 }
34
35 s32 GetNumSessions() const {
36 return num_sessions;
37 }
38 s32 GetPeakSessions() const {
39 return peak_sessions;
40 }
41 s32 GetMaxSessions() const {
42 return max_sessions;
43 }
44
45 bool IsLight() const;
46 bool IsServerClosed() const;
47
48 // Overridden virtual functions.
49 virtual void Destroy() override;
50 virtual bool IsSignaled() const override;
51
52 ResultCode CreateSession(KClientSession** out);
53
54private:
55 std::atomic<s32> num_sessions{};
56 std::atomic<s32> peak_sessions{};
57 s32 max_sessions{};
58 KPort* parent{};
59};
60
61} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
new file mode 100644
index 000000000..8ad1be762
--- /dev/null
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -0,0 +1,32 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/hle_ipc.h"
6#include "core/hle/kernel/k_client_session.h"
7#include "core/hle/kernel/k_server_session.h"
8#include "core/hle/kernel/k_session.h"
9#include "core/hle/kernel/k_thread.h"
10#include "core/hle/kernel/svc_results.h"
11#include "core/hle/result.h"
12
13namespace Kernel {
14
15KClientSession::KClientSession(KernelCore& kernel_)
16 : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
17KClientSession::~KClientSession() = default;
18
19void KClientSession::Destroy() {
20 parent->OnClientClosed();
21 parent->Close();
22}
23
24void KClientSession::OnServerClosed() {}
25
26ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
27 Core::Timing::CoreTiming& core_timing) {
28 // Signal the server session that new data is available
29 return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing);
30}
31
32} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h
new file mode 100644
index 000000000..720a8c243
--- /dev/null
+++ b/src/core/hle/kernel/k_client_session.h
@@ -0,0 +1,61 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include "core/hle/kernel/k_auto_object.h"
11#include "core/hle/kernel/k_synchronization_object.h"
12#include "core/hle/kernel/slab_helpers.h"
13#include "core/hle/result.h"
14
15union ResultCode;
16
17namespace Core::Memory {
18class Memory;
19}
20
21namespace Core::Timing {
22class CoreTiming;
23}
24
25namespace Kernel {
26
27class KernelCore;
28class KSession;
29class KThread;
30
31class KClientSession final
32 : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> {
33 KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
34
35public:
36 explicit KClientSession(KernelCore& kernel_);
37 virtual ~KClientSession();
38
39 void Initialize(KSession* parent_, std::string&& name_) {
40 // Set member variables.
41 parent = parent_;
42 name = std::move(name_);
43 }
44
45 virtual void Destroy() override;
46 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
47
48 KSession* GetParent() const {
49 return parent;
50 }
51
52 ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
53 Core::Timing::CoreTiming& core_timing);
54
55 void OnServerClosed();
56
57private:
58 KSession* parent{};
59};
60
61} // namespace Kernel
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 170d8fa0d..ce3bade60 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -7,12 +7,13 @@
7#include "core/arm/exclusive_monitor.h" 7#include "core/arm/exclusive_monitor.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/k_condition_variable.h" 9#include "core/hle/kernel/k_condition_variable.h"
10#include "core/hle/kernel/k_linked_list.h"
11#include "core/hle/kernel/k_process.h"
10#include "core/hle/kernel/k_scheduler.h" 12#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 13#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
12#include "core/hle/kernel/k_synchronization_object.h" 14#include "core/hle/kernel/k_synchronization_object.h"
13#include "core/hle/kernel/k_thread.h" 15#include "core/hle/kernel/k_thread.h"
14#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/process.h"
16#include "core/hle/kernel/svc_common.h" 17#include "core/hle/kernel/svc_common.h"
17#include "core/hle/kernel/svc_results.h" 18#include "core/hle/kernel/svc_results.h"
18#include "core/memory.h" 19#include "core/memory.h"
@@ -107,8 +108,8 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
107 108
108 // Wait for the address. 109 // Wait for the address.
109 { 110 {
110 std::shared_ptr<KThread> owner_thread; 111 KScopedAutoObject<KThread> owner_thread;
111 ASSERT(!owner_thread); 112 ASSERT(owner_thread.IsNull());
112 { 113 {
113 KScopedSchedulerLock sl(kernel); 114 KScopedSchedulerLock sl(kernel);
114 cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS); 115 cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
@@ -126,8 +127,10 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
126 R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS); 127 R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
127 128
128 // Get the lock owner thread. 129 // Get the lock owner thread.
129 owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle); 130 owner_thread =
130 R_UNLESS(owner_thread, ResultInvalidHandle); 131 kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>(
132 handle);
133 R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle);
131 134
132 // Update the lock. 135 // Update the lock.
133 cur_thread->SetAddressKey(addr, value); 136 cur_thread->SetAddressKey(addr, value);
@@ -137,7 +140,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
137 cur_thread->SetMutexWaitAddressForDebugging(addr); 140 cur_thread->SetMutexWaitAddressForDebugging(addr);
138 } 141 }
139 } 142 }
140 ASSERT(owner_thread); 143 ASSERT(owner_thread.IsNotNull());
141 } 144 }
142 145
143 // Remove the thread as a waiter from the lock owner. 146 // Remove the thread as a waiter from the lock owner.
@@ -176,19 +179,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
176 179
177 KThread* thread_to_close = nullptr; 180 KThread* thread_to_close = nullptr;
178 if (can_access) { 181 if (can_access) {
179 if (prev_tag == InvalidHandle) { 182 if (prev_tag == Svc::InvalidHandle) {
180 // If nobody held the lock previously, we're all good. 183 // If nobody held the lock previously, we're all good.
181 thread->SetSyncedObject(nullptr, RESULT_SUCCESS); 184 thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
182 thread->Wakeup(); 185 thread->Wakeup();
183 } else { 186 } else {
184 // Get the previous owner. 187 // Get the previous owner.
185 auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>( 188 KThread* owner_thread = kernel.CurrentProcess()
186 prev_tag & ~Svc::HandleWaitMask); 189 ->GetHandleTable()
190 .GetObjectWithoutPseudoHandle<KThread>(
191 static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
192 .ReleasePointerUnsafe();
187 193
188 if (owner_thread) { 194 if (owner_thread) {
189 // Add the thread as a waiter on the owner. 195 // Add the thread as a waiter on the owner.
190 owner_thread->AddWaiter(thread); 196 owner_thread->AddWaiter(thread);
191 thread_to_close = owner_thread.get(); 197 thread_to_close = owner_thread;
192 } else { 198 } else {
193 // The lock was tagged with a thread that doesn't exist. 199 // The lock was tagged with a thread that doesn't exist.
194 thread->SetSyncedObject(nullptr, ResultInvalidState); 200 thread->SetSyncedObject(nullptr, ResultInvalidState);
@@ -208,9 +214,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
208 // Prepare for signaling. 214 // Prepare for signaling.
209 constexpr int MaxThreads = 16; 215 constexpr int MaxThreads = 16;
210 216
211 // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using 217 KLinkedList<KThread> thread_list{kernel};
212 // std::shared_ptr.
213 std::vector<std::shared_ptr<KThread>> thread_list;
214 std::array<KThread*, MaxThreads> thread_array; 218 std::array<KThread*, MaxThreads> thread_array;
215 s32 num_to_close{}; 219 s32 num_to_close{};
216 220
@@ -228,7 +232,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
228 if (num_to_close < MaxThreads) { 232 if (num_to_close < MaxThreads) {
229 thread_array[num_to_close++] = thread; 233 thread_array[num_to_close++] = thread;
230 } else { 234 } else {
231 thread_list.push_back(SharedFrom(thread)); 235 thread_list.push_back(*thread);
232 } 236 }
233 } 237 }
234 238
@@ -251,7 +255,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
251 255
252 // Close threads in the list. 256 // Close threads in the list.
253 for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { 257 for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) {
254 (*it)->Close(); 258 (*it).Close();
255 } 259 }
256} 260}
257 261
diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp
index bb2fa4ad5..0720efece 100644
--- a/src/core/hle/kernel/k_event.cpp
+++ b/src/core/hle/kernel/k_event.cpp
@@ -3,30 +3,54 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/kernel/k_event.h" 5#include "core/hle/kernel/k_event.h"
6#include "core/hle/kernel/k_readable_event.h" 6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_writable_event.h" 7#include "core/hle/kernel/k_resource_limit.h"
8 8
9namespace Kernel { 9namespace Kernel {
10 10
11KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {} 11KEvent::KEvent(KernelCore& kernel_)
12 : KAutoObjectWithSlabHeapAndContainer{kernel_}, readable_event{kernel_}, writable_event{
13 kernel_} {}
12 14
13KEvent::~KEvent() = default; 15KEvent::~KEvent() = default;
14 16
15std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) { 17void KEvent::Initialize(std::string&& name_) {
16 return std::make_shared<KEvent>(kernel, std::move(name)); 18 // Increment reference count.
17} 19 // Because reference count is one on creation, this will result
20 // in a reference count of two. Thus, when both readable and
21 // writable events are closed this object will be destroyed.
22 Open();
18 23
19void KEvent::Initialize() {
20 // Create our sub events. 24 // Create our sub events.
21 readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable"); 25 KAutoObject::Create(std::addressof(readable_event));
22 writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable"); 26 KAutoObject::Create(std::addressof(writable_event));
23 27
24 // Initialize our sub sessions. 28 // Initialize our sub sessions.
25 readable_event->Initialize(this); 29 readable_event.Initialize(this, name_ + ":Readable");
26 writable_event->Initialize(this); 30 writable_event.Initialize(this, name_ + ":Writable");
31
32 // Set our owner process.
33 owner = kernel.CurrentProcess();
34 if (owner) {
35 owner->Open();
36 }
27 37
28 // Mark initialized. 38 // Mark initialized.
39 name = std::move(name_);
29 initialized = true; 40 initialized = true;
30} 41}
31 42
43void KEvent::Finalize() {
44 KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList>::Finalize();
45}
46
47void KEvent::PostDestroy(uintptr_t arg) {
48 // Release the event count resource the owner process holds.
49 KProcess* owner = reinterpret_cast<KProcess*>(arg);
50 if (owner) {
51 owner->GetResourceLimit()->Release(LimitableResource::Events, 1);
52 owner->Close();
53 }
54}
55
32} // namespace Kernel 56} // namespace Kernel
diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h
index 2fb887129..9a59ffb70 100644
--- a/src/core/hle/kernel/k_event.h
+++ b/src/core/hle/kernel/k_event.h
@@ -4,53 +4,54 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/k_readable_event.h"
8#include "core/hle/kernel/k_writable_event.h"
9#include "core/hle/kernel/slab_helpers.h"
8 10
9namespace Kernel { 11namespace Kernel {
10 12
11class KernelCore; 13class KernelCore;
12class KReadableEvent; 14class KReadableEvent;
13class KWritableEvent; 15class KWritableEvent;
16class KProcess;
14 17
15class KEvent final : public Object { 18class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList> {
16public: 19 KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject);
17 explicit KEvent(KernelCore& kernel, std::string&& name);
18 ~KEvent() override;
19 20
20 static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name); 21public:
22 explicit KEvent(KernelCore& kernel_);
23 virtual ~KEvent();
21 24
22 void Initialize(); 25 void Initialize(std::string&& name);
23 26
24 void Finalize() override {} 27 virtual void Finalize() override;
25 28
26 std::string GetTypeName() const override { 29 virtual bool IsInitialized() const override {
27 return "KEvent"; 30 return initialized;
28 } 31 }
29 32
30 static constexpr HandleType HANDLE_TYPE = HandleType::Event; 33 virtual uintptr_t GetPostDestroyArgument() const override {
31 HandleType GetHandleType() const override { 34 return reinterpret_cast<uintptr_t>(owner);
32 return HANDLE_TYPE;
33 } 35 }
34 36
35 std::shared_ptr<KReadableEvent>& GetReadableEvent() { 37 static void PostDestroy(uintptr_t arg);
36 return readable_event;
37 }
38 38
39 std::shared_ptr<KWritableEvent>& GetWritableEvent() { 39 virtual KProcess* GetOwner() const override {
40 return writable_event; 40 return owner;
41 } 41 }
42 42
43 const std::shared_ptr<KReadableEvent>& GetReadableEvent() const { 43 KReadableEvent& GetReadableEvent() {
44 return readable_event; 44 return readable_event;
45 } 45 }
46 46
47 const std::shared_ptr<KWritableEvent>& GetWritableEvent() const { 47 KWritableEvent& GetWritableEvent() {
48 return writable_event; 48 return writable_event;
49 } 49 }
50 50
51private: 51private:
52 std::shared_ptr<KReadableEvent> readable_event; 52 KReadableEvent readable_event;
53 std::shared_ptr<KWritableEvent> writable_event; 53 KWritableEvent writable_event;
54 KProcess* owner{};
54 bool initialized{}; 55 bool initialized{};
55}; 56};
56 57
diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp
new file mode 100644
index 000000000..0378447f6
--- /dev/null
+++ b/src/core/hle/kernel/k_handle_table.cpp
@@ -0,0 +1,135 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_handle_table.h"
6
7namespace Kernel {
8
9KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
10KHandleTable ::~KHandleTable() = default;
11
12ResultCode KHandleTable::Finalize() {
13 // Get the table and clear our record of it.
14 u16 saved_table_size = 0;
15 {
16 KScopedSpinLock lk(m_lock);
17
18 std::swap(m_table_size, saved_table_size);
19 }
20
21 // Close and free all entries.
22 for (size_t i = 0; i < saved_table_size; i++) {
23 if (KAutoObject* obj = m_objects[i]; obj != nullptr) {
24 obj->Close();
25 }
26 }
27
28 return RESULT_SUCCESS;
29}
30
31bool KHandleTable::Remove(Handle handle) {
32 // Don't allow removal of a pseudo-handle.
33 if (Svc::IsPseudoHandle(handle)) {
34 return false;
35 }
36
37 // Handles must not have reserved bits set.
38 const auto handle_pack = HandlePack(handle);
39 if (handle_pack.reserved != 0) {
40 return false;
41 }
42
43 // Find the object and free the entry.
44 KAutoObject* obj = nullptr;
45 {
46 KScopedSpinLock lk(m_lock);
47
48 if (this->IsValidHandle(handle)) {
49 const auto index = handle_pack.index;
50
51 obj = m_objects[index];
52 this->FreeEntry(index);
53 } else {
54 return false;
55 }
56 }
57
58 // Close the object.
59 obj->Close();
60 return true;
61}
62
63ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
64 KScopedSpinLock lk(m_lock);
65
66 // Never exceed our capacity.
67 R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
68
69 // Allocate entry, set output handle.
70 {
71 const auto linear_id = this->AllocateLinearId();
72 const auto index = this->AllocateEntry();
73
74 m_entry_infos[index].info = {.linear_id = linear_id, .type = type};
75 m_objects[index] = obj;
76
77 obj->Open();
78
79 *out_handle = EncodeHandle(static_cast<u16>(index), linear_id);
80 }
81
82 return RESULT_SUCCESS;
83}
84
85ResultCode KHandleTable::Reserve(Handle* out_handle) {
86 KScopedSpinLock lk(m_lock);
87
88 // Never exceed our capacity.
89 R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
90
91 *out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId());
92 return RESULT_SUCCESS;
93}
94
95void KHandleTable::Unreserve(Handle handle) {
96 KScopedSpinLock lk(m_lock);
97
98 // Unpack the handle.
99 const auto handle_pack = HandlePack(handle);
100 const auto index = handle_pack.index;
101 const auto linear_id = handle_pack.linear_id;
102 const auto reserved = handle_pack.reserved;
103 ASSERT(reserved == 0);
104 ASSERT(linear_id != 0);
105
106 if (index < m_table_size) {
107 // NOTE: This code does not check the linear id.
108 ASSERT(m_objects[index] == nullptr);
109 this->FreeEntry(index);
110 }
111}
112
113void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) {
114 KScopedSpinLock lk(m_lock);
115
116 // Unpack the handle.
117 const auto handle_pack = HandlePack(handle);
118 const auto index = handle_pack.index;
119 const auto linear_id = handle_pack.linear_id;
120 const auto reserved = handle_pack.reserved;
121 ASSERT(reserved == 0);
122 ASSERT(linear_id != 0);
123
124 if (index < m_table_size) {
125 // Set the entry.
126 ASSERT(m_objects[index] == nullptr);
127
128 m_entry_infos[index].info = {.linear_id = static_cast<u16>(linear_id), .type = type};
129 m_objects[index] = obj;
130
131 obj->Open();
132 }
133}
134
135} // namespace Kernel
diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h
new file mode 100644
index 000000000..ba9dd061d
--- /dev/null
+++ b/src/core/hle/kernel/k_handle_table.h
@@ -0,0 +1,310 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/bit_util.h"
12#include "common/common_types.h"
13#include "core/hle/kernel/k_auto_object.h"
14#include "core/hle/kernel/k_spin_lock.h"
15#include "core/hle/kernel/k_thread.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/svc_common.h"
18#include "core/hle/kernel/svc_results.h"
19#include "core/hle/result.h"
20
21namespace Kernel {
22
23class KernelCore;
24
25class KHandleTable {
26 YUZU_NON_COPYABLE(KHandleTable);
27 YUZU_NON_MOVEABLE(KHandleTable);
28
29public:
30 static constexpr size_t MaxTableSize = 1024;
31
32public:
33 explicit KHandleTable(KernelCore& kernel_);
34 ~KHandleTable();
35
36 ResultCode Initialize(s32 size) {
37 R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
38
39 // Initialize all fields.
40 m_max_count = 0;
41 m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size);
42 m_next_linear_id = MinLinearId;
43 m_count = 0;
44 m_free_head_index = -1;
45
46 // Free all entries.
47 for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
48 m_objects[i] = nullptr;
49 m_entry_infos[i].next_free_index = i - 1;
50 m_free_head_index = i;
51 }
52
53 return RESULT_SUCCESS;
54 }
55
56 size_t GetTableSize() const {
57 return m_table_size;
58 }
59 size_t GetCount() const {
60 return m_count;
61 }
62 size_t GetMaxCount() const {
63 return m_max_count;
64 }
65
66 ResultCode Finalize();
67 bool Remove(Handle handle);
68
69 template <typename T = KAutoObject>
70 KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
71 // Lock and look up in table.
72 KScopedSpinLock lk(m_lock);
73
74 if constexpr (std::is_same_v<T, KAutoObject>) {
75 return this->GetObjectImpl(handle);
76 } else {
77 if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) {
78 return obj->DynamicCast<T*>();
79 } else {
80 return nullptr;
81 }
82 }
83 }
84
85 template <typename T = KAutoObject>
86 KScopedAutoObject<T> GetObject(Handle handle) const {
87 // Handle pseudo-handles.
88 if constexpr (std::derived_from<KProcess, T>) {
89 if (handle == Svc::PseudoHandle::CurrentProcess) {
90 auto* const cur_process = kernel.CurrentProcess();
91 ASSERT(cur_process != nullptr);
92 return cur_process;
93 }
94 } else if constexpr (std::derived_from<KThread, T>) {
95 if (handle == Svc::PseudoHandle::CurrentThread) {
96 auto* const cur_thread = GetCurrentThreadPointer(kernel);
97 ASSERT(cur_thread != nullptr);
98 return cur_thread;
99 }
100 }
101
102 return this->template GetObjectWithoutPseudoHandle<T>(handle);
103 }
104
105 ResultCode Reserve(Handle* out_handle);
106 void Unreserve(Handle handle);
107
108 template <typename T>
109 ResultCode Add(Handle* out_handle, T* obj) {
110 static_assert(std::is_base_of_v<KAutoObject, T>);
111 return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken());
112 }
113
114 template <typename T>
115 void Register(Handle handle, T* obj) {
116 static_assert(std::is_base_of_v<KAutoObject, T>);
117 return this->Register(handle, obj, obj->GetTypeObj().GetClassToken());
118 }
119
120 template <typename T>
121 bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
122 // Try to convert and open all the handles.
123 size_t num_opened;
124 {
125 // Lock the table.
126 KScopedSpinLock lk(m_lock);
127 for (num_opened = 0; num_opened < num_handles; num_opened++) {
128 // Get the current handle.
129 const auto cur_handle = handles[num_opened];
130
131 // Get the object for the current handle.
132 KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
133 if (cur_object == nullptr) {
134 break;
135 }
136
137 // Cast the current object to the desired type.
138 T* cur_t = cur_object->DynamicCast<T*>();
139 if (cur_t == nullptr) {
140 break;
141 }
142
143 // Open a reference to the current object.
144 cur_t->Open();
145 out[num_opened] = cur_t;
146 }
147 }
148
149 // If we converted every object, succeed.
150 if (num_opened == num_handles) {
151 return true;
152 }
153
154 // If we didn't convert entry object, close the ones we opened.
155 for (size_t i = 0; i < num_opened; i++) {
156 out[i]->Close();
157 }
158
159 return false;
160 }
161
162private:
163 ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type);
164 void Register(Handle handle, KAutoObject* obj, u16 type);
165
166 s32 AllocateEntry() {
167 ASSERT(m_count < m_table_size);
168
169 const auto index = m_free_head_index;
170
171 m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
172
173 m_max_count = std::max(m_max_count, ++m_count);
174
175 return index;
176 }
177
178 void FreeEntry(s32 index) {
179 ASSERT(m_count > 0);
180
181 m_objects[index] = nullptr;
182 m_entry_infos[index].next_free_index = m_free_head_index;
183
184 m_free_head_index = index;
185
186 --m_count;
187 }
188
189 u16 AllocateLinearId() {
190 const u16 id = m_next_linear_id++;
191 if (m_next_linear_id > MaxLinearId) {
192 m_next_linear_id = MinLinearId;
193 }
194 return id;
195 }
196
197 bool IsValidHandle(Handle handle) const {
198 // Unpack the handle.
199 const auto handle_pack = HandlePack(handle);
200 const auto raw_value = handle_pack.raw;
201 const auto index = handle_pack.index;
202 const auto linear_id = handle_pack.linear_id;
203 const auto reserved = handle_pack.reserved;
204 ASSERT(reserved == 0);
205
206 // Validate our indexing information.
207 if (raw_value == 0) {
208 return false;
209 }
210 if (linear_id == 0) {
211 return false;
212 }
213 if (index >= m_table_size) {
214 return false;
215 }
216
217 // Check that there's an object, and our serial id is correct.
218 if (m_objects[index] == nullptr) {
219 return false;
220 }
221 if (m_entry_infos[index].GetLinearId() != linear_id) {
222 return false;
223 }
224
225 return true;
226 }
227
228 KAutoObject* GetObjectImpl(Handle handle) const {
229 // Handles must not have reserved bits set.
230 const auto handle_pack = HandlePack(handle);
231 if (handle_pack.reserved != 0) {
232 return nullptr;
233 }
234
235 if (this->IsValidHandle(handle)) {
236 return m_objects[handle_pack.index];
237 } else {
238 return nullptr;
239 }
240 }
241
242 KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
243
244 // Index must be in bounds.
245 if (index >= m_table_size) {
246 return nullptr;
247 }
248
249 // Ensure entry has an object.
250 if (KAutoObject* obj = m_objects[index]; obj != nullptr) {
251 *out_handle = EncodeHandle(static_cast<u16>(index), m_entry_infos[index].GetLinearId());
252 return obj;
253 } else {
254 return nullptr;
255 }
256 }
257
258private:
259 union HandlePack {
260 HandlePack() = default;
261 HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
262
263 u32 raw;
264 BitField<0, 15, u32> index;
265 BitField<15, 15, u32> linear_id;
266 BitField<30, 2, u32> reserved;
267 };
268
269 static constexpr u16 MinLinearId = 1;
270 static constexpr u16 MaxLinearId = 0x7FFF;
271
272 static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
273 HandlePack handle{};
274 handle.index.Assign(index);
275 handle.linear_id.Assign(linear_id);
276 handle.reserved.Assign(0);
277 return handle.raw;
278 }
279
280 union EntryInfo {
281 struct {
282 u16 linear_id;
283 u16 type;
284 } info;
285 s32 next_free_index;
286
287 constexpr u16 GetLinearId() const {
288 return info.linear_id;
289 }
290 constexpr u16 GetType() const {
291 return info.type;
292 }
293 constexpr s32 GetNextFreeIndex() const {
294 return next_free_index;
295 }
296 };
297
298private:
299 std::array<EntryInfo, MaxTableSize> m_entry_infos{};
300 std::array<KAutoObject*, MaxTableSize> m_objects{};
301 s32 m_free_head_index{-1};
302 u16 m_table_size{};
303 u16 m_max_count{};
304 u16 m_next_linear_id{MinLinearId};
305 u16 m_count{};
306 mutable KSpinLock m_lock;
307 KernelCore& kernel;
308};
309
310} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
index 362d0db28..ca2e539a7 100644
--- a/src/core/hle/kernel/k_light_condition_variable.h
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -18,7 +18,8 @@ class KernelCore;
18 18
19class KLightConditionVariable { 19class KLightConditionVariable {
20public: 20public:
21 explicit KLightConditionVariable(KernelCore& kernel) : thread_queue(kernel), kernel(kernel) {} 21 explicit KLightConditionVariable(KernelCore& kernel_)
22 : thread_queue(kernel_), kernel(kernel_) {}
22 23
23 void Wait(KLightLock* lock, s64 timeout = -1) { 24 void Wait(KLightLock* lock, s64 timeout = -1) {
24 WaitImpl(lock, timeout); 25 WaitImpl(lock, timeout);
diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h
new file mode 100644
index 000000000..6adfe1e34
--- /dev/null
+++ b/src/core/hle/kernel/k_linked_list.h
@@ -0,0 +1,238 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <boost/intrusive/list.hpp>
8
9#include "common/assert.h"
10#include "core/hle/kernel/slab_helpers.h"
11
12namespace Kernel {
13
14class KernelCore;
15
16class KLinkedListNode : public boost::intrusive::list_base_hook<>,
17 public KSlabAllocated<KLinkedListNode> {
18
19public:
20 KLinkedListNode() = default;
21
22 void Initialize(void* it) {
23 m_item = it;
24 }
25
26 void* GetItem() const {
27 return m_item;
28 }
29
30private:
31 void* m_item = nullptr;
32};
33
34template <typename T>
35class KLinkedList : private boost::intrusive::list<KLinkedListNode> {
36private:
37 using BaseList = boost::intrusive::list<KLinkedListNode>;
38
39public:
40 template <bool Const>
41 class Iterator;
42
43 using value_type = T;
44 using size_type = size_t;
45 using difference_type = ptrdiff_t;
46 using pointer = value_type*;
47 using const_pointer = const value_type*;
48 using reference = value_type&;
49 using const_reference = const value_type&;
50 using iterator = Iterator<false>;
51 using const_iterator = Iterator<true>;
52 using reverse_iterator = std::reverse_iterator<iterator>;
53 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
54
55 template <bool Const>
56 class Iterator {
57 private:
58 using BaseIterator = BaseList::iterator;
59 friend class KLinkedList;
60
61 public:
62 using iterator_category = std::bidirectional_iterator_tag;
63 using value_type = typename KLinkedList::value_type;
64 using difference_type = typename KLinkedList::difference_type;
65 using pointer = std::conditional_t<Const, KLinkedList::const_pointer, KLinkedList::pointer>;
66 using reference =
67 std::conditional_t<Const, KLinkedList::const_reference, KLinkedList::reference>;
68
69 public:
70 explicit Iterator(BaseIterator it) : m_base_it(it) {}
71
72 pointer GetItem() const {
73 return static_cast<pointer>(m_base_it->GetItem());
74 }
75
76 bool operator==(const Iterator& rhs) const {
77 return m_base_it == rhs.m_base_it;
78 }
79
80 bool operator!=(const Iterator& rhs) const {
81 return !(*this == rhs);
82 }
83
84 pointer operator->() const {
85 return this->GetItem();
86 }
87
88 reference operator*() const {
89 return *this->GetItem();
90 }
91
92 Iterator& operator++() {
93 ++m_base_it;
94 return *this;
95 }
96
97 Iterator& operator--() {
98 --m_base_it;
99 return *this;
100 }
101
102 Iterator operator++(int) {
103 const Iterator it{*this};
104 ++(*this);
105 return it;
106 }
107
108 Iterator operator--(int) {
109 const Iterator it{*this};
110 --(*this);
111 return it;
112 }
113
114 operator Iterator<true>() const {
115 return Iterator<true>(m_base_it);
116 }
117
118 private:
119 BaseIterator m_base_it;
120 };
121
122public:
123 constexpr KLinkedList(KernelCore& kernel_) : BaseList(), kernel{kernel_} {}
124
125 ~KLinkedList() {
126 // Erase all elements.
127 for (auto it = begin(); it != end(); it = erase(it)) {
128 }
129
130 // Ensure we succeeded.
131 ASSERT(this->empty());
132 }
133
134 // Iterator accessors.
135 iterator begin() {
136 return iterator(BaseList::begin());
137 }
138
139 const_iterator begin() const {
140 return const_iterator(BaseList::begin());
141 }
142
143 iterator end() {
144 return iterator(BaseList::end());
145 }
146
147 const_iterator end() const {
148 return const_iterator(BaseList::end());
149 }
150
151 const_iterator cbegin() const {
152 return this->begin();
153 }
154
155 const_iterator cend() const {
156 return this->end();
157 }
158
159 reverse_iterator rbegin() {
160 return reverse_iterator(this->end());
161 }
162
163 const_reverse_iterator rbegin() const {
164 return const_reverse_iterator(this->end());
165 }
166
167 reverse_iterator rend() {
168 return reverse_iterator(this->begin());
169 }
170
171 const_reverse_iterator rend() const {
172 return const_reverse_iterator(this->begin());
173 }
174
175 const_reverse_iterator crbegin() const {
176 return this->rbegin();
177 }
178
179 const_reverse_iterator crend() const {
180 return this->rend();
181 }
182
183 // Content management.
184 using BaseList::empty;
185 using BaseList::size;
186
187 reference back() {
188 return *(--this->end());
189 }
190
191 const_reference back() const {
192 return *(--this->end());
193 }
194
195 reference front() {
196 return *this->begin();
197 }
198
199 const_reference front() const {
200 return *this->begin();
201 }
202
203 iterator insert(const_iterator pos, reference ref) {
204 KLinkedListNode* new_node = KLinkedListNode::Allocate(kernel);
205 ASSERT(new_node != nullptr);
206 new_node->Initialize(std::addressof(ref));
207 return iterator(BaseList::insert(pos.m_base_it, *new_node));
208 }
209
210 void push_back(reference ref) {
211 this->insert(this->end(), ref);
212 }
213
214 void push_front(reference ref) {
215 this->insert(this->begin(), ref);
216 }
217
218 void pop_back() {
219 this->erase(--this->end());
220 }
221
222 void pop_front() {
223 this->erase(this->begin());
224 }
225
226 iterator erase(const iterator pos) {
227 KLinkedListNode* freed_node = std::addressof(*pos.m_base_it);
228 iterator ret = iterator(BaseList::erase(pos.m_base_it));
229 KLinkedListNode::Free(kernel, freed_node);
230
231 return ret;
232 }
233
234private:
235 KernelCore& kernel;
236};
237
238} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h
index c5b9c5e85..a7fdb5fb8 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -134,6 +134,10 @@ enum class KMemoryPermission : u8 {
134}; 134};
135DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); 135DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
136 136
137constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) {
138 return static_cast<KMemoryPermission>(perm);
139}
140
137enum class KMemoryAttribute : u8 { 141enum class KMemoryAttribute : u8 {
138 None = 0x00, 142 None = 0x00,
139 Mask = 0x7F, 143 Mask = 0x7F,
diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp
index 4a2d88008..fc7033564 100644
--- a/src/core/hle/kernel/k_memory_block_manager.cpp
+++ b/src/core/hle/kernel/k_memory_block_manager.cpp
@@ -7,8 +7,8 @@
7 7
8namespace Kernel { 8namespace Kernel {
9 9
10KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr) 10KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr_, VAddr end_addr_)
11 : start_addr{start_addr}, end_addr{end_addr} { 11 : start_addr{start_addr_}, end_addr{end_addr_} {
12 const u64 num_pages{(end_addr - start_addr) / PageSize}; 12 const u64 num_pages{(end_addr - start_addr) / PageSize};
13 memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free, 13 memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free,
14 KMemoryPermission::None, KMemoryAttribute::None); 14 KMemoryPermission::None, KMemoryAttribute::None);
@@ -17,8 +17,8 @@ KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr)
17KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) { 17KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) {
18 auto node{memory_block_tree.begin()}; 18 auto node{memory_block_tree.begin()};
19 while (node != end()) { 19 while (node != end()) {
20 const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()}; 20 const VAddr node_end_addr{node->GetNumPages() * PageSize + node->GetAddress()};
21 if (node->GetAddress() <= addr && end_addr - 1 >= addr) { 21 if (node->GetAddress() <= addr && node_end_addr - 1 >= addr) {
22 return node; 22 return node;
23 } 23 }
24 node = std::next(node); 24 node = std::next(node);
@@ -67,7 +67,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
67 KMemoryPermission prev_perm, KMemoryAttribute prev_attribute, 67 KMemoryPermission prev_perm, KMemoryAttribute prev_attribute,
68 KMemoryState state, KMemoryPermission perm, 68 KMemoryState state, KMemoryPermission perm,
69 KMemoryAttribute attribute) { 69 KMemoryAttribute attribute) {
70 const VAddr end_addr{addr + num_pages * PageSize}; 70 const VAddr update_end_addr{addr + num_pages * PageSize};
71 iterator node{memory_block_tree.begin()}; 71 iterator node{memory_block_tree.begin()};
72 72
73 prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped; 73 prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped;
@@ -78,7 +78,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
78 const VAddr cur_addr{block->GetAddress()}; 78 const VAddr cur_addr{block->GetAddress()};
79 const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; 79 const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
80 80
81 if (addr < cur_end_addr && cur_addr < end_addr) { 81 if (addr < cur_end_addr && cur_addr < update_end_addr) {
82 if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) { 82 if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) {
83 node = next_node; 83 node = next_node;
84 continue; 84 continue;
@@ -89,8 +89,8 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
89 memory_block_tree.insert(node, block->Split(addr)); 89 memory_block_tree.insert(node, block->Split(addr));
90 } 90 }
91 91
92 if (end_addr < cur_end_addr) { 92 if (update_end_addr < cur_end_addr) {
93 new_node = memory_block_tree.insert(node, block->Split(end_addr)); 93 new_node = memory_block_tree.insert(node, block->Split(update_end_addr));
94 } 94 }
95 95
96 new_node->Update(state, perm, attribute); 96 new_node->Update(state, perm, attribute);
@@ -98,7 +98,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
98 MergeAdjacent(new_node, next_node); 98 MergeAdjacent(new_node, next_node);
99 } 99 }
100 100
101 if (cur_end_addr - 1 >= end_addr - 1) { 101 if (cur_end_addr - 1 >= update_end_addr - 1) {
102 break; 102 break;
103 } 103 }
104 104
@@ -108,7 +108,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
108 108
109void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state, 109void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state,
110 KMemoryPermission perm, KMemoryAttribute attribute) { 110 KMemoryPermission perm, KMemoryAttribute attribute) {
111 const VAddr end_addr{addr + num_pages * PageSize}; 111 const VAddr update_end_addr{addr + num_pages * PageSize};
112 iterator node{memory_block_tree.begin()}; 112 iterator node{memory_block_tree.begin()};
113 113
114 while (node != memory_block_tree.end()) { 114 while (node != memory_block_tree.end()) {
@@ -117,15 +117,15 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
117 const VAddr cur_addr{block->GetAddress()}; 117 const VAddr cur_addr{block->GetAddress()};
118 const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; 118 const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
119 119
120 if (addr < cur_end_addr && cur_addr < end_addr) { 120 if (addr < cur_end_addr && cur_addr < update_end_addr) {
121 iterator new_node{node}; 121 iterator new_node{node};
122 122
123 if (addr > cur_addr) { 123 if (addr > cur_addr) {
124 memory_block_tree.insert(node, block->Split(addr)); 124 memory_block_tree.insert(node, block->Split(addr));
125 } 125 }
126 126
127 if (end_addr < cur_end_addr) { 127 if (update_end_addr < cur_end_addr) {
128 new_node = memory_block_tree.insert(node, block->Split(end_addr)); 128 new_node = memory_block_tree.insert(node, block->Split(update_end_addr));
129 } 129 }
130 130
131 new_node->Update(state, perm, attribute); 131 new_node->Update(state, perm, attribute);
@@ -133,7 +133,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
133 MergeAdjacent(new_node, next_node); 133 MergeAdjacent(new_node, next_node);
134 } 134 }
135 135
136 if (cur_end_addr - 1 >= end_addr - 1) { 136 if (cur_end_addr - 1 >= update_end_addr - 1) {
137 break; 137 break;
138 } 138 }
139 139
@@ -143,7 +143,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
143 143
144void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, 144void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
145 KMemoryPermission perm) { 145 KMemoryPermission perm) {
146 const VAddr end_addr{addr + num_pages * PageSize}; 146 const VAddr update_end_addr{addr + num_pages * PageSize};
147 iterator node{memory_block_tree.begin()}; 147 iterator node{memory_block_tree.begin()};
148 148
149 while (node != memory_block_tree.end()) { 149 while (node != memory_block_tree.end()) {
@@ -152,15 +152,15 @@ void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc
152 const VAddr cur_addr{block->GetAddress()}; 152 const VAddr cur_addr{block->GetAddress()};
153 const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; 153 const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
154 154
155 if (addr < cur_end_addr && cur_addr < end_addr) { 155 if (addr < cur_end_addr && cur_addr < update_end_addr) {
156 iterator new_node{node}; 156 iterator new_node{node};
157 157
158 if (addr > cur_addr) { 158 if (addr > cur_addr) {
159 memory_block_tree.insert(node, block->Split(addr)); 159 memory_block_tree.insert(node, block->Split(addr));
160 } 160 }
161 161
162 if (end_addr < cur_end_addr) { 162 if (update_end_addr < cur_end_addr) {
163 new_node = memory_block_tree.insert(node, block->Split(end_addr)); 163 new_node = memory_block_tree.insert(node, block->Split(update_end_addr));
164 } 164 }
165 165
166 lock_func(new_node, perm); 166 lock_func(new_node, perm);
@@ -168,7 +168,7 @@ void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc
168 MergeAdjacent(new_node, next_node); 168 MergeAdjacent(new_node, next_node);
169 } 169 }
170 170
171 if (cur_end_addr - 1 >= end_addr - 1) { 171 if (cur_end_addr - 1 >= update_end_addr - 1) {
172 break; 172 break;
173 } 173 }
174 174
diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h
index e11cc70c8..d222da919 100644
--- a/src/core/hle/kernel/k_memory_block_manager.h
+++ b/src/core/hle/kernel/k_memory_block_manager.h
@@ -19,7 +19,7 @@ public:
19 using const_iterator = MemoryBlockTree::const_iterator; 19 using const_iterator = MemoryBlockTree::const_iterator;
20 20
21public: 21public:
22 KMemoryBlockManager(VAddr start_addr, VAddr end_addr); 22 KMemoryBlockManager(VAddr start_addr_, VAddr end_addr_);
23 23
24 iterator end() { 24 iterator end() {
25 return memory_block_tree.end(); 25 return memory_block_tree.end();
diff --git a/src/core/hle/kernel/k_memory_region.h b/src/core/hle/kernel/k_memory_region.h
index a861c04ab..90ab8fd62 100644
--- a/src/core/hle/kernel/k_memory_region.h
+++ b/src/core/hle/kernel/k_memory_region.h
@@ -82,9 +82,9 @@ public:
82 type_id = type; 82 type_id = type;
83 } 83 }
84 84
85 constexpr bool Contains(u64 address) const { 85 constexpr bool Contains(u64 addr) const {
86 ASSERT(this->GetEndAddress() != 0); 86 ASSERT(this->GetEndAddress() != 0);
87 return this->GetAddress() <= address && address <= this->GetLastAddress(); 87 return this->GetAddress() <= addr && addr <= this->GetLastAddress();
88 } 88 }
89 89
90 constexpr bool IsDerivedFrom(u32 type) const { 90 constexpr bool IsDerivedFrom(u32 type) const {
diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h
index 64024d01f..dfdac5321 100644
--- a/src/core/hle/kernel/k_page_linked_list.h
+++ b/src/core/hle/kernel/k_page_linked_list.h
@@ -17,7 +17,7 @@ class KPageLinkedList final {
17public: 17public:
18 class Node final { 18 class Node final {
19 public: 19 public:
20 constexpr Node(u64 addr, std::size_t num_pages) : addr{addr}, num_pages{num_pages} {} 20 constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {}
21 21
22 constexpr u64 GetAddress() const { 22 constexpr u64 GetAddress() const {
23 return addr; 23 return addr;
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index d09d5ce48..27dbf0ebc 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -11,11 +11,11 @@
11#include "core/hle/kernel/k_memory_block_manager.h" 11#include "core/hle/kernel/k_memory_block_manager.h"
12#include "core/hle/kernel/k_page_linked_list.h" 12#include "core/hle/kernel/k_page_linked_list.h"
13#include "core/hle/kernel/k_page_table.h" 13#include "core/hle/kernel/k_page_table.h"
14#include "core/hle/kernel/k_process.h"
14#include "core/hle/kernel/k_resource_limit.h" 15#include "core/hle/kernel/k_resource_limit.h"
15#include "core/hle/kernel/k_scoped_resource_reservation.h" 16#include "core/hle/kernel/k_scoped_resource_reservation.h"
16#include "core/hle/kernel/k_system_control.h" 17#include "core/hle/kernel/k_system_control.h"
17#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/process.h"
19#include "core/hle/kernel/svc_results.h" 19#include "core/hle/kernel/svc_results.h"
20#include "core/memory.h" 20#include "core/memory.h"
21 21
@@ -58,7 +58,7 @@ constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr
58 58
59} // namespace 59} // namespace
60 60
61KPageTable::KPageTable(Core::System& system) : system{system} {} 61KPageTable::KPageTable(Core::System& system_) : system{system_} {}
62 62
63ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, 63ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
64 bool enable_aslr, VAddr code_addr, 64 bool enable_aslr, VAddr code_addr,
@@ -420,7 +420,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
420 remaining_size); 420 remaining_size);
421 if (!memory_reservation.Succeeded()) { 421 if (!memory_reservation.Succeeded()) {
422 LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); 422 LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size);
423 return ResultResourceLimitedExceeded; 423 return ResultLimitReached;
424 } 424 }
425 425
426 KPageLinkedList page_linked_list; 426 KPageLinkedList page_linked_list;
@@ -578,7 +578,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
578 AddRegionToPages(dst_addr, num_pages, dst_pages); 578 AddRegionToPages(dst_addr, num_pages, dst_pages);
579 579
580 if (!dst_pages.IsEqual(src_pages)) { 580 if (!dst_pages.IsEqual(src_pages)) {
581 return ResultInvalidMemoryRange; 581 return ResultInvalidMemoryRegion;
582 } 582 }
583 583
584 { 584 {
@@ -641,6 +641,45 @@ ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, K
641 return RESULT_SUCCESS; 641 return RESULT_SUCCESS;
642} 642}
643 643
644ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) {
645 VAddr cur_addr{addr};
646
647 for (const auto& node : page_linked_list.Nodes()) {
648 const std::size_t num_pages{(addr - cur_addr) / PageSize};
649 if (const auto result{
650 Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)};
651 result.IsError()) {
652 return result;
653 }
654
655 cur_addr += node.GetNumPages() * PageSize;
656 }
657
658 return RESULT_SUCCESS;
659}
660
661ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
662 KMemoryState state) {
663 std::lock_guard lock{page_table_lock};
664
665 const std::size_t num_pages{page_linked_list.GetNumPages()};
666 const std::size_t size{num_pages * PageSize};
667
668 if (!CanContain(addr, size, state)) {
669 return ResultInvalidCurrentMemory;
670 }
671
672 if (IsRegionMapped(addr, num_pages * PageSize)) {
673 return ResultInvalidCurrentMemory;
674 }
675
676 CASCADE_CODE(UnmapPages(addr, page_linked_list));
677
678 block_manager->Update(addr, num_pages, state, KMemoryPermission::None);
679
680 return RESULT_SUCCESS;
681}
682
644ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, 683ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size,
645 KMemoryPermission perm) { 684 KMemoryPermission perm) {
646 685
@@ -790,7 +829,7 @@ ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) {
790 829
791 if (!memory_reservation.Succeeded()) { 830 if (!memory_reservation.Succeeded()) {
792 LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); 831 LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta);
793 return ResultResourceLimitedExceeded; 832 return ResultLimitReached;
794 } 833 }
795 834
796 KPageLinkedList page_linked_list; 835 KPageLinkedList page_linked_list;
@@ -867,8 +906,8 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
867 906
868 block_manager->UpdateLock( 907 block_manager->UpdateLock(
869 addr, size / PageSize, 908 addr, size / PageSize,
870 [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { 909 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
871 block->ShareToDevice(perm); 910 block->ShareToDevice(permission);
872 }, 911 },
873 perm); 912 perm);
874 913
@@ -890,8 +929,8 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
890 929
891 block_manager->UpdateLock( 930 block_manager->UpdateLock(
892 addr, size / PageSize, 931 addr, size / PageSize,
893 [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { 932 [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
894 block->UnshareToDevice(perm); 933 block->UnshareToDevice(permission);
895 }, 934 },
896 perm); 935 perm);
897 936
@@ -1067,7 +1106,7 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
1067 } 1106 }
1068} 1107}
1069 1108
1070constexpr bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { 1109bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
1071 const VAddr end{addr + size}; 1110 const VAddr end{addr + size};
1072 const VAddr last{end - 1}; 1111 const VAddr last{end - 1};
1073 const VAddr region_start{GetRegionAddress(state)}; 1112 const VAddr region_start{GetRegionAddress(state)};
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 49b824379..770c4841c 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -24,7 +24,7 @@ class KMemoryBlockManager;
24 24
25class KPageTable final : NonCopyable { 25class KPageTable final : NonCopyable {
26public: 26public:
27 explicit KPageTable(Core::System& system); 27 explicit KPageTable(Core::System& system_);
28 28
29 ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, 29 ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
30 VAddr code_addr, std::size_t code_size, 30 VAddr code_addr, std::size_t code_size,
@@ -40,6 +40,7 @@ public:
40 ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); 40 ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size);
41 ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, 41 ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
42 KMemoryPermission perm); 42 KMemoryPermission perm);
43 ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
43 ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); 44 ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
44 KMemoryInfo QueryInfo(VAddr addr); 45 KMemoryInfo QueryInfo(VAddr addr);
45 ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); 46 ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
@@ -63,6 +64,8 @@ public:
63 return page_table_impl; 64 return page_table_impl;
64 } 65 }
65 66
67 bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const;
68
66private: 69private:
67 enum class OperationType : u32 { 70 enum class OperationType : u32 {
68 Map, 71 Map,
@@ -79,6 +82,7 @@ private:
79 ResultCode InitializeMemoryLayout(VAddr start, VAddr end); 82 ResultCode InitializeMemoryLayout(VAddr start, VAddr end);
80 ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, 83 ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
81 KMemoryPermission perm); 84 KMemoryPermission perm);
85 ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list);
82 void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); 86 void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end);
83 bool IsRegionMapped(VAddr address, u64 size); 87 bool IsRegionMapped(VAddr address, u64 size);
84 bool IsRegionContiguous(VAddr addr, u64 size) const; 88 bool IsRegionContiguous(VAddr addr, u64 size) const;
@@ -92,7 +96,6 @@ private:
92 OperationType operation, PAddr map_addr = 0); 96 OperationType operation, PAddr map_addr = 0);
93 constexpr VAddr GetRegionAddress(KMemoryState state) const; 97 constexpr VAddr GetRegionAddress(KMemoryState state) const;
94 constexpr std::size_t GetRegionSize(KMemoryState state) const; 98 constexpr std::size_t GetRegionSize(KMemoryState state) const;
95 constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const;
96 99
97 constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, 100 constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
98 KMemoryState state, KMemoryPermission perm_mask, 101 KMemoryState state, KMemoryPermission perm_mask,
@@ -216,8 +219,6 @@ public:
216 constexpr PAddr GetPhysicalAddr(VAddr addr) { 219 constexpr PAddr GetPhysicalAddr(VAddr addr) {
217 return page_table_impl.backing_addr[addr >> PageBits] + addr; 220 return page_table_impl.backing_addr[addr >> PageBits] + addr;
218 } 221 }
219
220private:
221 constexpr bool Contains(VAddr addr) const { 222 constexpr bool Contains(VAddr addr) const {
222 return address_space_start <= addr && addr <= address_space_end - 1; 223 return address_space_start <= addr && addr <= address_space_end - 1;
223 } 224 }
@@ -225,6 +226,8 @@ private:
225 return address_space_start <= addr && addr < addr + size && 226 return address_space_start <= addr && addr < addr + size &&
226 addr + size - 1 <= address_space_end - 1; 227 addr + size - 1 <= address_space_end - 1;
227 } 228 }
229
230private:
228 constexpr bool IsKernel() const { 231 constexpr bool IsKernel() const {
229 return is_kernel; 232 return is_kernel;
230 } 233 }
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp
new file mode 100644
index 000000000..feb2bb11f
--- /dev/null
+++ b/src/core/hle/kernel/k_port.cpp
@@ -0,0 +1,68 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/hle_ipc.h"
6#include "core/hle/kernel/k_port.h"
7#include "core/hle/kernel/k_scheduler.h"
8#include "core/hle/kernel/svc_results.h"
9
10namespace Kernel {
11
12KPort::KPort(KernelCore& kernel_)
13 : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
14
15KPort::~KPort() = default;
16
17void KPort::Initialize(s32 max_sessions_, bool is_light_, const std::string& name_) {
18 // Open a new reference count to the initialized port.
19 Open();
20
21 // Create and initialize our server/client pair.
22 KAutoObject::Create(std::addressof(server));
23 KAutoObject::Create(std::addressof(client));
24 server.Initialize(this, name_ + ":Server");
25 client.Initialize(this, max_sessions_, name_ + ":Client");
26
27 // Set our member variables.
28 is_light = is_light_;
29 name = name_;
30 state = State::Normal;
31}
32
33void KPort::OnClientClosed() {
34 KScopedSchedulerLock sl{kernel};
35
36 if (state == State::Normal) {
37 state = State::ClientClosed;
38 }
39}
40
41void KPort::OnServerClosed() {
42 KScopedSchedulerLock sl{kernel};
43
44 if (state == State::Normal) {
45 state = State::ServerClosed;
46 }
47}
48
49bool KPort::IsServerClosed() const {
50 KScopedSchedulerLock sl{kernel};
51 return state == State::ServerClosed;
52}
53
54ResultCode KPort::EnqueueSession(KServerSession* session) {
55 KScopedSchedulerLock sl{kernel};
56
57 R_UNLESS(state == State::Normal, ResultPortClosed);
58
59 if (server.HasHLEHandler()) {
60 server.GetHLEHandler()->ClientConnected(session);
61 } else {
62 server.EnqueueSession(session);
63 }
64
65 return RESULT_SUCCESS;
66}
67
68} // namespace Kernel
diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h
new file mode 100644
index 000000000..960f1f3a3
--- /dev/null
+++ b/src/core/hle/kernel/k_port.h
@@ -0,0 +1,69 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10#include "common/common_types.h"
11#include "core/hle/kernel/k_client_port.h"
12#include "core/hle/kernel/k_server_port.h"
13#include "core/hle/kernel/slab_helpers.h"
14#include "core/hle/result.h"
15
16namespace Kernel {
17
18class KServerSession;
19
20class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> {
21 KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject);
22
23public:
24 explicit KPort(KernelCore& kernel_);
25 virtual ~KPort();
26
27 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
28
29 void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_);
30 void OnClientClosed();
31 void OnServerClosed();
32
33 bool IsLight() const {
34 return is_light;
35 }
36
37 bool IsServerClosed() const;
38
39 ResultCode EnqueueSession(KServerSession* session);
40
41 KClientPort& GetClientPort() {
42 return client;
43 }
44 KServerPort& GetServerPort() {
45 return server;
46 }
47 const KClientPort& GetClientPort() const {
48 return client;
49 }
50 const KServerPort& GetServerPort() const {
51 return server;
52 }
53
54private:
55 enum class State : u8 {
56 Invalid = 0,
57 Normal = 1,
58 ClientClosed = 2,
59 ServerClosed = 3,
60 };
61
62private:
63 KServerPort server;
64 KClientPort client;
65 State state{State::Invalid};
66 bool is_light{};
67};
68
69} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/k_process.cpp
index e35deb8e2..bdcbaeeaa 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -17,13 +17,14 @@
17#include "core/hle/kernel/code_set.h" 17#include "core/hle/kernel/code_set.h"
18#include "core/hle/kernel/k_memory_block_manager.h" 18#include "core/hle/kernel/k_memory_block_manager.h"
19#include "core/hle/kernel/k_page_table.h" 19#include "core/hle/kernel/k_page_table.h"
20#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/k_resource_limit.h" 21#include "core/hle/kernel/k_resource_limit.h"
21#include "core/hle/kernel/k_scheduler.h" 22#include "core/hle/kernel/k_scheduler.h"
22#include "core/hle/kernel/k_scoped_resource_reservation.h" 23#include "core/hle/kernel/k_scoped_resource_reservation.h"
24#include "core/hle/kernel/k_shared_memory.h"
23#include "core/hle/kernel/k_slab_heap.h" 25#include "core/hle/kernel/k_slab_heap.h"
24#include "core/hle/kernel/k_thread.h" 26#include "core/hle/kernel/k_thread.h"
25#include "core/hle/kernel/kernel.h" 27#include "core/hle/kernel/kernel.h"
26#include "core/hle/kernel/process.h"
27#include "core/hle/kernel/svc_results.h" 28#include "core/hle/kernel/svc_results.h"
28#include "core/hle/lock.h" 29#include "core/hle/lock.h"
29#include "core/memory.h" 30#include "core/memory.h"
@@ -37,17 +38,20 @@ namespace {
37 * @param owner_process The parent process for the main thread 38 * @param owner_process The parent process for the main thread
38 * @param priority The priority to give the main thread 39 * @param priority The priority to give the main thread
39 */ 40 */
40void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { 41void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) {
41 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); 42 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
42 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); 43 ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
43 auto thread_res =
44 KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0,
45 owner_process.GetIdealCoreId(), stack_top, &owner_process);
46 44
47 std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap(); 45 KThread* thread = KThread::Create(system.Kernel());
46 ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
47 owner_process.GetIdealCoreId(), &owner_process)
48 .IsSuccess());
48 49
49 // Register 1 must be a handle to the main thread 50 // Register 1 must be a handle to the main thread
50 const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap(); 51 Handle thread_handle{};
52 owner_process.GetHandleTable().Add(&thread_handle, thread);
53
54 thread->SetName("main");
51 thread->GetContext32().cpu_registers[0] = 0; 55 thread->GetContext32().cpu_registers[0] = 0;
52 thread->GetContext64().cpu_registers[0] = 0; 56 thread->GetContext64().cpu_registers[0] = 0;
53 thread->GetContext32().cpu_registers[1] = thread_handle; 57 thread->GetContext32().cpu_registers[1] = thread_handle;
@@ -114,11 +118,11 @@ private:
114 std::bitset<num_slot_entries> is_slot_used; 118 std::bitset<num_slot_entries> is_slot_used;
115}; 119};
116 120
117std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { 121ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name,
122 ProcessType type) {
118 auto& kernel = system.Kernel(); 123 auto& kernel = system.Kernel();
119 124
120 std::shared_ptr<Process> process = std::make_shared<Process>(system); 125 process->name = std::move(process_name);
121 process->name = std::move(name);
122 126
123 process->resource_limit = kernel.GetSystemResourceLimit(); 127 process->resource_limit = kernel.GetSystemResourceLimit();
124 process->status = ProcessStatus::Created; 128 process->status = ProcessStatus::Created;
@@ -126,6 +130,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
126 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() 130 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
127 : kernel.CreateNewUserProcessID(); 131 : kernel.CreateNewUserProcessID();
128 process->capabilities.InitializeForMetadatalessProcess(); 132 process->capabilities.InitializeForMetadatalessProcess();
133 process->is_initialized = true;
129 134
130 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))); 135 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
131 std::uniform_int_distribution<u64> distribution; 136 std::uniform_int_distribution<u64> distribution;
@@ -133,14 +138,18 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
133 [&] { return distribution(rng); }); 138 [&] { return distribution(rng); });
134 139
135 kernel.AppendNewProcess(process); 140 kernel.AppendNewProcess(process);
136 return process; 141
142 // Open a reference to the resource limit.
143 process->resource_limit->Open();
144
145 return RESULT_SUCCESS;
137} 146}
138 147
139std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const { 148KResourceLimit* KProcess::GetResourceLimit() const {
140 return resource_limit; 149 return resource_limit;
141} 150}
142 151
143void Process::IncrementThreadCount() { 152void KProcess::IncrementThreadCount() {
144 ASSERT(num_threads >= 0); 153 ASSERT(num_threads >= 0);
145 num_created_threads++; 154 num_created_threads++;
146 155
@@ -149,7 +158,7 @@ void Process::IncrementThreadCount() {
149 } 158 }
150} 159}
151 160
152void Process::DecrementThreadCount() { 161void KProcess::DecrementThreadCount() {
153 ASSERT(num_threads > 0); 162 ASSERT(num_threads > 0);
154 163
155 if (const auto count = --num_threads; count == 0) { 164 if (const auto count = --num_threads; count == 0) {
@@ -157,31 +166,34 @@ void Process::DecrementThreadCount() {
157 } 166 }
158} 167}
159 168
160u64 Process::GetTotalPhysicalMemoryAvailable() const { 169u64 KProcess::GetTotalPhysicalMemoryAvailable() const {
161 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + 170 const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
162 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + 171 page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
163 main_thread_stack_size}; 172 main_thread_stack_size};
164 ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); 173 if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
174 capacity != pool_size) {
175 LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size);
176 }
165 if (capacity < memory_usage_capacity) { 177 if (capacity < memory_usage_capacity) {
166 return capacity; 178 return capacity;
167 } 179 }
168 return memory_usage_capacity; 180 return memory_usage_capacity;
169} 181}
170 182
171u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { 183u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
172 return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize(); 184 return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize();
173} 185}
174 186
175u64 Process::GetTotalPhysicalMemoryUsed() const { 187u64 KProcess::GetTotalPhysicalMemoryUsed() const {
176 return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() + 188 return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() +
177 GetSystemResourceSize(); 189 GetSystemResourceSize();
178} 190}
179 191
180u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { 192u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
181 return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage(); 193 return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
182} 194}
183 195
184bool Process::ReleaseUserException(KThread* thread) { 196bool KProcess::ReleaseUserException(KThread* thread) {
185 KScopedSchedulerLock sl{kernel}; 197 KScopedSchedulerLock sl{kernel};
186 198
187 if (exception_thread == thread) { 199 if (exception_thread == thread) {
@@ -206,7 +218,7 @@ bool Process::ReleaseUserException(KThread* thread) {
206 } 218 }
207} 219}
208 220
209void Process::PinCurrentThread() { 221void KProcess::PinCurrentThread() {
210 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 222 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
211 223
212 // Get the current thread. 224 // Get the current thread.
@@ -221,7 +233,7 @@ void Process::PinCurrentThread() {
221 KScheduler::SetSchedulerUpdateNeeded(kernel); 233 KScheduler::SetSchedulerUpdateNeeded(kernel);
222} 234}
223 235
224void Process::UnpinCurrentThread() { 236void KProcess::UnpinCurrentThread() {
225 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 237 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
226 238
227 // Get the current thread. 239 // Get the current thread.
@@ -236,15 +248,39 @@ void Process::UnpinCurrentThread() {
236 KScheduler::SetSchedulerUpdateNeeded(kernel); 248 KScheduler::SetSchedulerUpdateNeeded(kernel);
237} 249}
238 250
239void Process::RegisterThread(const KThread* thread) { 251ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
252 [[maybe_unused]] size_t size) {
253 // Lock ourselves, to prevent concurrent access.
254 KScopedLightLock lk(state_lock);
255
256 // TODO(bunnei): Manage KSharedMemoryInfo list here.
257
258 // Open a reference to the shared memory.
259 shmem->Open();
260
261 return RESULT_SUCCESS;
262}
263
264void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
265 [[maybe_unused]] size_t size) {
266 // Lock ourselves, to prevent concurrent access.
267 KScopedLightLock lk(state_lock);
268
269 // TODO(bunnei): Manage KSharedMemoryInfo list here.
270
271 // Close a reference to the shared memory.
272 shmem->Close();
273}
274
275void KProcess::RegisterThread(const KThread* thread) {
240 thread_list.push_back(thread); 276 thread_list.push_back(thread);
241} 277}
242 278
243void Process::UnregisterThread(const KThread* thread) { 279void KProcess::UnregisterThread(const KThread* thread) {
244 thread_list.remove(thread); 280 thread_list.remove(thread);
245} 281}
246 282
247ResultCode Process::Reset() { 283ResultCode KProcess::Reset() {
248 // Lock the process and the scheduler. 284 // Lock the process and the scheduler.
249 KScopedLightLock lk(state_lock); 285 KScopedLightLock lk(state_lock);
250 KScopedSchedulerLock sl{kernel}; 286 KScopedSchedulerLock sl{kernel};
@@ -258,8 +294,8 @@ ResultCode Process::Reset() {
258 return RESULT_SUCCESS; 294 return RESULT_SUCCESS;
259} 295}
260 296
261ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, 297ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
262 std::size_t code_size) { 298 std::size_t code_size) {
263 program_id = metadata.GetTitleID(); 299 program_id = metadata.GetTitleID();
264 ideal_core = metadata.GetMainThreadCore(); 300 ideal_core = metadata.GetMainThreadCore();
265 is_64bit_process = metadata.Is64BitProgram(); 301 is_64bit_process = metadata.Is64BitProgram();
@@ -271,7 +307,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
271 if (!memory_reservation.Succeeded()) { 307 if (!memory_reservation.Succeeded()) {
272 LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", 308 LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
273 code_size + system_resource_size); 309 code_size + system_resource_size);
274 return ResultResourceLimitedExceeded; 310 return ResultLimitReached;
275 } 311 }
276 // Initialize proces address space 312 // Initialize proces address space
277 if (const ResultCode result{ 313 if (const ResultCode result{
@@ -318,10 +354,10 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
318 tls_region_address = CreateTLSRegion(); 354 tls_region_address = CreateTLSRegion();
319 memory_reservation.Commit(); 355 memory_reservation.Commit();
320 356
321 return handle_table.SetSize(capabilities.GetHandleTableSize()); 357 return handle_table.Initialize(capabilities.GetHandleTableSize());
322} 358}
323 359
324void Process::Run(s32 main_thread_priority, u64 stack_size) { 360void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
325 AllocateMainThreadStack(stack_size); 361 AllocateMainThreadStack(stack_size);
326 resource_limit->Reserve(LimitableResource::Threads, 1); 362 resource_limit->Reserve(LimitableResource::Threads, 1);
327 resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); 363 resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
@@ -331,18 +367,18 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
331 367
332 ChangeStatus(ProcessStatus::Running); 368 ChangeStatus(ProcessStatus::Running);
333 369
334 SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); 370 SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top);
335} 371}
336 372
337void Process::PrepareForTermination() { 373void KProcess::PrepareForTermination() {
338 ChangeStatus(ProcessStatus::Exiting); 374 ChangeStatus(ProcessStatus::Exiting);
339 375
340 const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) { 376 const auto stop_threads = [this](const std::vector<KThread*>& in_thread_list) {
341 for (auto& thread : thread_list) { 377 for (auto& thread : in_thread_list) {
342 if (thread->GetOwnerProcess() != this) 378 if (thread->GetOwnerProcess() != this)
343 continue; 379 continue;
344 380
345 if (thread.get() == kernel.CurrentScheduler()->GetCurrentThread()) 381 if (thread == kernel.CurrentScheduler()->GetCurrentThread())
346 continue; 382 continue;
347 383
348 // TODO(Subv): When are the other running/ready threads terminated? 384 // TODO(Subv): When are the other running/ready threads terminated?
@@ -353,7 +389,7 @@ void Process::PrepareForTermination() {
353 } 389 }
354 }; 390 };
355 391
356 stop_threads(system.GlobalSchedulerContext().GetThreadList()); 392 stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList());
357 393
358 FreeTLSRegion(tls_region_address); 394 FreeTLSRegion(tls_region_address);
359 tls_region_address = 0; 395 tls_region_address = 0;
@@ -366,6 +402,16 @@ void Process::PrepareForTermination() {
366 ChangeStatus(ProcessStatus::Exited); 402 ChangeStatus(ProcessStatus::Exited);
367} 403}
368 404
405void KProcess::Finalize() {
406 // Release memory to the resource limit.
407 if (resource_limit != nullptr) {
408 resource_limit->Close();
409 }
410
411 // Perform inherited finalization.
412 KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
413}
414
369/** 415/**
370 * Attempts to find a TLS page that contains a free slot for 416 * Attempts to find a TLS page that contains a free slot for
371 * use by a thread. 417 * use by a thread.
@@ -379,8 +425,8 @@ static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) {
379 [](const auto& page) { return page.HasAvailableSlots(); }); 425 [](const auto& page) { return page.HasAvailableSlots(); });
380} 426}
381 427
382VAddr Process::CreateTLSRegion() { 428VAddr KProcess::CreateTLSRegion() {
383 KScopedSchedulerLock lock(system.Kernel()); 429 KScopedSchedulerLock lock(kernel);
384 if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; 430 if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)};
385 tls_page_iter != tls_pages.cend()) { 431 tls_page_iter != tls_pages.cend()) {
386 return *tls_page_iter->ReserveSlot(); 432 return *tls_page_iter->ReserveSlot();
@@ -391,7 +437,7 @@ VAddr Process::CreateTLSRegion() {
391 437
392 const VAddr start{page_table->GetKernelMapRegionStart()}; 438 const VAddr start{page_table->GetKernelMapRegionStart()};
393 const VAddr size{page_table->GetKernelMapRegionEnd() - start}; 439 const VAddr size{page_table->GetKernelMapRegionEnd() - start};
394 const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; 440 const PAddr tls_map_addr{kernel.System().DeviceMemory().GetPhysicalAddr(tls_page_ptr)};
395 const VAddr tls_page_addr{page_table 441 const VAddr tls_page_addr{page_table
396 ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, 442 ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize,
397 KMemoryState::ThreadLocal, 443 KMemoryState::ThreadLocal,
@@ -410,8 +456,8 @@ VAddr Process::CreateTLSRegion() {
410 return *reserve_result; 456 return *reserve_result;
411} 457}
412 458
413void Process::FreeTLSRegion(VAddr tls_address) { 459void KProcess::FreeTLSRegion(VAddr tls_address) {
414 KScopedSchedulerLock lock(system.Kernel()); 460 KScopedSchedulerLock lock(kernel);
415 const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); 461 const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE);
416 auto iter = 462 auto iter =
417 std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { 463 std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) {
@@ -425,33 +471,34 @@ void Process::FreeTLSRegion(VAddr tls_address) {
425 iter->ReleaseSlot(tls_address); 471 iter->ReleaseSlot(tls_address);
426} 472}
427 473
428void Process::LoadModule(CodeSet code_set, VAddr base_addr) { 474void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
429 std::lock_guard lock{HLE::g_hle_lock}; 475 std::lock_guard lock{HLE::g_hle_lock};
430 const auto ReprotectSegment = [&](const CodeSet::Segment& segment, 476 const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
431 KMemoryPermission permission) { 477 KMemoryPermission permission) {
432 page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); 478 page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
433 }; 479 };
434 480
435 system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size()); 481 kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
482 code_set.memory.size());
436 483
437 ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); 484 ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute);
438 ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); 485 ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read);
439 ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); 486 ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite);
440} 487}
441 488
442bool Process::IsSignaled() const { 489bool KProcess::IsSignaled() const {
443 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 490 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
444 return is_signaled; 491 return is_signaled;
445} 492}
446 493
447Process::Process(Core::System& system) 494KProcess::KProcess(KernelCore& kernel_)
448 : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique<KPageTable>(system)}, 495 : KAutoObjectWithSlabHeapAndContainer{kernel_},
449 handle_table{system.Kernel()}, address_arbiter{system}, condition_var{system}, 496 page_table{std::make_unique<KPageTable>(kernel_.System())}, handle_table{kernel_},
450 state_lock{system.Kernel()}, system{system} {} 497 address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {}
451 498
452Process::~Process() = default; 499KProcess::~KProcess() = default;
453 500
454void Process::ChangeStatus(ProcessStatus new_status) { 501void KProcess::ChangeStatus(ProcessStatus new_status) {
455 if (status == new_status) { 502 if (status == new_status) {
456 return; 503 return;
457 } 504 }
@@ -461,7 +508,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
461 NotifyAvailable(); 508 NotifyAvailable();
462} 509}
463 510
464ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { 511ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) {
465 ASSERT(stack_size); 512 ASSERT(stack_size);
466 513
467 // The kernel always ensures that the given stack size is page aligned. 514 // The kernel always ensures that the given stack size is page aligned.
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/k_process.h
index 45eefb90e..123d71cd3 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -11,11 +11,13 @@
11#include <unordered_map> 11#include <unordered_map>
12#include <vector> 12#include <vector>
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/hle/kernel/handle_table.h"
15#include "core/hle/kernel/k_address_arbiter.h" 14#include "core/hle/kernel/k_address_arbiter.h"
15#include "core/hle/kernel/k_auto_object.h"
16#include "core/hle/kernel/k_condition_variable.h" 16#include "core/hle/kernel/k_condition_variable.h"
17#include "core/hle/kernel/k_handle_table.h"
17#include "core/hle/kernel/k_synchronization_object.h" 18#include "core/hle/kernel/k_synchronization_object.h"
18#include "core/hle/kernel/process_capability.h" 19#include "core/hle/kernel/process_capability.h"
20#include "core/hle/kernel/slab_helpers.h"
19#include "core/hle/result.h" 21#include "core/hle/result.h"
20 22
21namespace Core { 23namespace Core {
@@ -60,10 +62,13 @@ enum class ProcessStatus {
60 DebugBreak, 62 DebugBreak,
61}; 63};
62 64
63class Process final : public KSynchronizationObject { 65class KProcess final
66 : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> {
67 KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
68
64public: 69public:
65 explicit Process(Core::System& system); 70 explicit KProcess(KernelCore& kernel_);
66 ~Process() override; 71 ~KProcess() override;
67 72
68 enum : u64 { 73 enum : u64 {
69 /// Lowest allowed process ID for a kernel initial process. 74 /// Lowest allowed process ID for a kernel initial process.
@@ -85,20 +90,8 @@ public:
85 90
86 static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; 91 static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
87 92
88 static std::shared_ptr<Process> Create(Core::System& system, std::string name, 93 static ResultCode Initialize(KProcess* process, Core::System& system, std::string process_name,
89 ProcessType type); 94 ProcessType type);
90
91 std::string GetTypeName() const override {
92 return "Process";
93 }
94 std::string GetName() const override {
95 return name;
96 }
97
98 static constexpr HandleType HANDLE_TYPE = HandleType::Process;
99 HandleType GetHandleType() const override {
100 return HANDLE_TYPE;
101 }
102 95
103 /// Gets a reference to the process' page table. 96 /// Gets a reference to the process' page table.
104 KPageTable& PageTable() { 97 KPageTable& PageTable() {
@@ -111,12 +104,12 @@ public:
111 } 104 }
112 105
113 /// Gets a reference to the process' handle table. 106 /// Gets a reference to the process' handle table.
114 HandleTable& GetHandleTable() { 107 KHandleTable& GetHandleTable() {
115 return handle_table; 108 return handle_table;
116 } 109 }
117 110
118 /// Gets a const reference to the process' handle table. 111 /// Gets a const reference to the process' handle table.
119 const HandleTable& GetHandleTable() const { 112 const KHandleTable& GetHandleTable() const {
120 return handle_table; 113 return handle_table;
121 } 114 }
122 115
@@ -167,7 +160,7 @@ public:
167 } 160 }
168 161
169 /// Gets the resource limit descriptor for this process 162 /// Gets the resource limit descriptor for this process
170 std::shared_ptr<KResourceLimit> GetResourceLimit() const; 163 KResourceLimit* GetResourceLimit() const;
171 164
172 /// Gets the ideal CPU core ID for this process 165 /// Gets the ideal CPU core ID for this process
173 u8 GetIdealCoreId() const { 166 u8 GetIdealCoreId() const {
@@ -338,9 +331,19 @@ public:
338 331
339 void LoadModule(CodeSet code_set, VAddr base_addr); 332 void LoadModule(CodeSet code_set, VAddr base_addr);
340 333
341 bool IsSignaled() const override; 334 virtual bool IsInitialized() const override {
335 return is_initialized;
336 }
337
338 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
339
340 virtual void Finalize();
341
342 virtual u64 GetId() const override final {
343 return GetProcessID();
344 }
342 345
343 void Finalize() override {} 346 virtual bool IsSignaled() const override;
344 347
345 void PinCurrentThread(); 348 void PinCurrentThread();
346 void UnpinCurrentThread(); 349 void UnpinCurrentThread();
@@ -349,6 +352,9 @@ public:
349 return state_lock; 352 return state_lock;
350 } 353 }
351 354
355 ResultCode AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
356 void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
357
352 /////////////////////////////////////////////////////////////////////////////////////////////// 358 ///////////////////////////////////////////////////////////////////////////////////////////////
353 // Thread-local storage management 359 // Thread-local storage management
354 360
@@ -399,7 +405,7 @@ private:
399 u32 system_resource_size = 0; 405 u32 system_resource_size = 0;
400 406
401 /// Resource limit descriptor for this process 407 /// Resource limit descriptor for this process
402 std::shared_ptr<KResourceLimit> resource_limit; 408 KResourceLimit* resource_limit{};
403 409
404 /// The ideal CPU core for this process, threads are scheduled on this core by default. 410 /// The ideal CPU core for this process, threads are scheduled on this core by default.
405 u8 ideal_core = 0; 411 u8 ideal_core = 0;
@@ -423,7 +429,7 @@ private:
423 u64 total_process_running_time_ticks = 0; 429 u64 total_process_running_time_ticks = 0;
424 430
425 /// Per-process handle table for storing created object handles in. 431 /// Per-process handle table for storing created object handles in.
426 HandleTable handle_table; 432 KHandleTable handle_table;
427 433
428 /// Per-process address arbiter. 434 /// Per-process address arbiter.
429 KAddressArbiter address_arbiter; 435 KAddressArbiter address_arbiter;
@@ -454,14 +460,12 @@ private:
454 /// Process total image size 460 /// Process total image size
455 std::size_t image_size{}; 461 std::size_t image_size{};
456 462
457 /// Name of this process
458 std::string name;
459
460 /// Schedule count of this process 463 /// Schedule count of this process
461 s64 schedule_count{}; 464 s64 schedule_count{};
462 465
463 bool is_signaled{}; 466 bool is_signaled{};
464 bool is_suspended{}; 467 bool is_suspended{};
468 bool is_initialized{};
465 469
466 std::atomic<s32> num_created_threads{}; 470 std::atomic<s32> num_created_threads{};
467 std::atomic<u16> num_threads{}; 471 std::atomic<u16> num_threads{};
@@ -474,9 +478,6 @@ private:
474 KThread* exception_thread{}; 478 KThread* exception_thread{};
475 479
476 KLightLock state_lock; 480 KLightLock state_lock;
477
478 /// System context
479 Core::System& system;
480}; 481};
481 482
482} // namespace Kernel 483} // namespace Kernel
diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp
index 4b4d34857..0ea2d0275 100644
--- a/src/core/hle/kernel/k_readable_event.cpp
+++ b/src/core/hle/kernel/k_readable_event.cpp
@@ -2,21 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include "common/assert.h" 5#include "common/assert.h"
7#include "common/common_funcs.h" 6#include "core/hle/kernel/k_event.h"
8#include "common/logging/log.h"
9#include "core/hle/kernel/k_readable_event.h" 7#include "core/hle/kernel/k_readable_event.h"
10#include "core/hle/kernel/k_scheduler.h" 8#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/k_thread.h" 9#include "core/hle/kernel/k_thread.h"
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/svc_results.h" 11#include "core/hle/kernel/svc_results.h"
15 12
16namespace Kernel { 13namespace Kernel {
17 14
18KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name) 15KReadableEvent::KReadableEvent(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
19 : KSynchronizationObject{kernel, std::move(name)} {} 16
20KReadableEvent::~KReadableEvent() = default; 17KReadableEvent::~KReadableEvent() = default;
21 18
22bool KReadableEvent::IsSignaled() const { 19bool KReadableEvent::IsSignaled() const {
@@ -25,6 +22,12 @@ bool KReadableEvent::IsSignaled() const {
25 return is_signaled; 22 return is_signaled;
26} 23}
27 24
25void KReadableEvent::Destroy() {
26 if (parent) {
27 parent->Close();
28 }
29}
30
28ResultCode KReadableEvent::Signal() { 31ResultCode KReadableEvent::Signal() {
29 KScopedSchedulerLock lk{kernel}; 32 KScopedSchedulerLock lk{kernel};
30 33
diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h
index e6f0fd900..33cd1dd3e 100644
--- a/src/core/hle/kernel/k_readable_event.h
+++ b/src/core/hle/kernel/k_readable_event.h
@@ -4,8 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_auto_object.h"
7#include "core/hle/kernel/k_synchronization_object.h" 8#include "core/hle/kernel/k_synchronization_object.h"
8#include "core/hle/kernel/object.h" 9#include "core/hle/kernel/slab_helpers.h"
9#include "core/hle/result.h" 10#include "core/hle/result.h"
10 11
11namespace Kernel { 12namespace Kernel {
@@ -13,31 +14,25 @@ namespace Kernel {
13class KernelCore; 14class KernelCore;
14class KEvent; 15class KEvent;
15 16
16class KReadableEvent final : public KSynchronizationObject { 17class KReadableEvent : public KSynchronizationObject {
18 KERNEL_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject);
19
17public: 20public:
18 explicit KReadableEvent(KernelCore& kernel, std::string&& name); 21 explicit KReadableEvent(KernelCore& kernel_);
19 ~KReadableEvent() override; 22 ~KReadableEvent() override;
20 23
21 std::string GetTypeName() const override { 24 void Initialize(KEvent* parent_, std::string&& name_) {
22 return "KReadableEvent"; 25 is_signaled = false;
23 } 26 parent = parent_;
24 27 name = std::move(name_);
25 static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
26 HandleType GetHandleType() const override {
27 return HANDLE_TYPE;
28 } 28 }
29 29
30 KEvent* GetParent() const { 30 KEvent* GetParent() const {
31 return parent; 31 return parent;
32 } 32 }
33 33
34 void Initialize(KEvent* parent_) { 34 virtual bool IsSignaled() const override;
35 is_signaled = false; 35 virtual void Destroy() override;
36 parent = parent_;
37 }
38
39 bool IsSignaled() const override;
40 void Finalize() override {}
41 36
42 ResultCode Signal(); 37 ResultCode Signal();
43 ResultCode Clear(); 38 ResultCode Clear();
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index d05b34ea3..bf20bf7d0 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -10,10 +10,16 @@
10namespace Kernel { 10namespace Kernel {
11constexpr s64 DefaultTimeout = 10000000000; // 10 seconds 11constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
12 12
13KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_) 13KResourceLimit::KResourceLimit(KernelCore& kernel_)
14 : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {} 14 : KAutoObjectWithSlabHeapAndContainer{kernel_}, lock{kernel_}, cond_var{kernel_} {}
15KResourceLimit::~KResourceLimit() = default; 15KResourceLimit::~KResourceLimit() = default;
16 16
17void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) {
18 core_timing = core_timing_;
19}
20
21void KResourceLimit::Finalize() {}
22
17s64 KResourceLimit::GetLimitValue(LimitableResource which) const { 23s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
18 const auto index = static_cast<std::size_t>(which); 24 const auto index = static_cast<std::size_t>(which);
19 s64 value{}; 25 s64 value{};
@@ -78,7 +84,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
78} 84}
79 85
80bool KResourceLimit::Reserve(LimitableResource which, s64 value) { 86bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
81 return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout); 87 return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
82} 88}
83 89
84bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { 90bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
@@ -109,7 +115,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
109 } 115 }
110 116
111 if (current_hints[index] + value <= limit_values[index] && 117 if (current_hints[index] + value <= limit_values[index] &&
112 (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) { 118 (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
113 waiter_count++; 119 waiter_count++;
114 cond_var.Wait(&lock, timeout); 120 cond_var.Wait(&lock, timeout);
115 waiter_count--; 121 waiter_count--;
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
index 4542317d0..0debbbb51 100644
--- a/src/core/hle/kernel/k_resource_limit.h
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -8,7 +8,6 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/kernel/k_light_condition_variable.h" 9#include "core/hle/kernel/k_light_condition_variable.h"
10#include "core/hle/kernel/k_light_lock.h" 10#include "core/hle/kernel/k_light_lock.h"
11#include "core/hle/kernel/object.h"
12 11
13union ResultCode; 12union ResultCode;
14 13
@@ -32,10 +31,16 @@ constexpr bool IsValidResourceType(LimitableResource type) {
32 return type < LimitableResource::Count; 31 return type < LimitableResource::Count;
33} 32}
34 33
35class KResourceLimit final : public Object { 34class KResourceLimit final
35 : public KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList> {
36 KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject);
37
36public: 38public:
37 explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_); 39 explicit KResourceLimit(KernelCore& kernel_);
38 ~KResourceLimit(); 40 virtual ~KResourceLimit();
41
42 void Initialize(const Core::Timing::CoreTiming* core_timing_);
43 virtual void Finalize() override;
39 44
40 s64 GetLimitValue(LimitableResource which) const; 45 s64 GetLimitValue(LimitableResource which) const;
41 s64 GetCurrentValue(LimitableResource which) const; 46 s64 GetCurrentValue(LimitableResource which) const;
@@ -49,19 +54,7 @@ public:
49 void Release(LimitableResource which, s64 value); 54 void Release(LimitableResource which, s64 value);
50 void Release(LimitableResource which, s64 value, s64 hint); 55 void Release(LimitableResource which, s64 value, s64 hint);
51 56
52 std::string GetTypeName() const override { 57 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
53 return "KResourceLimit";
54 }
55 std::string GetName() const override {
56 return GetTypeName();
57 }
58
59 static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
60 HandleType GetHandleType() const override {
61 return HANDLE_TYPE;
62 }
63
64 virtual void Finalize() override {}
65 58
66private: 59private:
67 using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>; 60 using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
@@ -72,6 +65,6 @@ private:
72 mutable KLightLock lock; 65 mutable KLightLock lock;
73 s32 waiter_count{}; 66 s32 waiter_count{};
74 KLightConditionVariable cond_var; 67 KLightConditionVariable cond_var;
75 const Core::Timing::CoreTiming& core_timing; 68 const Core::Timing::CoreTiming* core_timing{};
76}; 69};
77} // namespace Kernel 70} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index d1df97305..2f82fbcd6 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -15,12 +15,12 @@
15#include "core/core.h" 15#include "core/core.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/cpu_manager.h" 17#include "core/cpu_manager.h"
18#include "core/hle/kernel/k_process.h"
18#include "core/hle/kernel/k_scheduler.h" 19#include "core/hle/kernel/k_scheduler.h"
19#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 20#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
20#include "core/hle/kernel/k_thread.h" 21#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/physical_core.h" 23#include "core/hle/kernel/physical_core.h"
23#include "core/hle/kernel/process.h"
24#include "core/hle/kernel/time_manager.h" 24#include "core/hle/kernel/time_manager.h"
25 25
26namespace Kernel { 26namespace Kernel {
@@ -71,7 +71,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
71 } 71 }
72 if (state.should_count_idle) { 72 if (state.should_count_idle) {
73 if (highest_thread != nullptr) { 73 if (highest_thread != nullptr) {
74 if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) { 74 if (KProcess* process = highest_thread->GetOwnerProcess(); process != nullptr) {
75 process->SetRunningThread(core_id, highest_thread, state.idle_count); 75 process->SetRunningThread(core_id, highest_thread, state.idle_count);
76 } 76 }
77 } else { 77 } else {
@@ -104,7 +104,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
104 if (top_thread != nullptr) { 104 if (top_thread != nullptr) {
105 // If the thread has no waiters, we need to check if the process has a thread pinned. 105 // If the thread has no waiters, we need to check if the process has a thread pinned.
106 if (top_thread->GetNumKernelWaiters() == 0) { 106 if (top_thread->GetNumKernelWaiters() == 0) {
107 if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) { 107 if (KProcess* parent = top_thread->GetOwnerProcess(); parent != nullptr) {
108 if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id)); 108 if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id));
109 pinned != nullptr && pinned != top_thread) { 109 pinned != nullptr && pinned != top_thread) {
110 // We prefer our parent's pinned thread if possible. However, we also don't 110 // We prefer our parent's pinned thread if possible. However, we also don't
@@ -259,7 +259,7 @@ void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread
259 } 259 }
260} 260}
261 261
262void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) { 262void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) {
263 ASSERT(system.GlobalSchedulerContext().IsLocked()); 263 ASSERT(system.GlobalSchedulerContext().IsLocked());
264 264
265 // Get a reference to the priority queue. 265 // Get a reference to the priority queue.
@@ -267,7 +267,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
267 auto& priority_queue = GetPriorityQueue(kernel); 267 auto& priority_queue = GetPriorityQueue(kernel);
268 268
269 // Rotate the front of the queue to the end. 269 // Rotate the front of the queue to the end.
270 KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority); 270 KThread* top_thread = priority_queue.GetScheduledFront(cpu_core_id, priority);
271 KThread* next_thread = nullptr; 271 KThread* next_thread = nullptr;
272 if (top_thread != nullptr) { 272 if (top_thread != nullptr) {
273 next_thread = priority_queue.MoveToScheduledBack(top_thread); 273 next_thread = priority_queue.MoveToScheduledBack(top_thread);
@@ -279,7 +279,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
279 279
280 // While we have a suggested thread, try to migrate it! 280 // While we have a suggested thread, try to migrate it!
281 { 281 {
282 KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority); 282 KThread* suggested = priority_queue.GetSuggestedFront(cpu_core_id, priority);
283 while (suggested != nullptr) { 283 while (suggested != nullptr) {
284 // Check if the suggested thread is the top thread on its core. 284 // Check if the suggested thread is the top thread on its core.
285 const s32 suggested_core = suggested->GetActiveCore(); 285 const s32 suggested_core = suggested->GetActiveCore();
@@ -300,7 +300,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
300 // to the front of the queue. 300 // to the front of the queue.
301 if (top_on_suggested_core == nullptr || 301 if (top_on_suggested_core == nullptr ||
302 top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) { 302 top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) {
303 suggested->SetActiveCore(core_id); 303 suggested->SetActiveCore(cpu_core_id);
304 priority_queue.ChangeCore(suggested_core, suggested, true); 304 priority_queue.ChangeCore(suggested_core, suggested, true);
305 IncrementScheduledCount(suggested); 305 IncrementScheduledCount(suggested);
306 break; 306 break;
@@ -308,22 +308,22 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
308 } 308 }
309 309
310 // Get the next suggestion. 310 // Get the next suggestion.
311 suggested = priority_queue.GetSamePriorityNext(core_id, suggested); 311 suggested = priority_queue.GetSamePriorityNext(cpu_core_id, suggested);
312 } 312 }
313 } 313 }
314 314
315 // Now that we might have migrated a thread with the same priority, check if we can do better. 315 // Now that we might have migrated a thread with the same priority, check if we can do better.
316 316
317 { 317 {
318 KThread* best_thread = priority_queue.GetScheduledFront(core_id); 318 KThread* best_thread = priority_queue.GetScheduledFront(cpu_core_id);
319 if (best_thread == GetCurrentThread()) { 319 if (best_thread == GetCurrentThread()) {
320 best_thread = priority_queue.GetScheduledNext(core_id, best_thread); 320 best_thread = priority_queue.GetScheduledNext(cpu_core_id, best_thread);
321 } 321 }
322 322
323 // If the best thread we can choose has a priority the same or worse than ours, try to 323 // If the best thread we can choose has a priority the same or worse than ours, try to
324 // migrate a higher priority thread. 324 // migrate a higher priority thread.
325 if (best_thread != nullptr && best_thread->GetPriority() >= priority) { 325 if (best_thread != nullptr && best_thread->GetPriority() >= priority) {
326 KThread* suggested = priority_queue.GetSuggestedFront(core_id); 326 KThread* suggested = priority_queue.GetSuggestedFront(cpu_core_id);
327 while (suggested != nullptr) { 327 while (suggested != nullptr) {
328 // If the suggestion's priority is the same as ours, don't bother. 328 // If the suggestion's priority is the same as ours, don't bother.
329 if (suggested->GetPriority() >= best_thread->GetPriority()) { 329 if (suggested->GetPriority() >= best_thread->GetPriority()) {
@@ -342,7 +342,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
342 if (top_on_suggested_core == nullptr || 342 if (top_on_suggested_core == nullptr ||
343 top_on_suggested_core->GetPriority() >= 343 top_on_suggested_core->GetPriority() >=
344 HighestCoreMigrationAllowedPriority) { 344 HighestCoreMigrationAllowedPriority) {
345 suggested->SetActiveCore(core_id); 345 suggested->SetActiveCore(cpu_core_id);
346 priority_queue.ChangeCore(suggested_core, suggested, true); 346 priority_queue.ChangeCore(suggested_core, suggested, true);
347 IncrementScheduledCount(suggested); 347 IncrementScheduledCount(suggested);
348 break; 348 break;
@@ -350,7 +350,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
350 } 350 }
351 351
352 // Get the next suggestion. 352 // Get the next suggestion.
353 suggested = priority_queue.GetSuggestedNext(core_id, suggested); 353 suggested = priority_queue.GetSuggestedNext(cpu_core_id, suggested);
354 } 354 }
355 } 355 }
356 } 356 }
@@ -411,7 +411,7 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
411 411
412 // Get the current thread and process. 412 // Get the current thread and process.
413 KThread& cur_thread = Kernel::GetCurrentThread(kernel); 413 KThread& cur_thread = Kernel::GetCurrentThread(kernel);
414 Process& cur_process = *kernel.CurrentProcess(); 414 KProcess& cur_process = *kernel.CurrentProcess();
415 415
416 // If the thread's yield count matches, there's nothing for us to do. 416 // If the thread's yield count matches, there's nothing for us to do.
417 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { 417 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -450,7 +450,7 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
450 450
451 // Get the current thread and process. 451 // Get the current thread and process.
452 KThread& cur_thread = Kernel::GetCurrentThread(kernel); 452 KThread& cur_thread = Kernel::GetCurrentThread(kernel);
453 Process& cur_process = *kernel.CurrentProcess(); 453 KProcess& cur_process = *kernel.CurrentProcess();
454 454
455 // If the thread's yield count matches, there's nothing for us to do. 455 // If the thread's yield count matches, there's nothing for us to do.
456 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { 456 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -538,7 +538,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
538 538
539 // Get the current thread and process. 539 // Get the current thread and process.
540 KThread& cur_thread = Kernel::GetCurrentThread(kernel); 540 KThread& cur_thread = Kernel::GetCurrentThread(kernel);
541 Process& cur_process = *kernel.CurrentProcess(); 541 KProcess& cur_process = *kernel.CurrentProcess();
542 542
543 // If the thread's yield count matches, there's nothing for us to do. 543 // If the thread's yield count matches, there's nothing for us to do.
544 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) { 544 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -607,7 +607,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
607 } 607 }
608} 608}
609 609
610KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) { 610KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
611 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this); 611 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
612 state.needs_scheduling.store(true); 612 state.needs_scheduling.store(true);
613 state.interrupt_task_thread_runnable = false; 613 state.interrupt_task_thread_runnable = false;
@@ -617,7 +617,12 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core
617 state.highest_priority_thread = nullptr; 617 state.highest_priority_thread = nullptr;
618} 618}
619 619
620KScheduler::~KScheduler() = default; 620KScheduler::~KScheduler() {
621 if (idle_thread) {
622 idle_thread->Close();
623 idle_thread = nullptr;
624 }
625}
621 626
622KThread* KScheduler::GetCurrentThread() const { 627KThread* KScheduler::GetCurrentThread() const {
623 if (auto result = current_thread.load(); result) { 628 if (auto result = current_thread.load(); result) {
@@ -719,7 +724,7 @@ void KScheduler::ScheduleImpl() {
719 724
720 current_thread.store(next_thread); 725 current_thread.store(next_thread);
721 726
722 Process* const previous_process = system.Kernel().CurrentProcess(); 727 KProcess* const previous_process = system.Kernel().CurrentProcess();
723 728
724 UpdateLastContextSwitchTime(previous_thread, previous_process); 729 UpdateLastContextSwitchTime(previous_thread, previous_process);
725 730
@@ -775,7 +780,7 @@ void KScheduler::SwitchToCurrent() {
775 } 780 }
776} 781}
777 782
778void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) { 783void KScheduler::UpdateLastContextSwitchTime(KThread* thread, KProcess* process) {
779 const u64 prev_switch_ticks = last_context_switch_time; 784 const u64 prev_switch_ticks = last_context_switch_time;
780 const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); 785 const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
781 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; 786 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
@@ -792,13 +797,9 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process)
792} 797}
793 798
794void KScheduler::Initialize() { 799void KScheduler::Initialize() {
795 std::string name = "Idle Thread Id:" + std::to_string(core_id); 800 idle_thread = KThread::Create(system.Kernel());
796 std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); 801 ASSERT(KThread::InitializeIdleThread(system, idle_thread, core_id).IsSuccess());
797 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); 802 idle_thread->SetName(fmt::format("IdleThread:{}", core_id));
798 auto thread_res = KThread::CreateThread(
799 system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0,
800 static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter);
801 idle_thread = thread_res.Unwrap().get();
802} 803}
803 804
804KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) 805KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 8e32865aa..12cfae919 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -24,13 +24,13 @@ class System;
24namespace Kernel { 24namespace Kernel {
25 25
26class KernelCore; 26class KernelCore;
27class Process; 27class KProcess;
28class SchedulerLock; 28class SchedulerLock;
29class KThread; 29class KThread;
30 30
31class KScheduler final { 31class KScheduler final {
32public: 32public:
33 explicit KScheduler(Core::System& system, s32 core_id); 33 explicit KScheduler(Core::System& system_, s32 core_id_);
34 ~KScheduler(); 34 ~KScheduler();
35 35
36 /// Reschedules to the next available thread (call after current thread is suspended) 36 /// Reschedules to the next available thread (call after current thread is suspended)
@@ -141,7 +141,7 @@ private:
141 141
142 [[nodiscard]] static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel); 142 [[nodiscard]] static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel);
143 143
144 void RotateScheduledQueue(s32 core_id, s32 priority); 144 void RotateScheduledQueue(s32 cpu_core_id, s32 priority);
145 145
146 void Schedule() { 146 void Schedule() {
147 ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1); 147 ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1);
@@ -165,7 +165,7 @@ private:
165 * most recent tick count retrieved. No special arithmetic is 165 * most recent tick count retrieved. No special arithmetic is
166 * applied to it. 166 * applied to it.
167 */ 167 */
168 void UpdateLastContextSwitchTime(KThread* thread, Process* process); 168 void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
169 169
170 static void OnSwitch(void* this_scheduler); 170 static void OnSwitch(void* this_scheduler);
171 void SwitchToCurrent(); 171 void SwitchToCurrent();
@@ -173,12 +173,12 @@ private:
173 KThread* prev_thread{}; 173 KThread* prev_thread{};
174 std::atomic<KThread*> current_thread{}; 174 std::atomic<KThread*> current_thread{};
175 175
176 KThread* idle_thread; 176 KThread* idle_thread{};
177 177
178 std::shared_ptr<Common::Fiber> switch_fiber{}; 178 std::shared_ptr<Common::Fiber> switch_fiber{};
179 179
180 struct SchedulingState { 180 struct SchedulingState {
181 std::atomic<bool> needs_scheduling; 181 std::atomic<bool> needs_scheduling{};
182 bool interrupt_task_thread_runnable{}; 182 bool interrupt_task_thread_runnable{};
183 bool should_count_idle{}; 183 bool should_count_idle{};
184 u64 idle_count{}; 184 u64 idle_count{};
diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h
index c5deca00b..07272075d 100644
--- a/src/core/hle/kernel/k_scoped_resource_reservation.h
+++ b/src/core/hle/kernel/k_scoped_resource_reservation.h
@@ -8,15 +8,14 @@
8#pragma once 8#pragma once
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/k_process.h"
11#include "core/hle/kernel/k_resource_limit.h" 12#include "core/hle/kernel/k_resource_limit.h"
12#include "core/hle/kernel/process.h"
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16class KScopedResourceReservation { 16class KScopedResourceReservation {
17public: 17public:
18 explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r, 18 explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v, s64 timeout)
19 s64 v, s64 timeout)
20 : resource_limit(std::move(l)), value(v), resource(r) { 19 : resource_limit(std::move(l)), value(v), resource(r) {
21 if (resource_limit && value) { 20 if (resource_limit && value) {
22 success = resource_limit->Reserve(resource, value, timeout); 21 success = resource_limit->Reserve(resource, value, timeout);
@@ -25,8 +24,7 @@ public:
25 } 24 }
26 } 25 }
27 26
28 explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r, 27 explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v = 1)
29 s64 v = 1)
30 : resource_limit(std::move(l)), value(v), resource(r) { 28 : resource_limit(std::move(l)), value(v), resource(r) {
31 if (resource_limit && value) { 29 if (resource_limit && value) {
32 success = resource_limit->Reserve(resource, value); 30 success = resource_limit->Reserve(resource, value);
@@ -35,10 +33,10 @@ public:
35 } 33 }
36 } 34 }
37 35
38 explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t) 36 explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v, s64 t)
39 : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {} 37 : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {}
40 38
41 explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1) 39 explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v = 1)
42 : KScopedResourceReservation(p->GetResourceLimit(), r, v) {} 40 : KScopedResourceReservation(p->GetResourceLimit(), r, v) {}
43 41
44 ~KScopedResourceReservation() noexcept { 42 ~KScopedResourceReservation() noexcept {
@@ -58,7 +56,7 @@ public:
58 } 56 }
59 57
60private: 58private:
61 std::shared_ptr<KResourceLimit> resource_limit; 59 KResourceLimit* resource_limit{};
62 s64 value; 60 s64 value;
63 LimitableResource resource; 61 LimitableResource resource;
64 bool success; 62 bool success;
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 ebecf0c77..a86af56dd 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
@@ -8,7 +8,7 @@
8#pragma once 8#pragma once
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/handle_table.h" 11#include "core/hle/kernel/k_handle_table.h"
12#include "core/hle/kernel/k_thread.h" 12#include "core/hle/kernel/k_thread.h"
13#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/time_manager.h" 14#include "core/hle/kernel/time_manager.h"
@@ -17,8 +17,8 @@ namespace Kernel {
17 17
18class [[nodiscard]] KScopedSchedulerLockAndSleep { 18class [[nodiscard]] KScopedSchedulerLockAndSleep {
19public: 19public:
20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout) 20 explicit KScopedSchedulerLockAndSleep(KernelCore & kernel_, KThread * t, s64 timeout)
21 : kernel(kernel), thread(t), timeout_tick(timeout) { 21 : kernel(kernel_), thread(t), timeout_tick(timeout) {
22 // Lock the scheduler. 22 // Lock the scheduler.
23 kernel.GlobalSchedulerContext().scheduler_lock.Lock(); 23 kernel.GlobalSchedulerContext().scheduler_lock.Lock();
24 } 24 }
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
new file mode 100644
index 000000000..8cbde177a
--- /dev/null
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -0,0 +1,104 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <tuple>
6#include "common/assert.h"
7#include "core/hle/kernel/k_client_port.h"
8#include "core/hle/kernel/k_port.h"
9#include "core/hle/kernel/k_scheduler.h"
10#include "core/hle/kernel/k_server_port.h"
11#include "core/hle/kernel/k_server_session.h"
12#include "core/hle/kernel/k_thread.h"
13#include "core/hle/kernel/svc_results.h"
14
15namespace Kernel {
16
17KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
18KServerPort::~KServerPort() = default;
19
20void KServerPort::Initialize(KPort* parent_, std::string&& name_) {
21 // Set member variables.
22 parent = parent_;
23 name = std::move(name_);
24}
25
26bool KServerPort::IsLight() const {
27 return this->GetParent()->IsLight();
28}
29
30void KServerPort::CleanupSessions() {
31 // Ensure our preconditions are met.
32 if (this->IsLight()) {
33 UNIMPLEMENTED();
34 }
35
36 // Cleanup the session list.
37 while (true) {
38 // Get the last session in the list
39 KServerSession* session = nullptr;
40 {
41 KScopedSchedulerLock sl{kernel};
42 if (!session_list.empty()) {
43 session = std::addressof(session_list.front());
44 session_list.pop_front();
45 }
46 }
47
48 // Close the session.
49 if (session != nullptr) {
50 session->Close();
51 } else {
52 break;
53 }
54 }
55}
56
57void KServerPort::Destroy() {
58 // Note with our parent that we're closed.
59 parent->OnServerClosed();
60
61 // Perform necessary cleanup of our session lists.
62 this->CleanupSessions();
63
64 // Close our reference to our parent.
65 parent->Close();
66}
67
68bool KServerPort::IsSignaled() const {
69 if (this->IsLight()) {
70 UNIMPLEMENTED();
71 return false;
72 } else {
73 return !session_list.empty();
74 }
75}
76
77void KServerPort::EnqueueSession(KServerSession* session) {
78 ASSERT(!this->IsLight());
79
80 KScopedSchedulerLock sl{kernel};
81
82 // Add the session to our queue.
83 session_list.push_back(*session);
84 if (session_list.size() == 1) {
85 this->NotifyAvailable();
86 }
87}
88
89KServerSession* KServerPort::AcceptSession() {
90 ASSERT(!this->IsLight());
91
92 KScopedSchedulerLock sl{kernel};
93
94 // Return the first session in the list.
95 if (session_list.empty()) {
96 return nullptr;
97 }
98
99 KServerSession* session = std::addressof(session_list.front());
100 session_list.pop_front();
101 return session;
102}
103
104} // namespace Kernel
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
new file mode 100644
index 000000000..e76792253
--- /dev/null
+++ b/src/core/hle/kernel/k_server_port.h
@@ -0,0 +1,80 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include <boost/intrusive/list.hpp>
13
14#include "common/common_types.h"
15#include "core/hle/kernel/k_server_session.h"
16#include "core/hle/kernel/k_synchronization_object.h"
17#include "core/hle/result.h"
18
19namespace Kernel {
20
21class KernelCore;
22class KPort;
23class SessionRequestHandler;
24
25class KServerPort final : public KSynchronizationObject {
26 KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
27
28private:
29 using SessionList = boost::intrusive::list<KServerSession>;
30
31public:
32 explicit KServerPort(KernelCore& kernel_);
33 virtual ~KServerPort() override;
34
35 using HLEHandler = std::shared_ptr<SessionRequestHandler>;
36
37 void Initialize(KPort* parent_, std::string&& name_);
38
39 /// Whether or not this server port has an HLE handler available.
40 bool HasHLEHandler() const {
41 return hle_handler != nullptr;
42 }
43
44 /// Gets the HLE handler for this port.
45 HLEHandler GetHLEHandler() const {
46 return hle_handler;
47 }
48
49 /**
50 * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
51 * will inherit a reference to this handler.
52 */
53 void SetHleHandler(HLEHandler hle_handler_) {
54 hle_handler = std::move(hle_handler_);
55 }
56
57 void EnqueueSession(KServerSession* pending_session);
58
59 KServerSession* AcceptSession();
60
61 const KPort* GetParent() const {
62 return parent;
63 }
64
65 bool IsLight() const;
66
67 // Overridden virtual functions.
68 virtual void Destroy() override;
69 virtual bool IsSignaled() const override;
70
71private:
72 void CleanupSessions();
73
74private:
75 SessionList session_list;
76 HLEHandler hle_handler;
77 KPort* parent{};
78};
79
80} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 790dbb998..8850d9af5 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -10,49 +10,39 @@
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/core_timing.h" 11#include "core/core_timing.h"
12#include "core/hle/ipc_helpers.h" 12#include "core/hle/ipc_helpers.h"
13#include "core/hle/kernel/client_port.h"
14#include "core/hle/kernel/client_session.h"
15#include "core/hle/kernel/handle_table.h"
16#include "core/hle/kernel/hle_ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/kernel/k_client_port.h"
15#include "core/hle/kernel/k_handle_table.h"
16#include "core/hle/kernel/k_process.h"
17#include "core/hle/kernel/k_scheduler.h" 17#include "core/hle/kernel/k_scheduler.h"
18#include "core/hle/kernel/k_server_session.h"
19#include "core/hle/kernel/k_session.h"
18#include "core/hle/kernel/k_thread.h" 20#include "core/hle/kernel/k_thread.h"
19#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
20#include "core/hle/kernel/process.h"
21#include "core/hle/kernel/server_session.h"
22#include "core/hle/kernel/session.h"
23#include "core/memory.h" 22#include "core/memory.h"
24 23
25namespace Kernel { 24namespace Kernel {
26 25
27ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} 26KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
28 27
29ServerSession::~ServerSession() { 28KServerSession::~KServerSession() {
30 kernel.ReleaseServiceThread(service_thread); 29 kernel.ReleaseServiceThread(service_thread);
31} 30}
32 31
33ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, 32void KServerSession::Initialize(KSession* parent_, std::string&& name_) {
34 std::shared_ptr<Session> parent, 33 // Set member variables.
35 std::string name) { 34 parent = parent_;
36 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; 35 name = std::move(name_);
37 36 service_thread = kernel.CreateServiceThread(name);
38 session->name = std::move(name);
39 session->parent = std::move(parent);
40 session->service_thread = kernel.CreateServiceThread(session->name);
41
42 return MakeResult(std::move(session));
43} 37}
44 38
45bool ServerSession::IsSignaled() const { 39void KServerSession::Destroy() {
46 // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. 40 parent->OnServerClosed();
47 if (!parent->Client()) {
48 return true;
49 }
50 41
51 // Wait if we have no pending requests, or if we're currently handling a request. 42 parent->Close();
52 return !pending_requesting_threads.empty() && currently_handling == nullptr;
53} 43}
54 44
55void ServerSession::ClientDisconnected() { 45void KServerSession::OnClientClosed() {
56 // We keep a shared pointer to the hle handler to keep it alive throughout 46 // We keep a shared pointer to the hle handler to keep it alive throughout
57 // the call to ClientDisconnected, as ClientDisconnected invalidates the 47 // the call to ClientDisconnected, as ClientDisconnected invalidates the
58 // hle_handler member itself during the course of the function executing. 48 // hle_handler member itself during the course of the function executing.
@@ -60,24 +50,31 @@ void ServerSession::ClientDisconnected() {
60 if (handler) { 50 if (handler) {
61 // Note that after this returns, this server session's hle_handler is 51 // Note that after this returns, this server session's hle_handler is
62 // invalidated (set to null). 52 // invalidated (set to null).
63 handler->ClientDisconnected(SharedFrom(this)); 53 handler->ClientDisconnected(this);
54 }
55}
56
57bool KServerSession::IsSignaled() const {
58 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
59
60 // If the client is closed, we're always signaled.
61 if (parent->IsClientClosed()) {
62 return true;
64 } 63 }
65 64
66 // Clean up the list of client threads with pending requests, they are unneeded now that the 65 // Otherwise, we're signaled if we have a request and aren't handling one.
67 // client endpoint is closed. 66 return false;
68 pending_requesting_threads.clear();
69 currently_handling = nullptr;
70} 67}
71 68
72void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { 69void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) {
73 domain_request_handlers.push_back(std::move(handler)); 70 domain_request_handlers.push_back(std::move(handler));
74} 71}
75 72
76std::size_t ServerSession::NumDomainRequestHandlers() const { 73std::size_t KServerSession::NumDomainRequestHandlers() const {
77 return domain_request_handlers.size(); 74 return domain_request_handlers.size();
78} 75}
79 76
80ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { 77ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
81 if (!context.HasDomainMessageHeader()) { 78 if (!context.HasDomainMessageHeader()) {
82 return RESULT_SUCCESS; 79 return RESULT_SUCCESS;
83 } 80 }
@@ -98,7 +95,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
98 UNREACHABLE(); 95 UNREACHABLE();
99 return RESULT_SUCCESS; // Ignore error if asserts are off 96 return RESULT_SUCCESS; // Ignore error if asserts are off
100 } 97 }
101 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); 98 return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context);
102 99
103 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { 100 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
104 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); 101 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
@@ -116,23 +113,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
116 return RESULT_SUCCESS; 113 return RESULT_SUCCESS;
117} 114}
118 115
119ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<KThread> thread, 116ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
120 Core::Memory::Memory& memory) {
121 u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; 117 u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
122 auto context = 118 auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
123 std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
124 119
125 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); 120 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
126 121
127 if (auto strong_ptr = service_thread.lock()) { 122 if (auto strong_ptr = service_thread.lock()) {
128 strong_ptr->QueueSyncRequest(*this, std::move(context)); 123 strong_ptr->QueueSyncRequest(*parent, std::move(context));
129 return RESULT_SUCCESS; 124 return RESULT_SUCCESS;
130 } 125 }
131 126
132 return RESULT_SUCCESS; 127 return RESULT_SUCCESS;
133} 128}
134 129
135ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { 130ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
136 ResultCode result = RESULT_SUCCESS; 131 ResultCode result = RESULT_SUCCESS;
137 // If the session has been converted to a domain, handle the domain request 132 // If the session has been converted to a domain, handle the domain request
138 if (IsDomain() && context.HasDomainMessageHeader()) { 133 if (IsDomain() && context.HasDomainMessageHeader()) {
@@ -140,7 +135,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
140 // If there is no domain header, the regular session handler is used 135 // If there is no domain header, the regular session handler is used
141 } else if (hle_handler != nullptr) { 136 } else if (hle_handler != nullptr) {
142 // If this ServerSession has an associated HLE handler, forward the request to it. 137 // If this ServerSession has an associated HLE handler, forward the request to it.
143 result = hle_handler->HandleSyncRequest(context); 138 result = hle_handler->HandleSyncRequest(*this, context);
144 } 139 }
145 140
146 if (convert_to_domain) { 141 if (convert_to_domain) {
@@ -161,10 +156,9 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
161 return result; 156 return result;
162} 157}
163 158
164ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<KThread> thread, 159ResultCode KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
165 Core::Memory::Memory& memory, 160 Core::Timing::CoreTiming& core_timing) {
166 Core::Timing::CoreTiming& core_timing) { 161 return QueueSyncRequest(thread, memory);
167 return QueueSyncRequest(std::move(thread), memory);
168} 162}
169 163
170} // namespace Kernel 164} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/k_server_session.h
index c42d5ee59..597d76d38 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -9,6 +9,8 @@
9#include <utility> 9#include <utility>
10#include <vector> 10#include <vector>
11 11
12#include <boost/intrusive/list.hpp>
13
12#include "common/threadsafe_queue.h" 14#include "common/threadsafe_queue.h"
13#include "core/hle/kernel/k_synchronization_object.h" 15#include "core/hle/kernel/k_synchronization_object.h"
14#include "core/hle/kernel/service_thread.h" 16#include "core/hle/kernel/service_thread.h"
@@ -27,55 +29,35 @@ namespace Kernel {
27 29
28class HLERequestContext; 30class HLERequestContext;
29class KernelCore; 31class KernelCore;
30class Session; 32class KSession;
31class SessionRequestHandler; 33class SessionRequestHandler;
32class KThread; 34class KThread;
33 35
34/** 36class KServerSession final : public KSynchronizationObject,
35 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS 37 public boost::intrusive::list_base_hook<> {
36 * primitive for communication between different processes, and are used to implement service calls 38 KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
37 * to the various system services. 39
38 *
39 * To make a service call, the client must write the command header and parameters to the buffer
40 * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
41 * SVC call with its ClientSession handle. The kernel will read the command header, using it to
42 * marshall the parameters to the process at the server endpoint of the session.
43 * After the server replies to the request, the response is marshalled back to the caller's
44 * TLS buffer and control is transferred back to it.
45 */
46class ServerSession final : public KSynchronizationObject {
47 friend class ServiceThread; 40 friend class ServiceThread;
48 41
49public: 42public:
50 explicit ServerSession(KernelCore& kernel); 43 explicit KServerSession(KernelCore& kernel_);
51 ~ServerSession() override; 44 virtual ~KServerSession() override;
52 45
53 friend class Session; 46 virtual void Destroy() override;
54 47
55 static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, 48 void Initialize(KSession* parent_, std::string&& name_);
56 std::shared_ptr<Session> parent,
57 std::string name = "Unknown");
58 49
59 std::string GetTypeName() const override { 50 KSession* GetParent() {
60 return "ServerSession"; 51 return parent;
61 } 52 }
62 53
63 std::string GetName() const override { 54 const KSession* GetParent() const {
64 return name; 55 return parent;
65 } 56 }
66 57
67 static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; 58 virtual bool IsSignaled() const override;
68 HandleType GetHandleType() const override {
69 return HANDLE_TYPE;
70 }
71 59
72 Session* GetParent() { 60 void OnClientClosed();
73 return parent.get();
74 }
75
76 const Session* GetParent() const {
77 return parent.get();
78 }
79 61
80 /** 62 /**
81 * Sets the HLE handler for the session. This handler will be called to service IPC requests 63 * Sets the HLE handler for the session. This handler will be called to service IPC requests
@@ -95,12 +77,9 @@ public:
95 * 77 *
96 * @returns ResultCode from the operation. 78 * @returns ResultCode from the operation.
97 */ 79 */
98 ResultCode HandleSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory, 80 ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
99 Core::Timing::CoreTiming& core_timing); 81 Core::Timing::CoreTiming& core_timing);
100 82
101 /// Called when a client disconnection occurs.
102 void ClientDisconnected();
103
104 /// Adds a new domain request handler to the collection of request handlers within 83 /// Adds a new domain request handler to the collection of request handlers within
105 /// this ServerSession instance. 84 /// this ServerSession instance.
106 void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); 85 void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler);
@@ -124,13 +103,9 @@ public:
124 convert_to_domain = true; 103 convert_to_domain = true;
125 } 104 }
126 105
127 bool IsSignaled() const override;
128
129 void Finalize() override {}
130
131private: 106private:
132 /// Queues a sync request from the emulated application. 107 /// Queues a sync request from the emulated application.
133 ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory); 108 ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
134 109
135 /// Completes a sync request from the emulated application. 110 /// Completes a sync request from the emulated application.
136 ResultCode CompleteSyncRequest(HLERequestContext& context); 111 ResultCode CompleteSyncRequest(HLERequestContext& context);
@@ -139,33 +114,20 @@ private:
139 /// object handle. 114 /// object handle.
140 ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); 115 ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);
141 116
142 /// The parent session, which links to the client endpoint.
143 std::shared_ptr<Session> parent;
144
145 /// This session's HLE request handler (applicable when not a domain) 117 /// This session's HLE request handler (applicable when not a domain)
146 std::shared_ptr<SessionRequestHandler> hle_handler; 118 std::shared_ptr<SessionRequestHandler> hle_handler;
147 119
148 /// This is the list of domain request handlers (after conversion to a domain) 120 /// This is the list of domain request handlers (after conversion to a domain)
149 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; 121 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
150 122
151 /// List of threads that are pending a response after a sync request. This list is processed in
152 /// a LIFO manner, thus, the last request will be dispatched first.
153 /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
154 std::vector<std::shared_ptr<KThread>> pending_requesting_threads;
155
156 /// Thread whose request is currently being handled. A request is considered "handled" when a
157 /// response is sent via svcReplyAndReceive.
158 /// TODO(Subv): Find a better name for this.
159 std::shared_ptr<KThread> currently_handling;
160
161 /// When set to True, converts the session to a domain at the end of the command 123 /// When set to True, converts the session to a domain at the end of the command
162 bool convert_to_domain{}; 124 bool convert_to_domain{};
163 125
164 /// The name of this session (optional)
165 std::string name;
166
167 /// Thread to dispatch service requests 126 /// Thread to dispatch service requests
168 std::weak_ptr<ServiceThread> service_thread; 127 std::weak_ptr<ServiceThread> service_thread;
128
129 /// KSession that owns this KServerSession
130 KSession* parent{};
169}; 131};
170 132
171} // namespace Kernel 133} // namespace Kernel
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp
new file mode 100644
index 000000000..b7ce27a0b
--- /dev/null
+++ b/src/core/hle/kernel/k_session.cpp
@@ -0,0 +1,85 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/kernel/k_client_port.h"
7#include "core/hle/kernel/k_client_session.h"
8#include "core/hle/kernel/k_scoped_resource_reservation.h"
9#include "core/hle/kernel/k_server_session.h"
10#include "core/hle/kernel/k_session.h"
11
12namespace Kernel {
13
14KSession::KSession(KernelCore& kernel_)
15 : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
16KSession::~KSession() = default;
17
18void KSession::Initialize(KClientPort* port_, const std::string& name_) {
19 // Increment reference count.
20 // Because reference count is one on creation, this will result
21 // in a reference count of two. Thus, when both server and client are closed
22 // this object will be destroyed.
23 Open();
24
25 // Create our sub sessions.
26 KAutoObject::Create(std::addressof(server));
27 KAutoObject::Create(std::addressof(client));
28
29 // Initialize our sub sessions.
30 server.Initialize(this, name_ + ":Server");
31 client.Initialize(this, name_ + ":Client");
32
33 // Set state and name.
34 SetState(State::Normal);
35 name = name_;
36
37 // Set our owner process.
38 process = kernel.CurrentProcess();
39 process->Open();
40
41 // Set our port.
42 port = port_;
43 if (port != nullptr) {
44 port->Open();
45 }
46
47 // Mark initialized.
48 initialized = true;
49}
50
51void KSession::Finalize() {
52 if (port == nullptr) {
53 return;
54 }
55
56 port->OnSessionFinalized();
57 port->Close();
58}
59
60void KSession::OnServerClosed() {
61 if (GetState() != State::Normal) {
62 return;
63 }
64
65 SetState(State::ServerClosed);
66 client.OnServerClosed();
67}
68
69void KSession::OnClientClosed() {
70 if (GetState() != State::Normal) {
71 return;
72 }
73
74 SetState(State::ClientClosed);
75 server.OnClientClosed();
76}
77
78void KSession::PostDestroy(uintptr_t arg) {
79 // Release the session count resource the owner process holds.
80 KProcess* owner = reinterpret_cast<KProcess*>(arg);
81 // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1);
82 owner->Close();
83}
84
85} // namespace Kernel
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
new file mode 100644
index 000000000..16901e19c
--- /dev/null
+++ b/src/core/hle/kernel/k_session.h
@@ -0,0 +1,96 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <string>
9
10#include "core/hle/kernel/k_client_session.h"
11#include "core/hle/kernel/k_server_session.h"
12#include "core/hle/kernel/slab_helpers.h"
13
14namespace Kernel {
15
16class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
17 KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
18
19public:
20 explicit KSession(KernelCore& kernel_);
21 virtual ~KSession() override;
22
23 void Initialize(KClientPort* port_, const std::string& name_);
24
25 virtual void Finalize() override;
26
27 virtual bool IsInitialized() const override {
28 return initialized;
29 }
30
31 virtual uintptr_t GetPostDestroyArgument() const override {
32 return reinterpret_cast<uintptr_t>(process);
33 }
34
35 static void PostDestroy(uintptr_t arg);
36
37 void OnServerClosed();
38
39 void OnClientClosed();
40
41 bool IsServerClosed() const {
42 return this->GetState() != State::Normal;
43 }
44
45 bool IsClientClosed() const {
46 return this->GetState() != State::Normal;
47 }
48
49 KClientSession& GetClientSession() {
50 return client;
51 }
52
53 KServerSession& GetServerSession() {
54 return server;
55 }
56
57 const KClientSession& GetClientSession() const {
58 return client;
59 }
60
61 const KServerSession& GetServerSession() const {
62 return server;
63 }
64
65 const KClientPort* GetParent() const {
66 return port;
67 }
68
69private:
70 enum class State : u8 {
71 Invalid = 0,
72 Normal = 1,
73 ClientClosed = 2,
74 ServerClosed = 3,
75 };
76
77private:
78 void SetState(State state) {
79 atomic_state = static_cast<u8>(state);
80 }
81
82 State GetState() const {
83 return static_cast<State>(atomic_state.load(std::memory_order_relaxed));
84 }
85
86private:
87 KServerSession server;
88 KClientSession client;
89 std::atomic<std::underlying_type_t<State>> atomic_state{
90 static_cast<std::underlying_type_t<State>>(State::Invalid)};
91 KClientPort* port{};
92 KProcess* process{};
93 bool initialized{};
94};
95
96} // namespace Kernel
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp
index 9b14f42b5..7770b1868 100644
--- a/src/core/hle/kernel/k_shared_memory.cpp
+++ b/src/core/hle/kernel/k_shared_memory.cpp
@@ -8,50 +8,74 @@
8#include "core/hle/kernel/k_scoped_resource_reservation.h" 8#include "core/hle/kernel/k_scoped_resource_reservation.h"
9#include "core/hle/kernel/k_shared_memory.h" 9#include "core/hle/kernel/k_shared_memory.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/svc_results.h"
11 12
12namespace Kernel { 13namespace Kernel {
13 14
14KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) 15KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
15 : Object{kernel}, device_memory{device_memory} {}
16 16
17KSharedMemory::~KSharedMemory() { 17KSharedMemory::~KSharedMemory() {
18 kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); 18 kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size);
19} 19}
20 20
21std::shared_ptr<KSharedMemory> KSharedMemory::Create( 21ResultCode KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
22 KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, 22 KPageLinkedList&& page_list_,
23 KPageLinkedList&& page_list, KMemoryPermission owner_permission, 23 Svc::MemoryPermission owner_permission_,
24 KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) { 24 Svc::MemoryPermission user_permission_,
25 PAddr physical_address_, std::size_t size_,
26 std::string name_) {
27 // Set members.
28 owner_process = owner_process_;
29 device_memory = &device_memory_;
30 page_list = std::move(page_list_);
31 owner_permission = owner_permission_;
32 user_permission = user_permission_;
33 physical_address = physical_address_;
34 size = size_;
35 name = std::move(name_);
25 36
26 const auto resource_limit = kernel.GetSystemResourceLimit(); 37 // Get the resource limit.
27 KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, 38 KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
28 size);
29 ASSERT(memory_reservation.Succeeded());
30 39
31 std::shared_ptr<KSharedMemory> shared_memory{ 40 // Reserve memory for ourselves.
32 std::make_shared<KSharedMemory>(kernel, device_memory)}; 41 KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory,
33 42 size_);
34 shared_memory->owner_process = owner_process; 43 R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
35 shared_memory->page_list = std::move(page_list);
36 shared_memory->owner_permission = owner_permission;
37 shared_memory->user_permission = user_permission;
38 shared_memory->physical_address = physical_address;
39 shared_memory->size = size;
40 shared_memory->name = name;
41 44
45 // Commit our reservation.
42 memory_reservation.Commit(); 46 memory_reservation.Commit();
43 return shared_memory; 47
48 // Set our resource limit.
49 resource_limit = reslimit;
50 resource_limit->Open();
51
52 // Mark initialized.
53 is_initialized = true;
54
55 // Clear all pages in the memory.
56 std::memset(device_memory_.GetPointer(physical_address_), 0, size_);
57
58 return RESULT_SUCCESS;
59}
60
61void KSharedMemory::Finalize() {
62 // Release the memory reservation.
63 resource_limit->Release(LimitableResource::PhysicalMemory, size);
64 resource_limit->Close();
65
66 // Perform inherited finalization.
67 KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList>::Finalize();
44} 68}
45 69
46ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size, 70ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size,
47 KMemoryPermission permissions) { 71 Svc::MemoryPermission permissions) {
48 const u64 page_count{(size + PageSize - 1) / PageSize}; 72 const u64 page_count{(map_size + PageSize - 1) / PageSize};
49 73
50 if (page_list.GetNumPages() != page_count) { 74 if (page_list.GetNumPages() != page_count) {
51 UNIMPLEMENTED_MSG("Page count does not match"); 75 UNIMPLEMENTED_MSG("Page count does not match");
52 } 76 }
53 77
54 const KMemoryPermission expected = 78 const Svc::MemoryPermission expected =
55 &target_process == owner_process ? owner_permission : user_permission; 79 &target_process == owner_process ? owner_permission : user_permission;
56 80
57 if (permissions != expected) { 81 if (permissions != expected) {
@@ -59,7 +83,17 @@ ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_
59 } 83 }
60 84
61 return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, 85 return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared,
62 permissions); 86 ConvertToKMemoryPermission(permissions));
87}
88
89ResultCode KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
90 const u64 page_count{(unmap_size + PageSize - 1) / PageSize};
91
92 if (page_list.GetNumPages() != page_count) {
93 UNIMPLEMENTED_MSG("Page count does not match");
94 }
95
96 return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared);
63} 97}
64 98
65} // namespace Kernel 99} // namespace Kernel
diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h
index 016e34be5..553a56327 100644
--- a/src/core/hle/kernel/k_shared_memory.h
+++ b/src/core/hle/kernel/k_shared_memory.h
@@ -11,47 +11,44 @@
11#include "core/device_memory.h" 11#include "core/device_memory.h"
12#include "core/hle/kernel/k_memory_block.h" 12#include "core/hle/kernel/k_memory_block.h"
13#include "core/hle/kernel/k_page_linked_list.h" 13#include "core/hle/kernel/k_page_linked_list.h"
14#include "core/hle/kernel/object.h" 14#include "core/hle/kernel/k_process.h"
15#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/slab_helpers.h"
16#include "core/hle/result.h" 16#include "core/hle/result.h"
17 17
18namespace Kernel { 18namespace Kernel {
19 19
20class KernelCore; 20class KernelCore;
21 21
22class KSharedMemory final : public Object { 22class KSharedMemory final
23 : public KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList> {
24 KERNEL_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject);
25
23public: 26public:
24 explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory); 27 explicit KSharedMemory(KernelCore& kernel_);
25 ~KSharedMemory() override; 28 ~KSharedMemory() override;
26 29
27 static std::shared_ptr<KSharedMemory> Create( 30 ResultCode Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
28 KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, 31 KPageLinkedList&& page_list_, Svc::MemoryPermission owner_permission_,
29 KPageLinkedList&& page_list, KMemoryPermission owner_permission, 32 Svc::MemoryPermission user_permission_, PAddr physical_address_,
30 KMemoryPermission user_permission, PAddr physical_address, std::size_t size, 33 std::size_t size_, std::string name_);
31 std::string name);
32
33 std::string GetTypeName() const override {
34 return "SharedMemory";
35 }
36
37 std::string GetName() const override {
38 return name;
39 }
40
41 static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory;
42 HandleType GetHandleType() const override {
43 return HANDLE_TYPE;
44 }
45 34
46 /** 35 /**
47 * Maps a shared memory block to an address in the target process' address space 36 * Maps a shared memory block to an address in the target process' address space
48 * @param target_process Process on which to map the memory block 37 * @param target_process Process on which to map the memory block
49 * @param address Address in system memory to map shared memory block to 38 * @param address Address in system memory to map shared memory block to
50 * @param size Size of the shared memory block to map 39 * @param map_size Size of the shared memory block to map
51 * @param permissions Memory block map permissions (specified by SVC field) 40 * @param permissions Memory block map permissions (specified by SVC field)
52 */ 41 */
53 ResultCode Map(Process& target_process, VAddr address, std::size_t size, 42 ResultCode Map(KProcess& target_process, VAddr address, std::size_t map_size,
54 KMemoryPermission permissions); 43 Svc::MemoryPermission permissions);
44
45 /**
46 * Unmaps a shared memory block from an address in the target process' address space
47 * @param target_process Process on which to unmap the memory block
48 * @param address Address in system memory to unmap shared memory block
49 * @param unmap_size Size of the shared memory block to unmap
50 */
51 ResultCode Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size);
55 52
56 /** 53 /**
57 * Gets a pointer to the shared memory block 54 * Gets a pointer to the shared memory block
@@ -59,7 +56,7 @@ public:
59 * @return A pointer to the shared memory block from the specified offset 56 * @return A pointer to the shared memory block from the specified offset
60 */ 57 */
61 u8* GetPointer(std::size_t offset = 0) { 58 u8* GetPointer(std::size_t offset = 0) {
62 return device_memory.GetPointer(physical_address + offset); 59 return device_memory->GetPointer(physical_address + offset);
63 } 60 }
64 61
65 /** 62 /**
@@ -68,20 +65,26 @@ public:
68 * @return A pointer to the shared memory block from the specified offset 65 * @return A pointer to the shared memory block from the specified offset
69 */ 66 */
70 const u8* GetPointer(std::size_t offset = 0) const { 67 const u8* GetPointer(std::size_t offset = 0) const {
71 return device_memory.GetPointer(physical_address + offset); 68 return device_memory->GetPointer(physical_address + offset);
72 } 69 }
73 70
74 void Finalize() override {} 71 virtual void Finalize() override;
72
73 virtual bool IsInitialized() const override {
74 return is_initialized;
75 }
76 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
75 77
76private: 78private:
77 Core::DeviceMemory& device_memory; 79 Core::DeviceMemory* device_memory;
78 Process* owner_process{}; 80 KProcess* owner_process{};
79 KPageLinkedList page_list; 81 KPageLinkedList page_list;
80 KMemoryPermission owner_permission{}; 82 Svc::MemoryPermission owner_permission{};
81 KMemoryPermission user_permission{}; 83 Svc::MemoryPermission user_permission{};
82 PAddr physical_address{}; 84 PAddr physical_address{};
83 std::size_t size{}; 85 std::size_t size{};
84 std::string name; 86 KResourceLimit* resource_limit{};
87 bool is_initialized{};
85}; 88};
86 89
87} // namespace Kernel 90} // namespace Kernel
diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h
index aa4471d2f..5ce9a1d7c 100644
--- a/src/core/hle/kernel/k_slab_heap.h
+++ b/src/core/hle/kernel/k_slab_heap.h
@@ -97,6 +97,7 @@ public:
97 void FreeImpl(void* obj) { 97 void FreeImpl(void* obj) {
98 // Don't allow freeing an object that wasn't allocated from this heap 98 // Don't allow freeing an object that wasn't allocated from this heap
99 ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); 99 ASSERT(Contains(reinterpret_cast<uintptr_t>(obj)));
100
100 impl.Free(obj); 101 impl.Free(obj);
101 } 102 }
102 103
@@ -148,6 +149,14 @@ public:
148 return obj; 149 return obj;
149 } 150 }
150 151
152 T* AllocateWithKernel(KernelCore& kernel) {
153 T* obj = static_cast<T*>(AllocateImpl());
154 if (obj != nullptr) {
155 new (obj) T(kernel);
156 }
157 return obj;
158 }
159
151 void Free(T* obj) { 160 void Free(T* obj) {
152 FreeImpl(obj); 161 FreeImpl(obj);
153 } 162 }
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index 82f72a0fe..45380dea0 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -13,18 +13,23 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, 16void KSynchronizationObject::Finalize() {
17 this->OnFinalizeSynchronizationObject();
18 KAutoObject::Finalize();
19}
20
21ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
17 KSynchronizationObject** objects, const s32 num_objects, 22 KSynchronizationObject** objects, const s32 num_objects,
18 s64 timeout) { 23 s64 timeout) {
19 // Allocate space on stack for thread nodes. 24 // Allocate space on stack for thread nodes.
20 std::vector<ThreadListNode> thread_nodes(num_objects); 25 std::vector<ThreadListNode> thread_nodes(num_objects);
21 26
22 // Prepare for wait. 27 // Prepare for wait.
23 KThread* thread = kernel.CurrentScheduler()->GetCurrentThread(); 28 KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread();
24 29
25 { 30 {
26 // Setup the scheduling lock and sleep. 31 // Setup the scheduling lock and sleep.
27 KScopedSchedulerLockAndSleep slp{kernel, thread, timeout}; 32 KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout};
28 33
29 // Check if any of the objects are already signaled. 34 // Check if any of the objects are already signaled.
30 for (auto i = 0; i < num_objects; ++i) { 35 for (auto i = 0; i < num_objects; ++i) {
@@ -89,13 +94,13 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
89 thread->SetWaitObjectsForDebugging({}); 94 thread->SetWaitObjectsForDebugging({});
90 95
91 // Cancel the timer as needed. 96 // Cancel the timer as needed.
92 kernel.TimeManager().UnscheduleTimeEvent(thread); 97 kernel_ctx.TimeManager().UnscheduleTimeEvent(thread);
93 98
94 // Get the wait result. 99 // Get the wait result.
95 ResultCode wait_result{RESULT_SUCCESS}; 100 ResultCode wait_result{RESULT_SUCCESS};
96 s32 sync_index = -1; 101 s32 sync_index = -1;
97 { 102 {
98 KScopedSchedulerLock lock(kernel); 103 KScopedSchedulerLock lock(kernel_ctx);
99 KSynchronizationObject* synced_obj; 104 KSynchronizationObject* synced_obj;
100 wait_result = thread->GetWaitResult(std::addressof(synced_obj)); 105 wait_result = thread->GetWaitResult(std::addressof(synced_obj));
101 106
@@ -130,10 +135,8 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
130 return wait_result; 135 return wait_result;
131} 136}
132 137
133KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {} 138KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
134 139 : KAutoObjectWithList{kernel_} {}
135KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name)
136 : Object{kernel, std::move(name)} {}
137 140
138KSynchronizationObject::~KSynchronizationObject() = default; 141KSynchronizationObject::~KSynchronizationObject() = default;
139 142
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h
index 5803718fd..a41dd1220 100644
--- a/src/core/hle/kernel/k_synchronization_object.h
+++ b/src/core/hle/kernel/k_synchronization_object.h
@@ -6,7 +6,7 @@
6 6
7#include <vector> 7#include <vector>
8 8
9#include "core/hle/kernel/object.h" 9#include "core/hle/kernel/k_auto_object.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11 11
12namespace Kernel { 12namespace Kernel {
@@ -16,7 +16,9 @@ class Synchronization;
16class KThread; 16class KThread;
17 17
18/// Class that represents a Kernel object that a thread can be waiting on 18/// Class that represents a Kernel object that a thread can be waiting on
19class KSynchronizationObject : public Object { 19class KSynchronizationObject : public KAutoObjectWithList {
20 KERNEL_AUTOOBJECT_TRAITS(KSynchronizationObject, KAutoObject);
21
20public: 22public:
21 struct ThreadListNode { 23 struct ThreadListNode {
22 ThreadListNode* next{}; 24 ThreadListNode* next{};
@@ -27,15 +29,18 @@ public:
27 KSynchronizationObject** objects, const s32 num_objects, 29 KSynchronizationObject** objects, const s32 num_objects,
28 s64 timeout); 30 s64 timeout);
29 31
32 virtual void Finalize() override;
33
30 [[nodiscard]] virtual bool IsSignaled() const = 0; 34 [[nodiscard]] virtual bool IsSignaled() const = 0;
31 35
32 [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; 36 [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
33 37
34protected: 38protected:
35 explicit KSynchronizationObject(KernelCore& kernel); 39 explicit KSynchronizationObject(KernelCore& kernel);
36 explicit KSynchronizationObject(KernelCore& kernel, std::string&& name);
37 virtual ~KSynchronizationObject(); 40 virtual ~KSynchronizationObject();
38 41
42 virtual void OnFinalizeSynchronizationObject() {}
43
39 void NotifyAvailable(ResultCode result); 44 void NotifyAvailable(ResultCode result);
40 void NotifyAvailable() { 45 void NotifyAvailable() {
41 return this->NotifyAvailable(RESULT_SUCCESS); 46 return this->NotifyAvailable(RESULT_SUCCESS);
@@ -46,14 +51,4 @@ private:
46 ThreadListNode* thread_list_tail{}; 51 ThreadListNode* thread_list_tail{};
47}; 52};
48 53
49// Specialization of DynamicObjectCast for KSynchronizationObjects
50template <>
51inline std::shared_ptr<KSynchronizationObject> DynamicObjectCast<KSynchronizationObject>(
52 std::shared_ptr<Object> object) {
53 if (object != nullptr && object->IsWaitable()) {
54 return std::static_pointer_cast<KSynchronizationObject>(object);
55 }
56 return nullptr;
57}
58
59} // namespace Kernel 54} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index e0f53287c..e3f08f256 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -18,17 +18,16 @@
18#include "core/core.h" 18#include "core/core.h"
19#include "core/cpu_manager.h" 19#include "core/cpu_manager.h"
20#include "core/hardware_properties.h" 20#include "core/hardware_properties.h"
21#include "core/hle/kernel/handle_table.h"
22#include "core/hle/kernel/k_condition_variable.h" 21#include "core/hle/kernel/k_condition_variable.h"
22#include "core/hle/kernel/k_handle_table.h"
23#include "core/hle/kernel/k_memory_layout.h" 23#include "core/hle/kernel/k_memory_layout.h"
24#include "core/hle/kernel/k_process.h"
24#include "core/hle/kernel/k_resource_limit.h" 25#include "core/hle/kernel/k_resource_limit.h"
25#include "core/hle/kernel/k_scheduler.h" 26#include "core/hle/kernel/k_scheduler.h"
26#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" 27#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
27#include "core/hle/kernel/k_thread.h" 28#include "core/hle/kernel/k_thread.h"
28#include "core/hle/kernel/k_thread_queue.h" 29#include "core/hle/kernel/k_thread_queue.h"
29#include "core/hle/kernel/kernel.h" 30#include "core/hle/kernel/kernel.h"
30#include "core/hle/kernel/object.h"
31#include "core/hle/kernel/process.h"
32#include "core/hle/kernel/svc_results.h" 31#include "core/hle/kernel/svc_results.h"
33#include "core/hle/kernel/time_manager.h" 32#include "core/hle/kernel/time_manager.h"
34#include "core/hle/result.h" 33#include "core/hle/result.h"
@@ -61,12 +60,12 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
61 60
62namespace Kernel { 61namespace Kernel {
63 62
64KThread::KThread(KernelCore& kernel) 63KThread::KThread(KernelCore& kernel_)
65 : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {} 64 : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {}
66KThread::~KThread() = default; 65KThread::~KThread() = default;
67 66
68ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, 67ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
69 s32 virt_core, Process* owner, ThreadType type) { 68 s32 virt_core, KProcess* owner, ThreadType type) {
70 // Assert parameters are valid. 69 // Assert parameters are valid.
71 ASSERT((type == ThreadType::Main) || 70 ASSERT((type == ThreadType::Main) ||
72 (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); 71 (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority));
@@ -177,6 +176,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
177 // Set parent, if relevant. 176 // Set parent, if relevant.
178 if (owner != nullptr) { 177 if (owner != nullptr) {
179 parent = owner; 178 parent = owner;
179 parent->Open();
180 parent->IncrementThreadCount(); 180 parent->IncrementThreadCount();
181 } 181 }
182 182
@@ -209,14 +209,56 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
209} 209}
210 210
211ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, 211ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
212 VAddr user_stack_top, s32 prio, s32 core, Process* owner, 212 VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
213 ThreadType type) { 213 ThreadType type, std::function<void(void*)>&& init_func,
214 void* init_func_parameter) {
214 // Initialize the thread. 215 // Initialize the thread.
215 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); 216 R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
216 217
218 // Initialize host context.
219 thread->host_context =
220 std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
221
217 return RESULT_SUCCESS; 222 return RESULT_SUCCESS;
218} 223}
219 224
225ResultCode KThread::InitializeDummyThread(KThread* thread) {
226 return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main);
227}
228
229ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
230 return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
231 Core::CpuManager::GetIdleThreadStartFunc(),
232 system.GetCpuManager().GetStartFuncParamater());
233}
234
235ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
236 KThreadFunction func, uintptr_t arg,
237 s32 virt_core) {
238 return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
239 Core::CpuManager::GetSuspendThreadStartFunc(),
240 system.GetCpuManager().GetStartFuncParamater());
241}
242
243ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
244 KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
245 s32 prio, s32 virt_core, KProcess* owner) {
246 system.Kernel().GlobalSchedulerContext().AddThread(thread);
247 return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
248 ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
249 system.GetCpuManager().GetStartFuncParamater());
250}
251
252void KThread::PostDestroy(uintptr_t arg) {
253 KProcess* owner = reinterpret_cast<KProcess*>(arg & ~1ULL);
254 const bool resource_limit_release_hint = (arg & 1);
255 const s64 hint_value = (resource_limit_release_hint ? 0 : 1);
256 if (owner != nullptr) {
257 owner->GetResourceLimit()->Release(LimitableResource::Threads, 1, hint_value);
258 owner->Close();
259 }
260}
261
220void KThread::Finalize() { 262void KThread::Finalize() {
221 // If the thread has an owner process, unregister it. 263 // If the thread has an owner process, unregister it.
222 if (parent != nullptr) { 264 if (parent != nullptr) {
@@ -246,8 +288,10 @@ void KThread::Finalize() {
246 // Decrement the parent process's thread count. 288 // Decrement the parent process's thread count.
247 if (parent != nullptr) { 289 if (parent != nullptr) {
248 parent->DecrementThreadCount(); 290 parent->DecrementThreadCount();
249 parent->GetResourceLimit()->Release(LimitableResource::Threads, 1);
250 } 291 }
292
293 // Perform inherited finalization.
294 KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize();
251} 295}
252 296
253bool KThread::IsSignaled() const { 297bool KThread::IsSignaled() const {
@@ -294,6 +338,9 @@ void KThread::StartTermination() {
294 338
295 // Register terminated dpc flag. 339 // Register terminated dpc flag.
296 RegisterDpc(DpcFlag::Terminated); 340 RegisterDpc(DpcFlag::Terminated);
341
342 // Close the thread.
343 this->Close();
297} 344}
298 345
299void KThread::Pin() { 346void KThread::Pin() {
@@ -432,7 +479,7 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m
432 return RESULT_SUCCESS; 479 return RESULT_SUCCESS;
433} 480}
434 481
435ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) { 482ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {
436 ASSERT(parent != nullptr); 483 ASSERT(parent != nullptr);
437 ASSERT(v_affinity_mask != 0); 484 ASSERT(v_affinity_mask != 0);
438 KScopedLightLock lk{activity_pause_lock}; 485 KScopedLightLock lk{activity_pause_lock};
@@ -444,18 +491,18 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
444 ASSERT(num_core_migration_disables >= 0); 491 ASSERT(num_core_migration_disables >= 0);
445 492
446 // If the core id is no-update magic, preserve the ideal core id. 493 // If the core id is no-update magic, preserve the ideal core id.
447 if (core_id == Svc::IdealCoreNoUpdate) { 494 if (cpu_core_id == Svc::IdealCoreNoUpdate) {
448 core_id = virtual_ideal_core_id; 495 cpu_core_id = virtual_ideal_core_id;
449 R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, ResultInvalidCombination); 496 R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination);
450 } 497 }
451 498
452 // Set the virtual core/affinity mask. 499 // Set the virtual core/affinity mask.
453 virtual_ideal_core_id = core_id; 500 virtual_ideal_core_id = cpu_core_id;
454 virtual_affinity_mask = v_affinity_mask; 501 virtual_affinity_mask = v_affinity_mask;
455 502
456 // Translate the virtual core to a physical core. 503 // Translate the virtual core to a physical core.
457 if (core_id >= 0) { 504 if (cpu_core_id >= 0) {
458 core_id = Core::Hardware::VirtualToPhysicalCoreMap[core_id]; 505 cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id];
459 } 506 }
460 507
461 // Translate the virtual affinity mask to a physical one. 508 // Translate the virtual affinity mask to a physical one.
@@ -470,7 +517,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
470 const KAffinityMask old_mask = physical_affinity_mask; 517 const KAffinityMask old_mask = physical_affinity_mask;
471 518
472 // Set our new ideals. 519 // Set our new ideals.
473 physical_ideal_core_id = core_id; 520 physical_ideal_core_id = cpu_core_id;
474 physical_affinity_mask.SetAffinityMask(p_affinity_mask); 521 physical_affinity_mask.SetAffinityMask(p_affinity_mask);
475 522
476 if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { 523 if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
@@ -488,7 +535,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
488 } 535 }
489 } else { 536 } else {
490 // Otherwise, we edit the original affinity for restoration later. 537 // Otherwise, we edit the original affinity for restoration later.
491 original_physical_ideal_core_id = core_id; 538 original_physical_ideal_core_id = cpu_core_id;
492 original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); 539 original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
493 } 540 }
494 } 541 }
@@ -804,8 +851,8 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
804 thread->SetLockOwner(nullptr); 851 thread->SetLockOwner(nullptr);
805} 852}
806 853
807void KThread::RestorePriority(KernelCore& kernel, KThread* thread) { 854void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
808 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 855 ASSERT(kernel_ctx.GlobalSchedulerContext().IsLocked());
809 856
810 while (true) { 857 while (true) {
811 // We want to inherit priority where possible. 858 // We want to inherit priority where possible.
@@ -821,7 +868,7 @@ void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
821 868
822 // Ensure we don't violate condition variable red black tree invariants. 869 // Ensure we don't violate condition variable red black tree invariants.
823 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { 870 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
824 BeforeUpdatePriority(kernel, cv_tree, thread); 871 BeforeUpdatePriority(kernel_ctx, cv_tree, thread);
825 } 872 }
826 873
827 // Change the priority. 874 // Change the priority.
@@ -830,11 +877,11 @@ void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
830 877
831 // Restore the condition variable, if relevant. 878 // Restore the condition variable, if relevant.
832 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) { 879 if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
833 AfterUpdatePriority(kernel, cv_tree, thread); 880 AfterUpdatePriority(kernel_ctx, cv_tree, thread);
834 } 881 }
835 882
836 // Update the scheduler. 883 // Update the scheduler.
837 KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority); 884 KScheduler::OnThreadPriorityChanged(kernel_ctx, thread, old_priority);
838 885
839 // Keep the lock owner up to date. 886 // Keep the lock owner up to date.
840 KThread* lock_owner = thread->GetLockOwner(); 887 KThread* lock_owner = thread->GetLockOwner();
@@ -932,7 +979,7 @@ void KThread::Exit() {
932 979
933 // Release the thread resource hint from parent. 980 // Release the thread resource hint from parent.
934 if (parent != nullptr) { 981 if (parent != nullptr) {
935 // TODO(bunnei): Hint that the resource is about to be released. 982 parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1);
936 resource_limit_release_hint = true; 983 resource_limit_release_hint = true;
937 } 984 }
938 985
@@ -995,56 +1042,6 @@ std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
995 return host_context; 1042 return host_context;
996} 1043}
997 1044
998ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system,
999 ThreadType type_flags, std::string name,
1000 VAddr entry_point, u32 priority, u64 arg,
1001 s32 processor_id, VAddr stack_top,
1002 Process* owner_process) {
1003 auto& kernel = system.Kernel();
1004
1005 std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
1006
1007 if (const auto result =
1008 thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority,
1009 processor_id, owner_process, type_flags);
1010 result.IsError()) {
1011 return result;
1012 }
1013
1014 thread->name = name;
1015
1016 auto& scheduler = kernel.GlobalSchedulerContext();
1017 scheduler.AddThread(thread);
1018
1019 return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
1020}
1021
1022ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(
1023 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
1024 u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
1025 std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) {
1026 auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg,
1027 processor_id, stack_top, owner_process);
1028
1029 if (thread_result.Succeeded()) {
1030 (*thread_result)->host_context =
1031 std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
1032 }
1033
1034 return thread_result;
1035}
1036
1037ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread(
1038 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
1039 u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) {
1040 std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
1041
1042 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
1043
1044 return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id,
1045 stack_top, owner_process, std::move(init_func), init_func_parameter);
1046}
1047
1048KThread* GetCurrentThreadPointer(KernelCore& kernel) { 1045KThread* GetCurrentThreadPointer(KernelCore& kernel) {
1049 return kernel.GetCurrentEmuThread(); 1046 return kernel.GetCurrentEmuThread();
1050} 1047}
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index b442dfe57..4abfc2b49 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -19,7 +19,7 @@
19#include "core/hle/kernel/k_light_lock.h" 19#include "core/hle/kernel/k_light_lock.h"
20#include "core/hle/kernel/k_spin_lock.h" 20#include "core/hle/kernel/k_spin_lock.h"
21#include "core/hle/kernel/k_synchronization_object.h" 21#include "core/hle/kernel/k_synchronization_object.h"
22#include "core/hle/kernel/object.h" 22#include "core/hle/kernel/slab_helpers.h"
23#include "core/hle/kernel/svc_common.h" 23#include "core/hle/kernel/svc_common.h"
24#include "core/hle/kernel/svc_types.h" 24#include "core/hle/kernel/svc_types.h"
25#include "core/hle/result.h" 25#include "core/hle/result.h"
@@ -37,7 +37,7 @@ namespace Kernel {
37 37
38class GlobalSchedulerContext; 38class GlobalSchedulerContext;
39class KernelCore; 39class KernelCore;
40class Process; 40class KProcess;
41class KScheduler; 41class KScheduler;
42class KThreadQueue; 42class KThreadQueue;
43 43
@@ -99,15 +99,19 @@ enum class ThreadWaitReasonForDebugging : u32 {
99[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); 99[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
100[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); 100[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
101 101
102class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { 102class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>,
103 public boost::intrusive::list_base_hook<> {
104 KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
105
106private:
103 friend class KScheduler; 107 friend class KScheduler;
104 friend class Process; 108 friend class KProcess;
105 109
106public: 110public:
107 static constexpr s32 DefaultThreadPriority = 44; 111 static constexpr s32 DefaultThreadPriority = 44;
108 static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; 112 static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
109 113
110 explicit KThread(KernelCore& kernel); 114 explicit KThread(KernelCore& kernel_);
111 ~KThread() override; 115 ~KThread() override;
112 116
113public: 117public:
@@ -115,74 +119,10 @@ public:
115 using ThreadContext64 = Core::ARM_Interface::ThreadContext64; 119 using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
116 using WaiterList = boost::intrusive::list<KThread>; 120 using WaiterList = boost::intrusive::list<KThread>;
117 121
118 /**
119 * Creates and returns a new thread.
120 * @param system The instance of the whole system
121 * @param name The friendly name desired for the thread
122 * @param entry_point The address at which the thread should start execution
123 * @param priority The thread's priority
124 * @param arg User data to pass to the thread
125 * @param processor_id The ID(s) of the processors on which the thread is desired to be run
126 * @param stack_top The address of the thread's stack top
127 * @param owner_process The parent process for the thread, if null, it's a kernel thread
128 * @return A shared pointer to the newly created thread
129 */
130 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
131 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
132 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
133
134 /**
135 * Creates and returns a new thread, with a specified entry point.
136 * @param system The instance of the whole system
137 * @param name The friendly name desired for the thread
138 * @param entry_point The address at which the thread should start execution
139 * @param priority The thread's priority
140 * @param arg User data to pass to the thread
141 * @param processor_id The ID(s) of the processors on which the thread is desired to be run
142 * @param stack_top The address of the thread's stack top
143 * @param owner_process The parent process for the thread, if null, it's a kernel thread
144 * @param thread_start_func The function where the host context will start.
145 * @param thread_start_parameter The parameter which will passed to host context on init
146 * @return A shared pointer to the newly created thread
147 */
148 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
149 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
150 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
151 std::function<void(void*)>&& thread_start_func, void* thread_start_parameter);
152
153 /**
154 * Creates and returns a new thread for the emulated "user" process.
155 * @param system The instance of the whole system
156 * @param name The friendly name desired for the thread
157 * @param entry_point The address at which the thread should start execution
158 * @param priority The thread's priority
159 * @param arg User data to pass to the thread
160 * @param processor_id The ID(s) of the processors on which the thread is desired to be run
161 * @param stack_top The address of the thread's stack top
162 * @param owner_process The parent process for the thread, if null, it's a kernel thread
163 * @return A shared pointer to the newly created thread
164 */
165 [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread(
166 Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
167 u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
168
169 [[nodiscard]] std::string GetName() const override {
170 return name;
171 }
172
173 void SetName(std::string new_name) { 122 void SetName(std::string new_name) {
174 name = std::move(new_name); 123 name = std::move(new_name);
175 } 124 }
176 125
177 [[nodiscard]] std::string GetTypeName() const override {
178 return "Thread";
179 }
180
181 static constexpr HandleType HANDLE_TYPE = HandleType::Thread;
182 [[nodiscard]] HandleType GetHandleType() const override {
183 return HANDLE_TYPE;
184 }
185
186 /** 126 /**
187 * Gets the thread's current priority 127 * Gets the thread's current priority
188 * @return The current thread's priority 128 * @return The current thread's priority
@@ -257,10 +197,6 @@ public:
257 197
258 void Suspend(); 198 void Suspend();
259 199
260 void Finalize() override;
261
262 bool IsSignaled() const override;
263
264 void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { 200 void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) {
265 synced_object = obj; 201 synced_object = obj;
266 wait_result = wait_res; 202 wait_result = wait_res;
@@ -354,11 +290,11 @@ public:
354 current_core_id = core; 290 current_core_id = core;
355 } 291 }
356 292
357 [[nodiscard]] Process* GetOwnerProcess() { 293 [[nodiscard]] KProcess* GetOwnerProcess() {
358 return parent; 294 return parent;
359 } 295 }
360 296
361 [[nodiscard]] const Process* GetOwnerProcess() const { 297 [[nodiscard]] const KProcess* GetOwnerProcess() const {
362 return parent; 298 return parent;
363 } 299 }
364 300
@@ -382,7 +318,7 @@ public:
382 318
383 [[nodiscard]] ResultCode GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask); 319 [[nodiscard]] ResultCode GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
384 320
385 [[nodiscard]] ResultCode SetCoreMask(s32 core_id, u64 v_affinity_mask); 321 [[nodiscard]] ResultCode SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask);
386 322
387 [[nodiscard]] ResultCode SetActivity(Svc::ThreadActivity activity); 323 [[nodiscard]] ResultCode SetActivity(Svc::ThreadActivity activity);
388 324
@@ -422,6 +358,40 @@ public:
422 return termination_requested || GetRawState() == ThreadState::Terminated; 358 return termination_requested || GetRawState() == ThreadState::Terminated;
423 } 359 }
424 360
361 [[nodiscard]] virtual u64 GetId() const override final {
362 return this->GetThreadID();
363 }
364
365 [[nodiscard]] virtual bool IsInitialized() const override {
366 return initialized;
367 }
368
369 [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override {
370 return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0);
371 }
372
373 virtual void Finalize() override;
374
375 [[nodiscard]] virtual bool IsSignaled() const override;
376
377 static void PostDestroy(uintptr_t arg);
378
379 [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
380
381 [[nodiscard]] static ResultCode InitializeIdleThread(Core::System& system, KThread* thread,
382 s32 virt_core);
383
384 [[nodiscard]] static ResultCode InitializeHighPriorityThread(Core::System& system,
385 KThread* thread,
386 KThreadFunction func,
387 uintptr_t arg, s32 virt_core);
388
389 [[nodiscard]] static ResultCode InitializeUserThread(Core::System& system, KThread* thread,
390 KThreadFunction func, uintptr_t arg,
391 VAddr user_stack_top, s32 prio,
392 s32 virt_core, KProcess* owner);
393
394public:
425 struct StackParameters { 395 struct StackParameters {
426 u8 svc_permission[0x10]; 396 u8 svc_permission[0x10];
427 std::atomic<u8> dpc_flags; 397 std::atomic<u8> dpc_flags;
@@ -671,13 +641,15 @@ private:
671 void StartTermination(); 641 void StartTermination();
672 642
673 [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, 643 [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
674 s32 prio, s32 virt_core, Process* owner, ThreadType type); 644 s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
675 645
676 [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func, 646 [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func,
677 uintptr_t arg, VAddr user_stack_top, s32 prio, 647 uintptr_t arg, VAddr user_stack_top, s32 prio,
678 s32 core, Process* owner, ThreadType type); 648 s32 core, KProcess* owner, ThreadType type,
649 std::function<void(void*)>&& init_func,
650 void* init_func_parameter);
679 651
680 static void RestorePriority(KernelCore& kernel, KThread* thread); 652 static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
681 653
682 // For core KThread implementation 654 // For core KThread implementation
683 ThreadContext32 thread_context_32{}; 655 ThreadContext32 thread_context_32{};
@@ -697,7 +669,7 @@ private:
697 std::atomic<s64> cpu_time{}; 669 std::atomic<s64> cpu_time{};
698 KSynchronizationObject* synced_object{}; 670 KSynchronizationObject* synced_object{};
699 VAddr address_key{}; 671 VAddr address_key{};
700 Process* parent{}; 672 KProcess* parent{};
701 VAddr kernel_stack_top{}; 673 VAddr kernel_stack_top{};
702 u32* light_ipc_data{}; 674 u32* light_ipc_data{};
703 VAddr tls_address{}; 675 VAddr tls_address{};
@@ -742,7 +714,6 @@ private:
742 VAddr mutex_wait_address_for_debugging{}; 714 VAddr mutex_wait_address_for_debugging{};
743 ThreadWaitReasonForDebugging wait_reason_for_debugging{}; 715 ThreadWaitReasonForDebugging wait_reason_for_debugging{};
744 ThreadType thread_type_for_debugging{}; 716 ThreadType thread_type_for_debugging{};
745 std::string name;
746 717
747public: 718public:
748 using ConditionVariableThreadTreeType = ConditionVariableThreadTree; 719 using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h
index c52eba249..35d471dc5 100644
--- a/src/core/hle/kernel/k_thread_queue.h
+++ b/src/core/hle/kernel/k_thread_queue.h
@@ -10,7 +10,7 @@ namespace Kernel {
10 10
11class KThreadQueue { 11class KThreadQueue {
12public: 12public:
13 explicit KThreadQueue(KernelCore& kernel) : kernel{kernel} {} 13 explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
14 14
15 bool IsEmpty() const { 15 bool IsEmpty() const {
16 return wait_list.empty(); 16 return wait_list.empty();
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
new file mode 100644
index 000000000..5bc33706d
--- /dev/null
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -0,0 +1,45 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_process.h"
6#include "core/hle/kernel/k_resource_limit.h"
7#include "core/hle/kernel/k_transfer_memory.h"
8#include "core/hle/kernel/kernel.h"
9
10namespace Kernel {
11
12KTransferMemory::KTransferMemory(KernelCore& kernel_)
13 : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
14
15KTransferMemory::~KTransferMemory() = default;
16
17ResultCode KTransferMemory::Initialize(VAddr address_, std::size_t size_,
18 Svc::MemoryPermission owner_perm_) {
19 // Set members.
20 owner = kernel.CurrentProcess();
21
22 // TODO(bunnei): Lock for transfer memory
23
24 // Set remaining tracking members.
25 owner->Open();
26 owner_perm = owner_perm_;
27 address = address_;
28 size = size_;
29 is_initialized = true;
30
31 return RESULT_SUCCESS;
32}
33
34void KTransferMemory::Finalize() {
35 // Perform inherited finalization.
36 KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList>::Finalize();
37}
38
39void KTransferMemory::PostDestroy(uintptr_t arg) {
40 KProcess* owner = reinterpret_cast<KProcess*>(arg);
41 owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
42 owner->Close();
43}
44
45} // namespace Kernel
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
new file mode 100644
index 000000000..838fd2b18
--- /dev/null
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -0,0 +1,66 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "core/hle/kernel/slab_helpers.h"
10#include "core/hle/kernel/svc_types.h"
11#include "core/hle/result.h"
12
13union ResultCode;
14
15namespace Core::Memory {
16class Memory;
17}
18
19namespace Kernel {
20
21class KernelCore;
22class KProcess;
23
24class KTransferMemory final
25 : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> {
26 KERNEL_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject);
27
28public:
29 explicit KTransferMemory(KernelCore& kernel_);
30 virtual ~KTransferMemory() override;
31
32 ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
33
34 virtual void Finalize() override;
35
36 virtual bool IsInitialized() const override {
37 return is_initialized;
38 }
39
40 virtual uintptr_t GetPostDestroyArgument() const override {
41 return reinterpret_cast<uintptr_t>(owner);
42 }
43
44 static void PostDestroy(uintptr_t arg);
45
46 KProcess* GetOwner() const {
47 return owner;
48 }
49
50 VAddr GetSourceAddress() const {
51 return address;
52 }
53
54 size_t GetSize() const {
55 return is_initialized ? size * PageSize : 0;
56 }
57
58private:
59 KProcess* owner{};
60 VAddr address{};
61 Svc::MemoryPermission owner_perm{};
62 size_t size{};
63 bool is_initialized{};
64};
65
66} // namespace Kernel
diff --git a/src/core/hle/kernel/k_writable_event.cpp b/src/core/hle/kernel/k_writable_event.cpp
index 25c52edb2..b7b83c151 100644
--- a/src/core/hle/kernel/k_writable_event.cpp
+++ b/src/core/hle/kernel/k_writable_event.cpp
@@ -8,20 +8,29 @@
8 8
9namespace Kernel { 9namespace Kernel {
10 10
11KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name) 11KWritableEvent::KWritableEvent(KernelCore& kernel_)
12 : Object{kernel, std::move(name)} {} 12 : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
13
13KWritableEvent::~KWritableEvent() = default; 14KWritableEvent::~KWritableEvent() = default;
14 15
15void KWritableEvent::Initialize(KEvent* parent_) { 16void KWritableEvent::Initialize(KEvent* parent_, std::string&& name_) {
16 parent = parent_; 17 parent = parent_;
18 name = std::move(name_);
19 parent->GetReadableEvent().Open();
17} 20}
18 21
19ResultCode KWritableEvent::Signal() { 22ResultCode KWritableEvent::Signal() {
20 return parent->GetReadableEvent()->Signal(); 23 return parent->GetReadableEvent().Signal();
21} 24}
22 25
23ResultCode KWritableEvent::Clear() { 26ResultCode KWritableEvent::Clear() {
24 return parent->GetReadableEvent()->Clear(); 27 return parent->GetReadableEvent().Clear();
28}
29
30void KWritableEvent::Destroy() {
31 // Close our references.
32 parent->GetReadableEvent().Close();
33 parent->Close();
25} 34}
26 35
27} // namespace Kernel 36} // namespace Kernel
diff --git a/src/core/hle/kernel/k_writable_event.h b/src/core/hle/kernel/k_writable_event.h
index 518f5448d..607b0eadb 100644
--- a/src/core/hle/kernel/k_writable_event.h
+++ b/src/core/hle/kernel/k_writable_event.h
@@ -4,7 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/k_auto_object.h"
8#include "core/hle/kernel/slab_helpers.h"
8#include "core/hle/result.h" 9#include "core/hle/result.h"
9 10
10namespace Kernel { 11namespace Kernel {
@@ -12,24 +13,19 @@ namespace Kernel {
12class KernelCore; 13class KernelCore;
13class KEvent; 14class KEvent;
14 15
15class KWritableEvent final : public Object { 16class KWritableEvent final
17 : public KAutoObjectWithSlabHeapAndContainer<KWritableEvent, KAutoObjectWithList> {
18 KERNEL_AUTOOBJECT_TRAITS(KWritableEvent, KAutoObject);
19
16public: 20public:
17 explicit KWritableEvent(KernelCore& kernel, std::string&& name); 21 explicit KWritableEvent(KernelCore& kernel_);
18 ~KWritableEvent() override; 22 ~KWritableEvent() override;
19 23
20 std::string GetTypeName() const override { 24 virtual void Destroy() override;
21 return "KWritableEvent";
22 }
23
24 static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
25 HandleType GetHandleType() const override {
26 return HANDLE_TYPE;
27 }
28
29 void Initialize(KEvent* parent_);
30 25
31 void Finalize() override {} 26 static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
32 27
28 void Initialize(KEvent* parent_, std::string&& name_);
33 ResultCode Signal(); 29 ResultCode Signal();
34 ResultCode Clear(); 30 ResultCode Clear();
35 31
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 5c4f45ab4..8b55df82e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -26,10 +26,12 @@
26#include "core/cpu_manager.h" 26#include "core/cpu_manager.h"
27#include "core/device_memory.h" 27#include "core/device_memory.h"
28#include "core/hardware_properties.h" 28#include "core/hardware_properties.h"
29#include "core/hle/kernel/client_port.h" 29#include "core/hle/kernel/init/init_slab_setup.h"
30#include "core/hle/kernel/handle_table.h" 30#include "core/hle/kernel/k_client_port.h"
31#include "core/hle/kernel/k_handle_table.h"
31#include "core/hle/kernel/k_memory_layout.h" 32#include "core/hle/kernel/k_memory_layout.h"
32#include "core/hle/kernel/k_memory_manager.h" 33#include "core/hle/kernel/k_memory_manager.h"
34#include "core/hle/kernel/k_process.h"
33#include "core/hle/kernel/k_resource_limit.h" 35#include "core/hle/kernel/k_resource_limit.h"
34#include "core/hle/kernel/k_scheduler.h" 36#include "core/hle/kernel/k_scheduler.h"
35#include "core/hle/kernel/k_shared_memory.h" 37#include "core/hle/kernel/k_shared_memory.h"
@@ -37,12 +39,12 @@
37#include "core/hle/kernel/k_thread.h" 39#include "core/hle/kernel/k_thread.h"
38#include "core/hle/kernel/kernel.h" 40#include "core/hle/kernel/kernel.h"
39#include "core/hle/kernel/physical_core.h" 41#include "core/hle/kernel/physical_core.h"
40#include "core/hle/kernel/process.h"
41#include "core/hle/kernel/service_thread.h" 42#include "core/hle/kernel/service_thread.h"
42#include "core/hle/kernel/svc_results.h" 43#include "core/hle/kernel/svc_results.h"
43#include "core/hle/kernel/time_manager.h" 44#include "core/hle/kernel/time_manager.h"
44#include "core/hle/lock.h" 45#include "core/hle/lock.h"
45#include "core/hle/result.h" 46#include "core/hle/result.h"
47#include "core/hle/service/sm/sm.h"
46#include "core/memory.h" 48#include "core/memory.h"
47 49
48MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); 50MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
@@ -50,17 +52,16 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
50namespace Kernel { 52namespace Kernel {
51 53
52struct KernelCore::Impl { 54struct KernelCore::Impl {
53 explicit Impl(Core::System& system, KernelCore& kernel) 55 explicit Impl(Core::System& system_, KernelCore& kernel_)
54 : time_manager{system}, global_handle_table{kernel}, system{system} {} 56 : time_manager{system_}, object_list_container{kernel_}, system{system_} {}
55 57
56 void SetMulticore(bool is_multicore) { 58 void SetMulticore(bool is_multi) {
57 this->is_multicore = is_multicore; 59 is_multicore = is_multi;
58 } 60 }
59 61
60 void Initialize(KernelCore& kernel) { 62 void Initialize(KernelCore& kernel) {
61 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); 63 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
62 64 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
63 RegisterHostThread();
64 65
65 service_thread_manager = 66 service_thread_manager =
66 std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager"); 67 std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
@@ -69,14 +70,20 @@ struct KernelCore::Impl {
69 InitializePhysicalCores(); 70 InitializePhysicalCores();
70 71
71 // Derive the initial memory layout from the emulated board 72 // Derive the initial memory layout from the emulated board
73 Init::InitializeSlabResourceCounts(kernel);
72 KMemoryLayout memory_layout; 74 KMemoryLayout memory_layout;
73 DeriveInitialMemoryLayout(memory_layout); 75 DeriveInitialMemoryLayout(memory_layout);
74 InitializeMemoryLayout(memory_layout); 76 Init::InitializeSlabHeaps(system, memory_layout);
77
78 // Initialize kernel memory and resources.
75 InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout); 79 InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
76 InitializeSlabHeaps(); 80 InitializeMemoryLayout(memory_layout);
81 InitializePageSlab();
77 InitializeSchedulers(); 82 InitializeSchedulers();
78 InitializeSuspendThreads(); 83 InitializeSuspendThreads();
79 InitializePreemption(kernel); 84 InitializePreemption(kernel);
85
86 RegisterHostThread();
80 } 87 }
81 88
82 void InitializeCores() { 89 void InitializeCores() {
@@ -93,34 +100,49 @@ struct KernelCore::Impl {
93 service_threads.clear(); 100 service_threads.clear();
94 101
95 next_object_id = 0; 102 next_object_id = 0;
96 next_kernel_process_id = Process::InitialKIPIDMin; 103 next_kernel_process_id = KProcess::InitialKIPIDMin;
97 next_user_process_id = Process::ProcessIDMin; 104 next_user_process_id = KProcess::ProcessIDMin;
98 next_thread_id = 1; 105 next_thread_id = 1;
99 106
100 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { 107 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
101 if (suspend_threads[i]) { 108 if (suspend_threads[core_id]) {
102 suspend_threads[i].reset(); 109 suspend_threads[core_id]->Close();
110 suspend_threads[core_id] = nullptr;
103 } 111 }
112
113 schedulers[core_id].reset();
104 } 114 }
105 115
106 cores.clear(); 116 cores.clear();
107 117
108 current_process = nullptr; 118 if (current_process) {
119 current_process->Close();
120 current_process = nullptr;
121 }
109 122
110 global_handle_table.Clear(); 123 global_handle_table.reset();
111 124
112 preemption_event = nullptr; 125 preemption_event = nullptr;
113 126
127 for (auto& iter : named_ports) {
128 iter.second->Close();
129 }
114 named_ports.clear(); 130 named_ports.clear();
115 131
116 exclusive_monitor.reset(); 132 exclusive_monitor.reset();
117 133
118 hid_shared_mem = nullptr; 134 // Cleanup persistent kernel objects
119 font_shared_mem = nullptr; 135 auto CleanupObject = [](KAutoObject* obj) {
120 irs_shared_mem = nullptr; 136 if (obj) {
121 time_shared_mem = nullptr; 137 obj->Close();
122 138 obj = nullptr;
123 system_resource_limit = nullptr; 139 }
140 };
141 CleanupObject(hid_shared_mem);
142 CleanupObject(font_shared_mem);
143 CleanupObject(irs_shared_mem);
144 CleanupObject(time_shared_mem);
145 CleanupObject(system_resource_limit);
124 146
125 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others 147 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
126 next_host_thread_id = Core::Hardware::NUM_CPU_CORES; 148 next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
@@ -145,7 +167,9 @@ struct KernelCore::Impl {
145 void InitializeSystemResourceLimit(KernelCore& kernel, 167 void InitializeSystemResourceLimit(KernelCore& kernel,
146 const Core::Timing::CoreTiming& core_timing, 168 const Core::Timing::CoreTiming& core_timing,
147 const KMemoryLayout& memory_layout) { 169 const KMemoryLayout& memory_layout) {
148 system_resource_limit = std::make_shared<KResourceLimit>(kernel, core_timing); 170 system_resource_limit = KResourceLimit::Create(system.Kernel());
171 system_resource_limit->Initialize(&core_timing);
172
149 const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes(); 173 const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
150 174
151 // If setting the default system values fails, then something seriously wrong has occurred. 175 // If setting the default system values fails, then something seriously wrong has occurred.
@@ -189,19 +213,16 @@ struct KernelCore::Impl {
189 } 213 }
190 214
191 void InitializeSuspendThreads() { 215 void InitializeSuspendThreads() {
192 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { 216 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
193 std::string name = "Suspend Thread Id:" + std::to_string(i); 217 suspend_threads[core_id] = KThread::Create(system.Kernel());
194 std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); 218 ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {},
195 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); 219 core_id)
196 auto thread_res = KThread::CreateThread( 220 .IsSuccess());
197 system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, 221 suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
198 nullptr, std::move(init_func), init_func_parameter);
199
200 suspend_threads[i] = std::move(thread_res).Unwrap();
201 } 222 }
202 } 223 }
203 224
204 void MakeCurrentProcess(Process* process) { 225 void MakeCurrentProcess(KProcess* process) {
205 current_process = process; 226 current_process = process;
206 if (process == nullptr) { 227 if (process == nullptr) {
207 return; 228 return;
@@ -232,11 +253,15 @@ struct KernelCore::Impl {
232 253
233 // Gets the dummy KThread for the caller, allocating a new one if this is the first time 254 // Gets the dummy KThread for the caller, allocating a new one if this is the first time
234 KThread* GetHostDummyThread() { 255 KThread* GetHostDummyThread() {
235 const thread_local auto thread = 256 auto make_thread = [this]() {
236 KThread::CreateThread( 257 std::unique_ptr<KThread> thread = std::make_unique<KThread>(system.Kernel());
237 system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0, 258 KAutoObject::Create(thread.get());
238 KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr) 259 ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess());
239 .Unwrap(); 260 thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
261 return std::move(thread);
262 };
263
264 thread_local auto thread = make_thread();
240 return thread.get(); 265 return thread.get();
241 } 266 }
242 267
@@ -371,7 +396,8 @@ struct KernelCore::Impl {
371 const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit(); 396 const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
372 397
373 // Determine the size of the slab region. 398 // Determine the size of the slab region.
374 const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize); 399 const size_t slab_region_size =
400 Common::AlignUp(Init::CalculateTotalSlabHeapSize(system.Kernel()), PageSize);
375 ASSERT(slab_region_size <= resource_region_size); 401 ASSERT(slab_region_size <= resource_region_size);
376 402
377 // Setup the slab region. 403 // Setup the slab region.
@@ -569,25 +595,30 @@ struct KernelCore::Impl {
569 const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size}; 595 const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
570 const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size}; 596 const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
571 597
572 hid_shared_mem = Kernel::KSharedMemory::Create( 598 hid_shared_mem = KSharedMemory::Create(system.Kernel());
573 system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize}, 599 font_shared_mem = KSharedMemory::Create(system.Kernel());
574 KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size, 600 irs_shared_mem = KSharedMemory::Create(system.Kernel());
575 "HID:SharedMemory"); 601 time_shared_mem = KSharedMemory::Create(system.Kernel());
576 font_shared_mem = Kernel::KSharedMemory::Create( 602
577 system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize}, 603 hid_shared_mem->Initialize(system.DeviceMemory(), nullptr,
578 KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size, 604 {hid_phys_addr, hid_size / PageSize},
579 "Font:SharedMemory"); 605 Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
580 irs_shared_mem = Kernel::KSharedMemory::Create( 606 hid_phys_addr, hid_size, "HID:SharedMemory");
581 system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize}, 607 font_shared_mem->Initialize(system.DeviceMemory(), nullptr,
582 KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size, 608 {font_phys_addr, font_size / PageSize},
583 "IRS:SharedMemory"); 609 Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
584 time_shared_mem = Kernel::KSharedMemory::Create( 610 font_phys_addr, font_size, "Font:SharedMemory");
585 system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize}, 611 irs_shared_mem->Initialize(system.DeviceMemory(), nullptr,
586 KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size, 612 {irs_phys_addr, irs_size / PageSize},
587 "Time:SharedMemory"); 613 Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
614 irs_phys_addr, irs_size, "IRS:SharedMemory");
615 time_shared_mem->Initialize(system.DeviceMemory(), nullptr,
616 {time_phys_addr, time_size / PageSize},
617 Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
618 time_phys_addr, time_size, "Time:SharedMemory");
588 } 619 }
589 620
590 void InitializeSlabHeaps() { 621 void InitializePageSlab() {
591 // Allocate slab heaps 622 // Allocate slab heaps
592 user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); 623 user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
593 624
@@ -596,33 +627,37 @@ struct KernelCore::Impl {
596 // Reserve slab heaps 627 // Reserve slab heaps
597 ASSERT( 628 ASSERT(
598 system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); 629 system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));
599 // Initialize slab heaps 630 // Initialize slab heap
600 user_slab_heap_pages->Initialize( 631 user_slab_heap_pages->Initialize(
601 system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase), 632 system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase),
602 user_slab_heap_size); 633 user_slab_heap_size);
603 } 634 }
604 635
605 std::atomic<u32> next_object_id{0}; 636 std::atomic<u32> next_object_id{0};
606 std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; 637 std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
607 std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; 638 std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin};
608 std::atomic<u64> next_thread_id{1}; 639 std::atomic<u64> next_thread_id{1};
609 640
610 // Lists all processes that exist in the current session. 641 // Lists all processes that exist in the current session.
611 std::vector<std::shared_ptr<Process>> process_list; 642 std::vector<KProcess*> process_list;
612 Process* current_process = nullptr; 643 KProcess* current_process{};
613 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; 644 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
614 Kernel::TimeManager time_manager; 645 Kernel::TimeManager time_manager;
615 646
616 std::shared_ptr<KResourceLimit> system_resource_limit; 647 Init::KSlabResourceCounts slab_resource_counts{};
648 KResourceLimit* system_resource_limit{};
617 649
618 std::shared_ptr<Core::Timing::EventType> preemption_event; 650 std::shared_ptr<Core::Timing::EventType> preemption_event;
619 651
620 // This is the kernel's handle table or supervisor handle table which 652 // This is the kernel's handle table or supervisor handle table which
621 // stores all the objects in place. 653 // stores all the objects in place.
622 HandleTable global_handle_table; 654 std::unique_ptr<KHandleTable> global_handle_table;
655
656 KAutoObjectWithListContainer object_list_container;
623 657
624 /// Map of named ports managed by the kernel, which can be retrieved using 658 /// Map of named ports managed by the kernel, which can be retrieved using
625 /// the ConnectToPort SVC. 659 /// the ConnectToPort SVC.
660 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
626 NamedPortTable named_ports; 661 NamedPortTable named_ports;
627 662
628 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 663 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
@@ -636,10 +671,10 @@ struct KernelCore::Impl {
636 std::unique_ptr<KSlabHeap<Page>> user_slab_heap_pages; 671 std::unique_ptr<KSlabHeap<Page>> user_slab_heap_pages;
637 672
638 // Shared memory for services 673 // Shared memory for services
639 std::shared_ptr<Kernel::KSharedMemory> hid_shared_mem; 674 Kernel::KSharedMemory* hid_shared_mem{};
640 std::shared_ptr<Kernel::KSharedMemory> font_shared_mem; 675 Kernel::KSharedMemory* font_shared_mem{};
641 std::shared_ptr<Kernel::KSharedMemory> irs_shared_mem; 676 Kernel::KSharedMemory* irs_shared_mem{};
642 std::shared_ptr<Kernel::KSharedMemory> time_shared_mem; 677 Kernel::KSharedMemory* time_shared_mem{};
643 678
644 // Threads used for services 679 // Threads used for services
645 std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads; 680 std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
@@ -648,7 +683,7 @@ struct KernelCore::Impl {
648 // the release of itself 683 // the release of itself
649 std::unique_ptr<Common::ThreadWorker> service_thread_manager; 684 std::unique_ptr<Common::ThreadWorker> service_thread_manager;
650 685
651 std::array<std::shared_ptr<KThread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; 686 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
652 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; 687 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
653 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; 688 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
654 689
@@ -663,15 +698,14 @@ struct KernelCore::Impl {
663}; 698};
664 699
665KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {} 700KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
666KernelCore::~KernelCore() { 701KernelCore::~KernelCore() = default;
667 Shutdown();
668}
669 702
670void KernelCore::SetMulticore(bool is_multicore) { 703void KernelCore::SetMulticore(bool is_multicore) {
671 impl->SetMulticore(is_multicore); 704 impl->SetMulticore(is_multicore);
672} 705}
673 706
674void KernelCore::Initialize() { 707void KernelCore::Initialize() {
708 slab_heap_container = std::make_unique<SlabHeapContainer>();
675 impl->Initialize(*this); 709 impl->Initialize(*this);
676} 710}
677 711
@@ -683,31 +717,35 @@ void KernelCore::Shutdown() {
683 impl->Shutdown(); 717 impl->Shutdown();
684} 718}
685 719
686std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const { 720const KResourceLimit* KernelCore::GetSystemResourceLimit() const {
721 return impl->system_resource_limit;
722}
723
724KResourceLimit* KernelCore::GetSystemResourceLimit() {
687 return impl->system_resource_limit; 725 return impl->system_resource_limit;
688} 726}
689 727
690std::shared_ptr<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const { 728KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
691 return impl->global_handle_table.Get<KThread>(handle); 729 return impl->global_handle_table->GetObject<KThread>(handle);
692} 730}
693 731
694void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { 732void KernelCore::AppendNewProcess(KProcess* process) {
695 impl->process_list.push_back(std::move(process)); 733 impl->process_list.push_back(process);
696} 734}
697 735
698void KernelCore::MakeCurrentProcess(Process* process) { 736void KernelCore::MakeCurrentProcess(KProcess* process) {
699 impl->MakeCurrentProcess(process); 737 impl->MakeCurrentProcess(process);
700} 738}
701 739
702Process* KernelCore::CurrentProcess() { 740KProcess* KernelCore::CurrentProcess() {
703 return impl->current_process; 741 return impl->current_process;
704} 742}
705 743
706const Process* KernelCore::CurrentProcess() const { 744const KProcess* KernelCore::CurrentProcess() const {
707 return impl->current_process; 745 return impl->current_process;
708} 746}
709 747
710const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const { 748const std::vector<KProcess*>& KernelCore::GetProcessList() const {
711 return impl->process_list; 749 return impl->process_list;
712} 750}
713 751
@@ -781,6 +819,14 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
781 return *impl->exclusive_monitor; 819 return *impl->exclusive_monitor;
782} 820}
783 821
822KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
823 return impl->object_list_container;
824}
825
826const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
827 return impl->object_list_container;
828}
829
784void KernelCore::InvalidateAllInstructionCaches() { 830void KernelCore::InvalidateAllInstructionCaches() {
785 for (auto& physical_core : impl->cores) { 831 for (auto& physical_core : impl->cores) {
786 physical_core.ArmInterface().ClearInstructionCache(); 832 physical_core.ArmInterface().ClearInstructionCache();
@@ -800,17 +846,17 @@ void KernelCore::PrepareReschedule(std::size_t id) {
800 // TODO: Reimplement, this 846 // TODO: Reimplement, this
801} 847}
802 848
803void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { 849void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) {
804 impl->named_ports.emplace(std::move(name), std::move(port)); 850 impl->service_interface_factory.emplace(std::move(name), factory);
805} 851}
806 852
807KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) { 853KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
808 return impl->named_ports.find(name); 854 auto search = impl->service_interface_factory.find(name);
809} 855 if (search == impl->service_interface_factory.end()) {
810 856 UNIMPLEMENTED();
811KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort( 857 return {};
812 const std::string& name) const { 858 }
813 return impl->named_ports.find(name); 859 return &search->second(impl->system.ServiceManager(), impl->system);
814} 860}
815 861
816bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { 862bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
@@ -833,12 +879,12 @@ u64 KernelCore::CreateNewUserProcessID() {
833 return impl->next_user_process_id++; 879 return impl->next_user_process_id++;
834} 880}
835 881
836Kernel::HandleTable& KernelCore::GlobalHandleTable() { 882KHandleTable& KernelCore::GlobalHandleTable() {
837 return impl->global_handle_table; 883 return *impl->global_handle_table;
838} 884}
839 885
840const Kernel::HandleTable& KernelCore::GlobalHandleTable() const { 886const KHandleTable& KernelCore::GlobalHandleTable() const {
841 return impl->global_handle_table; 887 return *impl->global_handle_table;
842} 888}
843 889
844void KernelCore::RegisterCoreThread(std::size_t core_id) { 890void KernelCore::RegisterCoreThread(std::size_t core_id) {
@@ -910,9 +956,9 @@ void KernelCore::Suspend(bool in_suspention) {
910 { 956 {
911 KScopedSchedulerLock lock(*this); 957 KScopedSchedulerLock lock(*this);
912 const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; 958 const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting;
913 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { 959 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
914 impl->suspend_threads[i]->SetState(state); 960 impl->suspend_threads[core_id]->SetState(state);
915 impl->suspend_threads[i]->SetWaitReasonForDebugging( 961 impl->suspend_threads[core_id]->SetWaitReasonForDebugging(
916 ThreadWaitReasonForDebugging::Suspended); 962 ThreadWaitReasonForDebugging::Suspended);
917 } 963 }
918 } 964 }
@@ -952,6 +998,14 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi
952 }); 998 });
953} 999}
954 1000
1001Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
1002 return impl->slab_resource_counts;
1003}
1004
1005const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const {
1006 return impl->slab_resource_counts;
1007}
1008
955bool KernelCore::IsPhantomModeForSingleCore() const { 1009bool KernelCore::IsPhantomModeForSingleCore() const {
956 return impl->IsPhantomModeForSingleCore(); 1010 return impl->IsPhantomModeForSingleCore();
957} 1011}
@@ -960,4 +1014,12 @@ void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
960 impl->SetIsPhantomModeForSingleCore(value); 1014 impl->SetIsPhantomModeForSingleCore(value);
961} 1015}
962 1016
1017Core::System& KernelCore::System() {
1018 return impl->system;
1019}
1020
1021const Core::System& KernelCore::System() const {
1022 return impl->system;
1023}
1024
963} // namespace Kernel 1025} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a500e63bc..2d01e1ae0 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,8 +11,10 @@
11#include <vector> 11#include <vector>
12#include "core/arm/cpu_interrupt_handler.h" 12#include "core/arm/cpu_interrupt_handler.h"
13#include "core/hardware_properties.h" 13#include "core/hardware_properties.h"
14#include "core/hle/kernel/k_auto_object.h"
15#include "core/hle/kernel/k_slab_heap.h"
14#include "core/hle/kernel/memory_types.h" 16#include "core/hle/kernel/memory_types.h"
15#include "core/hle/kernel/object.h" 17#include "core/hle/kernel/svc_common.h"
16 18
17namespace Core { 19namespace Core {
18class CPUInterruptHandler; 20class CPUInterruptHandler;
@@ -25,22 +27,41 @@ class CoreTiming;
25struct EventType; 27struct EventType;
26} // namespace Core::Timing 28} // namespace Core::Timing
27 29
30namespace Service::SM {
31class ServiceManager;
32}
33
28namespace Kernel { 34namespace Kernel {
29 35
30class ClientPort; 36class KClientPort;
31class GlobalSchedulerContext; 37class GlobalSchedulerContext;
32class HandleTable; 38class KAutoObjectWithListContainer;
39class KClientSession;
40class KEvent;
41class KHandleTable;
42class KLinkedListNode;
33class KMemoryManager; 43class KMemoryManager;
44class KPort;
45class KProcess;
34class KResourceLimit; 46class KResourceLimit;
35class KScheduler; 47class KScheduler;
48class KSession;
36class KSharedMemory; 49class KSharedMemory;
37class KThread; 50class KThread;
51class KTransferMemory;
52class KWritableEvent;
38class PhysicalCore; 53class PhysicalCore;
39class Process;
40class ServiceThread; 54class ServiceThread;
41class Synchronization; 55class Synchronization;
42class TimeManager; 56class TimeManager;
43 57
58using ServiceInterfaceFactory =
59 std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
60
61namespace Init {
62struct KSlabResourceCounts;
63}
64
44template <typename T> 65template <typename T>
45class KSlabHeap; 66class KSlabHeap;
46 67
@@ -51,7 +72,7 @@ constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
51/// Represents a single instance of the kernel. 72/// Represents a single instance of the kernel.
52class KernelCore { 73class KernelCore {
53private: 74private:
54 using NamedPortTable = std::unordered_map<std::string, std::shared_ptr<ClientPort>>; 75 using NamedPortTable = std::unordered_map<std::string, KClientPort*>;
55 76
56public: 77public:
57 /// Constructs an instance of the kernel using the given System 78 /// Constructs an instance of the kernel using the given System
@@ -83,25 +104,28 @@ public:
83 void Shutdown(); 104 void Shutdown();
84 105
85 /// Retrieves a shared pointer to the system resource limit instance. 106 /// Retrieves a shared pointer to the system resource limit instance.
86 std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const; 107 const KResourceLimit* GetSystemResourceLimit() const;
108
109 /// Retrieves a shared pointer to the system resource limit instance.
110 KResourceLimit* GetSystemResourceLimit();
87 111
88 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. 112 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
89 std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const; 113 KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
90 114
91 /// Adds the given shared pointer to an internal list of active processes. 115 /// Adds the given shared pointer to an internal list of active processes.
92 void AppendNewProcess(std::shared_ptr<Process> process); 116 void AppendNewProcess(KProcess* process);
93 117
94 /// Makes the given process the new current process. 118 /// Makes the given process the new current process.
95 void MakeCurrentProcess(Process* process); 119 void MakeCurrentProcess(KProcess* process);
96 120
97 /// Retrieves a pointer to the current process. 121 /// Retrieves a pointer to the current process.
98 Process* CurrentProcess(); 122 KProcess* CurrentProcess();
99 123
100 /// Retrieves a const pointer to the current process. 124 /// Retrieves a const pointer to the current process.
101 const Process* CurrentProcess() const; 125 const KProcess* CurrentProcess() const;
102 126
103 /// Retrieves the list of processes. 127 /// Retrieves the list of processes.
104 const std::vector<std::shared_ptr<Process>>& GetProcessList() const; 128 const std::vector<KProcess*>& GetProcessList() const;
105 129
106 /// Gets the sole instance of the global scheduler 130 /// Gets the sole instance of the global scheduler
107 Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); 131 Kernel::GlobalSchedulerContext& GlobalSchedulerContext();
@@ -143,6 +167,10 @@ public:
143 167
144 const Core::ExclusiveMonitor& GetExclusiveMonitor() const; 168 const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
145 169
170 KAutoObjectWithListContainer& ObjectListContainer();
171
172 const KAutoObjectWithListContainer& ObjectListContainer() const;
173
146 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts(); 174 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts();
147 175
148 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const; 176 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
@@ -151,14 +179,11 @@ public:
151 179
152 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); 180 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
153 181
154 /// Adds a port to the named port table 182 /// Registers a named HLE service, passing a factory used to open a port to that service.
155 void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); 183 void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
156
157 /// Finds a port within the named port table with the given name.
158 NamedPortTable::iterator FindNamedPort(const std::string& name);
159 184
160 /// Finds a port within the named port table with the given name. 185 /// Opens a port to a service previously registered with RegisterNamedService.
161 NamedPortTable::const_iterator FindNamedPort(const std::string& name) const; 186 KClientPort* CreateNamedServicePort(std::string name);
162 187
163 /// Determines whether or not the given port is a valid named port. 188 /// Determines whether or not the given port is a valid named port.
164 bool IsValidNamedPort(NamedPortTable::const_iterator port) const; 189 bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
@@ -225,9 +250,10 @@ public:
225 250
226 /** 251 /**
227 * Creates an HLE service thread, which are used to execute service routines asynchronously. 252 * Creates an HLE service thread, which are used to execute service routines asynchronously.
228 * While these are allocated per ServerSession, these need to be owned and managed outside of 253 * While these are allocated per ServerSession, these need to be owned and managed outside
229 * ServerSession to avoid a circular dependency. 254 * of ServerSession to avoid a circular dependency.
230 * @param name String name for the ServerSession creating this thread, used for debug purposes. 255 * @param name String name for the ServerSession creating this thread, used for debug
256 * purposes.
231 * @returns The a weak pointer newly created service thread. 257 * @returns The a weak pointer newly created service thread.
232 */ 258 */
233 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name); 259 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
@@ -243,9 +269,45 @@ public:
243 bool IsPhantomModeForSingleCore() const; 269 bool IsPhantomModeForSingleCore() const;
244 void SetIsPhantomModeForSingleCore(bool value); 270 void SetIsPhantomModeForSingleCore(bool value);
245 271
272 Core::System& System();
273 const Core::System& System() const;
274
275 /// Gets the slab heap for the specified kernel object type.
276 template <typename T>
277 KSlabHeap<T>& SlabHeap() {
278 if constexpr (std::is_same_v<T, KClientSession>) {
279 return slab_heap_container->client_session;
280 } else if constexpr (std::is_same_v<T, KEvent>) {
281 return slab_heap_container->event;
282 } else if constexpr (std::is_same_v<T, KLinkedListNode>) {
283 return slab_heap_container->linked_list_node;
284 } else if constexpr (std::is_same_v<T, KPort>) {
285 return slab_heap_container->port;
286 } else if constexpr (std::is_same_v<T, KProcess>) {
287 return slab_heap_container->process;
288 } else if constexpr (std::is_same_v<T, KResourceLimit>) {
289 return slab_heap_container->resource_limit;
290 } else if constexpr (std::is_same_v<T, KSession>) {
291 return slab_heap_container->session;
292 } else if constexpr (std::is_same_v<T, KSharedMemory>) {
293 return slab_heap_container->shared_memory;
294 } else if constexpr (std::is_same_v<T, KThread>) {
295 return slab_heap_container->thread;
296 } else if constexpr (std::is_same_v<T, KTransferMemory>) {
297 return slab_heap_container->transfer_memory;
298 } else if constexpr (std::is_same_v<T, KWritableEvent>) {
299 return slab_heap_container->writeable_event;
300 }
301 }
302
303 /// Gets the current slab resource counts.
304 Init::KSlabResourceCounts& SlabResourceCounts();
305
306 /// Gets the current slab resource counts.
307 const Init::KSlabResourceCounts& SlabResourceCounts() const;
308
246private: 309private:
247 friend class Object; 310 friend class KProcess;
248 friend class Process;
249 friend class KThread; 311 friend class KThread;
250 312
251 /// Creates a new object ID, incrementing the internal object ID counter. 313 /// Creates a new object ID, incrementing the internal object ID counter.
@@ -261,14 +323,33 @@ private:
261 u64 CreateNewThreadID(); 323 u64 CreateNewThreadID();
262 324
263 /// Provides a reference to the global handle table. 325 /// Provides a reference to the global handle table.
264 Kernel::HandleTable& GlobalHandleTable(); 326 KHandleTable& GlobalHandleTable();
265 327
266 /// Provides a const reference to the global handle table. 328 /// Provides a const reference to the global handle table.
267 const Kernel::HandleTable& GlobalHandleTable() const; 329 const KHandleTable& GlobalHandleTable() const;
268 330
269 struct Impl; 331 struct Impl;
270 std::unique_ptr<Impl> impl; 332 std::unique_ptr<Impl> impl;
333
271 bool exception_exited{}; 334 bool exception_exited{};
335
336private:
337 /// Helper to encapsulate all slab heaps in a single heap allocated container
338 struct SlabHeapContainer {
339 KSlabHeap<KClientSession> client_session;
340 KSlabHeap<KEvent> event;
341 KSlabHeap<KLinkedListNode> linked_list_node;
342 KSlabHeap<KPort> port;
343 KSlabHeap<KProcess> process;
344 KSlabHeap<KResourceLimit> resource_limit;
345 KSlabHeap<KSession> session;
346 KSlabHeap<KSharedMemory> shared_memory;
347 KSlabHeap<KThread> thread;
348 KSlabHeap<KTransferMemory> transfer_memory;
349 KSlabHeap<KWritableEvent> writeable_event;
350 };
351
352 std::unique_ptr<SlabHeapContainer> slab_heap_container;
272}; 353};
273 354
274} // namespace Kernel 355} // namespace Kernel
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
deleted file mode 100644
index d7f40c403..000000000
--- a/src/core/hle/kernel/object.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/object.h"
8
9namespace Kernel {
10
11Object::Object(KernelCore& kernel_)
12 : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {}
13Object::Object(KernelCore& kernel_, std::string&& name_)
14 : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {}
15Object::~Object() = default;
16
17bool Object::IsWaitable() const {
18 switch (GetHandleType()) {
19 case HandleType::ReadableEvent:
20 case HandleType::Thread:
21 case HandleType::Process:
22 case HandleType::ServerPort:
23 case HandleType::ServerSession:
24 return true;
25
26 case HandleType::Unknown:
27 case HandleType::Event:
28 case HandleType::WritableEvent:
29 case HandleType::SharedMemory:
30 case HandleType::TransferMemory:
31 case HandleType::ResourceLimit:
32 case HandleType::ClientPort:
33 case HandleType::ClientSession:
34 case HandleType::Session:
35 return false;
36 }
37
38 UNREACHABLE();
39 return false;
40}
41
42} // namespace Kernel
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
deleted file mode 100644
index 501e58b33..000000000
--- a/src/core/hle/kernel/object.h
+++ /dev/null
@@ -1,96 +0,0 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <string>
10
11#include "common/common_types.h"
12
13namespace Kernel {
14
15class KernelCore;
16
17using Handle = u32;
18
19enum class HandleType : u32 {
20 Unknown,
21 Event,
22 WritableEvent,
23 ReadableEvent,
24 SharedMemory,
25 TransferMemory,
26 Thread,
27 Process,
28 ResourceLimit,
29 ClientPort,
30 ServerPort,
31 ClientSession,
32 ServerSession,
33 Session,
34};
35
36class Object : NonCopyable, public std::enable_shared_from_this<Object> {
37public:
38 explicit Object(KernelCore& kernel_);
39 explicit Object(KernelCore& kernel_, std::string&& name_);
40 virtual ~Object();
41
42 /// Returns a unique identifier for the object. For debugging purposes only.
43 u32 GetObjectId() const {
44 return object_id.load(std::memory_order_relaxed);
45 }
46
47 virtual std::string GetTypeName() const {
48 return "[BAD KERNEL OBJECT TYPE]";
49 }
50 virtual std::string GetName() const {
51 return name;
52 }
53 virtual HandleType GetHandleType() const = 0;
54
55 void Close() {
56 // TODO(bunnei): This is a placeholder to decrement the reference count, which we will use
57 // when we implement KAutoObject instead of using shared_ptr.
58 }
59
60 /**
61 * Check if a thread can wait on the object
62 * @return True if a thread can wait on the object, otherwise false
63 */
64 bool IsWaitable() const;
65
66 virtual void Finalize() = 0;
67
68protected:
69 /// The kernel instance this object was created under.
70 KernelCore& kernel;
71
72private:
73 std::atomic<u32> object_id{0};
74 std::string name;
75};
76
77template <typename T>
78std::shared_ptr<T> SharedFrom(T* raw) {
79 if (raw == nullptr)
80 return nullptr;
81 return std::static_pointer_cast<T>(raw->shared_from_this());
82}
83
84/**
85 * Attempts to downcast the given Object pointer to a pointer to T.
86 * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
87 */
88template <typename T>
89inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
90 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
91 return std::static_pointer_cast<T>(object);
92 }
93 return nullptr;
94}
95
96} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 7fea45f96..7f02d9471 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -13,10 +13,10 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, 16PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
17 Kernel::KScheduler& scheduler, Core::CPUInterrupts& interrupts) 17 Core::CPUInterrupts& interrupts_)
18 : core_index{core_index}, system{system}, scheduler{scheduler}, 18 : core_index{core_index_}, system{system_}, scheduler{scheduler_},
19 interrupts{interrupts}, guard{std::make_unique<Common::SpinLock>()} {} 19 interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {}
20 20
21PhysicalCore::~PhysicalCore() = default; 21PhysicalCore::~PhysicalCore() = default;
22 22
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index f2b0911aa..901f7e3b0 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -28,8 +28,8 @@ namespace Kernel {
28 28
29class PhysicalCore { 29class PhysicalCore {
30public: 30public:
31 PhysicalCore(std::size_t core_index, Core::System& system, Kernel::KScheduler& scheduler, 31 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
32 Core::CPUInterrupts& interrupts); 32 Core::CPUInterrupts& interrupts_);
33 ~PhysicalCore(); 33 ~PhysicalCore();
34 34
35 PhysicalCore(const PhysicalCore&) = delete; 35 PhysicalCore(const PhysicalCore&) = delete;
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp
index 1006ee50c..fcb8b1ea5 100644
--- a/src/core/hle/kernel/process_capability.cpp
+++ b/src/core/hle/kernel/process_capability.cpp
@@ -6,7 +6,7 @@
6 6
7#include "common/bit_util.h" 7#include "common/bit_util.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/hle/kernel/handle_table.h" 9#include "core/hle/kernel/k_handle_table.h"
10#include "core/hle/kernel/k_page_table.h" 10#include "core/hle/kernel/k_page_table.h"
11#include "core/hle/kernel/process_capability.h" 11#include "core/hle/kernel/process_capability.h"
12#include "core/hle/kernel/svc_results.h" 12#include "core/hle/kernel/svc_results.h"
@@ -99,7 +99,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() {
99 interrupt_capabilities.set(); 99 interrupt_capabilities.set();
100 100
101 // Allow using the maximum possible amount of handles 101 // Allow using the maximum possible amount of handles
102 handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT); 102 handle_table_size = static_cast<s32>(KHandleTable::MaxTableSize);
103 103
104 // Allow all debugging capabilities. 104 // Allow all debugging capabilities.
105 is_debuggable = true; 105 is_debuggable = true;
@@ -159,7 +159,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
159 const auto type = GetCapabilityType(flag); 159 const auto type = GetCapabilityType(flag);
160 160
161 if (type == CapabilityType::Unset) { 161 if (type == CapabilityType::Unset) {
162 return ResultInvalidCapabilityDescriptor; 162 return ResultInvalidArgument;
163 } 163 }
164 164
165 // Bail early on ignorable entries, as one would expect, 165 // Bail early on ignorable entries, as one would expect,
@@ -202,7 +202,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
202 } 202 }
203 203
204 LOG_ERROR(Kernel, "Invalid capability type! type={}", type); 204 LOG_ERROR(Kernel, "Invalid capability type! type={}", type);
205 return ResultInvalidCapabilityDescriptor; 205 return ResultInvalidArgument;
206} 206}
207 207
208void ProcessCapabilities::Clear() { 208void ProcessCapabilities::Clear() {
@@ -225,7 +225,7 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
225 if (priority_mask != 0 || core_mask != 0) { 225 if (priority_mask != 0 || core_mask != 0) {
226 LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}", 226 LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}",
227 priority_mask, core_mask); 227 priority_mask, core_mask);
228 return ResultInvalidCapabilityDescriptor; 228 return ResultInvalidArgument;
229 } 229 }
230 230
231 const u32 core_num_min = (flags >> 16) & 0xFF; 231 const u32 core_num_min = (flags >> 16) & 0xFF;
@@ -329,7 +329,7 @@ ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) {
329 const u32 reserved = flags >> 17; 329 const u32 reserved = flags >> 17;
330 if (reserved != 0) { 330 if (reserved != 0) {
331 LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); 331 LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
332 return ResultReservedValue; 332 return ResultReservedUsed;
333 } 333 }
334 334
335 program_type = static_cast<ProgramType>((flags >> 14) & 0b111); 335 program_type = static_cast<ProgramType>((flags >> 14) & 0b111);
@@ -349,7 +349,7 @@ ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) {
349 LOG_ERROR(Kernel, 349 LOG_ERROR(Kernel,
350 "Kernel version is non zero or flags are too small! major_version={}, flags={}", 350 "Kernel version is non zero or flags are too small! major_version={}, flags={}",
351 major_version, flags); 351 major_version, flags);
352 return ResultInvalidCapabilityDescriptor; 352 return ResultInvalidArgument;
353 } 353 }
354 354
355 kernel_version = flags; 355 kernel_version = flags;
@@ -360,7 +360,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
360 const u32 reserved = flags >> 26; 360 const u32 reserved = flags >> 26;
361 if (reserved != 0) { 361 if (reserved != 0) {
362 LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); 362 LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
363 return ResultReservedValue; 363 return ResultReservedUsed;
364 } 364 }
365 365
366 handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF); 366 handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);
@@ -371,7 +371,7 @@ ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) {
371 const u32 reserved = flags >> 19; 371 const u32 reserved = flags >> 19;
372 if (reserved != 0) { 372 if (reserved != 0) {
373 LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved); 373 LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
374 return ResultReservedValue; 374 return ResultReservedUsed;
375 } 375 }
376 376
377 is_debuggable = (flags & 0x20000) != 0; 377 is_debuggable = (flags & 0x20000) != 0;
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
deleted file mode 100644
index 5d17346ad..000000000
--- a/src/core/hle/kernel/server_port.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <tuple>
6#include "common/assert.h"
7#include "core/hle/kernel/client_port.h"
8#include "core/hle/kernel/k_thread.h"
9#include "core/hle/kernel/object.h"
10#include "core/hle/kernel/server_port.h"
11#include "core/hle/kernel/server_session.h"
12#include "core/hle/kernel/svc_results.h"
13
14namespace Kernel {
15
16ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
17ServerPort::~ServerPort() = default;
18
19ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
20 if (pending_sessions.empty()) {
21 return ResultNotFound;
22 }
23
24 auto session = std::move(pending_sessions.back());
25 pending_sessions.pop_back();
26 return MakeResult(std::move(session));
27}
28
29void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) {
30 pending_sessions.push_back(std::move(pending_session));
31 if (pending_sessions.size() == 1) {
32 NotifyAvailable();
33 }
34}
35
36bool ServerPort::IsSignaled() const {
37 return !pending_sessions.empty();
38}
39
40ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
41 std::string name) {
42 std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
43 std::shared_ptr<ClientPort> client_port = std::make_shared<ClientPort>(kernel);
44
45 server_port->name = name + "_Server";
46 client_port->name = name + "_Client";
47 client_port->server_port = server_port;
48 client_port->max_sessions = max_sessions;
49 client_port->active_sessions = 0;
50
51 return std::make_pair(std::move(server_port), std::move(client_port));
52}
53
54} // namespace Kernel
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
deleted file mode 100644
index 29b4f2509..000000000
--- a/src/core/hle/kernel/server_port.h
+++ /dev/null
@@ -1,98 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9#include <utility>
10#include <vector>
11#include "common/common_types.h"
12#include "core/hle/kernel/k_synchronization_object.h"
13#include "core/hle/kernel/object.h"
14#include "core/hle/result.h"
15
16namespace Kernel {
17
18class ClientPort;
19class KernelCore;
20class ServerSession;
21class SessionRequestHandler;
22
23class ServerPort final : public KSynchronizationObject {
24public:
25 explicit ServerPort(KernelCore& kernel);
26 ~ServerPort() override;
27
28 using HLEHandler = std::shared_ptr<SessionRequestHandler>;
29 using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
30
31 /**
32 * Creates a pair of ServerPort and an associated ClientPort.
33 *
34 * @param kernel The kernel instance to create the port pair under.
35 * @param max_sessions Maximum number of sessions to the port
36 * @param name Optional name of the ports
37 * @return The created port tuple
38 */
39 static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions,
40 std::string name = "UnknownPort");
41
42 std::string GetTypeName() const override {
43 return "ServerPort";
44 }
45 std::string GetName() const override {
46 return name;
47 }
48
49 static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort;
50 HandleType GetHandleType() const override {
51 return HANDLE_TYPE;
52 }
53
54 /**
55 * Accepts a pending incoming connection on this port. If there are no pending sessions, will
56 * return ERR_NO_PENDING_SESSIONS.
57 */
58 ResultVal<std::shared_ptr<ServerSession>> Accept();
59
60 /// Whether or not this server port has an HLE handler available.
61 bool HasHLEHandler() const {
62 return hle_handler != nullptr;
63 }
64
65 /// Gets the HLE handler for this port.
66 HLEHandler GetHLEHandler() const {
67 return hle_handler;
68 }
69
70 /**
71 * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
72 * will inherit a reference to this handler.
73 */
74 void SetHleHandler(HLEHandler hle_handler_) {
75 hle_handler = std::move(hle_handler_);
76 }
77
78 /// Appends a ServerSession to the collection of ServerSessions
79 /// waiting to be accepted by this port.
80 void AppendPendingSession(std::shared_ptr<ServerSession> pending_session);
81
82 bool IsSignaled() const override;
83
84 void Finalize() override {}
85
86private:
87 /// ServerSessions waiting to be accepted by the port
88 std::vector<std::shared_ptr<ServerSession>> pending_sessions;
89
90 /// This session's HLE request handler template (optional)
91 /// ServerSessions created from this port inherit a reference to this handler.
92 HLEHandler hle_handler;
93
94 /// Name of the port (optional)
95 std::string name;
96};
97
98} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index ee46f3e21..04be8a502 100644
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -13,8 +13,8 @@
13#include "common/scope_exit.h" 13#include "common/scope_exit.h"
14#include "common/thread.h" 14#include "common/thread.h"
15#include "core/core.h" 15#include "core/core.h"
16#include "core/hle/kernel/k_session.h"
16#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/server_session.h"
18#include "core/hle/kernel/service_thread.h" 18#include "core/hle/kernel/service_thread.h"
19#include "core/hle/lock.h" 19#include "core/hle/lock.h"
20#include "video_core/renderer_base.h" 20#include "video_core/renderer_base.h"
@@ -26,7 +26,7 @@ public:
26 explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); 26 explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
27 ~Impl(); 27 ~Impl();
28 28
29 void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); 29 void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
30 30
31private: 31private:
32 std::vector<std::thread> threads; 32 std::vector<std::thread> threads;
@@ -69,18 +69,27 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
69 }); 69 });
70} 70}
71 71
72void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, 72void ServiceThread::Impl::QueueSyncRequest(KSession& session,
73 std::shared_ptr<HLERequestContext>&& context) { 73 std::shared_ptr<HLERequestContext>&& context) {
74 { 74 {
75 std::unique_lock lock{queue_mutex}; 75 std::unique_lock lock{queue_mutex};
76 76
77 // ServerSession owns the service thread, so we cannot caption a strong pointer here in the 77 // Open a reference to the session to ensure it is not closes while the service request
78 // event that the ServerSession is terminated. 78 // completes asynchronously.
79 std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)}; 79 session.Open();
80 requests.emplace([weak_ptr, context{std::move(context)}]() { 80
81 if (auto strong_ptr = weak_ptr.lock()) { 81 requests.emplace([session_ptr{&session}, context{std::move(context)}]() {
82 strong_ptr->CompleteSyncRequest(*context); 82 // Close the reference.
83 SCOPE_EXIT({ session_ptr->Close(); });
84
85 // If the session has been closed, we are done.
86 if (session_ptr->IsServerClosed()) {
87 return;
83 } 88 }
89
90 // Complete the service request.
91 KScopedAutoObject server_session{&session_ptr->GetServerSession()};
92 server_session->CompleteSyncRequest(*context);
84 }); 93 });
85 } 94 }
86 condition.notify_one(); 95 condition.notify_one();
@@ -102,7 +111,7 @@ ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const
102 111
103ServiceThread::~ServiceThread() = default; 112ServiceThread::~ServiceThread() = default;
104 113
105void ServiceThread::QueueSyncRequest(ServerSession& session, 114void ServiceThread::QueueSyncRequest(KSession& session,
106 std::shared_ptr<HLERequestContext>&& context) { 115 std::shared_ptr<HLERequestContext>&& context) {
107 impl->QueueSyncRequest(session, std::move(context)); 116 impl->QueueSyncRequest(session, std::move(context));
108} 117}
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h
index 025ab8fb5..6a7fd7c56 100644
--- a/src/core/hle/kernel/service_thread.h
+++ b/src/core/hle/kernel/service_thread.h
@@ -11,14 +11,14 @@ namespace Kernel {
11 11
12class HLERequestContext; 12class HLERequestContext;
13class KernelCore; 13class KernelCore;
14class ServerSession; 14class KSession;
15 15
16class ServiceThread final { 16class ServiceThread final {
17public: 17public:
18 explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); 18 explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
19 ~ServiceThread(); 19 ~ServiceThread();
20 20
21 void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); 21 void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
22 22
23private: 23private:
24 class Impl; 24 class Impl;
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
deleted file mode 100644
index 8830d4e91..000000000
--- a/src/core/hle/kernel/session.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/kernel/client_session.h"
7#include "core/hle/kernel/k_scoped_resource_reservation.h"
8#include "core/hle/kernel/server_session.h"
9#include "core/hle/kernel/session.h"
10
11namespace Kernel {
12
13Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
14Session::~Session() {
15 // Release reserved resource when the Session pair was created.
16 kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1);
17}
18
19Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
20 // Reserve a new session from the resource limit.
21 KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(),
22 LimitableResource::Sessions);
23 ASSERT(session_reservation.Succeeded());
24 auto session{std::make_shared<Session>(kernel)};
25 auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()};
26 auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()};
27
28 session->name = std::move(name);
29 session->client = client_session;
30 session->server = server_session;
31
32 session_reservation.Commit();
33 return std::make_pair(std::move(client_session), std::move(server_session));
34}
35
36bool Session::IsSignaled() const {
37 UNIMPLEMENTED();
38 return true;
39}
40
41} // namespace Kernel
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
deleted file mode 100644
index fa3c5651a..000000000
--- a/src/core/hle/kernel/session.h
+++ /dev/null
@@ -1,64 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9#include <utility>
10
11#include "core/hle/kernel/k_synchronization_object.h"
12
13namespace Kernel {
14
15class ClientSession;
16class ServerSession;
17
18/**
19 * Parent structure to link the client and server endpoints of a session with their associated
20 * client port.
21 */
22class Session final : public KSynchronizationObject {
23public:
24 explicit Session(KernelCore& kernel);
25 ~Session() override;
26
27 using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>;
28
29 static SessionPair Create(KernelCore& kernel, std::string name = "Unknown");
30
31 std::string GetName() const override {
32 return name;
33 }
34
35 static constexpr HandleType HANDLE_TYPE = HandleType::Session;
36 HandleType GetHandleType() const override {
37 return HANDLE_TYPE;
38 }
39
40 bool IsSignaled() const override;
41
42 void Finalize() override {}
43
44 std::shared_ptr<ClientSession> Client() {
45 if (auto result{client.lock()}) {
46 return result;
47 }
48 return {};
49 }
50
51 std::shared_ptr<ServerSession> Server() {
52 if (auto result{server.lock()}) {
53 return result;
54 }
55 return {};
56 }
57
58private:
59 std::string name;
60 std::weak_ptr<ClientSession> client;
61 std::weak_ptr<ServerSession> server;
62};
63
64} // namespace Kernel
diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h
new file mode 100644
index 000000000..d0f7f084b
--- /dev/null
+++ b/src/core/hle/kernel/slab_helpers.h
@@ -0,0 +1,148 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8
9#include "common/assert.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "common/intrusive_red_black_tree.h"
13#include "core/hle/kernel/k_auto_object.h"
14#include "core/hle/kernel/k_auto_object_container.h"
15#include "core/hle/kernel/k_light_lock.h"
16#include "core/hle/kernel/k_slab_heap.h"
17#include "core/hle/kernel/kernel.h"
18
19namespace Kernel {
20
21template <class Derived>
22class KSlabAllocated {
23public:
24 constexpr KSlabAllocated() = default;
25
26 size_t GetSlabIndex(KernelCore& kernel) const {
27 return kernel.SlabHeap<Derived>().GetIndex(static_cast<const Derived*>(this));
28 }
29
30public:
31 static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
32 kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
33 }
34
35 static Derived* Allocate(KernelCore& kernel) {
36 return kernel.SlabHeap<Derived>().Allocate();
37 }
38
39 static void Free(KernelCore& kernel, Derived* obj) {
40 kernel.SlabHeap<Derived>().Free(obj);
41 }
42
43 static size_t GetObjectSize(KernelCore& kernel) {
44 return kernel.SlabHeap<Derived>().GetObjectSize();
45 }
46
47 static size_t GetSlabHeapSize(KernelCore& kernel) {
48 return kernel.SlabHeap<Derived>().GetSlabHeapSize();
49 }
50
51 static size_t GetPeakIndex(KernelCore& kernel) {
52 return kernel.SlabHeap<Derived>().GetPeakIndex();
53 }
54
55 static uintptr_t GetSlabHeapAddress(KernelCore& kernel) {
56 return kernel.SlabHeap<Derived>().GetSlabHeapAddress();
57 }
58
59 static size_t GetNumRemaining(KernelCore& kernel) {
60 return kernel.SlabHeap<Derived>().GetNumRemaining();
61 }
62};
63
64template <typename Derived, typename Base>
65class KAutoObjectWithSlabHeapAndContainer : public Base {
66 static_assert(std::is_base_of<KAutoObjectWithList, Base>::value);
67
68private:
69 static Derived* Allocate(KernelCore& kernel) {
70 return new Derived(kernel);
71 }
72
73 static void Free(KernelCore& kernel, Derived* obj) {
74 delete obj;
75 }
76
77public:
78 KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {}
79 virtual ~KAutoObjectWithSlabHeapAndContainer() {}
80
81 virtual void Destroy() override {
82 const bool is_initialized = this->IsInitialized();
83 uintptr_t arg = 0;
84 if (is_initialized) {
85 kernel.ObjectListContainer().Unregister(this);
86 arg = this->GetPostDestroyArgument();
87 this->Finalize();
88 }
89 Free(kernel, static_cast<Derived*>(this));
90 if (is_initialized) {
91 Derived::PostDestroy(arg);
92 }
93 }
94
95 virtual bool IsInitialized() const {
96 return true;
97 }
98 virtual uintptr_t GetPostDestroyArgument() const {
99 return 0;
100 }
101
102 size_t GetSlabIndex() const {
103 return SlabHeap<Derived>(kernel).GetObjectIndex(static_cast<const Derived*>(this));
104 }
105
106public:
107 static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
108 kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
109 kernel.ObjectListContainer().Initialize();
110 }
111
112 static Derived* Create(KernelCore& kernel) {
113 Derived* obj = Allocate(kernel);
114 if (obj != nullptr) {
115 KAutoObject::Create(obj);
116 }
117 return obj;
118 }
119
120 static void Register(KernelCore& kernel, Derived* obj) {
121 return kernel.ObjectListContainer().Register(obj);
122 }
123
124 static size_t GetObjectSize(KernelCore& kernel) {
125 return kernel.SlabHeap<Derived>().GetObjectSize();
126 }
127
128 static size_t GetSlabHeapSize(KernelCore& kernel) {
129 return kernel.SlabHeap<Derived>().GetSlabHeapSize();
130 }
131
132 static size_t GetPeakIndex(KernelCore& kernel) {
133 return kernel.SlabHeap<Derived>().GetPeakIndex();
134 }
135
136 static uintptr_t GetSlabHeapAddress(KernelCore& kernel) {
137 return kernel.SlabHeap<Derived>().GetSlabHeapAddress();
138 }
139
140 static size_t GetNumRemaining(KernelCore& kernel) {
141 return kernel.SlabHeap<Derived>().GetNumRemaining();
142 }
143
144protected:
145 KernelCore& kernel;
146};
147
148} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index bebb86154..81e23f700 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -21,15 +21,16 @@
21#include "core/core_timing.h" 21#include "core/core_timing.h"
22#include "core/core_timing_util.h" 22#include "core/core_timing_util.h"
23#include "core/cpu_manager.h" 23#include "core/cpu_manager.h"
24#include "core/hle/kernel/client_port.h"
25#include "core/hle/kernel/client_session.h"
26#include "core/hle/kernel/handle_table.h"
27#include "core/hle/kernel/k_address_arbiter.h" 24#include "core/hle/kernel/k_address_arbiter.h"
25#include "core/hle/kernel/k_client_port.h"
26#include "core/hle/kernel/k_client_session.h"
28#include "core/hle/kernel/k_condition_variable.h" 27#include "core/hle/kernel/k_condition_variable.h"
29#include "core/hle/kernel/k_event.h" 28#include "core/hle/kernel/k_event.h"
29#include "core/hle/kernel/k_handle_table.h"
30#include "core/hle/kernel/k_memory_block.h" 30#include "core/hle/kernel/k_memory_block.h"
31#include "core/hle/kernel/k_memory_layout.h" 31#include "core/hle/kernel/k_memory_layout.h"
32#include "core/hle/kernel/k_page_table.h" 32#include "core/hle/kernel/k_page_table.h"
33#include "core/hle/kernel/k_process.h"
33#include "core/hle/kernel/k_readable_event.h" 34#include "core/hle/kernel/k_readable_event.h"
34#include "core/hle/kernel/k_resource_limit.h" 35#include "core/hle/kernel/k_resource_limit.h"
35#include "core/hle/kernel/k_scheduler.h" 36#include "core/hle/kernel/k_scheduler.h"
@@ -38,16 +39,15 @@
38#include "core/hle/kernel/k_shared_memory.h" 39#include "core/hle/kernel/k_shared_memory.h"
39#include "core/hle/kernel/k_synchronization_object.h" 40#include "core/hle/kernel/k_synchronization_object.h"
40#include "core/hle/kernel/k_thread.h" 41#include "core/hle/kernel/k_thread.h"
42#include "core/hle/kernel/k_transfer_memory.h"
41#include "core/hle/kernel/k_writable_event.h" 43#include "core/hle/kernel/k_writable_event.h"
42#include "core/hle/kernel/kernel.h" 44#include "core/hle/kernel/kernel.h"
43#include "core/hle/kernel/physical_core.h" 45#include "core/hle/kernel/physical_core.h"
44#include "core/hle/kernel/process.h"
45#include "core/hle/kernel/svc.h" 46#include "core/hle/kernel/svc.h"
46#include "core/hle/kernel/svc_results.h" 47#include "core/hle/kernel/svc_results.h"
47#include "core/hle/kernel/svc_types.h" 48#include "core/hle/kernel/svc_types.h"
48#include "core/hle/kernel/svc_wrap.h" 49#include "core/hle/kernel/svc_wrap.h"
49#include "core/hle/kernel/time_manager.h" 50#include "core/hle/kernel/time_manager.h"
50#include "core/hle/kernel/transfer_memory.h"
51#include "core/hle/lock.h" 51#include "core/hle/lock.h"
52#include "core/hle/result.h" 52#include "core/hle/result.h"
53#include "core/hle/service/service.h" 53#include "core/hle/service/service.h"
@@ -113,7 +113,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
113 LOG_ERROR(Kernel_SVC, 113 LOG_ERROR(Kernel_SVC,
114 "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", 114 "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
115 dst_addr, size); 115 dst_addr, size);
116 return ResultInvalidMemoryRange; 116 return ResultInvalidMemoryRegion;
117 } 117 }
118 118
119 if (manager.IsInsideHeapRegion(dst_addr, size)) { 119 if (manager.IsInsideHeapRegion(dst_addr, size)) {
@@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
121 "Destination does not fit within the heap region, addr=0x{:016X}, " 121 "Destination does not fit within the heap region, addr=0x{:016X}, "
122 "size=0x{:016X}", 122 "size=0x{:016X}",
123 dst_addr, size); 123 dst_addr, size);
124 return ResultInvalidMemoryRange; 124 return ResultInvalidMemoryRegion;
125 } 125 }
126 126
127 if (manager.IsInsideAliasRegion(dst_addr, size)) { 127 if (manager.IsInsideAliasRegion(dst_addr, size)) {
@@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
129 "Destination does not fit within the map region, addr=0x{:016X}, " 129 "Destination does not fit within the map region, addr=0x{:016X}, "
130 "size=0x{:016X}", 130 "size=0x{:016X}",
131 dst_addr, size); 131 dst_addr, size);
132 return ResultInvalidMemoryRange; 132 return ResultInvalidMemoryRegion;
133 } 133 }
134 134
135 return RESULT_SUCCESS; 135 return RESULT_SUCCESS;
@@ -141,38 +141,6 @@ enum class ResourceLimitValueType {
141 PeakValue, 141 PeakValue,
142}; 142};
143 143
144ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
145 u32 resource_type, ResourceLimitValueType value_type) {
146 std::lock_guard lock{HLE::g_hle_lock};
147 const auto type = static_cast<LimitableResource>(resource_type);
148 if (!IsValidResourceType(type)) {
149 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
150 return ResultInvalidEnumValue;
151 }
152
153 const auto* const current_process = system.Kernel().CurrentProcess();
154 ASSERT(current_process != nullptr);
155
156 const auto resource_limit_object =
157 current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
158 if (!resource_limit_object) {
159 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
160 resource_limit);
161 return ResultInvalidHandle;
162 }
163
164 switch (value_type) {
165 case ResourceLimitValueType::CurrentValue:
166 return MakeResult(resource_limit_object->GetCurrentValue(type));
167 case ResourceLimitValueType::LimitValue:
168 return MakeResult(resource_limit_object->GetLimitValue(type));
169 case ResourceLimitValueType::PeakValue:
170 return MakeResult(resource_limit_object->GetPeakValue(type));
171 default:
172 LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type);
173 return ResultInvalidEnumValue;
174 }
175}
176} // Anonymous namespace 144} // Anonymous namespace
177 145
178/// Set the process heap to a given Size. It can both extend and shrink the heap. 146/// Set the process heap to a given Size. It can both extend and shrink the heap.
@@ -291,11 +259,8 @@ static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr
291} 259}
292 260
293/// Connect to an OS service given the port name, returns the handle to the port to out 261/// Connect to an OS service given the port name, returns the handle to the port to out
294static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, 262static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
295 VAddr port_name_address) {
296 std::lock_guard lock{HLE::g_hle_lock};
297 auto& memory = system.Memory(); 263 auto& memory = system.Memory();
298
299 if (!memory.IsValidVirtualAddress(port_name_address)) { 264 if (!memory.IsValidVirtualAddress(port_name_address)) {
300 LOG_ERROR(Kernel_SVC, 265 LOG_ERROR(Kernel_SVC,
301 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", 266 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
@@ -314,21 +279,32 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
314 279
315 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); 280 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
316 281
282 // Get the current handle table.
317 auto& kernel = system.Kernel(); 283 auto& kernel = system.Kernel();
318 const auto it = kernel.FindNamedPort(port_name); 284 auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
319 if (!kernel.IsValidNamedPort(it)) { 285
320 LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name); 286 // Find the client port.
287 auto port = kernel.CreateNamedServicePort(port_name);
288 if (!port) {
289 LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
321 return ResultNotFound; 290 return ResultNotFound;
322 } 291 }
323 292
324 auto client_port = it->second; 293 // Reserve a handle for the port.
294 // NOTE: Nintendo really does write directly to the output handle here.
295 R_TRY(handle_table.Reserve(out));
296 auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); });
325 297
326 std::shared_ptr<ClientSession> client_session; 298 // Create a session.
327 CASCADE_RESULT(client_session, client_port->Connect()); 299 KClientSession* session{};
300 R_TRY(port->CreateSession(std::addressof(session)));
328 301
329 // Return the client session 302 // Register the session in the table, close the extra reference.
330 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 303 handle_table.Register(*out, session);
331 CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); 304 session->Close();
305
306 // We succeeded.
307 handle_guard.Cancel();
332 return RESULT_SUCCESS; 308 return RESULT_SUCCESS;
333} 309}
334 310
@@ -340,14 +316,12 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
340 316
341/// Makes a blocking IPC call to an OS service. 317/// Makes a blocking IPC call to an OS service.
342static ResultCode SendSyncRequest(Core::System& system, Handle handle) { 318static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
319
343 auto& kernel = system.Kernel(); 320 auto& kernel = system.Kernel();
344 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
345 std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle);
346 if (!session) {
347 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
348 return ResultInvalidHandle;
349 }
350 321
322 KScopedAutoObject session =
323 kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
324 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
351 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); 325 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
352 326
353 auto thread = kernel.CurrentScheduler()->GetCurrentThread(); 327 auto thread = kernel.CurrentScheduler()->GetCurrentThread();
@@ -355,7 +329,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
355 KScopedSchedulerLock lock(kernel); 329 KScopedSchedulerLock lock(kernel);
356 thread->SetState(ThreadState::Waiting); 330 thread->SetState(ThreadState::Waiting);
357 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); 331 thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
358 session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); 332 session->SendSyncRequest(thread, system.Memory(), system.CoreTiming());
359 } 333 }
360 334
361 KSynchronizationObject* dummy{}; 335 KSynchronizationObject* dummy{};
@@ -368,18 +342,13 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
368 342
369/// Get the ID for the specified thread. 343/// Get the ID for the specified thread.
370static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) { 344static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
371 LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
372
373 // Get the thread from its handle. 345 // Get the thread from its handle.
374 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 346 KScopedAutoObject thread =
375 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 347 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
376 if (!thread) { 348 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
377 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
378 return ResultInvalidHandle;
379 }
380 349
381 // Get the thread's id. 350 // Get the thread's id.
382 *out_thread_id = thread->GetThreadID(); 351 *out_thread_id = thread->GetId();
383 return RESULT_SUCCESS; 352 return RESULT_SUCCESS;
384} 353}
385 354
@@ -395,110 +364,101 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low,
395} 364}
396 365
397/// Gets the ID of the specified process or a specified thread's owning process. 366/// Gets the ID of the specified process or a specified thread's owning process.
398static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) { 367static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
399 LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle); 368 LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
400 369
401 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 370 // Get the object from the handle table.
402 const std::shared_ptr<Process> process = handle_table.Get<Process>(handle); 371 KScopedAutoObject obj =
403 if (process) { 372 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>(
404 *process_id = process->GetProcessID(); 373 static_cast<Handle>(handle));
405 return RESULT_SUCCESS; 374 R_UNLESS(obj.IsNotNull(), ResultInvalidHandle);
375
376 // Get the process from the object.
377 KProcess* process = nullptr;
378 if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) {
379 // The object is a process, so we can use it directly.
380 process = p;
381 } else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) {
382 // The object is a thread, so we want to use its parent.
383 process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess();
384 } else {
385 // TODO(bunnei): This should also handle debug objects before returning.
386 UNIMPLEMENTED_MSG("Debug objects not implemented");
406 } 387 }
407 388
408 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 389 // Make sure the target process exists.
409 if (thread) { 390 R_UNLESS(process != nullptr, ResultInvalidHandle);
410 const Process* const owner_process = thread->GetOwnerProcess();
411 if (!owner_process) {
412 LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered.");
413 return ResultInvalidHandle;
414 }
415
416 *process_id = owner_process->GetProcessID();
417 return RESULT_SUCCESS;
418 }
419 391
420 // NOTE: This should also handle debug objects before returning. 392 // Get the process id.
393 *out_process_id = process->GetId();
421 394
422 LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle);
423 return ResultInvalidHandle; 395 return ResultInvalidHandle;
424} 396}
425 397
426static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, 398static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low,
427 Handle handle) { 399 u32* out_process_id_high, Handle handle) {
428 u64 process_id{}; 400 u64 out_process_id{};
429 const auto result = GetProcessId(system, &process_id, handle); 401 const auto result = GetProcessId(system, &out_process_id, handle);
430 *process_id_low = static_cast<u32>(process_id); 402 *out_process_id_low = static_cast<u32>(out_process_id);
431 *process_id_high = static_cast<u32>(process_id >> 32); 403 *out_process_id_high = static_cast<u32>(out_process_id >> 32);
432 return result; 404 return result;
433} 405}
434 406
435/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 407/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
436static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, 408static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
437 u64 handle_count, s64 nano_seconds) { 409 u64 num_handles, s64 nano_seconds) {
438 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", 410 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
439 handles_address, handle_count, nano_seconds); 411 handles_address, num_handles, nano_seconds);
440 412
441 auto& memory = system.Memory(); 413 // Ensure number of handles is valid.
442 if (!memory.IsValidVirtualAddress(handles_address)) { 414 R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
443 LOG_ERROR(Kernel_SVC,
444 "Handle address is not a valid virtual address, handle_address=0x{:016X}",
445 handles_address);
446 return ResultInvalidPointer;
447 }
448
449 static constexpr u64 MaxHandles = 0x40;
450
451 if (handle_count > MaxHandles) {
452 LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
453 MaxHandles, handle_count);
454 return ResultOutOfRange;
455 }
456 415
457 auto& kernel = system.Kernel(); 416 auto& kernel = system.Kernel();
458 std::vector<KSynchronizationObject*> objects(handle_count); 417 std::vector<KSynchronizationObject*> objs(num_handles);
459 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 418 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
419 Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
460 420
461 for (u64 i = 0; i < handle_count; ++i) { 421 // Copy user handles.
462 const Handle handle = memory.Read32(handles_address + i * sizeof(Handle)); 422 if (num_handles > 0) {
463 const auto object = handle_table.Get<KSynchronizationObject>(handle); 423 // Convert the handles to objects.
424 R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
425 num_handles),
426 ResultInvalidHandle);
427 }
464 428
465 if (object == nullptr) { 429 // Ensure handles are closed when we're done.
466 LOG_ERROR(Kernel_SVC, "Object is a nullptr"); 430 SCOPE_EXIT({
467 return ResultInvalidHandle; 431 for (u64 i = 0; i < num_handles; ++i) {
432 objs[i]->Close();
468 } 433 }
434 });
469 435
470 objects[i] = object.get(); 436 return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
471 } 437 nano_seconds);
472 return KSynchronizationObject::Wait(kernel, index, objects.data(),
473 static_cast<s32>(objects.size()), nano_seconds);
474} 438}
475 439
476static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address, 440static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
477 s32 handle_count, u32 timeout_high, s32* index) { 441 s32 num_handles, u32 timeout_high, s32* index) {
478 const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)}; 442 const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
479 return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds); 443 return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds);
480} 444}
481 445
482/// Resumes a thread waiting on WaitSynchronization 446/// Resumes a thread waiting on WaitSynchronization
483static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) { 447static ResultCode CancelSynchronization(Core::System& system, Handle handle) {
484 LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); 448 LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
485 449
486 // Get the thread from its handle. 450 // Get the thread from its handle.
487 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 451 KScopedAutoObject thread =
488 std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 452 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
489 453 static_cast<Handle>(handle));
490 if (!thread) {
491 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
492 return ResultInvalidHandle;
493 }
494 454
495 // Cancel the thread's wait. 455 // Cancel the thread's wait.
496 thread->WaitCancel(); 456 thread->WaitCancel();
497 return RESULT_SUCCESS; 457 return RESULT_SUCCESS;
498} 458}
499 459
500static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { 460static ResultCode CancelSynchronization32(Core::System& system, Handle handle) {
501 return CancelSynchronization(system, thread_handle); 461 return CancelSynchronization(system, handle);
502} 462}
503 463
504/// Attempts to locks a mutex 464/// Attempts to locks a mutex
@@ -678,7 +638,7 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
678} 638}
679 639
680/// Gets system/memory information for the current process 640/// Gets system/memory information for the current process
681static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, 641static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
682 u64 info_sub_id) { 642 u64 info_sub_id) {
683 std::lock_guard lock{HLE::g_hle_lock}; 643 std::lock_guard lock{HLE::g_hle_lock};
684 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, 644 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
@@ -744,10 +704,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
744 return ResultInvalidEnumValue; 704 return ResultInvalidEnumValue;
745 } 705 }
746 706
747 const auto& current_process_handle_table = 707 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
748 system.Kernel().CurrentProcess()->GetHandleTable(); 708 KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
749 const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle)); 709 if (process.IsNull()) {
750 if (!process) {
751 LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}", 710 LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}",
752 info_id, info_sub_id, handle); 711 info_id, info_sub_id, handle);
753 return ResultInvalidHandle; 712 return ResultInvalidHandle;
@@ -851,21 +810,19 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
851 return ResultInvalidCombination; 810 return ResultInvalidCombination;
852 } 811 }
853 812
854 Process* const current_process = system.Kernel().CurrentProcess(); 813 KProcess* const current_process = system.Kernel().CurrentProcess();
855 HandleTable& handle_table = current_process->GetHandleTable(); 814 KHandleTable& handle_table = current_process->GetHandleTable();
856 const auto resource_limit = current_process->GetResourceLimit(); 815 const auto resource_limit = current_process->GetResourceLimit();
857 if (!resource_limit) { 816 if (!resource_limit) {
858 *result = KernelHandle::InvalidHandle; 817 *result = Svc::InvalidHandle;
859 // Yes, the kernel considers this a successful operation. 818 // Yes, the kernel considers this a successful operation.
860 return RESULT_SUCCESS; 819 return RESULT_SUCCESS;
861 } 820 }
862 821
863 const auto table_result = handle_table.Create(resource_limit); 822 Handle resource_handle{};
864 if (table_result.Failed()) { 823 R_TRY(handle_table.Add(&resource_handle, resource_limit));
865 return table_result.Code();
866 }
867 824
868 *result = *table_result; 825 *result = resource_handle;
869 return RESULT_SUCCESS; 826 return RESULT_SUCCESS;
870 } 827 }
871 828
@@ -876,9 +833,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
876 return ResultInvalidHandle; 833 return ResultInvalidHandle;
877 } 834 }
878 835
879 if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { 836 if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) {
880 LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", 837 LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
881 Process::RANDOM_ENTROPY_SIZE, info_sub_id); 838 KProcess::RANDOM_ENTROPY_SIZE, info_sub_id);
882 return ResultInvalidCombination; 839 return ResultInvalidCombination;
883 } 840 }
884 841
@@ -899,9 +856,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
899 return ResultInvalidCombination; 856 return ResultInvalidCombination;
900 } 857 }
901 858
902 const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>( 859 KScopedAutoObject thread =
903 static_cast<Handle>(handle)); 860 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
904 if (!thread) { 861 static_cast<Handle>(handle));
862 if (thread.IsNull()) {
905 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", 863 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
906 static_cast<Handle>(handle)); 864 static_cast<Handle>(handle));
907 return ResultInvalidHandle; 865 return ResultInvalidHandle;
@@ -910,7 +868,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
910 const auto& core_timing = system.CoreTiming(); 868 const auto& core_timing = system.CoreTiming();
911 const auto& scheduler = *system.Kernel().CurrentScheduler(); 869 const auto& scheduler = *system.Kernel().CurrentScheduler();
912 const auto* const current_thread = scheduler.GetCurrentThread(); 870 const auto* const current_thread = scheduler.GetCurrentThread();
913 const bool same_thread = current_thread == thread.get(); 871 const bool same_thread = current_thread == thread.GetPointerUnsafe();
914 872
915 const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); 873 const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
916 u64 out_ticks = 0; 874 u64 out_ticks = 0;
@@ -966,10 +924,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
966 924
967 if (!(addr < addr + size)) { 925 if (!(addr < addr + size)) {
968 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); 926 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
969 return ResultInvalidMemoryRange; 927 return ResultInvalidMemoryRegion;
970 } 928 }
971 929
972 Process* const current_process{system.Kernel().CurrentProcess()}; 930 KProcess* const current_process{system.Kernel().CurrentProcess()};
973 auto& page_table{current_process->PageTable()}; 931 auto& page_table{current_process->PageTable()};
974 932
975 if (current_process->GetSystemResourceSize() == 0) { 933 if (current_process->GetSystemResourceSize() == 0) {
@@ -981,14 +939,14 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
981 LOG_ERROR(Kernel_SVC, 939 LOG_ERROR(Kernel_SVC,
982 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 940 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
983 size); 941 size);
984 return ResultInvalidMemoryRange; 942 return ResultInvalidMemoryRegion;
985 } 943 }
986 944
987 if (page_table.IsOutsideAliasRegion(addr, size)) { 945 if (page_table.IsOutsideAliasRegion(addr, size)) {
988 LOG_ERROR(Kernel_SVC, 946 LOG_ERROR(Kernel_SVC,
989 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, 947 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
990 size); 948 size);
991 return ResultInvalidMemoryRange; 949 return ResultInvalidMemoryRegion;
992 } 950 }
993 951
994 return page_table.MapPhysicalMemory(addr, size); 952 return page_table.MapPhysicalMemory(addr, size);
@@ -1020,10 +978,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
1020 978
1021 if (!(addr < addr + size)) { 979 if (!(addr < addr + size)) {
1022 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address"); 980 LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
1023 return ResultInvalidMemoryRange; 981 return ResultInvalidMemoryRegion;
1024 } 982 }
1025 983
1026 Process* const current_process{system.Kernel().CurrentProcess()}; 984 KProcess* const current_process{system.Kernel().CurrentProcess()};
1027 auto& page_table{current_process->PageTable()}; 985 auto& page_table{current_process->PageTable()};
1028 986
1029 if (current_process->GetSystemResourceSize() == 0) { 987 if (current_process->GetSystemResourceSize() == 0) {
@@ -1035,14 +993,14 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
1035 LOG_ERROR(Kernel_SVC, 993 LOG_ERROR(Kernel_SVC,
1036 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, 994 "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
1037 size); 995 size);
1038 return ResultInvalidMemoryRange; 996 return ResultInvalidMemoryRegion;
1039 } 997 }
1040 998
1041 if (page_table.IsOutsideAliasRegion(addr, size)) { 999 if (page_table.IsOutsideAliasRegion(addr, size)) {
1042 LOG_ERROR(Kernel_SVC, 1000 LOG_ERROR(Kernel_SVC,
1043 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, 1001 "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
1044 size); 1002 size);
1045 return ResultInvalidMemoryRange; 1003 return ResultInvalidMemoryRegion;
1046 } 1004 }
1047 1005
1048 return page_table.UnmapPhysicalMemory(addr, size); 1006 return page_table.UnmapPhysicalMemory(addr, size);
@@ -1062,37 +1020,19 @@ static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
1062 constexpr auto IsValidThreadActivity = [](ThreadActivity activity) { 1020 constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
1063 return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused; 1021 return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
1064 }; 1022 };
1065 if (!IsValidThreadActivity(thread_activity)) { 1023 R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue);
1066 LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
1067 thread_activity);
1068 return ResultInvalidEnumValue;
1069 }
1070 1024
1071 // Get the thread from its handle. 1025 // Get the thread from its handle.
1072 auto& kernel = system.Kernel(); 1026 KScopedAutoObject thread =
1073 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1027 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1074 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1028 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1075 if (!thread) {
1076 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
1077 return ResultInvalidHandle;
1078 }
1079 1029
1080 // Check that the activity is being set on a non-current thread for the current process. 1030 // Check that the activity is being set on a non-current thread for the current process.
1081 if (thread->GetOwnerProcess() != kernel.CurrentProcess()) { 1031 R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle);
1082 LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread."); 1032 R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
1083 return ResultInvalidHandle;
1084 }
1085 if (thread.get() == GetCurrentThreadPointer(kernel)) {
1086 LOG_ERROR(Kernel_SVC, "Thread is busy");
1087 return ResultBusy;
1088 }
1089 1033
1090 // Set the activity. 1034 // Set the activity.
1091 const auto set_result = thread->SetActivity(thread_activity); 1035 R_TRY(thread->SetActivity(thread_activity));
1092 if (set_result.IsError()) {
1093 LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
1094 return set_result;
1095 }
1096 1036
1097 return RESULT_SUCCESS; 1037 return RESULT_SUCCESS;
1098} 1038}
@@ -1107,36 +1047,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
1107 LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context, 1047 LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
1108 thread_handle); 1048 thread_handle);
1109 1049
1050 auto& kernel = system.Kernel();
1051
1110 // Get the thread from its handle. 1052 // Get the thread from its handle.
1111 const auto* current_process = system.Kernel().CurrentProcess(); 1053 KScopedAutoObject thread =
1112 const std::shared_ptr<KThread> thread = 1054 kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1113 current_process->GetHandleTable().Get<KThread>(thread_handle); 1055 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1114 if (!thread) {
1115 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
1116 return ResultInvalidHandle;
1117 }
1118 1056
1119 // Require the handle be to a non-current thread in the current process. 1057 // Require the handle be to a non-current thread in the current process.
1120 if (thread->GetOwnerProcess() != current_process) { 1058 const auto* current_process = kernel.CurrentProcess();
1121 LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process."); 1059 R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
1122 return ResultInvalidHandle;
1123 }
1124 if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
1125 LOG_ERROR(Kernel_SVC, "Current thread is busy.");
1126 return ResultBusy;
1127 }
1128 1060
1129 // Get the thread context. 1061 // Verify that the thread isn't terminated.
1130 std::vector<u8> context; 1062 R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
1131 const auto context_result = thread->GetThreadContext3(context); 1063
1132 if (context_result.IsError()) { 1064 /// Check that the thread is not the current one.
1133 LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})", 1065 /// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
1134 context_result.raw); 1066 R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
1135 return context_result; 1067
1136 } 1068 // Try to get the thread context until the thread isn't current on any core.
1069 while (true) {
1070 KScopedSchedulerLock sl{kernel};
1137 1071
1138 // Copy the thread context to user space. 1072 // TODO(bunnei): Enforce that thread is suspended for debug here.
1139 system.Memory().WriteBlock(out_context, context.data(), context.size()); 1073
1074 // If the thread's raw state isn't runnable, check if it's current on some core.
1075 if (thread->GetRawState() != ThreadState::Runnable) {
1076 bool current = false;
1077 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
1078 if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) {
1079 current = true;
1080 }
1081 break;
1082 }
1083
1084 // If the thread is current, retry until it isn't.
1085 if (current) {
1086 continue;
1087 }
1088 }
1089
1090 // Get the thread context.
1091 std::vector<u8> context;
1092 R_TRY(thread->GetThreadContext3(context));
1093
1094 // Copy the thread context to user space.
1095 system.Memory().WriteBlock(out_context, context.data(), context.size());
1096
1097 return RESULT_SUCCESS;
1098 }
1140 1099
1141 return RESULT_SUCCESS; 1100 return RESULT_SUCCESS;
1142} 1101}
@@ -1150,12 +1109,9 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
1150 LOG_TRACE(Kernel_SVC, "called"); 1109 LOG_TRACE(Kernel_SVC, "called");
1151 1110
1152 // Get the thread from its handle. 1111 // Get the thread from its handle.
1153 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1112 KScopedAutoObject thread =
1154 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 1113 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
1155 if (!thread) { 1114 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1156 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
1157 return ResultInvalidHandle;
1158 }
1159 1115
1160 // Get the thread's priority. 1116 // Get the thread's priority.
1161 *out_priority = thread->GetPriority(); 1117 *out_priority = thread->GetPriority();
@@ -1167,30 +1123,26 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H
1167} 1123}
1168 1124
1169/// Sets the priority for the specified thread 1125/// Sets the priority for the specified thread
1170static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) { 1126static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) {
1171 LOG_TRACE(Kernel_SVC, "called"); 1127 // Get the current process.
1128 KProcess& process = *system.Kernel().CurrentProcess();
1172 1129
1173 // Validate the priority. 1130 // Validate the priority.
1174 if (HighestThreadPriority > priority || priority > LowestThreadPriority) { 1131 R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
1175 LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority); 1132 ResultInvalidPriority);
1176 return ResultInvalidPriority; 1133 R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
1177 }
1178 1134
1179 // Get the thread from its handle. 1135 // Get the thread from its handle.
1180 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1136 KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
1181 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 1137 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1182 if (!thread) {
1183 LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
1184 return ResultInvalidHandle;
1185 }
1186 1138
1187 // Set the thread priority. 1139 // Set the thread priority.
1188 thread->SetBasePriority(priority); 1140 thread->SetBasePriority(priority);
1189 return RESULT_SUCCESS; 1141 return RESULT_SUCCESS;
1190} 1142}
1191 1143
1192static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { 1144static ResultCode SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) {
1193 return SetThreadPriority(system, handle, priority); 1145 return SetThreadPriority(system, thread_handle, priority);
1194} 1146}
1195 1147
1196/// Get which CPU core is executing the current thread 1148/// Get which CPU core is executing the current thread
@@ -1203,82 +1155,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
1203 return GetCurrentProcessorNumber(system); 1155 return GetCurrentProcessorNumber(system);
1204} 1156}
1205 1157
1206static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, 1158constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
1207 u64 size, u32 permissions) { 1159 switch (perm) {
1208 std::lock_guard lock{HLE::g_hle_lock}; 1160 case Svc::MemoryPermission::Read:
1161 case Svc::MemoryPermission::ReadWrite:
1162 return true;
1163 default:
1164 return false;
1165 }
1166}
1167
1168constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
1169 return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
1170}
1171
1172static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
1173 u64 size, Svc::MemoryPermission map_perm) {
1209 LOG_TRACE(Kernel_SVC, 1174 LOG_TRACE(Kernel_SVC,
1210 "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", 1175 "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
1211 shared_memory_handle, addr, size, permissions); 1176 shmem_handle, address, size, map_perm);
1212 1177
1213 if (!Common::Is4KBAligned(addr)) { 1178 // Validate the address/size.
1214 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); 1179 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1215 return ResultInvalidAddress; 1180 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1216 } 1181 R_UNLESS(size > 0, ResultInvalidSize);
1182 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1217 1183
1218 if (size == 0) { 1184 // Validate the permission.
1219 LOG_ERROR(Kernel_SVC, "Size is 0"); 1185 R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
1220 return ResultInvalidSize;
1221 }
1222 1186
1223 if (!Common::Is4KBAligned(size)) { 1187 // Get the current process.
1224 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); 1188 auto& process = *system.Kernel().CurrentProcess();
1225 return ResultInvalidSize; 1189 auto& page_table = process.PageTable();
1226 }
1227 1190
1228 if (!IsValidAddressRange(addr, size)) { 1191 // Get the shared memory.
1229 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", 1192 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
1230 addr, size); 1193 R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
1231 return ResultInvalidCurrentMemory;
1232 }
1233 1194
1234 const auto permission_type = static_cast<MemoryPermission>(permissions); 1195 // Verify that the mapping is in range.
1235 if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { 1196 R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
1236 LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
1237 permissions);
1238 return ResultInvalidMemoryPermissions;
1239 }
1240 1197
1241 auto* const current_process{system.Kernel().CurrentProcess()}; 1198 // Add the shared memory to the process.
1242 auto& page_table{current_process->PageTable()}; 1199 R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
1243 1200
1244 if (page_table.IsInvalidRegion(addr, size)) { 1201 // Ensure that we clean up the shared memory if we fail to map it.
1245 LOG_ERROR(Kernel_SVC, 1202 auto guard =
1246 "Addr does not fit within the valid region, addr=0x{:016X}, " 1203 SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
1247 "size=0x{:016X}",
1248 addr, size);
1249 return ResultInvalidMemoryRange;
1250 }
1251 1204
1252 if (page_table.IsInsideHeapRegion(addr, size)) { 1205 // Map the shared memory.
1253 LOG_ERROR(Kernel_SVC, 1206 R_TRY(shmem->Map(process, address, size, map_perm));
1254 "Addr does not fit within the heap region, addr=0x{:016X}, "
1255 "size=0x{:016X}",
1256 addr, size);
1257 return ResultInvalidMemoryRange;
1258 }
1259 1207
1260 if (page_table.IsInsideAliasRegion(addr, size)) { 1208 // We succeeded.
1261 LOG_ERROR(Kernel_SVC, 1209 guard.Cancel();
1262 "Address does not fit within the map region, addr=0x{:016X}, " 1210 return RESULT_SUCCESS;
1263 "size=0x{:016X}", 1211}
1264 addr, size);
1265 return ResultInvalidMemoryRange;
1266 }
1267 1212
1268 auto shared_memory{current_process->GetHandleTable().Get<KSharedMemory>(shared_memory_handle)}; 1213static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
1269 if (!shared_memory) { 1214 u32 size, Svc::MemoryPermission map_perm) {
1270 LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", 1215 return MapSharedMemory(system, shmem_handle, address, size, map_perm);
1271 shared_memory_handle); 1216}
1272 return ResultInvalidHandle; 1217
1273 } 1218static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
1219 u64 size) {
1220 // Validate the address/size.
1221 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1222 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1223 R_UNLESS(size > 0, ResultInvalidSize);
1224 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1225
1226 // Get the current process.
1227 auto& process = *system.Kernel().CurrentProcess();
1228 auto& page_table = process.PageTable();
1229
1230 // Get the shared memory.
1231 KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
1232 R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
1274 1233
1275 return shared_memory->Map(*current_process, addr, size, 1234 // Verify that the mapping is in range.
1276 static_cast<KMemoryPermission>(permission_type)); 1235 R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
1236
1237 // Unmap the shared memory.
1238 R_TRY(shmem->Unmap(process, address, size));
1239
1240 // Remove the shared memory from the process.
1241 process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
1242
1243 return RESULT_SUCCESS;
1277} 1244}
1278 1245
1279static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, 1246static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
1280 u32 size, u32 permissions) { 1247 u32 size) {
1281 return MapSharedMemory(system, shared_memory_handle, addr, size, permissions); 1248 return UnmapSharedMemory(system, shmem_handle, address, size);
1282} 1249}
1283 1250
1284static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, 1251static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
@@ -1287,8 +1254,8 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
1287 std::lock_guard lock{HLE::g_hle_lock}; 1254 std::lock_guard lock{HLE::g_hle_lock};
1288 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); 1255 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
1289 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1256 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1290 std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle); 1257 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
1291 if (!process) { 1258 if (process.IsNull()) {
1292 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", 1259 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
1293 process_handle); 1260 process_handle);
1294 return ResultInvalidHandle; 1261 return ResultInvalidHandle;
@@ -1369,8 +1336,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
1369 } 1336 }
1370 1337
1371 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1338 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1372 auto process = handle_table.Get<Process>(process_handle); 1339 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
1373 if (!process) { 1340 if (process.IsNull()) {
1374 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", 1341 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1375 process_handle); 1342 process_handle);
1376 return ResultInvalidHandle; 1343 return ResultInvalidHandle;
@@ -1390,7 +1357,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
1390 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " 1357 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1391 "size=0x{:016X}).", 1358 "size=0x{:016X}).",
1392 dst_address, size); 1359 dst_address, size);
1393 return ResultInvalidMemoryRange; 1360 return ResultInvalidMemoryRegion;
1394 } 1361 }
1395 1362
1396 return page_table.MapProcessCodeMemory(dst_address, src_address, size); 1363 return page_table.MapProcessCodeMemory(dst_address, src_address, size);
@@ -1437,8 +1404,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1437 } 1404 }
1438 1405
1439 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1406 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1440 auto process = handle_table.Get<Process>(process_handle); 1407 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
1441 if (!process) { 1408 if (process.IsNull()) {
1442 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).", 1409 LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
1443 process_handle); 1410 process_handle);
1444 return ResultInvalidHandle; 1411 return ResultInvalidHandle;
@@ -1458,7 +1425,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1458 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " 1425 "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
1459 "size=0x{:016X}).", 1426 "size=0x{:016X}).",
1460 dst_address, size); 1427 dst_address, size);
1461 return ResultInvalidMemoryRange; 1428 return ResultInvalidMemoryRegion;
1462 } 1429 }
1463 1430
1464 return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); 1431 return page_table.UnmapProcessCodeMemory(dst_address, src_address, size);
@@ -1483,7 +1450,7 @@ static void ExitProcess32(Core::System& system) {
1483 ExitProcess(system); 1450 ExitProcess(system);
1484} 1451}
1485 1452
1486static constexpr bool IsValidCoreId(int32_t core_id) { 1453static constexpr bool IsValidVirtualCoreId(int32_t core_id) {
1487 return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); 1454 return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
1488} 1455}
1489 1456
@@ -1503,7 +1470,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1503 } 1470 }
1504 1471
1505 // Validate arguments. 1472 // Validate arguments.
1506 if (!IsValidCoreId(core_id)) { 1473 if (!IsValidVirtualCoreId(core_id)) {
1507 LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id); 1474 LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
1508 return ResultInvalidCoreId; 1475 return ResultInvalidCoreId;
1509 } 1476 }
@@ -1521,35 +1488,42 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1521 return ResultInvalidPriority; 1488 return ResultInvalidPriority;
1522 } 1489 }
1523 1490
1491 // Reserve a new thread from the process resource limit (waiting up to 100ms).
1524 KScopedResourceReservation thread_reservation( 1492 KScopedResourceReservation thread_reservation(
1525 kernel.CurrentProcess(), LimitableResource::Threads, 1, 1493 kernel.CurrentProcess(), LimitableResource::Threads, 1,
1526 system.CoreTiming().GetGlobalTimeNs().count() + 100000000); 1494 system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
1527 if (!thread_reservation.Succeeded()) { 1495 if (!thread_reservation.Succeeded()) {
1528 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); 1496 LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
1529 return ResultResourceLimitedExceeded; 1497 return ResultLimitReached;
1530 } 1498 }
1531 1499
1532 std::shared_ptr<KThread> thread; 1500 // Create the thread.
1533 { 1501 KThread* thread = KThread::Create(kernel);
1534 KScopedLightLock lk{process.GetStateLock()}; 1502 if (!thread) {
1535 CASCADE_RESULT(thread, 1503 LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached.");
1536 KThread::CreateUserThread(system, ThreadType::User, "", entry_point, 1504 return ResultOutOfResource;
1537 priority, arg, core_id, stack_bottom, &process));
1538 } 1505 }
1506 SCOPE_EXIT({ thread->Close(); });
1539 1507
1540 const auto new_thread_handle = process.GetHandleTable().Create(thread); 1508 // Initialize the thread.
1541 if (new_thread_handle.Failed()) { 1509 {
1542 LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", 1510 KScopedLightLock lk{process.GetStateLock()};
1543 new_thread_handle.Code().raw); 1511 R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
1544 return new_thread_handle.Code(); 1512 priority, core_id, &process));
1545 } 1513 }
1546 *out_handle = *new_thread_handle;
1547 1514
1548 // Set the thread name for debugging purposes. 1515 // Set the thread name for debugging purposes.
1549 thread->SetName( 1516 thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle));
1550 fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); 1517
1518 // Commit the thread reservation.
1551 thread_reservation.Commit(); 1519 thread_reservation.Commit();
1552 1520
1521 // Register the new thread.
1522 KThread::Register(kernel, thread);
1523
1524 // Add the thread to the handle table.
1525 R_TRY(process.GetHandleTable().Add(out_handle, thread));
1526
1553 return RESULT_SUCCESS; 1527 return RESULT_SUCCESS;
1554} 1528}
1555 1529
@@ -1563,21 +1537,15 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
1563 LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); 1537 LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
1564 1538
1565 // Get the thread from its handle. 1539 // Get the thread from its handle.
1566 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1540 KScopedAutoObject thread =
1567 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1541 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1568 if (!thread) { 1542 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1569 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
1570 return ResultInvalidHandle;
1571 }
1572 1543
1573 // Try to start the thread. 1544 // Try to start the thread.
1574 const auto run_result = thread->Run(); 1545 R_TRY(thread->Run());
1575 if (run_result.IsError()) { 1546
1576 LOG_ERROR(Kernel_SVC, 1547 // If we succeeded, persist a reference to the thread.
1577 "Unable to successfuly start thread (thread handle={:08X}, result={})", 1548 thread->Open();
1578 thread_handle, run_result.raw);
1579 return run_result;
1580 }
1581 1549
1582 return RESULT_SUCCESS; 1550 return RESULT_SUCCESS;
1583} 1551}
@@ -1591,7 +1559,7 @@ static void ExitThread(Core::System& system) {
1591 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); 1559 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
1592 1560
1593 auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); 1561 auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
1594 system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread)); 1562 system.GlobalSchedulerContext().RemoveThread(current_thread);
1595 current_thread->Exit(); 1563 current_thread->Exit();
1596} 1564}
1597 1565
@@ -1824,8 +1792,11 @@ static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high)
1824static ResultCode CloseHandle(Core::System& system, Handle handle) { 1792static ResultCode CloseHandle(Core::System& system, Handle handle) {
1825 LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); 1793 LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
1826 1794
1827 auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1795 // Remove the handle.
1828 return handle_table.Close(handle); 1796 R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle),
1797 ResultInvalidHandle);
1798
1799 return RESULT_SUCCESS;
1829} 1800}
1830 1801
1831static ResultCode CloseHandle32(Core::System& system, Handle handle) { 1802static ResultCode CloseHandle32(Core::System& system, Handle handle) {
@@ -1841,16 +1812,16 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) {
1841 1812
1842 // Try to reset as readable event. 1813 // Try to reset as readable event.
1843 { 1814 {
1844 auto readable_event = handle_table.Get<KReadableEvent>(handle); 1815 KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
1845 if (readable_event) { 1816 if (readable_event.IsNotNull()) {
1846 return readable_event->Reset(); 1817 return readable_event->Reset();
1847 } 1818 }
1848 } 1819 }
1849 1820
1850 // Try to reset as process. 1821 // Try to reset as process.
1851 { 1822 {
1852 auto process = handle_table.Get<Process>(handle); 1823 KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
1853 if (process) { 1824 if (process.IsNotNull()) {
1854 return process->Reset(); 1825 return process->Reset();
1855 } 1826 }
1856 } 1827 }
@@ -1864,65 +1835,68 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) {
1864 return ResetSignal(system, handle); 1835 return ResetSignal(system, handle);
1865} 1836}
1866 1837
1867/// Creates a TransferMemory object 1838static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
1868static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, 1839 switch (perm) {
1869 u32 permissions) { 1840 case MemoryPermission::None:
1870 std::lock_guard lock{HLE::g_hle_lock}; 1841 case MemoryPermission::Read:
1871 LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, 1842 case MemoryPermission::ReadWrite:
1872 permissions); 1843 return true;
1873 1844 default:
1874 if (!Common::Is4KBAligned(addr)) { 1845 return false;
1875 LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr);
1876 return ResultInvalidAddress;
1877 } 1846 }
1847}
1878 1848
1879 if (!Common::Is4KBAligned(size) || size == 0) { 1849/// Creates a TransferMemory object
1880 LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size); 1850static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
1881 return ResultInvalidAddress; 1851 MemoryPermission map_perm) {
1882 } 1852 auto& kernel = system.Kernel();
1883 1853
1884 if (!IsValidAddressRange(addr, size)) { 1854 // Validate the size.
1885 LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})", 1855 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1886 addr, size); 1856 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1887 return ResultInvalidCurrentMemory; 1857 R_UNLESS(size > 0, ResultInvalidSize);
1888 } 1858 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1889 1859
1890 const auto perms{static_cast<MemoryPermission>(permissions)}; 1860 // Validate the permissions.
1891 if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { 1861 R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
1892 LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", 1862
1893 permissions); 1863 // Get the current process and handle table.
1894 return ResultInvalidMemoryPermissions; 1864 auto& process = *kernel.CurrentProcess();
1895 } 1865 auto& handle_table = process.GetHandleTable();
1896 1866
1897 auto& kernel = system.Kernel();
1898 // Reserve a new transfer memory from the process resource limit. 1867 // Reserve a new transfer memory from the process resource limit.
1899 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), 1868 KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
1900 LimitableResource::TransferMemory); 1869 LimitableResource::TransferMemory);
1901 if (!trmem_reservation.Succeeded()) { 1870 R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
1902 LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory");
1903 return ResultResourceLimitedExceeded;
1904 }
1905 auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size,
1906 static_cast<KMemoryPermission>(perms));
1907 1871
1908 if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { 1872 // Create the transfer memory.
1909 return reserve_result; 1873 KTransferMemory* trmem = KTransferMemory::Create(kernel);
1910 } 1874 R_UNLESS(trmem != nullptr, ResultOutOfResource);
1911 1875
1912 auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1876 // Ensure the only reference is in the handle table when we're done.
1913 const auto result{handle_table.Create(std::move(transfer_mem_handle))}; 1877 SCOPE_EXIT({ trmem->Close(); });
1914 if (result.Failed()) { 1878
1915 return result.Code(); 1879 // Ensure that the region is in range.
1916 } 1880 R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory);
1881
1882 // Initialize the transfer memory.
1883 R_TRY(trmem->Initialize(address, size, map_perm));
1884
1885 // Commit the reservation.
1917 trmem_reservation.Commit(); 1886 trmem_reservation.Commit();
1918 1887
1919 *handle = *result; 1888 // Register the transfer memory.
1889 KTransferMemory::Register(kernel, trmem);
1890
1891 // Add the transfer memory to the handle table.
1892 R_TRY(handle_table.Add(out, trmem));
1893
1920 return RESULT_SUCCESS; 1894 return RESULT_SUCCESS;
1921} 1895}
1922 1896
1923static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, 1897static ResultCode CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size,
1924 u32 permissions) { 1898 MemoryPermission map_perm) {
1925 return CreateTransferMemory(system, handle, addr, size, permissions); 1899 return CreateTransferMemory(system, out, address, size, map_perm);
1926} 1900}
1927 1901
1928static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id, 1902static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
@@ -1930,19 +1904,12 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
1930 LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); 1904 LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
1931 1905
1932 // Get the thread from its handle. 1906 // Get the thread from its handle.
1933 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1907 KScopedAutoObject thread =
1934 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1908 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
1935 if (!thread) { 1909 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
1936 LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
1937 return ResultInvalidHandle;
1938 }
1939 1910
1940 // Get the core mask. 1911 // Get the core mask.
1941 const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask); 1912 R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
1942 if (result.IsError()) {
1943 LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
1944 return result;
1945 }
1946 1913
1947 return RESULT_SUCCESS; 1914 return RESULT_SUCCESS;
1948} 1915}
@@ -1958,58 +1925,33 @@ static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle
1958 1925
1959static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id, 1926static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
1960 u64 affinity_mask) { 1927 u64 affinity_mask) {
1961 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}",
1962 thread_handle, core_id, affinity_mask);
1963
1964 const auto& current_process = *system.Kernel().CurrentProcess();
1965
1966 // Determine the core id/affinity mask. 1928 // Determine the core id/affinity mask.
1967 if (core_id == Svc::IdealCoreUseProcessValue) { 1929 if (core_id == IdealCoreUseProcessValue) {
1968 core_id = current_process.GetIdealCoreId(); 1930 core_id = system.Kernel().CurrentProcess()->GetIdealCoreId();
1969 affinity_mask = (1ULL << core_id); 1931 affinity_mask = (1ULL << core_id);
1970 } else { 1932 } else {
1971 // Validate the affinity mask. 1933 // Validate the affinity mask.
1972 const u64 process_core_mask = current_process.GetCoreMask(); 1934 const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask();
1973 if ((affinity_mask | process_core_mask) != process_core_mask) { 1935 R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId);
1974 LOG_ERROR(Kernel_SVC, 1936 R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
1975 "Affinity mask does match the process core mask (affinity mask={:016X}, core "
1976 "mask={:016X})",
1977 affinity_mask, process_core_mask);
1978 return ResultInvalidCoreId;
1979 }
1980 if (affinity_mask == 0) {
1981 LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
1982 return ResultInvalidCombination;
1983 }
1984 1937
1985 // Validate the core id. 1938 // Validate the core id.
1986 if (IsValidCoreId(core_id)) { 1939 if (IsValidVirtualCoreId(core_id)) {
1987 if (((1ULL << core_id) & affinity_mask) == 0) { 1940 R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
1988 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
1989 return ResultInvalidCombination;
1990 }
1991 } else { 1941 } else {
1992 if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) { 1942 R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
1993 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id); 1943 ResultInvalidCoreId);
1994 return ResultInvalidCoreId;
1995 }
1996 } 1944 }
1997 } 1945 }
1998 1946
1999 // Get the thread from its handle. 1947 // Get the thread from its handle.
2000 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1948 KScopedAutoObject thread =
2001 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1949 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
2002 if (!thread) { 1950 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
2003 LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
2004 return ResultInvalidHandle;
2005 }
2006 1951
2007 // Set the core mask. 1952 // Set the core mask.
2008 const auto set_result = thread->SetCoreMask(core_id, affinity_mask); 1953 R_TRY(thread->SetCoreMask(core_id, affinity_mask));
2009 if (set_result.IsError()) { 1954
2010 LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
2011 return set_result;
2012 }
2013 return RESULT_SUCCESS; 1955 return RESULT_SUCCESS;
2014} 1956}
2015 1957
@@ -2022,27 +1964,12 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
2022static ResultCode SignalEvent(Core::System& system, Handle event_handle) { 1964static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
2023 LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); 1965 LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
2024 1966
2025 auto& kernel = system.Kernel();
2026 // Get the current handle table. 1967 // Get the current handle table.
2027 const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1968 const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
2028
2029 // Reserve a new event from the process resource limit.
2030 KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
2031 LimitableResource::Events);
2032 if (!event_reservation.Succeeded()) {
2033 LOG_ERROR(Kernel, "Could not reserve a new event");
2034 return ResultResourceLimitedExceeded;
2035 }
2036 1969
2037 // Get the writable event. 1970 // Get the writable event.
2038 auto writable_event = handle_table.Get<KWritableEvent>(event_handle); 1971 KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
2039 if (!writable_event) { 1972 R_UNLESS(writable_event.IsNotNull(), ResultInvalidHandle);
2040 LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
2041 return ResultInvalidHandle;
2042 }
2043
2044 // Commit the successfuly reservation.
2045 event_reservation.Commit();
2046 1973
2047 return writable_event->Signal(); 1974 return writable_event->Signal();
2048} 1975}
@@ -2059,16 +1986,16 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) {
2059 1986
2060 // Try to clear the writable event. 1987 // Try to clear the writable event.
2061 { 1988 {
2062 auto writable_event = handle_table.Get<KWritableEvent>(event_handle); 1989 KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
2063 if (writable_event) { 1990 if (writable_event.IsNotNull()) {
2064 return writable_event->Clear(); 1991 return writable_event->Clear();
2065 } 1992 }
2066 } 1993 }
2067 1994
2068 // Try to clear the readable event. 1995 // Try to clear the readable event.
2069 { 1996 {
2070 auto readable_event = handle_table.Get<KReadableEvent>(event_handle); 1997 KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
2071 if (readable_event) { 1998 if (readable_event.IsNotNull()) {
2072 return readable_event->Clear(); 1999 return readable_event->Clear();
2073 } 2000 }
2074 } 2001 }
@@ -2087,34 +2014,40 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
2087 2014
2088 // Get the kernel reference and handle table. 2015 // Get the kernel reference and handle table.
2089 auto& kernel = system.Kernel(); 2016 auto& kernel = system.Kernel();
2090 HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); 2017 auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
2018
2019 // Reserve a new event from the process resource limit
2020 KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
2021 LimitableResource::Events);
2022 R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
2091 2023
2092 // Create a new event. 2024 // Create a new event.
2093 const auto event = KEvent::Create(kernel, "CreateEvent"); 2025 KEvent* event = KEvent::Create(kernel);
2094 if (!event) { 2026 R_UNLESS(event != nullptr, ResultOutOfResource);
2095 LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
2096 return ResultOutOfResource;
2097 }
2098 2027
2099 // Initialize the event. 2028 // Initialize the event.
2100 event->Initialize(); 2029 event->Initialize("CreateEvent");
2030
2031 // Commit the thread reservation.
2032 event_reservation.Commit();
2033
2034 // Ensure that we clean up the event (and its only references are handle table) on function end.
2035 SCOPE_EXIT({
2036 event->GetWritableEvent().Close();
2037 event->GetReadableEvent().Close();
2038 });
2039
2040 // Register the event.
2041 KEvent::Register(kernel, event);
2101 2042
2102 // Add the writable event to the handle table. 2043 // Add the writable event to the handle table.
2103 const auto write_create_result = handle_table.Create(event->GetWritableEvent()); 2044 R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent())));
2104 if (write_create_result.Failed()) {
2105 return write_create_result.Code();
2106 }
2107 *out_write = *write_create_result;
2108 2045
2109 // Add the writable event to the handle table. 2046 // Add the writable event to the handle table.
2110 auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); }); 2047 auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); });
2111 2048
2112 // Add the readable event to the handle table. 2049 // Add the readable event to the handle table.
2113 const auto read_create_result = handle_table.Create(event->GetReadableEvent()); 2050 R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
2114 if (read_create_result.Failed()) {
2115 return read_create_result.Code();
2116 }
2117 *out_read = *read_create_result;
2118 2051
2119 // We succeeded. 2052 // We succeeded.
2120 handle_guard.Cancel(); 2053 handle_guard.Cancel();
@@ -2134,8 +2067,8 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
2134 }; 2067 };
2135 2068
2136 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 2069 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
2137 const auto process = handle_table.Get<Process>(process_handle); 2070 KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
2138 if (!process) { 2071 if (process.IsNull()) {
2139 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", 2072 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
2140 process_handle); 2073 process_handle);
2141 return ResultInvalidHandle; 2074 return ResultInvalidHandle;
@@ -2152,83 +2085,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
2152} 2085}
2153 2086
2154static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { 2087static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
2155 std::lock_guard lock{HLE::g_hle_lock};
2156 LOG_DEBUG(Kernel_SVC, "called"); 2088 LOG_DEBUG(Kernel_SVC, "called");
2157 2089
2090 // Create a new resource limit.
2158 auto& kernel = system.Kernel(); 2091 auto& kernel = system.Kernel();
2159 auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming()); 2092 KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
2093 R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
2160 2094
2161 auto* const current_process = kernel.CurrentProcess(); 2095 // Ensure we don't leak a reference to the limit.
2162 ASSERT(current_process != nullptr); 2096 SCOPE_EXIT({ resource_limit->Close(); });
2163 2097
2164 const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); 2098 // Initialize the resource limit.
2165 if (handle.Failed()) { 2099 resource_limit->Initialize(&system.CoreTiming());
2166 return handle.Code(); 2100
2167 } 2101 // Register the limit.
2102 KResourceLimit::Register(kernel, resource_limit);
2103
2104 // Add the limit to the handle table.
2105 R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit));
2168 2106
2169 *out_handle = *handle;
2170 return RESULT_SUCCESS; 2107 return RESULT_SUCCESS;
2171} 2108}
2172 2109
2173static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value, 2110static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value,
2174 Handle resource_limit, u32 resource_type) { 2111 Handle resource_limit_handle,
2175 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); 2112 LimitableResource which) {
2113 LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
2114 which);
2176 2115
2177 const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, 2116 // Validate the resource.
2178 ResourceLimitValueType::LimitValue); 2117 R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
2179 if (limit_value.Failed()) { 2118
2180 return limit_value.Code(); 2119 // Get the resource limit.
2181 } 2120 auto& kernel = system.Kernel();
2121 KScopedAutoObject resource_limit =
2122 kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
2123 R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
2124
2125 // Get the limit value.
2126 *out_limit_value = resource_limit->GetLimitValue(which);
2182 2127
2183 *out_value = static_cast<u64>(*limit_value);
2184 return RESULT_SUCCESS; 2128 return RESULT_SUCCESS;
2185} 2129}
2186 2130
2187static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value, 2131static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value,
2188 Handle resource_limit, u32 resource_type) { 2132 Handle resource_limit_handle,
2189 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); 2133 LimitableResource which) {
2134 LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
2135 which);
2190 2136
2191 const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type, 2137 // Validate the resource.
2192 ResourceLimitValueType::CurrentValue); 2138 R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
2193 if (current_value.Failed()) { 2139
2194 return current_value.Code(); 2140 // Get the resource limit.
2195 } 2141 auto& kernel = system.Kernel();
2142 KScopedAutoObject resource_limit =
2143 kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
2144 R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
2145
2146 // Get the current value.
2147 *out_current_value = resource_limit->GetCurrentValue(which);
2196 2148
2197 *out_value = static_cast<u64>(*current_value);
2198 return RESULT_SUCCESS; 2149 return RESULT_SUCCESS;
2199} 2150}
2200 2151
2201static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit, 2152static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
2202 u32 resource_type, u64 value) { 2153 LimitableResource which, u64 limit_value) {
2203 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, 2154 LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
2204 resource_type, value); 2155 resource_limit_handle, which, limit_value);
2205 2156
2206 const auto type = static_cast<LimitableResource>(resource_type); 2157 // Validate the resource.
2207 if (!IsValidResourceType(type)) { 2158 R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
2208 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
2209 return ResultInvalidEnumValue;
2210 }
2211
2212 auto* const current_process = system.Kernel().CurrentProcess();
2213 ASSERT(current_process != nullptr);
2214 2159
2215 auto resource_limit_object = 2160 // Get the resource limit.
2216 current_process->GetHandleTable().Get<KResourceLimit>(resource_limit); 2161 auto& kernel = system.Kernel();
2217 if (!resource_limit_object) { 2162 KScopedAutoObject resource_limit =
2218 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", 2163 kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
2219 resource_limit); 2164 R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
2220 return ResultInvalidHandle;
2221 }
2222 2165
2223 const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); 2166 // Set the limit value.
2224 if (set_result.IsError()) { 2167 R_TRY(resource_limit->SetLimitValue(which, limit_value));
2225 LOG_ERROR(Kernel_SVC,
2226 "Attempted to lower resource limit ({}) for category '{}' below its current "
2227 "value ({})",
2228 resource_limit_object->GetLimitValue(type), resource_type,
2229 resource_limit_object->GetCurrentValue(type));
2230 return set_result;
2231 }
2232 2168
2233 return RESULT_SUCCESS; 2169 return RESULT_SUCCESS;
2234} 2170}
@@ -2351,7 +2287,7 @@ static const FunctionDef SVC_Table_32[] = {
2351 {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"}, 2287 {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
2352 {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"}, 2288 {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
2353 {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"}, 2289 {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
2354 {0x14, nullptr, "UnmapSharedMemory32"}, 2290 {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"},
2355 {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"}, 2291 {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
2356 {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"}, 2292 {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
2357 {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"}, 2293 {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
@@ -2546,7 +2482,7 @@ static const FunctionDef SVC_Table_64[] = {
2546 {0x11, SvcWrap64<SignalEvent>, "SignalEvent"}, 2482 {0x11, SvcWrap64<SignalEvent>, "SignalEvent"},
2547 {0x12, SvcWrap64<ClearEvent>, "ClearEvent"}, 2483 {0x12, SvcWrap64<ClearEvent>, "ClearEvent"},
2548 {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"}, 2484 {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"},
2549 {0x14, nullptr, "UnmapSharedMemory"}, 2485 {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"},
2550 {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"}, 2486 {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"},
2551 {0x16, SvcWrap64<CloseHandle>, "CloseHandle"}, 2487 {0x16, SvcWrap64<CloseHandle>, "CloseHandle"},
2552 {0x17, SvcWrap64<ResetSignal>, "ResetSignal"}, 2488 {0x17, SvcWrap64<ResetSignal>, "ResetSignal"},
diff --git a/src/core/hle/kernel/svc_common.h b/src/core/hle/kernel/svc_common.h
index 4af049551..60ea2c405 100644
--- a/src/core/hle/kernel/svc_common.h
+++ b/src/core/hle/kernel/svc_common.h
@@ -6,9 +6,24 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9namespace Kernel {
10using Handle = u32;
11}
12
9namespace Kernel::Svc { 13namespace Kernel::Svc {
10 14
11constexpr s32 ArgumentHandleCountMax = 0x40; 15constexpr s32 ArgumentHandleCountMax = 0x40;
12constexpr u32 HandleWaitMask{1u << 30}; 16constexpr u32 HandleWaitMask{1u << 30};
13 17
18constexpr inline Handle InvalidHandle = Handle(0);
19
20enum PseudoHandle : Handle {
21 CurrentThread = 0xFFFF8000,
22 CurrentProcess = 0xFFFF8001,
23};
24
25constexpr bool IsPseudoHandle(Handle handle) {
26 return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread;
27}
28
14} // namespace Kernel::Svc 29} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h
index a26d9f2c9..53a940723 100644
--- a/src/core/hle/kernel/svc_results.h
+++ b/src/core/hle/kernel/svc_results.h
@@ -10,18 +10,18 @@ namespace Kernel {
10 10
11// Confirmed Switch kernel error codes 11// Confirmed Switch kernel error codes
12 12
13constexpr ResultCode ResultMaxConnectionsReached{ErrorModule::Kernel, 7}; 13constexpr ResultCode ResultOutOfSessions{ErrorModule::Kernel, 7};
14constexpr ResultCode ResultInvalidCapabilityDescriptor{ErrorModule::Kernel, 14}; 14constexpr ResultCode ResultInvalidArgument{ErrorModule::Kernel, 14};
15constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57}; 15constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
16constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59}; 16constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
17constexpr ResultCode ResultInvalidSize{ErrorModule::Kernel, 101}; 17constexpr ResultCode ResultInvalidSize{ErrorModule::Kernel, 101};
18constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102}; 18constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
19constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103}; 19constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103};
20constexpr ResultCode ResultOutOfMemory{ErrorModule::Kernel, 104}; 20constexpr ResultCode ResultOutOfMemory{ErrorModule::Kernel, 104};
21constexpr ResultCode ResultHandleTableFull{ErrorModule::Kernel, 105}; 21constexpr ResultCode ResultOutOfHandles{ErrorModule::Kernel, 105};
22constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106}; 22constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
23constexpr ResultCode ResultInvalidMemoryPermissions{ErrorModule::Kernel, 108}; 23constexpr ResultCode ResultInvalidNewMemoryPermission{ErrorModule::Kernel, 108};
24constexpr ResultCode ResultInvalidMemoryRange{ErrorModule::Kernel, 110}; 24constexpr ResultCode ResultInvalidMemoryRegion{ErrorModule::Kernel, 110};
25constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112}; 25constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
26constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113}; 26constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
27constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114}; 27constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
@@ -33,9 +33,11 @@ constexpr ResultCode ResultOutOfRange{ErrorModule::Kernel, 119};
33constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120}; 33constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
34constexpr ResultCode ResultNotFound{ErrorModule::Kernel, 121}; 34constexpr ResultCode ResultNotFound{ErrorModule::Kernel, 121};
35constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122}; 35constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
36constexpr ResultCode ResultSessionClosedByRemote{ErrorModule::Kernel, 123}; 36constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123};
37constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125}; 37constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
38constexpr ResultCode ResultReservedValue{ErrorModule::Kernel, 126}; 38constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126};
39constexpr ResultCode ResultResourceLimitedExceeded{ErrorModule::Kernel, 132}; 39constexpr ResultCode ResultPortClosed{ErrorModule::Kernel, 131};
40constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132};
41constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519};
40 42
41} // namespace Kernel 43} // namespace Kernel
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 96afd544b..913b16494 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -154,15 +154,28 @@ void SvcWrap64(Core::System& system) {
154 FuncReturn(system, retval); 154 FuncReturn(system, retval);
155} 155}
156 156
157// Used by GetResourceLimitLimitValue.
158template <ResultCode func(Core::System&, u64*, Handle, LimitableResource)>
159void SvcWrap64(Core::System& system) {
160 u64 param_1 = 0;
161 const u32 retval = func(system, &param_1, static_cast<Handle>(Param(system, 1)),
162 static_cast<LimitableResource>(Param(system, 2)))
163 .raw;
164
165 system.CurrentArmInterface().SetReg(1, param_1);
166 FuncReturn(system, retval);
167}
168
157template <ResultCode func(Core::System&, u32, u64)> 169template <ResultCode func(Core::System&, u32, u64)>
158void SvcWrap64(Core::System& system) { 170void SvcWrap64(Core::System& system) {
159 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw); 171 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
160} 172}
161 173
162template <ResultCode func(Core::System&, u32, u32, u64)> 174// Used by SetResourceLimitLimitValue
175template <ResultCode func(Core::System&, Handle, LimitableResource, u64)>
163void SvcWrap64(Core::System& system) { 176void SvcWrap64(Core::System& system) {
164 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), 177 FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
165 static_cast<u32>(Param(system, 1)), Param(system, 2)) 178 static_cast<LimitableResource>(Param(system, 1)), Param(system, 2))
166 .raw); 179 .raw);
167} 180}
168 181
@@ -219,10 +232,11 @@ void SvcWrap64(Core::System& system) {
219 func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw); 232 func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
220} 233}
221 234
222template <ResultCode func(Core::System&, u32, u64, u64, u32)> 235// Used by MapSharedMemory
236template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)>
223void SvcWrap64(Core::System& system) { 237void SvcWrap64(Core::System& system) {
224 FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), 238 FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1),
225 Param(system, 2), static_cast<u32>(Param(system, 3))) 239 Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3)))
226 .raw); 240 .raw);
227} 241}
228 242
@@ -252,11 +266,13 @@ void SvcWrap64(Core::System& system) {
252 .raw); 266 .raw);
253} 267}
254 268
255template <ResultCode func(Core::System&, u64*, u64, u64, u64)> 269// Used by GetInfo
270template <ResultCode func(Core::System&, u64*, u64, Handle, u64)>
256void SvcWrap64(Core::System& system) { 271void SvcWrap64(Core::System& system) {
257 u64 param_1 = 0; 272 u64 param_1 = 0;
258 const u32 retval = 273 const u32 retval = func(system, &param_1, Param(system, 1),
259 func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw; 274 static_cast<Handle>(Param(system, 2)), Param(system, 3))
275 .raw;
260 276
261 system.CurrentArmInterface().SetReg(1, param_1); 277 system.CurrentArmInterface().SetReg(1, param_1);
262 FuncReturn(system, retval); 278 FuncReturn(system, retval);
@@ -273,11 +289,12 @@ void SvcWrap64(Core::System& system) {
273 FuncReturn(system, retval); 289 FuncReturn(system, retval);
274} 290}
275 291
276template <ResultCode func(Core::System&, u32*, u64, u64, u32)> 292// Used by CreateTransferMemory
293template <ResultCode func(Core::System&, Handle*, u64, u64, Svc::MemoryPermission)>
277void SvcWrap64(Core::System& system) { 294void SvcWrap64(Core::System& system) {
278 u32 param_1 = 0; 295 u32 param_1 = 0;
279 const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2), 296 const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2),
280 static_cast<u32>(Param(system, 3))) 297 static_cast<Svc::MemoryPermission>(Param(system, 3)))
281 .raw; 298 .raw;
282 299
283 system.CurrentArmInterface().SetReg(1, param_1); 300 system.CurrentArmInterface().SetReg(1, param_1);
@@ -537,6 +554,16 @@ void SvcWrap32(Core::System& system) {
537 FuncReturn(system, retval); 554 FuncReturn(system, retval);
538} 555}
539 556
557// Used by MapSharedMemory32
558template <ResultCode func(Core::System&, Handle, u32, u32, Svc::MemoryPermission)>
559void SvcWrap32(Core::System& system) {
560 const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
561 static_cast<u32>(Param(system, 1)), static_cast<u32>(Param(system, 2)),
562 static_cast<Svc::MemoryPermission>(Param(system, 3)))
563 .raw;
564 FuncReturn(system, retval);
565}
566
540// Used by SetThreadCoreMask32 567// Used by SetThreadCoreMask32
541template <ResultCode func(Core::System&, Handle, s32, u32, u32)> 568template <ResultCode func(Core::System&, Handle, s32, u32, u32)>
542void SvcWrap32(Core::System& system) { 569void SvcWrap32(Core::System& system) {
@@ -586,11 +613,12 @@ void SvcWrap32(Core::System& system) {
586} 613}
587 614
588// Used by CreateTransferMemory32 615// Used by CreateTransferMemory32
589template <ResultCode func(Core::System&, Handle*, u32, u32, u32)> 616template <ResultCode func(Core::System&, Handle*, u32, u32, Svc::MemoryPermission)>
590void SvcWrap32(Core::System& system) { 617void SvcWrap32(Core::System& system) {
591 Handle handle = 0; 618 Handle handle = 0;
592 const u32 retval = 619 const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2),
593 func(system, &handle, Param32(system, 1), Param32(system, 2), Param32(system, 3)).raw; 620 static_cast<Svc::MemoryPermission>(Param32(system, 3)))
621 .raw;
594 system.CurrentArmInterface().SetReg(1, handle); 622 system.CurrentArmInterface().SetReg(1, handle);
595 FuncReturn(system, retval); 623 FuncReturn(system, retval);
596} 624}
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index fd0630019..ae9b4be2f 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -6,7 +6,6 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/core_timing_util.h" 8#include "core/core_timing_util.h"
9#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/k_scheduler.h" 9#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/k_thread.h" 10#include "core/hle/kernel/k_thread.h"
12#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
@@ -15,16 +14,12 @@
15namespace Kernel { 14namespace Kernel {
16 15
17TimeManager::TimeManager(Core::System& system_) : system{system_} { 16TimeManager::TimeManager(Core::System& system_) : system{system_} {
18 time_manager_event_type = Core::Timing::CreateEvent( 17 time_manager_event_type =
19 "Kernel::TimeManagerCallback", 18 Core::Timing::CreateEvent("Kernel::TimeManagerCallback",
20 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { 19 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
21 std::shared_ptr<KThread> thread; 20 KThread* thread = reinterpret_cast<KThread*>(thread_handle);
22 { 21 thread->Wakeup();
23 std::lock_guard lock{mutex}; 22 });
24 thread = SharedFrom<KThread>(reinterpret_cast<KThread*>(thread_handle));
25 }
26 thread->Wakeup();
27 });
28} 23}
29 24
30void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) { 25void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
index 0d7f05f30..2d175a9c4 100644
--- a/src/core/hle/kernel/time_manager.h
+++ b/src/core/hle/kernel/time_manager.h
@@ -8,8 +8,6 @@
8#include <mutex> 8#include <mutex>
9#include <unordered_map> 9#include <unordered_map>
10 10
11#include "core/hle/kernel/object.h"
12
13namespace Core { 11namespace Core {
14class System; 12class System;
15} // namespace Core 13} // namespace Core
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp
deleted file mode 100644
index 1dd65468d..000000000
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/k_page_table.h"
6#include "core/hle/kernel/k_resource_limit.h"
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/process.h"
9#include "core/hle/kernel/transfer_memory.h"
10#include "core/hle/result.h"
11#include "core/memory.h"
12
13namespace Kernel {
14
15TransferMemory::TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory)
16 : Object{kernel}, memory{memory} {}
17
18TransferMemory::~TransferMemory() {
19 // Release memory region when transfer memory is destroyed
20 Reset();
21 owner_process->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
22}
23
24std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel,
25 Core::Memory::Memory& memory,
26 VAddr base_address, std::size_t size,
27 KMemoryPermission permissions) {
28 std::shared_ptr<TransferMemory> transfer_memory{
29 std::make_shared<TransferMemory>(kernel, memory)};
30
31 transfer_memory->base_address = base_address;
32 transfer_memory->size = size;
33 transfer_memory->owner_permissions = permissions;
34 transfer_memory->owner_process = kernel.CurrentProcess();
35
36 return transfer_memory;
37}
38
39u8* TransferMemory::GetPointer() {
40 return memory.GetPointer(base_address);
41}
42
43const u8* TransferMemory::GetPointer() const {
44 return memory.GetPointer(base_address);
45}
46
47ResultCode TransferMemory::Reserve() {
48 return owner_process->PageTable().ReserveTransferMemory(base_address, size, owner_permissions);
49}
50
51ResultCode TransferMemory::Reset() {
52 return owner_process->PageTable().ResetTransferMemory(base_address, size);
53}
54
55} // namespace Kernel
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
deleted file mode 100644
index 59328c0fe..000000000
--- a/src/core/hle/kernel/transfer_memory.h
+++ /dev/null
@@ -1,96 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "core/hle/kernel/k_memory_block.h"
10#include "core/hle/kernel/object.h"
11#include "core/hle/kernel/physical_memory.h"
12
13union ResultCode;
14
15namespace Core::Memory {
16class Memory;
17}
18
19namespace Kernel {
20
21class KernelCore;
22class Process;
23
24/// Defines the interface for transfer memory objects.
25///
26/// Transfer memory is typically used for the purpose of
27/// transferring memory between separate process instances,
28/// thus the name.
29///
30class TransferMemory final : public Object {
31public:
32 explicit TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory);
33 ~TransferMemory() override;
34
35 static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
36
37 static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Core::Memory::Memory& memory,
38 VAddr base_address, std::size_t size,
39 KMemoryPermission permissions);
40
41 TransferMemory(const TransferMemory&) = delete;
42 TransferMemory& operator=(const TransferMemory&) = delete;
43
44 TransferMemory(TransferMemory&&) = delete;
45 TransferMemory& operator=(TransferMemory&&) = delete;
46
47 std::string GetTypeName() const override {
48 return "TransferMemory";
49 }
50
51 std::string GetName() const override {
52 return GetTypeName();
53 }
54
55 HandleType GetHandleType() const override {
56 return HANDLE_TYPE;
57 }
58
59 /// Gets a pointer to the backing block of this instance.
60 u8* GetPointer();
61
62 /// Gets a pointer to the backing block of this instance.
63 const u8* GetPointer() const;
64
65 /// Gets the size of the memory backing this instance in bytes.
66 constexpr std::size_t GetSize() const {
67 return size;
68 }
69
70 /// Reserves the region to be used for the transfer memory, called after the transfer memory is
71 /// created.
72 ResultCode Reserve();
73
74 /// Resets the region previously used for the transfer memory, called after the transfer memory
75 /// is closed.
76 ResultCode Reset();
77
78 void Finalize() override {}
79
80private:
81 /// The base address for the memory managed by this instance.
82 VAddr base_address{};
83
84 /// Size of the memory, in bytes, that this instance manages.
85 std::size_t size{};
86
87 /// The memory permissions that are applied to this instance.
88 KMemoryPermission owner_permissions{};
89
90 /// The process that this transfer memory instance was created under.
91 Process* owner_process{};
92
93 Core::Memory::Memory& memory;
94};
95
96} // namespace Kernel
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 8feda7ad7..43968386f 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -56,7 +56,7 @@ enum class ErrorModule : u32 {
56 PCIe = 120, 56 PCIe = 120,
57 Friends = 121, 57 Friends = 121,
58 BCAT = 122, 58 BCAT = 122,
59 SSL = 123, 59 SSLSrv = 123,
60 Account = 124, 60 Account = 124,
61 News = 125, 61 News = 125,
62 Mii = 126, 62 Mii = 126,
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 5450dcf0f..49c09a570 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -16,8 +16,8 @@
16#include "core/file_sys/control_metadata.h" 16#include "core/file_sys/control_metadata.h"
17#include "core/file_sys/patch_manager.h" 17#include "core/file_sys/patch_manager.h"
18#include "core/hle/ipc_helpers.h" 18#include "core/hle/ipc_helpers.h"
19#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
20#include "core/hle/kernel/process.h"
21#include "core/hle/service/acc/acc.h" 21#include "core/hle/service/acc/acc.h"
22#include "core/hle/service/acc/acc_aa.h" 22#include "core/hle/service/acc/acc_aa.h"
23#include "core/hle/service/acc/acc_su.h" 23#include "core/hle/service/acc/acc_su.h"
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 58c7f2930..234173297 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -15,11 +15,11 @@
15#include "core/file_sys/savedata_factory.h" 15#include "core/file_sys/savedata_factory.h"
16#include "core/hle/ipc_helpers.h" 16#include "core/hle/ipc_helpers.h"
17#include "core/hle/kernel/k_event.h" 17#include "core/hle/kernel/k_event.h"
18#include "core/hle/kernel/k_process.h"
18#include "core/hle/kernel/k_readable_event.h" 19#include "core/hle/kernel/k_readable_event.h"
20#include "core/hle/kernel/k_transfer_memory.h"
19#include "core/hle/kernel/k_writable_event.h" 21#include "core/hle/kernel/k_writable_event.h"
20#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
21#include "core/hle/kernel/process.h"
22#include "core/hle/kernel/transfer_memory.h"
23#include "core/hle/service/acc/profile_manager.h" 23#include "core/hle/service/acc/profile_manager.h"
24#include "core/hle/service/am/am.h" 24#include "core/hle/service/am/am.h"
25#include "core/hle/service/am/applet_ae.h" 25#include "core/hle/service/am/applet_ae.h"
@@ -42,6 +42,7 @@
42#include "core/hle/service/set/set.h" 42#include "core/hle/service/set/set.h"
43#include "core/hle/service/sm/sm.h" 43#include "core/hle/service/sm/sm.h"
44#include "core/hle/service/vi/vi.h" 44#include "core/hle/service/vi/vi.h"
45#include "core/memory.h"
45 46
46namespace Service::AM { 47namespace Service::AM {
47 48
@@ -253,7 +254,8 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
253IDebugFunctions::~IDebugFunctions() = default; 254IDebugFunctions::~IDebugFunctions() = default;
254 255
255ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_) 256ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_)
256 : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_} { 257 : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_},
258 launchable_event{system.Kernel()}, accumulated_suspended_tick_changed_event{system.Kernel()} {
257 // clang-format off 259 // clang-format off
258 static const FunctionInfo functions[] = { 260 static const FunctionInfo functions[] = {
259 {0, &ISelfController::Exit, "Exit"}, 261 {0, &ISelfController::Exit, "Exit"},
@@ -306,19 +308,20 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
306 308
307 RegisterHandlers(functions); 309 RegisterHandlers(functions);
308 310
309 auto& kernel = system.Kernel(); 311 Kernel::KAutoObject::Create(std::addressof(launchable_event));
310 launchable_event = Kernel::KEvent::Create(kernel, "ISelfController:LaunchableEvent"); 312
311 launchable_event->Initialize(); 313 launchable_event.Initialize("ISelfController:LaunchableEvent");
312 314
313 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is 315 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
314 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple 316 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
315 // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not 317 // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
316 // suspended if the event has previously been created by a call to 318 // suspended if the event has previously been created by a call to
317 // GetAccumulatedSuspendedTickChangedEvent. 319 // GetAccumulatedSuspendedTickChangedEvent.
318 accumulated_suspended_tick_changed_event = 320
319 Kernel::KEvent::Create(kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent"); 321 Kernel::KAutoObject::Create(std::addressof(accumulated_suspended_tick_changed_event));
320 accumulated_suspended_tick_changed_event->Initialize(); 322 accumulated_suspended_tick_changed_event.Initialize(
321 accumulated_suspended_tick_changed_event->GetWritableEvent()->Signal(); 323 "ISelfController:AccumulatedSuspendedTickChangedEvent");
324 accumulated_suspended_tick_changed_event.GetWritableEvent().Signal();
322} 325}
323 326
324ISelfController::~ISelfController() = default; 327ISelfController::~ISelfController() = default;
@@ -377,11 +380,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
377void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 380void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
378 LOG_WARNING(Service_AM, "(STUBBED) called"); 381 LOG_WARNING(Service_AM, "(STUBBED) called");
379 382
380 launchable_event->GetWritableEvent()->Signal(); 383 launchable_event.GetWritableEvent().Signal();
381 384
382 IPC::ResponseBuilder rb{ctx, 2, 1}; 385 IPC::ResponseBuilder rb{ctx, 2, 1};
383 rb.Push(RESULT_SUCCESS); 386 rb.Push(RESULT_SUCCESS);
384 rb.PushCopyObjects(launchable_event->GetReadableEvent()); 387 rb.PushCopyObjects(launchable_event.GetReadableEvent());
385} 388}
386 389
387void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 390void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
@@ -560,7 +563,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
560 563
561 IPC::ResponseBuilder rb{ctx, 2, 1}; 564 IPC::ResponseBuilder rb{ctx, 2, 1};
562 rb.Push(RESULT_SUCCESS); 565 rb.Push(RESULT_SUCCESS);
563 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); 566 rb.PushCopyObjects(accumulated_suspended_tick_changed_event.GetReadableEvent());
564} 567}
565 568
566void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) { 569void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
@@ -578,39 +581,40 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo
578 rb.Push(RESULT_SUCCESS); 581 rb.Push(RESULT_SUCCESS);
579} 582}
580 583
581AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { 584AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel)
582 on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived"); 585 : on_new_message{kernel}, on_operation_mode_changed{kernel} {
583 on_new_message->Initialize(); 586
584 on_operation_mode_changed = 587 Kernel::KAutoObject::Create(std::addressof(on_new_message));
585 Kernel::KEvent::Create(kernel, "AMMessageQueue:OperationModeChanged"); 588 Kernel::KAutoObject::Create(std::addressof(on_operation_mode_changed));
586 on_operation_mode_changed->Initialize(); 589
590 on_new_message.Initialize("AMMessageQueue:OnMessageReceived");
591 on_operation_mode_changed.Initialize("AMMessageQueue:OperationModeChanged");
587} 592}
588 593
589AppletMessageQueue::~AppletMessageQueue() = default; 594AppletMessageQueue::~AppletMessageQueue() = default;
590 595
591const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const { 596Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
592 return on_new_message->GetReadableEvent(); 597 return on_new_message.GetReadableEvent();
593} 598}
594 599
595const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent() 600Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
596 const { 601 return on_operation_mode_changed.GetReadableEvent();
597 return on_operation_mode_changed->GetReadableEvent();
598} 602}
599 603
600void AppletMessageQueue::PushMessage(AppletMessage msg) { 604void AppletMessageQueue::PushMessage(AppletMessage msg) {
601 messages.push(msg); 605 messages.push(msg);
602 on_new_message->GetWritableEvent()->Signal(); 606 on_new_message.GetWritableEvent().Signal();
603} 607}
604 608
605AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { 609AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
606 if (messages.empty()) { 610 if (messages.empty()) {
607 on_new_message->GetWritableEvent()->Clear(); 611 on_new_message.GetWritableEvent().Clear();
608 return AppletMessage::NoMessage; 612 return AppletMessage::NoMessage;
609 } 613 }
610 auto msg = messages.front(); 614 auto msg = messages.front();
611 messages.pop(); 615 messages.pop();
612 if (messages.empty()) { 616 if (messages.empty()) {
613 on_new_message->GetWritableEvent()->Clear(); 617 on_new_message.GetWritableEvent().Clear();
614 } 618 }
615 return msg; 619 return msg;
616} 620}
@@ -630,7 +634,7 @@ void AppletMessageQueue::FocusStateChanged() {
630void AppletMessageQueue::OperationModeChanged() { 634void AppletMessageQueue::OperationModeChanged() {
631 PushMessage(AppletMessage::OperationModeChanged); 635 PushMessage(AppletMessage::OperationModeChanged);
632 PushMessage(AppletMessage::PerformanceModeChanged); 636 PushMessage(AppletMessage::PerformanceModeChanged);
633 on_operation_mode_changed->GetWritableEvent()->Signal(); 637 on_operation_mode_changed.GetWritableEvent().Signal();
634} 638}
635 639
636ICommonStateGetter::ICommonStateGetter(Core::System& system_, 640ICommonStateGetter::ICommonStateGetter(Core::System& system_,
@@ -829,7 +833,7 @@ IStorageImpl::~IStorageImpl() = default;
829 833
830class StorageDataImpl final : public IStorageImpl { 834class StorageDataImpl final : public IStorageImpl {
831public: 835public:
832 explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {} 836 explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {}
833 837
834 std::vector<u8>& GetData() override { 838 std::vector<u8>& GetData() override {
835 return buffer; 839 return buffer;
@@ -927,11 +931,9 @@ private:
927 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { 931 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
928 LOG_DEBUG(Service_AM, "called"); 932 LOG_DEBUG(Service_AM, "called");
929 933
930 const auto event = applet->GetBroker().GetStateChangedEvent();
931
932 IPC::ResponseBuilder rb{ctx, 2, 1}; 934 IPC::ResponseBuilder rb{ctx, 2, 1};
933 rb.Push(RESULT_SUCCESS); 935 rb.Push(RESULT_SUCCESS);
934 rb.PushCopyObjects(event); 936 rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent());
935 } 937 }
936 938
937 void IsCompleted(Kernel::HLERequestContext& ctx) { 939 void IsCompleted(Kernel::HLERequestContext& ctx) {
@@ -1213,16 +1215,16 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
1213 } 1215 }
1214 1216
1215 auto transfer_mem = 1217 auto transfer_mem =
1216 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); 1218 system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
1217 1219
1218 if (transfer_mem == nullptr) { 1220 if (transfer_mem.IsNull()) {
1219 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); 1221 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1220 IPC::ResponseBuilder rb{ctx, 2}; 1222 IPC::ResponseBuilder rb{ctx, 2};
1221 rb.Push(RESULT_UNKNOWN); 1223 rb.Push(RESULT_UNKNOWN);
1222 return; 1224 return;
1223 } 1225 }
1224 1226
1225 const u8* const mem_begin = transfer_mem->GetPointer(); 1227 const u8* const mem_begin = system.Memory().GetPointer(transfer_mem->GetSourceAddress());
1226 const u8* const mem_end = mem_begin + transfer_mem->GetSize(); 1228 const u8* const mem_end = mem_begin + transfer_mem->GetSize();
1227 std::vector<u8> memory{mem_begin, mem_end}; 1229 std::vector<u8> memory{mem_begin, mem_end};
1228 1230
@@ -1247,16 +1249,16 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
1247 } 1249 }
1248 1250
1249 auto transfer_mem = 1251 auto transfer_mem =
1250 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); 1252 system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
1251 1253
1252 if (transfer_mem == nullptr) { 1254 if (transfer_mem.IsNull()) {
1253 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); 1255 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1254 IPC::ResponseBuilder rb{ctx, 2}; 1256 IPC::ResponseBuilder rb{ctx, 2};
1255 rb.Push(RESULT_UNKNOWN); 1257 rb.Push(RESULT_UNKNOWN);
1256 return; 1258 return;
1257 } 1259 }
1258 1260
1259 const u8* const mem_begin = transfer_mem->GetPointer(); 1261 const u8* const mem_begin = system.Memory().GetPointer(transfer_mem->GetSourceAddress());
1260 const u8* const mem_end = mem_begin + transfer_mem->GetSize(); 1262 const u8* const mem_end = mem_begin + transfer_mem->GetSize();
1261 std::vector<u8> memory{mem_begin, mem_end}; 1263 std::vector<u8> memory{mem_begin, mem_end};
1262 1264
@@ -1266,7 +1268,9 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
1266} 1268}
1267 1269
1268IApplicationFunctions::IApplicationFunctions(Core::System& system_) 1270IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1269 : ServiceFramework{system_, "IApplicationFunctions"} { 1271 : ServiceFramework{system_, "IApplicationFunctions"}, gpu_error_detected_event{system.Kernel()},
1272 friend_invitation_storage_channel_event{system.Kernel()},
1273 health_warning_disappeared_system_event{system.Kernel()} {
1270 // clang-format off 1274 // clang-format off
1271 static const FunctionInfo functions[] = { 1275 static const FunctionInfo functions[] = {
1272 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, 1276 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -1334,16 +1338,15 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1334 1338
1335 RegisterHandlers(functions); 1339 RegisterHandlers(functions);
1336 1340
1337 auto& kernel = system.Kernel(); 1341 Kernel::KAutoObject::Create(std::addressof(gpu_error_detected_event));
1338 gpu_error_detected_event = 1342 Kernel::KAutoObject::Create(std::addressof(friend_invitation_storage_channel_event));
1339 Kernel::KEvent::Create(kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); 1343 Kernel::KAutoObject::Create(std::addressof(health_warning_disappeared_system_event));
1340 gpu_error_detected_event->Initialize(); 1344
1341 friend_invitation_storage_channel_event = 1345 gpu_error_detected_event.Initialize("IApplicationFunctions:GpuErrorDetectedSystemEvent");
1342 Kernel::KEvent::Create(kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent"); 1346 friend_invitation_storage_channel_event.Initialize(
1343 friend_invitation_storage_channel_event->Initialize(); 1347 "IApplicationFunctions:FriendInvitationStorageChannelEvent");
1344 health_warning_disappeared_system_event = 1348 health_warning_disappeared_system_event.Initialize(
1345 Kernel::KEvent::Create(kernel, "IApplicationFunctions:HealthWarningDisappearedSystemEvent"); 1349 "IApplicationFunctions:HealthWarningDisappearedSystemEvent");
1346 health_warning_disappeared_system_event->Initialize();
1347} 1350}
1348 1351
1349IApplicationFunctions::~IApplicationFunctions() = default; 1352IApplicationFunctions::~IApplicationFunctions() = default;
@@ -1510,9 +1513,9 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
1510 1513
1511 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), 1514 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
1512 system.GetContentProvider()}; 1515 system.GetContentProvider()};
1513 auto res = pm.GetControlMetadata(); 1516 auto metadata = pm.GetControlMetadata();
1514 if (res.first != nullptr) { 1517 if (metadata.first != nullptr) {
1515 return res; 1518 return metadata;
1516 } 1519 }
1517 1520
1518 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), 1521 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
@@ -1547,9 +1550,9 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1547 1550
1548 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), 1551 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
1549 system.GetContentProvider()}; 1552 system.GetContentProvider()};
1550 auto res = pm.GetControlMetadata(); 1553 auto metadata = pm.GetControlMetadata();
1551 if (res.first != nullptr) { 1554 if (metadata.first != nullptr) {
1552 return res; 1555 return metadata;
1553 } 1556 }
1554 1557
1555 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), 1558 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
@@ -1740,7 +1743,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
1740 1743
1741 IPC::ResponseBuilder rb{ctx, 2, 1}; 1744 IPC::ResponseBuilder rb{ctx, 2, 1};
1742 rb.Push(RESULT_SUCCESS); 1745 rb.Push(RESULT_SUCCESS);
1743 rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); 1746 rb.PushCopyObjects(gpu_error_detected_event.GetReadableEvent());
1744} 1747}
1745 1748
1746void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { 1749void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) {
@@ -1748,7 +1751,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
1748 1751
1749 IPC::ResponseBuilder rb{ctx, 2, 1}; 1752 IPC::ResponseBuilder rb{ctx, 2, 1};
1750 rb.Push(RESULT_SUCCESS); 1753 rb.Push(RESULT_SUCCESS);
1751 rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); 1754 rb.PushCopyObjects(friend_invitation_storage_channel_event.GetReadableEvent());
1752} 1755}
1753 1756
1754void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel( 1757void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
@@ -1764,7 +1767,7 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
1764 1767
1765 IPC::ResponseBuilder rb{ctx, 2, 1}; 1768 IPC::ResponseBuilder rb{ctx, 2, 1};
1766 rb.Push(RESULT_SUCCESS); 1769 rb.Push(RESULT_SUCCESS);
1767 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); 1770 rb.PushCopyObjects(health_warning_disappeared_system_event.GetReadableEvent());
1768} 1771}
1769 1772
1770void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 1773void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
@@ -1782,7 +1785,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
1782} 1785}
1783 1786
1784IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) 1787IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1785 : ServiceFramework{system_, "IHomeMenuFunctions"} { 1788 : ServiceFramework{system_, "IHomeMenuFunctions"}, pop_from_general_channel_event{
1789 system.Kernel()} {
1786 // clang-format off 1790 // clang-format off
1787 static const FunctionInfo functions[] = { 1791 static const FunctionInfo functions[] = {
1788 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, 1792 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
@@ -1803,9 +1807,8 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1803 1807
1804 RegisterHandlers(functions); 1808 RegisterHandlers(functions);
1805 1809
1806 pop_from_general_channel_event = 1810 Kernel::KAutoObject::Create(std::addressof(pop_from_general_channel_event));
1807 Kernel::KEvent::Create(system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent"); 1811 pop_from_general_channel_event.Initialize("IHomeMenuFunctions:PopFromGeneralChannelEvent");
1808 pop_from_general_channel_event->Initialize();
1809} 1812}
1810 1813
1811IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1814IHomeMenuFunctions::~IHomeMenuFunctions() = default;
@@ -1822,7 +1825,7 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext
1822 1825
1823 IPC::ResponseBuilder rb{ctx, 2, 1}; 1826 IPC::ResponseBuilder rb{ctx, 2, 1};
1824 rb.Push(RESULT_SUCCESS); 1827 rb.Push(RESULT_SUCCESS);
1825 rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); 1828 rb.PushCopyObjects(pop_from_general_channel_event.GetReadableEvent());
1826} 1829}
1827 1830
1828IGlobalStateController::IGlobalStateController(Core::System& system_) 1831IGlobalStateController::IGlobalStateController(Core::System& system_)
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 5d302e155..184030a8e 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -8,12 +8,12 @@
8#include <memory> 8#include <memory>
9#include <queue> 9#include <queue>
10 10
11#include "core/hle/kernel/k_event.h"
11#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
12 13
13namespace Kernel { 14namespace Kernel {
14class KernelCore; 15class KernelCore;
15class KEvent; 16class KTransferMemory;
16class TransferMemory;
17} // namespace Kernel 17} // namespace Kernel
18 18
19namespace Service::NVFlinger { 19namespace Service::NVFlinger {
@@ -56,8 +56,8 @@ public:
56 explicit AppletMessageQueue(Kernel::KernelCore& kernel); 56 explicit AppletMessageQueue(Kernel::KernelCore& kernel);
57 ~AppletMessageQueue(); 57 ~AppletMessageQueue();
58 58
59 const std::shared_ptr<Kernel::KReadableEvent>& GetMessageReceiveEvent() const; 59 Kernel::KReadableEvent& GetMessageReceiveEvent();
60 const std::shared_ptr<Kernel::KReadableEvent>& GetOperationModeChangedEvent() const; 60 Kernel::KReadableEvent& GetOperationModeChangedEvent();
61 void PushMessage(AppletMessage msg); 61 void PushMessage(AppletMessage msg);
62 AppletMessage PopMessage(); 62 AppletMessage PopMessage();
63 std::size_t GetMessageCount() const; 63 std::size_t GetMessageCount() const;
@@ -67,8 +67,8 @@ public:
67 67
68private: 68private:
69 std::queue<AppletMessage> messages; 69 std::queue<AppletMessage> messages;
70 std::shared_ptr<Kernel::KEvent> on_new_message; 70 Kernel::KEvent on_new_message;
71 std::shared_ptr<Kernel::KEvent> on_operation_mode_changed; 71 Kernel::KEvent on_operation_mode_changed;
72}; 72};
73 73
74class IWindowController final : public ServiceFramework<IWindowController> { 74class IWindowController final : public ServiceFramework<IWindowController> {
@@ -156,8 +156,8 @@ private:
156 }; 156 };
157 157
158 NVFlinger::NVFlinger& nvflinger; 158 NVFlinger::NVFlinger& nvflinger;
159 std::shared_ptr<Kernel::KEvent> launchable_event; 159 Kernel::KEvent launchable_event;
160 std::shared_ptr<Kernel::KEvent> accumulated_suspended_tick_changed_event; 160 Kernel::KEvent accumulated_suspended_tick_changed_event;
161 161
162 u32 idle_time_detection_extension = 0; 162 u32 idle_time_detection_extension = 0;
163 u64 num_fatal_sections_entered = 0; 163 u64 num_fatal_sections_entered = 0;
@@ -300,9 +300,9 @@ private:
300 bool launch_popped_application_specific = false; 300 bool launch_popped_application_specific = false;
301 bool launch_popped_account_preselect = false; 301 bool launch_popped_account_preselect = false;
302 s32 previous_program_index{-1}; 302 s32 previous_program_index{-1};
303 std::shared_ptr<Kernel::KEvent> gpu_error_detected_event; 303 Kernel::KEvent gpu_error_detected_event;
304 std::shared_ptr<Kernel::KEvent> friend_invitation_storage_channel_event; 304 Kernel::KEvent friend_invitation_storage_channel_event;
305 std::shared_ptr<Kernel::KEvent> health_warning_disappeared_system_event; 305 Kernel::KEvent health_warning_disappeared_system_event;
306}; 306};
307 307
308class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 308class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
@@ -314,7 +314,7 @@ private:
314 void RequestToGetForeground(Kernel::HLERequestContext& ctx); 314 void RequestToGetForeground(Kernel::HLERequestContext& ctx);
315 void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); 315 void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx);
316 316
317 std::shared_ptr<Kernel::KEvent> pop_from_general_channel_event; 317 Kernel::KEvent pop_from_general_channel_event;
318}; 318};
319 319
320class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { 320class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index a56df6a7e..ae995df6b 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -12,10 +12,8 @@
12#include "core/frontend/applets/profile_select.h" 12#include "core/frontend/applets/profile_select.h"
13#include "core/frontend/applets/software_keyboard.h" 13#include "core/frontend/applets/software_keyboard.h"
14#include "core/frontend/applets/web_browser.h" 14#include "core/frontend/applets/web_browser.h"
15#include "core/hle/kernel/k_event.h"
16#include "core/hle/kernel/k_readable_event.h" 15#include "core/hle/kernel/k_readable_event.h"
17#include "core/hle/kernel/k_writable_event.h" 16#include "core/hle/kernel/k_writable_event.h"
18#include "core/hle/kernel/server_session.h"
19#include "core/hle/service/am/am.h" 17#include "core/hle/service/am/am.h"
20#include "core/hle/service/am/applet_ae.h" 18#include "core/hle/service/am/applet_ae.h"
21#include "core/hle/service/am/applet_oe.h" 19#include "core/hle/service/am/applet_oe.h"
@@ -31,16 +29,16 @@
31namespace Service::AM::Applets { 29namespace Service::AM::Applets {
32 30
33AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_) 31AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
34 : system{system_}, applet_mode{applet_mode_} { 32 : system{system_}, applet_mode{applet_mode_}, state_changed_event{system.Kernel()},
35 state_changed_event = 33 pop_out_data_event{system.Kernel()}, pop_interactive_out_data_event{system.Kernel()} {
36 Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:StateChangedEvent"); 34
37 state_changed_event->Initialize(); 35 Kernel::KAutoObject::Create(std::addressof(state_changed_event));
38 pop_out_data_event = 36 Kernel::KAutoObject::Create(std::addressof(pop_out_data_event));
39 Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:PopDataOutEvent"); 37 Kernel::KAutoObject::Create(std::addressof(pop_interactive_out_data_event));
40 pop_out_data_event->Initialize(); 38
41 pop_interactive_out_data_event = Kernel::KEvent::Create( 39 state_changed_event.Initialize("ILibraryAppletAccessor:StateChangedEvent");
42 system.Kernel(), "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); 40 pop_out_data_event.Initialize("ILibraryAppletAccessor:PopDataOutEvent");
43 pop_interactive_out_data_event->Initialize(); 41 pop_interactive_out_data_event.Initialize("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
44} 42}
45 43
46AppletDataBroker::~AppletDataBroker() = default; 44AppletDataBroker::~AppletDataBroker() = default;
@@ -67,7 +65,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
67 65
68 auto out = std::move(out_channel.front()); 66 auto out = std::move(out_channel.front());
69 out_channel.pop_front(); 67 out_channel.pop_front();
70 pop_out_data_event->GetWritableEvent()->Clear(); 68 pop_out_data_event.GetWritableEvent().Clear();
71 return out; 69 return out;
72} 70}
73 71
@@ -86,7 +84,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
86 84
87 auto out = std::move(out_interactive_channel.front()); 85 auto out = std::move(out_interactive_channel.front());
88 out_interactive_channel.pop_front(); 86 out_interactive_channel.pop_front();
89 pop_interactive_out_data_event->GetWritableEvent()->Clear(); 87 pop_interactive_out_data_event.GetWritableEvent().Clear();
90 return out; 88 return out;
91} 89}
92 90
@@ -105,7 +103,7 @@ void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storag
105 103
106void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) { 104void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
107 out_channel.emplace_back(std::move(storage)); 105 out_channel.emplace_back(std::move(storage));
108 pop_out_data_event->GetWritableEvent()->Signal(); 106 pop_out_data_event.GetWritableEvent().Signal();
109} 107}
110 108
111void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) { 109void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
@@ -114,11 +112,11 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s
114 112
115void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) { 113void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
116 out_interactive_channel.emplace_back(std::move(storage)); 114 out_interactive_channel.emplace_back(std::move(storage));
117 pop_interactive_out_data_event->GetWritableEvent()->Signal(); 115 pop_interactive_out_data_event.GetWritableEvent().Signal();
118} 116}
119 117
120void AppletDataBroker::SignalStateChanged() const { 118void AppletDataBroker::SignalStateChanged() {
121 state_changed_event->GetWritableEvent()->Signal(); 119 state_changed_event.GetWritableEvent().Signal();
122 120
123 switch (applet_mode) { 121 switch (applet_mode) {
124 case LibraryAppletMode::AllForeground: 122 case LibraryAppletMode::AllForeground:
@@ -142,16 +140,16 @@ void AppletDataBroker::SignalStateChanged() const {
142 } 140 }
143} 141}
144 142
145std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const { 143Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
146 return pop_out_data_event->GetReadableEvent(); 144 return pop_out_data_event.GetReadableEvent();
147} 145}
148 146
149std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const { 147Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
150 return pop_interactive_out_data_event->GetReadableEvent(); 148 return pop_interactive_out_data_event.GetReadableEvent();
151} 149}
152 150
153std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() const { 151Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
154 return state_changed_event->GetReadableEvent(); 152 return state_changed_event.GetReadableEvent();
155} 153}
156 154
157Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_) 155Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 4215d2232..5c0b4b459 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -8,7 +8,7 @@
8#include <queue> 8#include <queue>
9 9
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/hle/kernel/object.h" 11#include "core/hle/kernel/k_event.h"
12 12
13union ResultCode; 13union ResultCode;
14 14
@@ -95,11 +95,11 @@ public:
95 void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage); 95 void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
96 void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage); 96 void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
97 97
98 void SignalStateChanged() const; 98 void SignalStateChanged();
99 99
100 std::shared_ptr<Kernel::KReadableEvent> GetNormalDataEvent() const; 100 Kernel::KReadableEvent& GetNormalDataEvent();
101 std::shared_ptr<Kernel::KReadableEvent> GetInteractiveDataEvent() const; 101 Kernel::KReadableEvent& GetInteractiveDataEvent();
102 std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const; 102 Kernel::KReadableEvent& GetStateChangedEvent();
103 103
104private: 104private:
105 Core::System& system; 105 Core::System& system;
@@ -119,13 +119,13 @@ private:
119 // PopInteractiveDataToGame and PushInteractiveDataFromApplet 119 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
120 std::deque<std::shared_ptr<IStorage>> out_interactive_channel; 120 std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
121 121
122 std::shared_ptr<Kernel::KEvent> state_changed_event; 122 Kernel::KEvent state_changed_event;
123 123
124 // Signaled on PushNormalDataFromApplet 124 // Signaled on PushNormalDataFromApplet
125 std::shared_ptr<Kernel::KEvent> pop_out_data_event; 125 Kernel::KEvent pop_out_data_event;
126 126
127 // Signaled on PushInteractiveDataFromApplet 127 // Signaled on PushInteractiveDataFromApplet
128 std::shared_ptr<Kernel::KEvent> pop_interactive_out_data_event; 128 Kernel::KEvent pop_interactive_out_data_event;
129}; 129};
130 130
131class Applet { 131class Applet {
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index 0dd6ec68e..08348b180 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -9,7 +9,7 @@
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/frontend/applets/error.h" 11#include "core/frontend/applets/error.h"
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/k_process.h"
13#include "core/hle/service/am/am.h" 13#include "core/hle/service/am/am.h"
14#include "core/hle/service/am/applets/error.h" 14#include "core/hle/service/am/applets/error.h"
15#include "core/reporter.h" 15#include "core/reporter.h"
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index b7483261e..e95499edd 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -9,7 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/frontend/applets/general_frontend.h" 11#include "core/frontend/applets/general_frontend.h"
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/k_process.h"
13#include "core/hle/result.h" 13#include "core/hle/result.h"
14#include "core/hle/service/am/am.h" 14#include "core/hle/service/am/am.h"
15#include "core/hle/service/am/applets/general_backend.h" 15#include "core/hle/service/am/applets/general_backend.h"
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 2404921fd..e5f4a4485 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -17,7 +17,7 @@
17#include "core/file_sys/system_archive/system_archive.h" 17#include "core/file_sys/system_archive/system_archive.h"
18#include "core/file_sys/vfs_vector.h" 18#include "core/file_sys/vfs_vector.h"
19#include "core/frontend/applets/web_browser.h" 19#include "core/frontend/applets/web_browser.h"
20#include "core/hle/kernel/process.h" 20#include "core/hle/kernel/k_process.h"
21#include "core/hle/result.h" 21#include "core/hle/result.h"
22#include "core/hle/service/am/am.h" 22#include "core/hle/service/am/am.h"
23#include "core/hle/service/am/applets/web_browser.h" 23#include "core/hle/service/am/applets/web_browser.h"
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 75867e349..1863260f1 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -16,10 +16,9 @@
16#include "core/file_sys/patch_manager.h" 16#include "core/file_sys/patch_manager.h"
17#include "core/file_sys/registered_cache.h" 17#include "core/file_sys/registered_cache.h"
18#include "core/hle/ipc_helpers.h" 18#include "core/hle/ipc_helpers.h"
19#include "core/hle/kernel/k_event.h" 19#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/k_readable_event.h" 20#include "core/hle/kernel/k_readable_event.h"
21#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/process.h"
23#include "core/hle/service/aoc/aoc_u.h" 22#include "core/hle/service/aoc/aoc_u.h"
24#include "core/loader/loader.h" 23#include "core/loader/loader.h"
25 24
@@ -50,7 +49,7 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
50class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> { 49class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
51public: 50public:
52 explicit IPurchaseEventManager(Core::System& system_) 51 explicit IPurchaseEventManager(Core::System& system_)
53 : ServiceFramework{system_, "IPurchaseEventManager"} { 52 : ServiceFramework{system_, "IPurchaseEventManager"}, purchased_event{system.Kernel()} {
54 // clang-format off 53 // clang-format off
55 static const FunctionInfo functions[] = { 54 static const FunctionInfo functions[] = {
56 {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"}, 55 {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
@@ -63,9 +62,8 @@ public:
63 62
64 RegisterHandlers(functions); 63 RegisterHandlers(functions);
65 64
66 purchased_event = 65 Kernel::KAutoObject::Create(std::addressof(purchased_event));
67 Kernel::KEvent::Create(system.Kernel(), "IPurchaseEventManager:PurchasedEvent"); 66 purchased_event.Initialize("IPurchaseEventManager:PurchasedEvent");
68 purchased_event->Initialize();
69 } 67 }
70 68
71private: 69private:
@@ -98,14 +96,15 @@ private:
98 96
99 IPC::ResponseBuilder rb{ctx, 2, 1}; 97 IPC::ResponseBuilder rb{ctx, 2, 1};
100 rb.Push(RESULT_SUCCESS); 98 rb.Push(RESULT_SUCCESS);
101 rb.PushCopyObjects(purchased_event->GetReadableEvent()); 99 rb.PushCopyObjects(purchased_event.GetReadableEvent());
102 } 100 }
103 101
104 std::shared_ptr<Kernel::KEvent> purchased_event; 102 Kernel::KEvent purchased_event;
105}; 103};
106 104
107AOC_U::AOC_U(Core::System& system_) 105AOC_U::AOC_U(Core::System& system_)
108 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)} { 106 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
107 aoc_change_event{system.Kernel()} {
109 // clang-format off 108 // clang-format off
110 static const FunctionInfo functions[] = { 109 static const FunctionInfo functions[] = {
111 {0, nullptr, "CountAddOnContentByApplicationId"}, 110 {0, nullptr, "CountAddOnContentByApplicationId"},
@@ -127,9 +126,8 @@ AOC_U::AOC_U(Core::System& system_)
127 126
128 RegisterHandlers(functions); 127 RegisterHandlers(functions);
129 128
130 auto& kernel = system.Kernel(); 129 Kernel::KAutoObject::Create(std::addressof(aoc_change_event));
131 aoc_change_event = Kernel::KEvent::Create(kernel, "GetAddOnContentListChanged:Event"); 130 aoc_change_event.Initialize("GetAddOnContentListChanged:Event");
132 aoc_change_event->Initialize();
133} 131}
134 132
135AOC_U::~AOC_U() = default; 133AOC_U::~AOC_U() = default;
@@ -256,7 +254,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
256 254
257 IPC::ResponseBuilder rb{ctx, 2, 1}; 255 IPC::ResponseBuilder rb{ctx, 2, 1};
258 rb.Push(RESULT_SUCCESS); 256 rb.Push(RESULT_SUCCESS);
259 rb.PushCopyObjects(aoc_change_event->GetReadableEvent()); 257 rb.PushCopyObjects(aoc_change_event.GetReadableEvent());
260} 258}
261 259
262void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) { 260void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 1aa23529e..65095baa2 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Core { 10namespace Core {
@@ -31,7 +32,7 @@ private:
31 void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx); 32 void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
32 33
33 std::vector<u64> add_on_content; 34 std::vector<u64> add_on_content;
34 std::shared_ptr<Kernel::KEvent> aoc_change_event; 35 Kernel::KEvent aoc_change_event;
35}; 36};
36 37
37/// Registers all AOC services with the specified service manager. 38/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 00c174bb0..8bfa7c0e4 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -15,11 +15,11 @@ namespace Service::APM {
15 15
16constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7; 16constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7;
17 17
18Controller::Controller(Core::Timing::CoreTiming& core_timing) 18Controller::Controller(Core::Timing::CoreTiming& core_timing_)
19 : core_timing{core_timing}, configs{ 19 : core_timing{core_timing_}, configs{
20 {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, 20 {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
21 {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, 21 {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
22 } {} 22 } {}
23 23
24Controller::~Controller() = default; 24Controller::~Controller() = default;
25 25
diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h
index af0c4cd34..8d48e0104 100644
--- a/src/core/hle/service/apm/controller.h
+++ b/src/core/hle/service/apm/controller.h
@@ -50,7 +50,7 @@ enum class PerformanceMode : u8 {
50// system during times of high load -- this simply maps to different PerformanceConfigs to use. 50// system during times of high load -- this simply maps to different PerformanceConfigs to use.
51class Controller { 51class Controller {
52public: 52public:
53 explicit Controller(Core::Timing::CoreTiming& core_timing); 53 explicit Controller(Core::Timing::CoreTiming& core_timing_);
54 ~Controller(); 54 ~Controller();
55 55
56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); 56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config);
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 5f51fca9a..e1ae726f5 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -43,9 +43,9 @@ class IAudioOut final : public ServiceFramework<IAudioOut> {
43public: 43public:
44 IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_, 44 IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_,
45 std::string&& device_name_, std::string&& unique_name) 45 std::string&& device_name_, std::string&& unique_name)
46 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, 46 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, device_name{std::move(
47 device_name{std::move(device_name_)}, audio_params{audio_params_}, main_memory{ 47 device_name_)},
48 system.Memory()} { 48 audio_params{audio_params_}, buffer_event{system.Kernel()}, main_memory{system.Memory()} {
49 // clang-format off 49 // clang-format off
50 static const FunctionInfo functions[] = { 50 static const FunctionInfo functions[] = {
51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -67,13 +67,13 @@ public:
67 RegisterHandlers(functions); 67 RegisterHandlers(functions);
68 68
69 // This is the event handle used to check if the audio buffer was released 69 // This is the event handle used to check if the audio buffer was released
70 buffer_event = Kernel::KEvent::Create(system.Kernel(), "IAudioOutBufferReleased"); 70 Kernel::KAutoObject::Create(std::addressof(buffer_event));
71 buffer_event->Initialize(); 71 buffer_event.Initialize("IAudioOutBufferReleased");
72 72
73 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, 73 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
74 audio_params.channel_count, std::move(unique_name), [this] { 74 audio_params.channel_count, std::move(unique_name), [this] {
75 const auto guard = LockService(); 75 const auto guard = LockService();
76 buffer_event->GetWritableEvent()->Signal(); 76 buffer_event.GetWritableEvent().Signal();
77 }); 77 });
78 } 78 }
79 79
@@ -126,7 +126,7 @@ private:
126 126
127 IPC::ResponseBuilder rb{ctx, 2, 1}; 127 IPC::ResponseBuilder rb{ctx, 2, 1};
128 rb.Push(RESULT_SUCCESS); 128 rb.Push(RESULT_SUCCESS);
129 rb.PushCopyObjects(buffer_event->GetReadableEvent()); 129 rb.PushCopyObjects(buffer_event.GetReadableEvent());
130 } 130 }
131 131
132 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 132 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -220,7 +220,7 @@ private:
220 [[maybe_unused]] AudoutParams audio_params{}; 220 [[maybe_unused]] AudoutParams audio_params{};
221 221
222 /// This is the event handle used to check if the audio buffer was released 222 /// This is the event handle used to check if the audio buffer was released
223 std::shared_ptr<Kernel::KEvent> buffer_event; 223 Kernel::KEvent buffer_event;
224 Core::Memory::Memory& main_memory; 224 Core::Memory::Memory& main_memory;
225}; 225};
226 226
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3a48342fd..ae4284adf 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -30,7 +30,7 @@ public:
30 explicit IAudioRenderer(Core::System& system_, 30 explicit IAudioRenderer(Core::System& system_,
31 const AudioCommon::AudioRendererParameter& audren_params, 31 const AudioCommon::AudioRendererParameter& audren_params,
32 const std::size_t instance_number) 32 const std::size_t instance_number)
33 : ServiceFramework{system_, "IAudioRenderer"} { 33 : ServiceFramework{system_, "IAudioRenderer"}, system_event{system.Kernel()} {
34 // clang-format off 34 // clang-format off
35 static const FunctionInfo functions[] = { 35 static const FunctionInfo functions[] = {
36 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, 36 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -49,13 +49,13 @@ public:
49 // clang-format on 49 // clang-format on
50 RegisterHandlers(functions); 50 RegisterHandlers(functions);
51 51
52 system_event = Kernel::KEvent::Create(system.Kernel(), "IAudioRenderer:SystemEvent"); 52 Kernel::KAutoObject::Create(std::addressof(system_event));
53 system_event->Initialize(); 53 system_event.Initialize("IAudioRenderer:SystemEvent");
54 renderer = std::make_unique<AudioCore::AudioRenderer>( 54 renderer = std::make_unique<AudioCore::AudioRenderer>(
55 system.CoreTiming(), system.Memory(), audren_params, 55 system.CoreTiming(), system.Memory(), audren_params,
56 [this]() { 56 [this]() {
57 const auto guard = LockService(); 57 const auto guard = LockService();
58 system_event->GetWritableEvent()->Signal(); 58 system_event.GetWritableEvent().Signal();
59 }, 59 },
60 instance_number); 60 instance_number);
61 } 61 }
@@ -128,7 +128,7 @@ private:
128 128
129 IPC::ResponseBuilder rb{ctx, 2, 1}; 129 IPC::ResponseBuilder rb{ctx, 2, 1};
130 rb.Push(RESULT_SUCCESS); 130 rb.Push(RESULT_SUCCESS);
131 rb.PushCopyObjects(system_event->GetReadableEvent()); 131 rb.PushCopyObjects(system_event.GetReadableEvent());
132 } 132 }
133 133
134 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { 134 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
@@ -162,15 +162,16 @@ private:
162 rb.Push(ERR_NOT_SUPPORTED); 162 rb.Push(ERR_NOT_SUPPORTED);
163 } 163 }
164 164
165 std::shared_ptr<Kernel::KEvent> system_event; 165 Kernel::KEvent system_event;
166 std::unique_ptr<AudioCore::AudioRenderer> renderer; 166 std::unique_ptr<AudioCore::AudioRenderer> renderer;
167 u32 rendering_time_limit_percent = 100; 167 u32 rendering_time_limit_percent = 100;
168}; 168};
169 169
170class IAudioDevice final : public ServiceFramework<IAudioDevice> { 170class IAudioDevice final : public ServiceFramework<IAudioDevice> {
171public: 171public:
172 explicit IAudioDevice(Core::System& system_, u32_le revision_num) 172 explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_)
173 : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num} { 173 : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{
174 revision_} {
174 static const FunctionInfo functions[] = { 175 static const FunctionInfo functions[] = {
175 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, 176 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
176 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, 177 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
@@ -187,21 +188,6 @@ public:
187 {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, 188 {13, nullptr, "GetAudioSystemMasterVolumeSetting"},
188 }; 189 };
189 RegisterHandlers(functions); 190 RegisterHandlers(functions);
190
191 auto& kernel = system.Kernel();
192 buffer_event = Kernel::KEvent::Create(kernel, "IAudioOutBufferReleasedEvent");
193 buffer_event->Initialize();
194
195 // Should be similar to audio_output_device_switch_event
196 audio_input_device_switch_event =
197 Kernel::KEvent::Create(kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent");
198 audio_input_device_switch_event->Initialize();
199
200 // Should only be signalled when an audio output device has been changed, example: speaker
201 // to headset
202 audio_output_device_switch_event =
203 Kernel::KEvent::Create(kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
204 audio_output_device_switch_event->Initialize();
205 } 191 }
206 192
207private: 193private:
@@ -290,11 +276,11 @@ private:
290 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { 276 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
291 LOG_WARNING(Service_Audio, "(STUBBED) called"); 277 LOG_WARNING(Service_Audio, "(STUBBED) called");
292 278
293 buffer_event->GetWritableEvent()->Signal(); 279 buffer_event.GetWritableEvent().Signal();
294 280
295 IPC::ResponseBuilder rb{ctx, 2, 1}; 281 IPC::ResponseBuilder rb{ctx, 2, 1};
296 rb.Push(RESULT_SUCCESS); 282 rb.Push(RESULT_SUCCESS);
297 rb.PushCopyObjects(buffer_event->GetReadableEvent()); 283 rb.PushCopyObjects(buffer_event.GetReadableEvent());
298 } 284 }
299 285
300 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { 286 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
@@ -311,7 +297,7 @@ private:
311 297
312 IPC::ResponseBuilder rb{ctx, 2, 1}; 298 IPC::ResponseBuilder rb{ctx, 2, 1};
313 rb.Push(RESULT_SUCCESS); 299 rb.Push(RESULT_SUCCESS);
314 rb.PushCopyObjects(audio_input_device_switch_event->GetReadableEvent()); 300 rb.PushCopyObjects(buffer_event.GetReadableEvent());
315 } 301 }
316 302
317 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { 303 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
@@ -319,17 +305,16 @@ private:
319 305
320 IPC::ResponseBuilder rb{ctx, 2, 1}; 306 IPC::ResponseBuilder rb{ctx, 2, 1};
321 rb.Push(RESULT_SUCCESS); 307 rb.Push(RESULT_SUCCESS);
322 rb.PushCopyObjects(audio_output_device_switch_event->GetReadableEvent()); 308 rb.PushCopyObjects(buffer_event.GetReadableEvent());
323 } 309 }
324 310
311 Kernel::KEvent& buffer_event;
325 u32_le revision = 0; 312 u32_le revision = 0;
326 std::shared_ptr<Kernel::KEvent> buffer_event; 313};
327 std::shared_ptr<Kernel::KEvent> audio_input_device_switch_event;
328 std::shared_ptr<Kernel::KEvent> audio_output_device_switch_event;
329 314
330}; // namespace Audio 315AudRenU::AudRenU(Core::System& system_)
316 : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} {
331 317
332AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} {
333 // clang-format off 318 // clang-format off
334 static const FunctionInfo functions[] = { 319 static const FunctionInfo functions[] = {
335 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 320 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
@@ -341,6 +326,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
341 // clang-format on 326 // clang-format on
342 327
343 RegisterHandlers(functions); 328 RegisterHandlers(functions);
329
330 Kernel::KAutoObject::Create(std::addressof(buffer_event));
331 buffer_event.Initialize("IAudioOutBufferReleasedEvent");
344} 332}
345 333
346AudRenU::~AudRenU() = default; 334AudRenU::~AudRenU() = default;
@@ -374,7 +362,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
374 static constexpr u64 max_perf_detail_entries = 100; 362 static constexpr u64 max_perf_detail_entries = 100;
375 363
376 // Size of the data structure representing the bulk of the voice-related state. 364 // Size of the data structure representing the bulk of the voice-related state.
377 static constexpr u64 voice_state_size = 0x100; 365 static constexpr u64 voice_state_size_bytes = 0x100;
378 366
379 // Size of the upsampler manager data structure 367 // Size of the upsampler manager data structure
380 constexpr u64 upsampler_manager_size = 0x48; 368 constexpr u64 upsampler_manager_size = 0x48;
@@ -461,7 +449,8 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
461 size += Common::AlignUp(voice_info_size * params.voice_count, info_field_alignment_size); 449 size += Common::AlignUp(voice_info_size * params.voice_count, info_field_alignment_size);
462 size += 450 size +=
463 Common::AlignUp(voice_resource_size * params.voice_count, info_field_alignment_size); 451 Common::AlignUp(voice_resource_size * params.voice_count, info_field_alignment_size);
464 size += Common::AlignUp(voice_state_size * params.voice_count, info_field_alignment_size); 452 size +=
453 Common::AlignUp(voice_state_size_bytes * params.voice_count, info_field_alignment_size);
465 return size; 454 return size;
466 }; 455 };
467 456
@@ -663,7 +652,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
663 // always assumes the initial release revision (REV1). 652 // always assumes the initial release revision (REV1).
664 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 653 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
665 rb.Push(RESULT_SUCCESS); 654 rb.Push(RESULT_SUCCESS);
666 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); 655 rb.PushIpcInterface<IAudioDevice>(system, buffer_event, Common::MakeMagic('R', 'E', 'V', '1'));
667} 656}
668 657
669void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) { 658void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
@@ -685,7 +674,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c
685 674
686 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 675 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
687 rb.Push(RESULT_SUCCESS); 676 rb.Push(RESULT_SUCCESS);
688 rb.PushIpcInterface<IAudioDevice>(system, revision); 677 rb.PushIpcInterface<IAudioDevice>(system, buffer_event, revision);
689} 678}
690 679
691void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) { 680void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 37e8b4716..0ee6f9542 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Core { 10namespace Core {
@@ -31,6 +32,7 @@ private:
31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); 32 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
32 33
33 std::size_t audren_instance_count = 0; 34 std::size_t audren_instance_count = 0;
35 Kernel::KEvent buffer_event;
34}; 36};
35 37
36// Describes a particular audio feature that may be supported in a particular revision. 38// Describes a particular audio feature that may be supported in a particular revision.
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 19c578b3a..ee5ec8cd6 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -50,8 +50,8 @@ public:
50 Enabled, 50 Enabled,
51 }; 51 };
52 52
53 explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count) 53 explicit OpusDecoderState(OpusDecoderPtr decoder_, u32 sample_rate_, u32 channel_count_)
54 : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {} 54 : decoder{std::move(decoder_)}, sample_rate{sample_rate_}, channel_count{channel_count_} {}
55 55
56 // Decodes interleaved Opus packets. Optionally allows reporting time taken to 56 // Decodes interleaved Opus packets. Optionally allows reporting time taken to
57 // perform the decoding, as well as any relevant extra behavior. 57 // perform the decoding, as well as any relevant extra behavior.
@@ -160,9 +160,9 @@ private:
160 160
161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { 161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
162public: 162public:
163 explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state) 163 explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state_)
164 : ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{ 164 : ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{
165 std::move(decoder_state)} { 165 std::move(decoder_state_)} {
166 // clang-format off 166 // clang-format off
167 static const FunctionInfo functions[] = { 167 static const FunctionInfo functions[] = {
168 {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, 168 {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"},
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index 92d25dbe4..0e935bfa6 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -5,7 +5,6 @@
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/kernel/k_readable_event.h" 8#include "core/hle/kernel/k_readable_event.h"
10#include "core/hle/kernel/k_writable_event.h" 9#include "core/hle/kernel/k_writable_event.h"
11#include "core/hle/lock.h" 10#include "core/hle/lock.h"
@@ -14,14 +13,14 @@
14namespace Service::BCAT { 13namespace Service::BCAT {
15 14
16ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel, 15ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel,
17 std::string_view event_name) { 16 std::string_view event_name)
18 event = Kernel::KEvent::Create(kernel, 17 : update_event{kernel} {
19 "ProgressServiceBackend:UpdateEvent:" + std::string(event_name)); 18 Kernel::KAutoObject::Create(std::addressof(update_event));
20 event->Initialize(); 19 update_event.Initialize("ProgressServiceBackend:UpdateEvent:" + std::string(event_name));
21} 20}
22 21
23std::shared_ptr<Kernel::KReadableEvent> ProgressServiceBackend::GetEvent() const { 22Kernel::KReadableEvent& ProgressServiceBackend::GetEvent() {
24 return event->GetReadableEvent(); 23 return update_event.GetReadableEvent();
25} 24}
26 25
27DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() { 26DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
@@ -86,12 +85,12 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
86 SignalUpdate(); 85 SignalUpdate();
87} 86}
88 87
89void ProgressServiceBackend::SignalUpdate() const { 88void ProgressServiceBackend::SignalUpdate() {
90 if (need_hle_lock) { 89 if (need_hle_lock) {
91 std::lock_guard lock(HLE::g_hle_lock); 90 std::lock_guard lock(HLE::g_hle_lock);
92 event->GetWritableEvent()->Signal(); 91 update_event.GetWritableEvent().Signal();
93 } else { 92 } else {
94 event->GetWritableEvent()->Signal(); 93 update_event.GetWritableEvent().Signal();
95 } 94 }
96} 95}
97 96
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h
index db585b069..f591a362a 100644
--- a/src/core/hle/service/bcat/backend/backend.h
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -11,6 +11,7 @@
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/file_sys/vfs_types.h" 13#include "core/file_sys/vfs_types.h"
14#include "core/hle/kernel/k_event.h"
14#include "core/hle/result.h" 15#include "core/hle/result.h"
15 16
16namespace Core { 17namespace Core {
@@ -98,13 +99,13 @@ public:
98private: 99private:
99 explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name); 100 explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name);
100 101
101 std::shared_ptr<Kernel::KReadableEvent> GetEvent() const; 102 Kernel::KReadableEvent& GetEvent();
102 DeliveryCacheProgressImpl& GetImpl(); 103 DeliveryCacheProgressImpl& GetImpl();
103 104
104 void SignalUpdate() const; 105 void SignalUpdate();
105 106
106 DeliveryCacheProgressImpl impl{}; 107 DeliveryCacheProgressImpl impl{};
107 std::shared_ptr<Kernel::KEvent> event; 108 Kernel::KEvent update_event;
108 bool need_hle_lock = false; 109 bool need_hle_lock = false;
109}; 110};
110 111
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index cee1774d1..d6d2f52e5 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -3,9 +3,18 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <fmt/ostream.h> 5#include <fmt/ostream.h>
6
7#ifdef __GNUC__
8#pragma GCC diagnostic push
9#pragma GCC diagnostic ignored "-Wshadow"
10#endif
6#include <httplib.h> 11#include <httplib.h>
7#include <mbedtls/sha256.h> 12#include <mbedtls/sha256.h>
8#include <nlohmann/json.hpp> 13#include <nlohmann/json.hpp>
14#ifdef __GNUC__
15#pragma GCC diagnostic pop
16#endif
17
9#include "common/hex_util.h" 18#include "common/hex_util.h"
10#include "common/logging/backend.h" 19#include "common/logging/backend.h"
11#include "common/logging/log.h" 20#include "common/logging/log.h"
@@ -178,8 +187,8 @@ bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest,
178 187
179class Boxcat::Client { 188class Boxcat::Client {
180public: 189public:
181 Client(std::string path, u64 title_id, u64 build_id) 190 Client(std::string path_, u64 title_id_, u64 build_id_)
182 : path(std::move(path)), title_id(title_id), build_id(build_id) {} 191 : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {}
183 192
184 DownloadResult DownloadDataZip() { 193 DownloadResult DownloadDataZip() {
185 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS, 194 return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS,
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 285085f2a..0206cbb6a 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -12,9 +12,9 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs.h"
14#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/k_process.h"
15#include "core/hle/kernel/k_readable_event.h" 16#include "core/hle/kernel/k_readable_event.h"
16#include "core/hle/kernel/k_writable_event.h" 17#include "core/hle/kernel/k_writable_event.h"
17#include "core/hle/kernel/process.h"
18#include "core/hle/service/bcat/backend/backend.h" 18#include "core/hle/service/bcat/backend/backend.h"
19#include "core/hle/service/bcat/bcat.h" 19#include "core/hle/service/bcat/bcat.h"
20#include "core/hle/service/bcat/module.h" 20#include "core/hle/service/bcat/module.h"
@@ -88,11 +88,9 @@ struct DeliveryCacheDirectoryEntry {
88 88
89class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { 89class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
90public: 90public:
91 explicit IDeliveryCacheProgressService(Core::System& system_, 91 explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_,
92 std::shared_ptr<Kernel::KReadableEvent> event_,
93 const DeliveryCacheProgressImpl& impl_) 92 const DeliveryCacheProgressImpl& impl_)
94 : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)}, 93 : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} {
95 impl{impl_} {
96 // clang-format off 94 // clang-format off
97 static const FunctionInfo functions[] = { 95 static const FunctionInfo functions[] = {
98 {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, 96 {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"},
@@ -121,7 +119,7 @@ private:
121 rb.Push(RESULT_SUCCESS); 119 rb.Push(RESULT_SUCCESS);
122 } 120 }
123 121
124 std::shared_ptr<Kernel::KReadableEvent> event; 122 Kernel::KReadableEvent& event;
125 const DeliveryCacheProgressImpl& impl; 123 const DeliveryCacheProgressImpl& impl;
126}; 124};
127 125
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index af3a5842d..fd97a822c 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -17,7 +17,8 @@ namespace Service::BtDrv {
17 17
18class Bt final : public ServiceFramework<Bt> { 18class Bt final : public ServiceFramework<Bt> {
19public: 19public:
20 explicit Bt(Core::System& system_) : ServiceFramework{system_, "bt"} { 20 explicit Bt(Core::System& system_)
21 : ServiceFramework{system_, "bt"}, register_event{system.Kernel()} {
21 // clang-format off 22 // clang-format off
22 static const FunctionInfo functions[] = { 23 static const FunctionInfo functions[] = {
23 {0, nullptr, "LeClientReadCharacteristic"}, 24 {0, nullptr, "LeClientReadCharacteristic"},
@@ -34,9 +35,8 @@ public:
34 // clang-format on 35 // clang-format on
35 RegisterHandlers(functions); 36 RegisterHandlers(functions);
36 37
37 auto& kernel = system.Kernel(); 38 Kernel::KAutoObject::Create(std::addressof(register_event));
38 register_event = Kernel::KEvent::Create(kernel, "BT:RegisterEvent"); 39 register_event.Initialize("BT:RegisterEvent");
39 register_event->Initialize();
40 } 40 }
41 41
42private: 42private:
@@ -45,10 +45,10 @@ private:
45 45
46 IPC::ResponseBuilder rb{ctx, 2, 1}; 46 IPC::ResponseBuilder rb{ctx, 2, 1};
47 rb.Push(RESULT_SUCCESS); 47 rb.Push(RESULT_SUCCESS);
48 rb.PushCopyObjects(register_event->GetReadableEvent()); 48 rb.PushCopyObjects(register_event.GetReadableEvent());
49 } 49 }
50 50
51 std::shared_ptr<Kernel::KEvent> register_event; 51 Kernel::KEvent register_event;
52}; 52};
53 53
54class BtDrv final : public ServiceFramework<BtDrv> { 54class BtDrv final : public ServiceFramework<BtDrv> {
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index d1ebc2388..3b5ef69e1 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -18,7 +18,10 @@ namespace Service::BTM {
18 18
19class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 19class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
20public: 20public:
21 explicit IBtmUserCore(Core::System& system_) : ServiceFramework{system_, "IBtmUserCore"} { 21 explicit IBtmUserCore(Core::System& system_)
22 : ServiceFramework{system_, "IBtmUserCore"}, scan_event{system.Kernel()},
23 connection_event{system.Kernel()}, service_discovery{system.Kernel()},
24 config_event{system.Kernel()} {
22 // clang-format off 25 // clang-format off
23 static const FunctionInfo functions[] = { 26 static const FunctionInfo functions[] = {
24 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, 27 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -57,15 +60,15 @@ public:
57 // clang-format on 60 // clang-format on
58 RegisterHandlers(functions); 61 RegisterHandlers(functions);
59 62
60 auto& kernel = system.Kernel(); 63 Kernel::KAutoObject::Create(std::addressof(scan_event));
61 scan_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ScanEvent"); 64 Kernel::KAutoObject::Create(std::addressof(connection_event));
62 scan_event->Initialize(); 65 Kernel::KAutoObject::Create(std::addressof(service_discovery));
63 connection_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConnectionEvent"); 66 Kernel::KAutoObject::Create(std::addressof(config_event));
64 connection_event->Initialize(); 67
65 service_discovery = Kernel::KEvent::Create(kernel, "IBtmUserCore:Discovery"); 68 scan_event.Initialize("IBtmUserCore:ScanEvent");
66 service_discovery->Initialize(); 69 connection_event.Initialize("IBtmUserCore:ConnectionEvent");
67 config_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConfigEvent"); 70 service_discovery.Initialize("IBtmUserCore:Discovery");
68 config_event->Initialize(); 71 config_event.Initialize("IBtmUserCore:ConfigEvent");
69 } 72 }
70 73
71private: 74private:
@@ -74,7 +77,7 @@ private:
74 77
75 IPC::ResponseBuilder rb{ctx, 2, 1}; 78 IPC::ResponseBuilder rb{ctx, 2, 1};
76 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
77 rb.PushCopyObjects(scan_event->GetReadableEvent()); 80 rb.PushCopyObjects(scan_event.GetReadableEvent());
78 } 81 }
79 82
80 void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) { 83 void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) {
@@ -82,7 +85,7 @@ private:
82 85
83 IPC::ResponseBuilder rb{ctx, 2, 1}; 86 IPC::ResponseBuilder rb{ctx, 2, 1};
84 rb.Push(RESULT_SUCCESS); 87 rb.Push(RESULT_SUCCESS);
85 rb.PushCopyObjects(connection_event->GetReadableEvent()); 88 rb.PushCopyObjects(connection_event.GetReadableEvent());
86 } 89 }
87 90
88 void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) { 91 void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) {
@@ -90,7 +93,7 @@ private:
90 93
91 IPC::ResponseBuilder rb{ctx, 2, 1}; 94 IPC::ResponseBuilder rb{ctx, 2, 1};
92 rb.Push(RESULT_SUCCESS); 95 rb.Push(RESULT_SUCCESS);
93 rb.PushCopyObjects(service_discovery->GetReadableEvent()); 96 rb.PushCopyObjects(service_discovery.GetReadableEvent());
94 } 97 }
95 98
96 void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) { 99 void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) {
@@ -98,13 +101,13 @@ private:
98 101
99 IPC::ResponseBuilder rb{ctx, 2, 1}; 102 IPC::ResponseBuilder rb{ctx, 2, 1};
100 rb.Push(RESULT_SUCCESS); 103 rb.Push(RESULT_SUCCESS);
101 rb.PushCopyObjects(config_event->GetReadableEvent()); 104 rb.PushCopyObjects(config_event.GetReadableEvent());
102 } 105 }
103 106
104 std::shared_ptr<Kernel::KEvent> scan_event; 107 Kernel::KEvent scan_event;
105 std::shared_ptr<Kernel::KEvent> connection_event; 108 Kernel::KEvent connection_event;
106 std::shared_ptr<Kernel::KEvent> service_discovery; 109 Kernel::KEvent service_discovery;
107 std::shared_ptr<Kernel::KEvent> config_event; 110 Kernel::KEvent config_event;
108}; 111};
109 112
110class BTM_USR final : public ServiceFramework<BTM_USR> { 113class BTM_USR final : public ServiceFramework<BTM_USR> {
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 13147472e..432abde76 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -12,7 +12,7 @@
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/k_process.h"
16#include "core/hle/service/fatal/fatal.h" 16#include "core/hle/service/fatal/fatal.h"
17#include "core/hle/service/fatal/fatal_p.h" 17#include "core/hle/service/fatal/fatal_p.h"
18#include "core/hle/service/fatal/fatal_u.h" 18#include "core/hle/service/fatal/fatal_u.h"
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 67b2b3102..67baaee9b 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -21,7 +21,7 @@
21#include "core/file_sys/sdmc_factory.h" 21#include "core/file_sys/sdmc_factory.h"
22#include "core/file_sys/vfs.h" 22#include "core/file_sys/vfs.h"
23#include "core/file_sys/vfs_offset.h" 23#include "core/file_sys/vfs_offset.h"
24#include "core/hle/kernel/process.h" 24#include "core/hle/kernel/k_process.h"
25#include "core/hle/service/filesystem/filesystem.h" 25#include "core/hle/service/filesystem/filesystem.h"
26#include "core/hle/service/filesystem/fsp_ldr.h" 26#include "core/hle/service/filesystem/fsp_ldr.h"
27#include "core/hle/service/filesystem/fsp_pr.h" 27#include "core/hle/service/filesystem/fsp_pr.h"
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 7dc487e48..92ea27074 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -25,7 +25,7 @@
25#include "core/file_sys/system_archive/system_archive.h" 25#include "core/file_sys/system_archive/system_archive.h"
26#include "core/file_sys/vfs.h" 26#include "core/file_sys/vfs.h"
27#include "core/hle/ipc_helpers.h" 27#include "core/hle/ipc_helpers.h"
28#include "core/hle/kernel/process.h" 28#include "core/hle/kernel/k_process.h"
29#include "core/hle/service/filesystem/filesystem.h" 29#include "core/hle/service/filesystem/filesystem.h"
30#include "core/hle/service/filesystem/fsp_srv.h" 30#include "core/hle/service/filesystem/fsp_srv.h"
31#include "core/reporter.h" 31#include "core/reporter.h"
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index a35979053..91c202952 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -185,7 +185,8 @@ private:
185class INotificationService final : public ServiceFramework<INotificationService> { 185class INotificationService final : public ServiceFramework<INotificationService> {
186public: 186public:
187 explicit INotificationService(Common::UUID uuid_, Core::System& system_) 187 explicit INotificationService(Common::UUID uuid_, Core::System& system_)
188 : ServiceFramework{system_, "INotificationService"}, uuid{uuid_} { 188 : ServiceFramework{system_, "INotificationService"}, uuid{uuid_}, notification_event{
189 system.Kernel()} {
189 // clang-format off 190 // clang-format off
190 static const FunctionInfo functions[] = { 191 static const FunctionInfo functions[] = {
191 {0, &INotificationService::GetEvent, "GetEvent"}, 192 {0, &INotificationService::GetEvent, "GetEvent"},
@@ -196,9 +197,8 @@ public:
196 197
197 RegisterHandlers(functions); 198 RegisterHandlers(functions);
198 199
199 notification_event = 200 Kernel::KAutoObject::Create(std::addressof(notification_event));
200 Kernel::KEvent::Create(system.Kernel(), "INotificationService:NotifyEvent"); 201 notification_event.Initialize("INotificationService:NotifyEvent");
201 notification_event->Initialize();
202 } 202 }
203 203
204private: 204private:
@@ -207,7 +207,7 @@ private:
207 207
208 IPC::ResponseBuilder rb{ctx, 2, 1}; 208 IPC::ResponseBuilder rb{ctx, 2, 1};
209 rb.Push(RESULT_SUCCESS); 209 rb.Push(RESULT_SUCCESS);
210 rb.PushCopyObjects(notification_event->GetReadableEvent()); 210 rb.PushCopyObjects(notification_event.GetReadableEvent());
211 } 211 }
212 212
213 void Clear(Kernel::HLERequestContext& ctx) { 213 void Clear(Kernel::HLERequestContext& ctx) {
@@ -273,7 +273,7 @@ private:
273 }; 273 };
274 274
275 Common::UUID uuid{Common::INVALID_UUID}; 275 Common::UUID uuid{Common::INVALID_UUID};
276 std::shared_ptr<Kernel::KEvent> notification_event; 276 Kernel::KEvent notification_event;
277 std::queue<SizedNotificationInfo> notifications; 277 std::queue<SizedNotificationInfo> notifications;
278 States states{}; 278 States states{};
279}; 279};
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index 7b1c6677c..6ad62ee5a 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -9,8 +9,8 @@
9#include "core/file_sys/control_metadata.h" 9#include "core/file_sys/control_metadata.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/hle_ipc.h" 11#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/kernel/k_process.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/process.h"
14#include "core/hle/service/glue/arp.h" 14#include "core/hle/service/glue/arp.h"
15#include "core/hle/service/glue/errors.h" 15#include "core/hle/service/glue/errors.h"
16#include "core/hle/service/glue/manager.h" 16#include "core/hle/service/glue/manager.h"
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
index 8091db9d7..9d1e6db6a 100644
--- a/src/core/hle/service/hid/controllers/controller_base.cpp
+++ b/src/core/hle/service/hid/controllers/controller_base.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::HID { 7namespace Service::HID {
8 8
9ControllerBase::ControllerBase(Core::System& system) : system(system) {} 9ControllerBase::ControllerBase(Core::System& system_) : system(system_) {}
10ControllerBase::~ControllerBase() = default; 10ControllerBase::~ControllerBase() = default;
11 11
12void ControllerBase::ActivateController() { 12void ControllerBase::ActivateController() {
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index f47a9e61c..1556fb08e 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -18,7 +18,7 @@ class System;
18namespace Service::HID { 18namespace Service::HID {
19class ControllerBase { 19class ControllerBase {
20public: 20public:
21 explicit ControllerBase(Core::System& system); 21 explicit ControllerBase(Core::System& system_);
22 virtual ~ControllerBase(); 22 virtual ~ControllerBase();
23 23
24 // Called when the controller is initialized 24 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index bb77d8959..d311f754b 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -1,10 +1,9 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/math_util.h"
8#include "common/settings.h" 7#include "common/settings.h"
9#include "core/core_timing.h" 8#include "core/core_timing.h"
10#include "core/frontend/emu_window.h" 9#include "core/frontend/emu_window.h"
@@ -12,10 +11,19 @@
12 11
13namespace Service::HID { 12namespace Service::HID {
14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; 13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
15constexpr f32 angle_threshold = 0.08f;
16constexpr f32 pinch_threshold = 100.0f;
17 14
18Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase{system_} {} 15// HW is around 700, value is set to 400 to make it easier to trigger with mouse
16constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
17constexpr f32 angle_threshold = 0.015f; // Threshold in radians
18constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels
19constexpr f32 press_delay = 0.5f; // Time in seconds
20constexpr f32 double_tap_delay = 0.35f; // Time in seconds
21
22constexpr f32 Square(s32 num) {
23 return static_cast<f32>(num * num);
24}
25
26Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {}
19Controller_Gesture::~Controller_Gesture() = default; 27Controller_Gesture::~Controller_Gesture() = default;
20 28
21void Controller_Gesture::OnInit() { 29void Controller_Gesture::OnInit() {
@@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() {
24 keyboard_finger_id[id] = MAX_POINTS; 32 keyboard_finger_id[id] = MAX_POINTS;
25 udp_finger_id[id] = MAX_POINTS; 33 udp_finger_id[id] = MAX_POINTS;
26 } 34 }
35 shared_memory.header.entry_count = 0;
36 force_update = true;
27} 37}
28 38
29void Controller_Gesture::OnRelease() {} 39void Controller_Gesture::OnRelease() {}
@@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
38 shared_memory.header.last_entry_index = 0; 48 shared_memory.header.last_entry_index = 0;
39 return; 49 return;
40 } 50 }
41 shared_memory.header.entry_count = 16;
42 51
43 const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; 52 ReadTouchInput();
44 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
45 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
46 53
47 cur_entry.sampling_number = last_entry.sampling_number + 1; 54 GestureProperties gesture = GetGestureProperties();
48 cur_entry.sampling_number2 = cur_entry.sampling_number; 55 f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) /
56 (1000 * 1000 * 1000);
49 57
50 // TODO(german77): Implement all gesture types 58 // Only update if necesary
59 if (!ShouldUpdateGesture(gesture, time_difference)) {
60 return;
61 }
51 62
63 last_update_timestamp = shared_memory.header.timestamp;
64 UpdateGestureSharedMemory(data, size, gesture, time_difference);
65}
66
67void Controller_Gesture::ReadTouchInput() {
52 const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); 68 const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus();
53 const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); 69 const Input::TouchStatus& udp_status = touch_udp_device->GetStatus();
54 for (std::size_t id = 0; id < mouse_status.size(); ++id) { 70 for (std::size_t id = 0; id < mouse_status.size(); ++id) {
@@ -63,50 +79,71 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
63 UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); 79 UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]);
64 } 80 }
65 } 81 }
82}
66 83
67 TouchType type = TouchType::Idle; 84bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
68 Attribute attributes{}; 85 f32 time_difference) {
69 GestureProperties gesture = GetGestureProperties(); 86 const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
70 if (last_gesture.active_points != gesture.active_points) { 87 if (force_update) {
71 ++last_gesture.detection_count; 88 force_update = false;
89 return true;
72 } 90 }
73 if (gesture.active_points > 0) {
74 if (last_gesture.active_points == 0) {
75 attributes.is_new_touch.Assign(true);
76 last_gesture.average_distance = gesture.average_distance;
77 last_gesture.angle = gesture.angle;
78 }
79 91
80 type = TouchType::Touch; 92 // Update if coordinates change
81 if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) { 93 for (size_t id = 0; id < MAX_POINTS; id++) {
82 type = TouchType::Pan; 94 if (gesture.points[id].x != last_gesture.points[id].x ||
83 } 95 gesture.points[id].y != last_gesture.points[id].y) {
84 if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { 96 return true;
85 type = TouchType::Pinch;
86 }
87 if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) {
88 type = TouchType::Rotate;
89 } 97 }
98 }
99
100 // Update on press and hold event after 0.5 seconds
101 if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 &&
102 time_difference > press_delay) {
103 return enable_press_and_tap;
104 }
105
106 return false;
107}
108
109void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
110 GestureProperties& gesture,
111 f32 time_difference) {
112 TouchType type = TouchType::Idle;
113 Attribute attributes{};
114
115 const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
116 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
117 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
90 118
91 cur_entry.delta_x = gesture.mid_point.x - last_entry.x; 119 if (shared_memory.header.entry_count < 16) {
92 cur_entry.delta_y = gesture.mid_point.y - last_entry.y; 120 shared_memory.header.entry_count++;
93 // TODO: Find how velocities are calculated 121 }
94 cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f;
95 cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f;
96 122
97 // Slowdown the rate of change for less flapping 123 cur_entry.sampling_number = last_entry.sampling_number + 1;
98 last_gesture.average_distance = 124 cur_entry.sampling_number2 = cur_entry.sampling_number;
99 (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f);
100 last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f);
101 125
126 // Reset values to default
127 cur_entry.delta_x = 0;
128 cur_entry.delta_y = 0;
129 cur_entry.vel_x = 0;
130 cur_entry.vel_y = 0;
131 cur_entry.direction = Direction::None;
132 cur_entry.rotation_angle = 0;
133 cur_entry.scale = 0;
134
135 if (gesture.active_points > 0) {
136 if (last_gesture.active_points == 0) {
137 NewGesture(gesture, type, attributes);
138 } else {
139 UpdateExistingGesture(gesture, type, time_difference);
140 }
102 } else { 141 } else {
103 cur_entry.delta_x = 0; 142 EndGesture(gesture, last_gesture, type, attributes, time_difference);
104 cur_entry.delta_y = 0;
105 cur_entry.vel_x = 0;
106 cur_entry.vel_y = 0;
107 } 143 }
108 last_gesture.active_points = gesture.active_points; 144
109 cur_entry.detection_count = last_gesture.detection_count; 145 // Apply attributes
146 cur_entry.detection_count = gesture.detection_count;
110 cur_entry.type = type; 147 cur_entry.type = type;
111 cur_entry.attributes = attributes; 148 cur_entry.attributes = attributes;
112 cur_entry.x = gesture.mid_point.x; 149 cur_entry.x = gesture.mid_point.x;
@@ -116,12 +153,195 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
116 cur_entry.points[id].x = gesture.points[id].x; 153 cur_entry.points[id].x = gesture.points[id].x;
117 cur_entry.points[id].y = gesture.points[id].y; 154 cur_entry.points[id].y = gesture.points[id].y;
118 } 155 }
119 cur_entry.rotation_angle = 0; 156 last_gesture = gesture;
120 cur_entry.scale = 0;
121 157
122 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); 158 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
123} 159}
124 160
161void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type,
162 Attribute& attributes) {
163 const auto& last_entry =
164 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
165 gesture.detection_count++;
166 type = TouchType::Touch;
167
168 // New touch after cancel is not considered new
169 if (last_entry.type != TouchType::Cancel) {
170 attributes.is_new_touch.Assign(1);
171 enable_press_and_tap = true;
172 }
173}
174
175void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type,
176 f32 time_difference) {
177 const auto& last_entry =
178 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
179
180 // Promote to pan type if touch moved
181 for (size_t id = 0; id < MAX_POINTS; id++) {
182 if (gesture.points[id].x != last_gesture.points[id].x ||
183 gesture.points[id].y != last_gesture.points[id].y) {
184 type = TouchType::Pan;
185 break;
186 }
187 }
188
189 // Number of fingers changed cancel the last event and clear data
190 if (gesture.active_points != last_gesture.active_points) {
191 type = TouchType::Cancel;
192 enable_press_and_tap = false;
193 gesture.active_points = 0;
194 gesture.mid_point = {};
195 for (size_t id = 0; id < MAX_POINTS; id++) {
196 gesture.points[id].x = 0;
197 gesture.points[id].y = 0;
198 }
199 return;
200 }
201
202 // Calculate extra parameters of panning
203 if (type == TouchType::Pan) {
204 UpdatePanEvent(gesture, last_gesture, type, time_difference);
205 return;
206 }
207
208 // Promote to press type
209 if (last_entry.type == TouchType::Touch) {
210 type = TouchType::Press;
211 }
212}
213
214void Controller_Gesture::EndGesture(GestureProperties& gesture,
215 GestureProperties& last_gesture_props, TouchType& type,
216 Attribute& attributes, f32 time_difference) {
217 const auto& last_entry =
218 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
219 if (last_gesture_props.active_points != 0) {
220 switch (last_entry.type) {
221 case TouchType::Touch:
222 if (enable_press_and_tap) {
223 SetTapEvent(gesture, last_gesture_props, type, attributes);
224 return;
225 }
226 type = TouchType::Cancel;
227 force_update = true;
228 break;
229 case TouchType::Press:
230 case TouchType::Tap:
231 case TouchType::Swipe:
232 case TouchType::Pinch:
233 case TouchType::Rotate:
234 type = TouchType::Complete;
235 force_update = true;
236 break;
237 case TouchType::Pan:
238 EndPanEvent(gesture, last_gesture_props, type, time_difference);
239 break;
240 default:
241 break;
242 }
243 return;
244 }
245 if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) {
246 gesture.detection_count++;
247 }
248}
249
250void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
251 GestureProperties& last_gesture_props, TouchType& type,
252 Attribute& attributes) {
253 type = TouchType::Tap;
254 gesture = last_gesture_props;
255 force_update = true;
256 f32 tap_time_difference =
257 static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
258 last_tap_timestamp = last_update_timestamp;
259 if (tap_time_difference < double_tap_delay) {
260 attributes.is_double_tap.Assign(1);
261 }
262}
263
264void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
265 GestureProperties& last_gesture_props, TouchType& type,
266 f32 time_difference) {
267 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
268 const auto& last_entry =
269 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
270 cur_entry.delta_x = gesture.mid_point.x - last_entry.x;
271 cur_entry.delta_y = gesture.mid_point.y - last_entry.y;
272
273 cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference;
274 cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference;
275 last_pan_time_difference = time_difference;
276
277 // Promote to pinch type
278 if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
279 pinch_threshold) {
280 type = TouchType::Pinch;
281 cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance;
282 }
283
284 const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
285 (1 + (gesture.angle * last_gesture_props.angle)));
286 // Promote to rotate type
287 if (std::abs(angle_between_two_lines) > angle_threshold) {
288 type = TouchType::Rotate;
289 cur_entry.scale = 0;
290 cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
291 }
292}
293
294void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
295 GestureProperties& last_gesture_props, TouchType& type,
296 f32 time_difference) {
297 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
298 const auto& last_entry =
299 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
300 cur_entry.vel_x =
301 static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference);
302 cur_entry.vel_y =
303 static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference);
304 const f32 curr_vel =
305 std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y));
306
307 // Set swipe event with parameters
308 if (curr_vel > swipe_threshold) {
309 SetSwipeEvent(gesture, last_gesture_props, type);
310 return;
311 }
312
313 // End panning without swipe
314 type = TouchType::Complete;
315 cur_entry.vel_x = 0;
316 cur_entry.vel_y = 0;
317 force_update = true;
318}
319
320void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
321 GestureProperties& last_gesture_props, TouchType& type) {
322 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
323 const auto& last_entry =
324 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
325 type = TouchType::Swipe;
326 gesture = last_gesture_props;
327 force_update = true;
328 cur_entry.delta_x = last_entry.delta_x;
329 cur_entry.delta_y = last_entry.delta_y;
330 if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) {
331 if (cur_entry.delta_x > 0) {
332 cur_entry.direction = Direction::Right;
333 return;
334 }
335 cur_entry.direction = Direction::Left;
336 return;
337 }
338 if (cur_entry.delta_y > 0) {
339 cur_entry.direction = Direction::Down;
340 return;
341 }
342 cur_entry.direction = Direction::Up;
343}
344
125void Controller_Gesture::OnLoadInputDevices() { 345void Controller_Gesture::OnLoadInputDevices() {
126 touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); 346 touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window");
127 touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); 347 touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp");
@@ -183,23 +403,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties()
183 403
184 for (size_t id = 0; id < gesture.active_points; ++id) { 404 for (size_t id = 0; id < gesture.active_points; ++id) {
185 gesture.points[id].x = 405 gesture.points[id].x =
186 static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); 406 static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width);
187 gesture.points[id].y = 407 gesture.points[id].y =
188 static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); 408 static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height);
189 gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); 409
190 gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points); 410 // Hack: There is no touch in docked but games still allow it
411 if (Settings::values.use_docked_mode.GetValue()) {
412 gesture.points[id].x =
413 static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width);
414 gesture.points[id].y =
415 static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height);
416 }
417
418 gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
419 gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
191 } 420 }
192 421
193 for (size_t id = 0; id < gesture.active_points; ++id) { 422 for (size_t id = 0; id < gesture.active_points; ++id) {
194 const double distance = 423 const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
195 std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + 424 Square(gesture.mid_point.y - gesture.points[id].y));
196 std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2); 425 gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
197 gesture.average_distance +=
198 static_cast<float>(distance) / static_cast<float>(gesture.active_points);
199 } 426 }
200 427
201 gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y), 428 gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
202 static_cast<float>(gesture.mid_point.x - gesture.points[0].x)); 429 static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
430
431 gesture.detection_count = last_gesture.detection_count;
432
203 return gesture; 433 return gesture;
204} 434}
205 435
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 7c357b977..f46e29411 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -1,4 +1,4 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -7,7 +7,6 @@
7#include <array> 7#include <array>
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/frontend/input.h" 10#include "core/frontend/input.h"
12#include "core/hle/service/hid/controllers/controller_base.h" 11#include "core/hle/service/hid/controllers/controller_base.h"
13 12
@@ -35,10 +34,10 @@ private:
35 34
36 enum class TouchType : u32 { 35 enum class TouchType : u32 {
37 Idle, // Nothing touching the screen 36 Idle, // Nothing touching the screen
38 Complete, // Unknown. End of touch? 37 Complete, // Set at the end of a touch event
39 Cancel, // Never triggered 38 Cancel, // Set when the number of fingers change
40 Touch, // Pressing without movement 39 Touch, // A finger just touched the screen
41 Press, // Never triggered 40 Press, // Set if last type is touch and the finger hasn't moved
42 Tap, // Fast press then release 41 Tap, // Fast press then release
43 Pan, // All points moving together across the screen 42 Pan, // All points moving together across the screen
44 Swipe, // Fast press movement and release of a single point 43 Swipe, // Fast press movement and release of a single point
@@ -58,8 +57,8 @@ private:
58 union { 57 union {
59 u32_le raw{}; 58 u32_le raw{};
60 59
61 BitField<0, 1, u32> is_new_touch; 60 BitField<4, 1, u32> is_new_touch;
62 BitField<1, 1, u32> is_double_tap; 61 BitField<8, 1, u32> is_double_tap;
63 }; 62 };
64 }; 63 };
65 static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); 64 static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size");
@@ -73,10 +72,9 @@ private:
73 struct GestureState { 72 struct GestureState {
74 s64_le sampling_number; 73 s64_le sampling_number;
75 s64_le sampling_number2; 74 s64_le sampling_number2;
76
77 s64_le detection_count; 75 s64_le detection_count;
78 TouchType type; 76 TouchType type;
79 Direction dir; 77 Direction direction;
80 s32_le x; 78 s32_le x;
81 s32_le y; 79 s32_le y;
82 s32_le delta_x; 80 s32_le delta_x;
@@ -84,8 +82,8 @@ private:
84 f32 vel_x; 82 f32 vel_x;
85 f32 vel_y; 83 f32 vel_y;
86 Attribute attributes; 84 Attribute attributes;
87 u32 scale; 85 f32 scale;
88 u32 rotation_angle; 86 f32 rotation_angle;
89 s32_le point_count; 87 s32_le point_count;
90 std::array<Points, 4> points; 88 std::array<Points, 4> points;
91 }; 89 };
@@ -109,17 +107,55 @@ private:
109 Points mid_point{}; 107 Points mid_point{};
110 s64_le detection_count{}; 108 s64_le detection_count{};
111 u64_le delta_time{}; 109 u64_le delta_time{};
112 float average_distance{}; 110 f32 average_distance{};
113 float angle{}; 111 f32 angle{};
114 }; 112 };
115 113
116 // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned 114 // Reads input from all available input engines
115 void ReadTouchInput();
116
117 // Returns true if gesture state needs to be updated
118 bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference);
119
120 // Updates the shared memory to the next state
121 void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture,
122 f32 time_difference);
123
124 // Initializes new gesture
125 void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes);
126
127 // Updates existing gesture state
128 void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference);
129
130 // Terminates exiting gesture
131 void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
132 TouchType& type, Attribute& attributes, f32 time_difference);
133
134 // Set current event to a tap event
135 void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
136 TouchType& type, Attribute& attributes);
137
138 // Calculates and set the extra parameters related to a pan event
139 void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
140 TouchType& type, f32 time_difference);
141
142 // Terminates the pan event
143 void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
144 TouchType& type, f32 time_difference);
145
146 // Set current event to a swipe event
147 void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
148 TouchType& type);
149
150 // Returns an unused finger id, if there is no fingers available std::nullopt is returned.
117 std::optional<size_t> GetUnusedFingerID() const; 151 std::optional<size_t> GetUnusedFingerID() const;
118 152
119 /** If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no 153 /**
154 * If the touch is new it tries to assign a new finger id, if there is no fingers available no
120 * changes will be made. Updates the coordinates if the finger id it's already set. If the touch 155 * changes will be made. Updates the coordinates if the finger id it's already set. If the touch
121 * ends delays the output by one frame to set the end_touch flag before finally freeing the 156 * ends delays the output by one frame to set the end_touch flag before finally freeing the
122 * finger id */ 157 * finger id
158 */
123 size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, 159 size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
124 size_t finger_id); 160 size_t finger_id);
125 161
@@ -134,6 +170,11 @@ private:
134 std::array<size_t, MAX_FINGERS> keyboard_finger_id; 170 std::array<size_t, MAX_FINGERS> keyboard_finger_id;
135 std::array<size_t, MAX_FINGERS> udp_finger_id; 171 std::array<size_t, MAX_FINGERS> udp_finger_id;
136 std::array<Finger, MAX_POINTS> fingers; 172 std::array<Finger, MAX_POINTS> fingers;
137 GestureProperties last_gesture; 173 GestureProperties last_gesture{};
174 s64_le last_update_timestamp{};
175 s64_le last_tap_timestamp{};
176 f32 last_pan_time_difference{};
177 bool force_update{false};
178 bool enable_press_and_tap{false};
138}; 179};
139} // namespace Service::HID 180} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index d4678ef49..7acad3798 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -159,7 +159,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
159 const auto controller_type = connected_controllers[controller_idx].type; 159 const auto controller_type = connected_controllers[controller_idx].type;
160 auto& controller = shared_memory_entries[controller_idx]; 160 auto& controller = shared_memory_entries[controller_idx];
161 if (controller_type == NPadControllerType::None) { 161 if (controller_type == NPadControllerType::None) {
162 styleset_changed_events[controller_idx]->GetWritableEvent()->Signal(); 162 styleset_changed_events[controller_idx]->GetWritableEvent().Signal();
163 return; 163 return;
164 } 164 }
165 controller.style_set.raw = 0; // Zero out 165 controller.style_set.raw = 0; // Zero out
@@ -253,9 +253,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
253void Controller_NPad::OnInit() { 253void Controller_NPad::OnInit() {
254 auto& kernel = system.Kernel(); 254 auto& kernel = system.Kernel();
255 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { 255 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
256 styleset_changed_events[i] = 256 styleset_changed_events[i] = Kernel::KEvent::Create(kernel);
257 Kernel::KEvent::Create(kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); 257 styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i));
258 styleset_changed_events[i]->Initialize();
259 } 258 }
260 259
261 if (!IsControllerActivated()) { 260 if (!IsControllerActivated()) {
@@ -341,6 +340,11 @@ void Controller_NPad::OnRelease() {
341 VibrateControllerAtIndex(npad_idx, device_idx, {}); 340 VibrateControllerAtIndex(npad_idx, device_idx, {});
342 } 341 }
343 } 342 }
343
344 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
345 styleset_changed_events[i]->Close();
346 styleset_changed_events[i] = nullptr;
347 }
344} 348}
345 349
346void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { 350void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
@@ -955,14 +959,12 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev
955 return vibration_devices_mounted[npad_index][device_index]; 959 return vibration_devices_mounted[npad_index][device_index];
956} 960}
957 961
958std::shared_ptr<Kernel::KReadableEvent> Controller_NPad::GetStyleSetChangedEvent( 962Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) {
959 u32 npad_id) const { 963 return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent();
960 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
961 return styleset_event->GetReadableEvent();
962} 964}
963 965
964void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { 966void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
965 styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent()->Signal(); 967 styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal();
966} 968}
967 969
968void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { 970void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index ea484d4bf..c050c9a44 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -11,7 +11,6 @@
11#include "common/quaternion.h" 11#include "common/quaternion.h"
12#include "common/settings.h" 12#include "common/settings.h"
13#include "core/frontend/input.h" 13#include "core/frontend/input.h"
14#include "core/hle/kernel/object.h"
15#include "core/hle/service/hid/controllers/controller_base.h" 14#include "core/hle/service/hid/controllers/controller_base.h"
16 15
17namespace Kernel { 16namespace Kernel {
@@ -199,7 +198,7 @@ public:
199 198
200 bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; 199 bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
201 200
202 std::shared_ptr<Kernel::KReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; 201 Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id);
203 void SignalStyleSetChangedEvent(u32 npad_id) const; 202 void SignalStyleSetChangedEvent(u32 npad_id) const;
204 203
205 // Adds a new controller at an index. 204 // Adds a new controller at an index.
@@ -573,8 +572,9 @@ private:
573 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; 572 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
574 NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; 573 NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
575 // Each controller should have their own styleset changed event 574 // Each controller should have their own styleset changed event
576 std::array<std::shared_ptr<Kernel::KEvent>, 10> styleset_changed_events; 575 std::array<Kernel::KEvent*, 10> styleset_changed_events{};
577 std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints; 576 std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10>
577 last_vibration_timepoints{};
578 std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; 578 std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
579 bool permit_vibration_session_enabled{false}; 579 bool permit_vibration_session_enabled{false};
580 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{}; 580 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 9c4bf6d16..49c17fd14 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,18 +13,18 @@
13#include "core/frontend/input.h" 13#include "core/frontend/input.h"
14#include "core/hardware_properties.h" 14#include "core/hardware_properties.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/client_port.h" 16#include "core/hle/kernel/k_client_port.h"
17#include "core/hle/kernel/client_session.h"
18#include "core/hle/kernel/k_readable_event.h" 17#include "core/hle/kernel/k_readable_event.h"
19#include "core/hle/kernel/k_shared_memory.h" 18#include "core/hle/kernel/k_shared_memory.h"
19#include "core/hle/kernel/k_transfer_memory.h"
20#include "core/hle/kernel/k_writable_event.h" 20#include "core/hle/kernel/k_writable_event.h"
21#include "core/hle/kernel/kernel.h" 21#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/transfer_memory.h"
23#include "core/hle/service/hid/errors.h" 22#include "core/hle/service/hid/errors.h"
24#include "core/hle/service/hid/hid.h" 23#include "core/hle/service/hid/hid.h"
25#include "core/hle/service/hid/irs.h" 24#include "core/hle/service/hid/irs.h"
26#include "core/hle/service/hid/xcd.h" 25#include "core/hle/service/hid/xcd.h"
27#include "core/hle/service/service.h" 26#include "core/hle/service/service.h"
27#include "core/memory.h"
28 28
29#include "core/hle/service/hid/controllers/console_sixaxis.h" 29#include "core/hle/service/hid/controllers/console_sixaxis.h"
30#include "core/hle/service/hid/controllers/controller_base.h" 30#include "core/hle/service/hid/controllers/controller_base.h"
@@ -53,9 +53,6 @@ IAppletResource::IAppletResource(Core::System& system_)
53 }; 53 };
54 RegisterHandlers(functions); 54 RegisterHandlers(functions);
55 55
56 auto& kernel = system.Kernel();
57 shared_mem = SharedFrom(&kernel.GetHidSharedMem());
58
59 MakeController<Controller_DebugPad>(HidController::DebugPad); 56 MakeController<Controller_DebugPad>(HidController::DebugPad);
60 MakeController<Controller_Touchscreen>(HidController::Touchscreen); 57 MakeController<Controller_Touchscreen>(HidController::Touchscreen);
61 MakeController<Controller_Mouse>(HidController::Mouse); 58 MakeController<Controller_Mouse>(HidController::Mouse);
@@ -118,7 +115,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
118 115
119 IPC::ResponseBuilder rb{ctx, 2, 1}; 116 IPC::ResponseBuilder rb{ctx, 2, 1};
120 rb.Push(RESULT_SUCCESS); 117 rb.Push(RESULT_SUCCESS);
121 rb.PushCopyObjects(shared_mem); 118 rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
122} 119}
123 120
124void IAppletResource::UpdateControllers(std::uintptr_t user_data, 121void IAppletResource::UpdateControllers(std::uintptr_t user_data,
@@ -130,7 +127,8 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
130 if (should_reload) { 127 if (should_reload) {
131 controller->OnLoadInputDevices(); 128 controller->OnLoadInputDevices();
132 } 129 }
133 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 130 controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
131 SHARED_MEMORY_SIZE);
134 } 132 }
135 133
136 // If ns_late is higher than the update rate ignore the delay 134 // If ns_late is higher than the update rate ignore the delay
@@ -145,7 +143,7 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
145 auto& core_timing = system.CoreTiming(); 143 auto& core_timing = system.CoreTiming();
146 144
147 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( 145 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(
148 core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 146 core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
149 147
150 // If ns_late is higher than the update rate ignore the delay 148 // If ns_late is higher than the update rate ignore the delay
151 if (ns_late > motion_update_ns) { 149 if (ns_late > motion_update_ns) {
@@ -1496,20 +1494,20 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
1496 ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes"); 1494 ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
1497 ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes"); 1495 ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
1498 1496
1499 auto t_mem_1 = 1497 auto t_mem_1 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1500 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_1_handle); 1498 t_mem_1_handle);
1501 1499
1502 if (t_mem_1 == nullptr) { 1500 if (t_mem_1.IsNull()) {
1503 LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle); 1501 LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
1504 IPC::ResponseBuilder rb{ctx, 2}; 1502 IPC::ResponseBuilder rb{ctx, 2};
1505 rb.Push(RESULT_UNKNOWN); 1503 rb.Push(RESULT_UNKNOWN);
1506 return; 1504 return;
1507 } 1505 }
1508 1506
1509 auto t_mem_2 = 1507 auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1510 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_2_handle); 1508 t_mem_2_handle);
1511 1509
1512 if (t_mem_2 == nullptr) { 1510 if (t_mem_2.IsNull()) {
1513 LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle); 1511 LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
1514 IPC::ResponseBuilder rb{ctx, 2}; 1512 IPC::ResponseBuilder rb{ctx, 2};
1515 rb.Push(RESULT_UNKNOWN); 1513 rb.Push(RESULT_UNKNOWN);
@@ -1524,7 +1522,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
1524 .ActivateController(); 1522 .ActivateController();
1525 1523
1526 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor) 1524 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1527 .SetTransferMemoryPointer(t_mem_1->GetPointer()); 1525 .SetTransferMemoryPointer(system.Memory().GetPointer(t_mem_1->GetSourceAddress()));
1528 1526
1529 LOG_WARNING(Service_HID, 1527 LOG_WARNING(Service_HID,
1530 "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, " 1528 "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index c2bdd39a3..aa3307955 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -13,10 +13,6 @@ namespace Core::Timing {
13struct EventType; 13struct EventType;
14} 14}
15 15
16namespace Kernel {
17class KSharedMemory;
18}
19
20namespace Service::SM { 16namespace Service::SM {
21class ServiceManager; 17class ServiceManager;
22} 18}
@@ -69,8 +65,6 @@ private:
69 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 65 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
70 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 66 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
71 67
72 std::shared_ptr<Kernel::KSharedMemory> shared_mem;
73
74 std::shared_ptr<Core::Timing::EventType> pad_update_event; 68 std::shared_ptr<Core::Timing::EventType> pad_update_event;
75 std::shared_ptr<Core::Timing::EventType> motion_update_event; 69 std::shared_ptr<Core::Timing::EventType> motion_update_event;
76 70
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 2dfa936fb..3c6085990 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -37,10 +37,6 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
37 // clang-format on 37 // clang-format on
38 38
39 RegisterHandlers(functions); 39 RegisterHandlers(functions);
40
41 auto& kernel = system.Kernel();
42
43 shared_mem = SharedFrom(&kernel.GetIrsSharedMem());
44} 40}
45 41
46void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { 42void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
@@ -62,7 +58,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
62 58
63 IPC::ResponseBuilder rb{ctx, 2, 1}; 59 IPC::ResponseBuilder rb{ctx, 2, 1};
64 rb.Push(RESULT_SUCCESS); 60 rb.Push(RESULT_SUCCESS);
65 rb.PushCopyObjects(shared_mem); 61 rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
66} 62}
67 63
68void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { 64void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index b0c8c7168..9bc6462b0 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -4,17 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/object.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
10namespace Core { 9namespace Core {
11class System; 10class System;
12} 11}
13 12
14namespace Kernel {
15class KSharedMemory;
16}
17
18namespace Service::HID { 13namespace Service::HID {
19 14
20class IRS final : public ServiceFramework<IRS> { 15class IRS final : public ServiceFramework<IRS> {
@@ -42,7 +37,6 @@ private:
42 void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); 37 void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
43 void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); 38 void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
44 39
45 std::shared_ptr<Kernel::KSharedMemory> shared_mem;
46 const u32 device_handle{0xABCD}; 40 const u32 device_handle{0xABCD};
47}; 41};
48 42
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index c8bc60ad1..c3948eb8e 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -12,8 +12,8 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/k_page_table.h" 14#include "core/hle/kernel/k_page_table.h"
15#include "core/hle/kernel/k_process.h"
15#include "core/hle/kernel/k_system_control.h" 16#include "core/hle/kernel/k_system_control.h"
16#include "core/hle/kernel/process.h"
17#include "core/hle/kernel/svc_results.h" 17#include "core/hle/kernel/svc_results.h"
18#include "core/hle/service/ldr/ldr.h" 18#include "core/hle/service/ldr/ldr.h"
19#include "core/hle/service/service.h" 19#include "core/hle/service/service.h"
@@ -321,7 +321,7 @@ public:
321 return addr; 321 return addr;
322 } 322 }
323 323
324 ResultVal<VAddr> MapProcessCodeMemory(Kernel::Process* process, VAddr baseAddress, 324 ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr baseAddress,
325 u64 size) const { 325 u64 size) const {
326 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { 326 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
327 auto& page_table{process->PageTable()}; 327 auto& page_table{process->PageTable()};
@@ -342,7 +342,7 @@ public:
342 return ERROR_INSUFFICIENT_ADDRESS_SPACE; 342 return ERROR_INSUFFICIENT_ADDRESS_SPACE;
343 } 343 }
344 344
345 ResultVal<VAddr> MapNro(Kernel::Process* process, VAddr nro_addr, std::size_t nro_size, 345 ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
346 VAddr bss_addr, std::size_t bss_size, std::size_t size) const { 346 VAddr bss_addr, std::size_t bss_size, std::size_t size) const {
347 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { 347 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
348 auto& page_table{process->PageTable()}; 348 auto& page_table{process->PageTable()};
@@ -378,7 +378,7 @@ public:
378 return ERROR_INSUFFICIENT_ADDRESS_SPACE; 378 return ERROR_INSUFFICIENT_ADDRESS_SPACE;
379 } 379 }
380 380
381 ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, 381 ResultCode LoadNro(Kernel::KProcess* process, const NROHeader& nro_header, VAddr nro_addr,
382 VAddr start) const { 382 VAddr start) const {
383 const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset}; 383 const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
384 const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset}; 384 const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
@@ -387,11 +387,9 @@ public:
387 const VAddr bss_end_addr{ 387 const VAddr bss_end_addr{
388 Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)}; 388 Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)};
389 389
390 auto CopyCode{[&](VAddr src_addr, VAddr dst_addr, u64 size) { 390 const auto CopyCode = [this, process](VAddr src_addr, VAddr dst_addr, u64 size) {
391 std::vector<u8> source_data(size); 391 system.Memory().CopyBlock(*process, dst_addr, src_addr, size);
392 system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); 392 };
393 system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size());
394 }};
395 CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start, 393 CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
396 nro_header.segment_headers[TEXT_INDEX].memory_size); 394 nro_header.segment_headers[TEXT_INDEX].memory_size);
397 CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start, 395 CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start,
diff --git a/src/core/hle/service/mii/manager.h b/src/core/hle/service/mii/manager.h
index 2106a528a..ec7efa5f7 100644
--- a/src/core/hle/service/mii/manager.h
+++ b/src/core/hle/service/mii/manager.h
@@ -89,7 +89,7 @@ static_assert(std::has_unique_object_representations_v<MiiInfo>,
89#pragma pack(push, 4) 89#pragma pack(push, 4)
90 90
91struct MiiInfoElement { 91struct MiiInfoElement {
92 MiiInfoElement(const MiiInfo& info, Source source) : info{info}, source{source} {} 92 MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {}
93 93
94 MiiInfo info{}; 94 MiiInfo info{};
95 Source source{}; 95 Source source{};
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 26be9e45b..81f150a88 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -253,8 +253,8 @@ private:
253 253
254class MiiDBModule final : public ServiceFramework<MiiDBModule> { 254class MiiDBModule final : public ServiceFramework<MiiDBModule> {
255public: 255public:
256 explicit MiiDBModule(Core::System& system_, const char* name) 256 explicit MiiDBModule(Core::System& system_, const char* name_)
257 : ServiceFramework{system_, name} { 257 : ServiceFramework{system_, name_} {
258 // clang-format off 258 // clang-format off
259 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
260 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, 260 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index b0cb07d24..c8519e2db 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/client_session.h"
8#include "core/hle/service/mm/mm_u.h" 7#include "core/hle/service/mm/mm_u.h"
9#include "core/hle/service/sm/sm.h" 8#include "core/hle/service/sm/sm.h"
10 9
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 2d1d4d67f..d25b20ab5 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -8,7 +8,6 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/kernel/k_readable_event.h" 11#include "core/hle/kernel/k_readable_event.h"
13#include "core/hle/kernel/k_thread.h" 12#include "core/hle/kernel/k_thread.h"
14#include "core/hle/kernel/k_writable_event.h" 13#include "core/hle/kernel/k_writable_event.h"
@@ -24,10 +23,9 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
24 23
25Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, 24Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
26 const char* name) 25 const char* name)
27 : ServiceFramework{system_, name}, module{std::move(module_)} { 26 : ServiceFramework{system_, name}, nfc_tag_load{system.Kernel()}, module{std::move(module_)} {
28 auto& kernel = system.Kernel(); 27 Kernel::KAutoObject::Create(std::addressof(nfc_tag_load));
29 nfc_tag_load = Kernel::KEvent::Create(kernel, "IUser:NFCTagDetected"); 28 nfc_tag_load.Initialize("IUser:NFCTagDetected");
30 nfc_tag_load->Initialize();
31} 29}
32 30
33Module::Interface::~Interface() = default; 31Module::Interface::~Interface() = default;
@@ -35,7 +33,8 @@ Module::Interface::~Interface() = default;
35class IUser final : public ServiceFramework<IUser> { 33class IUser final : public ServiceFramework<IUser> {
36public: 34public:
37 explicit IUser(Module::Interface& nfp_interface_, Core::System& system_) 35 explicit IUser(Module::Interface& nfp_interface_, Core::System& system_)
38 : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_} { 36 : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_},
37 deactivate_event{system.Kernel()}, availability_change_event{system.Kernel()} {
39 static const FunctionInfo functions[] = { 38 static const FunctionInfo functions[] = {
40 {0, &IUser::Initialize, "Initialize"}, 39 {0, &IUser::Initialize, "Initialize"},
41 {1, &IUser::Finalize, "Finalize"}, 40 {1, &IUser::Finalize, "Finalize"},
@@ -65,11 +64,11 @@ public:
65 }; 64 };
66 RegisterHandlers(functions); 65 RegisterHandlers(functions);
67 66
68 auto& kernel = system.Kernel(); 67 Kernel::KAutoObject::Create(std::addressof(deactivate_event));
69 deactivate_event = Kernel::KEvent::Create(kernel, "IUser:DeactivateEvent"); 68 Kernel::KAutoObject::Create(std::addressof(availability_change_event));
70 deactivate_event->Initialize(); 69
71 availability_change_event = Kernel::KEvent::Create(kernel, "IUser:AvailabilityChangeEvent"); 70 deactivate_event.Initialize("IUser:DeactivateEvent");
72 availability_change_event->Initialize(); 71 availability_change_event.Initialize("IUser:AvailabilityChangeEvent");
73 } 72 }
74 73
75private: 74private:
@@ -167,7 +166,7 @@ private:
167 166
168 IPC::ResponseBuilder rb{ctx, 2, 1}; 167 IPC::ResponseBuilder rb{ctx, 2, 1};
169 rb.Push(RESULT_SUCCESS); 168 rb.Push(RESULT_SUCCESS);
170 rb.PushCopyObjects(deactivate_event->GetReadableEvent()); 169 rb.PushCopyObjects(deactivate_event.GetReadableEvent());
171 } 170 }
172 171
173 void StopDetection(Kernel::HLERequestContext& ctx) { 172 void StopDetection(Kernel::HLERequestContext& ctx) {
@@ -176,7 +175,7 @@ private:
176 switch (device_state) { 175 switch (device_state) {
177 case DeviceState::TagFound: 176 case DeviceState::TagFound:
178 case DeviceState::TagNearby: 177 case DeviceState::TagNearby:
179 deactivate_event->GetWritableEvent()->Signal(); 178 deactivate_event.GetWritableEvent().Signal();
180 device_state = DeviceState::Initialized; 179 device_state = DeviceState::Initialized;
181 break; 180 break;
182 case DeviceState::SearchingForTag: 181 case DeviceState::SearchingForTag:
@@ -265,7 +264,7 @@ private:
265 264
266 IPC::ResponseBuilder rb{ctx, 2, 1}; 265 IPC::ResponseBuilder rb{ctx, 2, 1};
267 rb.Push(RESULT_SUCCESS); 266 rb.Push(RESULT_SUCCESS);
268 rb.PushCopyObjects(availability_change_event->GetReadableEvent()); 267 rb.PushCopyObjects(availability_change_event.GetReadableEvent());
269 } 268 }
270 269
271 void GetRegisterInfo(Kernel::HLERequestContext& ctx) { 270 void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -319,9 +318,9 @@ private:
319 const u32 npad_id{0}; // Player 1 controller 318 const u32 npad_id{0}; // Player 1 controller
320 State state{State::NonInitialized}; 319 State state{State::NonInitialized};
321 DeviceState device_state{DeviceState::Initialized}; 320 DeviceState device_state{DeviceState::Initialized};
322 std::shared_ptr<Kernel::KEvent> deactivate_event; 321 Module::Interface& nfp_interface;
323 std::shared_ptr<Kernel::KEvent> availability_change_event; 322 Kernel::KEvent deactivate_event;
324 const Module::Interface& nfp_interface; 323 Kernel::KEvent availability_change_event;
325}; 324};
326 325
327void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 326void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
@@ -339,12 +338,12 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
339 } 338 }
340 339
341 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 340 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
342 nfc_tag_load->GetWritableEvent()->Signal(); 341 nfc_tag_load.GetWritableEvent().Signal();
343 return true; 342 return true;
344} 343}
345 344
346const std::shared_ptr<Kernel::KReadableEvent>& Module::Interface::GetNFCEvent() const { 345Kernel::KReadableEvent& Module::Interface::GetNFCEvent() {
347 return nfc_tag_load->GetReadableEvent(); 346 return nfc_tag_load.GetReadableEvent();
348} 347}
349 348
350const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { 349const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index c46551760..5e4e49bc6 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <vector> 8#include <vector>
9 9
10#include "core/hle/kernel/k_event.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11 12
12namespace Kernel { 13namespace Kernel {
@@ -38,11 +39,11 @@ public:
38 39
39 void CreateUserInterface(Kernel::HLERequestContext& ctx); 40 void CreateUserInterface(Kernel::HLERequestContext& ctx);
40 bool LoadAmiibo(const std::vector<u8>& buffer); 41 bool LoadAmiibo(const std::vector<u8>& buffer);
41 const std::shared_ptr<Kernel::KReadableEvent>& GetNFCEvent() const; 42 Kernel::KReadableEvent& GetNFCEvent();
42 const AmiiboFile& GetAmiiboBuffer() const; 43 const AmiiboFile& GetAmiiboBuffer() const;
43 44
44 private: 45 private:
45 std::shared_ptr<Kernel::KEvent> nfc_tag_load; 46 Kernel::KEvent nfc_tag_load;
46 AmiiboFile amiibo{}; 47 AmiiboFile amiibo{};
47 48
48 protected: 49 protected:
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 9f110df8e..76e3832df 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -127,7 +127,8 @@ public:
127 127
128class IRequest final : public ServiceFramework<IRequest> { 128class IRequest final : public ServiceFramework<IRequest> {
129public: 129public:
130 explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} { 130 explicit IRequest(Core::System& system_)
131 : ServiceFramework{system_, "IRequest"}, event1{system.Kernel()}, event2{system.Kernel()} {
131 static const FunctionInfo functions[] = { 132 static const FunctionInfo functions[] = {
132 {0, &IRequest::GetRequestState, "GetRequestState"}, 133 {0, &IRequest::GetRequestState, "GetRequestState"},
133 {1, &IRequest::GetResult, "GetResult"}, 134 {1, &IRequest::GetResult, "GetResult"},
@@ -157,12 +158,11 @@ public:
157 }; 158 };
158 RegisterHandlers(functions); 159 RegisterHandlers(functions);
159 160
160 auto& kernel = system.Kernel(); 161 Kernel::KAutoObject::Create(std::addressof(event1));
162 Kernel::KAutoObject::Create(std::addressof(event2));
161 163
162 event1 = Kernel::KEvent::Create(kernel, "IRequest:Event1"); 164 event1.Initialize("IRequest:Event1");
163 event1->Initialize(); 165 event2.Initialize("IRequest:Event2");
164 event2 = Kernel::KEvent::Create(kernel, "IRequest:Event2");
165 event2->Initialize();
166 } 166 }
167 167
168private: 168private:
@@ -198,7 +198,7 @@ private:
198 198
199 IPC::ResponseBuilder rb{ctx, 2, 2}; 199 IPC::ResponseBuilder rb{ctx, 2, 2};
200 rb.Push(RESULT_SUCCESS); 200 rb.Push(RESULT_SUCCESS);
201 rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent()); 201 rb.PushCopyObjects(event1.GetReadableEvent(), event2.GetReadableEvent());
202 } 202 }
203 203
204 void Cancel(Kernel::HLERequestContext& ctx) { 204 void Cancel(Kernel::HLERequestContext& ctx) {
@@ -229,7 +229,7 @@ private:
229 rb.Push<u32>(0); 229 rb.Push<u32>(0);
230 } 230 }
231 231
232 std::shared_ptr<Kernel::KEvent> event1, event2; 232 Kernel::KEvent event1, event2;
233}; 233};
234 234
235class INetworkProfile final : public ServiceFramework<INetworkProfile> { 235class INetworkProfile final : public ServiceFramework<INetworkProfile> {
@@ -368,7 +368,7 @@ private:
368 }, 368 },
369 }; 369 };
370 370
371 IPC::ResponseBuilder rb{ctx, 2 + sizeof(IpConfigInfo) / sizeof(u32)}; 371 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
372 rb.Push(RESULT_SUCCESS); 372 rb.Push(RESULT_SUCCESS);
373 rb.PushRaw<IpConfigInfo>(ip_config_info); 373 rb.PushRaw<IpConfigInfo>(ip_config_info);
374 } 374 }
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index fee360ab9..420a5a075 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -300,7 +300,8 @@ class IEnsureNetworkClockAvailabilityService final
300 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { 300 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
301public: 301public:
302 explicit IEnsureNetworkClockAvailabilityService(Core::System& system_) 302 explicit IEnsureNetworkClockAvailabilityService(Core::System& system_)
303 : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"} { 303 : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"},
304 finished_event{system.Kernel()} {
304 static const FunctionInfo functions[] = { 305 static const FunctionInfo functions[] = {
305 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, 306 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
306 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, 307 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
@@ -312,19 +313,17 @@ public:
312 }; 313 };
313 RegisterHandlers(functions); 314 RegisterHandlers(functions);
314 315
315 auto& kernel = system.Kernel(); 316 Kernel::KAutoObject::Create(std::addressof(finished_event));
316 finished_event = 317 finished_event.Initialize("IEnsureNetworkClockAvailabilityService:FinishEvent");
317 Kernel::KEvent::Create(kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent");
318 finished_event->Initialize();
319 } 318 }
320 319
321private: 320private:
322 std::shared_ptr<Kernel::KEvent> finished_event; 321 Kernel::KEvent finished_event;
323 322
324 void StartTask(Kernel::HLERequestContext& ctx) { 323 void StartTask(Kernel::HLERequestContext& ctx) {
325 // No need to connect to the internet, just finish the task straight away. 324 // No need to connect to the internet, just finish the task straight away.
326 LOG_DEBUG(Service_NIM, "called"); 325 LOG_DEBUG(Service_NIM, "called");
327 finished_event->GetWritableEvent()->Signal(); 326 finished_event.GetWritableEvent().Signal();
328 IPC::ResponseBuilder rb{ctx, 2}; 327 IPC::ResponseBuilder rb{ctx, 2};
329 rb.Push(RESULT_SUCCESS); 328 rb.Push(RESULT_SUCCESS);
330 } 329 }
@@ -334,7 +333,7 @@ private:
334 333
335 IPC::ResponseBuilder rb{ctx, 2, 1}; 334 IPC::ResponseBuilder rb{ctx, 2, 1};
336 rb.Push(RESULT_SUCCESS); 335 rb.Push(RESULT_SUCCESS);
337 rb.PushCopyObjects(finished_event->GetReadableEvent()); 336 rb.PushCopyObjects(finished_event.GetReadableEvent());
338 } 337 }
339 338
340 void GetResult(Kernel::HLERequestContext& ctx) { 339 void GetResult(Kernel::HLERequestContext& ctx) {
@@ -346,7 +345,7 @@ private:
346 345
347 void Cancel(Kernel::HLERequestContext& ctx) { 346 void Cancel(Kernel::HLERequestContext& ctx) {
348 LOG_DEBUG(Service_NIM, "called"); 347 LOG_DEBUG(Service_NIM, "called");
349 finished_event->GetWritableEvent()->Clear(); 348 finished_event.GetWritableEvent().Clear();
350 IPC::ResponseBuilder rb{ctx, 2}; 349 IPC::ResponseBuilder rb{ctx, 2};
351 rb.Push(RESULT_SUCCESS); 350 rb.Push(RESULT_SUCCESS);
352 } 351 }
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index da139fdc4..e14acce58 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -130,9 +130,6 @@ struct PL_U::Impl {
130 } 130 }
131 } 131 }
132 132
133 /// Handle to shared memory region designated for a shared font
134 std::shared_ptr<Kernel::KSharedMemory> shared_font_mem;
135
136 /// Backing memory for the shared font data 133 /// Backing memory for the shared font data
137 std::shared_ptr<Kernel::PhysicalMemory> shared_font; 134 std::shared_ptr<Kernel::PhysicalMemory> shared_font;
138 135
@@ -260,14 +257,13 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
260 257
261 // Create shared font memory object 258 // Create shared font memory object
262 auto& kernel = system.Kernel(); 259 auto& kernel = system.Kernel();
263 impl->shared_font_mem = SharedFrom(&kernel.GetFontSharedMem());
264 260
265 std::memcpy(impl->shared_font_mem->GetPointer(), impl->shared_font->data(), 261 std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
266 impl->shared_font->size()); 262 impl->shared_font->size());
267 263
268 IPC::ResponseBuilder rb{ctx, 2, 1}; 264 IPC::ResponseBuilder rb{ctx, 2, 1};
269 rb.Push(RESULT_SUCCESS); 265 rb.Push(RESULT_SUCCESS);
270 rb.PushCopyObjects(impl->shared_font_mem); 266 rb.PushCopyObjects(&kernel.GetFontSharedMem());
271} 267}
272 268
273void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { 269void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index b37f023df..5b73a5a34 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -21,7 +21,7 @@ namespace Service::Nvidia::Devices {
21/// implement the ioctl interface. 21/// implement the ioctl interface.
22class nvdevice { 22class nvdevice {
23public: 23public:
24 explicit nvdevice(Core::System& system) : system{system} {} 24 explicit nvdevice(Core::System& system_) : system{system_} {}
25 virtual ~nvdevice() = default; 25 virtual ~nvdevice() = default;
26 26
27 /** 27 /**
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 229bf6350..24e3151cb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -48,13 +48,13 @@ private:
48 public: 48 public:
49 constexpr BufferMap() = default; 49 constexpr BufferMap() = default;
50 50
51 constexpr BufferMap(GPUVAddr start_addr, std::size_t size) 51 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
52 : start_addr{start_addr}, end_addr{start_addr + size} {} 52 : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
53 53
54 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr, 54 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
55 bool is_allocated) 55 bool is_allocated_)
56 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr}, 56 : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
57 is_allocated{is_allocated} {} 57 is_allocated{is_allocated_} {}
58 58
59 constexpr VAddr StartAddr() const { 59 constexpr VAddr StartAddr() const {
60 return start_addr; 60 return start_addr;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 6f4007294..775e76330 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -102,20 +102,20 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
102 return NvResult::Success; 102 return NvResult::Success;
103 } 103 }
104 104
105 auto event = events_interface.events[event_id]; 105 auto& event = events_interface.events[event_id];
106 auto& gpu = system.GPU(); 106 auto& gpu = system.GPU();
107 107
108 // This is mostly to take into account unimplemented features. As synced 108 // This is mostly to take into account unimplemented features. As synced
109 // gpu is always synced. 109 // gpu is always synced.
110 if (!gpu.IsAsync()) { 110 if (!gpu.IsAsync()) {
111 event.event->GetWritableEvent()->Signal(); 111 event.event->GetWritableEvent().Signal();
112 return NvResult::Success; 112 return NvResult::Success;
113 } 113 }
114 auto lock = gpu.LockSync(); 114 auto lock = gpu.LockSync();
115 const u32 current_syncpoint_value = event.fence.value; 115 const u32 current_syncpoint_value = event.fence.value;
116 const s32 diff = current_syncpoint_value - params.threshold; 116 const s32 diff = current_syncpoint_value - params.threshold;
117 if (diff >= 0) { 117 if (diff >= 0) {
118 event.event->GetWritableEvent()->Signal(); 118 event.event->GetWritableEvent().Signal();
119 params.value = current_syncpoint_value; 119 params.value = current_syncpoint_value;
120 std::memcpy(output.data(), &params, sizeof(params)); 120 std::memcpy(output.data(), &params, sizeof(params));
121 return NvResult::Success; 121 return NvResult::Success;
@@ -142,7 +142,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
142 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; 142 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
143 } 143 }
144 params.value |= event_id; 144 params.value |= event_id;
145 event.event->GetWritableEvent()->Clear(); 145 event.event->GetWritableEvent().Clear();
146 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); 146 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
147 std::memcpy(output.data(), &params, sizeof(params)); 147 std::memcpy(output.data(), &params, sizeof(params));
148 return NvResult::Timeout; 148 return NvResult::Timeout;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index 14d0d210a..da10f5f41 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -27,13 +27,13 @@ protected:
27 public: 27 public:
28 constexpr BufferMap() = default; 28 constexpr BufferMap() = default;
29 29
30 constexpr BufferMap(GPUVAddr start_addr, std::size_t size) 30 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
31 : start_addr{start_addr}, end_addr{start_addr + size} {} 31 : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
32 32
33 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr, 33 constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
34 bool is_allocated) 34 bool is_allocated_)
35 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr}, 35 : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
36 is_allocated{is_allocated} {} 36 is_allocated{is_allocated_} {}
37 37
38 constexpr VAddr StartAddr() const { 38 constexpr VAddr StartAddr() const {
39 return start_addr; 39 return start_addr;
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index eff9c3cc9..dc9b9341f 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -187,8 +187,8 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
187 if (event_id < MaxNvEvents) { 187 if (event_id < MaxNvEvents) {
188 IPC::ResponseBuilder rb{ctx, 3, 1}; 188 IPC::ResponseBuilder rb{ctx, 3, 1};
189 rb.Push(RESULT_SUCCESS); 189 rb.Push(RESULT_SUCCESS);
190 auto event = nvdrv->GetEvent(event_id); 190 auto& event = nvdrv->GetEvent(event_id);
191 event->Clear(); 191 event.Clear();
192 rb.PushCopyObjects(event); 192 rb.PushCopyObjects(event);
193 rb.PushEnum(NvResult::Success); 193 rb.PushEnum(NvResult::Success);
194 } else { 194 } else {
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index ede77858a..74796dce1 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -42,9 +42,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
42Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { 42Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
43 auto& kernel = system.Kernel(); 43 auto& kernel = system.Kernel();
44 for (u32 i = 0; i < MaxNvEvents; i++) { 44 for (u32 i = 0; i < MaxNvEvents; i++) {
45 std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); 45 events_interface.events[i].event = Kernel::KEvent::Create(kernel);
46 events_interface.events[i] = {Kernel::KEvent::Create(kernel, std::move(event_label))}; 46 events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i));
47 events_interface.events[i].event->Initialize();
48 events_interface.status[i] = EventState::Free; 47 events_interface.status[i] = EventState::Free;
49 events_interface.registered[i] = false; 48 events_interface.registered[i] = false;
50 } 49 }
@@ -64,7 +63,12 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
64 std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, syncpoint_manager); 63 std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, syncpoint_manager);
65} 64}
66 65
67Module::~Module() = default; 66Module::~Module() {
67 for (u32 i = 0; i < MaxNvEvents; i++) {
68 events_interface.events[i].event->Close();
69 events_interface.events[i].event = nullptr;
70 }
71}
68 72
69NvResult Module::VerifyFD(DeviceFD fd) const { 73NvResult Module::VerifyFD(DeviceFD fd) const {
70 if (fd < 0) { 74 if (fd < 0) {
@@ -172,16 +176,16 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
172 if (events_interface.assigned_syncpt[i] == syncpoint_id && 176 if (events_interface.assigned_syncpt[i] == syncpoint_id &&
173 events_interface.assigned_value[i] == value) { 177 events_interface.assigned_value[i] == value) {
174 events_interface.LiberateEvent(i); 178 events_interface.LiberateEvent(i);
175 events_interface.events[i].event->GetWritableEvent()->Signal(); 179 events_interface.events[i].event->GetWritableEvent().Signal();
176 } 180 }
177 } 181 }
178} 182}
179 183
180std::shared_ptr<Kernel::KReadableEvent> Module::GetEvent(const u32 event_id) const { 184Kernel::KReadableEvent& Module::GetEvent(const u32 event_id) {
181 return events_interface.events[event_id].event->GetReadableEvent(); 185 return events_interface.events[event_id].event->GetReadableEvent();
182} 186}
183 187
184std::shared_ptr<Kernel::KWritableEvent> Module::GetEventWriteable(const u32 event_id) const { 188Kernel::KWritableEvent& Module::GetEventWriteable(const u32 event_id) {
185 return events_interface.events[event_id].event->GetWritableEvent(); 189 return events_interface.events[event_id].event->GetWritableEvent();
186} 190}
187 191
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 53719aadd..a43ceb7ae 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -35,7 +35,7 @@ class nvdevice;
35 35
36/// Represents an Nvidia event 36/// Represents an Nvidia event
37struct NvEvent { 37struct NvEvent {
38 std::shared_ptr<Kernel::KEvent> event; 38 Kernel::KEvent* event{};
39 Fence fence{}; 39 Fence fence{};
40}; 40};
41 41
@@ -136,9 +136,9 @@ public:
136 136
137 void SignalSyncpt(const u32 syncpoint_id, const u32 value); 137 void SignalSyncpt(const u32 syncpoint_id, const u32 value);
138 138
139 std::shared_ptr<Kernel::KReadableEvent> GetEvent(u32 event_id) const; 139 Kernel::KReadableEvent& GetEvent(u32 event_id);
140 140
141 std::shared_ptr<Kernel::KWritableEvent> GetEventWriteable(u32 event_id) const; 141 Kernel::KWritableEvent& GetEventWriteable(u32 event_id);
142 142
143private: 143private:
144 /// Manages syncpoints on the host 144 /// Manages syncpoints on the host
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp
index 0151a03b7..3b6f55526 100644
--- a/src/core/hle/service/nvdrv/syncpoint_manager.cpp
+++ b/src/core/hle/service/nvdrv/syncpoint_manager.cpp
@@ -8,7 +8,7 @@
8 8
9namespace Service::Nvidia { 9namespace Service::Nvidia {
10 10
11SyncpointManager::SyncpointManager(Tegra::GPU& gpu) : gpu{gpu} {} 11SyncpointManager::SyncpointManager(Tegra::GPU& gpu_) : gpu{gpu_} {}
12 12
13SyncpointManager::~SyncpointManager() = default; 13SyncpointManager::~SyncpointManager() = default;
14 14
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h
index d395c5d0b..99f286474 100644
--- a/src/core/hle/service/nvdrv/syncpoint_manager.h
+++ b/src/core/hle/service/nvdrv/syncpoint_manager.h
@@ -18,7 +18,7 @@ namespace Service::Nvidia {
18 18
19class SyncpointManager final { 19class SyncpointManager final {
20public: 20public:
21 explicit SyncpointManager(Tegra::GPU& gpu); 21 explicit SyncpointManager(Tegra::GPU& gpu_);
22 ~SyncpointManager(); 22 ~SyncpointManager();
23 23
24 /** 24 /**
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 7842a82ed..59ddf6298 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -7,17 +7,16 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/k_event.h"
11#include "core/hle/kernel/k_writable_event.h" 10#include "core/hle/kernel/k_writable_event.h"
12#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
13#include "core/hle/service/nvflinger/buffer_queue.h" 12#include "core/hle/service/nvflinger/buffer_queue.h"
14 13
15namespace Service::NVFlinger { 14namespace Service::NVFlinger {
16 15
17BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id) 16BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_)
18 : id(id), layer_id(layer_id) { 17 : id(id_), layer_id(layer_id_), buffer_wait_event{kernel} {
19 buffer_wait_event = Kernel::KEvent::Create(kernel, "BufferQueue:WaitEvent"); 18 Kernel::KAutoObject::Create(std::addressof(buffer_wait_event));
20 buffer_wait_event->Initialize(); 19 buffer_wait_event.Initialize("BufferQueue:WaitEvent");
21} 20}
22 21
23BufferQueue::~BufferQueue() = default; 22BufferQueue::~BufferQueue() = default;
@@ -42,7 +41,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
42 .multi_fence = {}, 41 .multi_fence = {},
43 }; 42 };
44 43
45 buffer_wait_event->GetWritableEvent()->Signal(); 44 buffer_wait_event.GetWritableEvent().Signal();
46} 45}
47 46
48std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, 47std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
@@ -120,7 +119,7 @@ void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& mult
120 } 119 }
121 free_buffers_condition.notify_one(); 120 free_buffers_condition.notify_one();
122 121
123 buffer_wait_event->GetWritableEvent()->Signal(); 122 buffer_wait_event.GetWritableEvent().Signal();
124} 123}
125 124
126std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { 125std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
@@ -155,7 +154,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
155 } 154 }
156 free_buffers_condition.notify_one(); 155 free_buffers_condition.notify_one();
157 156
158 buffer_wait_event->GetWritableEvent()->Signal(); 157 buffer_wait_event.GetWritableEvent().Signal();
159} 158}
160 159
161void BufferQueue::Connect() { 160void BufferQueue::Connect() {
@@ -170,7 +169,7 @@ void BufferQueue::Disconnect() {
170 std::unique_lock lock{queue_sequence_mutex}; 169 std::unique_lock lock{queue_sequence_mutex};
171 queue_sequence.clear(); 170 queue_sequence.clear();
172 } 171 }
173 buffer_wait_event->GetWritableEvent()->Signal(); 172 buffer_wait_event.GetWritableEvent().Signal();
174 is_connect = false; 173 is_connect = false;
175 free_buffers_condition.notify_one(); 174 free_buffers_condition.notify_one();
176} 175}
@@ -189,12 +188,12 @@ u32 BufferQueue::Query(QueryType type) {
189 return 0; 188 return 0;
190} 189}
191 190
192std::shared_ptr<Kernel::KWritableEvent> BufferQueue::GetWritableBufferWaitEvent() const { 191Kernel::KWritableEvent& BufferQueue::GetWritableBufferWaitEvent() {
193 return buffer_wait_event->GetWritableEvent(); 192 return buffer_wait_event.GetWritableEvent();
194} 193}
195 194
196std::shared_ptr<Kernel::KReadableEvent> BufferQueue::GetBufferWaitEvent() const { 195Kernel::KReadableEvent& BufferQueue::GetBufferWaitEvent() {
197 return buffer_wait_event->GetReadableEvent(); 196 return buffer_wait_event.GetReadableEvent();
198} 197}
199 198
200} // namespace Service::NVFlinger 199} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 163fa4c54..61e337ac5 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -13,7 +13,8 @@
13#include "common/common_funcs.h" 13#include "common/common_funcs.h"
14#include "common/math_util.h" 14#include "common/math_util.h"
15#include "common/swap.h" 15#include "common/swap.h"
16#include "core/hle/kernel/object.h" 16#include "core/hle/kernel/k_event.h"
17#include "core/hle/kernel/k_readable_event.h"
17#include "core/hle/service/nvdrv/nvdata.h" 18#include "core/hle/service/nvdrv/nvdata.h"
18 19
19namespace Kernel { 20namespace Kernel {
@@ -53,7 +54,7 @@ public:
53 NativeWindowFormat = 2, 54 NativeWindowFormat = 2,
54 }; 55 };
55 56
56 explicit BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id); 57 explicit BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_);
57 ~BufferQueue(); 58 ~BufferQueue();
58 59
59 enum class BufferTransformFlags : u32 { 60 enum class BufferTransformFlags : u32 {
@@ -115,9 +116,9 @@ public:
115 return is_connect; 116 return is_connect;
116 } 117 }
117 118
118 std::shared_ptr<Kernel::KWritableEvent> GetWritableBufferWaitEvent() const; 119 Kernel::KWritableEvent& GetWritableBufferWaitEvent();
119 120
120 std::shared_ptr<Kernel::KReadableEvent> GetBufferWaitEvent() const; 121 Kernel::KReadableEvent& GetBufferWaitEvent();
121 122
122private: 123private:
123 BufferQueue(const BufferQueue&) = delete; 124 BufferQueue(const BufferQueue&) = delete;
@@ -129,7 +130,7 @@ private:
129 std::list<u32> free_buffers; 130 std::list<u32> free_buffers;
130 std::array<Buffer, buffer_slots> buffers; 131 std::array<Buffer, buffer_slots> buffers;
131 std::list<u32> queue_sequence; 132 std::list<u32> queue_sequence;
132 std::shared_ptr<Kernel::KEvent> buffer_wait_event; 133 Kernel::KEvent buffer_wait_event;
133 134
134 std::mutex free_buffers_mutex; 135 std::mutex free_buffers_mutex;
135 std::condition_variable free_buffers_condition; 136 std::condition_variable free_buffers_condition;
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 810312dc4..d1dbc659b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -61,7 +61,7 @@ void NVFlinger::SplitVSync() {
61 } 61 }
62} 62}
63 63
64NVFlinger::NVFlinger(Core::System& system) : system(system) { 64NVFlinger::NVFlinger(Core::System& system_) : system(system_) {
65 displays.emplace_back(0, "Default", system); 65 displays.emplace_back(0, "Default", system);
66 displays.emplace_back(1, "External", system); 66 displays.emplace_back(1, "External", system);
67 displays.emplace_back(2, "Edid", system); 67 displays.emplace_back(2, "Edid", system);
@@ -169,7 +169,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
169 return layer->GetBufferQueue().GetId(); 169 return layer->GetBufferQueue().GetId();
170} 170}
171 171
172std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { 172Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
173 const auto lock_guard = Lock(); 173 const auto lock_guard = Lock();
174 auto* const display = FindDisplay(display_id); 174 auto* const display = FindDisplay(display_id);
175 175
@@ -177,7 +177,7 @@ std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id
177 return nullptr; 177 return nullptr;
178 } 178 }
179 179
180 return display->GetVSyncEvent(); 180 return &display->GetVSyncEvent();
181} 181}
182 182
183BufferQueue* NVFlinger::FindBufferQueue(u32 id) { 183BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index ebc82c688..d80fd07ef 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <atomic> 7#include <atomic>
8#include <list>
8#include <memory> 9#include <memory>
9#include <mutex> 10#include <mutex>
10#include <optional> 11#include <optional>
@@ -14,7 +15,6 @@
14#include <vector> 15#include <vector>
15 16
16#include "common/common_types.h" 17#include "common/common_types.h"
17#include "core/hle/kernel/object.h"
18 18
19namespace Common { 19namespace Common {
20class Event; 20class Event;
@@ -45,7 +45,7 @@ class BufferQueue;
45 45
46class NVFlinger final { 46class NVFlinger final {
47public: 47public:
48 explicit NVFlinger(Core::System& system); 48 explicit NVFlinger(Core::System& system_);
49 ~NVFlinger(); 49 ~NVFlinger();
50 50
51 /// Sets the NVDrv module instance to use to send buffers to the GPU. 51 /// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -72,7 +72,7 @@ public:
72 /// Gets the vsync event for the specified display. 72 /// Gets the vsync event for the specified display.
73 /// 73 ///
74 /// If an invalid display ID is provided, then nullptr is returned. 74 /// If an invalid display ID is provided, then nullptr is returned.
75 [[nodiscard]] std::shared_ptr<Kernel::KReadableEvent> FindVsyncEvent(u64 display_id) const; 75 [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
76 76
77 /// Obtains a buffer queue identified by the ID. 77 /// Obtains a buffer queue identified by the ID.
78 [[nodiscard]] BufferQueue* FindBufferQueue(u32 id); 78 [[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
@@ -114,7 +114,7 @@ private:
114 114
115 std::shared_ptr<Nvidia::Module> nvdrv; 115 std::shared_ptr<Nvidia::Module> nvdrv;
116 116
117 std::vector<VI::Display> displays; 117 std::list<VI::Display> displays;
118 std::vector<std::unique_ptr<BufferQueue>> buffer_queues; 118 std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
119 119
120 /// Id to use for the next layer that is created, this counter is shared among all displays. 120 /// Id to use for the next layer that is created, this counter is shared among all displays.
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index 9bebe6088..1c3d81143 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -7,7 +7,7 @@
7#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h" 8#include "core/file_sys/patch_manager.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/process.h" 10#include "core/hle/kernel/k_process.h"
11#include "core/hle/service/pctl/module.h" 11#include "core/hle/service/pctl/module.h"
12#include "core/hle/service/pctl/pctl.h" 12#include "core/hle/service/pctl/pctl.h"
13 13
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index e4d155c86..908e0a1e3 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -7,8 +7,8 @@
7namespace Service::PCTL { 7namespace Service::PCTL {
8 8
9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
10 Capability capability) 10 Capability capability_)
11 : Interface{system_, std::move(module_), name, capability} { 11 : Interface{system_, std::move(module_), name, capability_} {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &PCTL::CreateService, "CreateService"}, 13 {0, &PCTL::CreateService, "CreateService"},
14 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 14 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index fd0a1e486..ea3b97823 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -15,7 +15,7 @@ namespace Service::PCTL {
15class PCTL final : public Module::Interface { 15class PCTL final : public Module::Interface {
16public: 16public:
17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
18 Capability capability); 18 Capability capability_);
19 ~PCTL() override; 19 ~PCTL() override;
20}; 20};
21 21
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 68736c40c..a43185c44 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -4,8 +4,8 @@
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/process.h"
9#include "core/hle/service/pm/pm.h" 9#include "core/hle/service/pm/pm.h"
10#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
11 11
@@ -17,9 +17,9 @@ constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
17 17
18constexpr u64 NO_PROCESS_FOUND_PID{0}; 18constexpr u64 NO_PROCESS_FOUND_PID{0};
19 19
20std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList( 20std::optional<Kernel::KProcess*> SearchProcessList(
21 const std::vector<std::shared_ptr<Kernel::Process>>& process_list, 21 const std::vector<Kernel::KProcess*>& process_list,
22 std::function<bool(const std::shared_ptr<Kernel::Process>&)> predicate) { 22 std::function<bool(Kernel::KProcess*)> predicate) {
23 const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); 23 const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
24 24
25 if (iter == process_list.end()) { 25 if (iter == process_list.end()) {
@@ -30,9 +30,9 @@ std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList(
30} 30}
31 31
32void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx, 32void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
33 const std::vector<std::shared_ptr<Kernel::Process>>& process_list) { 33 const std::vector<Kernel::KProcess*>& process_list) {
34 const auto process = SearchProcessList(process_list, [](const auto& process) { 34 const auto process = SearchProcessList(process_list, [](const auto& proc) {
35 return process->GetProcessID() == Kernel::Process::ProcessIDMin; 35 return proc->GetProcessID() == Kernel::KProcess::ProcessIDMin;
36 }); 36 });
37 37
38 IPC::ResponseBuilder rb{ctx, 4}; 38 IPC::ResponseBuilder rb{ctx, 4};
@@ -100,8 +100,8 @@ private:
100 LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id); 100 LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
101 101
102 const auto process = 102 const auto process =
103 SearchProcessList(kernel.GetProcessList(), [title_id](const auto& process) { 103 SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) {
104 return process->GetTitleID() == title_id; 104 return proc->GetTitleID() == title_id;
105 }); 105 });
106 106
107 if (!process.has_value()) { 107 if (!process.has_value()) {
@@ -125,8 +125,7 @@ private:
125 125
126class Info final : public ServiceFramework<Info> { 126class Info final : public ServiceFramework<Info> {
127public: 127public:
128 explicit Info(Core::System& system_, 128 explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_)
129 const std::vector<std::shared_ptr<Kernel::Process>>& process_list_)
130 : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { 129 : ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
131 static const FunctionInfo functions[] = { 130 static const FunctionInfo functions[] = {
132 {0, &Info::GetTitleId, "GetTitleId"}, 131 {0, &Info::GetTitleId, "GetTitleId"},
@@ -141,8 +140,8 @@ private:
141 140
142 LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); 141 LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
143 142
144 const auto process = SearchProcessList(process_list, [process_id](const auto& process) { 143 const auto process = SearchProcessList(process_list, [process_id](const auto& proc) {
145 return process->GetProcessID() == process_id; 144 return proc->GetProcessID() == process_id;
146 }); 145 });
147 146
148 if (!process.has_value()) { 147 if (!process.has_value()) {
@@ -156,7 +155,7 @@ private:
156 rb.Push((*process)->GetTitleID()); 155 rb.Push((*process)->GetTitleID());
157 } 156 }
158 157
159 const std::vector<std::shared_ptr<Kernel::Process>>& process_list; 158 const std::vector<Kernel::KProcess*>& process_list;
160}; 159};
161 160
162class Shell final : public ServiceFramework<Shell> { 161class Shell final : public ServiceFramework<Shell> {
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index d5b3b17a5..c914f8145 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -6,7 +6,7 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/k_process.h"
10#include "core/hle/service/acc/profile_manager.h" 10#include "core/hle/service/acc/profile_manager.h"
11#include "core/hle/service/prepo/prepo.h" 11#include "core/hle/service/prepo/prepo.h"
12#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
@@ -60,7 +60,7 @@ private:
60 const auto process_id = rp.PopRaw<u64>(); 60 const auto process_id = rp.PopRaw<u64>();
61 61
62 const auto data1 = ctx.ReadBuffer(0); 62 const auto data1 = ctx.ReadBuffer(0);
63 const auto data2 = [ctx] { 63 const auto data2 = [&ctx] {
64 if (ctx.CanReadBuffer(1)) { 64 if (ctx.CanReadBuffer(1)) {
65 return ctx.ReadBuffer(1); 65 return ctx.ReadBuffer(1);
66 } 66 }
@@ -87,7 +87,7 @@ private:
87 const auto process_id = rp.PopRaw<u64>(); 87 const auto process_id = rp.PopRaw<u64>();
88 88
89 const auto data1 = ctx.ReadBuffer(0); 89 const auto data1 = ctx.ReadBuffer(0);
90 const auto data2 = [ctx] { 90 const auto data2 = [&ctx] {
91 if (ctx.CanReadBuffer(1)) { 91 if (ctx.CanReadBuffer(1)) {
92 return ctx.ReadBuffer(1); 92 return ctx.ReadBuffer(1);
93 } 93 }
@@ -139,7 +139,7 @@ private:
139 const auto title_id = rp.PopRaw<u64>(); 139 const auto title_id = rp.PopRaw<u64>();
140 140
141 const auto data1 = ctx.ReadBuffer(0); 141 const auto data1 = ctx.ReadBuffer(0);
142 const auto data2 = [ctx] { 142 const auto data2 = [&ctx] {
143 if (ctx.CanReadBuffer(1)) { 143 if (ctx.CanReadBuffer(1)) {
144 return ctx.ReadBuffer(1); 144 return ctx.ReadBuffer(1);
145 } 145 }
@@ -163,7 +163,7 @@ private:
163 const auto title_id = rp.PopRaw<u64>(); 163 const auto title_id = rp.PopRaw<u64>();
164 164
165 const auto data1 = ctx.ReadBuffer(0); 165 const auto data1 = ctx.ReadBuffer(0);
166 const auto data2 = [ctx] { 166 const auto data2 = [&ctx] {
167 if (ctx.CanReadBuffer(1)) { 167 if (ctx.CanReadBuffer(1)) {
168 return ctx.ReadBuffer(1); 168 return ctx.ReadBuffer(1);
169 } 169 }
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 26ed52273..bb7af9217 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -19,7 +19,8 @@ namespace Service::PSM {
19 19
20class IPsmSession final : public ServiceFramework<IPsmSession> { 20class IPsmSession final : public ServiceFramework<IPsmSession> {
21public: 21public:
22 explicit IPsmSession(Core::System& system_) : ServiceFramework{system_, "IPsmSession"} { 22 explicit IPsmSession(Core::System& system_)
23 : ServiceFramework{system_, "IPsmSession"}, state_change_event{system.Kernel()} {
23 // clang-format off 24 // clang-format off
24 static const FunctionInfo functions[] = { 25 static const FunctionInfo functions[] = {
25 {0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"}, 26 {0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"},
@@ -32,28 +33,27 @@ public:
32 33
33 RegisterHandlers(functions); 34 RegisterHandlers(functions);
34 35
35 state_change_event = 36 Kernel::KAutoObject::Create(std::addressof(state_change_event));
36 Kernel::KEvent::Create(system_.Kernel(), "IPsmSession::state_change_event"); 37 state_change_event.Initialize("IPsmSession::state_change_event");
37 state_change_event->Initialize();
38 } 38 }
39 39
40 ~IPsmSession() override = default; 40 ~IPsmSession() override = default;
41 41
42 void SignalChargerTypeChanged() { 42 void SignalChargerTypeChanged() {
43 if (should_signal && should_signal_charger_type) { 43 if (should_signal && should_signal_charger_type) {
44 state_change_event->GetWritableEvent()->Signal(); 44 state_change_event.GetWritableEvent().Signal();
45 } 45 }
46 } 46 }
47 47
48 void SignalPowerSupplyChanged() { 48 void SignalPowerSupplyChanged() {
49 if (should_signal && should_signal_power_supply) { 49 if (should_signal && should_signal_power_supply) {
50 state_change_event->GetWritableEvent()->Signal(); 50 state_change_event.GetWritableEvent().Signal();
51 } 51 }
52 } 52 }
53 53
54 void SignalBatteryVoltageStateChanged() { 54 void SignalBatteryVoltageStateChanged() {
55 if (should_signal && should_signal_battery_voltage) { 55 if (should_signal && should_signal_battery_voltage) {
56 state_change_event->GetWritableEvent()->Signal(); 56 state_change_event.GetWritableEvent().Signal();
57 } 57 }
58 } 58 }
59 59
@@ -65,7 +65,7 @@ private:
65 65
66 IPC::ResponseBuilder rb{ctx, 2, 1}; 66 IPC::ResponseBuilder rb{ctx, 2, 1};
67 rb.Push(RESULT_SUCCESS); 67 rb.Push(RESULT_SUCCESS);
68 rb.PushCopyObjects(state_change_event->GetReadableEvent()); 68 rb.PushCopyObjects(state_change_event.GetReadableEvent());
69 } 69 }
70 70
71 void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) { 71 void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
@@ -114,7 +114,7 @@ private:
114 bool should_signal_power_supply{}; 114 bool should_signal_power_supply{};
115 bool should_signal_battery_voltage{}; 115 bool should_signal_battery_voltage{};
116 bool should_signal{}; 116 bool should_signal{};
117 std::shared_ptr<Kernel::KEvent> state_change_event; 117 Kernel::KEvent state_change_event;
118}; 118};
119 119
120class PSM final : public ServiceFramework<PSM> { 120class PSM final : public ServiceFramework<PSM> {
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 41a502d8d..2c9b2ce6d 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -11,11 +11,11 @@
11#include "core/core.h" 11#include "core/core.h"
12#include "core/hle/ipc.h" 12#include "core/hle/ipc.h"
13#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/client_port.h" 14#include "core/hle/kernel/k_client_port.h"
15#include "core/hle/kernel/k_process.h"
16#include "core/hle/kernel/k_server_port.h"
15#include "core/hle/kernel/k_thread.h" 17#include "core/hle/kernel/k_thread.h"
16#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/server_port.h"
19#include "core/hle/service/acc/acc.h" 19#include "core/hle/service/acc/acc.h"
20#include "core/hle/service/am/am.h" 20#include "core/hle/service/am/am.h"
21#include "core/hle/service/aoc/aoc_u.h" 21#include "core/hle/service/aoc/aoc_u.h"
@@ -111,16 +111,18 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
111 port_installed = true; 111 port_installed = true;
112} 112}
113 113
114void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { 114Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
115 const auto guard = LockService(); 115 const auto guard = LockService();
116 116
117 ASSERT(!port_installed); 117 ASSERT(!port_installed);
118 118
119 auto [server_port, client_port] = 119 auto* port = Kernel::KPort::Create(kernel);
120 Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); 120 port->Initialize(max_sessions, false, service_name);
121 server_port->SetHleHandler(shared_from_this()); 121 port->GetServerPort().SetHleHandler(shared_from_this());
122 kernel.AddNamedPort(service_name, std::move(client_port)); 122
123 port_installed = true; 123 port_installed = true;
124
125 return port->GetClientPort();
124} 126}
125 127
126void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { 128void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
@@ -131,6 +133,16 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function
131 } 133 }
132} 134}
133 135
136void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions,
137 std::size_t n) {
138 handlers_tipc.reserve(handlers_tipc.size() + n);
139 for (std::size_t i = 0; i < n; ++i) {
140 // Usually this array is sorted by id already, so hint to insert at the end
141 handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
142 functions[i]);
143 }
144}
145
134void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, 146void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx,
135 const FunctionInfoBase* info) { 147 const FunctionInfoBase* info) {
136 auto cmd_buf = ctx.CommandBuffer(); 148 auto cmd_buf = ctx.CommandBuffer();
@@ -165,33 +177,55 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
165 handler_invoker(this, info->handler_callback, ctx); 177 handler_invoker(this, info->handler_callback, ctx);
166} 178}
167 179
168ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { 180void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) {
181 boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
182
183 itr = handlers_tipc.find(ctx.GetCommand());
184
185 const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second;
186 if (info == nullptr || info->handler_callback == nullptr) {
187 return ReportUnimplementedFunction(ctx, info);
188 }
189
190 LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
191 handler_invoker(this, info->handler_callback, ctx);
192}
193
194ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
195 Kernel::HLERequestContext& ctx) {
169 const auto guard = LockService(); 196 const auto guard = LockService();
170 197
171 switch (context.GetCommandType()) { 198 switch (ctx.GetCommandType()) {
172 case IPC::CommandType::Close: { 199 case IPC::CommandType::Close:
173 IPC::ResponseBuilder rb{context, 2}; 200 case IPC::CommandType::TIPC_Close: {
201 session.Close();
202 IPC::ResponseBuilder rb{ctx, 2};
174 rb.Push(RESULT_SUCCESS); 203 rb.Push(RESULT_SUCCESS);
175 return IPC::ERR_REMOTE_PROCESS_DEAD; 204 return IPC::ERR_REMOTE_PROCESS_DEAD;
176 } 205 }
177 case IPC::CommandType::ControlWithContext: 206 case IPC::CommandType::ControlWithContext:
178 case IPC::CommandType::Control: { 207 case IPC::CommandType::Control: {
179 system.ServiceManager().InvokeControlRequest(context); 208 system.ServiceManager().InvokeControlRequest(ctx);
180 break; 209 break;
181 } 210 }
182 case IPC::CommandType::RequestWithContext: 211 case IPC::CommandType::RequestWithContext:
183 case IPC::CommandType::Request: { 212 case IPC::CommandType::Request: {
184 InvokeRequest(context); 213 InvokeRequest(ctx);
185 break; 214 break;
186 } 215 }
187 default: 216 default:
188 UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType()); 217 if (ctx.IsTipc()) {
218 InvokeRequestTipc(ctx);
219 break;
220 }
221
222 UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
189 } 223 }
190 224
191 // If emulation was shutdown, we are closing service threads, do not write the response back to 225 // If emulation was shutdown, we are closing service threads, do not write the response back to
192 // memory that may be shutting down as well. 226 // memory that may be shutting down as well.
193 if (system.IsPoweredOn()) { 227 if (system.IsPoweredOn()) {
194 context.WriteToOutgoingCommandBuffer(context.GetThread()); 228 ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
195 } 229 }
196 230
197 return RESULT_SUCCESS; 231 return RESULT_SUCCESS;
@@ -206,7 +240,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
206 240
207 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); 241 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
208 242
209 SM::ServiceManager::InstallInterfaces(sm, system); 243 system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
210 244
211 Account::InstallInterfaces(system); 245 Account::InstallInterfaces(system);
212 AM::InstallInterfaces(*sm, *nv_flinger, system); 246 AM::InstallInterfaces(*sm, *nv_flinger, system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 916445517..4c048173b 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -11,7 +11,6 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/spin_lock.h" 12#include "common/spin_lock.h"
13#include "core/hle/kernel/hle_ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
14#include "core/hle/kernel/object.h"
15 14
16//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
17// Namespace Service 16// Namespace Service
@@ -21,10 +20,9 @@ class System;
21} 20}
22 21
23namespace Kernel { 22namespace Kernel {
24class ClientPort;
25class ServerPort;
26class ServerSession;
27class HLERequestContext; 23class HLERequestContext;
24class KClientPort;
25class KServerSession;
28} // namespace Kernel 26} // namespace Kernel
29 27
30namespace Service { 28namespace Service {
@@ -68,12 +66,19 @@ public:
68 66
69 /// Creates a port pair and registers this service with the given ServiceManager. 67 /// Creates a port pair and registers this service with the given ServiceManager.
70 void InstallAsService(SM::ServiceManager& service_manager); 68 void InstallAsService(SM::ServiceManager& service_manager);
71 /// Creates a port pair and registers it on the kernel's global port registry. 69
72 void InstallAsNamedPort(Kernel::KernelCore& kernel); 70 /// Invokes a service request routine using the HIPC protocol.
73 /// Invokes a service request routine.
74 void InvokeRequest(Kernel::HLERequestContext& ctx); 71 void InvokeRequest(Kernel::HLERequestContext& ctx);
72
73 /// Invokes a service request routine using the HIPC protocol.
74 void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
75
76 /// Creates a port pair and registers it on the kernel's global port registry.
77 Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
78
75 /// Handles a synchronization request for the service. 79 /// Handles a synchronization request for the service.
76 ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; 80 ResultCode HandleSyncRequest(Kernel::KServerSession& session,
81 Kernel::HLERequestContext& context) override;
77 82
78protected: 83protected:
79 /// Member-function pointer type of SyncRequest handlers. 84 /// Member-function pointer type of SyncRequest handlers.
@@ -106,6 +111,7 @@ private:
106 ~ServiceFrameworkBase() override; 111 ~ServiceFrameworkBase() override;
107 112
108 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); 113 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
114 void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
109 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info); 115 void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
110 116
111 /// Identifier string used to connect to the service. 117 /// Identifier string used to connect to the service.
@@ -120,6 +126,7 @@ private:
120 /// Function used to safely up-cast pointers to the derived class before invoking a handler. 126 /// Function used to safely up-cast pointers to the derived class before invoking a handler.
121 InvokerFn* handler_invoker; 127 InvokerFn* handler_invoker;
122 boost::container::flat_map<u32, FunctionInfoBase> handlers; 128 boost::container::flat_map<u32, FunctionInfoBase> handlers;
129 boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
123 130
124 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread. 131 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
125 Common::SpinLock lock_service; 132 Common::SpinLock lock_service;
@@ -148,17 +155,17 @@ protected:
148 /** 155 /**
149 * Constructs a FunctionInfo for a function. 156 * Constructs a FunctionInfo for a function.
150 * 157 *
151 * @param expected_header request header in the command buffer which will trigger dispatch 158 * @param expected_header_ request header in the command buffer which will trigger dispatch
152 * to this handler 159 * to this handler
153 * @param handler_callback member function in this service which will be called to handle 160 * @param handler_callback_ member function in this service which will be called to handle
154 * the request 161 * the request
155 * @param name human-friendly name for the request. Used mostly for logging purposes. 162 * @param name_ human-friendly name for the request. Used mostly for logging purposes.
156 */ 163 */
157 FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name) 164 FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
158 : FunctionInfoBase{ 165 : FunctionInfoBase{
159 expected_header, 166 expected_header_,
160 // Type-erase member function pointer by casting it down to the base class. 167 // Type-erase member function pointer by casting it down to the base class.
161 static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {} 168 static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
162 }; 169 };
163 170
164 /** 171 /**
@@ -187,6 +194,20 @@ protected:
187 RegisterHandlersBase(functions, n); 194 RegisterHandlersBase(functions, n);
188 } 195 }
189 196
197 /// Registers handlers in the service.
198 template <std::size_t N>
199 void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
200 RegisterHandlersTipc(functions, N);
201 }
202
203 /**
204 * Registers handlers in the service. Usually prefer using the other RegisterHandlers
205 * overload in order to avoid needing to specify the array size.
206 */
207 void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
208 RegisterHandlersBaseTipc(functions, n);
209 }
210
190private: 211private:
191 /** 212 /**
192 * This function is used to allow invocation of pointers to handlers stored in the base class 213 * This function is used to allow invocation of pointers to handlers stored in the base class
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 5909fdd85..4f1ffe55f 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -7,7 +7,7 @@
7#include "core/file_sys/errors.h" 7#include "core/file_sys/errors.h"
8#include "core/file_sys/system_archive/system_version.h" 8#include "core/file_sys/system_archive/system_version.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/client_port.h" 10#include "core/hle/kernel/k_client_port.h"
11#include "core/hle/service/filesystem/filesystem.h" 11#include "core/hle/service/filesystem/filesystem.h"
12#include "core/hle/service/set/set_sys.h" 12#include "core/hle/service/set/set_sys.h"
13 13
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 916177efd..de530cbfb 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -5,16 +5,16 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/client_session.h" 8#include "core/hle/kernel/k_client_session.h"
9#include "core/hle/kernel/server_session.h" 9#include "core/hle/kernel/k_server_session.h"
10#include "core/hle/kernel/session.h" 10#include "core/hle/kernel/k_session.h"
11#include "core/hle/service/sm/controller.h" 11#include "core/hle/service/sm/controller.h"
12 12
13namespace Service::SM { 13namespace Service::SM {
14 14
15void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { 15void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); 16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); 17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
18 ctx.Session()->ConvertToDomain(); 18 ctx.Session()->ConvertToDomain();
19 19
20 IPC::ResponseBuilder rb{ctx, 3}; 20 IPC::ResponseBuilder rb{ctx, 3};
@@ -26,15 +26,23 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong 26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
27 // and that we probably want to actually make an entirely new Session, but we still need to 27 // and that we probably want to actually make an entirely new Session, but we still need to
28 // verify this on hardware. 28 // verify this on hardware.
29
29 LOG_DEBUG(Service, "called"); 30 LOG_DEBUG(Service, "called");
30 31
32 auto session = ctx.Session()->GetParent();
33
34 // Open a reference to the session to simulate a new one being created.
35 session->Open();
36 session->GetClientSession().Open();
37 session->GetServerSession().Open();
38
31 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 39 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
32 rb.Push(RESULT_SUCCESS); 40 rb.Push(RESULT_SUCCESS);
33 rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); 41 rb.PushMoveObjects(session->GetClientSession());
34} 42}
35 43
36void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { 44void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
37 LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); 45 LOG_DEBUG(Service, "called");
38 46
39 CloneCurrentObject(ctx); 47 CloneCurrentObject(ctx);
40} 48}
@@ -44,7 +52,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
44 52
45 IPC::ResponseBuilder rb{ctx, 3}; 53 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(RESULT_SUCCESS); 54 rb.Push(RESULT_SUCCESS);
47 rb.Push<u16>(0x1000); 55 rb.Push<u16>(0x8000);
48} 56}
49 57
50// https://switchbrew.org/wiki/IPC_Marshalling 58// https://switchbrew.org/wiki/IPC_Marshalling
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 94608d529..8cc9aee8a 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -6,15 +6,20 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/client_port.h" 9#include "core/hle/kernel/k_client_port.h"
10#include "core/hle/kernel/client_session.h" 10#include "core/hle/kernel/k_client_session.h"
11#include "core/hle/kernel/server_port.h" 11#include "core/hle/kernel/k_port.h"
12#include "core/hle/kernel/k_scoped_resource_reservation.h"
13#include "core/hle/kernel/k_server_port.h"
14#include "core/hle/kernel/k_server_session.h"
15#include "core/hle/kernel/k_session.h"
12#include "core/hle/result.h" 16#include "core/hle/result.h"
13#include "core/hle/service/sm/controller.h" 17#include "core/hle/service/sm/controller.h"
14#include "core/hle/service/sm/sm.h" 18#include "core/hle/service/sm/sm.h"
15 19
16namespace Service::SM { 20namespace Service::SM {
17 21
22constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2);
18constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4); 23constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
19constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6); 24constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
20constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); 25constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
@@ -31,24 +36,21 @@ static ResultCode ValidateServiceName(const std::string& name) {
31 LOG_ERROR(Service_SM, "Invalid service name! service={}", name); 36 LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
32 return ERR_INVALID_NAME; 37 return ERR_INVALID_NAME;
33 } 38 }
34 if (name.rfind('\0') != std::string::npos) {
35 LOG_ERROR(Service_SM, "A non null terminated service was passed");
36 return ERR_INVALID_NAME;
37 }
38 return RESULT_SUCCESS; 39 return RESULT_SUCCESS;
39} 40}
40 41
41void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) { 42Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
42 ASSERT(self->sm_interface.expired()); 43 ASSERT(self.sm_interface.expired());
43 44
44 auto sm = std::make_shared<SM>(self, system); 45 auto sm = std::make_shared<SM>(self, system);
45 sm->InstallAsNamedPort(system.Kernel()); 46 self.sm_interface = sm;
46 self->sm_interface = sm; 47 self.controller_interface = std::make_unique<Controller>(system);
47 self->controller_interface = std::make_unique<Controller>(system); 48
49 return sm->CreatePort(system.Kernel());
48} 50}
49 51
50ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, 52ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
51 u32 max_sessions) { 53 u32 max_sessions) {
52 54
53 CASCADE_CODE(ValidateServiceName(name)); 55 CASCADE_CODE(ValidateServiceName(name));
54 56
@@ -57,11 +59,12 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(s
57 return ERR_ALREADY_REGISTERED; 59 return ERR_ALREADY_REGISTERED;
58 } 60 }
59 61
60 auto [server_port, client_port] = 62 auto* port = Kernel::KPort::Create(kernel);
61 Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name); 63 port->Initialize(max_sessions, false, name);
62 64
63 registered_services.emplace(std::move(name), std::move(client_port)); 65 registered_services.emplace(std::move(name), port);
64 return MakeResult(std::move(server_port)); 66
67 return MakeResult(&port->GetServerPort());
65} 68}
66 69
67ResultCode ServiceManager::UnregisterService(const std::string& name) { 70ResultCode ServiceManager::UnregisterService(const std::string& name) {
@@ -72,12 +75,14 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
72 LOG_ERROR(Service_SM, "Server is not registered! service={}", name); 75 LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
73 return ERR_SERVICE_NOT_REGISTERED; 76 return ERR_SERVICE_NOT_REGISTERED;
74 } 77 }
78
79 iter->second->Close();
80
75 registered_services.erase(iter); 81 registered_services.erase(iter);
76 return RESULT_SUCCESS; 82 return RESULT_SUCCESS;
77} 83}
78 84
79ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort( 85ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
80 const std::string& name) {
81 86
82 CASCADE_CODE(ValidateServiceName(name)); 87 CASCADE_CODE(ValidateServiceName(name));
83 auto it = registered_services.find(name); 88 auto it = registered_services.find(name);
@@ -89,13 +94,6 @@ ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
89 return MakeResult(it->second); 94 return MakeResult(it->second);
90} 95}
91 96
92ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
93 const std::string& name) {
94
95 CASCADE_RESULT(auto client_port, GetServicePort(name));
96 return client_port->Connect();
97}
98
99SM::~SM() = default; 97SM::~SM() = default;
100 98
101/** 99/**
@@ -108,50 +106,81 @@ SM::~SM() = default;
108void SM::Initialize(Kernel::HLERequestContext& ctx) { 106void SM::Initialize(Kernel::HLERequestContext& ctx) {
109 LOG_DEBUG(Service_SM, "called"); 107 LOG_DEBUG(Service_SM, "called");
110 108
109 is_initialized = true;
110
111 IPC::ResponseBuilder rb{ctx, 2}; 111 IPC::ResponseBuilder rb{ctx, 2};
112 rb.Push(RESULT_SUCCESS); 112 rb.Push(RESULT_SUCCESS);
113} 113}
114 114
115void SM::GetService(Kernel::HLERequestContext& ctx) { 115void SM::GetService(Kernel::HLERequestContext& ctx) {
116 IPC::RequestParser rp{ctx}; 116 auto result = GetServiceImpl(ctx);
117 if (result.Succeeded()) {
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
119 rb.Push(result.Code());
120 rb.PushMoveObjects(result.Unwrap());
121 } else {
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(result.Code());
124 }
125}
126
127void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
128 auto result = GetServiceImpl(ctx);
129 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
130 rb.Push(result.Code());
131 rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
132}
133
134static std::string PopServiceName(IPC::RequestParser& rp) {
117 auto name_buf = rp.PopRaw<std::array<char, 8>>(); 135 auto name_buf = rp.PopRaw<std::array<char, 8>>();
118 auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 136 std::string result;
137 for (const auto& c : name_buf) {
138 if (c >= ' ' && c <= '~') {
139 result.push_back(c);
140 }
141 }
142 return result;
143}
119 144
120 std::string name(name_buf.begin(), end); 145ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) {
146 if (!is_initialized) {
147 return ERR_NOT_INITIALIZED;
148 }
121 149
122 auto client_port = service_manager->GetServicePort(name); 150 IPC::RequestParser rp{ctx};
123 if (client_port.Failed()) { 151 std::string name(PopServiceName(rp));
124 IPC::ResponseBuilder rb{ctx, 2}; 152
125 rb.Push(client_port.Code()); 153 auto result = service_manager.GetServicePort(name);
126 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw); 154 if (result.Failed()) {
127 if (name.length() == 0) 155 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
128 return; // LibNX Fix 156 return result.Code();
129 UNIMPLEMENTED();
130 return;
131 } 157 }
132 158
133 auto [client, server] = Kernel::Session::Create(kernel, name); 159 auto* port = result.Unwrap();
160
161 // Kernel::KScopedResourceReservation session_reservation(
162 // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
163 // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached);
164
165 auto* session = Kernel::KSession::Create(kernel);
166 session->Initialize(&port->GetClientPort(), std::move(name));
134 167
135 const auto& server_port = client_port.Unwrap()->GetServerPort(); 168 // Commit the session reservation.
136 if (server_port->GetHLEHandler()) { 169 // session_reservation.Commit();
137 server_port->GetHLEHandler()->ClientConnected(server); 170
171 if (port->GetServerPort().GetHLEHandler()) {
172 port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession());
138 } else { 173 } else {
139 server_port->AppendPendingSession(server); 174 port->EnqueueSession(&session->GetServerSession());
140 } 175 }
141 176
142 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); 177 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
143 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 178 return MakeResult(&session->GetClientSession());
144 rb.Push(RESULT_SUCCESS);
145 rb.PushMoveObjects(std::move(client));
146} 179}
147 180
148void SM::RegisterService(Kernel::HLERequestContext& ctx) { 181void SM::RegisterService(Kernel::HLERequestContext& ctx) {
149 IPC::RequestParser rp{ctx}; 182 IPC::RequestParser rp{ctx};
150 183 std::string name(PopServiceName(rp));
151 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
152 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
153
154 const std::string name(name_buf.begin(), end);
155 184
156 const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); 185 const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
157 const auto max_session_count = rp.PopRaw<u32>(); 186 const auto max_session_count = rp.PopRaw<u32>();
@@ -159,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
159 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, 188 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
160 max_session_count, is_light); 189 max_session_count, is_light);
161 190
162 auto handle = service_manager->RegisterService(name, max_session_count); 191 auto handle = service_manager.RegisterService(name, max_session_count);
163 if (handle.Failed()) { 192 if (handle.Failed()) {
164 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", 193 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
165 handle.Code().raw); 194 handle.Code().raw);
@@ -170,33 +199,38 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
170 199
171 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 200 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
172 rb.Push(handle.Code()); 201 rb.Push(handle.Code());
173 rb.PushMoveObjects(std::move(handle).Unwrap()); 202
203 auto server_port = handle.Unwrap();
204 rb.PushMoveObjects(server_port);
174} 205}
175 206
176void SM::UnregisterService(Kernel::HLERequestContext& ctx) { 207void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
177 IPC::RequestParser rp{ctx}; 208 IPC::RequestParser rp{ctx};
209 std::string name(PopServiceName(rp));
178 210
179 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
180 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
181
182 const std::string name(name_buf.begin(), end);
183 LOG_DEBUG(Service_SM, "called with name={}", name); 211 LOG_DEBUG(Service_SM, "called with name={}", name);
184 212
185 IPC::ResponseBuilder rb{ctx, 2}; 213 IPC::ResponseBuilder rb{ctx, 2};
186 rb.Push(service_manager->UnregisterService(name)); 214 rb.Push(service_manager.UnregisterService(name));
187} 215}
188 216
189SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_) 217SM::SM(ServiceManager& service_manager_, Core::System& system_)
190 : ServiceFramework{system_, "sm:", 4}, 218 : ServiceFramework{system_, "sm:", 4},
191 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} { 219 service_manager{service_manager_}, kernel{system_.Kernel()} {
192 static const FunctionInfo functions[] = { 220 RegisterHandlers({
193 {0, &SM::Initialize, "Initialize"}, 221 {0, &SM::Initialize, "Initialize"},
194 {1, &SM::GetService, "GetService"}, 222 {1, &SM::GetService, "GetService"},
195 {2, &SM::RegisterService, "RegisterService"}, 223 {2, &SM::RegisterService, "RegisterService"},
196 {3, &SM::UnregisterService, "UnregisterService"}, 224 {3, &SM::UnregisterService, "UnregisterService"},
197 {4, nullptr, "DetachClient"}, 225 {4, nullptr, "DetachClient"},
198 }; 226 });
199 RegisterHandlers(functions); 227 RegisterHandlersTipc({
228 {0, &SM::Initialize, "Initialize"},
229 {1, &SM::GetServiceTipc, "GetService"},
230 {2, &SM::RegisterService, "RegisterService"},
231 {3, &SM::UnregisterService, "UnregisterService"},
232 {4, nullptr, "DetachClient"},
233 });
200} 234}
201 235
202} // namespace Service::SM 236} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 3f46ae44f..60f0b3f8a 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -10,9 +10,7 @@
10#include <unordered_map> 10#include <unordered_map>
11 11
12#include "common/concepts.h" 12#include "common/concepts.h"
13#include "core/hle/kernel/client_port.h" 13#include "core/hle/kernel/k_port.h"
14#include "core/hle/kernel/object.h"
15#include "core/hle/kernel/server_port.h"
16#include "core/hle/result.h" 14#include "core/hle/result.h"
17#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
18 16
@@ -21,10 +19,11 @@ class System;
21} 19}
22 20
23namespace Kernel { 21namespace Kernel {
24class ClientPort; 22class KClientPort;
25class ClientSession; 23class KClientSession;
26class KernelCore; 24class KernelCore;
27class ServerPort; 25class KPort;
26class KServerPort;
28class SessionRequestHandler; 27class SessionRequestHandler;
29} // namespace Kernel 28} // namespace Kernel
30 29
@@ -35,31 +34,33 @@ class Controller;
35/// Interface to "sm:" service 34/// Interface to "sm:" service
36class SM final : public ServiceFramework<SM> { 35class SM final : public ServiceFramework<SM> {
37public: 36public:
38 explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_); 37 explicit SM(ServiceManager& service_manager_, Core::System& system_);
39 ~SM() override; 38 ~SM() override;
40 39
41private: 40private:
42 void Initialize(Kernel::HLERequestContext& ctx); 41 void Initialize(Kernel::HLERequestContext& ctx);
43 void GetService(Kernel::HLERequestContext& ctx); 42 void GetService(Kernel::HLERequestContext& ctx);
43 void GetServiceTipc(Kernel::HLERequestContext& ctx);
44 void RegisterService(Kernel::HLERequestContext& ctx); 44 void RegisterService(Kernel::HLERequestContext& ctx);
45 void UnregisterService(Kernel::HLERequestContext& ctx); 45 void UnregisterService(Kernel::HLERequestContext& ctx);
46 46
47 std::shared_ptr<ServiceManager> service_manager; 47 ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx);
48
49 ServiceManager& service_manager;
50 bool is_initialized{};
48 Kernel::KernelCore& kernel; 51 Kernel::KernelCore& kernel;
49}; 52};
50 53
51class ServiceManager { 54class ServiceManager {
52public: 55public:
53 static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system); 56 static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
54 57
55 explicit ServiceManager(Kernel::KernelCore& kernel_); 58 explicit ServiceManager(Kernel::KernelCore& kernel_);
56 ~ServiceManager(); 59 ~ServiceManager();
57 60
58 ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name, 61 ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions);
59 u32 max_sessions);
60 ResultCode UnregisterService(const std::string& name); 62 ResultCode UnregisterService(const std::string& name);
61 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); 63 ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
62 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
63 64
64 template <Common::DerivedFrom<Kernel::SessionRequestHandler> T> 65 template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
65 std::shared_ptr<T> GetService(const std::string& service_name) const { 66 std::shared_ptr<T> GetService(const std::string& service_name) const {
@@ -68,11 +69,11 @@ public:
68 LOG_DEBUG(Service, "Can't find service: {}", service_name); 69 LOG_DEBUG(Service, "Can't find service: {}", service_name);
69 return nullptr; 70 return nullptr;
70 } 71 }
71 auto port = service->second->GetServerPort(); 72 auto* port = service->second;
72 if (port == nullptr) { 73 if (port == nullptr) {
73 return nullptr; 74 return nullptr;
74 } 75 }
75 return std::static_pointer_cast<T>(port->GetHLEHandler()); 76 return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler());
76 } 77 }
77 78
78 void InvokeControlRequest(Kernel::HLERequestContext& context); 79 void InvokeControlRequest(Kernel::HLERequestContext& context);
@@ -81,8 +82,8 @@ private:
81 std::weak_ptr<SM> sm_interface; 82 std::weak_ptr<SM> sm_interface;
82 std::unique_ptr<Controller> controller_interface; 83 std::unique_ptr<Controller> controller_interface;
83 84
84 /// Map of registered services, retrieved using GetServicePort or ConnectToService. 85 /// Map of registered services, retrieved using GetServicePort.
85 std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services; 86 std::unordered_map<std::string, Kernel::KPort*> registered_services;
86 87
87 /// Kernel context 88 /// Kernel context
88 Kernel::KernelCore& kernel; 89 Kernel::KernelCore& kernel;
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index dc2baca4a..3b072f6bc 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -10,6 +10,11 @@
10 10
11namespace Service::SSL { 11namespace Service::SSL {
12 12
13enum class CertificateFormat : u32 {
14 Pem = 1,
15 Der = 2,
16};
17
13class ISslConnection final : public ServiceFramework<ISslConnection> { 18class ISslConnection final : public ServiceFramework<ISslConnection> {
14public: 19public:
15 explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { 20 explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} {
@@ -58,8 +63,8 @@ public:
58 {1, nullptr, "GetOption"}, 63 {1, nullptr, "GetOption"},
59 {2, &ISslContext::CreateConnection, "CreateConnection"}, 64 {2, &ISslContext::CreateConnection, "CreateConnection"},
60 {3, nullptr, "GetConnectionCount"}, 65 {3, nullptr, "GetConnectionCount"},
61 {4, nullptr, "ImportServerPki"}, 66 {4, &ISslContext::ImportServerPki, "ImportServerPki"},
62 {5, nullptr, "ImportClientPki"}, 67 {5, &ISslContext::ImportClientPki, "ImportClientPki"},
63 {6, nullptr, "RemoveServerPki"}, 68 {6, nullptr, "RemoveServerPki"},
64 {7, nullptr, "RemoveClientPki"}, 69 {7, nullptr, "RemoveClientPki"},
65 {8, nullptr, "RegisterInternalPki"}, 70 {8, nullptr, "RegisterInternalPki"},
@@ -94,6 +99,39 @@ private:
94 rb.Push(RESULT_SUCCESS); 99 rb.Push(RESULT_SUCCESS);
95 rb.PushIpcInterface<ISslConnection>(system); 100 rb.PushIpcInterface<ISslConnection>(system);
96 } 101 }
102
103 void ImportServerPki(Kernel::HLERequestContext& ctx) {
104 IPC::RequestParser rp{ctx};
105 const auto certificate_format = rp.PopEnum<CertificateFormat>();
106 const auto pkcs_12_certificates = ctx.ReadBuffer(0);
107
108 constexpr u64 server_id = 0;
109
110 LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format);
111
112 IPC::ResponseBuilder rb{ctx, 4};
113 rb.Push(RESULT_SUCCESS);
114 rb.Push(server_id);
115 }
116
117 void ImportClientPki(Kernel::HLERequestContext& ctx) {
118 const auto pkcs_12_certificate = ctx.ReadBuffer(0);
119 const auto ascii_password = [&ctx] {
120 if (ctx.CanReadBuffer(1)) {
121 return ctx.ReadBuffer(1);
122 }
123
124 return std::vector<u8>{};
125 }();
126
127 constexpr u64 client_id = 0;
128
129 LOG_WARNING(Service_SSL, "(STUBBED) called");
130
131 IPC::ResponseBuilder rb{ctx, 4};
132 rb.Push(RESULT_SUCCESS);
133 rb.Push(client_id);
134 }
97}; 135};
98 136
99class SSL final : public ServiceFramework<SSL> { 137class SSL final : public ServiceFramework<SSL> {
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_core.h b/src/core/hle/service/time/ephemeral_network_system_clock_core.h
index 4c6cdef86..d12cb5335 100644
--- a/src/core/hle/service/time/ephemeral_network_system_clock_core.h
+++ b/src/core/hle/service/time/ephemeral_network_system_clock_core.h
@@ -10,8 +10,8 @@ namespace Service::Time::Clock {
10 10
11class EphemeralNetworkSystemClockCore final : public SystemClockCore { 11class EphemeralNetworkSystemClockCore final : public SystemClockCore {
12public: 12public:
13 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core) 13 explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
14 : SystemClockCore{steady_clock_core} {} 14 : SystemClockCore{steady_clock_core_} {}
15}; 15};
16 16
17} // namespace Service::Time::Clock 17} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/local_system_clock_context_writer.h b/src/core/hle/service/time/local_system_clock_context_writer.h
index 7050844c6..490d0ef3e 100644
--- a/src/core/hle/service/time/local_system_clock_context_writer.h
+++ b/src/core/hle/service/time/local_system_clock_context_writer.h
@@ -12,8 +12,8 @@ namespace Service::Time::Clock {
12 12
13class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback { 13class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
14public: 14public:
15 explicit LocalSystemClockContextWriter(SharedMemory& shared_memory) 15 explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_)
16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {} 16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
17 17
18protected: 18protected:
19 ResultCode Update() override { 19 ResultCode Update() override {
diff --git a/src/core/hle/service/time/network_system_clock_context_writer.h b/src/core/hle/service/time/network_system_clock_context_writer.h
index 94d8788ff..e2920b8eb 100644
--- a/src/core/hle/service/time/network_system_clock_context_writer.h
+++ b/src/core/hle/service/time/network_system_clock_context_writer.h
@@ -12,8 +12,8 @@ namespace Service::Time::Clock {
12 12
13class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { 13class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
14public: 14public:
15 explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory) 15 explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_)
16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {} 16 : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
17 17
18protected: 18protected:
19 ResultCode Update() override { 19 ResultCode Update() override {
diff --git a/src/core/hle/service/time/standard_local_system_clock_core.h b/src/core/hle/service/time/standard_local_system_clock_core.h
index 8c1882eb1..6320c7af1 100644
--- a/src/core/hle/service/time/standard_local_system_clock_core.h
+++ b/src/core/hle/service/time/standard_local_system_clock_core.h
@@ -10,8 +10,8 @@ namespace Service::Time::Clock {
10 10
11class StandardLocalSystemClockCore final : public SystemClockCore { 11class StandardLocalSystemClockCore final : public SystemClockCore {
12public: 12public:
13 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core) 13 explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_)
14 : SystemClockCore{steady_clock_core} {} 14 : SystemClockCore{steady_clock_core_} {}
15}; 15};
16 16
17} // namespace Service::Time::Clock 17} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/standard_network_system_clock_core.h b/src/core/hle/service/time/standard_network_system_clock_core.h
index c993bdf79..9d0aeaedb 100644
--- a/src/core/hle/service/time/standard_network_system_clock_core.h
+++ b/src/core/hle/service/time/standard_network_system_clock_core.h
@@ -16,21 +16,21 @@ namespace Service::Time::Clock {
16 16
17class StandardNetworkSystemClockCore final : public SystemClockCore { 17class StandardNetworkSystemClockCore final : public SystemClockCore {
18public: 18public:
19 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core) 19 explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
20 : SystemClockCore{steady_clock_core} {} 20 : SystemClockCore{steady_clock_core_} {}
21 21
22 void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) { 22 void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
23 standard_network_clock_sufficient_accuracy = value; 23 standard_network_clock_sufficient_accuracy = value;
24 } 24 }
25 25
26 bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const { 26 bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const {
27 SystemClockContext context{}; 27 SystemClockContext clock_ctx{};
28 if (GetClockContext(system, context) != RESULT_SUCCESS) { 28 if (GetClockContext(system, clock_ctx) != RESULT_SUCCESS) {
29 return {}; 29 return {};
30 } 30 }
31 31
32 s64 span{}; 32 s64 span{};
33 if (context.steady_time_point.GetSpanBetween( 33 if (clock_ctx.steady_time_point.GetSpanBetween(
34 GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) { 34 GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) {
35 return {}; 35 return {};
36 } 36 }
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp
index 3172acc5a..41bc01abd 100644
--- a/src/core/hle/service/time/standard_user_system_clock_core.cpp
+++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/time/standard_local_system_clock_core.h" 7#include "core/hle/service/time/standard_local_system_clock_core.h"
9#include "core/hle/service/time/standard_network_system_clock_core.h" 8#include "core/hle/service/time/standard_network_system_clock_core.h"
10#include "core/hle/service/time/standard_user_system_clock_core.h" 9#include "core/hle/service/time/standard_user_system_clock_core.h"
@@ -12,15 +11,15 @@
12namespace Service::Time::Clock { 11namespace Service::Time::Clock {
13 12
14StandardUserSystemClockCore::StandardUserSystemClockCore( 13StandardUserSystemClockCore::StandardUserSystemClockCore(
15 StandardLocalSystemClockCore& local_system_clock_core, 14 StandardLocalSystemClockCore& local_system_clock_core_,
16 StandardNetworkSystemClockCore& network_system_clock_core, Core::System& system) 15 StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_)
17 : SystemClockCore(local_system_clock_core.GetSteadyClockCore()), 16 : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()),
18 local_system_clock_core{local_system_clock_core}, 17 local_system_clock_core{local_system_clock_core_},
19 network_system_clock_core{network_system_clock_core}, auto_correction_enabled{}, 18 network_system_clock_core{network_system_clock_core_},
20 auto_correction_time{SteadyClockTimePoint::GetRandom()}, 19 auto_correction_time{SteadyClockTimePoint::GetRandom()}, auto_correction_event{
21 auto_correction_event{Kernel::KEvent::Create( 20 system_.Kernel()} {
22 system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} { 21 Kernel::KAutoObject::Create(std::addressof(auto_correction_event));
23 auto_correction_event->Initialize(); 22 auto_correction_event.Initialize("StandardUserSystemClockCore:AutoCorrectionEvent");
24} 23}
25 24
26ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, 25ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
@@ -36,13 +35,13 @@ ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::Syst
36} 35}
37 36
38ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system, 37ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system,
39 SystemClockContext& context) const { 38 SystemClockContext& ctx) const {
40 if (const ResultCode result{ApplyAutomaticCorrection(system, false)}; 39 if (const ResultCode result{ApplyAutomaticCorrection(system, false)};
41 result != RESULT_SUCCESS) { 40 result != RESULT_SUCCESS) {
42 return result; 41 return result;
43 } 42 }
44 43
45 return local_system_clock_core.GetClockContext(system, context); 44 return local_system_clock_core.GetClockContext(system, ctx);
46} 45}
47 46
48ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) { 47ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) {
@@ -65,13 +64,13 @@ ResultCode StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& s
65 return ERROR_UNINITIALIZED_CLOCK; 64 return ERROR_UNINITIALIZED_CLOCK;
66 } 65 }
67 66
68 SystemClockContext context{}; 67 SystemClockContext ctx{};
69 if (const ResultCode result{network_system_clock_core.GetClockContext(system, context)}; 68 if (const ResultCode result{network_system_clock_core.GetClockContext(system, ctx)};
70 result != RESULT_SUCCESS) { 69 result != RESULT_SUCCESS) {
71 return result; 70 return result;
72 } 71 }
73 72
74 local_system_clock_core.SetClockContext(context); 73 local_system_clock_core.SetClockContext(ctx);
75 74
76 return RESULT_SUCCESS; 75 return RESULT_SUCCESS;
77} 76}
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h
index 5bc8bf5c2..bf9ec5e42 100644
--- a/src/core/hle/service/time/standard_user_system_clock_core.h
+++ b/src/core/hle/service/time/standard_user_system_clock_core.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/time/clock_types.h" 8#include "core/hle/service/time/clock_types.h"
8#include "core/hle/service/time/system_clock_core.h" 9#include "core/hle/service/time/system_clock_core.h"
9 10
@@ -22,13 +23,13 @@ class StandardNetworkSystemClockCore;
22 23
23class StandardUserSystemClockCore final : public SystemClockCore { 24class StandardUserSystemClockCore final : public SystemClockCore {
24public: 25public:
25 StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core, 26 StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_,
26 StandardNetworkSystemClockCore& network_system_clock_core, 27 StandardNetworkSystemClockCore& network_system_clock_core_,
27 Core::System& system); 28 Core::System& system_);
28 29
29 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value); 30 ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value);
30 31
31 ResultCode GetClockContext(Core::System& system, SystemClockContext& context) const override; 32 ResultCode GetClockContext(Core::System& system, SystemClockContext& ctx) const override;
32 33
33 bool IsAutomaticCorrectionEnabled() const { 34 bool IsAutomaticCorrectionEnabled() const {
34 return auto_correction_enabled; 35 return auto_correction_enabled;
@@ -54,7 +55,7 @@ private:
54 StandardNetworkSystemClockCore& network_system_clock_core; 55 StandardNetworkSystemClockCore& network_system_clock_core;
55 bool auto_correction_enabled{}; 56 bool auto_correction_enabled{};
56 SteadyClockTimePoint auto_correction_time; 57 SteadyClockTimePoint auto_correction_time;
57 std::shared_ptr<Kernel::KEvent> auto_correction_event; 58 Kernel::KEvent auto_correction_event;
58}; 59};
59 60
60} // namespace Service::Time::Clock 61} // namespace Service::Time::Clock
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp
index 46fc8c6c3..2ef442b56 100644
--- a/src/core/hle/service/time/system_clock_core.cpp
+++ b/src/core/hle/service/time/system_clock_core.cpp
@@ -8,8 +8,8 @@
8 8
9namespace Service::Time::Clock { 9namespace Service::Time::Clock {
10 10
11SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core) 11SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_)
12 : steady_clock_core{steady_clock_core} { 12 : steady_clock_core{steady_clock_core_} {
13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId(); 13 context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
14} 14}
15 15
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h
index 82a8b79ff..b8e6122bf 100644
--- a/src/core/hle/service/time/system_clock_core.h
+++ b/src/core/hle/service/time/system_clock_core.h
@@ -21,7 +21,7 @@ class SystemClockContextUpdateCallback;
21 21
22class SystemClockCore { 22class SystemClockCore {
23public: 23public:
24 explicit SystemClockCore(SteadyClockCore& steady_clock_core); 24 explicit SystemClockCore(SteadyClockCore& steady_clock_core_);
25 virtual ~SystemClockCore(); 25 virtual ~SystemClockCore();
26 26
27 SteadyClockCore& GetSteadyClockCore() const { 27 SteadyClockCore& GetSteadyClockCore() const {
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 32f372d71..e7991012b 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -8,8 +8,7 @@
8#include "core/core_timing_util.h" 8#include "core/core_timing_util.h"
9#include "core/hardware_properties.h" 9#include "core/hardware_properties.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/client_port.h" 11#include "core/hle/kernel/k_client_port.h"
12#include "core/hle/kernel/client_session.h"
13#include "core/hle/kernel/k_scheduler.h" 12#include "core/hle/kernel/k_scheduler.h"
14#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
15#include "core/hle/service/time/interface.h" 14#include "core/hle/service/time/interface.h"
@@ -393,7 +392,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
393 LOG_DEBUG(Service_Time, "called"); 392 LOG_DEBUG(Service_Time, "called");
394 IPC::ResponseBuilder rb{ctx, 2, 1}; 393 IPC::ResponseBuilder rb{ctx, 2, 1};
395 rb.Push(RESULT_SUCCESS); 394 rb.Push(RESULT_SUCCESS);
396 rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem())); 395 rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem());
397} 396}
398 397
399Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, 398Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index fe01a3739..4f9684de8 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -223,7 +223,7 @@ struct TimeManager::Impl final {
223 TimeZone::TimeZoneContentManager time_zone_content_manager; 223 TimeZone::TimeZoneContentManager time_zone_content_manager;
224}; 224};
225 225
226TimeManager::TimeManager(Core::System& system) : system{system} {} 226TimeManager::TimeManager(Core::System& system_) : system{system_} {}
227 227
228TimeManager::~TimeManager() = default; 228TimeManager::~TimeManager() = default;
229 229
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
index 4db8cc0e1..3af868d87 100644
--- a/src/core/hle/service/time/time_manager.h
+++ b/src/core/hle/service/time/time_manager.h
@@ -30,7 +30,7 @@ class NetworkSystemClockContextWriter;
30 30
31class TimeManager final { 31class TimeManager final {
32public: 32public:
33 explicit TimeManager(Core::System& system); 33 explicit TimeManager(Core::System& system_);
34 ~TimeManager(); 34 ~TimeManager();
35 35
36 void Initialize(); 36 void Initialize();
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index 018ce94ed..176ad0eee 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -15,17 +15,12 @@ namespace Service::Time {
15 15
16static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000}; 16static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
17 17
18SharedMemory::SharedMemory(Core::System& system) : system(system) { 18SharedMemory::SharedMemory(Core::System& system_) : system(system_) {
19 shared_memory_holder = SharedFrom(&system.Kernel().GetTimeSharedMem()); 19 std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE);
20 std::memset(shared_memory_holder->GetPointer(), 0, SHARED_MEMORY_SIZE);
21} 20}
22 21
23SharedMemory::~SharedMemory() = default; 22SharedMemory::~SharedMemory() = default;
24 23
25std::shared_ptr<Kernel::KSharedMemory> SharedMemory::GetSharedMemoryHolder() const {
26 return shared_memory_holder;
27}
28
29void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, 24void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
30 Clock::TimeSpanType current_time_point) { 25 Clock::TimeSpanType current_time_point) {
31 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( 26 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
@@ -34,22 +29,22 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
34 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), 29 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
35 clock_source_id}; 30 clock_source_id};
36 shared_memory_format.standard_steady_clock_timepoint.StoreData( 31 shared_memory_format.standard_steady_clock_timepoint.StoreData(
37 shared_memory_holder->GetPointer(), context); 32 system.Kernel().GetTimeSharedMem().GetPointer(), context);
38} 33}
39 34
40void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { 35void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
41 shared_memory_format.standard_local_system_clock_context.StoreData( 36 shared_memory_format.standard_local_system_clock_context.StoreData(
42 shared_memory_holder->GetPointer(), context); 37 system.Kernel().GetTimeSharedMem().GetPointer(), context);
43} 38}
44 39
45void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { 40void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
46 shared_memory_format.standard_network_system_clock_context.StoreData( 41 shared_memory_format.standard_network_system_clock_context.StoreData(
47 shared_memory_holder->GetPointer(), context); 42 system.Kernel().GetTimeSharedMem().GetPointer(), context);
48} 43}
49 44
50void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { 45void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
51 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( 46 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
52 shared_memory_holder->GetPointer(), is_enabled); 47 system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled);
53} 48}
54 49
55} // namespace Service::Time 50} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 3bc749114..d471b5d18 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -14,12 +14,9 @@ namespace Service::Time {
14 14
15class SharedMemory final { 15class SharedMemory final {
16public: 16public:
17 explicit SharedMemory(Core::System& system); 17 explicit SharedMemory(Core::System& system_);
18 ~SharedMemory(); 18 ~SharedMemory();
19 19
20 // Return the shared memory handle
21 std::shared_ptr<Kernel::KSharedMemory> GetSharedMemoryHolder() const;
22
23 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? 20 // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
24 template <typename T, std::size_t Offset> 21 template <typename T, std::size_t Offset>
25 struct MemoryBarrier { 22 struct MemoryBarrier {
@@ -63,7 +60,6 @@ public:
63 void SetAutomaticCorrectionEnabled(bool is_enabled); 60 void SetAutomaticCorrectionEnabled(bool is_enabled);
64 61
65private: 62private:
66 std::shared_ptr<Kernel::KSharedMemory> shared_memory_holder;
67 Core::System& system; 63 Core::System& system;
68 Format shared_memory_format{}; 64 Format shared_memory_format{};
69}; 65};
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index 3c8e71a3c..57f71e6f0 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -68,8 +68,8 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
68 return location_name_cache; 68 return location_name_cache;
69} 69}
70 70
71TimeZoneContentManager::TimeZoneContentManager(Core::System& system) 71TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
72 : system{system}, location_name_cache{BuildLocationNameCache(system)} {} 72 : system{system_}, location_name_cache{BuildLocationNameCache(system)} {}
73 73
74void TimeZoneContentManager::Initialize(TimeManager& time_manager) { 74void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
75 std::string location_name; 75 std::string location_name;
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h
index 52dd1a020..cfa601084 100644
--- a/src/core/hle/service/time/time_zone_content_manager.h
+++ b/src/core/hle/service/time/time_zone_content_manager.h
@@ -21,7 +21,7 @@ namespace Service::Time::TimeZone {
21 21
22class TimeZoneContentManager final { 22class TimeZoneContentManager final {
23public: 23public:
24 explicit TimeZoneContentManager(Core::System& system); 24 explicit TimeZoneContentManager(Core::System& system_);
25 25
26 void Initialize(TimeManager& time_manager); 26 void Initialize(TimeManager& time_manager);
27 27
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index ac9e87338..0dd342dbf 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -17,10 +17,10 @@
17 17
18namespace Service::VI { 18namespace Service::VI {
19 19
20Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} { 20Display::Display(u64 id, std::string name_, Core::System& system)
21 auto& kernel = system.Kernel(); 21 : display_id{id}, name{std::move(name_)}, vsync_event{system.Kernel()} {
22 vsync_event = Kernel::KEvent::Create(kernel, fmt::format("Display VSync Event {}", id)); 22 Kernel::KAutoObject::Create(std::addressof(vsync_event));
23 vsync_event->Initialize(); 23 vsync_event.Initialize(fmt::format("Display VSync Event {}", id));
24} 24}
25 25
26Display::~Display() = default; 26Display::~Display() = default;
@@ -33,12 +33,12 @@ const Layer& Display::GetLayer(std::size_t index) const {
33 return *layers.at(index); 33 return *layers.at(index);
34} 34}
35 35
36std::shared_ptr<Kernel::KReadableEvent> Display::GetVSyncEvent() const { 36Kernel::KReadableEvent& Display::GetVSyncEvent() {
37 return vsync_event->GetReadableEvent(); 37 return vsync_event.GetReadableEvent();
38} 38}
39 39
40void Display::SignalVSyncEvent() { 40void Display::SignalVSyncEvent() {
41 vsync_event->GetWritableEvent()->Signal(); 41 vsync_event.GetWritableEvent().Signal();
42} 42}
43 43
44void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) { 44void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) {
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 8340059de..166f2a4cc 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -8,6 +8,7 @@
8#include <string> 8#include <string>
9#include <vector> 9#include <vector>
10 10
11#include "common/common_funcs.h"
11#include "common/common_types.h" 12#include "common/common_types.h"
12 13
13namespace Kernel { 14namespace Kernel {
@@ -24,24 +25,21 @@ class Layer;
24 25
25/// Represents a single display type 26/// Represents a single display type
26class Display { 27class Display {
28 YUZU_NON_COPYABLE(Display);
29 YUZU_NON_MOVEABLE(Display);
30
27public: 31public:
28 /// Constructs a display with a given unique ID and name. 32 /// Constructs a display with a given unique ID and name.
29 /// 33 ///
30 /// @param id The unique ID for this display. 34 /// @param id The unique ID for this display.
31 /// @param name The name for this display. 35 /// @param name_ The name for this display.
32 /// 36 ///
33 Display(u64 id, std::string name, Core::System& system); 37 Display(u64 id, std::string name_, Core::System& system);
34 ~Display(); 38 ~Display();
35 39
36 Display(const Display&) = delete;
37 Display& operator=(const Display&) = delete;
38
39 Display(Display&&) = default;
40 Display& operator=(Display&&) = default;
41
42 /// Gets the unique ID assigned to this display. 40 /// Gets the unique ID assigned to this display.
43 u64 GetID() const { 41 u64 GetID() const {
44 return id; 42 return display_id;
45 } 43 }
46 44
47 /// Gets the name of this display 45 /// Gets the name of this display
@@ -61,7 +59,7 @@ public:
61 const Layer& GetLayer(std::size_t index) const; 59 const Layer& GetLayer(std::size_t index) const;
62 60
63 /// Gets the readable vsync event. 61 /// Gets the readable vsync event.
64 std::shared_ptr<Kernel::KReadableEvent> GetVSyncEvent() const; 62 Kernel::KReadableEvent& GetVSyncEvent();
65 63
66 /// Signals the internal vsync event. 64 /// Signals the internal vsync event.
67 void SignalVSyncEvent(); 65 void SignalVSyncEvent();
@@ -98,11 +96,11 @@ public:
98 const Layer* FindLayer(u64 layer_id) const; 96 const Layer* FindLayer(u64 layer_id) const;
99 97
100private: 98private:
101 u64 id; 99 u64 display_id;
102 std::string name; 100 std::string name;
103 101
104 std::vector<std::shared_ptr<Layer>> layers; 102 std::vector<std::shared_ptr<Layer>> layers;
105 std::shared_ptr<Kernel::KEvent> vsync_event; 103 Kernel::KEvent vsync_event;
106}; 104};
107 105
108} // namespace Service::VI 106} // namespace Service::VI
diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp
index 954225c26..9bc382587 100644
--- a/src/core/hle/service/vi/layer/vi_layer.cpp
+++ b/src/core/hle/service/vi/layer/vi_layer.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::VI { 7namespace Service::VI {
8 8
9Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : id{id}, buffer_queue{queue} {} 9Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {}
10 10
11Layer::~Layer() = default; 11Layer::~Layer() = default;
12 12
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h
index c6bfd01f6..ebdd85505 100644
--- a/src/core/hle/service/vi/layer/vi_layer.h
+++ b/src/core/hle/service/vi/layer/vi_layer.h
@@ -31,7 +31,7 @@ public:
31 31
32 /// Gets the ID for this layer. 32 /// Gets the ID for this layer.
33 u64 GetID() const { 33 u64 GetID() const {
34 return id; 34 return layer_id;
35 } 35 }
36 36
37 /// Gets a reference to the buffer queue this layer is using. 37 /// Gets a reference to the buffer queue this layer is using.
@@ -45,7 +45,7 @@ public:
45 } 45 }
46 46
47private: 47private:
48 u64 id; 48 u64 layer_id;
49 NVFlinger::BufferQueue& buffer_queue; 49 NVFlinger::BufferQueue& buffer_queue;
50}; 50};
51 51
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 7ae07d072..fdd2b4b4f 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -212,7 +212,7 @@ private:
212 212
213class IGBPConnectRequestParcel : public Parcel { 213class IGBPConnectRequestParcel : public Parcel {
214public: 214public:
215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
216 Deserialize(); 216 Deserialize();
217 } 217 }
218 218
@@ -274,8 +274,8 @@ private:
274 274
275class IGBPSetPreallocatedBufferRequestParcel : public Parcel { 275class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
276public: 276public:
277 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer) 277 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
278 : Parcel(std::move(buffer)) { 278 : Parcel(std::move(buffer_)) {
279 Deserialize(); 279 Deserialize();
280 } 280 }
281 281
@@ -312,7 +312,7 @@ protected:
312 312
313class IGBPCancelBufferRequestParcel : public Parcel { 313class IGBPCancelBufferRequestParcel : public Parcel {
314public: 314public:
315 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 315 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
316 Deserialize(); 316 Deserialize();
317 } 317 }
318 318
@@ -338,7 +338,7 @@ protected:
338 338
339class IGBPDequeueBufferRequestParcel : public Parcel { 339class IGBPDequeueBufferRequestParcel : public Parcel {
340public: 340public:
341 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 341 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
342 Deserialize(); 342 Deserialize();
343 } 343 }
344 344
@@ -360,8 +360,8 @@ public:
360 360
361class IGBPDequeueBufferResponseParcel : public Parcel { 361class IGBPDequeueBufferResponseParcel : public Parcel {
362public: 362public:
363 explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) 363 explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
364 : slot(slot), multi_fence(multi_fence) {} 364 : slot(slot_), multi_fence(multi_fence_) {}
365 365
366protected: 366protected:
367 void SerializeData() override { 367 void SerializeData() override {
@@ -377,7 +377,7 @@ protected:
377 377
378class IGBPRequestBufferRequestParcel : public Parcel { 378class IGBPRequestBufferRequestParcel : public Parcel {
379public: 379public:
380 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 380 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
381 Deserialize(); 381 Deserialize();
382 } 382 }
383 383
@@ -391,7 +391,7 @@ public:
391 391
392class IGBPRequestBufferResponseParcel : public Parcel { 392class IGBPRequestBufferResponseParcel : public Parcel {
393public: 393public:
394 explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) : buffer(buffer) {} 394 explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
395 ~IGBPRequestBufferResponseParcel() override = default; 395 ~IGBPRequestBufferResponseParcel() override = default;
396 396
397protected: 397protected:
@@ -408,7 +408,7 @@ protected:
408 408
409class IGBPQueueBufferRequestParcel : public Parcel { 409class IGBPQueueBufferRequestParcel : public Parcel {
410public: 410public:
411 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 411 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
412 Deserialize(); 412 Deserialize();
413 } 413 }
414 414
@@ -470,7 +470,7 @@ private:
470 470
471class IGBPQueryRequestParcel : public Parcel { 471class IGBPQueryRequestParcel : public Parcel {
472public: 472public:
473 explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 473 explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
474 Deserialize(); 474 Deserialize();
475 } 475 }
476 476
@@ -484,7 +484,7 @@ public:
484 484
485class IGBPQueryResponseParcel : public Parcel { 485class IGBPQueryResponseParcel : public Parcel {
486public: 486public:
487 explicit IGBPQueryResponseParcel(u32 value) : value(value) {} 487 explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
488 ~IGBPQueryResponseParcel() override = default; 488 ~IGBPQueryResponseParcel() override = default;
489 489
490protected: 490protected:
@@ -669,12 +669,10 @@ private:
669 669
670 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); 670 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
671 671
672 const auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
673
674 // TODO(Subv): Find out what this actually is. 672 // TODO(Subv): Find out what this actually is.
675 IPC::ResponseBuilder rb{ctx, 2, 1}; 673 IPC::ResponseBuilder rb{ctx, 2, 1};
676 rb.Push(RESULT_SUCCESS); 674 rb.Push(RESULT_SUCCESS);
677 rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); 675 rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent());
678 } 676 }
679 677
680 NVFlinger::NVFlinger& nv_flinger; 678 NVFlinger::NVFlinger& nv_flinger;
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index fed47ecda..022885c1b 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -13,8 +13,8 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/romfs_factory.h" 14#include "core/file_sys/romfs_factory.h"
15#include "core/hle/kernel/k_page_table.h" 15#include "core/hle/kernel/k_page_table.h"
16#include "core/hle/kernel/k_process.h"
16#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/process.h"
18#include "core/hle/service/filesystem/filesystem.h" 18#include "core/hle/service/filesystem/filesystem.h"
19#include "core/loader/deconstructed_rom_directory.h" 19#include "core/loader/deconstructed_rom_directory.h"
20#include "core/loader/nso.h" 20#include "core/loader/nso.h"
@@ -22,8 +22,8 @@
22namespace Loader { 22namespace Loader {
23 23
24AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_, 24AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
25 bool override_update) 25 bool override_update_)
26 : AppLoader(std::move(file_)), override_update(override_update) { 26 : AppLoader(std::move(file_)), override_update(override_update_) {
27 const auto file_dir = file->GetContainingDirectory(); 27 const auto file_dir = file->GetContainingDirectory();
28 28
29 // Title ID 29 // Title ID
@@ -48,9 +48,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
48 // Any png, jpeg, or bmp file 48 // Any png, jpeg, or bmp file
49 const auto& files = file_dir->GetFiles(); 49 const auto& files = file_dir->GetFiles();
50 const auto icon_iter = 50 const auto icon_iter =
51 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { 51 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
52 return file->GetExtension() == "png" || file->GetExtension() == "jpg" || 52 return f->GetExtension() == "png" || f->GetExtension() == "jpg" ||
53 file->GetExtension() == "bmp" || file->GetExtension() == "jpeg"; 53 f->GetExtension() == "bmp" || f->GetExtension() == "jpeg";
54 }); 54 });
55 if (icon_iter != files.end()) 55 if (icon_iter != files.end())
56 icon_data = (*icon_iter)->ReadAllBytes(); 56 icon_data = (*icon_iter)->ReadAllBytes();
@@ -61,9 +61,8 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
61 if (nacp_file == nullptr) { 61 if (nacp_file == nullptr) {
62 const auto& files = file_dir->GetFiles(); 62 const auto& files = file_dir->GetFiles();
63 const auto nacp_iter = 63 const auto nacp_iter =
64 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { 64 std::find_if(files.begin(), files.end(),
65 return file->GetExtension() == "nacp"; 65 [](const FileSys::VirtualFile& f) { return f->GetExtension() == "nacp"; });
66 });
67 if (nacp_iter != files.end()) 66 if (nacp_iter != files.end())
68 nacp_file = *nacp_iter; 67 nacp_file = *nacp_iter;
69 } 68 }
@@ -75,9 +74,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
75} 74}
76 75
77AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( 76AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
78 FileSys::VirtualDir directory, bool override_update) 77 FileSys::VirtualDir directory, bool override_update_)
79 : AppLoader(directory->GetFile("main")), dir(std::move(directory)), 78 : AppLoader(directory->GetFile("main")), dir(std::move(directory)),
80 override_update(override_update) {} 79 override_update(override_update_) {}
81 80
82FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) { 81FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
83 if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) { 82 if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
@@ -88,7 +87,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua
88} 87}
89 88
90AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load( 89AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load(
91 Kernel::Process& process, Core::System& system) { 90 Kernel::KProcess& process, Core::System& system) {
92 if (is_loaded) { 91 if (is_loaded) {
93 return {ResultStatus::ErrorAlreadyLoaded, {}}; 92 return {ResultStatus::ErrorAlreadyLoaded, {}};
94 } 93 }
@@ -184,8 +183,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
184 // Find the RomFS by searching for a ".romfs" file in this directory 183 // Find the RomFS by searching for a ".romfs" file in this directory
185 const auto& files = dir->GetFiles(); 184 const auto& files = dir->GetFiles();
186 const auto romfs_iter = 185 const auto romfs_iter =
187 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { 186 std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
188 return file->GetName().find(".romfs") != std::string::npos; 187 return f->GetName().find(".romfs") != std::string::npos;
189 }); 188 });
190 189
191 // Register the RomFS if a ".romfs" file was found 190 // Register the RomFS if a ".romfs" file was found
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 22a4ec5a6..79a4d4db5 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -24,11 +24,11 @@ namespace Loader {
24class AppLoader_DeconstructedRomDirectory final : public AppLoader { 24class AppLoader_DeconstructedRomDirectory final : public AppLoader {
25public: 25public:
26 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file, 26 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file,
27 bool override_update = false); 27 bool override_update_ = false);
28 28
29 // Overload to accept exefs directory. Must contain 'main' and 'main.npdm' 29 // Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
30 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory, 30 explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
31 bool override_update = false); 31 bool override_update_ = false);
32 32
33 /** 33 /**
34 * Identifies whether or not the given file is a deconstructed ROM directory. 34 * Identifies whether or not the given file is a deconstructed ROM directory.
@@ -44,7 +44,7 @@ public:
44 return IdentifyType(file); 44 return IdentifyType(file);
45 } 45 }
46 46
47 LoadResult Load(Kernel::Process& process, Core::System& system) override; 47 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
48 48
49 ResultStatus ReadRomFS(FileSys::VirtualFile& out_dir) override; 49 ResultStatus ReadRomFS(FileSys::VirtualFile& out_dir) override;
50 ResultStatus ReadIcon(std::vector<u8>& out_buffer) override; 50 ResultStatus ReadIcon(std::vector<u8>& out_buffer) override;
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 627c18c7e..c062a4259 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -11,7 +11,7 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/hle/kernel/code_set.h" 12#include "core/hle/kernel/code_set.h"
13#include "core/hle/kernel/k_page_table.h" 13#include "core/hle/kernel/k_page_table.h"
14#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/k_process.h"
15#include "core/loader/elf.h" 15#include "core/loader/elf.h"
16#include "core/memory.h" 16#include "core/memory.h"
17 17
@@ -386,7 +386,7 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& elf_file) {
386 return FileType::Error; 386 return FileType::Error;
387} 387}
388 388
389AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process, 389AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::KProcess& process,
390 [[maybe_unused]] Core::System& system) { 390 [[maybe_unused]] Core::System& system) {
391 if (is_loaded) { 391 if (is_loaded) {
392 return {ResultStatus::ErrorAlreadyLoaded, {}}; 392 return {ResultStatus::ErrorAlreadyLoaded, {}};
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 2b86c0b49..890299a20 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -32,7 +32,7 @@ public:
32 return IdentifyType(file); 32 return IdentifyType(file);
33 } 33 }
34 34
35 LoadResult Load(Kernel::Process& process, Core::System& system) override; 35 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
36}; 36};
37 37
38} // namespace Loader 38} // namespace Loader
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 9b447da2a..3ae9e6e0e 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -7,7 +7,7 @@
7#include "core/file_sys/program_metadata.h" 7#include "core/file_sys/program_metadata.h"
8#include "core/hle/kernel/code_set.h" 8#include "core/hle/kernel/code_set.h"
9#include "core/hle/kernel/k_page_table.h" 9#include "core/hle/kernel/k_page_table.h"
10#include "core/hle/kernel/process.h" 10#include "core/hle/kernel/k_process.h"
11#include "core/loader/kip.h" 11#include "core/loader/kip.h"
12#include "core/memory.h" 12#include "core/memory.h"
13 13
@@ -42,7 +42,7 @@ FileType AppLoader_KIP::GetFileType() const {
42 : FileType::Error; 42 : FileType::Error;
43} 43}
44 44
45AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process, 45AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
46 [[maybe_unused]] Core::System& system) { 46 [[maybe_unused]] Core::System& system) {
47 if (is_loaded) { 47 if (is_loaded) {
48 return {ResultStatus::ErrorAlreadyLoaded, {}}; 48 return {ResultStatus::ErrorAlreadyLoaded, {}};
diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h
index 2fe636f01..5f914b4a8 100644
--- a/src/core/loader/kip.h
+++ b/src/core/loader/kip.h
@@ -32,7 +32,7 @@ public:
32 32
33 FileType GetFileType() const override; 33 FileType GetFileType() const override;
34 34
35 LoadResult Load(Kernel::Process& process, Core::System& system) override; 35 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
36 36
37private: 37private:
38 std::unique_ptr<FileSys::KIP> kip; 38 std::unique_ptr<FileSys::KIP> kip;
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index e4f5fd40c..d4808fb5b 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -11,7 +11,7 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/string_util.h" 12#include "common/string_util.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/k_process.h"
15#include "core/loader/deconstructed_rom_directory.h" 15#include "core/loader/deconstructed_rom_directory.h"
16#include "core/loader/elf.h" 16#include "core/loader/elf.h"
17#include "core/loader/kip.h" 17#include "core/loader/kip.h"
@@ -194,7 +194,7 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status) {
194 return os; 194 return os;
195} 195}
196 196
197AppLoader::AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {} 197AppLoader::AppLoader(FileSys::VirtualFile file_) : file(std::move(file_)) {}
198AppLoader::~AppLoader() = default; 198AppLoader::~AppLoader() = default;
199 199
200/** 200/**
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index bf6db1ab1..edc8bb257 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -25,7 +25,7 @@ class NACP;
25 25
26namespace Kernel { 26namespace Kernel {
27struct AddressMapping; 27struct AddressMapping;
28class Process; 28class KProcess;
29} // namespace Kernel 29} // namespace Kernel
30 30
31namespace Loader { 31namespace Loader {
@@ -147,7 +147,7 @@ public:
147 }; 147 };
148 using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>; 148 using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>;
149 149
150 explicit AppLoader(FileSys::VirtualFile file); 150 explicit AppLoader(FileSys::VirtualFile file_);
151 virtual ~AppLoader(); 151 virtual ~AppLoader();
152 152
153 /** 153 /**
@@ -165,7 +165,7 @@ public:
165 * 165 *
166 * @return The status result of the operation. 166 * @return The status result of the operation.
167 */ 167 */
168 virtual LoadResult Load(Kernel::Process& process, Core::System& system) = 0; 168 virtual LoadResult Load(Kernel::KProcess& process, Core::System& system) = 0;
169 169
170 /** 170 /**
171 * Get the code (typically .code section) of the application 171 * Get the code (typically .code section) of the application
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index f53c3a72c..aceb66414 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -6,7 +6,7 @@
6#include "core/file_sys/content_archive.h" 6#include "core/file_sys/content_archive.h"
7#include "core/file_sys/romfs.h" 7#include "core/file_sys/romfs.h"
8#include "core/file_sys/xts_archive.h" 8#include "core/file_sys/xts_archive.h"
9#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/k_process.h"
10#include "core/loader/nax.h" 10#include "core/loader/nax.h"
11#include "core/loader/nca.h" 11#include "core/loader/nca.h"
12 12
@@ -41,7 +41,7 @@ FileType AppLoader_NAX::GetFileType() const {
41 return IdentifyTypeImpl(*nax); 41 return IdentifyTypeImpl(*nax);
42} 42}
43 43
44AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process, Core::System& system) { 44AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::KProcess& process, Core::System& system) {
45 if (is_loaded) { 45 if (is_loaded) {
46 return {ResultStatus::ErrorAlreadyLoaded, {}}; 46 return {ResultStatus::ErrorAlreadyLoaded, {}};
47 } 47 }
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index 68427c1cf..b3a50894f 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -37,7 +37,7 @@ public:
37 37
38 FileType GetFileType() const override; 38 FileType GetFileType() const override;
39 39
40 LoadResult Load(Kernel::Process& process, Core::System& system) override; 40 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
41 41
42 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 42 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
43 u64 ReadRomFSIVFCOffset() const override; 43 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 47e7a77a9..418cbf61b 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -9,7 +9,7 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
11#include "core/file_sys/romfs_factory.h" 11#include "core/file_sys/romfs_factory.h"
12#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/k_process.h"
13#include "core/hle/service/filesystem/filesystem.h" 13#include "core/hle/service/filesystem/filesystem.h"
14#include "core/loader/deconstructed_rom_directory.h" 14#include "core/loader/deconstructed_rom_directory.h"
15#include "core/loader/nca.h" 15#include "core/loader/nca.h"
@@ -32,7 +32,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& nca_file) {
32 return FileType::Error; 32 return FileType::Error;
33} 33}
34 34
35AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::System& system) { 35AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::System& system) {
36 if (is_loaded) { 36 if (is_loaded) {
37 return {ResultStatus::ErrorAlreadyLoaded, {}}; 37 return {ResultStatus::ErrorAlreadyLoaded, {}};
38 } 38 }
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index c9792f390..f2ff080bb 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -39,7 +39,7 @@ public:
39 return IdentifyType(file); 39 return IdentifyType(file);
40 } 40 }
41 41
42 LoadResult Load(Kernel::Process& process, Core::System& system) override; 42 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
43 43
44 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 44 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
45 u64 ReadRomFSIVFCOffset() const override; 45 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 0597cfa60..ef54fa574 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -17,8 +17,8 @@
17#include "core/file_sys/vfs_offset.h" 17#include "core/file_sys/vfs_offset.h"
18#include "core/hle/kernel/code_set.h" 18#include "core/hle/kernel/code_set.h"
19#include "core/hle/kernel/k_page_table.h" 19#include "core/hle/kernel/k_page_table.h"
20#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/k_thread.h" 21#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/process.h"
22#include "core/hle/service/filesystem/filesystem.h" 22#include "core/hle/service/filesystem/filesystem.h"
23#include "core/loader/nro.h" 23#include "core/loader/nro.h"
24#include "core/loader/nso.h" 24#include "core/loader/nso.h"
@@ -130,7 +130,7 @@ static constexpr u32 PageAlignSize(u32 size) {
130 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); 130 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
131} 131}
132 132
133static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data) { 133static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) {
134 if (data.size() < sizeof(NroHeader)) { 134 if (data.size() < sizeof(NroHeader)) {
135 return {}; 135 return {};
136 } 136 }
@@ -199,11 +199,11 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data) {
199 return true; 199 return true;
200} 200}
201 201
202bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& nro_file) { 202bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) {
203 return LoadNroImpl(process, nro_file.ReadAllBytes()); 203 return LoadNroImpl(process, nro_file.ReadAllBytes());
204} 204}
205 205
206AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::System& system) { 206AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) {
207 if (is_loaded) { 207 if (is_loaded) {
208 return {ResultStatus::ErrorAlreadyLoaded, {}}; 208 return {ResultStatus::ErrorAlreadyLoaded, {}};
209 } 209 }
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 20bbaeb0e..fd453b402 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -19,7 +19,7 @@ class NACP;
19} 19}
20 20
21namespace Kernel { 21namespace Kernel {
22class Process; 22class KProcess;
23} 23}
24 24
25namespace Loader { 25namespace Loader {
@@ -43,7 +43,7 @@ public:
43 return IdentifyType(file); 43 return IdentifyType(file);
44 } 44 }
45 45
46 LoadResult Load(Kernel::Process& process, Core::System& system) override; 46 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
47 47
48 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 48 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
49 ResultStatus ReadProgramId(u64& out_program_id) override; 49 ResultStatus ReadProgramId(u64& out_program_id) override;
@@ -53,7 +53,7 @@ public:
53 bool IsRomFSUpdatable() const override; 53 bool IsRomFSUpdatable() const override;
54 54
55private: 55private:
56 bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& nro_file); 56 bool LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file);
57 57
58 std::vector<u8> icon_data; 58 std::vector<u8> icon_data;
59 std::unique_ptr<FileSys::NACP> nacp; 59 std::unique_ptr<FileSys::NACP> nacp;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index f671afe02..df59412cf 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -17,8 +17,8 @@
17#include "core/file_sys/patch_manager.h" 17#include "core/file_sys/patch_manager.h"
18#include "core/hle/kernel/code_set.h" 18#include "core/hle/kernel/code_set.h"
19#include "core/hle/kernel/k_page_table.h" 19#include "core/hle/kernel/k_page_table.h"
20#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/k_thread.h" 21#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/process.h"
22#include "core/loader/nso.h" 22#include "core/loader/nso.h"
23#include "core/memory.h" 23#include "core/memory.h"
24 24
@@ -71,7 +71,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) {
71 return FileType::NSO; 71 return FileType::NSO;
72} 72}
73 73
74std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::System& system, 74std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system,
75 const FileSys::VfsFile& nso_file, VAddr load_base, 75 const FileSys::VfsFile& nso_file, VAddr load_base,
76 bool should_pass_arguments, bool load_into_process, 76 bool should_pass_arguments, bool load_into_process,
77 std::optional<FileSys::PatchManager> pm) { 77 std::optional<FileSys::PatchManager> pm) {
@@ -162,7 +162,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
162 return load_base + image_size; 162 return load_base + image_size;
163} 163}
164 164
165AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::System& system) { 165AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::System& system) {
166 if (is_loaded) { 166 if (is_loaded) {
167 return {ResultStatus::ErrorAlreadyLoaded, {}}; 167 return {ResultStatus::ErrorAlreadyLoaded, {}};
168 } 168 }
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 195149b55..f7b61bc2d 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -17,7 +17,7 @@ class System;
17} 17}
18 18
19namespace Kernel { 19namespace Kernel {
20class Process; 20class KProcess;
21} 21}
22 22
23namespace Loader { 23namespace Loader {
@@ -86,12 +86,12 @@ public:
86 return IdentifyType(file); 86 return IdentifyType(file);
87 } 87 }
88 88
89 static std::optional<VAddr> LoadModule(Kernel::Process& process, Core::System& system, 89 static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system,
90 const FileSys::VfsFile& nso_file, VAddr load_base, 90 const FileSys::VfsFile& nso_file, VAddr load_base,
91 bool should_pass_arguments, bool load_into_process, 91 bool should_pass_arguments, bool load_into_process,
92 std::optional<FileSys::PatchManager> pm = {}); 92 std::optional<FileSys::PatchManager> pm = {});
93 93
94 LoadResult Load(Kernel::Process& process, Core::System& system) override; 94 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
95 95
96 ResultStatus ReadNSOModules(Modules& out_modules) override; 96 ResultStatus ReadNSOModules(Modules& out_modules) override;
97 97
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index d7e590f1c..d815a7cd3 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -13,7 +13,7 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/submission_package.h" 15#include "core/file_sys/submission_package.h"
16#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/k_process.h"
17#include "core/hle/service/filesystem/filesystem.h" 17#include "core/hle/service/filesystem/filesystem.h"
18#include "core/loader/deconstructed_rom_directory.h" 18#include "core/loader/deconstructed_rom_directory.h"
19#include "core/loader/nca.h" 19#include "core/loader/nca.h"
@@ -79,7 +79,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) {
79 return FileType::Error; 79 return FileType::Error;
80} 80}
81 81
82AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::System& system) { 82AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::System& system) {
83 if (is_loaded) { 83 if (is_loaded) {
84 return {ResultStatus::ErrorAlreadyLoaded, {}}; 84 return {ResultStatus::ErrorAlreadyLoaded, {}};
85 } 85 }
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 1660f1b94..644c0ff58 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -45,7 +45,7 @@ public:
45 return IdentifyType(file); 45 return IdentifyType(file);
46 } 46 }
47 47
48 LoadResult Load(Kernel::Process& process, Core::System& system) override; 48 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
49 49
50 ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override; 50 ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
51 u64 ReadRomFSIVFCOffset() const override; 51 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 0125ddf33..635d6ae15 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -13,7 +13,7 @@
13#include "core/file_sys/registered_cache.h" 13#include "core/file_sys/registered_cache.h"
14#include "core/file_sys/romfs.h" 14#include "core/file_sys/romfs.h"
15#include "core/file_sys/submission_package.h" 15#include "core/file_sys/submission_package.h"
16#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/k_process.h"
17#include "core/hle/service/filesystem/filesystem.h" 17#include "core/hle/service/filesystem/filesystem.h"
18#include "core/loader/nca.h" 18#include "core/loader/nca.h"
19#include "core/loader/xci.h" 19#include "core/loader/xci.h"
@@ -56,7 +56,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& xci_file) {
56 return FileType::Error; 56 return FileType::Error;
57} 57}
58 58
59AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::System& system) { 59AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::System& system) {
60 if (is_loaded) { 60 if (is_loaded) {
61 return {ResultStatus::ErrorAlreadyLoaded, {}}; 61 return {ResultStatus::ErrorAlreadyLoaded, {}};
62 } 62 }
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 7ea8179af..708155c30 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -45,7 +45,7 @@ public:
45 return IdentifyType(file); 45 return IdentifyType(file);
46 } 46 }
47 47
48 LoadResult Load(Kernel::Process& process, Core::System& system) override; 48 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
49 49
50 ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override; 50 ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
51 u64 ReadRomFSIVFCOffset() const override; 51 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index b9dd3e275..b4c56e1c1 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -17,8 +17,8 @@
17#include "core/core.h" 17#include "core/core.h"
18#include "core/device_memory.h" 18#include "core/device_memory.h"
19#include "core/hle/kernel/k_page_table.h" 19#include "core/hle/kernel/k_page_table.h"
20#include "core/hle/kernel/k_process.h"
20#include "core/hle/kernel/physical_memory.h" 21#include "core/hle/kernel/physical_memory.h"
21#include "core/hle/kernel/process.h"
22#include "core/memory.h" 22#include "core/memory.h"
23#include "video_core/gpu.h" 23#include "video_core/gpu.h"
24 24
@@ -30,7 +30,7 @@ namespace Core::Memory {
30struct Memory::Impl { 30struct Memory::Impl {
31 explicit Impl(Core::System& system_) : system{system_} {} 31 explicit Impl(Core::System& system_) : system{system_} {}
32 32
33 void SetCurrentPageTable(Kernel::Process& process, u32 core_id) { 33 void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
34 current_page_table = &process.PageTable().PageTableImpl(); 34 current_page_table = &process.PageTable().PageTableImpl();
35 35
36 const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth(); 36 const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth();
@@ -50,7 +50,7 @@ struct Memory::Impl {
50 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped); 50 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped);
51 } 51 }
52 52
53 bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { 53 bool IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const {
54 const auto& page_table = process.PageTable().PageTableImpl(); 54 const auto& page_table = process.PageTable().PageTableImpl();
55 const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType(); 55 const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType();
56 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory; 56 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory;
@@ -82,6 +82,22 @@ struct Memory::Impl {
82 return nullptr; 82 return nullptr;
83 } 83 }
84 84
85 u8* GetKernelBuffer(VAddr start_vaddr, size_t size) {
86 // TODO(bunnei): This is just a workaround until we have kernel memory layout mapped &
87 // managed. Until then, we use this to allocate and access kernel memory regions.
88
89 auto search = kernel_memory_regions.find(start_vaddr);
90 if (search != kernel_memory_regions.end()) {
91 return search->second.get();
92 }
93
94 std::unique_ptr<u8[]> new_memory_region{new u8[size]};
95 u8* raw_ptr = new_memory_region.get();
96 kernel_memory_regions[start_vaddr] = std::move(new_memory_region);
97
98 return raw_ptr;
99 }
100
85 u8 Read8(const VAddr addr) { 101 u8 Read8(const VAddr addr) {
86 return Read<u8>(addr); 102 return Read<u8>(addr);
87 } 103 }
@@ -178,7 +194,7 @@ struct Memory::Impl {
178 return string; 194 return string;
179 } 195 }
180 196
181 void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 197 void ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
182 const std::size_t size) { 198 const std::size_t size) {
183 const auto& page_table = process.PageTable().PageTableImpl(); 199 const auto& page_table = process.PageTable().PageTableImpl();
184 200
@@ -223,7 +239,7 @@ struct Memory::Impl {
223 } 239 }
224 } 240 }
225 241
226 void ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 242 void ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
227 const std::size_t size) { 243 const std::size_t size) {
228 const auto& page_table = process.PageTable().PageTableImpl(); 244 const auto& page_table = process.PageTable().PageTableImpl();
229 245
@@ -275,7 +291,7 @@ struct Memory::Impl {
275 ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size); 291 ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size);
276 } 292 }
277 293
278 void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, 294 void WriteBlock(const Kernel::KProcess& process, const VAddr dest_addr, const void* src_buffer,
279 const std::size_t size) { 295 const std::size_t size) {
280 const auto& page_table = process.PageTable().PageTableImpl(); 296 const auto& page_table = process.PageTable().PageTableImpl();
281 std::size_t remaining_size = size; 297 std::size_t remaining_size = size;
@@ -318,7 +334,7 @@ struct Memory::Impl {
318 } 334 }
319 } 335 }
320 336
321 void WriteBlockUnsafe(const Kernel::Process& process, const VAddr dest_addr, 337 void WriteBlockUnsafe(const Kernel::KProcess& process, const VAddr dest_addr,
322 const void* src_buffer, const std::size_t size) { 338 const void* src_buffer, const std::size_t size) {
323 const auto& page_table = process.PageTable().PageTableImpl(); 339 const auto& page_table = process.PageTable().PageTableImpl();
324 std::size_t remaining_size = size; 340 std::size_t remaining_size = size;
@@ -368,7 +384,7 @@ struct Memory::Impl {
368 WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size); 384 WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size);
369 } 385 }
370 386
371 void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 387 void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) {
372 const auto& page_table = process.PageTable().PageTableImpl(); 388 const auto& page_table = process.PageTable().PageTableImpl();
373 std::size_t remaining_size = size; 389 std::size_t remaining_size = size;
374 std::size_t page_index = dest_addr >> PAGE_BITS; 390 std::size_t page_index = dest_addr >> PAGE_BITS;
@@ -413,7 +429,7 @@ struct Memory::Impl {
413 ZeroBlock(*system.CurrentProcess(), dest_addr, size); 429 ZeroBlock(*system.CurrentProcess(), dest_addr, size);
414 } 430 }
415 431
416 void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, 432 void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
417 const std::size_t size) { 433 const std::size_t size) {
418 const auto& page_table = process.PageTable().PageTableImpl(); 434 const auto& page_table = process.PageTable().PageTableImpl();
419 std::size_t remaining_size = size; 435 std::size_t remaining_size = size;
@@ -711,13 +727,21 @@ struct Memory::Impl {
711 } 727 }
712 728
713 Common::PageTable* current_page_table = nullptr; 729 Common::PageTable* current_page_table = nullptr;
730 std::unordered_map<VAddr, std::unique_ptr<u8[]>> kernel_memory_regions;
714 Core::System& system; 731 Core::System& system;
715}; 732};
716 733
717Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {} 734Memory::Memory(Core::System& system_) : system{system_} {
735 Reset();
736}
737
718Memory::~Memory() = default; 738Memory::~Memory() = default;
719 739
720void Memory::SetCurrentPageTable(Kernel::Process& process, u32 core_id) { 740void Memory::Reset() {
741 impl = std::make_unique<Impl>(system);
742}
743
744void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
721 impl->SetCurrentPageTable(process, core_id); 745 impl->SetCurrentPageTable(process, core_id);
722} 746}
723 747
@@ -729,7 +753,7 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
729 impl->UnmapRegion(page_table, base, size); 753 impl->UnmapRegion(page_table, base, size);
730} 754}
731 755
732bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { 756bool Memory::IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const {
733 return impl->IsValidVirtualAddress(process, vaddr); 757 return impl->IsValidVirtualAddress(process, vaddr);
734} 758}
735 759
@@ -741,6 +765,10 @@ u8* Memory::GetPointer(VAddr vaddr) {
741 return impl->GetPointer(vaddr); 765 return impl->GetPointer(vaddr);
742} 766}
743 767
768u8* Memory::GetKernelBuffer(VAddr start_vaddr, size_t size) {
769 return impl->GetKernelBuffer(start_vaddr, size);
770}
771
744const u8* Memory::GetPointer(VAddr vaddr) const { 772const u8* Memory::GetPointer(VAddr vaddr) const {
745 return impl->GetPointer(vaddr); 773 return impl->GetPointer(vaddr);
746} 774}
@@ -801,7 +829,7 @@ std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
801 return impl->ReadCString(vaddr, max_length); 829 return impl->ReadCString(vaddr, max_length);
802} 830}
803 831
804void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 832void Memory::ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
805 const std::size_t size) { 833 const std::size_t size) {
806 impl->ReadBlock(process, src_addr, dest_buffer, size); 834 impl->ReadBlock(process, src_addr, dest_buffer, size);
807} 835}
@@ -810,7 +838,7 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_
810 impl->ReadBlock(src_addr, dest_buffer, size); 838 impl->ReadBlock(src_addr, dest_buffer, size);
811} 839}
812 840
813void Memory::ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, 841void Memory::ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr,
814 void* dest_buffer, const std::size_t size) { 842 void* dest_buffer, const std::size_t size) {
815 impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size); 843 impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size);
816} 844}
@@ -819,7 +847,7 @@ void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std:
819 impl->ReadBlockUnsafe(src_addr, dest_buffer, size); 847 impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
820} 848}
821 849
822void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, 850void Memory::WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
823 std::size_t size) { 851 std::size_t size) {
824 impl->WriteBlock(process, dest_addr, src_buffer, size); 852 impl->WriteBlock(process, dest_addr, src_buffer, size);
825} 853}
@@ -828,7 +856,7 @@ void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std
828 impl->WriteBlock(dest_addr, src_buffer, size); 856 impl->WriteBlock(dest_addr, src_buffer, size);
829} 857}
830 858
831void Memory::WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, 859void Memory::WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr,
832 const void* src_buffer, std::size_t size) { 860 const void* src_buffer, std::size_t size) {
833 impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size); 861 impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size);
834} 862}
@@ -838,7 +866,7 @@ void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer,
838 impl->WriteBlockUnsafe(dest_addr, src_buffer, size); 866 impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
839} 867}
840 868
841void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) { 869void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
842 impl->ZeroBlock(process, dest_addr, size); 870 impl->ZeroBlock(process, dest_addr, size);
843} 871}
844 872
@@ -846,7 +874,7 @@ void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) {
846 impl->ZeroBlock(dest_addr, size); 874 impl->ZeroBlock(dest_addr, size);
847} 875}
848 876
849void Memory::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, 877void Memory::CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
850 const std::size_t size) { 878 const std::size_t size) {
851 impl->CopyBlock(process, dest_addr, src_addr, size); 879 impl->CopyBlock(process, dest_addr, src_addr, size);
852} 880}
diff --git a/src/core/memory.h b/src/core/memory.h
index 6d34fcfe2..345fd870d 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -19,7 +19,7 @@ class System;
19 19
20namespace Kernel { 20namespace Kernel {
21class PhysicalMemory; 21class PhysicalMemory;
22class Process; 22class KProcess;
23} // namespace Kernel 23} // namespace Kernel
24 24
25namespace Core::Memory { 25namespace Core::Memory {
@@ -59,11 +59,16 @@ public:
59 Memory& operator=(Memory&&) = default; 59 Memory& operator=(Memory&&) = default;
60 60
61 /** 61 /**
62 * Resets the state of the Memory system.
63 */
64 void Reset();
65
66 /**
62 * Changes the currently active page table to that of the given process instance. 67 * Changes the currently active page table to that of the given process instance.
63 * 68 *
64 * @param process The process to use the page table of. 69 * @param process The process to use the page table of.
65 */ 70 */
66 void SetCurrentPageTable(Kernel::Process& process, u32 core_id); 71 void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id);
67 72
68 /** 73 /**
69 * Maps an allocated buffer onto a region of the emulated process address space. 74 * Maps an allocated buffer onto a region of the emulated process address space.
@@ -94,7 +99,7 @@ public:
94 * 99 *
95 * @returns True if the given virtual address is valid, false otherwise. 100 * @returns True if the given virtual address is valid, false otherwise.
96 */ 101 */
97 bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const; 102 bool IsValidVirtualAddress(const Kernel::KProcess& process, VAddr vaddr) const;
98 103
99 /** 104 /**
100 * Checks whether or not the supplied address is a valid virtual 105 * Checks whether or not the supplied address is a valid virtual
@@ -116,6 +121,15 @@ public:
116 */ 121 */
117 u8* GetPointer(VAddr vaddr); 122 u8* GetPointer(VAddr vaddr);
118 123
124 /**
125 * Gets a pointer to the start of a kernel heap allocated memory region. Will allocate one if it
126 * does not already exist.
127 *
128 * @param start_vaddr Start virtual address for the memory region.
129 * @param size Size of the memory region.
130 */
131 u8* GetKernelBuffer(VAddr start_vaddr, size_t size);
132
119 template <typename T> 133 template <typename T>
120 T* GetPointer(VAddr vaddr) { 134 T* GetPointer(VAddr vaddr) {
121 return reinterpret_cast<T*>(GetPointer(vaddr)); 135 return reinterpret_cast<T*>(GetPointer(vaddr));
@@ -319,7 +333,7 @@ public:
319 * @post The range [dest_buffer, size) contains the read bytes from the 333 * @post The range [dest_buffer, size) contains the read bytes from the
320 * process' address space. 334 * process' address space.
321 */ 335 */
322 void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, 336 void ReadBlock(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer,
323 std::size_t size); 337 std::size_t size);
324 338
325 /** 339 /**
@@ -340,7 +354,7 @@ public:
340 * @post The range [dest_buffer, size) contains the read bytes from the 354 * @post The range [dest_buffer, size) contains the read bytes from the
341 * process' address space. 355 * process' address space.
342 */ 356 */
343 void ReadBlockUnsafe(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, 357 void ReadBlockUnsafe(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer,
344 std::size_t size); 358 std::size_t size);
345 359
346 /** 360 /**
@@ -400,7 +414,7 @@ public:
400 * and will mark that region as invalidated to caches that the active 414 * and will mark that region as invalidated to caches that the active
401 * graphics backend may be maintaining over the course of execution. 415 * graphics backend may be maintaining over the course of execution.
402 */ 416 */
403 void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, 417 void WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
404 std::size_t size); 418 std::size_t size);
405 419
406 /** 420 /**
@@ -420,7 +434,7 @@ public:
420 * will be ignored and an error will be logged. 434 * will be ignored and an error will be logged.
421 * 435 *
422 */ 436 */
423 void WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer, 437 void WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
424 std::size_t size); 438 std::size_t size);
425 439
426 /** 440 /**
@@ -472,7 +486,7 @@ public:
472 * @post The range [dest_addr, size) within the process' address space is 486 * @post The range [dest_addr, size) within the process' address space is
473 * filled with zeroes. 487 * filled with zeroes.
474 */ 488 */
475 void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); 489 void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
476 490
477 /** 491 /**
478 * Fills the specified address range within the current process' address space with zeroes. 492 * Fills the specified address range within the current process' address space with zeroes.
@@ -497,7 +511,7 @@ public:
497 * @post The range [dest_addr, size) within the process' address space contains the 511 * @post The range [dest_addr, size) within the process' address space contains the
498 * same data within the range [src_addr, size). 512 * same data within the range [src_addr, size).
499 */ 513 */
500 void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, 514 void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
501 std::size_t size); 515 std::size_t size);
502 516
503 /** 517 /**
@@ -524,6 +538,8 @@ public:
524 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached); 538 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
525 539
526private: 540private:
541 Core::System& system;
542
527 struct Impl; 543 struct Impl;
528 std::unique_ptr<Impl> impl; 544 std::unique_ptr<Impl> impl;
529}; 545};
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 7643b7846..46a7e09b4 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -11,7 +11,7 @@
11#include "core/core_timing_util.h" 11#include "core/core_timing_util.h"
12#include "core/hardware_properties.h" 12#include "core/hardware_properties.h"
13#include "core/hle/kernel/k_page_table.h" 13#include "core/hle/kernel/k_page_table.h"
14#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/k_process.h"
15#include "core/hle/service/hid/controllers/npad.h" 15#include "core/hle/service/hid/controllers/npad.h"
16#include "core/hle/service/hid/hid.h" 16#include "core/hle/service/hid/hid.h"
17#include "core/hle/service/sm/sm.h" 17#include "core/hle/service/sm/sm.h"
@@ -37,8 +37,8 @@ std::string_view ExtractName(std::string_view data, std::size_t start_index, cha
37} 37}
38} // Anonymous namespace 38} // Anonymous namespace
39 39
40StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata) 40StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_)
41 : metadata(metadata), system(system) {} 41 : metadata{metadata_}, system{system_} {}
42 42
43StandardVmCallbacks::~StandardVmCallbacks() = default; 43StandardVmCallbacks::~StandardVmCallbacks() = default;
44 44
@@ -174,11 +174,11 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
174 return out; 174 return out;
175} 175}
176 176
177CheatEngine::CheatEngine(Core::System& system, std::vector<CheatEntry> cheats, 177CheatEngine::CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
178 const std::array<u8, 0x20>& build_id) 178 const std::array<u8, 0x20>& build_id_)
179 : vm{std::make_unique<StandardVmCallbacks>(system, metadata)}, 179 : vm{std::make_unique<StandardVmCallbacks>(system_, metadata)},
180 cheats(std::move(cheats)), core_timing{system.CoreTiming()}, system{system} { 180 cheats(std::move(cheats_)), core_timing{system_.CoreTiming()}, system{system_} {
181 metadata.main_nso_build_id = build_id; 181 metadata.main_nso_build_id = build_id_;
182} 182}
183 183
184CheatEngine::~CheatEngine() { 184CheatEngine::~CheatEngine() {
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index 5e6f901ec..a8e041d9d 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -25,7 +25,7 @@ namespace Core::Memory {
25 25
26class StandardVmCallbacks : public DmntCheatVm::Callbacks { 26class StandardVmCallbacks : public DmntCheatVm::Callbacks {
27public: 27public:
28 StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata); 28 StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
29 ~StandardVmCallbacks() override; 29 ~StandardVmCallbacks() override;
30 30
31 void MemoryRead(VAddr address, void* data, u64 size) override; 31 void MemoryRead(VAddr address, void* data, u64 size) override;
@@ -38,7 +38,7 @@ private:
38 VAddr SanitizeAddress(VAddr address) const; 38 VAddr SanitizeAddress(VAddr address) const;
39 39
40 const CheatProcessMetadata& metadata; 40 const CheatProcessMetadata& metadata;
41 Core::System& system; 41 System& system;
42}; 42};
43 43
44// Intermediary class that parses a text file or other disk format for storing cheats into a 44// Intermediary class that parses a text file or other disk format for storing cheats into a
@@ -61,8 +61,8 @@ public:
61// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming 61// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
62class CheatEngine final { 62class CheatEngine final {
63public: 63public:
64 CheatEngine(Core::System& system_, std::vector<CheatEntry> cheats_, 64 CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
65 const std::array<u8, 0x20>& build_id); 65 const std::array<u8, 0x20>& build_id_);
66 ~CheatEngine(); 66 ~CheatEngine();
67 67
68 void Initialize(); 68 void Initialize();
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index 48be80c12..dc04e37d2 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -29,7 +29,8 @@
29 29
30namespace Core::Memory { 30namespace Core::Memory {
31 31
32DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {} 32DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks_)
33 : callbacks(std::move(callbacks_)) {}
33 34
34DmntCheatVm::~DmntCheatVm() = default; 35DmntCheatVm::~DmntCheatVm() = default;
35 36
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h
index 21b86b72c..707bee82b 100644
--- a/src/core/memory/dmnt_cheat_vm.h
+++ b/src/core/memory/dmnt_cheat_vm.h
@@ -293,7 +293,7 @@ public:
293 static constexpr std::size_t NumStaticRegisters = 293 static constexpr std::size_t NumStaticRegisters =
294 NumReadableStaticRegisters + NumWritableStaticRegisters; 294 NumReadableStaticRegisters + NumWritableStaticRegisters;
295 295
296 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks); 296 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks_);
297 ~DmntCheatVm(); 297 ~DmntCheatVm();
298 298
299 std::size_t GetProgramSize() const { 299 std::size_t GetProgramSize() const {
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index c92337079..b185a3884 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -27,7 +27,7 @@ constexpr std::size_t IgnoreFrames = 5;
27 27
28namespace Core { 28namespace Core {
29 29
30PerfStats::PerfStats(u64 title_id) : title_id(title_id) {} 30PerfStats::PerfStats(u64 title_id_) : title_id(title_id_) {}
31 31
32PerfStats::~PerfStats() { 32PerfStats::~PerfStats() {
33 if (!Settings::values.record_frame_times || title_id == 0) { 33 if (!Settings::values.record_frame_times || title_id == 0) {
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index 69256b960..ae4698696 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -29,7 +29,7 @@ struct PerfStatsResults {
29 */ 29 */
30class PerfStats { 30class PerfStats {
31public: 31public:
32 explicit PerfStats(u64 title_id); 32 explicit PerfStats(u64 title_id_);
33 ~PerfStats(); 33 ~PerfStats();
34 34
35 using Clock = std::chrono::high_resolution_clock; 35 using Clock = std::chrono::high_resolution_clock;
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 311d4dda8..d1e807dd4 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -19,7 +19,7 @@
19#include "core/core.h" 19#include "core/core.h"
20#include "core/hle/kernel/hle_ipc.h" 20#include "core/hle/kernel/hle_ipc.h"
21#include "core/hle/kernel/k_page_table.h" 21#include "core/hle/kernel/k_page_table.h"
22#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/k_process.h"
23#include "core/hle/result.h" 23#include "core/hle/result.h"
24#include "core/memory.h" 24#include "core/memory.h"
25#include "core/reporter.h" 25#include "core/reporter.h"
@@ -192,7 +192,7 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Core::Memory::Memo
192 192
193namespace Core { 193namespace Core {
194 194
195Reporter::Reporter(System& system) : system(system) {} 195Reporter::Reporter(System& system_) : system(system_) {}
196 196
197Reporter::~Reporter() = default; 197Reporter::~Reporter() = default;
198 198
diff --git a/src/core/reporter.h b/src/core/reporter.h
index b2c2d9a2e..6fb6ebffa 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -30,7 +30,7 @@ class System;
30 30
31class Reporter { 31class Reporter {
32public: 32public:
33 explicit Reporter(System& system); 33 explicit Reporter(System& system_);
34 ~Reporter(); 34 ~Reporter();
35 35
36 // Used by fatal services 36 // Used by fatal services
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 7c4e7dd3b..7399c3648 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -153,6 +153,11 @@ struct InputSubsystem::Impl {
153 // TODO return the correct motion device 153 // TODO return the correct motion device
154 return {}; 154 return {};
155 } 155 }
156#ifdef HAVE_SDL2
157 if (params.Get("class", "") == "sdl") {
158 return sdl->GetMotionMappingForDevice(params);
159 }
160#endif
156 return {}; 161 return {};
157 } 162 }
158 163
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 42bbf14d4..b5d41bba4 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -37,6 +37,9 @@ public:
37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { 37 virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
38 return {}; 38 return {};
39 } 39 }
40 virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) {
41 return {};
42 }
40}; 43};
41 44
42class NullState : public State { 45class NullState : public State {
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index f682a6db4..822d0b555 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -29,6 +29,7 @@
29#endif 29#endif
30 30
31#include "common/logging/log.h" 31#include "common/logging/log.h"
32#include "common/math_util.h"
32#include "common/param_package.h" 33#include "common/param_package.h"
33#include "common/settings_input.h" 34#include "common/settings_input.h"
34#include "common/threadsafe_queue.h" 35#include "common/threadsafe_queue.h"
@@ -68,13 +69,57 @@ public:
68 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, 69 SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
69 SDL_GameController* game_controller) 70 SDL_GameController* game_controller)
70 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, 71 : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
71 sdl_controller{game_controller, &SDL_GameControllerClose} {} 72 sdl_controller{game_controller, &SDL_GameControllerClose} {
73 EnableMotion();
74 }
75
76 void EnableMotion() {
77 if (sdl_controller) {
78 SDL_GameController* controller = sdl_controller.get();
79 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) {
80 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
81 has_accel = true;
82 }
83 if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) {
84 SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
85 has_gyro = true;
86 }
87 }
88 }
72 89
73 void SetButton(int button, bool value) { 90 void SetButton(int button, bool value) {
74 std::lock_guard lock{mutex}; 91 std::lock_guard lock{mutex};
75 state.buttons.insert_or_assign(button, value); 92 state.buttons.insert_or_assign(button, value);
76 } 93 }
77 94
95 void SetMotion(SDL_ControllerSensorEvent event) {
96 constexpr float gravity_constant = 9.80665f;
97 std::lock_guard lock{mutex};
98 u64 time_difference = event.timestamp - last_motion_update;
99 last_motion_update = event.timestamp;
100 switch (event.sensor) {
101 case SDL_SENSOR_ACCEL: {
102 const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]};
103 motion.SetAcceleration(acceleration / gravity_constant);
104 break;
105 }
106 case SDL_SENSOR_GYRO: {
107 const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]};
108 motion.SetGyroscope(gyroscope / (Common::PI * 2));
109 break;
110 }
111 }
112
113 // Ignore duplicated timestamps
114 if (time_difference == 0) {
115 return;
116 }
117
118 motion.SetGyroThreshold(0.0001f);
119 motion.UpdateRotation(time_difference * 1000);
120 motion.UpdateOrientation(time_difference * 1000);
121 }
122
78 bool GetButton(int button) const { 123 bool GetButton(int button) const {
79 std::lock_guard lock{mutex}; 124 std::lock_guard lock{mutex};
80 return state.buttons.at(button); 125 return state.buttons.at(button);
@@ -121,6 +166,14 @@ public:
121 return std::make_tuple(x, y); 166 return std::make_tuple(x, y);
122 } 167 }
123 168
169 bool HasGyro() const {
170 return has_gyro;
171 }
172
173 bool HasAccel() const {
174 return has_accel;
175 }
176
124 const MotionInput& GetMotion() const { 177 const MotionInput& GetMotion() const {
125 return motion; 178 return motion;
126 } 179 }
@@ -173,8 +226,11 @@ private:
173 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller; 226 std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
174 mutable std::mutex mutex; 227 mutable std::mutex mutex;
175 228
176 // Motion is initialized without PID values as motion input is not aviable for SDL2 229 // Motion is initialized with the PID values
177 MotionInput motion{0.0f, 0.0f, 0.0f}; 230 MotionInput motion{0.3f, 0.005f, 0.0f};
231 u64 last_motion_update{};
232 bool has_gyro{false};
233 bool has_accel{false};
178}; 234};
179 235
180std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { 236std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -296,6 +352,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
296 } 352 }
297 break; 353 break;
298 } 354 }
355 case SDL_CONTROLLERSENSORUPDATE: {
356 if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
357 joystick->SetMotion(event.csensor);
358 }
359 break;
360 }
299 case SDL_JOYDEVICEREMOVED: 361 case SDL_JOYDEVICEREMOVED:
300 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); 362 LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
301 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); 363 CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -449,6 +511,18 @@ private:
449 std::shared_ptr<SDLJoystick> joystick; 511 std::shared_ptr<SDLJoystick> joystick;
450}; 512};
451 513
514class SDLMotion final : public Input::MotionDevice {
515public:
516 explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {}
517
518 Input::MotionStatus GetStatus() const override {
519 return joystick->GetMotion().GetMotion();
520 }
521
522private:
523 std::shared_ptr<SDLJoystick> joystick;
524};
525
452class SDLDirectionMotion final : public Input::MotionDevice { 526class SDLDirectionMotion final : public Input::MotionDevice {
453public: 527public:
454 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) 528 explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
@@ -658,6 +732,10 @@ public:
658 732
659 auto joystick = state.GetSDLJoystickByGUID(guid, port); 733 auto joystick = state.GetSDLJoystickByGUID(guid, port);
660 734
735 if (params.Has("motion")) {
736 return std::make_unique<SDLMotion>(joystick);
737 }
738
661 if (params.Has("hat")) { 739 if (params.Has("hat")) {
662 const int hat = params.Get("hat", 0); 740 const int hat = params.Get("hat", 0);
663 const std::string direction_name = params.Get("direction", ""); 741 const std::string direction_name = params.Get("direction", "");
@@ -717,6 +795,17 @@ SDLState::SDLState() {
717 RegisterFactory<VibrationDevice>("sdl", vibration_factory); 795 RegisterFactory<VibrationDevice>("sdl", vibration_factory);
718 RegisterFactory<MotionDevice>("sdl", motion_factory); 796 RegisterFactory<MotionDevice>("sdl", motion_factory);
719 797
798 // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
799 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
800 SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
801
802 // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a
803 // GameController and not a generic one
804 SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1");
805
806 // Turn off Pro controller home led
807 SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0");
808
720 // If the frontend is going to manage the event loop, then we don't start one here 809 // If the frontend is going to manage the event loop, then we don't start one here
721 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; 810 start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
722 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { 811 if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
@@ -853,6 +942,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s
853 return params; 942 return params;
854} 943}
855 944
945Common::ParamPackage BuildMotionParam(int port, std::string guid) {
946 Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}});
947 params.Set("port", port);
948 params.Set("guid", std::move(guid));
949 return params;
950}
951
856Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { 952Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
857 switch (event.type) { 953 switch (event.type) {
858 case SDL_JOYAXISMOTION: { 954 case SDL_JOYAXISMOTION: {
@@ -907,6 +1003,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve
907 } 1003 }
908 break; 1004 break;
909 } 1005 }
1006 case SDL_CONTROLLERSENSORUPDATE: {
1007 bool is_motion_shaking = false;
1008 constexpr float gyro_threshold = 5.0f;
1009 constexpr float accel_threshold = 11.0f;
1010 if (event.csensor.sensor == SDL_SENSOR_ACCEL) {
1011 const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2],
1012 -event.csensor.data[1]};
1013 if (acceleration.Length() > accel_threshold) {
1014 is_motion_shaking = true;
1015 }
1016 }
1017
1018 if (event.csensor.sensor == SDL_SENSOR_GYRO) {
1019 const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2],
1020 event.csensor.data[1]};
1021 if (gyroscope.Length() > gyro_threshold) {
1022 is_motion_shaking = true;
1023 }
1024 }
1025
1026 if (!is_motion_shaking) {
1027 break;
1028 }
1029
1030 if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) {
1031 return BuildMotionParam(joystick->GetPort(), joystick->GetGUID());
1032 }
1033 break;
1034 }
910 } 1035 }
911 return {}; 1036 return {};
912} 1037}
@@ -1036,6 +1161,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
1036 return mapping; 1161 return mapping;
1037} 1162}
1038 1163
1164MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) {
1165 if (!params.Has("guid") || !params.Has("port")) {
1166 return {};
1167 }
1168 const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
1169 auto* controller = joystick->GetSDLGameController();
1170 if (controller == nullptr) {
1171 return {};
1172 }
1173
1174 joystick->EnableMotion();
1175
1176 if (!joystick->HasGyro() && !joystick->HasAccel()) {
1177 return {};
1178 }
1179
1180 MotionMapping mapping = {};
1181 mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
1182 BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
1183 return mapping;
1184}
1039namespace Polling { 1185namespace Polling {
1040class SDLPoller : public InputCommon::Polling::DevicePoller { 1186class SDLPoller : public InputCommon::Polling::DevicePoller {
1041public: 1187public:
@@ -1149,6 +1295,7 @@ public:
1149 [[fallthrough]]; 1295 [[fallthrough]];
1150 case SDL_JOYBUTTONUP: 1296 case SDL_JOYBUTTONUP:
1151 case SDL_JOYHATMOTION: 1297 case SDL_JOYHATMOTION:
1298 case SDL_CONTROLLERSENSORUPDATE:
1152 return {SDLEventToMotionParamPackage(state, event)}; 1299 return {SDLEventToMotionParamPackage(state, event)};
1153 } 1300 }
1154 return std::nullopt; 1301 return std::nullopt;
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index 8b7363f56..121e01913 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -57,6 +57,7 @@ public:
57 57
58 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; 58 ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
59 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; 59 AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
60 MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
60 61
61private: 62private:
62 void InitJoystick(int joystick_index); 63 void InitJoystick(int joystick_index);
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 4eb71efbd..eb58ac6b6 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -7,7 +7,7 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/k_page_table.h" 9#include "core/hle/kernel/k_page_table.h"
10#include "core/hle/kernel/process.h" 10#include "core/hle/kernel/k_process.h"
11#include "core/memory.h" 11#include "core/memory.h"
12#include "video_core/gpu.h" 12#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0863904e9..a5dbb9adf 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -19,7 +19,7 @@
19#include "common/scope_exit.h" 19#include "common/scope_exit.h"
20#include "common/settings.h" 20#include "common/settings.h"
21#include "core/core.h" 21#include "core/core.h"
22#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/k_process.h"
23#include "core/memory.h" 23#include "core/memory.h"
24#include "video_core/engines/kepler_compute.h" 24#include "video_core/engines/kepler_compute.h"
25#include "video_core/engines/maxwell_3d.h" 25#include "video_core/engines/maxwell_3d.h"
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 97fb11ac6..dbcb751cb 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -15,7 +15,7 @@
15#include "common/settings.h" 15#include "common/settings.h"
16#include "common/zstd_compression.h" 16#include "common/zstd_compression.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/k_process.h"
19#include "video_core/engines/shader_type.h" 19#include "video_core/engines/shader_type.h"
20#include "video_core/renderer_opengl/gl_shader_cache.h" 20#include "video_core/renderer_opengl/gl_shader_cache.h"
21#include "video_core/renderer_opengl/gl_shader_disk_cache.h" 21#include "video_core/renderer_opengl/gl_shader_disk_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 623b43d8a..ffe9edc1b 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -543,8 +543,7 @@ void TextureCacheRuntime::EmulateCopyImage(Image& dst, Image& src,
543} 543}
544 544
545void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src, 545void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
546 const std::array<Offset2D, 2>& dst_region, 546 const Region2D& dst_region, const Region2D& src_region,
547 const std::array<Offset2D, 2>& src_region,
548 Tegra::Engines::Fermi2D::Filter filter, 547 Tegra::Engines::Fermi2D::Filter filter,
549 Tegra::Engines::Fermi2D::Operation operation) { 548 Tegra::Engines::Fermi2D::Operation operation) {
550 state_tracker.NotifyScissor0(); 549 state_tracker.NotifyScissor0();
@@ -560,9 +559,9 @@ void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
560 const GLbitfield buffer_bits = dst->BufferBits(); 559 const GLbitfield buffer_bits = dst->BufferBits();
561 const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0; 560 const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0;
562 const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear; 561 const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
563 glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region[0].x, src_region[0].y, 562 glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region.start.x, src_region.start.y,
564 src_region[1].x, src_region[1].y, dst_region[0].x, dst_region[0].y, 563 src_region.end.x, src_region.end.y, dst_region.start.x,
565 dst_region[1].x, dst_region[1].y, buffer_bits, 564 dst_region.start.y, dst_region.end.x, dst_region.end.y, buffer_bits,
566 is_linear ? GL_LINEAR : GL_NEAREST); 565 is_linear ? GL_LINEAR : GL_NEAREST);
567} 566}
568 567
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h
index 3c871541b..df8be12ff 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.h
+++ b/src/video_core/renderer_opengl/gl_texture_cache.h
@@ -28,7 +28,7 @@ using VideoCommon::ImageId;
28using VideoCommon::ImageViewId; 28using VideoCommon::ImageViewId;
29using VideoCommon::ImageViewType; 29using VideoCommon::ImageViewType;
30using VideoCommon::NUM_RT; 30using VideoCommon::NUM_RT;
31using VideoCommon::Offset2D; 31using VideoCommon::Region2D;
32using VideoCommon::RenderTargets; 32using VideoCommon::RenderTargets;
33 33
34struct ImageBufferMap { 34struct ImageBufferMap {
@@ -73,10 +73,8 @@ public:
73 73
74 void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies); 74 void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
75 75
76 void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, 76 void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, const Region2D& dst_region,
77 const std::array<Offset2D, 2>& dst_region, 77 const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
78 const std::array<Offset2D, 2>& src_region,
79 Tegra::Engines::Fermi2D::Filter filter,
80 Tegra::Engines::Fermi2D::Operation operation); 78 Tegra::Engines::Fermi2D::Operation operation);
81 79
82 void AccelerateImageUpload(Image& image, const ImageBufferMap& map, 80 void AccelerateImageUpload(Image& image, const ImageBufferMap& map,
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 1f6a169ae..b7f5b8bc2 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -289,16 +289,15 @@ void UpdateTwoTexturesDescriptorSet(const Device& device, VkDescriptorSet descri
289 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr); 289 device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
290} 290}
291 291
292void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, 292void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
293 const std::array<Offset2D, 2>& dst_region, 293 const Region2D& src_region) {
294 const std::array<Offset2D, 2>& src_region) {
295 const VkOffset2D offset{ 294 const VkOffset2D offset{
296 .x = std::min(dst_region[0].x, dst_region[1].x), 295 .x = std::min(dst_region.start.x, dst_region.end.x),
297 .y = std::min(dst_region[0].y, dst_region[1].y), 296 .y = std::min(dst_region.start.y, dst_region.end.y),
298 }; 297 };
299 const VkExtent2D extent{ 298 const VkExtent2D extent{
300 .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)), 299 .width = static_cast<u32>(std::abs(dst_region.end.x - dst_region.start.x)),
301 .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)), 300 .height = static_cast<u32>(std::abs(dst_region.end.y - dst_region.start.y)),
302 }; 301 };
303 const VkViewport viewport{ 302 const VkViewport viewport{
304 .x = static_cast<float>(offset.x), 303 .x = static_cast<float>(offset.x),
@@ -313,11 +312,12 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
313 .offset = offset, 312 .offset = offset,
314 .extent = extent, 313 .extent = extent,
315 }; 314 };
316 const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x); 315 const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x);
317 const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y); 316 const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y);
318 const PushConstants push_constants{ 317 const PushConstants push_constants{
319 .tex_scale = {scale_x, scale_y}, 318 .tex_scale = {scale_x, scale_y},
320 .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)}, 319 .tex_offset = {static_cast<float>(src_region.start.x),
320 static_cast<float>(src_region.start.y)},
321 }; 321 };
322 cmdbuf.SetViewport(0, viewport); 322 cmdbuf.SetViewport(0, viewport);
323 cmdbuf.SetScissor(0, scissor); 323 cmdbuf.SetScissor(0, scissor);
@@ -353,8 +353,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
353BlitImageHelper::~BlitImageHelper() = default; 353BlitImageHelper::~BlitImageHelper() = default;
354 354
355void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, 355void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
356 const std::array<Offset2D, 2>& dst_region, 356 const Region2D& dst_region, const Region2D& src_region,
357 const std::array<Offset2D, 2>& src_region,
358 Tegra::Engines::Fermi2D::Filter filter, 357 Tegra::Engines::Fermi2D::Filter filter,
359 Tegra::Engines::Fermi2D::Operation operation) { 358 Tegra::Engines::Fermi2D::Operation operation) {
360 const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear; 359 const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
@@ -383,8 +382,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
383 382
384void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer, 383void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
385 VkImageView src_depth_view, VkImageView src_stencil_view, 384 VkImageView src_depth_view, VkImageView src_stencil_view,
386 const std::array<Offset2D, 2>& dst_region, 385 const Region2D& dst_region, const Region2D& src_region,
387 const std::array<Offset2D, 2>& src_region,
388 Tegra::Engines::Fermi2D::Filter filter, 386 Tegra::Engines::Fermi2D::Filter filter,
389 Tegra::Engines::Fermi2D::Operation operation) { 387 Tegra::Engines::Fermi2D::Operation operation) {
390 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); 388 ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index 43fd3d737..0d81a06ed 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -13,7 +13,7 @@
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
16using VideoCommon::Offset2D; 16using VideoCommon::Region2D;
17 17
18class Device; 18class Device;
19class Framebuffer; 19class Framebuffer;
@@ -35,15 +35,13 @@ public:
35 ~BlitImageHelper(); 35 ~BlitImageHelper();
36 36
37 void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view, 37 void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
38 const std::array<Offset2D, 2>& dst_region, 38 const Region2D& dst_region, const Region2D& src_region,
39 const std::array<Offset2D, 2>& src_region,
40 Tegra::Engines::Fermi2D::Filter filter, 39 Tegra::Engines::Fermi2D::Filter filter,
41 Tegra::Engines::Fermi2D::Operation operation); 40 Tegra::Engines::Fermi2D::Operation operation);
42 41
43 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view, 42 void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
44 VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region, 43 VkImageView src_stencil_view, const Region2D& dst_region,
45 const std::array<Offset2D, 2>& src_region, 44 const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
46 Tegra::Engines::Fermi2D::Filter filter,
47 Tegra::Engines::Fermi2D::Operation operation); 45 Tegra::Engines::Fermi2D::Operation operation);
48 46
49 void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view); 47 void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 017348e05..bdd0ce8bc 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -490,8 +490,7 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
490 write_barrier); 490 write_barrier);
491} 491}
492 492
493[[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region, 493[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
494 const std::array<Offset2D, 2>& src_region,
495 const VkImageSubresourceLayers& dst_layers, 494 const VkImageSubresourceLayers& dst_layers,
496 const VkImageSubresourceLayers& src_layers) { 495 const VkImageSubresourceLayers& src_layers) {
497 return VkImageBlit{ 496 return VkImageBlit{
@@ -499,13 +498,13 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
499 .srcOffsets = 498 .srcOffsets =
500 { 499 {
501 { 500 {
502 .x = src_region[0].x, 501 .x = src_region.start.x,
503 .y = src_region[0].y, 502 .y = src_region.start.y,
504 .z = 0, 503 .z = 0,
505 }, 504 },
506 { 505 {
507 .x = src_region[1].x, 506 .x = src_region.end.x,
508 .y = src_region[1].y, 507 .y = src_region.end.y,
509 .z = 1, 508 .z = 1,
510 }, 509 },
511 }, 510 },
@@ -513,42 +512,42 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
513 .dstOffsets = 512 .dstOffsets =
514 { 513 {
515 { 514 {
516 .x = dst_region[0].x, 515 .x = dst_region.start.x,
517 .y = dst_region[0].y, 516 .y = dst_region.start.y,
518 .z = 0, 517 .z = 0,
519 }, 518 },
520 { 519 {
521 .x = dst_region[1].x, 520 .x = dst_region.end.x,
522 .y = dst_region[1].y, 521 .y = dst_region.end.y,
523 .z = 1, 522 .z = 1,
524 }, 523 },
525 }, 524 },
526 }; 525 };
527} 526}
528 527
529[[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region, 528[[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region,
530 const std::array<Offset2D, 2>& src_region, 529 const Region2D& src_region,
531 const VkImageSubresourceLayers& dst_layers, 530 const VkImageSubresourceLayers& dst_layers,
532 const VkImageSubresourceLayers& src_layers) { 531 const VkImageSubresourceLayers& src_layers) {
533 return VkImageResolve{ 532 return VkImageResolve{
534 .srcSubresource = src_layers, 533 .srcSubresource = src_layers,
535 .srcOffset = 534 .srcOffset =
536 { 535 {
537 .x = src_region[0].x, 536 .x = src_region.start.x,
538 .y = src_region[0].y, 537 .y = src_region.start.y,
539 .z = 0, 538 .z = 0,
540 }, 539 },
541 .dstSubresource = dst_layers, 540 .dstSubresource = dst_layers,
542 .dstOffset = 541 .dstOffset =
543 { 542 {
544 .x = dst_region[0].x, 543 .x = dst_region.start.x,
545 .y = dst_region[0].y, 544 .y = dst_region.start.y,
546 .z = 0, 545 .z = 0,
547 }, 546 },
548 .extent = 547 .extent =
549 { 548 {
550 .width = static_cast<u32>(dst_region[1].x - dst_region[0].x), 549 .width = static_cast<u32>(dst_region.end.x - dst_region.start.x),
551 .height = static_cast<u32>(dst_region[1].y - dst_region[0].y), 550 .height = static_cast<u32>(dst_region.end.y - dst_region.start.y),
552 .depth = 1, 551 .depth = 1,
553 }, 552 },
554 }; 553 };
@@ -602,8 +601,7 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
602} 601}
603 602
604void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, 603void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
605 const std::array<Offset2D, 2>& dst_region, 604 const Region2D& dst_region, const Region2D& src_region,
606 const std::array<Offset2D, 2>& src_region,
607 Tegra::Engines::Fermi2D::Filter filter, 605 Tegra::Engines::Fermi2D::Filter filter,
608 Tegra::Engines::Fermi2D::Operation operation) { 606 Tegra::Engines::Fermi2D::Operation operation) {
609 const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format); 607 const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index 628785d5e..4a57d378b 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -16,7 +16,7 @@ namespace Vulkan {
16 16
17using VideoCommon::ImageId; 17using VideoCommon::ImageId;
18using VideoCommon::NUM_RT; 18using VideoCommon::NUM_RT;
19using VideoCommon::Offset2D; 19using VideoCommon::Region2D;
20using VideoCommon::RenderTargets; 20using VideoCommon::RenderTargets;
21using VideoCore::Surface::PixelFormat; 21using VideoCore::Surface::PixelFormat;
22 22
@@ -71,8 +71,7 @@ struct TextureCacheRuntime {
71 [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size); 71 [[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size);
72 72
73 void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, 73 void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
74 const std::array<Offset2D, 2>& dst_region, 74 const Region2D& dst_region, const Region2D& src_region,
75 const std::array<Offset2D, 2>& src_region,
76 Tegra::Engines::Fermi2D::Filter filter, 75 Tegra::Engines::Fermi2D::Filter filter,
77 Tegra::Engines::Fermi2D::Operation operation); 76 Tegra::Engines::Fermi2D::Operation operation);
78 77
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 98e33c3a0..59b7c678b 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -148,7 +148,9 @@ public:
148 /// Blit an image with the given parameters 148 /// Blit an image with the given parameters
149 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, 149 void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
150 const Tegra::Engines::Fermi2D::Surface& src, 150 const Tegra::Engines::Fermi2D::Surface& src,
151 const Tegra::Engines::Fermi2D::Config& copy); 151 const Tegra::Engines::Fermi2D::Config& copy,
152 std::optional<Region2D> src_region_override = {},
153 std::optional<Region2D> dst_region_override = {});
152 154
153 /// Invalidate the contents of the color buffer index 155 /// Invalidate the contents of the color buffer index
154 /// These contents become unspecified, the cache can assume aggressive optimizations. 156 /// These contents become unspecified, the cache can assume aggressive optimizations.
@@ -615,7 +617,9 @@ void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) {
615template <class P> 617template <class P>
616void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst, 618void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
617 const Tegra::Engines::Fermi2D::Surface& src, 619 const Tegra::Engines::Fermi2D::Surface& src,
618 const Tegra::Engines::Fermi2D::Config& copy) { 620 const Tegra::Engines::Fermi2D::Config& copy,
621 std::optional<Region2D> src_override,
622 std::optional<Region2D> dst_override) {
619 const BlitImages images = GetBlitImages(dst, src); 623 const BlitImages images = GetBlitImages(dst, src);
620 const ImageId dst_id = images.dst_id; 624 const ImageId dst_id = images.dst_id;
621 const ImageId src_id = images.src_id; 625 const ImageId src_id = images.src_id;
@@ -631,20 +635,42 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
631 const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range); 635 const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
632 const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info); 636 const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
633 const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples); 637 const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
634 const std::array src_region{ 638
635 Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y}, 639 // out of bounds texture blit checking
636 Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y}, 640 const bool use_override = src_override.has_value();
641 const s32 src_x0 = copy.src_x0 >> src_samples_x;
642 s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x;
643 const s32 src_y0 = copy.src_y0 >> src_samples_y;
644 const s32 src_y1 = copy.src_y1 >> src_samples_y;
645
646 const auto src_width = static_cast<s32>(src_image.info.size.width);
647 const bool width_oob = src_x1 > src_width;
648 const auto width_diff = width_oob ? src_x1 - src_width : 0;
649 if (width_oob) {
650 src_x1 = src_width;
651 }
652
653 const Region2D src_dimensions{
654 Offset2D{.x = src_x0, .y = src_y0},
655 Offset2D{.x = src_x1, .y = src_y1},
637 }; 656 };
657 const auto src_region = use_override ? *src_override : src_dimensions;
638 658
639 const std::optional src_base = src_image.TryFindBase(src.Address()); 659 const std::optional src_base = src_image.TryFindBase(src.Address());
640 const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}}; 660 const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}};
641 const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range); 661 const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range);
642 const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info); 662 const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info);
643 const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples); 663 const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
644 const std::array dst_region{ 664
645 Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y}, 665 const s32 dst_x0 = copy.dst_x0 >> dst_samples_x;
646 Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y}, 666 const s32 dst_x1 = copy.dst_x1 >> dst_samples_x;
667 const s32 dst_y0 = copy.dst_y0 >> dst_samples_y;
668 const s32 dst_y1 = copy.dst_y1 >> dst_samples_y;
669 const Region2D dst_dimensions{
670 Offset2D{.x = dst_x0, .y = dst_y0},
671 Offset2D{.x = dst_x1 - width_diff, .y = dst_y1},
647 }; 672 };
673 const auto dst_region = use_override ? *dst_override : dst_dimensions;
648 674
649 // Always call this after src_framebuffer_id was queried, as the address might be invalidated. 675 // Always call this after src_framebuffer_id was queried, as the address might be invalidated.
650 Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id]; 676 Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id];
@@ -661,6 +687,21 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
661 runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter, 687 runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter,
662 copy.operation); 688 copy.operation);
663 } 689 }
690
691 if (width_oob) {
692 // Continue copy of the oob region of the texture on the next row
693 auto oob_src = src;
694 oob_src.height++;
695 const Region2D src_region_override{
696 Offset2D{.x = 0, .y = src_y0 + 1},
697 Offset2D{.x = width_diff, .y = src_y1 + 1},
698 };
699 const Region2D dst_region_override{
700 Offset2D{.x = dst_x1 - width_diff, .y = dst_y0},
701 Offset2D{.x = dst_x1, .y = dst_y1},
702 };
703 BlitImage(dst, oob_src, copy, src_region_override, dst_region_override);
704 }
664} 705}
665 706
666template <class P> 707template <class P>
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h
index 2ad2d72a6..c9571f7e4 100644
--- a/src/video_core/texture_cache/types.h
+++ b/src/video_core/texture_cache/types.h
@@ -64,6 +64,13 @@ struct Offset3D {
64 s32 z; 64 s32 z;
65}; 65};
66 66
67struct Region2D {
68 constexpr auto operator<=>(const Region2D&) const noexcept = default;
69
70 Offset2D start;
71 Offset2D end;
72};
73
67struct Extent2D { 74struct Extent2D {
68 constexpr auto operator<=>(const Extent2D&) const noexcept = default; 75 constexpr auto operator<=>(const Extent2D&) const noexcept = default;
69 76
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 7ff9491f4..86495803e 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -32,7 +32,7 @@
32#include "common/settings.h" 32#include "common/settings.h"
33#include "core/core.h" 33#include "core/core.h"
34#include "core/frontend/framebuffer_layout.h" 34#include "core/frontend/framebuffer_layout.h"
35#include "core/hle/kernel/process.h" 35#include "core/hle/kernel/k_process.h"
36#include "input_common/keyboard.h" 36#include "input_common/keyboard.h"
37#include "input_common/main.h" 37#include "input_common/main.h"
38#include "input_common/mouse/mouse_input.h" 38#include "input_common/mouse/mouse_input.h"
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index c9318c562..ab3512810 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -153,6 +153,10 @@ QString ButtonToText(const Common::ParamPackage& param) {
153 return QObject::tr("Button %1").arg(button_str); 153 return QObject::tr("Button %1").arg(button_str);
154 } 154 }
155 155
156 if (param.Has("motion")) {
157 return QObject::tr("SDL Motion");
158 }
159
156 return {}; 160 return {};
157 } 161 }
158 162
@@ -1245,12 +1249,16 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
1245 const auto& device = input_devices[ui->comboDevices->currentIndex()]; 1249 const auto& device = input_devices[ui->comboDevices->currentIndex()];
1246 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); 1250 auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
1247 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); 1251 auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
1252 auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device);
1248 for (std::size_t i = 0; i < buttons_param.size(); ++i) { 1253 for (std::size_t i = 0; i < buttons_param.size(); ++i) {
1249 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)]; 1254 buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
1250 } 1255 }
1251 for (std::size_t i = 0; i < analogs_param.size(); ++i) { 1256 for (std::size_t i = 0; i < analogs_param.size(); ++i) {
1252 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)]; 1257 analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
1253 } 1258 }
1259 for (std::size_t i = 0; i < motions_param.size(); ++i) {
1260 motions_param[i] = motion_mapping[static_cast<Settings::NativeMotion::Values>(i)];
1261 }
1254 1262
1255 UpdateUI(); 1263 UpdateUI();
1256} 1264}
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index f35c89e04..0cdaea8a4 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -46,6 +46,7 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur
46 SetConfiguration(); 46 SetConfiguration();
47 47
48 // Force game list reload if any of the relevant settings are changed. 48 // Force game list reload if any of the relevant settings are changed.
49 connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
49 connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 50 connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
50 &ConfigureUi::RequestGameListUpdate); 51 &ConfigureUi::RequestGameListUpdate);
51 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 52 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 3bca6277b..bdfda6c54 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -12,12 +12,13 @@
12#include "common/assert.h" 12#include "common/assert.h"
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/kernel/handle_table.h" 15#include "core/hle/kernel/k_class_token.h"
16#include "core/hle/kernel/k_handle_table.h"
17#include "core/hle/kernel/k_process.h"
16#include "core/hle/kernel/k_readable_event.h" 18#include "core/hle/kernel/k_readable_event.h"
17#include "core/hle/kernel/k_scheduler.h" 19#include "core/hle/kernel/k_scheduler.h"
18#include "core/hle/kernel/k_synchronization_object.h" 20#include "core/hle/kernel/k_synchronization_object.h"
19#include "core/hle/kernel/k_thread.h" 21#include "core/hle/kernel/k_thread.h"
20#include "core/hle/kernel/process.h"
21#include "core/hle/kernel/svc_common.h" 22#include "core/hle/kernel/svc_common.h"
22#include "core/hle/kernel/svc_types.h" 23#include "core/hle/kernel/svc_types.h"
23#include "core/memory.h" 24#include "core/memory.h"
@@ -91,7 +92,7 @@ std::size_t WaitTreeItem::Row() const {
91std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { 92std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
92 std::vector<std::unique_ptr<WaitTreeThread>> item_list; 93 std::vector<std::unique_ptr<WaitTreeThread>> item_list;
93 std::size_t row = 0; 94 std::size_t row = 0;
94 auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) { 95 auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) {
95 for (std::size_t i = 0; i < threads.size(); ++i) { 96 for (std::size_t i = 0; i < threads.size(); ++i) {
96 if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { 97 if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) {
97 item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i])); 98 item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
@@ -114,11 +115,11 @@ QString WaitTreeText::GetText() const {
114 return text; 115 return text;
115} 116}
116 117
117WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table) 118WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table)
118 : mutex_address(mutex_address) { 119 : mutex_address(mutex_address) {
119 mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address); 120 mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
120 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); 121 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
121 owner = handle_table.Get<Kernel::KThread>(owner_handle); 122 owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe();
122} 123}
123 124
124WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; 125WaitTreeMutexInfo::~WaitTreeMutexInfo() = default;
@@ -183,18 +184,20 @@ bool WaitTreeExpandableItem::IsExpandable() const {
183} 184}
184 185
185QString WaitTreeSynchronizationObject::GetText() const { 186QString WaitTreeSynchronizationObject::GetText() const {
186 return tr("[%1]%2 %3") 187 return tr("[%1] %2 %3")
187 .arg(object.GetObjectId()) 188 .arg(object.GetId())
188 .arg(QString::fromStdString(object.GetTypeName()), 189 .arg(QString::fromStdString(object.GetTypeObj().GetName()),
189 QString::fromStdString(object.GetName())); 190 QString::fromStdString(object.GetName()));
190} 191}
191 192
192std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make( 193std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
193 const Kernel::KSynchronizationObject& object) { 194 const Kernel::KSynchronizationObject& object) {
194 switch (object.GetHandleType()) { 195 const auto type =
195 case Kernel::HandleType::ReadableEvent: 196 static_cast<Kernel::KClassTokenGenerator::ObjectType>(object.GetTypeObj().GetClassToken());
197 switch (type) {
198 case Kernel::KClassTokenGenerator::ObjectType::KReadableEvent:
196 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object)); 199 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object));
197 case Kernel::HandleType::Thread: 200 case Kernel::KClassTokenGenerator::ObjectType::KThread:
198 return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object)); 201 return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object));
199 default: 202 default:
200 return std::make_unique<WaitTreeSynchronizationObject>(object); 203 return std::make_unique<WaitTreeSynchronizationObject>(object);
@@ -204,12 +207,13 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma
204std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const { 207std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
205 std::vector<std::unique_ptr<WaitTreeItem>> list; 208 std::vector<std::unique_ptr<WaitTreeItem>> list;
206 209
207 const auto& threads = object.GetWaitingThreadsForDebugging(); 210 auto threads = object.GetWaitingThreadsForDebugging();
208 if (threads.empty()) { 211 if (threads.empty()) {
209 list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread"))); 212 list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
210 } else { 213 } else {
211 list.push_back(std::make_unique<WaitTreeThreadList>(threads)); 214 list.push_back(std::make_unique<WaitTreeThreadList>(std::move(threads)));
212 } 215 }
216
213 return list; 217 return list;
214} 218}
215 219
@@ -377,8 +381,8 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object)
377 : WaitTreeSynchronizationObject(object) {} 381 : WaitTreeSynchronizationObject(object) {}
378WaitTreeEvent::~WaitTreeEvent() = default; 382WaitTreeEvent::~WaitTreeEvent() = default;
379 383
380WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list) 384WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list)
381 : thread_list(list) {} 385 : thread_list(std::move(list)) {}
382WaitTreeThreadList::~WaitTreeThreadList() = default; 386WaitTreeThreadList::~WaitTreeThreadList() = default;
383 387
384QString WaitTreeThreadList::GetText() const { 388QString WaitTreeThreadList::GetText() const {
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 3da2fdfd2..d450345df 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -11,13 +11,15 @@
11#include <QAbstractItemModel> 11#include <QAbstractItemModel>
12#include <QDockWidget> 12#include <QDockWidget>
13#include <QTreeView> 13#include <QTreeView>
14
14#include "common/common_types.h" 15#include "common/common_types.h"
15#include "core/hle/kernel/object.h" 16#include "core/hle/kernel/k_auto_object.h"
17#include "core/hle/kernel/svc_common.h"
16 18
17class EmuThread; 19class EmuThread;
18 20
19namespace Kernel { 21namespace Kernel {
20class HandleTable; 22class KHandleTable;
21class KReadableEvent; 23class KReadableEvent;
22class KSynchronizationObject; 24class KSynchronizationObject;
23class KThread; 25class KThread;
@@ -73,17 +75,17 @@ public:
73class WaitTreeMutexInfo : public WaitTreeExpandableItem { 75class WaitTreeMutexInfo : public WaitTreeExpandableItem {
74 Q_OBJECT 76 Q_OBJECT
75public: 77public:
76 explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table); 78 explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table);
77 ~WaitTreeMutexInfo() override; 79 ~WaitTreeMutexInfo() override;
78 80
79 QString GetText() const override; 81 QString GetText() const override;
80 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 82 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
81 83
82private: 84private:
83 VAddr mutex_address; 85 VAddr mutex_address{};
84 u32 mutex_value; 86 u32 mutex_value{};
85 Kernel::Handle owner_handle; 87 Kernel::Handle owner_handle{};
86 std::shared_ptr<Kernel::KThread> owner; 88 Kernel::KThread* owner{};
87}; 89};
88 90
89class WaitTreeCallstack : public WaitTreeExpandableItem { 91class WaitTreeCallstack : public WaitTreeExpandableItem {
@@ -149,14 +151,14 @@ public:
149class WaitTreeThreadList : public WaitTreeExpandableItem { 151class WaitTreeThreadList : public WaitTreeExpandableItem {
150 Q_OBJECT 152 Q_OBJECT
151public: 153public:
152 explicit WaitTreeThreadList(const std::vector<Kernel::KThread*>& list); 154 explicit WaitTreeThreadList(std::vector<Kernel::KThread*>&& list);
153 ~WaitTreeThreadList() override; 155 ~WaitTreeThreadList() override;
154 156
155 QString GetText() const override; 157 QString GetText() const override;
156 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 158 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
157 159
158private: 160private:
159 const std::vector<Kernel::KThread*>& thread_list; 161 std::vector<Kernel::KThread*> thread_list;
160}; 162};
161 163
162class WaitTreeModel : public QAbstractItemModel { 164class WaitTreeModel : public QAbstractItemModel {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 00d4cfe67..30bb1aac7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -92,7 +92,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
92#include "core/file_sys/romfs.h" 92#include "core/file_sys/romfs.h"
93#include "core/file_sys/savedata_factory.h" 93#include "core/file_sys/savedata_factory.h"
94#include "core/file_sys/submission_package.h" 94#include "core/file_sys/submission_package.h"
95#include "core/hle/kernel/process.h" 95#include "core/hle/kernel/k_process.h"
96#include "core/hle/service/am/am.h" 96#include "core/hle/service/am/am.h"
97#include "core/hle/service/filesystem/filesystem.h" 97#include "core/hle/service/filesystem/filesystem.h"
98#include "core/hle/service/nfp/nfp.h" 98#include "core/hle/service/nfp/nfp.h"
@@ -2751,24 +2751,19 @@ void GMainWindow::MigrateConfigFiles() {
2751 2751
2752void GMainWindow::UpdateWindowTitle(const std::string& title_name, 2752void GMainWindow::UpdateWindowTitle(const std::string& title_name,
2753 const std::string& title_version) { 2753 const std::string& title_version) {
2754 const auto full_name = std::string(Common::g_build_fullname);
2755 const auto branch_name = std::string(Common::g_scm_branch); 2754 const auto branch_name = std::string(Common::g_scm_branch);
2756 const auto description = std::string(Common::g_scm_desc); 2755 const auto description = std::string(Common::g_scm_desc);
2757 const auto build_id = std::string(Common::g_build_id); 2756 const auto build_id = std::string(Common::g_build_id);
2758 2757
2759 const auto date = 2758 const auto yuzu_title = fmt::format("yuzu | {}-{}", branch_name, description);
2760 QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString(); 2759 const auto override_title = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
2760 const auto window_title = override_title.empty() ? yuzu_title : override_title;
2761 2761
2762 if (title_name.empty()) { 2762 if (title_name.empty()) {
2763 const auto fmt = std::string(Common::g_title_bar_format_idle); 2763 setWindowTitle(QString::fromStdString(window_title));
2764 setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt,
2765 full_name, branch_name, description,
2766 std::string{}, date, build_id)));
2767 } else { 2764 } else {
2768 const auto fmt = std::string(Common::g_title_bar_format_running); 2765 const auto run_title = fmt::format("{} | {} | {}", window_title, title_name, title_version);
2769 setWindowTitle(QString::fromStdString( 2766 setWindowTitle(QString::fromStdString(run_title));
2770 fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name,
2771 description, title_name, date, build_id, title_version)));
2772 } 2767 }
2773} 2768}
2774 2769
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 4871ac3bb..e2812ca61 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -27,7 +27,7 @@
27#include "core/crypto/key_manager.h" 27#include "core/crypto/key_manager.h"
28#include "core/file_sys/registered_cache.h" 28#include "core/file_sys/registered_cache.h"
29#include "core/file_sys/vfs_real.h" 29#include "core/file_sys/vfs_real.h"
30#include "core/hle/kernel/process.h" 30#include "core/hle/kernel/k_process.h"
31#include "core/hle/service/filesystem/filesystem.h" 31#include "core/hle/service/filesystem/filesystem.h"
32#include "core/loader/loader.h" 32#include "core/loader/loader.h"
33#include "core/telemetry_session.h" 33#include "core/telemetry_session.h"