summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/linux/docker.sh8
-rw-r--r--.ci/scripts/linux/upload.sh2
-rw-r--r--CMakeLists.txt36
-rw-r--r--dist/icons/overlay/osk_button_B.pngbin741 -> 2653 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark.pngbin767 -> 2721 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_dark_disabled.pngbin781 -> 2689 bytes
-rw-r--r--dist/icons/overlay/osk_button_B_disabled.pngbin791 -> 2694 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y.pngbin726 -> 2695 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark.pngbin502 -> 2073 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_dark_disabled.pngbin694 -> 2631 bytes
-rw-r--r--dist/icons/overlay/osk_button_Y_disabled.pngbin699 -> 2647 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus.pngbin626 -> 2226 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark.pngbin676 -> 2288 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_dark_disabled.pngbin645 -> 2233 bytes
-rw-r--r--dist/icons/overlay/osk_button_plus_disabled.pngbin664 -> 2254 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_off.pngbin281 -> 936 bytes
-rw-r--r--dist/icons/overlay/osk_button_shift_lock_on.pngbin274 -> 894 bytes
-rw-r--r--dist/qt_themes/default/style.qss36
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss36
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss36
-rw-r--r--externals/CMakeLists.txt15
m---------externals/SDL0
m---------externals/ffmpeg0
m---------externals/mbedtls0
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/common/common_funcs.h23
-rw-r--r--src/common/intrusive_red_black_tree.h1
-rw-r--r--src/common/parent_of_member.h11
-rw-r--r--src/common/settings.cpp9
-rw-r--r--src/common/settings.h10
-rw-r--r--src/common/tree.h2
-rw-r--r--src/core/CMakeLists.txt74
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp24
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp26
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp11
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.cpp4
-rw-r--r--src/core/arm/dynarmic/arm_exclusive_monitor.h2
-rw-r--r--src/core/core.cpp27
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/core_timing.cpp4
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/cpu_manager.h10
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp4
-rw-r--r--src/core/crypto/ctr_encryption_layer.h2
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/file_sys/card_image.cpp26
-rw-r--r--src/core/file_sys/content_archive.cpp21
-rw-r--r--src/core/file_sys/errors.h1
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp25
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h2
-rw-r--r--src/core/file_sys/nca_metadata.cpp8
-rw-r--r--src/core/file_sys/nca_metadata.h4
-rw-r--r--src/core/file_sys/nca_patch.cpp18
-rw-r--r--src/core/file_sys/registered_cache.cpp39
-rw-r--r--src/core/file_sys/registered_cache.h3
-rw-r--r--src/core/file_sys/romfs_factory.cpp6
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/savedata_factory.cpp20
-rw-r--r--src/core/file_sys/submission_package.cpp12
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs_concat.cpp10
-rw-r--r--src/core/file_sys/vfs_concat.h6
-rw-r--r--src/core/file_sys/vfs_layered.cpp24
-rw-r--r--src/core/file_sys/vfs_layered.h16
-rw-r--r--src/core/file_sys/vfs_libzip.cpp9
-rw-r--r--src/core/file_sys/vfs_offset.cpp4
-rw-r--r--src/core/file_sys/vfs_offset.h2
-rw-r--r--src/core/file_sys/vfs_real.cpp16
-rw-r--r--src/core/file_sys/vfs_real.h8
-rw-r--r--src/core/file_sys/vfs_static.h6
-rw-r--r--src/core/file_sys/vfs_vector.cpp16
-rw-r--r--src/core/file_sys/vfs_vector.h12
-rw-r--r--src/core/frontend/applets/web_browser.cpp4
-rw-r--r--src/core/frontend/applets/web_browser.h9
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/frontend/input.h12
-rw-r--r--src/core/hle/ipc.h17
-rw-r--r--src/core/hle/ipc_helpers.h151
-rw-r--r--src/core/hle/kernel/client_port.cpp47
-rw-r--r--src/core/hle/kernel/client_port.h63
-rw-r--r--src/core/hle/kernel/client_session.cpp53
-rw-r--r--src/core/hle/kernel/client_session.h68
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp10
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h10
-rw-r--r--src/core/hle/kernel/handle_table.cpp131
-rw-r--r--src/core/hle/kernel/handle_table.h144
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp199
-rw-r--r--src/core/hle/kernel/hle_ipc.h93
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp192
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.h43
-rw-r--r--src/core/hle/kernel/k_auto_object.cpp14
-rw-r--r--src/core/hle/kernel/k_auto_object.h302
-rw-r--r--src/core/hle/kernel/k_auto_object_container.cpp28
-rw-r--r--src/core/hle/kernel/k_auto_object_container.h70
-rw-r--r--src/core/hle/kernel/k_class_token.cpp133
-rw-r--r--src/core/hle/kernel/k_class_token.h131
-rw-r--r--src/core/hle/kernel/k_client_port.cpp125
-rw-r--r--src/core/hle/kernel/k_client_port.h61
-rw-r--r--src/core/hle/kernel/k_client_session.cpp32
-rw-r--r--src/core/hle/kernel/k_client_session.h61
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp34
-rw-r--r--src/core/hle/kernel/k_event.cpp46
-rw-r--r--src/core/hle/kernel/k_event.h45
-rw-r--r--src/core/hle/kernel/k_handle_table.cpp135
-rw-r--r--src/core/hle/kernel/k_handle_table.h310
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h3
-rw-r--r--src/core/hle/kernel/k_linked_list.h238
-rw-r--r--src/core/hle/kernel/k_memory_block.h4
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.cpp38
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.h2
-rw-r--r--src/core/hle/kernel/k_memory_region.h4
-rw-r--r--src/core/hle/kernel/k_page_linked_list.h2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp59
-rw-r--r--src/core/hle/kernel/k_page_table.h11
-rw-r--r--src/core/hle/kernel/k_port.cpp68
-rw-r--r--src/core/hle/kernel/k_port.h69
-rw-r--r--src/core/hle/kernel/k_process.cpp (renamed from src/core/hle/kernel/process.cpp)149
-rw-r--r--src/core/hle/kernel/k_process.h (renamed from src/core/hle/kernel/process.h)63
-rw-r--r--src/core/hle/kernel/k_readable_event.cpp15
-rw-r--r--src/core/hle/kernel/k_readable_event.h29
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp14
-rw-r--r--src/core/hle/kernel/k_resource_limit.h29
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp55
-rw-r--r--src/core/hle/kernel/k_scheduler.h12
-rw-r--r--src/core/hle/kernel/k_scoped_resource_reservation.h14
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h6
-rw-r--r--src/core/hle/kernel/k_server_port.cpp104
-rw-r--r--src/core/hle/kernel/k_server_port.h80
-rw-r--r--src/core/hle/kernel/k_server_session.cpp (renamed from src/core/hle/kernel/server_session.cpp)86
-rw-r--r--src/core/hle/kernel/k_server_session.h (renamed from src/core/hle/kernel/server_session.h)82
-rw-r--r--src/core/hle/kernel/k_session.cpp85
-rw-r--r--src/core/hle/kernel/k_session.h96
-rw-r--r--src/core/hle/kernel/k_shared_memory.cpp86
-rw-r--r--src/core/hle/kernel/k_shared_memory.h69
-rw-r--r--src/core/hle/kernel/k_slab_heap.h9
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp21
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h21
-rw-r--r--src/core/hle/kernel/k_thread.cpp145
-rw-r--r--src/core/hle/kernel/k_thread.h133
-rw-r--r--src/core/hle/kernel/k_thread_queue.h2
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp45
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h66
-rw-r--r--src/core/hle/kernel/k_writable_event.cpp19
-rw-r--r--src/core/hle/kernel/k_writable_event.h24
-rw-r--r--src/core/hle/kernel/kernel.cpp258
-rw-r--r--src/core/hle/kernel/kernel.h133
-rw-r--r--src/core/hle/kernel/object.cpp42
-rw-r--r--src/core/hle/kernel/object.h96
-rw-r--r--src/core/hle/kernel/physical_core.cpp8
-rw-r--r--src/core/hle/kernel/physical_core.h4
-rw-r--r--src/core/hle/kernel/process_capability.cpp18
-rw-r--r--src/core/hle/kernel/server_port.cpp54
-rw-r--r--src/core/hle/kernel/server_port.h98
-rw-r--r--src/core/hle/kernel/service_thread.cpp29
-rw-r--r--src/core/hle/kernel/service_thread.h4
-rw-r--r--src/core/hle/kernel/session.cpp41
-rw-r--r--src/core/hle/kernel/session.h64
-rw-r--r--src/core/hle/kernel/slab_helpers.h148
-rw-r--r--src/core/hle/kernel/svc.cpp1000
-rw-r--r--src/core/hle/kernel/svc_common.h15
-rw-r--r--src/core/hle/kernel/svc_results.h18
-rw-r--r--src/core/hle/kernel/svc_wrap.h56
-rw-r--r--src/core/hle/kernel/time_manager.cpp17
-rw-r--r--src/core/hle/kernel/time_manager.h2
-rw-r--r--src/core/hle/kernel/transfer_memory.cpp51
-rw-r--r--src/core/hle/kernel/transfer_memory.h93
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/acc/acc_aa.cpp8
-rw-r--r--src/core/hle/service/acc/acc_aa.h4
-rw-r--r--src/core/hle/service/acc/acc_su.cpp6
-rw-r--r--src/core/hle/service/acc/acc_su.h4
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u0.h4
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp6
-rw-r--r--src/core/hle/service/acc/acc_u1.h4
-rw-r--r--src/core/hle/service/am/am.cpp129
-rw-r--r--src/core/hle/service/am/am.h24
-rw-r--r--src/core/hle/service/am/applets/applets.cpp46
-rw-r--r--src/core/hle/service/am/applets/applets.h16
-rw-r--r--src/core/hle/service/am/applets/error.cpp8
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp4
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp6
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h2
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp2
-rw-r--r--src/core/hle/service/am/applets/web_browser.h9
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp24
-rw-r--r--src/core/hle/service/aoc/aoc_u.h3
-rw-r--r--src/core/hle/service/apm/controller.cpp10
-rw-r--r--src/core/hle/service/apm/controller.h2
-rw-r--r--src/core/hle/service/audio/audout_u.cpp16
-rw-r--r--src/core/hle/service/audio/audren_u.cpp64
-rw-r--r--src/core/hle/service/audio/audren_u.h2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp8
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp19
-rw-r--r--src/core/hle/service/bcat/backend/backend.h7
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp17
-rw-r--r--src/core/hle/service/bcat/bcat.cpp6
-rw-r--r--src/core/hle/service/bcat/bcat.h4
-rw-r--r--src/core/hle/service/bcat/module.cpp32
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp12
-rw-r--r--src/core/hle/service/btm/btm.cpp39
-rw-r--r--src/core/hle/service/fatal/fatal.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp11
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp23
-rw-r--r--src/core/hle/service/friend/friend.cpp12
-rw-r--r--src/core/hle/service/glue/arp.cpp2
-rw-r--r--src/core/hle/service/grc/grc.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.cpp90
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.h80
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h2
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h2
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp356
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h79
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp26
-rw-r--r--src/core/hle/service/hid/controllers/npad.h12
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp58
-rw-r--r--src/core/hle/service/hid/hid.h6
-rw-r--r--src/core/hle/service/hid/irs.cpp6
-rw-r--r--src/core/hle/service/hid/irs.h6
-rw-r--r--src/core/hle/service/lbl/lbl.cpp1
-rw-r--r--src/core/hle/service/ldr/ldr.cpp16
-rw-r--r--src/core/hle/service/mii/manager.h2
-rw-r--r--src/core/hle/service/mii/mii.cpp4
-rw-r--r--src/core/hle/service/mm/mm_u.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp39
-rw-r--r--src/core/hle/service/nfp/nfp.h5
-rw-r--r--src/core/hle/service/nifm/nifm.cpp18
-rw-r--r--src/core/hle/service/nim/nim.cpp17
-rw-r--r--src/core/hle/service/ns/pl_u.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp15
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h2
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp21
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp18
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h6
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.cpp2
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp25
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp50
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h18
-rw-r--r--src/core/hle/service/pctl/module.cpp13
-rw-r--r--src/core/hle/service/pctl/module.h4
-rw-r--r--src/core/hle/service/pctl/pctl.cpp4
-rw-r--r--src/core/hle/service/pctl/pctl.h2
-rw-r--r--src/core/hle/service/pm/pm.cpp27
-rw-r--r--src/core/hle/service/prepo/prepo.cpp10
-rw-r--r--src/core/hle/service/ptm/psm.cpp18
-rw-r--r--src/core/hle/service/service.cpp68
-rw-r--r--src/core/hle/service/service.h49
-rw-r--r--src/core/hle/service/set/set_sys.cpp2
-rw-r--r--src/core/hle/service/sm/controller.cpp22
-rw-r--r--src/core/hle/service/sm/sm.cpp164
-rw-r--r--src/core/hle/service/sm/sm.h35
-rw-r--r--src/core/hle/service/ssl/ssl.cpp42
-rw-r--r--src/core/hle/service/time/ephemeral_network_system_clock_core.h4
-rw-r--r--src/core/hle/service/time/interface.cpp4
-rw-r--r--src/core/hle/service/time/interface.h2
-rw-r--r--src/core/hle/service/time/local_system_clock_context_writer.h4
-rw-r--r--src/core/hle/service/time/network_system_clock_context_writer.h4
-rw-r--r--src/core/hle/service/time/standard_local_system_clock_core.h4
-rw-r--r--src/core/hle/service/time/standard_network_system_clock_core.h10
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.cpp33
-rw-r--r--src/core/hle/service/time/standard_user_system_clock_core.h13
-rw-r--r--src/core/hle/service/time/system_clock_core.cpp14
-rw-r--r--src/core/hle/service/time/system_clock_core.h4
-rw-r--r--src/core/hle/service/time/time.cpp5
-rw-r--r--src/core/hle/service/time/time_manager.cpp24
-rw-r--r--src/core/hle/service/time/time_manager.h2
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp20
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h10
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp4
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h2
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp39
-rw-r--r--src/core/hle/service/vi/display/vi_display.h38
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp2
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h4
-rw-r--r--src/core/hle/service/vi/vi.cpp28
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp71
-rw-r--r--src/core/loader/deconstructed_rom_directory.h23
-rw-r--r--src/core/loader/elf.cpp17
-rw-r--r--src/core/loader/elf.h12
-rw-r--r--src/core/loader/kip.cpp16
-rw-r--r--src/core/loader/kip.h12
-rw-r--r--src/core/loader/loader.cpp4
-rw-r--r--src/core/loader/loader.h63
-rw-r--r--src/core/loader/nax.cpp13
-rw-r--r--src/core/loader/nax.h14
-rw-r--r--src/core/loader/nca.cpp43
-rw-r--r--src/core/loader/nca.h14
-rw-r--r--src/core/loader/nro.cpp17
-rw-r--r--src/core/loader/nro.h18
-rw-r--r--src/core/loader/nso.cpp28
-rw-r--r--src/core/loader/nso.h22
-rw-r--r--src/core/loader/nsp.cpp57
-rw-r--r--src/core/loader/nsp.h20
-rw-r--r--src/core/loader/xci.cpp54
-rw-r--r--src/core/loader/xci.h20
-rw-r--r--src/core/memory.cpp64
-rw-r--r--src/core/memory.h34
-rw-r--r--src/core/memory/cheat_engine.cpp20
-rw-r--r--src/core/memory/cheat_engine.h10
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp3
-rw-r--r--src/core/memory/dmnt_cheat_vm.h2
-rw-r--r--src/core/perf_stats.cpp14
-rw-r--r--src/core/perf_stats.h11
-rw-r--r--src/core/reporter.cpp4
-rw-r--r--src/core/reporter.h2
-rw-r--r--src/core/tools/freezer.cpp4
-rw-r--r--src/core/tools/freezer.h2
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp8
-rw-r--r--src/input_common/gcadapter/gc_adapter.h1
-rw-r--r--src/input_common/main.cpp5
-rw-r--r--src/input_common/motion_input.cpp10
-rw-r--r--src/input_common/mouse/mouse_input.cpp9
-rw-r--r--src/input_common/mouse/mouse_input.h8
-rw-r--r--src/input_common/sdl/sdl.h3
-rw-r--r--src/input_common/sdl/sdl_impl.cpp153
-rw-r--r--src/input_common/sdl/sdl_impl.h1
-rw-r--r--src/input_common/udp/client.cpp23
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h5
-rw-r--r--src/video_core/gpu.cpp5
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/memory_manager.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.h8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp26
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h10
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp38
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h5
-rw-r--r--src/video_core/texture_cache/texture_cache.h57
-rw-r--r--src/video_core/texture_cache/types.h7
-rw-r--r--src/yuzu/about_dialog.cpp16
-rw-r--r--src/yuzu/aboutdialog.ui2
-rw-r--r--src/yuzu/applets/software_keyboard.cpp34
-rw-r--r--src/yuzu/applets/web_browser.cpp19
-rw-r--r--src/yuzu/applets/web_browser.h11
-rw-r--r--src/yuzu/bootmanager.cpp4
-rw-r--r--src/yuzu/configuration/config.cpp75
-rw-r--r--src/yuzu/configuration/config.h1
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp58
-rw-r--r--src/yuzu/configuration/configuration_shared.h34
-rw-r--r--src/yuzu/configuration/configure_audio.cpp10
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp86
-rw-r--r--src/yuzu/configuration/configure_cpu.h10
-rw-r--r--src/yuzu/configuration/configure_cpu.ui90
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu/configuration/configure_general.cpp12
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp42
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp46
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp8
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp1
-rw-r--r--src/yuzu/configuration/configure_per_game.ui11
-rw-r--r--src/yuzu/configuration/configure_system.cpp72
-rw-r--r--src/yuzu/configuration/configure_ui.cpp1
-rw-r--r--src/yuzu/debugger/wait_tree.cpp34
-rw-r--r--src/yuzu/debugger/wait_tree.h20
-rw-r--r--src/yuzu/game_list.cpp15
-rw-r--r--src/yuzu/game_list_p.h2
-rw-r--r--src/yuzu/main.cpp68
-rw-r--r--src/yuzu/main.h3
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp2
403 files changed, 7575 insertions, 4647 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh
index 1af5ded3d..9b451d3ab 100755
--- a/.ci/scripts/linux/docker.sh
+++ b/.ci/scripts/linux/docker.sh
@@ -30,10 +30,10 @@ make install DESTDIR=AppDir
rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester
# Download tools needed to build an AppImage
-wget -nc https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
-wget -nc https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
-wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-x86_64
-wget -nc https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/exec-x86_64.so
+wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-x86_64.AppImage
+wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/linuxdeploy-plugin-qt-x86_64.AppImage
+wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/AppRun-patched-x86_64
+wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so
# Set executable bit
chmod 755 \
AppRun-patched-x86_64 \
diff --git a/.ci/scripts/linux/upload.sh b/.ci/scripts/linux/upload.sh
index b2ea07388..208cd0d04 100644
--- a/.ci/scripts/linux/upload.sh
+++ b/.ci/scripts/linux/upload.sh
@@ -21,7 +21,7 @@ cp build/bin/yuzu "$DIR_NAME"
# Build an AppImage
cd build
-wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
+wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/appimagetool-x86_64.AppImage
chmod 755 appimagetool-x86_64.AppImage
if [ "${RELEASE_NAME}" = "mainline" ]; then
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 15ecb8a9c..3faa2b5ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,8 @@ project(yuzu)
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
+# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
+CMAKE_DEPENDENT_OPTION(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" NOT UNIX "ENABLE_SDL2" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
@@ -202,7 +204,7 @@ macro(yuzu_find_packages)
endmacro()
if (NOT YUZU_USE_BUNDLED_BOOST)
- find_package(Boost 1.73.0 COMPONENTS context headers QUIET)
+ find_package(Boost 1.73.0 CONFIG COMPONENTS context headers QUIET)
endif()
if (Boost_FOUND)
set(Boost_LIBRARIES Boost::boost)
@@ -224,7 +226,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST)
download_bundled_external("boost/" ${Boost_EXT_NAME} "")
set(Boost_USE_DEBUG_RUNTIME FALSE)
set(Boost_USE_STATIC_LIBS ON)
- find_package(Boost 1.75.0 REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH)
+ find_package(Boost 1.75.0 CONFIG REQUIRED COMPONENTS context headers PATHS ${Boost_PATH} NO_DEFAULT_PATH)
# Manually set the include dirs since the find_package sets it incorrectly
set(Boost_INCLUDE_DIRS ${Boost_PATH}/include CACHE PATH "Path to Boost headers" FORCE)
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
@@ -274,7 +276,7 @@ if (ENABLE_SDL2)
if (YUZU_USE_BUNDLED_SDL2)
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
- set(SDL2_VER "SDL2-2.0.14")
+ set(SDL2_VER "SDL2-2.0.15-prerelease")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
endif()
@@ -292,20 +294,24 @@ if (ENABLE_SDL2)
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
else()
- find_package(SDL2 2.0.14 QUIET)
-
- if (SDL2_FOUND)
- # Some installations don't set SDL2_LIBRARIES
- if("${SDL2_LIBRARIES}" STREQUAL "")
- message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
- set(SDL2_LIBRARIES "SDL2::SDL2")
+ if (YUZU_ALLOW_SYSTEM_SDL2)
+ find_package(SDL2 2.0.15 QUIET)
+
+ if (SDL2_FOUND)
+ # Some installations don't set SDL2_LIBRARIES
+ if("${SDL2_LIBRARIES}" STREQUAL "")
+ message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
+ set(SDL2_LIBRARIES "SDL2::SDL2")
+ endif()
+
+ include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
+ add_library(SDL2 INTERFACE)
+ target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
+ else()
+ message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.")
endif()
-
- include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
- add_library(SDL2 INTERFACE)
- target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
else()
- message(STATUS "SDL2 2.0.14 or newer not found, falling back to externals.")
+ message(STATUS "Using SDL2 from externals.")
endif()
endif()
endif()
diff --git a/dist/icons/overlay/osk_button_B.png b/dist/icons/overlay/osk_button_B.png
index f4a041178..2664b5923 100644
--- a/dist/icons/overlay/osk_button_B.png
+++ b/dist/icons/overlay/osk_button_B.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark.png b/dist/icons/overlay/osk_button_B_dark.png
index 2d2bffcca..1bd374571 100644
--- a/dist/icons/overlay/osk_button_B_dark.png
+++ b/dist/icons/overlay/osk_button_B_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_dark_disabled.png b/dist/icons/overlay/osk_button_B_dark_disabled.png
index 93c102b1b..3b88e393c 100644
--- a/dist/icons/overlay/osk_button_B_dark_disabled.png
+++ b/dist/icons/overlay/osk_button_B_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_B_disabled.png b/dist/icons/overlay/osk_button_B_disabled.png
index 5900982f6..0f35cd8f2 100644
--- a/dist/icons/overlay/osk_button_B_disabled.png
+++ b/dist/icons/overlay/osk_button_B_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y.png b/dist/icons/overlay/osk_button_Y.png
index b08b4e26b..2cd193481 100644
--- a/dist/icons/overlay/osk_button_Y.png
+++ b/dist/icons/overlay/osk_button_Y.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark.png b/dist/icons/overlay/osk_button_Y_dark.png
index 1fba9ca93..0cce567d3 100644
--- a/dist/icons/overlay/osk_button_Y_dark.png
+++ b/dist/icons/overlay/osk_button_Y_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_dark_disabled.png b/dist/icons/overlay/osk_button_Y_dark_disabled.png
index 6ce53f9e4..de619efa3 100644
--- a/dist/icons/overlay/osk_button_Y_dark_disabled.png
+++ b/dist/icons/overlay/osk_button_Y_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_Y_disabled.png b/dist/icons/overlay/osk_button_Y_disabled.png
index 25db07f66..8d607bc12 100644
--- a/dist/icons/overlay/osk_button_Y_disabled.png
+++ b/dist/icons/overlay/osk_button_Y_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus.png b/dist/icons/overlay/osk_button_plus.png
index 5baa5201e..9f9787419 100644
--- a/dist/icons/overlay/osk_button_plus.png
+++ b/dist/icons/overlay/osk_button_plus.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark.png b/dist/icons/overlay/osk_button_plus_dark.png
index 4cadb438b..dbe7b0c66 100644
--- a/dist/icons/overlay/osk_button_plus_dark.png
+++ b/dist/icons/overlay/osk_button_plus_dark.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_dark_disabled.png b/dist/icons/overlay/osk_button_plus_dark_disabled.png
index b8eb8dc3d..a79af6501 100644
--- a/dist/icons/overlay/osk_button_plus_dark_disabled.png
+++ b/dist/icons/overlay/osk_button_plus_dark_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_plus_disabled.png b/dist/icons/overlay/osk_button_plus_disabled.png
index c23e9d95d..52ace8eca 100644
--- a/dist/icons/overlay/osk_button_plus_disabled.png
+++ b/dist/icons/overlay/osk_button_plus_disabled.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_off.png b/dist/icons/overlay/osk_button_shift_lock_off.png
index 585500b3a..b506f456f 100644
--- a/dist/icons/overlay/osk_button_shift_lock_off.png
+++ b/dist/icons/overlay/osk_button_shift_lock_off.png
Binary files differ
diff --git a/dist/icons/overlay/osk_button_shift_lock_on.png b/dist/icons/overlay/osk_button_shift_lock_on.png
index 09077ab01..eaa4e98ed 100644
--- a/dist/icons/overlay/osk_button_shift_lock_on.png
+++ b/dist/icons/overlay/osk_button_shift_lock_on.png
Binary files differ
diff --git a/dist/qt_themes/default/style.qss b/dist/qt_themes/default/style.qss
index 3bc92b69d..cee219374 100644
--- a/dist/qt_themes/default/style.qss
+++ b/dist/qt_themes/default/style.qss
@@ -515,45 +515,35 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_B.png);
+ image: url(:/overlay/osk_button_B.png);
+ image-position: right;
qproperty-icon: url(:/overlay/osk_button_backspace.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_Y.png);
+ image: url(:/overlay/osk_button_Y.png);
+ image-position: right;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_plus.png);
+ image: url(:/overlay/osk_button_plus.png);
+ image-position: right;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
- background-position: left top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ image: url(:/overlay/osk_button_shift_lock_off.png);
+ image-position: left;
qproperty-icon: url(:/overlay/osk_button_shift.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
- background-position: left top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ image: url(:/overlay/osk_button_shift_lock_off.png);
+ image-position: left;
qproperty-icon: url(:/overlay/osk_button_shift_on.png);
qproperty-iconSize: 36px;
}
@@ -645,16 +635,16 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
- background-image: url(:/overlay/osk_button_plus_disabled.png);
+ image: url(:/overlay/osk_button_plus_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
- background-image: url(:/overlay/osk_button_B_disabled.png);
+ image: url(:/overlay/osk_button_B_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
- background-image: url(:/overlay/osk_button_Y_disabled.png);
+ image: url(:/overlay/osk_button_Y_disabled.png);
}
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 8ce6d75f7..3d0ccbb9e 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -1805,46 +1805,36 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_B_dark.png);
+ image: url(:/overlay/osk_button_B_dark.png);
+ image-position: right;
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_Y_dark.png);
+ image: url(:/overlay/osk_button_Y_dark.png);
+ image-position: right;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(44, 44, 44, 1);
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_plus_dark.png);
+ image: url(:/overlay/osk_button_plus_dark.png);
+ image-position: right;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
- background-position: left top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ image: url(:/overlay/osk_button_shift_lock_off.png);
+ image-position: left;
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
- background-position: left top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ image: url(:/overlay/osk_button_shift_lock_off.png);
+ image-position: left;
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
qproperty-iconSize: 36px;
}
@@ -1936,18 +1926,18 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
- background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
+ image: url(:/overlay/osk_button_plus_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
- background-image: url(:/overlay/osk_button_B_dark_disabled.png);
+ image: url(:/overlay/osk_button_B_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
- background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
+ image: url(:/overlay/osk_button_Y_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QFrame,
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index 64e1ecbcc..51bec2fd7 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -2740,46 +2740,36 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_B_dark.png);
+ image: url(:/overlay/osk_button_B_dark.png);
+ image-position: right;
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_Y_dark.png);
+ image: url(:/overlay/osk_button_Y_dark.png);
+ image-position: right;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(44, 44, 44, 1);
- background-position: right top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_plus_dark.png);
+ image: url(:/overlay/osk_button_plus_dark.png);
+ image-position: right;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
- background-position: left top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ image: url(:/overlay/osk_button_shift_lock_off.png);
+ image-position: left;
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
- background-position: left top;
- background-repeat: no-repeat;
- background-origin: content;
- background-image: url(:/overlay/osk_button_shift_lock_off.png);
+ image: url(:/overlay/osk_button_shift_lock_off.png);
+ image-position: left;
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
qproperty-iconSize: 36px;
}
@@ -2871,16 +2861,16 @@ QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
- background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
+ image: url(:/overlay/osk_button_plus_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
- background-image: url(:/overlay/osk_button_B_dark_disabled.png);
+ image: url(:/overlay/osk_button_B_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
- background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
+ image: url(:/overlay/osk_button_Y_dark_disabled.png);
}
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index e044d9730..fe1c088ca 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -47,7 +47,22 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include)
# SDL2
if (NOT SDL2_FOUND AND ENABLE_SDL2)
+ # Yuzu itself needs: Events Joystick Haptic Sensor Timers
+ # Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
+ set(SDL_UNUSED_SUBSYSTEMS
+ Atomic Audio Render Power Threads
+ File CPUinfo Filesystem Locale)
+ foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
+ string(TOUPPER ${_SUB} _OPT)
+ option(SDL_${_OPT} "" OFF)
+ endforeach()
+
+ set(SDL_STATIC ON)
+ set(SDL_SHARED OFF)
+ option(HIDAPI "" ON)
+
add_subdirectory(SDL EXCLUDE_FROM_ALL)
+ add_library(SDL2 ALIAS SDL2-static)
endif()
# SoundTouch
diff --git a/externals/SDL b/externals/SDL
-Subproject 4cd981609b50ed273d80c635c1ca4c1e5518fb2
+Subproject 107db2d89953ee7cc03417d43da1f26bd03aad5
diff --git a/externals/ffmpeg b/externals/ffmpeg
-Subproject 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fd
+Subproject 79e8d17024e6c6328a40fcee191ffd70798a9c6
diff --git a/externals/mbedtls b/externals/mbedtls
-Subproject eac2416b8fdb2cb9c867a538100bf95326bad75
+Subproject 8c88150ca139e06aa2aae8349df8292a88148ea
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8bd7e5f72..f30dd49a3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -54,6 +54,7 @@ if (MSVC)
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
/we4555 # Expression has no effect; expected expression with side-effect
+ /we4715 # 'function': not all control paths return a value
/we4834 # Discarding return value of function with 'nodiscard' attribute
/we5038 # data member 'member1' will be initialized after data member 'member2'
)
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);
} \
}
+#define YUZU_NON_COPYABLE(cls) \
+ cls(const cls&) = delete; \
+ cls& operator=(const cls&) = delete
+
+#define YUZU_NON_MOVEABLE(cls) \
+ cls(cls&&) = delete; \
+ cls& operator=(cls&&) = delete
+
#define R_SUCCEEDED(res) (res.IsSuccess())
/// Evaluates an expression that returns a result, and returns the result if it would fail.
@@ -128,4 +136,19 @@ namespace Common {
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
}
+// std::size() does not support zero-size C arrays. We're fixing that.
+template <class C>
+constexpr auto Size(const C& c) -> decltype(c.size()) {
+ return std::size(c);
+}
+
+template <class C>
+constexpr std::size_t Size(const C& c) {
+ if constexpr (sizeof(C) == 0) {
+ return 0;
+ } else {
+ return std::size(c);
+ }
+}
+
} // 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:
private:
static constexpr TypedStorage<Derived> DerivedStorage = {};
- static_assert(GetParent(GetNode(GetPointer(DerivedStorage))) == GetPointer(DerivedStorage));
};
template <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 {
}
}
- return (next - start) * sizeof(MemberType) + Offset;
+ return static_cast<ptrdiff_t>(static_cast<size_t>(next - start) * sizeof(MemberType) +
+ Offset);
}
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
@@ -133,27 +134,27 @@ template <auto MemberPtr>
using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
-static inline std::ptrdiff_t OffsetOf = [] {
+constexpr std::ptrdiff_t OffsetOf() {
using DeducedParentType = GetParentType<MemberPtr>;
using MemberType = GetMemberType<MemberPtr>;
static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
std::is_same<RealParentType, DeducedParentType>::value);
return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
-}();
+};
} // namespace impl
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
- std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
+ std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
return *static_cast<RealParentType*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
}
template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
- std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
+ std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
return *static_cast<const RealParentType*>(static_cast<const void*>(
static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
}
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() {
log_setting("System_RegionIndex", values.region_index.GetValue());
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
- log_setting("CPU_Accuracy", values.cpu_accuracy);
+ log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue());
log_setting("Renderer_FrameLimit", values.frame_limit.GetValue());
@@ -106,6 +106,12 @@ void RestoreGlobalState(bool is_powered_on) {
// Core
values.use_multi_core.SetGlobal(true);
+ // CPU
+ values.cpu_accuracy.SetGlobal(true);
+ values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
+ values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
+ values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
+
// Renderer
values.renderer_backend.SetGlobal(true);
values.vulkan_device.SetGlobal(true);
@@ -130,7 +136,6 @@ void RestoreGlobalState(bool is_powered_on) {
values.region_index.SetGlobal(true);
values.time_zone_index.SetGlobal(true);
values.rng_seed.SetGlobal(true);
- values.custom_rtc.SetGlobal(true);
values.sound_index.SetGlobal(true);
// 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 {
Setting<bool> use_multi_core;
// Cpu
- CPUAccuracy cpu_accuracy;
+ Setting<CPUAccuracy> cpu_accuracy;
bool cpuopt_page_tables;
bool cpuopt_block_linking;
@@ -126,9 +126,9 @@ struct Values {
bool cpuopt_misc_ir;
bool cpuopt_reduce_misalign_checks;
- bool cpuopt_unsafe_unfuse_fma;
- bool cpuopt_unsafe_reduce_fp_error;
- bool cpuopt_unsafe_inaccurate_nan;
+ Setting<bool> cpuopt_unsafe_unfuse_fma;
+ Setting<bool> cpuopt_unsafe_reduce_fp_error;
+ Setting<bool> cpuopt_unsafe_inaccurate_nan;
// Renderer
Setting<RendererBackend> renderer_backend;
@@ -157,7 +157,7 @@ struct Values {
// System
Setting<std::optional<u32>> rng_seed;
// Measured in seconds since epoch
- Setting<std::optional<std::chrono::seconds>> custom_rtc;
+ std::optional<std::chrono::seconds> custom_rtc;
// Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc`
std::chrono::seconds custom_rtc_differential;
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) {
template <typename Node>
void RB_REMOVE_COLOR(RBHead<Node>* head, Node* parent, Node* elm) {
Node* tmp;
- while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root()) {
+ while ((elm == nullptr || RB_IS_BLACK(elm)) && elm != head->Root() && parent != nullptr) {
if (RB_LEFT(parent) == elm) {
tmp = RB_RIGHT(parent);
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
hle/kernel/board/nintendo/nx/k_system_control.cpp
hle/kernel/board/nintendo/nx/k_system_control.h
hle/kernel/board/nintendo/nx/secure_monitor.h
- hle/kernel/client_port.cpp
- hle/kernel/client_port.h
- hle/kernel/client_session.cpp
- hle/kernel/client_session.h
hle/kernel/code_set.cpp
hle/kernel/code_set.h
hle/kernel/svc_results.h
hle/kernel/global_scheduler_context.cpp
hle/kernel/global_scheduler_context.h
- hle/kernel/handle_table.cpp
- hle/kernel/handle_table.h
hle/kernel/hle_ipc.cpp
hle/kernel/hle_ipc.h
+ hle/kernel/init/init_slab_setup.cpp
+ hle/kernel/init/init_slab_setup.h
hle/kernel/k_address_arbiter.cpp
hle/kernel/k_address_arbiter.h
hle/kernel/k_address_space_info.cpp
hle/kernel/k_address_space_info.h
+ hle/kernel/k_auto_object.cpp
+ hle/kernel/k_auto_object.h
+ hle/kernel/k_auto_object_container.cpp
+ hle/kernel/k_auto_object_container.h
hle/kernel/k_affinity_mask.h
+ hle/kernel/k_class_token.cpp
+ hle/kernel/k_class_token.h
+ hle/kernel/k_client_port.cpp
+ hle/kernel/k_client_port.h
+ hle/kernel/k_client_session.cpp
+ hle/kernel/k_client_session.h
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_event.cpp
hle/kernel/k_event.h
+ hle/kernel/k_handle_table.cpp
+ hle/kernel/k_handle_table.h
hle/kernel/k_light_condition_variable.h
hle/kernel/k_light_lock.cpp
hle/kernel/k_light_lock.h
+ hle/kernel/k_linked_list.h
hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h
@@ -185,7 +194,11 @@ add_library(core STATIC
hle/kernel/k_page_linked_list.h
hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h
+ hle/kernel/k_port.cpp
+ hle/kernel/k_port.h
hle/kernel/k_priority_queue.h
+ hle/kernel/k_process.cpp
+ hle/kernel/k_process.h
hle/kernel/k_readable_event.cpp
hle/kernel/k_readable_event.h
hle/kernel/k_resource_limit.cpp
@@ -196,6 +209,12 @@ add_library(core STATIC
hle/kernel/k_scoped_lock.h
hle/kernel/k_scoped_resource_reservation.h
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+ hle/kernel/k_server_port.cpp
+ hle/kernel/k_server_port.h
+ hle/kernel/k_server_session.cpp
+ hle/kernel/k_server_session.h
+ hle/kernel/k_session.cpp
+ hle/kernel/k_session.h
hle/kernel/k_shared_memory.cpp
hle/kernel/k_shared_memory.h
hle/kernel/k_slab_heap.h
@@ -208,28 +227,21 @@ add_library(core STATIC
hle/kernel/k_thread.h
hle/kernel/k_thread_queue.h
hle/kernel/k_trace.h
+ hle/kernel/k_transfer_memory.cpp
+ hle/kernel/k_transfer_memory.h
hle/kernel/k_writable_event.cpp
hle/kernel/k_writable_event.h
hle/kernel/kernel.cpp
hle/kernel/kernel.h
hle/kernel/memory_types.h
- hle/kernel/object.cpp
- hle/kernel/object.h
hle/kernel/physical_core.cpp
hle/kernel/physical_core.h
hle/kernel/physical_memory.h
- hle/kernel/process.cpp
- hle/kernel/process.h
hle/kernel/process_capability.cpp
hle/kernel/process_capability.h
- hle/kernel/server_port.cpp
- hle/kernel/server_port.h
- hle/kernel/server_session.cpp
- hle/kernel/server_session.h
hle/kernel/service_thread.cpp
hle/kernel/service_thread.h
- hle/kernel/session.cpp
- hle/kernel/session.h
+ hle/kernel/slab_helpers.h
hle/kernel/svc.cpp
hle/kernel/svc.h
hle/kernel/svc_common.h
@@ -237,8 +249,6 @@ add_library(core STATIC
hle/kernel/svc_wrap.h
hle/kernel/time_manager.cpp
hle/kernel/time_manager.h
- hle/kernel/transfer_memory.cpp
- hle/kernel/transfer_memory.h
hle/lock.cpp
hle/lock.h
hle/result.h
@@ -393,6 +403,8 @@ add_library(core STATIC
hle/service/hid/xcd.cpp
hle/service/hid/xcd.h
hle/service/hid/errors.h
+ hle/service/hid/controllers/console_sixaxis.cpp
+ hle/service/hid/controllers/console_sixaxis.h
hle/service/hid/controllers/controller_base.cpp
hle/service/hid/controllers/controller_base.h
hle/service/hid/controllers/debug_pad.cpp
@@ -639,20 +651,17 @@ endif()
if (MSVC)
target_compile_options(core PRIVATE
- # 'expression' : signed/unsigned mismatch
- /we4018
- # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
- /we4244
- # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
- /we4245
- # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
- /we4254
- # 'var' : conversion from 'size_t' to 'type', possible loss of data
- /we4267
- # 'context' : truncation from 'type1' to 'type2'
- /we4305
- # 'function' : not all control paths return a value
- /we4715
+ /we4018 # 'expression' : signed/unsigned mismatch
+ /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
+ /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
+ /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
+ /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
+ /we4305 # 'context' : truncation from 'type1' to 'type2'
+ /we4456 # Declaration of 'identifier' hides previous local declaration
+ /we4457 # Declaration of 'identifier' hides function parameter
+ /we4458 # Declaration of 'identifier' hides class member
+ /we4459 # Declaration of 'identifier' hides global declaration
+ /we4715 # 'function' : not all control paths return a value
)
else()
target_compile_options(core PRIVATE
@@ -660,6 +669,7 @@ else()
-Werror=ignored-qualifiers
-Werror=implicit-fallthrough
-Werror=sign-compare
+ -Werror=shadow
$<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
$<$<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 {
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
- explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent) : parent(parent) {}
+ explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) : parent{parent_} {}
u8 MemoryRead8(u32 vaddr) override {
return parent.system.Memory().Read8(vaddr);
@@ -142,7 +142,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.far_code_offset = 256 * 1024 * 1024;
// Safe optimizations
- if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
+ if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
config.page_table = nullptr;
}
@@ -170,15 +170,15 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
// Unsafe optimizations
- if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
+ if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
config.unsafe_optimizations = true;
- if (Settings::values.cpuopt_unsafe_unfuse_fma) {
+ if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
}
- if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
+ if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
- if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
+ if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
}
@@ -198,13 +198,13 @@ void ARM_Dynarmic_32::Step() {
jit->Step();
}
-ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers,
- bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
- std::size_t core_index)
- : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
+ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
+ bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
+ std::size_t core_index_)
+ : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
cb(std::make_unique<DynarmicCallbacks32>(*this)),
- cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index},
- exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
+ cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
+ exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
jit(MakeJit(nullptr)) {}
ARM_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;
class ARM_Dynarmic_32 final : public ARM_Interface {
public:
- ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
- ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
+ ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
+ ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
~ARM_Dynarmic_32() override;
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 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
@@ -27,7 +27,7 @@ using Vector = Dynarmic::A64::Vector;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
- explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent) : parent(parent) {}
+ explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) : parent{parent_} {}
u8 MemoryRead8(u64 vaddr) override {
return parent.system.Memory().Read8(vaddr);
@@ -182,7 +182,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.far_code_offset = 256 * 1024 * 1024;
// Safe optimizations
- if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
+ if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
if (!Settings::values.cpuopt_page_tables) {
config.page_table = nullptr;
}
@@ -210,15 +210,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
}
// Unsafe optimizations
- if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
+ if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Unsafe) {
config.unsafe_optimizations = true;
- if (Settings::values.cpuopt_unsafe_unfuse_fma) {
+ if (Settings::values.cpuopt_unsafe_unfuse_fma.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
}
- if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
+ if (Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
}
- if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
+ if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
}
}
@@ -238,12 +238,12 @@ void ARM_Dynarmic_64::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
-ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers,
- bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
- std::size_t core_index)
- : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
- cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
- exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)},
+ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
+ bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
+ std::size_t core_index_)
+ : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
+ cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
+ exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
jit(MakeJit(nullptr, 48)) {}
ARM_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;
class ARM_Dynarmic_64 final : public ARM_Interface {
public:
- ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
- ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
+ ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
+ ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
~ARM_Dynarmic_64() override;
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,
CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) {
if (!two && opc == 0 && CRm == CoprocReg::C14) {
// CNTPCT
- const auto callback = static_cast<u64 (*)(Dynarmic::A32::Jit*, void*, u32, u32)>(
- [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 {
- ARM_Dynarmic_32& parent = *(ARM_Dynarmic_32*)arg;
- return parent.system.CoreTiming().GetClockTicks();
- });
- return Dynarmic::A32::Coprocessor::Callback{callback, (void*)&parent};
+ const auto callback = [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 {
+ const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg);
+ return parent_arg.system.CoreTiming().GetClockTicks();
+ };
+ return Callback{callback, &parent};
}
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 {
public:
using CoprocReg = Dynarmic::A32::CoprocReg;
- explicit DynarmicCP15(ARM_Dynarmic_32& parent) : parent(parent) {}
+ explicit DynarmicCP15(ARM_Dynarmic_32& parent_) : parent{parent_} {}
std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd,
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 @@
namespace Core {
-DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count)
- : monitor(core_count), memory{memory} {}
+DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_)
+ : monitor{core_count_}, memory{memory_} {}
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
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 {
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
public:
- explicit DynarmicExclusiveMonitor(Memory::Memory& memory, std::size_t core_count);
+ explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_);
~DynarmicExclusiveMonitor() override;
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 @@
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/hardware_interrupt_manager.h"
-#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/controller.h"
#include "core/hle/service/filesystem/filesystem.h"
@@ -166,14 +166,14 @@ struct System::Impl {
cpu_manager.SetAsyncGpu(is_async_gpu);
core_timing.SetMulticore(is_multicore);
- core_timing.Initialize([&system]() { system.RegisterHostThread(); });
kernel.Initialize();
cpu_manager.Initialize();
+ core_timing.Initialize([&system]() { system.RegisterHostThread(); });
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch());
Settings::values.custom_rtc_differential =
- Settings::values.custom_rtc.GetValue().value_or(current_time) - current_time;
+ Settings::values.custom_rtc.value_or(current_time) - current_time;
// Create a default fs if one doesn't already exist.
if (virtual_filesystem == nullptr)
@@ -233,8 +233,11 @@ struct System::Impl {
}
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
- auto main_process =
- Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);
+ auto main_process = Kernel::KProcess::Create(system.Kernel());
+ ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
+ Kernel::KProcess::ProcessType::Userland)
+ .IsSuccess());
+ main_process->Open();
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
@@ -244,7 +247,7 @@ struct System::Impl {
static_cast<u32>(load_result));
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
- kernel.MakeCurrentProcess(main_process.get());
+ kernel.MakeCurrentProcess(main_process);
kernel.InitializeCores();
// Initialize cheat engine
@@ -286,7 +289,8 @@ struct System::Impl {
telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
perf_results.emulation_speed * 100.0);
- telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
+ telemetry_session->AddField(performance, "Shutdown_Framerate",
+ perf_results.average_game_fps);
telemetry_session->AddField(performance, "Shutdown_Frametime",
perf_results.frametime * 1000.0);
telemetry_session->AddField(performance, "Mean_Frametime_MS",
@@ -311,6 +315,7 @@ struct System::Impl {
gpu_core.reset();
perf_stats.reset();
kernel.Shutdown();
+ memory.Reset();
applet_manager.ClearAll();
LOG_DEBUG(Core, "Shutdown OK");
@@ -322,7 +327,7 @@ struct System::Impl {
return app_loader->ReadTitle(out);
}
- void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::Process& process) {
+ void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
std::vector<u8> nacp_data;
FileSys::NACP nacp;
if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
@@ -513,7 +518,7 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
return impl->kernel.GlobalSchedulerContext();
}
-Kernel::Process* System::CurrentProcess() {
+Kernel::KProcess* System::CurrentProcess() {
return impl->kernel.CurrentProcess();
}
@@ -525,7 +530,7 @@ const Core::DeviceMemory& System::DeviceMemory() const {
return *impl->device_memory;
}
-const Kernel::Process* System::CurrentProcess() const {
+const Kernel::KProcess* System::CurrentProcess() const {
return impl->kernel.CurrentProcess();
}
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 @@
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
-#include "core/hle/kernel/object.h"
namespace Core::Frontend {
class EmuWindow;
@@ -29,7 +28,7 @@ namespace Kernel {
class GlobalSchedulerContext;
class KernelCore;
class PhysicalCore;
-class Process;
+class KProcess;
class KScheduler;
} // namespace Kernel
@@ -264,10 +263,10 @@ public:
[[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
/// Provides a pointer to the current process
- [[nodiscard]] Kernel::Process* CurrentProcess();
+ [[nodiscard]] Kernel::KProcess* CurrentProcess();
/// Provides a constant pointer to the current process.
- [[nodiscard]] const Kernel::Process* CurrentProcess() const;
+ [[nodiscard]] const Kernel::KProcess* CurrentProcess() const;
/// Provides a reference to the core timing instance.
[[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,
}
}
-void CoreTiming::AddTicks(u64 ticks) {
- this->ticks += ticks;
+void CoreTiming::AddTicks(u64 ticks_to_add) {
+ ticks += ticks_to_add;
downcount -= static_cast<s64>(ticks);
}
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:
/// We only permit one event of each type in the queue at a time.
void RemoveEvent(const std::shared_ptr<EventType>& event_type);
- void AddTicks(u64 ticks);
+ void AddTicks(u64 ticks_to_add);
void ResetTicks();
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 @@
namespace Core {
-CpuManager::CpuManager(System& system) : system{system} {}
+CpuManager::CpuManager(System& system_) : system{system_} {}
CpuManager::~CpuManager() = default;
void 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;
class CpuManager {
public:
- explicit CpuManager(System& system);
+ explicit CpuManager(System& system_);
CpuManager(const CpuManager&) = delete;
CpuManager(CpuManager&&) = delete;
@@ -35,13 +35,13 @@ public:
CpuManager& operator=(CpuManager&&) = delete;
/// Sets if emulation is multicore or single core, must be set before Initialize
- void SetMulticore(bool is_multicore) {
- this->is_multicore = is_multicore;
+ void SetMulticore(bool is_multi) {
+ is_multicore = is_multi;
}
/// Sets if emulation is using an asynchronous GPU.
- void SetAsyncGpu(bool is_async_gpu) {
- this->is_async_gpu = is_async_gpu;
+ void SetAsyncGpu(bool is_async) {
+ is_async_gpu = is_async;
}
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 @@
namespace Core::Crypto {
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
- std::size_t base_offset)
- : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {}
+ std::size_t base_offset_)
+ : EncryptionLayer(std::move(base_)), base_offset(base_offset_), cipher(key_, Mode::CTR) {}
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
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 {
public:
using IVData = std::array<u8, 16>;
- CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
+ CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, std::size_t base_offset_);
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
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,
const std::array<u8, size>& rhs) {
std::array<u8, size> out;
std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(),
- [](u8 lhs, u8 rhs) { return u8(lhs ^ rhs); });
+ [](u8 lhs_elem, u8 rhs_elem) { return u8(lhs_elem ^ rhs_elem); });
return out;
}
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 {
u32 XCI::GetSystemUpdateVersion() {
const auto update = GetPartition(XCIPartition::Update);
- if (update == nullptr)
+ if (update == nullptr) {
return 0;
+ }
- for (const auto& file : update->GetFiles()) {
- NCA nca{file, nullptr, 0};
+ for (const auto& update_file : update->GetFiles()) {
+ NCA nca{update_file, nullptr, 0};
- if (nca.GetStatus() != Loader::ResultStatus::Success)
+ if (nca.GetStatus() != Loader::ResultStatus::Success) {
continue;
+ }
if (nca.GetType() == NCAContentType::Meta && nca.GetTitleId() == 0x0100000000000816) {
const auto dir = nca.GetSubdirectories()[0];
const auto cnmt = dir->GetFile("SystemUpdate_0100000000000816.cnmt");
- if (cnmt == nullptr)
+ if (cnmt == nullptr) {
continue;
+ }
CNMT cnmt_data{cnmt};
const auto metas = cnmt_data.GetMetaRecords();
- if (metas.empty())
+ if (metas.empty()) {
continue;
+ }
return metas[0].title_version;
}
@@ -262,8 +266,8 @@ VirtualDir XCI::ConcatenatedPseudoDirectory() {
if (part == nullptr)
continue;
- for (const auto& file : part->GetFiles())
- out->AddFile(file);
+ for (const auto& part_file : part->GetFiles())
+ out->AddFile(part_file);
}
return out;
@@ -283,12 +287,12 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
return Loader::ResultStatus::ErrorXCIMissingPartition;
}
- for (const VirtualFile& file : partition->GetFiles()) {
- if (file->GetExtension() != "nca") {
+ for (const VirtualFile& partition_file : partition->GetFiles()) {
+ if (partition_file->GetExtension() != "nca") {
continue;
}
- auto nca = std::make_shared<NCA>(file, nullptr, 0);
+ auto nca = std::make_shared<NCA>(partition_file, nullptr, 0);
if (nca->IsUpdate()) {
continue;
}
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 @@
#include <algorithm>
#include <cstring>
#include <optional>
+#include <ranges>
#include <utility>
#include "common/logging/log.h"
@@ -136,12 +137,11 @@ NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_off
return;
}
- has_rights_id = std::any_of(header.rights_id.begin(), header.rights_id.end(),
- [](char c) { return c != '\0'; });
+ has_rights_id = std::ranges::any_of(header.rights_id, [](char c) { return c != '\0'; });
const std::vector<NCASectionHeader> sections = ReadSectionHeaders();
- is_update = std::any_of(sections.begin(), sections.end(), [](const NCASectionHeader& header) {
- return header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
+ is_update = std::ranges::any_of(sections, [](const NCASectionHeader& nca_header) {
+ return nca_header.raw.header.crypto_type == NCASectionCryptoType::BKTR;
});
if (!ReadSections(sections, bktr_base_ivfc_offset)) {
@@ -202,8 +202,9 @@ bool NCA::HandlePotentialHeaderDecryption() {
std::vector<NCASectionHeader> NCA::ReadSectionHeaders() const {
const std::ptrdiff_t number_sections =
- std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
- [](NCASectionTableEntry entry) { return entry.media_offset > 0; });
+ std::ranges::count_if(header.section_tables, [](const NCASectionTableEntry& entry) {
+ return entry.media_offset > 0;
+ });
std::vector<NCASectionHeader> sections(number_sections);
const auto length_sections = SECTION_HEADER_SIZE * number_sections;
@@ -312,11 +313,11 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
}
std::vector<RelocationBucket> relocation_buckets(relocation_buckets_raw.size());
- std::transform(relocation_buckets_raw.begin(), relocation_buckets_raw.end(),
- relocation_buckets.begin(), &ConvertRelocationBucketRaw);
+ std::ranges::transform(relocation_buckets_raw, relocation_buckets.begin(),
+ &ConvertRelocationBucketRaw);
std::vector<SubsectionBucket> subsection_buckets(subsection_buckets_raw.size());
- std::transform(subsection_buckets_raw.begin(), subsection_buckets_raw.end(),
- subsection_buckets.begin(), &ConvertSubsectionBucketRaw);
+ std::ranges::transform(subsection_buckets_raw, subsection_buckets.begin(),
+ &ConvertSubsectionBucketRaw);
u32 ctr_low;
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 @@
namespace FileSys {
constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
+constexpr ResultCode ERROR_PATH_ALREADY_EXISTS{ErrorModule::FS, 2};
constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
constexpr 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) {
return count;
}
-void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
+void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext_dir,
std::shared_ptr<RomFSBuildDirectoryContext> parent) {
std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> child_dirs;
VirtualDir dir;
- if (parent->path_len == 0)
+ if (parent->path_len == 0) {
dir = root_romfs;
- else
+ } else {
dir = root_romfs->GetDirectoryRelative(parent->path);
+ }
const auto entries = dir->GetEntries();
@@ -147,8 +148,9 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
- if (ext != nullptr && ext->GetFileRelative(child->path + ".stub") != nullptr)
+ if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) {
continue;
+ }
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
@@ -163,21 +165,20 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
child->path = parent->path + "/" + kv.first;
- if (ext != nullptr && ext->GetFileRelative(child->path + ".stub") != nullptr)
+ if (ext_dir != nullptr && ext_dir->GetFileRelative(child->path + ".stub") != nullptr) {
continue;
+ }
// Sanity check on path_len
ASSERT(child->path_len < FS_MAX_PATH);
child->source = root_romfs->GetFileRelative(child->path);
- if (ext != nullptr) {
- const auto ips = ext->GetFileRelative(child->path + ".ips");
-
- if (ips != nullptr) {
- auto patched = PatchIPS(child->source, ips);
- if (patched != nullptr)
+ if (ext_dir != nullptr) {
+ if (const auto ips = ext_dir->GetFileRelative(child->path + ".ips")) {
+ if (auto patched = PatchIPS(child->source, ips)) {
child->source = std::move(patched);
+ }
}
}
@@ -188,7 +189,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, VirtualDir ext,
}
for (auto& child : child_dirs) {
- this->VisitDirectory(root_romfs, ext, child);
+ this->VisitDirectory(root_romfs, ext_dir, child);
}
}
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:
u64 file_hash_table_size = 0;
u64 file_partition_size = 0;
- void VisitDirectory(VirtualDir filesys, VirtualDir ext,
+ void VisitDirectory(VirtualDir filesys, VirtualDir ext_dir,
std::shared_ptr<RomFSBuildDirectoryContext> parent);
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) {
}
}
-CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
- std::vector<MetaRecord> meta_records)
- : header(std::move(header)), opt_header(std::move(opt_header)),
- content_records(std::move(content_records)), meta_records(std::move(meta_records)) {}
+CNMT::CNMT(CNMTHeader header_, OptionalHeader opt_header_,
+ std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_)
+ : header(std::move(header_)), opt_header(std::move(opt_header_)),
+ content_records(std::move(content_records_)), meta_records(std::move(meta_records_)) {}
CNMT::~CNMT() = default;
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.");
class CNMT {
public:
explicit CNMT(VirtualFile file);
- CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records,
- std::vector<MetaRecord> meta_records);
+ CNMT(CNMTHeader header_, OptionalHeader opt_header_,
+ std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_);
~CNMT();
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;
std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
// Read out of bounds.
- if (offset >= relocation.size)
+ if (offset >= relocation.size) {
return 0;
- const auto relocation = GetRelocationEntry(offset);
- const auto section_offset = offset - relocation.address_patch + relocation.address_source;
- const auto bktr_read = relocation.from_patch;
+ }
+
+ const auto relocation_entry = GetRelocationEntry(offset);
+ const auto section_offset =
+ offset - relocation_entry.address_patch + relocation_entry.address_source;
+ const auto bktr_read = relocation_entry.from_patch;
const auto next_relocation = GetNextRelocationEntry(offset);
@@ -106,15 +109,16 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
return bktr_romfs->Read(data, length, section_offset);
}
- const auto subsection = GetSubsectionEntry(section_offset);
+ const auto subsection_entry = GetSubsectionEntry(section_offset);
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
// Calculate AES IV
std::array<u8, 16> iv{};
- auto subsection_ctr = subsection.ctr;
+ auto subsection_ctr = subsection_entry.ctr;
auto offset_iv = section_offset + base_offset;
- for (std::size_t i = 0; i < section_ctr.size(); ++i)
+ for (std::size_t i = 0; i < section_ctr.size(); ++i) {
iv[i] = section_ctr[0x8 - i - 1];
+ }
offset_iv >>= 4;
for (std::size_t i = 0; i < sizeof(u64); ++i) {
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 @@
#include "common/logging/log.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
+#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
@@ -281,14 +282,14 @@ NcaID PlaceholderCache::Generate() {
return out;
}
-VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
+VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& open_dir,
std::string_view path) const {
- const auto file = dir->GetFileRelative(path);
+ const auto file = open_dir->GetFileRelative(path);
if (file != nullptr) {
return file;
}
- const auto nca_dir = dir->GetDirectoryRelative(path);
+ const auto nca_dir = open_dir->GetDirectoryRelative(path);
if (nca_dir == nullptr) {
return nullptr;
}
@@ -431,13 +432,15 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
}
void RegisteredCache::AccumulateYuzuMeta() {
- const auto dir = this->dir->GetSubdirectory("yuzu_meta");
- if (dir == nullptr)
+ const auto meta_dir = dir->GetSubdirectory("yuzu_meta");
+ if (meta_dir == nullptr) {
return;
+ }
- for (const auto& file : dir->GetFiles()) {
- if (file->GetExtension() != "cnmt")
+ for (const auto& file : meta_dir->GetFiles()) {
+ if (file->GetExtension() != "cnmt") {
continue;
+ }
CNMT cnmt(file);
yuzu_meta.insert_or_assign(cnmt.GetTitleID(), std::move(cnmt));
@@ -445,8 +448,10 @@ void RegisteredCache::AccumulateYuzuMeta() {
}
void RegisteredCache::Refresh() {
- if (dir == nullptr)
+ if (dir == nullptr) {
return;
+ }
+
const auto ids = AccumulateFiles();
ProcessFiles(ids);
AccumulateYuzuMeta();
@@ -566,7 +571,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
}
const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
- const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
+ const auto meta_id_data = Common::HexStringToArray<16>(meta_id_raw);
if ((*meta_iter)->GetSubdirectories().empty()) {
LOG_ERROR(Loader,
@@ -588,10 +593,16 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
const CNMT cnmt(cnmt_file);
const auto title_id = cnmt.GetTitleID();
+ const auto version = cnmt.GetTitleVersion();
+
+ if (title_id == GetBaseTitleID(title_id) && version == 0) {
+ return InstallResult::ErrorBaseInstall;
+ }
+
const auto result = RemoveExistingEntry(title_id);
// Install Metadata File
- const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
+ const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id_data);
if (res != InstallResult::Success) {
return res;
}
@@ -741,15 +752,15 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
// Reasoning behind this method can be found in the comment for InstallEntry, NCA overload.
- const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta");
+ const auto meta_dir = dir->CreateDirectoryRelative("yuzu_meta");
const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID());
- if (dir->GetFile(filename) == nullptr) {
- auto out = dir->CreateFile(filename);
+ if (meta_dir->GetFile(filename) == nullptr) {
+ auto out = meta_dir->CreateFile(filename);
const auto buffer = cnmt.Serialize();
out->Resize(buffer.size());
out->WriteBytes(buffer);
} else {
- auto out = dir->GetFile(filename);
+ auto out = meta_dir->GetFile(filename);
CNMT old_cnmt(out);
// Returns true on change
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 {
ErrorAlreadyExists,
ErrorCopyFailed,
ErrorMetaFailed,
+ ErrorBaseInstall,
};
struct ContentProviderEntry {
@@ -182,7 +183,7 @@ private:
void AccumulateYuzuMeta();
std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
VirtualFile GetFileAtID(NcaID id) const;
- VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
+ VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& open_dir, std::string_view path) const;
InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
bool overwrite_if_exists, std::optional<NcaID> override_id = {});
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 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
@@ -33,8 +33,8 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provi
RomFSFactory::~RomFSFactory() = default;
-void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
- this->update_raw = std::move(update_raw);
+void RomFSFactory::SetPackedUpdate(VirtualFile update_raw_file) {
+ update_raw = std::move(update_raw_file);
}
ResultVal<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:
Service::FileSystem::FileSystemController& controller);
~RomFSFactory();
- void SetPackedUpdate(VirtualFile update_raw);
+ void SetPackedUpdate(VirtualFile update_raw_file);
[[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
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 @@
#include "core/core.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
namespace FileSys {
@@ -170,26 +170,30 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
- const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
+ const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
- const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
- if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize))
+ const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME);
+ if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) {
return {0, 0};
+ }
SaveDataSize out;
- if (size_file->ReadObject(&out) != sizeof(SaveDataSize))
+ if (size_file->ReadObject(&out) != sizeof(SaveDataSize)) {
return {0, 0};
+ }
+
return out;
}
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const {
const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
- const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
+ const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
- const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
- if (size_file == nullptr)
+ const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
+ if (size_file == nullptr) {
return;
+ }
size_file->Resize(sizeof(SaveDataSize));
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 @@
namespace FileSys {
-NSP::NSP(VirtualFile file_, std::size_t program_index)
- : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},
+NSP::NSP(VirtualFile file_, std::size_t program_index_)
+ : file(std::move(file_)), program_index(program_index_), status{Loader::ResultStatus::Success},
pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
status = pfs->GetStatus();
@@ -232,15 +232,15 @@ void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
exefs = pfs;
- const auto romfs_iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& file) {
- return file->GetName().rfind(".romfs") != std::string::npos;
+ const auto iter = std::find_if(files.begin(), files.end(), [](const VirtualFile& entry) {
+ return entry->GetName().rfind(".romfs") != std::string::npos;
});
- if (romfs_iter == files.end()) {
+ if (iter == files.end()) {
return;
}
- romfs = *romfs_iter;
+ romfs = *iter;
}
void 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;
class NSP : public ReadOnlyVfsDirectory {
public:
- explicit NSP(VirtualFile file, std::size_t program_index = 0);
+ explicit NSP(VirtualFile file_, std::size_t program_index_ = 0);
~NSP() override;
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
return map.begin()->first == 0;
}
-ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name)
- : name(std::move(name)) {
+ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name_)
+ : name(std::move(name_)) {
std::size_t next_offset = 0;
for (const auto& file : files_) {
files.emplace(next_offset, file);
@@ -32,8 +32,8 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s
}
}
-ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name)
- : files(std::move(files_)), name(std::move(name)) {
+ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name_)
+ : files(std::move(files_)), name(std::move(name_)) {
ASSERT(VerifyConcatenationMapContinuity(files));
}
@@ -136,7 +136,7 @@ std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::
return 0;
}
-bool ConcatenatedVfsFile::Rename(std::string_view name) {
+bool ConcatenatedVfsFile::Rename(std::string_view new_name) {
return false;
}
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 {
// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
// read-only.
class ConcatenatedVfsFile : public VfsFile {
- ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
- ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name);
+ explicit ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name_);
+ explicit ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name_);
public:
~ConcatenatedVfsFile() override;
@@ -36,7 +36,7 @@ public:
bool IsReadable() const override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
- bool Rename(std::string_view name) override;
+ bool Rename(std::string_view new_name) override;
private:
// 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 @@
namespace FileSys {
-LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name)
- : dirs(std::move(dirs)), name(std::move(name)) {}
+LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_)
+ : dirs(std::move(dirs_)), name(std::move(name_)) {}
LayeredVfsDirectory::~LayeredVfsDirectory() = default;
@@ -45,12 +45,12 @@ VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) cons
return MakeLayeredDirectory(std::move(out));
}
-VirtualFile LayeredVfsDirectory::GetFile(std::string_view name) const {
- return GetFileRelative(name);
+VirtualFile LayeredVfsDirectory::GetFile(std::string_view file_name) const {
+ return GetFileRelative(file_name);
}
-VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view name) const {
- return GetDirectoryRelative(name);
+VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view subdir_name) const {
+ return GetDirectoryRelative(subdir_name);
}
std::string LayeredVfsDirectory::GetFullPath() const {
@@ -105,24 +105,24 @@ VirtualDir LayeredVfsDirectory::GetParentDirectory() const {
return dirs[0]->GetParentDirectory();
}
-VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view name) {
+VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
return nullptr;
}
-VirtualFile LayeredVfsDirectory::CreateFile(std::string_view name) {
+VirtualFile LayeredVfsDirectory::CreateFile(std::string_view file_name) {
return nullptr;
}
-bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view name) {
+bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
return false;
}
-bool LayeredVfsDirectory::DeleteFile(std::string_view name) {
+bool LayeredVfsDirectory::DeleteFile(std::string_view file_name) {
return false;
}
-bool LayeredVfsDirectory::Rename(std::string_view name_) {
- name = name_;
+bool LayeredVfsDirectory::Rename(std::string_view new_name) {
+ name = new_name;
return true;
}
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 {
// one and falling back to the one after. The highest priority directory (overwrites all others)
// should be element 0 in the dirs vector.
class LayeredVfsDirectory : public VfsDirectory {
- LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name);
+ explicit LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_);
public:
~LayeredVfsDirectory() override;
@@ -23,8 +23,8 @@ public:
VirtualFile GetFileRelative(std::string_view path) const override;
VirtualDir GetDirectoryRelative(std::string_view path) const override;
- VirtualFile GetFile(std::string_view name) const override;
- VirtualDir GetSubdirectory(std::string_view name) const override;
+ VirtualFile GetFile(std::string_view file_name) const override;
+ VirtualDir GetSubdirectory(std::string_view subdir_name) const override;
std::string GetFullPath() const override;
std::vector<VirtualFile> GetFiles() const override;
@@ -33,11 +33,11 @@ public:
bool IsReadable() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
- VirtualDir CreateSubdirectory(std::string_view name) override;
- VirtualFile CreateFile(std::string_view name) override;
- bool DeleteSubdirectory(std::string_view name) override;
- bool DeleteFile(std::string_view name) override;
- bool Rename(std::string_view name) override;
+ VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
+ VirtualFile CreateFile(std::string_view file_name) override;
+ bool DeleteSubdirectory(std::string_view subdir_name) override;
+ bool DeleteFile(std::string_view file_name) override;
+ bool Rename(std::string_view new_name) override;
private:
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 @@
// Refer to the license.txt file included.
#include <string>
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#endif
#include <zip.h>
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
#include "common/logging/backend.h"
#include "core/file_sys/vfs.h"
#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
return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
}
-bool OffsetVfsFile::Rename(std::string_view name) {
- return file->Rename(name);
+bool OffsetVfsFile::Rename(std::string_view new_name) {
+ return file->Rename(new_name);
}
std::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:
bool WriteByte(u8 data, std::size_t offset) override;
std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override;
- bool Rename(std::string_view name) override;
+ bool Rename(std::string_view new_name) override;
std::size_t GetOffset() const;
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&
RealVfsDirectory::~RealVfsDirectory() = default;
-VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const {
- const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
+VirtualFile RealVfsDirectory::GetFileRelative(std::string_view relative_path) const {
+ const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
return nullptr;
}
return base.OpenFile(full_path, perms);
}
-VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
- const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
+VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view relative_path) const {
+ const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
return nullptr;
}
@@ -382,13 +382,13 @@ VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const {
return GetDirectoryRelative(name);
}
-VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view path) {
- const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
+VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view relative_path) {
+ const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
return base.CreateFile(full_path, perms);
}
-VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
- const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
+VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view relative_path) {
+ const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path));
return base.CreateDirectory(full_path, perms);
}
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 {
public:
~RealVfsDirectory() override;
- VirtualFile GetFileRelative(std::string_view path) const override;
- VirtualDir GetDirectoryRelative(std::string_view path) const override;
+ VirtualFile GetFileRelative(std::string_view relative_path) const override;
+ VirtualDir GetDirectoryRelative(std::string_view relative_path) const override;
VirtualFile GetFile(std::string_view name) const override;
VirtualDir GetSubdirectory(std::string_view name) const override;
- VirtualFile CreateFileRelative(std::string_view path) override;
- VirtualDir CreateDirectoryRelative(std::string_view path) override;
+ VirtualFile CreateFileRelative(std::string_view relative_path) override;
+ VirtualDir CreateDirectoryRelative(std::string_view relative_path) override;
bool DeleteSubdirectoryRecursive(std::string_view name) override;
std::vector<VirtualFile> GetFiles() const override;
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 {
class StaticVfsFile : public VfsFile {
public:
- explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "",
- VirtualDir parent = nullptr)
- : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {}
+ explicit StaticVfsFile(u8 value_, std::size_t size_ = 0, std::string name_ = "",
+ VirtualDir parent_ = nullptr)
+ : value{value_}, size{size_}, name{std::move(name_)}, parent{std::move(parent_)} {}
std::string GetName() const override {
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 @@
#include "core/file_sys/vfs_vector.h"
namespace FileSys {
-VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent)
- : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {}
+VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name_, VirtualDir parent_)
+ : data(std::move(initial_data)), parent(std::move(parent_)), name(std::move(name_)) {}
VectorVfsFile::~VectorVfsFile() = default;
@@ -103,12 +103,12 @@ static bool FindAndRemoveVectorElement(std::vector<T>& vec, std::string_view nam
return true;
}
-bool VectorVfsDirectory::DeleteSubdirectory(std::string_view name) {
- return FindAndRemoveVectorElement(dirs, name);
+bool VectorVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
+ return FindAndRemoveVectorElement(dirs, subdir_name);
}
-bool VectorVfsDirectory::DeleteFile(std::string_view name) {
- return FindAndRemoveVectorElement(files, name);
+bool VectorVfsDirectory::DeleteFile(std::string_view file_name) {
+ return FindAndRemoveVectorElement(files, file_name);
}
bool VectorVfsDirectory::Rename(std::string_view name_) {
@@ -116,11 +116,11 @@ bool VectorVfsDirectory::Rename(std::string_view name_) {
return true;
}
-VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
+VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
return nullptr;
}
-VirtualFile VectorVfsDirectory::CreateFile(std::string_view name) {
+VirtualFile VectorVfsDirectory::CreateFile(std::string_view file_name) {
return nullptr;
}
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
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
class VectorVfsFile : public VfsFile {
public:
- explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name = "",
- VirtualDir parent = nullptr);
+ explicit VectorVfsFile(std::vector<u8> initial_data = {}, std::string name_ = "",
+ VirtualDir parent_ = nullptr);
~VectorVfsFile() override;
std::string GetName() const override;
@@ -112,11 +112,11 @@ public:
bool IsReadable() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
- bool DeleteSubdirectory(std::string_view name) override;
- bool DeleteFile(std::string_view name) override;
+ bool DeleteSubdirectory(std::string_view subdir_name) override;
+ bool DeleteFile(std::string_view file_name) override;
bool Rename(std::string_view name) override;
- VirtualDir CreateSubdirectory(std::string_view name) override;
- VirtualFile CreateFile(std::string_view name) override;
+ VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
+ VirtualFile CreateFile(std::string_view file_name) override;
virtual void AddFile(VirtualFile file);
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;
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
void DefaultWebBrowserApplet::OpenLocalWebPage(
- std::string_view local_url, std::function<void()> extract_romfs_callback,
+ const std::string& local_url, std::function<void()> extract_romfs_callback,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
local_url);
@@ -21,7 +21,7 @@ void DefaultWebBrowserApplet::OpenLocalWebPage(
}
void DefaultWebBrowserApplet::OpenExternalWebPage(
- std::string_view external_url,
+ const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
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:
virtual ~WebBrowserApplet();
virtual void OpenLocalWebPage(
- std::string_view local_url, std::function<void()> extract_romfs_callback,
+ const std::string& local_url, std::function<void()> extract_romfs_callback,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
virtual void OpenExternalWebPage(
- std::string_view external_url,
+ const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
};
@@ -28,11 +28,12 @@ class DefaultWebBrowserApplet final : public WebBrowserApplet {
public:
~DefaultWebBrowserApplet() override;
- void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback,
+ void OpenLocalWebPage(const std::string& local_url,
+ std::function<void()> extract_romfs_callback,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback) const override;
- void OpenExternalWebPage(std::string_view external_url,
+ void OpenExternalWebPage(const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback) const override;
};
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index cff49899a..e11ec0b0b 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -26,7 +26,7 @@ public:
private:
class Device : public Input::TouchDevice {
public:
- explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {}
+ explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {}
Input::TouchStatus GetStatus() const override {
if (auto state = touch_state.lock()) {
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 @@
#include <utility>
#include "common/logging/log.h"
#include "common/param_package.h"
+#include "common/quaternion.h"
#include "common/vector_math.h"
namespace Input {
@@ -143,9 +144,10 @@ using VibrationDevice = InputDevice<u8>;
/**
* A motion status is an object that returns a tuple of accelerometer state vector,
- * gyroscope state vector, rotation state vector and orientation state matrix.
+ * gyroscope state vector, rotation state vector, orientation state matrix and quaterion state
+ * vector.
*
- * For both vectors:
+ * For both 3D vectors:
* x+ is the same direction as RIGHT on D-pad.
* y+ is normal to the touch screen, pointing outward.
* z+ is the same direction as UP on D-pad.
@@ -164,9 +166,13 @@ using VibrationDevice = InputDevice<u8>;
* x vector
* y vector
* z vector
+ *
+ * For quaternion state vector
+ * xyz vector
+ * w float
*/
using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
- std::array<Common::Vec3f, 3>>;
+ std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>;
/**
* 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 {
Control = 5,
RequestWithContext = 6,
ControlWithContext = 7,
- Unspecified,
+ TIPC_Close = 15,
+ TIPC_CommandRegion = 16, // Start of TIPC commands, this is an offset.
};
struct CommandHeader {
@@ -57,6 +58,20 @@ struct CommandHeader {
BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags;
BitField<31, 1, u32> enable_handle_descriptor;
};
+
+ bool IsTipc() const {
+ return type.Value() >= CommandType::TIPC_CommandRegion;
+ }
+
+ bool IsCloseCommand() const {
+ switch (type.Value()) {
+ case CommandType::Close:
+ case CommandType::TIPC_Close:
+ return true;
+ default:
+ return false;
+ }
+ }
};
static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect");
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 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/ipc.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/k_session.h"
#include "core/hle/result.h"
namespace IPC {
@@ -29,19 +28,19 @@ class RequestHelperBase {
protected:
Kernel::HLERequestContext* context = nullptr;
u32* cmdbuf;
- ptrdiff_t index = 0;
+ u32 index = 0;
public:
explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {}
- explicit RequestHelperBase(Kernel::HLERequestContext& context)
- : context(&context), cmdbuf(context.CommandBuffer()) {}
+ explicit RequestHelperBase(Kernel::HLERequestContext& ctx)
+ : context(&ctx), cmdbuf(ctx.CommandBuffer()) {}
void Skip(u32 size_in_words, bool set_to_null) {
if (set_to_null) {
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
}
- index += static_cast<ptrdiff_t>(size_in_words);
+ index += size_in_words;
}
/**
@@ -54,11 +53,11 @@ public:
}
u32 GetCurrentOffset() const {
- return static_cast<u32>(index);
+ return index;
}
void SetCurrentOffset(u32 offset) {
- index = static_cast<ptrdiff_t>(offset);
+ index = offset;
}
};
@@ -72,64 +71,79 @@ public:
AlwaysMoveHandles = 1,
};
- explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
- u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
+ explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size_,
+ u32 num_handles_to_copy_ = 0, u32 num_objects_to_move_ = 0,
Flags flags = Flags::None)
- : RequestHelperBase(context), normal_params_size(normal_params_size),
- num_handles_to_copy(num_handles_to_copy),
- num_objects_to_move(num_objects_to_move), kernel{context.kernel} {
+ : RequestHelperBase(ctx), normal_params_size(normal_params_size_),
+ num_handles_to_copy(num_handles_to_copy_),
+ num_objects_to_move(num_objects_to_move_), kernel{ctx.kernel} {
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
- context.ClearIncomingObjects();
+ ctx.ClearIncomingObjects();
IPC::CommandHeader header{};
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
// padding.
- u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
+ u32 raw_data_size = ctx.IsTipc()
+ ? normal_params_size - 1
+ : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
u32 num_handles_to_move{};
u32 num_domain_objects{};
const bool always_move_handles{
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
- if (!context.Session()->IsDomain() || always_move_handles) {
+ if (!ctx.Session()->IsDomain() || always_move_handles) {
num_handles_to_move = num_objects_to_move;
} else {
num_domain_objects = num_objects_to_move;
}
- if (context.Session()->IsDomain()) {
- raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
+ if (ctx.Session()->IsDomain()) {
+ raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects);
}
+ if (ctx.IsTipc()) {
+ header.type.Assign(ctx.GetCommandType());
+ }
+
+ ctx.data_size = static_cast<u32>(raw_data_size);
header.data_size.Assign(static_cast<u32>(raw_data_size));
- if (num_handles_to_copy || num_handles_to_move) {
+ if (num_handles_to_copy != 0 || num_handles_to_move != 0) {
header.enable_handle_descriptor.Assign(1);
}
PushRaw(header);
if (header.enable_handle_descriptor) {
IPC::HandleDescriptorHeader handle_descriptor_header{};
- handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy);
+ handle_descriptor_header.num_handles_to_copy.Assign(num_handles_to_copy_);
handle_descriptor_header.num_handles_to_move.Assign(num_handles_to_move);
PushRaw(handle_descriptor_header);
+
+ ctx.handles_offset = index;
+
Skip(num_handles_to_copy + num_handles_to_move, true);
}
- AlignWithPadding();
+ if (!ctx.IsTipc()) {
+ AlignWithPadding();
- if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) {
- IPC::DomainMessageHeader domain_header{};
- domain_header.num_objects = num_domain_objects;
- PushRaw(domain_header);
+ if (ctx.Session()->IsDomain() && ctx.HasDomainMessageHeader()) {
+ IPC::DomainMessageHeader domain_header{};
+ domain_header.num_objects = num_domain_objects;
+ PushRaw(domain_header);
+ }
+
+ IPC::DataPayloadHeader data_payload_header{};
+ data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
+ PushRaw(data_payload_header);
}
- IPC::DataPayloadHeader data_payload_header{};
- data_payload_header.magic = Common::MakeMagic('S', 'F', 'C', 'O');
- PushRaw(data_payload_header);
+ data_payload_index = index;
- datapayload_index = index;
+ ctx.data_payload_offset = index;
+ ctx.domain_offset = index + raw_data_size / 4;
}
template <class T>
@@ -137,9 +151,14 @@ public:
if (context->Session()->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
- auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
- context->AddMoveObject(std::move(client));
- iface->ClientConnected(std::move(server));
+ // kernel.CurrentProcess()->GetResourceLimit()->Reserve(
+ // Kernel::LimitableResource::Sessions, 1);
+
+ auto* session = Kernel::KSession::Create(kernel);
+ session->Initialize(nullptr, iface->GetServiceName());
+
+ context->AddMoveObject(&session->GetClientSession());
+ iface->ClientConnected(&session->GetServerSession());
}
}
@@ -153,7 +172,7 @@ public:
const std::size_t num_move_objects = context->NumMoveObjects();
ASSERT_MSG(!num_domain_objects || !num_move_objects,
"cannot move normal handles and domain objects");
- ASSERT_MSG((index - datapayload_index) == normal_params_size,
+ ASSERT_MSG((index - data_payload_index) == normal_params_size,
"normal_params_size value is incorrect");
ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move,
"num_objects_to_move value is incorrect");
@@ -215,23 +234,29 @@ public:
void PushRaw(const T& value);
template <typename... O>
- void PushMoveObjects(std::shared_ptr<O>... pointers);
+ void PushMoveObjects(O*... pointers);
+
+ template <typename... O>
+ void PushMoveObjects(O&... pointers);
+
+ template <typename... O>
+ void PushCopyObjects(O*... pointers);
template <typename... O>
- void PushCopyObjects(std::shared_ptr<O>... pointers);
+ void PushCopyObjects(O&... pointers);
private:
u32 normal_params_size{};
u32 num_handles_to_copy{};
u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
- std::ptrdiff_t datapayload_index{};
+ u32 data_payload_index{};
Kernel::KernelCore& kernel;
};
/// Push ///
inline void ResponseBuilder::PushImpl(s32 value) {
- cmdbuf[index++] = static_cast<u32>(value);
+ cmdbuf[index++] = value;
}
inline void ResponseBuilder::PushImpl(u32 value) {
@@ -301,18 +326,34 @@ void ResponseBuilder::Push(const First& first_value, const Other&... other_value
}
template <typename... O>
-inline void ResponseBuilder::PushCopyObjects(std::shared_ptr<O>... pointers) {
+inline void ResponseBuilder::PushCopyObjects(O*... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
- context->AddCopyObject(std::move(object));
+ context->AddCopyObject(object);
+ }
+}
+
+template <typename... O>
+inline void ResponseBuilder::PushCopyObjects(O&... pointers) {
+ auto objects = {&pointers...};
+ for (auto& object : objects) {
+ context->AddCopyObject(object);
}
}
template <typename... O>
-inline void ResponseBuilder::PushMoveObjects(std::shared_ptr<O>... pointers) {
+inline void ResponseBuilder::PushMoveObjects(O*... pointers) {
auto objects = {pointers...};
for (auto& object : objects) {
- context->AddMoveObject(std::move(object));
+ context->AddMoveObject(object);
+ }
+}
+
+template <typename... O>
+inline void ResponseBuilder::PushMoveObjects(O&... pointers) {
+ auto objects = {&pointers...};
+ for (auto& object : objects) {
+ context->AddMoveObject(object);
}
}
@@ -320,9 +361,9 @@ class RequestParser : public RequestHelperBase {
public:
explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
- explicit RequestParser(Kernel::HLERequestContext& context) : RequestHelperBase(context) {
- ASSERT_MSG(context.GetDataPayloadOffset(), "context is incomplete");
- Skip(context.GetDataPayloadOffset(), false);
+ explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) {
+ ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
+ Skip(ctx.GetDataPayloadOffset(), false);
// Skip the u64 command id, it's already stored in the context
static constexpr u32 CommandIdSize = 2;
Skip(CommandIdSize, false);
@@ -359,12 +400,6 @@ public:
template <typename T>
T PopRaw();
- template <typename T>
- std::shared_ptr<T> GetMoveObject(std::size_t index);
-
- template <typename T>
- std::shared_ptr<T> GetCopyObject(std::size_t index);
-
template <class T>
std::shared_ptr<T> PopIpcInterface() {
ASSERT(context->Session()->IsDomain());
@@ -469,14 +504,4 @@ void RequestParser::Pop(First& first_value, Other&... other_values) {
Pop(other_values...);
}
-template <typename T>
-std::shared_ptr<T> RequestParser::GetMoveObject(std::size_t index) {
- return context->GetMoveObject<T>(index);
-}
-
-template <typename T>
-std::shared_ptr<T> RequestParser::GetCopyObject(std::size_t index) {
- return context->GetCopyObject<T>(index);
-}
-
} // 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 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/server_port.h"
-#include "core/hle/kernel/session.h"
-#include "core/hle/kernel/svc_results.h"
-
-namespace Kernel {
-
-ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {}
-ClientPort::~ClientPort() = default;
-
-std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
- return server_port;
-}
-
-ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
- if (active_sessions >= max_sessions) {
- return ResultMaxConnectionsReached;
- }
- active_sessions++;
-
- auto [client, server] = Kernel::Session::Create(kernel, name);
-
- if (server_port->HasHLEHandler()) {
- server_port->GetHLEHandler()->ClientConnected(std::move(server));
- } else {
- server_port->AppendPendingSession(std::move(server));
- }
-
- return MakeResult(std::move(client));
-}
-
-void ClientPort::ConnectionClosed() {
- if (active_sessions == 0) {
- return;
- }
-
- --active_sessions;
-}
-
-} // 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 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-class ClientSession;
-class KernelCore;
-class ServerPort;
-
-class ClientPort final : public Object {
-public:
- explicit ClientPort(KernelCore& kernel);
- ~ClientPort() override;
-
- friend class ServerPort;
- std::string GetTypeName() const override {
- return "ClientPort";
- }
- std::string GetName() const override {
- return name;
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::ClientPort;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- std::shared_ptr<ServerPort> GetServerPort() const;
-
- /**
- * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
- * list of pending sessions, and signals the ServerPort, causing any threads
- * waiting on it to awake.
- * @returns ClientSession The client endpoint of the created Session pair, or error code.
- */
- ResultVal<std::shared_ptr<ClientSession>> Connect();
-
- /**
- * Signifies that a previously active connection has been closed,
- * decreasing the total number of active connections to this port.
- */
- void ConnectionClosed();
-
- void Finalize() override {}
-
-private:
- std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
- u32 max_sessions = 0; ///< Maximum number of simultaneous sessions the port can have
- u32 active_sessions = 0; ///< Number of currently open sessions to this port
- std::string name; ///< Name of client port (optional)
-};
-
-} // 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 @@
-// Copyright 2019 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/session.h"
-#include "core/hle/kernel/svc_results.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
-
-ClientSession::~ClientSession() {
- // This destructor will be called automatically when the last ClientSession handle is closed by
- // the emulated application.
- if (parent->Server()) {
- parent->Server()->ClientDisconnected();
- }
-}
-
-bool ClientSession::IsSignaled() const {
- UNIMPLEMENTED();
- return true;
-}
-
-ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel,
- std::shared_ptr<Session> parent,
- std::string name) {
- std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)};
-
- client_session->name = std::move(name);
- client_session->parent = std::move(parent);
-
- return MakeResult(std::move(client_session));
-}
-
-ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread,
- Core::Memory::Memory& memory,
- Core::Timing::CoreTiming& core_timing) {
- // Keep ServerSession alive until we're done working with it.
- if (!parent->Server()) {
- return ResultSessionClosedByRemote;
- }
-
- // Signal the server session that new data is available
- return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing);
-}
-
-} // 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 @@
-// Copyright 2019 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-#include "core/hle/kernel/k_synchronization_object.h"
-#include "core/hle/result.h"
-
-union ResultCode;
-
-namespace Core::Memory {
-class Memory;
-}
-
-namespace Core::Timing {
-class CoreTiming;
-}
-
-namespace Kernel {
-
-class KernelCore;
-class Session;
-class KThread;
-
-class ClientSession final : public KSynchronizationObject {
-public:
- explicit ClientSession(KernelCore& kernel);
- ~ClientSession() override;
-
- friend class Session;
-
- std::string GetTypeName() const override {
- return "ClientSession";
- }
-
- std::string GetName() const override {
- return name;
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
- Core::Timing::CoreTiming& core_timing);
-
- bool IsSignaled() const override;
-
- void Finalize() override {}
-
-private:
- static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
- std::shared_ptr<Session> parent,
- std::string name = "Unknown");
-
- /// The parent session, which links to the server endpoint.
- std::shared_ptr<Session> parent;
-
- /// Name of the client session (optional)
- std::string name;
-};
-
-} // 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 @@
namespace Kernel {
-GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
- : kernel{kernel}, scheduler_lock{kernel} {}
+GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel_)
+ : kernel{kernel_}, scheduler_lock{kernel_} {}
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
-void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) {
+void GlobalSchedulerContext::AddThread(KThread* thread) {
std::scoped_lock lock{global_list_guard};
- thread_list.push_back(std::move(thread));
+ thread_list.push_back(thread);
}
-void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) {
+void GlobalSchedulerContext::RemoveThread(KThread* thread) {
std::scoped_lock lock{global_list_guard};
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
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 {
public:
using LockType = KAbstractSchedulerLock<KScheduler>;
- explicit GlobalSchedulerContext(KernelCore& kernel);
+ explicit GlobalSchedulerContext(KernelCore& kernel_);
~GlobalSchedulerContext();
/// Adds a new thread to the scheduler
- void AddThread(std::shared_ptr<KThread> thread);
+ void AddThread(KThread* thread);
/// Removes a thread from the scheduler
- void RemoveThread(std::shared_ptr<KThread> thread);
+ void RemoveThread(KThread* thread);
/// Returns a list of all threads managed by the scheduler
- [[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const {
+ [[nodiscard]] const std::vector<KThread*>& GetThreadList() const {
return thread_list;
}
@@ -79,7 +79,7 @@ private:
LockType scheduler_lock;
/// Lists all thread ids that aren't deleted/etc.
- std::vector<std::shared_ptr<KThread>> thread_list;
+ std::vector<KThread*> thread_list;
Common::SpinLock global_list_guard{};
};
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 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <utility>
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hle/kernel/handle_table.h"
-#include "core/hle/kernel/k_scheduler.h"
-#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/svc_results.h"
-
-namespace Kernel {
-namespace {
-constexpr u16 GetSlot(Handle handle) {
- return static_cast<u16>(handle >> 15);
-}
-
-constexpr u16 GetGeneration(Handle handle) {
- return static_cast<u16>(handle & 0x7FFF);
-}
-} // Anonymous namespace
-
-HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} {
- Clear();
-}
-
-HandleTable::~HandleTable() = default;
-
-ResultCode HandleTable::SetSize(s32 handle_table_size) {
- if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
- LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT);
- return ResultOutOfMemory;
- }
-
- // Values less than or equal to zero indicate to use the maximum allowable
- // size for the handle table in the actual kernel, so we ignore the given
- // value in that case, since we assume this by default unless this function
- // is called.
- if (handle_table_size > 0) {
- table_size = static_cast<u16>(handle_table_size);
- }
-
- return RESULT_SUCCESS;
-}
-
-ResultVal<Handle> HandleTable::Create(std::shared_ptr<Object> obj) {
- DEBUG_ASSERT(obj != nullptr);
-
- const u16 slot = next_free_slot;
- if (slot >= table_size) {
- LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
- return ResultHandleTableFull;
- }
- next_free_slot = generations[slot];
-
- const u16 generation = next_generation++;
-
- // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
- // Horizon OS uses zero to represent an invalid handle, so skip to 1.
- if (next_generation >= (1 << 15)) {
- next_generation = 1;
- }
-
- generations[slot] = generation;
- objects[slot] = std::move(obj);
-
- Handle handle = generation | (slot << 15);
- return MakeResult<Handle>(handle);
-}
-
-ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
- std::shared_ptr<Object> object = GetGeneric(handle);
- if (object == nullptr) {
- LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
- return ResultInvalidHandle;
- }
- return Create(std::move(object));
-}
-
-ResultCode HandleTable::Close(Handle handle) {
- if (!IsValid(handle)) {
- LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle);
- return ResultInvalidHandle;
- }
-
- const u16 slot = GetSlot(handle);
-
- if (objects[slot].use_count() == 1) {
- objects[slot]->Finalize();
- }
-
- objects[slot] = nullptr;
-
- generations[slot] = next_free_slot;
- next_free_slot = slot;
- return RESULT_SUCCESS;
-}
-
-bool HandleTable::IsValid(Handle handle) const {
- const std::size_t slot = GetSlot(handle);
- const u16 generation = GetGeneration(handle);
-
- return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;
-}
-
-std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
- if (handle == CurrentThread) {
- return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread());
- } else if (handle == CurrentProcess) {
- return SharedFrom(kernel.CurrentProcess());
- }
-
- if (!IsValid(handle)) {
- return nullptr;
- }
- return objects[GetSlot(handle)];
-}
-
-void HandleTable::Clear() {
- for (u16 i = 0; i < table_size; ++i) {
- generations[i] = static_cast<u16>(i + 1);
- objects[i] = nullptr;
- }
- next_free_slot = 0;
-}
-
-} // 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 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <array>
-#include <cstddef>
-#include <memory>
-
-#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-class KernelCore;
-
-enum KernelHandle : Handle {
- InvalidHandle = 0,
- CurrentThread = 0xFFFF8000,
- CurrentProcess = 0xFFFF8001,
-};
-
-/**
- * This class allows the creation of Handles, which are references to objects that can be tested
- * for validity and looked up. Here they are used to pass references to kernel objects to/from the
- * emulated process. it has been designed so that it follows the same handle format and has
- * approximately the same restrictions as the handle manager in the CTR-OS.
- *
- * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
- * The slot index is used to index into the arrays in this class to access the data corresponding
- * to the Handle.
- *
- * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
- * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
- * value of the counter is stored into the Handle as well as in the handle table (in the
- * "generations" array). When looking up a handle, the Handle's generation must match with the
- * value stored on the class, otherwise the Handle is considered invalid.
- *
- * To find free slots when allocating a Handle without needing to scan the entire object array, the
- * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
- * When a Handle is created, an index is popped off the list and used for the new Handle. When it
- * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
- * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
- * verified and isn't likely to cause any problems.
- */
-class HandleTable final : NonCopyable {
-public:
- /// This is the maximum limit of handles allowed per process in Horizon
- static constexpr std::size_t MAX_COUNT = 1024;
-
- explicit HandleTable(KernelCore& kernel);
- ~HandleTable();
-
- /**
- * Sets the number of handles that may be in use at one time
- * for this handle table.
- *
- * @param handle_table_size The desired size to limit the handle table to.
- *
- * @returns an error code indicating if initialization was successful.
- * If initialization was not successful, then ERR_OUT_OF_MEMORY
- * will be returned.
- *
- * @pre handle_table_size must be within the range [0, 1024]
- */
- ResultCode SetSize(s32 handle_table_size);
-
- /**
- * Allocates a handle for the given object.
- * @return The created Handle or one of the following errors:
- * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded.
- */
- ResultVal<Handle> Create(std::shared_ptr<Object> obj);
-
- /**
- * Returns a new handle that points to the same object as the passed in handle.
- * @return The duplicated Handle or one of the following errors:
- * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
- * - Any errors returned by `Create()`.
- */
- ResultVal<Handle> Duplicate(Handle handle);
-
- /**
- * Closes a handle, removing it from the table and decreasing the object's ref-count.
- * @return `RESULT_SUCCESS` or one of the following errors:
- * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
- */
- ResultCode Close(Handle handle);
-
- /// Checks if a handle is valid and points to an existing object.
- bool IsValid(Handle handle) const;
-
- /**
- * Looks up a handle.
- * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
- */
- std::shared_ptr<Object> GetGeneric(Handle handle) const;
-
- /**
- * Looks up a handle while verifying its type.
- * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
- * type differs from the requested one.
- */
- template <class T>
- std::shared_ptr<T> Get(Handle handle) const {
- return DynamicObjectCast<T>(GetGeneric(handle));
- }
-
- /// Closes all handles held in this table.
- void Clear();
-
-private:
- /// Stores the Object referenced by the handle or null if the slot is empty.
- std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
-
- /**
- * The value of `next_generation` when the handle was created, used to check for validity. For
- * empty slots, contains the index of the next free slot in the list.
- */
- std::array<u16, MAX_COUNT> generations;
-
- /**
- * The limited size of the handle table. This can be specified by process
- * capabilities in order to restrict the overall number of handles that
- * can be created in a process instance
- */
- u16 table_size = static_cast<u16>(MAX_COUNT);
-
- /**
- * Global counter of the number of created handles. Stored in `generations` when a handle is
- * created, and wraps around to 1 when it hits 0x8000.
- */
- u16 next_generation = 1;
-
- /// Head of the free slots linked list.
- u16 next_free_slot = 0;
-
- /// Underlying kernel instance that this handle table operates under.
- KernelCore& kernel;
-};
-
-} // 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 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_handle_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/memory.h"
@@ -35,33 +34,28 @@ SessionRequestHandler::SessionRequestHandler() = default;
SessionRequestHandler::~SessionRequestHandler() = default;
-void SessionRequestHandler::ClientConnected(std::shared_ptr<ServerSession> server_session) {
- server_session->SetHleHandler(shared_from_this());
- connected_sessions.push_back(std::move(server_session));
+void SessionRequestHandler::ClientConnected(KServerSession* session) {
+ session->SetHleHandler(shared_from_this());
}
-void SessionRequestHandler::ClientDisconnected(
- const std::shared_ptr<ServerSession>& server_session) {
- server_session->SetHleHandler(nullptr);
- boost::range::remove_erase(connected_sessions, server_session);
+void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
+ session->SetHleHandler(nullptr);
}
-HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
- std::shared_ptr<ServerSession> server_session,
- std::shared_ptr<KThread> thread)
- : server_session(std::move(server_session)),
- thread(std::move(thread)), kernel{kernel}, memory{memory} {
+HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
+ KServerSession* server_session_, KThread* thread_)
+ : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
cmd_buf[0] = 0;
}
HLERequestContext::~HLERequestContext() = default;
-void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf,
+void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf,
bool incoming) {
IPC::RequestParser rp(src_cmdbuf);
command_header = rp.PopRaw<IPC::CommandHeader>();
- if (command_header->type == IPC::CommandType::Close) {
+ if (command_header->IsCloseCommand()) {
// Close does not populate the rest of the IPC header
return;
}
@@ -70,19 +64,19 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
if (command_header->enable_handle_descriptor) {
handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
if (handle_descriptor_header->send_current_pid) {
- rp.Skip(2, false);
+ pid = rp.Pop<u64>();
}
if (incoming) {
// Populate the object lists with the data in the IPC request.
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
const u32 copy_handle{rp.Pop<Handle>()};
copy_handles.push_back(copy_handle);
- copy_objects.push_back(handle_table.GetGeneric(copy_handle));
+ copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe());
}
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
const u32 move_handle{rp.Pop<Handle>()};
move_handles.push_back(move_handle);
- move_objects.push_back(handle_table.GetGeneric(move_handle));
+ move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe());
}
} else {
// 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_
}
}
- for (unsigned i = 0; i < command_header->num_buf_x_descriptors; ++i) {
+ for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
}
- for (unsigned i = 0; i < command_header->num_buf_a_descriptors; ++i) {
+ for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
}
- for (unsigned i = 0; i < command_header->num_buf_b_descriptors; ++i) {
+ for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
}
- for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) {
+ for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
}
- buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
-
- // Padding to align to 16 bytes
- rp.AlignWithPadding();
-
- if (Session()->IsDomain() && ((command_header->type == IPC::CommandType::Request ||
- command_header->type == IPC::CommandType::RequestWithContext) ||
- !incoming)) {
- // If this is an incoming message, only CommandType "Request" has a domain header
- // All outgoing domain messages have the domain header, if only incoming has it
- if (incoming || domain_message_header) {
- domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
- } else {
- if (Session()->IsDomain()) {
- LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
+ const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
+
+ if (!command_header->IsTipc()) {
+ // Padding to align to 16 bytes
+ rp.AlignWithPadding();
+
+ if (Session()->IsDomain() &&
+ ((command_header->type == IPC::CommandType::Request ||
+ command_header->type == IPC::CommandType::RequestWithContext) ||
+ !incoming)) {
+ // If this is an incoming message, only CommandType "Request" has a domain header
+ // All outgoing domain messages have the domain header, if only incoming has it
+ if (incoming || domain_message_header) {
+ domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
+ } else {
+ if (Session()->IsDomain()) {
+ LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
+ }
}
}
- }
- data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>();
+ data_payload_header = rp.PopRaw<IPC::DataPayloadHeader>();
- data_payload_offset = rp.GetCurrentOffset();
+ data_payload_offset = rp.GetCurrentOffset();
- if (domain_message_header && domain_message_header->command ==
- IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) {
- // CloseVirtualHandle command does not have SFC* or any data
- return;
- }
+ if (domain_message_header &&
+ domain_message_header->command ==
+ IPC::DomainMessageHeader::CommandType::CloseVirtualHandle) {
+ // CloseVirtualHandle command does not have SFC* or any data
+ return;
+ }
- if (incoming) {
- ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
- } else {
- ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
+ if (incoming) {
+ ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'I'));
+ } else {
+ ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
+ }
}
rp.SetCurrentOffset(buffer_c_offset);
@@ -150,14 +148,14 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} else {
- unsigned num_buf_c_descriptors =
- static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2;
+ u32 num_buf_c_descriptors =
+ static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
// This is used to detect possible underflows, in case something is broken
// with the two ifs above and the flags value is == 0 || == 1.
ASSERT(num_buf_c_descriptors < 14);
- for (unsigned i = 0; i < num_buf_c_descriptors; ++i) {
+ for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
}
}
@@ -169,87 +167,70 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
}
-ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
+ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
u32_le* src_cmdbuf) {
ParseCommandBuffer(handle_table, src_cmdbuf, true);
- if (command_header->type == IPC::CommandType::Close) {
+
+ if (command_header->IsCloseCommand()) {
// Close does not populate the rest of the IPC header
return RESULT_SUCCESS;
}
- // The data_size already includes the payload header, the padding and the domain header.
- std::size_t size = data_payload_offset + command_header->data_size -
- sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
- if (domain_message_header)
- size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
- std::copy_n(src_cmdbuf, size, cmd_buf.begin());
+ std::copy_n(src_cmdbuf, IPC::COMMAND_BUFFER_LENGTH, cmd_buf.begin());
+
return RESULT_SUCCESS;
}
-ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) {
- auto& owner_process = *thread.GetOwnerProcess();
+ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
+ auto current_offset = handles_offset;
+ auto& owner_process = *requesting_thread.GetOwnerProcess();
auto& handle_table = owner_process.GetHandleTable();
- std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
- memory.ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
- dst_cmdbuf.size() * sizeof(u32));
-
- // The header was already built in the internal command buffer. Attempt to parse it to verify
- // the integrity and then copy it over to the target command buffer.
- ParseCommandBuffer(handle_table, cmd_buf.data(), false);
-
// The data_size already includes the payload header, the padding and the domain header.
- std::size_t size = data_payload_offset + command_header->data_size -
- sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
- if (domain_message_header)
- size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
-
- std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data());
+ std::size_t size{};
- if (command_header->enable_handle_descriptor) {
- ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(),
- "Handle descriptor bit set but no handles to translate");
- // We write the translated handles at a specific offset in the command buffer, this space
- // was already reserved when writing the header.
- std::size_t current_offset =
- (sizeof(IPC::CommandHeader) + sizeof(IPC::HandleDescriptorHeader)) / sizeof(u32);
- ASSERT_MSG(!handle_descriptor_header->send_current_pid, "Sending PID is not implemented");
-
- ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
- ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
-
- // We don't make a distinction between copy and move handles when translating since HLE
- // services don't deal with handles directly. However, the guest applications might check
- // for specific values in each of these descriptors.
- for (auto& object : copy_objects) {
- ASSERT(object != nullptr);
- dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
+ if (IsTipc()) {
+ size = cmd_buf.size();
+ } else {
+ size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4;
+ if (Session()->IsDomain()) {
+ size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32);
}
+ }
- for (auto& object : move_objects) {
- ASSERT(object != nullptr);
- dst_cmdbuf[current_offset++] = handle_table.Create(object).Unwrap();
+ for (auto& object : copy_objects) {
+ Handle handle{};
+ if (object) {
+ R_TRY(handle_table.Add(&handle, object));
}
+ cmd_buf[current_offset++] = handle;
}
+ for (auto& object : move_objects) {
+ Handle handle{};
+ if (object) {
+ R_TRY(handle_table.Add(&handle, object));
- // TODO(Subv): Translate the X/A/B/W buffers.
+ // Close our reference to the object, as it is being moved to the caller.
+ object->Close();
+ }
+ cmd_buf[current_offset++] = handle;
+ }
- if (Session()->IsDomain() && domain_message_header) {
- ASSERT(domain_message_header->num_objects == domain_objects.size());
- // Write the domain objects to the command buffer, these go after the raw untranslated data.
- // TODO(Subv): This completely ignores C buffers.
- std::size_t domain_offset = size - domain_message_header->num_objects;
+ // Write the domain objects to the command buffer, these go after the raw untranslated data.
+ // TODO(Subv): This completely ignores C buffers.
+ if (Session()->IsDomain()) {
+ current_offset = domain_offset - static_cast<u32>(domain_objects.size());
for (const auto& object : domain_objects) {
server_session->AppendDomainRequestHandler(object);
- dst_cmdbuf[domain_offset++] =
+ cmd_buf[current_offset++] =
static_cast<u32_le>(server_session->NumDomainRequestHandlers());
}
}
// Copy the translated command buffer back into the thread's command buffer area.
- memory.WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
- dst_cmdbuf.size() * sizeof(u32));
+ memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(),
+ size * sizeof(u32));
return RESULT_SUCCESS;
}
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 @@
#include "common/concepts.h"
#include "common/swap.h"
#include "core/hle/ipc.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/svc_common.h"
union ResultCode;
@@ -35,13 +36,14 @@ class ServiceFrameworkBase;
namespace Kernel {
class Domain;
-class HandleTable;
class HLERequestContext;
class KernelCore;
-class Process;
-class ServerSession;
+class KHandleTable;
+class KProcess;
+class KServerSession;
class KThread;
class KReadableEvent;
+class KSession;
class KWritableEvent;
enum class ThreadWakeupReason;
@@ -64,27 +66,22 @@ public:
* this request (ServerSession, Originator thread, Translated command buffer, etc).
* @returns ResultCode the result code of the translate operation.
*/
- virtual ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) = 0;
+ virtual ResultCode HandleSyncRequest(Kernel::KServerSession& session,
+ Kernel::HLERequestContext& context) = 0;
/**
* Signals that a client has just connected to this HLE handler and keeps the
* associated ServerSession alive for the duration of the connection.
* @param server_session Owning pointer to the ServerSession associated with the connection.
*/
- void ClientConnected(std::shared_ptr<ServerSession> server_session);
+ void ClientConnected(KServerSession* session);
/**
* Signals that a client has just disconnected from this HLE handler and releases the
* associated ServerSession.
* @param server_session ServerSession associated with the connection.
*/
- void ClientDisconnected(const std::shared_ptr<ServerSession>& server_session);
-
-protected:
- /// List of sessions that are connected to this handler.
- /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
- /// for the duration of the connection.
- std::vector<std::shared_ptr<ServerSession>> connected_sessions;
+ void ClientDisconnected(KServerSession* session);
};
/**
@@ -109,8 +106,7 @@ protected:
class HLERequestContext {
public:
explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
- std::shared_ptr<ServerSession> session,
- std::shared_ptr<KThread> thread);
+ KServerSession* session, KThread* thread);
~HLERequestContext();
/// Returns a pointer to the IPC command buffer for this request.
@@ -122,26 +118,43 @@ public:
* Returns the session through which this request was made. This can be used as a map key to
* access per-client data on services.
*/
- const std::shared_ptr<Kernel::ServerSession>& Session() const {
+ Kernel::KServerSession* Session() {
return server_session;
}
/// Populates this context with data from the requesting process/thread.
- ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
+ ResultCode PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
u32_le* src_cmdbuf);
/// Writes data from this context back to the requesting process/thread.
- ResultCode WriteToOutgoingCommandBuffer(KThread& thread);
+ ResultCode WriteToOutgoingCommandBuffer(KThread& requesting_thread);
- u32_le GetCommand() const {
+ u32_le GetHipcCommand() const {
return command;
}
+ u32_le GetTipcCommand() const {
+ return static_cast<u32_le>(command_header->type.Value()) -
+ static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion);
+ }
+
+ u32_le GetCommand() const {
+ return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand();
+ }
+
+ bool IsTipc() const {
+ return command_header->IsTipc();
+ }
+
IPC::CommandType GetCommandType() const {
return command_header->type;
}
- unsigned GetDataPayloadOffset() const {
+ u64 GetPID() const {
+ return pid;
+ }
+
+ u32 GetDataPayloadOffset() const {
return data_payload_offset;
}
@@ -218,22 +231,12 @@ public:
return move_handles.at(index);
}
- template <typename T>
- std::shared_ptr<T> GetCopyObject(std::size_t index) {
- return DynamicObjectCast<T>(copy_objects.at(index));
- }
-
- template <typename T>
- std::shared_ptr<T> GetMoveObject(std::size_t index) {
- return DynamicObjectCast<T>(move_objects.at(index));
- }
-
- void AddMoveObject(std::shared_ptr<Object> object) {
- move_objects.emplace_back(std::move(object));
+ void AddMoveObject(KAutoObject* object) {
+ move_objects.emplace_back(object);
}
- void AddCopyObject(std::shared_ptr<Object> object) {
- copy_objects.emplace_back(std::move(object));
+ void AddCopyObject(KAutoObject* object) {
+ copy_objects.emplace_back(object);
}
void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) {
@@ -276,10 +279,6 @@ public:
return *thread;
}
- const KThread& GetThread() const {
- return *thread;
- }
-
bool IsThreadWaiting() const {
return is_thread_waiting;
}
@@ -287,16 +286,17 @@ public:
private:
friend class IPC::ResponseBuilder;
- void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
+ void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
- std::shared_ptr<Kernel::ServerSession> server_session;
- std::shared_ptr<KThread> thread;
+ Kernel::KServerSession* server_session{};
+ KThread* thread;
+
// TODO(yuriks): Check common usage of this and optimize size accordingly
boost::container::small_vector<Handle, 8> move_handles;
boost::container::small_vector<Handle, 8> copy_handles;
- boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
- boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
+ boost::container::small_vector<KAutoObject*, 8> move_objects;
+ boost::container::small_vector<KAutoObject*, 8> copy_objects;
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;
std::optional<IPC::CommandHeader> command_header;
@@ -309,9 +309,12 @@ private:
std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
- unsigned data_payload_offset{};
- unsigned buffer_c_offset{};
u32_le command{};
+ u64 pid{};
+ u32 data_payload_offset{};
+ u32 handles_offset{};
+ u32 domain_offset{};
+ u32 data_size{};
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "core/core.h"
+#include "core/hardware_properties.h"
+#include "core/hle/kernel/init/init_slab_setup.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/k_session.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/k_system_control.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/kernel/memory_types.h"
+#include "core/memory.h"
+
+namespace Kernel::Init {
+
+#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS
+
+#define FOREACH_SLAB_TYPE(HANDLER, ...) \
+ HANDLER(KProcess, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \
+ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \
+ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
+ HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \
+ HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \
+ HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
+ HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
+ HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
+
+namespace {
+
+#define DEFINE_SLAB_TYPE_ENUM_MEMBER(NAME, COUNT, ...) KSlabType_##NAME,
+
+enum KSlabType : u32 {
+ FOREACH_SLAB_TYPE(DEFINE_SLAB_TYPE_ENUM_MEMBER) KSlabType_Count,
+};
+
+#undef DEFINE_SLAB_TYPE_ENUM_MEMBER
+
+// Constexpr counts.
+constexpr size_t SlabCountKProcess = 80;
+constexpr size_t SlabCountKThread = 800;
+constexpr size_t SlabCountKEvent = 700;
+constexpr size_t SlabCountKInterruptEvent = 100;
+constexpr size_t SlabCountKPort = 256 + 0x20; // Extra 0x20 ports over Nintendo for homebrew.
+constexpr size_t SlabCountKSharedMemory = 80;
+constexpr size_t SlabCountKTransferMemory = 200;
+constexpr size_t SlabCountKCodeMemory = 10;
+constexpr size_t SlabCountKDeviceAddressSpace = 300;
+constexpr size_t SlabCountKSession = 933;
+constexpr size_t SlabCountKLightSession = 100;
+constexpr size_t SlabCountKObjectName = 7;
+constexpr size_t SlabCountKResourceLimit = 5;
+constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES;
+constexpr size_t SlabCountKAlpha = 1;
+constexpr size_t SlabCountKBeta = 6;
+
+constexpr size_t SlabCountExtraKThread = 160;
+
+template <typename T>
+VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address,
+ size_t num_objects) {
+ const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*));
+ VAddr start = Common::AlignUp(address, alignof(T));
+
+ if (size > 0) {
+ const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1);
+ ASSERT(region != nullptr);
+ ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab));
+ T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size);
+ }
+
+ return start + size;
+}
+
+} // namespace
+
+KSlabResourceCounts KSlabResourceCounts::CreateDefault() {
+ return {
+ .num_KProcess = SlabCountKProcess,
+ .num_KThread = SlabCountKThread,
+ .num_KEvent = SlabCountKEvent,
+ .num_KInterruptEvent = SlabCountKInterruptEvent,
+ .num_KPort = SlabCountKPort,
+ .num_KSharedMemory = SlabCountKSharedMemory,
+ .num_KTransferMemory = SlabCountKTransferMemory,
+ .num_KCodeMemory = SlabCountKCodeMemory,
+ .num_KDeviceAddressSpace = SlabCountKDeviceAddressSpace,
+ .num_KSession = SlabCountKSession,
+ .num_KLightSession = SlabCountKLightSession,
+ .num_KObjectName = SlabCountKObjectName,
+ .num_KResourceLimit = SlabCountKResourceLimit,
+ .num_KDebug = SlabCountKDebug,
+ .num_KAlpha = SlabCountKAlpha,
+ .num_KBeta = SlabCountKBeta,
+ };
+}
+
+void InitializeSlabResourceCounts(KernelCore& kernel) {
+ kernel.SlabResourceCounts() = KSlabResourceCounts::CreateDefault();
+ if (KSystemControl::Init::ShouldIncreaseThreadResourceLimit()) {
+ kernel.SlabResourceCounts().num_KThread += SlabCountExtraKThread;
+ }
+}
+
+size_t CalculateTotalSlabHeapSize(const KernelCore& kernel) {
+ size_t size = 0;
+
+#define ADD_SLAB_SIZE(NAME, COUNT, ...) \
+ { \
+ size += alignof(NAME); \
+ size += Common::AlignUp(sizeof(NAME) * (COUNT), alignof(void*)); \
+ };
+
+ // Add the size required for each slab.
+ FOREACH_SLAB_TYPE(ADD_SLAB_SIZE)
+
+#undef ADD_SLAB_SIZE
+
+ // Add the reserved size.
+ size += KernelSlabHeapGapsSize;
+
+ return size;
+}
+
+void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
+ auto& kernel = system.Kernel();
+
+ // Get the start of the slab region, since that's where we'll be working.
+ VAddr address = memory_layout.GetSlabRegionAddress();
+
+ // Initialize slab type array to be in sorted order.
+ std::array<KSlabType, KSlabType_Count> slab_types;
+ for (size_t i = 0; i < slab_types.size(); i++) {
+ slab_types[i] = static_cast<KSlabType>(i);
+ }
+
+ // N shuffles the slab type array with the following simple algorithm.
+ for (size_t i = 0; i < slab_types.size(); i++) {
+ const size_t rnd = KSystemControl::GenerateRandomRange(0, slab_types.size() - 1);
+ std::swap(slab_types[i], slab_types[rnd]);
+ }
+
+ // Create an array to represent the gaps between the slabs.
+ const size_t total_gap_size = KernelSlabHeapGapsSize;
+ std::array<size_t, slab_types.size()> slab_gaps;
+ for (size_t i = 0; i < slab_gaps.size(); i++) {
+ // Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange
+ // is inclusive. However, Nintendo also has the off-by-one error, and it's "harmless", so we
+ // will include it ourselves.
+ slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size);
+ }
+
+ // Sort the array, so that we can treat differences between values as offsets to the starts of
+ // slabs.
+ for (size_t i = 1; i < slab_gaps.size(); i++) {
+ for (size_t j = i; j > 0 && slab_gaps[j - 1] > slab_gaps[j]; j--) {
+ std::swap(slab_gaps[j], slab_gaps[j - 1]);
+ }
+ }
+
+ for (size_t i = 0; i < slab_types.size(); i++) {
+ // Add the random gap to the address.
+ address += (i == 0) ? slab_gaps[0] : slab_gaps[i] - slab_gaps[i - 1];
+
+#define INITIALIZE_SLAB_HEAP(NAME, COUNT, ...) \
+ case KSlabType_##NAME: \
+ address = InitializeSlabHeap<NAME>(system, memory_layout, address, COUNT); \
+ break;
+
+ // Initialize the slabheap.
+ switch (slab_types[i]) {
+ // For each of the slab types, we want to initialize that heap.
+ FOREACH_SLAB_TYPE(INITIALIZE_SLAB_HEAP)
+ // If we somehow get an invalid type, abort.
+ default:
+ UNREACHABLE();
+ }
+ }
+}
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Kernel {
+class KernelCore;
+class KMemoryLayout;
+} // namespace Kernel
+
+namespace Kernel::Init {
+
+struct KSlabResourceCounts {
+ static KSlabResourceCounts CreateDefault();
+
+ size_t num_KProcess;
+ size_t num_KThread;
+ size_t num_KEvent;
+ size_t num_KInterruptEvent;
+ size_t num_KPort;
+ size_t num_KSharedMemory;
+ size_t num_KTransferMemory;
+ size_t num_KCodeMemory;
+ size_t num_KDeviceAddressSpace;
+ size_t num_KSession;
+ size_t num_KLightSession;
+ size_t num_KObjectName;
+ size_t num_KResourceLimit;
+ size_t num_KDebug;
+ size_t num_KAlpha;
+ size_t num_KBeta;
+};
+
+void InitializeSlabResourceCounts(KernelCore& kernel);
+size_t CalculateTotalSlabHeapSize(const KernelCore& kernel);
+void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout);
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_auto_object.h"
+
+namespace Kernel {
+
+KAutoObject* KAutoObject::Create(KAutoObject* obj) {
+ obj->m_ref_count = 1;
+ return obj;
+}
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+#include <string>
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/intrusive_red_black_tree.h"
+#include "core/hle/kernel/k_class_token.h"
+
+namespace Kernel {
+
+class KernelCore;
+class KProcess;
+
+#define KERNEL_AUTOOBJECT_TRAITS(CLASS, BASE_CLASS) \
+ YUZU_NON_COPYABLE(CLASS); \
+ YUZU_NON_MOVEABLE(CLASS); \
+ \
+private: \
+ friend class ::Kernel::KClassTokenGenerator; \
+ static constexpr inline auto ObjectType = ::Kernel::KClassTokenGenerator::ObjectType::CLASS; \
+ static constexpr inline const char* const TypeName = #CLASS; \
+ static constexpr inline ClassTokenType ClassToken() { \
+ return ::Kernel::ClassToken<CLASS>; \
+ } \
+ \
+public: \
+ using BaseClass = BASE_CLASS; \
+ static constexpr TypeObj GetStaticTypeObj() { \
+ constexpr ClassTokenType Token = ClassToken(); \
+ return TypeObj(TypeName, Token); \
+ } \
+ static constexpr const char* GetStaticTypeName() { \
+ return TypeName; \
+ } \
+ virtual TypeObj GetTypeObj() const { \
+ return GetStaticTypeObj(); \
+ } \
+ virtual const char* GetTypeName() const { \
+ return GetStaticTypeName(); \
+ } \
+ \
+private: \
+ constexpr bool operator!=(const TypeObj& rhs)
+
+class KAutoObject {
+protected:
+ class TypeObj {
+ public:
+ constexpr explicit TypeObj(const char* n, ClassTokenType tok)
+ : m_name(n), m_class_token(tok) {}
+
+ constexpr const char* GetName() const {
+ return m_name;
+ }
+ constexpr ClassTokenType GetClassToken() const {
+ return m_class_token;
+ }
+
+ constexpr bool operator==(const TypeObj& rhs) const {
+ return this->GetClassToken() == rhs.GetClassToken();
+ }
+
+ constexpr bool operator!=(const TypeObj& rhs) const {
+ return this->GetClassToken() != rhs.GetClassToken();
+ }
+
+ constexpr bool IsDerivedFrom(const TypeObj& rhs) const {
+ return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
+ }
+
+ private:
+ const char* m_name;
+ ClassTokenType m_class_token;
+ };
+
+private:
+ KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
+
+public:
+ explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {}
+ virtual ~KAutoObject() = default;
+
+ static KAutoObject* Create(KAutoObject* ptr);
+
+ // Destroy is responsible for destroying the auto object's resources when ref_count hits zero.
+ virtual void Destroy() {
+ UNIMPLEMENTED();
+ }
+
+ // Finalize is responsible for cleaning up resource, but does not destroy the object.
+ virtual void Finalize() {}
+
+ virtual KProcess* GetOwner() const {
+ return nullptr;
+ }
+
+ u32 GetReferenceCount() const {
+ return m_ref_count.load();
+ }
+
+ bool IsDerivedFrom(const TypeObj& rhs) const {
+ return this->GetTypeObj().IsDerivedFrom(rhs);
+ }
+
+ bool IsDerivedFrom(const KAutoObject& rhs) const {
+ return this->IsDerivedFrom(rhs.GetTypeObj());
+ }
+
+ template <typename Derived>
+ Derived DynamicCast() {
+ static_assert(std::is_pointer_v<Derived>);
+ using DerivedType = std::remove_pointer_t<Derived>;
+
+ if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
+ return static_cast<Derived>(this);
+ } else {
+ return nullptr;
+ }
+ }
+
+ template <typename Derived>
+ const Derived DynamicCast() const {
+ static_assert(std::is_pointer_v<Derived>);
+ using DerivedType = std::remove_pointer_t<Derived>;
+
+ if (this->IsDerivedFrom(DerivedType::GetStaticTypeObj())) {
+ return static_cast<Derived>(this);
+ } else {
+ return nullptr;
+ }
+ }
+
+ bool Open() {
+ // Atomically increment the reference count, only if it's positive.
+ u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
+ do {
+ if (cur_ref_count == 0) {
+ return false;
+ }
+ ASSERT(cur_ref_count < cur_ref_count + 1);
+ } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count + 1,
+ std::memory_order_relaxed));
+
+ return true;
+ }
+
+ void Close() {
+ // Atomically decrement the reference count, not allowing it to become negative.
+ u32 cur_ref_count = m_ref_count.load(std::memory_order_acquire);
+ do {
+ ASSERT(cur_ref_count > 0);
+ } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1,
+ std::memory_order_relaxed));
+
+ // If ref count hits zero, destroy the object.
+ if (cur_ref_count - 1 == 0) {
+ this->Destroy();
+ }
+ }
+
+protected:
+ KernelCore& kernel;
+ std::string name;
+
+private:
+ std::atomic<u32> m_ref_count{};
+};
+
+class KAutoObjectWithListContainer;
+
+class KAutoObjectWithList : public KAutoObject {
+public:
+ explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
+
+ static int Compare(const KAutoObjectWithList& lhs, const KAutoObjectWithList& rhs) {
+ const u64 lid = lhs.GetId();
+ const u64 rid = rhs.GetId();
+
+ if (lid < rid) {
+ return -1;
+ } else if (lid > rid) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+public:
+ virtual u64 GetId() const {
+ return reinterpret_cast<u64>(this);
+ }
+
+ virtual const std::string& GetName() const {
+ return name;
+ }
+
+private:
+ friend class KAutoObjectWithListContainer;
+
+ Common::IntrusiveRedBlackTreeNode list_node;
+};
+
+template <typename T>
+class KScopedAutoObject {
+ YUZU_NON_COPYABLE(KScopedAutoObject);
+
+public:
+ constexpr KScopedAutoObject() = default;
+
+ constexpr KScopedAutoObject(T* o) : m_obj(o) {
+ if (m_obj != nullptr) {
+ m_obj->Open();
+ }
+ }
+
+ ~KScopedAutoObject() {
+ if (m_obj != nullptr) {
+ m_obj->Close();
+ }
+ m_obj = nullptr;
+ }
+
+ template <typename U>
+ requires(std::derived_from<T, U> ||
+ std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
+ if constexpr (std::derived_from<U, T>) {
+ // Upcast.
+ m_obj = rhs.m_obj;
+ rhs.m_obj = nullptr;
+ } else {
+ // Downcast.
+ T* derived = nullptr;
+ if (rhs.m_obj != nullptr) {
+ derived = rhs.m_obj->template DynamicCast<T*>();
+ if (derived == nullptr) {
+ rhs.m_obj->Close();
+ }
+ }
+
+ m_obj = derived;
+ rhs.m_obj = nullptr;
+ }
+ }
+
+ constexpr KScopedAutoObject<T>& operator=(KScopedAutoObject<T>&& rhs) {
+ rhs.Swap(*this);
+ return *this;
+ }
+
+ constexpr T* operator->() {
+ return m_obj;
+ }
+ constexpr T& operator*() {
+ return *m_obj;
+ }
+
+ constexpr void Reset(T* o) {
+ KScopedAutoObject(o).Swap(*this);
+ }
+
+ constexpr T* GetPointerUnsafe() {
+ return m_obj;
+ }
+
+ constexpr T* GetPointerUnsafe() const {
+ return m_obj;
+ }
+
+ constexpr T* ReleasePointerUnsafe() {
+ T* ret = m_obj;
+ m_obj = nullptr;
+ return ret;
+ }
+
+ constexpr bool IsNull() const {
+ return m_obj == nullptr;
+ }
+ constexpr bool IsNotNull() const {
+ return m_obj != nullptr;
+ }
+
+private:
+ template <typename U>
+ friend class KScopedAutoObject;
+
+private:
+ T* m_obj{};
+
+private:
+ constexpr void Swap(KScopedAutoObject& rhs) noexcept {
+ std::swap(m_obj, rhs.m_obj);
+ }
+};
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_auto_object_container.h"
+
+namespace Kernel {
+
+void KAutoObjectWithListContainer::Register(KAutoObjectWithList* obj) {
+ KScopedLightLock lk(m_lock);
+
+ m_object_list.insert(*obj);
+}
+
+void KAutoObjectWithListContainer::Unregister(KAutoObjectWithList* obj) {
+ KScopedLightLock lk(m_lock);
+
+ m_object_list.erase(m_object_list.iterator_to(*obj));
+}
+
+size_t KAutoObjectWithListContainer::GetOwnedCount(KProcess* owner) {
+ KScopedLightLock lk(m_lock);
+
+ return std::count_if(m_object_list.begin(), m_object_list.end(),
+ [&](const auto& obj) { return obj.GetOwner() == owner; });
+}
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/intrusive_red_black_tree.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_light_lock.h"
+
+namespace Kernel {
+
+class KernelCore;
+class KProcess;
+
+class KAutoObjectWithListContainer {
+ YUZU_NON_COPYABLE(KAutoObjectWithListContainer);
+ YUZU_NON_MOVEABLE(KAutoObjectWithListContainer);
+
+public:
+ using ListType = Common::IntrusiveRedBlackTreeMemberTraits<
+ &KAutoObjectWithList::list_node>::TreeType<KAutoObjectWithList>;
+
+public:
+ class ListAccessor : public KScopedLightLock {
+ public:
+ explicit ListAccessor(KAutoObjectWithListContainer* container)
+ : KScopedLightLock(container->m_lock), m_list(container->m_object_list) {}
+ explicit ListAccessor(KAutoObjectWithListContainer& container)
+ : KScopedLightLock(container.m_lock), m_list(container.m_object_list) {}
+
+ typename ListType::iterator begin() const {
+ return m_list.begin();
+ }
+
+ typename ListType::iterator end() const {
+ return m_list.end();
+ }
+
+ typename ListType::iterator find(typename ListType::const_reference ref) const {
+ return m_list.find(ref);
+ }
+
+ private:
+ ListType& m_list;
+ };
+
+ friend class ListAccessor;
+
+public:
+ KAutoObjectWithListContainer(KernelCore& kernel) : m_lock(kernel), m_object_list() {}
+
+ void Initialize() {}
+ void Finalize() {}
+
+ void Register(KAutoObjectWithList* obj);
+ void Unregister(KAutoObjectWithList* obj);
+ size_t GetOwnedCount(KProcess* owner);
+
+private:
+ KLightLock m_lock;
+ ListType m_object_list;
+};
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_class_token.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_readable_event.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/k_server_port.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_session.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/kernel/k_writable_event.h"
+
+namespace Kernel {
+
+// Ensure that we generate correct class tokens for all types.
+
+// Ensure that the absolute token values are correct.
+static_assert(ClassToken<KAutoObject> == 0b00000000'00000000);
+static_assert(ClassToken<KSynchronizationObject> == 0b00000000'00000001);
+static_assert(ClassToken<KReadableEvent> == 0b00000000'00000011);
+// static_assert(ClassToken<KInterruptEvent> == 0b00000111'00000011);
+// static_assert(ClassToken<KDebug> == 0b00001011'00000001);
+static_assert(ClassToken<KThread> == 0b00010011'00000001);
+static_assert(ClassToken<KServerPort> == 0b00100011'00000001);
+static_assert(ClassToken<KServerSession> == 0b01000011'00000001);
+static_assert(ClassToken<KClientPort> == 0b10000011'00000001);
+static_assert(ClassToken<KClientSession> == 0b00001101'00000000);
+static_assert(ClassToken<KProcess> == 0b00010101'00000001);
+static_assert(ClassToken<KResourceLimit> == 0b00100101'00000000);
+// static_assert(ClassToken<KLightSession> == 0b01000101'00000000);
+static_assert(ClassToken<KPort> == 0b10000101'00000000);
+static_assert(ClassToken<KSession> == 0b00011001'00000000);
+static_assert(ClassToken<KSharedMemory> == 0b00101001'00000000);
+static_assert(ClassToken<KEvent> == 0b01001001'00000000);
+static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000);
+// static_assert(ClassToken<KLightClientSession> == 0b00110001'00000000);
+// static_assert(ClassToken<KLightServerSession> == 0b01010001'00000000);
+static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000);
+// static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000);
+// static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000);
+// static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000);
+
+// Ensure that the token hierarchy is correct.
+
+// Base classes
+static_assert(ClassToken<KAutoObject> == (0b00000000));
+static_assert(ClassToken<KSynchronizationObject> == (0b00000001 | ClassToken<KAutoObject>));
+static_assert(ClassToken<KReadableEvent> == (0b00000010 | ClassToken<KSynchronizationObject>));
+
+// Final classes
+// static_assert(ClassToken<KInterruptEvent> == ((0b00000111 << 8) | ClassToken<KReadableEvent>));
+// static_assert(ClassToken<KDebug> == ((0b00001011 << 8) | ClassToken<KSynchronizationObject>));
+static_assert(ClassToken<KThread> == ((0b00010011 << 8) | ClassToken<KSynchronizationObject>));
+static_assert(ClassToken<KServerPort> == ((0b00100011 << 8) | ClassToken<KSynchronizationObject>));
+static_assert(ClassToken<KServerSession> ==
+ ((0b01000011 << 8) | ClassToken<KSynchronizationObject>));
+static_assert(ClassToken<KClientPort> == ((0b10000011 << 8) | ClassToken<KSynchronizationObject>));
+static_assert(ClassToken<KClientSession> == ((0b00001101 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KProcess> == ((0b00010101 << 8) | ClassToken<KSynchronizationObject>));
+static_assert(ClassToken<KResourceLimit> == ((0b00100101 << 8) | ClassToken<KAutoObject>));
+// static_assert(ClassToken<KLightSession> == ((0b01000101 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KPort> == ((0b10000101 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KSession> == ((0b00011001 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KSharedMemory> == ((0b00101001 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KEvent> == ((0b01001001 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAutoObject>));
+// static_assert(ClassToken<KLightClientSession> == ((0b00110001 << 8) | ClassToken<KAutoObject>));
+// static_assert(ClassToken<KLightServerSession> == ((0b01010001 << 8) | ClassToken<KAutoObject>));
+static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>));
+// static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>));
+// static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>));
+// static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>));
+
+// Ensure that the token hierarchy reflects the class hierarchy.
+
+// Base classes.
+static_assert(!std::is_final<KSynchronizationObject>::value &&
+ std::is_base_of<KAutoObject, KSynchronizationObject>::value);
+static_assert(!std::is_final<KReadableEvent>::value &&
+ std::is_base_of<KSynchronizationObject, KReadableEvent>::value);
+
+// Final classes
+// static_assert(std::is_final<KInterruptEvent>::value &&
+// std::is_base_of<KReadableEvent, KInterruptEvent>::value);
+// static_assert(std::is_final<KDebug>::value &&
+// std::is_base_of<KSynchronizationObject, KDebug>::value);
+static_assert(std::is_final<KThread>::value &&
+ std::is_base_of<KSynchronizationObject, KThread>::value);
+static_assert(std::is_final<KServerPort>::value &&
+ std::is_base_of<KSynchronizationObject, KServerPort>::value);
+static_assert(std::is_final<KServerSession>::value &&
+ std::is_base_of<KSynchronizationObject, KServerSession>::value);
+static_assert(std::is_final<KClientPort>::value &&
+ std::is_base_of<KSynchronizationObject, KClientPort>::value);
+static_assert(std::is_final<KClientSession>::value &&
+ std::is_base_of<KAutoObject, KClientSession>::value);
+static_assert(std::is_final<KProcess>::value &&
+ std::is_base_of<KSynchronizationObject, KProcess>::value);
+static_assert(std::is_final<KResourceLimit>::value &&
+ std::is_base_of<KAutoObject, KResourceLimit>::value);
+// static_assert(std::is_final<KLightSession>::value &&
+// std::is_base_of<KAutoObject, KLightSession>::value);
+static_assert(std::is_final<KPort>::value && std::is_base_of<KAutoObject, KPort>::value);
+static_assert(std::is_final<KSession>::value && std::is_base_of<KAutoObject, KSession>::value);
+static_assert(std::is_final<KSharedMemory>::value &&
+ std::is_base_of<KAutoObject, KSharedMemory>::value);
+static_assert(std::is_final<KEvent>::value && std::is_base_of<KAutoObject, KEvent>::value);
+static_assert(std::is_final<KWritableEvent>::value &&
+ std::is_base_of<KAutoObject, KWritableEvent>::value);
+// static_assert(std::is_final<KLightClientSession>::value &&
+// std::is_base_of<KAutoObject, KLightClientSession>::value);
+// static_assert(std::is_final<KLightServerSession>::value &&
+// std::is_base_of<KAutoObject, KLightServerSession>::value);
+static_assert(std::is_final<KTransferMemory>::value &&
+ std::is_base_of<KAutoObject, KTransferMemory>::value);
+// static_assert(std::is_final<KDeviceAddressSpace>::value &&
+// std::is_base_of<KAutoObject, KDeviceAddressSpace>::value);
+// static_assert(std::is_final<KSessionRequest>::value &&
+// std::is_base_of<KAutoObject, KSessionRequest>::value);
+// static_assert(std::is_final<KCodeMemory>::value &&
+// std::is_base_of<KAutoObject, KCodeMemory>::value);
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+
+#include "common/assert.h"
+#include "common/bit_util.h"
+#include "common/common_types.h"
+
+namespace Kernel {
+
+class KAutoObject;
+
+class KClassTokenGenerator {
+public:
+ using TokenBaseType = u16;
+
+public:
+ static constexpr size_t BaseClassBits = 8;
+ static constexpr size_t FinalClassBits = (sizeof(TokenBaseType) * CHAR_BIT) - BaseClassBits;
+ // One bit per base class.
+ static constexpr size_t NumBaseClasses = BaseClassBits;
+ // Final classes are permutations of three bits.
+ static constexpr size_t NumFinalClasses = [] {
+ TokenBaseType index = 0;
+ for (size_t i = 0; i < FinalClassBits; i++) {
+ for (size_t j = i + 1; j < FinalClassBits; j++) {
+ for (size_t k = j + 1; k < FinalClassBits; k++) {
+ index++;
+ }
+ }
+ }
+ return index;
+ }();
+
+private:
+ template <TokenBaseType Index>
+ static constexpr inline TokenBaseType BaseClassToken = 1U << Index;
+
+ template <TokenBaseType Index>
+ static constexpr inline TokenBaseType FinalClassToken = [] {
+ TokenBaseType index = 0;
+ for (size_t i = 0; i < FinalClassBits; i++) {
+ for (size_t j = i + 1; j < FinalClassBits; j++) {
+ for (size_t k = j + 1; k < FinalClassBits; k++) {
+ if ((index++) == Index) {
+ return static_cast<TokenBaseType>(((1ULL << i) | (1ULL << j) | (1ULL << k))
+ << BaseClassBits);
+ }
+ }
+ }
+ }
+ }();
+
+ template <typename T>
+ static constexpr inline TokenBaseType GetClassToken() {
+ static_assert(std::is_base_of<KAutoObject, T>::value);
+ if constexpr (std::is_same<T, KAutoObject>::value) {
+ static_assert(T::ObjectType == ObjectType::KAutoObject);
+ return 0;
+ } else if constexpr (!std::is_final<T>::value) {
+ static_assert(ObjectType::BaseClassesStart <= T::ObjectType &&
+ T::ObjectType < ObjectType::BaseClassesEnd);
+ constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
+ static_cast<TokenBaseType>(ObjectType::BaseClassesStart);
+ return BaseClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
+ } else if constexpr (ObjectType::FinalClassesStart <= T::ObjectType &&
+ T::ObjectType < ObjectType::FinalClassesEnd) {
+ constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
+ static_cast<TokenBaseType>(ObjectType::FinalClassesStart);
+ return FinalClassToken<ClassIndex> | GetClassToken<typename T::BaseClass>();
+ } else {
+ static_assert(!std::is_same<T, T>::value, "GetClassToken: Invalid Type");
+ }
+ };
+
+public:
+ enum class ObjectType {
+ KAutoObject,
+
+ BaseClassesStart,
+
+ KSynchronizationObject = BaseClassesStart,
+ KReadableEvent,
+
+ BaseClassesEnd,
+
+ FinalClassesStart = BaseClassesEnd,
+
+ KInterruptEvent = FinalClassesStart,
+ KDebug,
+ KThread,
+ KServerPort,
+ KServerSession,
+ KClientPort,
+ KClientSession,
+ KProcess,
+ KResourceLimit,
+ KLightSession,
+ KPort,
+ KSession,
+ KSharedMemory,
+ KEvent,
+ KWritableEvent,
+ KLightClientSession,
+ KLightServerSession,
+ KTransferMemory,
+ KDeviceAddressSpace,
+ KSessionRequest,
+ KCodeMemory,
+
+ // NOTE: True order for these has not been determined yet.
+ KAlpha,
+ KBeta,
+
+ FinalClassesEnd = FinalClassesStart + NumFinalClasses,
+ };
+
+ template <typename T>
+ static constexpr inline TokenBaseType ClassToken = GetClassToken<T>();
+};
+
+using ClassTokenType = KClassTokenGenerator::TokenBaseType;
+
+template <typename T>
+static constexpr inline ClassTokenType ClassToken = KClassTokenGenerator::ClassToken<T>;
+
+} // 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 @@
+// Copyright 2021 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/scope_exit.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_session.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+KClientPort::~KClientPort() = default;
+
+void KClientPort::Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_) {
+ // Set member variables.
+ num_sessions = 0;
+ peak_sessions = 0;
+ parent = parent_;
+ max_sessions = max_sessions_;
+ name = std::move(name_);
+}
+
+void KClientPort::OnSessionFinalized() {
+ KScopedSchedulerLock sl{kernel};
+
+ const auto prev = num_sessions--;
+ if (prev == max_sessions) {
+ this->NotifyAvailable();
+ }
+}
+
+void KClientPort::OnServerClosed() {}
+
+bool KClientPort::IsLight() const {
+ return this->GetParent()->IsLight();
+}
+
+bool KClientPort::IsServerClosed() const {
+ return this->GetParent()->IsServerClosed();
+}
+
+void KClientPort::Destroy() {
+ // Note with our parent that we're closed.
+ parent->OnClientClosed();
+
+ // Close our reference to our parent.
+ parent->Close();
+}
+
+bool KClientPort::IsSignaled() const {
+ return num_sessions < max_sessions;
+}
+
+ResultCode KClientPort::CreateSession(KClientSession** out) {
+ // Reserve a new session from the resource limit.
+ // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
+ // LimitableResource::Sessions);
+ // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
+
+ // Update the session counts.
+ {
+ // Atomically increment the number of sessions.
+ s32 new_sessions;
+ {
+ const auto max = max_sessions;
+ auto cur_sessions = num_sessions.load(std::memory_order_acquire);
+ do {
+ R_UNLESS(cur_sessions < max, ResultOutOfSessions);
+ new_sessions = cur_sessions + 1;
+ } while (!num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
+ std::memory_order_relaxed));
+ }
+
+ // Atomically update the peak session tracking.
+ {
+ auto peak = peak_sessions.load(std::memory_order_acquire);
+ do {
+ if (peak >= new_sessions) {
+ break;
+ }
+ } while (!peak_sessions.compare_exchange_weak(peak, new_sessions,
+ std::memory_order_relaxed));
+ }
+ }
+
+ // Create a new session.
+ KSession* session = KSession::Create(kernel);
+ if (session == nullptr) {
+ // Decrement the session count.
+ const auto prev = num_sessions--;
+ if (prev == max_sessions) {
+ this->NotifyAvailable();
+ }
+
+ return ResultOutOfResource;
+ }
+
+ // Initialize the session.
+ session->Initialize(this, parent->GetName());
+
+ // Commit the session reservation.
+ // session_reservation.Commit();
+
+ // Register the session.
+ KSession::Register(kernel, session);
+ auto session_guard = SCOPE_GUARD({
+ session->GetClientSession().Close();
+ session->GetServerSession().Close();
+ });
+
+ // Enqueue the session with our parent.
+ R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession())));
+
+ // We succeeded, so set the output.
+ session_guard.Cancel();
+ *out = std::addressof(session->GetClientSession());
+ return RESULT_SUCCESS;
+}
+
+} // 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 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KClientSession;
+class KernelCore;
+class KPort;
+
+class KClientPort final : public KSynchronizationObject {
+ KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
+
+public:
+ explicit KClientPort(KernelCore& kernel_);
+ virtual ~KClientPort() override;
+
+ void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
+ void OnSessionFinalized();
+ void OnServerClosed();
+
+ const KPort* GetParent() const {
+ return parent;
+ }
+
+ s32 GetNumSessions() const {
+ return num_sessions;
+ }
+ s32 GetPeakSessions() const {
+ return peak_sessions;
+ }
+ s32 GetMaxSessions() const {
+ return max_sessions;
+ }
+
+ bool IsLight() const;
+ bool IsServerClosed() const;
+
+ // Overridden virtual functions.
+ virtual void Destroy() override;
+ virtual bool IsSignaled() const override;
+
+ ResultCode CreateSession(KClientSession** out);
+
+private:
+ std::atomic<s32> num_sessions{};
+ std::atomic<s32> peak_sessions{};
+ s32 max_sessions{};
+ KPort* parent{};
+};
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_session.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+KClientSession::KClientSession(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+KClientSession::~KClientSession() = default;
+
+void KClientSession::Destroy() {
+ parent->OnClientClosed();
+ parent->Close();
+}
+
+void KClientSession::OnServerClosed() {}
+
+ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing) {
+ // Signal the server session that new data is available
+ return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing);
+}
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/result.h"
+
+union ResultCode;
+
+namespace Core::Memory {
+class Memory;
+}
+
+namespace Core::Timing {
+class CoreTiming;
+}
+
+namespace Kernel {
+
+class KernelCore;
+class KSession;
+class KThread;
+
+class KClientSession final
+ : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
+
+public:
+ explicit KClientSession(KernelCore& kernel_);
+ virtual ~KClientSession();
+
+ void Initialize(KSession* parent_, std::string&& name_) {
+ // Set member variables.
+ parent = parent_;
+ name = std::move(name_);
+ }
+
+ virtual void Destroy() override;
+ static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+
+ KSession* GetParent() const {
+ return parent;
+ }
+
+ ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing);
+
+ void OnServerClosed();
+
+private:
+ KSession* parent{};
+};
+
+} // 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 @@
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_linked_list.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_common.h"
#include "core/hle/kernel/svc_results.h"
#include "core/memory.h"
@@ -107,8 +108,8 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
// Wait for the address.
{
- std::shared_ptr<KThread> owner_thread;
- ASSERT(!owner_thread);
+ KScopedAutoObject<KThread> owner_thread;
+ ASSERT(owner_thread.IsNull());
{
KScopedSchedulerLock sl(kernel);
cur_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
@@ -126,8 +127,10 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
// Get the lock owner thread.
- owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle);
- R_UNLESS(owner_thread, ResultInvalidHandle);
+ owner_thread =
+ kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>(
+ handle);
+ R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle);
// Update the lock.
cur_thread->SetAddressKey(addr, value);
@@ -137,7 +140,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
cur_thread->SetMutexWaitAddressForDebugging(addr);
}
}
- ASSERT(owner_thread);
+ ASSERT(owner_thread.IsNotNull());
}
// Remove the thread as a waiter from the lock owner.
@@ -176,19 +179,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) {
KThread* thread_to_close = nullptr;
if (can_access) {
- if (prev_tag == InvalidHandle) {
+ if (prev_tag == Svc::InvalidHandle) {
// If nobody held the lock previously, we're all good.
thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
thread->Wakeup();
} else {
// Get the previous owner.
- auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(
- prev_tag & ~Svc::HandleWaitMask);
+ KThread* owner_thread = kernel.CurrentProcess()
+ ->GetHandleTable()
+ .GetObjectWithoutPseudoHandle<KThread>(
+ static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
+ .ReleasePointerUnsafe();
if (owner_thread) {
// Add the thread as a waiter on the owner.
owner_thread->AddWaiter(thread);
- thread_to_close = owner_thread.get();
+ thread_to_close = owner_thread;
} else {
// The lock was tagged with a thread that doesn't exist.
thread->SetSyncedObject(nullptr, ResultInvalidState);
@@ -208,9 +214,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
// Prepare for signaling.
constexpr int MaxThreads = 16;
- // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using
- // std::shared_ptr.
- std::vector<std::shared_ptr<KThread>> thread_list;
+ KLinkedList<KThread> thread_list{kernel};
std::array<KThread*, MaxThreads> thread_array;
s32 num_to_close{};
@@ -228,7 +232,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
if (num_to_close < MaxThreads) {
thread_array[num_to_close++] = thread;
} else {
- thread_list.push_back(SharedFrom(thread));
+ thread_list.push_back(*thread);
}
}
@@ -251,7 +255,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
// Close threads in the list.
for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) {
- (*it)->Close();
+ (*it).Close();
}
}
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 @@
// Refer to the license.txt file included.
#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_readable_event.h"
-#include "core/hle/kernel/k_writable_event.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_resource_limit.h"
namespace Kernel {
-KEvent::KEvent(KernelCore& kernel, std::string&& name) : Object{kernel, std::move(name)} {}
+KEvent::KEvent(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_}, readable_event{kernel_}, writable_event{
+ kernel_} {}
KEvent::~KEvent() = default;
-std::shared_ptr<KEvent> KEvent::Create(KernelCore& kernel, std::string&& name) {
- return std::make_shared<KEvent>(kernel, std::move(name));
-}
+void KEvent::Initialize(std::string&& name_) {
+ // Increment reference count.
+ // Because reference count is one on creation, this will result
+ // in a reference count of two. Thus, when both readable and
+ // writable events are closed this object will be destroyed.
+ Open();
-void KEvent::Initialize() {
// Create our sub events.
- readable_event = std::make_shared<KReadableEvent>(kernel, GetName() + ":Readable");
- writable_event = std::make_shared<KWritableEvent>(kernel, GetName() + ":Writable");
+ KAutoObject::Create(std::addressof(readable_event));
+ KAutoObject::Create(std::addressof(writable_event));
// Initialize our sub sessions.
- readable_event->Initialize(this);
- writable_event->Initialize(this);
+ readable_event.Initialize(this, name_ + ":Readable");
+ writable_event.Initialize(this, name_ + ":Writable");
+
+ // Set our owner process.
+ owner = kernel.CurrentProcess();
+ if (owner) {
+ owner->Open();
+ }
// Mark initialized.
+ name = std::move(name_);
initialized = true;
}
+void KEvent::Finalize() {
+ KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList>::Finalize();
+}
+
+void KEvent::PostDestroy(uintptr_t arg) {
+ // Release the event count resource the owner process holds.
+ KProcess* owner = reinterpret_cast<KProcess*>(arg);
+ if (owner) {
+ owner->GetResourceLimit()->Release(LimitableResource::Events, 1);
+ owner->Close();
+ }
+}
+
} // 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 @@
#pragma once
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_readable_event.h"
+#include "core/hle/kernel/k_writable_event.h"
+#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
class KernelCore;
class KReadableEvent;
class KWritableEvent;
+class KProcess;
-class KEvent final : public Object {
-public:
- explicit KEvent(KernelCore& kernel, std::string&& name);
- ~KEvent() override;
+class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject);
- static std::shared_ptr<KEvent> Create(KernelCore& kernel, std::string&& name);
+public:
+ explicit KEvent(KernelCore& kernel_);
+ virtual ~KEvent();
- void Initialize();
+ void Initialize(std::string&& name);
- void Finalize() override {}
+ virtual void Finalize() override;
- std::string GetTypeName() const override {
- return "KEvent";
+ virtual bool IsInitialized() const override {
+ return initialized;
}
- static constexpr HandleType HANDLE_TYPE = HandleType::Event;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
+ virtual uintptr_t GetPostDestroyArgument() const override {
+ return reinterpret_cast<uintptr_t>(owner);
}
- std::shared_ptr<KReadableEvent>& GetReadableEvent() {
- return readable_event;
- }
+ static void PostDestroy(uintptr_t arg);
- std::shared_ptr<KWritableEvent>& GetWritableEvent() {
- return writable_event;
+ virtual KProcess* GetOwner() const override {
+ return owner;
}
- const std::shared_ptr<KReadableEvent>& GetReadableEvent() const {
+ KReadableEvent& GetReadableEvent() {
return readable_event;
}
- const std::shared_ptr<KWritableEvent>& GetWritableEvent() const {
+ KWritableEvent& GetWritableEvent() {
return writable_event;
}
private:
- std::shared_ptr<KReadableEvent> readable_event;
- std::shared_ptr<KWritableEvent> writable_event;
+ KReadableEvent readable_event;
+ KWritableEvent writable_event;
+ KProcess* owner{};
bool initialized{};
};
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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_handle_table.h"
+
+namespace Kernel {
+
+KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
+KHandleTable ::~KHandleTable() = default;
+
+ResultCode KHandleTable::Finalize() {
+ // Get the table and clear our record of it.
+ u16 saved_table_size = 0;
+ {
+ KScopedSpinLock lk(m_lock);
+
+ std::swap(m_table_size, saved_table_size);
+ }
+
+ // Close and free all entries.
+ for (size_t i = 0; i < saved_table_size; i++) {
+ if (KAutoObject* obj = m_objects[i]; obj != nullptr) {
+ obj->Close();
+ }
+ }
+
+ return RESULT_SUCCESS;
+}
+
+bool KHandleTable::Remove(Handle handle) {
+ // Don't allow removal of a pseudo-handle.
+ if (Svc::IsPseudoHandle(handle)) {
+ return false;
+ }
+
+ // Handles must not have reserved bits set.
+ const auto handle_pack = HandlePack(handle);
+ if (handle_pack.reserved != 0) {
+ return false;
+ }
+
+ // Find the object and free the entry.
+ KAutoObject* obj = nullptr;
+ {
+ KScopedSpinLock lk(m_lock);
+
+ if (this->IsValidHandle(handle)) {
+ const auto index = handle_pack.index;
+
+ obj = m_objects[index];
+ this->FreeEntry(index);
+ } else {
+ return false;
+ }
+ }
+
+ // Close the object.
+ obj->Close();
+ return true;
+}
+
+ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
+ KScopedSpinLock lk(m_lock);
+
+ // Never exceed our capacity.
+ R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
+
+ // Allocate entry, set output handle.
+ {
+ const auto linear_id = this->AllocateLinearId();
+ const auto index = this->AllocateEntry();
+
+ m_entry_infos[index].info = {.linear_id = linear_id, .type = type};
+ m_objects[index] = obj;
+
+ obj->Open();
+
+ *out_handle = EncodeHandle(static_cast<u16>(index), linear_id);
+ }
+
+ return RESULT_SUCCESS;
+}
+
+ResultCode KHandleTable::Reserve(Handle* out_handle) {
+ KScopedSpinLock lk(m_lock);
+
+ // Never exceed our capacity.
+ R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
+
+ *out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId());
+ return RESULT_SUCCESS;
+}
+
+void KHandleTable::Unreserve(Handle handle) {
+ KScopedSpinLock lk(m_lock);
+
+ // Unpack the handle.
+ const auto handle_pack = HandlePack(handle);
+ const auto index = handle_pack.index;
+ const auto linear_id = handle_pack.linear_id;
+ const auto reserved = handle_pack.reserved;
+ ASSERT(reserved == 0);
+ ASSERT(linear_id != 0);
+
+ if (index < m_table_size) {
+ // NOTE: This code does not check the linear id.
+ ASSERT(m_objects[index] == nullptr);
+ this->FreeEntry(index);
+ }
+}
+
+void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) {
+ KScopedSpinLock lk(m_lock);
+
+ // Unpack the handle.
+ const auto handle_pack = HandlePack(handle);
+ const auto index = handle_pack.index;
+ const auto linear_id = handle_pack.linear_id;
+ const auto reserved = handle_pack.reserved;
+ ASSERT(reserved == 0);
+ ASSERT(linear_id != 0);
+
+ if (index < m_table_size) {
+ // Set the entry.
+ ASSERT(m_objects[index] == nullptr);
+
+ m_entry_infos[index].info = {.linear_id = static_cast<u16>(linear_id), .type = type};
+ m_objects[index] = obj;
+
+ obj->Open();
+ }
+}
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/bit_util.h"
+#include "common/common_types.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_spin_lock.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_common.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KernelCore;
+
+class KHandleTable {
+ YUZU_NON_COPYABLE(KHandleTable);
+ YUZU_NON_MOVEABLE(KHandleTable);
+
+public:
+ static constexpr size_t MaxTableSize = 1024;
+
+public:
+ explicit KHandleTable(KernelCore& kernel_);
+ ~KHandleTable();
+
+ ResultCode Initialize(s32 size) {
+ R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
+
+ // Initialize all fields.
+ m_max_count = 0;
+ m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size);
+ m_next_linear_id = MinLinearId;
+ m_count = 0;
+ m_free_head_index = -1;
+
+ // Free all entries.
+ for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
+ m_objects[i] = nullptr;
+ m_entry_infos[i].next_free_index = i - 1;
+ m_free_head_index = i;
+ }
+
+ return RESULT_SUCCESS;
+ }
+
+ size_t GetTableSize() const {
+ return m_table_size;
+ }
+ size_t GetCount() const {
+ return m_count;
+ }
+ size_t GetMaxCount() const {
+ return m_max_count;
+ }
+
+ ResultCode Finalize();
+ bool Remove(Handle handle);
+
+ template <typename T = KAutoObject>
+ KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
+ // Lock and look up in table.
+ KScopedSpinLock lk(m_lock);
+
+ if constexpr (std::is_same_v<T, KAutoObject>) {
+ return this->GetObjectImpl(handle);
+ } else {
+ if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) {
+ return obj->DynamicCast<T*>();
+ } else {
+ return nullptr;
+ }
+ }
+ }
+
+ template <typename T = KAutoObject>
+ KScopedAutoObject<T> GetObject(Handle handle) const {
+ // Handle pseudo-handles.
+ if constexpr (std::derived_from<KProcess, T>) {
+ if (handle == Svc::PseudoHandle::CurrentProcess) {
+ auto* const cur_process = kernel.CurrentProcess();
+ ASSERT(cur_process != nullptr);
+ return cur_process;
+ }
+ } else if constexpr (std::derived_from<KThread, T>) {
+ if (handle == Svc::PseudoHandle::CurrentThread) {
+ auto* const cur_thread = GetCurrentThreadPointer(kernel);
+ ASSERT(cur_thread != nullptr);
+ return cur_thread;
+ }
+ }
+
+ return this->template GetObjectWithoutPseudoHandle<T>(handle);
+ }
+
+ ResultCode Reserve(Handle* out_handle);
+ void Unreserve(Handle handle);
+
+ template <typename T>
+ ResultCode Add(Handle* out_handle, T* obj) {
+ static_assert(std::is_base_of_v<KAutoObject, T>);
+ return this->Add(out_handle, obj, obj->GetTypeObj().GetClassToken());
+ }
+
+ template <typename T>
+ void Register(Handle handle, T* obj) {
+ static_assert(std::is_base_of_v<KAutoObject, T>);
+ return this->Register(handle, obj, obj->GetTypeObj().GetClassToken());
+ }
+
+ template <typename T>
+ bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
+ // Try to convert and open all the handles.
+ size_t num_opened;
+ {
+ // Lock the table.
+ KScopedSpinLock lk(m_lock);
+ for (num_opened = 0; num_opened < num_handles; num_opened++) {
+ // Get the current handle.
+ const auto cur_handle = handles[num_opened];
+
+ // Get the object for the current handle.
+ KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
+ if (cur_object == nullptr) {
+ break;
+ }
+
+ // Cast the current object to the desired type.
+ T* cur_t = cur_object->DynamicCast<T*>();
+ if (cur_t == nullptr) {
+ break;
+ }
+
+ // Open a reference to the current object.
+ cur_t->Open();
+ out[num_opened] = cur_t;
+ }
+ }
+
+ // If we converted every object, succeed.
+ if (num_opened == num_handles) {
+ return true;
+ }
+
+ // If we didn't convert entry object, close the ones we opened.
+ for (size_t i = 0; i < num_opened; i++) {
+ out[i]->Close();
+ }
+
+ return false;
+ }
+
+private:
+ ResultCode Add(Handle* out_handle, KAutoObject* obj, u16 type);
+ void Register(Handle handle, KAutoObject* obj, u16 type);
+
+ s32 AllocateEntry() {
+ ASSERT(m_count < m_table_size);
+
+ const auto index = m_free_head_index;
+
+ m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
+
+ m_max_count = std::max(m_max_count, ++m_count);
+
+ return index;
+ }
+
+ void FreeEntry(s32 index) {
+ ASSERT(m_count > 0);
+
+ m_objects[index] = nullptr;
+ m_entry_infos[index].next_free_index = m_free_head_index;
+
+ m_free_head_index = index;
+
+ --m_count;
+ }
+
+ u16 AllocateLinearId() {
+ const u16 id = m_next_linear_id++;
+ if (m_next_linear_id > MaxLinearId) {
+ m_next_linear_id = MinLinearId;
+ }
+ return id;
+ }
+
+ bool IsValidHandle(Handle handle) const {
+ // Unpack the handle.
+ const auto handle_pack = HandlePack(handle);
+ const auto raw_value = handle_pack.raw;
+ const auto index = handle_pack.index;
+ const auto linear_id = handle_pack.linear_id;
+ const auto reserved = handle_pack.reserved;
+ ASSERT(reserved == 0);
+
+ // Validate our indexing information.
+ if (raw_value == 0) {
+ return false;
+ }
+ if (linear_id == 0) {
+ return false;
+ }
+ if (index >= m_table_size) {
+ return false;
+ }
+
+ // Check that there's an object, and our serial id is correct.
+ if (m_objects[index] == nullptr) {
+ return false;
+ }
+ if (m_entry_infos[index].GetLinearId() != linear_id) {
+ return false;
+ }
+
+ return true;
+ }
+
+ KAutoObject* GetObjectImpl(Handle handle) const {
+ // Handles must not have reserved bits set.
+ const auto handle_pack = HandlePack(handle);
+ if (handle_pack.reserved != 0) {
+ return nullptr;
+ }
+
+ if (this->IsValidHandle(handle)) {
+ return m_objects[handle_pack.index];
+ } else {
+ return nullptr;
+ }
+ }
+
+ KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
+
+ // Index must be in bounds.
+ if (index >= m_table_size) {
+ return nullptr;
+ }
+
+ // Ensure entry has an object.
+ if (KAutoObject* obj = m_objects[index]; obj != nullptr) {
+ *out_handle = EncodeHandle(static_cast<u16>(index), m_entry_infos[index].GetLinearId());
+ return obj;
+ } else {
+ return nullptr;
+ }
+ }
+
+private:
+ union HandlePack {
+ HandlePack() = default;
+ HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
+
+ u32 raw;
+ BitField<0, 15, u32> index;
+ BitField<15, 15, u32> linear_id;
+ BitField<30, 2, u32> reserved;
+ };
+
+ static constexpr u16 MinLinearId = 1;
+ static constexpr u16 MaxLinearId = 0x7FFF;
+
+ static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
+ HandlePack handle{};
+ handle.index.Assign(index);
+ handle.linear_id.Assign(linear_id);
+ handle.reserved.Assign(0);
+ return handle.raw;
+ }
+
+ union EntryInfo {
+ struct {
+ u16 linear_id;
+ u16 type;
+ } info;
+ s32 next_free_index;
+
+ constexpr u16 GetLinearId() const {
+ return info.linear_id;
+ }
+ constexpr u16 GetType() const {
+ return info.type;
+ }
+ constexpr s32 GetNextFreeIndex() const {
+ return next_free_index;
+ }
+ };
+
+private:
+ std::array<EntryInfo, MaxTableSize> m_entry_infos{};
+ std::array<KAutoObject*, MaxTableSize> m_objects{};
+ s32 m_free_head_index{-1};
+ u16 m_table_size{};
+ u16 m_max_count{};
+ u16 m_next_linear_id{MinLinearId};
+ u16 m_count{};
+ mutable KSpinLock m_lock;
+ KernelCore& kernel;
+};
+
+} // 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;
class KLightConditionVariable {
public:
- explicit KLightConditionVariable(KernelCore& kernel) : thread_queue(kernel), kernel(kernel) {}
+ explicit KLightConditionVariable(KernelCore& kernel_)
+ : thread_queue(kernel_), kernel(kernel_) {}
void Wait(KLightLock* lock, s64 timeout = -1) {
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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <boost/intrusive/list.hpp>
+
+#include "common/assert.h"
+#include "core/hle/kernel/slab_helpers.h"
+
+namespace Kernel {
+
+class KernelCore;
+
+class KLinkedListNode : public boost::intrusive::list_base_hook<>,
+ public KSlabAllocated<KLinkedListNode> {
+
+public:
+ KLinkedListNode() = default;
+
+ void Initialize(void* it) {
+ m_item = it;
+ }
+
+ void* GetItem() const {
+ return m_item;
+ }
+
+private:
+ void* m_item = nullptr;
+};
+
+template <typename T>
+class KLinkedList : private boost::intrusive::list<KLinkedListNode> {
+private:
+ using BaseList = boost::intrusive::list<KLinkedListNode>;
+
+public:
+ template <bool Const>
+ class Iterator;
+
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using iterator = Iterator<false>;
+ using const_iterator = Iterator<true>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ template <bool Const>
+ class Iterator {
+ private:
+ using BaseIterator = BaseList::iterator;
+ friend class KLinkedList;
+
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = typename KLinkedList::value_type;
+ using difference_type = typename KLinkedList::difference_type;
+ using pointer = std::conditional_t<Const, KLinkedList::const_pointer, KLinkedList::pointer>;
+ using reference =
+ std::conditional_t<Const, KLinkedList::const_reference, KLinkedList::reference>;
+
+ public:
+ explicit Iterator(BaseIterator it) : m_base_it(it) {}
+
+ pointer GetItem() const {
+ return static_cast<pointer>(m_base_it->GetItem());
+ }
+
+ bool operator==(const Iterator& rhs) const {
+ return m_base_it == rhs.m_base_it;
+ }
+
+ bool operator!=(const Iterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ pointer operator->() const {
+ return this->GetItem();
+ }
+
+ reference operator*() const {
+ return *this->GetItem();
+ }
+
+ Iterator& operator++() {
+ ++m_base_it;
+ return *this;
+ }
+
+ Iterator& operator--() {
+ --m_base_it;
+ return *this;
+ }
+
+ Iterator operator++(int) {
+ const Iterator it{*this};
+ ++(*this);
+ return it;
+ }
+
+ Iterator operator--(int) {
+ const Iterator it{*this};
+ --(*this);
+ return it;
+ }
+
+ operator Iterator<true>() const {
+ return Iterator<true>(m_base_it);
+ }
+
+ private:
+ BaseIterator m_base_it;
+ };
+
+public:
+ constexpr KLinkedList(KernelCore& kernel_) : BaseList(), kernel{kernel_} {}
+
+ ~KLinkedList() {
+ // Erase all elements.
+ for (auto it = begin(); it != end(); it = erase(it)) {
+ }
+
+ // Ensure we succeeded.
+ ASSERT(this->empty());
+ }
+
+ // Iterator accessors.
+ iterator begin() {
+ return iterator(BaseList::begin());
+ }
+
+ const_iterator begin() const {
+ return const_iterator(BaseList::begin());
+ }
+
+ iterator end() {
+ return iterator(BaseList::end());
+ }
+
+ const_iterator end() const {
+ return const_iterator(BaseList::end());
+ }
+
+ const_iterator cbegin() const {
+ return this->begin();
+ }
+
+ const_iterator cend() const {
+ return this->end();
+ }
+
+ reverse_iterator rbegin() {
+ return reverse_iterator(this->end());
+ }
+
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(this->end());
+ }
+
+ reverse_iterator rend() {
+ return reverse_iterator(this->begin());
+ }
+
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(this->begin());
+ }
+
+ const_reverse_iterator crbegin() const {
+ return this->rbegin();
+ }
+
+ const_reverse_iterator crend() const {
+ return this->rend();
+ }
+
+ // Content management.
+ using BaseList::empty;
+ using BaseList::size;
+
+ reference back() {
+ return *(--this->end());
+ }
+
+ const_reference back() const {
+ return *(--this->end());
+ }
+
+ reference front() {
+ return *this->begin();
+ }
+
+ const_reference front() const {
+ return *this->begin();
+ }
+
+ iterator insert(const_iterator pos, reference ref) {
+ KLinkedListNode* new_node = KLinkedListNode::Allocate(kernel);
+ ASSERT(new_node != nullptr);
+ new_node->Initialize(std::addressof(ref));
+ return iterator(BaseList::insert(pos.m_base_it, *new_node));
+ }
+
+ void push_back(reference ref) {
+ this->insert(this->end(), ref);
+ }
+
+ void push_front(reference ref) {
+ this->insert(this->begin(), ref);
+ }
+
+ void pop_back() {
+ this->erase(--this->end());
+ }
+
+ void pop_front() {
+ this->erase(this->begin());
+ }
+
+ iterator erase(const iterator pos) {
+ KLinkedListNode* freed_node = std::addressof(*pos.m_base_it);
+ iterator ret = iterator(BaseList::erase(pos.m_base_it));
+ KLinkedListNode::Free(kernel, freed_node);
+
+ return ret;
+ }
+
+private:
+ KernelCore& kernel;
+};
+
+} // 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 {
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
+constexpr KMemoryPermission ConvertToKMemoryPermission(Svc::MemoryPermission perm) {
+ return static_cast<KMemoryPermission>(perm);
+}
+
enum class KMemoryAttribute : u8 {
None = 0x00,
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 @@
namespace Kernel {
-KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr)
- : start_addr{start_addr}, end_addr{end_addr} {
+KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr_, VAddr end_addr_)
+ : start_addr{start_addr_}, end_addr{end_addr_} {
const u64 num_pages{(end_addr - start_addr) / PageSize};
memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free,
KMemoryPermission::None, KMemoryAttribute::None);
@@ -17,8 +17,8 @@ KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr)
KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) {
auto node{memory_block_tree.begin()};
while (node != end()) {
- const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()};
- if (node->GetAddress() <= addr && end_addr - 1 >= addr) {
+ const VAddr node_end_addr{node->GetNumPages() * PageSize + node->GetAddress()};
+ if (node->GetAddress() <= addr && node_end_addr - 1 >= addr) {
return node;
}
node = std::next(node);
@@ -67,7 +67,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
KMemoryPermission prev_perm, KMemoryAttribute prev_attribute,
KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attribute) {
- const VAddr end_addr{addr + num_pages * PageSize};
+ const VAddr update_end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped;
@@ -78,7 +78,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
- if (addr < cur_end_addr && cur_addr < end_addr) {
+ if (addr < cur_end_addr && cur_addr < update_end_addr) {
if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) {
node = next_node;
continue;
@@ -89,8 +89,8 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
memory_block_tree.insert(node, block->Split(addr));
}
- if (end_addr < cur_end_addr) {
- new_node = memory_block_tree.insert(node, block->Split(end_addr));
+ if (update_end_addr < cur_end_addr) {
+ new_node = memory_block_tree.insert(node, block->Split(update_end_addr));
}
new_node->Update(state, perm, attribute);
@@ -98,7 +98,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
MergeAdjacent(new_node, next_node);
}
- if (cur_end_addr - 1 >= end_addr - 1) {
+ if (cur_end_addr - 1 >= update_end_addr - 1) {
break;
}
@@ -108,7 +108,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state,
KMemoryPermission perm, KMemoryAttribute attribute) {
- const VAddr end_addr{addr + num_pages * PageSize};
+ const VAddr update_end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
while (node != memory_block_tree.end()) {
@@ -117,15 +117,15 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
- if (addr < cur_end_addr && cur_addr < end_addr) {
+ if (addr < cur_end_addr && cur_addr < update_end_addr) {
iterator new_node{node};
if (addr > cur_addr) {
memory_block_tree.insert(node, block->Split(addr));
}
- if (end_addr < cur_end_addr) {
- new_node = memory_block_tree.insert(node, block->Split(end_addr));
+ if (update_end_addr < cur_end_addr) {
+ new_node = memory_block_tree.insert(node, block->Split(update_end_addr));
}
new_node->Update(state, perm, attribute);
@@ -133,7 +133,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
MergeAdjacent(new_node, next_node);
}
- if (cur_end_addr - 1 >= end_addr - 1) {
+ if (cur_end_addr - 1 >= update_end_addr - 1) {
break;
}
@@ -143,7 +143,7 @@ void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState
void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func,
KMemoryPermission perm) {
- const VAddr end_addr{addr + num_pages * PageSize};
+ const VAddr update_end_addr{addr + num_pages * PageSize};
iterator node{memory_block_tree.begin()};
while (node != memory_block_tree.end()) {
@@ -152,15 +152,15 @@ void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc
const VAddr cur_addr{block->GetAddress()};
const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr};
- if (addr < cur_end_addr && cur_addr < end_addr) {
+ if (addr < cur_end_addr && cur_addr < update_end_addr) {
iterator new_node{node};
if (addr > cur_addr) {
memory_block_tree.insert(node, block->Split(addr));
}
- if (end_addr < cur_end_addr) {
- new_node = memory_block_tree.insert(node, block->Split(end_addr));
+ if (update_end_addr < cur_end_addr) {
+ new_node = memory_block_tree.insert(node, block->Split(update_end_addr));
}
lock_func(new_node, perm);
@@ -168,7 +168,7 @@ void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc
MergeAdjacent(new_node, next_node);
}
- if (cur_end_addr - 1 >= end_addr - 1) {
+ if (cur_end_addr - 1 >= update_end_addr - 1) {
break;
}
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:
using const_iterator = MemoryBlockTree::const_iterator;
public:
- KMemoryBlockManager(VAddr start_addr, VAddr end_addr);
+ KMemoryBlockManager(VAddr start_addr_, VAddr end_addr_);
iterator end() {
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:
type_id = type;
}
- constexpr bool Contains(u64 address) const {
+ constexpr bool Contains(u64 addr) const {
ASSERT(this->GetEndAddress() != 0);
- return this->GetAddress() <= address && address <= this->GetLastAddress();
+ return this->GetAddress() <= addr && addr <= this->GetLastAddress();
}
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 {
public:
class Node final {
public:
- constexpr Node(u64 addr, std::size_t num_pages) : addr{addr}, num_pages{num_pages} {}
+ constexpr Node(u64 addr_, std::size_t num_pages_) : addr{addr_}, num_pages{num_pages_} {}
constexpr u64 GetAddress() const {
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 @@
#include "core/hle/kernel/k_memory_block_manager.h"
#include "core/hle/kernel/k_page_linked_list.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_results.h"
#include "core/memory.h"
@@ -58,7 +58,7 @@ constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr
} // namespace
-KPageTable::KPageTable(Core::System& system) : system{system} {}
+KPageTable::KPageTable(Core::System& system_) : system{system_} {}
ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type,
bool enable_aslr, VAddr code_addr,
@@ -420,7 +420,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
remaining_size);
if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size);
- return ResultResourceLimitedExceeded;
+ return ResultLimitReached;
}
KPageLinkedList page_linked_list;
@@ -578,7 +578,7 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
AddRegionToPages(dst_addr, num_pages, dst_pages);
if (!dst_pages.IsEqual(src_pages)) {
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
{
@@ -641,6 +641,45 @@ ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, K
return RESULT_SUCCESS;
}
+ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list) {
+ VAddr cur_addr{addr};
+
+ for (const auto& node : page_linked_list.Nodes()) {
+ const std::size_t num_pages{(addr - cur_addr) / PageSize};
+ if (const auto result{
+ Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)};
+ result.IsError()) {
+ return result;
+ }
+
+ cur_addr += node.GetNumPages() * PageSize;
+ }
+
+ return RESULT_SUCCESS;
+}
+
+ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
+ KMemoryState state) {
+ std::lock_guard lock{page_table_lock};
+
+ const std::size_t num_pages{page_linked_list.GetNumPages()};
+ const std::size_t size{num_pages * PageSize};
+
+ if (!CanContain(addr, size, state)) {
+ return ResultInvalidCurrentMemory;
+ }
+
+ if (IsRegionMapped(addr, num_pages * PageSize)) {
+ return ResultInvalidCurrentMemory;
+ }
+
+ CASCADE_CODE(UnmapPages(addr, page_linked_list));
+
+ block_manager->Update(addr, num_pages, state, KMemoryPermission::None);
+
+ return RESULT_SUCCESS;
+}
+
ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size,
KMemoryPermission perm) {
@@ -790,7 +829,7 @@ ResultVal<VAddr> KPageTable::SetHeapSize(std::size_t size) {
if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta);
- return ResultResourceLimitedExceeded;
+ return ResultLimitReached;
}
KPageLinkedList page_linked_list;
@@ -867,8 +906,8 @@ ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
block_manager->UpdateLock(
addr, size / PageSize,
- [](KMemoryBlockManager::iterator block, KMemoryPermission perm) {
- block->ShareToDevice(perm);
+ [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
+ block->ShareToDevice(permission);
},
perm);
@@ -890,8 +929,8 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
block_manager->UpdateLock(
addr, size / PageSize,
- [](KMemoryBlockManager::iterator block, KMemoryPermission perm) {
- block->UnshareToDevice(perm);
+ [](KMemoryBlockManager::iterator block, KMemoryPermission permission) {
+ block->UnshareToDevice(permission);
},
perm);
@@ -1067,7 +1106,7 @@ constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const {
}
}
-constexpr bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
+bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const {
const VAddr end{addr + size};
const VAddr last{end - 1};
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;
class KPageTable final : NonCopyable {
public:
- explicit KPageTable(Core::System& system);
+ explicit KPageTable(Core::System& system_);
ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
VAddr code_addr, std::size_t code_size,
@@ -40,6 +40,7 @@ public:
ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size);
ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
KMemoryPermission perm);
+ ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm);
KMemoryInfo QueryInfo(VAddr addr);
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
@@ -63,6 +64,8 @@ public:
return page_table_impl;
}
+ bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const;
+
private:
enum class OperationType : u32 {
Map,
@@ -79,6 +82,7 @@ private:
ResultCode InitializeMemoryLayout(VAddr start, VAddr end);
ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list,
KMemoryPermission perm);
+ ResultCode UnmapPages(VAddr addr, const KPageLinkedList& page_linked_list);
void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end);
bool IsRegionMapped(VAddr address, u64 size);
bool IsRegionContiguous(VAddr addr, u64 size) const;
@@ -92,7 +96,6 @@ private:
OperationType operation, PAddr map_addr = 0);
constexpr VAddr GetRegionAddress(KMemoryState state) const;
constexpr std::size_t GetRegionSize(KMemoryState state) const;
- constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const;
constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
@@ -216,8 +219,6 @@ public:
constexpr PAddr GetPhysicalAddr(VAddr addr) {
return page_table_impl.backing_addr[addr >> PageBits] + addr;
}
-
-private:
constexpr bool Contains(VAddr addr) const {
return address_space_start <= addr && addr <= address_space_end - 1;
}
@@ -225,6 +226,8 @@ private:
return address_space_start <= addr && addr < addr + size &&
addr + size - 1 <= address_space_end - 1;
}
+
+private:
constexpr bool IsKernel() const {
return is_kernel;
}
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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+KPort::KPort(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
+
+KPort::~KPort() = default;
+
+void KPort::Initialize(s32 max_sessions_, bool is_light_, const std::string& name_) {
+ // Open a new reference count to the initialized port.
+ Open();
+
+ // Create and initialize our server/client pair.
+ KAutoObject::Create(std::addressof(server));
+ KAutoObject::Create(std::addressof(client));
+ server.Initialize(this, name_ + ":Server");
+ client.Initialize(this, max_sessions_, name_ + ":Client");
+
+ // Set our member variables.
+ is_light = is_light_;
+ name = name_;
+ state = State::Normal;
+}
+
+void KPort::OnClientClosed() {
+ KScopedSchedulerLock sl{kernel};
+
+ if (state == State::Normal) {
+ state = State::ClientClosed;
+ }
+}
+
+void KPort::OnServerClosed() {
+ KScopedSchedulerLock sl{kernel};
+
+ if (state == State::Normal) {
+ state = State::ServerClosed;
+ }
+}
+
+bool KPort::IsServerClosed() const {
+ KScopedSchedulerLock sl{kernel};
+ return state == State::ServerClosed;
+}
+
+ResultCode KPort::EnqueueSession(KServerSession* session) {
+ KScopedSchedulerLock sl{kernel};
+
+ R_UNLESS(state == State::Normal, ResultPortClosed);
+
+ if (server.HasHLEHandler()) {
+ server.GetHLEHandler()->ClientConnected(session);
+ } else {
+ server.EnqueueSession(session);
+ }
+
+ return RESULT_SUCCESS;
+}
+
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_server_port.h"
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KServerSession;
+
+class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject);
+
+public:
+ explicit KPort(KernelCore& kernel_);
+ virtual ~KPort();
+
+ static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+
+ void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_);
+ void OnClientClosed();
+ void OnServerClosed();
+
+ bool IsLight() const {
+ return is_light;
+ }
+
+ bool IsServerClosed() const;
+
+ ResultCode EnqueueSession(KServerSession* session);
+
+ KClientPort& GetClientPort() {
+ return client;
+ }
+ KServerPort& GetServerPort() {
+ return server;
+ }
+ const KClientPort& GetClientPort() const {
+ return client;
+ }
+ const KServerPort& GetServerPort() const {
+ return server;
+ }
+
+private:
+ enum class State : u8 {
+ Invalid = 0,
+ Normal = 1,
+ ClientClosed = 2,
+ ServerClosed = 3,
+ };
+
+private:
+ KServerPort server;
+ KClientPort client;
+ State state{State::Invalid};
+ bool is_light{};
+};
+
+} // 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 @@
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_memory_block_manager.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_slab_heap.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/lock.h"
#include "core/memory.h"
@@ -37,17 +38,20 @@ namespace {
* @param owner_process The parent process for the main thread
* @param priority The priority to give the main thread
*/
-void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
+void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) {
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
- auto thread_res =
- KThread::CreateUserThread(system, ThreadType::User, "main", entry_point, priority, 0,
- owner_process.GetIdealCoreId(), stack_top, &owner_process);
- std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
+ KThread* thread = KThread::Create(system.Kernel());
+ ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
+ owner_process.GetIdealCoreId(), &owner_process)
+ .IsSuccess());
// Register 1 must be a handle to the main thread
- const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
+ Handle thread_handle{};
+ owner_process.GetHandleTable().Add(&thread_handle, thread);
+
+ thread->SetName("main");
thread->GetContext32().cpu_registers[0] = 0;
thread->GetContext64().cpu_registers[0] = 0;
thread->GetContext32().cpu_registers[1] = thread_handle;
@@ -114,11 +118,11 @@ private:
std::bitset<num_slot_entries> is_slot_used;
};
-std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) {
+ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name,
+ ProcessType type) {
auto& kernel = system.Kernel();
- std::shared_ptr<Process> process = std::make_shared<Process>(system);
- process->name = std::move(name);
+ process->name = std::move(process_name);
process->resource_limit = kernel.GetSystemResourceLimit();
process->status = ProcessStatus::Created;
@@ -126,6 +130,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
: kernel.CreateNewUserProcessID();
process->capabilities.InitializeForMetadatalessProcess();
+ process->is_initialized = true;
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
std::uniform_int_distribution<u64> distribution;
@@ -133,14 +138,18 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
[&] { return distribution(rng); });
kernel.AppendNewProcess(process);
- return process;
+
+ // Open a reference to the resource limit.
+ process->resource_limit->Open();
+
+ return RESULT_SUCCESS;
}
-std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
+KResourceLimit* KProcess::GetResourceLimit() const {
return resource_limit;
}
-void Process::IncrementThreadCount() {
+void KProcess::IncrementThreadCount() {
ASSERT(num_threads >= 0);
num_created_threads++;
@@ -149,7 +158,7 @@ void Process::IncrementThreadCount() {
}
}
-void Process::DecrementThreadCount() {
+void KProcess::DecrementThreadCount() {
ASSERT(num_threads > 0);
if (const auto count = --num_threads; count == 0) {
@@ -157,31 +166,34 @@ void Process::DecrementThreadCount() {
}
}
-u64 Process::GetTotalPhysicalMemoryAvailable() const {
+u64 KProcess::GetTotalPhysicalMemoryAvailable() const {
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
- ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
+ if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
+ capacity != pool_size) {
+ LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size);
+ }
if (capacity < memory_usage_capacity) {
return capacity;
}
return memory_usage_capacity;
}
-u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
+u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize();
}
-u64 Process::GetTotalPhysicalMemoryUsed() const {
+u64 KProcess::GetTotalPhysicalMemoryUsed() const {
return image_size + main_thread_stack_size + page_table->GetTotalHeapSize() +
GetSystemResourceSize();
}
-u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
+u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
}
-bool Process::ReleaseUserException(KThread* thread) {
+bool KProcess::ReleaseUserException(KThread* thread) {
KScopedSchedulerLock sl{kernel};
if (exception_thread == thread) {
@@ -206,7 +218,7 @@ bool Process::ReleaseUserException(KThread* thread) {
}
}
-void Process::PinCurrentThread() {
+void KProcess::PinCurrentThread() {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// Get the current thread.
@@ -221,7 +233,7 @@ void Process::PinCurrentThread() {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
-void Process::UnpinCurrentThread() {
+void KProcess::UnpinCurrentThread() {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
// Get the current thread.
@@ -236,15 +248,39 @@ void Process::UnpinCurrentThread() {
KScheduler::SetSchedulerUpdateNeeded(kernel);
}
-void Process::RegisterThread(const KThread* thread) {
+ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
+ [[maybe_unused]] size_t size) {
+ // Lock ourselves, to prevent concurrent access.
+ KScopedLightLock lk(state_lock);
+
+ // TODO(bunnei): Manage KSharedMemoryInfo list here.
+
+ // Open a reference to the shared memory.
+ shmem->Open();
+
+ return RESULT_SUCCESS;
+}
+
+void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
+ [[maybe_unused]] size_t size) {
+ // Lock ourselves, to prevent concurrent access.
+ KScopedLightLock lk(state_lock);
+
+ // TODO(bunnei): Manage KSharedMemoryInfo list here.
+
+ // Close a reference to the shared memory.
+ shmem->Close();
+}
+
+void KProcess::RegisterThread(const KThread* thread) {
thread_list.push_back(thread);
}
-void Process::UnregisterThread(const KThread* thread) {
+void KProcess::UnregisterThread(const KThread* thread) {
thread_list.remove(thread);
}
-ResultCode Process::Reset() {
+ResultCode KProcess::Reset() {
// Lock the process and the scheduler.
KScopedLightLock lk(state_lock);
KScopedSchedulerLock sl{kernel};
@@ -258,8 +294,8 @@ ResultCode Process::Reset() {
return RESULT_SUCCESS;
}
-ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
- std::size_t code_size) {
+ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
+ std::size_t code_size) {
program_id = metadata.GetTitleID();
ideal_core = metadata.GetMainThreadCore();
is_64bit_process = metadata.Is64BitProgram();
@@ -271,7 +307,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
code_size + system_resource_size);
- return ResultResourceLimitedExceeded;
+ return ResultLimitReached;
}
// Initialize proces address space
if (const ResultCode result{
@@ -318,10 +354,10 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
tls_region_address = CreateTLSRegion();
memory_reservation.Commit();
- return handle_table.SetSize(capabilities.GetHandleTableSize());
+ return handle_table.Initialize(capabilities.GetHandleTableSize());
}
-void Process::Run(s32 main_thread_priority, u64 stack_size) {
+void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
AllocateMainThreadStack(stack_size);
resource_limit->Reserve(LimitableResource::Threads, 1);
resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
@@ -331,18 +367,18 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
ChangeStatus(ProcessStatus::Running);
- SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
+ SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top);
}
-void Process::PrepareForTermination() {
+void KProcess::PrepareForTermination() {
ChangeStatus(ProcessStatus::Exiting);
- const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) {
- for (auto& thread : thread_list) {
+ const auto stop_threads = [this](const std::vector<KThread*>& in_thread_list) {
+ for (auto& thread : in_thread_list) {
if (thread->GetOwnerProcess() != this)
continue;
- if (thread.get() == kernel.CurrentScheduler()->GetCurrentThread())
+ if (thread == kernel.CurrentScheduler()->GetCurrentThread())
continue;
// TODO(Subv): When are the other running/ready threads terminated?
@@ -353,7 +389,7 @@ void Process::PrepareForTermination() {
}
};
- stop_threads(system.GlobalSchedulerContext().GetThreadList());
+ stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList());
FreeTLSRegion(tls_region_address);
tls_region_address = 0;
@@ -366,6 +402,16 @@ void Process::PrepareForTermination() {
ChangeStatus(ProcessStatus::Exited);
}
+void KProcess::Finalize() {
+ // Release memory to the resource limit.
+ if (resource_limit != nullptr) {
+ resource_limit->Close();
+ }
+
+ // Perform inherited finalization.
+ KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
+}
+
/**
* Attempts to find a TLS page that contains a free slot for
* use by a thread.
@@ -379,8 +425,8 @@ static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) {
[](const auto& page) { return page.HasAvailableSlots(); });
}
-VAddr Process::CreateTLSRegion() {
- KScopedSchedulerLock lock(system.Kernel());
+VAddr KProcess::CreateTLSRegion() {
+ KScopedSchedulerLock lock(kernel);
if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)};
tls_page_iter != tls_pages.cend()) {
return *tls_page_iter->ReserveSlot();
@@ -391,7 +437,7 @@ VAddr Process::CreateTLSRegion() {
const VAddr start{page_table->GetKernelMapRegionStart()};
const VAddr size{page_table->GetKernelMapRegionEnd() - start};
- const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)};
+ const PAddr tls_map_addr{kernel.System().DeviceMemory().GetPhysicalAddr(tls_page_ptr)};
const VAddr tls_page_addr{page_table
->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize,
KMemoryState::ThreadLocal,
@@ -410,8 +456,8 @@ VAddr Process::CreateTLSRegion() {
return *reserve_result;
}
-void Process::FreeTLSRegion(VAddr tls_address) {
- KScopedSchedulerLock lock(system.Kernel());
+void KProcess::FreeTLSRegion(VAddr tls_address) {
+ KScopedSchedulerLock lock(kernel);
const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE);
auto iter =
std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) {
@@ -425,33 +471,34 @@ void Process::FreeTLSRegion(VAddr tls_address) {
iter->ReleaseSlot(tls_address);
}
-void Process::LoadModule(CodeSet code_set, VAddr base_addr) {
+void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
std::lock_guard lock{HLE::g_hle_lock};
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
KMemoryPermission permission) {
page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
- system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size());
+ kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
+ code_set.memory.size());
ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute);
ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read);
ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite);
}
-bool Process::IsSignaled() const {
+bool KProcess::IsSignaled() const {
ASSERT(kernel.GlobalSchedulerContext().IsLocked());
return is_signaled;
}
-Process::Process(Core::System& system)
- : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique<KPageTable>(system)},
- handle_table{system.Kernel()}, address_arbiter{system}, condition_var{system},
- state_lock{system.Kernel()}, system{system} {}
+KProcess::KProcess(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_},
+ page_table{std::make_unique<KPageTable>(kernel_.System())}, handle_table{kernel_},
+ address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {}
-Process::~Process() = default;
+KProcess::~KProcess() = default;
-void Process::ChangeStatus(ProcessStatus new_status) {
+void KProcess::ChangeStatus(ProcessStatus new_status) {
if (status == new_status) {
return;
}
@@ -461,7 +508,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
NotifyAvailable();
}
-ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) {
+ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) {
ASSERT(stack_size);
// 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 @@
#include <unordered_map>
#include <vector>
#include "common/common_types.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_address_arbiter.h"
+#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/process_capability.h"
+#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Core {
@@ -60,10 +62,13 @@ enum class ProcessStatus {
DebugBreak,
};
-class Process final : public KSynchronizationObject {
+class KProcess final
+ : public KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject> {
+ KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
+
public:
- explicit Process(Core::System& system);
- ~Process() override;
+ explicit KProcess(KernelCore& kernel_);
+ ~KProcess() override;
enum : u64 {
/// Lowest allowed process ID for a kernel initial process.
@@ -85,20 +90,8 @@ public:
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
- static std::shared_ptr<Process> Create(Core::System& system, std::string name,
- ProcessType type);
-
- std::string GetTypeName() const override {
- return "Process";
- }
- std::string GetName() const override {
- return name;
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::Process;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
+ static ResultCode Initialize(KProcess* process, Core::System& system, std::string process_name,
+ ProcessType type);
/// Gets a reference to the process' page table.
KPageTable& PageTable() {
@@ -111,12 +104,12 @@ public:
}
/// Gets a reference to the process' handle table.
- HandleTable& GetHandleTable() {
+ KHandleTable& GetHandleTable() {
return handle_table;
}
/// Gets a const reference to the process' handle table.
- const HandleTable& GetHandleTable() const {
+ const KHandleTable& GetHandleTable() const {
return handle_table;
}
@@ -167,7 +160,7 @@ public:
}
/// Gets the resource limit descriptor for this process
- std::shared_ptr<KResourceLimit> GetResourceLimit() const;
+ KResourceLimit* GetResourceLimit() const;
/// Gets the ideal CPU core ID for this process
u8 GetIdealCoreId() const {
@@ -338,9 +331,19 @@ public:
void LoadModule(CodeSet code_set, VAddr base_addr);
- bool IsSignaled() const override;
+ virtual bool IsInitialized() const override {
+ return is_initialized;
+ }
+
+ static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+
+ virtual void Finalize();
+
+ virtual u64 GetId() const override final {
+ return GetProcessID();
+ }
- void Finalize() override {}
+ virtual bool IsSignaled() const override;
void PinCurrentThread();
void UnpinCurrentThread();
@@ -349,6 +352,9 @@ public:
return state_lock;
}
+ ResultCode AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
+ void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
+
///////////////////////////////////////////////////////////////////////////////////////////////
// Thread-local storage management
@@ -399,7 +405,7 @@ private:
u32 system_resource_size = 0;
/// Resource limit descriptor for this process
- std::shared_ptr<KResourceLimit> resource_limit;
+ KResourceLimit* resource_limit{};
/// The ideal CPU core for this process, threads are scheduled on this core by default.
u8 ideal_core = 0;
@@ -423,7 +429,7 @@ private:
u64 total_process_running_time_ticks = 0;
/// Per-process handle table for storing created object handles in.
- HandleTable handle_table;
+ KHandleTable handle_table;
/// Per-process address arbiter.
KAddressArbiter address_arbiter;
@@ -454,14 +460,12 @@ private:
/// Process total image size
std::size_t image_size{};
- /// Name of this process
- std::string name;
-
/// Schedule count of this process
s64 schedule_count{};
bool is_signaled{};
bool is_suspended{};
+ bool is_initialized{};
std::atomic<s32> num_created_threads{};
std::atomic<u16> num_threads{};
@@ -474,9 +478,6 @@ private:
KThread* exception_thread{};
KLightLock state_lock;
-
- /// System context
- Core::System& system;
};
} // 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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <algorithm>
#include "common/assert.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
+#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/object.h"
#include "core/hle/kernel/svc_results.h"
namespace Kernel {
-KReadableEvent::KReadableEvent(KernelCore& kernel, std::string&& name)
- : KSynchronizationObject{kernel, std::move(name)} {}
+KReadableEvent::KReadableEvent(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+
KReadableEvent::~KReadableEvent() = default;
bool KReadableEvent::IsSignaled() const {
@@ -25,6 +22,12 @@ bool KReadableEvent::IsSignaled() const {
return is_signaled;
}
+void KReadableEvent::Destroy() {
+ if (parent) {
+ parent->Close();
+ }
+}
+
ResultCode KReadableEvent::Signal() {
KScopedSchedulerLock lk{kernel};
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 @@
#pragma once
+#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_synchronization_object.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -13,31 +14,25 @@ namespace Kernel {
class KernelCore;
class KEvent;
-class KReadableEvent final : public KSynchronizationObject {
+class KReadableEvent : public KSynchronizationObject {
+ KERNEL_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject);
+
public:
- explicit KReadableEvent(KernelCore& kernel, std::string&& name);
+ explicit KReadableEvent(KernelCore& kernel_);
~KReadableEvent() override;
- std::string GetTypeName() const override {
- return "KReadableEvent";
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::ReadableEvent;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
+ void Initialize(KEvent* parent_, std::string&& name_) {
+ is_signaled = false;
+ parent = parent_;
+ name = std::move(name_);
}
KEvent* GetParent() const {
return parent;
}
- void Initialize(KEvent* parent_) {
- is_signaled = false;
- parent = parent_;
- }
-
- bool IsSignaled() const override;
- void Finalize() override {}
+ virtual bool IsSignaled() const override;
+ virtual void Destroy() override;
ResultCode Signal();
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 @@
namespace Kernel {
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
-KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_)
- : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {}
+KResourceLimit::KResourceLimit(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_}, lock{kernel_}, cond_var{kernel_} {}
KResourceLimit::~KResourceLimit() = default;
+void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) {
+ core_timing = core_timing_;
+}
+
+void KResourceLimit::Finalize() {}
+
s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
@@ -78,7 +84,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
- return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout);
+ return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
@@ -109,7 +115,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
}
if (current_hints[index] + value <= limit_values[index] &&
- (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) {
+ (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
waiter_count++;
cond_var.Wait(&lock, timeout);
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 @@
#include "common/common_types.h"
#include "core/hle/kernel/k_light_condition_variable.h"
#include "core/hle/kernel/k_light_lock.h"
-#include "core/hle/kernel/object.h"
union ResultCode;
@@ -32,10 +31,16 @@ constexpr bool IsValidResourceType(LimitableResource type) {
return type < LimitableResource::Count;
}
-class KResourceLimit final : public Object {
+class KResourceLimit final
+ : public KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject);
+
public:
- explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_);
- ~KResourceLimit();
+ explicit KResourceLimit(KernelCore& kernel_);
+ virtual ~KResourceLimit();
+
+ void Initialize(const Core::Timing::CoreTiming* core_timing_);
+ virtual void Finalize() override;
s64 GetLimitValue(LimitableResource which) const;
s64 GetCurrentValue(LimitableResource which) const;
@@ -49,19 +54,7 @@ public:
void Release(LimitableResource which, s64 value);
void Release(LimitableResource which, s64 value, s64 hint);
- std::string GetTypeName() const override {
- return "KResourceLimit";
- }
- std::string GetName() const override {
- return GetTypeName();
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::ResourceLimit;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- virtual void Finalize() override {}
+ static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
private:
using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
@@ -72,6 +65,6 @@ private:
mutable KLightLock lock;
s32 waiter_count{};
KLightConditionVariable cond_var;
- const Core::Timing::CoreTiming& core_timing;
+ const Core::Timing::CoreTiming* core_timing{};
};
} // 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 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/time_manager.h"
namespace Kernel {
@@ -71,7 +71,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
}
if (state.should_count_idle) {
if (highest_thread != nullptr) {
- if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) {
+ if (KProcess* process = highest_thread->GetOwnerProcess(); process != nullptr) {
process->SetRunningThread(core_id, highest_thread, state.idle_count);
}
} else {
@@ -104,7 +104,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
if (top_thread != nullptr) {
// If the thread has no waiters, we need to check if the process has a thread pinned.
if (top_thread->GetNumKernelWaiters() == 0) {
- if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) {
+ if (KProcess* parent = top_thread->GetOwnerProcess(); parent != nullptr) {
if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id));
pinned != nullptr && pinned != top_thread) {
// 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
}
}
-void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
+void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) {
ASSERT(system.GlobalSchedulerContext().IsLocked());
// Get a reference to the priority queue.
@@ -267,7 +267,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
auto& priority_queue = GetPriorityQueue(kernel);
// Rotate the front of the queue to the end.
- KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority);
+ KThread* top_thread = priority_queue.GetScheduledFront(cpu_core_id, priority);
KThread* next_thread = nullptr;
if (top_thread != nullptr) {
next_thread = priority_queue.MoveToScheduledBack(top_thread);
@@ -279,7 +279,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
// While we have a suggested thread, try to migrate it!
{
- KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority);
+ KThread* suggested = priority_queue.GetSuggestedFront(cpu_core_id, priority);
while (suggested != nullptr) {
// Check if the suggested thread is the top thread on its core.
const s32 suggested_core = suggested->GetActiveCore();
@@ -300,7 +300,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
// to the front of the queue.
if (top_on_suggested_core == nullptr ||
top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) {
- suggested->SetActiveCore(core_id);
+ suggested->SetActiveCore(cpu_core_id);
priority_queue.ChangeCore(suggested_core, suggested, true);
IncrementScheduledCount(suggested);
break;
@@ -308,22 +308,22 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
}
// Get the next suggestion.
- suggested = priority_queue.GetSamePriorityNext(core_id, suggested);
+ suggested = priority_queue.GetSamePriorityNext(cpu_core_id, suggested);
}
}
// Now that we might have migrated a thread with the same priority, check if we can do better.
{
- KThread* best_thread = priority_queue.GetScheduledFront(core_id);
+ KThread* best_thread = priority_queue.GetScheduledFront(cpu_core_id);
if (best_thread == GetCurrentThread()) {
- best_thread = priority_queue.GetScheduledNext(core_id, best_thread);
+ best_thread = priority_queue.GetScheduledNext(cpu_core_id, best_thread);
}
// If the best thread we can choose has a priority the same or worse than ours, try to
// migrate a higher priority thread.
if (best_thread != nullptr && best_thread->GetPriority() >= priority) {
- KThread* suggested = priority_queue.GetSuggestedFront(core_id);
+ KThread* suggested = priority_queue.GetSuggestedFront(cpu_core_id);
while (suggested != nullptr) {
// If the suggestion's priority is the same as ours, don't bother.
if (suggested->GetPriority() >= best_thread->GetPriority()) {
@@ -342,7 +342,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
if (top_on_suggested_core == nullptr ||
top_on_suggested_core->GetPriority() >=
HighestCoreMigrationAllowedPriority) {
- suggested->SetActiveCore(core_id);
+ suggested->SetActiveCore(cpu_core_id);
priority_queue.ChangeCore(suggested_core, suggested, true);
IncrementScheduledCount(suggested);
break;
@@ -350,7 +350,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
}
// Get the next suggestion.
- suggested = priority_queue.GetSuggestedNext(core_id, suggested);
+ suggested = priority_queue.GetSuggestedNext(cpu_core_id, suggested);
}
}
}
@@ -411,7 +411,7 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
// Get the current thread and process.
KThread& cur_thread = Kernel::GetCurrentThread(kernel);
- Process& cur_process = *kernel.CurrentProcess();
+ KProcess& cur_process = *kernel.CurrentProcess();
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -450,7 +450,7 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
// Get the current thread and process.
KThread& cur_thread = Kernel::GetCurrentThread(kernel);
- Process& cur_process = *kernel.CurrentProcess();
+ KProcess& cur_process = *kernel.CurrentProcess();
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -538,7 +538,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
// Get the current thread and process.
KThread& cur_thread = Kernel::GetCurrentThread(kernel);
- Process& cur_process = *kernel.CurrentProcess();
+ KProcess& cur_process = *kernel.CurrentProcess();
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -607,7 +607,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
}
}
-KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) {
+KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, core_id{core_id_} {
switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
state.needs_scheduling.store(true);
state.interrupt_task_thread_runnable = false;
@@ -617,7 +617,12 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core
state.highest_priority_thread = nullptr;
}
-KScheduler::~KScheduler() = default;
+KScheduler::~KScheduler() {
+ if (idle_thread) {
+ idle_thread->Close();
+ idle_thread = nullptr;
+ }
+}
KThread* KScheduler::GetCurrentThread() const {
if (auto result = current_thread.load(); result) {
@@ -719,7 +724,7 @@ void KScheduler::ScheduleImpl() {
current_thread.store(next_thread);
- Process* const previous_process = system.Kernel().CurrentProcess();
+ KProcess* const previous_process = system.Kernel().CurrentProcess();
UpdateLastContextSwitchTime(previous_thread, previous_process);
@@ -775,7 +780,7 @@ void KScheduler::SwitchToCurrent() {
}
}
-void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) {
+void KScheduler::UpdateLastContextSwitchTime(KThread* thread, KProcess* process) {
const u64 prev_switch_ticks = last_context_switch_time;
const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
@@ -792,13 +797,9 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process)
}
void KScheduler::Initialize() {
- std::string name = "Idle Thread Id:" + std::to_string(core_id);
- std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
- void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
- auto thread_res = KThread::CreateThread(
- system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0,
- static_cast<u32>(core_id), 0, nullptr, std::move(init_func), init_func_parameter);
- idle_thread = thread_res.Unwrap().get();
+ idle_thread = KThread::Create(system.Kernel());
+ ASSERT(KThread::InitializeIdleThread(system, idle_thread, core_id).IsSuccess());
+ idle_thread->SetName(fmt::format("IdleThread:{}", core_id));
}
KScopedSchedulerLock::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;
namespace Kernel {
class KernelCore;
-class Process;
+class KProcess;
class SchedulerLock;
class KThread;
class KScheduler final {
public:
- explicit KScheduler(Core::System& system, s32 core_id);
+ explicit KScheduler(Core::System& system_, s32 core_id_);
~KScheduler();
/// Reschedules to the next available thread (call after current thread is suspended)
@@ -141,7 +141,7 @@ private:
[[nodiscard]] static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel);
- void RotateScheduledQueue(s32 core_id, s32 priority);
+ void RotateScheduledQueue(s32 cpu_core_id, s32 priority);
void Schedule() {
ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1);
@@ -165,7 +165,7 @@ private:
* most recent tick count retrieved. No special arithmetic is
* applied to it.
*/
- void UpdateLastContextSwitchTime(KThread* thread, Process* process);
+ void UpdateLastContextSwitchTime(KThread* thread, KProcess* process);
static void OnSwitch(void* this_scheduler);
void SwitchToCurrent();
@@ -173,12 +173,12 @@ private:
KThread* prev_thread{};
std::atomic<KThread*> current_thread{};
- KThread* idle_thread;
+ KThread* idle_thread{};
std::shared_ptr<Common::Fiber> switch_fiber{};
struct SchedulingState {
- std::atomic<bool> needs_scheduling;
+ std::atomic<bool> needs_scheduling{};
bool interrupt_task_thread_runnable{};
bool should_count_idle{};
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 @@
#pragma once
#include "common/common_types.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
-#include "core/hle/kernel/process.h"
namespace Kernel {
class KScopedResourceReservation {
public:
- explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
- s64 v, s64 timeout)
+ explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v, s64 timeout)
: resource_limit(std::move(l)), value(v), resource(r) {
if (resource_limit && value) {
success = resource_limit->Reserve(resource, value, timeout);
@@ -25,8 +24,7 @@ public:
}
}
- explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
- s64 v = 1)
+ explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v = 1)
: resource_limit(std::move(l)), value(v), resource(r) {
if (resource_limit && value) {
success = resource_limit->Reserve(resource, value);
@@ -35,10 +33,10 @@ public:
}
}
- explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t)
+ explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v, s64 t)
: KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {}
- explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1)
+ explicit KScopedResourceReservation(const KProcess* p, LimitableResource r, s64 v = 1)
: KScopedResourceReservation(p->GetResourceLimit(), r, v) {}
~KScopedResourceReservation() noexcept {
@@ -58,7 +56,7 @@ public:
}
private:
- std::shared_ptr<KResourceLimit> resource_limit;
+ KResourceLimit* resource_limit{};
s64 value;
LimitableResource resource;
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 @@
#pragma once
#include "common/common_types.h"
-#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/time_manager.h"
@@ -17,8 +17,8 @@ namespace Kernel {
class [[nodiscard]] KScopedSchedulerLockAndSleep {
public:
- explicit KScopedSchedulerLockAndSleep(KernelCore & kernel, KThread * t, s64 timeout)
- : kernel(kernel), thread(t), timeout_tick(timeout) {
+ explicit KScopedSchedulerLockAndSleep(KernelCore & kernel_, KThread * t, s64 timeout)
+ : kernel(kernel_), thread(t), timeout_tick(timeout) {
// Lock the scheduler.
kernel.GlobalSchedulerContext().scheduler_lock.Lock();
}
diff --git a/src/core/hle/kernel/k_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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <tuple>
+#include "common/assert.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_server_port.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+KServerPort::~KServerPort() = default;
+
+void KServerPort::Initialize(KPort* parent_, std::string&& name_) {
+ // Set member variables.
+ parent = parent_;
+ name = std::move(name_);
+}
+
+bool KServerPort::IsLight() const {
+ return this->GetParent()->IsLight();
+}
+
+void KServerPort::CleanupSessions() {
+ // Ensure our preconditions are met.
+ if (this->IsLight()) {
+ UNIMPLEMENTED();
+ }
+
+ // Cleanup the session list.
+ while (true) {
+ // Get the last session in the list
+ KServerSession* session = nullptr;
+ {
+ KScopedSchedulerLock sl{kernel};
+ if (!session_list.empty()) {
+ session = std::addressof(session_list.front());
+ session_list.pop_front();
+ }
+ }
+
+ // Close the session.
+ if (session != nullptr) {
+ session->Close();
+ } else {
+ break;
+ }
+ }
+}
+
+void KServerPort::Destroy() {
+ // Note with our parent that we're closed.
+ parent->OnServerClosed();
+
+ // Perform necessary cleanup of our session lists.
+ this->CleanupSessions();
+
+ // Close our reference to our parent.
+ parent->Close();
+}
+
+bool KServerPort::IsSignaled() const {
+ if (this->IsLight()) {
+ UNIMPLEMENTED();
+ return false;
+ } else {
+ return !session_list.empty();
+ }
+}
+
+void KServerPort::EnqueueSession(KServerSession* session) {
+ ASSERT(!this->IsLight());
+
+ KScopedSchedulerLock sl{kernel};
+
+ // Add the session to our queue.
+ session_list.push_back(*session);
+ if (session_list.size() == 1) {
+ this->NotifyAvailable();
+ }
+}
+
+KServerSession* KServerPort::AcceptSession() {
+ ASSERT(!this->IsLight());
+
+ KScopedSchedulerLock sl{kernel};
+
+ // Return the first session in the list.
+ if (session_list.empty()) {
+ return nullptr;
+ }
+
+ KServerSession* session = std::addressof(session_list.front());
+ session_list.pop_front();
+ return session;
+}
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <boost/intrusive/list.hpp>
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KernelCore;
+class KPort;
+class SessionRequestHandler;
+
+class KServerPort final : public KSynchronizationObject {
+ KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
+
+private:
+ using SessionList = boost::intrusive::list<KServerSession>;
+
+public:
+ explicit KServerPort(KernelCore& kernel_);
+ virtual ~KServerPort() override;
+
+ using HLEHandler = std::shared_ptr<SessionRequestHandler>;
+
+ void Initialize(KPort* parent_, std::string&& name_);
+
+ /// Whether or not this server port has an HLE handler available.
+ bool HasHLEHandler() const {
+ return hle_handler != nullptr;
+ }
+
+ /// Gets the HLE handler for this port.
+ HLEHandler GetHLEHandler() const {
+ return hle_handler;
+ }
+
+ /**
+ * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
+ * will inherit a reference to this handler.
+ */
+ void SetHleHandler(HLEHandler hle_handler_) {
+ hle_handler = std::move(hle_handler_);
+ }
+
+ void EnqueueSession(KServerSession* pending_session);
+
+ KServerSession* AcceptSession();
+
+ const KPort* GetParent() const {
+ return parent;
+ }
+
+ bool IsLight() const;
+
+ // Overridden virtual functions.
+ virtual void Destroy() override;
+ virtual bool IsSignaled() const override;
+
+private:
+ void CleanupSessions();
+
+private:
+ SessionList session_list;
+ HLEHandler hle_handler;
+ KPort* parent{};
+};
+
+} // 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 @@
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_handle_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/session.h"
#include "core/memory.h"
namespace Kernel {
-ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {}
+KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
-ServerSession::~ServerSession() {
+KServerSession::~KServerSession() {
kernel.ReleaseServiceThread(service_thread);
}
-ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
- std::shared_ptr<Session> parent,
- std::string name) {
- std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
-
- session->name = std::move(name);
- session->parent = std::move(parent);
- session->service_thread = kernel.CreateServiceThread(session->name);
-
- return MakeResult(std::move(session));
+void KServerSession::Initialize(KSession* parent_, std::string&& name_) {
+ // Set member variables.
+ parent = parent_;
+ name = std::move(name_);
+ service_thread = kernel.CreateServiceThread(name);
}
-bool ServerSession::IsSignaled() const {
- // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
- if (!parent->Client()) {
- return true;
- }
+void KServerSession::Destroy() {
+ parent->OnServerClosed();
- // Wait if we have no pending requests, or if we're currently handling a request.
- return !pending_requesting_threads.empty() && currently_handling == nullptr;
+ parent->Close();
}
-void ServerSession::ClientDisconnected() {
+void KServerSession::OnClientClosed() {
// We keep a shared pointer to the hle handler to keep it alive throughout
// the call to ClientDisconnected, as ClientDisconnected invalidates the
// hle_handler member itself during the course of the function executing.
@@ -60,24 +50,31 @@ void ServerSession::ClientDisconnected() {
if (handler) {
// Note that after this returns, this server session's hle_handler is
// invalidated (set to null).
- handler->ClientDisconnected(SharedFrom(this));
+ handler->ClientDisconnected(this);
+ }
+}
+
+bool KServerSession::IsSignaled() const {
+ ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+ // If the client is closed, we're always signaled.
+ if (parent->IsClientClosed()) {
+ return true;
}
- // Clean up the list of client threads with pending requests, they are unneeded now that the
- // client endpoint is closed.
- pending_requesting_threads.clear();
- currently_handling = nullptr;
+ // Otherwise, we're signaled if we have a request and aren't handling one.
+ return false;
}
-void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) {
+void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) {
domain_request_handlers.push_back(std::move(handler));
}
-std::size_t ServerSession::NumDomainRequestHandlers() const {
+std::size_t KServerSession::NumDomainRequestHandlers() const {
return domain_request_handlers.size();
}
-ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
+ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
if (!context.HasDomainMessageHeader()) {
return RESULT_SUCCESS;
}
@@ -98,7 +95,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
UNREACHABLE();
return RESULT_SUCCESS; // Ignore error if asserts are off
}
- return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
+ return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context);
case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
@@ -116,23 +113,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
return RESULT_SUCCESS;
}
-ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<KThread> thread,
- Core::Memory::Memory& memory) {
+ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
- auto context =
- std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
+ auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
if (auto strong_ptr = service_thread.lock()) {
- strong_ptr->QueueSyncRequest(*this, std::move(context));
+ strong_ptr->QueueSyncRequest(*parent, std::move(context));
return RESULT_SUCCESS;
}
return RESULT_SUCCESS;
}
-ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
+ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
ResultCode result = RESULT_SUCCESS;
// If the session has been converted to a domain, handle the domain request
if (IsDomain() && context.HasDomainMessageHeader()) {
@@ -140,7 +135,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
// If there is no domain header, the regular session handler is used
} else if (hle_handler != nullptr) {
// If this ServerSession has an associated HLE handler, forward the request to it.
- result = hle_handler->HandleSyncRequest(context);
+ result = hle_handler->HandleSyncRequest(*this, context);
}
if (convert_to_domain) {
@@ -161,10 +156,9 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
return result;
}
-ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<KThread> thread,
- Core::Memory::Memory& memory,
- Core::Timing::CoreTiming& core_timing) {
- return QueueSyncRequest(std::move(thread), memory);
+ResultCode KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
+ Core::Timing::CoreTiming& core_timing) {
+ return QueueSyncRequest(thread, memory);
}
} // 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 @@
#include <utility>
#include <vector>
+#include <boost/intrusive/list.hpp>
+
#include "common/threadsafe_queue.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/service_thread.h"
@@ -27,55 +29,35 @@ namespace Kernel {
class HLERequestContext;
class KernelCore;
-class Session;
+class KSession;
class SessionRequestHandler;
class KThread;
-/**
- * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
- * primitive for communication between different processes, and are used to implement service calls
- * to the various system services.
- *
- * To make a service call, the client must write the command header and parameters to the buffer
- * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
- * SVC call with its ClientSession handle. The kernel will read the command header, using it to
- * marshall the parameters to the process at the server endpoint of the session.
- * After the server replies to the request, the response is marshalled back to the caller's
- * TLS buffer and control is transferred back to it.
- */
-class ServerSession final : public KSynchronizationObject {
+class KServerSession final : public KSynchronizationObject,
+ public boost::intrusive::list_base_hook<> {
+ KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
+
friend class ServiceThread;
public:
- explicit ServerSession(KernelCore& kernel);
- ~ServerSession() override;
+ explicit KServerSession(KernelCore& kernel_);
+ virtual ~KServerSession() override;
- friend class Session;
+ virtual void Destroy() override;
- static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel,
- std::shared_ptr<Session> parent,
- std::string name = "Unknown");
+ void Initialize(KSession* parent_, std::string&& name_);
- std::string GetTypeName() const override {
- return "ServerSession";
+ KSession* GetParent() {
+ return parent;
}
- std::string GetName() const override {
- return name;
+ const KSession* GetParent() const {
+ return parent;
}
- static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
+ virtual bool IsSignaled() const override;
- Session* GetParent() {
- return parent.get();
- }
-
- const Session* GetParent() const {
- return parent.get();
- }
+ void OnClientClosed();
/**
* Sets the HLE handler for the session. This handler will be called to service IPC requests
@@ -95,12 +77,9 @@ public:
*
* @returns ResultCode from the operation.
*/
- ResultCode HandleSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
+ ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory,
Core::Timing::CoreTiming& core_timing);
- /// Called when a client disconnection occurs.
- void ClientDisconnected();
-
/// Adds a new domain request handler to the collection of request handlers within
/// this ServerSession instance.
void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler);
@@ -124,13 +103,9 @@ public:
convert_to_domain = true;
}
- bool IsSignaled() const override;
-
- void Finalize() override {}
-
private:
/// Queues a sync request from the emulated application.
- ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory);
+ ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
/// Completes a sync request from the emulated application.
ResultCode CompleteSyncRequest(HLERequestContext& context);
@@ -139,33 +114,20 @@ private:
/// object handle.
ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);
- /// The parent session, which links to the client endpoint.
- std::shared_ptr<Session> parent;
-
/// This session's HLE request handler (applicable when not a domain)
std::shared_ptr<SessionRequestHandler> hle_handler;
/// This is the list of domain request handlers (after conversion to a domain)
std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;
- /// List of threads that are pending a response after a sync request. This list is processed in
- /// a LIFO manner, thus, the last request will be dispatched first.
- /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
- std::vector<std::shared_ptr<KThread>> pending_requesting_threads;
-
- /// Thread whose request is currently being handled. A request is considered "handled" when a
- /// response is sent via svcReplyAndReceive.
- /// TODO(Subv): Find a better name for this.
- std::shared_ptr<KThread> currently_handling;
-
/// When set to True, converts the session to a domain at the end of the command
bool convert_to_domain{};
- /// The name of this session (optional)
- std::string name;
-
/// Thread to dispatch service requests
std::weak_ptr<ServiceThread> service_thread;
+
+ /// KSession that owns this KServerSession
+ KSession* parent{};
};
} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_session.h"
+
+namespace Kernel {
+
+KSession::KSession(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
+KSession::~KSession() = default;
+
+void KSession::Initialize(KClientPort* port_, const std::string& name_) {
+ // Increment reference count.
+ // Because reference count is one on creation, this will result
+ // in a reference count of two. Thus, when both server and client are closed
+ // this object will be destroyed.
+ Open();
+
+ // Create our sub sessions.
+ KAutoObject::Create(std::addressof(server));
+ KAutoObject::Create(std::addressof(client));
+
+ // Initialize our sub sessions.
+ server.Initialize(this, name_ + ":Server");
+ client.Initialize(this, name_ + ":Client");
+
+ // Set state and name.
+ SetState(State::Normal);
+ name = name_;
+
+ // Set our owner process.
+ process = kernel.CurrentProcess();
+ process->Open();
+
+ // Set our port.
+ port = port_;
+ if (port != nullptr) {
+ port->Open();
+ }
+
+ // Mark initialized.
+ initialized = true;
+}
+
+void KSession::Finalize() {
+ if (port == nullptr) {
+ return;
+ }
+
+ port->OnSessionFinalized();
+ port->Close();
+}
+
+void KSession::OnServerClosed() {
+ if (GetState() != State::Normal) {
+ return;
+ }
+
+ SetState(State::ServerClosed);
+ client.OnServerClosed();
+}
+
+void KSession::OnClientClosed() {
+ if (GetState() != State::Normal) {
+ return;
+ }
+
+ SetState(State::ClientClosed);
+ server.OnClientClosed();
+}
+
+void KSession::PostDestroy(uintptr_t arg) {
+ // Release the session count resource the owner process holds.
+ KProcess* owner = reinterpret_cast<KProcess*>(arg);
+ // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1);
+ owner->Close();
+}
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+#include <string>
+
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/slab_helpers.h"
+
+namespace Kernel {
+
+class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
+
+public:
+ explicit KSession(KernelCore& kernel_);
+ virtual ~KSession() override;
+
+ void Initialize(KClientPort* port_, const std::string& name_);
+
+ virtual void Finalize() override;
+
+ virtual bool IsInitialized() const override {
+ return initialized;
+ }
+
+ virtual uintptr_t GetPostDestroyArgument() const override {
+ return reinterpret_cast<uintptr_t>(process);
+ }
+
+ static void PostDestroy(uintptr_t arg);
+
+ void OnServerClosed();
+
+ void OnClientClosed();
+
+ bool IsServerClosed() const {
+ return this->GetState() != State::Normal;
+ }
+
+ bool IsClientClosed() const {
+ return this->GetState() != State::Normal;
+ }
+
+ KClientSession& GetClientSession() {
+ return client;
+ }
+
+ KServerSession& GetServerSession() {
+ return server;
+ }
+
+ const KClientSession& GetClientSession() const {
+ return client;
+ }
+
+ const KServerSession& GetServerSession() const {
+ return server;
+ }
+
+ const KClientPort* GetParent() const {
+ return port;
+ }
+
+private:
+ enum class State : u8 {
+ Invalid = 0,
+ Normal = 1,
+ ClientClosed = 2,
+ ServerClosed = 3,
+ };
+
+private:
+ void SetState(State state) {
+ atomic_state = static_cast<u8>(state);
+ }
+
+ State GetState() const {
+ return static_cast<State>(atomic_state.load(std::memory_order_relaxed));
+ }
+
+private:
+ KServerSession server;
+ KClientSession client;
+ std::atomic<std::underlying_type_t<State>> atomic_state{
+ static_cast<std::underlying_type_t<State>>(State::Invalid)};
+ KClientPort* port{};
+ KProcess* process{};
+ bool initialized{};
+};
+
+} // 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 @@
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_results.h"
namespace Kernel {
-KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory)
- : Object{kernel}, device_memory{device_memory} {}
+KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
KSharedMemory::~KSharedMemory() {
kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size);
}
-std::shared_ptr<KSharedMemory> KSharedMemory::Create(
- KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
- KPageLinkedList&& page_list, KMemoryPermission owner_permission,
- KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) {
+ResultCode KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
+ KPageLinkedList&& page_list_,
+ Svc::MemoryPermission owner_permission_,
+ Svc::MemoryPermission user_permission_,
+ PAddr physical_address_, std::size_t size_,
+ std::string name_) {
+ // Set members.
+ owner_process = owner_process_;
+ device_memory = &device_memory_;
+ page_list = std::move(page_list_);
+ owner_permission = owner_permission_;
+ user_permission = user_permission_;
+ physical_address = physical_address_;
+ size = size_;
+ name = std::move(name_);
- const auto resource_limit = kernel.GetSystemResourceLimit();
- KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
- size);
- ASSERT(memory_reservation.Succeeded());
+ // Get the resource limit.
+ KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
- std::shared_ptr<KSharedMemory> shared_memory{
- std::make_shared<KSharedMemory>(kernel, device_memory)};
-
- shared_memory->owner_process = owner_process;
- shared_memory->page_list = std::move(page_list);
- shared_memory->owner_permission = owner_permission;
- shared_memory->user_permission = user_permission;
- shared_memory->physical_address = physical_address;
- shared_memory->size = size;
- shared_memory->name = name;
+ // Reserve memory for ourselves.
+ KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory,
+ size_);
+ R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
+ // Commit our reservation.
memory_reservation.Commit();
- return shared_memory;
+
+ // Set our resource limit.
+ resource_limit = reslimit;
+ resource_limit->Open();
+
+ // Mark initialized.
+ is_initialized = true;
+
+ // Clear all pages in the memory.
+ std::memset(device_memory_.GetPointer(physical_address_), 0, size_);
+
+ return RESULT_SUCCESS;
+}
+
+void KSharedMemory::Finalize() {
+ // Release the memory reservation.
+ resource_limit->Release(LimitableResource::PhysicalMemory, size);
+ resource_limit->Close();
+
+ // Perform inherited finalization.
+ KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList>::Finalize();
}
-ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size,
- KMemoryPermission permissions) {
- const u64 page_count{(size + PageSize - 1) / PageSize};
+ResultCode KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size,
+ Svc::MemoryPermission permissions) {
+ const u64 page_count{(map_size + PageSize - 1) / PageSize};
if (page_list.GetNumPages() != page_count) {
UNIMPLEMENTED_MSG("Page count does not match");
}
- const KMemoryPermission expected =
+ const Svc::MemoryPermission expected =
&target_process == owner_process ? owner_permission : user_permission;
if (permissions != expected) {
@@ -59,7 +83,17 @@ ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_
}
return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared,
- permissions);
+ ConvertToKMemoryPermission(permissions));
+}
+
+ResultCode KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
+ const u64 page_count{(unmap_size + PageSize - 1) / PageSize};
+
+ if (page_list.GetNumPages() != page_count) {
+ UNIMPLEMENTED_MSG("Page count does not match");
+ }
+
+ return target_process.PageTable().UnmapPages(address, page_list, KMemoryState::Shared);
}
} // 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 @@
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_page_linked_list.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Kernel {
class KernelCore;
-class KSharedMemory final : public Object {
+class KSharedMemory final
+ : public KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject);
+
public:
- explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory);
+ explicit KSharedMemory(KernelCore& kernel_);
~KSharedMemory() override;
- static std::shared_ptr<KSharedMemory> Create(
- KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,
- KPageLinkedList&& page_list, KMemoryPermission owner_permission,
- KMemoryPermission user_permission, PAddr physical_address, std::size_t size,
- std::string name);
-
- std::string GetTypeName() const override {
- return "SharedMemory";
- }
-
- std::string GetName() const override {
- return name;
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
+ ResultCode Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
+ KPageLinkedList&& page_list_, Svc::MemoryPermission owner_permission_,
+ Svc::MemoryPermission user_permission_, PAddr physical_address_,
+ std::size_t size_, std::string name_);
/**
* Maps a shared memory block to an address in the target process' address space
* @param target_process Process on which to map the memory block
* @param address Address in system memory to map shared memory block to
- * @param size Size of the shared memory block to map
+ * @param map_size Size of the shared memory block to map
* @param permissions Memory block map permissions (specified by SVC field)
*/
- ResultCode Map(Process& target_process, VAddr address, std::size_t size,
- KMemoryPermission permissions);
+ ResultCode Map(KProcess& target_process, VAddr address, std::size_t map_size,
+ Svc::MemoryPermission permissions);
+
+ /**
+ * Unmaps a shared memory block from an address in the target process' address space
+ * @param target_process Process on which to unmap the memory block
+ * @param address Address in system memory to unmap shared memory block
+ * @param unmap_size Size of the shared memory block to unmap
+ */
+ ResultCode Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size);
/**
* Gets a pointer to the shared memory block
@@ -59,7 +56,7 @@ public:
* @return A pointer to the shared memory block from the specified offset
*/
u8* GetPointer(std::size_t offset = 0) {
- return device_memory.GetPointer(physical_address + offset);
+ return device_memory->GetPointer(physical_address + offset);
}
/**
@@ -68,20 +65,26 @@ public:
* @return A pointer to the shared memory block from the specified offset
*/
const u8* GetPointer(std::size_t offset = 0) const {
- return device_memory.GetPointer(physical_address + offset);
+ return device_memory->GetPointer(physical_address + offset);
}
- void Finalize() override {}
+ virtual void Finalize() override;
+
+ virtual bool IsInitialized() const override {
+ return is_initialized;
+ }
+ static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
private:
- Core::DeviceMemory& device_memory;
- Process* owner_process{};
+ Core::DeviceMemory* device_memory;
+ KProcess* owner_process{};
KPageLinkedList page_list;
- KMemoryPermission owner_permission{};
- KMemoryPermission user_permission{};
+ Svc::MemoryPermission owner_permission{};
+ Svc::MemoryPermission user_permission{};
PAddr physical_address{};
std::size_t size{};
- std::string name;
+ KResourceLimit* resource_limit{};
+ bool is_initialized{};
};
} // 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:
void FreeImpl(void* obj) {
// Don't allow freeing an object that wasn't allocated from this heap
ASSERT(Contains(reinterpret_cast<uintptr_t>(obj)));
+
impl.Free(obj);
}
@@ -148,6 +149,14 @@ public:
return obj;
}
+ T* AllocateWithKernel(KernelCore& kernel) {
+ T* obj = static_cast<T*>(AllocateImpl());
+ if (obj != nullptr) {
+ new (obj) T(kernel);
+ }
+ return obj;
+ }
+
void Free(T* obj) {
FreeImpl(obj);
}
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 @@
namespace Kernel {
-ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
+void KSynchronizationObject::Finalize() {
+ this->OnFinalizeSynchronizationObject();
+ KAutoObject::Finalize();
+}
+
+ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
KSynchronizationObject** objects, const s32 num_objects,
s64 timeout) {
// Allocate space on stack for thread nodes.
std::vector<ThreadListNode> thread_nodes(num_objects);
// Prepare for wait.
- KThread* thread = kernel.CurrentScheduler()->GetCurrentThread();
+ KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread();
{
// Setup the scheduling lock and sleep.
- KScopedSchedulerLockAndSleep slp{kernel, thread, timeout};
+ KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout};
// Check if any of the objects are already signaled.
for (auto i = 0; i < num_objects; ++i) {
@@ -89,13 +94,13 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
thread->SetWaitObjectsForDebugging({});
// Cancel the timer as needed.
- kernel.TimeManager().UnscheduleTimeEvent(thread);
+ kernel_ctx.TimeManager().UnscheduleTimeEvent(thread);
// Get the wait result.
ResultCode wait_result{RESULT_SUCCESS};
s32 sync_index = -1;
{
- KScopedSchedulerLock lock(kernel);
+ KScopedSchedulerLock lock(kernel_ctx);
KSynchronizationObject* synced_obj;
wait_result = thread->GetWaitResult(std::addressof(synced_obj));
@@ -130,10 +135,8 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
return wait_result;
}
-KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {}
-
-KSynchronizationObject::KSynchronizationObject(KernelCore& kernel, std::string&& name)
- : Object{kernel, std::move(name)} {}
+KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
+ : KAutoObjectWithList{kernel_} {}
KSynchronizationObject::~KSynchronizationObject() = default;
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 @@
#include <vector>
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -16,7 +16,9 @@ class Synchronization;
class KThread;
/// Class that represents a Kernel object that a thread can be waiting on
-class KSynchronizationObject : public Object {
+class KSynchronizationObject : public KAutoObjectWithList {
+ KERNEL_AUTOOBJECT_TRAITS(KSynchronizationObject, KAutoObject);
+
public:
struct ThreadListNode {
ThreadListNode* next{};
@@ -27,15 +29,18 @@ public:
KSynchronizationObject** objects, const s32 num_objects,
s64 timeout);
+ virtual void Finalize() override;
+
[[nodiscard]] virtual bool IsSignaled() const = 0;
[[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
protected:
explicit KSynchronizationObject(KernelCore& kernel);
- explicit KSynchronizationObject(KernelCore& kernel, std::string&& name);
virtual ~KSynchronizationObject();
+ virtual void OnFinalizeSynchronizationObject() {}
+
void NotifyAvailable(ResultCode result);
void NotifyAvailable() {
return this->NotifyAvailable(RESULT_SUCCESS);
@@ -46,14 +51,4 @@ private:
ThreadListNode* thread_list_tail{};
};
-// Specialization of DynamicObjectCast for KSynchronizationObjects
-template <>
-inline std::shared_ptr<KSynchronizationObject> DynamicObjectCast<KSynchronizationObject>(
- std::shared_ptr<Object> object) {
- if (object != nullptr && object->IsWaitable()) {
- return std::static_pointer_cast<KSynchronizationObject>(object);
- }
- return nullptr;
-}
-
} // 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 @@
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/hardware_properties.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_condition_variable.h"
+#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/hle/result.h"
@@ -61,12 +60,12 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
namespace Kernel {
-KThread::KThread(KernelCore& kernel)
- : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {}
+KThread::KThread(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {}
KThread::~KThread() = default;
ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
- s32 virt_core, Process* owner, ThreadType type) {
+ s32 virt_core, KProcess* owner, ThreadType type) {
// Assert parameters are valid.
ASSERT((type == ThreadType::Main) ||
(Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority));
@@ -177,6 +176,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
// Set parent, if relevant.
if (owner != nullptr) {
parent = owner;
+ parent->Open();
parent->IncrementThreadCount();
}
@@ -209,14 +209,56 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
}
ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
- VAddr user_stack_top, s32 prio, s32 core, Process* owner,
- ThreadType type) {
+ VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
+ ThreadType type, std::function<void(void*)>&& init_func,
+ void* init_func_parameter) {
// Initialize the thread.
R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
+ // Initialize host context.
+ thread->host_context =
+ std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter);
+
return RESULT_SUCCESS;
}
+ResultCode KThread::InitializeDummyThread(KThread* thread) {
+ return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main);
+}
+
+ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
+ return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
+ Core::CpuManager::GetIdleThreadStartFunc(),
+ system.GetCpuManager().GetStartFuncParamater());
+}
+
+ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
+ KThreadFunction func, uintptr_t arg,
+ s32 virt_core) {
+ return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
+ Core::CpuManager::GetSuspendThreadStartFunc(),
+ system.GetCpuManager().GetStartFuncParamater());
+}
+
+ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
+ KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
+ s32 prio, s32 virt_core, KProcess* owner) {
+ system.Kernel().GlobalSchedulerContext().AddThread(thread);
+ return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
+ ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
+ system.GetCpuManager().GetStartFuncParamater());
+}
+
+void KThread::PostDestroy(uintptr_t arg) {
+ KProcess* owner = reinterpret_cast<KProcess*>(arg & ~1ULL);
+ const bool resource_limit_release_hint = (arg & 1);
+ const s64 hint_value = (resource_limit_release_hint ? 0 : 1);
+ if (owner != nullptr) {
+ owner->GetResourceLimit()->Release(LimitableResource::Threads, 1, hint_value);
+ owner->Close();
+ }
+}
+
void KThread::Finalize() {
// If the thread has an owner process, unregister it.
if (parent != nullptr) {
@@ -246,8 +288,10 @@ void KThread::Finalize() {
// Decrement the parent process's thread count.
if (parent != nullptr) {
parent->DecrementThreadCount();
- parent->GetResourceLimit()->Release(LimitableResource::Threads, 1);
}
+
+ // Perform inherited finalization.
+ KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize();
}
bool KThread::IsSignaled() const {
@@ -294,6 +338,9 @@ void KThread::StartTermination() {
// Register terminated dpc flag.
RegisterDpc(DpcFlag::Terminated);
+
+ // Close the thread.
+ this->Close();
}
void KThread::Pin() {
@@ -432,7 +479,7 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m
return RESULT_SUCCESS;
}
-ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
+ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) {
ASSERT(parent != nullptr);
ASSERT(v_affinity_mask != 0);
KScopedLightLock lk{activity_pause_lock};
@@ -444,18 +491,18 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
ASSERT(num_core_migration_disables >= 0);
// If the core id is no-update magic, preserve the ideal core id.
- if (core_id == Svc::IdealCoreNoUpdate) {
- core_id = virtual_ideal_core_id;
- R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, ResultInvalidCombination);
+ if (cpu_core_id == Svc::IdealCoreNoUpdate) {
+ cpu_core_id = virtual_ideal_core_id;
+ R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination);
}
// Set the virtual core/affinity mask.
- virtual_ideal_core_id = core_id;
+ virtual_ideal_core_id = cpu_core_id;
virtual_affinity_mask = v_affinity_mask;
// Translate the virtual core to a physical core.
- if (core_id >= 0) {
- core_id = Core::Hardware::VirtualToPhysicalCoreMap[core_id];
+ if (cpu_core_id >= 0) {
+ cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id];
}
// Translate the virtual affinity mask to a physical one.
@@ -470,7 +517,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
const KAffinityMask old_mask = physical_affinity_mask;
// Set our new ideals.
- physical_ideal_core_id = core_id;
+ physical_ideal_core_id = cpu_core_id;
physical_affinity_mask.SetAffinityMask(p_affinity_mask);
if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
@@ -488,7 +535,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
}
} else {
// Otherwise, we edit the original affinity for restoration later.
- original_physical_ideal_core_id = core_id;
+ original_physical_ideal_core_id = cpu_core_id;
original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
}
}
@@ -804,8 +851,8 @@ void KThread::RemoveWaiterImpl(KThread* thread) {
thread->SetLockOwner(nullptr);
}
-void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
+ ASSERT(kernel_ctx.GlobalSchedulerContext().IsLocked());
while (true) {
// We want to inherit priority where possible.
@@ -821,7 +868,7 @@ void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
// Ensure we don't violate condition variable red black tree invariants.
if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
- BeforeUpdatePriority(kernel, cv_tree, thread);
+ BeforeUpdatePriority(kernel_ctx, cv_tree, thread);
}
// Change the priority.
@@ -830,11 +877,11 @@ void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
// Restore the condition variable, if relevant.
if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
- AfterUpdatePriority(kernel, cv_tree, thread);
+ AfterUpdatePriority(kernel_ctx, cv_tree, thread);
}
// Update the scheduler.
- KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority);
+ KScheduler::OnThreadPriorityChanged(kernel_ctx, thread, old_priority);
// Keep the lock owner up to date.
KThread* lock_owner = thread->GetLockOwner();
@@ -932,7 +979,7 @@ void KThread::Exit() {
// Release the thread resource hint from parent.
if (parent != nullptr) {
- // TODO(bunnei): Hint that the resource is about to be released.
+ parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1);
resource_limit_release_hint = true;
}
@@ -995,56 +1042,6 @@ std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
return host_context;
}
-ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(Core::System& system,
- ThreadType type_flags, std::string name,
- VAddr entry_point, u32 priority, u64 arg,
- s32 processor_id, VAddr stack_top,
- Process* owner_process) {
- auto& kernel = system.Kernel();
-
- std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
-
- if (const auto result =
- thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority,
- processor_id, owner_process, type_flags);
- result.IsError()) {
- return result;
- }
-
- thread->name = name;
-
- auto& scheduler = kernel.GlobalSchedulerContext();
- scheduler.AddThread(thread);
-
- return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
-}
-
-ResultVal<std::shared_ptr<KThread>> KThread::CreateThread(
- Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
- u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
- std::function<void(void*)>&& thread_start_func, void* thread_start_parameter) {
- auto thread_result = CreateThread(system, type_flags, name, entry_point, priority, arg,
- processor_id, stack_top, owner_process);
-
- if (thread_result.Succeeded()) {
- (*thread_result)->host_context =
- std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
- }
-
- return thread_result;
-}
-
-ResultVal<std::shared_ptr<KThread>> KThread::CreateUserThread(
- Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority,
- u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) {
- std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
-
- void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-
- return CreateThread(system, type_flags, name, entry_point, priority, arg, processor_id,
- stack_top, owner_process, std::move(init_func), init_func_parameter);
-}
-
KThread* GetCurrentThreadPointer(KernelCore& kernel) {
return kernel.GetCurrentEmuThread();
}
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 @@
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_synchronization_object.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_common.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
@@ -37,7 +37,7 @@ namespace Kernel {
class GlobalSchedulerContext;
class KernelCore;
-class Process;
+class KProcess;
class KScheduler;
class KThreadQueue;
@@ -99,15 +99,19 @@ enum class ThreadWaitReasonForDebugging : u32 {
[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
-class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
+class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>,
+ public boost::intrusive::list_base_hook<> {
+ KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
+
+private:
friend class KScheduler;
- friend class Process;
+ friend class KProcess;
public:
static constexpr s32 DefaultThreadPriority = 44;
static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
- explicit KThread(KernelCore& kernel);
+ explicit KThread(KernelCore& kernel_);
~KThread() override;
public:
@@ -115,74 +119,10 @@ public:
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
using WaiterList = boost::intrusive::list<KThread>;
- /**
- * Creates and returns a new thread.
- * @param system The instance of the whole system
- * @param name The friendly name desired for the thread
- * @param entry_point The address at which the thread should start execution
- * @param priority The thread's priority
- * @param arg User data to pass to the thread
- * @param processor_id The ID(s) of the processors on which the thread is desired to be run
- * @param stack_top The address of the thread's stack top
- * @param owner_process The parent process for the thread, if null, it's a kernel thread
- * @return A shared pointer to the newly created thread
- */
- [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
- Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
- u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
-
- /**
- * Creates and returns a new thread, with a specified entry point.
- * @param system The instance of the whole system
- * @param name The friendly name desired for the thread
- * @param entry_point The address at which the thread should start execution
- * @param priority The thread's priority
- * @param arg User data to pass to the thread
- * @param processor_id The ID(s) of the processors on which the thread is desired to be run
- * @param stack_top The address of the thread's stack top
- * @param owner_process The parent process for the thread, if null, it's a kernel thread
- * @param thread_start_func The function where the host context will start.
- * @param thread_start_parameter The parameter which will passed to host context on init
- * @return A shared pointer to the newly created thread
- */
- [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateThread(
- Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
- u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
- std::function<void(void*)>&& thread_start_func, void* thread_start_parameter);
-
- /**
- * Creates and returns a new thread for the emulated "user" process.
- * @param system The instance of the whole system
- * @param name The friendly name desired for the thread
- * @param entry_point The address at which the thread should start execution
- * @param priority The thread's priority
- * @param arg User data to pass to the thread
- * @param processor_id The ID(s) of the processors on which the thread is desired to be run
- * @param stack_top The address of the thread's stack top
- * @param owner_process The parent process for the thread, if null, it's a kernel thread
- * @return A shared pointer to the newly created thread
- */
- [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> CreateUserThread(
- Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
- u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
-
- [[nodiscard]] std::string GetName() const override {
- return name;
- }
-
void SetName(std::string new_name) {
name = std::move(new_name);
}
- [[nodiscard]] std::string GetTypeName() const override {
- return "Thread";
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::Thread;
- [[nodiscard]] HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
/**
* Gets the thread's current priority
* @return The current thread's priority
@@ -257,10 +197,6 @@ public:
void Suspend();
- void Finalize() override;
-
- bool IsSignaled() const override;
-
void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) {
synced_object = obj;
wait_result = wait_res;
@@ -354,11 +290,11 @@ public:
current_core_id = core;
}
- [[nodiscard]] Process* GetOwnerProcess() {
+ [[nodiscard]] KProcess* GetOwnerProcess() {
return parent;
}
- [[nodiscard]] const Process* GetOwnerProcess() const {
+ [[nodiscard]] const KProcess* GetOwnerProcess() const {
return parent;
}
@@ -382,7 +318,7 @@ public:
[[nodiscard]] ResultCode GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
- [[nodiscard]] ResultCode SetCoreMask(s32 core_id, u64 v_affinity_mask);
+ [[nodiscard]] ResultCode SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask);
[[nodiscard]] ResultCode SetActivity(Svc::ThreadActivity activity);
@@ -422,6 +358,40 @@ public:
return termination_requested || GetRawState() == ThreadState::Terminated;
}
+ [[nodiscard]] virtual u64 GetId() const override final {
+ return this->GetThreadID();
+ }
+
+ [[nodiscard]] virtual bool IsInitialized() const override {
+ return initialized;
+ }
+
+ [[nodiscard]] virtual uintptr_t GetPostDestroyArgument() const override {
+ return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0);
+ }
+
+ virtual void Finalize() override;
+
+ [[nodiscard]] virtual bool IsSignaled() const override;
+
+ static void PostDestroy(uintptr_t arg);
+
+ [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread);
+
+ [[nodiscard]] static ResultCode InitializeIdleThread(Core::System& system, KThread* thread,
+ s32 virt_core);
+
+ [[nodiscard]] static ResultCode InitializeHighPriorityThread(Core::System& system,
+ KThread* thread,
+ KThreadFunction func,
+ uintptr_t arg, s32 virt_core);
+
+ [[nodiscard]] static ResultCode InitializeUserThread(Core::System& system, KThread* thread,
+ KThreadFunction func, uintptr_t arg,
+ VAddr user_stack_top, s32 prio,
+ s32 virt_core, KProcess* owner);
+
+public:
struct StackParameters {
u8 svc_permission[0x10];
std::atomic<u8> dpc_flags;
@@ -671,13 +641,15 @@ private:
void StartTermination();
[[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
- s32 prio, s32 virt_core, Process* owner, ThreadType type);
+ s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
[[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func,
uintptr_t arg, VAddr user_stack_top, s32 prio,
- s32 core, Process* owner, ThreadType type);
+ s32 core, KProcess* owner, ThreadType type,
+ std::function<void(void*)>&& init_func,
+ void* init_func_parameter);
- static void RestorePriority(KernelCore& kernel, KThread* thread);
+ static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
// For core KThread implementation
ThreadContext32 thread_context_32{};
@@ -697,7 +669,7 @@ private:
std::atomic<s64> cpu_time{};
KSynchronizationObject* synced_object{};
VAddr address_key{};
- Process* parent{};
+ KProcess* parent{};
VAddr kernel_stack_top{};
u32* light_ipc_data{};
VAddr tls_address{};
@@ -742,7 +714,6 @@ private:
VAddr mutex_wait_address_for_debugging{};
ThreadWaitReasonForDebugging wait_reason_for_debugging{};
ThreadType thread_type_for_debugging{};
- std::string name;
public:
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 {
class KThreadQueue {
public:
- explicit KThreadQueue(KernelCore& kernel) : kernel{kernel} {}
+ explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
bool IsEmpty() const {
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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+KTransferMemory::KTransferMemory(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+
+KTransferMemory::~KTransferMemory() = default;
+
+ResultCode KTransferMemory::Initialize(VAddr address_, std::size_t size_,
+ Svc::MemoryPermission owner_perm_) {
+ // Set members.
+ owner = kernel.CurrentProcess();
+
+ // TODO(bunnei): Lock for transfer memory
+
+ // Set remaining tracking members.
+ owner->Open();
+ owner_perm = owner_perm_;
+ address = address_;
+ size = size_;
+ is_initialized = true;
+
+ return RESULT_SUCCESS;
+}
+
+void KTransferMemory::Finalize() {
+ // Perform inherited finalization.
+ KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList>::Finalize();
+}
+
+void KTransferMemory::PostDestroy(uintptr_t arg) {
+ KProcess* owner = reinterpret_cast<KProcess*>(arg);
+ owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
+ owner->Close();
+}
+
+} // 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 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/kernel/svc_types.h"
+#include "core/hle/result.h"
+
+union ResultCode;
+
+namespace Core::Memory {
+class Memory;
+}
+
+namespace Kernel {
+
+class KernelCore;
+class KProcess;
+
+class KTransferMemory final
+ : public KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject);
+
+public:
+ explicit KTransferMemory(KernelCore& kernel_);
+ virtual ~KTransferMemory() override;
+
+ ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
+
+ virtual void Finalize() override;
+
+ virtual bool IsInitialized() const override {
+ return is_initialized;
+ }
+
+ virtual uintptr_t GetPostDestroyArgument() const override {
+ return reinterpret_cast<uintptr_t>(owner);
+ }
+
+ static void PostDestroy(uintptr_t arg);
+
+ KProcess* GetOwner() const {
+ return owner;
+ }
+
+ VAddr GetSourceAddress() const {
+ return address;
+ }
+
+ size_t GetSize() const {
+ return is_initialized ? size : 0;
+ }
+
+private:
+ KProcess* owner{};
+ VAddr address{};
+ Svc::MemoryPermission owner_perm{};
+ size_t size{};
+ bool is_initialized{};
+};
+
+} // 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 @@
namespace Kernel {
-KWritableEvent::KWritableEvent(KernelCore& kernel, std::string&& name)
- : Object{kernel, std::move(name)} {}
+KWritableEvent::KWritableEvent(KernelCore& kernel_)
+ : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+
KWritableEvent::~KWritableEvent() = default;
-void KWritableEvent::Initialize(KEvent* parent_) {
+void KWritableEvent::Initialize(KEvent* parent_, std::string&& name_) {
parent = parent_;
+ name = std::move(name_);
+ parent->GetReadableEvent().Open();
}
ResultCode KWritableEvent::Signal() {
- return parent->GetReadableEvent()->Signal();
+ return parent->GetReadableEvent().Signal();
}
ResultCode KWritableEvent::Clear() {
- return parent->GetReadableEvent()->Clear();
+ return parent->GetReadableEvent().Clear();
+}
+
+void KWritableEvent::Destroy() {
+ // Close our references.
+ parent->GetReadableEvent().Close();
+ parent->Close();
}
} // 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 @@
#pragma once
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -12,24 +13,19 @@ namespace Kernel {
class KernelCore;
class KEvent;
-class KWritableEvent final : public Object {
+class KWritableEvent final
+ : public KAutoObjectWithSlabHeapAndContainer<KWritableEvent, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KWritableEvent, KAutoObject);
+
public:
- explicit KWritableEvent(KernelCore& kernel, std::string&& name);
+ explicit KWritableEvent(KernelCore& kernel_);
~KWritableEvent() override;
- std::string GetTypeName() const override {
- return "KWritableEvent";
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::WritableEvent;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- void Initialize(KEvent* parent_);
+ virtual void Destroy() override;
- void Finalize() override {}
+ static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ void Initialize(KEvent* parent_, std::string&& name_);
ResultCode Signal();
ResultCode Clear();
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 @@
#include "core/cpu_manager.h"
#include "core/device_memory.h"
#include "core/hardware_properties.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/init/init_slab_setup.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_shared_memory.h"
@@ -37,12 +39,12 @@
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/service_thread.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/time_manager.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
+#include "core/hle/service/sm/sm.h"
#include "core/memory.h"
MICROPROFILE_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));
namespace Kernel {
struct KernelCore::Impl {
- explicit Impl(Core::System& system, KernelCore& kernel)
- : time_manager{system}, global_handle_table{kernel}, system{system} {}
+ explicit Impl(Core::System& system_, KernelCore& kernel_)
+ : time_manager{system_}, object_list_container{kernel_}, system{system_} {}
- void SetMulticore(bool is_multicore) {
- this->is_multicore = is_multicore;
+ void SetMulticore(bool is_multi) {
+ is_multicore = is_multi;
}
void Initialize(KernelCore& kernel) {
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
-
- RegisterHostThread();
+ global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
service_thread_manager =
std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
@@ -69,14 +70,20 @@ struct KernelCore::Impl {
InitializePhysicalCores();
// Derive the initial memory layout from the emulated board
+ Init::InitializeSlabResourceCounts(kernel);
KMemoryLayout memory_layout;
DeriveInitialMemoryLayout(memory_layout);
- InitializeMemoryLayout(memory_layout);
+ Init::InitializeSlabHeaps(system, memory_layout);
+
+ // Initialize kernel memory and resources.
InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
- InitializeSlabHeaps();
+ InitializeMemoryLayout(memory_layout);
+ InitializePageSlab();
InitializeSchedulers();
InitializeSuspendThreads();
InitializePreemption(kernel);
+
+ RegisterHostThread();
}
void InitializeCores() {
@@ -93,34 +100,49 @@ struct KernelCore::Impl {
service_threads.clear();
next_object_id = 0;
- next_kernel_process_id = Process::InitialKIPIDMin;
- next_user_process_id = Process::ProcessIDMin;
+ next_kernel_process_id = KProcess::InitialKIPIDMin;
+ next_user_process_id = KProcess::ProcessIDMin;
next_thread_id = 1;
- for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
- if (suspend_threads[i]) {
- suspend_threads[i].reset();
+ for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
+ if (suspend_threads[core_id]) {
+ suspend_threads[core_id]->Close();
+ suspend_threads[core_id] = nullptr;
}
+
+ schedulers[core_id].reset();
}
cores.clear();
- current_process = nullptr;
+ if (current_process) {
+ current_process->Close();
+ current_process = nullptr;
+ }
- global_handle_table.Clear();
+ global_handle_table.reset();
preemption_event = nullptr;
+ for (auto& iter : named_ports) {
+ iter.second->Close();
+ }
named_ports.clear();
exclusive_monitor.reset();
- hid_shared_mem = nullptr;
- font_shared_mem = nullptr;
- irs_shared_mem = nullptr;
- time_shared_mem = nullptr;
-
- system_resource_limit = nullptr;
+ // Cleanup persistent kernel objects
+ auto CleanupObject = [](KAutoObject* obj) {
+ if (obj) {
+ obj->Close();
+ obj = nullptr;
+ }
+ };
+ CleanupObject(hid_shared_mem);
+ CleanupObject(font_shared_mem);
+ CleanupObject(irs_shared_mem);
+ CleanupObject(time_shared_mem);
+ CleanupObject(system_resource_limit);
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
@@ -145,7 +167,9 @@ struct KernelCore::Impl {
void InitializeSystemResourceLimit(KernelCore& kernel,
const Core::Timing::CoreTiming& core_timing,
const KMemoryLayout& memory_layout) {
- system_resource_limit = std::make_shared<KResourceLimit>(kernel, core_timing);
+ system_resource_limit = KResourceLimit::Create(system.Kernel());
+ system_resource_limit->Initialize(&core_timing);
+
const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
// If setting the default system values fails, then something seriously wrong has occurred.
@@ -189,19 +213,16 @@ struct KernelCore::Impl {
}
void InitializeSuspendThreads() {
- for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
- std::string name = "Suspend Thread Id:" + std::to_string(i);
- std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
- void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
- auto thread_res = KThread::CreateThread(
- system, ThreadType::HighPriority, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
- nullptr, std::move(init_func), init_func_parameter);
-
- suspend_threads[i] = std::move(thread_res).Unwrap();
+ for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
+ suspend_threads[core_id] = KThread::Create(system.Kernel());
+ ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {},
+ core_id)
+ .IsSuccess());
+ suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
}
}
- void MakeCurrentProcess(Process* process) {
+ void MakeCurrentProcess(KProcess* process) {
current_process = process;
if (process == nullptr) {
return;
@@ -232,11 +253,15 @@ struct KernelCore::Impl {
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
KThread* GetHostDummyThread() {
- const thread_local auto thread =
- KThread::CreateThread(
- system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0,
- KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr)
- .Unwrap();
+ auto make_thread = [this]() {
+ std::unique_ptr<KThread> thread = std::make_unique<KThread>(system.Kernel());
+ KAutoObject::Create(thread.get());
+ ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess());
+ thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
+ return std::move(thread);
+ };
+
+ thread_local auto thread = make_thread();
return thread.get();
}
@@ -371,7 +396,8 @@ struct KernelCore::Impl {
const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
// Determine the size of the slab region.
- const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
+ const size_t slab_region_size =
+ Common::AlignUp(Init::CalculateTotalSlabHeapSize(system.Kernel()), PageSize);
ASSERT(slab_region_size <= resource_region_size);
// Setup the slab region.
@@ -569,25 +595,30 @@ struct KernelCore::Impl {
const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
- hid_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
- "HID:SharedMemory");
- font_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
- "Font:SharedMemory");
- irs_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
- "IRS:SharedMemory");
- time_shared_mem = Kernel::KSharedMemory::Create(
- system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
- KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
- "Time:SharedMemory");
+ hid_shared_mem = KSharedMemory::Create(system.Kernel());
+ font_shared_mem = KSharedMemory::Create(system.Kernel());
+ irs_shared_mem = KSharedMemory::Create(system.Kernel());
+ time_shared_mem = KSharedMemory::Create(system.Kernel());
+
+ hid_shared_mem->Initialize(system.DeviceMemory(), nullptr,
+ {hid_phys_addr, hid_size / PageSize},
+ Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
+ hid_phys_addr, hid_size, "HID:SharedMemory");
+ font_shared_mem->Initialize(system.DeviceMemory(), nullptr,
+ {font_phys_addr, font_size / PageSize},
+ Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
+ font_phys_addr, font_size, "Font:SharedMemory");
+ irs_shared_mem->Initialize(system.DeviceMemory(), nullptr,
+ {irs_phys_addr, irs_size / PageSize},
+ Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
+ irs_phys_addr, irs_size, "IRS:SharedMemory");
+ time_shared_mem->Initialize(system.DeviceMemory(), nullptr,
+ {time_phys_addr, time_size / PageSize},
+ Svc::MemoryPermission::None, Svc::MemoryPermission::Read,
+ time_phys_addr, time_size, "Time:SharedMemory");
}
- void InitializeSlabHeaps() {
+ void InitializePageSlab() {
// Allocate slab heaps
user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
@@ -596,33 +627,37 @@ struct KernelCore::Impl {
// Reserve slab heaps
ASSERT(
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));
- // Initialize slab heaps
+ // Initialize slab heap
user_slab_heap_pages->Initialize(
system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase),
user_slab_heap_size);
}
std::atomic<u32> next_object_id{0};
- std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
- std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
+ std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin};
+ std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin};
std::atomic<u64> next_thread_id{1};
// Lists all processes that exist in the current session.
- std::vector<std::shared_ptr<Process>> process_list;
- Process* current_process = nullptr;
+ std::vector<KProcess*> process_list;
+ KProcess* current_process{};
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
Kernel::TimeManager time_manager;
- std::shared_ptr<KResourceLimit> system_resource_limit;
+ Init::KSlabResourceCounts slab_resource_counts{};
+ KResourceLimit* system_resource_limit{};
std::shared_ptr<Core::Timing::EventType> preemption_event;
// This is the kernel's handle table or supervisor handle table which
// stores all the objects in place.
- HandleTable global_handle_table;
+ std::unique_ptr<KHandleTable> global_handle_table;
+
+ KAutoObjectWithListContainer object_list_container;
/// Map of named ports managed by the kernel, which can be retrieved using
/// the ConnectToPort SVC.
+ std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
NamedPortTable named_ports;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
@@ -636,10 +671,10 @@ struct KernelCore::Impl {
std::unique_ptr<KSlabHeap<Page>> user_slab_heap_pages;
// Shared memory for services
- std::shared_ptr<Kernel::KSharedMemory> hid_shared_mem;
- std::shared_ptr<Kernel::KSharedMemory> font_shared_mem;
- std::shared_ptr<Kernel::KSharedMemory> irs_shared_mem;
- std::shared_ptr<Kernel::KSharedMemory> time_shared_mem;
+ Kernel::KSharedMemory* hid_shared_mem{};
+ Kernel::KSharedMemory* font_shared_mem{};
+ Kernel::KSharedMemory* irs_shared_mem{};
+ Kernel::KSharedMemory* time_shared_mem{};
// Threads used for services
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
@@ -648,7 +683,7 @@ struct KernelCore::Impl {
// the release of itself
std::unique_ptr<Common::ThreadWorker> service_thread_manager;
- std::array<std::shared_ptr<KThread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
+ std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@@ -663,15 +698,14 @@ struct KernelCore::Impl {
};
KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
-KernelCore::~KernelCore() {
- Shutdown();
-}
+KernelCore::~KernelCore() = default;
void KernelCore::SetMulticore(bool is_multicore) {
impl->SetMulticore(is_multicore);
}
void KernelCore::Initialize() {
+ slab_heap_container = std::make_unique<SlabHeapContainer>();
impl->Initialize(*this);
}
@@ -683,31 +717,35 @@ void KernelCore::Shutdown() {
impl->Shutdown();
}
-std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
+const KResourceLimit* KernelCore::GetSystemResourceLimit() const {
+ return impl->system_resource_limit;
+}
+
+KResourceLimit* KernelCore::GetSystemResourceLimit() {
return impl->system_resource_limit;
}
-std::shared_ptr<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
- return impl->global_handle_table.Get<KThread>(handle);
+KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
+ return impl->global_handle_table->GetObject<KThread>(handle);
}
-void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
- impl->process_list.push_back(std::move(process));
+void KernelCore::AppendNewProcess(KProcess* process) {
+ impl->process_list.push_back(process);
}
-void KernelCore::MakeCurrentProcess(Process* process) {
+void KernelCore::MakeCurrentProcess(KProcess* process) {
impl->MakeCurrentProcess(process);
}
-Process* KernelCore::CurrentProcess() {
+KProcess* KernelCore::CurrentProcess() {
return impl->current_process;
}
-const Process* KernelCore::CurrentProcess() const {
+const KProcess* KernelCore::CurrentProcess() const {
return impl->current_process;
}
-const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const {
+const std::vector<KProcess*>& KernelCore::GetProcessList() const {
return impl->process_list;
}
@@ -781,6 +819,14 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
return *impl->exclusive_monitor;
}
+KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
+ return impl->object_list_container;
+}
+
+const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
+ return impl->object_list_container;
+}
+
void KernelCore::InvalidateAllInstructionCaches() {
for (auto& physical_core : impl->cores) {
physical_core.ArmInterface().ClearInstructionCache();
@@ -800,17 +846,17 @@ void KernelCore::PrepareReschedule(std::size_t id) {
// TODO: Reimplement, this
}
-void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
- impl->named_ports.emplace(std::move(name), std::move(port));
+void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) {
+ impl->service_interface_factory.emplace(std::move(name), factory);
}
-KernelCore::NamedPortTable::iterator KernelCore::FindNamedPort(const std::string& name) {
- return impl->named_ports.find(name);
-}
-
-KernelCore::NamedPortTable::const_iterator KernelCore::FindNamedPort(
- const std::string& name) const {
- return impl->named_ports.find(name);
+KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
+ auto search = impl->service_interface_factory.find(name);
+ if (search == impl->service_interface_factory.end()) {
+ UNIMPLEMENTED();
+ return {};
+ }
+ return &search->second(impl->system.ServiceManager(), impl->system);
}
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
@@ -833,12 +879,12 @@ u64 KernelCore::CreateNewUserProcessID() {
return impl->next_user_process_id++;
}
-Kernel::HandleTable& KernelCore::GlobalHandleTable() {
- return impl->global_handle_table;
+KHandleTable& KernelCore::GlobalHandleTable() {
+ return *impl->global_handle_table;
}
-const Kernel::HandleTable& KernelCore::GlobalHandleTable() const {
- return impl->global_handle_table;
+const KHandleTable& KernelCore::GlobalHandleTable() const {
+ return *impl->global_handle_table;
}
void KernelCore::RegisterCoreThread(std::size_t core_id) {
@@ -910,9 +956,9 @@ void KernelCore::Suspend(bool in_suspention) {
{
KScopedSchedulerLock lock(*this);
const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting;
- for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
- impl->suspend_threads[i]->SetState(state);
- impl->suspend_threads[i]->SetWaitReasonForDebugging(
+ for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
+ impl->suspend_threads[core_id]->SetState(state);
+ impl->suspend_threads[core_id]->SetWaitReasonForDebugging(
ThreadWaitReasonForDebugging::Suspended);
}
}
@@ -952,6 +998,14 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi
});
}
+Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
+ return impl->slab_resource_counts;
+}
+
+const Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() const {
+ return impl->slab_resource_counts;
+}
+
bool KernelCore::IsPhantomModeForSingleCore() const {
return impl->IsPhantomModeForSingleCore();
}
@@ -960,4 +1014,12 @@ void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
impl->SetIsPhantomModeForSingleCore(value);
}
+Core::System& KernelCore::System() {
+ return impl->system;
+}
+
+const Core::System& KernelCore::System() const {
+ return impl->system;
+}
+
} // 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 @@
#include <vector>
#include "core/arm/cpu_interrupt_handler.h"
#include "core/hardware_properties.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_slab_heap.h"
#include "core/hle/kernel/memory_types.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/svc_common.h"
namespace Core {
class CPUInterruptHandler;
@@ -25,22 +27,41 @@ class CoreTiming;
struct EventType;
} // namespace Core::Timing
+namespace Service::SM {
+class ServiceManager;
+}
+
namespace Kernel {
-class ClientPort;
+class KClientPort;
class GlobalSchedulerContext;
-class HandleTable;
+class KAutoObjectWithListContainer;
+class KClientSession;
+class KEvent;
+class KHandleTable;
+class KLinkedListNode;
class KMemoryManager;
+class KPort;
+class KProcess;
class KResourceLimit;
class KScheduler;
+class KSession;
class KSharedMemory;
class KThread;
+class KTransferMemory;
+class KWritableEvent;
class PhysicalCore;
-class Process;
class ServiceThread;
class Synchronization;
class TimeManager;
+using ServiceInterfaceFactory =
+ std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
+
+namespace Init {
+struct KSlabResourceCounts;
+}
+
template <typename T>
class KSlabHeap;
@@ -51,7 +72,7 @@ constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
/// Represents a single instance of the kernel.
class KernelCore {
private:
- using NamedPortTable = std::unordered_map<std::string, std::shared_ptr<ClientPort>>;
+ using NamedPortTable = std::unordered_map<std::string, KClientPort*>;
public:
/// Constructs an instance of the kernel using the given System
@@ -83,25 +104,28 @@ public:
void Shutdown();
/// Retrieves a shared pointer to the system resource limit instance.
- std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const;
+ const KResourceLimit* GetSystemResourceLimit() const;
+
+ /// Retrieves a shared pointer to the system resource limit instance.
+ KResourceLimit* GetSystemResourceLimit();
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
- std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
+ KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes.
- void AppendNewProcess(std::shared_ptr<Process> process);
+ void AppendNewProcess(KProcess* process);
/// Makes the given process the new current process.
- void MakeCurrentProcess(Process* process);
+ void MakeCurrentProcess(KProcess* process);
/// Retrieves a pointer to the current process.
- Process* CurrentProcess();
+ KProcess* CurrentProcess();
/// Retrieves a const pointer to the current process.
- const Process* CurrentProcess() const;
+ const KProcess* CurrentProcess() const;
/// Retrieves the list of processes.
- const std::vector<std::shared_ptr<Process>>& GetProcessList() const;
+ const std::vector<KProcess*>& GetProcessList() const;
/// Gets the sole instance of the global scheduler
Kernel::GlobalSchedulerContext& GlobalSchedulerContext();
@@ -143,6 +167,10 @@ public:
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
+ KAutoObjectWithListContainer& ObjectListContainer();
+
+ const KAutoObjectWithListContainer& ObjectListContainer() const;
+
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts();
const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
@@ -151,14 +179,11 @@ public:
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
- /// Adds a port to the named port table
- void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
-
- /// Finds a port within the named port table with the given name.
- NamedPortTable::iterator FindNamedPort(const std::string& name);
+ /// Registers a named HLE service, passing a factory used to open a port to that service.
+ void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
- /// Finds a port within the named port table with the given name.
- NamedPortTable::const_iterator FindNamedPort(const std::string& name) const;
+ /// Opens a port to a service previously registered with RegisterNamedService.
+ KClientPort* CreateNamedServicePort(std::string name);
/// Determines whether or not the given port is a valid named port.
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
@@ -225,9 +250,10 @@ public:
/**
* Creates an HLE service thread, which are used to execute service routines asynchronously.
- * While these are allocated per ServerSession, these need to be owned and managed outside of
- * ServerSession to avoid a circular dependency.
- * @param name String name for the ServerSession creating this thread, used for debug purposes.
+ * While these are allocated per ServerSession, these need to be owned and managed outside
+ * of ServerSession to avoid a circular dependency.
+ * @param name String name for the ServerSession creating this thread, used for debug
+ * purposes.
* @returns The a weak pointer newly created service thread.
*/
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
@@ -243,9 +269,45 @@ public:
bool IsPhantomModeForSingleCore() const;
void SetIsPhantomModeForSingleCore(bool value);
+ Core::System& System();
+ const Core::System& System() const;
+
+ /// Gets the slab heap for the specified kernel object type.
+ template <typename T>
+ KSlabHeap<T>& SlabHeap() {
+ if constexpr (std::is_same_v<T, KClientSession>) {
+ return slab_heap_container->client_session;
+ } else if constexpr (std::is_same_v<T, KEvent>) {
+ return slab_heap_container->event;
+ } else if constexpr (std::is_same_v<T, KLinkedListNode>) {
+ return slab_heap_container->linked_list_node;
+ } else if constexpr (std::is_same_v<T, KPort>) {
+ return slab_heap_container->port;
+ } else if constexpr (std::is_same_v<T, KProcess>) {
+ return slab_heap_container->process;
+ } else if constexpr (std::is_same_v<T, KResourceLimit>) {
+ return slab_heap_container->resource_limit;
+ } else if constexpr (std::is_same_v<T, KSession>) {
+ return slab_heap_container->session;
+ } else if constexpr (std::is_same_v<T, KSharedMemory>) {
+ return slab_heap_container->shared_memory;
+ } else if constexpr (std::is_same_v<T, KThread>) {
+ return slab_heap_container->thread;
+ } else if constexpr (std::is_same_v<T, KTransferMemory>) {
+ return slab_heap_container->transfer_memory;
+ } else if constexpr (std::is_same_v<T, KWritableEvent>) {
+ return slab_heap_container->writeable_event;
+ }
+ }
+
+ /// Gets the current slab resource counts.
+ Init::KSlabResourceCounts& SlabResourceCounts();
+
+ /// Gets the current slab resource counts.
+ const Init::KSlabResourceCounts& SlabResourceCounts() const;
+
private:
- friend class Object;
- friend class Process;
+ friend class KProcess;
friend class KThread;
/// Creates a new object ID, incrementing the internal object ID counter.
@@ -261,14 +323,33 @@ private:
u64 CreateNewThreadID();
/// Provides a reference to the global handle table.
- Kernel::HandleTable& GlobalHandleTable();
+ KHandleTable& GlobalHandleTable();
/// Provides a const reference to the global handle table.
- const Kernel::HandleTable& GlobalHandleTable() const;
+ const KHandleTable& GlobalHandleTable() const;
struct Impl;
std::unique_ptr<Impl> impl;
+
bool exception_exited{};
+
+private:
+ /// Helper to encapsulate all slab heaps in a single heap allocated container
+ struct SlabHeapContainer {
+ KSlabHeap<KClientSession> client_session;
+ KSlabHeap<KEvent> event;
+ KSlabHeap<KLinkedListNode> linked_list_node;
+ KSlabHeap<KPort> port;
+ KSlabHeap<KProcess> process;
+ KSlabHeap<KResourceLimit> resource_limit;
+ KSlabHeap<KSession> session;
+ KSlabHeap<KSharedMemory> shared_memory;
+ KSlabHeap<KThread> thread;
+ KSlabHeap<KTransferMemory> transfer_memory;
+ KSlabHeap<KWritableEvent> writeable_event;
+ };
+
+ std::unique_ptr<SlabHeapContainer> slab_heap_container;
};
} // 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 @@
-// Copyright 2018 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/assert.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/object.h"
-
-namespace Kernel {
-
-Object::Object(KernelCore& kernel_)
- : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{"[UNKNOWN KERNEL OBJECT]"} {}
-Object::Object(KernelCore& kernel_, std::string&& name_)
- : kernel{kernel_}, object_id{kernel_.CreateNewObjectID()}, name{std::move(name_)} {}
-Object::~Object() = default;
-
-bool Object::IsWaitable() const {
- switch (GetHandleType()) {
- case HandleType::ReadableEvent:
- case HandleType::Thread:
- case HandleType::Process:
- case HandleType::ServerPort:
- case HandleType::ServerSession:
- return true;
-
- case HandleType::Unknown:
- case HandleType::Event:
- case HandleType::WritableEvent:
- case HandleType::SharedMemory:
- case HandleType::TransferMemory:
- case HandleType::ResourceLimit:
- case HandleType::ClientPort:
- case HandleType::ClientSession:
- case HandleType::Session:
- return false;
- }
-
- UNREACHABLE();
- return false;
-}
-
-} // 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 @@
-// Copyright 2018 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <atomic>
-#include <memory>
-#include <string>
-
-#include "common/common_types.h"
-
-namespace Kernel {
-
-class KernelCore;
-
-using Handle = u32;
-
-enum class HandleType : u32 {
- Unknown,
- Event,
- WritableEvent,
- ReadableEvent,
- SharedMemory,
- TransferMemory,
- Thread,
- Process,
- ResourceLimit,
- ClientPort,
- ServerPort,
- ClientSession,
- ServerSession,
- Session,
-};
-
-class Object : NonCopyable, public std::enable_shared_from_this<Object> {
-public:
- explicit Object(KernelCore& kernel_);
- explicit Object(KernelCore& kernel_, std::string&& name_);
- virtual ~Object();
-
- /// Returns a unique identifier for the object. For debugging purposes only.
- u32 GetObjectId() const {
- return object_id.load(std::memory_order_relaxed);
- }
-
- virtual std::string GetTypeName() const {
- return "[BAD KERNEL OBJECT TYPE]";
- }
- virtual std::string GetName() const {
- return name;
- }
- virtual HandleType GetHandleType() const = 0;
-
- void Close() {
- // TODO(bunnei): This is a placeholder to decrement the reference count, which we will use
- // when we implement KAutoObject instead of using shared_ptr.
- }
-
- /**
- * Check if a thread can wait on the object
- * @return True if a thread can wait on the object, otherwise false
- */
- bool IsWaitable() const;
-
- virtual void Finalize() = 0;
-
-protected:
- /// The kernel instance this object was created under.
- KernelCore& kernel;
-
-private:
- std::atomic<u32> object_id{0};
- std::string name;
-};
-
-template <typename T>
-std::shared_ptr<T> SharedFrom(T* raw) {
- if (raw == nullptr)
- return nullptr;
- return std::static_pointer_cast<T>(raw->shared_from_this());
-}
-
-/**
- * Attempts to downcast the given Object pointer to a pointer to T.
- * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
- */
-template <typename T>
-inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
- if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
- return std::static_pointer_cast<T>(object);
- }
- return nullptr;
-}
-
-} // 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 @@
namespace Kernel {
-PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system,
- Kernel::KScheduler& scheduler, Core::CPUInterrupts& interrupts)
- : core_index{core_index}, system{system}, scheduler{scheduler},
- interrupts{interrupts}, guard{std::make_unique<Common::SpinLock>()} {}
+PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
+ Core::CPUInterrupts& interrupts_)
+ : core_index{core_index_}, system{system_}, scheduler{scheduler_},
+ interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {}
PhysicalCore::~PhysicalCore() = default;
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 {
class PhysicalCore {
public:
- PhysicalCore(std::size_t core_index, Core::System& system, Kernel::KScheduler& scheduler,
- Core::CPUInterrupts& interrupts);
+ PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
+ Core::CPUInterrupts& interrupts_);
~PhysicalCore();
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 @@
#include "common/bit_util.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/svc_results.h"
@@ -99,7 +99,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() {
interrupt_capabilities.set();
// Allow using the maximum possible amount of handles
- handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT);
+ handle_table_size = static_cast<s32>(KHandleTable::MaxTableSize);
// Allow all debugging capabilities.
is_debuggable = true;
@@ -159,7 +159,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
const auto type = GetCapabilityType(flag);
if (type == CapabilityType::Unset) {
- return ResultInvalidCapabilityDescriptor;
+ return ResultInvalidArgument;
}
// Bail early on ignorable entries, as one would expect,
@@ -202,7 +202,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
}
LOG_ERROR(Kernel, "Invalid capability type! type={}", type);
- return ResultInvalidCapabilityDescriptor;
+ return ResultInvalidArgument;
}
void ProcessCapabilities::Clear() {
@@ -225,7 +225,7 @@ ResultCode ProcessCapabilities::HandlePriorityCoreNumFlags(u32 flags) {
if (priority_mask != 0 || core_mask != 0) {
LOG_ERROR(Kernel, "Core or priority mask are not zero! priority_mask={}, core_mask={}",
priority_mask, core_mask);
- return ResultInvalidCapabilityDescriptor;
+ return ResultInvalidArgument;
}
const u32 core_num_min = (flags >> 16) & 0xFF;
@@ -329,7 +329,7 @@ ResultCode ProcessCapabilities::HandleProgramTypeFlags(u32 flags) {
const u32 reserved = flags >> 17;
if (reserved != 0) {
LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
- return ResultReservedValue;
+ return ResultReservedUsed;
}
program_type = static_cast<ProgramType>((flags >> 14) & 0b111);
@@ -349,7 +349,7 @@ ResultCode ProcessCapabilities::HandleKernelVersionFlags(u32 flags) {
LOG_ERROR(Kernel,
"Kernel version is non zero or flags are too small! major_version={}, flags={}",
major_version, flags);
- return ResultInvalidCapabilityDescriptor;
+ return ResultInvalidArgument;
}
kernel_version = flags;
@@ -360,7 +360,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
const u32 reserved = flags >> 26;
if (reserved != 0) {
LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
- return ResultReservedValue;
+ return ResultReservedUsed;
}
handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);
@@ -371,7 +371,7 @@ ResultCode ProcessCapabilities::HandleDebugFlags(u32 flags) {
const u32 reserved = flags >> 19;
if (reserved != 0) {
LOG_ERROR(Kernel, "Reserved value is non-zero! reserved={}", reserved);
- return ResultReservedValue;
+ return ResultReservedUsed;
}
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 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <tuple>
-#include "common/assert.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/server_port.h"
-#include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/svc_results.h"
-
-namespace Kernel {
-
-ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
-ServerPort::~ServerPort() = default;
-
-ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
- if (pending_sessions.empty()) {
- return ResultNotFound;
- }
-
- auto session = std::move(pending_sessions.back());
- pending_sessions.pop_back();
- return MakeResult(std::move(session));
-}
-
-void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) {
- pending_sessions.push_back(std::move(pending_session));
- if (pending_sessions.size() == 1) {
- NotifyAvailable();
- }
-}
-
-bool ServerPort::IsSignaled() const {
- return !pending_sessions.empty();
-}
-
-ServerPort::PortPair ServerPort::CreatePortPair(KernelCore& kernel, u32 max_sessions,
- std::string name) {
- std::shared_ptr<ServerPort> server_port = std::make_shared<ServerPort>(kernel);
- std::shared_ptr<ClientPort> client_port = std::make_shared<ClientPort>(kernel);
-
- server_port->name = name + "_Server";
- client_port->name = name + "_Client";
- client_port->server_port = server_port;
- client_port->max_sessions = max_sessions;
- client_port->active_sessions = 0;
-
- return std::make_pair(std::move(server_port), std::move(client_port));
-}
-
-} // 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 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-#include "common/common_types.h"
-#include "core/hle/kernel/k_synchronization_object.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/result.h"
-
-namespace Kernel {
-
-class ClientPort;
-class KernelCore;
-class ServerSession;
-class SessionRequestHandler;
-
-class ServerPort final : public KSynchronizationObject {
-public:
- explicit ServerPort(KernelCore& kernel);
- ~ServerPort() override;
-
- using HLEHandler = std::shared_ptr<SessionRequestHandler>;
- using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
-
- /**
- * Creates a pair of ServerPort and an associated ClientPort.
- *
- * @param kernel The kernel instance to create the port pair under.
- * @param max_sessions Maximum number of sessions to the port
- * @param name Optional name of the ports
- * @return The created port tuple
- */
- static PortPair CreatePortPair(KernelCore& kernel, u32 max_sessions,
- std::string name = "UnknownPort");
-
- std::string GetTypeName() const override {
- return "ServerPort";
- }
- std::string GetName() const override {
- return name;
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::ServerPort;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- /**
- * Accepts a pending incoming connection on this port. If there are no pending sessions, will
- * return ERR_NO_PENDING_SESSIONS.
- */
- ResultVal<std::shared_ptr<ServerSession>> Accept();
-
- /// Whether or not this server port has an HLE handler available.
- bool HasHLEHandler() const {
- return hle_handler != nullptr;
- }
-
- /// Gets the HLE handler for this port.
- HLEHandler GetHLEHandler() const {
- return hle_handler;
- }
-
- /**
- * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
- * will inherit a reference to this handler.
- */
- void SetHleHandler(HLEHandler hle_handler_) {
- hle_handler = std::move(hle_handler_);
- }
-
- /// Appends a ServerSession to the collection of ServerSessions
- /// waiting to be accepted by this port.
- void AppendPendingSession(std::shared_ptr<ServerSession> pending_session);
-
- bool IsSignaled() const override;
-
- void Finalize() override {}
-
-private:
- /// ServerSessions waiting to be accepted by the port
- std::vector<std::shared_ptr<ServerSession>> pending_sessions;
-
- /// This session's HLE request handler template (optional)
- /// ServerSessions created from this port inherit a reference to this handler.
- HLEHandler hle_handler;
-
- /// Name of the port (optional)
- std::string name;
-};
-
-} // 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 @@
#include "common/scope_exit.h"
#include "common/thread.h"
#include "core/core.h"
+#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/service_thread.h"
#include "core/hle/lock.h"
#include "video_core/renderer_base.h"
@@ -26,7 +26,7 @@ public:
explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
~Impl();
- void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
+ void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
private:
std::vector<std::thread> threads;
@@ -69,18 +69,27 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
});
}
-void ServiceThread::Impl::QueueSyncRequest(ServerSession& session,
+void ServiceThread::Impl::QueueSyncRequest(KSession& session,
std::shared_ptr<HLERequestContext>&& context) {
{
std::unique_lock lock{queue_mutex};
- // ServerSession owns the service thread, so we cannot caption a strong pointer here in the
- // event that the ServerSession is terminated.
- std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)};
- requests.emplace([weak_ptr, context{std::move(context)}]() {
- if (auto strong_ptr = weak_ptr.lock()) {
- strong_ptr->CompleteSyncRequest(*context);
+ // Open a reference to the session to ensure it is not closes while the service request
+ // completes asynchronously.
+ session.Open();
+
+ requests.emplace([session_ptr{&session}, context{std::move(context)}]() {
+ // Close the reference.
+ SCOPE_EXIT({ session_ptr->Close(); });
+
+ // If the session has been closed, we are done.
+ if (session_ptr->IsServerClosed()) {
+ return;
}
+
+ // Complete the service request.
+ KScopedAutoObject server_session{&session_ptr->GetServerSession()};
+ server_session->CompleteSyncRequest(*context);
});
}
condition.notify_one();
@@ -102,7 +111,7 @@ ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const
ServiceThread::~ServiceThread() = default;
-void ServiceThread::QueueSyncRequest(ServerSession& session,
+void ServiceThread::QueueSyncRequest(KSession& session,
std::shared_ptr<HLERequestContext>&& context) {
impl->QueueSyncRequest(session, std::move(context));
}
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 {
class HLERequestContext;
class KernelCore;
-class ServerSession;
+class KSession;
class ServiceThread final {
public:
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
~ServiceThread();
- void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
+ void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
private:
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 @@
-// Copyright 2019 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/assert.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.h"
-#include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/session.h"
-
-namespace Kernel {
-
-Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
-Session::~Session() {
- // Release reserved resource when the Session pair was created.
- kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1);
-}
-
-Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
- // Reserve a new session from the resource limit.
- KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(),
- LimitableResource::Sessions);
- ASSERT(session_reservation.Succeeded());
- auto session{std::make_shared<Session>(kernel)};
- auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()};
- auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()};
-
- session->name = std::move(name);
- session->client = client_session;
- session->server = server_session;
-
- session_reservation.Commit();
- return std::make_pair(std::move(client_session), std::move(server_session));
-}
-
-bool Session::IsSignaled() const {
- UNIMPLEMENTED();
- return true;
-}
-
-} // 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 @@
-// Copyright 2019 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "core/hle/kernel/k_synchronization_object.h"
-
-namespace Kernel {
-
-class ClientSession;
-class ServerSession;
-
-/**
- * Parent structure to link the client and server endpoints of a session with their associated
- * client port.
- */
-class Session final : public KSynchronizationObject {
-public:
- explicit Session(KernelCore& kernel);
- ~Session() override;
-
- using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>;
-
- static SessionPair Create(KernelCore& kernel, std::string name = "Unknown");
-
- std::string GetName() const override {
- return name;
- }
-
- static constexpr HandleType HANDLE_TYPE = HandleType::Session;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- bool IsSignaled() const override;
-
- void Finalize() override {}
-
- std::shared_ptr<ClientSession> Client() {
- if (auto result{client.lock()}) {
- return result;
- }
- return {};
- }
-
- std::shared_ptr<ServerSession> Server() {
- if (auto result{server.lock()}) {
- return result;
- }
- return {};
- }
-
-private:
- std::string name;
- std::weak_ptr<ClientSession> client;
- std::weak_ptr<ServerSession> server;
-};
-
-} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/intrusive_red_black_tree.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/k_auto_object_container.h"
+#include "core/hle/kernel/k_light_lock.h"
+#include "core/hle/kernel/k_slab_heap.h"
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+template <class Derived>
+class KSlabAllocated {
+public:
+ constexpr KSlabAllocated() = default;
+
+ size_t GetSlabIndex(KernelCore& kernel) const {
+ return kernel.SlabHeap<Derived>().GetIndex(static_cast<const Derived*>(this));
+ }
+
+public:
+ static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
+ kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
+ }
+
+ static Derived* Allocate(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().Allocate();
+ }
+
+ static void Free(KernelCore& kernel, Derived* obj) {
+ kernel.SlabHeap<Derived>().Free(obj);
+ }
+
+ static size_t GetObjectSize(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetObjectSize();
+ }
+
+ static size_t GetSlabHeapSize(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetSlabHeapSize();
+ }
+
+ static size_t GetPeakIndex(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetPeakIndex();
+ }
+
+ static uintptr_t GetSlabHeapAddress(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetSlabHeapAddress();
+ }
+
+ static size_t GetNumRemaining(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetNumRemaining();
+ }
+};
+
+template <typename Derived, typename Base>
+class KAutoObjectWithSlabHeapAndContainer : public Base {
+ static_assert(std::is_base_of<KAutoObjectWithList, Base>::value);
+
+private:
+ static Derived* Allocate(KernelCore& kernel) {
+ return new Derived(kernel);
+ }
+
+ static void Free(KernelCore& kernel, Derived* obj) {
+ delete obj;
+ }
+
+public:
+ KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {}
+ virtual ~KAutoObjectWithSlabHeapAndContainer() {}
+
+ virtual void Destroy() override {
+ const bool is_initialized = this->IsInitialized();
+ uintptr_t arg = 0;
+ if (is_initialized) {
+ kernel.ObjectListContainer().Unregister(this);
+ arg = this->GetPostDestroyArgument();
+ this->Finalize();
+ }
+ Free(kernel, static_cast<Derived*>(this));
+ if (is_initialized) {
+ Derived::PostDestroy(arg);
+ }
+ }
+
+ virtual bool IsInitialized() const {
+ return true;
+ }
+ virtual uintptr_t GetPostDestroyArgument() const {
+ return 0;
+ }
+
+ size_t GetSlabIndex() const {
+ return SlabHeap<Derived>(kernel).GetObjectIndex(static_cast<const Derived*>(this));
+ }
+
+public:
+ static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
+ kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
+ kernel.ObjectListContainer().Initialize();
+ }
+
+ static Derived* Create(KernelCore& kernel) {
+ Derived* obj = Allocate(kernel);
+ if (obj != nullptr) {
+ KAutoObject::Create(obj);
+ }
+ return obj;
+ }
+
+ static void Register(KernelCore& kernel, Derived* obj) {
+ return kernel.ObjectListContainer().Register(obj);
+ }
+
+ static size_t GetObjectSize(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetObjectSize();
+ }
+
+ static size_t GetSlabHeapSize(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetSlabHeapSize();
+ }
+
+ static size_t GetPeakIndex(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetPeakIndex();
+ }
+
+ static uintptr_t GetSlabHeapAddress(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetSlabHeapAddress();
+ }
+
+ static size_t GetNumRemaining(KernelCore& kernel) {
+ return kernel.SlabHeap<Derived>().GetNumRemaining();
+ }
+
+protected:
+ KernelCore& kernel;
+};
+
+} // 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 @@
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/cpu_manager.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_address_arbiter.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_client_session.h"
#include "core/hle/kernel/k_condition_variable.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
@@ -38,16 +39,15 @@
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/kernel/svc_wrap.h"
#include "core/hle/kernel/time_manager.h"
-#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -113,7 +113,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
LOG_ERROR(Kernel_SVC,
"Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
dst_addr, size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
if (manager.IsInsideHeapRegion(dst_addr, size)) {
@@ -121,7 +121,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
"Destination does not fit within the heap region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
if (manager.IsInsideAliasRegion(dst_addr, size)) {
@@ -129,7 +129,7 @@ ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr,
"Destination does not fit within the map region, addr=0x{:016X}, "
"size=0x{:016X}",
dst_addr, size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
return RESULT_SUCCESS;
@@ -141,38 +141,6 @@ enum class ResourceLimitValueType {
PeakValue,
};
-ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
- u32 resource_type, ResourceLimitValueType value_type) {
- std::lock_guard lock{HLE::g_hle_lock};
- const auto type = static_cast<LimitableResource>(resource_type);
- if (!IsValidResourceType(type)) {
- LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
- return ResultInvalidEnumValue;
- }
-
- const auto* const current_process = system.Kernel().CurrentProcess();
- ASSERT(current_process != nullptr);
-
- const auto resource_limit_object =
- current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
- if (!resource_limit_object) {
- LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
- resource_limit);
- return ResultInvalidHandle;
- }
-
- switch (value_type) {
- case ResourceLimitValueType::CurrentValue:
- return MakeResult(resource_limit_object->GetCurrentValue(type));
- case ResourceLimitValueType::LimitValue:
- return MakeResult(resource_limit_object->GetLimitValue(type));
- case ResourceLimitValueType::PeakValue:
- return MakeResult(resource_limit_object->GetPeakValue(type));
- default:
- LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type);
- return ResultInvalidEnumValue;
- }
-}
} // Anonymous namespace
/// 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
}
/// Connect to an OS service given the port name, returns the handle to the port to out
-static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
- VAddr port_name_address) {
- std::lock_guard lock{HLE::g_hle_lock};
+static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_name_address) {
auto& memory = system.Memory();
-
if (!memory.IsValidVirtualAddress(port_name_address)) {
LOG_ERROR(Kernel_SVC,
"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,
LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
+ // Get the current handle table.
auto& kernel = system.Kernel();
- const auto it = kernel.FindNamedPort(port_name);
- if (!kernel.IsValidNamedPort(it)) {
- LOG_WARNING(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
+ auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+
+ // Find the client port.
+ auto port = kernel.CreateNamedServicePort(port_name);
+ if (!port) {
+ LOG_ERROR(Kernel_SVC, "tried to connect to unknown port: {}", port_name);
return ResultNotFound;
}
- auto client_port = it->second;
+ // Reserve a handle for the port.
+ // NOTE: Nintendo really does write directly to the output handle here.
+ R_TRY(handle_table.Reserve(out));
+ auto handle_guard = SCOPE_GUARD({ handle_table.Unreserve(*out); });
- std::shared_ptr<ClientSession> client_session;
- CASCADE_RESULT(client_session, client_port->Connect());
+ // Create a session.
+ KClientSession* session{};
+ R_TRY(port->CreateSession(std::addressof(session)));
- // Return the client session
- auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- CASCADE_RESULT(*out_handle, handle_table.Create(client_session));
+ // Register the session in the table, close the extra reference.
+ handle_table.Register(*out, session);
+ session->Close();
+
+ // We succeeded.
+ handle_guard.Cancel();
return RESULT_SUCCESS;
}
@@ -340,14 +316,12 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
/// Makes a blocking IPC call to an OS service.
static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
+
auto& kernel = system.Kernel();
- const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle);
- if (!session) {
- LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject session =
+ kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
+ R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
auto thread = kernel.CurrentScheduler()->GetCurrentThread();
@@ -355,7 +329,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
KScopedSchedulerLock lock(kernel);
thread->SetState(ThreadState::Waiting);
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
- session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
+ session->SendSyncRequest(thread, system.Memory(), system.CoreTiming());
}
KSynchronizationObject* dummy{};
@@ -368,18 +342,13 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
/// Get the ID for the specified thread.
static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
- LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
-
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Get the thread's id.
- *out_thread_id = thread->GetThreadID();
+ *out_thread_id = thread->GetId();
return RESULT_SUCCESS;
}
@@ -395,110 +364,101 @@ static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low,
}
/// Gets the ID of the specified process or a specified thread's owning process.
-static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle handle) {
+static ResultCode GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<Process> process = handle_table.Get<Process>(handle);
- if (process) {
- *process_id = process->GetProcessID();
- return RESULT_SUCCESS;
+ // Get the object from the handle table.
+ KScopedAutoObject obj =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>(
+ static_cast<Handle>(handle));
+ R_UNLESS(obj.IsNotNull(), ResultInvalidHandle);
+
+ // Get the process from the object.
+ KProcess* process = nullptr;
+ if (KProcess* p = obj->DynamicCast<KProcess*>(); p != nullptr) {
+ // The object is a process, so we can use it directly.
+ process = p;
+ } else if (KThread* t = obj->DynamicCast<KThread*>(); t != nullptr) {
+ // The object is a thread, so we want to use its parent.
+ process = reinterpret_cast<KThread*>(obj.GetPointerUnsafe())->GetOwnerProcess();
+ } else {
+ // TODO(bunnei): This should also handle debug objects before returning.
+ UNIMPLEMENTED_MSG("Debug objects not implemented");
}
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
- if (thread) {
- const Process* const owner_process = thread->GetOwnerProcess();
- if (!owner_process) {
- LOG_ERROR(Kernel_SVC, "Non-existent owning process encountered.");
- return ResultInvalidHandle;
- }
-
- *process_id = owner_process->GetProcessID();
- return RESULT_SUCCESS;
- }
+ // Make sure the target process exists.
+ R_UNLESS(process != nullptr, ResultInvalidHandle);
- // NOTE: This should also handle debug objects before returning.
+ // Get the process id.
+ *out_process_id = process->GetId();
- LOG_ERROR(Kernel_SVC, "Handle does not exist, handle=0x{:08X}", handle);
return ResultInvalidHandle;
}
-static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high,
- Handle handle) {
- u64 process_id{};
- const auto result = GetProcessId(system, &process_id, handle);
- *process_id_low = static_cast<u32>(process_id);
- *process_id_high = static_cast<u32>(process_id >> 32);
+static ResultCode GetProcessId32(Core::System& system, u32* out_process_id_low,
+ u32* out_process_id_high, Handle handle) {
+ u64 out_process_id{};
+ const auto result = GetProcessId(system, &out_process_id, handle);
+ *out_process_id_low = static_cast<u32>(out_process_id);
+ *out_process_id_high = static_cast<u32>(out_process_id >> 32);
return result;
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
- u64 handle_count, s64 nano_seconds) {
- LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
- handles_address, handle_count, nano_seconds);
+ u64 num_handles, s64 nano_seconds) {
+ LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
+ handles_address, num_handles, nano_seconds);
- auto& memory = system.Memory();
- if (!memory.IsValidVirtualAddress(handles_address)) {
- LOG_ERROR(Kernel_SVC,
- "Handle address is not a valid virtual address, handle_address=0x{:016X}",
- handles_address);
- return ResultInvalidPointer;
- }
-
- static constexpr u64 MaxHandles = 0x40;
-
- if (handle_count > MaxHandles) {
- LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
- MaxHandles, handle_count);
- return ResultOutOfRange;
- }
+ // Ensure number of handles is valid.
+ R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
auto& kernel = system.Kernel();
- std::vector<KSynchronizationObject*> objects(handle_count);
+ std::vector<KSynchronizationObject*> objs(num_handles);
const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+ Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
- for (u64 i = 0; i < handle_count; ++i) {
- const Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
- const auto object = handle_table.Get<KSynchronizationObject>(handle);
+ // Copy user handles.
+ if (num_handles > 0) {
+ // Convert the handles to objects.
+ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
+ num_handles),
+ ResultInvalidHandle);
+ }
- if (object == nullptr) {
- LOG_ERROR(Kernel_SVC, "Object is a nullptr");
- return ResultInvalidHandle;
+ // Ensure handles are closed when we're done.
+ SCOPE_EXIT({
+ for (u64 i = 0; i < num_handles; ++i) {
+ objs[i]->Close();
}
+ });
- objects[i] = object.get();
- }
- return KSynchronizationObject::Wait(kernel, index, objects.data(),
- static_cast<s32>(objects.size()), nano_seconds);
+ return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
+ nano_seconds);
}
static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
- s32 handle_count, u32 timeout_high, s32* index) {
+ s32 num_handles, u32 timeout_high, s32* index) {
const s64 nano_seconds{(static_cast<s64>(timeout_high) << 32) | static_cast<s64>(timeout_low)};
- return WaitSynchronization(system, index, handles_address, handle_count, nano_seconds);
+ return WaitSynchronization(system, index, handles_address, num_handles, nano_seconds);
}
/// Resumes a thread waiting on WaitSynchronization
-static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) {
- LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
+static ResultCode CancelSynchronization(Core::System& system, Handle handle) {
+ LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
+ static_cast<Handle>(handle));
// Cancel the thread's wait.
thread->WaitCancel();
return RESULT_SUCCESS;
}
-static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) {
- return CancelSynchronization(system, thread_handle);
+static ResultCode CancelSynchronization32(Core::System& system, Handle handle) {
+ return CancelSynchronization(system, handle);
}
/// Attempts to locks a mutex
@@ -678,7 +638,7 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
}
/// Gets system/memory information for the current process
-static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle,
+static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
u64 info_sub_id) {
std::lock_guard lock{HLE::g_hle_lock};
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
return ResultInvalidEnumValue;
}
- const auto& current_process_handle_table =
- system.Kernel().CurrentProcess()->GetHandleTable();
- const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
- if (!process) {
+ const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
+ if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Process is not valid! info_id={}, info_sub_id={}, handle={:08X}",
info_id, info_sub_id, handle);
return ResultInvalidHandle;
@@ -851,21 +810,19 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
return ResultInvalidCombination;
}
- Process* const current_process = system.Kernel().CurrentProcess();
- HandleTable& handle_table = current_process->GetHandleTable();
+ KProcess* const current_process = system.Kernel().CurrentProcess();
+ KHandleTable& handle_table = current_process->GetHandleTable();
const auto resource_limit = current_process->GetResourceLimit();
if (!resource_limit) {
- *result = KernelHandle::InvalidHandle;
+ *result = Svc::InvalidHandle;
// Yes, the kernel considers this a successful operation.
return RESULT_SUCCESS;
}
- const auto table_result = handle_table.Create(resource_limit);
- if (table_result.Failed()) {
- return table_result.Code();
- }
+ Handle resource_handle{};
+ R_TRY(handle_table.Add(&resource_handle, resource_limit));
- *result = *table_result;
+ *result = resource_handle;
return RESULT_SUCCESS;
}
@@ -876,9 +833,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
return ResultInvalidHandle;
}
- if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
+ if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) {
LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
- Process::RANDOM_ENTROPY_SIZE, info_sub_id);
+ KProcess::RANDOM_ENTROPY_SIZE, info_sub_id);
return ResultInvalidCombination;
}
@@ -899,9 +856,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
return ResultInvalidCombination;
}
- const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>(
- static_cast<Handle>(handle));
- if (!thread) {
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(
+ static_cast<Handle>(handle));
+ if (thread.IsNull()) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
return ResultInvalidHandle;
@@ -910,7 +868,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
const auto& core_timing = system.CoreTiming();
const auto& scheduler = *system.Kernel().CurrentScheduler();
const auto* const current_thread = scheduler.GetCurrentThread();
- const bool same_thread = current_thread == thread.get();
+ const bool same_thread = current_thread == thread.GetPointerUnsafe();
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
u64 out_ticks = 0;
@@ -966,10 +924,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
if (!(addr < addr + size)) {
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
- Process* const current_process{system.Kernel().CurrentProcess()};
+ KProcess* const current_process{system.Kernel().CurrentProcess()};
auto& page_table{current_process->PageTable()};
if (current_process->GetSystemResourceSize() == 0) {
@@ -981,14 +939,14 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
return page_table.MapPhysicalMemory(addr, size);
@@ -1020,10 +978,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
if (!(addr < addr + size)) {
LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
- Process* const current_process{system.Kernel().CurrentProcess()};
+ KProcess* const current_process{system.Kernel().CurrentProcess()};
auto& page_table{current_process->PageTable()};
if (current_process->GetSystemResourceSize() == 0) {
@@ -1035,14 +993,14 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
LOG_ERROR(Kernel_SVC,
"Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
if (page_table.IsOutsideAliasRegion(addr, size)) {
LOG_ERROR(Kernel_SVC,
"Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr,
size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
return page_table.UnmapPhysicalMemory(addr, size);
@@ -1062,37 +1020,19 @@ static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
};
- if (!IsValidThreadActivity(thread_activity)) {
- LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
- thread_activity);
- return ResultInvalidEnumValue;
- }
+ R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue);
// Get the thread from its handle.
- auto& kernel = system.Kernel();
- const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Check that the activity is being set on a non-current thread for the current process.
- if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
- LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
- return ResultInvalidHandle;
- }
- if (thread.get() == GetCurrentThreadPointer(kernel)) {
- LOG_ERROR(Kernel_SVC, "Thread is busy");
- return ResultBusy;
- }
+ R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle);
+ R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
// Set the activity.
- const auto set_result = thread->SetActivity(thread_activity);
- if (set_result.IsError()) {
- LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
- return set_result;
- }
+ R_TRY(thread->SetActivity(thread_activity));
return RESULT_SUCCESS;
}
@@ -1107,36 +1047,55 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
thread_handle);
+ auto& kernel = system.Kernel();
+
// Get the thread from its handle.
- const auto* current_process = system.Kernel().CurrentProcess();
- const std::shared_ptr<KThread> thread =
- current_process->GetHandleTable().Get<KThread>(thread_handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Require the handle be to a non-current thread in the current process.
- if (thread->GetOwnerProcess() != current_process) {
- LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
- return ResultInvalidHandle;
- }
- if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
- LOG_ERROR(Kernel_SVC, "Current thread is busy.");
- return ResultBusy;
- }
+ const auto* current_process = kernel.CurrentProcess();
+ R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
- // Get the thread context.
- std::vector<u8> context;
- const auto context_result = thread->GetThreadContext3(context);
- if (context_result.IsError()) {
- LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
- context_result.raw);
- return context_result;
- }
+ // Verify that the thread isn't terminated.
+ R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
+
+ /// Check that the thread is not the current one.
+ /// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
+ R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
+
+ // Try to get the thread context until the thread isn't current on any core.
+ while (true) {
+ KScopedSchedulerLock sl{kernel};
- // Copy the thread context to user space.
- system.Memory().WriteBlock(out_context, context.data(), context.size());
+ // TODO(bunnei): Enforce that thread is suspended for debug here.
+
+ // If the thread's raw state isn't runnable, check if it's current on some core.
+ if (thread->GetRawState() != ThreadState::Runnable) {
+ bool current = false;
+ for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
+ if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) {
+ current = true;
+ }
+ break;
+ }
+
+ // If the thread is current, retry until it isn't.
+ if (current) {
+ continue;
+ }
+ }
+
+ // Get the thread context.
+ std::vector<u8> context;
+ R_TRY(thread->GetThreadContext3(context));
+
+ // Copy the thread context to user space.
+ system.Memory().WriteBlock(out_context, context.data(), context.size());
+
+ return RESULT_SUCCESS;
+ }
return RESULT_SUCCESS;
}
@@ -1150,12 +1109,9 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
LOG_TRACE(Kernel_SVC, "called");
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Get the thread's priority.
*out_priority = thread->GetPriority();
@@ -1167,30 +1123,26 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, H
}
/// Sets the priority for the specified thread
-static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
- LOG_TRACE(Kernel_SVC, "called");
+static ResultCode SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) {
+ // Get the current process.
+ KProcess& process = *system.Kernel().CurrentProcess();
// Validate the priority.
- if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
- LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
- return ResultInvalidPriority;
- }
+ R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
+ ResultInvalidPriority);
+ R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Set the thread priority.
thread->SetBasePriority(priority);
return RESULT_SUCCESS;
}
-static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) {
- return SetThreadPriority(system, handle, priority);
+static ResultCode SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) {
+ return SetThreadPriority(system, thread_handle, priority);
}
/// Get which CPU core is executing the current thread
@@ -1203,82 +1155,97 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) {
return GetCurrentProcessorNumber(system);
}
-static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr,
- u64 size, u32 permissions) {
- std::lock_guard lock{HLE::g_hle_lock};
+constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
+ switch (perm) {
+ case Svc::MemoryPermission::Read:
+ case Svc::MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
+ return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
+}
+
+static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
+ u64 size, Svc::MemoryPermission map_perm) {
LOG_TRACE(Kernel_SVC,
"called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
- shared_memory_handle, addr, size, permissions);
+ shmem_handle, address, size, map_perm);
- if (!Common::Is4KBAligned(addr)) {
- LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
- return ResultInvalidAddress;
- }
+ // Validate the address/size.
+ R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
- if (size == 0) {
- LOG_ERROR(Kernel_SVC, "Size is 0");
- return ResultInvalidSize;
- }
+ // Validate the permission.
+ R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
- if (!Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
- return ResultInvalidSize;
- }
+ // Get the current process.
+ auto& process = *system.Kernel().CurrentProcess();
+ auto& page_table = process.PageTable();
- if (!IsValidAddressRange(addr, size)) {
- LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
- addr, size);
- return ResultInvalidCurrentMemory;
- }
+ // Get the shared memory.
+ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
+ R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
- const auto permission_type = static_cast<MemoryPermission>(permissions);
- if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) {
- LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
- permissions);
- return ResultInvalidMemoryPermissions;
- }
+ // Verify that the mapping is in range.
+ R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
- auto* const current_process{system.Kernel().CurrentProcess()};
- auto& page_table{current_process->PageTable()};
+ // Add the shared memory to the process.
+ R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
- if (page_table.IsInvalidRegion(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Addr does not fit within the valid region, addr=0x{:016X}, "
- "size=0x{:016X}",
- addr, size);
- return ResultInvalidMemoryRange;
- }
+ // Ensure that we clean up the shared memory if we fail to map it.
+ auto guard =
+ SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
- if (page_table.IsInsideHeapRegion(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Addr does not fit within the heap region, addr=0x{:016X}, "
- "size=0x{:016X}",
- addr, size);
- return ResultInvalidMemoryRange;
- }
+ // Map the shared memory.
+ R_TRY(shmem->Map(process, address, size, map_perm));
- if (page_table.IsInsideAliasRegion(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Address does not fit within the map region, addr=0x{:016X}, "
- "size=0x{:016X}",
- addr, size);
- return ResultInvalidMemoryRange;
- }
+ // We succeeded.
+ guard.Cancel();
+ return RESULT_SUCCESS;
+}
- auto shared_memory{current_process->GetHandleTable().Get<KSharedMemory>(shared_memory_handle)};
- if (!shared_memory) {
- LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
- shared_memory_handle);
- return ResultInvalidHandle;
- }
+static ResultCode MapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
+ u32 size, Svc::MemoryPermission map_perm) {
+ return MapSharedMemory(system, shmem_handle, address, size, map_perm);
+}
+
+static ResultCode UnmapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
+ u64 size) {
+ // Validate the address/size.
+ R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
+
+ // Get the current process.
+ auto& process = *system.Kernel().CurrentProcess();
+ auto& page_table = process.PageTable();
+
+ // Get the shared memory.
+ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
+ R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
- return shared_memory->Map(*current_process, addr, size,
- static_cast<KMemoryPermission>(permission_type));
+ // Verify that the mapping is in range.
+ R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
+
+ // Unmap the shared memory.
+ R_TRY(shmem->Unmap(process, address, size));
+
+ // Remove the shared memory from the process.
+ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
+
+ return RESULT_SUCCESS;
}
-static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr,
- u32 size, u32 permissions) {
- return MapSharedMemory(system, shared_memory_handle, addr, size, permissions);
+static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
+ u32 size) {
+ return UnmapSharedMemory(system, shmem_handle, address, size);
}
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
@@ -1287,8 +1254,8 @@ static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_add
std::lock_guard lock{HLE::g_hle_lock};
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- std::shared_ptr<Process> process = handle_table.Get<Process>(process_handle);
- if (!process) {
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
+ if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
return ResultInvalidHandle;
@@ -1369,8 +1336,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
}
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- auto process = handle_table.Get<Process>(process_handle);
- if (!process) {
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
+ if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
process_handle);
return ResultInvalidHandle;
@@ -1390,7 +1357,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
return page_table.MapProcessCodeMemory(dst_address, src_address, size);
@@ -1437,8 +1404,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
}
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- auto process = handle_table.Get<Process>(process_handle);
- if (!process) {
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
+ if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
process_handle);
return ResultInvalidHandle;
@@ -1458,7 +1425,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
"Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
"size=0x{:016X}).",
dst_address, size);
- return ResultInvalidMemoryRange;
+ return ResultInvalidMemoryRegion;
}
return page_table.UnmapProcessCodeMemory(dst_address, src_address, size);
@@ -1483,7 +1450,7 @@ static void ExitProcess32(Core::System& system) {
ExitProcess(system);
}
-static constexpr bool IsValidCoreId(int32_t core_id) {
+static constexpr bool IsValidVirtualCoreId(int32_t core_id) {
return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
}
@@ -1503,7 +1470,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
}
// Validate arguments.
- if (!IsValidCoreId(core_id)) {
+ if (!IsValidVirtualCoreId(core_id)) {
LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
return ResultInvalidCoreId;
}
@@ -1521,35 +1488,42 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
return ResultInvalidPriority;
}
+ // Reserve a new thread from the process resource limit (waiting up to 100ms).
KScopedResourceReservation thread_reservation(
kernel.CurrentProcess(), LimitableResource::Threads, 1,
system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
if (!thread_reservation.Succeeded()) {
LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
- return ResultResourceLimitedExceeded;
+ return ResultLimitReached;
}
- std::shared_ptr<KThread> thread;
- {
- KScopedLightLock lk{process.GetStateLock()};
- CASCADE_RESULT(thread,
- KThread::CreateUserThread(system, ThreadType::User, "", entry_point,
- priority, arg, core_id, stack_bottom, &process));
+ // Create the thread.
+ KThread* thread = KThread::Create(kernel);
+ if (!thread) {
+ LOG_ERROR(Kernel_SVC, "Unable to create new threads. Thread creation limit reached.");
+ return ResultOutOfResource;
}
+ SCOPE_EXIT({ thread->Close(); });
- const auto new_thread_handle = process.GetHandleTable().Create(thread);
- if (new_thread_handle.Failed()) {
- LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
- new_thread_handle.Code().raw);
- return new_thread_handle.Code();
+ // Initialize the thread.
+ {
+ KScopedLightLock lk{process.GetStateLock()};
+ R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
+ priority, core_id, &process));
}
- *out_handle = *new_thread_handle;
// Set the thread name for debugging purposes.
- thread->SetName(
- fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle));
+ thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle));
+
+ // Commit the thread reservation.
thread_reservation.Commit();
+ // Register the new thread.
+ KThread::Register(kernel, thread);
+
+ // Add the thread to the handle table.
+ R_TRY(process.GetHandleTable().Add(out_handle, thread));
+
return RESULT_SUCCESS;
}
@@ -1563,21 +1537,15 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Try to start the thread.
- const auto run_result = thread->Run();
- if (run_result.IsError()) {
- LOG_ERROR(Kernel_SVC,
- "Unable to successfuly start thread (thread handle={:08X}, result={})",
- thread_handle, run_result.raw);
- return run_result;
- }
+ R_TRY(thread->Run());
+
+ // If we succeeded, persist a reference to the thread.
+ thread->Open();
return RESULT_SUCCESS;
}
@@ -1591,7 +1559,7 @@ static void ExitThread(Core::System& system) {
LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
- system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread));
+ system.GlobalSchedulerContext().RemoveThread(current_thread);
current_thread->Exit();
}
@@ -1824,8 +1792,11 @@ static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high)
static ResultCode CloseHandle(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
- auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- return handle_table.Close(handle);
+ // Remove the handle.
+ R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle),
+ ResultInvalidHandle);
+
+ return RESULT_SUCCESS;
}
static ResultCode CloseHandle32(Core::System& system, Handle handle) {
@@ -1841,16 +1812,16 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) {
// Try to reset as readable event.
{
- auto readable_event = handle_table.Get<KReadableEvent>(handle);
- if (readable_event) {
+ KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
+ if (readable_event.IsNotNull()) {
return readable_event->Reset();
}
}
// Try to reset as process.
{
- auto process = handle_table.Get<Process>(handle);
- if (process) {
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
+ if (process.IsNotNull()) {
return process->Reset();
}
}
@@ -1864,65 +1835,68 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) {
return ResetSignal(system, handle);
}
-/// Creates a TransferMemory object
-static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size,
- u32 permissions) {
- std::lock_guard lock{HLE::g_hle_lock};
- LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
- permissions);
-
- if (!Common::Is4KBAligned(addr)) {
- LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr);
- return ResultInvalidAddress;
+static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
+ switch (perm) {
+ case MemoryPermission::None:
+ case MemoryPermission::Read:
+ case MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
}
+}
- if (!Common::Is4KBAligned(size) || size == 0) {
- LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size);
- return ResultInvalidAddress;
- }
+/// Creates a TransferMemory object
+static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
+ MemoryPermission map_perm) {
+ auto& kernel = system.Kernel();
- if (!IsValidAddressRange(addr, size)) {
- LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})",
- addr, size);
- return ResultInvalidCurrentMemory;
- }
+ // Validate the size.
+ R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
- const auto perms{static_cast<MemoryPermission>(permissions)};
- if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) {
- LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})",
- permissions);
- return ResultInvalidMemoryPermissions;
- }
+ // Validate the permissions.
+ R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
+
+ // Get the current process and handle table.
+ auto& process = *kernel.CurrentProcess();
+ auto& handle_table = process.GetHandleTable();
- auto& kernel = system.Kernel();
// Reserve a new transfer memory from the process resource limit.
KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
LimitableResource::TransferMemory);
- if (!trmem_reservation.Succeeded()) {
- LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory");
- return ResultResourceLimitedExceeded;
- }
- auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size,
- static_cast<KMemoryPermission>(perms));
+ R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
- if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) {
- return reserve_result;
- }
+ // Create the transfer memory.
+ KTransferMemory* trmem = KTransferMemory::Create(kernel);
+ R_UNLESS(trmem != nullptr, ResultOutOfResource);
- auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- const auto result{handle_table.Create(std::move(transfer_mem_handle))};
- if (result.Failed()) {
- return result.Code();
- }
+ // Ensure the only reference is in the handle table when we're done.
+ SCOPE_EXIT({ trmem->Close(); });
+
+ // Ensure that the region is in range.
+ R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Initialize the transfer memory.
+ R_TRY(trmem->Initialize(address, size, map_perm));
+
+ // Commit the reservation.
trmem_reservation.Commit();
- *handle = *result;
+ // Register the transfer memory.
+ KTransferMemory::Register(kernel, trmem);
+
+ // Add the transfer memory to the handle table.
+ R_TRY(handle_table.Add(out, trmem));
+
return RESULT_SUCCESS;
}
-static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size,
- u32 permissions) {
- return CreateTransferMemory(system, handle, addr, size, permissions);
+static ResultCode CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size,
+ MemoryPermission map_perm) {
+ return CreateTransferMemory(system, out, address, size, map_perm);
}
static 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,
LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Get the core mask.
- const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
- if (result.IsError()) {
- LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
- return result;
- }
+ R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
return RESULT_SUCCESS;
}
@@ -1958,58 +1925,33 @@ static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle
static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
u64 affinity_mask) {
- LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}",
- thread_handle, core_id, affinity_mask);
-
- const auto& current_process = *system.Kernel().CurrentProcess();
-
// Determine the core id/affinity mask.
- if (core_id == Svc::IdealCoreUseProcessValue) {
- core_id = current_process.GetIdealCoreId();
+ if (core_id == IdealCoreUseProcessValue) {
+ core_id = system.Kernel().CurrentProcess()->GetIdealCoreId();
affinity_mask = (1ULL << core_id);
} else {
// Validate the affinity mask.
- const u64 process_core_mask = current_process.GetCoreMask();
- if ((affinity_mask | process_core_mask) != process_core_mask) {
- LOG_ERROR(Kernel_SVC,
- "Affinity mask does match the process core mask (affinity mask={:016X}, core "
- "mask={:016X})",
- affinity_mask, process_core_mask);
- return ResultInvalidCoreId;
- }
- if (affinity_mask == 0) {
- LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
- return ResultInvalidCombination;
- }
+ const u64 process_core_mask = system.Kernel().CurrentProcess()->GetCoreMask();
+ R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId);
+ R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
// Validate the core id.
- if (IsValidCoreId(core_id)) {
- if (((1ULL << core_id) & affinity_mask) == 0) {
- LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
- return ResultInvalidCombination;
- }
+ if (IsValidVirtualCoreId(core_id)) {
+ R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
} else {
- if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
- LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
- return ResultInvalidCoreId;
- }
+ R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
+ ResultInvalidCoreId);
}
}
// Get the thread from its handle.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
- if (!thread) {
- LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
- return ResultInvalidHandle;
- }
+ KScopedAutoObject thread =
+ system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
// Set the core mask.
- const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
- if (set_result.IsError()) {
- LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
- return set_result;
- }
+ R_TRY(thread->SetCoreMask(core_id, affinity_mask));
+
return RESULT_SUCCESS;
}
@@ -2022,27 +1964,12 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle
static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
- auto& kernel = system.Kernel();
// Get the current handle table.
- const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
-
- // Reserve a new event from the process resource limit.
- KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
- LimitableResource::Events);
- if (!event_reservation.Succeeded()) {
- LOG_ERROR(Kernel, "Could not reserve a new event");
- return ResultResourceLimitedExceeded;
- }
+ const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
// Get the writable event.
- auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
- if (!writable_event) {
- LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
- return ResultInvalidHandle;
- }
-
- // Commit the successfuly reservation.
- event_reservation.Commit();
+ KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
+ R_UNLESS(writable_event.IsNotNull(), ResultInvalidHandle);
return writable_event->Signal();
}
@@ -2059,16 +1986,16 @@ static ResultCode ClearEvent(Core::System& system, Handle event_handle) {
// Try to clear the writable event.
{
- auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
- if (writable_event) {
+ KScopedAutoObject writable_event = handle_table.GetObject<KWritableEvent>(event_handle);
+ if (writable_event.IsNotNull()) {
return writable_event->Clear();
}
}
// Try to clear the readable event.
{
- auto readable_event = handle_table.Get<KReadableEvent>(event_handle);
- if (readable_event) {
+ KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
+ if (readable_event.IsNotNull()) {
return readable_event->Clear();
}
}
@@ -2087,34 +2014,40 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
// Get the kernel reference and handle table.
auto& kernel = system.Kernel();
- HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
+ auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+
+ // Reserve a new event from the process resource limit
+ KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
+ LimitableResource::Events);
+ R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
// Create a new event.
- const auto event = KEvent::Create(kernel, "CreateEvent");
- if (!event) {
- LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
- return ResultOutOfResource;
- }
+ KEvent* event = KEvent::Create(kernel);
+ R_UNLESS(event != nullptr, ResultOutOfResource);
// Initialize the event.
- event->Initialize();
+ event->Initialize("CreateEvent");
+
+ // Commit the thread reservation.
+ event_reservation.Commit();
+
+ // Ensure that we clean up the event (and its only references are handle table) on function end.
+ SCOPE_EXIT({
+ event->GetWritableEvent().Close();
+ event->GetReadableEvent().Close();
+ });
+
+ // Register the event.
+ KEvent::Register(kernel, event);
// Add the writable event to the handle table.
- const auto write_create_result = handle_table.Create(event->GetWritableEvent());
- if (write_create_result.Failed()) {
- return write_create_result.Code();
- }
- *out_write = *write_create_result;
+ R_TRY(handle_table.Add(out_write, std::addressof(event->GetWritableEvent())));
// Add the writable event to the handle table.
- auto handle_guard = SCOPE_GUARD({ handle_table.Close(*write_create_result); });
+ auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); });
// Add the readable event to the handle table.
- const auto read_create_result = handle_table.Create(event->GetReadableEvent());
- if (read_create_result.Failed()) {
- return read_create_result.Code();
- }
- *out_read = *read_create_result;
+ R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
// We succeeded.
handle_guard.Cancel();
@@ -2134,8 +2067,8 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
};
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- const auto process = handle_table.Get<Process>(process_handle);
- if (!process) {
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
+ if (process.IsNull()) {
LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
process_handle);
return ResultInvalidHandle;
@@ -2152,83 +2085,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
}
static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
- std::lock_guard lock{HLE::g_hle_lock};
LOG_DEBUG(Kernel_SVC, "called");
+ // Create a new resource limit.
auto& kernel = system.Kernel();
- auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming());
+ KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
+ R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
- auto* const current_process = kernel.CurrentProcess();
- ASSERT(current_process != nullptr);
+ // Ensure we don't leak a reference to the limit.
+ SCOPE_EXIT({ resource_limit->Close(); });
- const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit));
- if (handle.Failed()) {
- return handle.Code();
- }
+ // Initialize the resource limit.
+ resource_limit->Initialize(&system.CoreTiming());
+
+ // Register the limit.
+ KResourceLimit::Register(kernel, resource_limit);
+
+ // Add the limit to the handle table.
+ R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit));
- *out_handle = *handle;
return RESULT_SUCCESS;
}
-static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value,
- Handle resource_limit, u32 resource_type) {
- LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
+static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value,
+ Handle resource_limit_handle,
+ LimitableResource which) {
+ LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
+ which);
- const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type,
- ResourceLimitValueType::LimitValue);
- if (limit_value.Failed()) {
- return limit_value.Code();
- }
+ // Validate the resource.
+ R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+ // Get the resource limit.
+ auto& kernel = system.Kernel();
+ KScopedAutoObject resource_limit =
+ kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
+ R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+ // Get the limit value.
+ *out_limit_value = resource_limit->GetLimitValue(which);
- *out_value = static_cast<u64>(*limit_value);
return RESULT_SUCCESS;
}
-static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value,
- Handle resource_limit, u32 resource_type) {
- LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
+static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value,
+ Handle resource_limit_handle,
+ LimitableResource which) {
+ LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
+ which);
- const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type,
- ResourceLimitValueType::CurrentValue);
- if (current_value.Failed()) {
- return current_value.Code();
- }
+ // Validate the resource.
+ R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+ // Get the resource limit.
+ auto& kernel = system.Kernel();
+ KScopedAutoObject resource_limit =
+ kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
+ R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+ // Get the current value.
+ *out_current_value = resource_limit->GetCurrentValue(which);
- *out_value = static_cast<u64>(*current_value);
return RESULT_SUCCESS;
}
-static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit,
- u32 resource_type, u64 value) {
- LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
- resource_type, value);
+static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
+ LimitableResource which, u64 limit_value) {
+ LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
+ resource_limit_handle, which, limit_value);
- const auto type = static_cast<LimitableResource>(resource_type);
- if (!IsValidResourceType(type)) {
- LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
- return ResultInvalidEnumValue;
- }
-
- auto* const current_process = system.Kernel().CurrentProcess();
- ASSERT(current_process != nullptr);
+ // Validate the resource.
+ R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
- auto resource_limit_object =
- current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
- if (!resource_limit_object) {
- LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
- resource_limit);
- return ResultInvalidHandle;
- }
+ // Get the resource limit.
+ auto& kernel = system.Kernel();
+ KScopedAutoObject resource_limit =
+ kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
+ R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
- const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value));
- if (set_result.IsError()) {
- LOG_ERROR(Kernel_SVC,
- "Attempted to lower resource limit ({}) for category '{}' below its current "
- "value ({})",
- resource_limit_object->GetLimitValue(type), resource_type,
- resource_limit_object->GetCurrentValue(type));
- return set_result;
- }
+ // Set the limit value.
+ R_TRY(resource_limit->SetLimitValue(which, limit_value));
return RESULT_SUCCESS;
}
@@ -2351,7 +2287,7 @@ static const FunctionDef SVC_Table_32[] = {
{0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
{0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
{0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
- {0x14, nullptr, "UnmapSharedMemory32"},
+ {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"},
{0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
{0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
{0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
@@ -2546,7 +2482,7 @@ static const FunctionDef SVC_Table_64[] = {
{0x11, SvcWrap64<SignalEvent>, "SignalEvent"},
{0x12, SvcWrap64<ClearEvent>, "ClearEvent"},
{0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"},
- {0x14, nullptr, "UnmapSharedMemory"},
+ {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"},
{0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"},
{0x16, SvcWrap64<CloseHandle>, "CloseHandle"},
{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 @@
#include "common/common_types.h"
+namespace Kernel {
+using Handle = u32;
+}
+
namespace Kernel::Svc {
constexpr s32 ArgumentHandleCountMax = 0x40;
constexpr u32 HandleWaitMask{1u << 30};
+constexpr inline Handle InvalidHandle = Handle(0);
+
+enum PseudoHandle : Handle {
+ CurrentThread = 0xFFFF8000,
+ CurrentProcess = 0xFFFF8001,
+};
+
+constexpr bool IsPseudoHandle(Handle handle) {
+ return handle == PseudoHandle::CurrentProcess || handle == PseudoHandle::CurrentThread;
+}
+
} // 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 {
// Confirmed Switch kernel error codes
-constexpr ResultCode ResultMaxConnectionsReached{ErrorModule::Kernel, 7};
-constexpr ResultCode ResultInvalidCapabilityDescriptor{ErrorModule::Kernel, 14};
+constexpr ResultCode ResultOutOfSessions{ErrorModule::Kernel, 7};
+constexpr ResultCode ResultInvalidArgument{ErrorModule::Kernel, 14};
constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
constexpr ResultCode ResultInvalidSize{ErrorModule::Kernel, 101};
constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
constexpr ResultCode ResultOutOfResource{ErrorModule::Kernel, 103};
constexpr ResultCode ResultOutOfMemory{ErrorModule::Kernel, 104};
-constexpr ResultCode ResultHandleTableFull{ErrorModule::Kernel, 105};
+constexpr ResultCode ResultOutOfHandles{ErrorModule::Kernel, 105};
constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
-constexpr ResultCode ResultInvalidMemoryPermissions{ErrorModule::Kernel, 108};
-constexpr ResultCode ResultInvalidMemoryRange{ErrorModule::Kernel, 110};
+constexpr ResultCode ResultInvalidNewMemoryPermission{ErrorModule::Kernel, 108};
+constexpr ResultCode ResultInvalidMemoryRegion{ErrorModule::Kernel, 110};
constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
@@ -33,9 +33,11 @@ constexpr ResultCode ResultOutOfRange{ErrorModule::Kernel, 119};
constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
constexpr ResultCode ResultNotFound{ErrorModule::Kernel, 121};
constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
-constexpr ResultCode ResultSessionClosedByRemote{ErrorModule::Kernel, 123};
+constexpr ResultCode ResultSessionClosed{ErrorModule::Kernel, 123};
constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
-constexpr ResultCode ResultReservedValue{ErrorModule::Kernel, 126};
-constexpr ResultCode ResultResourceLimitedExceeded{ErrorModule::Kernel, 132};
+constexpr ResultCode ResultReservedUsed{ErrorModule::Kernel, 126};
+constexpr ResultCode ResultPortClosed{ErrorModule::Kernel, 131};
+constexpr ResultCode ResultLimitReached{ErrorModule::Kernel, 132};
+constexpr ResultCode ResultInvalidId{ErrorModule::Kernel, 519};
} // 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) {
FuncReturn(system, retval);
}
+// Used by GetResourceLimitLimitValue.
+template <ResultCode func(Core::System&, u64*, Handle, LimitableResource)>
+void SvcWrap64(Core::System& system) {
+ u64 param_1 = 0;
+ const u32 retval = func(system, &param_1, static_cast<Handle>(Param(system, 1)),
+ static_cast<LimitableResource>(Param(system, 2)))
+ .raw;
+
+ system.CurrentArmInterface().SetReg(1, param_1);
+ FuncReturn(system, retval);
+}
+
template <ResultCode func(Core::System&, u32, u64)>
void SvcWrap64(Core::System& system) {
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
}
-template <ResultCode func(Core::System&, u32, u32, u64)>
+// Used by SetResourceLimitLimitValue
+template <ResultCode func(Core::System&, Handle, LimitableResource, u64)>
void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
- static_cast<u32>(Param(system, 1)), Param(system, 2))
+ FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
+ static_cast<LimitableResource>(Param(system, 1)), Param(system, 2))
.raw);
}
@@ -219,10 +232,11 @@ void SvcWrap64(Core::System& system) {
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
}
-template <ResultCode func(Core::System&, u32, u64, u64, u32)>
+// Used by MapSharedMemory
+template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
- Param(system, 2), static_cast<u32>(Param(system, 3)))
+ FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1),
+ Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3)))
.raw);
}
@@ -252,11 +266,13 @@ void SvcWrap64(Core::System& system) {
.raw);
}
-template <ResultCode func(Core::System&, u64*, u64, u64, u64)>
+// Used by GetInfo
+template <ResultCode func(Core::System&, u64*, u64, Handle, u64)>
void SvcWrap64(Core::System& system) {
u64 param_1 = 0;
- const u32 retval =
- func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3)).raw;
+ const u32 retval = func(system, &param_1, Param(system, 1),
+ static_cast<Handle>(Param(system, 2)), Param(system, 3))
+ .raw;
system.CurrentArmInterface().SetReg(1, param_1);
FuncReturn(system, retval);
@@ -273,11 +289,12 @@ void SvcWrap64(Core::System& system) {
FuncReturn(system, retval);
}
-template <ResultCode func(Core::System&, u32*, u64, u64, u32)>
+// Used by CreateTransferMemory
+template <ResultCode func(Core::System&, Handle*, u64, u64, Svc::MemoryPermission)>
void SvcWrap64(Core::System& system) {
u32 param_1 = 0;
const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2),
- static_cast<u32>(Param(system, 3)))
+ static_cast<Svc::MemoryPermission>(Param(system, 3)))
.raw;
system.CurrentArmInterface().SetReg(1, param_1);
@@ -537,6 +554,16 @@ void SvcWrap32(Core::System& system) {
FuncReturn(system, retval);
}
+// Used by MapSharedMemory32
+template <ResultCode func(Core::System&, Handle, u32, u32, Svc::MemoryPermission)>
+void SvcWrap32(Core::System& system) {
+ const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
+ static_cast<u32>(Param(system, 1)), static_cast<u32>(Param(system, 2)),
+ static_cast<Svc::MemoryPermission>(Param(system, 3)))
+ .raw;
+ FuncReturn(system, retval);
+}
+
// Used by SetThreadCoreMask32
template <ResultCode func(Core::System&, Handle, s32, u32, u32)>
void SvcWrap32(Core::System& system) {
@@ -586,11 +613,12 @@ void SvcWrap32(Core::System& system) {
}
// Used by CreateTransferMemory32
-template <ResultCode func(Core::System&, Handle*, u32, u32, u32)>
+template <ResultCode func(Core::System&, Handle*, u32, u32, Svc::MemoryPermission)>
void SvcWrap32(Core::System& system) {
Handle handle = 0;
- const u32 retval =
- func(system, &handle, Param32(system, 1), Param32(system, 2), Param32(system, 3)).raw;
+ const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2),
+ static_cast<Svc::MemoryPermission>(Param32(system, 3)))
+ .raw;
system.CurrentArmInterface().SetReg(1, handle);
FuncReturn(system, retval);
}
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 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
-#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
@@ -15,16 +14,12 @@
namespace Kernel {
TimeManager::TimeManager(Core::System& system_) : system{system_} {
- time_manager_event_type = Core::Timing::CreateEvent(
- "Kernel::TimeManagerCallback",
- [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
- std::shared_ptr<KThread> thread;
- {
- std::lock_guard lock{mutex};
- thread = SharedFrom<KThread>(reinterpret_cast<KThread*>(thread_handle));
- }
- thread->Wakeup();
- });
+ time_manager_event_type =
+ Core::Timing::CreateEvent("Kernel::TimeManagerCallback",
+ [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
+ KThread* thread = reinterpret_cast<KThread*>(thread_handle);
+ thread->Wakeup();
+ });
}
void 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 @@
#include <mutex>
#include <unordered_map>
-#include "core/hle/kernel/object.h"
-
namespace Core {
class System;
} // 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 @@
-// Copyright 2019 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/k_resource_limit.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/transfer_memory.h"
-#include "core/hle/result.h"
-#include "core/memory.h"
-
-namespace Kernel {
-
-TransferMemory::TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory)
- : Object{kernel}, memory{memory} {}
-
-TransferMemory::~TransferMemory() {
- // Release memory region when transfer memory is destroyed
- Reset();
- owner_process->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
-}
-
-std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel,
- Core::Memory::Memory& memory,
- VAddr base_address, std::size_t size,
- KMemoryPermission permissions) {
- std::shared_ptr<TransferMemory> transfer_memory{
- std::make_shared<TransferMemory>(kernel, memory)};
-
- transfer_memory->base_address = base_address;
- transfer_memory->size = size;
- transfer_memory->owner_permissions = permissions;
- transfer_memory->owner_process = kernel.CurrentProcess();
-
- return transfer_memory;
-}
-
-const u8* TransferMemory::GetPointer() const {
- return memory.GetPointer(base_address);
-}
-
-ResultCode TransferMemory::Reserve() {
- return owner_process->PageTable().ReserveTransferMemory(base_address, size, owner_permissions);
-}
-
-ResultCode TransferMemory::Reset() {
- return owner_process->PageTable().ResetTransferMemory(base_address, size);
-}
-
-} // 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 @@
-// Copyright 2019 yuzu emulator team
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <memory>
-
-#include "core/hle/kernel/k_memory_block.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/physical_memory.h"
-
-union ResultCode;
-
-namespace Core::Memory {
-class Memory;
-}
-
-namespace Kernel {
-
-class KernelCore;
-class Process;
-
-/// Defines the interface for transfer memory objects.
-///
-/// Transfer memory is typically used for the purpose of
-/// transferring memory between separate process instances,
-/// thus the name.
-///
-class TransferMemory final : public Object {
-public:
- explicit TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory);
- ~TransferMemory() override;
-
- static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
-
- static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Core::Memory::Memory& memory,
- VAddr base_address, std::size_t size,
- KMemoryPermission permissions);
-
- TransferMemory(const TransferMemory&) = delete;
- TransferMemory& operator=(const TransferMemory&) = delete;
-
- TransferMemory(TransferMemory&&) = delete;
- TransferMemory& operator=(TransferMemory&&) = delete;
-
- std::string GetTypeName() const override {
- return "TransferMemory";
- }
-
- std::string GetName() const override {
- return GetTypeName();
- }
-
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- /// Gets a pointer to the backing block of this instance.
- const u8* GetPointer() const;
-
- /// Gets the size of the memory backing this instance in bytes.
- constexpr std::size_t GetSize() const {
- return size;
- }
-
- /// Reserves the region to be used for the transfer memory, called after the transfer memory is
- /// created.
- ResultCode Reserve();
-
- /// Resets the region previously used for the transfer memory, called after the transfer memory
- /// is closed.
- ResultCode Reset();
-
- void Finalize() override {}
-
-private:
- /// The base address for the memory managed by this instance.
- VAddr base_address{};
-
- /// Size of the memory, in bytes, that this instance manages.
- std::size_t size{};
-
- /// The memory permissions that are applied to this instance.
- KMemoryPermission owner_permissions{};
-
- /// The process that this transfer memory instance was created under.
- Process* owner_process{};
-
- Core::Memory::Memory& memory;
-};
-
-} // 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 {
PCIe = 120,
Friends = 121,
BCAT = 122,
- SSL = 123,
+ SSLSrv = 123,
Account = 124,
News = 125,
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 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/acc/acc.h"
#include "core/hle/service/acc/acc_aa.h"
#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 @@
namespace Service::Account {
-ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system)
- : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:aa") {
+ACC_AA::ACC_AA(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
+ Core::System& system_)
+ : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:aa") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "EnsureCacheAsync"},
{1, nullptr, "LoadCache"},
@@ -16,6 +17,7 @@ ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{50, nullptr, "RegisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
{51, nullptr, "UnregisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0
};
+ // clang-format on
RegisterHandlers(functions);
}
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 {
class ACC_AA final : public Module::Interface {
public:
- explicit ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system);
+ explicit ACC_AA(std::shared_ptr<Module> module_,
+ std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
~ACC_AA() override;
};
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 @@
namespace Service::Account {
-ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system)
- : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:su") {
+ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
+ Core::System& system_)
+ : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:su") {
// clang-format off
static const FunctionInfo functions[] = {
{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 {
class ACC_SU final : public Module::Interface {
public:
- explicit ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system);
+ explicit ACC_SU(std::shared_ptr<Module> module_,
+ std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
~ACC_SU() override;
};
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 @@
namespace Service::Account {
-ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system)
- : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u0") {
+ACC_U0::ACC_U0(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
+ Core::System& system_)
+ : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:u0") {
// clang-format off
static const FunctionInfo functions[] = {
{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 {
class ACC_U0 final : public Module::Interface {
public:
- explicit ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system);
+ explicit ACC_U0(std::shared_ptr<Module> module_,
+ std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
~ACC_U0() override;
};
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 @@
namespace Service::Account {
-ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system)
- : Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u1") {
+ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager> profile_manager_,
+ Core::System& system_)
+ : Interface(std::move(module_), std::move(profile_manager_), system_, "acc:u1") {
// clang-format off
static const FunctionInfo functions[] = {
{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 {
class ACC_U1 final : public Module::Interface {
public:
- explicit ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
- Core::System& system);
+ explicit ACC_U1(std::shared_ptr<Module> module_,
+ std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_);
~ACC_U1() override;
};
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 @@
#include "core/file_sys/savedata_factory.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
+#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
@@ -42,6 +42,7 @@
#include "core/hle/service/set/set.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
+#include "core/memory.h"
namespace Service::AM {
@@ -253,7 +254,8 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
IDebugFunctions::~IDebugFunctions() = default;
ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_)
- : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_} {
+ : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_},
+ launchable_event{system.Kernel()}, accumulated_suspended_tick_changed_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISelfController::Exit, "Exit"},
@@ -306,19 +308,20 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- launchable_event = Kernel::KEvent::Create(kernel, "ISelfController:LaunchableEvent");
- launchable_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(launchable_event));
+
+ launchable_event.Initialize("ISelfController:LaunchableEvent");
// This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
// called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
// ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
// suspended if the event has previously been created by a call to
// GetAccumulatedSuspendedTickChangedEvent.
- accumulated_suspended_tick_changed_event =
- Kernel::KEvent::Create(kernel, "ISelfController:AccumulatedSuspendedTickChangedEvent");
- accumulated_suspended_tick_changed_event->Initialize();
- accumulated_suspended_tick_changed_event->GetWritableEvent()->Signal();
+
+ Kernel::KAutoObject::Create(std::addressof(accumulated_suspended_tick_changed_event));
+ accumulated_suspended_tick_changed_event.Initialize(
+ "ISelfController:AccumulatedSuspendedTickChangedEvent");
+ accumulated_suspended_tick_changed_event.GetWritableEvent().Signal();
}
ISelfController::~ISelfController() = default;
@@ -377,11 +380,11 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
- launchable_event->GetWritableEvent()->Signal();
+ launchable_event.GetWritableEvent().Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(launchable_event->GetReadableEvent());
+ rb.PushCopyObjects(launchable_event.GetReadableEvent());
}
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
@@ -560,7 +563,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
+ rb.PushCopyObjects(accumulated_suspended_tick_changed_event.GetReadableEvent());
}
void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
@@ -578,39 +581,40 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo
rb.Push(RESULT_SUCCESS);
}
-AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
- on_new_message = Kernel::KEvent::Create(kernel, "AMMessageQueue:OnMessageReceived");
- on_new_message->Initialize();
- on_operation_mode_changed =
- Kernel::KEvent::Create(kernel, "AMMessageQueue:OperationModeChanged");
- on_operation_mode_changed->Initialize();
+AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel)
+ : on_new_message{kernel}, on_operation_mode_changed{kernel} {
+
+ Kernel::KAutoObject::Create(std::addressof(on_new_message));
+ Kernel::KAutoObject::Create(std::addressof(on_operation_mode_changed));
+
+ on_new_message.Initialize("AMMessageQueue:OnMessageReceived");
+ on_operation_mode_changed.Initialize("AMMessageQueue:OperationModeChanged");
}
AppletMessageQueue::~AppletMessageQueue() = default;
-const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const {
- return on_new_message->GetReadableEvent();
+Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
+ return on_new_message.GetReadableEvent();
}
-const std::shared_ptr<Kernel::KReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
- const {
- return on_operation_mode_changed->GetReadableEvent();
+Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
+ return on_operation_mode_changed.GetReadableEvent();
}
void AppletMessageQueue::PushMessage(AppletMessage msg) {
messages.push(msg);
- on_new_message->GetWritableEvent()->Signal();
+ on_new_message.GetWritableEvent().Signal();
}
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
if (messages.empty()) {
- on_new_message->GetWritableEvent()->Clear();
+ on_new_message.GetWritableEvent().Clear();
return AppletMessage::NoMessage;
}
auto msg = messages.front();
messages.pop();
if (messages.empty()) {
- on_new_message->GetWritableEvent()->Clear();
+ on_new_message.GetWritableEvent().Clear();
}
return msg;
}
@@ -630,7 +634,7 @@ void AppletMessageQueue::FocusStateChanged() {
void AppletMessageQueue::OperationModeChanged() {
PushMessage(AppletMessage::OperationModeChanged);
PushMessage(AppletMessage::PerformanceModeChanged);
- on_operation_mode_changed->GetWritableEvent()->Signal();
+ on_operation_mode_changed.GetWritableEvent().Signal();
}
ICommonStateGetter::ICommonStateGetter(Core::System& system_,
@@ -829,7 +833,7 @@ IStorageImpl::~IStorageImpl() = default;
class StorageDataImpl final : public IStorageImpl {
public:
- explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {}
+ explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {}
std::vector<u8>& GetData() override {
return buffer;
@@ -927,11 +931,9 @@ private:
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
- const auto event = applet->GetBroker().GetStateChangedEvent();
-
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event);
+ rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent());
}
void IsCompleted(Kernel::HLERequestContext& ctx) {
@@ -1213,16 +1215,16 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
}
auto transfer_mem =
- system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
+ system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
- if (transfer_mem == nullptr) {
+ if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
- const u8* const mem_begin = transfer_mem->GetPointer();
+ const u8* const mem_begin = system.Memory().GetPointer(transfer_mem->GetSourceAddress());
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
std::vector<u8> memory{mem_begin, mem_end};
@@ -1247,16 +1249,16 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
}
auto transfer_mem =
- system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
+ system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
- if (transfer_mem == nullptr) {
+ if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
- const u8* const mem_begin = transfer_mem->GetPointer();
+ const u8* const mem_begin = system.Memory().GetPointer(transfer_mem->GetSourceAddress());
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
std::vector<u8> memory{mem_begin, mem_end};
@@ -1266,7 +1268,9 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
}
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
- : ServiceFramework{system_, "IApplicationFunctions"} {
+ : ServiceFramework{system_, "IApplicationFunctions"}, gpu_error_detected_event{system.Kernel()},
+ friend_invitation_storage_channel_event{system.Kernel()},
+ health_warning_disappeared_system_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -1334,16 +1338,15 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- gpu_error_detected_event =
- Kernel::KEvent::Create(kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent");
- gpu_error_detected_event->Initialize();
- friend_invitation_storage_channel_event =
- Kernel::KEvent::Create(kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent");
- friend_invitation_storage_channel_event->Initialize();
- health_warning_disappeared_system_event =
- Kernel::KEvent::Create(kernel, "IApplicationFunctions:HealthWarningDisappearedSystemEvent");
- health_warning_disappeared_system_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(gpu_error_detected_event));
+ Kernel::KAutoObject::Create(std::addressof(friend_invitation_storage_channel_event));
+ Kernel::KAutoObject::Create(std::addressof(health_warning_disappeared_system_event));
+
+ gpu_error_detected_event.Initialize("IApplicationFunctions:GpuErrorDetectedSystemEvent");
+ friend_invitation_storage_channel_event.Initialize(
+ "IApplicationFunctions:FriendInvitationStorageChannelEvent");
+ health_warning_disappeared_system_event.Initialize(
+ "IApplicationFunctions:HealthWarningDisappearedSystemEvent");
}
IApplicationFunctions::~IApplicationFunctions() = default;
@@ -1510,9 +1513,9 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
- auto res = pm.GetControlMetadata();
- if (res.first != nullptr) {
- return res;
+ auto metadata = pm.GetControlMetadata();
+ if (metadata.first != nullptr) {
+ return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
@@ -1547,9 +1550,9 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
- auto res = pm.GetControlMetadata();
- if (res.first != nullptr) {
- return res;
+ auto metadata = pm.GetControlMetadata();
+ if (metadata.first != nullptr) {
+ return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
@@ -1740,7 +1743,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent());
+ rb.PushCopyObjects(gpu_error_detected_event.GetReadableEvent());
}
void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) {
@@ -1748,7 +1751,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent());
+ rb.PushCopyObjects(friend_invitation_storage_channel_event.GetReadableEvent());
}
void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
@@ -1764,7 +1767,7 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
+ rb.PushCopyObjects(health_warning_disappeared_system_event.GetReadableEvent());
}
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
@@ -1782,7 +1785,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
}
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
- : ServiceFramework{system_, "IHomeMenuFunctions"} {
+ : ServiceFramework{system_, "IHomeMenuFunctions"}, pop_from_general_channel_event{
+ system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
@@ -1803,9 +1807,8 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
RegisterHandlers(functions);
- pop_from_general_channel_event =
- Kernel::KEvent::Create(system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent");
- pop_from_general_channel_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(pop_from_general_channel_event));
+ pop_from_general_channel_event.Initialize("IHomeMenuFunctions:PopFromGeneralChannelEvent");
}
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
@@ -1822,7 +1825,7 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
+ rb.PushCopyObjects(pop_from_general_channel_event.GetReadableEvent());
}
IGlobalStateController::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 @@
#include <memory>
#include <queue>
+#include "core/hle/kernel/k_event.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KernelCore;
-class KEvent;
-class TransferMemory;
+class KTransferMemory;
} // namespace Kernel
namespace Service::NVFlinger {
@@ -56,8 +56,8 @@ public:
explicit AppletMessageQueue(Kernel::KernelCore& kernel);
~AppletMessageQueue();
- const std::shared_ptr<Kernel::KReadableEvent>& GetMessageReceiveEvent() const;
- const std::shared_ptr<Kernel::KReadableEvent>& GetOperationModeChangedEvent() const;
+ Kernel::KReadableEvent& GetMessageReceiveEvent();
+ Kernel::KReadableEvent& GetOperationModeChangedEvent();
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
@@ -67,8 +67,8 @@ public:
private:
std::queue<AppletMessage> messages;
- std::shared_ptr<Kernel::KEvent> on_new_message;
- std::shared_ptr<Kernel::KEvent> on_operation_mode_changed;
+ Kernel::KEvent on_new_message;
+ Kernel::KEvent on_operation_mode_changed;
};
class IWindowController final : public ServiceFramework<IWindowController> {
@@ -156,8 +156,8 @@ private:
};
NVFlinger::NVFlinger& nvflinger;
- std::shared_ptr<Kernel::KEvent> launchable_event;
- std::shared_ptr<Kernel::KEvent> accumulated_suspended_tick_changed_event;
+ Kernel::KEvent launchable_event;
+ Kernel::KEvent accumulated_suspended_tick_changed_event;
u32 idle_time_detection_extension = 0;
u64 num_fatal_sections_entered = 0;
@@ -300,9 +300,9 @@ private:
bool launch_popped_application_specific = false;
bool launch_popped_account_preselect = false;
s32 previous_program_index{-1};
- std::shared_ptr<Kernel::KEvent> gpu_error_detected_event;
- std::shared_ptr<Kernel::KEvent> friend_invitation_storage_channel_event;
- std::shared_ptr<Kernel::KEvent> health_warning_disappeared_system_event;
+ Kernel::KEvent gpu_error_detected_event;
+ Kernel::KEvent friend_invitation_storage_channel_event;
+ Kernel::KEvent health_warning_disappeared_system_event;
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
@@ -314,7 +314,7 @@ private:
void RequestToGetForeground(Kernel::HLERequestContext& ctx);
void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx);
- std::shared_ptr<Kernel::KEvent> pop_from_general_channel_event;
+ Kernel::KEvent pop_from_general_channel_event;
};
class 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 @@
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
-#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_writable_event.h"
-#include "core/hle/kernel/server_session.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
@@ -31,16 +29,16 @@
namespace Service::AM::Applets {
AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
- : system{system_}, applet_mode{applet_mode_} {
- state_changed_event =
- Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:StateChangedEvent");
- state_changed_event->Initialize();
- pop_out_data_event =
- Kernel::KEvent::Create(system.Kernel(), "ILibraryAppletAccessor:PopDataOutEvent");
- pop_out_data_event->Initialize();
- pop_interactive_out_data_event = Kernel::KEvent::Create(
- system.Kernel(), "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
- pop_interactive_out_data_event->Initialize();
+ : system{system_}, applet_mode{applet_mode_}, state_changed_event{system.Kernel()},
+ pop_out_data_event{system.Kernel()}, pop_interactive_out_data_event{system.Kernel()} {
+
+ Kernel::KAutoObject::Create(std::addressof(state_changed_event));
+ Kernel::KAutoObject::Create(std::addressof(pop_out_data_event));
+ Kernel::KAutoObject::Create(std::addressof(pop_interactive_out_data_event));
+
+ state_changed_event.Initialize("ILibraryAppletAccessor:StateChangedEvent");
+ pop_out_data_event.Initialize("ILibraryAppletAccessor:PopDataOutEvent");
+ pop_interactive_out_data_event.Initialize("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
}
AppletDataBroker::~AppletDataBroker() = default;
@@ -67,7 +65,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
auto out = std::move(out_channel.front());
out_channel.pop_front();
- pop_out_data_event->GetWritableEvent()->Clear();
+ pop_out_data_event.GetWritableEvent().Clear();
return out;
}
@@ -86,7 +84,7 @@ std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
auto out = std::move(out_interactive_channel.front());
out_interactive_channel.pop_front();
- pop_interactive_out_data_event->GetWritableEvent()->Clear();
+ pop_interactive_out_data_event.GetWritableEvent().Clear();
return out;
}
@@ -105,7 +103,7 @@ void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storag
void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
out_channel.emplace_back(std::move(storage));
- pop_out_data_event->GetWritableEvent()->Signal();
+ pop_out_data_event.GetWritableEvent().Signal();
}
void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
@@ -114,11 +112,11 @@ void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& s
void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
out_interactive_channel.emplace_back(std::move(storage));
- pop_interactive_out_data_event->GetWritableEvent()->Signal();
+ pop_interactive_out_data_event.GetWritableEvent().Signal();
}
-void AppletDataBroker::SignalStateChanged() const {
- state_changed_event->GetWritableEvent()->Signal();
+void AppletDataBroker::SignalStateChanged() {
+ state_changed_event.GetWritableEvent().Signal();
switch (applet_mode) {
case LibraryAppletMode::AllForeground:
@@ -142,16 +140,16 @@ void AppletDataBroker::SignalStateChanged() const {
}
}
-std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
- return pop_out_data_event->GetReadableEvent();
+Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
+ return pop_out_data_event.GetReadableEvent();
}
-std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
- return pop_interactive_out_data_event->GetReadableEvent();
+Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
+ return pop_interactive_out_data_event.GetReadableEvent();
}
-std::shared_ptr<Kernel::KReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
- return state_changed_event->GetReadableEvent();
+Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
+ return state_changed_event.GetReadableEvent();
}
Applet::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 @@
#include <queue>
#include "common/swap.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_event.h"
union ResultCode;
@@ -95,11 +95,11 @@ public:
void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
- void SignalStateChanged() const;
+ void SignalStateChanged();
- std::shared_ptr<Kernel::KReadableEvent> GetNormalDataEvent() const;
- std::shared_ptr<Kernel::KReadableEvent> GetInteractiveDataEvent() const;
- std::shared_ptr<Kernel::KReadableEvent> GetStateChangedEvent() const;
+ Kernel::KReadableEvent& GetNormalDataEvent();
+ Kernel::KReadableEvent& GetInteractiveDataEvent();
+ Kernel::KReadableEvent& GetStateChangedEvent();
private:
Core::System& system;
@@ -119,13 +119,13 @@ private:
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
- std::shared_ptr<Kernel::KEvent> state_changed_event;
+ Kernel::KEvent state_changed_event;
// Signaled on PushNormalDataFromApplet
- std::shared_ptr<Kernel::KEvent> pop_out_data_event;
+ Kernel::KEvent pop_out_data_event;
// Signaled on PushInteractiveDataFromApplet
- std::shared_ptr<Kernel::KEvent> pop_interactive_out_data_event;
+ Kernel::KEvent pop_interactive_out_data_event;
};
class 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 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/error.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/error.h"
#include "core/reporter.h"
@@ -158,11 +158,11 @@ void Error::Execute() {
break;
case ErrorAppletMode::ShowSystemError:
case ErrorAppletMode::ShowApplicationError: {
- const auto system = mode == ErrorAppletMode::ShowSystemError;
+ const auto is_system = mode == ErrorAppletMode::ShowSystemError;
const auto& main_text =
- system ? args->system_error.main_text : args->application_error.main_text;
+ is_system ? args->system_error.main_text : args->application_error.main_text;
const auto& detail_text =
- system ? args->system_error.detail_text : args->application_error.detail_text;
+ is_system ? args->system_error.detail_text : args->application_error.detail_text;
const auto main_text_string =
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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/frontend/applets/general_frontend.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/general_backend.h"
@@ -96,7 +96,7 @@ void Auth::Execute() {
switch (type) {
case AuthAppletType::ShowParentalAuthentication: {
- const auto callback = [this](bool successful) { AuthFinished(successful); };
+ const auto callback = [this](bool is_successful) { AuthFinished(is_successful); };
if (arg0 == 1 && arg1 == 0 && arg2 == 1) {
// 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() {
InitializeFrontendKeyboard();
}
-void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) {
+void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mode) {
LOG_INFO(Service_AM, "Initializing Inline Software Keyboard Applet.");
is_background = true;
@@ -256,9 +256,9 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode applet_mode) {
swkbd_inline_initialize_arg.size());
if (swkbd_initialize_arg.library_applet_mode_flag) {
- ASSERT(applet_mode == LibraryAppletMode::Background);
+ ASSERT(library_applet_mode == LibraryAppletMode::Background);
} else {
- ASSERT(applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
+ ASSERT(library_applet_mode == LibraryAppletMode::BackgroundIndirectDisplay);
}
}
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:
void InitializeForeground();
/// Initializes the inline software keyboard.
- void InitializeBackground(LibraryAppletMode applet_mode);
+ void InitializeBackground(LibraryAppletMode library_applet_mode);
/// Processes the text check sent by the application.
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 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs_vector.h"
#include "core/frontend/applets/web_browser.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#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:
bool complete{false};
ResultCode status{RESULT_SUCCESS};
- WebAppletVersion web_applet_version;
- WebExitReason web_exit_reason;
- WebArgHeader web_arg_header;
+ WebAppletVersion web_applet_version{};
+ WebArgHeader web_arg_header{};
WebArgInputTLVMap web_arg_input_tlv_map;
- u64 title_id;
- FileSys::ContentRecordType nca_type;
+ u64 title_id{};
+ FileSys::ContentRecordType nca_type{};
std::string offline_cache_dir;
std::string offline_document;
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 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/loader/loader.h"
@@ -50,7 +49,7 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
public:
explicit IPurchaseEventManager(Core::System& system_)
- : ServiceFramework{system_, "IPurchaseEventManager"} {
+ : ServiceFramework{system_, "IPurchaseEventManager"}, purchased_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
@@ -63,9 +62,8 @@ public:
RegisterHandlers(functions);
- purchased_event =
- Kernel::KEvent::Create(system.Kernel(), "IPurchaseEventManager:PurchasedEvent");
- purchased_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(purchased_event));
+ purchased_event.Initialize("IPurchaseEventManager:PurchasedEvent");
}
private:
@@ -98,14 +96,15 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(purchased_event->GetReadableEvent());
+ rb.PushCopyObjects(purchased_event.GetReadableEvent());
}
- std::shared_ptr<Kernel::KEvent> purchased_event;
+ Kernel::KEvent purchased_event;
};
AOC_U::AOC_U(Core::System& system_)
- : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)} {
+ : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)},
+ aoc_change_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CountAddOnContentByApplicationId"},
@@ -127,9 +126,8 @@ AOC_U::AOC_U(Core::System& system_)
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- aoc_change_event = Kernel::KEvent::Create(kernel, "GetAddOnContentListChanged:Event");
- aoc_change_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(aoc_change_event));
+ aoc_change_event.Initialize("GetAddOnContentListChanged:Event");
}
AOC_U::~AOC_U() = default;
@@ -256,7 +254,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
+ rb.PushCopyObjects(aoc_change_event.GetReadableEvent());
}
void 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 @@
#pragma once
+#include "core/hle/kernel/k_event.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -31,7 +32,7 @@ private:
void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
std::vector<u64> add_on_content;
- std::shared_ptr<Kernel::KEvent> aoc_change_event;
+ Kernel::KEvent aoc_change_event;
};
/// 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 {
constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7;
-Controller::Controller(Core::Timing::CoreTiming& core_timing)
- : core_timing{core_timing}, configs{
- {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
- {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
- } {}
+Controller::Controller(Core::Timing::CoreTiming& core_timing_)
+ : core_timing{core_timing_}, configs{
+ {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION},
+ {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION},
+ } {}
Controller::~Controller() = default;
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 {
// system during times of high load -- this simply maps to different PerformanceConfigs to use.
class Controller {
public:
- explicit Controller(Core::Timing::CoreTiming& core_timing);
+ explicit Controller(Core::Timing::CoreTiming& core_timing_);
~Controller();
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> {
public:
IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_,
std::string&& device_name_, std::string&& unique_name)
- : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_},
- device_name{std::move(device_name_)}, audio_params{audio_params_}, main_memory{
- system.Memory()} {
+ : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_}, device_name{std::move(
+ device_name_)},
+ audio_params{audio_params_}, buffer_event{system.Kernel()}, main_memory{system.Memory()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -67,13 +67,13 @@ public:
RegisterHandlers(functions);
// This is the event handle used to check if the audio buffer was released
- buffer_event = Kernel::KEvent::Create(system.Kernel(), "IAudioOutBufferReleased");
- buffer_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(buffer_event));
+ buffer_event.Initialize("IAudioOutBufferReleased");
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
audio_params.channel_count, std::move(unique_name), [this] {
const auto guard = LockService();
- buffer_event->GetWritableEvent()->Signal();
+ buffer_event.GetWritableEvent().Signal();
});
}
@@ -126,7 +126,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_event->GetReadableEvent());
+ rb.PushCopyObjects(buffer_event.GetReadableEvent());
}
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -220,7 +220,7 @@ private:
[[maybe_unused]] AudoutParams audio_params{};
/// This is the event handle used to check if the audio buffer was released
- std::shared_ptr<Kernel::KEvent> buffer_event;
+ Kernel::KEvent buffer_event;
Core::Memory::Memory& main_memory;
};
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 {
class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
public:
- explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params,
+ explicit IAudioRenderer(Core::System& system_,
+ const AudioCommon::AudioRendererParameter& audren_params,
const std::size_t instance_number)
- : ServiceFramework{system, "IAudioRenderer"} {
+ : ServiceFramework{system_, "IAudioRenderer"}, system_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -48,13 +49,13 @@ public:
// clang-format on
RegisterHandlers(functions);
- system_event = Kernel::KEvent::Create(system.Kernel(), "IAudioRenderer:SystemEvent");
- system_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(system_event));
+ system_event.Initialize("IAudioRenderer:SystemEvent");
renderer = std::make_unique<AudioCore::AudioRenderer>(
system.CoreTiming(), system.Memory(), audren_params,
[this]() {
const auto guard = LockService();
- system_event->GetWritableEvent()->Signal();
+ system_event.GetWritableEvent().Signal();
},
instance_number);
}
@@ -127,7 +128,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(system_event->GetReadableEvent());
+ rb.PushCopyObjects(system_event.GetReadableEvent());
}
void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
@@ -161,15 +162,16 @@ private:
rb.Push(ERR_NOT_SUPPORTED);
}
- std::shared_ptr<Kernel::KEvent> system_event;
+ Kernel::KEvent system_event;
std::unique_ptr<AudioCore::AudioRenderer> renderer;
u32 rendering_time_limit_percent = 100;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
public:
- explicit IAudioDevice(Core::System& system_, u32_le revision_num)
- : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num} {
+ explicit IAudioDevice(Core::System& system_, Kernel::KEvent& buffer_event_, u32_le revision_)
+ : ServiceFramework{system_, "IAudioDevice"}, buffer_event{buffer_event_}, revision{
+ revision_} {
static const FunctionInfo functions[] = {
{0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
{1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
@@ -186,21 +188,6 @@ public:
{13, nullptr, "GetAudioSystemMasterVolumeSetting"},
};
RegisterHandlers(functions);
-
- auto& kernel = system.Kernel();
- buffer_event = Kernel::KEvent::Create(kernel, "IAudioOutBufferReleasedEvent");
- buffer_event->Initialize();
-
- // Should be similar to audio_output_device_switch_event
- audio_input_device_switch_event =
- Kernel::KEvent::Create(kernel, "IAudioDevice:AudioInputDeviceSwitchedEvent");
- audio_input_device_switch_event->Initialize();
-
- // Should only be signalled when an audio output device has been changed, example: speaker
- // to headset
- audio_output_device_switch_event =
- Kernel::KEvent::Create(kernel, "IAudioDevice:AudioOutputDeviceSwitchedEvent");
- audio_output_device_switch_event->Initialize();
}
private:
@@ -289,11 +276,11 @@ private:
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
- buffer_event->GetWritableEvent()->Signal();
+ buffer_event.GetWritableEvent().Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_event->GetReadableEvent());
+ rb.PushCopyObjects(buffer_event.GetReadableEvent());
}
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
@@ -310,7 +297,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(audio_input_device_switch_event->GetReadableEvent());
+ rb.PushCopyObjects(buffer_event.GetReadableEvent());
}
void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
@@ -318,17 +305,16 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(audio_output_device_switch_event->GetReadableEvent());
+ rb.PushCopyObjects(buffer_event.GetReadableEvent());
}
+ Kernel::KEvent& buffer_event;
u32_le revision = 0;
- std::shared_ptr<Kernel::KEvent> buffer_event;
- std::shared_ptr<Kernel::KEvent> audio_input_device_switch_event;
- std::shared_ptr<Kernel::KEvent> audio_output_device_switch_event;
+};
-}; // namespace Audio
+AudRenU::AudRenU(Core::System& system_)
+ : ServiceFramework{system_, "audren:u"}, buffer_event{system.Kernel()} {
-AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
@@ -340,6 +326,9 @@ AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"}
// clang-format on
RegisterHandlers(functions);
+
+ Kernel::KAutoObject::Create(std::addressof(buffer_event));
+ buffer_event.Initialize("IAudioOutBufferReleasedEvent");
}
AudRenU::~AudRenU() = default;
@@ -373,7 +362,7 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
static constexpr u64 max_perf_detail_entries = 100;
// Size of the data structure representing the bulk of the voice-related state.
- static constexpr u64 voice_state_size = 0x100;
+ static constexpr u64 voice_state_size_bytes = 0x100;
// Size of the upsampler manager data structure
constexpr u64 upsampler_manager_size = 0x48;
@@ -460,7 +449,8 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
size += Common::AlignUp(voice_info_size * params.voice_count, info_field_alignment_size);
size +=
Common::AlignUp(voice_resource_size * params.voice_count, info_field_alignment_size);
- size += Common::AlignUp(voice_state_size * params.voice_count, info_field_alignment_size);
+ size +=
+ Common::AlignUp(voice_state_size_bytes * params.voice_count, info_field_alignment_size);
return size;
};
@@ -662,7 +652,7 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
// always assumes the initial release revision (REV1).
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IAudioDevice>(system, Common::MakeMagic('R', 'E', 'V', '1'));
+ rb.PushIpcInterface<IAudioDevice>(system, buffer_event, Common::MakeMagic('R', 'E', 'V', '1'));
}
void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
@@ -684,7 +674,7 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IAudioDevice>(system, revision);
+ rb.PushIpcInterface<IAudioDevice>(system, buffer_event, revision);
}
void 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 @@
#pragma once
+#include "core/hle/kernel/k_event.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -31,6 +32,7 @@ private:
void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
std::size_t audren_instance_count = 0;
+ Kernel::KEvent buffer_event;
};
// 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:
Enabled,
};
- explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count)
- : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {}
+ explicit OpusDecoderState(OpusDecoderPtr decoder_, u32 sample_rate_, u32 channel_count_)
+ : decoder{std::move(decoder_)}, sample_rate{sample_rate_}, channel_count{channel_count_} {}
// Decodes interleaved Opus packets. Optionally allows reporting time taken to
// perform the decoding, as well as any relevant extra behavior.
@@ -160,9 +160,9 @@ private:
class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
public:
- explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state)
+ explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state_)
: ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{
- std::move(decoder_state)} {
+ std::move(decoder_state_)} {
// clang-format off
static const FunctionInfo functions[] = {
{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 @@
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/lock.h"
@@ -14,14 +13,14 @@
namespace Service::BCAT {
ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel,
- std::string_view event_name) {
- event = Kernel::KEvent::Create(kernel,
- "ProgressServiceBackend:UpdateEvent:" + std::string(event_name));
- event->Initialize();
+ std::string_view event_name)
+ : update_event{kernel} {
+ Kernel::KAutoObject::Create(std::addressof(update_event));
+ update_event.Initialize("ProgressServiceBackend:UpdateEvent:" + std::string(event_name));
}
-std::shared_ptr<Kernel::KReadableEvent> ProgressServiceBackend::GetEvent() const {
- return event->GetReadableEvent();
+Kernel::KReadableEvent& ProgressServiceBackend::GetEvent() {
+ return update_event.GetReadableEvent();
}
DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
@@ -86,12 +85,12 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
SignalUpdate();
}
-void ProgressServiceBackend::SignalUpdate() const {
+void ProgressServiceBackend::SignalUpdate() {
if (need_hle_lock) {
std::lock_guard lock(HLE::g_hle_lock);
- event->GetWritableEvent()->Signal();
+ update_event.GetWritableEvent().Signal();
} else {
- event->GetWritableEvent()->Signal();
+ update_event.GetWritableEvent().Signal();
}
}
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 @@
#include "common/common_types.h"
#include "core/file_sys/vfs_types.h"
+#include "core/hle/kernel/k_event.h"
#include "core/hle/result.h"
namespace Core {
@@ -98,13 +99,13 @@ public:
private:
explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name);
- std::shared_ptr<Kernel::KReadableEvent> GetEvent() const;
+ Kernel::KReadableEvent& GetEvent();
DeliveryCacheProgressImpl& GetImpl();
- void SignalUpdate() const;
+ void SignalUpdate();
DeliveryCacheProgressImpl impl{};
- std::shared_ptr<Kernel::KEvent> event;
+ Kernel::KEvent update_event;
bool need_hle_lock = false;
};
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 @@
// Refer to the license.txt file included.
#include <fmt/ostream.h>
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#endif
#include <httplib.h>
#include <mbedtls/sha256.h>
#include <nlohmann/json.hpp>
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
#include "common/hex_util.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
@@ -178,8 +187,8 @@ bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest,
class Boxcat::Client {
public:
- Client(std::string path, u64 title_id, u64 build_id)
- : path(std::move(path)), title_id(title_id), build_id(build_id) {}
+ Client(std::string path_, u64 title_id_, u64 build_id_)
+ : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {}
DownloadResult DownloadDataZip() {
return DownloadInternal(fmt::format(BOXCAT_PATHNAME_DATA, title_id), TIMEOUT_SECONDS,
@@ -415,9 +424,9 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
if (Settings::values.bcat_boxcat_local) {
LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download.");
} else {
- Boxcat::Client client{path, title.title_id, title.build_id};
+ Client launch_client{path, title.title_id, title.build_id};
- const auto res = client.DownloadLaunchParam();
+ const auto res = launch_client.DownloadLaunchParam();
if (res != DownloadResult::Success) {
LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
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 @@
namespace Service::BCAT {
-BCAT::BCAT(Core::System& system, std::shared_ptr<Module> module,
- FileSystem::FileSystemController& fsc, const char* name)
- : Interface(system, std::move(module), fsc, name) {
+BCAT::BCAT(Core::System& system_, std::shared_ptr<Module> module_,
+ FileSystem::FileSystemController& fsc_, const char* name_)
+ : Interface(system_, std::move(module_), fsc_, name_) {
// clang-format off
static const FunctionInfo functions[] = {
{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 {
class BCAT final : public Module::Interface {
public:
- explicit BCAT(Core::System& system, std::shared_ptr<Module> module,
- FileSystem::FileSystemController& fsc, const char* name);
+ explicit BCAT(Core::System& system_, std::shared_ptr<Module> module_,
+ FileSystem::FileSystemController& fsc_, const char* name_);
~BCAT() override;
};
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 @@
#include "core/core.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_writable_event.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/bcat/bcat.h"
#include "core/hle/service/bcat/module.h"
@@ -88,11 +88,9 @@ struct DeliveryCacheDirectoryEntry {
class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
public:
- explicit IDeliveryCacheProgressService(Core::System& system_,
- std::shared_ptr<Kernel::KReadableEvent> event_,
+ explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_,
const DeliveryCacheProgressImpl& impl_)
- : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)},
- impl{impl_} {
+ : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"},
@@ -121,7 +119,7 @@ private:
rb.Push(RESULT_SUCCESS);
}
- std::shared_ptr<Kernel::KReadableEvent> event;
+ Kernel::KReadableEvent& event;
const DeliveryCacheProgressImpl& impl;
};
@@ -174,9 +172,9 @@ private:
};
std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) {
- auto& backend{progress.at(static_cast<std::size_t>(type))};
- return std::make_shared<IDeliveryCacheProgressService>(system, backend.GetEvent(),
- backend.GetImpl());
+ auto& progress_backend{GetProgressBackend(type)};
+ return std::make_shared<IDeliveryCacheProgressService>(system, progress_backend.GetEvent(),
+ progress_backend.GetImpl());
}
void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) {
@@ -184,7 +182,7 @@ private:
backend.Synchronize({system.CurrentProcess()->GetTitleID(),
GetCurrentBuildID(system.GetCurrentProcessBuildID())},
- progress.at(static_cast<std::size_t>(SyncType::Normal)));
+ GetProgressBackend(SyncType::Normal));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -201,8 +199,7 @@ private:
backend.SynchronizeDirectory({system.CurrentProcess()->GetTitleID(),
GetCurrentBuildID(system.GetCurrentProcessBuildID())},
- name,
- progress.at(static_cast<std::size_t>(SyncType::Directory)));
+ name, GetProgressBackend(SyncType::Directory));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -265,9 +262,16 @@ private:
rb.Push(RESULT_SUCCESS);
}
- Backend& backend;
+ ProgressServiceBackend& GetProgressBackend(SyncType type) {
+ return progress.at(static_cast<size_t>(type));
+ }
- std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress;
+ const ProgressServiceBackend& GetProgressBackend(SyncType type) const {
+ return progress.at(static_cast<size_t>(type));
+ }
+
+ Backend& backend;
+ std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
};
void 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 {
class Bt final : public ServiceFramework<Bt> {
public:
- explicit Bt(Core::System& system_) : ServiceFramework{system_, "bt"} {
+ explicit Bt(Core::System& system_)
+ : ServiceFramework{system_, "bt"}, register_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "LeClientReadCharacteristic"},
@@ -34,9 +35,8 @@ public:
// clang-format on
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- register_event = Kernel::KEvent::Create(kernel, "BT:RegisterEvent");
- register_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(register_event));
+ register_event.Initialize("BT:RegisterEvent");
}
private:
@@ -45,10 +45,10 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(register_event->GetReadableEvent());
+ rb.PushCopyObjects(register_event.GetReadableEvent());
}
- std::shared_ptr<Kernel::KEvent> register_event;
+ Kernel::KEvent register_event;
};
class 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 {
class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
public:
- explicit IBtmUserCore(Core::System& system_) : ServiceFramework{system_, "IBtmUserCore"} {
+ explicit IBtmUserCore(Core::System& system_)
+ : ServiceFramework{system_, "IBtmUserCore"}, scan_event{system.Kernel()},
+ connection_event{system.Kernel()}, service_discovery{system.Kernel()},
+ config_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -57,15 +60,15 @@ public:
// clang-format on
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- scan_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ScanEvent");
- scan_event->Initialize();
- connection_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConnectionEvent");
- connection_event->Initialize();
- service_discovery = Kernel::KEvent::Create(kernel, "IBtmUserCore:Discovery");
- service_discovery->Initialize();
- config_event = Kernel::KEvent::Create(kernel, "IBtmUserCore:ConfigEvent");
- config_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(scan_event));
+ Kernel::KAutoObject::Create(std::addressof(connection_event));
+ Kernel::KAutoObject::Create(std::addressof(service_discovery));
+ Kernel::KAutoObject::Create(std::addressof(config_event));
+
+ scan_event.Initialize("IBtmUserCore:ScanEvent");
+ connection_event.Initialize("IBtmUserCore:ConnectionEvent");
+ service_discovery.Initialize("IBtmUserCore:Discovery");
+ config_event.Initialize("IBtmUserCore:ConfigEvent");
}
private:
@@ -74,7 +77,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(scan_event->GetReadableEvent());
+ rb.PushCopyObjects(scan_event.GetReadableEvent());
}
void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) {
@@ -82,7 +85,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(connection_event->GetReadableEvent());
+ rb.PushCopyObjects(connection_event.GetReadableEvent());
}
void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) {
@@ -90,7 +93,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(service_discovery->GetReadableEvent());
+ rb.PushCopyObjects(service_discovery.GetReadableEvent());
}
void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) {
@@ -98,13 +101,13 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(config_event->GetReadableEvent());
+ rb.PushCopyObjects(config_event.GetReadableEvent());
}
- std::shared_ptr<Kernel::KEvent> scan_event;
- std::shared_ptr<Kernel::KEvent> connection_event;
- std::shared_ptr<Kernel::KEvent> service_discovery;
- std::shared_ptr<Kernel::KEvent> config_event;
+ Kernel::KEvent scan_event;
+ Kernel::KEvent connection_event;
+ Kernel::KEvent service_discovery;
+ Kernel::KEvent config_event;
};
class 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 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/fatal/fatal_p.h"
#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 @@
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_offset.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_ldr.h"
#include "core/hle/service/filesystem/fsp_pr.h"
@@ -55,10 +55,15 @@ std::string VfsDirectoryServiceWrapper::GetName() const {
ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
- // dir can be nullptr if path contains subdirectories, create those prior to creating the file.
if (dir == nullptr) {
- dir = backing->CreateSubdirectory(Common::FS::GetParentPath(path));
+ return FileSys::ERROR_PATH_NOT_FOUND;
+ }
+
+ const auto entry_type = GetEntryType(path);
+ if (entry_type.Code() == RESULT_SUCCESS) {
+ return FileSys::ERROR_PATH_ALREADY_EXISTS;
}
+
auto file = dir->CreateFile(Common::FS::GetFilename(path));
if (file == nullptr) {
// 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 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/reporter.h"
@@ -337,13 +337,14 @@ public:
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
- const u64 mode = rp.Pop<u64>();
- const u32 size = rp.Pop<u32>();
+ const u64 file_mode = rp.Pop<u64>();
+ const u32 file_size = rp.Pop<u32>();
- LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, mode, size);
+ LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
+ file_size);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CreateFile(name, size));
+ rb.Push(backend.CreateFile(name, file_size));
}
void DeleteFile(Kernel::HLERequestContext& ctx) {
@@ -935,8 +936,8 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- auto romfs = fsc.OpenRomFSCurrentProcess();
- if (romfs.Failed()) {
+ auto current_romfs = fsc.OpenRomFSCurrentProcess();
+ if (current_romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -944,7 +945,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
return;
}
- auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap()));
+ auto storage = std::make_shared<IStorage>(system, std::move(current_romfs.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -1010,10 +1011,10 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
- auto romfs = fsc.OpenPatchedRomFSWithProgramIndex(
+ auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex(
system.CurrentProcess()->GetTitleID(), program_index, FileSys::ContentRecordType::Program);
- if (romfs.Failed()) {
+ if (patched_romfs.Failed()) {
// TODO: Find the right error code to use here
LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
@@ -1022,7 +1023,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
return;
}
- auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap()));
+ auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs.Unwrap()));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
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:
class INotificationService final : public ServiceFramework<INotificationService> {
public:
explicit INotificationService(Common::UUID uuid_, Core::System& system_)
- : ServiceFramework{system_, "INotificationService"}, uuid{uuid_} {
+ : ServiceFramework{system_, "INotificationService"}, uuid{uuid_}, notification_event{
+ system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &INotificationService::GetEvent, "GetEvent"},
@@ -196,9 +197,8 @@ public:
RegisterHandlers(functions);
- notification_event =
- Kernel::KEvent::Create(system.Kernel(), "INotificationService:NotifyEvent");
- notification_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(notification_event));
+ notification_event.Initialize("INotificationService:NotifyEvent");
}
private:
@@ -207,7 +207,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(notification_event->GetReadableEvent());
+ rb.PushCopyObjects(notification_event.GetReadableEvent());
}
void Clear(Kernel::HLERequestContext& ctx) {
@@ -273,7 +273,7 @@ private:
};
Common::UUID uuid{Common::INVALID_UUID};
- std::shared_ptr<Kernel::KEvent> notification_event;
+ Kernel::KEvent notification_event;
std::queue<SizedNotificationInfo> notifications;
States states{};
};
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 @@
#include "core/file_sys/control_metadata.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/glue/arp.h"
#include "core/hle/service/glue/errors.h"
#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 {
class GRC final : public ServiceFramework<GRC> {
public:
- explicit GRC(Core::System& system) : ServiceFramework{system, "grc:c"} {
+ explicit GRC(Core::System& system_) : ServiceFramework{system_, "grc:c"} {
// clang-format off
static const FunctionInfo functions[] = {
{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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/settings.h"
+#include "core/core_timing.h"
+#include "core/hle/service/hid/controllers/console_sixaxis.h"
+
+namespace Service::HID {
+constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
+
+Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_)
+ : ControllerBase{system_} {}
+Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
+
+void Controller_ConsoleSixAxis::OnInit() {}
+
+void Controller_ConsoleSixAxis::OnRelease() {}
+
+void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
+ std::size_t size) {
+ seven_six_axis.header.timestamp = core_timing.GetCPUTicks();
+ seven_six_axis.header.total_entry_count = 17;
+
+ if (!IsControllerActivated() || !is_transfer_memory_set) {
+ seven_six_axis.header.entry_count = 0;
+ seven_six_axis.header.last_entry_index = 0;
+ return;
+ }
+ seven_six_axis.header.entry_count = 16;
+
+ const auto& last_entry =
+ seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
+ seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17;
+ auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
+
+ cur_entry.sampling_number = last_entry.sampling_number + 1;
+ cur_entry.sampling_number2 = cur_entry.sampling_number;
+
+ // Try to read sixaxis sensor states
+ MotionDevice motion_device{};
+ const auto& device = motions[0];
+ if (device) {
+ std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation,
+ motion_device.orientation, motion_device.quaternion) = device->GetStatus();
+ console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f;
+ }
+
+ cur_entry.accel = motion_device.accel;
+ // Zero gyro values as they just mess up with the camera
+ // Note: Probably a correct sensivity setting must be set
+ cur_entry.gyro = {};
+ cur_entry.quaternion = {
+ {
+ motion_device.quaternion.xyz.y,
+ motion_device.quaternion.xyz.x,
+ -motion_device.quaternion.w,
+ },
+ -motion_device.quaternion.xyz.z,
+ };
+
+ console_six_axis.sampling_number++;
+ // TODO(German77): Find the purpose of those values
+ console_six_axis.verticalization_error = 0.0f;
+ console_six_axis.gyro_bias = {0.0f, 0.0f, 0.0f};
+
+ // Update console six axis shared memory
+ std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis));
+ // Update seven six axis transfer memory
+ std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis));
+}
+
+void Controller_ConsoleSixAxis::OnLoadInputDevices() {
+ const auto player = Settings::values.players.GetValue()[0];
+ std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
+ player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(),
+ Input::CreateDevice<Input::MotionDevice>);
+}
+
+void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
+ is_transfer_memory_set = true;
+ transfer_memory = t_mem;
+}
+
+void Controller_ConsoleSixAxis::ResetTimestamp() {
+ auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index];
+ cur_entry.sampling_number = 0;
+ cur_entry.sampling_number2 = 0;
+}
+} // 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 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/quaternion.h"
+#include "core/frontend/input.h"
+#include "core/hle/service/hid/controllers/controller_base.h"
+
+namespace Service::HID {
+class Controller_ConsoleSixAxis final : public ControllerBase {
+public:
+ explicit Controller_ConsoleSixAxis(Core::System& system_);
+ ~Controller_ConsoleSixAxis() override;
+
+ // Called when the controller is initialized
+ void OnInit() override;
+
+ // When the controller is released
+ void OnRelease() override;
+
+ // When the controller is requesting an update for the shared memory
+ void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
+
+ // Called when input devices should be loaded
+ void OnLoadInputDevices() override;
+
+ // Called on InitializeSevenSixAxisSensor
+ void SetTransferMemoryPointer(u8* t_mem);
+
+ // Called on ResetSevenSixAxisSensorTimestamp
+ void ResetTimestamp();
+
+private:
+ struct SevenSixAxisState {
+ INSERT_PADDING_WORDS(4); // unused
+ s64_le sampling_number{};
+ s64_le sampling_number2{};
+ u64 unknown{};
+ Common::Vec3f accel{};
+ Common::Vec3f gyro{};
+ Common::Quaternion<f32> quaternion{};
+ };
+ static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size");
+
+ struct SevenSixAxisMemory {
+ CommonHeader header{};
+ std::array<SevenSixAxisState, 0x21> sevensixaxis_states{};
+ };
+ static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size");
+
+ struct ConsoleSharedMemory {
+ u64_le sampling_number{};
+ bool is_seven_six_axis_sensor_at_rest{};
+ f32 verticalization_error{};
+ Common::Vec3f gyro_bias{};
+ };
+ static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
+
+ struct MotionDevice {
+ Common::Vec3f accel;
+ Common::Vec3f gyro;
+ Common::Vec3f rotation;
+ std::array<Common::Vec3f, 3> orientation;
+ Common::Quaternion<f32> quaternion;
+ };
+
+ using MotionArray =
+ std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>;
+ MotionArray motions;
+ u8* transfer_memory = nullptr;
+ bool is_transfer_memory_set = false;
+ ConsoleSharedMemory console_six_axis{};
+ SevenSixAxisMemory seven_six_axis{};
+};
+} // 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 @@
namespace Service::HID {
-ControllerBase::ControllerBase(Core::System& system) : system(system) {}
+ControllerBase::ControllerBase(Core::System& system_) : system(system_) {}
ControllerBase::~ControllerBase() = default;
void 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;
namespace Service::HID {
class ControllerBase {
public:
- explicit ControllerBase(Core::System& system);
+ explicit ControllerBase(Core::System& system_);
virtual ~ControllerBase();
// 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;
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
-Controller_DebugPad::Controller_DebugPad(Core::System& system) : ControllerBase(system) {}
+Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {}
Controller_DebugPad::~Controller_DebugPad() = default;
void 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 @@
namespace Service::HID {
class Controller_DebugPad final : public ControllerBase {
public:
- explicit Controller_DebugPad(Core::System& system);
+ explicit Controller_DebugPad(Core::System& system_);
~Controller_DebugPad() override;
// 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 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <cstring>
-#include "common/common_types.h"
#include "common/logging/log.h"
+#include "common/math_util.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
@@ -12,10 +11,19 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
-constexpr f32 angle_threshold = 0.08f;
-constexpr f32 pinch_threshold = 100.0f;
-Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {}
+// HW is around 700, value is set to 400 to make it easier to trigger with mouse
+constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
+constexpr f32 angle_threshold = 0.015f; // Threshold in radians
+constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels
+constexpr f32 press_delay = 0.5f; // Time in seconds
+constexpr f32 double_tap_delay = 0.35f; // Time in seconds
+
+constexpr f32 Square(s32 num) {
+ return static_cast<f32>(num * num);
+}
+
+Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {}
Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() {
@@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() {
keyboard_finger_id[id] = MAX_POINTS;
udp_finger_id[id] = MAX_POINTS;
}
+ shared_memory.header.entry_count = 0;
+ force_update = true;
}
void Controller_Gesture::OnRelease() {}
@@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
shared_memory.header.last_entry_index = 0;
return;
}
- shared_memory.header.entry_count = 16;
- const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
- shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
- auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+ ReadTouchInput();
- cur_entry.sampling_number = last_entry.sampling_number + 1;
- cur_entry.sampling_number2 = cur_entry.sampling_number;
+ GestureProperties gesture = GetGestureProperties();
+ f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) /
+ (1000 * 1000 * 1000);
- // TODO(german77): Implement all gesture types
+ // Only update if necesary
+ if (!ShouldUpdateGesture(gesture, time_difference)) {
+ return;
+ }
+ last_update_timestamp = shared_memory.header.timestamp;
+ UpdateGestureSharedMemory(data, size, gesture, time_difference);
+}
+
+void Controller_Gesture::ReadTouchInput() {
const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus();
const Input::TouchStatus& udp_status = touch_udp_device->GetStatus();
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
UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]);
}
}
+}
- TouchType type = TouchType::Idle;
- Attribute attributes{};
- GestureProperties gesture = GetGestureProperties();
- if (last_gesture.active_points != gesture.active_points) {
- ++last_gesture.detection_count;
+bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
+ f32 time_difference) {
+ const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+ if (force_update) {
+ force_update = false;
+ return true;
}
- if (gesture.active_points > 0) {
- if (last_gesture.active_points == 0) {
- attributes.is_new_touch.Assign(true);
- last_gesture.average_distance = gesture.average_distance;
- last_gesture.angle = gesture.angle;
- }
- type = TouchType::Touch;
- if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) {
- type = TouchType::Pan;
- }
- if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) {
- type = TouchType::Pinch;
- }
- if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) {
- type = TouchType::Rotate;
+ // Update if coordinates change
+ for (size_t id = 0; id < MAX_POINTS; id++) {
+ if (gesture.points[id].x != last_gesture.points[id].x ||
+ gesture.points[id].y != last_gesture.points[id].y) {
+ return true;
}
+ }
- cur_entry.delta_x = gesture.mid_point.x - last_entry.x;
- cur_entry.delta_y = gesture.mid_point.y - last_entry.y;
- // TODO: Find how velocities are calculated
- cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f;
- cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f;
+ // Update on press and hold event after 0.5 seconds
+ if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 &&
+ time_difference > press_delay) {
+ return enable_press_and_tap;
+ }
- // Slowdown the rate of change for less flapping
- last_gesture.average_distance =
- (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f);
- last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f);
+ return false;
+}
+void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
+ GestureProperties& gesture,
+ f32 time_difference) {
+ TouchType type = TouchType::Idle;
+ Attribute attributes{};
+
+ const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+ shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
+ auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+
+ if (shared_memory.header.entry_count < 16) {
+ shared_memory.header.entry_count++;
+ }
+
+ cur_entry.sampling_number = last_entry.sampling_number + 1;
+ cur_entry.sampling_number2 = cur_entry.sampling_number;
+
+ // Reset values to default
+ cur_entry.delta_x = 0;
+ cur_entry.delta_y = 0;
+ cur_entry.vel_x = 0;
+ cur_entry.vel_y = 0;
+ cur_entry.direction = Direction::None;
+ cur_entry.rotation_angle = 0;
+ cur_entry.scale = 0;
+
+ if (gesture.active_points > 0) {
+ if (last_gesture.active_points == 0) {
+ NewGesture(gesture, type, attributes);
+ } else {
+ UpdateExistingGesture(gesture, type, time_difference);
+ }
} else {
- cur_entry.delta_x = 0;
- cur_entry.delta_y = 0;
- cur_entry.vel_x = 0;
- cur_entry.vel_y = 0;
+ EndGesture(gesture, last_gesture, type, attributes, time_difference);
}
- last_gesture.active_points = gesture.active_points;
- cur_entry.detection_count = last_gesture.detection_count;
+
+ // Apply attributes
+ cur_entry.detection_count = gesture.detection_count;
cur_entry.type = type;
cur_entry.attributes = attributes;
cur_entry.x = gesture.mid_point.x;
@@ -116,12 +153,195 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
cur_entry.points[id].x = gesture.points[id].x;
cur_entry.points[id].y = gesture.points[id].y;
}
- cur_entry.rotation_angle = 0;
- cur_entry.scale = 0;
+ last_gesture = gesture;
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
}
+void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type,
+ Attribute& attributes) {
+ const auto& last_entry =
+ shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
+ gesture.detection_count++;
+ type = TouchType::Touch;
+
+ // New touch after cancel is not considered new
+ if (last_entry.type != TouchType::Cancel) {
+ attributes.is_new_touch.Assign(1);
+ enable_press_and_tap = true;
+ }
+}
+
+void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type,
+ f32 time_difference) {
+ const auto& last_entry =
+ shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
+
+ // Promote to pan type if touch moved
+ for (size_t id = 0; id < MAX_POINTS; id++) {
+ if (gesture.points[id].x != last_gesture.points[id].x ||
+ gesture.points[id].y != last_gesture.points[id].y) {
+ type = TouchType::Pan;
+ break;
+ }
+ }
+
+ // Number of fingers changed cancel the last event and clear data
+ if (gesture.active_points != last_gesture.active_points) {
+ type = TouchType::Cancel;
+ enable_press_and_tap = false;
+ gesture.active_points = 0;
+ gesture.mid_point = {};
+ for (size_t id = 0; id < MAX_POINTS; id++) {
+ gesture.points[id].x = 0;
+ gesture.points[id].y = 0;
+ }
+ return;
+ }
+
+ // Calculate extra parameters of panning
+ if (type == TouchType::Pan) {
+ UpdatePanEvent(gesture, last_gesture, type, time_difference);
+ return;
+ }
+
+ // Promote to press type
+ if (last_entry.type == TouchType::Touch) {
+ type = TouchType::Press;
+ }
+}
+
+void Controller_Gesture::EndGesture(GestureProperties& gesture,
+ GestureProperties& last_gesture_props, TouchType& type,
+ Attribute& attributes, f32 time_difference) {
+ const auto& last_entry =
+ shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
+ if (last_gesture_props.active_points != 0) {
+ switch (last_entry.type) {
+ case TouchType::Touch:
+ if (enable_press_and_tap) {
+ SetTapEvent(gesture, last_gesture_props, type, attributes);
+ return;
+ }
+ type = TouchType::Cancel;
+ force_update = true;
+ break;
+ case TouchType::Press:
+ case TouchType::Tap:
+ case TouchType::Swipe:
+ case TouchType::Pinch:
+ case TouchType::Rotate:
+ type = TouchType::Complete;
+ force_update = true;
+ break;
+ case TouchType::Pan:
+ EndPanEvent(gesture, last_gesture_props, type, time_difference);
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) {
+ gesture.detection_count++;
+ }
+}
+
+void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
+ GestureProperties& last_gesture_props, TouchType& type,
+ Attribute& attributes) {
+ type = TouchType::Tap;
+ gesture = last_gesture_props;
+ force_update = true;
+ f32 tap_time_difference =
+ static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
+ last_tap_timestamp = last_update_timestamp;
+ if (tap_time_difference < double_tap_delay) {
+ attributes.is_double_tap.Assign(1);
+ }
+}
+
+void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
+ GestureProperties& last_gesture_props, TouchType& type,
+ f32 time_difference) {
+ auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+ const auto& last_entry =
+ shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
+ cur_entry.delta_x = gesture.mid_point.x - last_entry.x;
+ cur_entry.delta_y = gesture.mid_point.y - last_entry.y;
+
+ cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference;
+ cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference;
+ last_pan_time_difference = time_difference;
+
+ // Promote to pinch type
+ if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
+ pinch_threshold) {
+ type = TouchType::Pinch;
+ cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance;
+ }
+
+ const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
+ (1 + (gesture.angle * last_gesture_props.angle)));
+ // Promote to rotate type
+ if (std::abs(angle_between_two_lines) > angle_threshold) {
+ type = TouchType::Rotate;
+ cur_entry.scale = 0;
+ cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
+ }
+}
+
+void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
+ GestureProperties& last_gesture_props, TouchType& type,
+ f32 time_difference) {
+ auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+ const auto& last_entry =
+ shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
+ cur_entry.vel_x =
+ static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference);
+ cur_entry.vel_y =
+ static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference);
+ const f32 curr_vel =
+ std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y));
+
+ // Set swipe event with parameters
+ if (curr_vel > swipe_threshold) {
+ SetSwipeEvent(gesture, last_gesture_props, type);
+ return;
+ }
+
+ // End panning without swipe
+ type = TouchType::Complete;
+ cur_entry.vel_x = 0;
+ cur_entry.vel_y = 0;
+ force_update = true;
+}
+
+void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
+ GestureProperties& last_gesture_props, TouchType& type) {
+ auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
+ const auto& last_entry =
+ shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
+ type = TouchType::Swipe;
+ gesture = last_gesture_props;
+ force_update = true;
+ cur_entry.delta_x = last_entry.delta_x;
+ cur_entry.delta_y = last_entry.delta_y;
+ if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) {
+ if (cur_entry.delta_x > 0) {
+ cur_entry.direction = Direction::Right;
+ return;
+ }
+ cur_entry.direction = Direction::Left;
+ return;
+ }
+ if (cur_entry.delta_y > 0) {
+ cur_entry.direction = Direction::Down;
+ return;
+ }
+ cur_entry.direction = Direction::Up;
+}
+
void Controller_Gesture::OnLoadInputDevices() {
touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window");
touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp");
@@ -129,6 +349,10 @@ void Controller_Gesture::OnLoadInputDevices() {
}
std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const {
+ // Dont assign any touch input to a point if disabled
+ if (!Settings::values.touchscreen.enabled) {
+ return std::nullopt;
+ }
std::size_t first_free_id = 0;
while (first_free_id < MAX_POINTS) {
if (!fingers[first_free_id].pressed) {
@@ -179,23 +403,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties()
for (size_t id = 0; id < gesture.active_points; ++id) {
gesture.points[id].x =
- static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width);
+ static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width);
gesture.points[id].y =
- static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height);
- gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points);
- gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points);
+ static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height);
+
+ // Hack: There is no touch in docked but games still allow it
+ if (Settings::values.use_docked_mode.GetValue()) {
+ gesture.points[id].x =
+ static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width);
+ gesture.points[id].y =
+ static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height);
+ }
+
+ gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
+ gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
}
for (size_t id = 0; id < gesture.active_points; ++id) {
- const double distance =
- std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) +
- std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2);
- gesture.average_distance +=
- static_cast<float>(distance) / static_cast<float>(gesture.active_points);
+ const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
+ Square(gesture.mid_point.y - gesture.points[id].y));
+ gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
}
- gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y),
- static_cast<float>(gesture.mid_point.x - gesture.points[0].x));
+ gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
+ static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
+
+ gesture.detection_count = last_gesture.detection_count;
+
return gesture;
}
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 @@
-// Copyright 2018 yuzu emulator team
+// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,14 +7,13 @@
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
-#include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
namespace Service::HID {
class Controller_Gesture final : public ControllerBase {
public:
- explicit Controller_Gesture(Core::System& system);
+ explicit Controller_Gesture(Core::System& system_);
~Controller_Gesture() override;
// Called when the controller is initialized
@@ -35,10 +34,10 @@ private:
enum class TouchType : u32 {
Idle, // Nothing touching the screen
- Complete, // Unknown. End of touch?
- Cancel, // Never triggered
- Touch, // Pressing without movement
- Press, // Never triggered
+ Complete, // Set at the end of a touch event
+ Cancel, // Set when the number of fingers change
+ Touch, // A finger just touched the screen
+ Press, // Set if last type is touch and the finger hasn't moved
Tap, // Fast press then release
Pan, // All points moving together across the screen
Swipe, // Fast press movement and release of a single point
@@ -58,8 +57,8 @@ private:
union {
u32_le raw{};
- BitField<0, 1, u32> is_new_touch;
- BitField<1, 1, u32> is_double_tap;
+ BitField<4, 1, u32> is_new_touch;
+ BitField<8, 1, u32> is_double_tap;
};
};
static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size");
@@ -73,10 +72,9 @@ private:
struct GestureState {
s64_le sampling_number;
s64_le sampling_number2;
-
s64_le detection_count;
TouchType type;
- Direction dir;
+ Direction direction;
s32_le x;
s32_le y;
s32_le delta_x;
@@ -84,8 +82,8 @@ private:
f32 vel_x;
f32 vel_y;
Attribute attributes;
- u32 scale;
- u32 rotation_angle;
+ f32 scale;
+ f32 rotation_angle;
s32_le point_count;
std::array<Points, 4> points;
};
@@ -109,17 +107,55 @@ private:
Points mid_point{};
s64_le detection_count{};
u64_le delta_time{};
- float average_distance{};
- float angle{};
+ f32 average_distance{};
+ f32 angle{};
};
- // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned
+ // Reads input from all available input engines
+ void ReadTouchInput();
+
+ // Returns true if gesture state needs to be updated
+ bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference);
+
+ // Updates the shared memory to the next state
+ void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture,
+ f32 time_difference);
+
+ // Initializes new gesture
+ void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes);
+
+ // Updates existing gesture state
+ void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference);
+
+ // Terminates exiting gesture
+ void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
+ TouchType& type, Attribute& attributes, f32 time_difference);
+
+ // Set current event to a tap event
+ void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
+ TouchType& type, Attribute& attributes);
+
+ // Calculates and set the extra parameters related to a pan event
+ void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
+ TouchType& type, f32 time_difference);
+
+ // Terminates the pan event
+ void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
+ TouchType& type, f32 time_difference);
+
+ // Set current event to a swipe event
+ void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
+ TouchType& type);
+
+ // Returns an unused finger id, if there is no fingers available std::nullopt is returned.
std::optional<size_t> GetUnusedFingerID() const;
- /** If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no
+ /**
+ * If the touch is new it tries to assign a new finger id, if there is no fingers available no
* changes will be made. Updates the coordinates if the finger id it's already set. If the touch
* ends delays the output by one frame to set the end_touch flag before finally freeing the
- * finger id */
+ * finger id
+ */
size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
size_t finger_id);
@@ -134,6 +170,11 @@ private:
std::array<size_t, MAX_FINGERS> keyboard_finger_id;
std::array<size_t, MAX_FINGERS> udp_finger_id;
std::array<Finger, MAX_POINTS> fingers;
- GestureProperties last_gesture;
+ GestureProperties last_gesture{};
+ s64_le last_update_timestamp{};
+ s64_le last_tap_timestamp{};
+ f32 last_pan_time_difference{};
+ bool force_update{false};
+ bool enable_press_and_tap{false};
};
} // 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 {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
constexpr u8 KEYS_PER_BYTE = 8;
-Controller_Keyboard::Controller_Keyboard(Core::System& system) : ControllerBase(system) {}
+Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {}
Controller_Keyboard::~Controller_Keyboard() = default;
void 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 @@
namespace Service::HID {
class Controller_Keyboard final : public ControllerBase {
public:
- explicit Controller_Keyboard(Core::System& system);
+ explicit Controller_Keyboard(Core::System& system_);
~Controller_Keyboard() override;
// 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
-Controller_Mouse::Controller_Mouse(Core::System& system) : ControllerBase(system) {}
+Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {}
Controller_Mouse::~Controller_Mouse() = default;
void 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 @@
namespace Service::HID {
class Controller_Mouse final : public ControllerBase {
public:
- explicit Controller_Mouse(Core::System& system);
+ explicit Controller_Mouse(Core::System& system_);
~Controller_Mouse() override;
// 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) {
device_handle.device_index < DeviceIndex::MaxDeviceIndex;
}
-Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system) {
+Controller_NPad::Controller_NPad(Core::System& system_) : ControllerBase{system_} {
latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
}
@@ -159,7 +159,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
const auto controller_type = connected_controllers[controller_idx].type;
auto& controller = shared_memory_entries[controller_idx];
if (controller_type == NPadControllerType::None) {
- styleset_changed_events[controller_idx]->GetWritableEvent()->Signal();
+ styleset_changed_events[controller_idx]->GetWritableEvent().Signal();
return;
}
controller.style_set.raw = 0; // Zero out
@@ -253,9 +253,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
void Controller_NPad::OnInit() {
auto& kernel = system.Kernel();
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
- styleset_changed_events[i] =
- Kernel::KEvent::Create(kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
- styleset_changed_events[i]->Initialize();
+ styleset_changed_events[i] = Kernel::KEvent::Create(kernel);
+ styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i));
}
if (!IsControllerActivated()) {
@@ -341,6 +340,11 @@ void Controller_NPad::OnRelease() {
VibrateControllerAtIndex(npad_idx, device_idx, {});
}
}
+
+ for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
+ styleset_changed_events[i]->Close();
+ styleset_changed_events[i] = nullptr;
+ }
}
void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
@@ -654,8 +658,8 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
const auto& device = motions[i][e];
if (device) {
std::tie(motion_devices[e].accel, motion_devices[e].gyro,
- motion_devices[e].rotation, motion_devices[e].orientation) =
- device->GetStatus();
+ motion_devices[e].rotation, motion_devices[e].orientation,
+ motion_devices[e].quaternion) = device->GetStatus();
sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
}
}
@@ -955,14 +959,12 @@ bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_dev
return vibration_devices_mounted[npad_index][device_index];
}
-std::shared_ptr<Kernel::KReadableEvent> Controller_NPad::GetStyleSetChangedEvent(
- u32 npad_id) const {
- const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
- return styleset_event->GetReadableEvent();
+Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) {
+ return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent();
}
void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
- styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent()->Signal();
+ styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal();
}
void 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 @@
#include <atomic>
#include "common/bit_field.h"
#include "common/common_types.h"
+#include "common/quaternion.h"
#include "common/settings.h"
#include "core/frontend/input.h"
-#include "core/hle/kernel/object.h"
#include "core/hle/service/hid/controllers/controller_base.h"
namespace Kernel {
@@ -25,7 +25,7 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
class Controller_NPad final : public ControllerBase {
public:
- explicit Controller_NPad(Core::System& system);
+ explicit Controller_NPad(Core::System& system_);
~Controller_NPad() override;
// Called when the controller is initialized
@@ -198,7 +198,7 @@ public:
bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
- std::shared_ptr<Kernel::KReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
+ Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id);
void SignalStyleSetChangedEvent(u32 npad_id) const;
// Adds a new controller at an index.
@@ -467,6 +467,7 @@ private:
Common::Vec3f gyro;
Common::Vec3f rotation;
std::array<Common::Vec3f, 3> orientation;
+ Common::Quaternion<f32> quaternion;
};
struct NfcXcdHandle {
@@ -571,8 +572,9 @@ private:
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
// Each controller should have their own styleset changed event
- std::array<std::shared_ptr<Kernel::KEvent>, 10> styleset_changed_events;
- std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints;
+ std::array<Kernel::KEvent*, 10> styleset_changed_events{};
+ std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10>
+ last_vibration_timepoints{};
std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
bool permit_vibration_session_enabled{false};
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 @@
namespace Service::HID {
-Controller_Stubbed::Controller_Stubbed(Core::System& system) : ControllerBase(system) {}
+Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {}
Controller_Stubbed::~Controller_Stubbed() = default;
void 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 @@
namespace Service::HID {
class Controller_Stubbed final : public ControllerBase {
public:
- explicit Controller_Stubbed(Core::System& system);
+ explicit Controller_Stubbed(Core::System& system_);
~Controller_Stubbed() override;
// 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
-Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {}
+Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {}
Controller_Touchscreen::~Controller_Touchscreen() = default;
void Controller_Touchscreen::OnInit() {
@@ -105,6 +105,10 @@ void Controller_Touchscreen::OnLoadInputDevices() {
}
std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const {
+ // Dont assign any touch input to a finger if disabled
+ if (!Settings::values.touchscreen.enabled) {
+ return std::nullopt;
+ }
std::size_t first_free_id = 0;
while (first_free_id < MAX_FINGERS) {
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 @@
namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase {
public:
- explicit Controller_Touchscreen(Core::System& system);
+ explicit Controller_Touchscreen(Core::System& system_);
~Controller_Touchscreen() override;
// 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 @@
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
-Controller_XPad::Controller_XPad(Core::System& system) : ControllerBase(system) {}
+Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {}
Controller_XPad::~Controller_XPad() = default;
void 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 @@
namespace Service::HID {
class Controller_XPad final : public ControllerBase {
public:
- explicit Controller_XPad(Core::System& system);
+ explicit Controller_XPad(Core::System& system_);
~Controller_XPad() override;
// 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 @@
#include "core/frontend/input.h"
#include "core/hardware_properties.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
#include "core/hle/service/service.h"
+#include "core/memory.h"
+#include "core/hle/service/hid/controllers/console_sixaxis.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
#include "core/hle/service/hid/controllers/gesture.h"
@@ -52,9 +53,6 @@ IAppletResource::IAppletResource(Core::System& system_)
};
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- shared_mem = SharedFrom(&kernel.GetHidSharedMem());
-
MakeController<Controller_DebugPad>(HidController::DebugPad);
MakeController<Controller_Touchscreen>(HidController::Touchscreen);
MakeController<Controller_Mouse>(HidController::Mouse);
@@ -67,7 +65,7 @@ IAppletResource::IAppletResource(Core::System& system_)
MakeController<Controller_Stubbed>(HidController::UniquePad);
MakeController<Controller_NPad>(HidController::NPad);
MakeController<Controller_Gesture>(HidController::Gesture);
- MakeController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor);
+ MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor);
// Homebrew doesn't try to activate some controllers, so we activate them by default
GetController<Controller_NPad>(HidController::NPad).ActivateController();
@@ -78,8 +76,6 @@ IAppletResource::IAppletResource(Core::System& system_)
GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
- GetController<Controller_Stubbed>(HidController::ConsoleSixAxisSensor)
- .SetCommonHeaderOffset(0x3C200);
// Register update callbacks
pad_update_event = Core::Timing::CreateEvent(
@@ -119,7 +115,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(shared_mem);
+ rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
}
void IAppletResource::UpdateControllers(std::uintptr_t user_data,
@@ -131,7 +127,8 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
if (should_reload) {
controller->OnLoadInputDevices();
}
- controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
+ controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
+ SHARED_MEMORY_SIZE);
}
// 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
auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(
- core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
+ core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > motion_update_ns) {
@@ -1404,8 +1401,9 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
+ applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
+
+ LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -1455,8 +1453,9 @@ void Hid::ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
+ applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
+
+ LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -1495,20 +1494,20 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
- auto t_mem_1 =
- system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_1_handle);
+ auto t_mem_1 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_1_handle);
- if (t_mem_1 == nullptr) {
+ if (t_mem_1.IsNull()) {
LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
- auto t_mem_2 =
- system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(t_mem_2_handle);
+ auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_2_handle);
- if (t_mem_2 == nullptr) {
+ if (t_mem_2.IsNull()) {
LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
@@ -1518,8 +1517,15 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size");
ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
+ // Activate console six axis controller
+ applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
+ .ActivateController();
+
+ applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
+ .SetTransferMemoryPointer(system.Memory().GetPointer(t_mem_1->GetSourceAddress()));
+
LOG_WARNING(Service_HID,
- "(STUBBED) called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
+ "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
"applet_resource_user_id={}",
t_mem_1_handle, t_mem_2_handle, applet_resource_user_id);
@@ -1542,8 +1548,10 @@ void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
+ applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
+ .ResetTimestamp();
+
+ LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
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 {
struct EventType;
}
-namespace Kernel {
-class KSharedMemory;
-}
-
namespace Service::SM {
class ServiceManager;
}
@@ -69,8 +65,6 @@ private:
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
- std::shared_ptr<Kernel::KSharedMemory> shared_mem;
-
std::shared_ptr<Core::Timing::EventType> pad_update_event;
std::shared_ptr<Core::Timing::EventType> motion_update_event;
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"} {
// clang-format on
RegisterHandlers(functions);
-
- auto& kernel = system.Kernel();
-
- shared_mem = SharedFrom(&kernel.GetIrsSharedMem());
}
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
@@ -62,7 +58,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(shared_mem);
+ rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
}
void 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 @@
#pragma once
-#include "core/hle/kernel/object.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
-namespace Kernel {
-class KSharedMemory;
-}
-
namespace Service::HID {
class IRS final : public ServiceFramework<IRS> {
@@ -42,7 +37,6 @@ private:
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
- std::shared_ptr<Kernel::KSharedMemory> shared_mem;
const u32 device_handle{0xABCD};
};
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:
bool vr_mode_enabled = false;
float current_brightness = 1.0f;
- float backlight_brightness = 1.0f;
float ambient_light_value = 0.0f;
float current_vr_brightness = 1.0f;
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 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_system_control.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/service/ldr/ldr.h"
#include "core/hle/service/service.h"
@@ -321,7 +321,7 @@ public:
return addr;
}
- ResultVal<VAddr> MapProcessCodeMemory(Kernel::Process* process, VAddr baseAddress,
+ ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr baseAddress,
u64 size) const {
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
auto& page_table{process->PageTable()};
@@ -342,7 +342,7 @@ public:
return ERROR_INSUFFICIENT_ADDRESS_SPACE;
}
- ResultVal<VAddr> MapNro(Kernel::Process* process, VAddr nro_addr, std::size_t nro_size,
+ ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size,
VAddr bss_addr, std::size_t bss_size, std::size_t size) const {
for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
auto& page_table{process->PageTable()};
@@ -378,7 +378,7 @@ public:
return ERROR_INSUFFICIENT_ADDRESS_SPACE;
}
- ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr,
+ ResultCode LoadNro(Kernel::KProcess* process, const NROHeader& nro_header, VAddr nro_addr,
VAddr start) const {
const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
@@ -387,11 +387,9 @@ public:
const VAddr bss_end_addr{
Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)};
- auto CopyCode{[&](VAddr src_addr, VAddr dst_addr, u64 size) {
- std::vector<u8> source_data(size);
- system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size());
- system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size());
- }};
+ const auto CopyCode = [this, process](VAddr src_addr, VAddr dst_addr, u64 size) {
+ system.Memory().CopyBlock(*process, dst_addr, src_addr, size);
+ };
CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
nro_header.segment_headers[TEXT_INDEX].memory_size);
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>,
#pragma pack(push, 4)
struct MiiInfoElement {
- MiiInfoElement(const MiiInfo& info, Source source) : info{info}, source{source} {}
+ MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {}
MiiInfo info{};
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:
class MiiDBModule final : public ServiceFramework<MiiDBModule> {
public:
- explicit MiiDBModule(Core::System& system_, const char* name)
- : ServiceFramework{system_, name} {
+ explicit MiiDBModule(Core::System& system_, const char* name_)
+ : ServiceFramework{system_, name_} {
// clang-format off
static const FunctionInfo functions[] = {
{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 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_session.h"
#include "core/hle/service/mm/mm_u.h"
#include "core/hle/service/sm/sm.h"
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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_writable_event.h"
@@ -24,10 +23,9 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
const char* name)
- : ServiceFramework{system_, name}, module{std::move(module_)} {
- auto& kernel = system.Kernel();
- nfc_tag_load = Kernel::KEvent::Create(kernel, "IUser:NFCTagDetected");
- nfc_tag_load->Initialize();
+ : ServiceFramework{system_, name}, nfc_tag_load{system.Kernel()}, module{std::move(module_)} {
+ Kernel::KAutoObject::Create(std::addressof(nfc_tag_load));
+ nfc_tag_load.Initialize("IUser:NFCTagDetected");
}
Module::Interface::~Interface() = default;
@@ -35,7 +33,8 @@ Module::Interface::~Interface() = default;
class IUser final : public ServiceFramework<IUser> {
public:
explicit IUser(Module::Interface& nfp_interface_, Core::System& system_)
- : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_} {
+ : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_},
+ deactivate_event{system.Kernel()}, availability_change_event{system.Kernel()} {
static const FunctionInfo functions[] = {
{0, &IUser::Initialize, "Initialize"},
{1, &IUser::Finalize, "Finalize"},
@@ -65,11 +64,11 @@ public:
};
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- deactivate_event = Kernel::KEvent::Create(kernel, "IUser:DeactivateEvent");
- deactivate_event->Initialize();
- availability_change_event = Kernel::KEvent::Create(kernel, "IUser:AvailabilityChangeEvent");
- availability_change_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(deactivate_event));
+ Kernel::KAutoObject::Create(std::addressof(availability_change_event));
+
+ deactivate_event.Initialize("IUser:DeactivateEvent");
+ availability_change_event.Initialize("IUser:AvailabilityChangeEvent");
}
private:
@@ -167,7 +166,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(deactivate_event->GetReadableEvent());
+ rb.PushCopyObjects(deactivate_event.GetReadableEvent());
}
void StopDetection(Kernel::HLERequestContext& ctx) {
@@ -176,7 +175,7 @@ private:
switch (device_state) {
case DeviceState::TagFound:
case DeviceState::TagNearby:
- deactivate_event->GetWritableEvent()->Signal();
+ deactivate_event.GetWritableEvent().Signal();
device_state = DeviceState::Initialized;
break;
case DeviceState::SearchingForTag:
@@ -265,7 +264,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(availability_change_event->GetReadableEvent());
+ rb.PushCopyObjects(availability_change_event.GetReadableEvent());
}
void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -319,9 +318,9 @@ private:
const u32 npad_id{0}; // Player 1 controller
State state{State::NonInitialized};
DeviceState device_state{DeviceState::Initialized};
- std::shared_ptr<Kernel::KEvent> deactivate_event;
- std::shared_ptr<Kernel::KEvent> availability_change_event;
- const Module::Interface& nfp_interface;
+ Module::Interface& nfp_interface;
+ Kernel::KEvent deactivate_event;
+ Kernel::KEvent availability_change_event;
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
@@ -339,12 +338,12 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
}
std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
- nfc_tag_load->GetWritableEvent()->Signal();
+ nfc_tag_load.GetWritableEvent().Signal();
return true;
}
-const std::shared_ptr<Kernel::KReadableEvent>& Module::Interface::GetNFCEvent() const {
- return nfc_tag_load->GetReadableEvent();
+Kernel::KReadableEvent& Module::Interface::GetNFCEvent() {
+ return nfc_tag_load.GetReadableEvent();
}
const 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 @@
#include <array>
#include <vector>
+#include "core/hle/kernel/k_event.h"
#include "core/hle/service/service.h"
namespace Kernel {
@@ -38,11 +39,11 @@ public:
void CreateUserInterface(Kernel::HLERequestContext& ctx);
bool LoadAmiibo(const std::vector<u8>& buffer);
- const std::shared_ptr<Kernel::KReadableEvent>& GetNFCEvent() const;
+ Kernel::KReadableEvent& GetNFCEvent();
const AmiiboFile& GetAmiiboBuffer() const;
private:
- std::shared_ptr<Kernel::KEvent> nfc_tag_load;
+ Kernel::KEvent nfc_tag_load;
AmiiboFile amiibo{};
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:
class IRequest final : public ServiceFramework<IRequest> {
public:
- explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} {
+ explicit IRequest(Core::System& system_)
+ : ServiceFramework{system_, "IRequest"}, event1{system.Kernel()}, event2{system.Kernel()} {
static const FunctionInfo functions[] = {
{0, &IRequest::GetRequestState, "GetRequestState"},
{1, &IRequest::GetResult, "GetResult"},
@@ -157,12 +158,11 @@ public:
};
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
+ Kernel::KAutoObject::Create(std::addressof(event1));
+ Kernel::KAutoObject::Create(std::addressof(event2));
- event1 = Kernel::KEvent::Create(kernel, "IRequest:Event1");
- event1->Initialize();
- event2 = Kernel::KEvent::Create(kernel, "IRequest:Event2");
- event2->Initialize();
+ event1.Initialize("IRequest:Event1");
+ event2.Initialize("IRequest:Event2");
}
private:
@@ -198,7 +198,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 2};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent());
+ rb.PushCopyObjects(event1.GetReadableEvent(), event2.GetReadableEvent());
}
void Cancel(Kernel::HLERequestContext& ctx) {
@@ -229,7 +229,7 @@ private:
rb.Push<u32>(0);
}
- std::shared_ptr<Kernel::KEvent> event1, event2;
+ Kernel::KEvent event1, event2;
};
class INetworkProfile final : public ServiceFramework<INetworkProfile> {
@@ -368,7 +368,7 @@ private:
},
};
- IPC::ResponseBuilder rb{ctx, 2 + sizeof(IpConfigInfo) / sizeof(u32)};
+ IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<IpConfigInfo>(ip_config_info);
}
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
: public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
public:
explicit IEnsureNetworkClockAvailabilityService(Core::System& system_)
- : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"} {
+ : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"},
+ finished_event{system.Kernel()} {
static const FunctionInfo functions[] = {
{0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
{1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
@@ -312,19 +313,17 @@ public:
};
RegisterHandlers(functions);
- auto& kernel = system.Kernel();
- finished_event =
- Kernel::KEvent::Create(kernel, "IEnsureNetworkClockAvailabilityService:FinishEvent");
- finished_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(finished_event));
+ finished_event.Initialize("IEnsureNetworkClockAvailabilityService:FinishEvent");
}
private:
- std::shared_ptr<Kernel::KEvent> finished_event;
+ Kernel::KEvent finished_event;
void StartTask(Kernel::HLERequestContext& ctx) {
// No need to connect to the internet, just finish the task straight away.
LOG_DEBUG(Service_NIM, "called");
- finished_event->GetWritableEvent()->Signal();
+ finished_event.GetWritableEvent().Signal();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -334,7 +333,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(finished_event->GetReadableEvent());
+ rb.PushCopyObjects(finished_event.GetReadableEvent());
}
void GetResult(Kernel::HLERequestContext& ctx) {
@@ -346,7 +345,7 @@ private:
void Cancel(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
- finished_event->GetWritableEvent()->Clear();
+ finished_event.GetWritableEvent().Clear();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
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 {
}
}
- /// Handle to shared memory region designated for a shared font
- std::shared_ptr<Kernel::KSharedMemory> shared_font_mem;
-
/// Backing memory for the shared font data
std::shared_ptr<Kernel::PhysicalMemory> shared_font;
@@ -260,14 +257,13 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
// Create shared font memory object
auto& kernel = system.Kernel();
- impl->shared_font_mem = SharedFrom(&kernel.GetFontSharedMem());
- std::memcpy(impl->shared_font_mem->GetPointer(), impl->shared_font->data(),
+ std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font->data(),
impl->shared_font->size());
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(impl->shared_font_mem);
+ rb.PushCopyObjects(&kernel.GetFontSharedMem());
}
void 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 {
/// implement the ioctl interface.
class nvdevice {
public:
- explicit nvdevice(Core::System& system) : system{system} {}
+ explicit nvdevice(Core::System& system_) : system{system_} {}
virtual ~nvdevice() = default;
/**
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 @@
namespace Service::Nvidia::Devices {
-nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
- : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
+nvdisp_disp0::nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
+ : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
nvdisp_disp0 ::~nvdisp_disp0() = default;
NvResult 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
addr, offset, width, height, stride, static_cast<PixelFormat>(format),
transform, crop_rect};
- system.GetPerfStats().EndGameFrame();
system.GetPerfStats().EndSystemFrame();
system.GPU().SwapBuffers(&framebuffer);
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;
class nvdisp_disp0 final : public nvdevice {
public:
- explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
+ explicit nvdisp_disp0(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_);
~nvdisp_disp0() override;
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 @@
namespace Service::Nvidia::Devices {
-nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
- : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
+nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_)
+ : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)} {}
nvhost_as_gpu::~nvhost_as_gpu() = default;
NvResult 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);
class nvhost_as_gpu final : public nvdevice {
public:
- explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
+ explicit nvhost_as_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_);
~nvhost_as_gpu() override;
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
@@ -48,13 +48,13 @@ private:
public:
constexpr BufferMap() = default;
- constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
- : start_addr{start_addr}, end_addr{start_addr + size} {}
+ constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
+ : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
- constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
- bool is_allocated)
- : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
- is_allocated{is_allocated} {}
+ constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
+ bool is_allocated_)
+ : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
+ is_allocated{is_allocated_} {}
constexpr VAddr StartAddr() const {
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 @@
namespace Service::Nvidia::Devices {
-nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
- SyncpointManager& syncpoint_manager)
- : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
+nvhost_ctrl::nvhost_ctrl(Core::System& system_, EventInterface& events_interface_,
+ SyncpointManager& syncpoint_manager_)
+ : nvdevice{system_}, events_interface{events_interface_}, syncpoint_manager{
+ syncpoint_manager_} {}
nvhost_ctrl::~nvhost_ctrl() = default;
NvResult 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
return NvResult::Success;
}
- auto event = events_interface.events[event_id];
+ auto& event = events_interface.events[event_id];
auto& gpu = system.GPU();
// This is mostly to take into account unimplemented features. As synced
// gpu is always synced.
if (!gpu.IsAsync()) {
- event.event->GetWritableEvent()->Signal();
+ event.event->GetWritableEvent().Signal();
return NvResult::Success;
}
auto lock = gpu.LockSync();
const u32 current_syncpoint_value = event.fence.value;
const s32 diff = current_syncpoint_value - params.threshold;
if (diff >= 0) {
- event.event->GetWritableEvent()->Signal();
+ event.event->GetWritableEvent().Signal();
params.value = current_syncpoint_value;
std::memcpy(output.data(), &params, sizeof(params));
return NvResult::Success;
@@ -141,7 +142,7 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
}
params.value |= event_id;
- event.event->GetWritableEvent()->Clear();
+ event.event->GetWritableEvent().Clear();
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
std::memcpy(output.data(), &params, sizeof(params));
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 {
class nvhost_ctrl final : public nvdevice {
public:
- explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface,
- SyncpointManager& syncpoint_manager);
+ explicit nvhost_ctrl(Core::System& system_, EventInterface& events_interface_,
+ SyncpointManager& syncpoint_manager_);
~nvhost_ctrl() override;
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 @@
namespace Service::Nvidia::Devices {
-nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
+nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_) : nvdevice{system_} {}
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
NvResult 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 {
class nvhost_ctrl_gpu final : public nvdevice {
public:
- explicit nvhost_ctrl_gpu(Core::System& system);
+ explicit nvhost_ctrl_gpu(Core::System& system_);
~nvhost_ctrl_gpu() override;
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 @@
namespace Service::Nvidia::Devices {
-nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager)
- : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} {
- channel_fence.id = syncpoint_manager.AllocateSyncpoint();
- channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id);
+nvhost_gpu::nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_)
+ : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} {
+ channel_fence.id = syncpoint_manager_.AllocateSyncpoint();
+ channel_fence.value = system_.GPU().GetSyncpointValue(channel_fence.id);
}
nvhost_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 {
class nvmap;
class nvhost_gpu final : public nvdevice {
public:
- explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager);
+ explicit nvhost_gpu(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_);
~nvhost_gpu() override;
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 @@
namespace Service::Nvidia::Devices {
-nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager)
- : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
+nvhost_nvdec::nvhost_nvdec(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_)
+ : nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {}
nvhost_nvdec::~nvhost_nvdec() = default;
NvResult 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 {
class nvhost_nvdec final : public nvhost_nvdec_common {
public:
- explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager);
+ explicit nvhost_nvdec(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_);
~nvhost_nvdec() override;
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
}
} // Anonymous namespace
-nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager)
- : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager(syncpoint_manager) {}
+nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_)
+ : nvdevice{system_}, nvmap_dev{std::move(nvmap_dev_)}, syncpoint_manager{syncpoint_manager_} {}
nvhost_nvdec_common::~nvhost_nvdec_common() = default;
NvResult 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;
class nvhost_nvdec_common : public nvdevice {
public:
- explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager);
+ explicit nvhost_nvdec_common(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_);
~nvhost_nvdec_common() override;
protected:
@@ -27,13 +27,13 @@ protected:
public:
constexpr BufferMap() = default;
- constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
- : start_addr{start_addr}, end_addr{start_addr + size} {}
+ constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_)
+ : start_addr{start_addr_}, end_addr{start_addr_ + size_} {}
- constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
- bool is_allocated)
- : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
- is_allocated{is_allocated} {}
+ constexpr BufferMap(GPUVAddr start_addr_, std::size_t size_, VAddr cpu_addr_,
+ bool is_allocated_)
+ : start_addr{start_addr_}, end_addr{start_addr_ + size_}, cpu_addr{cpu_addr_},
+ is_allocated{is_allocated_} {}
constexpr VAddr StartAddr() const {
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 @@
namespace Service::Nvidia::Devices {
-nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
+nvhost_nvjpg::nvhost_nvjpg(Core::System& system_) : nvdevice{system_} {}
nvhost_nvjpg::~nvhost_nvjpg() = default;
NvResult 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 {
class nvhost_nvjpg final : public nvdevice {
public:
- explicit nvhost_nvjpg(Core::System& system);
+ explicit nvhost_nvjpg(Core::System& system_);
~nvhost_nvjpg() override;
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 @@
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
-nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager)
- : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
+nvhost_vic::nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_)
+ : nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {}
nvhost_vic::~nvhost_vic() = default;
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 {
class nvhost_vic final : public nvhost_nvdec_common {
public:
- explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
- SyncpointManager& syncpoint_manager);
+ explicit nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
+ SyncpointManager& syncpoint_manager_);
~nvhost_vic();
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 @@
namespace Service::Nvidia::Devices {
-nvmap::nvmap(Core::System& system) : nvdevice(system) {
+nvmap::nvmap(Core::System& system_) : nvdevice{system_} {
// Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
// represent this.
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 {
class nvmap final : public nvdevice {
public:
- explicit nvmap(Core::System& system);
+ explicit nvmap(Core::System& system_);
~nvmap() override;
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) {
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NVDRV, "called");
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
if (!is_initialized) {
- ServiceError(ctx, NvResult::NotInitialized);
+ rb.Push<DeviceFD>(0);
+ rb.PushEnum(NvResult::NotInitialized);
+
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
return;
}
const auto& buffer = ctx.ReadBuffer();
const std::string device_name(buffer.begin(), buffer.end());
+
+ if (device_name == "/dev/nvhost-prof-gpu") {
+ rb.Push<DeviceFD>(0);
+ rb.PushEnum(NvResult::NotSupported);
+
+ LOG_WARNING(Service_NVDRV, "/dev/nvhost-prof-gpu cannot be opened in production");
+ return;
+ }
+
DeviceFD fd = nvdrv->Open(device_name);
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(RESULT_SUCCESS);
rb.Push<DeviceFD>(fd);
rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
}
@@ -176,8 +187,8 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
if (event_id < MaxNvEvents) {
IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(RESULT_SUCCESS);
- auto event = nvdrv->GetEvent(event_id);
- event->Clear();
+ auto& event = nvdrv->GetEvent(event_id);
+ event.Clear();
rb.PushCopyObjects(event);
rb.PushEnum(NvResult::Success);
} 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
Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
auto& kernel = system.Kernel();
for (u32 i = 0; i < MaxNvEvents; i++) {
- std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
- events_interface.events[i] = {Kernel::KEvent::Create(kernel, std::move(event_label))};
- events_interface.events[i].event->Initialize();
+ events_interface.events[i].event = Kernel::KEvent::Create(kernel);
+ events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i));
events_interface.status[i] = EventState::Free;
events_interface.registered[i] = false;
}
@@ -64,7 +63,12 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, syncpoint_manager);
}
-Module::~Module() = default;
+Module::~Module() {
+ for (u32 i = 0; i < MaxNvEvents; i++) {
+ events_interface.events[i].event->Close();
+ events_interface.events[i].event = nullptr;
+ }
+}
NvResult Module::VerifyFD(DeviceFD fd) const {
if (fd < 0) {
@@ -172,16 +176,16 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
if (events_interface.assigned_syncpt[i] == syncpoint_id &&
events_interface.assigned_value[i] == value) {
events_interface.LiberateEvent(i);
- events_interface.events[i].event->GetWritableEvent()->Signal();
+ events_interface.events[i].event->GetWritableEvent().Signal();
}
}
}
-std::shared_ptr<Kernel::KReadableEvent> Module::GetEvent(const u32 event_id) const {
+Kernel::KReadableEvent& Module::GetEvent(const u32 event_id) {
return events_interface.events[event_id].event->GetReadableEvent();
}
-std::shared_ptr<Kernel::KWritableEvent> Module::GetEventWriteable(const u32 event_id) const {
+Kernel::KWritableEvent& Module::GetEventWriteable(const u32 event_id) {
return events_interface.events[event_id].event->GetWritableEvent();
}
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;
/// Represents an Nvidia event
struct NvEvent {
- std::shared_ptr<Kernel::KEvent> event;
+ Kernel::KEvent* event{};
Fence fence{};
};
@@ -136,9 +136,9 @@ public:
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
- std::shared_ptr<Kernel::KReadableEvent> GetEvent(u32 event_id) const;
+ Kernel::KReadableEvent& GetEvent(u32 event_id);
- std::shared_ptr<Kernel::KWritableEvent> GetEventWriteable(u32 event_id) const;
+ Kernel::KWritableEvent& GetEventWriteable(u32 event_id);
private:
/// 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 @@
namespace Service::Nvidia {
-SyncpointManager::SyncpointManager(Tegra::GPU& gpu) : gpu{gpu} {}
+SyncpointManager::SyncpointManager(Tegra::GPU& gpu_) : gpu{gpu_} {}
SyncpointManager::~SyncpointManager() = default;
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 {
class SyncpointManager final {
public:
- explicit SyncpointManager(Tegra::GPU& gpu);
+ explicit SyncpointManager(Tegra::GPU& gpu_);
~SyncpointManager();
/**
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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
namespace Service::NVFlinger {
-BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id)
- : id(id), layer_id(layer_id) {
- buffer_wait_event = Kernel::KEvent::Create(kernel, "BufferQueue:WaitEvent");
- buffer_wait_event->Initialize();
+BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_)
+ : id(id_), layer_id(layer_id_), buffer_wait_event{kernel} {
+ Kernel::KAutoObject::Create(std::addressof(buffer_wait_event));
+ buffer_wait_event.Initialize("BufferQueue:WaitEvent");
}
BufferQueue::~BufferQueue() = default;
@@ -42,7 +41,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
.multi_fence = {},
};
- buffer_wait_event->GetWritableEvent()->Signal();
+ buffer_wait_event.GetWritableEvent().Signal();
}
std::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
}
free_buffers_condition.notify_one();
- buffer_wait_event->GetWritableEvent()->Signal();
+ buffer_wait_event.GetWritableEvent().Signal();
}
std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
@@ -155,7 +154,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
}
free_buffers_condition.notify_one();
- buffer_wait_event->GetWritableEvent()->Signal();
+ buffer_wait_event.GetWritableEvent().Signal();
}
void BufferQueue::Connect() {
@@ -170,7 +169,7 @@ void BufferQueue::Disconnect() {
std::unique_lock lock{queue_sequence_mutex};
queue_sequence.clear();
}
- buffer_wait_event->GetWritableEvent()->Signal();
+ buffer_wait_event.GetWritableEvent().Signal();
is_connect = false;
free_buffers_condition.notify_one();
}
@@ -189,12 +188,12 @@ u32 BufferQueue::Query(QueryType type) {
return 0;
}
-std::shared_ptr<Kernel::KWritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
- return buffer_wait_event->GetWritableEvent();
+Kernel::KWritableEvent& BufferQueue::GetWritableBufferWaitEvent() {
+ return buffer_wait_event.GetWritableEvent();
}
-std::shared_ptr<Kernel::KReadableEvent> BufferQueue::GetBufferWaitEvent() const {
- return buffer_wait_event->GetReadableEvent();
+Kernel::KReadableEvent& BufferQueue::GetBufferWaitEvent() {
+ return buffer_wait_event.GetReadableEvent();
}
} // 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 @@
#include "common/common_funcs.h"
#include "common/math_util.h"
#include "common/swap.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/nvdrv/nvdata.h"
namespace Kernel {
@@ -53,7 +54,7 @@ public:
NativeWindowFormat = 2,
};
- explicit BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id);
+ explicit BufferQueue(Kernel::KernelCore& kernel, u32 id_, u64 layer_id_);
~BufferQueue();
enum class BufferTransformFlags : u32 {
@@ -115,9 +116,9 @@ public:
return is_connect;
}
- std::shared_ptr<Kernel::KWritableEvent> GetWritableBufferWaitEvent() const;
+ Kernel::KWritableEvent& GetWritableBufferWaitEvent();
- std::shared_ptr<Kernel::KReadableEvent> GetBufferWaitEvent() const;
+ Kernel::KReadableEvent& GetBufferWaitEvent();
private:
BufferQueue(const BufferQueue&) = delete;
@@ -129,7 +130,7 @@ private:
std::list<u32> free_buffers;
std::array<Buffer, buffer_slots> buffers;
std::list<u32> queue_sequence;
- std::shared_ptr<Kernel::KEvent> buffer_wait_event;
+ Kernel::KEvent buffer_wait_event;
std::mutex free_buffers_mutex;
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() {
}
}
-NVFlinger::NVFlinger(Core::System& system) : system(system) {
+NVFlinger::NVFlinger(Core::System& system_) : system(system_) {
displays.emplace_back(0, "Default", system);
displays.emplace_back(1, "External", system);
displays.emplace_back(2, "Edid", system);
@@ -72,7 +72,7 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
// Schedule the screen composition events
composition_event = Core::Timing::CreateEvent(
"ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
- const auto guard = Lock();
+ const auto lock_guard = Lock();
Compose();
const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
@@ -112,7 +112,7 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
}
std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
- const auto guard = Lock();
+ const auto lock_guard = Lock();
LOG_DEBUG(Service, "Opening \"{}\" display", name);
@@ -131,7 +131,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
}
std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
- const auto guard = Lock();
+ const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
@@ -139,24 +139,28 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
}
const u64 layer_id = next_layer_id++;
+ CreateLayerAtId(*display, layer_id);
+ return layer_id;
+}
+
+void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
const u32 buffer_queue_id = next_buffer_queue_id++;
buffer_queues.emplace_back(
std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id));
- display->CreateLayer(layer_id, *buffer_queues.back());
- return layer_id;
+ display.CreateLayer(layer_id, *buffer_queues.back());
}
void NVFlinger::CloseLayer(u64 layer_id) {
- const auto guard = Lock();
+ const auto lock_guard = Lock();
for (auto& display : displays) {
display.CloseLayer(layer_id);
}
}
-std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const {
- const auto guard = Lock();
- const auto* const layer = FindLayer(display_id, layer_id);
+std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
+ const auto lock_guard = Lock();
+ const auto* const layer = FindOrCreateLayer(display_id, layer_id);
if (layer == nullptr) {
return std::nullopt;
@@ -165,19 +169,19 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
return layer->GetBufferQueue().GetId();
}
-std::shared_ptr<Kernel::KReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
- const auto guard = Lock();
+Kernel::KReadableEvent* NVFlinger::FindVsyncEvent(u64 display_id) {
+ const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
return nullptr;
}
- return display->GetVSyncEvent();
+ return &display->GetVSyncEvent();
}
BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
- const auto guard = Lock();
+ const auto lock_guard = Lock();
const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
[id](const auto& queue) { return queue->GetId() == id; });
@@ -232,6 +236,24 @@ const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
return display->FindLayer(layer_id);
}
+VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
+ auto* const display = FindDisplay(display_id);
+
+ if (display == nullptr) {
+ return nullptr;
+ }
+
+ auto* layer = display->FindLayer(layer_id);
+
+ if (layer == nullptr) {
+ LOG_DEBUG(Service, "Layer at id {} not found. Trying to create it.", layer_id);
+ CreateLayerAtId(*display, layer_id);
+ return display->FindLayer(layer_id);
+ }
+
+ return layer;
+}
+
void NVFlinger::Compose() {
for (auto& display : displays) {
// 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 @@
#pragma once
#include <atomic>
+#include <list>
#include <memory>
#include <mutex>
#include <optional>
@@ -14,7 +15,6 @@
#include <vector>
#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
namespace Common {
class Event;
@@ -45,7 +45,7 @@ class BufferQueue;
class NVFlinger final {
public:
- explicit NVFlinger(Core::System& system);
+ explicit NVFlinger(Core::System& system_);
~NVFlinger();
/// Sets the NVDrv module instance to use to send buffers to the GPU.
@@ -67,12 +67,12 @@ public:
/// Finds the buffer queue ID of the specified layer in the specified display.
///
/// If an invalid display ID or layer ID is provided, then an empty optional is returned.
- [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const;
+ [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id);
/// Gets the vsync event for the specified display.
///
/// If an invalid display ID is provided, then nullptr is returned.
- [[nodiscard]] std::shared_ptr<Kernel::KReadableEvent> FindVsyncEvent(u64 display_id) const;
+ [[nodiscard]] Kernel::KReadableEvent* FindVsyncEvent(u64 display_id);
/// Obtains a buffer queue identified by the ID.
[[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
@@ -100,13 +100,21 @@ private:
/// Finds the layer identified by the specified ID in the desired display.
[[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
+ /// Finds the layer identified by the specified ID in the desired display,
+ /// or creates the layer if it is not found.
+ /// To be used when the system expects the specified ID to already exist.
+ [[nodiscard]] VI::Layer* FindOrCreateLayer(u64 display_id, u64 layer_id);
+
+ /// Creates a layer with the specified layer ID in the desired display.
+ void CreateLayerAtId(VI::Display& display, u64 layer_id);
+
static void VSyncThread(NVFlinger& nv_flinger);
void SplitVSync();
std::shared_ptr<Nvidia::Module> nvdrv;
- std::vector<VI::Display> displays;
+ std::list<VI::Display> displays;
std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
/// 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 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/pctl/module.h"
#include "core/hle/service/pctl/pctl.h"
@@ -24,9 +24,8 @@ constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
- explicit IParentalControlService(Core::System& system_, Capability capability)
- : ServiceFramework{system_, "IParentalControlService"}, system(system_),
- capability(capability) {
+ explicit IParentalControlService(Core::System& system_, Capability capability_)
+ : ServiceFramework{system_, "IParentalControlService"}, capability{capability_} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IParentalControlService::Initialize, "Initialize"},
@@ -362,8 +361,6 @@ private:
States states{};
ParentalControlSettings settings{};
std::array<char, 8> pin_code{};
- bool can_use_stereo_vision = true;
- Core::System& system;
Capability capability{};
};
@@ -386,8 +383,8 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
}
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name, Capability capability)
- : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
+ const char* name_, Capability capability_)
+ : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {}
Module::Interface::~Interface() = default;
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 {
public:
class Interface : public ServiceFramework<Interface> {
public:
- explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability);
+ explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
+ const char* name_, Capability capability_);
~Interface() override;
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 @@
namespace Service::PCTL {
PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability)
- : Interface{system_, std::move(module_), name, capability} {
+ Capability capability_)
+ : Interface{system_, std::move(module_), name, capability_} {
static const FunctionInfo functions[] = {
{0, &PCTL::CreateService, "CreateService"},
{1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 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 {
class PCTL final : public Module::Interface {
public:
explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability);
+ Capability capability_);
~PCTL() override;
};
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 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
@@ -17,9 +17,9 @@ constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1};
constexpr u64 NO_PROCESS_FOUND_PID{0};
-std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList(
- const std::vector<std::shared_ptr<Kernel::Process>>& process_list,
- std::function<bool(const std::shared_ptr<Kernel::Process>&)> predicate) {
+std::optional<Kernel::KProcess*> SearchProcessList(
+ const std::vector<Kernel::KProcess*>& process_list,
+ std::function<bool(Kernel::KProcess*)> predicate) {
const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
if (iter == process_list.end()) {
@@ -30,9 +30,9 @@ std::optional<std::shared_ptr<Kernel::Process>> SearchProcessList(
}
void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
- const std::vector<std::shared_ptr<Kernel::Process>>& process_list) {
- const auto process = SearchProcessList(process_list, [](const auto& process) {
- return process->GetProcessID() == Kernel::Process::ProcessIDMin;
+ const std::vector<Kernel::KProcess*>& process_list) {
+ const auto process = SearchProcessList(process_list, [](const auto& proc) {
+ return proc->GetProcessID() == Kernel::KProcess::ProcessIDMin;
});
IPC::ResponseBuilder rb{ctx, 4};
@@ -100,8 +100,8 @@ private:
LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id);
const auto process =
- SearchProcessList(kernel.GetProcessList(), [title_id](const auto& process) {
- return process->GetTitleID() == title_id;
+ SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) {
+ return proc->GetTitleID() == title_id;
});
if (!process.has_value()) {
@@ -125,8 +125,7 @@ private:
class Info final : public ServiceFramework<Info> {
public:
- explicit Info(Core::System& system_,
- const std::vector<std::shared_ptr<Kernel::Process>>& process_list_)
+ explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_)
: ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
static const FunctionInfo functions[] = {
{0, &Info::GetTitleId, "GetTitleId"},
@@ -141,8 +140,8 @@ private:
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
- const auto process = SearchProcessList(process_list, [process_id](const auto& process) {
- return process->GetProcessID() == process_id;
+ const auto process = SearchProcessList(process_list, [process_id](const auto& proc) {
+ return proc->GetProcessID() == process_id;
});
if (!process.has_value()) {
@@ -156,7 +155,7 @@ private:
rb.Push((*process)->GetTitleID());
}
- const std::vector<std::shared_ptr<Kernel::Process>>& process_list;
+ const std::vector<Kernel::KProcess*>& process_list;
};
class 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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/service.h"
@@ -60,7 +60,7 @@ private:
const auto process_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = [ctx] {
+ const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
@@ -87,7 +87,7 @@ private:
const auto process_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = [ctx] {
+ const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
@@ -139,7 +139,7 @@ private:
const auto title_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = [ctx] {
+ const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
@@ -163,7 +163,7 @@ private:
const auto title_id = rp.PopRaw<u64>();
const auto data1 = ctx.ReadBuffer(0);
- const auto data2 = [ctx] {
+ const auto data2 = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
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 {
class IPsmSession final : public ServiceFramework<IPsmSession> {
public:
- explicit IPsmSession(Core::System& system_) : ServiceFramework{system_, "IPsmSession"} {
+ explicit IPsmSession(Core::System& system_)
+ : ServiceFramework{system_, "IPsmSession"}, state_change_event{system.Kernel()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IPsmSession::BindStateChangeEvent, "BindStateChangeEvent"},
@@ -32,28 +33,27 @@ public:
RegisterHandlers(functions);
- state_change_event =
- Kernel::KEvent::Create(system_.Kernel(), "IPsmSession::state_change_event");
- state_change_event->Initialize();
+ Kernel::KAutoObject::Create(std::addressof(state_change_event));
+ state_change_event.Initialize("IPsmSession::state_change_event");
}
~IPsmSession() override = default;
void SignalChargerTypeChanged() {
if (should_signal && should_signal_charger_type) {
- state_change_event->GetWritableEvent()->Signal();
+ state_change_event.GetWritableEvent().Signal();
}
}
void SignalPowerSupplyChanged() {
if (should_signal && should_signal_power_supply) {
- state_change_event->GetWritableEvent()->Signal();
+ state_change_event.GetWritableEvent().Signal();
}
}
void SignalBatteryVoltageStateChanged() {
if (should_signal && should_signal_battery_voltage) {
- state_change_event->GetWritableEvent()->Signal();
+ state_change_event.GetWritableEvent().Signal();
}
}
@@ -65,7 +65,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(state_change_event->GetReadableEvent());
+ rb.PushCopyObjects(state_change_event.GetReadableEvent());
}
void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
@@ -114,7 +114,7 @@ private:
bool should_signal_power_supply{};
bool should_signal_battery_voltage{};
bool should_signal{};
- std::shared_ptr<Kernel::KEvent> state_change_event;
+ Kernel::KEvent state_change_event;
};
class 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 @@
#include "core/core.h"
#include "core/hle/ipc.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/server_port.h"
#include "core/hle/service/acc/acc.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/aoc/aoc_u.h"
@@ -111,16 +111,18 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
port_installed = true;
}
-void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
+Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
const auto guard = LockService();
ASSERT(!port_installed);
- auto [server_port, client_port] =
- Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
- server_port->SetHleHandler(shared_from_this());
- kernel.AddNamedPort(service_name, std::move(client_port));
+ auto* port = Kernel::KPort::Create(kernel);
+ port->Initialize(max_sessions, false, service_name);
+ port->GetServerPort().SetHleHandler(shared_from_this());
+
port_installed = true;
+
+ return port->GetClientPort();
}
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
@@ -131,6 +133,16 @@ void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* function
}
}
+void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions,
+ std::size_t n) {
+ handlers_tipc.reserve(handlers_tipc.size() + n);
+ for (std::size_t i = 0; i < n; ++i) {
+ // Usually this array is sorted by id already, so hint to insert at the end
+ handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
+ functions[i]);
+ }
+}
+
void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx,
const FunctionInfoBase* info) {
auto cmd_buf = ctx.CommandBuffer();
@@ -165,33 +177,55 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
handler_invoker(this, info->handler_callback, ctx);
}
-ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
+void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) {
+ boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
+
+ itr = handlers_tipc.find(ctx.GetCommand());
+
+ const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second;
+ if (info == nullptr || info->handler_callback == nullptr) {
+ return ReportUnimplementedFunction(ctx, info);
+ }
+
+ LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
+ handler_invoker(this, info->handler_callback, ctx);
+}
+
+ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
+ Kernel::HLERequestContext& ctx) {
const auto guard = LockService();
- switch (context.GetCommandType()) {
- case IPC::CommandType::Close: {
- IPC::ResponseBuilder rb{context, 2};
+ switch (ctx.GetCommandType()) {
+ case IPC::CommandType::Close:
+ case IPC::CommandType::TIPC_Close: {
+ session.Close();
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
return IPC::ERR_REMOTE_PROCESS_DEAD;
}
case IPC::CommandType::ControlWithContext:
case IPC::CommandType::Control: {
- system.ServiceManager().InvokeControlRequest(context);
+ system.ServiceManager().InvokeControlRequest(ctx);
break;
}
case IPC::CommandType::RequestWithContext:
case IPC::CommandType::Request: {
- InvokeRequest(context);
+ InvokeRequest(ctx);
break;
}
default:
- UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType());
+ if (ctx.IsTipc()) {
+ InvokeRequestTipc(ctx);
+ break;
+ }
+
+ UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
}
// If emulation was shutdown, we are closing service threads, do not write the response back to
// memory that may be shutting down as well.
if (system.IsPoweredOn()) {
- context.WriteToOutgoingCommandBuffer(context.GetThread());
+ ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
}
return RESULT_SUCCESS;
@@ -206,7 +240,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
- SM::ServiceManager::InstallInterfaces(sm, system);
+ system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
Account::InstallInterfaces(system);
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 @@
#include "common/common_types.h"
#include "common/spin_lock.h"
#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/object.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -21,10 +20,9 @@ class System;
}
namespace Kernel {
-class ClientPort;
-class ServerPort;
-class ServerSession;
class HLERequestContext;
+class KClientPort;
+class KServerSession;
} // namespace Kernel
namespace Service {
@@ -68,12 +66,19 @@ public:
/// Creates a port pair and registers this service with the given ServiceManager.
void InstallAsService(SM::ServiceManager& service_manager);
- /// Creates a port pair and registers it on the kernel's global port registry.
- void InstallAsNamedPort(Kernel::KernelCore& kernel);
- /// Invokes a service request routine.
+
+ /// Invokes a service request routine using the HIPC protocol.
void InvokeRequest(Kernel::HLERequestContext& ctx);
+
+ /// Invokes a service request routine using the HIPC protocol.
+ void InvokeRequestTipc(Kernel::HLERequestContext& ctx);
+
+ /// Creates a port pair and registers it on the kernel's global port registry.
+ Kernel::KClientPort& CreatePort(Kernel::KernelCore& kernel);
+
/// Handles a synchronization request for the service.
- ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
+ ResultCode HandleSyncRequest(Kernel::KServerSession& session,
+ Kernel::HLERequestContext& context) override;
protected:
/// Member-function pointer type of SyncRequest handlers.
@@ -106,6 +111,7 @@ private:
~ServiceFrameworkBase() override;
void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
+ void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
/// Identifier string used to connect to the service.
@@ -120,6 +126,7 @@ private:
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
InvokerFn* handler_invoker;
boost::container::flat_map<u32, FunctionInfoBase> handlers;
+ boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
Common::SpinLock lock_service;
@@ -148,17 +155,17 @@ protected:
/**
* Constructs a FunctionInfo for a function.
*
- * @param expected_header request header in the command buffer which will trigger dispatch
+ * @param expected_header_ request header in the command buffer which will trigger dispatch
* to this handler
- * @param handler_callback member function in this service which will be called to handle
+ * @param handler_callback_ member function in this service which will be called to handle
* the request
- * @param name human-friendly name for the request. Used mostly for logging purposes.
+ * @param name_ human-friendly name for the request. Used mostly for logging purposes.
*/
- FunctionInfo(u32 expected_header, HandlerFnP<Self> handler_callback, const char* name)
+ FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
: FunctionInfoBase{
- expected_header,
+ expected_header_,
// Type-erase member function pointer by casting it down to the base class.
- static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback), name} {}
+ static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
};
/**
@@ -187,6 +194,20 @@ protected:
RegisterHandlersBase(functions, n);
}
+ /// Registers handlers in the service.
+ template <std::size_t N>
+ void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
+ RegisterHandlersTipc(functions, N);
+ }
+
+ /**
+ * Registers handlers in the service. Usually prefer using the other RegisterHandlers
+ * overload in order to avoid needing to specify the array size.
+ */
+ void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
+ RegisterHandlersBaseTipc(functions, n);
+ }
+
private:
/**
* 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 @@
#include "core/file_sys/errors.h"
#include "core/file_sys/system_archive/system_version.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/k_client_port.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/set/set_sys.h"
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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_session.h"
#include "core/hle/service/sm/controller.h"
namespace Service::SM {
void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
- LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
+ LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
ctx.Session()->ConvertToDomain();
IPC::ResponseBuilder rb{ctx, 3};
@@ -26,15 +26,23 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
// and that we probably want to actually make an entirely new Session, but we still need to
// verify this on hardware.
+
LOG_DEBUG(Service, "called");
+ auto session = ctx.Session()->GetParent();
+
+ // Open a reference to the session to simulate a new one being created.
+ session->Open();
+ session->GetClientSession().Open();
+ session->GetServerSession().Open();
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
+ rb.PushMoveObjects(session->GetClientSession());
}
void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject");
+ LOG_DEBUG(Service, "called");
CloneCurrentObject(ctx);
}
@@ -44,7 +52,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u16>(0x1000);
+ rb.Push<u16>(0x8000);
}
// 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 @@
#include "common/assert.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_server_port.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_session.h"
#include "core/hle/result.h"
#include "core/hle/service/sm/controller.h"
#include "core/hle/service/sm/sm.h"
namespace Service::SM {
+constexpr ResultCode ERR_NOT_INITIALIZED(ErrorModule::SM, 2);
constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
@@ -31,24 +36,21 @@ static ResultCode ValidateServiceName(const std::string& name) {
LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
return ERR_INVALID_NAME;
}
- if (name.rfind('\0') != std::string::npos) {
- LOG_ERROR(Service_SM, "A non null terminated service was passed");
- return ERR_INVALID_NAME;
- }
return RESULT_SUCCESS;
}
-void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) {
- ASSERT(self->sm_interface.expired());
+Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
+ ASSERT(self.sm_interface.expired());
auto sm = std::make_shared<SM>(self, system);
- sm->InstallAsNamedPort(system.Kernel());
- self->sm_interface = sm;
- self->controller_interface = std::make_unique<Controller>(system);
+ self.sm_interface = sm;
+ self.controller_interface = std::make_unique<Controller>(system);
+
+ return sm->CreatePort(system.Kernel());
}
-ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name,
- u32 max_sessions) {
+ResultVal<Kernel::KServerPort*> ServiceManager::RegisterService(std::string name,
+ u32 max_sessions) {
CASCADE_CODE(ValidateServiceName(name));
@@ -57,11 +59,12 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(s
return ERR_ALREADY_REGISTERED;
}
- auto [server_port, client_port] =
- Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name);
+ auto* port = Kernel::KPort::Create(kernel);
+ port->Initialize(max_sessions, false, name);
- registered_services.emplace(std::move(name), std::move(client_port));
- return MakeResult(std::move(server_port));
+ registered_services.emplace(std::move(name), port);
+
+ return MakeResult(&port->GetServerPort());
}
ResultCode ServiceManager::UnregisterService(const std::string& name) {
@@ -72,12 +75,14 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
return ERR_SERVICE_NOT_REGISTERED;
}
+
+ iter->second->Close();
+
registered_services.erase(iter);
return RESULT_SUCCESS;
}
-ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
- const std::string& name) {
+ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
auto it = registered_services.find(name);
@@ -89,13 +94,6 @@ ResultVal<std::shared_ptr<Kernel::ClientPort>> ServiceManager::GetServicePort(
return MakeResult(it->second);
}
-ResultVal<std::shared_ptr<Kernel::ClientSession>> ServiceManager::ConnectToService(
- const std::string& name) {
-
- CASCADE_RESULT(auto client_port, GetServicePort(name));
- return client_port->Connect();
-}
-
SM::~SM() = default;
/**
@@ -108,50 +106,81 @@ SM::~SM() = default;
void SM::Initialize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SM, "called");
+ is_initialized = true;
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void SM::GetService(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
+ auto result = GetServiceImpl(ctx);
+ if (result.Succeeded()) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+ rb.Push(result.Code());
+ rb.PushMoveObjects(result.Unwrap());
+ } else {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result.Code());
+ }
+}
+
+void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
+ auto result = GetServiceImpl(ctx);
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+ rb.Push(result.Code());
+ rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
+}
+
+static std::string PopServiceName(IPC::RequestParser& rp) {
auto name_buf = rp.PopRaw<std::array<char, 8>>();
- auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
+ std::string result;
+ for (const auto& c : name_buf) {
+ if (c >= ' ' && c <= '~') {
+ result.push_back(c);
+ }
+ }
+ return result;
+}
- std::string name(name_buf.begin(), end);
+ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) {
+ if (!is_initialized) {
+ return ERR_NOT_INITIALIZED;
+ }
- auto client_port = service_manager->GetServicePort(name);
- if (client_port.Failed()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(client_port.Code());
- LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, client_port.Code().raw);
- if (name.length() == 0)
- return; // LibNX Fix
- UNIMPLEMENTED();
- return;
+ IPC::RequestParser rp{ctx};
+ std::string name(PopServiceName(rp));
+
+ auto result = service_manager.GetServicePort(name);
+ if (result.Failed()) {
+ LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw);
+ return result.Code();
}
- auto [client, server] = Kernel::Session::Create(kernel, name);
+ auto* port = result.Unwrap();
+
+ // Kernel::KScopedResourceReservation session_reservation(
+ // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions);
+ // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached);
+
+ auto* session = Kernel::KSession::Create(kernel);
+ session->Initialize(&port->GetClientPort(), std::move(name));
- const auto& server_port = client_port.Unwrap()->GetServerPort();
- if (server_port->GetHLEHandler()) {
- server_port->GetHLEHandler()->ClientConnected(server);
+ // Commit the session reservation.
+ // session_reservation.Commit();
+
+ if (port->GetServerPort().GetHLEHandler()) {
+ port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession());
} else {
- server_port->AppendPendingSession(server);
+ port->EnqueueSession(&session->GetServerSession());
}
- LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
- IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
- rb.Push(RESULT_SUCCESS);
- rb.PushMoveObjects(std::move(client));
+ LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
+ return MakeResult(&session->GetClientSession());
}
void SM::RegisterService(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
-
- const auto name_buf = rp.PopRaw<std::array<char, 8>>();
- const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
-
- const std::string name(name_buf.begin(), end);
+ std::string name(PopServiceName(rp));
const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
const auto max_session_count = rp.PopRaw<u32>();
@@ -159,7 +188,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
max_session_count, is_light);
- auto handle = service_manager->RegisterService(name, max_session_count);
+ auto handle = service_manager.RegisterService(name, max_session_count);
if (handle.Failed()) {
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
handle.Code().raw);
@@ -170,33 +199,38 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(handle.Code());
- rb.PushMoveObjects(std::move(handle).Unwrap());
+
+ auto server_port = handle.Unwrap();
+ rb.PushMoveObjects(server_port);
}
void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
+ std::string name(PopServiceName(rp));
- const auto name_buf = rp.PopRaw<std::array<char, 8>>();
- const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
-
- const std::string name(name_buf.begin(), end);
LOG_DEBUG(Service_SM, "called with name={}", name);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(service_manager->UnregisterService(name));
+ rb.Push(service_manager.UnregisterService(name));
}
-SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
+SM::SM(ServiceManager& service_manager_, Core::System& system_)
: ServiceFramework{system_, "sm:", 4},
- service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
- static const FunctionInfo functions[] = {
+ service_manager{service_manager_}, kernel{system_.Kernel()} {
+ RegisterHandlers({
{0, &SM::Initialize, "Initialize"},
{1, &SM::GetService, "GetService"},
{2, &SM::RegisterService, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"},
- };
- RegisterHandlers(functions);
+ });
+ RegisterHandlersTipc({
+ {0, &SM::Initialize, "Initialize"},
+ {1, &SM::GetServiceTipc, "GetService"},
+ {2, &SM::RegisterService, "RegisterService"},
+ {3, &SM::UnregisterService, "UnregisterService"},
+ {4, nullptr, "DetachClient"},
+ });
}
} // 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 @@
#include <unordered_map>
#include "common/concepts.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/object.h"
-#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/k_port.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
@@ -21,10 +19,11 @@ class System;
}
namespace Kernel {
-class ClientPort;
-class ClientSession;
+class KClientPort;
+class KClientSession;
class KernelCore;
-class ServerPort;
+class KPort;
+class KServerPort;
class SessionRequestHandler;
} // namespace Kernel
@@ -35,31 +34,33 @@ class Controller;
/// Interface to "sm:" service
class SM final : public ServiceFramework<SM> {
public:
- explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_);
+ explicit SM(ServiceManager& service_manager_, Core::System& system_);
~SM() override;
private:
void Initialize(Kernel::HLERequestContext& ctx);
void GetService(Kernel::HLERequestContext& ctx);
+ void GetServiceTipc(Kernel::HLERequestContext& ctx);
void RegisterService(Kernel::HLERequestContext& ctx);
void UnregisterService(Kernel::HLERequestContext& ctx);
- std::shared_ptr<ServiceManager> service_manager;
+ ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx);
+
+ ServiceManager& service_manager;
+ bool is_initialized{};
Kernel::KernelCore& kernel;
};
class ServiceManager {
public:
- static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system);
+ static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager();
- ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name,
- u32 max_sessions);
+ ResultVal<Kernel::KServerPort*> RegisterService(std::string name, u32 max_sessions);
ResultCode UnregisterService(const std::string& name);
- ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
- ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
+ ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const {
@@ -68,11 +69,11 @@ public:
LOG_DEBUG(Service, "Can't find service: {}", service_name);
return nullptr;
}
- auto port = service->second->GetServerPort();
+ auto* port = service->second;
if (port == nullptr) {
return nullptr;
}
- return std::static_pointer_cast<T>(port->GetHLEHandler());
+ return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler());
}
void InvokeControlRequest(Kernel::HLERequestContext& context);
@@ -81,8 +82,8 @@ private:
std::weak_ptr<SM> sm_interface;
std::unique_ptr<Controller> controller_interface;
- /// Map of registered services, retrieved using GetServicePort or ConnectToService.
- std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services;
+ /// Map of registered services, retrieved using GetServicePort.
+ std::unordered_map<std::string, Kernel::KPort*> registered_services;
/// Kernel context
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 @@
namespace Service::SSL {
+enum class CertificateFormat : u32 {
+ Pem = 1,
+ Der = 2,
+};
+
class ISslConnection final : public ServiceFramework<ISslConnection> {
public:
explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} {
@@ -58,8 +63,8 @@ public:
{1, nullptr, "GetOption"},
{2, &ISslContext::CreateConnection, "CreateConnection"},
{3, nullptr, "GetConnectionCount"},
- {4, nullptr, "ImportServerPki"},
- {5, nullptr, "ImportClientPki"},
+ {4, &ISslContext::ImportServerPki, "ImportServerPki"},
+ {5, &ISslContext::ImportClientPki, "ImportClientPki"},
{6, nullptr, "RemoveServerPki"},
{7, nullptr, "RemoveClientPki"},
{8, nullptr, "RegisterInternalPki"},
@@ -94,6 +99,39 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISslConnection>(system);
}
+
+ void ImportServerPki(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto certificate_format = rp.PopEnum<CertificateFormat>();
+ const auto pkcs_12_certificates = ctx.ReadBuffer(0);
+
+ constexpr u64 server_id = 0;
+
+ LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(server_id);
+ }
+
+ void ImportClientPki(Kernel::HLERequestContext& ctx) {
+ const auto pkcs_12_certificate = ctx.ReadBuffer(0);
+ const auto ascii_password = [&ctx] {
+ if (ctx.CanReadBuffer(1)) {
+ return ctx.ReadBuffer(1);
+ }
+
+ return std::vector<u8>{};
+ }();
+
+ constexpr u64 client_id = 0;
+
+ LOG_WARNING(Service_SSL, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(client_id);
+ }
};
class 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 {
class EphemeralNetworkSystemClockCore final : public SystemClockCore {
public:
- explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core)
- : SystemClockCore{steady_clock_core} {}
+ explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
+ : SystemClockCore{steady_clock_core_} {}
};
} // 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 @@
namespace Service::Time {
-Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name)
- : Interface(std::move(module), system, name) {
+Time::Time(std::shared_ptr<Module> module_, Core::System& system_, const char* name_)
+ : Interface{std::move(module_), system_, name_} {
// clang-format off
static const FunctionInfo functions[] = {
{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 {
class Time final : public Module::Interface {
public:
- explicit Time(std::shared_ptr<Module> time, Core::System& system, const char* name);
+ explicit Time(std::shared_ptr<Module> time, Core::System& system_, const char* name_);
~Time() override;
};
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 {
class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
public:
- explicit LocalSystemClockContextWriter(SharedMemory& shared_memory)
- : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {}
+ explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_)
+ : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
protected:
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 {
class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
public:
- explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory)
- : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {}
+ explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_)
+ : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {}
protected:
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 {
class StandardLocalSystemClockCore final : public SystemClockCore {
public:
- explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core)
- : SystemClockCore{steady_clock_core} {}
+ explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_)
+ : SystemClockCore{steady_clock_core_} {}
};
} // 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 {
class StandardNetworkSystemClockCore final : public SystemClockCore {
public:
- explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core)
- : SystemClockCore{steady_clock_core} {}
+ explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_)
+ : SystemClockCore{steady_clock_core_} {}
void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
standard_network_clock_sufficient_accuracy = value;
}
bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const {
- SystemClockContext context{};
- if (GetClockContext(system, context) != RESULT_SUCCESS) {
+ SystemClockContext clock_ctx{};
+ if (GetClockContext(system, clock_ctx) != RESULT_SUCCESS) {
return {};
}
s64 span{};
- if (context.steady_time_point.GetSpanBetween(
+ if (clock_ctx.steady_time_point.GetSpanBetween(
GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) {
return {};
}
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 @@
#include "common/assert.h"
#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
#include "core/hle/service/time/standard_local_system_clock_core.h"
#include "core/hle/service/time/standard_network_system_clock_core.h"
#include "core/hle/service/time/standard_user_system_clock_core.h"
@@ -12,15 +11,15 @@
namespace Service::Time::Clock {
StandardUserSystemClockCore::StandardUserSystemClockCore(
- StandardLocalSystemClockCore& local_system_clock_core,
- StandardNetworkSystemClockCore& network_system_clock_core, Core::System& system)
- : SystemClockCore(local_system_clock_core.GetSteadyClockCore()),
- local_system_clock_core{local_system_clock_core},
- network_system_clock_core{network_system_clock_core}, auto_correction_enabled{},
- auto_correction_time{SteadyClockTimePoint::GetRandom()},
- auto_correction_event{Kernel::KEvent::Create(
- system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} {
- auto_correction_event->Initialize();
+ StandardLocalSystemClockCore& local_system_clock_core_,
+ StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_)
+ : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()),
+ local_system_clock_core{local_system_clock_core_},
+ network_system_clock_core{network_system_clock_core_},
+ auto_correction_time{SteadyClockTimePoint::GetRandom()}, auto_correction_event{
+ system_.Kernel()} {
+ Kernel::KAutoObject::Create(std::addressof(auto_correction_event));
+ auto_correction_event.Initialize("StandardUserSystemClockCore:AutoCorrectionEvent");
}
ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
@@ -36,21 +35,21 @@ ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::Syst
}
ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system,
- SystemClockContext& context) const {
+ SystemClockContext& ctx) const {
if (const ResultCode result{ApplyAutomaticCorrection(system, false)};
result != RESULT_SUCCESS) {
return result;
}
- return local_system_clock_core.GetClockContext(system, context);
+ return local_system_clock_core.GetClockContext(system, ctx);
}
-ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext& context) {
+ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext&) {
UNREACHABLE();
return ERROR_NOT_IMPLEMENTED;
}
-ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext& context) {
+ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) {
UNREACHABLE();
return ERROR_NOT_IMPLEMENTED;
}
@@ -65,13 +64,13 @@ ResultCode StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& s
return ERROR_UNINITIALIZED_CLOCK;
}
- SystemClockContext context{};
- if (const ResultCode result{network_system_clock_core.GetClockContext(system, context)};
+ SystemClockContext ctx{};
+ if (const ResultCode result{network_system_clock_core.GetClockContext(system, ctx)};
result != RESULT_SUCCESS) {
return result;
}
- local_system_clock_core.SetClockContext(context);
+ local_system_clock_core.SetClockContext(ctx);
return RESULT_SUCCESS;
}
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 @@
#pragma once
+#include "core/hle/kernel/k_event.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/system_clock_core.h"
@@ -22,13 +23,13 @@ class StandardNetworkSystemClockCore;
class StandardUserSystemClockCore final : public SystemClockCore {
public:
- StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core,
- StandardNetworkSystemClockCore& network_system_clock_core,
- Core::System& system);
+ StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_,
+ StandardNetworkSystemClockCore& network_system_clock_core_,
+ Core::System& system_);
ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value);
- ResultCode GetClockContext(Core::System& system, SystemClockContext& context) const override;
+ ResultCode GetClockContext(Core::System& system, SystemClockContext& ctx) const override;
bool IsAutomaticCorrectionEnabled() const {
return auto_correction_enabled;
@@ -39,7 +40,7 @@ public:
}
protected:
- ResultCode Flush(const SystemClockContext& context) override;
+ ResultCode Flush(const SystemClockContext&) override;
ResultCode SetClockContext(const SystemClockContext&) override;
@@ -54,7 +55,7 @@ private:
StandardNetworkSystemClockCore& network_system_clock_core;
bool auto_correction_enabled{};
SteadyClockTimePoint auto_correction_time;
- std::shared_ptr<Kernel::KEvent> auto_correction_event;
+ Kernel::KEvent auto_correction_event;
};
} // 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 @@
namespace Service::Time::Clock {
-SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core)
- : steady_clock_core{steady_clock_core} {
+SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_)
+ : steady_clock_core{steady_clock_core_} {
context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
}
@@ -45,18 +45,18 @@ ResultCode SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time)
return Flush(clock_context);
}
-ResultCode SystemClockCore::Flush(const SystemClockContext& context) {
+ResultCode SystemClockCore::Flush(const SystemClockContext& clock_context) {
if (!system_clock_context_update_callback) {
return RESULT_SUCCESS;
}
- return system_clock_context_update_callback->Update(context);
+ return system_clock_context_update_callback->Update(clock_context);
}
-ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& context) {
- if (const ResultCode result{SetClockContext(context)}; result != RESULT_SUCCESS) {
+ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& clock_context) {
+ if (const ResultCode result{SetClockContext(clock_context)}; result != RESULT_SUCCESS) {
return result;
}
- return Flush(context);
+ return Flush(clock_context);
}
bool 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;
class SystemClockCore {
public:
- explicit SystemClockCore(SteadyClockCore& steady_clock_core);
+ explicit SystemClockCore(SteadyClockCore& steady_clock_core_);
virtual ~SystemClockCore();
SteadyClockCore& GetSteadyClockCore() const {
@@ -43,7 +43,7 @@ public:
return RESULT_SUCCESS;
}
- virtual ResultCode Flush(const SystemClockContext& context);
+ virtual ResultCode Flush(const SystemClockContext& clock_context);
void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) {
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 @@
#include "core/core_timing_util.h"
#include "core/hardware_properties.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/client_port.h"
-#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/time/interface.h"
@@ -393,7 +392,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem()));
+ rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem());
}
Module::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 {
return 0;
}
- void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
+ void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
standard_steady_clock_core.SetClockSourceId(clock_source_id);
@@ -137,21 +137,21 @@ struct TimeManager::Impl final {
standard_steady_clock_core.SetInternalOffset(internal_offset);
standard_steady_clock_core.MarkAsInitialized();
- const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
- shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
+ const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system_)};
+ shared_memory.SetupStandardSteadyClock(clock_source_id, current_time_point);
}
- void SetupStandardLocalSystemClock(Core::System& system,
+ void SetupStandardLocalSystemClock(Core::System& system_,
Clock::SystemClockContext clock_context, s64 posix_time) {
standard_local_system_clock_core.SetUpdateCallbackInstance(
local_system_clock_context_writer);
const auto current_time_point{
- standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
+ standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system_)};
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
standard_local_system_clock_core.SetSystemClockContext(clock_context);
} else {
- if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) !=
+ if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) !=
RESULT_SUCCESS) {
UNREACHABLE();
return;
@@ -177,10 +177,10 @@ struct TimeManager::Impl final {
standard_network_system_clock_core.MarkAsInitialized();
}
- void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
+ void SetupStandardUserSystemClock(Core::System& system_, bool is_automatic_correction_enabled,
Clock::SteadyClockTimePoint steady_clock_time_point) {
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
- system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
+ system_, is_automatic_correction_enabled) != RESULT_SUCCESS) {
UNREACHABLE();
return;
}
@@ -196,10 +196,10 @@ struct TimeManager::Impl final {
ephemeral_network_system_clock_core.MarkAsInitialized();
}
- void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) {
- const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)};
+ void UpdateLocalSystemClockTime(Core::System& system_, s64 posix_time) {
+ const auto timespan{Clock::TimeSpanType::FromSeconds(posix_time)};
if (GetStandardLocalSystemClockCore()
- .SetCurrentTime(system, timespan.ToSeconds())
+ .SetCurrentTime(system_, timespan.ToSeconds())
.IsError()) {
UNREACHABLE();
return;
@@ -223,7 +223,7 @@ struct TimeManager::Impl final {
TimeZone::TimeZoneContentManager time_zone_content_manager;
};
-TimeManager::TimeManager(Core::System& system) : system{system} {}
+TimeManager::TimeManager(Core::System& system_) : system{system_} {}
TimeManager::~TimeManager() = default;
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;
class TimeManager final {
public:
- explicit TimeManager(Core::System& system);
+ explicit TimeManager(Core::System& system_);
~TimeManager();
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 {
static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
-SharedMemory::SharedMemory(Core::System& system) : system(system) {
- shared_memory_holder = SharedFrom(&system.Kernel().GetTimeSharedMem());
- std::memset(shared_memory_holder->GetPointer(), 0, SHARED_MEMORY_SIZE);
+SharedMemory::SharedMemory(Core::System& system_) : system(system_) {
+ std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE);
}
SharedMemory::~SharedMemory() = default;
-std::shared_ptr<Kernel::KSharedMemory> SharedMemory::GetSharedMemoryHolder() const {
- return shared_memory_holder;
-}
-
-void SharedMemory::SetupStandardSteadyClock(Core::System& system,
- const Common::UUID& clock_source_id,
+void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
Clock::TimeSpanType current_time_point) {
const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)};
@@ -35,22 +29,22 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system,
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
clock_source_id};
shared_memory_format.standard_steady_clock_timepoint.StoreData(
- shared_memory_holder->GetPointer(), context);
+ system.Kernel().GetTimeSharedMem().GetPointer(), context);
}
void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
shared_memory_format.standard_local_system_clock_context.StoreData(
- shared_memory_holder->GetPointer(), context);
+ system.Kernel().GetTimeSharedMem().GetPointer(), context);
}
void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
shared_memory_format.standard_network_system_clock_context.StoreData(
- shared_memory_holder->GetPointer(), context);
+ system.Kernel().GetTimeSharedMem().GetPointer(), context);
}
void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
- shared_memory_holder->GetPointer(), is_enabled);
+ system.Kernel().GetTimeSharedMem().GetPointer(), is_enabled);
}
} // 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 {
class SharedMemory final {
public:
- explicit SharedMemory(Core::System& system);
+ explicit SharedMemory(Core::System& system_);
~SharedMemory();
- // Return the shared memory handle
- std::shared_ptr<Kernel::KSharedMemory> GetSharedMemoryHolder() const;
-
// TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
template <typename T, std::size_t Offset>
struct MemoryBarrier {
@@ -56,14 +53,13 @@ public:
};
static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
- void SetupStandardSteadyClock(Core::System& system, const Common::UUID& clock_source_id,
- Clock::TimeSpanType currentTimePoint);
+ void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
+ Clock::TimeSpanType current_time_point);
void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
void SetAutomaticCorrectionEnabled(bool is_enabled);
private:
- std::shared_ptr<Kernel::KSharedMemory> shared_memory_holder;
Core::System& system;
Format shared_memory_format{};
};
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) {
return location_name_cache;
}
-TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
- : system{system}, location_name_cache{BuildLocationNameCache(system)} {}
+TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
+ : system{system_}, location_name_cache{BuildLocationNameCache(system)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
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 {
class TimeZoneContentManager final {
public:
- explicit TimeZoneContentManager(Core::System& system);
+ explicit TimeZoneContentManager(Core::System& system_);
void Initialize(TimeManager& time_manager);
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 @@
namespace Service::VI {
-Display::Display(u64 id, std::string name, Core::System& system) : id{id}, name{std::move(name)} {
- auto& kernel = system.Kernel();
- vsync_event = Kernel::KEvent::Create(kernel, fmt::format("Display VSync Event {}", id));
- vsync_event->Initialize();
+Display::Display(u64 id, std::string name_, Core::System& system)
+ : display_id{id}, name{std::move(name_)}, vsync_event{system.Kernel()} {
+ Kernel::KAutoObject::Create(std::addressof(vsync_event));
+ vsync_event.Initialize(fmt::format("Display VSync Event {}", id));
}
Display::~Display() = default;
@@ -33,32 +33,30 @@ const Layer& Display::GetLayer(std::size_t index) const {
return *layers.at(index);
}
-std::shared_ptr<Kernel::KReadableEvent> Display::GetVSyncEvent() const {
- return vsync_event->GetReadableEvent();
+Kernel::KReadableEvent& Display::GetVSyncEvent() {
+ return vsync_event.GetReadableEvent();
}
void Display::SignalVSyncEvent() {
- vsync_event->GetWritableEvent()->Signal();
+ vsync_event.GetWritableEvent().Signal();
}
-void Display::CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue) {
+void Display::CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue) {
// TODO(Subv): Support more than 1 layer.
ASSERT_MSG(layers.empty(), "Only one layer is supported per display at the moment");
- layers.emplace_back(std::make_shared<Layer>(id, buffer_queue));
+ layers.emplace_back(std::make_shared<Layer>(layer_id, buffer_queue));
}
-void Display::CloseLayer(u64 id) {
- layers.erase(
- std::remove_if(layers.begin(), layers.end(),
- [id](const std::shared_ptr<Layer>& layer) { return layer->GetID() == id; }),
- layers.end());
+void Display::CloseLayer(u64 layer_id) {
+ std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetID() == layer_id; });
}
-Layer* Display::FindLayer(u64 id) {
+Layer* Display::FindLayer(u64 layer_id) {
const auto itr =
- std::find_if(layers.begin(), layers.end(),
- [id](const std::shared_ptr<Layer>& layer) { return layer->GetID() == id; });
+ std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
+ return layer->GetID() == layer_id;
+ });
if (itr == layers.end()) {
return nullptr;
@@ -67,10 +65,11 @@ Layer* Display::FindLayer(u64 id) {
return itr->get();
}
-const Layer* Display::FindLayer(u64 id) const {
+const Layer* Display::FindLayer(u64 layer_id) const {
const auto itr =
- std::find_if(layers.begin(), layers.end(),
- [id](const std::shared_ptr<Layer>& layer) { return layer->GetID() == id; });
+ std::find_if(layers.begin(), layers.end(), [layer_id](const std::shared_ptr<Layer>& layer) {
+ return layer->GetID() == layer_id;
+ });
if (itr == layers.end()) {
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 @@
#include <string>
#include <vector>
+#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Kernel {
@@ -24,24 +25,21 @@ class Layer;
/// Represents a single display type
class Display {
+ YUZU_NON_COPYABLE(Display);
+ YUZU_NON_MOVEABLE(Display);
+
public:
/// Constructs a display with a given unique ID and name.
///
/// @param id The unique ID for this display.
- /// @param name The name for this display.
+ /// @param name_ The name for this display.
///
- Display(u64 id, std::string name, Core::System& system);
+ Display(u64 id, std::string name_, Core::System& system);
~Display();
- Display(const Display&) = delete;
- Display& operator=(const Display&) = delete;
-
- Display(Display&&) = default;
- Display& operator=(Display&&) = default;
-
/// Gets the unique ID assigned to this display.
u64 GetID() const {
- return id;
+ return display_id;
}
/// Gets the name of this display
@@ -61,48 +59,48 @@ public:
const Layer& GetLayer(std::size_t index) const;
/// Gets the readable vsync event.
- std::shared_ptr<Kernel::KReadableEvent> GetVSyncEvent() const;
+ Kernel::KReadableEvent& GetVSyncEvent();
/// Signals the internal vsync event.
void SignalVSyncEvent();
/// Creates and adds a layer to this display with the given ID.
///
- /// @param id The ID to assign to the created layer.
+ /// @param layer_id The ID to assign to the created layer.
/// @param buffer_queue The buffer queue for the layer instance to use.
///
- void CreateLayer(u64 id, NVFlinger::BufferQueue& buffer_queue);
+ void CreateLayer(u64 layer_id, NVFlinger::BufferQueue& buffer_queue);
/// Closes and removes a layer from this display with the given ID.
///
- /// @param id The ID assigned to the layer to close.
+ /// @param layer_id The ID assigned to the layer to close.
///
- void CloseLayer(u64 id);
+ void CloseLayer(u64 layer_id);
/// Attempts to find a layer with the given ID.
///
- /// @param id The layer ID.
+ /// @param layer_id The layer ID.
///
/// @returns If found, the Layer instance with the given ID.
/// If not found, then nullptr is returned.
///
- Layer* FindLayer(u64 id);
+ Layer* FindLayer(u64 layer_id);
/// Attempts to find a layer with the given ID.
///
- /// @param id The layer ID.
+ /// @param layer_id The layer ID.
///
/// @returns If found, the Layer instance with the given ID.
/// If not found, then nullptr is returned.
///
- const Layer* FindLayer(u64 id) const;
+ const Layer* FindLayer(u64 layer_id) const;
private:
- u64 id;
+ u64 display_id;
std::string name;
std::vector<std::shared_ptr<Layer>> layers;
- std::shared_ptr<Kernel::KEvent> vsync_event;
+ Kernel::KEvent vsync_event;
};
} // 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 @@
namespace Service::VI {
-Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : id{id}, buffer_queue{queue} {}
+Layer::Layer(u64 id, NVFlinger::BufferQueue& queue) : layer_id{id}, buffer_queue{queue} {}
Layer::~Layer() = default;
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:
/// Gets the ID for this layer.
u64 GetID() const {
- return id;
+ return layer_id;
}
/// Gets a reference to the buffer queue this layer is using.
@@ -45,7 +45,7 @@ public:
}
private:
- u64 id;
+ u64 layer_id;
NVFlinger::BufferQueue& buffer_queue;
};
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:
class IGBPConnectRequestParcel : public Parcel {
public:
- explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ explicit IGBPConnectRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -274,8 +274,8 @@ private:
class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
public:
- explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer)
- : Parcel(std::move(buffer)) {
+ explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer_)
+ : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -312,7 +312,7 @@ protected:
class IGBPCancelBufferRequestParcel : public Parcel {
public:
- explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -338,7 +338,7 @@ protected:
class IGBPDequeueBufferRequestParcel : public Parcel {
public:
- explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -360,8 +360,8 @@ public:
class IGBPDequeueBufferResponseParcel : public Parcel {
public:
- explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
- : slot(slot), multi_fence(multi_fence) {}
+ explicit IGBPDequeueBufferResponseParcel(u32 slot_, Nvidia::MultiFence& multi_fence_)
+ : slot(slot_), multi_fence(multi_fence_) {}
protected:
void SerializeData() override {
@@ -377,7 +377,7 @@ protected:
class IGBPRequestBufferRequestParcel : public Parcel {
public:
- explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -391,7 +391,7 @@ public:
class IGBPRequestBufferResponseParcel : public Parcel {
public:
- explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer) : buffer(buffer) {}
+ explicit IGBPRequestBufferResponseParcel(NVFlinger::IGBPBuffer buffer_) : buffer(buffer_) {}
~IGBPRequestBufferResponseParcel() override = default;
protected:
@@ -408,7 +408,7 @@ protected:
class IGBPQueueBufferRequestParcel : public Parcel {
public:
- explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -470,7 +470,7 @@ private:
class IGBPQueryRequestParcel : public Parcel {
public:
- explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
+ explicit IGBPQueryRequestParcel(std::vector<u8> buffer_) : Parcel(std::move(buffer_)) {
Deserialize();
}
@@ -484,7 +484,7 @@ public:
class IGBPQueryResponseParcel : public Parcel {
public:
- explicit IGBPQueryResponseParcel(u32 value) : value(value) {}
+ explicit IGBPQueryResponseParcel(u32 value_) : value{value_} {}
~IGBPQueryResponseParcel() override = default;
protected:
@@ -669,12 +669,10 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
- const auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
-
// TODO(Subv): Find out what this actually is.
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent());
+ rb.PushCopyObjects(nv_flinger.FindBufferQueue(id)->GetBufferWaitEvent());
}
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 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nso.h"
@@ -22,12 +22,12 @@
namespace Loader {
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
- bool override_update)
- : AppLoader(std::move(file_)), override_update(override_update) {
- const auto dir = file->GetContainingDirectory();
+ bool override_update_)
+ : AppLoader(std::move(file_)), override_update(override_update_) {
+ const auto file_dir = file->GetContainingDirectory();
// Title ID
- const auto npdm = dir->GetFile("main.npdm");
+ const auto npdm = file_dir->GetFile("main.npdm");
if (npdm != nullptr) {
const auto res = metadata.Load(npdm);
if (res == ResultStatus::Success)
@@ -37,7 +37,7 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
// Icon
FileSys::VirtualFile icon_file = nullptr;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
- icon_file = dir->GetFile("icon_" + std::string(language) + ".dat");
+ icon_file = file_dir->GetFile("icon_" + std::string(language) + ".dat");
if (icon_file != nullptr) {
icon_data = icon_file->ReadAllBytes();
break;
@@ -46,24 +46,23 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
if (icon_data.empty()) {
// Any png, jpeg, or bmp file
- const auto& files = dir->GetFiles();
+ const auto& files = file_dir->GetFiles();
const auto icon_iter =
- std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
- return file->GetExtension() == "png" || file->GetExtension() == "jpg" ||
- file->GetExtension() == "bmp" || file->GetExtension() == "jpeg";
+ std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
+ return f->GetExtension() == "png" || f->GetExtension() == "jpg" ||
+ f->GetExtension() == "bmp" || f->GetExtension() == "jpeg";
});
if (icon_iter != files.end())
icon_data = (*icon_iter)->ReadAllBytes();
}
// Metadata
- FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp");
+ FileSys::VirtualFile nacp_file = file_dir->GetFile("control.nacp");
if (nacp_file == nullptr) {
- const auto& files = dir->GetFiles();
+ const auto& files = file_dir->GetFiles();
const auto nacp_iter =
- std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
- return file->GetExtension() == "nacp";
- });
+ std::find_if(files.begin(), files.end(),
+ [](const FileSys::VirtualFile& f) { return f->GetExtension() == "nacp"; });
if (nacp_iter != files.end())
nacp_file = *nacp_iter;
}
@@ -75,12 +74,12 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
}
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
- FileSys::VirtualDir directory, bool override_update)
+ FileSys::VirtualDir directory, bool override_update_)
: AppLoader(directory->GetFile("main")), dir(std::move(directory)),
- override_update(override_update) {}
+ override_update(override_update_) {}
-FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) {
- if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) {
+FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
+ if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
return FileType::DeconstructedRomDirectory;
}
@@ -88,7 +87,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua
}
AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirectory::Load(
- Kernel::Process& process, Core::System& system) {
+ Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -184,8 +183,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Find the RomFS by searching for a ".romfs" file in this directory
const auto& files = dir->GetFiles();
const auto romfs_iter =
- std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) {
- return file->GetName().find(".romfs") != std::string::npos;
+ std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
+ return f->GetName().find(".romfs") != std::string::npos;
});
// Register the RomFS if a ".romfs" file was found
@@ -200,17 +199,21 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}};
}
-ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) {
- if (romfs == nullptr)
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& out_dir) {
+ if (romfs == nullptr) {
return ResultStatus::ErrorNoRomFS;
- dir = romfs;
+ }
+
+ out_dir = romfs;
return ResultStatus::Success;
}
-ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
- if (icon_data.empty())
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& out_buffer) {
+ if (icon_data.empty()) {
return ResultStatus::ErrorNoIcon;
- buffer = icon_data;
+ }
+
+ out_buffer = icon_data;
return ResultStatus::Success;
}
@@ -219,10 +222,12 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program
return ResultStatus::Success;
}
-ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
- if (name.empty())
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& out_title) {
+ if (name.empty()) {
return ResultStatus::ErrorNoControl;
- title = name;
+ }
+
+ out_title = name;
return ResultStatus::Success;
}
@@ -230,12 +235,12 @@ bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() const {
return false;
}
-ResultStatus AppLoader_DeconstructedRomDirectory::ReadNSOModules(Modules& modules) {
+ResultStatus AppLoader_DeconstructedRomDirectory::ReadNSOModules(Modules& out_modules) {
if (!is_loaded) {
return ResultStatus::ErrorNotInitialized;
}
- modules = this->modules;
+ out_modules = this->modules;
return ResultStatus::Success;
}
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 {
class AppLoader_DeconstructedRomDirectory final : public AppLoader {
public:
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file,
- bool override_update = false);
+ bool override_update_ = false);
// Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
- bool override_update = false);
+ bool override_update_ = false);
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is a deconstructed ROM directory.
+ *
+ * @param dir_file The file to verify.
+ *
+ * @return FileType::DeconstructedRomDirectory, or FileType::Error
+ * if the file is not a deconstructed ROM directory.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& dir_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
- ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
- ResultStatus ReadIcon(std::vector<u8>& buffer) override;
+ ResultStatus ReadRomFS(FileSys::VirtualFile& out_dir) override;
+ ResultStatus ReadIcon(std::vector<u8>& out_buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadTitle(std::string& title) override;
bool IsRomFSUpdatable() const override;
- ResultStatus ReadNSOModules(Modules& modules) override;
+ ResultStatus ReadNSOModules(Modules& out_modules) override;
private:
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 @@
#include "common/logging/log.h"
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/loader/elf.h"
#include "core/memory.h"
@@ -364,26 +364,29 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const
namespace Loader {
-AppLoader_ELF::AppLoader_ELF(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
+AppLoader_ELF::AppLoader_ELF(FileSys::VirtualFile file_) : AppLoader(std::move(file_)) {}
-FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) {
+FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& elf_file) {
static constexpr u16 ELF_MACHINE_ARM{0x28};
u32 magic = 0;
- if (4 != file->ReadObject(&magic))
+ if (4 != elf_file->ReadObject(&magic)) {
return FileType::Error;
+ }
u16 machine = 0;
- if (2 != file->ReadObject(&machine, 18))
+ if (2 != elf_file->ReadObject(&machine, 18)) {
return FileType::Error;
+ }
- if (Common::MakeMagic('\x7f', 'E', 'L', 'F') == magic && ELF_MACHINE_ARM == machine)
+ if (Common::MakeMagic('\x7f', 'E', 'L', 'F') == magic && ELF_MACHINE_ARM == machine) {
return FileType::ELF;
+ }
return FileType::Error;
}
-AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::Process& process,
+AppLoader_ELF::LoadResult AppLoader_ELF::Load(Kernel::KProcess& process,
[[maybe_unused]] Core::System& system) {
if (is_loaded) {
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:
explicit AppLoader_ELF(FileSys::VirtualFile file);
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is an ELF file.
+ *
+ * @param elf_file The file to identify.
+ *
+ * @return FileType::ELF, or FileType::Error if the file is not an ELF file.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& elf_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
};
} // 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 @@
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/loader/kip.h"
#include "core/memory.h"
@@ -24,9 +24,9 @@ AppLoader_KIP::AppLoader_KIP(FileSys::VirtualFile file_)
AppLoader_KIP::~AppLoader_KIP() = default;
-FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& file) {
+FileType AppLoader_KIP::IdentifyType(const FileSys::VirtualFile& in_file) {
u32_le magic{};
- if (file->GetSize() < sizeof(u32) || file->ReadObject(&magic) != sizeof(u32)) {
+ if (in_file->GetSize() < sizeof(u32) || in_file->ReadObject(&magic) != sizeof(u32)) {
return FileType::Error;
}
@@ -42,7 +42,7 @@ FileType AppLoader_KIP::GetFileType() const {
: FileType::Error;
}
-AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,
+AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
[[maybe_unused]] Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
@@ -56,10 +56,10 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,
return {kip->GetStatus(), {}};
}
- const auto get_kip_address_space_type = [](const auto& kip) {
- return kip.Is64Bit()
- ? (kip.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit
- : FileSys::ProgramAddressSpaceType::Is36Bit)
+ const auto get_kip_address_space_type = [](const auto& kip_type) {
+ return kip_type.Is64Bit()
+ ? (kip_type.Is39BitAddressSpace() ? FileSys::ProgramAddressSpaceType::Is39Bit
+ : FileSys::ProgramAddressSpaceType::Is36Bit)
: FileSys::ProgramAddressSpaceType::Is32Bit;
};
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:
~AppLoader_KIP() override;
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is a KIP.
+ *
+ * @param in_file The file to identify.
+ *
+ * @return FileType::KIP if found, or FileType::Error if unknown.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& in_file);
FileType GetFileType() const override;
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
private:
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 @@
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/elf.h"
#include "core/loader/kip.h"
@@ -194,7 +194,7 @@ std::ostream& operator<<(std::ostream& os, ResultStatus status) {
return os;
}
-AppLoader::AppLoader(FileSys::VirtualFile file) : file(std::move(file)) {}
+AppLoader::AppLoader(FileSys::VirtualFile file_) : file(std::move(file_)) {}
AppLoader::~AppLoader() = default;
/**
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;
namespace Kernel {
struct AddressMapping;
-class Process;
+class KProcess;
} // namespace Kernel
namespace Loader {
@@ -147,26 +147,31 @@ public:
};
using LoadResult = std::pair<ResultStatus, std::optional<LoadParameters>>;
- explicit AppLoader(FileSys::VirtualFile file);
+ explicit AppLoader(FileSys::VirtualFile file_);
virtual ~AppLoader();
/**
* Returns the type of this file
+ *
* @return FileType corresponding to the loaded file
*/
virtual FileType GetFileType() const = 0;
/**
* Load the application and return the created Process instance
+ *
* @param process The newly created process.
* @param system The system that this process is being loaded under.
+ *
* @return The status result of the operation.
*/
- virtual LoadResult Load(Kernel::Process& process, Core::System& system) = 0;
+ virtual LoadResult Load(Kernel::KProcess& process, Core::System& system) = 0;
/**
* Get the code (typically .code section) of the application
- * @param buffer Reference to buffer to store data
+ *
+ * @param[out] buffer Reference to buffer to store data
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadCode(std::vector<u8>& buffer) {
@@ -175,7 +180,9 @@ public:
/**
* Get the icon (typically icon section) of the application
- * @param buffer Reference to buffer to store data
+ *
+ * @param[out] buffer Reference to buffer to store data
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadIcon(std::vector<u8>& buffer) {
@@ -186,7 +193,9 @@ public:
* Get the banner (typically banner section) of the application
* In the context of NX, this is the animation that displays in the bottom right of the screen
* when a game boots. Stored in GIF format.
- * @param buffer Reference to buffer to store data
+ *
+ * @param[out] buffer Reference to buffer to store data
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadBanner(std::vector<u8>& buffer) {
@@ -197,7 +206,9 @@ public:
* Get the logo (typically logo section) of the application
* In the context of NX, this is the static image that displays in the top left of the screen
* when a game boots. Stored in JPEG format.
- * @param buffer Reference to buffer to store data
+ *
+ * @param[out] buffer Reference to buffer to store data
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadLogo(std::vector<u8>& buffer) {
@@ -206,7 +217,9 @@ public:
/**
* Get the program id of the application
- * @param out_program_id Reference to store program id into
+ *
+ * @param[out] out_program_id Reference to store program id into
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadProgramId(u64& out_program_id) {
@@ -216,19 +229,23 @@ public:
/**
* Get the RomFS of the application
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer
- * @param file The directory containing the RomFS
+ *
+ * @param[out] out_file The directory containing the RomFS
+ *
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadRomFS(FileSys::VirtualFile& file) {
+ virtual ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) {
return ResultStatus::ErrorNotImplemented;
}
/**
* Get the raw update of the application, should it come packed with one
- * @param file The raw update NCA file (Program-type
+ *
+ * @param[out] out_file The raw update NCA file (Program-type)
+ *
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) {
+ virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) {
return ResultStatus::ErrorNotImplemented;
}
@@ -236,7 +253,8 @@ public:
* Get whether or not updates can be applied to the RomFS.
* By default, this is true, however for formats where it cannot be guaranteed that the RomFS is
* the base game it should be set to false.
- * @return bool whether or not updatable.
+ *
+ * @return bool indicating whether or not the RomFS is updatable.
*/
virtual bool IsRomFSUpdatable() const {
return true;
@@ -244,8 +262,9 @@ public:
/**
* Gets the difference between the start of the IVFC header and the start of level 6 (RomFS)
- * data. Needed for bktr patching.
- * @return IVFC offset for romfs.
+ * data. Needed for BKTR patching.
+ *
+ * @return IVFC offset for RomFS.
*/
virtual u64 ReadRomFSIVFCOffset() const {
return 0;
@@ -253,7 +272,9 @@ public:
/**
* Get the title of the application
- * @param title Reference to store the application title into
+ *
+ * @param[out] title Reference to store the application title into
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadTitle(std::string& title) {
@@ -262,7 +283,9 @@ public:
/**
* Get the control data (CNMT) of the application
- * @param control Reference to store the application control data into
+ *
+ * @param[out] control Reference to store the application control data into
+ *
* @return ResultStatus result of function
*/
virtual ResultStatus ReadControlData(FileSys::NACP& control) {
@@ -271,10 +294,12 @@ public:
/**
* Get the RomFS of the manual of the application
- * @param file The raw manual RomFS of the game
+ *
+ * @param[out] out_file The raw manual RomFS of the game
+ *
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) {
+ virtual ResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) {
return ResultStatus::ErrorNotImplemented;
}
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 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/xts_archive.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/loader/nax.h"
#include "core/loader/nca.h"
@@ -26,14 +26,14 @@ FileType IdentifyTypeImpl(const FileSys::NAX& nax) {
}
} // Anonymous namespace
-AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file)
- : AppLoader(file), nax(std::make_unique<FileSys::NAX>(file)),
+AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file_)
+ : AppLoader(file_), nax(std::make_unique<FileSys::NAX>(file_)),
nca_loader(std::make_unique<AppLoader_NCA>(nax->GetDecrypted())) {}
AppLoader_NAX::~AppLoader_NAX() = default;
-FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) {
- const FileSys::NAX nax(file);
+FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& nax_file) {
+ const FileSys::NAX nax(nax_file);
return IdentifyTypeImpl(nax);
}
@@ -41,8 +41,7 @@ FileType AppLoader_NAX::GetFileType() const {
return IdentifyTypeImpl(*nax);
}
-AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::Process& process,
- [[maybe_unused]] Core::System& system) {
+AppLoader_NAX::LoadResult AppLoader_NAX::Load(Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
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;
/// Loads a NAX file
class AppLoader_NAX final : public AppLoader {
public:
- explicit AppLoader_NAX(FileSys::VirtualFile file);
+ explicit AppLoader_NAX(FileSys::VirtualFile file_);
~AppLoader_NAX() override;
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is a NAX file.
+ *
+ * @param nax_file The file to identify.
+ *
+ * @return FileType::NAX, or FileType::Error if the file is not a NAX file.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& nax_file);
FileType GetFileType() const override;
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
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 @@
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/romfs_factory.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nca.h"
@@ -21,17 +21,18 @@ AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_)
AppLoader_NCA::~AppLoader_NCA() = default;
-FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
- FileSys::NCA nca(file);
+FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& nca_file) {
+ const FileSys::NCA nca(nca_file);
if (nca.GetStatus() == ResultStatus::Success &&
- nca.GetType() == FileSys::NCAContentType::Program)
+ nca.GetType() == FileSys::NCAContentType::Program) {
return FileType::NCA;
+ }
return FileType::Error;
}
-AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::System& system) {
+AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -67,43 +68,59 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process, Core::Sy
}
ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
- if (nca == nullptr)
+ if (nca == nullptr) {
return ResultStatus::ErrorNotInitialized;
- if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
+ }
+
+ if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0) {
return ResultStatus::ErrorNoRomFS;
+ }
+
dir = nca->GetRomFS();
return ResultStatus::Success;
}
u64 AppLoader_NCA::ReadRomFSIVFCOffset() const {
- if (nca == nullptr)
+ if (nca == nullptr) {
return 0;
+ }
+
return nca->GetBaseIVFCOffset();
}
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
- if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
+ if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
return ResultStatus::ErrorNotInitialized;
+ }
+
out_program_id = nca->GetTitleId();
return ResultStatus::Success;
}
ResultStatus AppLoader_NCA::ReadBanner(std::vector<u8>& buffer) {
- if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
+ if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
return ResultStatus::ErrorNotInitialized;
+ }
+
const auto logo = nca->GetLogoPartition();
- if (logo == nullptr)
+ if (logo == nullptr) {
return ResultStatus::ErrorNoIcon;
+ }
+
buffer = logo->GetFile("StartupMovie.gif")->ReadAllBytes();
return ResultStatus::Success;
}
ResultStatus AppLoader_NCA::ReadLogo(std::vector<u8>& buffer) {
- if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
+ if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
return ResultStatus::ErrorNotInitialized;
+ }
+
const auto logo = nca->GetLogoPartition();
- if (logo == nullptr)
+ if (logo == nullptr) {
return ResultStatus::ErrorNoIcon;
+ }
+
buffer = logo->GetFile("NintendoLogo.png")->ReadAllBytes();
return ResultStatus::Success;
}
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;
/// Loads an NCA file
class AppLoader_NCA final : public AppLoader {
public:
- explicit AppLoader_NCA(FileSys::VirtualFile file);
+ explicit AppLoader_NCA(FileSys::VirtualFile file_);
~AppLoader_NCA() override;
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is an NCA file.
+ *
+ * @param nca_file The file to identify.
+ *
+ * @return FileType::NCA, or FileType::Error if the file is not an NCA file.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& nca_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
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 @@
#include "core/file_sys/vfs_offset.h"
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/nro.h"
#include "core/loader/nso.h"
@@ -72,7 +72,7 @@ struct AssetHeader {
};
static_assert(sizeof(AssetHeader) == 0x38, "AssetHeader has incorrect size.");
-AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) {
+AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file_) : AppLoader(std::move(file_)) {
NroHeader nro_header{};
if (file->ReadObject(&nro_header) != sizeof(NroHeader)) {
return;
@@ -114,10 +114,10 @@ AppLoader_NRO::AppLoader_NRO(FileSys::VirtualFile file) : AppLoader(file) {
AppLoader_NRO::~AppLoader_NRO() = default;
-FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
+FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
// Read NSO header
NroHeader nro_header{};
- if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
+ if (sizeof(NroHeader) != nro_file->ReadObject(&nro_header)) {
return FileType::Error;
}
if (nro_header.magic == Common::MakeMagic('N', 'R', 'O', '0')) {
@@ -130,8 +130,7 @@ static constexpr u32 PageAlignSize(u32 size) {
return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
}
-static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
- const std::string& name) {
+static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) {
if (data.size() < sizeof(NroHeader)) {
return {};
}
@@ -200,11 +199,11 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
return true;
}
-bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file) {
- return LoadNroImpl(process, file.ReadAllBytes(), file.GetName());
+bool AppLoader_NRO::LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file) {
+ return LoadNroImpl(process, nro_file.ReadAllBytes());
}
-AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::System& system) {
+AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
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;
}
namespace Kernel {
-class Process;
+class KProcess;
}
namespace Loader {
@@ -27,21 +27,23 @@ namespace Loader {
/// Loads an NRO file
class AppLoader_NRO final : public AppLoader {
public:
- explicit AppLoader_NRO(FileSys::VirtualFile file);
+ explicit AppLoader_NRO(FileSys::VirtualFile file_);
~AppLoader_NRO() override;
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is an NRO file.
+ *
+ * @param nro_file The file to identify.
+ *
+ * @return FileType::NRO, or FileType::Error if the file is not an NRO file.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
@@ -51,7 +53,7 @@ public:
bool IsRomFSUpdatable() const override;
private:
- bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file);
+ bool LoadNro(Kernel::KProcess& process, const FileSys::VfsFile& nro_file);
std::vector<u8> icon_data;
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 @@
#include "core/file_sys/patch_manager.h"
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/process.h"
#include "core/loader/nso.h"
#include "core/memory.h"
@@ -56,11 +56,11 @@ bool NSOHeader::IsSegmentCompressed(size_t segment_num) const {
return ((flags >> segment_num) & 1) != 0;
}
-AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
+AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file_) : AppLoader(std::move(file_)) {}
-FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
+FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) {
u32 magic = 0;
- if (file->ReadObject(&magic) != sizeof(magic)) {
+ if (in_file->ReadObject(&magic) != sizeof(magic)) {
return FileType::Error;
}
@@ -71,16 +71,16 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::NSO;
}
-std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::System& system,
- const FileSys::VfsFile& file, VAddr load_base,
+std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system,
+ const FileSys::VfsFile& nso_file, VAddr load_base,
bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm) {
- if (file.GetSize() < sizeof(NSOHeader)) {
+ if (nso_file.GetSize() < sizeof(NSOHeader)) {
return std::nullopt;
}
NSOHeader nso_header{};
- if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) {
+ if (sizeof(NSOHeader) != nso_file.ReadObject(&nso_header)) {
return std::nullopt;
}
@@ -92,8 +92,8 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
Kernel::CodeSet codeset;
Kernel::PhysicalMemory program_image;
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
- std::vector<u8> data =
- file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
+ std::vector<u8> data = nso_file.ReadBytes(nso_header.segments_compressed_size[i],
+ nso_header.segments[i].offset);
if (nso_header.IsSegmentCompressed(i)) {
data = DecompressSegment(data, nso_header.segments[i]);
}
@@ -136,7 +136,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
pi_header.insert(pi_header.begin() + sizeof(NSOHeader), program_image.data(),
program_image.data() + program_image.size());
- pi_header = pm->PatchNSO(pi_header, file.GetName());
+ pi_header = pm->PatchNSO(pi_header, nso_file.GetName());
std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
}
@@ -162,7 +162,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
return load_base + image_size;
}
-AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::System& system) {
+AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -183,8 +183,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::Sy
Core::Memory::DEFAULT_STACK_SIZE}};
}
-ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) {
- modules = this->modules;
+ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
+ out_modules = this->modules;
return ResultStatus::Success;
}
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;
}
namespace Kernel {
-class Process;
+class KProcess;
}
namespace Loader {
@@ -71,27 +71,29 @@ static_assert(sizeof(NSOArgumentHeader) == 0x20, "NSOArgumentHeader has incorrec
/// Loads an NSO file
class AppLoader_NSO final : public AppLoader {
public:
- explicit AppLoader_NSO(FileSys::VirtualFile file);
+ explicit AppLoader_NSO(FileSys::VirtualFile file_);
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is a form of NSO file.
+ *
+ * @param in_file The file to be identified.
+ *
+ * @return FileType::NSO if found, or FileType::Error if some other type of file.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& in_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- static std::optional<VAddr> LoadModule(Kernel::Process& process, Core::System& system,
- const FileSys::VfsFile& file, VAddr load_base,
+ static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system,
+ const FileSys::VfsFile& nso_file, VAddr load_base,
bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm = {});
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
- ResultStatus ReadNSOModules(Modules& modules) override;
+ ResultStatus ReadNSOModules(Modules& out_modules) override;
private:
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 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nca.h"
@@ -21,11 +21,11 @@
namespace Loader {
-AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
+AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
const Service::FileSystem::FileSystemController& fsc,
const FileSys::ContentProvider& content_provider,
std::size_t program_index)
- : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)),
+ : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)),
title_id(nsp->GetProgramTitleID()) {
if (nsp->GetStatus() != ResultStatus::Success) {
@@ -57,8 +57,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
AppLoader_NSP::~AppLoader_NSP() = default;
-FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
- FileSys::NSP nsp(file);
+FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) {
+ const FileSys::NSP nsp(nsp_file);
if (nsp.GetStatus() == ResultStatus::Success) {
// Extracted Type case
@@ -79,7 +79,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::System& system) {
+AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -121,67 +121,80 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process, Core::Sy
return result;
}
-ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) {
- return secondary_loader->ReadRomFS(file);
+ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& out_file) {
+ return secondary_loader->ReadRomFS(out_file);
}
u64 AppLoader_NSP::ReadRomFSIVFCOffset() const {
return secondary_loader->ReadRomFSIVFCOffset();
}
-ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& file) {
- if (nsp->IsExtractedType())
+ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
+ if (nsp->IsExtractedType()) {
return ResultStatus::ErrorNoPackedUpdate;
+ }
const auto read =
nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
- if (read == nullptr)
+ if (read == nullptr) {
return ResultStatus::ErrorNoPackedUpdate;
- const auto nca_test = std::make_shared<FileSys::NCA>(read);
+ }
- if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
+ const auto nca_test = std::make_shared<FileSys::NCA>(read);
+ if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS) {
return nca_test->GetStatus();
+ }
- file = read;
+ out_file = read;
return ResultStatus::Success;
}
ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
- if (title_id == 0)
+ if (title_id == 0) {
return ResultStatus::ErrorNotInitialized;
+ }
+
out_program_id = title_id;
return ResultStatus::Success;
}
ResultStatus AppLoader_NSP::ReadIcon(std::vector<u8>& buffer) {
- if (icon_file == nullptr)
+ if (icon_file == nullptr) {
return ResultStatus::ErrorNoControl;
+ }
+
buffer = icon_file->ReadAllBytes();
return ResultStatus::Success;
}
ResultStatus AppLoader_NSP::ReadTitle(std::string& title) {
- if (nacp_file == nullptr)
+ if (nacp_file == nullptr) {
return ResultStatus::ErrorNoControl;
+ }
+
title = nacp_file->GetApplicationName();
return ResultStatus::Success;
}
ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {
- if (nacp_file == nullptr)
+ if (nacp_file == nullptr) {
return ResultStatus::ErrorNoControl;
+ }
+
nacp = *nacp_file;
return ResultStatus::Success;
}
-ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) {
+ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& out_file) {
const auto nca =
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::HtmlDocument);
- if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)
+ if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr) {
return ResultStatus::ErrorNoRomFS;
- file = nca->GetRomFS();
- return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
+ }
+
+ out_file = nca->GetRomFS();
+ return out_file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
}
ResultStatus 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;
/// Loads an XCI file
class AppLoader_NSP final : public AppLoader {
public:
- explicit AppLoader_NSP(FileSys::VirtualFile file,
+ explicit AppLoader_NSP(FileSys::VirtualFile file_,
const Service::FileSystem::FileSystemController& fsc,
const FileSys::ContentProvider& content_provider,
std::size_t program_index);
~AppLoader_NSP() override;
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is an NSP file.
+ *
+ * @param nsp_file The file to identify.
+ *
+ * @return FileType::NSP, or FileType::Error if the file is not an NSP.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& nsp_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
- ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
+ ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
u64 ReadRomFSIVFCOffset() const override;
- ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
+ ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override;
ResultStatus ReadControlData(FileSys::NACP& nacp) override;
- ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
+ ResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) override;
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
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 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/submission_package.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/nca.h"
#include "core/loader/xci.h"
namespace Loader {
-AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
+AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_,
const Service::FileSystem::FileSystemController& fsc,
const FileSys::ContentProvider& content_provider,
std::size_t program_index)
- : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)),
+ : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_index)),
nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
if (xci->GetStatus() != ResultStatus::Success) {
return;
@@ -43,8 +43,8 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
AppLoader_XCI::~AppLoader_XCI() = default;
-FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
- FileSys::XCI xci(file);
+FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& xci_file) {
+ const FileSys::XCI xci(xci_file);
if (xci.GetStatus() == ResultStatus::Success &&
xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr &&
@@ -56,7 +56,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
return FileType::Error;
}
-AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::System& system) {
+AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::System& system) {
if (is_loaded) {
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
@@ -87,31 +87,33 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process, Core::Sy
return result;
}
-ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) {
- return nca_loader->ReadRomFS(file);
+ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& out_file) {
+ return nca_loader->ReadRomFS(out_file);
}
u64 AppLoader_XCI::ReadRomFSIVFCOffset() const {
return nca_loader->ReadRomFSIVFCOffset();
}
-ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& file) {
+ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
u64 program_id{};
nca_loader->ReadProgramId(program_id);
- if (program_id == 0)
+ if (program_id == 0) {
return ResultStatus::ErrorXCIMissingProgramNCA;
+ }
const auto read = xci->GetSecurePartitionNSP()->GetNCAFile(
FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program);
-
- if (read == nullptr)
+ if (read == nullptr) {
return ResultStatus::ErrorNoPackedUpdate;
- const auto nca_test = std::make_shared<FileSys::NCA>(read);
+ }
- if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
+ const auto nca_test = std::make_shared<FileSys::NCA>(read);
+ if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS) {
return nca_test->GetStatus();
+ }
- file = read;
+ out_file = read;
return ResultStatus::Success;
}
@@ -120,33 +122,41 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
}
ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
- if (icon_file == nullptr)
+ if (icon_file == nullptr) {
return ResultStatus::ErrorNoControl;
+ }
+
buffer = icon_file->ReadAllBytes();
return ResultStatus::Success;
}
ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
- if (nacp_file == nullptr)
+ if (nacp_file == nullptr) {
return ResultStatus::ErrorNoControl;
+ }
+
title = nacp_file->GetApplicationName();
return ResultStatus::Success;
}
ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
- if (nacp_file == nullptr)
+ if (nacp_file == nullptr) {
return ResultStatus::ErrorNoControl;
+ }
+
control = *nacp_file;
return ResultStatus::Success;
}
-ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {
+ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) {
const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
FileSys::ContentRecordType::HtmlDocument);
- if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)
+ if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) {
return ResultStatus::ErrorXCIMissingPartition;
- file = nca->GetRomFS();
- return file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
+ }
+
+ out_file = nca->GetRomFS();
+ return out_file == nullptr ? ResultStatus::ErrorNoRomFS : ResultStatus::Success;
}
ResultStatus 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;
/// Loads an XCI file
class AppLoader_XCI final : public AppLoader {
public:
- explicit AppLoader_XCI(FileSys::VirtualFile file,
+ explicit AppLoader_XCI(FileSys::VirtualFile file_,
const Service::FileSystem::FileSystemController& fsc,
const FileSys::ContentProvider& content_provider,
std::size_t program_index);
~AppLoader_XCI() override;
/**
- * Returns the type of the file
- * @param file open file
- * @return FileType found, or FileType::Error if this loader doesn't know it
+ * Identifies whether or not the given file is an XCI file.
+ *
+ * @param xci_file The file to identify.
+ *
+ * @return FileType::XCI, or FileType::Error if the file is not an XCI file.
*/
- static FileType IdentifyType(const FileSys::VirtualFile& file);
+ static FileType IdentifyType(const FileSys::VirtualFile& xci_file);
FileType GetFileType() const override {
return IdentifyType(file);
}
- LoadResult Load(Kernel::Process& process, Core::System& system) override;
+ LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
- ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
+ ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
u64 ReadRomFSIVFCOffset() const override;
- ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
+ ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override;
ResultStatus ReadControlData(FileSys::NACP& control) override;
- ResultStatus ReadManualRomFS(FileSys::VirtualFile& file) override;
+ ResultStatus ReadManualRomFS(FileSys::VirtualFile& out_file) override;
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
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 @@
#include "core/core.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/physical_memory.h"
-#include "core/hle/kernel/process.h"
#include "core/memory.h"
#include "video_core/gpu.h"
@@ -30,7 +30,7 @@ namespace Core::Memory {
struct Memory::Impl {
explicit Impl(Core::System& system_) : system{system_} {}
- void SetCurrentPageTable(Kernel::Process& process, u32 core_id) {
+ void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
current_page_table = &process.PageTable().PageTableImpl();
const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth();
@@ -50,7 +50,7 @@ struct Memory::Impl {
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped);
}
- bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
+ bool IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const {
const auto& page_table = process.PageTable().PageTableImpl();
const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType();
return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory;
@@ -82,6 +82,22 @@ struct Memory::Impl {
return nullptr;
}
+ u8* GetKernelBuffer(VAddr start_vaddr, size_t size) {
+ // TODO(bunnei): This is just a workaround until we have kernel memory layout mapped &
+ // managed. Until then, we use this to allocate and access kernel memory regions.
+
+ auto search = kernel_memory_regions.find(start_vaddr);
+ if (search != kernel_memory_regions.end()) {
+ return search->second.get();
+ }
+
+ std::unique_ptr<u8[]> new_memory_region{new u8[size]};
+ u8* raw_ptr = new_memory_region.get();
+ kernel_memory_regions[start_vaddr] = std::move(new_memory_region);
+
+ return raw_ptr;
+ }
+
u8 Read8(const VAddr addr) {
return Read<u8>(addr);
}
@@ -178,7 +194,7 @@ struct Memory::Impl {
return string;
}
- void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
+ void ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
const std::size_t size) {
const auto& page_table = process.PageTable().PageTableImpl();
@@ -223,7 +239,7 @@ struct Memory::Impl {
}
}
- void ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
+ void ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
const std::size_t size) {
const auto& page_table = process.PageTable().PageTableImpl();
@@ -275,7 +291,7 @@ struct Memory::Impl {
ReadBlockUnsafe(*system.CurrentProcess(), src_addr, dest_buffer, size);
}
- void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
+ void WriteBlock(const Kernel::KProcess& process, const VAddr dest_addr, const void* src_buffer,
const std::size_t size) {
const auto& page_table = process.PageTable().PageTableImpl();
std::size_t remaining_size = size;
@@ -318,7 +334,7 @@ struct Memory::Impl {
}
}
- void WriteBlockUnsafe(const Kernel::Process& process, const VAddr dest_addr,
+ void WriteBlockUnsafe(const Kernel::KProcess& process, const VAddr dest_addr,
const void* src_buffer, const std::size_t size) {
const auto& page_table = process.PageTable().PageTableImpl();
std::size_t remaining_size = size;
@@ -368,7 +384,7 @@ struct Memory::Impl {
WriteBlockUnsafe(*system.CurrentProcess(), dest_addr, src_buffer, size);
}
- void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
+ void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) {
const auto& page_table = process.PageTable().PageTableImpl();
std::size_t remaining_size = size;
std::size_t page_index = dest_addr >> PAGE_BITS;
@@ -413,7 +429,7 @@ struct Memory::Impl {
ZeroBlock(*system.CurrentProcess(), dest_addr, size);
}
- void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+ void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
const std::size_t size) {
const auto& page_table = process.PageTable().PageTableImpl();
std::size_t remaining_size = size;
@@ -711,13 +727,21 @@ struct Memory::Impl {
}
Common::PageTable* current_page_table = nullptr;
+ std::unordered_map<VAddr, std::unique_ptr<u8[]>> kernel_memory_regions;
Core::System& system;
};
-Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
+Memory::Memory(Core::System& system_) : system{system_} {
+ Reset();
+}
+
Memory::~Memory() = default;
-void Memory::SetCurrentPageTable(Kernel::Process& process, u32 core_id) {
+void Memory::Reset() {
+ impl = std::make_unique<Impl>(system);
+}
+
+void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
impl->SetCurrentPageTable(process, core_id);
}
@@ -729,7 +753,7 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
impl->UnmapRegion(page_table, base, size);
}
-bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
+bool Memory::IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const {
return impl->IsValidVirtualAddress(process, vaddr);
}
@@ -741,6 +765,10 @@ u8* Memory::GetPointer(VAddr vaddr) {
return impl->GetPointer(vaddr);
}
+u8* Memory::GetKernelBuffer(VAddr start_vaddr, size_t size) {
+ return impl->GetKernelBuffer(start_vaddr, size);
+}
+
const u8* Memory::GetPointer(VAddr vaddr) const {
return impl->GetPointer(vaddr);
}
@@ -801,7 +829,7 @@ std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
return impl->ReadCString(vaddr, max_length);
}
-void Memory::ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
+void Memory::ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
const std::size_t size) {
impl->ReadBlock(process, src_addr, dest_buffer, size);
}
@@ -810,7 +838,7 @@ void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_
impl->ReadBlock(src_addr, dest_buffer, size);
}
-void Memory::ReadBlockUnsafe(const Kernel::Process& process, const VAddr src_addr,
+void Memory::ReadBlockUnsafe(const Kernel::KProcess& process, const VAddr src_addr,
void* dest_buffer, const std::size_t size) {
impl->ReadBlockUnsafe(process, src_addr, dest_buffer, size);
}
@@ -819,7 +847,7 @@ void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std:
impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
}
-void Memory::WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+void Memory::WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
std::size_t size) {
impl->WriteBlock(process, dest_addr, src_buffer, size);
}
@@ -828,7 +856,7 @@ void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std
impl->WriteBlock(dest_addr, src_buffer, size);
}
-void Memory::WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr,
+void Memory::WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr,
const void* src_buffer, std::size_t size) {
impl->WriteBlockUnsafe(process, dest_addr, src_buffer, size);
}
@@ -838,7 +866,7 @@ void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer,
impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
}
-void Memory::ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size) {
+void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
impl->ZeroBlock(process, dest_addr, size);
}
@@ -846,7 +874,7 @@ void Memory::ZeroBlock(VAddr dest_addr, std::size_t size) {
impl->ZeroBlock(dest_addr, size);
}
-void Memory::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+void Memory::CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
const std::size_t size) {
impl->CopyBlock(process, dest_addr, src_addr, size);
}
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;
namespace Kernel {
class PhysicalMemory;
-class Process;
+class KProcess;
} // namespace Kernel
namespace Core::Memory {
@@ -59,11 +59,16 @@ public:
Memory& operator=(Memory&&) = default;
/**
+ * Resets the state of the Memory system.
+ */
+ void Reset();
+
+ /**
* Changes the currently active page table to that of the given process instance.
*
* @param process The process to use the page table of.
*/
- void SetCurrentPageTable(Kernel::Process& process, u32 core_id);
+ void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id);
/**
* Maps an allocated buffer onto a region of the emulated process address space.
@@ -94,7 +99,7 @@ public:
*
* @returns True if the given virtual address is valid, false otherwise.
*/
- bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr) const;
+ bool IsValidVirtualAddress(const Kernel::KProcess& process, VAddr vaddr) const;
/**
* Checks whether or not the supplied address is a valid virtual
@@ -116,6 +121,15 @@ public:
*/
u8* GetPointer(VAddr vaddr);
+ /**
+ * Gets a pointer to the start of a kernel heap allocated memory region. Will allocate one if it
+ * does not already exist.
+ *
+ * @param start_vaddr Start virtual address for the memory region.
+ * @param size Size of the memory region.
+ */
+ u8* GetKernelBuffer(VAddr start_vaddr, size_t size);
+
template <typename T>
T* GetPointer(VAddr vaddr) {
return reinterpret_cast<T*>(GetPointer(vaddr));
@@ -319,7 +333,7 @@ public:
* @post The range [dest_buffer, size) contains the read bytes from the
* process' address space.
*/
- void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
+ void ReadBlock(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer,
std::size_t size);
/**
@@ -340,7 +354,7 @@ public:
* @post The range [dest_buffer, size) contains the read bytes from the
* process' address space.
*/
- void ReadBlockUnsafe(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
+ void ReadBlockUnsafe(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer,
std::size_t size);
/**
@@ -400,7 +414,7 @@ public:
* and will mark that region as invalidated to caches that the active
* graphics backend may be maintaining over the course of execution.
*/
- void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ void WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
std::size_t size);
/**
@@ -420,7 +434,7 @@ public:
* will be ignored and an error will be logged.
*
*/
- void WriteBlockUnsafe(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
+ void WriteBlockUnsafe(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
std::size_t size);
/**
@@ -472,7 +486,7 @@ public:
* @post The range [dest_addr, size) within the process' address space is
* filled with zeroes.
*/
- void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
+ void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
/**
* Fills the specified address range within the current process' address space with zeroes.
@@ -497,7 +511,7 @@ public:
* @post The range [dest_addr, size) within the process' address space contains the
* same data within the range [src_addr, size).
*/
- void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
+ void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
std::size_t size);
/**
@@ -524,6 +538,8 @@ public:
void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
private:
+ Core::System& system;
+
struct Impl;
std::unique_ptr<Impl> impl;
};
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 @@
#include "core/core_timing_util.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
#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
}
} // Anonymous namespace
-StandardVmCallbacks::StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata)
- : metadata(metadata), system(system) {}
+StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_)
+ : metadata{metadata_}, system{system_} {}
StandardVmCallbacks::~StandardVmCallbacks() = default;
@@ -174,11 +174,11 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
return out;
}
-CheatEngine::CheatEngine(Core::System& system, std::vector<CheatEntry> cheats,
- const std::array<u8, 0x20>& build_id)
- : vm{std::make_unique<StandardVmCallbacks>(system, metadata)},
- cheats(std::move(cheats)), core_timing{system.CoreTiming()}, system{system} {
- metadata.main_nso_build_id = build_id;
+CheatEngine::CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
+ const std::array<u8, 0x20>& build_id_)
+ : vm{std::make_unique<StandardVmCallbacks>(system_, metadata)},
+ cheats(std::move(cheats_)), core_timing{system_.CoreTiming()}, system{system_} {
+ metadata.main_nso_build_id = build_id_;
}
CheatEngine::~CheatEngine() {
@@ -222,8 +222,8 @@ void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_regi
};
}
-void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
- this->cheats = std::move(cheats);
+void CheatEngine::Reload(std::vector<CheatEntry> reload_cheats) {
+ cheats = std::move(reload_cheats);
is_pending_reload.exchange(true);
}
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 {
class StandardVmCallbacks : public DmntCheatVm::Callbacks {
public:
- StandardVmCallbacks(Core::System& system, const CheatProcessMetadata& metadata);
+ StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
~StandardVmCallbacks() override;
void MemoryRead(VAddr address, void* data, u64 size) override;
@@ -38,7 +38,7 @@ private:
VAddr SanitizeAddress(VAddr address) const;
const CheatProcessMetadata& metadata;
- Core::System& system;
+ System& system;
};
// Intermediary class that parses a text file or other disk format for storing cheats into a
@@ -61,14 +61,14 @@ public:
// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
class CheatEngine final {
public:
- CheatEngine(Core::System& system_, std::vector<CheatEntry> cheats_,
- const std::array<u8, 0x20>& build_id);
+ CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
+ const std::array<u8, 0x20>& build_id_);
~CheatEngine();
void Initialize();
void SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size);
- void Reload(std::vector<CheatEntry> cheats);
+ void Reload(std::vector<CheatEntry> reload_cheats);
private:
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 @@
namespace Core::Memory {
-DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {}
+DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks_)
+ : callbacks(std::move(callbacks_)) {}
DmntCheatVm::~DmntCheatVm() = default;
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:
static constexpr std::size_t NumStaticRegisters =
NumReadableStaticRegisters + NumWritableStaticRegisters;
- explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks);
+ explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks_);
~DmntCheatVm();
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;
namespace Core {
-PerfStats::PerfStats(u64 title_id) : title_id(title_id) {}
+PerfStats::PerfStats(u64 title_id_) : title_id(title_id_) {}
PerfStats::~PerfStats() {
if (!Settings::values.record_frame_times || title_id == 0) {
@@ -69,9 +69,7 @@ void PerfStats::EndSystemFrame() {
}
void PerfStats::EndGameFrame() {
- std::lock_guard lock{object_mutex};
-
- game_frames += 1;
+ game_frames.fetch_add(1, std::memory_order_relaxed);
}
double PerfStats::GetMeanFrametime() const {
@@ -94,10 +92,11 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
const auto interval = duration_cast<DoubleSecs>(now - reset_point).count();
const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval;
-
+ const auto current_frames = static_cast<double>(game_frames.load(std::memory_order_relaxed));
+ const auto current_fps = current_frames / interval;
const PerfStatsResults results{
.system_fps = static_cast<double>(system_frames) / interval,
- .game_fps = static_cast<double>(game_frames) / interval,
+ .average_game_fps = (current_fps + previous_fps) / 2.0,
.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() /
static_cast<double>(system_frames),
.emulation_speed = system_us_per_second.count() / 1'000'000.0,
@@ -108,7 +107,8 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
reset_point_system_us = current_system_time_us;
accumulated_frametime = Clock::duration::zero();
system_frames = 0;
- game_frames = 0;
+ game_frames.store(0, std::memory_order_relaxed);
+ previous_fps = current_fps;
return results;
}
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 @@
#pragma once
#include <array>
+#include <atomic>
#include <chrono>
#include <cstddef>
#include <mutex>
@@ -15,8 +16,8 @@ namespace Core {
struct PerfStatsResults {
/// System FPS (LCD VBlanks) in Hz
double system_fps;
- /// Game FPS (GSP frame submissions) in Hz
- double game_fps;
+ /// Average game FPS (GPU frame renders) in Hz
+ double average_game_fps;
/// Walltime per system frame, in seconds, excluding any waits
double frametime;
/// Ratio of walltime / emulated time elapsed
@@ -29,7 +30,7 @@ struct PerfStatsResults {
*/
class PerfStats {
public:
- explicit PerfStats(u64 title_id);
+ explicit PerfStats(u64 title_id_);
~PerfStats();
using Clock = std::chrono::high_resolution_clock;
@@ -72,7 +73,7 @@ private:
/// Cumulative number of system frames (LCD VBlanks) presented since last reset
u32 system_frames = 0;
/// Cumulative number of game frames (GSP frame submissions) since last reset
- u32 game_frames = 0;
+ std::atomic<u32> game_frames = 0;
/// Point when the previous system frame ended
Clock::time_point previous_frame_end = reset_point;
@@ -80,6 +81,8 @@ private:
Clock::time_point frame_begin = reset_point;
/// Total visible duration (including frame-limiting, etc.) of the previous system frame
Clock::duration previous_frame_length = Clock::duration::zero();
+ /// Previously computed fps
+ double previous_fps = 0;
};
class 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 @@
#include "core/core.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/reporter.h"
@@ -192,7 +192,7 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Core::Memory::Memo
namespace Core {
-Reporter::Reporter(System& system) : system(system) {}
+Reporter::Reporter(System& system_) : system(system_) {}
Reporter::~Reporter() = default;
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;
class Reporter {
public:
- explicit Reporter(System& system);
+ explicit Reporter(System& system_);
~Reporter();
// 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() {
core_timing.UnscheduleEvent(event, 0);
}
-void Freezer::SetActive(bool active) {
- if (!this->active.exchange(active)) {
+void Freezer::SetActive(bool is_active) {
+ if (!active.exchange(is_active)) {
FillEntryReads();
core_timing.ScheduleEvent(memory_freezer_ns, event);
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:
~Freezer();
// Enables or disables the entire memory freezer.
- void SetActive(bool active);
+ void SetActive(bool is_active);
// Returns whether or not the freezer is active.
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
for (const PadAxes axis : axes) {
const auto index = static_cast<std::size_t>(axis);
const u8 axis_value = adapter_payload[offset + 3 + index];
- if (pads[port].axis_origin[index] == 255) {
+ if (pads[port].reset_origin_counter <= 18) {
+ if (pads[port].axis_origin[index] != axis_value) {
+ pads[port].reset_origin_counter = 0;
+ }
pads[port].axis_origin[index] = axis_value;
+ pads[port].reset_origin_counter++;
}
pads[port].axis_values[index] =
static_cast<s16>(axis_value - pads[port].axis_origin[index]);
@@ -375,7 +379,7 @@ void Adapter::ResetDevice(std::size_t port) {
pads[port].buttons = 0;
pads[port].last_button = PadButton::Undefined;
pads[port].axis_values.fill(0);
- pads[port].axis_origin.fill(255);
+ pads[port].reset_origin_counter = 0;
}
void 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 {
PadButton last_button{};
std::array<s16, 6> axis_values{};
std::array<u8, 6> axis_origin{};
+ u8 reset_origin_counter{};
};
class 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 {
// TODO return the correct motion device
return {};
}
+#ifdef HAVE_SDL2
+ if (params.Get("class", "") == "sdl") {
+ return sdl->GetMotionMappingForDevice(params);
+ }
+#endif
return {};
}
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 {
const Common::Vec3f accelerometer = GetAcceleration();
const Common::Vec3f rotation = GetRotations();
const std::array<Common::Vec3f, 3> orientation = GetOrientation();
- return {accelerometer, gyroscope, rotation, orientation};
+ const Common::Quaternion<f32> quaternion = GetQuaternion();
+ return {accelerometer, gyroscope, rotation, orientation, quaternion};
}
Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_magnitude) const {
@@ -218,7 +219,12 @@ Input::MotionStatus MotionInput::GetRandomMotion(int accel_magnitude, int gyro_m
Common::Vec3f{0.0f, 1.0f, 0.0f},
Common::Vec3f{0.0f, 0.0f, 1.0f},
};
- return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation};
+ constexpr Common::Quaternion<f32> quaternion{
+ {0.0f, 0.0f, 0.0f},
+ 1.0f,
+ };
+ return {accelerometer * accel_magnitude, gyroscope * gyro_magnitude, rotation, orientation,
+ quaternion};
}
void 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_) {
mouse_info[button_index].data.axis = {0, 0};
}
+void Mouse::ReleaseAllButtons() {
+ buttons = 0;
+ for (auto& info : mouse_info) {
+ info.tilt_speed = 0;
+ info.data.pressed = false;
+ info.data.axis = {0, 0};
+ }
+}
+
void Mouse::BeginConfiguration() {
buttons = 0;
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:
void MouseMove(int x, int y, int center_x, int center_y);
/**
- * Signals that a motion sensor tilt has ended.
+ * Signals that a button is released.
+ * @param button_ the button pressed
*/
void ReleaseButton(MouseButton button_);
+ /**
+ * Signals that all buttons are released
+ */
+ void ReleaseAllButtons();
+
[[nodiscard]] bool ToggleButton(std::size_t button_);
[[nodiscard]] bool UnlockButton(std::size_t button_);
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:
virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
return {};
}
+ virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) {
+ return {};
+ }
};
class 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 @@
#endif
#include "common/logging/log.h"
+#include "common/math_util.h"
#include "common/param_package.h"
#include "common/settings_input.h"
#include "common/threadsafe_queue.h"
@@ -68,13 +69,57 @@ public:
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
SDL_GameController* game_controller)
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
- sdl_controller{game_controller, &SDL_GameControllerClose} {}
+ sdl_controller{game_controller, &SDL_GameControllerClose} {
+ EnableMotion();
+ }
+
+ void EnableMotion() {
+ if (sdl_controller) {
+ SDL_GameController* controller = sdl_controller.get();
+ if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) {
+ SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE);
+ has_accel = true;
+ }
+ if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) {
+ SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE);
+ has_gyro = true;
+ }
+ }
+ }
void SetButton(int button, bool value) {
std::lock_guard lock{mutex};
state.buttons.insert_or_assign(button, value);
}
+ void SetMotion(SDL_ControllerSensorEvent event) {
+ constexpr float gravity_constant = 9.80665f;
+ std::lock_guard lock{mutex};
+ u64 time_difference = event.timestamp - last_motion_update;
+ last_motion_update = event.timestamp;
+ switch (event.sensor) {
+ case SDL_SENSOR_ACCEL: {
+ const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]};
+ motion.SetAcceleration(acceleration / gravity_constant);
+ break;
+ }
+ case SDL_SENSOR_GYRO: {
+ const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]};
+ motion.SetGyroscope(gyroscope / (Common::PI * 2));
+ break;
+ }
+ }
+
+ // Ignore duplicated timestamps
+ if (time_difference == 0) {
+ return;
+ }
+
+ motion.SetGyroThreshold(0.0001f);
+ motion.UpdateRotation(time_difference * 1000);
+ motion.UpdateOrientation(time_difference * 1000);
+ }
+
bool GetButton(int button) const {
std::lock_guard lock{mutex};
return state.buttons.at(button);
@@ -121,6 +166,14 @@ public:
return std::make_tuple(x, y);
}
+ bool HasGyro() const {
+ return has_gyro;
+ }
+
+ bool HasAccel() const {
+ return has_accel;
+ }
+
const MotionInput& GetMotion() const {
return motion;
}
@@ -173,8 +226,11 @@ private:
std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
mutable std::mutex mutex;
- // Motion is initialized without PID values as motion input is not aviable for SDL2
- MotionInput motion{0.0f, 0.0f, 0.0f};
+ // Motion is initialized with the PID values
+ MotionInput motion{0.3f, 0.005f, 0.0f};
+ u64 last_motion_update{};
+ bool has_gyro{false};
+ bool has_accel{false};
};
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
@@ -296,6 +352,12 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
}
break;
}
+ case SDL_CONTROLLERSENSORUPDATE: {
+ if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) {
+ joystick->SetMotion(event.csensor);
+ }
+ break;
+ }
case SDL_JOYDEVICEREMOVED:
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
@@ -449,6 +511,18 @@ private:
std::shared_ptr<SDLJoystick> joystick;
};
+class SDLMotion final : public Input::MotionDevice {
+public:
+ explicit SDLMotion(std::shared_ptr<SDLJoystick> joystick_) : joystick(std::move(joystick_)) {}
+
+ Input::MotionStatus GetStatus() const override {
+ return joystick->GetMotion().GetMotion();
+ }
+
+private:
+ std::shared_ptr<SDLJoystick> joystick;
+};
+
class SDLDirectionMotion final : public Input::MotionDevice {
public:
explicit SDLDirectionMotion(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_)
@@ -658,6 +732,10 @@ public:
auto joystick = state.GetSDLJoystickByGUID(guid, port);
+ if (params.Has("motion")) {
+ return std::make_unique<SDLMotion>(joystick);
+ }
+
if (params.Has("hat")) {
const int hat = params.Get("hat", 0);
const std::string direction_name = params.Get("direction", "");
@@ -717,6 +795,17 @@ SDLState::SDLState() {
RegisterFactory<VibrationDevice>("sdl", vibration_factory);
RegisterFactory<MotionDevice>("sdl", motion_factory);
+ // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
+ SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
+
+ // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a
+ // GameController and not a generic one
+ SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1");
+
+ // Turn off Pro controller home led
+ SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0");
+
// If the frontend is going to manage the event loop, then we don't start one here
start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0;
if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) {
@@ -853,6 +942,13 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s
return params;
}
+Common::ParamPackage BuildMotionParam(int port, std::string guid) {
+ Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}});
+ params.Set("port", port);
+ params.Set("guid", std::move(guid));
+ return params;
+}
+
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
switch (event.type) {
case SDL_JOYAXISMOTION: {
@@ -907,6 +1003,35 @@ Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Eve
}
break;
}
+ case SDL_CONTROLLERSENSORUPDATE: {
+ bool is_motion_shaking = false;
+ constexpr float gyro_threshold = 5.0f;
+ constexpr float accel_threshold = 11.0f;
+ if (event.csensor.sensor == SDL_SENSOR_ACCEL) {
+ const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2],
+ -event.csensor.data[1]};
+ if (acceleration.Length() > accel_threshold) {
+ is_motion_shaking = true;
+ }
+ }
+
+ if (event.csensor.sensor == SDL_SENSOR_GYRO) {
+ const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2],
+ event.csensor.data[1]};
+ if (gyroscope.Length() > gyro_threshold) {
+ is_motion_shaking = true;
+ }
+ }
+
+ if (!is_motion_shaking) {
+ break;
+ }
+
+ if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) {
+ return BuildMotionParam(joystick->GetPort(), joystick->GetGUID());
+ }
+ break;
+ }
}
return {};
}
@@ -1036,6 +1161,27 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
return mapping;
}
+MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) {
+ if (!params.Has("guid") || !params.Has("port")) {
+ return {};
+ }
+ const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
+ auto* controller = joystick->GetSDLGameController();
+ if (controller == nullptr) {
+ return {};
+ }
+
+ joystick->EnableMotion();
+
+ if (!joystick->HasGyro() && !joystick->HasAccel()) {
+ return {};
+ }
+
+ MotionMapping mapping = {};
+ mapping.insert_or_assign(Settings::NativeMotion::MotionLeft,
+ BuildMotionParam(joystick->GetPort(), joystick->GetGUID()));
+ return mapping;
+}
namespace Polling {
class SDLPoller : public InputCommon::Polling::DevicePoller {
public:
@@ -1149,6 +1295,7 @@ public:
[[fallthrough]];
case SDL_JOYBUTTONUP:
case SDL_JOYHATMOTION:
+ case SDL_CONTROLLERSENSORUPDATE:
return {SDLEventToMotionParamPackage(state, event)};
}
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:
ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
+ MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
private:
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:
case Type::PadData: {
Response::PadData pad_data;
std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData));
+ SanitizeMotion(pad_data);
callback.pad_data(std::move(pad_data));
break;
}
@@ -114,6 +115,28 @@ private:
StartSend(timer.expiry());
}
+ void SanitizeMotion(Response::PadData& data) {
+ // Zero out any non number value
+ if (!std::isnormal(data.gyro.pitch)) {
+ data.gyro.pitch = 0;
+ }
+ if (!std::isnormal(data.gyro.roll)) {
+ data.gyro.roll = 0;
+ }
+ if (!std::isnormal(data.gyro.yaw)) {
+ data.gyro.yaw = 0;
+ }
+ if (!std::isnormal(data.accel.x)) {
+ data.accel.x = 0;
+ }
+ if (!std::isnormal(data.accel.y)) {
+ data.accel.y = 0;
+ }
+ if (!std::isnormal(data.accel.z)) {
+ data.accel.z = 0;
+ }
+ }
+
SocketCallback callback;
boost::asio::io_service io_service;
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
const VAddr cpu_addr = binding.cpu_addr;
const u32 size = binding.size;
Buffer& buffer = slot_buffers[binding.buffer_id];
- if (size <= uniform_buffer_skip_cache_size && !buffer.IsRegionGpuModified(cpu_addr, size)) {
+ const bool use_fast_buffer = binding.buffer_id != NULL_BUFFER_ID &&
+ size <= uniform_buffer_skip_cache_size &&
+ !buffer.IsRegionGpuModified(cpu_addr, size);
+ if (use_fast_buffer) {
if constexpr (IS_OPENGL) {
if (runtime.HasFastBufferSubData()) {
// 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 @@
#include "core/frontend/emu_window.h"
#include "core/hardware_interrupt_manager.h"
#include "core/memory.h"
+#include "core/perf_stats.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/kepler_compute.h"
#include "video_core/engines/kepler_memory.h"
@@ -191,6 +192,10 @@ u64 GPU::GetTicks() const {
return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
}
+void GPU::RendererFrameEndNotify() {
+ system.GetPerfStats().EndGameFrame();
+}
+
void GPU::FlushCommands() {
rasterizer->FlushCommands();
}
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:
return use_nvdec;
}
+ void RendererFrameEndNotify();
+
enum class FenceOperation : u32 {
Acquire = 0,
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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/memory.h"
#include "video_core/gpu.h"
#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 @@
#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/core.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/memory.h"
#include "video_core/engines/kepler_compute.h"
#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 @@
#include "common/settings.h"
#include "common/zstd_compression.h"
#include "core/core.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "video_core/engines/shader_type.h"
#include "video_core/renderer_opengl/gl_shader_cache.h"
#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,
}
void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+ const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) {
state_tracker.NotifyScissor0();
@@ -560,9 +559,9 @@ void TextureCacheRuntime::BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
const GLbitfield buffer_bits = dst->BufferBits();
const bool has_depth = (buffer_bits & ~GL_COLOR_BUFFER_BIT) != 0;
const bool is_linear = !has_depth && filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
- glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region[0].x, src_region[0].y,
- src_region[1].x, src_region[1].y, dst_region[0].x, dst_region[0].y,
- dst_region[1].x, dst_region[1].y, buffer_bits,
+ glBlitNamedFramebuffer(src->Handle(), dst->Handle(), src_region.start.x, src_region.start.y,
+ src_region.end.x, src_region.end.y, dst_region.start.x,
+ dst_region.start.y, dst_region.end.x, dst_region.end.y, buffer_bits,
is_linear ? GL_LINEAR : GL_NEAREST);
}
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;
using VideoCommon::ImageViewId;
using VideoCommon::ImageViewType;
using VideoCommon::NUM_RT;
-using VideoCommon::Offset2D;
+using VideoCommon::Region2D;
using VideoCommon::RenderTargets;
struct ImageBufferMap {
@@ -73,10 +73,8 @@ public:
void EmulateCopyImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
- void BlitFramebuffer(Framebuffer* dst, Framebuffer* src,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
- Tegra::Engines::Fermi2D::Filter filter,
+ void BlitFramebuffer(Framebuffer* dst, Framebuffer* src, const Region2D& dst_region,
+ const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation);
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) {
++m_current_frame;
+ gpu.RendererFrameEndNotify();
rasterizer.TickFrame();
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
device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
}
-void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region) {
+void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Region2D& dst_region,
+ const Region2D& src_region) {
const VkOffset2D offset{
- .x = std::min(dst_region[0].x, dst_region[1].x),
- .y = std::min(dst_region[0].y, dst_region[1].y),
+ .x = std::min(dst_region.start.x, dst_region.end.x),
+ .y = std::min(dst_region.start.y, dst_region.end.y),
};
const VkExtent2D extent{
- .width = static_cast<u32>(std::abs(dst_region[1].x - dst_region[0].x)),
- .height = static_cast<u32>(std::abs(dst_region[1].y - dst_region[0].y)),
+ .width = static_cast<u32>(std::abs(dst_region.end.x - dst_region.start.x)),
+ .height = static_cast<u32>(std::abs(dst_region.end.y - dst_region.start.y)),
};
const VkViewport viewport{
.x = static_cast<float>(offset.x),
@@ -313,11 +312,12 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
.offset = offset,
.extent = extent,
};
- const float scale_x = static_cast<float>(src_region[1].x - src_region[0].x);
- const float scale_y = static_cast<float>(src_region[1].y - src_region[0].y);
+ const float scale_x = static_cast<float>(src_region.end.x - src_region.start.x);
+ const float scale_y = static_cast<float>(src_region.end.y - src_region.start.y);
const PushConstants push_constants{
.tex_scale = {scale_x, scale_y},
- .tex_offset = {static_cast<float>(src_region[0].x), static_cast<float>(src_region[0].y)},
+ .tex_offset = {static_cast<float>(src_region.start.x),
+ static_cast<float>(src_region.start.y)},
};
cmdbuf.SetViewport(0, viewport);
cmdbuf.SetScissor(0, scissor);
@@ -353,8 +353,7 @@ BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
BlitImageHelper::~BlitImageHelper() = default;
void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+ const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) {
const bool is_linear = filter == Tegra::Engines::Fermi2D::Filter::Bilinear;
@@ -383,8 +382,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
VkImageView src_depth_view, VkImageView src_stencil_view,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+ const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) {
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 @@
namespace Vulkan {
-using VideoCommon::Offset2D;
+using VideoCommon::Region2D;
class Device;
class Framebuffer;
@@ -35,15 +35,13 @@ public:
~BlitImageHelper();
void BlitColor(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+ const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation);
void BlitDepthStencil(const Framebuffer* dst_framebuffer, VkImageView src_depth_view,
- VkImageView src_stencil_view, const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
- Tegra::Engines::Fermi2D::Filter filter,
+ VkImageView src_stencil_view, const Region2D& dst_region,
+ const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation);
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) {
if (swapchain.Present(render_semaphore)) {
blit_screen.Recreate();
}
+ gpu.RendererFrameEndNotify();
rasterizer.TickFrame();
}
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
write_barrier);
}
-[[nodiscard]] VkImageBlit MakeImageBlit(const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+[[nodiscard]] VkImageBlit MakeImageBlit(const Region2D& dst_region, const Region2D& src_region,
const VkImageSubresourceLayers& dst_layers,
const VkImageSubresourceLayers& src_layers) {
return VkImageBlit{
@@ -499,13 +498,13 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
.srcOffsets =
{
{
- .x = src_region[0].x,
- .y = src_region[0].y,
+ .x = src_region.start.x,
+ .y = src_region.start.y,
.z = 0,
},
{
- .x = src_region[1].x,
- .y = src_region[1].y,
+ .x = src_region.end.x,
+ .y = src_region.end.y,
.z = 1,
},
},
@@ -513,42 +512,42 @@ void CopyBufferToImage(vk::CommandBuffer cmdbuf, VkBuffer src_buffer, VkImage im
.dstOffsets =
{
{
- .x = dst_region[0].x,
- .y = dst_region[0].y,
+ .x = dst_region.start.x,
+ .y = dst_region.start.y,
.z = 0,
},
{
- .x = dst_region[1].x,
- .y = dst_region[1].y,
+ .x = dst_region.end.x,
+ .y = dst_region.end.y,
.z = 1,
},
},
};
}
-[[nodiscard]] VkImageResolve MakeImageResolve(const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+[[nodiscard]] VkImageResolve MakeImageResolve(const Region2D& dst_region,
+ const Region2D& src_region,
const VkImageSubresourceLayers& dst_layers,
const VkImageSubresourceLayers& src_layers) {
return VkImageResolve{
.srcSubresource = src_layers,
.srcOffset =
{
- .x = src_region[0].x,
- .y = src_region[0].y,
+ .x = src_region.start.x,
+ .y = src_region.start.y,
.z = 0,
},
.dstSubresource = dst_layers,
.dstOffset =
{
- .x = dst_region[0].x,
- .y = dst_region[0].y,
+ .x = dst_region.start.x,
+ .y = dst_region.start.y,
.z = 0,
},
.extent =
{
- .width = static_cast<u32>(dst_region[1].x - dst_region[0].x),
- .height = static_cast<u32>(dst_region[1].y - dst_region[0].y),
+ .width = static_cast<u32>(dst_region.end.x - dst_region.start.x),
+ .height = static_cast<u32>(dst_region.end.y - dst_region.start.y),
.depth = 1,
},
};
@@ -602,8 +601,7 @@ StagingBufferRef TextureCacheRuntime::DownloadStagingBuffer(size_t size) {
}
void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+ const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) {
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 {
using VideoCommon::ImageId;
using VideoCommon::NUM_RT;
-using VideoCommon::Offset2D;
+using VideoCommon::Region2D;
using VideoCommon::RenderTargets;
using VideoCore::Surface::PixelFormat;
@@ -71,8 +71,7 @@ struct TextureCacheRuntime {
[[nodiscard]] StagingBufferRef DownloadStagingBuffer(size_t size);
void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src,
- const std::array<Offset2D, 2>& dst_region,
- const std::array<Offset2D, 2>& src_region,
+ const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation);
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:
/// Blit an image with the given parameters
void BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const Tegra::Engines::Fermi2D::Surface& src,
- const Tegra::Engines::Fermi2D::Config& copy);
+ const Tegra::Engines::Fermi2D::Config& copy,
+ std::optional<Region2D> src_region_override = {},
+ std::optional<Region2D> dst_region_override = {});
/// Invalidate the contents of the color buffer index
/// These contents become unspecified, the cache can assume aggressive optimizations.
@@ -615,7 +617,9 @@ void TextureCache<P>::UnmapMemory(VAddr cpu_addr, size_t size) {
template <class P>
void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const Tegra::Engines::Fermi2D::Surface& src,
- const Tegra::Engines::Fermi2D::Config& copy) {
+ const Tegra::Engines::Fermi2D::Config& copy,
+ std::optional<Region2D> src_override,
+ std::optional<Region2D> dst_override) {
const BlitImages images = GetBlitImages(dst, src);
const ImageId dst_id = images.dst_id;
const ImageId src_id = images.src_id;
@@ -631,20 +635,42 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
const ImageViewInfo dst_view_info(ImageViewType::e2D, images.dst_format, dst_range);
const auto [dst_framebuffer_id, dst_view_id] = RenderTargetFromImage(dst_id, dst_view_info);
const auto [src_samples_x, src_samples_y] = SamplesLog2(src_image.info.num_samples);
- const std::array src_region{
- Offset2D{.x = copy.src_x0 >> src_samples_x, .y = copy.src_y0 >> src_samples_y},
- Offset2D{.x = copy.src_x1 >> src_samples_x, .y = copy.src_y1 >> src_samples_y},
+
+ // out of bounds texture blit checking
+ const bool use_override = src_override.has_value();
+ const s32 src_x0 = copy.src_x0 >> src_samples_x;
+ s32 src_x1 = use_override ? src_override->end.x : copy.src_x1 >> src_samples_x;
+ const s32 src_y0 = copy.src_y0 >> src_samples_y;
+ const s32 src_y1 = copy.src_y1 >> src_samples_y;
+
+ const auto src_width = static_cast<s32>(src_image.info.size.width);
+ const bool width_oob = src_x1 > src_width;
+ const auto width_diff = width_oob ? src_x1 - src_width : 0;
+ if (width_oob) {
+ src_x1 = src_width;
+ }
+
+ const Region2D src_dimensions{
+ Offset2D{.x = src_x0, .y = src_y0},
+ Offset2D{.x = src_x1, .y = src_y1},
};
+ const auto src_region = use_override ? *src_override : src_dimensions;
const std::optional src_base = src_image.TryFindBase(src.Address());
const SubresourceRange src_range{.base = src_base.value(), .extent = {1, 1}};
const ImageViewInfo src_view_info(ImageViewType::e2D, images.src_format, src_range);
const auto [src_framebuffer_id, src_view_id] = RenderTargetFromImage(src_id, src_view_info);
const auto [dst_samples_x, dst_samples_y] = SamplesLog2(dst_image.info.num_samples);
- const std::array dst_region{
- Offset2D{.x = copy.dst_x0 >> dst_samples_x, .y = copy.dst_y0 >> dst_samples_y},
- Offset2D{.x = copy.dst_x1 >> dst_samples_x, .y = copy.dst_y1 >> dst_samples_y},
+
+ const s32 dst_x0 = copy.dst_x0 >> dst_samples_x;
+ const s32 dst_x1 = copy.dst_x1 >> dst_samples_x;
+ const s32 dst_y0 = copy.dst_y0 >> dst_samples_y;
+ const s32 dst_y1 = copy.dst_y1 >> dst_samples_y;
+ const Region2D dst_dimensions{
+ Offset2D{.x = dst_x0, .y = dst_y0},
+ Offset2D{.x = dst_x1 - width_diff, .y = dst_y1},
};
+ const auto dst_region = use_override ? *dst_override : dst_dimensions;
// Always call this after src_framebuffer_id was queried, as the address might be invalidated.
Framebuffer* const dst_framebuffer = &slot_framebuffers[dst_framebuffer_id];
@@ -661,6 +687,21 @@ void TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
runtime.BlitImage(dst_framebuffer, dst_view, src_view, dst_region, src_region, copy.filter,
copy.operation);
}
+
+ if (width_oob) {
+ // Continue copy of the oob region of the texture on the next row
+ auto oob_src = src;
+ oob_src.height++;
+ const Region2D src_region_override{
+ Offset2D{.x = 0, .y = src_y0 + 1},
+ Offset2D{.x = width_diff, .y = src_y1 + 1},
+ };
+ const Region2D dst_region_override{
+ Offset2D{.x = dst_x1 - width_diff, .y = dst_y0},
+ Offset2D{.x = dst_x1, .y = dst_y1},
+ };
+ BlitImage(dst, oob_src, copy, src_region_override, dst_region_override);
+ }
}
template <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 {
s32 z;
};
+struct Region2D {
+ constexpr auto operator<=>(const Region2D&) const noexcept = default;
+
+ Offset2D start;
+ Offset2D end;
+};
+
struct Extent2D {
constexpr auto operator<=>(const Extent2D&) const noexcept = default;
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 @@
#include "yuzu/about_dialog.h"
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) {
+ const auto branch_name = std::string(Common::g_scm_branch);
+ const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id);
- const auto fmt = std::string(Common::g_title_bar_format_idle);
- const auto yuzu_build_version =
- fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{},
- std::string{}, std::string{}, std::string{}, build_id);
+
+ const auto yuzu_build = fmt::format("yuzu Development Build | {}-{}", branch_name, description);
+ const auto override_build = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
+ const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
ui->setupUi(this);
ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200));
- ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg(
- QString::fromStdString(yuzu_build_version), QString::fromUtf8(Common::g_scm_branch),
- QString::fromUtf8(Common::g_scm_desc), QString::fromUtf8(Common::g_build_date).left(10)));
+ ui->labelBuildInfo->setText(
+ ui->labelBuildInfo->text().arg(QString::fromStdString(yuzu_build_version),
+ QString::fromUtf8(Common::g_build_date).left(10)));
}
AboutDialog::~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 @@
</sizepolicy>
</property>
<property name="text">
- <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>
+ <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>
</property>
</widget>
</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(
OverlayDialog dialog(this, system, QString{}, QString::fromStdU16String(text_check_message),
tr("Cancel"), tr("OK"), Qt::AlignCenter);
- if (dialog.exec() == QDialog::Accepted) {
- emit SubmitNormalText(SwkbdResult::Ok, current_text);
+ if (dialog.exec() != QDialog::Accepted) {
+ StartInputThread();
break;
}
- StartInputThread();
+ auto text = ui->topOSK->currentIndex() == 1
+ ? ui->text_edit_osk->toPlainText().toStdU16String()
+ : ui->line_edit_osk->text().toStdU16String();
+
+ emit SubmitNormalText(SwkbdResult::Ok, std::move(text));
break;
}
}
@@ -480,11 +484,7 @@ void QtSoftwareKeyboardDialog::open() {
void QtSoftwareKeyboardDialog::reject() {
// Pressing the ESC key in a dialog calls QDialog::reject().
// We will override this behavior to the "Cancel" action on the software keyboard.
- if (is_inline) {
- emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
- } else {
- emit SubmitNormalText(SwkbdResult::Cancel, current_text);
- }
+ TranslateButtonPress(HIDButton::X);
}
void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
@@ -1027,10 +1027,8 @@ void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
ui->bottomOSK->setCurrentIndex(static_cast<int>(bottom_osk_index));
ui->button_shift_shift->setStyleSheet(
- QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);"
- "\nbackground-position: left top;"
- "\nbackground-repeat: no-repeat;"
- "\nbackground-origin: content;"));
+ QStringLiteral("image: url(:/overlay/osk_button_shift_lock_off.png);"
+ "\nimage-position: left;"));
ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
@@ -1040,10 +1038,8 @@ void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
caps_lock_enabled = false;
ui->button_shift_shift->setStyleSheet(
- QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_off.png);"
- "\nbackground-position: left top;"
- "\nbackground-repeat: no-repeat;"
- "\nbackground-origin: content;"));
+ QStringLiteral("image: url(:/overlay/osk_button_shift_lock_off.png);"
+ "\nimage-position: left;"));
ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
ui->button_backspace_shift->setIconSize(ui->button_backspace->iconSize());
@@ -1056,10 +1052,8 @@ void QtSoftwareKeyboardDialog::ChangeBottomOSKIndex() {
caps_lock_enabled = true;
ui->button_shift_shift->setStyleSheet(
- QStringLiteral("background-image: url(:/overlay/osk_button_shift_lock_on.png);"
- "\nbackground-position: left top;"
- "\nbackground-repeat: no-repeat;"
- "\nbackground-origin: content;"));
+ QStringLiteral("image: url(:/overlay/osk_button_shift_lock_on.png);"
+ "\nimage-position: left;"));
ui->button_shift_shift->setIconSize(ui->button_shift->iconSize());
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() {
StopInputThread();
}
-void QtNXWebEngineView::LoadLocalWebPage(std::string_view main_url,
- std::string_view additional_args) {
+void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url,
+ const std::string& additional_args) {
is_local = true;
LoadExtractedFonts();
@@ -113,12 +113,12 @@ void QtNXWebEngineView::LoadLocalWebPage(std::string_view main_url,
SetLastURL("http://localhost/");
StartInputThread();
- load(QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(main_url))).toString() +
- QString::fromStdString(std::string(additional_args))));
+ load(QUrl(QUrl::fromLocalFile(QString::fromStdString(main_url)).toString() +
+ QString::fromStdString(additional_args)));
}
-void QtNXWebEngineView::LoadExternalWebPage(std::string_view main_url,
- std::string_view additional_args) {
+void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url,
+ const std::string& additional_args) {
is_local = false;
SetUserAgent(UserAgent::WebApplet);
@@ -127,8 +127,7 @@ void QtNXWebEngineView::LoadExternalWebPage(std::string_view main_url,
SetLastURL("http://localhost/");
StartInputThread();
- load(QUrl(QString::fromStdString(std::string(main_url)) +
- QString::fromStdString(std::string(additional_args))));
+ load(QUrl(QString::fromStdString(main_url) + QString::fromStdString(additional_args)));
}
void QtNXWebEngineView::SetUserAgent(UserAgent user_agent) {
@@ -375,7 +374,7 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
QtWebBrowser::~QtWebBrowser() = default;
void QtWebBrowser::OpenLocalWebPage(
- std::string_view local_url, std::function<void()> extract_romfs_callback_,
+ const std::string& local_url, std::function<void()> extract_romfs_callback_,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const {
extract_romfs_callback = std::move(extract_romfs_callback_);
callback = std::move(callback_);
@@ -390,7 +389,7 @@ void QtWebBrowser::OpenLocalWebPage(
}
void QtWebBrowser::OpenExternalWebPage(
- std::string_view external_url,
+ const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const {
callback = std::move(callback_);
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:
* @param main_url The url to the file.
* @param additional_args Additional arguments appended to the main url.
*/
- void LoadLocalWebPage(std::string_view main_url, std::string_view additional_args);
+ void LoadLocalWebPage(const std::string& main_url, const std::string& additional_args);
/**
* Loads an external website. Cannot be used to load local urls.
@@ -66,7 +66,7 @@ public:
* @param main_url The url to the website.
* @param additional_args Additional arguments appended to the main url.
*/
- void LoadExternalWebPage(std::string_view main_url, std::string_view additional_args);
+ void LoadExternalWebPage(const std::string& main_url, const std::string& additional_args);
/**
* Sets the background color of the web page.
@@ -193,16 +193,17 @@ public:
explicit QtWebBrowser(GMainWindow& parent);
~QtWebBrowser() override;
- void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback_,
+ void OpenLocalWebPage(const std::string& local_url,
+ std::function<void()> extract_romfs_callback_,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback_) const override;
- void OpenExternalWebPage(std::string_view external_url,
+ void OpenExternalWebPage(const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback_) const override;
signals:
- void MainWindowOpenWebPage(std::string_view main_url, std::string_view additional_args,
+ void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args,
bool is_local) const;
private:
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 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/frontend/framebuffer_layout.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/mouse/mouse_input.h"
@@ -539,6 +539,8 @@ bool GRenderWindow::event(QEvent* event) {
void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event);
input_subsystem->GetKeyboard()->ReleaseAllKeys();
+ input_subsystem->GetMouse()->ReleaseAllButtons();
+ this->TouchReleased(0);
}
void 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() {
void Config::ReadCpuValues() {
qt_config->beginGroup(QStringLiteral("Cpu"));
- if (global) {
- Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>(
- ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt());
+ ReadSettingGlobal(Settings::values.cpu_accuracy, QStringLiteral("cpu_accuracy"), 0);
+
+ ReadSettingGlobal(Settings::values.cpuopt_unsafe_unfuse_fma,
+ QStringLiteral("cpuopt_unsafe_unfuse_fma"), true);
+ ReadSettingGlobal(Settings::values.cpuopt_unsafe_reduce_fp_error,
+ QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true);
+ ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
+ QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
+ if (global) {
Settings::values.cpuopt_page_tables =
ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool();
Settings::values.cpuopt_block_linking =
@@ -756,13 +762,6 @@ void Config::ReadCpuValues() {
ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
Settings::values.cpuopt_reduce_misalign_checks =
ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
-
- Settings::values.cpuopt_unsafe_unfuse_fma =
- ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool();
- Settings::values.cpuopt_unsafe_reduce_fp_error =
- ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool();
- Settings::values.cpuopt_unsafe_inaccurate_nan =
- ReadSetting(QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true).toBool();
}
qt_config->endGroup();
@@ -863,24 +862,20 @@ void Config::ReadSystemValues() {
Settings::values.rng_seed.SetGlobal(rng_seed_global);
if (global || !rng_seed_global) {
if (rng_seed_enabled) {
- Settings::values.rng_seed.SetValue(
- ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong());
+ Settings::values.rng_seed.SetValue(ReadSetting(QStringLiteral("rng_seed"), 0).toUInt());
} else {
Settings::values.rng_seed.SetValue(std::nullopt);
}
}
- bool custom_rtc_enabled;
- ReadSettingGlobal(custom_rtc_enabled, QStringLiteral("custom_rtc_enabled"), false);
- bool custom_rtc_global =
- global || qt_config->value(QStringLiteral("custom_rtc/use_global"), true).toBool();
- Settings::values.custom_rtc.SetGlobal(custom_rtc_global);
- if (global || !custom_rtc_global) {
+ if (global) {
+ const auto custom_rtc_enabled =
+ ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
if (custom_rtc_enabled) {
- Settings::values.custom_rtc.SetValue(
- std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong()));
+ Settings::values.custom_rtc =
+ std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong());
} else {
- Settings::values.custom_rtc.SetValue(std::nullopt);
+ Settings::values.custom_rtc = std::nullopt;
}
}
@@ -1314,10 +1309,19 @@ void Config::SavePathValues() {
void Config::SaveCpuValues() {
qt_config->beginGroup(QStringLiteral("Cpu"));
- if (global) {
- WriteSetting(QStringLiteral("cpu_accuracy"),
- static_cast<int>(Settings::values.cpu_accuracy), 0);
+ WriteSettingGlobal(QStringLiteral("cpu_accuracy"),
+ static_cast<u32>(Settings::values.cpu_accuracy.GetValue(global)),
+ Settings::values.cpu_accuracy.UsingGlobal(),
+ static_cast<u32>(Settings::CPUAccuracy::Accurate));
+ WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
+ Settings::values.cpuopt_unsafe_unfuse_fma, true);
+ WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
+ Settings::values.cpuopt_unsafe_reduce_fp_error, true);
+ WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
+ Settings::values.cpuopt_unsafe_inaccurate_nan, true);
+
+ if (global) {
WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
true);
WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking,
@@ -1332,13 +1336,6 @@ void Config::SaveCpuValues() {
WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
Settings::values.cpuopt_reduce_misalign_checks, true);
-
- WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"),
- Settings::values.cpuopt_unsafe_unfuse_fma, true);
- WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"),
- Settings::values.cpuopt_unsafe_reduce_fp_error, true);
- WriteSetting(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
- Settings::values.cpuopt_unsafe_inaccurate_nan, true);
}
qt_config->endGroup();
@@ -1433,14 +1430,14 @@ void Config::SaveSystemValues() {
Settings::values.rng_seed.GetValue(global).value_or(0),
Settings::values.rng_seed.UsingGlobal(), 0);
- WriteSettingGlobal(QStringLiteral("custom_rtc_enabled"),
- Settings::values.custom_rtc.GetValue(global).has_value(),
- Settings::values.custom_rtc.UsingGlobal(), false);
- WriteSettingGlobal(
- QStringLiteral("custom_rtc"),
- QVariant::fromValue<long long>(
- Settings::values.custom_rtc.GetValue(global).value_or(std::chrono::seconds{}).count()),
- Settings::values.custom_rtc.UsingGlobal(), 0);
+ if (global) {
+ WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
+ false);
+ WriteSetting(QStringLiteral("custom_rtc"),
+ QVariant::fromValue<long long>(
+ Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
+ 0);
+ }
WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
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:
};
// These metatype declarations cannot be in common/settings.h because core is devoid of QT
+Q_DECLARE_METATYPE(Settings::CPUAccuracy);
Q_DECLARE_METATYPE(Settings::RendererBackend);
Q_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 @@
void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
const QCheckBox* checkbox,
const CheckState& tracker) {
- if (tracker == CheckState::Global) {
- setting->SetGlobal(true);
- } else {
- setting->SetGlobal(false);
+ if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
setting->SetValue(checkbox->checkState());
+ } else if (!Settings::IsConfiguringGlobal()) {
+ if (tracker == CheckState::Global) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(checkbox->checkState());
+ }
}
}
void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
const QComboBox* combobox) {
- if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
- setting->SetGlobal(true);
- } else {
- setting->SetGlobal(false);
- setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
- }
-}
-
-void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
- const QComboBox* combobox) {
- if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
- setting->SetGlobal(true);
- } else {
- setting->SetGlobal(false);
- setting->SetValue(static_cast<Settings::RendererBackend>(
- combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
+ if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
+ setting->SetValue(combobox->currentIndex());
+ } else if (!Settings::IsConfiguringGlobal()) {
+ if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
+ }
}
}
@@ -51,27 +48,6 @@ void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
}
}
-void ConfigurationShared::SetPerGameSetting(QComboBox* combobox,
- const Settings::Setting<int>* setting) {
- combobox->setCurrentIndex(setting->UsingGlobal()
- ? ConfigurationShared::USE_GLOBAL_INDEX
- : setting->GetValue() + ConfigurationShared::USE_GLOBAL_OFFSET);
-}
-
-void ConfigurationShared::SetPerGameSetting(
- QComboBox* combobox, const Settings::Setting<Settings::RendererBackend>* setting) {
- combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
- : static_cast<int>(setting->GetValue()) +
- ConfigurationShared::USE_GLOBAL_OFFSET);
-}
-
-void ConfigurationShared::SetPerGameSetting(
- QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting) {
- combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
- : static_cast<int>(setting->GetValue()) +
- ConfigurationShared::USE_GLOBAL_OFFSET);
-}
-
void ConfigurationShared::SetHighlight(QWidget* widget, bool highlighted) {
if (highlighted) {
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;
constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
constexpr int USE_GLOBAL_OFFSET = 2;
+// CheckBoxes require a tracker for their state since we emulate a tristate CheckBox
enum class CheckState {
- Off,
- On,
- Global,
- Count,
+ Off, // Checkbox overrides to off/false
+ On, // Checkbox overrides to on/true
+ Global, // Checkbox defers to the global state
+ Count, // Simply the number of states, not a valid checkbox state
};
// Global-aware apply and set functions
+// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox,
const CheckState& tracker);
void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
-void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
- const QComboBox* combobox);
-void ApplyPerGameSetting(Settings::Setting<Settings::GPUAccuracy>* setting,
- const QComboBox* combobox);
+// Sets a Qt UI element given a Settings::Setting
void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
-void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<int>* setting);
-void SetPerGameSetting(QComboBox* combobox,
- const Settings::Setting<Settings::RendererBackend>* setting);
-void SetPerGameSetting(QComboBox* combobox,
- const Settings::Setting<Settings::GPUAccuracy>* setting);
+template <typename Type>
+void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<Type>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
+ : static_cast<int>(setting->GetValue()) +
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+// (Un)highlights a Qt UI element
void SetHighlight(QWidget* widget, bool highlighted);
+
+// Sets up a QCheckBox like a tristate one, given a Setting
void SetColoredTristate(QCheckBox* checkbox, const Settings::Setting<bool>& setting,
CheckState& tracker);
void SetColoredTristate(QCheckBox* checkbox, bool global, bool state, bool global_state,
CheckState& tracker);
+
+// Sets up coloring of a QWidget `target` based on the state of a QComboBox, and calls
+// InsertGlobalItem
void SetColoredComboBox(QComboBox* combobox, QWidget* target, int global);
+// Adds the "Use Global Configuration" selection and separator to the beginning of a QComboBox
void InsertGlobalItem(QComboBox* combobox, int global_index);
} // 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) {
}
void ConfigureAudio::ApplyConfiguration() {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
+ ui->toggle_audio_stretching, enable_audio_stretching);
+
if (Settings::IsConfiguringGlobal()) {
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
@@ -108,19 +111,12 @@ void ConfigureAudio::ApplyConfiguration() {
.toStdString();
// Guard if during game and set to game-specific value
- if (Settings::values.enable_audio_stretching.UsingGlobal()) {
- Settings::values.enable_audio_stretching.SetValue(
- ui->toggle_audio_stretching->isChecked());
- }
if (Settings::values.volume.UsingGlobal()) {
Settings::values.volume.SetValue(
static_cast<float>(ui->volume_slider->sliderPosition()) /
ui->volume_slider->maximum());
}
} else {
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
- ui->toggle_audio_stretching,
- enable_audio_stretching);
if (ui->volume_combo_box->currentIndex() == 0) {
Settings::values.volume.SetGlobal(true);
} 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 @@
#include "common/settings.h"
#include "core/core.h"
#include "ui_configure_cpu.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_cpu.h"
ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) {
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,
@@ -29,19 +32,29 @@ void ConfigureCpu::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->accuracy->setEnabled(runtime_lock);
- ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy));
- UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy));
-
ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
- ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma);
ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
- ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error);
ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
- ui->cpuopt_unsafe_inaccurate_nan->setChecked(Settings::values.cpuopt_unsafe_inaccurate_nan);
+
+ ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
+ ui->cpuopt_unsafe_reduce_fp_error->setChecked(
+ Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue());
+ ui->cpuopt_unsafe_inaccurate_nan->setChecked(
+ Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
+
+ if (Settings::IsConfiguringGlobal()) {
+ ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->accuracy, &Settings::values.cpu_accuracy);
+ ConfigurationShared::SetHighlight(ui->widget_accuracy,
+ !Settings::values.cpu_accuracy.UsingGlobal());
+ }
+ UpdateGroup(ui->accuracy->currentIndex());
}
void ConfigureCpu::AccuracyUpdated(int index) {
- if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
+ if (Settings::IsConfiguringGlobal() &&
+ static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) {
const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"),
tr("CPU Debug Mode is only intended for developer "
"use. Are you sure you want to enable this?"),
@@ -54,16 +67,39 @@ void ConfigureCpu::AccuracyUpdated(int index) {
}
void ConfigureCpu::UpdateGroup(int index) {
- ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) ==
- Settings::CPUAccuracy::Unsafe);
+ if (!Settings::IsConfiguringGlobal()) {
+ index -= ConfigurationShared::USE_GLOBAL_OFFSET;
+ }
+ const auto accuracy = static_cast<Settings::CPUAccuracy>(index);
+ ui->unsafe_group->setVisible(accuracy == Settings::CPUAccuracy::Unsafe);
}
void ConfigureCpu::ApplyConfiguration() {
- Settings::values.cpu_accuracy =
- static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex());
- Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked();
- Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked();
- Settings::values.cpuopt_unsafe_inaccurate_nan = ui->cpuopt_unsafe_inaccurate_nan->isChecked();
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma,
+ ui->cpuopt_unsafe_unfuse_fma,
+ cpuopt_unsafe_unfuse_fma);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_reduce_fp_error,
+ ui->cpuopt_unsafe_reduce_fp_error,
+ cpuopt_unsafe_reduce_fp_error);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan,
+ ui->cpuopt_unsafe_inaccurate_nan,
+ cpuopt_unsafe_inaccurate_nan);
+
+ if (Settings::IsConfiguringGlobal()) {
+ // Guard if during game and set to game-specific value
+ if (Settings::values.cpu_accuracy.UsingGlobal()) {
+ Settings::values.cpu_accuracy.SetValue(
+ static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()));
+ }
+ } else {
+ if (ui->accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.cpu_accuracy.SetGlobal(true);
+ } else {
+ Settings::values.cpu_accuracy.SetGlobal(false);
+ Settings::values.cpu_accuracy.SetValue(static_cast<Settings::CPUAccuracy>(
+ ui->accuracy->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
+ }
+ }
}
void ConfigureCpu::changeEvent(QEvent* event) {
@@ -77,3 +113,25 @@ void ConfigureCpu::changeEvent(QEvent* event) {
void ConfigureCpu::RetranslateUI() {
ui->retranslateUi(this);
}
+
+void ConfigureCpu::SetupPerGameUI() {
+ if (Settings::IsConfiguringGlobal()) {
+ return;
+ }
+
+ ConfigurationShared::SetColoredComboBox(
+ ui->accuracy, ui->widget_accuracy,
+ static_cast<u32>(Settings::values.cpu_accuracy.GetValue(true)));
+ ui->accuracy->removeItem(static_cast<u32>(Settings::CPUAccuracy::DebugMode) +
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+
+ ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_unfuse_fma,
+ Settings::values.cpuopt_unsafe_unfuse_fma,
+ cpuopt_unsafe_unfuse_fma);
+ ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_reduce_fp_error,
+ Settings::values.cpuopt_unsafe_reduce_fp_error,
+ cpuopt_unsafe_reduce_fp_error);
+ ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan,
+ Settings::values.cpuopt_unsafe_inaccurate_nan,
+ cpuopt_unsafe_inaccurate_nan);
+}
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 @@
#include <QWidget>
#include "common/settings.h"
+namespace ConfigurationShared {
+enum class CheckState;
+}
+
namespace Ui {
class ConfigureCpu;
}
@@ -30,5 +34,11 @@ private:
void SetConfiguration();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureCpu> ui;
+
+ ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma;
+ ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error;
+ ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
};
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 @@
</property>
<layout class="QVBoxLayout">
<item>
- <layout class="QHBoxLayout">
- <item>
- <widget class="QLabel">
- <property name="text">
- <string>Accuracy:</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="accuracy">
- <item>
+ <widget class="QWidget" name="widget_accuracy" native="true">
+ <layout class="QHBoxLayout" name="layout_accuracy">
+ <item>
+ <widget class="QLabel" name="label">
<property name="text">
- <string>Accurate</string>
+ <string>Accuracy:</string>
</property>
- </item>
- <item>
- <property name="text">
- <string>Unsafe</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Enable Debug Mode</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="accuracy">
+ <item>
+ <property name="text">
+ <string>Accurate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Unsafe</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Enable Debug Mode</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</item>
<item>
- <widget class="QLabel">
- <property name="wordWrap">
- <bool>1</bool>
- </property>
+ <widget class="QLabel" name="label">
<property name="text">
- <string>We recommend setting accuracy to "Accurate".</string>
+ <string>We recommend setting accuracy to &quot;Accurate&quot;.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
</property>
</widget>
</item>
@@ -76,49 +78,49 @@
</property>
<layout class="QVBoxLayout">
<item>
- <widget class="QLabel">
- <property name="wordWrap">
- <bool>1</bool>
- </property>
+ <widget class="QLabel" name="label">
<property name="text">
<string>These settings reduce accuracy for speed.</string>
</property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma">
- <property name="text">
- <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
- </property>
<property name="toolTip">
<string>
&lt;div&gt;This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Unfuse FMA (improve performance on CPUs without FMA)</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error">
- <property name="text">
- <string>Faster FRSQRTE and FRECPE</string>
- </property>
<property name="toolTip">
<string>
&lt;div&gt;This option improves the speed of some approximate floating-point functions by using less accurate native approximations.&lt;/div&gt;
</string>
</property>
+ <property name="text">
+ <string>Faster FRSQRTE and FRECPE</string>
+ </property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cpuopt_unsafe_inaccurate_nan">
- <property name="text">
- <string>Inaccurate NaN handling</string>
- </property>
<property name="toolTip">
<string>
&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;
</string>
</property>
+ <property name="text">
+ <string>Inaccurate NaN handling</string>
+ </property>
</widget>
</item>
</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 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="label_1">
<property name="text">
<string>Global Log Filter</string>
</property>
@@ -66,7 +66,7 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="label_3">
+ <widget class="QLabel" name="label_2">
<property name="font">
<font>
<italic>true</italic>
@@ -92,7 +92,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
- <widget class="QLabel" name="label_4">
+ <widget class="QLabel" name="label_3">
<property name="text">
<string>Arguments String</string>
</property>
@@ -155,7 +155,7 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="label_5">
+ <widget class="QLabel" name="label_4">
<property name="font">
<font>
<italic>true</italic>
@@ -200,7 +200,7 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="label_3">
+ <widget class="QLabel" name="label_5">
<property name="font">
<font>
<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() {
}
void ConfigureGeneral::ApplyConfiguration() {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
+ use_multi_core);
+
if (Settings::IsConfiguringGlobal()) {
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
@@ -62,13 +65,7 @@ void ConfigureGeneral::ApplyConfiguration() {
Qt::Checked);
Settings::values.frame_limit.SetValue(ui->frame_limit->value());
}
- if (Settings::values.use_multi_core.UsingGlobal()) {
- Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
- }
} else {
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
- ui->use_multi_core, use_multi_core);
-
bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global;
Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
Settings::values.frame_limit.SetGlobal(global_frame_limit);
@@ -94,6 +91,9 @@ void ConfigureGeneral::RetranslateUI() {
void ConfigureGeneral::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) {
+ // Disables each setting if:
+ // - A game is running (thus settings in use), and
+ // - A non-global setting is applied.
ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
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() {
}
void ConfigureGraphics::ApplyConfiguration() {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
+ ui->fullscreen_mode_combobox);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
+ ui->aspect_ratio_combobox);
+
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
+ ui->use_disk_shader_cache, use_disk_shader_cache);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
+ ui->use_asynchronous_gpu_emulation,
+ use_asynchronous_gpu_emulation);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
+ ui->use_nvdec_emulation, use_nvdec_emulation);
+
if (Settings::IsConfiguringGlobal()) {
// Guard if during game and set to game-specific value
if (Settings::values.renderer_backend.UsingGlobal()) {
@@ -114,22 +127,6 @@ void ConfigureGraphics::ApplyConfiguration() {
if (Settings::values.vulkan_device.UsingGlobal()) {
Settings::values.vulkan_device.SetValue(vulkan_device);
}
- if (Settings::values.fullscreen_mode.UsingGlobal()) {
- Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
- }
- if (Settings::values.aspect_ratio.UsingGlobal()) {
- Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
- }
- if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
- Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
- }
- if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
- Settings::values.use_asynchronous_gpu_emulation.SetValue(
- ui->use_asynchronous_gpu_emulation->isChecked());
- }
- if (Settings::values.use_nvdec_emulation.UsingGlobal()) {
- Settings::values.use_nvdec_emulation.SetValue(ui->use_nvdec_emulation->isChecked());
- }
if (Settings::values.bg_red.UsingGlobal()) {
Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
@@ -150,19 +147,6 @@ void ConfigureGraphics::ApplyConfiguration() {
}
}
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
- ui->fullscreen_mode_combobox);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
- ui->aspect_ratio_combobox);
-
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
- ui->use_disk_shader_cache, use_disk_shader_cache);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
- ui->use_asynchronous_gpu_emulation,
- use_asynchronous_gpu_emulation);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_nvdec_emulation,
- ui->use_nvdec_emulation, use_nvdec_emulation);
-
if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.bg_red.SetGlobal(true);
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() {
ui->gpu_accuracy->currentIndex() -
((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
+ ui->anisotropic_filtering_combobox);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
+ ui->use_assembly_shaders, use_assembly_shaders);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
+ ui->use_asynchronous_shaders,
+ use_asynchronous_shaders);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
+ ui->use_fast_gpu_time, use_fast_gpu_time);
+
if (Settings::IsConfiguringGlobal()) {
// Must guard in case of a during-game configuration when set to be game-specific.
if (Settings::values.gpu_accuracy.UsingGlobal()) {
Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
}
- if (Settings::values.use_vsync.UsingGlobal()) {
- Settings::values.use_vsync.SetValue(ui->use_vsync->isChecked());
- }
- if (Settings::values.use_assembly_shaders.UsingGlobal()) {
- Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
- }
- if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
- Settings::values.use_asynchronous_shaders.SetValue(
- ui->use_asynchronous_shaders->isChecked());
- }
- if (Settings::values.use_asynchronous_shaders.UsingGlobal()) {
- Settings::values.use_asynchronous_shaders.SetValue(
- ui->use_asynchronous_shaders->isChecked());
- }
- if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
- Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
- }
- if (Settings::values.max_anisotropy.UsingGlobal()) {
- Settings::values.max_anisotropy.SetValue(
- ui->anisotropic_filtering_combobox->currentIndex());
- }
} else {
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
- ui->anisotropic_filtering_combobox);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync,
- use_vsync);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
- ui->use_assembly_shaders, use_assembly_shaders);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
- ui->use_asynchronous_shaders,
- use_asynchronous_shaders);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
- ui->use_fast_gpu_time, use_fast_gpu_time);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
- ui->anisotropic_filtering_combobox);
-
if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
Settings::values.gpu_accuracy.SetGlobal(true);
} 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) {
return QObject::tr("Button %1").arg(button_str);
}
+ if (param.Has("motion")) {
+ return QObject::tr("SDL Motion");
+ }
+
return {};
}
@@ -1245,12 +1249,16 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
const auto& device = input_devices[ui->comboDevices->currentIndex()];
auto button_mapping = input_subsystem->GetButtonMappingForDevice(device);
auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device);
+ auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device);
for (std::size_t i = 0; i < buttons_param.size(); ++i) {
buttons_param[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)];
}
for (std::size_t i = 0; i < analogs_param.size(); ++i) {
analogs_param[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)];
}
+ for (std::size_t i = 0; i < motions_param.size(); ++i) {
+ motions_param[i] = motion_mapping[static_cast<Settings::NativeMotion::Values>(i)];
+ }
UpdateUI();
}
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;
void ConfigurePerGame::ApplyConfiguration() {
ui->addonsTab->ApplyConfiguration();
ui->generalTab->ApplyConfiguration();
+ ui->cpuTab->ApplyConfiguration();
ui->systemTab->ApplyConfiguration();
ui->graphicsTab->ApplyConfiguration();
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 @@
<string>System</string>
</attribute>
</widget>
+ <widget class="ConfigureCpu" name="cpuTab">
+ <attribute name="title">
+ <string>CPU</string>
+ </attribute>
+ </widget>
<widget class="ConfigureGraphics" name="graphicsTab">
<attribute name="title">
<string>Graphics</string>
@@ -311,6 +316,12 @@
<header>configuration/configure_per_game_addons.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ConfigureCpu</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_cpu.h</header>
+ <container>1</container>
+ </customwidget>
</customwidgets>
<resources/>
<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() {
QStringLiteral("%1")
.arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
.toUpper();
- const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or(
+ const auto rtc_time = Settings::values.custom_rtc.value_or(
std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
@@ -73,9 +73,8 @@ void ConfigureSystem::SetConfiguration() {
Settings::values.rng_seed.UsingGlobal());
ui->rng_seed_edit->setText(rng_seed);
- ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
- ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
- Settings::values.rng_seed.UsingGlobal());
+ ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
if (Settings::IsConfiguringGlobal()) {
@@ -109,17 +108,17 @@ void ConfigureSystem::ApplyConfiguration() {
// Allow setting custom RTC even if system is powered on,
// to allow in-game time to be fast forwarded
- if (Settings::values.custom_rtc.UsingGlobal()) {
+ if (Settings::IsConfiguringGlobal()) {
if (ui->custom_rtc_checkbox->isChecked()) {
- Settings::values.custom_rtc.SetValue(
- std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
+ Settings::values.custom_rtc =
+ std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
if (system.IsPoweredOn()) {
- const s64 posix_time{Settings::values.custom_rtc.GetValue()->count() +
+ const s64 posix_time{Settings::values.custom_rtc->count() +
Service::Time::TimeManager::GetExternalTimeZoneOffset()};
system.GetTimeManager().UpdateLocalSystemClockTime(posix_time);
}
} else {
- Settings::values.custom_rtc.SetValue(std::nullopt);
+ Settings::values.custom_rtc = std::nullopt;
}
}
@@ -127,21 +126,14 @@ void ConfigureSystem::ApplyConfiguration() {
return;
}
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index, ui->combo_language);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
+ ui->combo_time_zone);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
+
if (Settings::IsConfiguringGlobal()) {
// Guard if during game and set to game-specific value
- if (Settings::values.language_index.UsingGlobal()) {
- Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
- }
- if (Settings::values.region_index.UsingGlobal()) {
- Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
- }
- if (Settings::values.time_zone_index.UsingGlobal()) {
- Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
- }
- if (Settings::values.sound_index.UsingGlobal()) {
- Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
- }
-
if (Settings::values.rng_seed.UsingGlobal()) {
if (ui->rng_seed_checkbox->isChecked()) {
Settings::values.rng_seed.SetValue(
@@ -151,13 +143,6 @@ void ConfigureSystem::ApplyConfiguration() {
}
}
} else {
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
- ui->combo_language);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
- ui->combo_time_zone);
- ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
-
switch (use_rng_seed) {
case ConfigurationShared::CheckState::On:
case ConfigurationShared::CheckState::Off:
@@ -177,26 +162,6 @@ void ConfigureSystem::ApplyConfiguration() {
case ConfigurationShared::CheckState::Count:
break;
}
-
- switch (use_custom_rtc) {
- case ConfigurationShared::CheckState::On:
- case ConfigurationShared::CheckState::Off:
- Settings::values.custom_rtc.SetGlobal(false);
- if (ui->custom_rtc_checkbox->isChecked()) {
- Settings::values.custom_rtc.SetValue(
- std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
- } else {
- Settings::values.custom_rtc.SetValue(std::nullopt);
- }
- break;
- case ConfigurationShared::CheckState::Global:
- Settings::values.custom_rtc.SetGlobal(false);
- Settings::values.custom_rtc.SetValue(std::nullopt);
- Settings::values.custom_rtc.SetGlobal(true);
- break;
- case ConfigurationShared::CheckState::Count:
- break;
- }
}
system.ApplySettings();
@@ -227,8 +192,6 @@ void ConfigureSystem::SetupPerGameUI() {
ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
- ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
- ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
return;
}
@@ -246,8 +209,7 @@ void ConfigureSystem::SetupPerGameUI() {
ui->rng_seed_checkbox, Settings::values.rng_seed.UsingGlobal(),
Settings::values.rng_seed.GetValue().has_value(),
Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
- ConfigurationShared::SetColoredTristate(
- ui->custom_rtc_checkbox, Settings::values.custom_rtc.UsingGlobal(),
- Settings::values.custom_rtc.GetValue().has_value(),
- Settings::values.custom_rtc.GetValue(true).has_value(), use_custom_rtc);
+
+ ui->custom_rtc_checkbox->setVisible(false);
+ ui->custom_rtc_edit->setVisible(false);
}
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
SetConfiguration();
// Force game list reload if any of the relevant settings are changed.
+ connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate);
connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureUi::RequestGameListUpdate);
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 @@
#include "common/assert.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/k_class_token.h"
+#include "core/hle/kernel/k_handle_table.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread.h"
-#include "core/hle/kernel/process.h"
#include "core/hle/kernel/svc_common.h"
#include "core/hle/kernel/svc_types.h"
#include "core/memory.h"
@@ -91,7 +92,7 @@ std::size_t WaitTreeItem::Row() const {
std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
std::vector<std::unique_ptr<WaitTreeThread>> item_list;
std::size_t row = 0;
- auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) {
+ auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) {
for (std::size_t i = 0; i < threads.size(); ++i) {
if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) {
item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
@@ -114,11 +115,11 @@ QString WaitTreeText::GetText() const {
return text;
}
-WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table)
+WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table)
: mutex_address(mutex_address) {
mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
- owner = handle_table.Get<Kernel::KThread>(owner_handle);
+ owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe();
}
WaitTreeMutexInfo::~WaitTreeMutexInfo() = default;
@@ -183,18 +184,20 @@ bool WaitTreeExpandableItem::IsExpandable() const {
}
QString WaitTreeSynchronizationObject::GetText() const {
- return tr("[%1]%2 %3")
- .arg(object.GetObjectId())
- .arg(QString::fromStdString(object.GetTypeName()),
+ return tr("[%1] %2 %3")
+ .arg(object.GetId())
+ .arg(QString::fromStdString(object.GetTypeObj().GetName()),
QString::fromStdString(object.GetName()));
}
std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::make(
const Kernel::KSynchronizationObject& object) {
- switch (object.GetHandleType()) {
- case Kernel::HandleType::ReadableEvent:
+ const auto type =
+ static_cast<Kernel::KClassTokenGenerator::ObjectType>(object.GetTypeObj().GetClassToken());
+ switch (type) {
+ case Kernel::KClassTokenGenerator::ObjectType::KReadableEvent:
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::KReadableEvent&>(object));
- case Kernel::HandleType::Thread:
+ case Kernel::KClassTokenGenerator::ObjectType::KThread:
return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object));
default:
return std::make_unique<WaitTreeSynchronizationObject>(object);
@@ -204,12 +207,13 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list;
- const auto& threads = object.GetWaitingThreadsForDebugging();
+ auto threads = object.GetWaitingThreadsForDebugging();
if (threads.empty()) {
list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
} else {
- list.push_back(std::make_unique<WaitTreeThreadList>(threads));
+ list.push_back(std::make_unique<WaitTreeThreadList>(std::move(threads)));
}
+
return list;
}
@@ -377,8 +381,8 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::KReadableEvent& object)
: WaitTreeSynchronizationObject(object) {}
WaitTreeEvent::~WaitTreeEvent() = default;
-WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list)
- : thread_list(list) {}
+WaitTreeThreadList::WaitTreeThreadList(std::vector<Kernel::KThread*>&& list)
+ : thread_list(std::move(list)) {}
WaitTreeThreadList::~WaitTreeThreadList() = default;
QString 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 @@
#include <QAbstractItemModel>
#include <QDockWidget>
#include <QTreeView>
+
#include "common/common_types.h"
-#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/svc_common.h"
class EmuThread;
namespace Kernel {
-class HandleTable;
+class KHandleTable;
class KReadableEvent;
class KSynchronizationObject;
class KThread;
@@ -73,17 +75,17 @@ public:
class WaitTreeMutexInfo : public WaitTreeExpandableItem {
Q_OBJECT
public:
- explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTable& handle_table);
+ explicit WaitTreeMutexInfo(VAddr mutex_address, const Kernel::KHandleTable& handle_table);
~WaitTreeMutexInfo() override;
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
private:
- VAddr mutex_address;
- u32 mutex_value;
- Kernel::Handle owner_handle;
- std::shared_ptr<Kernel::KThread> owner;
+ VAddr mutex_address{};
+ u32 mutex_value{};
+ Kernel::Handle owner_handle{};
+ Kernel::KThread* owner{};
};
class WaitTreeCallstack : public WaitTreeExpandableItem {
@@ -149,14 +151,14 @@ public:
class WaitTreeThreadList : public WaitTreeExpandableItem {
Q_OBJECT
public:
- explicit WaitTreeThreadList(const std::vector<Kernel::KThread*>& list);
+ explicit WaitTreeThreadList(std::vector<Kernel::KThread*>&& list);
~WaitTreeThreadList() override;
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
private:
- const std::vector<Kernel::KThread*>& thread_list;
+ std::vector<Kernel::KThread*> thread_list;
};
class 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) {
label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
}
-bool GameListSearchField::isEmpty() const {
- return edit_filter->text().isEmpty();
+QString GameListSearchField::filterText() const {
+ return edit_filter->text();
}
QString GameList::GetLastFilterResultItem() const {
@@ -236,9 +236,9 @@ void GameList::OnTextChanged(const QString& new_text) {
} else {
tree_view->setRowHidden(j, folder_index, true);
}
- search_field->setFilterResult(result_count, children_total);
}
}
+ search_field->setFilterResult(result_count, children_total);
}
}
@@ -595,6 +595,7 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
connect(delete_dir, &QAction::triggered, [this, &game_dir, selected] {
UISettings::values.game_dirs.removeOne(game_dir);
item_model->invisibleRootItem()->removeRow(selected.row());
+ OnTextChanged(search_field->filterText());
});
}
@@ -622,7 +623,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
// move the treeview items
QList<QStandardItem*> item = item_model->takeRow(row);
item_model->invisibleRootItem()->insertRow(row - 1, item);
- tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
+ tree_view->setExpanded(selected.sibling(row - 1, 0),
+ UISettings::values.game_dirs[other_index].expanded);
});
connect(move_down, &QAction::triggered, [this, selected, row, game_dir_index] {
@@ -637,7 +639,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
// move the treeview items
const QList<QStandardItem*> item = item_model->takeRow(row);
item_model->invisibleRootItem()->insertRow(row + 1, item);
- tree_view->setExpanded(selected, UISettings::values.game_dirs[game_dir_index].expanded);
+ tree_view->setExpanded(selected.sibling(row + 1, 0),
+ UISettings::values.game_dirs[other_index].expanded);
});
connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
@@ -774,7 +777,7 @@ void GameList::RefreshGameDirectory() {
void GameList::ToggleFavorite(u64 program_id) {
if (!UISettings::values.favorited_ids.contains(program_id)) {
tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(),
- !search_field->isEmpty());
+ !search_field->filterText().isEmpty());
UISettings::values.favorited_ids.append(program_id);
AddFavorite(program_id);
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 {
public:
explicit GameListSearchField(GameList* parent = nullptr);
+ QString filterText() const;
void setFilterResult(int visible, int total);
- bool isEmpty() const;
void clear();
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
#include "core/file_sys/romfs.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/submission_package.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nfp/nfp.h"
@@ -241,14 +241,15 @@ GMainWindow::GMainWindow()
ConnectMenuEvents();
ConnectWidgetEvents();
+ const auto branch_name = std::string(Common::g_scm_branch);
+ const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id);
- const auto fmt = std::string(Common::g_title_bar_format_idle);
- const auto yuzu_build_version =
- fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{},
- std::string{}, std::string{}, std::string{}, build_id);
- LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch,
- Common::g_scm_desc);
+ const auto yuzu_build = fmt::format("yuzu Development Build | {}-{}", branch_name, description);
+ const auto override_build = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
+ const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build;
+
+ LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version);
#ifdef ARCHITECTURE_x86_64
const auto& caps = Common::GetCPUCaps();
std::string cpu_string = caps.cpu_string;
@@ -349,7 +350,7 @@ GMainWindow::GMainWindow()
continue;
}
- Settings::values.current_user = selected_user;
+ Settings::values.current_user = static_cast<s32>(selected_user);
continue;
}
@@ -574,8 +575,8 @@ void GMainWindow::SoftwareKeyboardExit() {
software_keyboard = nullptr;
}
-void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
- bool is_local) {
+void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
+ const std::string& additional_args, bool is_local) {
#ifdef YUZU_USE_QT_WEB_ENGINE
if (disable_web_applet) {
@@ -596,13 +597,15 @@ void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_v
loading_progress.setRange(0, 3);
loading_progress.setValue(0);
- if (is_local && !Common::FS::Exists(std::string(main_url))) {
+ if (is_local && !Common::FS::Exists(main_url)) {
loading_progress.show();
auto future = QtConcurrent::run([this] { emit WebBrowserExtractOfflineRomFS(); });
while (!future.isFinished()) {
QCoreApplication::processEvents();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
@@ -1375,7 +1378,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
game_list->hide();
game_list_placeholder->hide();
}
- status_bar_update_timer.start(2000);
+ status_bar_update_timer.start(500);
async_status_button->setDisabled(true);
multicore_status_button->setDisabled(true);
renderer_status_button->setDisabled(true);
@@ -2099,6 +2102,7 @@ void GMainWindow::OnMenuInstallToNAND() {
QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
QStringList failed_files{}; // Files that failed to install due to errors
+ bool detected_base_install{}; // Whether a base game was attempted to be installed
ui.action_Install_File_NAND->setEnabled(false);
@@ -2124,6 +2128,7 @@ void GMainWindow::OnMenuInstallToNAND() {
while (!future.isFinished()) {
QCoreApplication::processEvents();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
result = future.result();
@@ -2144,6 +2149,10 @@ void GMainWindow::OnMenuInstallToNAND() {
case InstallResult::Failure:
failed_files.append(QFileInfo(file).fileName());
break;
+ case InstallResult::BaseInstallAttempted:
+ failed_files.append(QFileInfo(file).fileName());
+ detected_base_install = true;
+ break;
}
--remaining;
@@ -2151,6 +2160,13 @@ void GMainWindow::OnMenuInstallToNAND() {
install_progress->close();
+ if (detected_base_install) {
+ QMessageBox::warning(
+ this, tr("Install Results"),
+ tr("To avoid possible conflicts, we discourage users from installing base games to the "
+ "NAND.\nPlease, only use this feature to install updates and DLC."));
+ }
+
const QString install_results =
(new_files.isEmpty() ? QString{}
: tr("%n file(s) were newly installed\n", "", new_files.size())) +
@@ -2212,11 +2228,14 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
const auto res =
Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
*nsp, true, qt_raw_copy);
- if (res == FileSys::InstallResult::Success) {
+ switch (res) {
+ case FileSys::InstallResult::Success:
return InstallResult::Success;
- } else if (res == FileSys::InstallResult::OverwriteExisting) {
+ case FileSys::InstallResult::OverwriteExisting:
return InstallResult::Overwrite;
- } else {
+ case FileSys::InstallResult::ErrorBaseInstall:
+ return InstallResult::BaseInstallAttempted;
+ default:
return InstallResult::Failure;
}
}
@@ -2749,24 +2768,19 @@ void GMainWindow::MigrateConfigFiles() {
void GMainWindow::UpdateWindowTitle(const std::string& title_name,
const std::string& title_version) {
- const auto full_name = std::string(Common::g_build_fullname);
const auto branch_name = std::string(Common::g_scm_branch);
const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id);
- const auto date =
- QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString();
+ const auto yuzu_title = fmt::format("yuzu | {}-{}", branch_name, description);
+ const auto override_title = fmt::format(std::string(Common::g_title_bar_format_idle), build_id);
+ const auto window_title = override_title.empty() ? yuzu_title : override_title;
if (title_name.empty()) {
- const auto fmt = std::string(Common::g_title_bar_format_idle);
- setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt,
- full_name, branch_name, description,
- std::string{}, date, build_id)));
+ setWindowTitle(QString::fromStdString(window_title));
} else {
- const auto fmt = std::string(Common::g_title_bar_format_running);
- setWindowTitle(QString::fromStdString(
- fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name,
- description, title_name, date, build_id, title_version)));
+ const auto run_title = fmt::format("{} | {} | {}", window_title, title_name, title_version);
+ setWindowTitle(QString::fromStdString(run_title));
}
}
@@ -2795,7 +2809,7 @@ void GMainWindow::UpdateStatusBar() {
} else {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
}
- game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
+ game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
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 {
Success,
Overwrite,
Failure,
+ BaseInstallAttempted,
};
enum class ReinitializeKeyBehavior {
@@ -159,7 +160,7 @@ public slots:
void SoftwareKeyboardExit();
void ErrorDisplayDisplayError(QString error_code, QString error_text);
void ProfileSelectorSelectProfile();
- void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
+ void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args,
bool is_local);
void OnAppFocusStateChanged(Qt::ApplicationState state);
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() {
const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false);
if (custom_rtc_enabled) {
- Settings::values.custom_rtc.SetValue(
- std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)));
+ Settings::values.custom_rtc =
+ std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0));
} else {
- Settings::values.custom_rtc.SetValue(std::nullopt);
+ Settings::values.custom_rtc = std::nullopt;
}
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() {
const auto results = Core::System::GetInstance().GetAndResetPerfStats();
const auto title =
fmt::format("yuzu {} | {}-{} | FPS: {:.0f} ({:.0f}%)", Common::g_build_fullname,
- Common::g_scm_branch, Common::g_scm_desc, results.game_fps,
+ Common::g_scm_branch, Common::g_scm_desc, results.average_game_fps,
results.emulation_speed * 100.0);
SDL_SetWindowTitle(render_window, title.c_str());
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 @@
#include "core/crypto/key_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h"
-#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/telemetry_session.h"