summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/linux/docker.sh8
-rw-r--r--.ci/scripts/linux/upload.sh2
-rw-r--r--CMakeLists.txt36
-rw-r--r--dist/icons/overlay/osk_button_B.pngbin741 -> 2653 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark.pngbin767 -> 2721 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark_disabled.pngbin781 -> 2689 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_disabled.pngbin791 -> 2694 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y.pngbin726 -> 2695 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark.pngbin502 -> 2073 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark_disabled.pngbin694 -> 2631 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_disabled.pngbin699 -> 2647 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus.pngbin626 -> 2226 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark.pngbin676 -> 2288 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark_disabled.pngbin645 -> 2233 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_disabled.pngbin664 -> 2254 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_off.pngbin281 -> 936 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_on.pngbin274 -> 894 bytes
-rw-r--r--dist/qt_themes/default/style.qss36
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss36
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss36
-rw-r--r--externals/CMakeLists.txt15
m---------externals/SDL0
m---------externals/ffmpeg0
m---------externals/mbedtls0
-rw-r--r--src/CMakeLists.txt1
-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.h11
-rw-r--r--src/common/settings.cpp9
-rw-r--r--src/common/settings.h10
-rw-r--r--src/common/tree.h2
-rw-r--r--src/core/CMakeLists.txt74
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp24
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp26
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp11
-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.cpp27
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/core_timing.cpp4
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/cpu_manager.h10
-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/card_image.cpp26
-rw-r--r--src/core/file_sys/content_archive.cpp21
-rw-r--r--src/core/file_sys/errors.h1
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp25
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h2
-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/nca_patch.cpp18
-rw-r--r--src/core/file_sys/registered_cache.cpp39
-rw-r--r--src/core/file_sys/registered_cache.h3
-rw-r--r--src/core/file_sys/romfs_factory.cpp6
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp20
-rw-r--r--src/core/file_sys/submission_package.cpp12
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp10
-rw-r--r--src/core/file_sys/vfs_concat.h6
-rw-r--r--src/core/file_sys/vfs_layered.cpp24
-rw-r--r--src/core/file_sys/vfs_layered.h16
-rw-r--r--src/core/file_sys/vfs_libzip.cpp9
-rw-r--r--src/core/file_sys/vfs_offset.cpp4
-rw-r--r--src/core/file_sys/vfs_offset.h2
-rw-r--r--src/core/file_sys/vfs_real.cpp16
-rw-r--r--src/core/file_sys/vfs_real.h8
-rw-r--r--src/core/file_sys/vfs_static.h6
-rw-r--r--src/core/file_sys/vfs_vector.cpp16
-rw-r--r--src/core/file_sys/vfs_vector.h12
-rw-r--r--src/core/frontend/applets/web_browser.cpp4
-rw-r--r--src/core/frontend/applets/web_browser.h9
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/frontend/input.h12
-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.cpp199
-rw-r--r--src/core/hle/kernel/hle_ipc.h93
-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.cpp51
-rw-r--r--src/core/hle/kernel/transfer_memory.h93
-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/acc/acc_aa.cpp8
-rw-r--r--src/core/hle/service/acc/acc_aa.h4
-rw-r--r--src/core/hle/service/acc/acc_su.cpp6
-rw-r--r--src/core/hle/service/acc/acc_su.h4
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u0.h4
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u1.h4
-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.cpp8
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp4
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp6
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h2
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/am/applets/web_browser.h9
-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.cpp64
-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.cpp17
-rw-r--r--src/core/hle/service/bcat/bcat.cpp6
-rw-r--r--src/core/hle/service/bcat/bcat.h4
-rw-r--r--src/core/hle/service/bcat/module.cpp32
-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.cpp11
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp23
-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/grc/grc.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.cpp90
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.h80
-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/debug_pad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp356
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h79
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp26
-rw-r--r--src/core/hle/service/hid/controllers/npad.h12
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp58
-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/lbl/lbl.cpp1
-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/nvdisp_disp0.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h2
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp21
-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.cpp50
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h18
-rw-r--r--src/core/hle/service/pctl/module.cpp13
-rw-r--r--src/core/hle/service/pctl/module.h4
-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/interface.cpp4
-rw-r--r--src/core/hle/service/time/interface.h2
-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.cpp33
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h13
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp14
-rw-r--r--src/core/hle/service/time/system_clock_core.h4
-rw-r--r--src/core/hle/service/time/time.cpp5
-rw-r--r--src/core/hle/service/time/time_manager.cpp24
-rw-r--r--src/core/hle/service/time/time_manager.h2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp20
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h10
-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.cpp39
-rw-r--r--src/core/hle/service/vi/display/vi_display.h38
-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.cpp71
-rw-r--r--src/core/loader/deconstructed_rom_directory.h23
-rw-r--r--src/core/loader/elf.cpp17
-rw-r--r--src/core/loader/elf.h12
-rw-r--r--src/core/loader/kip.cpp16
-rw-r--r--src/core/loader/kip.h12
-rw-r--r--src/core/loader/loader.cpp4
-rw-r--r--src/core/loader/loader.h63
-rw-r--r--src/core/loader/nax.cpp13
-rw-r--r--src/core/loader/nax.h14
-rw-r--r--src/core/loader/nca.cpp43
-rw-r--r--src/core/loader/nca.h14
-rw-r--r--src/core/loader/nro.cpp17
-rw-r--r--src/core/loader/nro.h18
-rw-r--r--src/core/loader/nso.cpp28
-rw-r--r--src/core/loader/nso.h22
-rw-r--r--src/core/loader/nsp.cpp57
-rw-r--r--src/core/loader/nsp.h20
-rw-r--r--src/core/loader/xci.cpp54
-rw-r--r--src/core/loader/xci.h20
-rw-r--r--src/core/memory.cpp64
-rw-r--r--src/core/memory.h34
-rw-r--r--src/core/memory/cheat_engine.cpp20
-rw-r--r--src/core/memory/cheat_engine.h10
-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.cpp14
-rw-r--r--src/core/perf_stats.h11
-rw-r--r--src/core/reporter.cpp4
-rw-r--r--src/core/reporter.h2
-rw-r--r--src/core/tools/freezer.cpp4
-rw-r--r--src/core/tools/freezer.h2
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp8
-rw-r--r--src/input_common/gcadapter/gc_adapter.h1
-rw-r--r--src/input_common/main.cpp5
-rw-r--r--src/input_common/motion_input.cpp10
-rw-r--r--src/input_common/mouse/mouse_input.cpp9
-rw-r--r--src/input_common/mouse/mouse_input.h8
-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/input_common/udp/client.cpp23
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h5
-rw-r--r--src/video_core/gpu.cpp5
-rw-r--r--src/video_core/gpu.h2
-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_opengl/renderer_opengl.cpp1
-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/renderer_vulkan.cpp1
-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/about_dialog.cpp16
-rw-r--r--src/yuzu/aboutdialog.ui2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp34
-rw-r--r--src/yuzu/applets/web_browser.cpp19
-rw-r--r--src/yuzu/applets/web_browser.h11
-rw-r--r--src/yuzu/bootmanager.cpp4
-rw-r--r--src/yuzu/configuration/config.cpp75
-rw-r--r--src/yuzu/configuration/config.h1
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp58
-rw-r--r--src/yuzu/configuration/configuration_shared.h34
-rw-r--r--src/yuzu/configuration/configure_audio.cpp10
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp86
-rw-r--r--src/yuzu/configuration/configure_cpu.h10
-rw-r--r--src/yuzu/configuration/configure_cpu.ui90
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu/configuration/configure_general.cpp12
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp42
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp46
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp8
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp1
-rw-r--r--src/yuzu/configuration/configure_per_game.ui11
-rw-r--r--src/yuzu/configuration/configure_system.cpp72
-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/game_list.cpp15
-rw-r--r--src/yuzu/game_list_p.h2
-rw-r--r--src/yuzu/main.cpp68
-rw-r--r--src/yuzu/main.h3
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
403 files changed, 7575 insertions, 4647 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh
index 1af5ded3d..9b451d3ab 100755
--- a/.ci/scripts/linux/docker.sh
+++ b/.ci/scripts/linux/docker.sh
@@ -30,10 +30,10 @@ make install DESTDIR=AppDir
30rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester 30rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
31 31
32# Download tools needed to build an AppImage 32# Download tools needed to build an AppImage
33wget -nc https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage 33wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-x86_64.AppImage
34wget -nc https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage 34wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-plugin-qt-x86_64.AppImage
35wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64 35wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/AppRun-patched-x86_64
36wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/exec-x86_64.so 36wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so
37# Set executable bit 37# Set executable bit
38chmod 755 \ 38chmod 755 \
39 AppRun-patched-x86_64 \ 39 AppRun-patched-x86_64 \
diff --git a/.ci/scripts/linux/upload.sh b/.ci/scripts/linux/upload.sh
index b2ea07388..208cd0d04 100644
--- a/.ci/scripts/linux/upload.sh
+++ b/.ci/scripts/linux/upload.sh
@@ -21,7 +21,7 @@ cp build/bin/yuzu "$DIR_NAME"
21# Build an AppImage 21# Build an AppImage
22cd build 22cd build
23 23
24wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage 24wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/appimagetool-x86_64.AppImage
25chmod 755 appimagetool-x86_64.AppImage 25chmod 755 appimagetool-x86_64.AppImage
26 26
27if [ "${RELEASE_NAME}" = "mainline" ]; then 27if [ "${RELEASE_NAME}" = "mainline" ]; then
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 15ecb8a9c..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)
@@ -202,7 +204,7 @@ macro(yuzu_find_packages)
202endmacro() 204endmacro()
203 205
204if (NOT YUZU_USE_BUNDLED_BOOST) 206if (NOT YUZU_USE_BUNDLED_BOOST)
205 find_package(Boost 1.73.0 COMPONENTS context headers QUIET) 207 find_package(Boost 1.73.0 CONFIG COMPONENTS context headers QUIET)
206endif() 208endif()
207if (Boost_FOUND) 209if (Boost_FOUND)
208 set(Boost_LIBRARIES Boost::boost) 210 set(Boost_LIBRARIES Boost::boost)
@@ -224,7 +226,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST)
224 download_bundled_external("boost/" ${Boost_EXT_NAME} "") 226 download_bundled_external("boost/" ${Boost_EXT_NAME} "")
225 set(Boost_USE_DEBUG_RUNTIME FALSE) 227 set(Boost_USE_DEBUG_RUNTIME FALSE)
226 set(Boost_USE_STATIC_LIBS ON) 228 set(Boost_USE_STATIC_LIBS ON)
227 find_package(Boost 1.75.0 REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH) 229 find_package(Boost 1.75.0 CONFIG REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH)
228 # Manually set the include dirs since the find_package sets it incorrectly 230 # Manually set the include dirs since the find_package sets it incorrectly
229 set(Boost_INCLUDE_DIRS ${Boost_PATH}/include CACHE PATH "Path to Boost headers" FORCE) 231 set(Boost_INCLUDE_DIRS ${Boost_PATH}/include CACHE PATH "Path to Boost headers" FORCE)
230 include_directories(SYSTEM "${Boost_INCLUDE_DIRS}") 232 include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
@@ -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/dist/icons/overlay/osk_button_B.png b/dist/icons/overlay/osk_button_B.png
index f4a041178..2664b5923 100644
--- a/dist/icons/overlay/osk_button_B.png
+++ b/dist/icons/overlay/osk_button_B.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark.png b/dist/icons/overlay/osk_button_B_dark.png
index 2d2bffcca..1bd374571 100644
--- a/dist/icons/overlay/osk_button_B_dark.png
+++ b/dist/icons/overlay/osk_button_B_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark_disabled.png b/dist/icons/overlay/osk_button_B_dark_disabled.png
index 93c102b1b..3b88e393c 100644
--- a/dist/icons/overlay/osk_button_B_dark_disabled.png
+++ b/dist/icons/overlay/osk_button_B_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_disabled.png b/dist/icons/overlay/osk_button_B_disabled.png
index 5900982f6..0f35cd8f2 100644
--- a/dist/icons/overlay/osk_button_B_disabled.png
+++ b/dist/icons/overlay/osk_button_B_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y.png b/dist/icons/overlay/osk_button_Y.png
index b08b4e26b..2cd193481 100644
--- a/dist/icons/overlay/osk_button_Y.png
+++ b/dist/icons/overlay/osk_button_Y.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark.png b/dist/icons/overlay/osk_button_Y_dark.png
index 1fba9ca93..0cce567d3 100644
--- a/dist/icons/overlay/osk_button_Y_dark.png
+++ b/dist/icons/overlay/osk_button_Y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark_disabled.png b/dist/icons/overlay/osk_button_Y_dark_disabled.png
index 6ce53f9e4..de619efa3 100644
--- a/dist/icons/overlay/osk_button_Y_dark_disabled.png
+++ b/dist/icons/overlay/osk_button_Y_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_disabled.png b/dist/icons/overlay/osk_button_Y_disabled.png
index 25db07f66..8d607bc12 100644
--- a/dist/icons/overlay/osk_button_Y_disabled.png
+++ b/dist/icons/overlay/osk_button_Y_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus.png b/dist/icons/overlay/osk_button_plus.png
index 5baa5201e..9f9787419 100644
--- a/dist/icons/overlay/osk_button_plus.png
+++ b/dist/icons/overlay/osk_button_plus.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark.png b/dist/icons/overlay/osk_button_plus_dark.png
index 4cadb438b..dbe7b0c66 100644
--- a/dist/icons/overlay/osk_button_plus_dark.png
+++ b/dist/icons/overlay/osk_button_plus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark_disabled.png b/dist/icons/overlay/osk_button_plus_dark_disabled.png
index b8eb8dc3d..a79af6501 100644
--- a/dist/icons/overlay/osk_button_plus_dark_disabled.png
+++ b/dist/icons/overlay/osk_button_plus_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_disabled.png b/dist/icons/overlay/osk_button_plus_disabled.png
index c23e9d95d..52ace8eca 100644
--- a/dist/icons/overlay/osk_button_plus_disabled.png
+++ b/dist/icons/overlay/osk_button_plus_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_off.png b/dist/icons/overlay/osk_button_shift_lock_off.png
index 585500b3a..b506f456f 100644
--- a/dist/icons/overlay/osk_button_shift_lock_off.png
+++ b/dist/icons/overlay/osk_button_shift_lock_off.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_on.png b/dist/icons/overlay/osk_button_shift_lock_on.png
index 09077ab01..eaa4e98ed 100644
--- a/dist/icons/overlay/osk_button_shift_lock_on.png
+++ b/dist/icons/overlay/osk_button_shift_lock_on.png
Binary files differ
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index 3bc92b69d..cee219374 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -515,45 +515,35 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
515QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace, 515QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
516QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift, 516QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
517QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num { 517QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
518 background-position: right top; 518 image: url(:/overlay/osk_button_B.png);
519 background-repeat: no-repeat; 519 image-position: right;
520 background-origin: content;
521 background-image: url(:/overlay/osk_button_B.png);
522 qproperty-icon: url(:/overlay/osk_button_backspace.png); 520 qproperty-icon: url(:/overlay/osk_button_backspace.png);
523 qproperty-iconSize: 36px; 521 qproperty-iconSize: 36px;
524} 522}
525 523
526QDialog#QtSoftwareKeyboardDialog QPushButton#button_space, 524QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
527QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift { 525QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
528 background-position: right top; 526 image: url(:/overlay/osk_button_Y.png);
529 background-repeat: no-repeat; 527 image-position: right;
530 background-origin: content;
531 background-image: url(:/overlay/osk_button_Y.png);
532} 528}
533 529
534QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok, 530QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
535QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift, 531QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
536QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num { 532QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
537 background-position: right top; 533 image: url(:/overlay/osk_button_plus.png);
538 background-repeat: no-repeat; 534 image-position: right;
539 background-origin: content;
540 background-image: url(:/overlay/osk_button_plus.png);
541} 535}
542 536
543QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift { 537QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
544 background-position: left top; 538 image: url(:/overlay/osk_button_shift_lock_off.png);
545 background-repeat: no-repeat; 539 image-position: left;
546 background-origin: content;
547 background-image: url(:/overlay/osk_button_shift_lock_off.png);
548 qproperty-icon: url(:/overlay/osk_button_shift.png); 540 qproperty-icon: url(:/overlay/osk_button_shift.png);
549 qproperty-iconSize: 36px; 541 qproperty-iconSize: 36px;
550} 542}
551 543
552QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift { 544QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
553 background-position: left top; 545 image: url(:/overlay/osk_button_shift_lock_off.png);
554 background-repeat: no-repeat; 546 image-position: left;
555 background-origin: content;
556 background-image: url(:/overlay/osk_button_shift_lock_off.png);
557 qproperty-icon: url(:/overlay/osk_button_shift_on.png); 547 qproperty-icon: url(:/overlay/osk_button_shift_on.png);
558 qproperty-iconSize: 36px; 548 qproperty-iconSize: 36px;
559} 549}
@@ -645,16 +635,16 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
645QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled, 635QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
646QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled, 636QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
647QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled { 637QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
648 background-image: url(:/overlay/osk_button_plus_disabled.png); 638 image: url(:/overlay/osk_button_plus_disabled.png);
649} 639}
650 640
651QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled, 641QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
652QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled, 642QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
653QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled { 643QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
654 background-image: url(:/overlay/osk_button_B_disabled.png); 644 image: url(:/overlay/osk_button_B_disabled.png);
655} 645}
656 646
657QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled, 647QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
658QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled { 648QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
659 background-image: url(:/overlay/osk_button_Y_disabled.png); 649 image: url(:/overlay/osk_button_Y_disabled.png);
660} 650}
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 8ce6d75f7..3d0ccbb9e 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1805,46 +1805,36 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
1805QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace, 1805QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
1806QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift, 1806QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
1807QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num { 1807QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
1808 background-position: right top; 1808 image: url(:/overlay/osk_button_B_dark.png);
1809 background-repeat: no-repeat; 1809 image-position: right;
1810 background-origin: content;
1811 background-image: url(:/overlay/osk_button_B_dark.png);
1812 qproperty-icon: url(:/overlay/osk_button_backspace_dark.png); 1810 qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
1813 qproperty-iconSize: 36px; 1811 qproperty-iconSize: 36px;
1814} 1812}
1815 1813
1816QDialog#QtSoftwareKeyboardDialog QPushButton#button_space, 1814QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
1817QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift { 1815QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
1818 background-position: right top; 1816 image: url(:/overlay/osk_button_Y_dark.png);
1819 background-repeat: no-repeat; 1817 image-position: right;
1820 background-origin: content;
1821 background-image: url(:/overlay/osk_button_Y_dark.png);
1822} 1818}
1823 1819
1824QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok, 1820QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
1825QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift, 1821QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
1826QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num { 1822QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
1827 color: rgba(44, 44, 44, 1); 1823 color: rgba(44, 44, 44, 1);
1828 background-position: right top; 1824 image: url(:/overlay/osk_button_plus_dark.png);
1829 background-repeat: no-repeat; 1825 image-position: right;
1830 background-origin: content;
1831 background-image: url(:/overlay/osk_button_plus_dark.png);
1832} 1826}
1833 1827
1834QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift { 1828QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
1835 background-position: left top; 1829 image: url(:/overlay/osk_button_shift_lock_off.png);
1836 background-repeat: no-repeat; 1830 image-position: left;
1837 background-origin: content;
1838 background-image: url(:/overlay/osk_button_shift_lock_off.png);
1839 qproperty-icon: url(:/overlay/osk_button_shift_dark.png); 1831 qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
1840 qproperty-iconSize: 36px; 1832 qproperty-iconSize: 36px;
1841} 1833}
1842 1834
1843QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift { 1835QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
1844 background-position: left top; 1836 image: url(:/overlay/osk_button_shift_lock_off.png);
1845 background-repeat: no-repeat; 1837 image-position: left;
1846 background-origin: content;
1847 background-image: url(:/overlay/osk_button_shift_lock_off.png);
1848 qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png); 1838 qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
1849 qproperty-iconSize: 36px; 1839 qproperty-iconSize: 36px;
1850} 1840}
@@ -1936,18 +1926,18 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
1936QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled, 1926QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
1937QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled, 1927QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
1938QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled { 1928QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
1939 background-image: url(:/overlay/osk_button_plus_dark_disabled.png); 1929 image: url(:/overlay/osk_button_plus_dark_disabled.png);
1940} 1930}
1941 1931
1942QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled, 1932QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
1943QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled, 1933QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
1944QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled { 1934QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
1945 background-image: url(:/overlay/osk_button_B_dark_disabled.png); 1935 image: url(:/overlay/osk_button_B_dark_disabled.png);
1946} 1936}
1947 1937
1948QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled, 1938QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
1949QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled { 1939QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
1950 background-image: url(:/overlay/osk_button_Y_dark_disabled.png); 1940 image: url(:/overlay/osk_button_Y_dark_disabled.png);
1951} 1941}
1952 1942
1953QDialog#QtSoftwareKeyboardDialog QFrame, 1943QDialog#QtSoftwareKeyboardDialog QFrame,
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index 64e1ecbcc..51bec2fd7 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -2740,46 +2740,36 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
2740QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace, 2740QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
2741QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift, 2741QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
2742QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num { 2742QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
2743 background-position: right top; 2743 image: url(:/overlay/osk_button_B_dark.png);
2744 background-repeat: no-repeat; 2744 image-position: right;
2745 background-origin: content;
2746 background-image: url(:/overlay/osk_button_B_dark.png);
2747 qproperty-icon: url(:/overlay/osk_button_backspace_dark.png); 2745 qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
2748 qproperty-iconSize: 36px; 2746 qproperty-iconSize: 36px;
2749} 2747}
2750 2748
2751QDialog#QtSoftwareKeyboardDialog QPushButton#button_space, 2749QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
2752QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift { 2750QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
2753 background-position: right top; 2751 image: url(:/overlay/osk_button_Y_dark.png);
2754 background-repeat: no-repeat; 2752 image-position: right;
2755 background-origin: content;
2756 background-image: url(:/overlay/osk_button_Y_dark.png);
2757} 2753}
2758 2754
2759QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok, 2755QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
2760QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift, 2756QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
2761QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num { 2757QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
2762 color: rgba(44, 44, 44, 1); 2758 color: rgba(44, 44, 44, 1);
2763 background-position: right top; 2759 image: url(:/overlay/osk_button_plus_dark.png);
2764 background-repeat: no-repeat; 2760 image-position: right;
2765 background-origin: content;
2766 background-image: url(:/overlay/osk_button_plus_dark.png);
2767} 2761}
2768 2762
2769QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift { 2763QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
2770 background-position: left top; 2764 image: url(:/overlay/osk_button_shift_lock_off.png);
2771 background-repeat: no-repeat; 2765 image-position: left;
2772 background-origin: content;
2773 background-image: url(:/overlay/osk_button_shift_lock_off.png);
2774 qproperty-icon: url(:/overlay/osk_button_shift_dark.png); 2766 qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
2775 qproperty-iconSize: 36px; 2767 qproperty-iconSize: 36px;
2776} 2768}
2777 2769
2778QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift { 2770QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
2779 background-position: left top; 2771 image: url(:/overlay/osk_button_shift_lock_off.png);
2780 background-repeat: no-repeat; 2772 image-position: left;
2781 background-origin: content;
2782 background-image: url(:/overlay/osk_button_shift_lock_off.png);
2783 qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png); 2773 qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
2784 qproperty-iconSize: 36px; 2774 qproperty-iconSize: 36px;
2785} 2775}
@@ -2871,16 +2861,16 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
2871QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled, 2861QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
2872QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled, 2862QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
2873QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled { 2863QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
2874 background-image: url(:/overlay/osk_button_plus_dark_disabled.png); 2864 image: url(:/overlay/osk_button_plus_dark_disabled.png);
2875} 2865}
2876 2866
2877QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled, 2867QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
2878QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled, 2868QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
2879QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled { 2869QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
2880 background-image: url(:/overlay/osk_button_B_dark_disabled.png); 2870 image: url(:/overlay/osk_button_B_dark_disabled.png);
2881} 2871}
2882 2872
2883QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled, 2873QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
2884QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled { 2874QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
2885 background-image: url(:/overlay/osk_button_Y_dark_disabled.png); 2875 image: url(:/overlay/osk_button_Y_dark_disabled.png);
2886} 2876}
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/CMakeLists.txt b/src/CMakeLists.txt
index 8bd7e5f72..f30dd49a3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -54,6 +54,7 @@ if (MSVC)
54 /we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect 54 /we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
55 /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'? 55 /we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
56 /we4555 # Expression has no effect; expected expression with side-effect 56 /we4555 # Expression has no effect; expected expression with side-effect
57 /we4715 # 'function': not all control paths return a value
57 /we4834 # Discarding return value of function with 'nodiscard' attribute 58 /we4834 # Discarding return value of function with 'nodiscard' attribute
58 /we5038 # data member 'member1' will be initialized after data member 'member2' 59 /we5038 # data member 'member1' will be initialized after data member 'member2'
59 ) 60 )
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..58c70b0e7 100644
--- a/src/common/parent_of_member.h
+++ b/src/common/parent_of_member.h
@@ -109,7 +109,8 @@ struct OffsetOfCalculator {
109 } 109 }
110 } 110 }
111 111
112 return (next - start) * sizeof(MemberType) + Offset; 112 return static_cast<ptrdiff_t>(static_cast<size_t>(next - start) * sizeof(MemberType) +
113 Offset);
113 } 114 }
114 115
115 static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) { 116 static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
@@ -133,27 +134,27 @@ template <auto MemberPtr>
133using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member; 134using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
134 135
135template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> 136template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
136static inline std::ptrdiff_t OffsetOf = [] { 137constexpr std::ptrdiff_t OffsetOf() {
137 using DeducedParentType = GetParentType<MemberPtr>; 138 using DeducedParentType = GetParentType<MemberPtr>;
138 using MemberType = GetMemberType<MemberPtr>; 139 using MemberType = GetMemberType<MemberPtr>;
139 static_assert(std::is_base_of<DeducedParentType, RealParentType>::value || 140 static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
140 std::is_same<RealParentType, DeducedParentType>::value); 141 std::is_same<RealParentType, DeducedParentType>::value);
141 142
142 return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr); 143 return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
143}(); 144};
144 145
145} // namespace impl 146} // namespace impl
146 147
147template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> 148template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
148constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) { 149constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
149 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; 150 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
150 return *static_cast<RealParentType*>( 151 return *static_cast<RealParentType*>(
151 static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset)); 152 static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
152} 153}
153 154
154template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> 155template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
155constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) { 156constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
156 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; 157 std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
157 return *static_cast<const RealParentType*>(static_cast<const void*>( 158 return *static_cast<const RealParentType*>(static_cast<const void*>(
158 static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset)); 159 static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
159} 160}
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 702b6598d..e29cbf506 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -42,7 +42,7 @@ void LogSettings() {
42 log_setting("System_RegionIndex", values.region_index.GetValue()); 42 log_setting("System_RegionIndex", values.region_index.GetValue());
43 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 43 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
44 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 44 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
45 log_setting("CPU_Accuracy", values.cpu_accuracy); 45 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
46 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); 46 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
47 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); 47 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue());
48 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); 48 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue());
@@ -106,6 +106,12 @@ void RestoreGlobalState(bool is_powered_on) {
106 // Core 106 // Core
107 values.use_multi_core.SetGlobal(true); 107 values.use_multi_core.SetGlobal(true);
108 108
109 // CPU
110 values.cpu_accuracy.SetGlobal(true);
111 values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
112 values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
113 values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
114
109 // Renderer 115 // Renderer
110 values.renderer_backend.SetGlobal(true); 116 values.renderer_backend.SetGlobal(true);
111 values.vulkan_device.SetGlobal(true); 117 values.vulkan_device.SetGlobal(true);
@@ -130,7 +136,6 @@ void RestoreGlobalState(bool is_powered_on) {
130 values.region_index.SetGlobal(true); 136 values.region_index.SetGlobal(true);
131 values.time_zone_index.SetGlobal(true); 137 values.time_zone_index.SetGlobal(true);
132 values.rng_seed.SetGlobal(true); 138 values.rng_seed.SetGlobal(true);
133 values.custom_rtc.SetGlobal(true);
134 values.sound_index.SetGlobal(true); 139 values.sound_index.SetGlobal(true);
135 140
136 // Controls 141 // Controls
diff --git a/src/common/settings.h b/src/common/settings.h
index d39b4aa45..48085b9a9 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -115,7 +115,7 @@ struct Values {
115 Setting<bool> use_multi_core; 115 Setting<bool> use_multi_core;
116 116
117 // Cpu 117 // Cpu
118 CPUAccuracy cpu_accuracy; 118 Setting<CPUAccuracy> cpu_accuracy;
119 119
120 bool cpuopt_page_tables; 120 bool cpuopt_page_tables;
121 bool cpuopt_block_linking; 121 bool cpuopt_block_linking;
@@ -126,9 +126,9 @@ struct Values {
126 bool cpuopt_misc_ir; 126 bool cpuopt_misc_ir;
127 bool cpuopt_reduce_misalign_checks; 127 bool cpuopt_reduce_misalign_checks;
128 128
129 bool cpuopt_unsafe_unfuse_fma; 129 Setting<bool> cpuopt_unsafe_unfuse_fma;
130 bool cpuopt_unsafe_reduce_fp_error; 130 Setting<bool> cpuopt_unsafe_reduce_fp_error;
131 bool cpuopt_unsafe_inaccurate_nan; 131 Setting<bool> cpuopt_unsafe_inaccurate_nan;
132 132
133 // Renderer 133 // Renderer
134 Setting<RendererBackend> renderer_backend; 134 Setting<RendererBackend> renderer_backend;
@@ -157,7 +157,7 @@ struct Values {
157 // System 157 // System
158 Setting<std::optional<u32>> rng_seed; 158 Setting<std::optional<u32>> rng_seed;
159 // Measured in seconds since epoch 159 // Measured in seconds since epoch
160 Setting<std::optional<std::chrono::seconds>> custom_rtc; 160 std::optional<std::chrono::seconds> custom_rtc;
161 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` 161 // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
162 std::chrono::seconds custom_rtc_differential; 162 std::chrono::seconds custom_rtc_differential;
163 163
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 04cf3f5b9..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
@@ -393,6 +403,8 @@ add_library(core STATIC
393 hle/service/hid/xcd.cpp 403 hle/service/hid/xcd.cpp
394 hle/service/hid/xcd.h 404 hle/service/hid/xcd.h
395 hle/service/hid/errors.h 405 hle/service/hid/errors.h
406 hle/service/hid/controllers/console_sixaxis.cpp
407 hle/service/hid/controllers/console_sixaxis.h
396 hle/service/hid/controllers/controller_base.cpp 408 hle/service/hid/controllers/controller_base.cpp
397 hle/service/hid/controllers/controller_base.h 409 hle/service/hid/controllers/controller_base.h
398 hle/service/hid/controllers/debug_pad.cpp 410 hle/service/hid/controllers/debug_pad.cpp
@@ -639,20 +651,17 @@ endif()
639 651
640if (MSVC) 652if (MSVC)
641 target_compile_options(core PRIVATE 653 target_compile_options(core PRIVATE
642 # 'expression' : signed/unsigned mismatch 654 /we4018 # 'expression' : signed/unsigned mismatch
643 /we4018 655 /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
644 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point) 656 /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
645 /we4244 657 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
646 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch 658 /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
647 /we4245 659 /we4305 # 'context' : truncation from 'type1' to 'type2'
648 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 660 /we4456 # Declaration of 'identifier' hides previous local declaration
649 /we4254 661 /we4457 # Declaration of 'identifier' hides function parameter
650 # 'var' : conversion from 'size_t' to 'type', possible loss of data 662 /we4458 # Declaration of 'identifier' hides class member
651 /we4267 663 /we4459 # Declaration of 'identifier' hides global declaration
652 # 'context' : truncation from 'type1' to 'type2' 664 /we4715 # 'function' : not all control paths return a value
653 /we4305
654 # 'function' : not all control paths return a value
655 /we4715
656 ) 665 )
657else() 666else()
658 target_compile_options(core PRIVATE 667 target_compile_options(core PRIVATE
@@ -660,6 +669,7 @@ else()
660 -Werror=ignored-qualifiers 669 -Werror=ignored-qualifiers
661 -Werror=implicit-fallthrough 670 -Werror=implicit-fallthrough
662 -Werror=sign-compare 671 -Werror=sign-compare
672 -Werror=shadow
663 673
664 $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> 674 $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
665 $<$<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 7aeb2a658..93d43e22e 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);
@@ -142,7 +142,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
142 config.far_code_offset = 256 * 1024 * 1024; 142 config.far_code_offset = 256 * 1024 * 1024;
143 143
144 // Safe optimizations 144 // Safe optimizations
145 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 145 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
146 if (!Settings::values.cpuopt_page_tables) { 146 if (!Settings::values.cpuopt_page_tables) {
147 config.page_table = nullptr; 147 config.page_table = nullptr;
148 } 148 }
@@ -170,15 +170,15 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
170 } 170 }
171 171
172 // Unsafe optimizations 172 // Unsafe optimizations
173 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { 173 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
174 config.unsafe_optimizations = true; 174 config.unsafe_optimizations = true;
175 if (Settings::values.cpuopt_unsafe_unfuse_fma) { 175 if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
176 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 176 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
177 } 177 }
178 if (Settings::values.cpuopt_unsafe_reduce_fp_error) { 178 if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
179 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 179 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
180 } 180 }
181 if (Settings::values.cpuopt_unsafe_inaccurate_nan) { 181 if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
182 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 182 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
183 } 183 }
184 } 184 }
@@ -198,13 +198,13 @@ void ARM_Dynarmic_32::Step() {
198 jit->Step(); 198 jit->Step();
199} 199}
200 200
201ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, 201ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
202 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, 202 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
203 std::size_t core_index) 203 std::size_t core_index_)
204 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 204 : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
205 cb(std::make_unique<DynarmicCallbacks32>(*this)), 205 cb(std::make_unique<DynarmicCallbacks32>(*this)),
206 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, 206 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
207 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)}, 207 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
208 jit(MakeJit(nullptr)) {} 208 jit(MakeJit(nullptr)) {}
209 209
210ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; 210ARM_Dynarmic_32::~ARM_Dynarmic_32() = default;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index d40aef7a9..42778c02c 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -29,8 +29,8 @@ class System;
29 29
30class ARM_Dynarmic_32 final : public ARM_Interface { 30class ARM_Dynarmic_32 final : public ARM_Interface {
31public: 31public:
32 ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, 32 ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
33 ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 33 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
34 ~ARM_Dynarmic_32() override; 34 ~ARM_Dynarmic_32() override;
35 35
36 void SetPC(u64 pc) override; 36 void SetPC(u64 pc) override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 040529f4d..08fa85904 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);
@@ -182,7 +182,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
182 config.far_code_offset = 256 * 1024 * 1024; 182 config.far_code_offset = 256 * 1024 * 1024;
183 183
184 // Safe optimizations 184 // Safe optimizations
185 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { 185 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
186 if (!Settings::values.cpuopt_page_tables) { 186 if (!Settings::values.cpuopt_page_tables) {
187 config.page_table = nullptr; 187 config.page_table = nullptr;
188 } 188 }
@@ -210,15 +210,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
210 } 210 }
211 211
212 // Unsafe optimizations 212 // Unsafe optimizations
213 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { 213 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
214 config.unsafe_optimizations = true; 214 config.unsafe_optimizations = true;
215 if (Settings::values.cpuopt_unsafe_unfuse_fma) { 215 if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
217 } 217 }
218 if (Settings::values.cpuopt_unsafe_reduce_fp_error) { 218 if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
219 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 219 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
220 } 220 }
221 if (Settings::values.cpuopt_unsafe_inaccurate_nan) { 221 if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
222 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; 222 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
223 } 223 }
224 } 224 }
@@ -238,12 +238,12 @@ void ARM_Dynarmic_64::Step() {
238 cb->InterpreterFallback(jit->GetPC(), 1); 238 cb->InterpreterFallback(jit->GetPC(), 1);
239} 239}
240 240
241ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, 241ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
242 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, 242 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
243 std::size_t core_index) 243 std::size_t core_index_)
244 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 244 : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
245 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index}, 245 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
246 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)}, 246 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
247 jit(MakeJit(nullptr, 48)) {} 247 jit(MakeJit(nullptr, 48)) {}
248 248
249ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; 249ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index edef04376..b81fbcc66 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -26,8 +26,8 @@ class System;
26 26
27class ARM_Dynarmic_64 final : public ARM_Interface { 27class ARM_Dynarmic_64 final : public ARM_Interface {
28public: 28public:
29 ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, 29 ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
30 ExclusiveMonitor& exclusive_monitor, std::size_t core_index); 30 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
31 ~ARM_Dynarmic_64() override; 31 ~ARM_Dynarmic_64() override;
32 32
33 void SetPC(u64 pc) override; 33 void SetPC(u64 pc) override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index caefc09f4..ebd506121 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -94,12 +94,11 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1,
94CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { 94CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) {
95 if (!two && opc == 0 && CRm == CoprocReg::C14) { 95 if (!two && opc == 0 && CRm == CoprocReg::C14) {
96 // CNTPCT 96 // CNTPCT
97 const auto callback = static_cast<u64 (*)(Dynarmic::A32::Jit*, void*, u32, u32)>( 97 const auto callback = [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 {
98 [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 { 98 const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg);
99 ARM_Dynarmic_32& parent = *(ARM_Dynarmic_32*)arg; 99 return parent_arg.system.CoreTiming().GetClockTicks();
100 return parent.system.CoreTiming().GetClockTicks(); 100 };
101 }); 101 return Callback{callback, &parent};
102 return Dynarmic::A32::Coprocessor::Callback{callback, (void*)&parent};
103 } 102 }
104 103
105 LOG_CRITICAL(Core_ARM, "CP15: mrrc{} p15, {}, <Rt>, <Rt2>, {}", two ? "2" : "", opc, CRm); 104 LOG_CRITICAL(Core_ARM, "CP15: mrrc{} p15, {}, <Rt>, <Rt2>, {}", two ? "2" : "", opc, CRm);
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..826a00ad6 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,14 +166,14 @@ 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());
175 Settings::values.custom_rtc_differential = 175 Settings::values.custom_rtc_differential =
176 Settings::values.custom_rtc.GetValue().value_or(current_time) - current_time; 176 Settings::values.custom_rtc.value_or(current_time) - current_time;
177 177
178 // Create a default fs if one doesn't already exist. 178 // Create a default fs if one doesn't already exist.
179 if (virtual_filesystem == nullptr) 179 if (virtual_filesystem == nullptr)
@@ -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
@@ -286,7 +289,8 @@ struct System::Impl {
286 289
287 telemetry_session->AddField(performance, "Shutdown_EmulationSpeed", 290 telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
288 perf_results.emulation_speed * 100.0); 291 perf_results.emulation_speed * 100.0);
289 telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps); 292 telemetry_session->AddField(performance, "Shutdown_Framerate",
293 perf_results.average_game_fps);
290 telemetry_session->AddField(performance, "Shutdown_Frametime", 294 telemetry_session->AddField(performance, "Shutdown_Frametime",
291 perf_results.frametime * 1000.0); 295 perf_results.frametime * 1000.0);
292 telemetry_session->AddField(performance, "Mean_Frametime_MS", 296 telemetry_session->AddField(performance, "Mean_Frametime_MS",
@@ -311,6 +315,7 @@ struct System::Impl {
311 gpu_core.reset(); 315 gpu_core.reset();
312 perf_stats.reset(); 316 perf_stats.reset();
313 kernel.Shutdown(); 317 kernel.Shutdown();
318 memory.Reset();
314 applet_manager.ClearAll(); 319 applet_manager.ClearAll();
315 320
316 LOG_DEBUG(Core, "Shutdown OK"); 321 LOG_DEBUG(Core, "Shutdown OK");
@@ -322,7 +327,7 @@ struct System::Impl {
322 return app_loader->ReadTitle(out); 327 return app_loader->ReadTitle(out);
323 } 328 }
324 329
325 void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::Process& process) { 330 void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
326 std::vector<u8> nacp_data; 331 std::vector<u8> nacp_data;
327 FileSys::NACP nacp; 332 FileSys::NACP nacp;
328 if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) { 333 if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
@@ -513,7 +518,7 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
513 return impl->kernel.GlobalSchedulerContext(); 518 return impl->kernel.GlobalSchedulerContext();
514} 519}
515 520
516Kernel::Process* System::CurrentProcess() { 521Kernel::KProcess* System::CurrentProcess() {
517 return impl->kernel.CurrentProcess(); 522 return impl->kernel.CurrentProcess();
518} 523}
519 524
@@ -525,7 +530,7 @@ const Core::DeviceMemory& System::DeviceMemory() const {
525 return *impl->device_memory; 530 return *impl->device_memory;
526} 531}
527 532
528const Kernel::Process* System::CurrentProcess() const { 533const Kernel::KProcess* System::CurrentProcess() const {
529 return impl->kernel.CurrentProcess(); 534 return impl->kernel.CurrentProcess();
530} 535}
531 536
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/core_timing.cpp b/src/core/core_timing.cpp
index 874b5673a..c2f0f609f 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -133,8 +133,8 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
133 } 133 }
134} 134}
135 135
136void CoreTiming::AddTicks(u64 ticks) { 136void CoreTiming::AddTicks(u64 ticks_to_add) {
137 this->ticks += ticks; 137 ticks += ticks_to_add;
138 downcount -= static_cast<s64>(ticks); 138 downcount -= static_cast<s64>(ticks);
139} 139}
140 140
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 77ff4c6fe..b64caacda 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -102,7 +102,7 @@ public:
102 /// We only permit one event of each type in the queue at a time. 102 /// We only permit one event of each type in the queue at a time.
103 void RemoveEvent(const std::shared_ptr<EventType>& event_type); 103 void RemoveEvent(const std::shared_ptr<EventType>& event_type);
104 104
105 void AddTicks(u64 ticks); 105 void AddTicks(u64 ticks_to_add);
106 106
107 void ResetTicks(); 107 void ResetTicks();
108 108
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 17420c941..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
@@ -35,13 +35,13 @@ public:
35 CpuManager& operator=(CpuManager&&) = delete; 35 CpuManager& operator=(CpuManager&&) = delete;
36 36
37 /// Sets if emulation is multicore or single core, must be set before Initialize 37 /// Sets if emulation is multicore or single core, must be set before Initialize
38 void SetMulticore(bool is_multicore) { 38 void SetMulticore(bool is_multi) {
39 this->is_multicore = is_multicore; 39 is_multicore = is_multi;
40 } 40 }
41 41
42 /// Sets if emulation is using an asynchronous GPU. 42 /// Sets if emulation is using an asynchronous GPU.
43 void SetAsyncGpu(bool is_async_gpu) { 43 void SetAsyncGpu(bool is_async) {
44 this->is_async_gpu = is_async_gpu; 44 is_async_gpu = is_async;
45 } 45 }
46 46
47 void Initialize(); 47 void Initialize();
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/card_image.cpp b/src/core/file_sys/card_image.cpp
index 8dee5590b..db2f6a955 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -176,26 +176,30 @@ u64 XCI::GetProgramTitleID() const {
176 176
177u32 XCI::GetSystemUpdateVersion() { 177u32 XCI::GetSystemUpdateVersion() {
178 const auto update = GetPartition(XCIPartition::Update); 178 const auto update = GetPartition(XCIPartition::Update);
179 if (update == nullptr) 179 if (update == nullptr) {
180 return 0; 180 return 0;
181 }
181 182
182 for (const auto& file : update->GetFiles()) { 183 for (const auto& update_file : update->GetFiles()) {
183 NCA nca{file, nullptr, 0}; 184 NCA nca{update_file, nullptr, 0};
184 185
185 if (nca.GetStatus() != Loader::ResultStatus::Success) 186 if (nca.GetStatus() != Loader::ResultStatus::Success) {
186 continue; 187 continue;
188 }
187 189
188 if (nca.GetType() == NCAContentType::Meta && nca.GetTitleId() == 0x0100000000000816) { 190 if (nca.GetType() == NCAContentType::Meta && nca.GetTitleId() == 0x0100000000000816) {
189 const auto dir = nca.GetSubdirectories()[0]; 191 const auto dir = nca.GetSubdirectories()[0];
190 const auto cnmt = dir->GetFile("SystemUpdate_0100000000000816.cnmt"); 192 const auto cnmt = dir->GetFile("SystemUpdate_0100000000000816.cnmt");
191 if (cnmt == nullptr) 193 if (cnmt == nullptr) {
192 continue; 194 continue;
195 }
193 196
194 CNMT cnmt_data{cnmt}; 197 CNMT cnmt_data{cnmt};
195 198
196 const auto metas = cnmt_data.GetMetaRecords(); 199 const auto metas = cnmt_data.GetMetaRecords();
197 if (metas.empty()) 200 if (metas.empty()) {
198 continue; 201 continue;
202 }
199 203
200 return metas[0].title_version; 204 return metas[0].title_version;
201 } 205 }
@@ -262,8 +266,8 @@ VirtualDir XCI::ConcatenatedPseudoDirectory() {
262 if (part == nullptr) 266 if (part == nullptr)
263 continue; 267 continue;
264 268
265 for (const auto& file : part->GetFiles()) 269 for (const auto& part_file : part->GetFiles())
266 out->AddFile(file); 270 out->AddFile(part_file);
267 } 271 }
268 272
269 return out; 273 return out;
@@ -283,12 +287,12 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
283 return Loader::ResultStatus::ErrorXCIMissingPartition; 287 return Loader::ResultStatus::ErrorXCIMissingPartition;
284 } 288 }
285 289
286 for (const VirtualFile& file : partition->GetFiles()) { 290 for (const VirtualFile& partition_file : partition->GetFiles()) {
287 if (file->GetExtension() != "nca") { 291 if (partition_file->GetExtension() != "nca") {
288 continue; 292 continue;
289 } 293 }
290 294
291 auto nca = std::make_shared<NCA>(file, nullptr, 0); 295 auto nca = std::make_shared<NCA>(partition_file, nullptr, 0);
292 if (nca->IsUpdate()) { 296 if (nca->IsUpdate()) {
293 continue; 297 continue;
294 } 298 }
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index d12218fc2..24eff210f 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <optional> 7#include <optional>
8#include <ranges>
8#include <utility> 9#include <utility>
9 10
10#include "common/logging/log.h" 11#include "common/logging/log.h"
@@ -136,12 +137,11 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
136 return; 137 return;
137 } 138 }
138 139
139 has_rights_id = std::any_of(header.rights_id.begin(), header.rights_id.end(), 140 has_rights_id = std::ranges::any_of(header.rights_id, [](char c) { return c != '\0'; });
140 [](char c) { return c != '\0'; });
141 141
142 const std::vector<NCASectionHeader> sections = ReadSectionHeaders(); 142 const std::vector<NCASectionHeader> sections = ReadSectionHeaders();
143 is_update = std::any_of(sections.begin(), sections.end(), [](const NCASectionHeader& header) { 143 is_update = std::ranges::any_of(sections, [](const NCASectionHeader& nca_header) {
144 return header.raw.header.crypto_type == NCASectionCryptoType::BKTR; 144 return nca_header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
145 }); 145 });
146 146
147 if (!ReadSections(sections, bktr_base_ivfc_offset)) { 147 if (!ReadSections(sections, bktr_base_ivfc_offset)) {
@@ -202,8 +202,9 @@ bool NCA::HandlePotentialHeaderDecryption() {
202 202
203std::vector<NCASectionHeader> NCA::ReadSectionHeaders() const { 203std::vector<NCASectionHeader> NCA::ReadSectionHeaders() const {
204 const std::ptrdiff_t number_sections = 204 const std::ptrdiff_t number_sections =
205 std::count_if(std::begin(header.section_tables), std::end(header.section_tables), 205 std::ranges::count_if(header.section_tables, [](const NCASectionTableEntry& entry) {
206 [](NCASectionTableEntry entry) { return entry.media_offset > 0; }); 206 return entry.media_offset > 0;
207 });
207 208
208 std::vector<NCASectionHeader> sections(number_sections); 209 std::vector<NCASectionHeader> sections(number_sections);
209 const auto length_sections = SECTION_HEADER_SIZE * number_sections; 210 const auto length_sections = SECTION_HEADER_SIZE * number_sections;
@@ -312,11 +313,11 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
312 } 313 }
313 314
314 std::vector<RelocationBucket> relocation_buckets(relocation_buckets_raw.size()); 315 std::vector<RelocationBucket> relocation_buckets(relocation_buckets_raw.size());
315 std::transform(relocation_buckets_raw.begin(), relocation_buckets_raw.end(), 316 std::ranges::transform(relocation_buckets_raw, relocation_buckets.begin(),
316 relocation_buckets.begin(), &ConvertRelocationBucketRaw); 317 &ConvertRelocationBucketRaw);
317 std::vector<SubsectionBucket> subsection_buckets(subsection_buckets_raw.size()); 318 std::vector<SubsectionBucket> subsection_buckets(subsection_buckets_raw.size());
318 std::transform(subsection_buckets_raw.begin(), subsection_buckets_raw.end(), 319 std::ranges::transform(subsection_buckets_raw, subsection_buckets.begin(),
319 subsection_buckets.begin(), &ConvertSubsectionBucketRaw); 320 &ConvertSubsectionBucketRaw);
320 321
321 u32 ctr_low; 322 u32 ctr_low;
322 std::memcpy(&ctr_low, section.raw.section_ctr.data(), sizeof(ctr_low)); 323 std::memcpy(&ctr_low, section.raw.section_ctr.data(), sizeof(ctr_low));
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index bb4654366..1a920b45d 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -9,6 +9,7 @@
9namespace FileSys { 9namespace FileSys {
10 10
11constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1}; 11constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
12constexpr ResultCode ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2};
12constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002}; 13constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
13constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001}; 14constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
14constexpr ResultCode ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005}; 15constexpr ResultCode ERROR_OUT_OF_BOUNDS{ErrorModule::FS, 3005};
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index c52fafb6f..1ca1d536f 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -126,16 +126,17 @@ static u64 romfs_get_hash_table_count(u64 num_entries) {
126 return count; 126 return count;
127} 127}
128 128
129void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext, 129void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir,
130 std::shared_ptr<RomFSBuildDirectoryContext> parent) { 130 std::shared_ptr<RomFSBuildDirectoryContext> parent) {
131 std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs; 131 std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
132 132
133 VirtualDir dir; 133 VirtualDir dir;
134 134
135 if (parent->path_len == 0) 135 if (parent->path_len == 0) {
136 dir = root_romfs; 136 dir = root_romfs;
137 else 137 } else {
138 dir = root_romfs->GetDirectoryRelative(parent->path); 138 dir = root_romfs->GetDirectoryRelative(parent->path);
139 }
139 140
140 const auto entries = dir->GetEntries(); 141 const auto entries = dir->GetEntries();
141 142
@@ -147,8 +148,9 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
147 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); 148 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
148 child->path = parent->path + "/" + kv.first; 149 child->path = parent->path + "/" + kv.first;
149 150
150 if (ext != nullptr && ext->GetFileRelative(child->path + ".stub") != nullptr) 151 if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) {
151 continue; 152 continue;
153 }
152 154
153 // Sanity check on path_len 155 // Sanity check on path_len
154 ASSERT(child->path_len < FS_MAX_PATH); 156 ASSERT(child->path_len < FS_MAX_PATH);
@@ -163,21 +165,20 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
163 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); 165 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
164 child->path = parent->path + "/" + kv.first; 166 child->path = parent->path + "/" + kv.first;
165 167
166 if (ext != nullptr && ext->GetFileRelative(child->path + ".stub") != nullptr) 168 if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) {
167 continue; 169 continue;
170 }
168 171
169 // Sanity check on path_len 172 // Sanity check on path_len
170 ASSERT(child->path_len < FS_MAX_PATH); 173 ASSERT(child->path_len < FS_MAX_PATH);
171 174
172 child->source = root_romfs->GetFileRelative(child->path); 175 child->source = root_romfs->GetFileRelative(child->path);
173 176
174 if (ext != nullptr) { 177 if (ext_dir != nullptr) {
175 const auto ips = ext->GetFileRelative(child->path + ".ips"); 178 if (const auto ips = ext_dir->GetFileRelative(child->path + ".ips")) {
176 179 if (auto patched = PatchIPS(child->source, ips)) {
177 if (ips != nullptr) {
178 auto patched = PatchIPS(child->source, ips);
179 if (patched != nullptr)
180 child->source = std::move(patched); 180 child->source = std::move(patched);
181 }
181 } 182 }
182 } 183 }
183 184
@@ -188,7 +189,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
188 } 189 }
189 190
190 for (auto& child : child_dirs) { 191 for (auto& child : child_dirs) {
191 this->VisitDirectory(root_romfs, ext, child); 192 this->VisitDirectory(root_romfs, ext_dir, child);
192 } 193 }
193} 194}
194 195
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index 049de180b..8d4d89fab 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -59,7 +59,7 @@ private:
59 u64 file_hash_table_size = 0; 59 u64 file_hash_table_size = 0;
60 u64 file_partition_size = 0; 60 u64 file_partition_size = 0;
61 61
62 void VisitDirectory(VirtualDir filesys, VirtualDir ext, 62 void VisitDirectory(VirtualDir filesys, VirtualDir ext_dir,
63 std::shared_ptr<RomFSBuildDirectoryContext> parent); 63 std::shared_ptr<RomFSBuildDirectoryContext> parent);
64 64
65 bool AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 65 bool AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
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/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp
index a65ec6798..b36827b75 100644
--- a/src/core/file_sys/nca_patch.cpp
+++ b/src/core/file_sys/nca_patch.cpp
@@ -83,11 +83,14 @@ BKTR::~BKTR() = default;
83 83
84std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const { 84std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
85 // Read out of bounds. 85 // Read out of bounds.
86 if (offset >= relocation.size) 86 if (offset >= relocation.size) {
87 return 0; 87 return 0;
88 const auto relocation = GetRelocationEntry(offset); 88 }
89 const auto section_offset = offset - relocation.address_patch + relocation.address_source; 89
90 const auto bktr_read = relocation.from_patch; 90 const auto relocation_entry = GetRelocationEntry(offset);
91 const auto section_offset =
92 offset - relocation_entry.address_patch + relocation_entry.address_source;
93 const auto bktr_read = relocation_entry.from_patch;
91 94
92 const auto next_relocation = GetNextRelocationEntry(offset); 95 const auto next_relocation = GetNextRelocationEntry(offset);
93 96
@@ -106,15 +109,16 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
106 return bktr_romfs->Read(data, length, section_offset); 109 return bktr_romfs->Read(data, length, section_offset);
107 } 110 }
108 111
109 const auto subsection = GetSubsectionEntry(section_offset); 112 const auto subsection_entry = GetSubsectionEntry(section_offset);
110 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR); 113 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
111 114
112 // Calculate AES IV 115 // Calculate AES IV
113 std::array<u8, 16> iv{}; 116 std::array<u8, 16> iv{};
114 auto subsection_ctr = subsection.ctr; 117 auto subsection_ctr = subsection_entry.ctr;
115 auto offset_iv = section_offset + base_offset; 118 auto offset_iv = section_offset + base_offset;
116 for (std::size_t i = 0; i < section_ctr.size(); ++i) 119 for (std::size_t i = 0; i < section_ctr.size(); ++i) {
117 iv[i] = section_ctr[0x8 - i - 1]; 120 iv[i] = section_ctr[0x8 - i - 1];
121 }
118 offset_iv >>= 4; 122 offset_iv >>= 4;
119 for (std::size_t i = 0; i < sizeof(u64); ++i) { 123 for (std::size_t i = 0; i < sizeof(u64); ++i) {
120 iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF); 124 iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF);
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 431302f55..b0cb65952 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -12,6 +12,7 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/crypto/key_manager.h" 13#include "core/crypto/key_manager.h"
14#include "core/file_sys/card_image.h" 14#include "core/file_sys/card_image.h"
15#include "core/file_sys/common_funcs.h"
15#include "core/file_sys/content_archive.h" 16#include "core/file_sys/content_archive.h"
16#include "core/file_sys/nca_metadata.h" 17#include "core/file_sys/nca_metadata.h"
17#include "core/file_sys/registered_cache.h" 18#include "core/file_sys/registered_cache.h"
@@ -281,14 +282,14 @@ NcaID PlaceholderCache::Generate() {
281 return out; 282 return out;
282} 283}
283 284
284VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, 285VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& open_dir,
285 std::string_view path) const { 286 std::string_view path) const {
286 const auto file = dir->GetFileRelative(path); 287 const auto file = open_dir->GetFileRelative(path);
287 if (file != nullptr) { 288 if (file != nullptr) {
288 return file; 289 return file;
289 } 290 }
290 291
291 const auto nca_dir = dir->GetDirectoryRelative(path); 292 const auto nca_dir = open_dir->GetDirectoryRelative(path);
292 if (nca_dir == nullptr) { 293 if (nca_dir == nullptr) {
293 return nullptr; 294 return nullptr;
294 } 295 }
@@ -431,13 +432,15 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
431} 432}
432 433
433void RegisteredCache::AccumulateYuzuMeta() { 434void RegisteredCache::AccumulateYuzuMeta() {
434 const auto dir = this->dir->GetSubdirectory("yuzu_meta"); 435 const auto meta_dir = dir->GetSubdirectory("yuzu_meta");
435 if (dir == nullptr) 436 if (meta_dir == nullptr) {
436 return; 437 return;
438 }
437 439
438 for (const auto& file : dir->GetFiles()) { 440 for (const auto& file : meta_dir->GetFiles()) {
439 if (file->GetExtension() != "cnmt") 441 if (file->GetExtension() != "cnmt") {
440 continue; 442 continue;
443 }
441 444
442 CNMT cnmt(file); 445 CNMT cnmt(file);
443 yuzu_meta.insert_or_assign(cnmt.GetTitleID(), std::move(cnmt)); 446 yuzu_meta.insert_or_assign(cnmt.GetTitleID(), std::move(cnmt));
@@ -445,8 +448,10 @@ void RegisteredCache::AccumulateYuzuMeta() {
445} 448}
446 449
447void RegisteredCache::Refresh() { 450void RegisteredCache::Refresh() {
448 if (dir == nullptr) 451 if (dir == nullptr) {
449 return; 452 return;
453 }
454
450 const auto ids = AccumulateFiles(); 455 const auto ids = AccumulateFiles();
451 ProcessFiles(ids); 456 ProcessFiles(ids);
452 AccumulateYuzuMeta(); 457 AccumulateYuzuMeta();
@@ -566,7 +571,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
566 } 571 }
567 572
568 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); 573 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
569 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); 574 const auto meta_id_data = Common::HexStringToArray<16>(meta_id_raw);
570 575
571 if ((*meta_iter)->GetSubdirectories().empty()) { 576 if ((*meta_iter)->GetSubdirectories().empty()) {
572 LOG_ERROR(Loader, 577 LOG_ERROR(Loader,
@@ -588,10 +593,16 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
588 const CNMT cnmt(cnmt_file); 593 const CNMT cnmt(cnmt_file);
589 594
590 const auto title_id = cnmt.GetTitleID(); 595 const auto title_id = cnmt.GetTitleID();
596 const auto version = cnmt.GetTitleVersion();
597
598 if (title_id == GetBaseTitleID(title_id) && version == 0) {
599 return InstallResult::ErrorBaseInstall;
600 }
601
591 const auto result = RemoveExistingEntry(title_id); 602 const auto result = RemoveExistingEntry(title_id);
592 603
593 // Install Metadata File 604 // Install Metadata File
594 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); 605 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data);
595 if (res != InstallResult::Success) { 606 if (res != InstallResult::Success) {
596 return res; 607 return res;
597 } 608 }
@@ -741,15 +752,15 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
741 752
742bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { 753bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
743 // Reasoning behind this method can be found in the comment for InstallEntry, NCA overload. 754 // Reasoning behind this method can be found in the comment for InstallEntry, NCA overload.
744 const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta"); 755 const auto meta_dir = dir->CreateDirectoryRelative("yuzu_meta");
745 const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID()); 756 const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID());
746 if (dir->GetFile(filename) == nullptr) { 757 if (meta_dir->GetFile(filename) == nullptr) {
747 auto out = dir->CreateFile(filename); 758 auto out = meta_dir->CreateFile(filename);
748 const auto buffer = cnmt.Serialize(); 759 const auto buffer = cnmt.Serialize();
749 out->Resize(buffer.size()); 760 out->Resize(buffer.size());
750 out->WriteBytes(buffer); 761 out->WriteBytes(buffer);
751 } else { 762 } else {
752 auto out = dir->GetFile(filename); 763 auto out = meta_dir->GetFile(filename);
753 CNMT old_cnmt(out); 764 CNMT old_cnmt(out);
754 // Returns true on change 765 // Returns true on change
755 if (old_cnmt.UnionRecords(cnmt)) { 766 if (old_cnmt.UnionRecords(cnmt)) {
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index b08a1687a..d042aef90 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -38,6 +38,7 @@ enum class InstallResult {
38 ErrorAlreadyExists, 38 ErrorAlreadyExists,
39 ErrorCopyFailed, 39 ErrorCopyFailed,
40 ErrorMetaFailed, 40 ErrorMetaFailed,
41 ErrorBaseInstall,
41}; 42};
42 43
43struct ContentProviderEntry { 44struct ContentProviderEntry {
@@ -182,7 +183,7 @@ private:
182 void AccumulateYuzuMeta(); 183 void AccumulateYuzuMeta();
183 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; 184 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
184 VirtualFile GetFileAtID(NcaID id) const; 185 VirtualFile GetFileAtID(NcaID id) const;
185 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; 186 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& open_dir, std::string_view path) const;
186 InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, 187 InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
187 bool overwrite_if_exists, std::optional<NcaID> override_id = {}); 188 bool overwrite_if_exists, std::optional<NcaID> override_id = {});
188 bool RawInstallYuzuMeta(const CNMT& cnmt); 189 bool RawInstallYuzuMeta(const CNMT& cnmt);
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index f4e16e4be..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
@@ -33,8 +33,8 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provi
33 33
34RomFSFactory::~RomFSFactory() = default; 34RomFSFactory::~RomFSFactory() = default;
35 35
36void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) { 36void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
37 this->update_raw = std::move(update_raw); 37 update_raw = std::move(update_raw_file);
38} 38}
39 39
40ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { 40ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index 96dd0d578..39db09e4e 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -40,7 +40,7 @@ public:
40 Service::FileSystem::FileSystemController& controller); 40 Service::FileSystem::FileSystemController& controller);
41 ~RomFSFactory(); 41 ~RomFSFactory();
42 42
43 void SetPackedUpdate(VirtualFile update_raw); 43 void SetPackedUpdate(VirtualFile update_raw_file);
44 [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; 44 [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
45 [[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id, 45 [[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
46 ContentRecordType type) const; 46 ContentRecordType type) const;
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index b7bfe0928..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
@@ -170,26 +170,30 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
170SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, 170SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
171 u128 user_id) const { 171 u128 user_id) const {
172 const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 172 const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
173 const auto dir = GetOrCreateDirectoryRelative(this->dir, path); 173 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
174 174
175 const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME); 175 const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME);
176 if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) 176 if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) {
177 return {0, 0}; 177 return {0, 0};
178 }
178 179
179 SaveDataSize out; 180 SaveDataSize out;
180 if (size_file->ReadObject(&out) != sizeof(SaveDataSize)) 181 if (size_file->ReadObject(&out) != sizeof(SaveDataSize)) {
181 return {0, 0}; 182 return {0, 0};
183 }
184
182 return out; 185 return out;
183} 186}
184 187
185void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 188void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
186 SaveDataSize new_value) const { 189 SaveDataSize new_value) const {
187 const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 190 const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
188 const auto dir = GetOrCreateDirectoryRelative(this->dir, path); 191 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
189 192
190 const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME); 193 const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
191 if (size_file == nullptr) 194 if (size_file == nullptr) {
192 return; 195 return;
196 }
193 197
194 size_file->Resize(sizeof(SaveDataSize)); 198 size_file->Resize(sizeof(SaveDataSize));
195 size_file->WriteObject(new_value); 199 size_file->WriteObject(new_value);
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index c05735ddd..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();
@@ -232,15 +232,15 @@ void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
232void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) { 232void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
233 exefs = pfs; 233 exefs = pfs;
234 234
235 const auto romfs_iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& file) { 235 const auto iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& entry) {
236 return file->GetName().rfind(".romfs") != std::string::npos; 236 return entry->GetName().rfind(".romfs") != std::string::npos;
237 }); 237 });
238 238
239 if (romfs_iter == files.end()) { 239 if (iter == files.end()) {
240 return; 240 return;
241 } 241 }
242 242
243 romfs = *romfs_iter; 243 romfs = *iter;
244} 244}
245 245
246void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { 246void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
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 3c5a7d87a..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
@@ -136,7 +136,7 @@ std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::
136 return 0; 136 return 0;
137} 137}
138 138
139bool ConcatenatedVfsFile::Rename(std::string_view name) { 139bool ConcatenatedVfsFile::Rename(std::string_view new_name) {
140 return false; 140 return false;
141} 141}
142 142
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 287c72555..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;
@@ -36,7 +36,7 @@ public:
36 bool IsReadable() const override; 36 bool IsReadable() const override;
37 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 37 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
38 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; 38 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
39 bool Rename(std::string_view name) override; 39 bool Rename(std::string_view new_name) override;
40 40
41private: 41private:
42 // Maps starting offset to file -- more efficient. 42 // Maps starting offset to file -- more efficient.
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 434b03cec..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
@@ -45,12 +45,12 @@ VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) cons
45 return MakeLayeredDirectory(std::move(out)); 45 return MakeLayeredDirectory(std::move(out));
46} 46}
47 47
48VirtualFile LayeredVfsDirectory::GetFile(std::string_view name) const { 48VirtualFile LayeredVfsDirectory::GetFile(std::string_view file_name) const {
49 return GetFileRelative(name); 49 return GetFileRelative(file_name);
50} 50}
51 51
52VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view name) const { 52VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view subdir_name) const {
53 return GetDirectoryRelative(name); 53 return GetDirectoryRelative(subdir_name);
54} 54}
55 55
56std::string LayeredVfsDirectory::GetFullPath() const { 56std::string LayeredVfsDirectory::GetFullPath() const {
@@ -105,24 +105,24 @@ VirtualDir LayeredVfsDirectory::GetParentDirectory() const {
105 return dirs[0]->GetParentDirectory(); 105 return dirs[0]->GetParentDirectory();
106} 106}
107 107
108VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view name) { 108VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
109 return nullptr; 109 return nullptr;
110} 110}
111 111
112VirtualFile LayeredVfsDirectory::CreateFile(std::string_view name) { 112VirtualFile LayeredVfsDirectory::CreateFile(std::string_view file_name) {
113 return nullptr; 113 return nullptr;
114} 114}
115 115
116bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view name) { 116bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
117 return false; 117 return false;
118} 118}
119 119
120bool LayeredVfsDirectory::DeleteFile(std::string_view name) { 120bool LayeredVfsDirectory::DeleteFile(std::string_view file_name) {
121 return false; 121 return false;
122} 122}
123 123
124bool LayeredVfsDirectory::Rename(std::string_view name_) { 124bool LayeredVfsDirectory::Rename(std::string_view new_name) {
125 name = name_; 125 name = new_name;
126 return true; 126 return true;
127} 127}
128 128
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h
index 6d7513ac6..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;
@@ -23,8 +23,8 @@ public:
23 23
24 VirtualFile GetFileRelative(std::string_view path) const override; 24 VirtualFile GetFileRelative(std::string_view path) const override;
25 VirtualDir GetDirectoryRelative(std::string_view path) const override; 25 VirtualDir GetDirectoryRelative(std::string_view path) const override;
26 VirtualFile GetFile(std::string_view name) const override; 26 VirtualFile GetFile(std::string_view file_name) const override;
27 VirtualDir GetSubdirectory(std::string_view name) const override; 27 VirtualDir GetSubdirectory(std::string_view subdir_name) const override;
28 std::string GetFullPath() const override; 28 std::string GetFullPath() const override;
29 29
30 std::vector<VirtualFile> GetFiles() const override; 30 std::vector<VirtualFile> GetFiles() const override;
@@ -33,11 +33,11 @@ public:
33 bool IsReadable() const override; 33 bool IsReadable() const override;
34 std::string GetName() const override; 34 std::string GetName() const override;
35 VirtualDir GetParentDirectory() const override; 35 VirtualDir GetParentDirectory() const override;
36 VirtualDir CreateSubdirectory(std::string_view name) override; 36 VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
37 VirtualFile CreateFile(std::string_view name) override; 37 VirtualFile CreateFile(std::string_view file_name) override;
38 bool DeleteSubdirectory(std::string_view name) override; 38 bool DeleteSubdirectory(std::string_view subdir_name) override;
39 bool DeleteFile(std::string_view name) override; 39 bool DeleteFile(std::string_view file_name) override;
40 bool Rename(std::string_view name) override; 40 bool Rename(std::string_view new_name) override;
41 41
42private: 42private:
43 std::vector<VirtualDir> dirs; 43 std::vector<VirtualDir> dirs;
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_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index 056737b54..870ed1cf8 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -84,8 +84,8 @@ std::size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, std::size_t r
84 return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset); 84 return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
85} 85}
86 86
87bool OffsetVfsFile::Rename(std::string_view name) { 87bool OffsetVfsFile::Rename(std::string_view new_name) {
88 return file->Rename(name); 88 return file->Rename(new_name);
89} 89}
90 90
91std::size_t OffsetVfsFile::GetOffset() const { 91std::size_t OffsetVfsFile::GetOffset() const {
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index b2ccc5c7b..42f78b3d9 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -35,7 +35,7 @@ public:
35 bool WriteByte(u8 data, std::size_t offset) override; 35 bool WriteByte(u8 data, std::size_t offset) override;
36 std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override; 36 std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override;
37 37
38 bool Rename(std::string_view name) override; 38 bool Rename(std::string_view new_name) override;
39 39
40 std::size_t GetOffset() const; 40 std::size_t GetOffset() const;
41 41
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index a44ce6288..3d89dd644 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -358,16 +358,16 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string&
358 358
359RealVfsDirectory::~RealVfsDirectory() = default; 359RealVfsDirectory::~RealVfsDirectory() = default;
360 360
361VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const { 361VirtualFile RealVfsDirectory::GetFileRelative(std::string_view relative_path) const {
362 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 362 const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
363 if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) { 363 if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
364 return nullptr; 364 return nullptr;
365 } 365 }
366 return base.OpenFile(full_path, perms); 366 return base.OpenFile(full_path, perms);
367} 367}
368 368
369VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { 369VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view relative_path) const {
370 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 370 const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
371 if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) { 371 if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
372 return nullptr; 372 return nullptr;
373 } 373 }
@@ -382,13 +382,13 @@ VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const {
382 return GetDirectoryRelative(name); 382 return GetDirectoryRelative(name);
383} 383}
384 384
385VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view path) { 385VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view relative_path) {
386 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 386 const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
387 return base.CreateFile(full_path, perms); 387 return base.CreateFile(full_path, perms);
388} 388}
389 389
390VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { 390VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view relative_path) {
391 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 391 const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
392 return base.CreateDirectory(full_path, perms); 392 return base.CreateDirectory(full_path, perms);
393} 393}
394 394
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 23e99865e..0666f2679 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -79,12 +79,12 @@ class RealVfsDirectory : public VfsDirectory {
79public: 79public:
80 ~RealVfsDirectory() override; 80 ~RealVfsDirectory() override;
81 81
82 VirtualFile GetFileRelative(std::string_view path) const override; 82 VirtualFile GetFileRelative(std::string_view relative_path) const override;
83 VirtualDir GetDirectoryRelative(std::string_view path) const override; 83 VirtualDir GetDirectoryRelative(std::string_view relative_path) const override;
84 VirtualFile GetFile(std::string_view name) const override; 84 VirtualFile GetFile(std::string_view name) const override;
85 VirtualDir GetSubdirectory(std::string_view name) const override; 85 VirtualDir GetSubdirectory(std::string_view name) const override;
86 VirtualFile CreateFileRelative(std::string_view path) override; 86 VirtualFile CreateFileRelative(std::string_view relative_path) override;
87 VirtualDir CreateDirectoryRelative(std::string_view path) override; 87 VirtualDir CreateDirectoryRelative(std::string_view relative_path) override;
88 bool DeleteSubdirectoryRecursive(std::string_view name) override; 88 bool DeleteSubdirectoryRecursive(std::string_view name) override;
89 std::vector<VirtualFile> GetFiles() const override; 89 std::vector<VirtualFile> GetFiles() const override;
90 std::vector<VirtualDir> GetSubdirectories() const override; 90 std::vector<VirtualDir> GetSubdirectories() const override;
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 c1ec1e645..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
@@ -103,12 +103,12 @@ static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view nam
103 return true; 103 return true;
104} 104}
105 105
106bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) { 106bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
107 return FindAndRemoveVectorElement(dirs, name); 107 return FindAndRemoveVectorElement(dirs, subdir_name);
108} 108}
109 109
110bool VectorVfsDirectory::DeleteFile(std::string_view name) { 110bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
111 return FindAndRemoveVectorElement(files, name); 111 return FindAndRemoveVectorElement(files, file_name);
112} 112}
113 113
114bool VectorVfsDirectory::Rename(std::string_view name_) { 114bool VectorVfsDirectory::Rename(std::string_view name_) {
@@ -116,11 +116,11 @@ bool VectorVfsDirectory::Rename(std::string_view name_) {
116 return true; 116 return true;
117} 117}
118 118
119VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view name) { 119VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
120 return nullptr; 120 return nullptr;
121} 121}
122 122
123VirtualFile VectorVfsDirectory::CreateFile(std::string_view name) { 123VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
124 return nullptr; 124 return nullptr;
125} 125}
126 126
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 2aff9ca34..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;
@@ -112,11 +112,11 @@ public:
112 bool IsReadable() const override; 112 bool IsReadable() const override;
113 std::string GetName() const override; 113 std::string GetName() const override;
114 VirtualDir GetParentDirectory() const override; 114 VirtualDir GetParentDirectory() const override;
115 bool DeleteSubdirectory(std::string_view name) override; 115 bool DeleteSubdirectory(std::string_view subdir_name) override;
116 bool DeleteFile(std::string_view name) override; 116 bool DeleteFile(std::string_view file_name) override;
117 bool Rename(std::string_view name) override; 117 bool Rename(std::string_view name) override;
118 VirtualDir CreateSubdirectory(std::string_view name) override; 118 VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
119 VirtualFile CreateFile(std::string_view name) override; 119 VirtualFile CreateFile(std::string_view file_name) override;
120 120
121 virtual void AddFile(VirtualFile file); 121 virtual void AddFile(VirtualFile file);
122 virtual void AddDirectory(VirtualDir dir); 122 virtual void AddDirectory(VirtualDir dir);
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
index 50db6a654..be4736f47 100644
--- a/src/core/frontend/applets/web_browser.cpp
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -12,7 +12,7 @@ WebBrowserApplet::~WebBrowserApplet() = default;
12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; 12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
13 13
14void DefaultWebBrowserApplet::OpenLocalWebPage( 14void DefaultWebBrowserApplet::OpenLocalWebPage(
15 std::string_view local_url, std::function<void()> extract_romfs_callback, 15 const std::string& local_url, std::function<void()> extract_romfs_callback,
16 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const { 16 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
17 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}", 17 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
18 local_url); 18 local_url);
@@ -21,7 +21,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(
21} 21}
22 22
23void DefaultWebBrowserApplet::OpenExternalWebPage( 23void DefaultWebBrowserApplet::OpenExternalWebPage(
24 std::string_view external_url, 24 const std::string& external_url,
25 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const { 25 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}", 26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
27 external_url); 27 external_url);
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
index 1c5ef19a9..d7bd44c27 100644
--- a/src/core/frontend/applets/web_browser.h
+++ b/src/core/frontend/applets/web_browser.h
@@ -16,11 +16,11 @@ public:
16 virtual ~WebBrowserApplet(); 16 virtual ~WebBrowserApplet();
17 17
18 virtual void OpenLocalWebPage( 18 virtual void OpenLocalWebPage(
19 std::string_view local_url, std::function<void()> extract_romfs_callback, 19 const std::string& local_url, std::function<void()> extract_romfs_callback,
20 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0; 20 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
21 21
22 virtual void OpenExternalWebPage( 22 virtual void OpenExternalWebPage(
23 std::string_view external_url, 23 const std::string& external_url,
24 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0; 24 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
25}; 25};
26 26
@@ -28,11 +28,12 @@ class DefaultWebBrowserApplet final : public WebBrowserApplet {
28public: 28public:
29 ~DefaultWebBrowserApplet() override; 29 ~DefaultWebBrowserApplet() override;
30 30
31 void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback, 31 void OpenLocalWebPage(const std::string& local_url,
32 std::function<void()> extract_romfs_callback,
32 std::function<void(Service::AM::Applets::WebExitReason, std::string)> 33 std::function<void(Service::AM::Applets::WebExitReason, std::string)>
33 callback) const override; 34 callback) const override;
34 35
35 void OpenExternalWebPage(std::string_view external_url, 36 void OpenExternalWebPage(const std::string& external_url,
36 std::function<void(Service::AM::Applets::WebExitReason, std::string)> 37 std::function<void(Service::AM::Applets::WebExitReason, std::string)>
37 callback) const override; 38 callback) const override;
38}; 39};
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/frontend/input.h b/src/core/frontend/input.h
index 88ebc6497..0c5d2b3b0 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -11,6 +11,7 @@
11#include <utility> 11#include <utility>
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/param_package.h" 13#include "common/param_package.h"
14#include "common/quaternion.h"
14#include "common/vector_math.h" 15#include "common/vector_math.h"
15 16
16namespace Input { 17namespace Input {
@@ -143,9 +144,10 @@ using VibrationDevice = InputDevice<u8>;
143 144
144/** 145/**
145 * A motion status is an object that returns a tuple of accelerometer state vector, 146 * A motion status is an object that returns a tuple of accelerometer state vector,
146 * gyroscope state vector, rotation state vector and orientation state matrix. 147 * gyroscope state vector, rotation state vector, orientation state matrix and quaterion state
148 * vector.
147 * 149 *
148 * For both vectors: 150 * For both 3D vectors:
149 * x+ is the same direction as RIGHT on D-pad. 151 * x+ is the same direction as RIGHT on D-pad.
150 * y+ is normal to the touch screen, pointing outward. 152 * y+ is normal to the touch screen, pointing outward.
151 * z+ is the same direction as UP on D-pad. 153 * z+ is the same direction as UP on D-pad.
@@ -164,9 +166,13 @@ using VibrationDevice = InputDevice<u8>;
164 * x vector 166 * x vector
165 * y vector 167 * y vector
166 * z vector 168 * z vector
169 *
170 * For quaternion state vector
171 * xyz vector
172 * w float
167 */ 173 */
168using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>, 174using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
169 std::array<Common::Vec3f, 3>>; 175 std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>;
170 176
171/** 177/**
172 * A motion device is an input device that returns a motion status object 178 * A motion device is an input device that returns a motion status object
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..24700f7a5 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 }
@@ -70,19 +64,19 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
70 if (command_header->enable_handle_descriptor) { 64 if (command_header->enable_handle_descriptor) {
71 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); 65 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
72 if (handle_descriptor_header->send_current_pid) { 66 if (handle_descriptor_header->send_current_pid) {
73 rp.Skip(2, false); 67 pid = rp.Pop<u64>();
74 } 68 }
75 if (incoming) { 69 if (incoming) {
76 // Populate the object lists with the data in the IPC request. 70 // Populate the object lists with the data in the IPC request.
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
@@ -92,52 +86,56 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
92 } 86 }
93 } 87 }
94 88
95 for (unsigned i = 0; i < command_header->num_buf_x_descriptors; ++i) { 89 for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
96 buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); 90 buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
97 } 91 }
98 for (unsigned i = 0; i < command_header->num_buf_a_descriptors; ++i) { 92 for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
99 buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 93 buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
100 } 94 }
101 for (unsigned i = 0; i < command_header->num_buf_b_descriptors; ++i) { 95 for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
102 buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 96 buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
103 } 97 }
104 for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) { 98 for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
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);
@@ -150,14 +148,14 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
150 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { 148 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
151 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); 149 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
152 } else { 150 } else {
153 unsigned num_buf_c_descriptors = 151 u32 num_buf_c_descriptors =
154 static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2; 152 static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
155 153
156 // This is used to detect possible underflows, in case something is broken 154 // This is used to detect possible underflows, in case something is broken
157 // with the two ifs above and the flags value is == 0 || == 1. 155 // with the two ifs above and the flags value is == 0 || == 1.
158 ASSERT(num_buf_c_descriptors < 14); 156 ASSERT(num_buf_c_descriptors < 14);
159 157
160 for (unsigned i = 0; i < num_buf_c_descriptors; ++i) { 158 for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
161 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); 159 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
162 } 160 }
163 } 161 }
@@ -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..e1b128281 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,43 @@ 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 u64 GetPID() const {
154 return pid;
155 }
156
157 u32 GetDataPayloadOffset() const {
145 return data_payload_offset; 158 return data_payload_offset;
146 } 159 }
147 160
@@ -218,22 +231,12 @@ public:
218 return move_handles.at(index); 231 return move_handles.at(index);
219 } 232 }
220 233
221 template <typename T> 234 void AddMoveObject(KAutoObject* object) {
222 std::shared_ptr<T> GetCopyObject(std::size_t index) { 235 move_objects.emplace_back(object);
223 return DynamicObjectCast<T>(copy_objects.at(index));
224 }
225
226 template <typename T>
227 std::shared_ptr<T> GetMoveObject(std::size_t index) {
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 } 236 }
234 237
235 void AddCopyObject(std::shared_ptr<Object> object) { 238 void AddCopyObject(KAutoObject* object) {
236 copy_objects.emplace_back(std::move(object)); 239 copy_objects.emplace_back(object);
237 } 240 }
238 241
239 void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { 242 void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
@@ -276,10 +279,6 @@ public:
276 return *thread; 279 return *thread;
277 } 280 }
278 281
279 const KThread& GetThread() const {
280 return *thread;
281 }
282
283 bool IsThreadWaiting() const { 282 bool IsThreadWaiting() const {
284 return is_thread_waiting; 283 return is_thread_waiting;
285 } 284 }
@@ -287,16 +286,17 @@ public:
287private: 286private:
288 friend class IPC::ResponseBuilder; 287 friend class IPC::ResponseBuilder;
289 288
290 void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); 289 void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
291 290
292 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 291 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
293 std::shared_ptr<Kernel::ServerSession> server_session; 292 Kernel::KServerSession* server_session{};
294 std::shared_ptr<KThread> thread; 293 KThread* thread;
294
295 // TODO(yuriks): Check common usage of this and optimize size accordingly 295 // TODO(yuriks): Check common usage of this and optimize size accordingly
296 boost::container::small_vector<Handle, 8> move_handles; 296 boost::container::small_vector<Handle, 8> move_handles;
297 boost::container::small_vector<Handle, 8> copy_handles; 297 boost::container::small_vector<Handle, 8> copy_handles;
298 boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; 298 boost::container::small_vector<KAutoObject*, 8> move_objects;
299 boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; 299 boost::container::small_vector<KAutoObject*, 8> copy_objects;
300 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; 300 boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
301 301
302 std::optional<IPC::CommandHeader> command_header; 302 std::optional<IPC::CommandHeader> command_header;
@@ -309,9 +309,12 @@ private:
309 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; 309 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
310 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; 310 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
311 311
312 unsigned data_payload_offset{};
313 unsigned buffer_c_offset{};
314 u32_le command{}; 312 u32_le command{};
313 u64 pid{};
314 u32 data_payload_offset{};
315 u32 handles_offset{};
316 u32 domain_offset{};
317 u32 data_size{};
315 318
316 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; 319 std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
317 bool is_thread_waiting{}; 320 bool is_thread_waiting{};
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..c2d0f1eaf
--- /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 : 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 cad063e4d..000000000
--- a/src/core/hle/kernel/transfer_memory.cpp
+++ /dev/null
@@ -1,51 +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
39const u8* TransferMemory::GetPointer() const {
40 return memory.GetPointer(base_address);
41}
42
43ResultCode TransferMemory::Reserve() {
44 return owner_process->PageTable().ReserveTransferMemory(base_address, size, owner_permissions);
45}
46
47ResultCode TransferMemory::Reset() {
48 return owner_process->PageTable().ResetTransferMemory(base_address, size);
49}
50
51} // 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 521951424..000000000
--- a/src/core/hle/kernel/transfer_memory.h
+++ /dev/null
@@ -1,93 +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 const u8* GetPointer() const;
61
62 /// Gets the size of the memory backing this instance in bytes.
63 constexpr std::size_t GetSize() const {
64 return size;
65 }
66
67 /// Reserves the region to be used for the transfer memory, called after the transfer memory is
68 /// created.
69 ResultCode Reserve();
70
71 /// Resets the region previously used for the transfer memory, called after the transfer memory
72 /// is closed.
73 ResultCode Reset();
74
75 void Finalize() override {}
76
77private:
78 /// The base address for the memory managed by this instance.
79 VAddr base_address{};
80
81 /// Size of the memory, in bytes, that this instance manages.
82 std::size_t size{};
83
84 /// The memory permissions that are applied to this instance.
85 KMemoryPermission owner_permissions{};
86
87 /// The process that this transfer memory instance was created under.
88 Process* owner_process{};
89
90 Core::Memory::Memory& memory;
91};
92
93} // 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/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp
index 51f119b12..e498fb64d 100644
--- a/src/core/hle/service/acc/acc_aa.cpp
+++ b/src/core/hle/service/acc/acc_aa.cpp
@@ -6,9 +6,10 @@
6 6
7namespace Service::Account { 7namespace Service::Account {
8 8
9ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 9ACC_AA::ACC_AA(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
10 Core::System& system) 10 Core::System& system_)
11 : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:aa") { 11 : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:aa") {
12 // clang-format off
12 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
13 {0, nullptr, "EnsureCacheAsync"}, 14 {0, nullptr, "EnsureCacheAsync"},
14 {1, nullptr, "LoadCache"}, 15 {1, nullptr, "LoadCache"},
@@ -16,6 +17,7 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
16 {50, nullptr, "RegisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0 17 {50, nullptr, "RegisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
17 {51, nullptr, "UnregisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0 18 {51, nullptr, "UnregisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
18 }; 19 };
20 // clang-format on
19 RegisterHandlers(functions); 21 RegisterHandlers(functions);
20} 22}
21 23
diff --git a/src/core/hle/service/acc/acc_aa.h b/src/core/hle/service/acc/acc_aa.h
index 932c04890..d1be20ff3 100644
--- a/src/core/hle/service/acc/acc_aa.h
+++ b/src/core/hle/service/acc/acc_aa.h
@@ -10,8 +10,8 @@ namespace Service::Account {
10 10
11class ACC_AA final : public Module::Interface { 11class ACC_AA final : public Module::Interface {
12public: 12public:
13 explicit ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 13 explicit ACC_AA(std::shared_ptr<Module> module_,
14 Core::System& system); 14 std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
15 ~ACC_AA() override; 15 ~ACC_AA() override;
16}; 16};
17 17
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index bb6118abf..94a1b8814 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -6,9 +6,9 @@
6 6
7namespace Service::Account { 7namespace Service::Account {
8 8
9ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 9ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
10 Core::System& system) 10 Core::System& system_)
11 : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:su") { 11 : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:su") {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &ACC_SU::GetUserCount, "GetUserCount"}, 14 {0, &ACC_SU::GetUserCount, "GetUserCount"},
diff --git a/src/core/hle/service/acc/acc_su.h b/src/core/hle/service/acc/acc_su.h
index 0a700d9bf..132a126b4 100644
--- a/src/core/hle/service/acc/acc_su.h
+++ b/src/core/hle/service/acc/acc_su.h
@@ -10,8 +10,8 @@ namespace Service::Account {
10 10
11class ACC_SU final : public Module::Interface { 11class ACC_SU final : public Module::Interface {
12public: 12public:
13 explicit ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 13 explicit ACC_SU(std::shared_ptr<Module> module_,
14 Core::System& system); 14 std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
15 ~ACC_SU() override; 15 ~ACC_SU() override;
16}; 16};
17 17
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 8d66d180d..ed241647c 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -6,9 +6,9 @@
6 6
7namespace Service::Account { 7namespace Service::Account {
8 8
9ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 9ACC_U0::ACC_U0(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
10 Core::System& system) 10 Core::System& system_)
11 : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u0") { 11 : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:u0") {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &ACC_U0::GetUserCount, "GetUserCount"}, 14 {0, &ACC_U0::GetUserCount, "GetUserCount"},
diff --git a/src/core/hle/service/acc/acc_u0.h b/src/core/hle/service/acc/acc_u0.h
index 3bd9c3164..4c2600b67 100644
--- a/src/core/hle/service/acc/acc_u0.h
+++ b/src/core/hle/service/acc/acc_u0.h
@@ -10,8 +10,8 @@ namespace Service::Account {
10 10
11class ACC_U0 final : public Module::Interface { 11class ACC_U0 final : public Module::Interface {
12public: 12public:
13 explicit ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 13 explicit ACC_U0(std::shared_ptr<Module> module_,
14 Core::System& system); 14 std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
15 ~ACC_U0() override; 15 ~ACC_U0() override;
16}; 16};
17 17
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index 71982ad5a..6ce7fe8e6 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -6,9 +6,9 @@
6 6
7namespace Service::Account { 7namespace Service::Account {
8 8
9ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 9ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
10 Core::System& system) 10 Core::System& system_)
11 : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u1") { 11 : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:u1") {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &ACC_U1::GetUserCount, "GetUserCount"}, 14 {0, &ACC_U1::GetUserCount, "GetUserCount"},
diff --git a/src/core/hle/service/acc/acc_u1.h b/src/core/hle/service/acc/acc_u1.h
index 829f8a744..2d478324a 100644
--- a/src/core/hle/service/acc/acc_u1.h
+++ b/src/core/hle/service/acc/acc_u1.h
@@ -10,8 +10,8 @@ namespace Service::Account {
10 10
11class ACC_U1 final : public Module::Interface { 11class ACC_U1 final : public Module::Interface {
12public: 12public:
13 explicit ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager, 13 explicit ACC_U1(std::shared_ptr<Module> module_,
14 Core::System& system); 14 std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
15 ~ACC_U1() override; 15 ~ACC_U1() override;
16}; 16};
17 17
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 23e30aa45..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"
@@ -158,11 +158,11 @@ void Error::Execute() {
158 break; 158 break;
159 case ErrorAppletMode::ShowSystemError: 159 case ErrorAppletMode::ShowSystemError:
160 case ErrorAppletMode::ShowApplicationError: { 160 case ErrorAppletMode::ShowApplicationError: {
161 const auto system = mode == ErrorAppletMode::ShowSystemError; 161 const auto is_system = mode == ErrorAppletMode::ShowSystemError;
162 const auto& main_text = 162 const auto& main_text =
163 system ? args->system_error.main_text : args->application_error.main_text; 163 is_system ? args->system_error.main_text : args->application_error.main_text;
164 const auto& detail_text = 164 const auto& detail_text =
165 system ? args->system_error.detail_text : args->application_error.detail_text; 165 is_system ? args->system_error.detail_text : args->application_error.detail_text;
166 166
167 const auto main_text_string = 167 const auto main_text_string =
168 Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()); 168 Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size());
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index b26abad36..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"
@@ -96,7 +96,7 @@ void Auth::Execute() {
96 96
97 switch (type) { 97 switch (type) {
98 case AuthAppletType::ShowParentalAuthentication: { 98 case AuthAppletType::ShowParentalAuthentication: {
99 const auto callback = [this](bool successful) { AuthFinished(successful); }; 99 const auto callback = [this](bool is_successful) { AuthFinished(is_successful); };
100 100
101 if (arg0 == 1 && arg1 == 0 && arg2 == 1) { 101 if (arg0 == 1 && arg1 == 0 && arg2 == 1) {
102 // ShowAuthenticatorForConfiguration 102 // ShowAuthenticatorForConfiguration
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 73a06def1..b05a5da04 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -241,7 +241,7 @@ void SoftwareKeyboard::InitializeForeground() {
241 InitializeFrontendKeyboard(); 241 InitializeFrontendKeyboard();
242} 242}
243 243
244void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) { 244void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
245 LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet."); 245 LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
246 246
247 is_background = true; 247 is_background = true;
@@ -256,9 +256,9 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) {
256 swkbd_inline_initialize_arg.size()); 256 swkbd_inline_initialize_arg.size());
257 257
258 if (swkbd_initialize_arg.library_applet_mode_flag) { 258 if (swkbd_initialize_arg.library_applet_mode_flag) {
259 ASSERT(applet_mode == LibraryAppletMode::Background); 259 ASSERT(library_applet_mode == LibraryAppletMode::Background);
260 } else { 260 } else {
261 ASSERT(applet_mode == LibraryAppletMode::BackgroundIndirectDisplay); 261 ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
262 } 262 }
263} 263}
264 264
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index 7c67b7574..7bdef78a7 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -57,7 +57,7 @@ private:
57 void InitializeForeground(); 57 void InitializeForeground();
58 58
59 /// Initializes the inline software keyboard. 59 /// Initializes the inline software keyboard.
60 void InitializeBackground(LibraryAppletMode applet_mode); 60 void InitializeBackground(LibraryAppletMode library_applet_mode);
61 61
62 /// Processes the text check sent by the application. 62 /// Processes the text check sent by the application.
63 void ProcessTextCheck(); 63 void ProcessTextCheck();
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/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 21fd910c2..1e1812f36 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -69,13 +69,12 @@ private:
69 bool complete{false}; 69 bool complete{false};
70 ResultCode status{RESULT_SUCCESS}; 70 ResultCode status{RESULT_SUCCESS};
71 71
72 WebAppletVersion web_applet_version; 72 WebAppletVersion web_applet_version{};
73 WebExitReason web_exit_reason; 73 WebArgHeader web_arg_header{};
74 WebArgHeader web_arg_header;
75 WebArgInputTLVMap web_arg_input_tlv_map; 74 WebArgInputTLVMap web_arg_input_tlv_map;
76 75
77 u64 title_id; 76 u64 title_id{};
78 FileSys::ContentRecordType nca_type; 77 FileSys::ContentRecordType nca_type{};
79 std::string offline_cache_dir; 78 std::string offline_cache_dir;
80 std::string offline_document; 79 std::string offline_document;
81 FileSys::VirtualFile offline_romfs; 80 FileSys::VirtualFile offline_romfs;
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 572be8e00..ae4284adf 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -27,9 +27,10 @@ namespace Service::Audio {
27 27
28class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { 28class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
29public: 29public:
30 explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params, 30 explicit IAudioRenderer(Core::System& system_,
31 const AudioCommon::AudioRendererParameter& audren_params,
31 const std::size_t instance_number) 32 const std::size_t instance_number)
32 : ServiceFramework{system, "IAudioRenderer"} { 33 : ServiceFramework{system_, "IAudioRenderer"}, system_event{system.Kernel()} {
33 // clang-format off 34 // clang-format off
34 static const FunctionInfo functions[] = { 35 static const FunctionInfo functions[] = {
35 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, 36 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -48,13 +49,13 @@ public:
48 // clang-format on 49 // clang-format on
49 RegisterHandlers(functions); 50 RegisterHandlers(functions);
50 51
51 system_event = Kernel::KEvent::Create(system.Kernel(), "IAudioRenderer:SystemEvent"); 52 Kernel::KAutoObject::Create(std::addressof(system_event));
52 system_event->Initialize(); 53 system_event.Initialize("IAudioRenderer:SystemEvent");
53 renderer = std::make_unique<AudioCore::AudioRenderer>( 54 renderer = std::make_unique<AudioCore::AudioRenderer>(
54 system.CoreTiming(), system.Memory(), audren_params, 55 system.CoreTiming(), system.Memory(), audren_params,
55 [this]() { 56 [this]() {
56 const auto guard = LockService(); 57 const auto guard = LockService();
57 system_event->GetWritableEvent()->Signal(); 58 system_event.GetWritableEvent().Signal();
58 }, 59 },
59 instance_number); 60 instance_number);
60 } 61 }
@@ -127,7 +128,7 @@ private:
127 128
128 IPC::ResponseBuilder rb{ctx, 2, 1}; 129 IPC::ResponseBuilder rb{ctx, 2, 1};
129 rb.Push(RESULT_SUCCESS); 130 rb.Push(RESULT_SUCCESS);
130 rb.PushCopyObjects(system_event->GetReadableEvent()); 131 rb.PushCopyObjects(system_event.GetReadableEvent());
131 } 132 }
132 133
133 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { 134 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
@@ -161,15 +162,16 @@ private:
161 rb.Push(ERR_NOT_SUPPORTED); 162 rb.Push(ERR_NOT_SUPPORTED);
162 } 163 }
163 164
164 std::shared_ptr<Kernel::KEvent> system_event; 165 Kernel::KEvent system_event;
165 std::unique_ptr<AudioCore::AudioRenderer> renderer; 166 std::unique_ptr<AudioCore::AudioRenderer> renderer;
166 u32 rendering_time_limit_percent = 100; 167 u32 rendering_time_limit_percent = 100;
167}; 168};
168 169
169class IAudioDevice final : public ServiceFramework<IAudioDevice> { 170class IAudioDevice final : public ServiceFramework<IAudioDevice> {
170public: 171public:
171 explicit IAudioDevice(Core::System& system_, u32_le revision_num) 172 explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_)
172 : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num} { 173 : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{
174 revision_} {
173 static const FunctionInfo functions[] = { 175 static const FunctionInfo functions[] = {
174 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, 176 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
175 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, 177 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
@@ -186,21 +188,6 @@ public:
186 {13, nullptr, "GetAudioSystemMasterVolumeSetting"}, 188 {13, nullptr, "GetAudioSystemMasterVolumeSetting"},
187 }; 189 };
188 RegisterHandlers(functions); 190 RegisterHandlers(functions);
189
190 auto& kernel = system.Kernel();
191 buffer_event = Kernel::KEvent::Create(kernel, "IAudioOutBufferReleasedEvent");
192 buffer_event->Initialize();
193
194 // Should be similar to audio_output_device_switch_event
195 audio_input_device_switch_event =
196 Kernel::KEvent::Create(kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent");
197 audio_input_device_switch_event->Initialize();
198
199 // Should only be signalled when an audio output device has been changed, example: speaker
200 // to headset
201 audio_output_device_switch_event =
202 Kernel::KEvent::Create(kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
203 audio_output_device_switch_event->Initialize();
204 } 191 }
205 192
206private: 193private:
@@ -289,11 +276,11 @@ private:
289 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { 276 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
290 LOG_WARNING(Service_Audio, "(STUBBED) called"); 277 LOG_WARNING(Service_Audio, "(STUBBED) called");
291 278
292 buffer_event->GetWritableEvent()->Signal(); 279 buffer_event.GetWritableEvent().Signal();
293 280
294 IPC::ResponseBuilder rb{ctx, 2, 1}; 281 IPC::ResponseBuilder rb{ctx, 2, 1};
295 rb.Push(RESULT_SUCCESS); 282 rb.Push(RESULT_SUCCESS);
296 rb.PushCopyObjects(buffer_event->GetReadableEvent()); 283 rb.PushCopyObjects(buffer_event.GetReadableEvent());
297 } 284 }
298 285
299 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { 286 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
@@ -310,7 +297,7 @@ private:
310 297
311 IPC::ResponseBuilder rb{ctx, 2, 1}; 298 IPC::ResponseBuilder rb{ctx, 2, 1};
312 rb.Push(RESULT_SUCCESS); 299 rb.Push(RESULT_SUCCESS);
313 rb.PushCopyObjects(audio_input_device_switch_event->GetReadableEvent()); 300 rb.PushCopyObjects(buffer_event.GetReadableEvent());
314 } 301 }
315 302
316 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { 303 void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
@@ -318,17 +305,16 @@ private:
318 305
319 IPC::ResponseBuilder rb{ctx, 2, 1}; 306 IPC::ResponseBuilder rb{ctx, 2, 1};
320 rb.Push(RESULT_SUCCESS); 307 rb.Push(RESULT_SUCCESS);
321 rb.PushCopyObjects(audio_output_device_switch_event->GetReadableEvent()); 308 rb.PushCopyObjects(buffer_event.GetReadableEvent());
322 } 309 }
323 310
311 Kernel::KEvent& buffer_event;
324 u32_le revision = 0; 312 u32_le revision = 0;
325 std::shared_ptr<Kernel::KEvent> buffer_event; 313};
326 std::shared_ptr<Kernel::KEvent> audio_input_device_switch_event;
327 std::shared_ptr<Kernel::KEvent> audio_output_device_switch_event;
328 314
329}; // namespace Audio 315AudRenU::AudRenU(Core::System& system_)
316 : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} {
330 317
331AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} {
332 // clang-format off 318 // clang-format off
333 static const FunctionInfo functions[] = { 319 static const FunctionInfo functions[] = {
334 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 320 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
@@ -340,6 +326,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
340 // clang-format on 326 // clang-format on
341 327
342 RegisterHandlers(functions); 328 RegisterHandlers(functions);
329
330 Kernel::KAutoObject::Create(std::addressof(buffer_event));
331 buffer_event.Initialize("IAudioOutBufferReleasedEvent");
343} 332}
344 333
345AudRenU::~AudRenU() = default; 334AudRenU::~AudRenU() = default;
@@ -373,7 +362,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
373 static constexpr u64 max_perf_detail_entries = 100; 362 static constexpr u64 max_perf_detail_entries = 100;
374 363
375 // 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.
376 static constexpr u64 voice_state_size = 0x100; 365 static constexpr u64 voice_state_size_bytes = 0x100;
377 366
378 // Size of the upsampler manager data structure 367 // Size of the upsampler manager data structure
379 constexpr u64 upsampler_manager_size = 0x48; 368 constexpr u64 upsampler_manager_size = 0x48;
@@ -460,7 +449,8 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
460 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);
461 size += 450 size +=
462 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);
463 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);
464 return size; 454 return size;
465 }; 455 };
466 456
@@ -662,7 +652,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
662 // always assumes the initial release revision (REV1). 652 // always assumes the initial release revision (REV1).
663 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 653 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
664 rb.Push(RESULT_SUCCESS); 654 rb.Push(RESULT_SUCCESS);
665 rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1')); 655 rb.PushIpcInterface<IAudioDevice>(system, buffer_event, Common::MakeMagic('R', 'E', 'V', '1'));
666} 656}
667 657
668void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) { 658void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
@@ -684,7 +674,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c
684 674
685 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 675 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
686 rb.Push(RESULT_SUCCESS); 676 rb.Push(RESULT_SUCCESS);
687 rb.PushIpcInterface<IAudioDevice>(system, revision); 677 rb.PushIpcInterface<IAudioDevice>(system, buffer_event, revision);
688} 678}
689 679
690void 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 78c047bd2..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,
@@ -415,9 +424,9 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
415 if (Settings::values.bcat_boxcat_local) { 424 if (Settings::values.bcat_boxcat_local) {
416 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); 425 LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download.");
417 } else { 426 } else {
418 Boxcat::Client client{path, title.title_id, title.build_id}; 427 Client launch_client{path, title.title_id, title.build_id};
419 428
420 const auto res = client.DownloadLaunchParam(); 429 const auto res = launch_client.DownloadLaunchParam();
421 if (res != DownloadResult::Success) { 430 if (res != DownloadResult::Success) {
422 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); 431 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
423 432
diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp
index b31766212..5a95707de 100644
--- a/src/core/hle/service/bcat/bcat.cpp
+++ b/src/core/hle/service/bcat/bcat.cpp
@@ -6,9 +6,9 @@
6 6
7namespace Service::BCAT { 7namespace Service::BCAT {
8 8
9BCAT::BCAT(Core::System& system, std::shared_ptr<Module> module, 9BCAT::BCAT(Core::System& system_, std::shared_ptr<Module> module_,
10 FileSystem::FileSystemController& fsc, const char* name) 10 FileSystem::FileSystemController& fsc_, const char* name_)
11 : Interface(system, std::move(module), fsc, name) { 11 : Interface(system_, std::move(module_), fsc_, name_) {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &BCAT::CreateBcatService, "CreateBcatService"}, 14 {0, &BCAT::CreateBcatService, "CreateBcatService"},
diff --git a/src/core/hle/service/bcat/bcat.h b/src/core/hle/service/bcat/bcat.h
index 6354465fc..d72798980 100644
--- a/src/core/hle/service/bcat/bcat.h
+++ b/src/core/hle/service/bcat/bcat.h
@@ -14,8 +14,8 @@ namespace Service::BCAT {
14 14
15class BCAT final : public Module::Interface { 15class BCAT final : public Module::Interface {
16public: 16public:
17 explicit BCAT(Core::System& system, std::shared_ptr<Module> module, 17 explicit BCAT(Core::System& system_, std::shared_ptr<Module> module_,
18 FileSystem::FileSystemController& fsc, const char* name); 18 FileSystem::FileSystemController& fsc_, const char* name_);
19 ~BCAT() override; 19 ~BCAT() override;
20}; 20};
21 21
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index c7dd04a6e..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
@@ -174,9 +172,9 @@ private:
174 }; 172 };
175 173
176 std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { 174 std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) {
177 auto& backend{progress.at(static_cast<std::size_t>(type))}; 175 auto& progress_backend{GetProgressBackend(type)};
178 return std::make_shared<IDeliveryCacheProgressService>(system, backend.GetEvent(), 176 return std::make_shared<IDeliveryCacheProgressService>(system, progress_backend.GetEvent(),
179 backend.GetImpl()); 177 progress_backend.GetImpl());
180 } 178 }
181 179
182 void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) { 180 void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) {
@@ -184,7 +182,7 @@ private:
184 182
185 backend.Synchronize({system.CurrentProcess()->GetTitleID(), 183 backend.Synchronize({system.CurrentProcess()->GetTitleID(),
186 GetCurrentBuildID(system.GetCurrentProcessBuildID())}, 184 GetCurrentBuildID(system.GetCurrentProcessBuildID())},
187 progress.at(static_cast<std::size_t>(SyncType::Normal))); 185 GetProgressBackend(SyncType::Normal));
188 186
189 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 187 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
190 rb.Push(RESULT_SUCCESS); 188 rb.Push(RESULT_SUCCESS);
@@ -201,8 +199,7 @@ private:
201 199
202 backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(), 200 backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(),
203 GetCurrentBuildID(system.GetCurrentProcessBuildID())}, 201 GetCurrentBuildID(system.GetCurrentProcessBuildID())},
204 name, 202 name, GetProgressBackend(SyncType::Directory));
205 progress.at(static_cast<std::size_t>(SyncType::Directory)));
206 203
207 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
208 rb.Push(RESULT_SUCCESS); 205 rb.Push(RESULT_SUCCESS);
@@ -265,9 +262,16 @@ private:
265 rb.Push(RESULT_SUCCESS); 262 rb.Push(RESULT_SUCCESS);
266 } 263 }
267 264
268 Backend& backend; 265 ProgressServiceBackend& GetProgressBackend(SyncType type) {
266 return progress.at(static_cast<size_t>(type));
267 }
269 268
270 std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress; 269 const ProgressServiceBackend& GetProgressBackend(SyncType type) const {
270 return progress.at(static_cast<size_t>(type));
271 }
272
273 Backend& backend;
274 std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
271}; 275};
272 276
273void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 277void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
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 72ad273b2..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"
@@ -55,10 +55,15 @@ std::string VfsDirectoryServiceWrapper::GetName() const {
55ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const { 55ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
56 std::string path(Common::FS::SanitizePath(path_)); 56 std::string path(Common::FS::SanitizePath(path_));
57 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 57 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
58 // dir can be nullptr if path contains subdirectories, create those prior to creating the file.
59 if (dir == nullptr) { 58 if (dir == nullptr) {
60 dir = backing->CreateSubdirectory(Common::FS::GetParentPath(path)); 59 return FileSys::ERROR_PATH_NOT_FOUND;
60 }
61
62 const auto entry_type = GetEntryType(path);
63 if (entry_type.Code() == RESULT_SUCCESS) {
64 return FileSys::ERROR_PATH_ALREADY_EXISTS;
61 } 65 }
66
62 auto file = dir->CreateFile(Common::FS::GetFilename(path)); 67 auto file = dir->CreateFile(Common::FS::GetFilename(path));
63 if (file == nullptr) { 68 if (file == nullptr) {
64 // TODO(DarkLordZach): Find a better error code for this 69 // TODO(DarkLordZach): Find a better error code for this
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index a0215c4d7..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"
@@ -337,13 +337,14 @@ public:
337 const auto file_buffer = ctx.ReadBuffer(); 337 const auto file_buffer = ctx.ReadBuffer();
338 const std::string name = Common::StringFromBuffer(file_buffer); 338 const std::string name = Common::StringFromBuffer(file_buffer);
339 339
340 const u64 mode = rp.Pop<u64>(); 340 const u64 file_mode = rp.Pop<u64>();
341 const u32 size = rp.Pop<u32>(); 341 const u32 file_size = rp.Pop<u32>();
342 342
343 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, mode, size); 343 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
344 file_size);
344 345
345 IPC::ResponseBuilder rb{ctx, 2}; 346 IPC::ResponseBuilder rb{ctx, 2};
346 rb.Push(backend.CreateFile(name, size)); 347 rb.Push(backend.CreateFile(name, file_size));
347 } 348 }
348 349
349 void DeleteFile(Kernel::HLERequestContext& ctx) { 350 void DeleteFile(Kernel::HLERequestContext& ctx) {
@@ -935,8 +936,8 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
935void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { 936void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
936 LOG_DEBUG(Service_FS, "called"); 937 LOG_DEBUG(Service_FS, "called");
937 938
938 auto romfs = fsc.OpenRomFSCurrentProcess(); 939 auto current_romfs = fsc.OpenRomFSCurrentProcess();
939 if (romfs.Failed()) { 940 if (current_romfs.Failed()) {
940 // TODO (bunnei): Find the right error code to use here 941 // TODO (bunnei): Find the right error code to use here
941 LOG_CRITICAL(Service_FS, "no file system interface available!"); 942 LOG_CRITICAL(Service_FS, "no file system interface available!");
942 IPC::ResponseBuilder rb{ctx, 2}; 943 IPC::ResponseBuilder rb{ctx, 2};
@@ -944,7 +945,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
944 return; 945 return;
945 } 946 }
946 947
947 auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap())); 948 auto storage = std::make_shared<IStorage>(system, std::move(current_romfs.Unwrap()));
948 949
949 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 950 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
950 rb.Push(RESULT_SUCCESS); 951 rb.Push(RESULT_SUCCESS);
@@ -1010,10 +1011,10 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
1010 1011
1011 LOG_DEBUG(Service_FS, "called, program_index={}", program_index); 1012 LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
1012 1013
1013 auto romfs = fsc.OpenPatchedRomFSWithProgramIndex( 1014 auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex(
1014 system.CurrentProcess()->GetTitleID(), program_index, FileSys::ContentRecordType::Program); 1015 system.CurrentProcess()->GetTitleID(), program_index, FileSys::ContentRecordType::Program);
1015 1016
1016 if (romfs.Failed()) { 1017 if (patched_romfs.Failed()) {
1017 // TODO: Find the right error code to use here 1018 // TODO: Find the right error code to use here
1018 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); 1019 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
1019 1020
@@ -1022,7 +1023,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
1022 return; 1023 return;
1023 } 1024 }
1024 1025
1025 auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap())); 1026 auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs.Unwrap()));
1026 1027
1027 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1028 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1028 rb.Push(RESULT_SUCCESS); 1029 rb.Push(RESULT_SUCCESS);
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/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp
index a502ab47f..f918bdf03 100644
--- a/src/core/hle/service/grc/grc.cpp
+++ b/src/core/hle/service/grc/grc.cpp
@@ -12,7 +12,7 @@ namespace Service::GRC {
12 12
13class GRC final : public ServiceFramework<GRC> { 13class GRC final : public ServiceFramework<GRC> {
14public: 14public:
15 explicit GRC(Core::System& system) : ServiceFramework{system, "grc:c"} { 15 explicit GRC(Core::System& system_) : ServiceFramework{system_, "grc:c"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {1, nullptr, "OpenContinuousRecorder"}, 18 {1, nullptr, "OpenContinuousRecorder"},
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp
new file mode 100644
index 000000000..bda6e2557
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp
@@ -0,0 +1,90 @@
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 "common/settings.h"
6#include "core/core_timing.h"
7#include "core/hle/service/hid/controllers/console_sixaxis.h"
8
9namespace Service::HID {
10constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
11
12Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_)
13 : ControllerBase{system_} {}
14Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
15
16void Controller_ConsoleSixAxis::OnInit() {}
17
18void Controller_ConsoleSixAxis::OnRelease() {}
19
20void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
21 std::size_t size) {
22 seven_six_axis.header.timestamp = core_timing.GetCPUTicks();
23 seven_six_axis.header.total_entry_count = 17;
24
25 if (!IsControllerActivated() || !is_transfer_memory_set) {
26 seven_six_axis.header.entry_count = 0;
27 seven_six_axis.header.last_entry_index = 0;
28 return;
29 }
30 seven_six_axis.header.entry_count = 16;
31
32 const auto& last_entry =
33 seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
34 seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17;
35 auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
36
37 cur_entry.sampling_number = last_entry.sampling_number + 1;
38 cur_entry.sampling_number2 = cur_entry.sampling_number;
39
40 // Try to read sixaxis sensor states
41 MotionDevice motion_device{};
42 const auto& device = motions[0];
43 if (device) {
44 std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation,
45 motion_device.orientation, motion_device.quaternion) = device->GetStatus();
46 console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f;
47 }
48
49 cur_entry.accel = motion_device.accel;
50 // Zero gyro values as they just mess up with the camera
51 // Note: Probably a correct sensivity setting must be set
52 cur_entry.gyro = {};
53 cur_entry.quaternion = {
54 {
55 motion_device.quaternion.xyz.y,
56 motion_device.quaternion.xyz.x,
57 -motion_device.quaternion.w,
58 },
59 -motion_device.quaternion.xyz.z,
60 };
61
62 console_six_axis.sampling_number++;
63 // TODO(German77): Find the purpose of those values
64 console_six_axis.verticalization_error = 0.0f;
65 console_six_axis.gyro_bias = {0.0f, 0.0f, 0.0f};
66
67 // Update console six axis shared memory
68 std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis));
69 // Update seven six axis transfer memory
70 std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis));
71}
72
73void Controller_ConsoleSixAxis::OnLoadInputDevices() {
74 const auto player = Settings::values.players.GetValue()[0];
75 std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
76 player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(),
77 Input::CreateDevice<Input::MotionDevice>);
78}
79
80void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
81 is_transfer_memory_set = true;
82 transfer_memory = t_mem;
83}
84
85void Controller_ConsoleSixAxis::ResetTimestamp() {
86 auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
87 cur_entry.sampling_number = 0;
88 cur_entry.sampling_number2 = 0;
89}
90} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h
new file mode 100644
index 000000000..fd8a427af
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/console_sixaxis.h
@@ -0,0 +1,80 @@
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 <array>
8#include "common/bit_field.h"
9#include "common/common_types.h"
10#include "common/quaternion.h"
11#include "core/frontend/input.h"
12#include "core/hle/service/hid/controllers/controller_base.h"
13
14namespace Service::HID {
15class Controller_ConsoleSixAxis final : public ControllerBase {
16public:
17 explicit Controller_ConsoleSixAxis(Core::System& system_);
18 ~Controller_ConsoleSixAxis() override;
19
20 // Called when the controller is initialized
21 void OnInit() override;
22
23 // When the controller is released
24 void OnRelease() override;
25
26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
28
29 // Called when input devices should be loaded
30 void OnLoadInputDevices() override;
31
32 // Called on InitializeSevenSixAxisSensor
33 void SetTransferMemoryPointer(u8* t_mem);
34
35 // Called on ResetSevenSixAxisSensorTimestamp
36 void ResetTimestamp();
37
38private:
39 struct SevenSixAxisState {
40 INSERT_PADDING_WORDS(4); // unused
41 s64_le sampling_number{};
42 s64_le sampling_number2{};
43 u64 unknown{};
44 Common::Vec3f accel{};
45 Common::Vec3f gyro{};
46 Common::Quaternion<f32> quaternion{};
47 };
48 static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size");
49
50 struct SevenSixAxisMemory {
51 CommonHeader header{};
52 std::array<SevenSixAxisState, 0x21> sevensixaxis_states{};
53 };
54 static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size");
55
56 struct ConsoleSharedMemory {
57 u64_le sampling_number{};
58 bool is_seven_six_axis_sensor_at_rest{};
59 f32 verticalization_error{};
60 Common::Vec3f gyro_bias{};
61 };
62 static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
63
64 struct MotionDevice {
65 Common::Vec3f accel;
66 Common::Vec3f gyro;
67 Common::Vec3f rotation;
68 std::array<Common::Vec3f, 3> orientation;
69 Common::Quaternion<f32> quaternion;
70 };
71
72 using MotionArray =
73 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>;
74 MotionArray motions;
75 u8* transfer_memory = nullptr;
76 bool is_transfer_memory_set = false;
77 ConsoleSharedMemory console_six_axis{};
78 SevenSixAxisMemory seven_six_axis{};
79};
80} // namespace Service::HID
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/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index a460f2f79..d439b8fb0 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -14,7 +14,7 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
14[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 14[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
15enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; 15enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
16 16
17Controller_DebugPad::Controller_DebugPad(Core::System& system) : ControllerBase(system) {} 17Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {}
18Controller_DebugPad::~Controller_DebugPad() = default; 18Controller_DebugPad::~Controller_DebugPad() = default;
19 19
20void Controller_DebugPad::OnInit() {} 20void Controller_DebugPad::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 0593d7d39..1b1645184 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -16,7 +16,7 @@
16namespace Service::HID { 16namespace Service::HID {
17class Controller_DebugPad final : public ControllerBase { 17class Controller_DebugPad final : public ControllerBase {
18public: 18public:
19 explicit Controller_DebugPad(Core::System& system); 19 explicit Controller_DebugPad(Core::System& system_);
20 ~Controller_DebugPad() override; 20 ~Controller_DebugPad() override;
21 21
22 // Called when the controller is initialized 22 // 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 155808f6a..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 }
90 99
91 cur_entry.delta_x = gesture.mid_point.x - last_entry.x; 100 // Update on press and hold event after 0.5 seconds
92 cur_entry.delta_y = gesture.mid_point.y - last_entry.y; 101 if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 &&
93 // TODO: Find how velocities are calculated 102 time_difference > press_delay) {
94 cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f; 103 return enable_press_and_tap;
95 cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f; 104 }
96 105
97 // Slowdown the rate of change for less flapping 106 return false;
98 last_gesture.average_distance = 107}
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 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];
118
119 if (shared_memory.header.entry_count < 16) {
120 shared_memory.header.entry_count++;
121 }
122
123 cur_entry.sampling_number = last_entry.sampling_number + 1;
124 cur_entry.sampling_number2 = cur_entry.sampling_number;
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");
@@ -129,6 +349,10 @@ void Controller_Gesture::OnLoadInputDevices() {
129} 349}
130 350
131std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const { 351std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const {
352 // Dont assign any touch input to a point if disabled
353 if (!Settings::values.touchscreen.enabled) {
354 return std::nullopt;
355 }
132 std::size_t first_free_id = 0; 356 std::size_t first_free_id = 0;
133 while (first_free_id < MAX_POINTS) { 357 while (first_free_id < MAX_POINTS) {
134 if (!fingers[first_free_id].pressed) { 358 if (!fingers[first_free_id].pressed) {
@@ -179,23 +403,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties()
179 403
180 for (size_t id = 0; id < gesture.active_points; ++id) { 404 for (size_t id = 0; id < gesture.active_points; ++id) {
181 gesture.points[id].x = 405 gesture.points[id].x =
182 static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); 406 static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width);
183 gesture.points[id].y = 407 gesture.points[id].y =
184 static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); 408 static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height);
185 gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); 409
186 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);
187 } 420 }
188 421
189 for (size_t id = 0; id < gesture.active_points; ++id) { 422 for (size_t id = 0; id < gesture.active_points; ++id) {
190 const double distance = 423 const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
191 std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + 424 Square(gesture.mid_point.y - gesture.points[id].y));
192 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);
193 gesture.average_distance +=
194 static_cast<float>(distance) / static_cast<float>(gesture.active_points);
195 } 426 }
196 427
197 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),
198 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
199 return gesture; 433 return gesture;
200} 434}
201 435
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 60ecc7822..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,14 +7,13 @@
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
14namespace Service::HID { 13namespace Service::HID {
15class Controller_Gesture final : public ControllerBase { 14class Controller_Gesture final : public ControllerBase {
16public: 15public:
17 explicit Controller_Gesture(Core::System& system); 16 explicit Controller_Gesture(Core::System& system_);
18 ~Controller_Gesture() override; 17 ~Controller_Gesture() override;
19 18
20 // Called when the controller is initialized 19 // Called when the controller is initialized
@@ -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/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 18b76038f..c6c620008 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -12,7 +12,7 @@ namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
13constexpr u8 KEYS_PER_BYTE = 8; 13constexpr u8 KEYS_PER_BYTE = 8;
14 14
15Controller_Keyboard::Controller_Keyboard(Core::System& system) : ControllerBase(system) {} 15Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {}
16Controller_Keyboard::~Controller_Keyboard() = default; 16Controller_Keyboard::~Controller_Keyboard() = default;
17 17
18void Controller_Keyboard::OnInit() {} 18void Controller_Keyboard::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index e72948591..172a80e9c 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -16,7 +16,7 @@
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Keyboard final : public ControllerBase { 17class Controller_Keyboard final : public ControllerBase {
18public: 18public:
19 explicit Controller_Keyboard(Core::System& system); 19 explicit Controller_Keyboard(Core::System& system_);
20 ~Controller_Keyboard() override; 20 ~Controller_Keyboard() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 2e7457604..544a71948 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -11,7 +11,7 @@
11namespace Service::HID { 11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
13 13
14Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system) {} 14Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {}
15Controller_Mouse::~Controller_Mouse() = default; 15Controller_Mouse::~Controller_Mouse() = default;
16 16
17void Controller_Mouse::OnInit() {} 17void Controller_Mouse::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 0ec0c2b94..3d391a798 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -15,7 +15,7 @@
15namespace Service::HID { 15namespace Service::HID {
16class Controller_Mouse final : public ControllerBase { 16class Controller_Mouse final : public ControllerBase {
17public: 17public:
18 explicit Controller_Mouse(Core::System& system); 18 explicit Controller_Mouse(Core::System& system_);
19 ~Controller_Mouse() override; 19 ~Controller_Mouse() override;
20 20
21 // Called when the controller is initialized 21 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 113a41254..7acad3798 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -147,7 +147,7 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
147 device_handle.device_index < DeviceIndex::MaxDeviceIndex; 147 device_handle.device_index < DeviceIndex::MaxDeviceIndex;
148} 148}
149 149
150Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system) { 150Controller_NPad::Controller_NPad(Core::System& system_) : ControllerBase{system_} {
151 latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); 151 latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
152} 152}
153 153
@@ -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) {
@@ -654,8 +658,8 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
654 const auto& device = motions[i][e]; 658 const auto& device = motions[i][e];
655 if (device) { 659 if (device) {
656 std::tie(motion_devices[e].accel, motion_devices[e].gyro, 660 std::tie(motion_devices[e].accel, motion_devices[e].gyro,
657 motion_devices[e].rotation, motion_devices[e].orientation) = 661 motion_devices[e].rotation, motion_devices[e].orientation,
658 device->GetStatus(); 662 motion_devices[e].quaternion) = device->GetStatus();
659 sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f; 663 sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
660 } 664 }
661 } 665 }
@@ -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 c3b07bd41..c050c9a44 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -8,9 +8,9 @@
8#include <atomic> 8#include <atomic>
9#include "common/bit_field.h" 9#include "common/bit_field.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/quaternion.h"
11#include "common/settings.h" 12#include "common/settings.h"
12#include "core/frontend/input.h" 13#include "core/frontend/input.h"
13#include "core/hle/kernel/object.h"
14#include "core/hle/service/hid/controllers/controller_base.h" 14#include "core/hle/service/hid/controllers/controller_base.h"
15 15
16namespace Kernel { 16namespace Kernel {
@@ -25,7 +25,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
25 25
26class Controller_NPad final : public ControllerBase { 26class Controller_NPad final : public ControllerBase {
27public: 27public:
28 explicit Controller_NPad(Core::System& system); 28 explicit Controller_NPad(Core::System& system_);
29 ~Controller_NPad() override; 29 ~Controller_NPad() override;
30 30
31 // Called when the controller is initialized 31 // Called when the controller is initialized
@@ -198,7 +198,7 @@ public:
198 198
199 bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; 199 bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
200 200
201 std::shared_ptr<Kernel::KReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; 201 Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id);
202 void SignalStyleSetChangedEvent(u32 npad_id) const; 202 void SignalStyleSetChangedEvent(u32 npad_id) const;
203 203
204 // Adds a new controller at an index. 204 // Adds a new controller at an index.
@@ -467,6 +467,7 @@ private:
467 Common::Vec3f gyro; 467 Common::Vec3f gyro;
468 Common::Vec3f rotation; 468 Common::Vec3f rotation;
469 std::array<Common::Vec3f, 3> orientation; 469 std::array<Common::Vec3f, 3> orientation;
470 Common::Quaternion<f32> quaternion;
470 }; 471 };
471 472
472 struct NfcXcdHandle { 473 struct NfcXcdHandle {
@@ -571,8 +572,9 @@ private:
571 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; 572 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
572 NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; 573 NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
573 // Each controller should have their own styleset changed event 574 // Each controller should have their own styleset changed event
574 std::array<std::shared_ptr<Kernel::KEvent>, 10> styleset_changed_events; 575 std::array<Kernel::KEvent*, 10> styleset_changed_events{};
575 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{};
576 std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; 578 std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
577 bool permit_vibration_session_enabled{false}; 579 bool permit_vibration_session_enabled{false};
578 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/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index e7483bfa2..772c20453 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -9,7 +9,7 @@
9 9
10namespace Service::HID { 10namespace Service::HID {
11 11
12Controller_Stubbed::Controller_Stubbed(Core::System& system) : ControllerBase(system) {} 12Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {}
13Controller_Stubbed::~Controller_Stubbed() = default; 13Controller_Stubbed::~Controller_Stubbed() = default;
14 14
15void Controller_Stubbed::OnInit() {} 15void Controller_Stubbed::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 4fa83ac85..21092af0d 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -10,7 +10,7 @@
10namespace Service::HID { 10namespace Service::HID {
11class Controller_Stubbed final : public ControllerBase { 11class Controller_Stubbed final : public ControllerBase {
12public: 12public:
13 explicit Controller_Stubbed(Core::System& system); 13 explicit Controller_Stubbed(Core::System& system_);
14 ~Controller_Stubbed() override; 14 ~Controller_Stubbed() override;
15 15
16 // Called when the controller is initialized 16 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index b5f8077be..ac9112c40 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -15,7 +15,7 @@
15namespace Service::HID { 15namespace Service::HID {
16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; 16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
17 17
18Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} 18Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {}
19Controller_Touchscreen::~Controller_Touchscreen() = default; 19Controller_Touchscreen::~Controller_Touchscreen() = default;
20 20
21void Controller_Touchscreen::OnInit() { 21void Controller_Touchscreen::OnInit() {
@@ -105,6 +105,10 @@ void Controller_Touchscreen::OnLoadInputDevices() {
105} 105}
106 106
107std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { 107std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const {
108 // Dont assign any touch input to a finger if disabled
109 if (!Settings::values.touchscreen.enabled) {
110 return std::nullopt;
111 }
108 std::size_t first_free_id = 0; 112 std::size_t first_free_id = 0;
109 while (first_free_id < MAX_FINGERS) { 113 while (first_free_id < MAX_FINGERS) {
110 if (!fingers[first_free_id].pressed) { 114 if (!fingers[first_free_id].pressed) {
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 784124e25..2869d0cfd 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -14,7 +14,7 @@
14namespace Service::HID { 14namespace Service::HID {
15class Controller_Touchscreen final : public ControllerBase { 15class Controller_Touchscreen final : public ControllerBase {
16public: 16public:
17 explicit Controller_Touchscreen(Core::System& system); 17 explicit Controller_Touchscreen(Core::System& system_);
18 ~Controller_Touchscreen() override; 18 ~Controller_Touchscreen() override;
19 19
20 // Called when the controller is initialized 20 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
index 2503ef241..41dc22cf9 100644
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ b/src/core/hle/service/hid/controllers/xpad.cpp
@@ -10,7 +10,7 @@
10namespace Service::HID { 10namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; 11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
12 12
13Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system) {} 13Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {}
14Controller_XPad::~Controller_XPad() = default; 14Controller_XPad::~Controller_XPad() = default;
15 15
16void Controller_XPad::OnInit() {} 16void Controller_XPad::OnInit() {}
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
index 5b59961bd..f9ab5facf 100644
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -13,7 +13,7 @@
13namespace Service::HID { 13namespace Service::HID {
14class Controller_XPad final : public ControllerBase { 14class Controller_XPad final : public ControllerBase {
15public: 15public:
16 explicit Controller_XPad(Core::System& system); 16 explicit Controller_XPad(Core::System& system_);
17 ~Controller_XPad() override; 17 ~Controller_XPad() override;
18 18
19 // Called when the controller is initialized 19 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 2aa1942cb..49c17fd14 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,19 +13,20 @@
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/controller_base.h" 30#include "core/hle/service/hid/controllers/controller_base.h"
30#include "core/hle/service/hid/controllers/debug_pad.h" 31#include "core/hle/service/hid/controllers/debug_pad.h"
31#include "core/hle/service/hid/controllers/gesture.h" 32#include "core/hle/service/hid/controllers/gesture.h"
@@ -52,9 +53,6 @@ IAppletResource::IAppletResource(Core::System& system_)
52 }; 53 };
53 RegisterHandlers(functions); 54 RegisterHandlers(functions);
54 55
55 auto& kernel = system.Kernel();
56 shared_mem = SharedFrom(&kernel.GetHidSharedMem());
57
58 MakeController<Controller_DebugPad>(HidController::DebugPad); 56 MakeController<Controller_DebugPad>(HidController::DebugPad);
59 MakeController<Controller_Touchscreen>(HidController::Touchscreen); 57 MakeController<Controller_Touchscreen>(HidController::Touchscreen);
60 MakeController<Controller_Mouse>(HidController::Mouse); 58 MakeController<Controller_Mouse>(HidController::Mouse);
@@ -67,7 +65,7 @@ IAppletResource::IAppletResource(Core::System& system_)
67 MakeController<Controller_Stubbed>(HidController::UniquePad); 65 MakeController<Controller_Stubbed>(HidController::UniquePad);
68 MakeController<Controller_NPad>(HidController::NPad); 66 MakeController<Controller_NPad>(HidController::NPad);
69 MakeController<Controller_Gesture>(HidController::Gesture); 67 MakeController<Controller_Gesture>(HidController::Gesture);
70 MakeController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor); 68 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
71 69
72 // Homebrew doesn't try to activate some controllers, so we activate them by default 70 // Homebrew doesn't try to activate some controllers, so we activate them by default
73 GetController<Controller_NPad>(HidController::NPad).ActivateController(); 71 GetController<Controller_NPad>(HidController::NPad).ActivateController();
@@ -78,8 +76,6 @@ IAppletResource::IAppletResource(Core::System& system_)
78 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000); 76 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
79 GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200); 77 GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
80 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); 78 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
81 GetController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor)
82 .SetCommonHeaderOffset(0x3C200);
83 79
84 // Register update callbacks 80 // Register update callbacks
85 pad_update_event = Core::Timing::CreateEvent( 81 pad_update_event = Core::Timing::CreateEvent(
@@ -119,7 +115,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
119 115
120 IPC::ResponseBuilder rb{ctx, 2, 1}; 116 IPC::ResponseBuilder rb{ctx, 2, 1};
121 rb.Push(RESULT_SUCCESS); 117 rb.Push(RESULT_SUCCESS);
122 rb.PushCopyObjects(shared_mem); 118 rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
123} 119}
124 120
125void IAppletResource::UpdateControllers(std::uintptr_t user_data, 121void IAppletResource::UpdateControllers(std::uintptr_t user_data,
@@ -131,7 +127,8 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
131 if (should_reload) { 127 if (should_reload) {
132 controller->OnLoadInputDevices(); 128 controller->OnLoadInputDevices();
133 } 129 }
134 controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 130 controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
131 SHARED_MEMORY_SIZE);
135 } 132 }
136 133
137 // 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
@@ -146,7 +143,7 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
146 auto& core_timing = system.CoreTiming(); 143 auto& core_timing = system.CoreTiming();
147 144
148 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( 145 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(
149 core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); 146 core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
150 147
151 // 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
152 if (ns_late > motion_update_ns) { 149 if (ns_late > motion_update_ns) {
@@ -1404,8 +1401,9 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
1404 IPC::RequestParser rp{ctx}; 1401 IPC::RequestParser rp{ctx};
1405 const auto applet_resource_user_id{rp.Pop<u64>()}; 1402 const auto applet_resource_user_id{rp.Pop<u64>()};
1406 1403
1407 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", 1404 applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
1408 applet_resource_user_id); 1405
1406 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1409 1407
1410 IPC::ResponseBuilder rb{ctx, 2}; 1408 IPC::ResponseBuilder rb{ctx, 2};
1411 rb.Push(RESULT_SUCCESS); 1409 rb.Push(RESULT_SUCCESS);
@@ -1455,8 +1453,9 @@ void Hid::ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
1455 IPC::RequestParser rp{ctx}; 1453 IPC::RequestParser rp{ctx};
1456 const auto applet_resource_user_id{rp.Pop<u64>()}; 1454 const auto applet_resource_user_id{rp.Pop<u64>()};
1457 1455
1458 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", 1456 applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
1459 applet_resource_user_id); 1457
1458 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1460 1459
1461 IPC::ResponseBuilder rb{ctx, 2}; 1460 IPC::ResponseBuilder rb{ctx, 2};
1462 rb.Push(RESULT_SUCCESS); 1461 rb.Push(RESULT_SUCCESS);
@@ -1495,20 +1494,20 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
1495 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");
1496 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");
1497 1496
1498 auto t_mem_1 = 1497 auto t_mem_1 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1499 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_1_handle); 1498 t_mem_1_handle);
1500 1499
1501 if (t_mem_1 == nullptr) { 1500 if (t_mem_1.IsNull()) {
1502 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);
1503 IPC::ResponseBuilder rb{ctx, 2}; 1502 IPC::ResponseBuilder rb{ctx, 2};
1504 rb.Push(RESULT_UNKNOWN); 1503 rb.Push(RESULT_UNKNOWN);
1505 return; 1504 return;
1506 } 1505 }
1507 1506
1508 auto t_mem_2 = 1507 auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1509 system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_2_handle); 1508 t_mem_2_handle);
1510 1509
1511 if (t_mem_2 == nullptr) { 1510 if (t_mem_2.IsNull()) {
1512 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);
1513 IPC::ResponseBuilder rb{ctx, 2}; 1512 IPC::ResponseBuilder rb{ctx, 2};
1514 rb.Push(RESULT_UNKNOWN); 1513 rb.Push(RESULT_UNKNOWN);
@@ -1518,8 +1517,15 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
1518 ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size"); 1517 ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size");
1519 ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size"); 1518 ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
1520 1519
1520 // Activate console six axis controller
1521 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1522 .ActivateController();
1523
1524 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1525 .SetTransferMemoryPointer(system.Memory().GetPointer(t_mem_1->GetSourceAddress()));
1526
1521 LOG_WARNING(Service_HID, 1527 LOG_WARNING(Service_HID,
1522 "(STUBBED) 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}, "
1523 "applet_resource_user_id={}", 1529 "applet_resource_user_id={}",
1524 t_mem_1_handle, t_mem_2_handle, applet_resource_user_id); 1530 t_mem_1_handle, t_mem_2_handle, applet_resource_user_id);
1525 1531
@@ -1542,8 +1548,10 @@ void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) {
1542 IPC::RequestParser rp{ctx}; 1548 IPC::RequestParser rp{ctx};
1543 const auto applet_resource_user_id{rp.Pop<u64>()}; 1549 const auto applet_resource_user_id{rp.Pop<u64>()};
1544 1550
1545 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", 1551 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1546 applet_resource_user_id); 1552 .ResetTimestamp();
1553
1554 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1547 1555
1548 IPC::ResponseBuilder rb{ctx, 2}; 1556 IPC::ResponseBuilder rb{ctx, 2};
1549 rb.Push(RESULT_SUCCESS); 1557 rb.Push(RESULT_SUCCESS);
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/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index e11a0c45a..3a5a2f4f5 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -312,7 +312,6 @@ private:
312 312
313 bool vr_mode_enabled = false; 313 bool vr_mode_enabled = false;
314 float current_brightness = 1.0f; 314 float current_brightness = 1.0f;
315 float backlight_brightness = 1.0f;
316 float ambient_light_value = 0.0f; 315 float ambient_light_value = 0.0f;
317 float current_vr_brightness = 1.0f; 316 float current_vr_brightness = 1.0f;
318 bool dimming = true; 317 bool dimming = true;
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/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 5ab7e39b0..2cc0da124 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -14,8 +14,8 @@
14 14
15namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
16 16
17nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 17nvdisp_disp0::nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 18 : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
19nvdisp_disp0 ::~nvdisp_disp0() = default; 19nvdisp_disp0 ::~nvdisp_disp0() = default;
20 20
21NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 21NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -52,7 +52,6 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
52 addr, offset, width, height, stride, static_cast<PixelFormat>(format), 52 addr, offset, width, height, stride, static_cast<PixelFormat>(format),
53 transform, crop_rect}; 53 transform, crop_rect};
54 54
55 system.GetPerfStats().EndGameFrame();
56 system.GetPerfStats().EndSystemFrame(); 55 system.GetPerfStats().EndSystemFrame();
57 system.GPU().SwapBuffers(&framebuffer); 56 system.GPU().SwapBuffers(&framebuffer);
58 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); 57 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 59c9b6101..de01e1d5f 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -17,7 +17,7 @@ class nvmap;
17 17
18class nvdisp_disp0 final : public nvdevice { 18class nvdisp_disp0 final : public nvdevice {
19public: 19public:
20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_);
21 ~nvdisp_disp0() override; 21 ~nvdisp_disp0() override;
22 22
23 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 23 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index f7b3dc317..7dc41d875 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -17,8 +17,8 @@
17 17
18namespace Service::Nvidia::Devices { 18namespace Service::Nvidia::Devices {
19 19
20nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 20nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
21 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 21 : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
22nvhost_as_gpu::~nvhost_as_gpu() = default; 22nvhost_as_gpu::~nvhost_as_gpu() = default;
23 23
24NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 24NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
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 d86a9cab6..24e3151cb 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -30,7 +30,7 @@ DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags);
30 30
31class nvhost_as_gpu final : public nvdevice { 31class nvhost_as_gpu final : public nvdevice {
32public: 32public:
33 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 33 explicit nvhost_as_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_);
34 ~nvhost_as_gpu() override; 34 ~nvhost_as_gpu() override;
35 35
36 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 36 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -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 9f00d5cb0..775e76330 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -15,9 +15,10 @@
15 15
16namespace Service::Nvidia::Devices { 16namespace Service::Nvidia::Devices {
17 17
18nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface, 18nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_,
19 SyncpointManager& syncpoint_manager) 19 SyncpointManager& syncpoint_manager_)
20 : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} 20 : nvdevice{system_}, events_interface{events_interface_}, syncpoint_manager{
21 syncpoint_manager_} {}
21nvhost_ctrl::~nvhost_ctrl() = default; 22nvhost_ctrl::~nvhost_ctrl() = default;
22 23
23NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 24NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -101,20 +102,20 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
101 return NvResult::Success; 102 return NvResult::Success;
102 } 103 }
103 104
104 auto event = events_interface.events[event_id]; 105 auto& event = events_interface.events[event_id];
105 auto& gpu = system.GPU(); 106 auto& gpu = system.GPU();
106 107
107 // This is mostly to take into account unimplemented features. As synced 108 // This is mostly to take into account unimplemented features. As synced
108 // gpu is always synced. 109 // gpu is always synced.
109 if (!gpu.IsAsync()) { 110 if (!gpu.IsAsync()) {
110 event.event->GetWritableEvent()->Signal(); 111 event.event->GetWritableEvent().Signal();
111 return NvResult::Success; 112 return NvResult::Success;
112 } 113 }
113 auto lock = gpu.LockSync(); 114 auto lock = gpu.LockSync();
114 const u32 current_syncpoint_value = event.fence.value; 115 const u32 current_syncpoint_value = event.fence.value;
115 const s32 diff = current_syncpoint_value - params.threshold; 116 const s32 diff = current_syncpoint_value - params.threshold;
116 if (diff >= 0) { 117 if (diff >= 0) {
117 event.event->GetWritableEvent()->Signal(); 118 event.event->GetWritableEvent().Signal();
118 params.value = current_syncpoint_value; 119 params.value = current_syncpoint_value;
119 std::memcpy(output.data(), &params, sizeof(params)); 120 std::memcpy(output.data(), &params, sizeof(params));
120 return NvResult::Success; 121 return NvResult::Success;
@@ -141,7 +142,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
141 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; 142 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
142 } 143 }
143 params.value |= event_id; 144 params.value |= event_id;
144 event.event->GetWritableEvent()->Clear(); 145 event.event->GetWritableEvent().Clear();
145 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); 146 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
146 std::memcpy(output.data(), &params, sizeof(params)); 147 std::memcpy(output.data(), &params, sizeof(params));
147 return NvResult::Timeout; 148 return NvResult::Timeout;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 9178789c3..cdf03887d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -14,8 +14,8 @@ namespace Service::Nvidia::Devices {
14 14
15class nvhost_ctrl final : public nvdevice { 15class nvhost_ctrl final : public nvdevice {
16public: 16public:
17 explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface, 17 explicit nvhost_ctrl(Core::System& system_, EventInterface& events_interface_,
18 SyncpointManager& syncpoint_manager); 18 SyncpointManager& syncpoint_manager_);
19 ~nvhost_ctrl() override; 19 ~nvhost_ctrl() override;
20 20
21 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 21 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 2edd803f3..d8b684f4f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Service::Nvidia::Devices { 13namespace Service::Nvidia::Devices {
14 14
15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} 15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_) : nvdevice{system_} {}
16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; 16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
17 17
18NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 18NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index f98aa841a..898d00a17 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -13,7 +13,7 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_ctrl_gpu final : public nvdevice { 14class nvhost_ctrl_gpu final : public nvdevice {
15public: 15public:
16 explicit nvhost_ctrl_gpu(Core::System& system); 16 explicit nvhost_ctrl_gpu(Core::System& system_);
17 ~nvhost_ctrl_gpu() override; 17 ~nvhost_ctrl_gpu() override;
18 18
19 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 19 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index e83aaa798..c0a380088 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -14,11 +14,11 @@
14 14
15namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
16 16
17nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 17nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
18 SyncpointManager& syncpoint_manager) 18 SyncpointManager& syncpoint_manager_)
19 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} { 19 : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} {
20 channel_fence.id = syncpoint_manager.AllocateSyncpoint(); 20 channel_fence.id = syncpoint_manager_.AllocateSyncpoint();
21 channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id); 21 channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id);
22} 22}
23 23
24nvhost_gpu::~nvhost_gpu() = default; 24nvhost_gpu::~nvhost_gpu() = default;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 12a1a1133..f27a82bff 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -22,8 +22,8 @@ namespace Service::Nvidia::Devices {
22class nvmap; 22class nvmap;
23class nvhost_gpu final : public nvdevice { 23class nvhost_gpu final : public nvdevice {
24public: 24public:
25 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 25 explicit nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
26 SyncpointManager& syncpoint_manager); 26 SyncpointManager& syncpoint_manager_);
27 ~nvhost_gpu() override; 27 ~nvhost_gpu() override;
28 28
29 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 29 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index e2f671d8e..6c1edce33 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -11,9 +11,9 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 14nvhost_nvdec::nvhost_nvdec(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
15 SyncpointManager& syncpoint_manager) 15 SyncpointManager& syncpoint_manager_)
16 : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} 16 : nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {}
17nvhost_nvdec::~nvhost_nvdec() = default; 17nvhost_nvdec::~nvhost_nvdec() = default;
18 18
19NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 19NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 6c38a8c24..523d96e3a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -11,8 +11,8 @@ namespace Service::Nvidia::Devices {
11 11
12class nvhost_nvdec final : public nvhost_nvdec_common { 12class nvhost_nvdec final : public nvhost_nvdec_common {
13public: 13public:
14 explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 14 explicit nvhost_nvdec(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
15 SyncpointManager& syncpoint_manager); 15 SyncpointManager& syncpoint_manager_);
16 ~nvhost_nvdec() override; 16 ~nvhost_nvdec() override;
17 17
18 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 18 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index c2f152190..98e6296f1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -42,9 +42,9 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s
42} 42}
43} // Anonymous namespace 43} // Anonymous namespace
44 44
45nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 45nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
46 SyncpointManager& syncpoint_manager) 46 SyncpointManager& syncpoint_manager_)
47 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager(syncpoint_manager) {} 47 : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} {}
48nvhost_nvdec_common::~nvhost_nvdec_common() = default; 48nvhost_nvdec_common::~nvhost_nvdec_common() = default;
49 49
50NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { 50NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
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 4c9d4ba41..da10f5f41 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -18,8 +18,8 @@ class nvmap;
18 18
19class nvhost_nvdec_common : public nvdevice { 19class nvhost_nvdec_common : public nvdevice {
20public: 20public:
21 explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 21 explicit nvhost_nvdec_common(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
22 SyncpointManager& syncpoint_manager); 22 SyncpointManager& syncpoint_manager_);
23 ~nvhost_nvdec_common() override; 23 ~nvhost_nvdec_common() override;
24 24
25protected: 25protected:
@@ -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/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 0a9c35c01..c2be3cea7 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -10,7 +10,7 @@
10 10
11namespace Service::Nvidia::Devices { 11namespace Service::Nvidia::Devices {
12 12
13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} 13nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {}
14nvhost_nvjpg::~nvhost_nvjpg() = default; 14nvhost_nvjpg::~nvhost_nvjpg() = default;
15 15
16NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 16NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 1f97b642f..6045e5cbd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -13,7 +13,7 @@ namespace Service::Nvidia::Devices {
13 13
14class nvhost_nvjpg final : public nvdevice { 14class nvhost_nvjpg final : public nvdevice {
15public: 15public:
16 explicit nvhost_nvjpg(Core::System& system); 16 explicit nvhost_nvjpg(Core::System& system_);
17 ~nvhost_nvjpg() override; 17 ~nvhost_nvjpg() override;
18 18
19 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 19 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 301efe8a1..21d101e8a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -10,9 +10,9 @@
10#include "video_core/renderer_base.h" 10#include "video_core/renderer_base.h"
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 13nvhost_vic::nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
14 SyncpointManager& syncpoint_manager) 14 SyncpointManager& syncpoint_manager_)
15 : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} 15 : nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {}
16 16
17nvhost_vic::~nvhost_vic() = default; 17nvhost_vic::~nvhost_vic() = default;
18 18
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index cebefad71..6d7fda9d1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -10,8 +10,8 @@ namespace Service::Nvidia::Devices {
10 10
11class nvhost_vic final : public nvhost_nvdec_common { 11class nvhost_vic final : public nvhost_nvdec_common {
12public: 12public:
13 explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 13 explicit nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
14 SyncpointManager& syncpoint_manager); 14 SyncpointManager& syncpoint_manager_);
15 ~nvhost_vic(); 15 ~nvhost_vic();
16 16
17 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 17 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index dd1355522..dc59b4494 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -11,7 +11,7 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14nvmap::nvmap(Core::System& system) : nvdevice(system) { 14nvmap::nvmap(Core::System& system_) : nvdevice{system_} {
15 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to 15 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
16 // represent this. 16 // represent this.
17 CreateObject(0); 17 CreateObject(0);
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 208875845..d90b69e5a 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -16,7 +16,7 @@ namespace Service::Nvidia::Devices {
16 16
17class nvmap final : public nvdevice { 17class nvmap final : public nvdevice {
18public: 18public:
19 explicit nvmap(Core::System& system); 19 explicit nvmap(Core::System& system_);
20 ~nvmap() override; 20 ~nvmap() override;
21 21
22 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, 22 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 2e1150867..dc9b9341f 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -22,19 +22,30 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
22 22
23void NVDRV::Open(Kernel::HLERequestContext& ctx) { 23void NVDRV::Open(Kernel::HLERequestContext& ctx) {
24 LOG_DEBUG(Service_NVDRV, "called"); 24 LOG_DEBUG(Service_NVDRV, "called");
25 IPC::ResponseBuilder rb{ctx, 4};
26 rb.Push(RESULT_SUCCESS);
25 27
26 if (!is_initialized) { 28 if (!is_initialized) {
27 ServiceError(ctx, NvResult::NotInitialized); 29 rb.Push<DeviceFD>(0);
30 rb.PushEnum(NvResult::NotInitialized);
31
28 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!"); 32 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
29 return; 33 return;
30 } 34 }
31 35
32 const auto& buffer = ctx.ReadBuffer(); 36 const auto& buffer = ctx.ReadBuffer();
33 const std::string device_name(buffer.begin(), buffer.end()); 37 const std::string device_name(buffer.begin(), buffer.end());
38
39 if (device_name == "/dev/nvhost-prof-gpu") {
40 rb.Push<DeviceFD>(0);
41 rb.PushEnum(NvResult::NotSupported);
42
43 LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production");
44 return;
45 }
46
34 DeviceFD fd = nvdrv->Open(device_name); 47 DeviceFD fd = nvdrv->Open(device_name);
35 48
36 IPC::ResponseBuilder rb{ctx, 4};
37 rb.Push(RESULT_SUCCESS);
38 rb.Push<DeviceFD>(fd); 49 rb.Push<DeviceFD>(fd);
39 rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); 50 rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
40} 51}
@@ -176,8 +187,8 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
176 if (event_id < MaxNvEvents) { 187 if (event_id < MaxNvEvents) {
177 IPC::ResponseBuilder rb{ctx, 3, 1}; 188 IPC::ResponseBuilder rb{ctx, 3, 1};
178 rb.Push(RESULT_SUCCESS); 189 rb.Push(RESULT_SUCCESS);
179 auto event = nvdrv->GetEvent(event_id); 190 auto& event = nvdrv->GetEvent(event_id);
180 event->Clear(); 191 event.Clear();
181 rb.PushCopyObjects(event); 192 rb.PushCopyObjects(event);
182 rb.PushEnum(NvResult::Success); 193 rb.PushEnum(NvResult::Success);
183 } 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 539b02bc4..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);
@@ -72,7 +72,7 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
72 // Schedule the screen composition events 72 // Schedule the screen composition events
73 composition_event = Core::Timing::CreateEvent( 73 composition_event = Core::Timing::CreateEvent(
74 "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) { 74 "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
75 const auto guard = Lock(); 75 const auto lock_guard = Lock();
76 Compose(); 76 Compose();
77 77
78 const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; 78 const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
@@ -112,7 +112,7 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
112} 112}
113 113
114std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { 114std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
115 const auto guard = Lock(); 115 const auto lock_guard = Lock();
116 116
117 LOG_DEBUG(Service, "Opening \"{}\" display", name); 117 LOG_DEBUG(Service, "Opening \"{}\" display", name);
118 118
@@ -131,7 +131,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
131} 131}
132 132
133std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { 133std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
134 const auto guard = Lock(); 134 const auto lock_guard = Lock();
135 auto* const display = FindDisplay(display_id); 135 auto* const display = FindDisplay(display_id);
136 136
137 if (display == nullptr) { 137 if (display == nullptr) {
@@ -139,24 +139,28 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
139 } 139 }
140 140
141 const u64 layer_id = next_layer_id++; 141 const u64 layer_id = next_layer_id++;
142 CreateLayerAtId(*display, layer_id);
143 return layer_id;
144}
145
146void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
142 const u32 buffer_queue_id = next_buffer_queue_id++; 147 const u32 buffer_queue_id = next_buffer_queue_id++;
143 buffer_queues.emplace_back( 148 buffer_queues.emplace_back(
144 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id)); 149 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id));
145 display->CreateLayer(layer_id, *buffer_queues.back()); 150 display.CreateLayer(layer_id, *buffer_queues.back());
146 return layer_id;
147} 151}
148 152
149void NVFlinger::CloseLayer(u64 layer_id) { 153void NVFlinger::CloseLayer(u64 layer_id) {
150 const auto guard = Lock(); 154 const auto lock_guard = Lock();
151 155
152 for (auto& display : displays) { 156 for (auto& display : displays) {
153 display.CloseLayer(layer_id); 157 display.CloseLayer(layer_id);
154 } 158 }
155} 159}
156 160
157std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const { 161std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
158 const auto guard = Lock(); 162 const auto lock_guard = Lock();
159 const auto* const layer = FindLayer(display_id, layer_id); 163 const auto* const layer = FindOrCreateLayer(display_id, layer_id);
160 164
161 if (layer == nullptr) { 165 if (layer == nullptr) {
162 return std::nullopt; 166 return std::nullopt;
@@ -165,19 +169,19 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
165 return layer->GetBufferQueue().GetId(); 169 return layer->GetBufferQueue().GetId();
166} 170}
167 171
168std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { 172Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
169 const auto guard = Lock(); 173 const auto lock_guard = Lock();
170 auto* const display = FindDisplay(display_id); 174 auto* const display = FindDisplay(display_id);
171 175
172 if (display == nullptr) { 176 if (display == nullptr) {
173 return nullptr; 177 return nullptr;
174 } 178 }
175 179
176 return display->GetVSyncEvent(); 180 return &display->GetVSyncEvent();
177} 181}
178 182
179BufferQueue* NVFlinger::FindBufferQueue(u32 id) { 183BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
180 const auto guard = Lock(); 184 const auto lock_guard = Lock();
181 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), 185 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
182 [id](const auto& queue) { return queue->GetId() == id; }); 186 [id](const auto& queue) { return queue->GetId() == id; });
183 187
@@ -232,6 +236,24 @@ const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
232 return display->FindLayer(layer_id); 236 return display->FindLayer(layer_id);
233} 237}
234 238
239VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
240 auto* const display = FindDisplay(display_id);
241
242 if (display == nullptr) {
243 return nullptr;
244 }
245
246 auto* layer = display->FindLayer(layer_id);
247
248 if (layer == nullptr) {
249 LOG_DEBUG(Service, "Layer at id {} not found. Trying to create it.", layer_id);
250 CreateLayerAtId(*display, layer_id);
251 return display->FindLayer(layer_id);
252 }
253
254 return layer;
255}
256
235void NVFlinger::Compose() { 257void NVFlinger::Compose() {
236 for (auto& display : displays) { 258 for (auto& display : displays) {
237 // Trigger vsync for this display at the end of drawing 259 // Trigger vsync for this display at the end of drawing
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 6fe2c7f2a..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.
@@ -67,12 +67,12 @@ public:
67 /// Finds the buffer queue ID of the specified layer in the specified display. 67 /// Finds the buffer queue ID of the specified layer in the specified display.
68 /// 68 ///
69 /// If an invalid display ID or layer ID is provided, then an empty optional is returned. 69 /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
70 [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const; 70 [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id);
71 71
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);
@@ -100,13 +100,21 @@ private:
100 /// Finds the layer identified by the specified ID in the desired display. 100 /// Finds the layer identified by the specified ID in the desired display.
101 [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; 101 [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
102 102
103 /// Finds the layer identified by the specified ID in the desired display,
104 /// or creates the layer if it is not found.
105 /// To be used when the system expects the specified ID to already exist.
106 [[nodiscard]] VI::Layer* FindOrCreateLayer(u64 display_id, u64 layer_id);
107
108 /// Creates a layer with the specified layer ID in the desired display.
109 void CreateLayerAtId(VI::Display& display, u64 layer_id);
110
103 static void VSyncThread(NVFlinger& nv_flinger); 111 static void VSyncThread(NVFlinger& nv_flinger);
104 112
105 void SplitVSync(); 113 void SplitVSync();
106 114
107 std::shared_ptr<Nvidia::Module> nvdrv; 115 std::shared_ptr<Nvidia::Module> nvdrv;
108 116
109 std::vector<VI::Display> displays; 117 std::list<VI::Display> displays;
110 std::vector<std::unique_ptr<BufferQueue>> buffer_queues; 118 std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
111 119
112 /// 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 dc59702f1..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
@@ -24,9 +24,8 @@ constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
24 24
25class IParentalControlService final : public ServiceFramework<IParentalControlService> { 25class IParentalControlService final : public ServiceFramework<IParentalControlService> {
26public: 26public:
27 explicit IParentalControlService(Core::System& system_, Capability capability) 27 explicit IParentalControlService(Core::System& system_, Capability capability_)
28 : ServiceFramework{system_, "IParentalControlService"}, system(system_), 28 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_} {
29 capability(capability) {
30 // clang-format off 29 // clang-format off
31 static const FunctionInfo functions[] = { 30 static const FunctionInfo functions[] = {
32 {1, &IParentalControlService::Initialize, "Initialize"}, 31 {1, &IParentalControlService::Initialize, "Initialize"},
@@ -362,8 +361,6 @@ private:
362 States states{}; 361 States states{};
363 ParentalControlSettings settings{}; 362 ParentalControlSettings settings{};
364 std::array<char, 8> pin_code{}; 363 std::array<char, 8> pin_code{};
365 bool can_use_stereo_vision = true;
366 Core::System& system;
367 Capability capability{}; 364 Capability capability{};
368}; 365};
369 366
@@ -386,8 +383,8 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
386} 383}
387 384
388Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, 385Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
389 const char* name, Capability capability) 386 const char* name_, Capability capability_)
390 : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {} 387 : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {}
391 388
392Module::Interface::~Interface() = default; 389Module::Interface::~Interface() = default;
393 390
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h
index 032481b00..f25c5c557 100644
--- a/src/core/hle/service/pctl/module.h
+++ b/src/core/hle/service/pctl/module.h
@@ -28,8 +28,8 @@ class Module final {
28public: 28public:
29 class Interface : public ServiceFramework<Interface> { 29 class Interface : public ServiceFramework<Interface> {
30 public: 30 public:
31 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 31 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
32 Capability capability); 32 const char* name_, Capability capability_);
33 ~Interface() override; 33 ~Interface() override;
34 34
35 void CreateService(Kernel::HLERequestContext& ctx); 35 void CreateService(Kernel::HLERequestContext& ctx);
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/interface.cpp b/src/core/hle/service/time/interface.cpp
index a01d9e0ff..53a204796 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::Time { 7namespace Service::Time {
8 8
9Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name) 9Time::Time(std::shared_ptr<Module> module_, Core::System& system_, const char* name_)
10 : Interface(std::move(module), system, name) { 10 : Interface{std::move(module_), system_, name_} {
11 // clang-format off 11 // clang-format off
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, 13 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h
index 4f49e1f07..c41766f1a 100644
--- a/src/core/hle/service/time/interface.h
+++ b/src/core/hle/service/time/interface.h
@@ -14,7 +14,7 @@ namespace Service::Time {
14 14
15class Time final : public Module::Interface { 15class Time final : public Module::Interface {
16public: 16public:
17 explicit Time(std::shared_ptr<Module> time, Core::System& system, const char* name); 17 explicit Time(std::shared_ptr<Module> time, Core::System& system_, const char* name_);
18 ~Time() override; 18 ~Time() override;
19}; 19};
20 20
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 b9faa474e..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,21 +35,21 @@ 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& context) { 47ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) {
49 UNREACHABLE(); 48 UNREACHABLE();
50 return ERROR_NOT_IMPLEMENTED; 49 return ERROR_NOT_IMPLEMENTED;
51} 50}
52 51
53ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext& context) { 52ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) {
54 UNREACHABLE(); 53 UNREACHABLE();
55 return ERROR_NOT_IMPLEMENTED; 54 return ERROR_NOT_IMPLEMENTED;
56} 55}
@@ -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 aac44d72f..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;
@@ -39,7 +40,7 @@ public:
39 } 40 }
40 41
41protected: 42protected:
42 ResultCode Flush(const SystemClockContext& context) override; 43 ResultCode Flush(const SystemClockContext&) override;
43 44
44 ResultCode SetClockContext(const SystemClockContext&) override; 45 ResultCode SetClockContext(const SystemClockContext&) override;
45 46
@@ -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 d31d4e2ca..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
@@ -45,18 +45,18 @@ ResultCode SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time)
45 return Flush(clock_context); 45 return Flush(clock_context);
46} 46}
47 47
48ResultCode SystemClockCore::Flush(const SystemClockContext& context) { 48ResultCode SystemClockCore::Flush(const SystemClockContext& clock_context) {
49 if (!system_clock_context_update_callback) { 49 if (!system_clock_context_update_callback) {
50 return RESULT_SUCCESS; 50 return RESULT_SUCCESS;
51 } 51 }
52 return system_clock_context_update_callback->Update(context); 52 return system_clock_context_update_callback->Update(clock_context);
53} 53}
54 54
55ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& context) { 55ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& clock_context) {
56 if (const ResultCode result{SetClockContext(context)}; result != RESULT_SUCCESS) { 56 if (const ResultCode result{SetClockContext(clock_context)}; result != RESULT_SUCCESS) {
57 return result; 57 return result;
58 } 58 }
59 return Flush(context); 59 return Flush(clock_context);
60} 60}
61 61
62bool SystemClockCore::IsClockSetup(Core::System& system) const { 62bool SystemClockCore::IsClockSetup(Core::System& system) const {
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h
index 608dd3b2e..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 {
@@ -43,7 +43,7 @@ public:
43 return RESULT_SUCCESS; 43 return RESULT_SUCCESS;
44 } 44 }
45 45
46 virtual ResultCode Flush(const SystemClockContext& context); 46 virtual ResultCode Flush(const SystemClockContext& clock_context);
47 47
48 void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) { 48 void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) {
49 system_clock_context_update_callback = std::move(callback); 49 system_clock_context_update_callback = std::move(callback);
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 f89c5aaad..4f9684de8 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -129,7 +129,7 @@ struct TimeManager::Impl final {
129 return 0; 129 return 0;
130 } 130 }
131 131
132 void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, 132 void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id,
133 Clock::TimeSpanType setup_value, 133 Clock::TimeSpanType setup_value,
134 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { 134 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
135 standard_steady_clock_core.SetClockSourceId(clock_source_id); 135 standard_steady_clock_core.SetClockSourceId(clock_source_id);
@@ -137,21 +137,21 @@ struct TimeManager::Impl final {
137 standard_steady_clock_core.SetInternalOffset(internal_offset); 137 standard_steady_clock_core.SetInternalOffset(internal_offset);
138 standard_steady_clock_core.MarkAsInitialized(); 138 standard_steady_clock_core.MarkAsInitialized();
139 139
140 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)}; 140 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system_)};
141 shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point); 141 shared_memory.SetupStandardSteadyClock(clock_source_id, current_time_point);
142 } 142 }
143 143
144 void SetupStandardLocalSystemClock(Core::System& system, 144 void SetupStandardLocalSystemClock(Core::System& system_,
145 Clock::SystemClockContext clock_context, s64 posix_time) { 145 Clock::SystemClockContext clock_context, s64 posix_time) {
146 standard_local_system_clock_core.SetUpdateCallbackInstance( 146 standard_local_system_clock_core.SetUpdateCallbackInstance(
147 local_system_clock_context_writer); 147 local_system_clock_context_writer);
148 148
149 const auto current_time_point{ 149 const auto current_time_point{
150 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)}; 150 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system_)};
151 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { 151 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
152 standard_local_system_clock_core.SetSystemClockContext(clock_context); 152 standard_local_system_clock_core.SetSystemClockContext(clock_context);
153 } else { 153 } else {
154 if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != 154 if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) !=
155 RESULT_SUCCESS) { 155 RESULT_SUCCESS) {
156 UNREACHABLE(); 156 UNREACHABLE();
157 return; 157 return;
@@ -177,10 +177,10 @@ struct TimeManager::Impl final {
177 standard_network_system_clock_core.MarkAsInitialized(); 177 standard_network_system_clock_core.MarkAsInitialized();
178 } 178 }
179 179
180 void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled, 180 void SetupStandardUserSystemClock(Core::System& system_, bool is_automatic_correction_enabled,
181 Clock::SteadyClockTimePoint steady_clock_time_point) { 181 Clock::SteadyClockTimePoint steady_clock_time_point) {
182 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( 182 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
183 system, is_automatic_correction_enabled) != RESULT_SUCCESS) { 183 system_, is_automatic_correction_enabled) != RESULT_SUCCESS) {
184 UNREACHABLE(); 184 UNREACHABLE();
185 return; 185 return;
186 } 186 }
@@ -196,10 +196,10 @@ struct TimeManager::Impl final {
196 ephemeral_network_system_clock_core.MarkAsInitialized(); 196 ephemeral_network_system_clock_core.MarkAsInitialized();
197 } 197 }
198 198
199 void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) { 199 void UpdateLocalSystemClockTime(Core::System& system_, s64 posix_time) {
200 const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)}; 200 const auto timespan{Clock::TimeSpanType::FromSeconds(posix_time)};
201 if (GetStandardLocalSystemClockCore() 201 if (GetStandardLocalSystemClockCore()
202 .SetCurrentTime(system, timespan.ToSeconds()) 202 .SetCurrentTime(system_, timespan.ToSeconds())
203 .IsError()) { 203 .IsError()) {
204 UNREACHABLE(); 204 UNREACHABLE();
205 return; 205 return;
@@ -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 4d8de81be..176ad0eee 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -15,19 +15,13 @@ 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 { 24void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
26 return shared_memory_holder;
27}
28
29void SharedMemory::SetupStandardSteadyClock(Core::System& system,
30 const Common::UUID& clock_source_id,
31 Clock::TimeSpanType current_time_point) { 25 Clock::TimeSpanType current_time_point) {
32 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( 26 const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
33 system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; 27 system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)};
@@ -35,22 +29,22 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system,
35 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), 29 static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
36 clock_source_id}; 30 clock_source_id};
37 shared_memory_format.standard_steady_clock_timepoint.StoreData( 31 shared_memory_format.standard_steady_clock_timepoint.StoreData(
38 shared_memory_holder->GetPointer(), context); 32 system.Kernel().GetTimeSharedMem().GetPointer(), context);
39} 33}
40 34
41void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { 35void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
42 shared_memory_format.standard_local_system_clock_context.StoreData( 36 shared_memory_format.standard_local_system_clock_context.StoreData(
43 shared_memory_holder->GetPointer(), context); 37 system.Kernel().GetTimeSharedMem().GetPointer(), context);
44} 38}
45 39
46void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { 40void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
47 shared_memory_format.standard_network_system_clock_context.StoreData( 41 shared_memory_format.standard_network_system_clock_context.StoreData(
48 shared_memory_holder->GetPointer(), context); 42 system.Kernel().GetTimeSharedMem().GetPointer(), context);
49} 43}
50 44
51void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { 45void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
52 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( 46 shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
53 shared_memory_holder->GetPointer(), is_enabled); 47 system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled);
54} 48}
55 49
56} // 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 299680517..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 {
@@ -56,14 +53,13 @@ public:
56 }; 53 };
57 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); 54 static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
58 55
59 void SetupStandardSteadyClock(Core::System& system, const Common::UUID& clock_source_id, 56 void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
60 Clock::TimeSpanType currentTimePoint); 57 Clock::TimeSpanType current_time_point);
61 void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); 58 void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
62 void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); 59 void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
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 7f42aa4a0..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,32 +33,30 @@ 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 id, NVFlinger::BufferQueue& buffer_queue) { 44void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) {
45 // TODO(Subv): Support more than 1 layer. 45 // TODO(Subv): Support more than 1 layer.
46 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment"); 46 ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
47 47
48 layers.emplace_back(std::make_shared<Layer>(id, buffer_queue)); 48 layers.emplace_back(std::make_shared<Layer>(layer_id, buffer_queue));
49} 49}
50 50
51void Display::CloseLayer(u64 id) { 51void Display::CloseLayer(u64 layer_id) {
52 layers.erase( 52 std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; });
53 std::remove_if(layers.begin(), layers.end(),
54 [id](const std::shared_ptr<Layer>& layer) { return layer->GetID() == id; }),
55 layers.end());
56} 53}
57 54
58Layer* Display::FindLayer(u64 id) { 55Layer* Display::FindLayer(u64 layer_id) {
59 const auto itr = 56 const auto itr =
60 std::find_if(layers.begin(), layers.end(), 57 std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
61 [id](const std::shared_ptr<Layer>& layer) { return layer->GetID() == id; }); 58 return layer->GetID() == layer_id;
59 });
62 60
63 if (itr == layers.end()) { 61 if (itr == layers.end()) {
64 return nullptr; 62 return nullptr;
@@ -67,10 +65,11 @@ Layer* Display::FindLayer(u64 id) {
67 return itr->get(); 65 return itr->get();
68} 66}
69 67
70const Layer* Display::FindLayer(u64 id) const { 68const Layer* Display::FindLayer(u64 layer_id) const {
71 const auto itr = 69 const auto itr =
72 std::find_if(layers.begin(), layers.end(), 70 std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
73 [id](const std::shared_ptr<Layer>& layer) { return layer->GetID() == id; }); 71 return layer->GetID() == layer_id;
72 });
74 73
75 if (itr == layers.end()) { 74 if (itr == layers.end()) {
76 return nullptr; 75 return nullptr;
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 931c898f6..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,48 +59,48 @@ 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();
68 66
69 /// Creates and adds a layer to this display with the given ID. 67 /// Creates and adds a layer to this display with the given ID.
70 /// 68 ///
71 /// @param id The ID to assign to the created layer. 69 /// @param layer_id The ID to assign to the created layer.
72 /// @param buffer_queue The buffer queue for the layer instance to use. 70 /// @param buffer_queue The buffer queue for the layer instance to use.
73 /// 71 ///
74 void CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue); 72 void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue);
75 73
76 /// Closes and removes a layer from this display with the given ID. 74 /// Closes and removes a layer from this display with the given ID.
77 /// 75 ///
78 /// @param id The ID assigned to the layer to close. 76 /// @param layer_id The ID assigned to the layer to close.
79 /// 77 ///
80 void CloseLayer(u64 id); 78 void CloseLayer(u64 layer_id);
81 79
82 /// Attempts to find a layer with the given ID. 80 /// Attempts to find a layer with the given ID.
83 /// 81 ///
84 /// @param id The layer ID. 82 /// @param layer_id The layer ID.
85 /// 83 ///
86 /// @returns If found, the Layer instance with the given ID. 84 /// @returns If found, the Layer instance with the given ID.
87 /// If not found, then nullptr is returned. 85 /// If not found, then nullptr is returned.
88 /// 86 ///
89 Layer* FindLayer(u64 id); 87 Layer* FindLayer(u64 layer_id);
90 88
91 /// Attempts to find a layer with the given ID. 89 /// Attempts to find a layer with the given ID.
92 /// 90 ///
93 /// @param id The layer ID. 91 /// @param layer_id The layer ID.
94 /// 92 ///
95 /// @returns If found, the Layer instance with the given ID. 93 /// @returns If found, the Layer instance with the given ID.
96 /// If not found, then nullptr is returned. 94 /// If not found, then nullptr is returned.
97 /// 95 ///
98 const Layer* FindLayer(u64 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 4a10211f6..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,12 +22,12 @@
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 dir = file->GetContainingDirectory(); 27 const auto file_dir = file->GetContainingDirectory();
28 28
29 // Title ID 29 // Title ID
30 const auto npdm = dir->GetFile("main.npdm"); 30 const auto npdm = file_dir->GetFile("main.npdm");
31 if (npdm != nullptr) { 31 if (npdm != nullptr) {
32 const auto res = metadata.Load(npdm); 32 const auto res = metadata.Load(npdm);
33 if (res == ResultStatus::Success) 33 if (res == ResultStatus::Success)
@@ -37,7 +37,7 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
37 // Icon 37 // Icon
38 FileSys::VirtualFile icon_file = nullptr; 38 FileSys::VirtualFile icon_file = nullptr;
39 for (const auto& language : FileSys::LANGUAGE_NAMES) { 39 for (const auto& language : FileSys::LANGUAGE_NAMES) {
40 icon_file = dir->GetFile("icon_" + std::string(language) + ".dat"); 40 icon_file = file_dir->GetFile("icon_" + std::string(language) + ".dat");
41 if (icon_file != nullptr) { 41 if (icon_file != nullptr) {
42 icon_data = icon_file->ReadAllBytes(); 42 icon_data = icon_file->ReadAllBytes();
43 break; 43 break;
@@ -46,24 +46,23 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
46 46
47 if (icon_data.empty()) { 47 if (icon_data.empty()) {
48 // Any png, jpeg, or bmp file 48 // Any png, jpeg, or bmp file
49 const auto& files = 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();
57 } 57 }
58 58
59 // Metadata 59 // Metadata
60 FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp"); 60 FileSys::VirtualFile nacp_file = file_dir->GetFile("control.nacp");
61 if (nacp_file == nullptr) { 61 if (nacp_file == nullptr) {
62 const auto& files = 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,12 +74,12 @@ 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& file) { 81FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
83 if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) { 82 if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
84 return FileType::DeconstructedRomDirectory; 83 return FileType::DeconstructedRomDirectory;
85 } 84 }
86 85
@@ -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
@@ -200,17 +199,21 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
200 LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}}; 199 LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}};
201} 200}
202 201
203ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) { 202ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& out_dir) {
204 if (romfs == nullptr) 203 if (romfs == nullptr) {
205 return ResultStatus::ErrorNoRomFS; 204 return ResultStatus::ErrorNoRomFS;
206 dir = romfs; 205 }
206
207 out_dir = romfs;
207 return ResultStatus::Success; 208 return ResultStatus::Success;
208} 209}
209 210
210ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { 211ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& out_buffer) {
211 if (icon_data.empty()) 212 if (icon_data.empty()) {
212 return ResultStatus::ErrorNoIcon; 213 return ResultStatus::ErrorNoIcon;
213 buffer = icon_data; 214 }
215
216 out_buffer = icon_data;
214 return ResultStatus::Success; 217 return ResultStatus::Success;
215} 218}
216 219
@@ -219,10 +222,12 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program
219 return ResultStatus::Success; 222 return ResultStatus::Success;
220} 223}
221 224
222ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { 225ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& out_title) {
223 if (name.empty()) 226 if (name.empty()) {
224 return ResultStatus::ErrorNoControl; 227 return ResultStatus::ErrorNoControl;
225 title = name; 228 }
229
230 out_title = name;
226 return ResultStatus::Success; 231 return ResultStatus::Success;
227} 232}
228 233
@@ -230,12 +235,12 @@ bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() const {
230 return false; 235 return false;
231} 236}
232 237
233ResultStatus AppLoader_DeconstructedRomDirectory::ReadNSOModules(Modules& modules) { 238ResultStatus AppLoader_DeconstructedRomDirectory::ReadNSOModules(Modules& out_modules) {
234 if (!is_loaded) { 239 if (!is_loaded) {
235 return ResultStatus::ErrorNotInitialized; 240 return ResultStatus::ErrorNotInitialized;
236 } 241 }
237 242
238 modules = this->modules; 243 out_modules = this->modules;
239 return ResultStatus::Success; 244 return ResultStatus::Success;
240} 245}
241 246
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 3c968580f..79a4d4db5 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -24,32 +24,35 @@ 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 * Returns the type of the file 34 * Identifies whether or not the given file is a deconstructed ROM directory.
35 * @param file open file 35 *
36 * @return FileType found, or FileType::Error if this loader doesn't know it 36 * @param dir_file The file to verify.
37 *
38 * @return FileType::DeconstructedRomDirectory, or FileType::Error
39 * if the file is not a deconstructed ROM directory.
37 */ 40 */
38 static FileType IdentifyType(const FileSys::VirtualFile& file); 41 static FileType IdentifyType(const FileSys::VirtualFile& dir_file);
39 42
40 FileType GetFileType() const override { 43 FileType GetFileType() const override {
41 return IdentifyType(file); 44 return IdentifyType(file);
42 } 45 }
43 46
44 LoadResult Load(Kernel::Process& process, Core::System& system) override; 47 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
45 48
46 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 49 ResultStatus ReadRomFS(FileSys::VirtualFile& out_dir) override;
47 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 50 ResultStatus ReadIcon(std::vector<u8>& out_buffer) override;
48 ResultStatus ReadProgramId(u64& out_program_id) override; 51 ResultStatus ReadProgramId(u64& out_program_id) override;
49 ResultStatus ReadTitle(std::string& title) override; 52 ResultStatus ReadTitle(std::string& title) override;
50 bool IsRomFSUpdatable() const override; 53 bool IsRomFSUpdatable() const override;
51 54
52 ResultStatus ReadNSOModules(Modules& modules) override; 55 ResultStatus ReadNSOModules(Modules& out_modules) override;
53 56
54private: 57private:
55 FileSys::ProgramMetadata metadata; 58 FileSys::ProgramMetadata metadata;
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index f4a339390..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
@@ -364,26 +364,29 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const
364 364
365namespace Loader { 365namespace Loader {
366 366
367AppLoader_ELF::AppLoader_ELF(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} 367AppLoader_ELF::AppLoader_ELF(FileSys::VirtualFile file_) : AppLoader(std::move(file_)) {}
368 368
369FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) { 369FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& elf_file) {
370 static constexpr u16 ELF_MACHINE_ARM{0x28}; 370 static constexpr u16 ELF_MACHINE_ARM{0x28};
371 371
372 u32 magic = 0; 372 u32 magic = 0;
373 if (4 != file->ReadObject(&magic)) 373 if (4 != elf_file->ReadObject(&magic)) {
374 return FileType::Error; 374 return FileType::Error;
375 }
375 376
376 u16 machine = 0; 377 u16 machine = 0;
377 if (2 != file->ReadObject(&machine, 18)) 378 if (2 != elf_file->ReadObject(&machine, 18)) {
378 return FileType::Error; 379 return FileType::Error;
380 }
379 381
380 if (Common::MakeMagic('\x7f', 'E', 'L', 'F') == magic && ELF_MACHINE_ARM == machine) 382 if (Common::MakeMagic('\x7f', 'E', 'L', 'F') == magic && ELF_MACHINE_ARM == machine) {
381 return FileType::ELF; 383 return FileType::ELF;
384 }
382 385
383 return FileType::Error; 386 return FileType::Error;
384} 387}
385 388
386AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process, 389AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::KProcess& process,
387 [[maybe_unused]] Core::System& system) { 390 [[maybe_unused]] Core::System& system) {
388 if (is_loaded) { 391 if (is_loaded) {
389 return {ResultStatus::ErrorAlreadyLoaded, {}}; 392 return {ResultStatus::ErrorAlreadyLoaded, {}};
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 2067932c7..890299a20 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -20,17 +20,19 @@ public:
20 explicit AppLoader_ELF(FileSys::VirtualFile file); 20 explicit AppLoader_ELF(FileSys::VirtualFile file);
21 21
22 /** 22 /**
23 * Returns the type of the file 23 * Identifies whether or not the given file is an ELF file.
24 * @param file open file 24 *
25 * @return FileType found, or FileType::Error if this loader doesn't know it 25 * @param elf_file The file to identify.
26 *
27 * @return FileType::ELF, or FileType::Error if the file is not an ELF file.
26 */ 28 */
27 static FileType IdentifyType(const FileSys::VirtualFile& file); 29 static FileType IdentifyType(const FileSys::VirtualFile& elf_file);
28 30
29 FileType GetFileType() const override { 31 FileType GetFileType() const override {
30 return IdentifyType(file); 32 return IdentifyType(file);
31 } 33 }
32 34
33 LoadResult Load(Kernel::Process& process, Core::System& system) override; 35 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
34}; 36};
35 37
36} // namespace Loader 38} // namespace Loader
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 55e6de794..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
@@ -24,9 +24,9 @@ AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
24 24
25AppLoader_KIP::~AppLoader_KIP() = default; 25AppLoader_KIP::~AppLoader_KIP() = default;
26 26
27FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& file) { 27FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& in_file) {
28 u32_le magic{}; 28 u32_le magic{};
29 if (file->GetSize() < sizeof(u32) || file->ReadObject(&magic) != sizeof(u32)) { 29 if (in_file->GetSize() < sizeof(u32) || in_file->ReadObject(&magic) != sizeof(u32)) {
30 return FileType::Error; 30 return FileType::Error;
31 } 31 }
32 32
@@ -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, {}};
@@ -56,10 +56,10 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,
56 return {kip->GetStatus(), {}}; 56 return {kip->GetStatus(), {}};
57 } 57 }
58 58
59 const auto get_kip_address_space_type = [](const auto& kip) { 59 const auto get_kip_address_space_type = [](const auto& kip_type) {
60 return kip.Is64Bit() 60 return kip_type.Is64Bit()
61 ? (kip.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit 61 ? (kip_type.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit
62 : FileSys::ProgramAddressSpaceType::Is36Bit) 62 : FileSys::ProgramAddressSpaceType::Is36Bit)
63 : FileSys::ProgramAddressSpaceType::Is32Bit; 63 : FileSys::ProgramAddressSpaceType::Is32Bit;
64 }; 64 };
65 65
diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h
index 14a85e295..5f914b4a8 100644
--- a/src/core/loader/kip.h
+++ b/src/core/loader/kip.h
@@ -22,15 +22,17 @@ public:
22 ~AppLoader_KIP() override; 22 ~AppLoader_KIP() override;
23 23
24 /** 24 /**
25 * Returns the type of the file 25 * Identifies whether or not the given file is a KIP.
26 * @param file open file 26 *
27 * @return FileType found, or FileType::Error if this loader doesn't know it 27 * @param in_file The file to identify.
28 *
29 * @return FileType::KIP if found, or FileType::Error if unknown.
28 */ 30 */
29 static FileType IdentifyType(const FileSys::VirtualFile& file); 31 static FileType IdentifyType(const FileSys::VirtualFile& in_file);
30 32
31 FileType GetFileType() const override; 33 FileType GetFileType() const override;
32 34
33 LoadResult Load(Kernel::Process& process, Core::System& system) override; 35 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
34 36
35private: 37private:
36 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 b2e5b13de..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,26 +147,31 @@ 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 /**
154 * Returns the type of this file 154 * Returns the type of this file
155 *
155 * @return FileType corresponding to the loaded file 156 * @return FileType corresponding to the loaded file
156 */ 157 */
157 virtual FileType GetFileType() const = 0; 158 virtual FileType GetFileType() const = 0;
158 159
159 /** 160 /**
160 * Load the application and return the created Process instance 161 * Load the application and return the created Process instance
162 *
161 * @param process The newly created process. 163 * @param process The newly created process.
162 * @param system The system that this process is being loaded under. 164 * @param system The system that this process is being loaded under.
165 *
163 * @return The status result of the operation. 166 * @return The status result of the operation.
164 */ 167 */
165 virtual LoadResult Load(Kernel::Process& process, Core::System& system) = 0; 168 virtual LoadResult Load(Kernel::KProcess& process, Core::System& system) = 0;
166 169
167 /** 170 /**
168 * Get the code (typically .code section) of the application 171 * Get the code (typically .code section) of the application
169 * @param buffer Reference to buffer to store data 172 *
173 * @param[out] buffer Reference to buffer to store data
174 *
170 * @return ResultStatus result of function 175 * @return ResultStatus result of function
171 */ 176 */
172 virtual ResultStatus ReadCode(std::vector<u8>& buffer) { 177 virtual ResultStatus ReadCode(std::vector<u8>& buffer) {
@@ -175,7 +180,9 @@ public:
175 180
176 /** 181 /**
177 * Get the icon (typically icon section) of the application 182 * Get the icon (typically icon section) of the application
178 * @param buffer Reference to buffer to store data 183 *
184 * @param[out] buffer Reference to buffer to store data
185 *
179 * @return ResultStatus result of function 186 * @return ResultStatus result of function
180 */ 187 */
181 virtual ResultStatus ReadIcon(std::vector<u8>& buffer) { 188 virtual ResultStatus ReadIcon(std::vector<u8>& buffer) {
@@ -186,7 +193,9 @@ public:
186 * Get the banner (typically banner section) of the application 193 * Get the banner (typically banner section) of the application
187 * In the context of NX, this is the animation that displays in the bottom right of the screen 194 * In the context of NX, this is the animation that displays in the bottom right of the screen
188 * when a game boots. Stored in GIF format. 195 * when a game boots. Stored in GIF format.
189 * @param buffer Reference to buffer to store data 196 *
197 * @param[out] buffer Reference to buffer to store data
198 *
190 * @return ResultStatus result of function 199 * @return ResultStatus result of function
191 */ 200 */
192 virtual ResultStatus ReadBanner(std::vector<u8>& buffer) { 201 virtual ResultStatus ReadBanner(std::vector<u8>& buffer) {
@@ -197,7 +206,9 @@ public:
197 * Get the logo (typically logo section) of the application 206 * Get the logo (typically logo section) of the application
198 * In the context of NX, this is the static image that displays in the top left of the screen 207 * In the context of NX, this is the static image that displays in the top left of the screen
199 * when a game boots. Stored in JPEG format. 208 * when a game boots. Stored in JPEG format.
200 * @param buffer Reference to buffer to store data 209 *
210 * @param[out] buffer Reference to buffer to store data
211 *
201 * @return ResultStatus result of function 212 * @return ResultStatus result of function
202 */ 213 */
203 virtual ResultStatus ReadLogo(std::vector<u8>& buffer) { 214 virtual ResultStatus ReadLogo(std::vector<u8>& buffer) {
@@ -206,7 +217,9 @@ public:
206 217
207 /** 218 /**
208 * Get the program id of the application 219 * Get the program id of the application
209 * @param out_program_id Reference to store program id into 220 *
221 * @param[out] out_program_id Reference to store program id into
222 *
210 * @return ResultStatus result of function 223 * @return ResultStatus result of function
211 */ 224 */
212 virtual ResultStatus ReadProgramId(u64& out_program_id) { 225 virtual ResultStatus ReadProgramId(u64& out_program_id) {
@@ -216,19 +229,23 @@ public:
216 /** 229 /**
217 * Get the RomFS of the application 230 * Get the RomFS of the application
218 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer 231 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
219 * @param file The directory containing the RomFS 232 *
233 * @param[out] out_file The directory containing the RomFS
234 *
220 * @return ResultStatus result of function 235 * @return ResultStatus result of function
221 */ 236 */
222 virtual ResultStatus ReadRomFS(FileSys::VirtualFile& file) { 237 virtual ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) {
223 return ResultStatus::ErrorNotImplemented; 238 return ResultStatus::ErrorNotImplemented;
224 } 239 }
225 240
226 /** 241 /**
227 * Get the raw update of the application, should it come packed with one 242 * Get the raw update of the application, should it come packed with one
228 * @param file The raw update NCA file (Program-type 243 *
244 * @param[out] out_file The raw update NCA file (Program-type)
245 *
229 * @return ResultStatus result of function 246 * @return ResultStatus result of function
230 */ 247 */
231 virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) { 248 virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) {
232 return ResultStatus::ErrorNotImplemented; 249 return ResultStatus::ErrorNotImplemented;
233 } 250 }
234 251
@@ -236,7 +253,8 @@ public:
236 * Get whether or not updates can be applied to the RomFS. 253 * Get whether or not updates can be applied to the RomFS.
237 * By default, this is true, however for formats where it cannot be guaranteed that the RomFS is 254 * By default, this is true, however for formats where it cannot be guaranteed that the RomFS is
238 * the base game it should be set to false. 255 * the base game it should be set to false.
239 * @return bool whether or not updatable. 256 *
257 * @return bool indicating whether or not the RomFS is updatable.
240 */ 258 */
241 virtual bool IsRomFSUpdatable() const { 259 virtual bool IsRomFSUpdatable() const {
242 return true; 260 return true;
@@ -244,8 +262,9 @@ public:
244 262
245 /** 263 /**
246 * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS) 264 * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS)
247 * data. Needed for bktr patching. 265 * data. Needed for BKTR patching.
248 * @return IVFC offset for romfs. 266 *
267 * @return IVFC offset for RomFS.
249 */ 268 */
250 virtual u64 ReadRomFSIVFCOffset() const { 269 virtual u64 ReadRomFSIVFCOffset() const {
251 return 0; 270 return 0;
@@ -253,7 +272,9 @@ public:
253 272
254 /** 273 /**
255 * Get the title of the application 274 * Get the title of the application
256 * @param title Reference to store the application title into 275 *
276 * @param[out] title Reference to store the application title into
277 *
257 * @return ResultStatus result of function 278 * @return ResultStatus result of function
258 */ 279 */
259 virtual ResultStatus ReadTitle(std::string& title) { 280 virtual ResultStatus ReadTitle(std::string& title) {
@@ -262,7 +283,9 @@ public:
262 283
263 /** 284 /**
264 * Get the control data (CNMT) of the application 285 * Get the control data (CNMT) of the application
265 * @param control Reference to store the application control data into 286 *
287 * @param[out] control Reference to store the application control data into
288 *
266 * @return ResultStatus result of function 289 * @return ResultStatus result of function
267 */ 290 */
268 virtual ResultStatus ReadControlData(FileSys::NACP& control) { 291 virtual ResultStatus ReadControlData(FileSys::NACP& control) {
@@ -271,10 +294,12 @@ public:
271 294
272 /** 295 /**
273 * Get the RomFS of the manual of the application 296 * Get the RomFS of the manual of the application
274 * @param file The raw manual RomFS of the game 297 *
298 * @param[out] out_file The raw manual RomFS of the game
299 *
275 * @return ResultStatus result of function 300 * @return ResultStatus result of function
276 */ 301 */
277 virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) { 302 virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) {
278 return ResultStatus::ErrorNotImplemented; 303 return ResultStatus::ErrorNotImplemented;
279 } 304 }
280 305
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index 49028177b..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
@@ -26,14 +26,14 @@ FileType IdentifyTypeImpl(const FileSys::NAX& nax) {
26} 26}
27} // Anonymous namespace 27} // Anonymous namespace
28 28
29AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) 29AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file_)
30 : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)), 30 : AppLoader(file_), nax(std::make_unique<FileSys::NAX>(file_)),
31 nca_loader(std::make_unique<AppLoader_NCA>(nax->GetDecrypted())) {} 31 nca_loader(std::make_unique<AppLoader_NCA>(nax->GetDecrypted())) {}
32 32
33AppLoader_NAX::~AppLoader_NAX() = default; 33AppLoader_NAX::~AppLoader_NAX() = default;
34 34
35FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { 35FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& nax_file) {
36 const FileSys::NAX nax(file); 36 const FileSys::NAX nax(nax_file);
37 return IdentifyTypeImpl(nax); 37 return IdentifyTypeImpl(nax);
38} 38}
39 39
@@ -41,8 +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, 44AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::KProcess& process, Core::System& system) {
45 [[maybe_unused]] Core::System& system) {
46 if (is_loaded) { 45 if (is_loaded) {
47 return {ResultStatus::ErrorAlreadyLoaded, {}}; 46 return {ResultStatus::ErrorAlreadyLoaded, {}};
48 } 47 }
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index a5b5e2ae1..b3a50894f 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -23,19 +23,21 @@ class AppLoader_NCA;
23/// Loads a NAX file 23/// Loads a NAX file
24class AppLoader_NAX final : public AppLoader { 24class AppLoader_NAX final : public AppLoader {
25public: 25public:
26 explicit AppLoader_NAX(FileSys::VirtualFile file); 26 explicit AppLoader_NAX(FileSys::VirtualFile file_);
27 ~AppLoader_NAX() override; 27 ~AppLoader_NAX() override;
28 28
29 /** 29 /**
30 * Returns the type of the file 30 * Identifies whether or not the given file is a NAX file.
31 * @param file open file 31 *
32 * @return FileType found, or FileType::Error if this loader doesn't know it 32 * @param nax_file The file to identify.
33 *
34 * @return FileType::NAX, or FileType::Error if the file is not a NAX file.
33 */ 35 */
34 static FileType IdentifyType(const FileSys::VirtualFile& file); 36 static FileType IdentifyType(const FileSys::VirtualFile& nax_file);
35 37
36 FileType GetFileType() const override; 38 FileType GetFileType() const override;
37 39
38 LoadResult Load(Kernel::Process& process, Core::System& system) override; 40 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
39 41
40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 42 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
41 u64 ReadRomFSIVFCOffset() const override; 43 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index fa694de37..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"
@@ -21,17 +21,18 @@ AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_)
21 21
22AppLoader_NCA::~AppLoader_NCA() = default; 22AppLoader_NCA::~AppLoader_NCA() = default;
23 23
24FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) { 24FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& nca_file) {
25 FileSys::NCA nca(file); 25 const FileSys::NCA nca(nca_file);
26 26
27 if (nca.GetStatus() == ResultStatus::Success && 27 if (nca.GetStatus() == ResultStatus::Success &&
28 nca.GetType() == FileSys::NCAContentType::Program) 28 nca.GetType() == FileSys::NCAContentType::Program) {
29 return FileType::NCA; 29 return FileType::NCA;
30 }
30 31
31 return FileType::Error; 32 return FileType::Error;
32} 33}
33 34
34AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::System& system) { 35AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::System& system) {
35 if (is_loaded) { 36 if (is_loaded) {
36 return {ResultStatus::ErrorAlreadyLoaded, {}}; 37 return {ResultStatus::ErrorAlreadyLoaded, {}};
37 } 38 }
@@ -67,43 +68,59 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::Sy
67} 68}
68 69
69ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { 70ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
70 if (nca == nullptr) 71 if (nca == nullptr) {
71 return ResultStatus::ErrorNotInitialized; 72 return ResultStatus::ErrorNotInitialized;
72 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0) 73 }
74
75 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0) {
73 return ResultStatus::ErrorNoRomFS; 76 return ResultStatus::ErrorNoRomFS;
77 }
78
74 dir = nca->GetRomFS(); 79 dir = nca->GetRomFS();
75 return ResultStatus::Success; 80 return ResultStatus::Success;
76} 81}
77 82
78u64 AppLoader_NCA::ReadRomFSIVFCOffset() const { 83u64 AppLoader_NCA::ReadRomFSIVFCOffset() const {
79 if (nca == nullptr) 84 if (nca == nullptr) {
80 return 0; 85 return 0;
86 }
87
81 return nca->GetBaseIVFCOffset(); 88 return nca->GetBaseIVFCOffset();
82} 89}
83 90
84ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { 91ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
85 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) 92 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
86 return ResultStatus::ErrorNotInitialized; 93 return ResultStatus::ErrorNotInitialized;
94 }
95
87 out_program_id = nca->GetTitleId(); 96 out_program_id = nca->GetTitleId();
88 return ResultStatus::Success; 97 return ResultStatus::Success;
89} 98}
90 99
91ResultStatus AppLoader_NCA::ReadBanner(std::vector<u8>& buffer) { 100ResultStatus AppLoader_NCA::ReadBanner(std::vector<u8>& buffer) {
92 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) 101 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
93 return ResultStatus::ErrorNotInitialized; 102 return ResultStatus::ErrorNotInitialized;
103 }
104
94 const auto logo = nca->GetLogoPartition(); 105 const auto logo = nca->GetLogoPartition();
95 if (logo == nullptr) 106 if (logo == nullptr) {
96 return ResultStatus::ErrorNoIcon; 107 return ResultStatus::ErrorNoIcon;
108 }
109
97 buffer = logo->GetFile("StartupMovie.gif")->ReadAllBytes(); 110 buffer = logo->GetFile("StartupMovie.gif")->ReadAllBytes();
98 return ResultStatus::Success; 111 return ResultStatus::Success;
99} 112}
100 113
101ResultStatus AppLoader_NCA::ReadLogo(std::vector<u8>& buffer) { 114ResultStatus AppLoader_NCA::ReadLogo(std::vector<u8>& buffer) {
102 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) 115 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
103 return ResultStatus::ErrorNotInitialized; 116 return ResultStatus::ErrorNotInitialized;
117 }
118
104 const auto logo = nca->GetLogoPartition(); 119 const auto logo = nca->GetLogoPartition();
105 if (logo == nullptr) 120 if (logo == nullptr) {
106 return ResultStatus::ErrorNoIcon; 121 return ResultStatus::ErrorNoIcon;
122 }
123
107 buffer = logo->GetFile("NintendoLogo.png")->ReadAllBytes(); 124 buffer = logo->GetFile("NintendoLogo.png")->ReadAllBytes();
108 return ResultStatus::Success; 125 return ResultStatus::Success;
109} 126}
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 918792800..f2ff080bb 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -23,21 +23,23 @@ class AppLoader_DeconstructedRomDirectory;
23/// Loads an NCA file 23/// Loads an NCA file
24class AppLoader_NCA final : public AppLoader { 24class AppLoader_NCA final : public AppLoader {
25public: 25public:
26 explicit AppLoader_NCA(FileSys::VirtualFile file); 26 explicit AppLoader_NCA(FileSys::VirtualFile file_);
27 ~AppLoader_NCA() override; 27 ~AppLoader_NCA() override;
28 28
29 /** 29 /**
30 * Returns the type of the file 30 * Identifies whether or not the given file is an NCA file.
31 * @param file open file 31 *
32 * @return FileType found, or FileType::Error if this loader doesn't know it 32 * @param nca_file The file to identify.
33 *
34 * @return FileType::NCA, or FileType::Error if the file is not an NCA file.
33 */ 35 */
34 static FileType IdentifyType(const FileSys::VirtualFile& file); 36 static FileType IdentifyType(const FileSys::VirtualFile& nca_file);
35 37
36 FileType GetFileType() const override { 38 FileType GetFileType() const override {
37 return IdentifyType(file); 39 return IdentifyType(file);
38 } 40 }
39 41
40 LoadResult Load(Kernel::Process& process, Core::System& system) override; 42 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
41 43
42 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 44 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
43 u64 ReadRomFSIVFCOffset() const override; 45 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 0115ed0c4..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"
@@ -72,7 +72,7 @@ struct AssetHeader {
72}; 72};
73static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size."); 73static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size.");
74 74
75AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) { 75AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file_) : AppLoader(std::move(file_)) {
76 NroHeader nro_header{}; 76 NroHeader nro_header{};
77 if (file->ReadObject(&nro_header) != sizeof(NroHeader)) { 77 if (file->ReadObject(&nro_header) != sizeof(NroHeader)) {
78 return; 78 return;
@@ -114,10 +114,10 @@ AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) {
114 114
115AppLoader_NRO::~AppLoader_NRO() = default; 115AppLoader_NRO::~AppLoader_NRO() = default;
116 116
117FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) { 117FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
118 // Read NSO header 118 // Read NSO header
119 NroHeader nro_header{}; 119 NroHeader nro_header{};
120 if (sizeof(NroHeader) != file->ReadObject(&nro_header)) { 120 if (sizeof(NroHeader) != nro_file->ReadObject(&nro_header)) {
121 return FileType::Error; 121 return FileType::Error;
122 } 122 }
123 if (nro_header.magic == Common::MakeMagic('N', 'R', 'O', '0')) { 123 if (nro_header.magic == Common::MakeMagic('N', 'R', 'O', '0')) {
@@ -130,8 +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 const std::string& name) {
135 if (data.size() < sizeof(NroHeader)) { 134 if (data.size() < sizeof(NroHeader)) {
136 return {}; 135 return {};
137 } 136 }
@@ -200,11 +199,11 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
200 return true; 199 return true;
201} 200}
202 201
203bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file) { 202bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) {
204 return LoadNroImpl(process, file.ReadAllBytes(), file.GetName()); 203 return LoadNroImpl(process, nro_file.ReadAllBytes());
205} 204}
206 205
207AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::System& system) { 206AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) {
208 if (is_loaded) { 207 if (is_loaded) {
209 return {ResultStatus::ErrorAlreadyLoaded, {}}; 208 return {ResultStatus::ErrorAlreadyLoaded, {}};
210 } 209 }
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index a82b66221..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 {
@@ -27,21 +27,23 @@ namespace Loader {
27/// Loads an NRO file 27/// Loads an NRO file
28class AppLoader_NRO final : public AppLoader { 28class AppLoader_NRO final : public AppLoader {
29public: 29public:
30 explicit AppLoader_NRO(FileSys::VirtualFile file); 30 explicit AppLoader_NRO(FileSys::VirtualFile file_);
31 ~AppLoader_NRO() override; 31 ~AppLoader_NRO() override;
32 32
33 /** 33 /**
34 * Returns the type of the file 34 * Identifies whether or not the given file is an NRO file.
35 * @param file open file 35 *
36 * @return FileType found, or FileType::Error if this loader doesn't know it 36 * @param nro_file The file to identify.
37 *
38 * @return FileType::NRO, or FileType::Error if the file is not an NRO file.
37 */ 39 */
38 static FileType IdentifyType(const FileSys::VirtualFile& file); 40 static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
39 41
40 FileType GetFileType() const override { 42 FileType GetFileType() const override {
41 return IdentifyType(file); 43 return IdentifyType(file);
42 } 44 }
43 45
44 LoadResult Load(Kernel::Process& process, Core::System& system) override; 46 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
45 47
46 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 48 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
47 ResultStatus ReadProgramId(u64& out_program_id) override; 49 ResultStatus ReadProgramId(u64& out_program_id) override;
@@ -51,7 +53,7 @@ public:
51 bool IsRomFSUpdatable() const override; 53 bool IsRomFSUpdatable() const override;
52 54
53private: 55private:
54 bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file); 56 bool LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file);
55 57
56 std::vector<u8> icon_data; 58 std::vector<u8> icon_data;
57 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 0c83dd666..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
@@ -56,11 +56,11 @@ bool NSOHeader::IsSegmentCompressed(size_t segment_num) const {
56 return ((flags >> segment_num) & 1) != 0; 56 return ((flags >> segment_num) & 1) != 0;
57} 57}
58 58
59AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} 59AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file_) : AppLoader(std::move(file_)) {}
60 60
61FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) { 61FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) {
62 u32 magic = 0; 62 u32 magic = 0;
63 if (file->ReadObject(&magic) != sizeof(magic)) { 63 if (in_file->ReadObject(&magic) != sizeof(magic)) {
64 return FileType::Error; 64 return FileType::Error;
65 } 65 }
66 66
@@ -71,16 +71,16 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& 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& 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) {
78 if (file.GetSize() < sizeof(NSOHeader)) { 78 if (nso_file.GetSize() < sizeof(NSOHeader)) {
79 return std::nullopt; 79 return std::nullopt;
80 } 80 }
81 81
82 NSOHeader nso_header{}; 82 NSOHeader nso_header{};
83 if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) { 83 if (sizeof(NSOHeader) != nso_file.ReadObject(&nso_header)) {
84 return std::nullopt; 84 return std::nullopt;
85 } 85 }
86 86
@@ -92,8 +92,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
92 Kernel::CodeSet codeset; 92 Kernel::CodeSet codeset;
93 Kernel::PhysicalMemory program_image; 93 Kernel::PhysicalMemory program_image;
94 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { 94 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
95 std::vector<u8> data = 95 std::vector<u8> data = nso_file.ReadBytes(nso_header.segments_compressed_size[i],
96 file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); 96 nso_header.segments[i].offset);
97 if (nso_header.IsSegmentCompressed(i)) { 97 if (nso_header.IsSegmentCompressed(i)) {
98 data = DecompressSegment(data, nso_header.segments[i]); 98 data = DecompressSegment(data, nso_header.segments[i]);
99 } 99 }
@@ -136,7 +136,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
136 pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(), 136 pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(),
137 program_image.data() + program_image.size()); 137 program_image.data() + program_image.size());
138 138
139 pi_header = pm->PatchNSO(pi_header, file.GetName()); 139 pi_header = pm->PatchNSO(pi_header, nso_file.GetName());
140 140
141 std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data()); 141 std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
142 } 142 }
@@ -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 }
@@ -183,8 +183,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::Sy
183 Core::Memory::DEFAULT_STACK_SIZE}}; 183 Core::Memory::DEFAULT_STACK_SIZE}};
184} 184}
185 185
186ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) { 186ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
187 modules = this->modules; 187 out_modules = this->modules;
188 return ResultStatus::Success; 188 return ResultStatus::Success;
189} 189}
190 190
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 3af461b5f..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 {
@@ -71,27 +71,29 @@ static_assert(sizeof(NSOArgumentHeader) == 0x20, "NSOArgumentHeader has incorrec
71/// Loads an NSO file 71/// Loads an NSO file
72class AppLoader_NSO final : public AppLoader { 72class AppLoader_NSO final : public AppLoader {
73public: 73public:
74 explicit AppLoader_NSO(FileSys::VirtualFile file); 74 explicit AppLoader_NSO(FileSys::VirtualFile file_);
75 75
76 /** 76 /**
77 * Returns the type of the file 77 * Identifies whether or not the given file is a form of NSO file.
78 * @param file open file 78 *
79 * @return FileType found, or FileType::Error if this loader doesn't know it 79 * @param in_file The file to be identified.
80 *
81 * @return FileType::NSO if found, or FileType::Error if some other type of file.
80 */ 82 */
81 static FileType IdentifyType(const FileSys::VirtualFile& file); 83 static FileType IdentifyType(const FileSys::VirtualFile& in_file);
82 84
83 FileType GetFileType() const override { 85 FileType GetFileType() const override {
84 return IdentifyType(file); 86 return IdentifyType(file);
85 } 87 }
86 88
87 static std::optional<VAddr> LoadModule(Kernel::Process& process, Core::System& system, 89 static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system,
88 const FileSys::VfsFile& file, VAddr load_base, 90 const FileSys::VfsFile& nso_file, VAddr load_base,
89 bool should_pass_arguments, bool load_into_process, 91 bool should_pass_arguments, bool load_into_process,
90 std::optional<FileSys::PatchManager> pm = {}); 92 std::optional<FileSys::PatchManager> pm = {});
91 93
92 LoadResult Load(Kernel::Process& process, Core::System& system) override; 94 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
93 95
94 ResultStatus ReadNSOModules(Modules& modules) override; 96 ResultStatus ReadNSOModules(Modules& out_modules) override;
95 97
96private: 98private:
97 Modules modules; 99 Modules modules;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 928f64c8c..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"
@@ -21,11 +21,11 @@
21 21
22namespace Loader { 22namespace Loader {
23 23
24AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, 24AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
25 const Service::FileSystem::FileSystemController& fsc, 25 const Service::FileSystem::FileSystemController& fsc,
26 const FileSys::ContentProvider& content_provider, 26 const FileSys::ContentProvider& content_provider,
27 std::size_t program_index) 27 std::size_t program_index)
28 : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)), 28 : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)),
29 title_id(nsp->GetProgramTitleID()) { 29 title_id(nsp->GetProgramTitleID()) {
30 30
31 if (nsp->GetStatus() != ResultStatus::Success) { 31 if (nsp->GetStatus() != ResultStatus::Success) {
@@ -57,8 +57,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
57 57
58AppLoader_NSP::~AppLoader_NSP() = default; 58AppLoader_NSP::~AppLoader_NSP() = default;
59 59
60FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { 60FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) {
61 FileSys::NSP nsp(file); 61 const FileSys::NSP nsp(nsp_file);
62 62
63 if (nsp.GetStatus() == ResultStatus::Success) { 63 if (nsp.GetStatus() == ResultStatus::Success) {
64 // Extracted Type case 64 // Extracted Type case
@@ -79,7 +79,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& 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 }
@@ -121,67 +121,80 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::Sy
121 return result; 121 return result;
122} 122}
123 123
124ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) { 124ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& out_file) {
125 return secondary_loader->ReadRomFS(file); 125 return secondary_loader->ReadRomFS(out_file);
126} 126}
127 127
128u64 AppLoader_NSP::ReadRomFSIVFCOffset() const { 128u64 AppLoader_NSP::ReadRomFSIVFCOffset() const {
129 return secondary_loader->ReadRomFSIVFCOffset(); 129 return secondary_loader->ReadRomFSIVFCOffset();
130} 130}
131 131
132ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& file) { 132ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
133 if (nsp->IsExtractedType()) 133 if (nsp->IsExtractedType()) {
134 return ResultStatus::ErrorNoPackedUpdate; 134 return ResultStatus::ErrorNoPackedUpdate;
135 }
135 136
136 const auto read = 137 const auto read =
137 nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program); 138 nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
138 139
139 if (read == nullptr) 140 if (read == nullptr) {
140 return ResultStatus::ErrorNoPackedUpdate; 141 return ResultStatus::ErrorNoPackedUpdate;
141 const auto nca_test = std::make_shared<FileSys::NCA>(read); 142 }
142 143
143 if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS) 144 const auto nca_test = std::make_shared<FileSys::NCA>(read);
145 if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS) {
144 return nca_test->GetStatus(); 146 return nca_test->GetStatus();
147 }
145 148
146 file = read; 149 out_file = read;
147 return ResultStatus::Success; 150 return ResultStatus::Success;
148} 151}
149 152
150ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { 153ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
151 if (title_id == 0) 154 if (title_id == 0) {
152 return ResultStatus::ErrorNotInitialized; 155 return ResultStatus::ErrorNotInitialized;
156 }
157
153 out_program_id = title_id; 158 out_program_id = title_id;
154 return ResultStatus::Success; 159 return ResultStatus::Success;
155} 160}
156 161
157ResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) { 162ResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) {
158 if (icon_file == nullptr) 163 if (icon_file == nullptr) {
159 return ResultStatus::ErrorNoControl; 164 return ResultStatus::ErrorNoControl;
165 }
166
160 buffer = icon_file->ReadAllBytes(); 167 buffer = icon_file->ReadAllBytes();
161 return ResultStatus::Success; 168 return ResultStatus::Success;
162} 169}
163 170
164ResultStatus AppLoader_NSP::ReadTitle(std::string& title) { 171ResultStatus AppLoader_NSP::ReadTitle(std::string& title) {
165 if (nacp_file == nullptr) 172 if (nacp_file == nullptr) {
166 return ResultStatus::ErrorNoControl; 173 return ResultStatus::ErrorNoControl;
174 }
175
167 title = nacp_file->GetApplicationName(); 176 title = nacp_file->GetApplicationName();
168 return ResultStatus::Success; 177 return ResultStatus::Success;
169} 178}
170 179
171ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) { 180ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
172 if (nacp_file == nullptr) 181 if (nacp_file == nullptr) {
173 return ResultStatus::ErrorNoControl; 182 return ResultStatus::ErrorNoControl;
183 }
184
174 nacp = *nacp_file; 185 nacp = *nacp_file;
175 return ResultStatus::Success; 186 return ResultStatus::Success;
176} 187}
177 188
178ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) { 189ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& out_file) {
179 const auto nca = 190 const auto nca =
180 nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::HtmlDocument); 191 nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::HtmlDocument);
181 if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr) 192 if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr) {
182 return ResultStatus::ErrorNoRomFS; 193 return ResultStatus::ErrorNoRomFS;
183 file = nca->GetRomFS(); 194 }
184 return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success; 195
196 out_file = nca->GetRomFS();
197 return out_file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
185} 198}
186 199
187ResultStatus AppLoader_NSP::ReadBanner(std::vector<u8>& buffer) { 200ResultStatus AppLoader_NSP::ReadBanner(std::vector<u8>& buffer) {
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index d48d87f2c..644c0ff58 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -26,33 +26,35 @@ class AppLoader_NCA;
26/// Loads an XCI file 26/// Loads an XCI file
27class AppLoader_NSP final : public AppLoader { 27class AppLoader_NSP final : public AppLoader {
28public: 28public:
29 explicit AppLoader_NSP(FileSys::VirtualFile file, 29 explicit AppLoader_NSP(FileSys::VirtualFile file_,
30 const Service::FileSystem::FileSystemController& fsc, 30 const Service::FileSystem::FileSystemController& fsc,
31 const FileSys::ContentProvider& content_provider, 31 const FileSys::ContentProvider& content_provider,
32 std::size_t program_index); 32 std::size_t program_index);
33 ~AppLoader_NSP() override; 33 ~AppLoader_NSP() override;
34 34
35 /** 35 /**
36 * Returns the type of the file 36 * Identifies whether or not the given file is an NSP file.
37 * @param file open file 37 *
38 * @return FileType found, or FileType::Error if this loader doesn't know it 38 * @param nsp_file The file to identify.
39 *
40 * @return FileType::NSP, or FileType::Error if the file is not an NSP.
39 */ 41 */
40 static FileType IdentifyType(const FileSys::VirtualFile& file); 42 static FileType IdentifyType(const FileSys::VirtualFile& nsp_file);
41 43
42 FileType GetFileType() const override { 44 FileType GetFileType() const override {
43 return IdentifyType(file); 45 return IdentifyType(file);
44 } 46 }
45 47
46 LoadResult Load(Kernel::Process& process, Core::System& system) override; 48 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
47 49
48 ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; 50 ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
49 u64 ReadRomFSIVFCOffset() const override; 51 u64 ReadRomFSIVFCOffset() const override;
50 ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override; 52 ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
51 ResultStatus ReadProgramId(u64& out_program_id) override; 53 ResultStatus ReadProgramId(u64& out_program_id) override;
52 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 54 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
53 ResultStatus ReadTitle(std::string& title) override; 55 ResultStatus ReadTitle(std::string& title) override;
54 ResultStatus ReadControlData(FileSys::NACP& nacp) override; 56 ResultStatus ReadControlData(FileSys::NACP& nacp) override;
55 ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override; 57 ResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) override;
56 58
57 ResultStatus ReadBanner(std::vector<u8>& buffer) override; 59 ResultStatus ReadBanner(std::vector<u8>& buffer) override;
58 ResultStatus ReadLogo(std::vector<u8>& buffer) override; 60 ResultStatus ReadLogo(std::vector<u8>& buffer) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index aaa250cea..635d6ae15 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -13,18 +13,18 @@
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"
20 20
21namespace Loader { 21namespace Loader {
22 22
23AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, 23AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_,
24 const Service::FileSystem::FileSystemController& fsc, 24 const Service::FileSystem::FileSystemController& fsc,
25 const FileSys::ContentProvider& content_provider, 25 const FileSys::ContentProvider& content_provider,
26 std::size_t program_index) 26 std::size_t program_index)
27 : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)), 27 : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_index)),
28 nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { 28 nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
29 if (xci->GetStatus() != ResultStatus::Success) { 29 if (xci->GetStatus() != ResultStatus::Success) {
30 return; 30 return;
@@ -43,8 +43,8 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
43 43
44AppLoader_XCI::~AppLoader_XCI() = default; 44AppLoader_XCI::~AppLoader_XCI() = default;
45 45
46FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) { 46FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& xci_file) {
47 FileSys::XCI xci(file); 47 const FileSys::XCI xci(xci_file);
48 48
49 if (xci.GetStatus() == ResultStatus::Success && 49 if (xci.GetStatus() == ResultStatus::Success &&
50 xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr && 50 xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr &&
@@ -56,7 +56,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& 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 }
@@ -87,31 +87,33 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::Sy
87 return result; 87 return result;
88} 88}
89 89
90ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) { 90ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& out_file) {
91 return nca_loader->ReadRomFS(file); 91 return nca_loader->ReadRomFS(out_file);
92} 92}
93 93
94u64 AppLoader_XCI::ReadRomFSIVFCOffset() const { 94u64 AppLoader_XCI::ReadRomFSIVFCOffset() const {
95 return nca_loader->ReadRomFSIVFCOffset(); 95 return nca_loader->ReadRomFSIVFCOffset();
96} 96}
97 97
98ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& file) { 98ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
99 u64 program_id{}; 99 u64 program_id{};
100 nca_loader->ReadProgramId(program_id); 100 nca_loader->ReadProgramId(program_id);
101 if (program_id == 0) 101 if (program_id == 0) {
102 return ResultStatus::ErrorXCIMissingProgramNCA; 102 return ResultStatus::ErrorXCIMissingProgramNCA;
103 }
103 104
104 const auto read = xci->GetSecurePartitionNSP()->GetNCAFile( 105 const auto read = xci->GetSecurePartitionNSP()->GetNCAFile(
105 FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program); 106 FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program);
106 107 if (read == nullptr) {
107 if (read == nullptr)
108 return ResultStatus::ErrorNoPackedUpdate; 108 return ResultStatus::ErrorNoPackedUpdate;
109 const auto nca_test = std::make_shared<FileSys::NCA>(read); 109 }
110 110
111 if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS) 111 const auto nca_test = std::make_shared<FileSys::NCA>(read);
112 if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS) {
112 return nca_test->GetStatus(); 113 return nca_test->GetStatus();
114 }
113 115
114 file = read; 116 out_file = read;
115 return ResultStatus::Success; 117 return ResultStatus::Success;
116} 118}
117 119
@@ -120,33 +122,41 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
120} 122}
121 123
122ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { 124ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
123 if (icon_file == nullptr) 125 if (icon_file == nullptr) {
124 return ResultStatus::ErrorNoControl; 126 return ResultStatus::ErrorNoControl;
127 }
128
125 buffer = icon_file->ReadAllBytes(); 129 buffer = icon_file->ReadAllBytes();
126 return ResultStatus::Success; 130 return ResultStatus::Success;
127} 131}
128 132
129ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { 133ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
130 if (nacp_file == nullptr) 134 if (nacp_file == nullptr) {
131 return ResultStatus::ErrorNoControl; 135 return ResultStatus::ErrorNoControl;
136 }
137
132 title = nacp_file->GetApplicationName(); 138 title = nacp_file->GetApplicationName();
133 return ResultStatus::Success; 139 return ResultStatus::Success;
134} 140}
135 141
136ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) { 142ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
137 if (nacp_file == nullptr) 143 if (nacp_file == nullptr) {
138 return ResultStatus::ErrorNoControl; 144 return ResultStatus::ErrorNoControl;
145 }
146
139 control = *nacp_file; 147 control = *nacp_file;
140 return ResultStatus::Success; 148 return ResultStatus::Success;
141} 149}
142 150
143ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) { 151ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) {
144 const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), 152 const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
145 FileSys::ContentRecordType::HtmlDocument); 153 FileSys::ContentRecordType::HtmlDocument);
146 if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) 154 if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) {
147 return ResultStatus::ErrorXCIMissingPartition; 155 return ResultStatus::ErrorXCIMissingPartition;
148 file = nca->GetRomFS(); 156 }
149 return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success; 157
158 out_file = nca->GetRomFS();
159 return out_file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
150} 160}
151 161
152ResultStatus AppLoader_XCI::ReadBanner(std::vector<u8>& buffer) { 162ResultStatus AppLoader_XCI::ReadBanner(std::vector<u8>& buffer) {
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 9f0ceb5ef..708155c30 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -26,33 +26,35 @@ class AppLoader_NCA;
26/// Loads an XCI file 26/// Loads an XCI file
27class AppLoader_XCI final : public AppLoader { 27class AppLoader_XCI final : public AppLoader {
28public: 28public:
29 explicit AppLoader_XCI(FileSys::VirtualFile file, 29 explicit AppLoader_XCI(FileSys::VirtualFile file_,
30 const Service::FileSystem::FileSystemController& fsc, 30 const Service::FileSystem::FileSystemController& fsc,
31 const FileSys::ContentProvider& content_provider, 31 const FileSys::ContentProvider& content_provider,
32 std::size_t program_index); 32 std::size_t program_index);
33 ~AppLoader_XCI() override; 33 ~AppLoader_XCI() override;
34 34
35 /** 35 /**
36 * Returns the type of the file 36 * Identifies whether or not the given file is an XCI file.
37 * @param file open file 37 *
38 * @return FileType found, or FileType::Error if this loader doesn't know it 38 * @param xci_file The file to identify.
39 *
40 * @return FileType::XCI, or FileType::Error if the file is not an XCI file.
39 */ 41 */
40 static FileType IdentifyType(const FileSys::VirtualFile& file); 42 static FileType IdentifyType(const FileSys::VirtualFile& xci_file);
41 43
42 FileType GetFileType() const override { 44 FileType GetFileType() const override {
43 return IdentifyType(file); 45 return IdentifyType(file);
44 } 46 }
45 47
46 LoadResult Load(Kernel::Process& process, Core::System& system) override; 48 LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
47 49
48 ResultStatus ReadRomFS(FileSys::VirtualFile& file) override; 50 ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
49 u64 ReadRomFSIVFCOffset() const override; 51 u64 ReadRomFSIVFCOffset() const override;
50 ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override; 52 ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
51 ResultStatus ReadProgramId(u64& out_program_id) override; 53 ResultStatus ReadProgramId(u64& out_program_id) override;
52 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 54 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
53 ResultStatus ReadTitle(std::string& title) override; 55 ResultStatus ReadTitle(std::string& title) override;
54 ResultStatus ReadControlData(FileSys::NACP& control) override; 56 ResultStatus ReadControlData(FileSys::NACP& control) override;
55 ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override; 57 ResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) override;
56 58
57 ResultStatus ReadBanner(std::vector<u8>& buffer) override; 59 ResultStatus ReadBanner(std::vector<u8>& buffer) override;
58 ResultStatus ReadLogo(std::vector<u8>& buffer) override; 60 ResultStatus ReadLogo(std::vector<u8>& buffer) 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 8eec567ab..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() {
@@ -222,8 +222,8 @@ void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_regi
222 }; 222 };
223} 223}
224 224
225void CheatEngine::Reload(std::vector<CheatEntry> cheats) { 225void CheatEngine::Reload(std::vector<CheatEntry> reload_cheats) {
226 this->cheats = std::move(cheats); 226 cheats = std::move(reload_cheats);
227 is_pending_reload.exchange(true); 227 is_pending_reload.exchange(true);
228} 228}
229 229
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index a31002346..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,14 +61,14 @@ 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();
69 void SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size); 69 void SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size);
70 70
71 void Reload(std::vector<CheatEntry> cheats); 71 void Reload(std::vector<CheatEntry> reload_cheats);
72 72
73private: 73private:
74 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 74 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
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..c42c437b7 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) {
@@ -69,9 +69,7 @@ void PerfStats::EndSystemFrame() {
69} 69}
70 70
71void PerfStats::EndGameFrame() { 71void PerfStats::EndGameFrame() {
72 std::lock_guard lock{object_mutex}; 72 game_frames.fetch_add(1, std::memory_order_relaxed);
73
74 game_frames += 1;
75} 73}
76 74
77double PerfStats::GetMeanFrametime() const { 75double PerfStats::GetMeanFrametime() const {
@@ -94,10 +92,11 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
94 const auto interval = duration_cast<DoubleSecs>(now - reset_point).count(); 92 const auto interval = duration_cast<DoubleSecs>(now - reset_point).count();
95 93
96 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval; 94 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval;
97 95 const auto current_frames = static_cast<double>(game_frames.load(std::memory_order_relaxed));
96 const auto current_fps = current_frames / interval;
98 const PerfStatsResults results{ 97 const PerfStatsResults results{
99 .system_fps = static_cast<double>(system_frames) / interval, 98 .system_fps = static_cast<double>(system_frames) / interval,
100 .game_fps = static_cast<double>(game_frames) / interval, 99 .average_game_fps = (current_fps + previous_fps) / 2.0,
101 .frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / 100 .frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() /
102 static_cast<double>(system_frames), 101 static_cast<double>(system_frames),
103 .emulation_speed = system_us_per_second.count() / 1'000'000.0, 102 .emulation_speed = system_us_per_second.count() / 1'000'000.0,
@@ -108,7 +107,8 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
108 reset_point_system_us = current_system_time_us; 107 reset_point_system_us = current_system_time_us;
109 accumulated_frametime = Clock::duration::zero(); 108 accumulated_frametime = Clock::duration::zero();
110 system_frames = 0; 109 system_frames = 0;
111 game_frames = 0; 110 game_frames.store(0, std::memory_order_relaxed);
111 previous_fps = current_fps;
112 112
113 return results; 113 return results;
114} 114}
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index 69256b960..e5d603717 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include <chrono> 9#include <chrono>
9#include <cstddef> 10#include <cstddef>
10#include <mutex> 11#include <mutex>
@@ -15,8 +16,8 @@ namespace Core {
15struct PerfStatsResults { 16struct PerfStatsResults {
16 /// System FPS (LCD VBlanks) in Hz 17 /// System FPS (LCD VBlanks) in Hz
17 double system_fps; 18 double system_fps;
18 /// Game FPS (GSP frame submissions) in Hz 19 /// Average game FPS (GPU frame renders) in Hz
19 double game_fps; 20 double average_game_fps;
20 /// Walltime per system frame, in seconds, excluding any waits 21 /// Walltime per system frame, in seconds, excluding any waits
21 double frametime; 22 double frametime;
22 /// Ratio of walltime / emulated time elapsed 23 /// Ratio of walltime / emulated time elapsed
@@ -29,7 +30,7 @@ struct PerfStatsResults {
29 */ 30 */
30class PerfStats { 31class PerfStats {
31public: 32public:
32 explicit PerfStats(u64 title_id); 33 explicit PerfStats(u64 title_id_);
33 ~PerfStats(); 34 ~PerfStats();
34 35
35 using Clock = std::chrono::high_resolution_clock; 36 using Clock = std::chrono::high_resolution_clock;
@@ -72,7 +73,7 @@ private:
72 /// Cumulative number of system frames (LCD VBlanks) presented since last reset 73 /// Cumulative number of system frames (LCD VBlanks) presented since last reset
73 u32 system_frames = 0; 74 u32 system_frames = 0;
74 /// Cumulative number of game frames (GSP frame submissions) since last reset 75 /// Cumulative number of game frames (GSP frame submissions) since last reset
75 u32 game_frames = 0; 76 std::atomic<u32> game_frames = 0;
76 77
77 /// Point when the previous system frame ended 78 /// Point when the previous system frame ended
78 Clock::time_point previous_frame_end = reset_point; 79 Clock::time_point previous_frame_end = reset_point;
@@ -80,6 +81,8 @@ private:
80 Clock::time_point frame_begin = reset_point; 81 Clock::time_point frame_begin = reset_point;
81 /// Total visible duration (including frame-limiting, etc.) of the previous system frame 82 /// Total visible duration (including frame-limiting, etc.) of the previous system frame
82 Clock::duration previous_frame_length = Clock::duration::zero(); 83 Clock::duration previous_frame_length = Clock::duration::zero();
84 /// Previously computed fps
85 double previous_fps = 0;
83}; 86};
84 87
85class FrameLimiter { 88class FrameLimiter {
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/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 5c674a099..2e09faa6d 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -67,8 +67,8 @@ Freezer::~Freezer() {
67 core_timing.UnscheduleEvent(event, 0); 67 core_timing.UnscheduleEvent(event, 0);
68} 68}
69 69
70void Freezer::SetActive(bool active) { 70void Freezer::SetActive(bool is_active) {
71 if (!this->active.exchange(active)) { 71 if (!active.exchange(is_active)) {
72 FillEntryReads(); 72 FillEntryReads();
73 core_timing.ScheduleEvent(memory_freezer_ns, event); 73 core_timing.ScheduleEvent(memory_freezer_ns, event);
74 LOG_DEBUG(Common_Memory, "Memory freezer activated!"); 74 LOG_DEBUG(Common_Memory, "Memory freezer activated!");
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 0fdb701a7..067134e93 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -43,7 +43,7 @@ public:
43 ~Freezer(); 43 ~Freezer();
44 44
45 // Enables or disables the entire memory freezer. 45 // Enables or disables the entire memory freezer.
46 void SetActive(bool active); 46 void SetActive(bool is_active);
47 47
48 // Returns whether or not the freezer is active. 48 // Returns whether or not the freezer is active.
49 bool IsActive() const; 49 bool IsActive() const;
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index ec3167bea..320f51ee6 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -155,8 +155,12 @@ void Adapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_pa
155 for (const PadAxes axis : axes) { 155 for (const PadAxes axis : axes) {
156 const auto index = static_cast<std::size_t>(axis); 156 const auto index = static_cast<std::size_t>(axis);
157 const u8 axis_value = adapter_payload[offset + 3 + index]; 157 const u8 axis_value = adapter_payload[offset + 3 + index];
158 if (pads[port].axis_origin[index] == 255) { 158 if (pads[port].reset_origin_counter <= 18) {
159 if (pads[port].axis_origin[index] != axis_value) {
160 pads[port].reset_origin_counter = 0;
161 }
159 pads[port].axis_origin[index] = axis_value; 162 pads[port].axis_origin[index] = axis_value;
163 pads[port].reset_origin_counter++;
160 } 164 }
161 pads[port].axis_values[index] = 165 pads[port].axis_values[index] =
162 static_cast<s16>(axis_value - pads[port].axis_origin[index]); 166 static_cast<s16>(axis_value - pads[port].axis_origin[index]);
@@ -375,7 +379,7 @@ void Adapter::ResetDevice(std::size_t port) {
375 pads[port].buttons = 0; 379 pads[port].buttons = 0;
376 pads[port].last_button = PadButton::Undefined; 380 pads[port].last_button = PadButton::Undefined;
377 pads[port].axis_values.fill(0); 381 pads[port].axis_values.fill(0);
378 pads[port].axis_origin.fill(255); 382 pads[port].reset_origin_counter = 0;
379} 383}
380 384
381void Adapter::Reset() { 385void Adapter::Reset() {
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index 7a6c545bd..e5de5e94f 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -70,6 +70,7 @@ struct GCController {
70 PadButton last_button{}; 70 PadButton last_button{};
71 std::array<s16, 6> axis_values{}; 71 std::array<s16, 6> axis_values{};
72 std::array<u8, 6> axis_origin{}; 72 std::array<u8, 6> axis_origin{};
73 u8 reset_origin_counter{};
73}; 74};
74 75
75class Adapter { 76class Adapter {
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/motion_input.cpp b/src/input_common/motion_input.cpp
index 6a65f175e..1c9d561c0 100644
--- a/src/input_common/motion_input.cpp
+++ b/src/input_common/motion_input.cpp
@@ -195,7 +195,8 @@ Input::MotionStatus MotionInput::GetMotion() const {
195 const Common::Vec3f accelerometer = GetAcceleration(); 195 const Common::Vec3f accelerometer = GetAcceleration();
196 const Common::Vec3f rotation = GetRotations(); 196 const Common::Vec3f rotation = GetRotations();
197 const std::array<Common::Vec3f, 3> orientation = GetOrientation(); 197 const std::array<Common::Vec3f, 3> orientation = GetOrientation();
198 return {accelerometer, gyroscope, rotation, orientation}; 198 const Common::Quaternion<f32> quaternion = GetQuaternion();
199 return {accelerometer, gyroscope, rotation, orientation, quaternion};
199} 200}
200 201
201Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const { 202Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
@@ -218,7 +219,12 @@ Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_m
218 Common::Vec3f{0.0f, 1.0f, 0.0f}, 219 Common::Vec3f{0.0f, 1.0f, 0.0f},
219 Common::Vec3f{0.0f, 0.0f, 1.0f}, 220 Common::Vec3f{0.0f, 0.0f, 1.0f},
220 }; 221 };
221 return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation}; 222 constexpr Common::Quaternion<f32> quaternion{
223 {0.0f, 0.0f, 0.0f},
224 1.0f,
225 };
226 return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation,
227 quaternion};
222} 228}
223 229
224void MotionInput::ResetOrientation() { 230void MotionInput::ResetOrientation() {
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index fff1c6b45..a335e6da1 100644
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -143,6 +143,15 @@ void Mouse::ReleaseButton(MouseButton button_) {
143 mouse_info[button_index].data.axis = {0, 0}; 143 mouse_info[button_index].data.axis = {0, 0};
144} 144}
145 145
146void Mouse::ReleaseAllButtons() {
147 buttons = 0;
148 for (auto& info : mouse_info) {
149 info.tilt_speed = 0;
150 info.data.pressed = false;
151 info.data.axis = {0, 0};
152 }
153}
154
146void Mouse::BeginConfiguration() { 155void Mouse::BeginConfiguration() {
147 buttons = 0; 156 buttons = 0;
148 last_button = MouseButton::Undefined; 157 last_button = MouseButton::Undefined;
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
index 750d9b011..5a971ad67 100644
--- a/src/input_common/mouse/mouse_input.h
+++ b/src/input_common/mouse/mouse_input.h
@@ -65,10 +65,16 @@ public:
65 void MouseMove(int x, int y, int center_x, int center_y); 65 void MouseMove(int x, int y, int center_x, int center_y);
66 66
67 /** 67 /**
68 * Signals that a motion sensor tilt has ended. 68 * Signals that a button is released.
69 * @param button_ the button pressed
69 */ 70 */
70 void ReleaseButton(MouseButton button_); 71 void ReleaseButton(MouseButton button_);
71 72
73 /**
74 * Signals that all buttons are released
75 */
76 void ReleaseAllButtons();
77
72 [[nodiscard]] bool ToggleButton(std::size_t button_); 78 [[nodiscard]] bool ToggleButton(std::size_t button_);
73 [[nodiscard]] bool UnlockButton(std::size_t button_); 79 [[nodiscard]] bool UnlockButton(std::size_t button_);
74 80
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/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 8a38a380d..bc1dfab3d 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -86,6 +86,7 @@ private:
86 case Type::PadData: { 86 case Type::PadData: {
87 Response::PadData pad_data; 87 Response::PadData pad_data;
88 std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); 88 std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData));
89 SanitizeMotion(pad_data);
89 callback.pad_data(std::move(pad_data)); 90 callback.pad_data(std::move(pad_data));
90 break; 91 break;
91 } 92 }
@@ -114,6 +115,28 @@ private:
114 StartSend(timer.expiry()); 115 StartSend(timer.expiry());
115 } 116 }
116 117
118 void SanitizeMotion(Response::PadData& data) {
119 // Zero out any non number value
120 if (!std::isnormal(data.gyro.pitch)) {
121 data.gyro.pitch = 0;
122 }
123 if (!std::isnormal(data.gyro.roll)) {
124 data.gyro.roll = 0;
125 }
126 if (!std::isnormal(data.gyro.yaw)) {
127 data.gyro.yaw = 0;
128 }
129 if (!std::isnormal(data.accel.x)) {
130 data.accel.x = 0;
131 }
132 if (!std::isnormal(data.accel.y)) {
133 data.accel.y = 0;
134 }
135 if (!std::isnormal(data.accel.z)) {
136 data.accel.z = 0;
137 }
138 }
139
117 SocketCallback callback; 140 SocketCallback callback;
118 boost::asio::io_service io_service; 141 boost::asio::io_service io_service;
119 boost::asio::basic_waitable_timer<clock> timer; 142 boost::asio::basic_waitable_timer<clock> timer;
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 32dcbd693..de971041f 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -690,7 +690,10 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
690 const VAddr cpu_addr = binding.cpu_addr; 690 const VAddr cpu_addr = binding.cpu_addr;
691 const u32 size = binding.size; 691 const u32 size = binding.size;
692 Buffer& buffer = slot_buffers[binding.buffer_id]; 692 Buffer& buffer = slot_buffers[binding.buffer_id];
693 if (size <= uniform_buffer_skip_cache_size && !buffer.IsRegionGpuModified(cpu_addr, size)) { 693 const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
694 size <= uniform_buffer_skip_cache_size &&
695 !buffer.IsRegionGpuModified(cpu_addr, size);
696 if (use_fast_buffer) {
694 if constexpr (IS_OPENGL) { 697 if constexpr (IS_OPENGL) {
695 if (runtime.HasFastBufferSubData()) { 698 if (runtime.HasFastBufferSubData()) {
696 // Fast path for Nvidia 699 // Fast path for Nvidia
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index a38024242..37f7b24e1 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -13,6 +13,7 @@
13#include "core/frontend/emu_window.h" 13#include "core/frontend/emu_window.h"
14#include "core/hardware_interrupt_manager.h" 14#include "core/hardware_interrupt_manager.h"
15#include "core/memory.h" 15#include "core/memory.h"
16#include "core/perf_stats.h"
16#include "video_core/engines/fermi_2d.h" 17#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_compute.h" 18#include "video_core/engines/kepler_compute.h"
18#include "video_core/engines/kepler_memory.h" 19#include "video_core/engines/kepler_memory.h"
@@ -191,6 +192,10 @@ u64 GPU::GetTicks() const {
191 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den; 192 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
192} 193}
193 194
195void GPU::RendererFrameEndNotify() {
196 system.GetPerfStats().EndGameFrame();
197}
198
194void GPU::FlushCommands() { 199void GPU::FlushCommands() {
195 rasterizer->FlushCommands(); 200 rasterizer->FlushCommands();
196} 201}
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 8669e9940..29a867863 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -247,6 +247,8 @@ public:
247 return use_nvdec; 247 return use_nvdec;
248 } 248 }
249 249
250 void RendererFrameEndNotify();
251
250 enum class FenceOperation : u32 { 252 enum class FenceOperation : u32 {
251 Acquire = 0, 253 Acquire = 0,
252 Increment = 1, 254 Increment = 1,
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_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index cc2e499f9..a718bff7a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -155,6 +155,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
155 155
156 ++m_current_frame; 156 ++m_current_frame;
157 157
158 gpu.RendererFrameEndNotify();
158 rasterizer.TickFrame(); 159 rasterizer.TickFrame();
159 160
160 context->SwapBuffers(); 161 context->SwapBuffers();
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/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 2e0cf4232..3986eb172 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -154,6 +154,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
154 if (swapchain.Present(render_semaphore)) { 154 if (swapchain.Present(render_semaphore)) {
155 blit_screen.Recreate(); 155 blit_screen.Recreate();
156 } 156 }
157 gpu.RendererFrameEndNotify();
157 rasterizer.TickFrame(); 158 rasterizer.TickFrame();
158 } 159 }
159 160
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/about_dialog.cpp b/src/yuzu/about_dialog.cpp
index 695b2ef5f..a2e0e6962 100644
--- a/src/yuzu/about_dialog.cpp
+++ b/src/yuzu/about_dialog.cpp
@@ -9,17 +9,19 @@
9#include "yuzu/about_dialog.h" 9#include "yuzu/about_dialog.h"
10 10
11AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) { 11AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) {
12 const auto branch_name = std::string(Common::g_scm_branch);
13 const auto description = std::string(Common::g_scm_desc);
12 const auto build_id = std::string(Common::g_build_id); 14 const auto build_id = std::string(Common::g_build_id);
13 const auto fmt = std::string(Common::g_title_bar_format_idle); 15
14 const auto yuzu_build_version = 16 const auto yuzu_build = fmt::format("yuzu Development Build | {}-{}", branch_name, description);
15 fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{}, 17 const auto override_build = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
16 std::string{}, std::string{}, std::string{}, build_id); 18 const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
17 19
18 ui->setupUi(this); 20 ui->setupUi(this);
19 ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200)); 21 ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200));
20 ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg( 22 ui->labelBuildInfo->setText(
21 QString::fromStdString(yuzu_build_version), QString::fromUtf8(Common::g_scm_branch), 23 ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version),
22 QString::fromUtf8(Common::g_scm_desc), QString::fromUtf8(Common::g_build_date).left(10))); 24 QString::fromUtf8(Common::g_build_date).left(10)));
23} 25}
24 26
25AboutDialog::~AboutDialog() = default; 27AboutDialog::~AboutDialog() = default;
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui
index 1b320630c..27d81cd13 100644
--- a/src/yuzu/aboutdialog.ui
+++ b/src/yuzu/aboutdialog.ui
@@ -70,7 +70,7 @@
70 </sizepolicy> 70 </sizepolicy>
71 </property> 71 </property>
72 <property name="text"> 72 <property name="text">
73 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 | %2-%3 (%4)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 73 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;%1 (%2)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
74 </property> 74 </property>
75 </widget> 75 </widget>
76 </item> 76 </item>
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp
index fd3368479..b0f764994 100644
--- a/src/yuzu/applets/software_keyboard.cpp
+++ b/src/yuzu/applets/software_keyboard.cpp
@@ -404,12 +404,16 @@ void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
404 404
405 OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message), 405 OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
406 tr("Cancel"), tr("OK"), Qt::AlignCenter); 406 tr("Cancel"), tr("OK"), Qt::AlignCenter);
407 if (dialog.exec() == QDialog::Accepted) { 407 if (dialog.exec() != QDialog::Accepted) {
408 emit SubmitNormalText(SwkbdResult::Ok, current_text); 408 StartInputThread();
409 break; 409 break;
410 } 410 }
411 411
412 StartInputThread(); 412 auto text = ui->topOSK->currentIndex() == 1
413 ? ui->text_edit_osk->toPlainText().toStdU16String()
414 : ui->line_edit_osk->text().toStdU16String();
415
416 emit SubmitNormalText(SwkbdResult::Ok, std::move(text));
413 break; 417 break;
414 } 418 }
415 } 419 }
@@ -480,11 +484,7 @@ void QtSoftwareKeyboardDialog::open() {
480void QtSoftwareKeyboardDialog::reject() { 484void QtSoftwareKeyboardDialog::reject() {
481 // Pressing the ESC key in a dialog calls QDialog::reject(). 485 // Pressing the ESC key in a dialog calls QDialog::reject().
482 // We will override this behavior to the "Cancel" action on the software keyboard. 486 // We will override this behavior to the "Cancel" action on the software keyboard.
483 if (is_inline) { 487 TranslateButtonPress(HIDButton::X);
484 emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
485 } else {
486 emit SubmitNormalText(SwkbdResult::Cancel, current_text);
487 }
488} 488}
489 489
490void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { 490void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
@@ -1027,10 +1027,8 @@ void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
1027 ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index)); 1027 ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
1028 1028
1029 ui->button_shift_shift->setStyleSheet( 1029 ui->button_shift_shift->setStyleSheet(
1030 QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);" 1030 QStringLiteral("image: url(:/overlay/osk_button_shift_lock_off.png);"
1031 "\nbackground-position: left top;" 1031 "\nimage-position: left;"));
1032 "\nbackground-repeat: no-repeat;"
1033 "\nbackground-origin: content;"));
1034 1032
1035 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); 1033 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
1036 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); 1034 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
@@ -1040,10 +1038,8 @@ void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
1040 caps_lock_enabled = false; 1038 caps_lock_enabled = false;
1041 1039
1042 ui->button_shift_shift->setStyleSheet( 1040 ui->button_shift_shift->setStyleSheet(
1043 QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);" 1041 QStringLiteral("image: url(:/overlay/osk_button_shift_lock_off.png);"
1044 "\nbackground-position: left top;" 1042 "\nimage-position: left;"));
1045 "\nbackground-repeat: no-repeat;"
1046 "\nbackground-origin: content;"));
1047 1043
1048 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); 1044 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
1049 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); 1045 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
@@ -1056,10 +1052,8 @@ void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
1056 caps_lock_enabled = true; 1052 caps_lock_enabled = true;
1057 1053
1058 ui->button_shift_shift->setStyleSheet( 1054 ui->button_shift_shift->setStyleSheet(
1059 QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_on.png);" 1055 QStringLiteral("image: url(:/overlay/osk_button_shift_lock_on.png);"
1060 "\nbackground-position: left top;" 1056 "\nimage-position: left;"));
1061 "\nbackground-repeat: no-repeat;"
1062 "\nbackground-origin: content;"));
1063 1057
1064 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize()); 1058 ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
1065 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize()); 1059 ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
diff --git a/src/yuzu/applets/web_browser.cpp b/src/yuzu/applets/web_browser.cpp
index e482ba029..93e3a4f6f 100644
--- a/src/yuzu/applets/web_browser.cpp
+++ b/src/yuzu/applets/web_browser.cpp
@@ -102,8 +102,8 @@ QtNXWebEngineView::~QtNXWebEngineView() {
102 StopInputThread(); 102 StopInputThread();
103} 103}
104 104
105void QtNXWebEngineView::LoadLocalWebPage(std::string_view main_url, 105void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url,
106 std::string_view additional_args) { 106 const std::string& additional_args) {
107 is_local = true; 107 is_local = true;
108 108
109 LoadExtractedFonts(); 109 LoadExtractedFonts();
@@ -113,12 +113,12 @@ void QtNXWebEngineView::LoadLocalWebPage(std::string_view main_url,
113 SetLastURL("http://localhost/"); 113 SetLastURL("http://localhost/");
114 StartInputThread(); 114 StartInputThread();
115 115
116 load(QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(main_url))).toString() + 116 load(QUrl(QUrl::fromLocalFile(QString::fromStdString(main_url)).toString() +
117 QString::fromStdString(std::string(additional_args)))); 117 QString::fromStdString(additional_args)));
118} 118}
119 119
120void QtNXWebEngineView::LoadExternalWebPage(std::string_view main_url, 120void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url,
121 std::string_view additional_args) { 121 const std::string& additional_args) {
122 is_local = false; 122 is_local = false;
123 123
124 SetUserAgent(UserAgent::WebApplet); 124 SetUserAgent(UserAgent::WebApplet);
@@ -127,8 +127,7 @@ void QtNXWebEngineView::LoadExternalWebPage(std::string_view main_url,
127 SetLastURL("http://localhost/"); 127 SetLastURL("http://localhost/");
128 StartInputThread(); 128 StartInputThread();
129 129
130 load(QUrl(QString::fromStdString(std::string(main_url)) + 130 load(QUrl(QString::fromStdString(main_url) + QString::fromStdString(additional_args)));
131 QString::fromStdString(std::string(additional_args))));
132} 131}
133 132
134void QtNXWebEngineView::SetUserAgent(UserAgent user_agent) { 133void QtNXWebEngineView::SetUserAgent(UserAgent user_agent) {
@@ -375,7 +374,7 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
375QtWebBrowser::~QtWebBrowser() = default; 374QtWebBrowser::~QtWebBrowser() = default;
376 375
377void QtWebBrowser::OpenLocalWebPage( 376void QtWebBrowser::OpenLocalWebPage(
378 std::string_view local_url, std::function<void()> extract_romfs_callback_, 377 const std::string& local_url, std::function<void()> extract_romfs_callback_,
379 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const { 378 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const {
380 extract_romfs_callback = std::move(extract_romfs_callback_); 379 extract_romfs_callback = std::move(extract_romfs_callback_);
381 callback = std::move(callback_); 380 callback = std::move(callback_);
@@ -390,7 +389,7 @@ void QtWebBrowser::OpenLocalWebPage(
390} 389}
391 390
392void QtWebBrowser::OpenExternalWebPage( 391void QtWebBrowser::OpenExternalWebPage(
393 std::string_view external_url, 392 const std::string& external_url,
394 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const { 393 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const {
395 callback = std::move(callback_); 394 callback = std::move(callback_);
396 395
diff --git a/src/yuzu/applets/web_browser.h b/src/yuzu/applets/web_browser.h
index 47f960d69..7ad07409f 100644
--- a/src/yuzu/applets/web_browser.h
+++ b/src/yuzu/applets/web_browser.h
@@ -58,7 +58,7 @@ public:
58 * @param main_url The url to the file. 58 * @param main_url The url to the file.
59 * @param additional_args Additional arguments appended to the main url. 59 * @param additional_args Additional arguments appended to the main url.
60 */ 60 */
61 void LoadLocalWebPage(std::string_view main_url, std::string_view additional_args); 61 void LoadLocalWebPage(const std::string& main_url, const std::string& additional_args);
62 62
63 /** 63 /**
64 * Loads an external website. Cannot be used to load local urls. 64 * Loads an external website. Cannot be used to load local urls.
@@ -66,7 +66,7 @@ public:
66 * @param main_url The url to the website. 66 * @param main_url The url to the website.
67 * @param additional_args Additional arguments appended to the main url. 67 * @param additional_args Additional arguments appended to the main url.
68 */ 68 */
69 void LoadExternalWebPage(std::string_view main_url, std::string_view additional_args); 69 void LoadExternalWebPage(const std::string& main_url, const std::string& additional_args);
70 70
71 /** 71 /**
72 * Sets the background color of the web page. 72 * Sets the background color of the web page.
@@ -193,16 +193,17 @@ public:
193 explicit QtWebBrowser(GMainWindow& parent); 193 explicit QtWebBrowser(GMainWindow& parent);
194 ~QtWebBrowser() override; 194 ~QtWebBrowser() override;
195 195
196 void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback_, 196 void OpenLocalWebPage(const std::string& local_url,
197 std::function<void()> extract_romfs_callback_,
197 std::function<void(Service::AM::Applets::WebExitReason, std::string)> 198 std::function<void(Service::AM::Applets::WebExitReason, std::string)>
198 callback_) const override; 199 callback_) const override;
199 200
200 void OpenExternalWebPage(std::string_view external_url, 201 void OpenExternalWebPage(const std::string& external_url,
201 std::function<void(Service::AM::Applets::WebExitReason, std::string)> 202 std::function<void(Service::AM::Applets::WebExitReason, std::string)>
202 callback_) const override; 203 callback_) const override;
203 204
204signals: 205signals:
205 void MainWindowOpenWebPage(std::string_view main_url, std::string_view additional_args, 206 void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args,
206 bool is_local) const; 207 bool is_local) const;
207 208
208private: 209private:
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 9c7daeac7..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"
@@ -539,6 +539,8 @@ bool GRenderWindow::event(QEvent* event) {
539void GRenderWindow::focusOutEvent(QFocusEvent* event) { 539void GRenderWindow::focusOutEvent(QFocusEvent* event) {
540 QWidget::focusOutEvent(event); 540 QWidget::focusOutEvent(event);
541 input_subsystem->GetKeyboard()->ReleaseAllKeys(); 541 input_subsystem->GetKeyboard()->ReleaseAllKeys();
542 input_subsystem->GetMouse()->ReleaseAllButtons();
543 this->TouchReleased(0);
542} 544}
543 545
544void GRenderWindow::resizeEvent(QResizeEvent* event) { 546void GRenderWindow::resizeEvent(QResizeEvent* event) {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d1b8c4fc9..125feb86b 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -736,10 +736,16 @@ void Config::ReadPathValues() {
736void Config::ReadCpuValues() { 736void Config::ReadCpuValues() {
737 qt_config->beginGroup(QStringLiteral("Cpu")); 737 qt_config->beginGroup(QStringLiteral("Cpu"));
738 738
739 if (global) { 739 ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0);
740 Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>( 740
741 ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt()); 741 ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma,
742 QStringLiteral("cpuopt_unsafe_unfuse_fma"), true);
743 ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error,
744 QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true);
745 ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
746 QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
742 747
748 if (global) {
743 Settings::values.cpuopt_page_tables = 749 Settings::values.cpuopt_page_tables =
744 ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool(); 750 ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
745 Settings::values.cpuopt_block_linking = 751 Settings::values.cpuopt_block_linking =
@@ -756,13 +762,6 @@ void Config::ReadCpuValues() {
756 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); 762 ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
757 Settings::values.cpuopt_reduce_misalign_checks = 763 Settings::values.cpuopt_reduce_misalign_checks =
758 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); 764 ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
759
760 Settings::values.cpuopt_unsafe_unfuse_fma =
761 ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool();
762 Settings::values.cpuopt_unsafe_reduce_fp_error =
763 ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool();
764 Settings::values.cpuopt_unsafe_inaccurate_nan =
765 ReadSetting(QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true).toBool();
766 } 765 }
767 766
768 qt_config->endGroup(); 767 qt_config->endGroup();
@@ -863,24 +862,20 @@ void Config::ReadSystemValues() {
863 Settings::values.rng_seed.SetGlobal(rng_seed_global); 862 Settings::values.rng_seed.SetGlobal(rng_seed_global);
864 if (global || !rng_seed_global) { 863 if (global || !rng_seed_global) {
865 if (rng_seed_enabled) { 864 if (rng_seed_enabled) {
866 Settings::values.rng_seed.SetValue( 865 Settings::values.rng_seed.SetValue(ReadSetting(QStringLiteral("rng_seed"), 0).toUInt());
867 ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong());
868 } else { 866 } else {
869 Settings::values.rng_seed.SetValue(std::nullopt); 867 Settings::values.rng_seed.SetValue(std::nullopt);
870 } 868 }
871 } 869 }
872 870
873 bool custom_rtc_enabled; 871 if (global) {
874 ReadSettingGlobal(custom_rtc_enabled, QStringLiteral("custom_rtc_enabled"), false); 872 const auto custom_rtc_enabled =
875 bool custom_rtc_global = 873 ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
876 global || qt_config->value(QStringLiteral("custom_rtc/use_global"), true).toBool();
877 Settings::values.custom_rtc.SetGlobal(custom_rtc_global);
878 if (global || !custom_rtc_global) {
879 if (custom_rtc_enabled) { 874 if (custom_rtc_enabled) {
880 Settings::values.custom_rtc.SetValue( 875 Settings::values.custom_rtc =
881 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong())); 876 std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong());
882 } else { 877 } else {
883 Settings::values.custom_rtc.SetValue(std::nullopt); 878 Settings::values.custom_rtc = std::nullopt;
884 } 879 }
885 } 880 }
886 881
@@ -1314,10 +1309,19 @@ void Config::SavePathValues() {
1314void Config::SaveCpuValues() { 1309void Config::SaveCpuValues() {
1315 qt_config->beginGroup(QStringLiteral("Cpu")); 1310 qt_config->beginGroup(QStringLiteral("Cpu"));
1316 1311
1317 if (global) { 1312 WriteSettingGlobal(QStringLiteral("cpu_accuracy"),
1318 WriteSetting(QStringLiteral("cpu_accuracy"), 1313 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
1319 static_cast<int>(Settings::values.cpu_accuracy), 0); 1314 Settings::values.cpu_accuracy.UsingGlobal(),
1315 static_cast<u32>(Settings::CPUAccuracy::Accurate));
1320 1316
1317 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
1318 Settings::values.cpuopt_unsafe_unfuse_fma, true);
1319 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
1320 Settings::values.cpuopt_unsafe_reduce_fp_error, true);
1321 WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
1322 Settings::values.cpuopt_unsafe_inaccurate_nan, true);
1323
1324 if (global) {
1321 WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables, 1325 WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
1322 true); 1326 true);
1323 WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking, 1327 WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
@@ -1332,13 +1336,6 @@ void Config::SaveCpuValues() {
1332 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); 1336 WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
1333 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), 1337 WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
1334 Settings::values.cpuopt_reduce_misalign_checks, true); 1338 Settings::values.cpuopt_reduce_misalign_checks, true);
1335
1336 WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
1337 Settings::values.cpuopt_unsafe_unfuse_fma, true);
1338 WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
1339 Settings::values.cpuopt_unsafe_reduce_fp_error, true);
1340 WriteSetting(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
1341 Settings::values.cpuopt_unsafe_inaccurate_nan, true);
1342 } 1339 }
1343 1340
1344 qt_config->endGroup(); 1341 qt_config->endGroup();
@@ -1433,14 +1430,14 @@ void Config::SaveSystemValues() {
1433 Settings::values.rng_seed.GetValue(global).value_or(0), 1430 Settings::values.rng_seed.GetValue(global).value_or(0),
1434 Settings::values.rng_seed.UsingGlobal(), 0); 1431 Settings::values.rng_seed.UsingGlobal(), 0);
1435 1432
1436 WriteSettingGlobal(QStringLiteral("custom_rtc_enabled"), 1433 if (global) {
1437 Settings::values.custom_rtc.GetValue(global).has_value(), 1434 WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
1438 Settings::values.custom_rtc.UsingGlobal(), false); 1435 false);
1439 WriteSettingGlobal( 1436 WriteSetting(QStringLiteral("custom_rtc"),
1440 QStringLiteral("custom_rtc"), 1437 QVariant::fromValue<long long>(
1441 QVariant::fromValue<long long>( 1438 Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
1442 Settings::values.custom_rtc.GetValue(global).value_or(std::chrono::seconds{}).count()), 1439 0);
1443 Settings::values.custom_rtc.UsingGlobal(), 0); 1440 }
1444 1441
1445 WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1); 1442 WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
1446 1443
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 5a2c026b3..ce3355588 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -132,5 +132,6 @@ private:
132}; 132};
133 133
134// These metatype declarations cannot be in common/settings.h because core is devoid of QT 134// These metatype declarations cannot be in common/settings.h because core is devoid of QT
135Q_DECLARE_METATYPE(Settings::CPUAccuracy);
135Q_DECLARE_METATYPE(Settings::RendererBackend); 136Q_DECLARE_METATYPE(Settings::RendererBackend);
136Q_DECLARE_METATYPE(Settings::GPUAccuracy); 137Q_DECLARE_METATYPE(Settings::GPUAccuracy);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
index 89be4a62d..096e42e94 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -13,32 +13,29 @@
13void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, 13void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
14 const QCheckBox* checkbox, 14 const QCheckBox* checkbox,
15 const CheckState& tracker) { 15 const CheckState& tracker) {
16 if (tracker == CheckState::Global) { 16 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
17 setting->SetGlobal(true);
18 } else {
19 setting->SetGlobal(false);
20 setting->SetValue(checkbox->checkState()); 17 setting->SetValue(checkbox->checkState());
18 } else if (!Settings::IsConfiguringGlobal()) {
19 if (tracker == CheckState::Global) {
20 setting->SetGlobal(true);
21 } else {
22 setting->SetGlobal(false);
23 setting->SetValue(checkbox->checkState());
24 }
21 } 25 }
22} 26}
23 27
24void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting, 28void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
25 const QComboBox* combobox) { 29 const QComboBox* combobox) {
26 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 30 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
27 setting->SetGlobal(true); 31 setting->SetValue(combobox->currentIndex());
28 } else { 32 } else if (!Settings::IsConfiguringGlobal()) {
29 setting->SetGlobal(false); 33 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
30 setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET); 34 setting->SetGlobal(true);
31 } 35 } else {
32} 36 setting->SetGlobal(false);
33 37 setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
34void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting, 38 }
35 const QComboBox* combobox) {
36 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
37 setting->SetGlobal(true);
38 } else {
39 setting->SetGlobal(false);
40 setting->SetValue(static_cast<Settings::RendererBackend>(
41 combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
42 } 39 }
43} 40}
44 41
@@ -51,27 +48,6 @@ void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
51 } 48 }
52} 49}
53 50
54void ConfigurationShared::SetPerGameSetting(QComboBox* combobox,
55 const Settings::Setting<int>* setting) {
56 combobox->setCurrentIndex(setting->UsingGlobal()
57 ? ConfigurationShared::USE_GLOBAL_INDEX
58 : setting->GetValue() + ConfigurationShared::USE_GLOBAL_OFFSET);
59}
60
61void ConfigurationShared::SetPerGameSetting(
62 QComboBox* combobox, const Settings::Setting<Settings::RendererBackend>* setting) {
63 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
64 : static_cast<int>(setting->GetValue()) +
65 ConfigurationShared::USE_GLOBAL_OFFSET);
66}
67
68void ConfigurationShared::SetPerGameSetting(
69 QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting) {
70 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
71 : static_cast<int>(setting->GetValue()) +
72 ConfigurationShared::USE_GLOBAL_OFFSET);
73}
74
75void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) { 51void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
76 if (highlighted) { 52 if (highlighted) {
77 widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }") 53 widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }")
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 5b344cdbd..1e0ef01ca 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -15,37 +15,45 @@ constexpr int USE_GLOBAL_INDEX = 0;
15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1; 15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
16constexpr int USE_GLOBAL_OFFSET = 2; 16constexpr int USE_GLOBAL_OFFSET = 2;
17 17
18// CheckBoxes require a tracker for their state since we emulate a tristate CheckBox
18enum class CheckState { 19enum class CheckState {
19 Off, 20 Off, // Checkbox overrides to off/false
20 On, 21 On, // Checkbox overrides to on/true
21 Global, 22 Global, // Checkbox defers to the global state
22 Count, 23 Count, // Simply the number of states, not a valid checkbox state
23}; 24};
24 25
25// Global-aware apply and set functions 26// Global-aware apply and set functions
26 27
28// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
27void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, 29void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox,
28 const CheckState& tracker); 30 const CheckState& tracker);
29void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); 31void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
30void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
31 const QComboBox* combobox);
32void ApplyPerGameSetting(Settings::Setting<Settings::GPUAccuracy>* setting,
33 const QComboBox* combobox);
34 32
33// Sets a Qt UI element given a Settings::Setting
35void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); 34void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
36void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<int>* setting);
37void SetPerGameSetting(QComboBox* combobox,
38 const Settings::Setting<Settings::RendererBackend>* setting);
39void SetPerGameSetting(QComboBox* combobox,
40 const Settings::Setting<Settings::GPUAccuracy>* setting);
41 35
36template <typename Type>
37void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setting) {
38 combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
39 : static_cast<int>(setting->GetValue()) +
40 ConfigurationShared::USE_GLOBAL_OFFSET);
41}
42
43// (Un)highlights a Qt UI element
42void SetHighlight(QWidget* widget, bool highlighted); 44void SetHighlight(QWidget* widget, bool highlighted);
45
46// Sets up a QCheckBox like a tristate one, given a Setting
43void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting, 47void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting,
44 CheckState& tracker); 48 CheckState& tracker);
45void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state, 49void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
46 CheckState& tracker); 50 CheckState& tracker);
51
52// Sets up coloring of a QWidget `target` based on the state of a QComboBox, and calls
53// InsertGlobalItem
47void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global); 54void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global);
48 55
56// Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox
49void InsertGlobalItem(QComboBox* combobox, int global_index); 57void InsertGlobalItem(QComboBox* combobox, int global_index);
50 58
51} // namespace ConfigurationShared 59} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index f9507e228..fc0191432 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -99,6 +99,9 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
99} 99}
100 100
101void ConfigureAudio::ApplyConfiguration() { 101void ConfigureAudio::ApplyConfiguration() {
102 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
103 ui->toggle_audio_stretching, enable_audio_stretching);
104
102 if (Settings::IsConfiguringGlobal()) { 105 if (Settings::IsConfiguringGlobal()) {
103 Settings::values.sink_id = 106 Settings::values.sink_id =
104 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex()) 107 ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
@@ -108,19 +111,12 @@ void ConfigureAudio::ApplyConfiguration() {
108 .toStdString(); 111 .toStdString();
109 112
110 // Guard if during game and set to game-specific value 113 // Guard if during game and set to game-specific value
111 if (Settings::values.enable_audio_stretching.UsingGlobal()) {
112 Settings::values.enable_audio_stretching.SetValue(
113 ui->toggle_audio_stretching->isChecked());
114 }
115 if (Settings::values.volume.UsingGlobal()) { 114 if (Settings::values.volume.UsingGlobal()) {
116 Settings::values.volume.SetValue( 115 Settings::values.volume.SetValue(
117 static_cast<float>(ui->volume_slider->sliderPosition()) / 116 static_cast<float>(ui->volume_slider->sliderPosition()) /
118 ui->volume_slider->maximum()); 117 ui->volume_slider->maximum());
119 } 118 }
120 } else { 119 } else {
121 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
122 ui->toggle_audio_stretching,
123 enable_audio_stretching);
124 if (ui->volume_combo_box->currentIndex() == 0) { 120 if (ui->volume_combo_box->currentIndex() == 0) {
125 Settings::values.volume.SetGlobal(true); 121 Settings::values.volume.SetGlobal(true);
126 } else { 122 } else {
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 4f99bc80f..525c42ff0 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -10,11 +10,14 @@
10#include "common/settings.h" 10#include "common/settings.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "ui_configure_cpu.h" 12#include "ui_configure_cpu.h"
13#include "yuzu/configuration/configuration_shared.h"
13#include "yuzu/configuration/configure_cpu.h" 14#include "yuzu/configuration/configure_cpu.h"
14 15
15ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) { 16ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) {
16 ui->setupUi(this); 17 ui->setupUi(this);
17 18
19 SetupPerGameUI();
20
18 SetConfiguration(); 21 SetConfiguration();
19 22
20 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, 23 connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
@@ -29,19 +32,29 @@ void ConfigureCpu::SetConfiguration() {
29 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); 32 const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
30 33
31 ui->accuracy->setEnabled(runtime_lock); 34 ui->accuracy->setEnabled(runtime_lock);
32 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
33 UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy));
34
35 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock); 35 ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
36 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma);
37 ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock); 36 ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
38 ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error);
39 ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock); 37 ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
40 ui->cpuopt_unsafe_inaccurate_nan->setChecked(Settings::values.cpuopt_unsafe_inaccurate_nan); 38
39 ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
40 ui->cpuopt_unsafe_reduce_fp_error->setChecked(
41 Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue());
42 ui->cpuopt_unsafe_inaccurate_nan->setChecked(
43 Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
44
45 if (Settings::IsConfiguringGlobal()) {
46 ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
47 } else {
48 ConfigurationShared::SetPerGameSetting(ui->accuracy, &Settings::values.cpu_accuracy);
49 ConfigurationShared::SetHighlight(ui->widget_accuracy,
50 !Settings::values.cpu_accuracy.UsingGlobal());
51 }
52 UpdateGroup(ui->accuracy->currentIndex());
41} 53}
42 54
43void ConfigureCpu::AccuracyUpdated(int index) { 55void ConfigureCpu::AccuracyUpdated(int index) {
44 if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) { 56 if (Settings::IsConfiguringGlobal() &&
57 static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
45 const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"), 58 const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
46 tr("CPU Debug Mode is only intended for developer " 59 tr("CPU Debug Mode is only intended for developer "
47 "use. Are you sure you want to enable this?"), 60 "use. Are you sure you want to enable this?"),
@@ -54,16 +67,39 @@ void ConfigureCpu::AccuracyUpdated(int index) {
54} 67}
55 68
56void ConfigureCpu::UpdateGroup(int index) { 69void ConfigureCpu::UpdateGroup(int index) {
57 ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) == 70 if (!Settings::IsConfiguringGlobal()) {
58 Settings::CPUAccuracy::Unsafe); 71 index -= ConfigurationShared::USE_GLOBAL_OFFSET;
72 }
73 const auto accuracy = static_cast<Settings::CPUAccuracy>(index);
74 ui->unsafe_group->setVisible(accuracy == Settings::CPUAccuracy::Unsafe);
59} 75}
60 76
61void ConfigureCpu::ApplyConfiguration() { 77void ConfigureCpu::ApplyConfiguration() {
62 Settings::values.cpu_accuracy = 78 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma,
63 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); 79 ui->cpuopt_unsafe_unfuse_fma,
64 Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked(); 80 cpuopt_unsafe_unfuse_fma);
65 Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked(); 81 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_reduce_fp_error,
66 Settings::values.cpuopt_unsafe_inaccurate_nan = ui->cpuopt_unsafe_inaccurate_nan->isChecked(); 82 ui->cpuopt_unsafe_reduce_fp_error,
83 cpuopt_unsafe_reduce_fp_error);
84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan,
85 ui->cpuopt_unsafe_inaccurate_nan,
86 cpuopt_unsafe_inaccurate_nan);
87
88 if (Settings::IsConfiguringGlobal()) {
89 // Guard if during game and set to game-specific value
90 if (Settings::values.cpu_accuracy.UsingGlobal()) {
91 Settings::values.cpu_accuracy.SetValue(
92 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()));
93 }
94 } else {
95 if (ui->accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
96 Settings::values.cpu_accuracy.SetGlobal(true);
97 } else {
98 Settings::values.cpu_accuracy.SetGlobal(false);
99 Settings::values.cpu_accuracy.SetValue(static_cast<Settings::CPUAccuracy>(
100 ui->accuracy->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
101 }
102 }
67} 103}
68 104
69void ConfigureCpu::changeEvent(QEvent* event) { 105void ConfigureCpu::changeEvent(QEvent* event) {
@@ -77,3 +113,25 @@ void ConfigureCpu::changeEvent(QEvent* event) {
77void ConfigureCpu::RetranslateUI() { 113void ConfigureCpu::RetranslateUI() {
78 ui->retranslateUi(this); 114 ui->retranslateUi(this);
79} 115}
116
117void ConfigureCpu::SetupPerGameUI() {
118 if (Settings::IsConfiguringGlobal()) {
119 return;
120 }
121
122 ConfigurationShared::SetColoredComboBox(
123 ui->accuracy, ui->widget_accuracy,
124 static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
125 ui->accuracy->removeItem(static_cast<u32>(Settings::CPUAccuracy::DebugMode) +
126 ConfigurationShared::USE_GLOBAL_OFFSET);
127
128 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
129 Settings::values.cpuopt_unsafe_unfuse_fma,
130 cpuopt_unsafe_unfuse_fma);
131 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_reduce_fp_error,
132 Settings::values.cpuopt_unsafe_reduce_fp_error,
133 cpuopt_unsafe_reduce_fp_error);
134 ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan,
135 Settings::values.cpuopt_unsafe_inaccurate_nan,
136 cpuopt_unsafe_inaccurate_nan);
137}
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index ef77b2e7e..8e2eeb7a6 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -8,6 +8,10 @@
8#include <QWidget> 8#include <QWidget>
9#include "common/settings.h" 9#include "common/settings.h"
10 10
11namespace ConfigurationShared {
12enum class CheckState;
13}
14
11namespace Ui { 15namespace Ui {
12class ConfigureCpu; 16class ConfigureCpu;
13} 17}
@@ -30,5 +34,11 @@ private:
30 34
31 void SetConfiguration(); 35 void SetConfiguration();
32 36
37 void SetupPerGameUI();
38
33 std::unique_ptr<Ui::ConfigureCpu> ui; 39 std::unique_ptr<Ui::ConfigureCpu> ui;
40
41 ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma;
42 ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error;
43 ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
34}; 44};
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index bcd0962e9..d0e7e7bfe 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -23,42 +23,44 @@
23 </property> 23 </property>
24 <layout class="QVBoxLayout"> 24 <layout class="QVBoxLayout">
25 <item> 25 <item>
26 <layout class="QHBoxLayout"> 26 <widget class="QWidget" name="widget_accuracy" native="true">
27 <item> 27 <layout class="QHBoxLayout" name="layout_accuracy">
28 <widget class="QLabel"> 28 <item>
29 <property name="text"> 29 <widget class="QLabel" name="label">
30 <string>Accuracy:</string>
31 </property>
32 </widget>
33 </item>
34 <item>
35 <widget class="QComboBox" name="accuracy">
36 <item>
37 <property name="text"> 30 <property name="text">
38 <string>Accurate</string> 31 <string>Accuracy:</string>
39 </property> 32 </property>
40 </item> 33 </widget>
41 <item> 34 </item>
42 <property name="text"> 35 <item>
43 <string>Unsafe</string> 36 <widget class="QComboBox" name="accuracy">
44 </property> 37 <item>
45 </item> 38 <property name="text">
46 <item> 39 <string>Accurate</string>
47 <property name="text"> 40 </property>
48 <string>Enable Debug Mode</string> 41 </item>
49 </property> 42 <item>
50 </item> 43 <property name="text">
51 </widget> 44 <string>Unsafe</string>
52 </item> 45 </property>
53 </layout> 46 </item>
47 <item>
48 <property name="text">
49 <string>Enable Debug Mode</string>
50 </property>
51 </item>
52 </widget>
53 </item>
54 </layout>
55 </widget>
54 </item> 56 </item>
55 <item> 57 <item>
56 <widget class="QLabel"> 58 <widget class="QLabel" name="label">
57 <property name="wordWrap">
58 <bool>1</bool>
59 </property>
60 <property name="text"> 59 <property name="text">
61 <string>We recommend setting accuracy to "Accurate".</string> 60 <string>We recommend setting accuracy to &quot;Accurate&quot;.</string>
61 </property>
62 <property name="wordWrap">
63 <bool>false</bool>
62 </property> 64 </property>
63 </widget> 65 </widget>
64 </item> 66 </item>
@@ -76,49 +78,49 @@
76 </property> 78 </property>
77 <layout class="QVBoxLayout"> 79 <layout class="QVBoxLayout">
78 <item> 80 <item>
79 <widget class="QLabel"> 81 <widget class="QLabel" name="label">
80 <property name="wordWrap">
81 <bool>1</bool>
82 </property>
83 <property name="text"> 82 <property name="text">
84 <string>These settings reduce accuracy for speed.</string> 83 <string>These settings reduce accuracy for speed.</string>
85 </property> 84 </property>
85 <property name="wordWrap">
86 <bool>false</bool>
87 </property>
86 </widget> 88 </widget>
87 </item> 89 </item>
88 <item> 90 <item>
89 <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma"> 91 <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
90 <property name="text">
91 <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
92 </property>
93 <property name="toolTip"> 92 <property name="toolTip">
94 <string> 93 <string>
95 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt; 94 &lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
96 </string> 95 </string>
97 </property> 96 </property>
97 <property name="text">
98 <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
99 </property>
98 </widget> 100 </widget>
99 </item> 101 </item>
100 <item> 102 <item>
101 <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error"> 103 <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
102 <property name="text">
103 <string>Faster FRSQRTE and FRECPE</string>
104 </property>
105 <property name="toolTip"> 104 <property name="toolTip">
106 <string> 105 <string>
107 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt; 106 &lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
108 </string> 107 </string>
109 </property> 108 </property>
109 <property name="text">
110 <string>Faster FRSQRTE and FRECPE</string>
111 </property>
110 </widget> 112 </widget>
111 </item> 113 </item>
112 <item> 114 <item>
113 <widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan"> 115 <widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan">
114 <property name="text">
115 <string>Inaccurate NaN handling</string>
116 </property>
117 <property name="toolTip"> 116 <property name="toolTip">
118 <string> 117 <string>
119 &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt; 118 &lt;div&gt;This option improves speed by removing NaN checking. Please note this also reduces accuracy of certain floating-point instructions.&lt;/div&gt;
120 </string> 119 </string>
121 </property> 120 </property>
121 <property name="text">
122 <string>Inaccurate NaN handling</string>
123 </property>
122 </widget> 124 </widget>
123 </item> 125 </item>
124 </layout> 126 </layout>
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index d812858b6..c9e60ee08 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -23,7 +23,7 @@
23 <item> 23 <item>
24 <layout class="QHBoxLayout" name="horizontalLayout_2"> 24 <layout class="QHBoxLayout" name="horizontalLayout_2">
25 <item> 25 <item>
26 <widget class="QLabel" name="label_2"> 26 <widget class="QLabel" name="label_1">
27 <property name="text"> 27 <property name="text">
28 <string>Global Log Filter</string> 28 <string>Global Log Filter</string>
29 </property> 29 </property>
@@ -66,7 +66,7 @@
66 </widget> 66 </widget>
67 </item> 67 </item>
68 <item> 68 <item>
69 <widget class="QLabel" name="label_3"> 69 <widget class="QLabel" name="label_2">
70 <property name="font"> 70 <property name="font">
71 <font> 71 <font>
72 <italic>true</italic> 72 <italic>true</italic>
@@ -92,7 +92,7 @@
92 <item> 92 <item>
93 <layout class="QHBoxLayout" name="horizontalLayout_4"> 93 <layout class="QHBoxLayout" name="horizontalLayout_4">
94 <item> 94 <item>
95 <widget class="QLabel" name="label_4"> 95 <widget class="QLabel" name="label_3">
96 <property name="text"> 96 <property name="text">
97 <string>Arguments String</string> 97 <string>Arguments String</string>
98 </property> 98 </property>
@@ -155,7 +155,7 @@
155 </widget> 155 </widget>
156 </item> 156 </item>
157 <item> 157 <item>
158 <widget class="QLabel" name="label_5"> 158 <widget class="QLabel" name="label_4">
159 <property name="font"> 159 <property name="font">
160 <font> 160 <font>
161 <italic>true</italic> 161 <italic>true</italic>
@@ -200,7 +200,7 @@
200 </widget> 200 </widget>
201 </item> 201 </item>
202 <item> 202 <item>
203 <widget class="QLabel" name="label_3"> 203 <widget class="QLabel" name="label_5">
204 <property name="font"> 204 <property name="font">
205 <font> 205 <font>
206 <italic>true</italic> 206 <italic>true</italic>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 2fa88dcec..55a6a37bd 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -50,6 +50,9 @@ void ConfigureGeneral::SetConfiguration() {
50} 50}
51 51
52void ConfigureGeneral::ApplyConfiguration() { 52void ConfigureGeneral::ApplyConfiguration() {
53 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
54 use_multi_core);
55
53 if (Settings::IsConfiguringGlobal()) { 56 if (Settings::IsConfiguringGlobal()) {
54 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); 57 UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
55 UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); 58 UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
@@ -62,13 +65,7 @@ void ConfigureGeneral::ApplyConfiguration() {
62 Qt::Checked); 65 Qt::Checked);
63 Settings::values.frame_limit.SetValue(ui->frame_limit->value()); 66 Settings::values.frame_limit.SetValue(ui->frame_limit->value());
64 } 67 }
65 if (Settings::values.use_multi_core.UsingGlobal()) {
66 Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
67 }
68 } else { 68 } else {
69 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
70 ui->use_multi_core, use_multi_core);
71
72 bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global; 69 bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global;
73 Settings::values.use_frame_limit.SetGlobal(global_frame_limit); 70 Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
74 Settings::values.frame_limit.SetGlobal(global_frame_limit); 71 Settings::values.frame_limit.SetGlobal(global_frame_limit);
@@ -94,6 +91,9 @@ void ConfigureGeneral::RetranslateUI() {
94 91
95void ConfigureGeneral::SetupPerGameUI() { 92void ConfigureGeneral::SetupPerGameUI() {
96 if (Settings::IsConfiguringGlobal()) { 93 if (Settings::IsConfiguringGlobal()) {
94 // Disables each setting if:
95 // - A game is running (thus settings in use), and
96 // - A non-global setting is applied.
97 ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal()); 97 ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
98 ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal()); 98 ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
99 99
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 0a7536617..fb9ec093c 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -106,6 +106,19 @@ void ConfigureGraphics::SetConfiguration() {
106} 106}
107 107
108void ConfigureGraphics::ApplyConfiguration() { 108void ConfigureGraphics::ApplyConfiguration() {
109 ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
110 ui->fullscreen_mode_combobox);
111 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
112 ui->aspect_ratio_combobox);
113
114 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
115 ui->use_disk_shader_cache, use_disk_shader_cache);
116 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
117 ui->use_asynchronous_gpu_emulation,
118 use_asynchronous_gpu_emulation);
119 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
120 ui->use_nvdec_emulation, use_nvdec_emulation);
121
109 if (Settings::IsConfiguringGlobal()) { 122 if (Settings::IsConfiguringGlobal()) {
110 // Guard if during game and set to game-specific value 123 // Guard if during game and set to game-specific value
111 if (Settings::values.renderer_backend.UsingGlobal()) { 124 if (Settings::values.renderer_backend.UsingGlobal()) {
@@ -114,22 +127,6 @@ void ConfigureGraphics::ApplyConfiguration() {
114 if (Settings::values.vulkan_device.UsingGlobal()) { 127 if (Settings::values.vulkan_device.UsingGlobal()) {
115 Settings::values.vulkan_device.SetValue(vulkan_device); 128 Settings::values.vulkan_device.SetValue(vulkan_device);
116 } 129 }
117 if (Settings::values.fullscreen_mode.UsingGlobal()) {
118 Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
119 }
120 if (Settings::values.aspect_ratio.UsingGlobal()) {
121 Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
122 }
123 if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
124 Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
125 }
126 if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
127 Settings::values.use_asynchronous_gpu_emulation.SetValue(
128 ui->use_asynchronous_gpu_emulation->isChecked());
129 }
130 if (Settings::values.use_nvdec_emulation.UsingGlobal()) {
131 Settings::values.use_nvdec_emulation.SetValue(ui->use_nvdec_emulation->isChecked());
132 }
133 if (Settings::values.bg_red.UsingGlobal()) { 130 if (Settings::values.bg_red.UsingGlobal()) {
134 Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF())); 131 Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
135 Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF())); 132 Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
@@ -150,19 +147,6 @@ void ConfigureGraphics::ApplyConfiguration() {
150 } 147 }
151 } 148 }
152 149
153 ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
154 ui->fullscreen_mode_combobox);
155 ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
156 ui->aspect_ratio_combobox);
157
158 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
159 ui->use_disk_shader_cache, use_disk_shader_cache);
160 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
161 ui->use_asynchronous_gpu_emulation,
162 use_asynchronous_gpu_emulation);
163 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
164 ui->use_nvdec_emulation, use_nvdec_emulation);
165
166 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 150 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
167 Settings::values.bg_red.SetGlobal(true); 151 Settings::values.bg_red.SetGlobal(true);
168 Settings::values.bg_green.SetGlobal(true); 152 Settings::values.bg_green.SetGlobal(true);
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index c67609b0e..35bf9c6be 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -54,47 +54,23 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
54 ui->gpu_accuracy->currentIndex() - 54 ui->gpu_accuracy->currentIndex() -
55 ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET)); 55 ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
56 56
57 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
58 ui->anisotropic_filtering_combobox);
59 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
60 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
61 ui->use_assembly_shaders, use_assembly_shaders);
62 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
63 ui->use_asynchronous_shaders,
64 use_asynchronous_shaders);
65 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
66 ui->use_fast_gpu_time, use_fast_gpu_time);
67
57 if (Settings::IsConfiguringGlobal()) { 68 if (Settings::IsConfiguringGlobal()) {
58 // Must guard in case of a during-game configuration when set to be game-specific. 69 // Must guard in case of a during-game configuration when set to be game-specific.
59 if (Settings::values.gpu_accuracy.UsingGlobal()) { 70 if (Settings::values.gpu_accuracy.UsingGlobal()) {
60 Settings::values.gpu_accuracy.SetValue(gpu_accuracy); 71 Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
61 } 72 }
62 if (Settings::values.use_vsync.UsingGlobal()) {
63 Settings::values.use_vsync.SetValue(ui->use_vsync->isChecked());
64 }
65 if (Settings::values.use_assembly_shaders.UsingGlobal()) {
66 Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
67 }
68 if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
69 Settings::values.use_asynchronous_shaders.SetValue(
70 ui->use_asynchronous_shaders->isChecked());
71 }
72 if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
73 Settings::values.use_asynchronous_shaders.SetValue(
74 ui->use_asynchronous_shaders->isChecked());
75 }
76 if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
77 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
78 }
79 if (Settings::values.max_anisotropy.UsingGlobal()) {
80 Settings::values.max_anisotropy.SetValue(
81 ui->anisotropic_filtering_combobox->currentIndex());
82 }
83 } else { 73 } else {
84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
85 ui->anisotropic_filtering_combobox);
86 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync,
87 use_vsync);
88 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
89 ui->use_assembly_shaders, use_assembly_shaders);
90 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
91 ui->use_asynchronous_shaders,
92 use_asynchronous_shaders);
93 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
94 ui->use_fast_gpu_time, use_fast_gpu_time);
95 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
96 ui->anisotropic_filtering_combobox);
97
98 if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 74 if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
99 Settings::values.gpu_accuracy.SetGlobal(true); 75 Settings::values.gpu_accuracy.SetGlobal(true);
100 } else { 76 } else {
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_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index bd91ebc42..f550567e2 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -52,6 +52,7 @@ ConfigurePerGame::~ConfigurePerGame() = default;
52void ConfigurePerGame::ApplyConfiguration() { 52void ConfigurePerGame::ApplyConfiguration() {
53 ui->addonsTab->ApplyConfiguration(); 53 ui->addonsTab->ApplyConfiguration();
54 ui->generalTab->ApplyConfiguration(); 54 ui->generalTab->ApplyConfiguration();
55 ui->cpuTab->ApplyConfiguration();
55 ui->systemTab->ApplyConfiguration(); 56 ui->systemTab->ApplyConfiguration();
56 ui->graphicsTab->ApplyConfiguration(); 57 ui->graphicsTab->ApplyConfiguration();
57 ui->graphicsAdvancedTab->ApplyConfiguration(); 58 ui->graphicsAdvancedTab->ApplyConfiguration();
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
index 25975b3b9..adf6d0b39 100644
--- a/src/yuzu/configuration/configure_per_game.ui
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -235,6 +235,11 @@
235 <string>System</string> 235 <string>System</string>
236 </attribute> 236 </attribute>
237 </widget> 237 </widget>
238 <widget class="ConfigureCpu" name="cpuTab">
239 <attribute name="title">
240 <string>CPU</string>
241 </attribute>
242 </widget>
238 <widget class="ConfigureGraphics" name="graphicsTab"> 243 <widget class="ConfigureGraphics" name="graphicsTab">
239 <attribute name="title"> 244 <attribute name="title">
240 <string>Graphics</string> 245 <string>Graphics</string>
@@ -311,6 +316,12 @@
311 <header>configuration/configure_per_game_addons.h</header> 316 <header>configuration/configure_per_game_addons.h</header>
312 <container>1</container> 317 <container>1</container>
313 </customwidget> 318 </customwidget>
319 <customwidget>
320 <class>ConfigureCpu</class>
321 <extends>QWidget</extends>
322 <header>configuration/configure_cpu.h</header>
323 <container>1</container>
324 </customwidget>
314 </customwidgets> 325 </customwidgets>
315 <resources/> 326 <resources/>
316 <connections> 327 <connections>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 268ed44c3..85418f969 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -65,7 +65,7 @@ void ConfigureSystem::SetConfiguration() {
65 QStringLiteral("%1") 65 QStringLiteral("%1")
66 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'}) 66 .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
67 .toUpper(); 67 .toUpper();
68 const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or( 68 const auto rtc_time = Settings::values.custom_rtc.value_or(
69 std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); 69 std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
70 70
71 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value()); 71 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
@@ -73,9 +73,8 @@ void ConfigureSystem::SetConfiguration() {
73 Settings::values.rng_seed.UsingGlobal()); 73 Settings::values.rng_seed.UsingGlobal());
74 ui->rng_seed_edit->setText(rng_seed); 74 ui->rng_seed_edit->setText(rng_seed);
75 75
76 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value()); 76 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
77 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() && 77 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
78 Settings::values.rng_seed.UsingGlobal());
79 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); 78 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
80 79
81 if (Settings::IsConfiguringGlobal()) { 80 if (Settings::IsConfiguringGlobal()) {
@@ -109,17 +108,17 @@ void ConfigureSystem::ApplyConfiguration() {
109 108
110 // Allow setting custom RTC even if system is powered on, 109 // Allow setting custom RTC even if system is powered on,
111 // to allow in-game time to be fast forwarded 110 // to allow in-game time to be fast forwarded
112 if (Settings::values.custom_rtc.UsingGlobal()) { 111 if (Settings::IsConfiguringGlobal()) {
113 if (ui->custom_rtc_checkbox->isChecked()) { 112 if (ui->custom_rtc_checkbox->isChecked()) {
114 Settings::values.custom_rtc.SetValue( 113 Settings::values.custom_rtc =
115 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch())); 114 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
116 if (system.IsPoweredOn()) { 115 if (system.IsPoweredOn()) {
117 const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() + 116 const s64 posix_time{Settings::values.custom_rtc->count() +
118 Service::Time::TimeManager::GetExternalTimeZoneOffset()}; 117 Service::Time::TimeManager::GetExternalTimeZoneOffset()};
119 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time); 118 system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
120 } 119 }
121 } else { 120 } else {
122 Settings::values.custom_rtc.SetValue(std::nullopt); 121 Settings::values.custom_rtc = std::nullopt;
123 } 122 }
124 } 123 }
125 124
@@ -127,21 +126,14 @@ void ConfigureSystem::ApplyConfiguration() {
127 return; 126 return;
128 } 127 }
129 128
129 ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index, ui->combo_language);
130 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
131 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
132 ui->combo_time_zone);
133 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
134
130 if (Settings::IsConfiguringGlobal()) { 135 if (Settings::IsConfiguringGlobal()) {
131 // Guard if during game and set to game-specific value 136 // Guard if during game and set to game-specific value
132 if (Settings::values.language_index.UsingGlobal()) {
133 Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
134 }
135 if (Settings::values.region_index.UsingGlobal()) {
136 Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
137 }
138 if (Settings::values.time_zone_index.UsingGlobal()) {
139 Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
140 }
141 if (Settings::values.sound_index.UsingGlobal()) {
142 Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
143 }
144
145 if (Settings::values.rng_seed.UsingGlobal()) { 137 if (Settings::values.rng_seed.UsingGlobal()) {
146 if (ui->rng_seed_checkbox->isChecked()) { 138 if (ui->rng_seed_checkbox->isChecked()) {
147 Settings::values.rng_seed.SetValue( 139 Settings::values.rng_seed.SetValue(
@@ -151,13 +143,6 @@ void ConfigureSystem::ApplyConfiguration() {
151 } 143 }
152 } 144 }
153 } else { 145 } else {
154 ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
155 ui->combo_language);
156 ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
157 ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
158 ui->combo_time_zone);
159 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
160
161 switch (use_rng_seed) { 146 switch (use_rng_seed) {
162 case ConfigurationShared::CheckState::On: 147 case ConfigurationShared::CheckState::On:
163 case ConfigurationShared::CheckState::Off: 148 case ConfigurationShared::CheckState::Off:
@@ -177,26 +162,6 @@ void ConfigureSystem::ApplyConfiguration() {
177 case ConfigurationShared::CheckState::Count: 162 case ConfigurationShared::CheckState::Count:
178 break; 163 break;
179 } 164 }
180
181 switch (use_custom_rtc) {
182 case ConfigurationShared::CheckState::On:
183 case ConfigurationShared::CheckState::Off:
184 Settings::values.custom_rtc.SetGlobal(false);
185 if (ui->custom_rtc_checkbox->isChecked()) {
186 Settings::values.custom_rtc.SetValue(
187 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
188 } else {
189 Settings::values.custom_rtc.SetValue(std::nullopt);
190 }
191 break;
192 case ConfigurationShared::CheckState::Global:
193 Settings::values.custom_rtc.SetGlobal(false);
194 Settings::values.custom_rtc.SetValue(std::nullopt);
195 Settings::values.custom_rtc.SetGlobal(true);
196 break;
197 case ConfigurationShared::CheckState::Count:
198 break;
199 }
200 } 165 }
201 166
202 system.ApplySettings(); 167 system.ApplySettings();
@@ -227,8 +192,6 @@ void ConfigureSystem::SetupPerGameUI() {
227 ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal()); 192 ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
228 ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal()); 193 ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
229 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal()); 194 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
230 ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
231 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
232 195
233 return; 196 return;
234 } 197 }
@@ -246,8 +209,7 @@ void ConfigureSystem::SetupPerGameUI() {
246 ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(), 209 ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(),
247 Settings::values.rng_seed.GetValue().has_value(), 210 Settings::values.rng_seed.GetValue().has_value(),
248 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed); 211 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
249 ConfigurationShared::SetColoredTristate( 212
250 ui->custom_rtc_checkbox, Settings::values.custom_rtc.UsingGlobal(), 213 ui->custom_rtc_checkbox->setVisible(false);
251 Settings::values.custom_rtc.GetValue().has_value(), 214 ui->custom_rtc_edit->setVisible(false);
252 Settings::values.custom_rtc.GetValue(true).has_value(), use_custom_rtc);
253} 215}
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/game_list.cpp b/src/yuzu/game_list.cpp
index 48b78d65f..63cf82f7d 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -85,8 +85,8 @@ void GameListSearchField::setFilterResult(int visible, int total) {
85 label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); 85 label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
86} 86}
87 87
88bool GameListSearchField::isEmpty() const { 88QString GameListSearchField::filterText() const {
89 return edit_filter->text().isEmpty(); 89 return edit_filter->text();
90} 90}
91 91
92QString GameList::GetLastFilterResultItem() const { 92QString GameList::GetLastFilterResultItem() const {
@@ -236,9 +236,9 @@ void GameList::OnTextChanged(const QString& new_text) {
236 } else { 236 } else {
237 tree_view->setRowHidden(j, folder_index, true); 237 tree_view->setRowHidden(j, folder_index, true);
238 } 238 }
239 search_field->setFilterResult(result_count, children_total);
240 } 239 }
241 } 240 }
241 search_field->setFilterResult(result_count, children_total);
242 } 242 }
243} 243}
244 244
@@ -595,6 +595,7 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
595 connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] { 595 connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] {
596 UISettings::values.game_dirs.removeOne(game_dir); 596 UISettings::values.game_dirs.removeOne(game_dir);
597 item_model->invisibleRootItem()->removeRow(selected.row()); 597 item_model->invisibleRootItem()->removeRow(selected.row());
598 OnTextChanged(search_field->filterText());
598 }); 599 });
599} 600}
600 601
@@ -622,7 +623,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
622 // move the treeview items 623 // move the treeview items
623 QList<QStandardItem*> item = item_model->takeRow(row); 624 QList<QStandardItem*> item = item_model->takeRow(row);
624 item_model->invisibleRootItem()->insertRow(row - 1, item); 625 item_model->invisibleRootItem()->insertRow(row - 1, item);
625 tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); 626 tree_view->setExpanded(selected.sibling(row - 1, 0),
627 UISettings::values.game_dirs[other_index].expanded);
626 }); 628 });
627 629
628 connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] { 630 connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] {
@@ -637,7 +639,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
637 // move the treeview items 639 // move the treeview items
638 const QList<QStandardItem*> item = item_model->takeRow(row); 640 const QList<QStandardItem*> item = item_model->takeRow(row);
639 item_model->invisibleRootItem()->insertRow(row + 1, item); 641 item_model->invisibleRootItem()->insertRow(row + 1, item);
640 tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded); 642 tree_view->setExpanded(selected.sibling(row + 1, 0),
643 UISettings::values.game_dirs[other_index].expanded);
641 }); 644 });
642 645
643 connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { 646 connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
@@ -774,7 +777,7 @@ void GameList::RefreshGameDirectory() {
774void GameList::ToggleFavorite(u64 program_id) { 777void GameList::ToggleFavorite(u64 program_id) {
775 if (!UISettings::values.favorited_ids.contains(program_id)) { 778 if (!UISettings::values.favorited_ids.contains(program_id)) {
776 tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), 779 tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(),
777 !search_field->isEmpty()); 780 !search_field->filterText().isEmpty());
778 UISettings::values.favorited_ids.append(program_id); 781 UISettings::values.favorited_ids.append(program_id);
779 AddFavorite(program_id); 782 AddFavorite(program_id);
780 item_model->sort(tree_view->header()->sortIndicatorSection(), 783 item_model->sort(tree_view->header()->sortIndicatorSection(),
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index 7ca8ece23..978d27325 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -346,8 +346,8 @@ class GameListSearchField : public QWidget {
346public: 346public:
347 explicit GameListSearchField(GameList* parent = nullptr); 347 explicit GameListSearchField(GameList* parent = nullptr);
348 348
349 QString filterText() const;
349 void setFilterResult(int visible, int total); 350 void setFilterResult(int visible, int total);
350 bool isEmpty() const;
351 351
352 void clear(); 352 void clear();
353 void setFocus(); 353 void setFocus();
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 5f6cdc0c6..9275cba53 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"
@@ -241,14 +241,15 @@ GMainWindow::GMainWindow()
241 ConnectMenuEvents(); 241 ConnectMenuEvents();
242 ConnectWidgetEvents(); 242 ConnectWidgetEvents();
243 243
244 const auto branch_name = std::string(Common::g_scm_branch);
245 const auto description = std::string(Common::g_scm_desc);
244 const auto build_id = std::string(Common::g_build_id); 246 const auto build_id = std::string(Common::g_build_id);
245 const auto fmt = std::string(Common::g_title_bar_format_idle);
246 const auto yuzu_build_version =
247 fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{},
248 std::string{}, std::string{}, std::string{}, build_id);
249 247
250 LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch, 248 const auto yuzu_build = fmt::format("yuzu Development Build | {}-{}", branch_name, description);
251 Common::g_scm_desc); 249 const auto override_build = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
250 const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
251
252 LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version);
252#ifdef ARCHITECTURE_x86_64 253#ifdef ARCHITECTURE_x86_64
253 const auto& caps = Common::GetCPUCaps(); 254 const auto& caps = Common::GetCPUCaps();
254 std::string cpu_string = caps.cpu_string; 255 std::string cpu_string = caps.cpu_string;
@@ -349,7 +350,7 @@ GMainWindow::GMainWindow()
349 continue; 350 continue;
350 } 351 }
351 352
352 Settings::values.current_user = selected_user; 353 Settings::values.current_user = static_cast<s32>(selected_user);
353 continue; 354 continue;
354 } 355 }
355 356
@@ -574,8 +575,8 @@ void GMainWindow::SoftwareKeyboardExit() {
574 software_keyboard = nullptr; 575 software_keyboard = nullptr;
575} 576}
576 577
577void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, 578void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
578 bool is_local) { 579 const std::string& additional_args, bool is_local) {
579#ifdef YUZU_USE_QT_WEB_ENGINE 580#ifdef YUZU_USE_QT_WEB_ENGINE
580 581
581 if (disable_web_applet) { 582 if (disable_web_applet) {
@@ -596,13 +597,15 @@ void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_v
596 loading_progress.setRange(0, 3); 597 loading_progress.setRange(0, 3);
597 loading_progress.setValue(0); 598 loading_progress.setValue(0);
598 599
599 if (is_local && !Common::FS::Exists(std::string(main_url))) { 600 if (is_local && !Common::FS::Exists(main_url)) {
600 loading_progress.show(); 601 loading_progress.show();
601 602
602 auto future = QtConcurrent::run([this] { emit WebBrowserExtractOfflineRomFS(); }); 603 auto future = QtConcurrent::run([this] { emit WebBrowserExtractOfflineRomFS(); });
603 604
604 while (!future.isFinished()) { 605 while (!future.isFinished()) {
605 QCoreApplication::processEvents(); 606 QCoreApplication::processEvents();
607
608 std::this_thread::sleep_for(std::chrono::milliseconds(1));
606 } 609 }
607 } 610 }
608 611
@@ -1375,7 +1378,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
1375 game_list->hide(); 1378 game_list->hide();
1376 game_list_placeholder->hide(); 1379 game_list_placeholder->hide();
1377 } 1380 }
1378 status_bar_update_timer.start(2000); 1381 status_bar_update_timer.start(500);
1379 async_status_button->setDisabled(true); 1382 async_status_button->setDisabled(true);
1380 multicore_status_button->setDisabled(true); 1383 multicore_status_button->setDisabled(true);
1381 renderer_status_button->setDisabled(true); 1384 renderer_status_button->setDisabled(true);
@@ -2099,6 +2102,7 @@ void GMainWindow::OnMenuInstallToNAND() {
2099 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND 2102 QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
2100 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND 2103 QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
2101 QStringList failed_files{}; // Files that failed to install due to errors 2104 QStringList failed_files{}; // Files that failed to install due to errors
2105 bool detected_base_install{}; // Whether a base game was attempted to be installed
2102 2106
2103 ui.action_Install_File_NAND->setEnabled(false); 2107 ui.action_Install_File_NAND->setEnabled(false);
2104 2108
@@ -2124,6 +2128,7 @@ void GMainWindow::OnMenuInstallToNAND() {
2124 2128
2125 while (!future.isFinished()) { 2129 while (!future.isFinished()) {
2126 QCoreApplication::processEvents(); 2130 QCoreApplication::processEvents();
2131 std::this_thread::sleep_for(std::chrono::milliseconds(1));
2127 } 2132 }
2128 2133
2129 result = future.result(); 2134 result = future.result();
@@ -2144,6 +2149,10 @@ void GMainWindow::OnMenuInstallToNAND() {
2144 case InstallResult::Failure: 2149 case InstallResult::Failure:
2145 failed_files.append(QFileInfo(file).fileName()); 2150 failed_files.append(QFileInfo(file).fileName());
2146 break; 2151 break;
2152 case InstallResult::BaseInstallAttempted:
2153 failed_files.append(QFileInfo(file).fileName());
2154 detected_base_install = true;
2155 break;
2147 } 2156 }
2148 2157
2149 --remaining; 2158 --remaining;
@@ -2151,6 +2160,13 @@ void GMainWindow::OnMenuInstallToNAND() {
2151 2160
2152 install_progress->close(); 2161 install_progress->close();
2153 2162
2163 if (detected_base_install) {
2164 QMessageBox::warning(
2165 this, tr("Install Results"),
2166 tr("To avoid possible conflicts, we discourage users from installing base games to the "
2167 "NAND.\nPlease, only use this feature to install updates and DLC."));
2168 }
2169
2154 const QString install_results = 2170 const QString install_results =
2155 (new_files.isEmpty() ? QString{} 2171 (new_files.isEmpty() ? QString{}
2156 : tr("%n file(s) were newly installed\n", "", new_files.size())) + 2172 : tr("%n file(s) were newly installed\n", "", new_files.size())) +
@@ -2212,11 +2228,14 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
2212 const auto res = 2228 const auto res =
2213 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry( 2229 Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
2214 *nsp, true, qt_raw_copy); 2230 *nsp, true, qt_raw_copy);
2215 if (res == FileSys::InstallResult::Success) { 2231 switch (res) {
2232 case FileSys::InstallResult::Success:
2216 return InstallResult::Success; 2233 return InstallResult::Success;
2217 } else if (res == FileSys::InstallResult::OverwriteExisting) { 2234 case FileSys::InstallResult::OverwriteExisting:
2218 return InstallResult::Overwrite; 2235 return InstallResult::Overwrite;
2219 } else { 2236 case FileSys::InstallResult::ErrorBaseInstall:
2237 return InstallResult::BaseInstallAttempted;
2238 default:
2220 return InstallResult::Failure; 2239 return InstallResult::Failure;
2221 } 2240 }
2222} 2241}
@@ -2749,24 +2768,19 @@ void GMainWindow::MigrateConfigFiles() {
2749 2768
2750void GMainWindow::UpdateWindowTitle(const std::string& title_name, 2769void GMainWindow::UpdateWindowTitle(const std::string& title_name,
2751 const std::string& title_version) { 2770 const std::string& title_version) {
2752 const auto full_name = std::string(Common::g_build_fullname);
2753 const auto branch_name = std::string(Common::g_scm_branch); 2771 const auto branch_name = std::string(Common::g_scm_branch);
2754 const auto description = std::string(Common::g_scm_desc); 2772 const auto description = std::string(Common::g_scm_desc);
2755 const auto build_id = std::string(Common::g_build_id); 2773 const auto build_id = std::string(Common::g_build_id);
2756 2774
2757 const auto date = 2775 const auto yuzu_title = fmt::format("yuzu | {}-{}", branch_name, description);
2758 QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString(); 2776 const auto override_title = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
2777 const auto window_title = override_title.empty() ? yuzu_title : override_title;
2759 2778
2760 if (title_name.empty()) { 2779 if (title_name.empty()) {
2761 const auto fmt = std::string(Common::g_title_bar_format_idle); 2780 setWindowTitle(QString::fromStdString(window_title));
2762 setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt,
2763 full_name, branch_name, description,
2764 std::string{}, date, build_id)));
2765 } else { 2781 } else {
2766 const auto fmt = std::string(Common::g_title_bar_format_running); 2782 const auto run_title = fmt::format("{} | {} | {}", window_title, title_name, title_version);
2767 setWindowTitle(QString::fromStdString( 2783 setWindowTitle(QString::fromStdString(run_title));
2768 fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name,
2769 description, title_name, date, build_id, title_version)));
2770 } 2784 }
2771} 2785}
2772 2786
@@ -2795,7 +2809,7 @@ void GMainWindow::UpdateStatusBar() {
2795 } else { 2809 } else {
2796 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); 2810 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
2797 } 2811 }
2798 game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); 2812 game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
2799 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); 2813 emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
2800 2814
2801 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); 2815 emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 7f1e50a5b..b3a5033ce 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -76,6 +76,7 @@ enum class InstallResult {
76 Success, 76 Success,
77 Overwrite, 77 Overwrite,
78 Failure, 78 Failure,
79 BaseInstallAttempted,
79}; 80};
80 81
81enum class ReinitializeKeyBehavior { 82enum class ReinitializeKeyBehavior {
@@ -159,7 +160,7 @@ public slots:
159 void SoftwareKeyboardExit(); 160 void SoftwareKeyboardExit();
160 void ErrorDisplayDisplayError(QString error_code, QString error_text); 161 void ErrorDisplayDisplayError(QString error_code, QString error_text);
161 void ProfileSelectorSelectProfile(); 162 void ProfileSelectorSelectProfile();
162 void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, 163 void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args,
163 bool is_local); 164 bool is_local);
164 void OnAppFocusStateChanged(Qt::ApplicationState state); 165 void OnAppFocusStateChanged(Qt::ApplicationState state);
165 166
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 7e1d5f379..38d896d65 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -361,10 +361,10 @@ void Config::ReadValues() {
361 361
362 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); 362 const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
363 if (custom_rtc_enabled) { 363 if (custom_rtc_enabled) {
364 Settings::values.custom_rtc.SetValue( 364 Settings::values.custom_rtc =
365 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0))); 365 std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0));
366 } else { 366 } else {
367 Settings::values.custom_rtc.SetValue(std::nullopt); 367 Settings::values.custom_rtc = std::nullopt;
368 } 368 }
369 369
370 Settings::values.language_index.SetValue( 370 Settings::values.language_index.SetValue(
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index d64f81106..06b20c975 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -215,7 +215,7 @@ void EmuWindow_SDL2::WaitEvent() {
215 const auto results = Core::System::GetInstance().GetAndResetPerfStats(); 215 const auto results = Core::System::GetInstance().GetAndResetPerfStats();
216 const auto title = 216 const auto title =
217 fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname, 217 fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname,
218 Common::g_scm_branch, Common::g_scm_desc, results.game_fps, 218 Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps,
219 results.emulation_speed * 100.0); 219 results.emulation_speed * 100.0);
220 SDL_SetWindowTitle(render_window, title.c_str()); 220 SDL_SetWindowTitle(render_window, title.c_str());
221 last_time = current_time; 221 last_time = current_time;
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"