summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
379 files changed, 7495 insertions, 4558 deletions
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"